diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..ba26f5568a --- /dev/null +++ b/.clang-format @@ -0,0 +1,15 @@ +--- +Language : Cpp +# BasedOnStyle : GNU +AlwaysBreakAfterReturnType: TopLevelDefinitions +AlwaysBreakTemplateDeclarations: true +BraceWrapping: + SplitEmptyFunction: false +ColumnLimit: 130 +IndentPPDirectives: AfterHash +PointerAlignment: Left +SortIncludes: false +SortUsingDeclarations: false +SpaceBeforeParens: ControlStatements +Standard: Cpp11 +... diff --git a/.gitattributes b/.gitattributes index 70faca108b..7d845e399e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,14 @@ +# currently empty attributes (using pre-commit) +[attr]cppfiles +[attr]cfiles +[attr]pyfiles +*.cpp cppfiles +*.cxx cppfiles +*.h cppfiles +*.inl cppfiles +*.txx cppfiles +*.c cfiles +*.py pyfiles *.v -text -diff *.s -text -diff *.scn -text -diff diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000000..1ffa1ebeb8 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,13 @@ +name: Check +on: +- push +- pull_request +jobs: + check: + runs-on: ubuntu-latest + name: pre-commit + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - run: sudo apt-get install -yqq clang-format + - uses: pre-commit/action@v2.0.0 diff --git a/.gitignore b/.gitignore index 52958752bb..fea9b2b25e 100644 --- a/.gitignore +++ b/.gitignore @@ -84,4 +84,7 @@ install_manifest.txt # other stuff .cache *.idea -*.user \ No newline at end of file +*.user + +build +out diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..f1589c12c3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,6 @@ +repos: +- repo: git://github.com/doublify/pre-commit-clang-format + rev: 62302476d0da01515660132d76902359bed0f782 + hooks: + - id: clang-format + files: \.(c|cc|cxx|cpp|h|hpp|hxx|inl|txx)$ diff --git a/CMakeLists.txt b/CMakeLists.txt index fc92c31b73..15473dd98a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,10 @@ if(NOT DISABLE_CERN_ROOT) endif() endif() +if(NOT DISABLE_HDF5_SUPPORT) + find_package(HDF5 COMPONENTS CXX) +endif() + if(NOT DISABLE_AVW) find_package(AVW) endif() diff --git a/CMakeLists.txt.user.4.10-pre1 b/CMakeLists.txt.user.4.10-pre1 new file mode 100644 index 0000000000..b7880ef2eb --- /dev/null +++ b/CMakeLists.txt.user.4.10-pre1 @@ -0,0 +1,9206 @@ + + + + + + EnvironmentId + {c62e0ab5-e250-4d63-8bd6-413f8f0df425} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {7a6826a5-1cc3-4f1a-a2f0-7c499b37d398} + 0 + 0 + 57 + + + BUILD_DOCUMENTATION:BOOL=OFF + CMAKE_BUILD_TYPE:STRING=Debug + CMAKE_CXX_COMPILER:STRING=/usr/bin/g++ + CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C} + CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} + DISABLE_AVW:BOOL=ON + DISABLE_CERN_ROOT:BOOL=ON + DISABLE_CERN_ROOT_SUPPORT:BOOL=ON + DISABLE_HDF5_SUPPORT:BOOL=ON + DISABLE_ITK:BOOL=ON + DISABLE_LLN_MATRIX:BOOL=ON + DISABLE_RDF:BOOL=ON + DISABLE_SIMSET:BOOL=OFF + DISABLE_STIR_LOCAL:BOOL=ON + QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} + SIMSET_INCLUDE_DIRS:PATH=/home/nikos/Workspace/src/2.9.2/src + SIMSET_LIBRARY:FILEPATH=/home/nikos/Workspace/src/2.9.2/lib/libsimset.so + STIR_OPENMP:BOOL=OFF + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug + + + -j7 + + Current executable + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + + + clean + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + Debug + CMakeProjectManager.CMakeBuildConfiguration + + + + BUILD_DOCUMENTATION:BOOL=OFF + CMAKE_BUILD_TYPE:STRING=Release + CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx} + CMAKE_C_COMPILER:STRING=/usr/bin/gcc + CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} + DISABLE_AVW:BOOL=ON + DISABLE_CERN_ROOT:BOOL=ON + DISABLE_HDF5_SUPPORT:BOOL=ON + DISABLE_ITK:BOOL=ON + DISABLE_LLN_MATRIX:BOOL=ON + DISABLE_RDF:BOOL=ON + DISABLE_SIMSET:BOOL=OFF + DISABLE_STIR_LOCAL:BOOL=ON + QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} + SIMSET_INCLUDE_DIRS:PATH=/home/nikos/Workspace/src/2.9.2/src + SIMSET_LIBRARY:FILEPATH=/home/nikos/Workspace/src/2.9.2/lib/libsimset.so + STIR_OPENMP:BOOL=ON + + /home/nikos/Workspace/src/build-STIR-Desktop-Release + + + -j7 + + Current executable + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + + + clean + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + Release + CMakeProjectManager.CMakeBuildConfiguration + + 2 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy Configuration + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + find_ML_singles_from_delayed + CMakeProjectManager.CMakeRunConfiguration.find_ML_singles_from_delayed +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + zeropad_planes + CMakeProjectManager.CMakeRunConfiguration.zeropad_planes +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + list_detector_and_bin_info + CMakeProjectManager.CMakeRunConfiguration.list_detector_and_bin_info +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_proj_data_in_memory + CMakeProjectManager.CMakeRunConfiguration.test_proj_data_in_memory +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_convert_array + CMakeProjectManager.CMakeRunConfiguration.test_convert_array +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_export_array + CMakeProjectManager.CMakeRunConfiguration.test_export_array +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_NestedIterator + CMakeProjectManager.CMakeRunConfiguration.test_NestedIterator +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_multiple_proj_data + CMakeProjectManager.CMakeRunConfiguration.test_multiple_proj_data +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_GeneralisedPoissonNoiseGenerator + CMakeProjectManager.CMakeRunConfiguration.test_GeneralisedPoissonNoiseGenerator +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_SeparableMetzArrayFilter + CMakeProjectManager.CMakeRunConfiguration.test_SeparableMetzArrayFilter +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_Fourier + CMakeProjectManager.CMakeRunConfiguration.test_Fourier +/home/nikos/Workspace/src/STIR/src/test/numerics/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/numerics + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_integrate_discrete_function + CMakeProjectManager.CMakeRunConfiguration.test_integrate_discrete_function +/home/nikos/Workspace/src/STIR/src/test/numerics/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/numerics + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_overlap_interpolate + CMakeProjectManager.CMakeRunConfiguration.test_overlap_interpolate +/home/nikos/Workspace/src/STIR/src/test/numerics/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/numerics + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + correct_projdata + CMakeProjectManager.CMakeRunConfiguration.correct_projdata +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_BSplines + CMakeProjectManager.CMakeRunConfiguration.test_BSplines +/home/nikos/Workspace/src/STIR/src/test/numerics/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/numerics + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_BSplinesRegularGrid + CMakeProjectManager.CMakeRunConfiguration.test_BSplinesRegularGrid +/home/nikos/Workspace/src/STIR/src/test/numerics/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/numerics + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_IR_filters + CMakeProjectManager.CMakeRunConfiguration.test_IR_filters +/home/nikos/Workspace/src/STIR/src/test/numerics/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/numerics + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_matrices + CMakeProjectManager.CMakeRunConfiguration.test_matrices +/home/nikos/Workspace/src/STIR/src/test/numerics/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/numerics + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_BSplinesRegularGrid1D + CMakeProjectManager.CMakeRunConfiguration.test_BSplinesRegularGrid1D +/home/nikos/Workspace/src/STIR/src/test/numerics/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/numerics + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_erf + CMakeProjectManager.CMakeRunConfiguration.test_erf +/home/nikos/Workspace/src/STIR/src/test/numerics/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/numerics + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_modelling + CMakeProjectManager.CMakeRunConfiguration.test_modelling +/home/nikos/Workspace/src/STIR/src/test/modelling/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/modelling + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_ParametricDiscretisedDensity + CMakeProjectManager.CMakeRunConfiguration.test_ParametricDiscretisedDensity +/home/nikos/Workspace/src/STIR/src/test/modelling/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test/modelling + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + rebin_sgl_file + CMakeProjectManager.CMakeRunConfiguration.rebin_sgl_file +/home/nikos/Workspace/src/STIR/src/listmode_utilities/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + add_ecat7_header_to_sgl + CMakeProjectManager.CMakeRunConfiguration.add_ecat7_header_to_sgl +/home/nikos/Workspace/src/STIR/src/listmode_utilities/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + manip_image + CMakeProjectManager.CMakeRunConfiguration.manip_image +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + print_sgl_values + CMakeProjectManager.CMakeRunConfiguration.print_sgl_values +/home/nikos/Workspace/src/STIR/src/listmode_utilities/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + scan_sgl_file + CMakeProjectManager.CMakeRunConfiguration.scan_sgl_file +/home/nikos/Workspace/src/STIR/src/listmode_utilities/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + conv_to_ecat6 + CMakeProjectManager.CMakeRunConfiguration.conv_to_ecat6 +/home/nikos/Workspace/src/STIR/src/utilities/ecat/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + copy_ecat7_header + CMakeProjectManager.CMakeRunConfiguration.copy_ecat7_header +/home/nikos/Workspace/src/STIR/src/utilities/ecat/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + ifheaders_for_ecat7 + CMakeProjectManager.CMakeRunConfiguration.ifheaders_for_ecat7 +/home/nikos/Workspace/src/STIR/src/utilities/ecat/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + ecat_swap_corners + CMakeProjectManager.CMakeRunConfiguration.ecat_swap_corners +/home/nikos/Workspace/src/STIR/src/utilities/ecat/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + is_ecat7_file + CMakeProjectManager.CMakeRunConfiguration.is_ecat7_file +/home/nikos/Workspace/src/STIR/src/utilities/ecat/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + conv_to_ecat7 + CMakeProjectManager.CMakeRunConfiguration.conv_to_ecat7 +/home/nikos/Workspace/src/STIR/src/utilities/ecat/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + print_ecat_singles_values + CMakeProjectManager.CMakeRunConfiguration.print_ecat_singles_values +/home/nikos/Workspace/src/STIR/src/utilities/ecat/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + convecat6_if + CMakeProjectManager.CMakeRunConfiguration.convecat6_if +/home/nikos/Workspace/src/STIR/src/utilities/ecat/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + find_fwhm_in_image + CMakeProjectManager.CMakeRunConfiguration.find_fwhm_in_image +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_time_of_flight + CMakeProjectManager.CMakeRunConfiguration.test_time_of_flight +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + read_geo_factors + CMakeProjectManager.CMakeRunConfiguration.read_geo_factors +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + extract_dynamic_images + CMakeProjectManager.CMakeRunConfiguration.extract_dynamic_images +/home/nikos/Workspace/src/STIR/src/modelling_utilities/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + conv_GEHDF5_to_interfile + CMakeProjectManager.CMakeRunConfiguration.conv_GEHDF5_to_interfile +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + construct_randoms_from_GEsingles + CMakeProjectManager.CMakeRunConfiguration.construct_randoms_from_GEsingles +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + read_nontof_conv_tof + CMakeProjectManager.CMakeRunConfiguration.read_nontof_conv_tof +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + extract_segments + CMakeProjectManager.CMakeRunConfiguration.extract_segments +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + calculate_attenuation_coefficients + CMakeProjectManager.CMakeRunConfiguration.calculate_attenuation_coefficients +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + compare_image + CMakeProjectManager.CMakeRunConfiguration.compare_image +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + compare_projdata + CMakeProjectManager.CMakeRunConfiguration.compare_projdata +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + list_image_values + CMakeProjectManager.CMakeRunConfiguration.list_image_values +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + stir_math + CMakeProjectManager.CMakeRunConfiguration.stir_math +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + find_ML_normfactors3D + CMakeProjectManager.CMakeRunConfiguration.find_ML_normfactors3D +/home/nikos/Workspace/src/STIR/src/utilities/ + norm norm_sino_f1g1d0b0.hs forward_model.hs 3 3 + 3768 + false + true + false + false + true + true + /home/nikos/Desktop/cur_Active/York/norm/ + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + shift_image_origin + CMakeProjectManager.CMakeRunConfiguration.shift_image_origin +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + list_projdata_info + CMakeProjectManager.CMakeRunConfiguration.list_projdata_info +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + postfilter + CMakeProjectManager.CMakeRunConfiguration.postfilter +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + list_image_info + CMakeProjectManager.CMakeRunConfiguration.list_image_info +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + display_projdata + CMakeProjectManager.CMakeRunConfiguration.display_projdata +/home/nikos/Workspace/src/STIR/src/utilities/ + sim_SSino_f1g1d0b0.hs + 3768 + false + true + false + false + true + true + /home/nikos/Desktop/tmp/ + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + do_linear_regression + CMakeProjectManager.CMakeRunConfiguration.do_linear_regression +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + create_projdata_template + CMakeProjectManager.CMakeRunConfiguration.create_projdata_template +/home/nikos/Workspace/src/STIR/src/utilities/ + tmpl_scanner + 3768 + false + true + false + false + true + true + /home/nikos/Desktop/cur_Active/XCAT_Test_Short/ + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + SSRB + CMakeProjectManager.CMakeRunConfiguration.SSRB +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + list_ROI_values + CMakeProjectManager.CMakeRunConfiguration.list_ROI_values +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + poisson_noise + CMakeProjectManager.CMakeRunConfiguration.poisson_noise +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + apply_normfactors3D + CMakeProjectManager.CMakeRunConfiguration.apply_normfactors3D +/home/nikos/Workspace/src/STIR/src/utilities/ + norm_sino norm ones.hs 0 3 3 1 1 0 0 + 3768 + false + true + false + false + true + true + /home/nikos/Desktop/cur_Active/York/norm/ + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + attenuation_coefficients_to_projections + CMakeProjectManager.CMakeRunConfiguration.attenuation_coefficients_to_projections +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + manip_projdata + CMakeProjectManager.CMakeRunConfiguration.manip_projdata +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + get_time_frame_info + CMakeProjectManager.CMakeRunConfiguration.get_time_frame_info +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + generate_image + CMakeProjectManager.CMakeRunConfiguration.generate_image +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + zoom_image + CMakeProjectManager.CMakeRunConfiguration.zoom_image +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + abs_image + CMakeProjectManager.CMakeRunConfiguration.abs_image +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + conv_interfile_to_gipl + CMakeProjectManager.CMakeRunConfiguration.conv_interfile_to_gipl +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + convert_to_binary_image + CMakeProjectManager.CMakeRunConfiguration.convert_to_binary_image +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + construct_randoms_from_singles + CMakeProjectManager.CMakeRunConfiguration.construct_randoms_from_singles +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + apply_normfactors + CMakeProjectManager.CMakeRunConfiguration.apply_normfactors +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + warp_image + CMakeProjectManager.CMakeRunConfiguration.warp_image +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + rebin_projdata + CMakeProjectManager.CMakeRunConfiguration.rebin_projdata +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + write_proj_matrix_by_bin + CMakeProjectManager.CMakeRunConfiguration.write_proj_matrix_by_bin +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + conv_gipl_to_interfile + CMakeProjectManager.CMakeRunConfiguration.conv_gipl_to_interfile +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + shift_image + CMakeProjectManager.CMakeRunConfiguration.shift_image +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + back_project + CMakeProjectManager.CMakeRunConfiguration.back_project +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + conv_GATE_raw_ECAT_projdata_to_interfile + CMakeProjectManager.CMakeRunConfiguration.conv_GATE_raw_ECAT_projdata_to_interfile +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + estimate_scatter + CMakeProjectManager.CMakeRunConfiguration.estimate_scatter +/home/nikos/Workspace/src/STIR/src/scatter_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/scatter_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + create_tail_mask_from_ACFs + CMakeProjectManager.CMakeRunConfiguration.create_tail_mask_from_ACFs +/home/nikos/Workspace/src/STIR/src/scatter_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/scatter_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + upsample_and_fit_single_scatter + CMakeProjectManager.CMakeRunConfiguration.upsample_and_fit_single_scatter +/home/nikos/Workspace/src/STIR/src/scatter_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/scatter_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + mult_image_parameters + CMakeProjectManager.CMakeRunConfiguration.mult_image_parameters +/home/nikos/Workspace/src/STIR/src/modelling_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/modelling_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + warp_and_accumulate_gated_images + CMakeProjectManager.CMakeRunConfiguration.warp_and_accumulate_gated_images +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + get_dynamic_images_from_parametric_images + CMakeProjectManager.CMakeRunConfiguration.get_dynamic_images_from_parametric_images +/home/nikos/Workspace/src/STIR/src/modelling_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/modelling_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + extract_single_images_from_dynamic_image + CMakeProjectManager.CMakeRunConfiguration.extract_single_images_from_dynamic_image +/home/nikos/Workspace/src/STIR/src/modelling_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/modelling_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + apply_patlak_to_images + CMakeProjectManager.CMakeRunConfiguration.apply_patlak_to_images +/home/nikos/Workspace/src/STIR/src/modelling_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/modelling_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + make_parametric_image_from_components + CMakeProjectManager.CMakeRunConfiguration.make_parametric_image_from_components +/home/nikos/Workspace/src/STIR/src/modelling_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/modelling_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + mult_model_with_dyn_images + CMakeProjectManager.CMakeRunConfiguration.mult_model_with_dyn_images +/home/nikos/Workspace/src/STIR/src/modelling_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/modelling_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + write_patlak_matrix + CMakeProjectManager.CMakeRunConfiguration.write_patlak_matrix +/home/nikos/Workspace/src/STIR/src/modelling_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/modelling_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + lm_to_projdata_bootstrap + CMakeProjectManager.CMakeRunConfiguration.lm_to_projdata_bootstrap +/home/nikos/Workspace/src/STIR/src/listmode_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/listmode_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + lm_to_projdata + CMakeProjectManager.CMakeRunConfiguration.lm_to_projdata +/home/nikos/Workspace/src/STIR/src/listmode_utilities/ + lm_to_projdata.par + 3768 + false + true + false + false + true + true + /home/nikos/Desktop/cur_Active/XCAT_Test_Short/ + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/listmode_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + lm_fansums + CMakeProjectManager.CMakeRunConfiguration.lm_fansums +/home/nikos/Workspace/src/STIR/src/listmode_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/listmode_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + list_lm_events + CMakeProjectManager.CMakeRunConfiguration.list_lm_events +/home/nikos/Workspace/src/STIR/src/listmode_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/listmode_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + find_maxima_in_image + CMakeProjectManager.CMakeRunConfiguration.find_maxima_in_image +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + list_lm_countrates + CMakeProjectManager.CMakeRunConfiguration.list_lm_countrates +/home/nikos/Workspace/src/STIR/src/listmode_utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/listmode_utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + FBP2D + CMakeProjectManager.CMakeRunConfiguration.FBP2D +/home/nikos/Workspace/src/STIR/src/analytic/FBP2D/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/analytic/FBP2D + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + FBP3DRP + CMakeProjectManager.CMakeRunConfiguration.FBP3DRP +/home/nikos/Workspace/src/STIR/src/analytic/FBP3DRP/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/analytic/FBP3DRP + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + OSMAPOSL + CMakeProjectManager.CMakeRunConfiguration.OSMAPOSL +/home/nikos/Workspace/src/STIR/src/iterative/OSMAPOSL/ + OSMAPOSL_test_lm.par + 3768 + false + true + false + false + true + true + /home/nikos/Desktop/tmp/ + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/iterative/OSMAPOSL + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + OSSPS + CMakeProjectManager.CMakeRunConfiguration.OSSPS +/home/nikos/Workspace/src/STIR/src/iterative/OSSPS/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/iterative/OSSPS + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + POSMAPOSL + CMakeProjectManager.CMakeRunConfiguration.POSMAPOSL +/home/nikos/Workspace/src/STIR/src/iterative/POSMAPOSL/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/iterative/POSMAPOSL + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + POSSPS + CMakeProjectManager.CMakeRunConfiguration.POSSPS +/home/nikos/Workspace/src/STIR/src/iterative/POSSPS/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/iterative/POSSPS + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + conv_to_SimSET_att_image + CMakeProjectManager.CMakeRunConfiguration.conv_to_SimSET_att_image +/home/nikos/Workspace/src/STIR/src/SimSET/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/SimSET + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + write_phg_image_info + CMakeProjectManager.CMakeRunConfiguration.write_phg_image_info +/home/nikos/Workspace/src/STIR/src/SimSET/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/SimSET + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + conv_SimSET_projdata_to_STIR + CMakeProjectManager.CMakeRunConfiguration.conv_SimSET_projdata_to_STIR +/home/nikos/Workspace/src/STIR/src/SimSET/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/SimSET + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + stir_write_pgm + CMakeProjectManager.CMakeRunConfiguration.stir_write_pgm +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_DataSymmetriesForBins_PET_CartesianGrid + CMakeProjectManager.CMakeRunConfiguration.test_DataSymmetriesForBins_PET_CartesianGrid +/home/nikos/Workspace/src/STIR/src/recon_test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/recon_test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_PoissonLogLikelihoodWithLinearModelForMeanAndProjData + CMakeProjectManager.CMakeRunConfiguration.test_PoissonLogLikelihoodWithLinearModelForMeanAndProjData +/home/nikos/Workspace/src/STIR/src/recon_test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/recon_test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + fwdtest + CMakeProjectManager.CMakeRunConfiguration.fwdtest +/home/nikos/Workspace/src/STIR/src/recon_test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/recon_test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + bcktest + CMakeProjectManager.CMakeRunConfiguration.bcktest +/home/nikos/Workspace/src/STIR/src/recon_test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/recon_test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + recontest + CMakeProjectManager.CMakeRunConfiguration.recontest +/home/nikos/Workspace/src/STIR/src/recon_test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/recon_test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_display + CMakeProjectManager.CMakeRunConfiguration.test_display +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_linear_regression + CMakeProjectManager.CMakeRunConfiguration.test_linear_regression +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_filename_functions + CMakeProjectManager.CMakeRunConfiguration.test_filename_functions +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_interpolate + CMakeProjectManager.CMakeRunConfiguration.test_interpolate +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_Array + CMakeProjectManager.CMakeRunConfiguration.test_Array +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + forward_project + CMakeProjectManager.CMakeRunConfiguration.forward_project +/home/nikos/Workspace/src/STIR/src/utilities/ + forward_model norm_im.hv tmpl_scanner.hs + 3768 + false + true + false + false + true + true + /home/nikos/Desktop/cur_Active/York/norm/ + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_stir_math + CMakeProjectManager.CMakeRunConfiguration.test_stir_math +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_IO_ITKMulticomponent + CMakeProjectManager.CMakeRunConfiguration.test_IO_ITKMulticomponent +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_IO_ParametricDiscretisedDensity + CMakeProjectManager.CMakeRunConfiguration.test_IO_ParametricDiscretisedDensity +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_warp_image + CMakeProjectManager.CMakeRunConfiguration.test_warp_image +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_IO_DynamicDiscretisedDensity + CMakeProjectManager.CMakeRunConfiguration.test_IO_DynamicDiscretisedDensity +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_OutputFileFormat + CMakeProjectManager.CMakeRunConfiguration.test_OutputFileFormat +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_DynamicDiscretisedDensity + CMakeProjectManager.CMakeRunConfiguration.test_DynamicDiscretisedDensity +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_IO_DiscretisedDensity + CMakeProjectManager.CMakeRunConfiguration.test_IO_DiscretisedDensity +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_VectorWithOffset + CMakeProjectManager.CMakeRunConfiguration.test_VectorWithOffset +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_IndexRange + CMakeProjectManager.CMakeRunConfiguration.test_IndexRange +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + find_ML_normfactors + CMakeProjectManager.CMakeRunConfiguration.find_ML_normfactors +/home/nikos/Workspace/src/STIR/src/utilities/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/utilities + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_ArcCorrection + CMakeProjectManager.CMakeRunConfiguration.test_ArcCorrection +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_coordinates + CMakeProjectManager.CMakeRunConfiguration.test_coordinates +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_Scanner + CMakeProjectManager.CMakeRunConfiguration.test_Scanner +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_VoxelsOnCartesianGrid + CMakeProjectManager.CMakeRunConfiguration.test_VoxelsOnCartesianGrid +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_ROIs + CMakeProjectManager.CMakeRunConfiguration.test_ROIs +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_ArrayFilter + CMakeProjectManager.CMakeRunConfiguration.test_ArrayFilter +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_ByteOrder + CMakeProjectManager.CMakeRunConfiguration.test_ByteOrder +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_zoom_image + CMakeProjectManager.CMakeRunConfiguration.test_zoom_image +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_find_fwhm_in_image + CMakeProjectManager.CMakeRunConfiguration.test_find_fwhm_in_image +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + test_proj_data_info + CMakeProjectManager.CMakeRunConfiguration.test_proj_data_info +/home/nikos/Workspace/src/STIR/src/test/ + + 3768 + false + true + false + false + true + + /home/nikos/Workspace/src/build-STIR-Desktop-Debug/src/test + + 136 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 21 + + + Version + 21 + + diff --git a/documentation/devel/README.md b/documentation/devel/README.md new file mode 100644 index 0000000000..f3226412f6 --- /dev/null +++ b/documentation/devel/README.md @@ -0,0 +1,8 @@ +# Information specific for developers + +Please check files here for information/code practices for developers. + +- Do read our [contribution guidelines](../../CONTRIBUTING.md) +- Set your editor settings appropriately: [instructions](editor-settings.md) +- Install git hooks for serious development: [instructions](git-hooks.md) +- Read the documentation, including the STIR developers guide \ No newline at end of file diff --git a/documentation/devel/editor-settings.md b/documentation/devel/editor-settings.md new file mode 100644 index 0000000000..999f00a84d --- /dev/null +++ b/documentation/devel/editor-settings.md @@ -0,0 +1,5 @@ +# Developer documentation: editor settings + +White-spaces and indentation with multiple developers are a pain. Please adhere to +our white-space policy, which we try to enforce via [clang-format](https://clang.llvm.org/docs/ClangFormat.html). +Check that site for integration with your editor/IDE. diff --git a/documentation/devel/git-hooks.md b/documentation/devel/git-hooks.md new file mode 100644 index 0000000000..28ec3a5d86 --- /dev/null +++ b/documentation/devel/git-hooks.md @@ -0,0 +1,28 @@ +# Developer documentation: how to install (software for) git hooks + +You first need to have Python and pip + +## Install [pre-commit](https://pre-commit.com) +See https://pre-commit.com/#install but the following might work. + + pip install pre-commit + +If this fails with a permission error, try adding `--user` to the command. + +If that fails with a message about `PyYAML` and `distutils`, try + + pip install --ignore-installed PyYAML + +## Install clang-format +### debian/Ubuntu + sudo apt install clang-format +### MacOS + brew install clang-format +### Others +search the internet and tell us + +## Enable pre-commit hooks +```sh +cd /whereever/STIR +pre-commit install +``` diff --git a/examples/C++/General_Reconstruction/General_Reconstruction.cxx b/examples/C++/General_Reconstruction/General_Reconstruction.cxx index 277dc792ff..d24605ce04 100644 --- a/examples/C++/General_Reconstruction/General_Reconstruction.cxx +++ b/examples/C++/General_Reconstruction/General_Reconstruction.cxx @@ -5,53 +5,40 @@ #include START_NAMESPACE_STIR -General_Reconstruction:: -General_Reconstruction() -{ - this->set_defaults(); -} +General_Reconstruction::General_Reconstruction() { this->set_defaults(); } void -General_Reconstruction::set_defaults() -{ - -} +General_Reconstruction::set_defaults() {} void -General_Reconstruction::initialise_keymap() -{ - this->parser.add_start_key("General reconstruction"); - this->parser.add_stop_key("End General reconstruction"); +General_Reconstruction::initialise_keymap() { + this->parser.add_start_key("General reconstruction"); + this->parser.add_stop_key("End General reconstruction"); - this->parser.add_parsing_key("reconstruction method", &this->reconstruction_method_sptr); + this->parser.add_parsing_key("reconstruction method", &this->reconstruction_method_sptr); } bool -General_Reconstruction::post_processing() -{ - return false; +General_Reconstruction::post_processing() { + return false; } Succeeded -General_Reconstruction::process_data() -{ - HighResWallClockTimer t; - t.reset(); - t.start(); - - //return reconstruction_object.reconstruct() == Succeeded::yes ? - // EXIT_SUCCESS : EXIT_FAILURE; - if (reconstruction_method_sptr->reconstruct() == Succeeded::yes) - { - t.stop(); - std::cout << "Total Wall clock time: " << t.value() << " seconds" << std::endl; - return Succeeded::yes; - } - else - { - t.stop(); - return Succeeded::no; - } +General_Reconstruction::process_data() { + HighResWallClockTimer t; + t.reset(); + t.start(); + + // return reconstruction_object.reconstruct() == Succeeded::yes ? + // EXIT_SUCCESS : EXIT_FAILURE; + if (reconstruction_method_sptr->reconstruct() == Succeeded::yes) { + t.stop(); + std::cout << "Total Wall clock time: " << t.value() << " seconds" << std::endl; + return Succeeded::yes; + } else { + t.stop(); + return Succeeded::no; + } } END_NAMESPACE_STIR diff --git a/examples/C++/General_Reconstruction/General_Reconstruction.h b/examples/C++/General_Reconstruction/General_Reconstruction.h index a97321c60a..f2da886158 100644 --- a/examples/C++/General_Reconstruction/General_Reconstruction.h +++ b/examples/C++/General_Reconstruction/General_Reconstruction.h @@ -16,31 +16,26 @@ #include "stir/CartesianCoordinate3D.h" #include "Reconstruction.h" - START_NAMESPACE_STIR class Succeeded; -class General_Reconstruction : public ParsingObject -{ +class General_Reconstruction : public ParsingObject { public: - //! - //! \brief General_Reconstuction - //! \details Default constructor - General_Reconstruction(); + //! + //! \brief General_Reconstuction + //! \details Default constructor + General_Reconstruction(); - virtual Succeeded process_data(); -protected: + virtual Succeeded process_data(); - void set_defaults(); - void initialise_keymap(); - bool post_processing(); +protected: + void set_defaults(); + void initialise_keymap(); + bool post_processing(); private: - - shared_ptr < Reconstruction < DiscretisedDensity < 3, float > > > - reconstruction_method_sptr; - + shared_ptr>> reconstruction_method_sptr; }; END_NAMESPACE_STIR diff --git a/examples/C++/src/demo1.cxx b/examples/C++/src/demo1.cxx index 8b9a10168d..ed91da07d9 100644 --- a/examples/C++/src/demo1.cxx +++ b/examples/C++/src/demo1.cxx @@ -6,20 +6,20 @@ \brief A simple program that backprojects some projection data. It illustrates - - basic interaction with the user, - - reading of images and projection data - - construction of a specified type of back-projector, - - how to use back-project all projection data - - output of images + - basic interaction with the user, + - reading of images and projection data + - construction of a specified type of back-projector, + - how to use back-project all projection data + - output of images See README.txt in the directory where this file is located. - \author Kris Thielemans + \author Kris Thielemans */ /* Copyright (C) 2004- 2011, Hammersmith Imanet Ltd - This software is distributed under the terms + This software is distributed under the terms of the GNU General Public Licence (GPL) See STIR/LICENSE.txt for details */ @@ -33,25 +33,20 @@ #include "stir/utilities.h" #include "stir/Succeeded.h" -int main() -{ +int +main() { using namespace stir; - + /////////////// input sinogram - const std::string input_filename = - ask_filename_with_extension("Input file",".hs"); + const std::string input_filename = ask_filename_with_extension("Input file", ".hs"); - shared_ptr - proj_data_sptr(ProjData::read_from_file(input_filename)); - shared_ptr - proj_data_info_sptr(proj_data_sptr->get_proj_data_info_sptr()->clone()); + shared_ptr proj_data_sptr(ProjData::read_from_file(input_filename)); + shared_ptr proj_data_info_sptr(proj_data_sptr->get_proj_data_info_sptr()->clone()); /////////////// template image (for sizes etc) - const std::string template_filename = - ask_filename_with_extension("Template image file",".hv"); + const std::string template_filename = ask_filename_with_extension("Template image file", ".hv"); - shared_ptr > - density_sptr(read_from_file >(template_filename)); + shared_ptr> density_sptr(read_from_file>(template_filename)); density_sptr->fill(0); diff --git a/examples/C++/src/demo2.cxx b/examples/C++/src/demo2.cxx index 028122ef07..4c9f367dd6 100644 --- a/examples/C++/src/demo2.cxx +++ b/examples/C++/src/demo2.cxx @@ -4,23 +4,23 @@ \file \ingroup examples \brief A small modification of demo1.cxx to ask the user for the - back projector she wants to use. + back projector she wants to use. It illustrates - - how to ask the user for objects for which different types - exist (e.g. back-projector, forward-projectors, image processors - etc), anything based on the RegisteredObject hierarchy. - - that STIR is able to select basic processing units at run-time - - how to use the (very) basic display facilities in STIR + - how to ask the user for objects for which different types + exist (e.g. back-projector, forward-projectors, image processors + etc), anything based on the RegisteredObject hierarchy. + - that STIR is able to select basic processing units at run-time + - how to use the (very) basic display facilities in STIR See README.txt in the directory where this file is located. - \author Kris Thielemans + \author Kris Thielemans */ /* Copyright (C) 2004- 2012, Hammersmith Imanet Ltd - This software is distributed under the terms + This software is distributed under the terms of the GNU General Public Licence (GPL) See STIR/LICENSE.txt for details */ @@ -34,31 +34,25 @@ #include "stir/Succeeded.h" #include "stir/display.h" -int main() -{ +int +main() { using namespace stir; - + /////////////// input sinogram - const std::string input_filename = - ask_filename_with_extension("Input file",".hs"); + const std::string input_filename = ask_filename_with_extension("Input file", ".hs"); - shared_ptr - proj_data_sptr(ProjData::read_from_file(input_filename)); - shared_ptr - proj_data_info_sptr(proj_data_sptr->get_proj_data_info_sptr()->clone()); + shared_ptr proj_data_sptr(ProjData::read_from_file(input_filename)); + shared_ptr proj_data_info_sptr(proj_data_sptr->get_proj_data_info_sptr()->clone()); /////////////// template image (for sizes etc) - const std::string template_filename = - ask_filename_with_extension("Template image file",".hv"); + const std::string template_filename = ask_filename_with_extension("Template image file", ".hv"); - shared_ptr > - density_sptr(read_from_file >(template_filename)); + shared_ptr> density_sptr(read_from_file>(template_filename)); density_sptr->fill(0); /////////////// back project - shared_ptr back_projector_sptr - (BackProjectorByBin::ask_type_and_parameters()); + shared_ptr back_projector_sptr(BackProjectorByBin::ask_type_and_parameters()); back_projector_sptr->set_up(proj_data_info_sptr, density_sptr); diff --git a/examples/C++/src/demo3.cxx b/examples/C++/src/demo3.cxx index 3ae745d11f..989d9b3bd4 100644 --- a/examples/C++/src/demo3.cxx +++ b/examples/C++/src/demo3.cxx @@ -6,10 +6,10 @@ \brief A modification of demo2.cxx that parses all parameters from a parameter file. It illustrates - - basic class derivation principles - - how to use ParsingObject to have automatic capabilities of parsing - parameters files (and interactive questions to the user) - - how most STIR programs parse the parameter files. + - basic class derivation principles + - how to use ParsingObject to have automatic capabilities of parsing + parameters files (and interactive questions to the user) + - how most STIR programs parse the parameter files. Note that the same functionality could be provided without deriving a new class from ParsingObject. One could have a KeyParser object @@ -17,12 +17,12 @@ See README.txt in the directory where this file is located. - \author Kris Thielemans + \author Kris Thielemans */ /* Copyright (C) 2004- 2012, Hammersmith Imanet Ltd - This software is distributed under the terms + This software is distributed under the terms of the GNU General Public Licence (GPL) See STIR/LICENSE.txt for details */ @@ -38,29 +38,27 @@ namespace stir { -class MyStuff: public ParsingObject -{ +class MyStuff : public ParsingObject { public: void set_defaults(); void initialise_keymap(); void run(); + private: std::string input_filename; std::string template_filename; shared_ptr back_projector_sptr; - shared_ptr > > output_file_format_sptr; + shared_ptr>> output_file_format_sptr; }; void -MyStuff::set_defaults() -{ +MyStuff::set_defaults() { back_projector_sptr.reset(new BackProjectorByBinUsingInterpolation); - output_file_format_sptr = OutputFileFormat >::default_sptr(); + output_file_format_sptr = OutputFileFormat>::default_sptr(); } -void -MyStuff::initialise_keymap() -{ +void +MyStuff::initialise_keymap() { parser.add_start_key("MyStuff parameters"); parser.add_key("input file", &input_filename); parser.add_key("template image file", &template_filename); @@ -70,16 +68,12 @@ MyStuff::initialise_keymap() } void -MyStuff::run() -{ +MyStuff::run() { - shared_ptr - proj_data_sptr(ProjData::read_from_file(input_filename)); - shared_ptr - proj_data_info_sptr(proj_data_sptr->get_proj_data_info_sptr()->clone()); + shared_ptr proj_data_sptr(ProjData::read_from_file(input_filename)); + shared_ptr proj_data_info_sptr(proj_data_sptr->get_proj_data_info_sptr()->clone()); - shared_ptr > - density_sptr(read_from_file >(template_filename)); + shared_ptr> density_sptr(read_from_file>(template_filename)); density_sptr->fill(0); @@ -94,20 +88,19 @@ MyStuff::run() display(*density_sptr, density_sptr->find_max(), "Output"); } -}// end of namespace stir +} // end of namespace stir -int main(int argc, char **argv) -{ +int +main(int argc, char** argv) { using namespace stir; - if (argc!=2) - { - std::cerr << "Normal usage: " << argv[0] << " parameter-file\n"; - std::cerr << "I will now ask you the questions interactively\n"; - } + if (argc != 2) { + std::cerr << "Normal usage: " << argv[0] << " parameter-file\n"; + std::cerr << "I will now ask you the questions interactively\n"; + } MyStuff my_stuff; my_stuff.set_defaults(); - if (argc!=2) + if (argc != 2) my_stuff.ask_parameters(); else my_stuff.parse(argv[1]); diff --git a/examples/PET_simulation/generate_input_data.sh b/examples/PET_simulation/generate_input_data.sh index aaf4790307..ab83aa01c8 100755 --- a/examples/PET_simulation/generate_input_data.sh +++ b/examples/PET_simulation/generate_input_data.sh @@ -49,6 +49,7 @@ template_sino=my_DSTE_3D_rd1_template.hs cat > my_input.txt < target_type; + typedef DiscretisedDensity<3, float> target_type; protected: - shared_ptr > objective_function_sptr; + shared_ptr> objective_function_sptr; private: std::string input_filename; std::string image_filename; int num_iterations; float step_size; - shared_ptr > > output_file_format_sptr; + shared_ptr>> output_file_format_sptr; void initialise_keymap(); bool post_processing(); }; -MyStuff::MyStuff() -{ - set_defaults(); -} +MyStuff::MyStuff() { set_defaults(); } void -MyStuff::set_defaults() -{ +MyStuff::set_defaults() { objective_function_sptr.reset(new PoissonLogLikelihoodWithLinearModelForMeanAndProjData); - output_file_format_sptr = OutputFileFormat >::default_sptr(); + output_file_format_sptr = OutputFileFormat>::default_sptr(); num_iterations = 10; step_size = 0.001; } -void -MyStuff::initialise_keymap() -{ +void +MyStuff::initialise_keymap() { parser.add_start_key("MyStuff parameters"); parser.add_key("input file", &input_filename); parser.add_key("image filename", &image_filename); @@ -85,27 +79,22 @@ MyStuff::initialise_keymap() parser.add_stop_key("End"); } -bool MyStuff:: -post_processing() -{ - if (is_null_ptr(this->objective_function_sptr)) - { - error("objective_function_sptr is null"); - return true; +bool +MyStuff::post_processing() { + if (is_null_ptr(this->objective_function_sptr)) { + error("objective_function_sptr is null"); + return true; } return false; } void -MyStuff::run() -{ +MyStuff::run() { /////// load initial density from file - shared_ptr > - density_sptr(read_from_file >(image_filename)); + shared_ptr> density_sptr(read_from_file>(image_filename)); //////// gradient it copied Density filled with 0's - shared_ptr > - gradient_sptr(density_sptr->get_empty_copy()); + shared_ptr> gradient_sptr(density_sptr->get_empty_copy()); /////// setup objective function object objective_function_sptr->set_up(density_sptr); @@ -132,25 +121,24 @@ MyStuff::run() /////// Return the objective function values and improvement std::cout << "The initial Objective Function Value = " << my_objective_function_value1 << "\n"; - std::cout << "The Objective Function Value of after " << num_iterations << " iteration(s) =" - << my_objective_function_value2 << "\n"; + std::cout << "The Objective Function Value of after " << num_iterations << " iteration(s) =" << my_objective_function_value2 + << "\n"; std::cout << "A change of " << my_objective_function_value2 - my_objective_function_value1 << "\n"; } -}// end of namespace stir +} // end of namespace stir -int main(int argc, char **argv) -{ +int +main(int argc, char** argv) { using namespace stir; - if (argc!=2) - { - std::cerr << "Normal usage: " << argv[0] << " parameter-file\n"; - std::cerr << "I will now ask you the questions interactively\n"; - } + if (argc != 2) { + std::cerr << "Normal usage: " << argv[0] << " parameter-file\n"; + std::cerr << "I will now ask you the questions interactively\n"; + } MyStuff my_stuff; my_stuff.set_defaults(); - if (argc!=2) + if (argc != 2) my_stuff.ask_parameters(); else my_stuff.parse(argv[1]); diff --git a/recon_test_pack/OSMAPOSL_test_lmf.par b/recon_test_pack/OSMAPOSL_test_lmf.par new file mode 100755 index 0000000000..775ae5d047 --- /dev/null +++ b/recon_test_pack/OSMAPOSL_test_lmf.par @@ -0,0 +1,38 @@ +OSMAPOSLParameters := +objective function type:= PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin Parameters:= + list mode filename := PET_ACQ_small.l.hdr.STIR + max ring difference num to process := 2 + projector pair type := Matrix + Projector Pair Using Matrix Parameters := + Matrix type := Ray Tracing + Ray tracing matrix parameters := + ; use multiple (almost) parallel LORs for every bin in the sinogram + ; to avoid discretisation artefacts + number of rays in tangential direction to trace for each bin:= 3 + ; you could disable some symmetries if you have enough memory + ; this would for instance allow you to increase the number of subsets + ; do_symmetry_90degrees_min_phi:=0 + End Ray tracing matrix parameters := + End Projector Pair Using Matrix Parameters := + + Bin Normalisation type := From ProjData + Bin Normalisation From ProjData := + normalisation projdata filename:= my_acfs.hs + End Bin Normalisation From ProjData:= + + ;num_events_to_store := 100 + recompute sensitivity :=1 + use subset sensitivities:= 0 + sensitivity filename:= my_sens_t_lm_pr_seg2.hv + zoom := 1 + +additive sinogram := my_MLrandoms_f1.hs + +end PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin Parameters:= +enforce initial positivity condition:= 1 +number of subsets:= 1 +number of subiterations:= 1 +save estimates at subiteration intervals:= 1 +output filename prefix := my_output_t_lm_pr_seg2 +END := diff --git a/recon_test_pack/Siemens_mMR_seg2.hs b/recon_test_pack/Siemens_mMR_seg2.hs index f419f744ec..6337e33864 100644 --- a/recon_test_pack/Siemens_mMR_seg2.hs +++ b/recon_test_pack/Siemens_mMR_seg2.hs @@ -44,4 +44,6 @@ Number of crystals per singles unit in transaxial direction := 9 end scanner parameters:= effective central bin size (cm) := 0.208815 number of time frames := 1 +start vertical bed position (mm) := 0 +start horizontal bed position (mm) := 0 !END OF INTERFILE := diff --git a/recon_test_pack/lm_generate_atten_cylinder.par b/recon_test_pack/lm_generate_atten_cylinder.par index 0aa3511bfb..c7227c749c 100644 --- a/recon_test_pack/lm_generate_atten_cylinder.par +++ b/recon_test_pack/lm_generate_atten_cylinder.par @@ -1,8 +1,8 @@ generate_image Parameters := output filename:=my_atten_image -X output image size (in pixels):=111 -Y output image size (in pixels):=111 -Z output image size (in pixels):=65 +X output image size (in pixels):=100 +Y output image size (in pixels):=100 +Z output image size (in pixels):=127 X voxel size (in mm):= 3 Y voxel size (in mm):= 3 Z voxel size (in mm) := 0.40625 @@ -16,7 +16,7 @@ Ellipsoidal Cylinder Parameters:= radius-x (in mm):=100 radius-y (in mm):=100 length-z (in mm):=110 - origin (in mm):={70,10,20} + origin (in mm):={70,0,0} END:= value := 0.096 diff --git a/recon_test_pack/lm_to_projdata.par b/recon_test_pack/lm_to_projdata.par old mode 100755 new mode 100644 diff --git a/recon_test_pack/root_header.hroot b/recon_test_pack/root_header.hroot index f509a4cf52..0e929b2f7b 100644 --- a/recon_test_pack/root_header.hroot +++ b/recon_test_pack/root_header.hroot @@ -11,7 +11,11 @@ Default bin size (cm) := 0.208626 Maximum number of non-arc-corrected bins := 344 Default number of arc-corrected bins := 344 View offset (degrees) := 0 +Number of TOF time bins := 410 +Size of timing bin (ps) := 10.00 +Timing resolution (ps) := 400.0 +%TOF mashing factor:= 82 GATE scanner type := GATE_Cylindrical_PET GATE_Cylindrical_PET Parameters := diff --git a/recon_test_pack/run_test_listmode_recon.sh b/recon_test_pack/run_test_listmode_recon.sh index 7e11805093..0948e5d1f5 100755 --- a/recon_test_pack/run_test_listmode_recon.sh +++ b/recon_test_pack/run_test_listmode_recon.sh @@ -78,7 +78,7 @@ ThereWereErrors=0 echo "=== Simulate normalisation data" # For normalisation data we are going to use a cylinder in the center, # with water attenuation values -echo "=== Gnerete fake emission image" +echo "=== Generate fake emission image" generate_image lm_generate_atten_cylinder.par echo "=== Calculate ACFs" calculate_attenuation_coefficients --ACF my_acfs.hs my_atten_image.hv Siemens_mMR_seg2.hs > my_create_acfs.log 2>&1 diff --git a/recon_test_pack/run_test_simulate_and_recon.sh b/recon_test_pack/run_test_simulate_and_recon.sh index cb2329481b..9405b3937e 100755 --- a/recon_test_pack/run_test_simulate_and_recon.sh +++ b/recon_test_pack/run_test_simulate_and_recon.sh @@ -78,6 +78,7 @@ LC_ALL=C export LC_ALL ./simulate_PET_data_for_tests.sh + if [ $? -ne 0 ]; then echo "Error running simulation" exit 1 diff --git a/recon_test_pack/run_test_simulate_and_recon_with_motion.sh b/recon_test_pack/run_test_simulate_and_recon_with_motion.sh index 64c006b613..9f28d1d198 100755 --- a/recon_test_pack/run_test_simulate_and_recon_with_motion.sh +++ b/recon_test_pack/run_test_simulate_and_recon_with_motion.sh @@ -124,7 +124,7 @@ fi echo "=== create template sinogram (DSTE in 3D with max ring diff 2 to save time)" template_sino=my_DSTE_3D_rd2_template.hs cat > my_input.txt <'3.0. If you have +echo a later version, you might have to update your test pack. +echo Please check the web site. +echo + +if [ $# -eq 1 ]; then + echo "Prepending $1 to your PATH for the duration of this script." + PATH=$1:$PATH +fi + +# first need to set this to the C locale, as this is what the STIR utilities use +# otherwise, awk might interpret floating point numbers incorrectly +LC_ALL=C +export LC_ALL + +echo "=== create template sinogram. We'll use a test_scanner which is small and +has TOF info" +template_sino=my_test_scanner_template.hs +cat > my_input.txt < my_create_${template_sino}.log 2>&1 +if [ $? -ne 0 ]; then + echo "ERROR running create_projdata_template. Check my_create_${template_sino}.log"; exit 1; +fi + +export INPUT_ROOT_FILE=test_PET_GATE.root +export EXCLUDE_RANDOM=1 +export EXCLUDE_SCATTERED=1 + +INPUT=root_header.hroot TEMPLATE=$template_sino OUT_PROJDATA_FILE=my_tof_sinogram lm_to_projdata --test_timing_positions lm_to_projdata.par > my_write_TOF_values_${template_sino}.log 2>&1 + +if [ $? -ne 0 ]; then + echo "ERROR running lm_to_projdata --test_timing_positions. Check my_write_TOF_values_${template_sino}.log"; exit 1; +fi + +echo "Comparing values in TOF sinogram ..." +list_projdata_info --all my_tof_sinogram_f179g1d0b0.hs > my_sino_values_$template_sino.log 2>&1 +if [ $? -ne 0 ]; then + echo "ERROR running list_projdata_info. Check my_sino_values_$template_sino.log"; + exit 1; +fi + + +TOF_bins=$(grep 'Total number of timing positions' my_sino_values_$template_sino.log | awk -F ':' '{ print $2 }') +echo "Total number of TOF bins:" $TOF_bins + +Timming_Locations=$(grep 'Timing location' my_sino_values_$template_sino.log | awk -F ':' '{ print $2 }') +echo "Timming_Locations:" $Timming_Locations + +Data_mins=$(grep 'Data min' my_sino_values_$template_sino.log | awk -F ':' '{ print $2 }') +echo "Data mins:" $Data_mins + +Data_maxs=$(grep 'Data max' my_sino_values_$template_sino.log | awk -F ':' '{ print $2 }') +echo "Data maxs:" $Data_maxs + +for i in $(seq 5) +do + if [ $(( $((i-1 - TOF_bins/2)) - Data_mins[i])) -ne 0 ]; then + echo "Wrong values in TOF sinogram. Error. $(( $(($((i-1)) -TOF_bins/2)) - Data_mins[i]))" + exit 1 + fi +done + + +echo +echo '--------------- End of Time-Of-Flight tests -------------' +echo +echo "Everything seems to be fine !" +echo 'You could remove all generated files using "rm -f my_* *.log"' +exit 0 + diff --git a/recon_test_pack/run_test_zoom_image.sh b/recon_test_pack/run_test_zoom_image.sh index 9613e5296e..0233aaeffb 100755 --- a/recon_test_pack/run_test_zoom_image.sh +++ b/recon_test_pack/run_test_zoom_image.sh @@ -156,6 +156,7 @@ template_sino=my_DSTE_3D_rd2_template.hs cat > my_input.txt < my_input.txt < scanner_ptr ( - Scanner::get_scanner_from_name(default_scanner_name)); + shared_ptr scanner_ptr(Scanner::get_scanner_from_name(default_scanner_name)); - if (find_ECAT_system_type(*scanner_ptr)==0) - { - warning("ECAT6OutputFileFormat: default_scanner_name %s is not supported\n", - default_scanner_name.c_str()); - return true; - } + if (find_ECAT_system_type(*scanner_ptr) == 0) { + warning("ECAT6OutputFileFormat: default_scanner_name %s is not supported\n", default_scanner_name.c_str()); + return true; + } return false; } -NumericType -ECAT6OutputFileFormat:: -set_type_of_numbers(const NumericType& new_type, const bool warn) -{ - const NumericType supported_type_of_numbers = - NumericType("signed integer", 2); - if (new_type != supported_type_of_numbers) - { +NumericType +ECAT6OutputFileFormat::set_type_of_numbers(const NumericType& new_type, const bool warn) { + const NumericType supported_type_of_numbers = NumericType("signed integer", 2); + if (new_type != supported_type_of_numbers) { if (warn) warning("ECAT6OutputFileFormat: output type of numbers is currently fixed to short (2 byte signed integers)\n"); type_of_numbers = supported_type_of_numbers; - } - else + } else type_of_numbers = new_type; return type_of_numbers; - } -ByteOrder -ECAT6OutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) -{ - if (new_byte_order != ByteOrder::little_endian) - { +ByteOrder +ECAT6OutputFileFormat::set_byte_order(const ByteOrder& new_byte_order, const bool warn) { + if (new_byte_order != ByteOrder::little_endian) { if (warn) warning("ECAT6OutputFileFormat: byte_order is currently fixed to little-endian\n"); file_byte_order = ByteOrder::little_endian; - } - else + } else file_byte_order = new_byte_order; return file_byte_order; } -Succeeded -ECAT6OutputFileFormat:: -actual_write_to_file(std::string& filename, - const DiscretisedDensity<3,float>& density) const -{ - shared_ptr scanner_ptr( - Scanner::get_scanner_from_name(default_scanner_name)); - +Succeeded +ECAT6OutputFileFormat::actual_write_to_file(std::string& filename, const DiscretisedDensity<3, float>& density) const { + shared_ptr scanner_ptr(Scanner::get_scanner_from_name(default_scanner_name)); + add_extension(filename, ".img"); ECAT6_Main_header mhead; make_ECAT6_Main_header(mhead, *scanner_ptr, "", density); mhead.num_frames = 1; - - FILE *fptr= cti_create (filename.c_str(), &mhead); - if (fptr == NULL) - { - warning("ECAT6OutputFileFormat::write_to_file: error opening output file %s\n", - filename.c_str()); + + FILE* fptr = cti_create(filename.c_str(), &mhead); + if (fptr == NULL) { + warning("ECAT6OutputFileFormat::write_to_file: error opening output file %s\n", filename.c_str()); return Succeeded::no; } - Succeeded success = - DiscretisedDensity_to_ECAT6(fptr, - density, - mhead, - 1 /*frame_num*/); + Succeeded success = DiscretisedDensity_to_ECAT6(fptr, density, mhead, 1 /*frame_num*/); fclose(fptr); - + return success; } END_NAMESPACE_ECAT6 END_NAMESPACE_ECAT END_NAMESPACE_STIR - - diff --git a/src/IO/ECAT7DynamicDiscretisedDensityInputFileFormat.cxx b/src/IO/ECAT7DynamicDiscretisedDensityInputFileFormat.cxx index 8f8449b5a0..b2f8ff1cf4 100644 --- a/src/IO/ECAT7DynamicDiscretisedDensityInputFileFormat.cxx +++ b/src/IO/ECAT7DynamicDiscretisedDensityInputFileFormat.cxx @@ -34,9 +34,8 @@ #include #include - #ifndef HAVE_LLN_MATRIX -#error HAVE_LLN_MATRIX not defined: you need the lln ecat library. +# error HAVE_LLN_MATRIX not defined: you need the lln ecat library. #endif #include "stir/IO/stir_ecat7.h" @@ -49,11 +48,8 @@ START_NAMESPACE_ECAT7 \preliminary */ -bool -ECAT7DynamicDiscretisedDensityInputFileFormat:: -actual_can_read(const FileSignature& signature, - std::istream& input) const -{ +bool +ECAT7DynamicDiscretisedDensityInputFileFormat::actual_can_read(const FileSignature& signature, std::istream& input) const { if (strncmp(signature.get_signature(), "MATRIX", 6) != 0) return false; @@ -63,70 +59,53 @@ actual_can_read(const FileSignature& signature, } unique_ptr -ECAT7DynamicDiscretisedDensityInputFileFormat:: -read_from_file(std::istream& input) const -{ - //TODO - error("read_from_file for ECAT7 with istream not implemented %s:%s. Sorry", - __FILE__, __LINE__); - return - unique_ptr(); +ECAT7DynamicDiscretisedDensityInputFileFormat::read_from_file(std::istream& input) const { + // TODO + error("read_from_file for ECAT7 with istream not implemented %s:%s. Sorry", __FILE__, __LINE__); + return unique_ptr(); } unique_ptr -ECAT7DynamicDiscretisedDensityInputFileFormat:: -read_from_file(const std::string& filename) const -{ - if (is_ECAT7_image_file(filename)) - { - Main_header mhead; - if (read_ECAT7_main_header(mhead, filename) == Succeeded::no) - { - error("ECAT7DynamicDiscretisedDensityInputFileFormat::read_from_file cannot read %s as ECAT7 (failed to read main header)", filename.c_str()); - return unique_ptr(); - } - - TimeFrameDefinitions time_frame_definitions(filename); - shared_ptr scanner_sptr(find_scanner_from_ECAT_system_type(mhead.system_type)); - - unique_ptr - dynamic_image_ptr - (new DynamicDiscretisedDensity(time_frame_definitions, - static_cast(mhead.scan_start_time), - scanner_sptr) - ); - - dynamic_image_ptr->set_calibration_factor(mhead.calibration_factor); - - dynamic_image_ptr->set_isotope_halflife(mhead.isotope_halflife); - - // TODO get this from the subheader fields or so - // dynamic_image_ptr->_is_decay_corrected = - // shead.processing_code & DecayPrc - dynamic_image_ptr->set_if_decay_corrected(false); - - for (unsigned int frame_num=1; frame_num <= dynamic_image_ptr->get_num_time_frames(); ++ frame_num) - { - shared_ptr dens_sptr - (ECAT7_to_VoxelsOnCartesianGrid(filename, - frame_num, - /* gate_num, data_num, bed_num */ 1,0,0) - ); - if (is_null_ptr(dens_sptr)) - error("read_from_file for DynamicDiscretisedDensity: No frame %d available", frame_num); - dynamic_image_ptr->set_density(*dens_sptr, frame_num ); - } - return dynamic_image_ptr; - } - else - { - error("read_from_file for DynamicDiscretisedDensity: ECAT7 file %s is not an image file", filename.c_str()); - // return something to satisfy compilers +ECAT7DynamicDiscretisedDensityInputFileFormat::read_from_file(const std::string& filename) const { + if (is_ECAT7_image_file(filename)) { + Main_header mhead; + if (read_ECAT7_main_header(mhead, filename) == Succeeded::no) { + error("ECAT7DynamicDiscretisedDensityInputFileFormat::read_from_file cannot read %s as ECAT7 (failed to read main header)", + filename.c_str()); return unique_ptr(); } + + TimeFrameDefinitions time_frame_definitions(filename); + shared_ptr scanner_sptr(find_scanner_from_ECAT_system_type(mhead.system_type)); + + unique_ptr dynamic_image_ptr( + new DynamicDiscretisedDensity(time_frame_definitions, static_cast(mhead.scan_start_time), scanner_sptr)); + + dynamic_image_ptr->set_calibration_factor(mhead.calibration_factor); + + dynamic_image_ptr->set_isotope_halflife(mhead.isotope_halflife); + + // TODO get this from the subheader fields or so + // dynamic_image_ptr->_is_decay_corrected = + // shead.processing_code & DecayPrc + dynamic_image_ptr->set_if_decay_corrected(false); + + for (unsigned int frame_num = 1; frame_num <= dynamic_image_ptr->get_num_time_frames(); ++frame_num) { + shared_ptr dens_sptr( + ECAT7_to_VoxelsOnCartesianGrid(filename, frame_num, + /* gate_num, data_num, bed_num */ 1, 0, 0)); + if (is_null_ptr(dens_sptr)) + error("read_from_file for DynamicDiscretisedDensity: No frame %d available", frame_num); + dynamic_image_ptr->set_density(*dens_sptr, frame_num); + } + return dynamic_image_ptr; + } else { + error("read_from_file for DynamicDiscretisedDensity: ECAT7 file %s is not an image file", filename.c_str()); + // return something to satisfy compilers + return unique_ptr(); + } } END_NAMESPACE_ECAT END_NAMESPACE_ECAT7 END_NAMESPACE_STIR - diff --git a/src/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx b/src/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx index 674c8f5289..1d29a6c02b 100644 --- a/src/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx +++ b/src/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx @@ -36,32 +36,25 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 -const char * const -ECAT7DynamicDiscretisedDensityOutputFileFormat::registered_name = "ECAT7"; +const char* const ECAT7DynamicDiscretisedDensityOutputFileFormat::registered_name = "ECAT7"; -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -ECAT7DynamicDiscretisedDensityOutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) -{ +ECAT7DynamicDiscretisedDensityOutputFileFormat::ECAT7DynamicDiscretisedDensityOutputFileFormat(const NumericType& type, + const ByteOrder& byte_order) { this->set_defaults(); this->set_type_of_numbers(type); this->set_byte_order(byte_order); } -void -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -initialise_keymap() -{ +void +ECAT7DynamicDiscretisedDensityOutputFileFormat::initialise_keymap() { this->parser.add_start_key("ECAT7 Output File Format Parameters"); this->parser.add_stop_key("End ECAT7 Output File Format Parameters"); this->parser.add_key("default scanner name", &default_scanner_name); base_type::initialise_keymap(); } -void -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_defaults() -{ +void +ECAT7DynamicDiscretisedDensityOutputFileFormat::set_defaults() { this->default_scanner_name = "ECAT 962"; base_type::set_defaults(); this->file_byte_order = ByteOrder::big_endian; @@ -71,69 +64,53 @@ set_defaults() } bool -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -post_processing() -{ +ECAT7DynamicDiscretisedDensityOutputFileFormat::post_processing() { if (base_type::post_processing()) return true; - shared_ptr scanner_ptr( - Scanner::get_scanner_from_name(this->default_scanner_name)); + shared_ptr scanner_ptr(Scanner::get_scanner_from_name(this->default_scanner_name)); - if (find_ECAT_system_type(*scanner_ptr)==0) - { - warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: default_scanner_name %s is not supported\n", - this->default_scanner_name.c_str()); - return true; - } + if (find_ECAT_system_type(*scanner_ptr) == 0) { + warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: default_scanner_name %s is not supported\n", + this->default_scanner_name.c_str()); + return true; + } return false; } -NumericType -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_type_of_numbers(const NumericType& new_type, const bool warn) -{ - const NumericType supported_type_of_numbers = - NumericType("signed integer", 2); - if (new_type != supported_type_of_numbers) - { +NumericType +ECAT7DynamicDiscretisedDensityOutputFileFormat::set_type_of_numbers(const NumericType& new_type, const bool warn) { + const NumericType supported_type_of_numbers = NumericType("signed integer", 2); + if (new_type != supported_type_of_numbers) { if (warn) - warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: output type of numbers is currently fixed to short (2 byte signed integers)\n"); + warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: output type of numbers is currently fixed to short (2 byte signed " + "integers)\n"); this->type_of_numbers = supported_type_of_numbers; - } - else + } else this->type_of_numbers = new_type; return this->type_of_numbers; } -ByteOrder -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) -{ - if (new_byte_order != ByteOrder::big_endian) - { +ByteOrder +ECAT7DynamicDiscretisedDensityOutputFileFormat::set_byte_order(const ByteOrder& new_byte_order, const bool warn) { + if (new_byte_order != ByteOrder::big_endian) { if (warn) warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: byte_order is currently fixed to big-endian\n"); this->file_byte_order = ByteOrder::big_endian; - } - else + } else this->file_byte_order = new_byte_order; return this->file_byte_order; } -Succeeded -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -actual_write_to_file(std::string& filename, - const DynamicDiscretisedDensity& dynamic_density) const -{ +Succeeded +ECAT7DynamicDiscretisedDensityOutputFileFormat::actual_write_to_file(std::string& filename, + const DynamicDiscretisedDensity& dynamic_density) const { add_extension(filename, ".img"); - return - dynamic_density.write_to_ecat7(filename); + return dynamic_density.write_to_ecat7(filename); } - -//template class ECAT7DynamicDiscretisedDensityOutputFileFormat; +// template class ECAT7DynamicDiscretisedDensityOutputFileFormat; END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT diff --git a/src/IO/ECAT7OutputFileFormat.cxx b/src/IO/ECAT7OutputFileFormat.cxx index f90a8a01df..65a1f0195e 100644 --- a/src/IO/ECAT7OutputFileFormat.cxx +++ b/src/IO/ECAT7OutputFileFormat.cxx @@ -35,120 +35,90 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 -const char * const -ECAT7OutputFileFormat::registered_name = "ECAT7"; +const char* const ECAT7OutputFileFormat::registered_name = "ECAT7"; -ECAT7OutputFileFormat:: -ECAT7OutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) -{ +ECAT7OutputFileFormat::ECAT7OutputFileFormat(const NumericType& type, const ByteOrder& byte_order) { base_type::set_defaults(); set_type_of_numbers(type); set_byte_order(byte_order); } -void -ECAT7OutputFileFormat:: -initialise_keymap() -{ +void +ECAT7OutputFileFormat::initialise_keymap() { parser.add_start_key("ECAT7 Output File Format Parameters"); parser.add_stop_key("End ECAT7 Output File Format Parameters"); parser.add_key("default scanner name", &default_scanner_name); base_type::initialise_keymap(); } -void -ECAT7OutputFileFormat:: -set_defaults() -{ +void +ECAT7OutputFileFormat::set_defaults() { default_scanner_name = "ECAT 962"; base_type::set_defaults(); file_byte_order = ByteOrder::big_endian; type_of_numbers = NumericType::SHORT; set_key_values(); - } bool -ECAT7OutputFileFormat:: -post_processing() -{ +ECAT7OutputFileFormat::post_processing() { if (base_type::post_processing()) return true; shared_ptr scanner_ptr(Scanner::get_scanner_from_name(default_scanner_name)); - if (find_ECAT_system_type(*scanner_ptr)==0) - { - warning("ECAT7OutputFileFormat: default_scanner_name %s is not supported\n", - default_scanner_name.c_str()); - return true; - } + if (find_ECAT_system_type(*scanner_ptr) == 0) { + warning("ECAT7OutputFileFormat: default_scanner_name %s is not supported\n", default_scanner_name.c_str()); + return true; + } return false; } -NumericType -ECAT7OutputFileFormat:: -set_type_of_numbers(const NumericType& new_type, const bool warn) -{ - const NumericType supported_type_of_numbers = - NumericType("signed integer", 2); - if (new_type != supported_type_of_numbers) - { +NumericType +ECAT7OutputFileFormat::set_type_of_numbers(const NumericType& new_type, const bool warn) { + const NumericType supported_type_of_numbers = NumericType("signed integer", 2); + if (new_type != supported_type_of_numbers) { if (warn) warning("ECAT7OutputFileFormat: output type of numbers is currently fixed to short (2 byte signed integers)\n"); type_of_numbers = supported_type_of_numbers; - } - else + } else type_of_numbers = new_type; return type_of_numbers; - } -ByteOrder -ECAT7OutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) -{ - if (new_byte_order != ByteOrder::big_endian) - { +ByteOrder +ECAT7OutputFileFormat::set_byte_order(const ByteOrder& new_byte_order, const bool warn) { + if (new_byte_order != ByteOrder::big_endian) { if (warn) warning("ECAT7OutputFileFormat: byte_order is currently fixed to big-endian\n"); file_byte_order = ByteOrder::big_endian; - } - else + } else file_byte_order = new_byte_order; return file_byte_order; } -Succeeded -ECAT7OutputFileFormat:: -actual_write_to_file(std::string& filename, - const DiscretisedDensity<3,float>& density) const -{ +Succeeded +ECAT7OutputFileFormat::actual_write_to_file(std::string& filename, const DiscretisedDensity<3, float>& density) const { shared_ptr scanner_ptr(Scanner::get_scanner_from_name(default_scanner_name)); - + add_extension(filename, ".img"); Main_header mhead; make_ECAT7_main_header(mhead, *scanner_ptr, "", density); mhead.num_frames = 1; - mhead.acquisition_type = - mhead.num_frames>1 ? DynamicEmission : StaticEmission; - - MatrixFile* mptr= matrix_create (filename.c_str(), MAT_CREATE, &mhead); - if (mptr == 0) - { - warning("ECAT7OutputFileFormat::write_to_file: error opening output file %s\n", - filename.c_str()); + mhead.acquisition_type = mhead.num_frames > 1 ? DynamicEmission : StaticEmission; + + MatrixFile* mptr = matrix_create(filename.c_str(), MAT_CREATE, &mhead); + if (mptr == 0) { + warning("ECAT7OutputFileFormat::write_to_file: error opening output file %s\n", filename.c_str()); return Succeeded::no; } - - Succeeded success = - DiscretisedDensity_to_ECAT7(mptr, density, 1 /*frame_num*/); + + Succeeded success = DiscretisedDensity_to_ECAT7(mptr, density, 1 /*frame_num*/); matrix_close(mptr); - + return success; } diff --git a/src/IO/ECAT7ParametricDensityOutputFileFormat.cxx b/src/IO/ECAT7ParametricDensityOutputFileFormat.cxx index 0778b22ddb..788048a419 100644 --- a/src/IO/ECAT7ParametricDensityOutputFileFormat.cxx +++ b/src/IO/ECAT7ParametricDensityOutputFileFormat.cxx @@ -36,24 +36,19 @@ START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 template -const char * const -ECAT7ParametricDensityOutputFileFormat::registered_name = "ECAT7"; +const char* const ECAT7ParametricDensityOutputFileFormat::registered_name = "ECAT7"; template -ECAT7ParametricDensityOutputFileFormat:: -ECAT7ParametricDensityOutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) -{ +ECAT7ParametricDensityOutputFileFormat::ECAT7ParametricDensityOutputFileFormat(const NumericType& type, + const ByteOrder& byte_order) { this->set_defaults(); this->set_type_of_numbers(type); this->set_byte_order(byte_order); } template -void -ECAT7ParametricDensityOutputFileFormat:: -initialise_keymap() -{ +void +ECAT7ParametricDensityOutputFileFormat::initialise_keymap() { this->parser.add_start_key("ECAT7 Output File Format Parameters"); this->parser.add_stop_key("End ECAT7 Output File Format Parameters"); this->parser.add_key("default scanner name", &default_scanner_name); @@ -61,89 +56,68 @@ initialise_keymap() } template -void -ECAT7ParametricDensityOutputFileFormat:: -set_defaults() -{ +void +ECAT7ParametricDensityOutputFileFormat::set_defaults() { this->default_scanner_name = "ECAT 962"; base_type::set_defaults(); this->file_byte_order = ByteOrder::big_endian; this->type_of_numbers = NumericType::SHORT; this->set_key_values(); - } template bool -ECAT7ParametricDensityOutputFileFormat:: -post_processing() -{ +ECAT7ParametricDensityOutputFileFormat::post_processing() { if (base_type::post_processing()) return true; - shared_ptr scanner_ptr( - Scanner::get_scanner_from_name(this->default_scanner_name)); + shared_ptr scanner_ptr(Scanner::get_scanner_from_name(this->default_scanner_name)); - if (find_ECAT_system_type(*scanner_ptr)==0) - { - warning("ECAT7ParametricDensityOutputFileFormat: default_scanner_name %s is not supported\n", - this->default_scanner_name.c_str()); - return true; - } + if (find_ECAT_system_type(*scanner_ptr) == 0) { + warning("ECAT7ParametricDensityOutputFileFormat: default_scanner_name %s is not supported\n", + this->default_scanner_name.c_str()); + return true; + } return false; } template -NumericType -ECAT7ParametricDensityOutputFileFormat:: -set_type_of_numbers(const NumericType& new_type, const bool warn) -{ - const NumericType supported_type_of_numbers = - NumericType("signed integer", 2); - if (new_type != supported_type_of_numbers) - { +NumericType +ECAT7ParametricDensityOutputFileFormat::set_type_of_numbers(const NumericType& new_type, const bool warn) { + const NumericType supported_type_of_numbers = NumericType("signed integer", 2); + if (new_type != supported_type_of_numbers) { if (warn) - warning("ECAT7ParametricDensityOutputFileFormat: output type of numbers is currently fixed to short (2 byte signed integers)\n"); + warning("ECAT7ParametricDensityOutputFileFormat: output type of numbers is currently fixed to short (2 byte signed " + "integers)\n"); this->type_of_numbers = supported_type_of_numbers; - } - else + } else this->type_of_numbers = new_type; return this->type_of_numbers; - } template -ByteOrder -ECAT7ParametricDensityOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) -{ - if (new_byte_order != ByteOrder::big_endian) - { +ByteOrder +ECAT7ParametricDensityOutputFileFormat::set_byte_order(const ByteOrder& new_byte_order, const bool warn) { + if (new_byte_order != ByteOrder::big_endian) { if (warn) warning("ECAT7ParametricDensityOutputFileFormat: byte_order is currently fixed to big-endian\n"); this->file_byte_order = ByteOrder::big_endian; - } - else + } else this->file_byte_order = new_byte_order; return this->file_byte_order; } template -Succeeded -ECAT7ParametricDensityOutputFileFormat:: -actual_write_to_file(std::string& filename, - const ParametricDiscretisedDensity& parametric_density) const -{ - shared_ptr scanner_ptr( - Scanner::get_scanner_from_name(this->default_scanner_name)); - +Succeeded +ECAT7ParametricDensityOutputFileFormat::actual_write_to_file( + std::string& filename, const ParametricDiscretisedDensity& parametric_density) const { + shared_ptr scanner_ptr(Scanner::get_scanner_from_name(this->default_scanner_name)); + add_extension(filename, ".img"); - typedef - typename ParametricDiscretisedDensity::SingleDiscretisedDensityType - SingleDensityType; + typedef typename ParametricDiscretisedDensity::SingleDiscretisedDensityType SingleDensityType; // somewhat naughty trick to get elemT of DiscretisedDensityT typedef typename DiscretisedDensityT::full_value_type KinParsT; @@ -154,34 +128,28 @@ actual_write_to_file(std::string& filename, mhead.num_frames = KinParsT::size(); mhead.acquisition_type = DynamicEmission; - - MatrixFile* mptr= matrix_create (filename.c_str(), MAT_CREATE, &mhead); - if (mptr == 0) - { - warning("ECAT7ParametricDensityOutputFileFormat::write_to_file: error opening output file %s\n", - filename.c_str()); + + MatrixFile* mptr = matrix_create(filename.c_str(), MAT_CREATE, &mhead); + if (mptr == 0) { + warning("ECAT7ParametricDensityOutputFileFormat::write_to_file: error opening output file %s\n", filename.c_str()); return Succeeded::no; } - - for (unsigned int f=1; f<=KinParsT::size(); ++f) - { - parametric_density.construct_single_density(single_density,f); - Succeeded success = - DiscretisedDensity_to_ECAT7(mptr, single_density, f); - if (success == Succeeded::no) - { - matrix_close(mptr); - return success; - } + + for (unsigned int f = 1; f <= KinParsT::size(); ++f) { + parametric_density.construct_single_density(single_density, f); + Succeeded success = DiscretisedDensity_to_ECAT7(mptr, single_density, f); + if (success == Succeeded::no) { + matrix_close(mptr); + return success; } + } matrix_close(mptr); - + return Succeeded::yes; } -template class ECAT7ParametricDensityOutputFileFormat; +template class ECAT7ParametricDensityOutputFileFormat; END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT END_NAMESPACE_STIR - diff --git a/src/IO/GEHDF5Wrapper.cxx b/src/IO/GEHDF5Wrapper.cxx index 8bc4b135d4..b875b39fba 100644 --- a/src/IO/GEHDF5Wrapper.cxx +++ b/src/IO/GEHDF5Wrapper.cxx @@ -37,66 +37,61 @@ #include "stir/info.h" #include - START_NAMESPACE_STIR namespace GE { namespace RDF_HDF5 { std::uint32_t -GEHDF5Wrapper::read_dataset_uint32(const std::string& dataset_name) -{ - std::uint32_t tmp=0U; +GEHDF5Wrapper::read_dataset_uint32(const std::string& dataset_name) { + std::uint32_t tmp = 0U; H5::DataSet dataset = file.openDataSet(dataset_name); dataset.read(&tmp, H5::PredType::NATIVE_UINT32); return tmp; } std::int32_t -GEHDF5Wrapper::read_dataset_int32(const std::string& dataset_name) -{ - std::int32_t tmp=0; +GEHDF5Wrapper::read_dataset_int32(const std::string& dataset_name) { + std::int32_t tmp = 0; H5::DataSet dataset = file.openDataSet(dataset_name); dataset.read(&tmp, H5::PredType::NATIVE_INT32); return tmp; } -bool GEHDF5Wrapper::check_GE_signature(const std::string& filename) -{ - try - { - if(!H5::H5File::isHdf5(filename)) - return false; +bool +GEHDF5Wrapper::check_GE_signature(const std::string& filename) { + try { + if (!H5::H5File::isHdf5(filename)) + return false; - H5::H5File file; - file.openFile( filename, H5F_ACC_RDONLY ); + H5::H5File file; + file.openFile(filename, H5F_ACC_RDONLY); - return (check_GE_signature(file)); - } - catch(...) - { - return false; - } + return (check_GE_signature(file)); + } catch (...) { + return false; + } } -bool GEHDF5Wrapper::check_GE_signature(H5::H5File& file) -{ - if(file.getId() == -1) - error("File is not open. Aborting"); - - H5::StrType vlst(0,37); // 37 here is the length of the string (PW got it from the text file generated by list2txt with the LIST000_decomp.BLF - std::string read_str_manufacturer; - - H5::DataSet dataset2= file.openDataSet("/HeaderData/ExamData/manufacturer"); - dataset2.read(read_str_manufacturer,vlst); - - if(read_str_manufacturer == "GE MEDICAL SYSTEMS") - { - return true; - } - return false; +bool +GEHDF5Wrapper::check_GE_signature(H5::H5File& file) { + if (file.getId() == -1) + error("File is not open. Aborting"); + + H5::StrType vlst( + 0, + 37); // 37 here is the length of the string (PW got it from the text file generated by list2txt with the LIST000_decomp.BLF + std::string read_str_manufacturer; + + H5::DataSet dataset2 = file.openDataSet("/HeaderData/ExamData/manufacturer"); + dataset2.read(read_str_manufacturer, vlst); + + if (read_str_manufacturer == "GE MEDICAL SYSTEMS") { + return true; + } + return false; } -// // Checks if input file is listfile. +// // Checks if input file is listfile. // AB: todo do we want this func? helps test from filename /* bool @@ -118,774 +113,750 @@ GEHDF5Wrapper::is_list_file(const std::string& filename) } */ - // AB todo: only valid for RDF9 (until they tell us otherwise) bool -GEHDF5Wrapper::is_list_file() const -{ - // have we already checked this? - if(is_list) - return true; - - if(file.getId() == -1) - error("File is not open. Aborting"); - - // All RDF files shoudl have this DataSet - H5::DataSet dataset = file.openDataSet("/HeaderData/RDFConfiguration/isListFile"); - std::uint32_t is_list_file; - dataset.read(&is_list_file, H5::PredType::NATIVE_UINT32); - return is_list_file; - +GEHDF5Wrapper::is_list_file() const { + // have we already checked this? + if (is_list) + return true; + + if (file.getId() == -1) + error("File is not open. Aborting"); + + // All RDF files shoudl have this DataSet + H5::DataSet dataset = file.openDataSet("/HeaderData/RDFConfiguration/isListFile"); + std::uint32_t is_list_file; + dataset.read(&is_list_file, H5::PredType::NATIVE_UINT32); + return is_list_file; } -// Checks if file is a sino file. +// Checks if file is a sino file. // AB todo: only valid for RDF9 (until they tell us otherwise) bool -GEHDF5Wrapper::is_sino_file() const -{ - if(is_sino) - return true; - if(file.getId() == -1) - error("File is not open. Aborting"); - - // If this Group exists, its a sino file. - // huh, no C++ way to do this without try catch. https://stackoverflow.com/questions/35668056/test-group-existence-in-hdf5-c - return H5Lexists( file.getId(), "/SegmentData/Segment2", H5P_DEFAULT ) > 0; +GEHDF5Wrapper::is_sino_file() const { + if (is_sino) + return true; + if (file.getId() == -1) + error("File is not open. Aborting"); + + // If this Group exists, its a sino file. + // huh, no C++ way to do this without try catch. https://stackoverflow.com/questions/35668056/test-group-existence-in-hdf5-c + return H5Lexists(file.getId(), "/SegmentData/Segment2", H5P_DEFAULT) > 0; } bool -GEHDF5Wrapper::is_geo_file() const -{ - // Apparently the norm file has the geo file inside. This means that the geo file is superfluous. - // For now, lets just make this fucntion is_geo_or_norm_file(). Perhaps later versions will no be like this and this we need to change this function. - - if(is_geo || is_norm) - return true; - if(file.getId() == -1) - error("File is not open. Aborting"); - return H5Lexists( file.getId(), "/SegmentData/Segment4/3D_Norm_Correction/slice1", H5P_DEFAULT ) > 0; - // AB if you want to make sure geo is definetly geo, and not geo or norm, add to the avobe line: && !H5Lexists( file.getId(), "/3DCrystalEfficiency/crystalEfficiency", H5P_DEFAULT ); +GEHDF5Wrapper::is_geo_file() const { + // Apparently the norm file has the geo file inside. This means that the geo file is superfluous. + // For now, lets just make this fucntion is_geo_or_norm_file(). Perhaps later versions will no be like this and this we need to + // change this function. + + if (is_geo || is_norm) + return true; + if (file.getId() == -1) + error("File is not open. Aborting"); + return H5Lexists(file.getId(), "/SegmentData/Segment4/3D_Norm_Correction/slice1", H5P_DEFAULT) > 0; + // AB if you want to make sure geo is definetly geo, and not geo or norm, add to the avobe line: && !H5Lexists( file.getId(), + // "/3DCrystalEfficiency/crystalEfficiency", H5P_DEFAULT ); } bool -GEHDF5Wrapper::is_norm_file() const -{ - if(is_norm) - return true; - if(file.getId() == -1) - error("File is not open. Aborting"); +GEHDF5Wrapper::is_norm_file() const { + if (is_norm) + return true; + if (file.getId() == -1) + error("File is not open. Aborting"); - return H5Lexists( file.getId(), "/3DCrystalEfficiency/crystalEfficiency", H5P_DEFAULT ) > 0; + return H5Lexists(file.getId(), "/3DCrystalEfficiency/crystalEfficiency", H5P_DEFAULT) > 0; } -GEHDF5Wrapper::GEHDF5Wrapper() -{ - // Not much. +GEHDF5Wrapper::GEHDF5Wrapper() { + // Not much. } -GEHDF5Wrapper::GEHDF5Wrapper(const std::string& filename) -{ - if(open(filename) == Succeeded::no) - error("GEHDF5Wrapper: Error opening HDF5 file. Abort."); +GEHDF5Wrapper::GEHDF5Wrapper(const std::string& filename) { + if (open(filename) == Succeeded::no) + error("GEHDF5Wrapper: Error opening HDF5 file. Abort."); } unsigned int -GEHDF5Wrapper::check_geo_type() -{ - if(!is_geo ) - error("Not a geo file. Aborting"); - if(file.getId() == -1) - error("File is not open. Aborting"); - - unsigned int geo_type=0; - H5::DataSet str_geo_size = file.openDataSet("/HeaderData/Sorter/Segment4/dimension3Size"); - str_geo_size.read(&geo_type, H5::PredType::NATIVE_UINT32); - if (geo_type>1) - geo_type=3; - else - geo_type=2; - return geo_type; +GEHDF5Wrapper::check_geo_type() { + if (!is_geo) + error("Not a geo file. Aborting"); + if (file.getId() == -1) + error("File is not open. Aborting"); + + unsigned int geo_type = 0; + H5::DataSet str_geo_size = file.openDataSet("/HeaderData/Sorter/Segment4/dimension3Size"); + str_geo_size.read(&geo_type, H5::PredType::NATIVE_UINT32); + if (geo_type > 1) + geo_type = 3; + else + geo_type = 2; + return geo_type; } // Function that error checks the input file and sets flags for the correct formats. GEHDF5Wrapper.file must be already open. -// AB todo: this file is only valid for RDF 9. -Succeeded -GEHDF5Wrapper::check_file() -{ - if(file.getId()==-1) - error("File is not open. Aborting"); - if(!check_GE_signature(file)) - error("File is HDF5 but not GE data. Aborting"); - - //AB: We are openign a new file. The same class should not be used twice, but lets make sure that if it happens, we reseted the file identifiers. - is_list=false; is_norm=false;is_geo=false;is_sino=false; - - //AB Find out the RDF version of the file. - H5::DataSet str_file_version = file.openDataSet("/HeaderData/RDFConfiguration/fileVersion/majorVersion"); - str_file_version.read(&rdf_ver, H5::PredType::NATIVE_UINT32); - - //AB Lets just error for now. - if (rdf_ver!=9) - error("Only RDF version 9 supported. Aborting"); - - if(is_list_file()) - { - is_list = true; - // AB Now lets check all things that are required - if (rdf_ver == 9) //AB todo: is this valid for 10? - { - // Check 1: Is the file compressed? - unsigned int is_compressed; - H5::DataSet str_file_version = file.openDataSet("/HeaderData/ListHeader/isListCompressed"); - str_file_version.read(&is_compressed, H5::PredType::NATIVE_UINT32); - if (is_compressed) - error("The RDF9 Listmode file is compressed, we won't be able to read it. Please uncompress it and retry. Aborting"); - } - - return Succeeded::yes; - } - if(is_sino_file()) - { - is_sino = true; - if (rdf_ver == 9) //AB todo: is this valid for 10? - { - // Check 1: Is the file compressed? - unsigned int is_compressed; - H5::DataSet str_file_version = file.openDataSet("/HeaderData/Sorter/Segment2/compDataSegSize"); - str_file_version.read(&is_compressed, H5::PredType::NATIVE_UINT32); - if (is_compressed) - error("The RDF9 file sinogram is compressed, we won't be able to read it. Please uncompress it and retry. Aborting"); - } - return Succeeded::yes; - } - if(is_norm_file()) +// AB todo: this file is only valid for RDF 9. +Succeeded +GEHDF5Wrapper::check_file() { + if (file.getId() == -1) + error("File is not open. Aborting"); + if (!check_GE_signature(file)) + error("File is HDF5 but not GE data. Aborting"); + + // AB: We are openign a new file. The same class should not be used twice, but lets make sure that if it happens, we reseted the + // file identifiers. + is_list = false; + is_norm = false; + is_geo = false; + is_sino = false; + + // AB Find out the RDF version of the file. + H5::DataSet str_file_version = file.openDataSet("/HeaderData/RDFConfiguration/fileVersion/majorVersion"); + str_file_version.read(&rdf_ver, H5::PredType::NATIVE_UINT32); + + // AB Lets just error for now. + if (rdf_ver != 9) + error("Only RDF version 9 supported. Aborting"); + + if (is_list_file()) { + is_list = true; + // AB Now lets check all things that are required + if (rdf_ver == 9) // AB todo: is this valid for 10? { - is_norm=true; - is_geo =true; // in RFD9, if its norm, it is also geo (it contains it) - // Check the type of geo file it contains. - geo_dims = check_geo_type(); - - return Succeeded::yes; + // Check 1: Is the file compressed? + unsigned int is_compressed; + H5::DataSet str_file_version = file.openDataSet("/HeaderData/ListHeader/isListCompressed"); + str_file_version.read(&is_compressed, H5::PredType::NATIVE_UINT32); + if (is_compressed) + error("The RDF9 Listmode file is compressed, we won't be able to read it. Please uncompress it and retry. Aborting"); } - if(is_geo_file()) + + return Succeeded::yes; + } + if (is_sino_file()) { + is_sino = true; + if (rdf_ver == 9) // AB todo: is this valid for 10? { - is_geo=true; - geo_dims = check_geo_type(); - - return Succeeded::yes; + // Check 1: Is the file compressed? + unsigned int is_compressed; + H5::DataSet str_file_version = file.openDataSet("/HeaderData/Sorter/Segment2/compDataSegSize"); + str_file_version.read(&is_compressed, H5::PredType::NATIVE_UINT32); + if (is_compressed) + error("The RDF9 file sinogram is compressed, we won't be able to read it. Please uncompress it and retry. Aborting"); } - // should not get here. - return Succeeded::no; + return Succeeded::yes; + } + if (is_norm_file()) { + is_norm = true; + is_geo = true; // in RFD9, if its norm, it is also geo (it contains it) + // Check the type of geo file it contains. + geo_dims = check_geo_type(); + + return Succeeded::yes; + } + if (is_geo_file()) { + is_geo = true; + geo_dims = check_geo_type(); + + return Succeeded::yes; + } + // should not get here. + return Succeeded::no; } Succeeded -GEHDF5Wrapper::open(const std::string& filename) -{ - if(!file.isHdf5(filename)) - error("GEHDF5Wrapper: The input file is not HDF5! Abort."); +GEHDF5Wrapper::open(const std::string& filename) { + if (!file.isHdf5(filename)) + error("GEHDF5Wrapper: The input file is not HDF5! Abort."); - file.openFile(filename, H5F_ACC_RDONLY); + file.openFile(filename, H5F_ACC_RDONLY); - //AB: check if the input file is valid, not only as a HDF5, also a valid PET file. - check_file(); + // AB: check if the input file is valid, not only as a HDF5, also a valid PET file. + check_file(); - initialise_exam_info(); - initialise_proj_data_info_from_HDF5(); + initialise_exam_info(); + initialise_proj_data_info_from_HDF5(); - // functions above will throw actually, so if we get here, it worked. - return Succeeded::yes; + // functions above will throw actually, so if we get here, it worked. + return Succeeded::yes; } -shared_ptr GEHDF5Wrapper::get_scanner_from_HDF5() -{ - std::string read_str_scanner; - H5::StrType vlst(0,37); // 37 here is the length of the string (PW got it from the text file generated by list2txt with the LIST000_decomp.BLF - - H5::DataSet dataset = file.openDataSet("/HeaderData/ExamData/scannerDesc"); - dataset.read(read_str_scanner,vlst); - - float effective_ring_diameter; - int num_transaxial_blocks_per_bucket = 0; - int num_axial_blocks_per_bucket = 0; - int axial_blocks_per_unit = 0; - int radial_blocks_per_unit = 0; - int axial_units_per_module = 0; - int radial_units_per_module = 0; - int axial_modules_per_system = 0; - int radial_modules_per_system = 0; - int max_num_non_arccorrected_bins = 0; - int num_transaxial_crystals_per_block = 0; - int num_axial_crystals_per_block = 0 ; - float detector_axial_size = 0.0; - float intrinsic_tilt = 0.0; - int num_detector_layers = 1; - - H5::DataSet str_effective_ring_diameter = file.openDataSet("/HeaderData/SystemGeometry/effectiveRingDiameter"); - H5::DataSet str_axial_blocks_per_module = file.openDataSet("/HeaderData/SystemGeometry/axialBlocksPerModule"); - H5::DataSet str_radial_blocks_per_module = file.openDataSet("/HeaderData/SystemGeometry/radialBlocksPerModule"); - H5::DataSet str_axial_blocks_per_unit = file.openDataSet("/HeaderData/SystemGeometry/axialBlocksPerUnit"); - H5::DataSet str_radial_blocks_per_unit = file.openDataSet("/HeaderData/SystemGeometry/radialBlocksPerUnit"); - H5::DataSet str_axial_units_per_module = file.openDataSet("/HeaderData/SystemGeometry/axialUnitsPerModule"); - H5::DataSet str_radial_units_per_module = file.openDataSet("/HeaderData/SystemGeometry/radialUnitsPerModule"); - H5::DataSet str_axial_modules_per_system = file.openDataSet("/HeaderData/SystemGeometry/axialModulesPerSystem"); - H5::DataSet str_radial_modules_per_system = file.openDataSet("/HeaderData/SystemGeometry/radialModulesPerSystem"); - //! \todo P.W: Find the crystal gaps and other info missing. - H5::DataSet str_detector_axial_size = file.openDataSet("/HeaderData/SystemGeometry/detectorAxialSize"); - H5::DataSet str_intrinsic_tilt = file.openDataSet("/HeaderData/SystemGeometry/transaxial_crystal_0_offset"); - - H5::DataSet str_max_number_of_non_arc_corrected_bins; - // TODO RDF10, what happens here? - if (rdf_ver == 9) - { // Bug in RDF9 makes this dimension2Size instead of the expected dimension1Size - if(is_sino_file()) - str_max_number_of_non_arc_corrected_bins = file.openDataSet("/HeaderData/Sorter/dimension2Size"); - else - str_max_number_of_non_arc_corrected_bins = file.openDataSet("/HeaderData/Sorter/dimension1Size"); - } - H5::DataSet str_axial_crystals_per_block = file.openDataSet("/HeaderData/SystemGeometry/axialCrystalsPerBlock"); - H5::DataSet str_radial_crystals_per_block = file.openDataSet("/HeaderData/SystemGeometry/radialCrystalsPerBlock"); - // Convert to numbers. - - str_radial_blocks_per_module.read(&num_transaxial_blocks_per_bucket, H5::PredType::NATIVE_UINT32); - str_axial_blocks_per_module.read(&num_axial_blocks_per_bucket, H5::PredType::NATIVE_UINT32); - str_axial_blocks_per_unit.read(&axial_blocks_per_unit, H5::PredType::NATIVE_UINT32); - str_radial_blocks_per_unit.read(&radial_blocks_per_unit, H5::PredType::NATIVE_UINT32); - str_axial_units_per_module.read(&axial_units_per_module, H5::PredType::NATIVE_UINT32); - str_radial_units_per_module.read(&radial_units_per_module, H5::PredType::NATIVE_UINT32); - str_axial_modules_per_system.read(&axial_modules_per_system, H5::PredType::NATIVE_UINT32); - str_radial_modules_per_system.read(&radial_modules_per_system, H5::PredType::NATIVE_UINT32); - str_detector_axial_size.read(&detector_axial_size, H5::PredType::NATIVE_FLOAT); - str_intrinsic_tilt.read(&intrinsic_tilt, H5::PredType::NATIVE_FLOAT); - str_effective_ring_diameter.read(&effective_ring_diameter, H5::PredType::NATIVE_FLOAT); - str_max_number_of_non_arc_corrected_bins.read(&max_num_non_arccorrected_bins, H5::PredType::NATIVE_UINT32); - str_radial_crystals_per_block.read(&num_transaxial_crystals_per_block, H5::PredType::NATIVE_UINT32); - str_axial_crystals_per_block.read(&num_axial_crystals_per_block, H5::PredType::NATIVE_UINT32); - - int num_rings = num_axial_blocks_per_bucket*num_axial_crystals_per_block*axial_modules_per_system; - int num_detectors_per_ring = num_transaxial_blocks_per_bucket*num_transaxial_crystals_per_block*radial_modules_per_system; - float ring_spacing = detector_axial_size/num_rings; - - //PW Bin Size, default num of arc corrected bins and inner ring radius not found in RDF header. - // They will be set from the default STIR values - shared_ptr scanner_sptr(Scanner::get_scanner_from_name(read_str_scanner)); - if (is_null_ptr(scanner_sptr)) - error("Scanner read from RDF file is " + read_str_scanner + ", but this is not supported yet"); - - scanner_sptr->set_num_detectors_per_ring(num_detectors_per_ring); - scanner_sptr->set_num_rings(num_rings); - if (!is_list_file()) - scanner_sptr->set_max_num_non_arccorrected_bins(max_num_non_arccorrected_bins); - scanner_sptr->set_ring_spacing(ring_spacing); - scanner_sptr->set_default_intrinsic_tilt(intrinsic_tilt*_PI/180); - scanner_sptr->set_num_axial_blocks_per_bucket(num_axial_blocks_per_bucket); - scanner_sptr->set_num_transaxial_blocks_per_bucket(num_transaxial_blocks_per_bucket); - scanner_sptr->set_num_axial_crystals_per_block(num_axial_crystals_per_block); - scanner_sptr->set_num_transaxial_crystals_per_block(num_transaxial_crystals_per_block); - scanner_sptr->set_num_detector_layers(num_detector_layers); - scanner_sptr->set_reference_energy(511.F); - - if (fabs(scanner_sptr->get_effective_ring_radius() - effective_ring_diameter/2) > .1F) - { - const float def_DOI = .0F; - warning("GEHDF5Wrapper: default STIR effective ring radius is " - + std::to_string(scanner_sptr->get_effective_ring_radius()) - + ", while RDF says " + std::to_string(effective_ring_diameter/2) - + "\nWill adjust scanner info to fit with the RDF file using default average DOI of " - + std::to_string(def_DOI) + "mm"); - scanner_sptr->set_inner_ring_radius((effective_ring_diameter/2) - def_DOI); - scanner_sptr->set_average_depth_of_interaction(def_DOI); - } - if (scanner_sptr->get_default_bin_size() <= 0.F) - { - warning("GEHDF5Wrapper: default bin-size is not set. This will create trouble for FBP etc"); - } - if (scanner_sptr->get_default_num_arccorrected_bins() <= 0) - { - warning("GEHDF5Wrapper: default num_arccorrected bins is not set. This will create trouble for FBP etc"); - } - if (scanner_sptr->get_energy_resolution() <= 0) - { - warning("GEHDF5Wrapper: energy resolution is not set. This will create trouble for scatter estimation"); - } - - return scanner_sptr; - +shared_ptr +GEHDF5Wrapper::get_scanner_from_HDF5() { + std::string read_str_scanner; + H5::StrType vlst( + 0, + 37); // 37 here is the length of the string (PW got it from the text file generated by list2txt with the LIST000_decomp.BLF + + H5::DataSet dataset = file.openDataSet("/HeaderData/ExamData/scannerDesc"); + dataset.read(read_str_scanner, vlst); + + float effective_ring_diameter; + int num_transaxial_blocks_per_bucket = 0; + int num_axial_blocks_per_bucket = 0; + int axial_blocks_per_unit = 0; + int radial_blocks_per_unit = 0; + int axial_units_per_module = 0; + int radial_units_per_module = 0; + int axial_modules_per_system = 0; + int radial_modules_per_system = 0; + int max_num_non_arccorrected_bins = 0; + int num_transaxial_crystals_per_block = 0; + int num_axial_crystals_per_block = 0; + float detector_axial_size = 0.0; + float intrinsic_tilt = 0.0; + int num_detector_layers = 1; + + H5::DataSet str_effective_ring_diameter = file.openDataSet("/HeaderData/SystemGeometry/effectiveRingDiameter"); + H5::DataSet str_axial_blocks_per_module = file.openDataSet("/HeaderData/SystemGeometry/axialBlocksPerModule"); + H5::DataSet str_radial_blocks_per_module = file.openDataSet("/HeaderData/SystemGeometry/radialBlocksPerModule"); + H5::DataSet str_axial_blocks_per_unit = file.openDataSet("/HeaderData/SystemGeometry/axialBlocksPerUnit"); + H5::DataSet str_radial_blocks_per_unit = file.openDataSet("/HeaderData/SystemGeometry/radialBlocksPerUnit"); + H5::DataSet str_axial_units_per_module = file.openDataSet("/HeaderData/SystemGeometry/axialUnitsPerModule"); + H5::DataSet str_radial_units_per_module = file.openDataSet("/HeaderData/SystemGeometry/radialUnitsPerModule"); + H5::DataSet str_axial_modules_per_system = file.openDataSet("/HeaderData/SystemGeometry/axialModulesPerSystem"); + H5::DataSet str_radial_modules_per_system = file.openDataSet("/HeaderData/SystemGeometry/radialModulesPerSystem"); + //! \todo P.W: Find the crystal gaps and other info missing. + H5::DataSet str_detector_axial_size = file.openDataSet("/HeaderData/SystemGeometry/detectorAxialSize"); + H5::DataSet str_intrinsic_tilt = file.openDataSet("/HeaderData/SystemGeometry/transaxial_crystal_0_offset"); + + H5::DataSet str_max_number_of_non_arc_corrected_bins; + // TODO RDF10, what happens here? + if (rdf_ver == 9) { // Bug in RDF9 makes this dimension2Size instead of the expected dimension1Size + if (is_sino_file()) + str_max_number_of_non_arc_corrected_bins = file.openDataSet("/HeaderData/Sorter/dimension2Size"); + else + str_max_number_of_non_arc_corrected_bins = file.openDataSet("/HeaderData/Sorter/dimension1Size"); + } + H5::DataSet str_axial_crystals_per_block = file.openDataSet("/HeaderData/SystemGeometry/axialCrystalsPerBlock"); + H5::DataSet str_radial_crystals_per_block = file.openDataSet("/HeaderData/SystemGeometry/radialCrystalsPerBlock"); + // Convert to numbers. + + str_radial_blocks_per_module.read(&num_transaxial_blocks_per_bucket, H5::PredType::NATIVE_UINT32); + str_axial_blocks_per_module.read(&num_axial_blocks_per_bucket, H5::PredType::NATIVE_UINT32); + str_axial_blocks_per_unit.read(&axial_blocks_per_unit, H5::PredType::NATIVE_UINT32); + str_radial_blocks_per_unit.read(&radial_blocks_per_unit, H5::PredType::NATIVE_UINT32); + str_axial_units_per_module.read(&axial_units_per_module, H5::PredType::NATIVE_UINT32); + str_radial_units_per_module.read(&radial_units_per_module, H5::PredType::NATIVE_UINT32); + str_axial_modules_per_system.read(&axial_modules_per_system, H5::PredType::NATIVE_UINT32); + str_radial_modules_per_system.read(&radial_modules_per_system, H5::PredType::NATIVE_UINT32); + str_detector_axial_size.read(&detector_axial_size, H5::PredType::NATIVE_FLOAT); + str_intrinsic_tilt.read(&intrinsic_tilt, H5::PredType::NATIVE_FLOAT); + str_effective_ring_diameter.read(&effective_ring_diameter, H5::PredType::NATIVE_FLOAT); + str_max_number_of_non_arc_corrected_bins.read(&max_num_non_arccorrected_bins, H5::PredType::NATIVE_UINT32); + str_radial_crystals_per_block.read(&num_transaxial_crystals_per_block, H5::PredType::NATIVE_UINT32); + str_axial_crystals_per_block.read(&num_axial_crystals_per_block, H5::PredType::NATIVE_UINT32); + + int num_rings = num_axial_blocks_per_bucket * num_axial_crystals_per_block * axial_modules_per_system; + int num_detectors_per_ring = num_transaxial_blocks_per_bucket * num_transaxial_crystals_per_block * radial_modules_per_system; + float ring_spacing = detector_axial_size / num_rings; + // PW Bin Size, default num of arc corrected bins and inner ring radius not found in RDF header. + // They will be set from the default STIR values + shared_ptr scanner_sptr(Scanner::get_scanner_from_name(read_str_scanner)); + if (is_null_ptr(scanner_sptr)) + error("Scanner read from RDF file is " + read_str_scanner + ", but this is not supported yet"); + + scanner_sptr->set_num_detectors_per_ring(num_detectors_per_ring); + scanner_sptr->set_num_rings(num_rings); + if (!is_list_file()) + scanner_sptr->set_max_num_non_arccorrected_bins(max_num_non_arccorrected_bins); + scanner_sptr->set_ring_spacing(ring_spacing); + scanner_sptr->set_default_intrinsic_tilt(intrinsic_tilt * _PI / 180); + scanner_sptr->set_num_axial_blocks_per_bucket(num_axial_blocks_per_bucket); + scanner_sptr->set_num_transaxial_blocks_per_bucket(num_transaxial_blocks_per_bucket); + scanner_sptr->set_num_axial_crystals_per_block(num_axial_crystals_per_block); + scanner_sptr->set_num_transaxial_crystals_per_block(num_transaxial_crystals_per_block); + scanner_sptr->set_num_detector_layers(num_detector_layers); + scanner_sptr->set_reference_energy(511.F); + + if (fabs(scanner_sptr->get_effective_ring_radius() - effective_ring_diameter / 2) > .1F) { + const float def_DOI = .0F; + warning("GEHDF5Wrapper: default STIR effective ring radius is " + std::to_string(scanner_sptr->get_effective_ring_radius()) + + ", while RDF says " + std::to_string(effective_ring_diameter / 2) + + "\nWill adjust scanner info to fit with the RDF file using default average DOI of " + std::to_string(def_DOI) + "mm"); + scanner_sptr->set_inner_ring_radius((effective_ring_diameter / 2) - def_DOI); + scanner_sptr->set_average_depth_of_interaction(def_DOI); + } + if (scanner_sptr->get_default_bin_size() <= 0.F) { + warning("GEHDF5Wrapper: default bin-size is not set. This will create trouble for FBP etc"); + } + if (scanner_sptr->get_default_num_arccorrected_bins() <= 0) { + warning("GEHDF5Wrapper: default num_arccorrected bins is not set. This will create trouble for FBP etc"); + } + if (scanner_sptr->get_energy_resolution() <= 0) { + warning("GEHDF5Wrapper: energy resolution is not set. This will create trouble for scatter estimation"); + } + + return scanner_sptr; } -void GEHDF5Wrapper::initialise_proj_data_info_from_HDF5() -{ +void +GEHDF5Wrapper::initialise_proj_data_info_from_HDF5() { shared_ptr scanner_sptr = get_scanner_from_HDF5(); this->proj_data_info_sptr = - ProjDataInfo::construct_proj_data_info(scanner_sptr, - /*span*/ 2, - /* max_delta*/ scanner_sptr->get_num_rings()-1, - /* num_views */ scanner_sptr->get_num_detectors_per_ring()/2, - /* num_tangential_poss */ scanner_sptr->get_max_num_non_arccorrected_bins(), - /* arc_corrected */ false - ); - this->proj_data_info_sptr-> - set_bed_position_horizontal(this->read_dataset_int32("/HeaderData/AcqParameters/LandmarkParameters/absTableLongitude")/10.F); /* units in RDF are 0.1 mm */ - //this->proj_data_info_sptr->set_gantry_tilt(this->read_dataset_uint32("/HeaderData/AcqParameters/LandmarkParameters/gantryTilt")); /* units in RDF are 0.25 degrees, patient relative */ - this->proj_data_info_sptr-> - set_bed_position_vertical(this->read_dataset_int32("/HeaderData/AcqParameters/LandmarkParameters/tableElevation")/10.F); /* units in RDF are 0.1 mm */ + ProjDataInfo::construct_proj_data_info(scanner_sptr, + /*span*/ 2, + /* max_delta*/ scanner_sptr->get_num_rings() - 1, + /* num_views */ scanner_sptr->get_num_detectors_per_ring() / 2, + /* num_tangential_poss */ scanner_sptr->get_max_num_non_arccorrected_bins(), + /* arc_corrected */ false); + this->proj_data_info_sptr->set_bed_position_horizontal( + this->read_dataset_int32("/HeaderData/AcqParameters/LandmarkParameters/absTableLongitude") / + 10.F); /* units in RDF are 0.1 mm */ + // this->proj_data_info_sptr->set_gantry_tilt(this->read_dataset_uint32("/HeaderData/AcqParameters/LandmarkParameters/gantryTilt")); + // /* units in RDF are 0.25 degrees, patient relative */ + this->proj_data_info_sptr->set_bed_position_vertical( + this->read_dataset_int32("/HeaderData/AcqParameters/LandmarkParameters/tableElevation") / + 10.F); /* units in RDF are 0.1 mm */ } -unsigned int GEHDF5Wrapper::get_num_singles_samples() -{ - return m_num_singles_samples; +unsigned int +GEHDF5Wrapper::get_num_singles_samples() { + return m_num_singles_samples; } - -void GEHDF5Wrapper::initialise_exam_info() -{ - this->exam_info_sptr.reset(new ExamInfo()); - this->exam_info_sptr->imaging_modality = ImagingModality(ImagingModality::PT); - { - const std::uint32_t patientEntry = read_dataset_uint32("/HeaderData/AcqParameters/LandmarkParameters/patientEntry"); - const std::uint32_t patientPosition = read_dataset_uint32("/HeaderData/AcqParameters/LandmarkParameters/patientPosition"); - PatientPosition::OrientationValue orientation; - PatientPosition::RotationValue rotation; - switch (patientEntry) - { - case AcqPatientEntries::ACQ_HEAD_FIRST: orientation = PatientPosition::OrientationValue::head_in; break; - case AcqPatientEntries::ACQ_FEET_FIRST: orientation = PatientPosition::OrientationValue::feet_in; break; - default: orientation = PatientPosition::OrientationValue::unknown_orientation; - } - switch (patientPosition) - { - case AcqPatientPositions::ACQ_SUPINE: rotation = PatientPosition::RotationValue::supine; break; - case AcqPatientPositions::ACQ_PRONE: rotation = PatientPosition::RotationValue::prone; break; - case AcqPatientPositions::ACQ_LEFT_DECUB: rotation = PatientPosition::RotationValue::left; break; - case AcqPatientPositions::ACQ_RIGHT_DECUB: rotation = PatientPosition::RotationValue::right; break; - default: rotation = PatientPosition::RotationValue::unknown_rotation; break; - } - exam_info_sptr->patient_position = PatientPosition(orientation, rotation); +void +GEHDF5Wrapper::initialise_exam_info() { + this->exam_info_sptr.reset(new ExamInfo()); + this->exam_info_sptr->imaging_modality = ImagingModality(ImagingModality::PT); + { + const std::uint32_t patientEntry = read_dataset_uint32("/HeaderData/AcqParameters/LandmarkParameters/patientEntry"); + const std::uint32_t patientPosition = read_dataset_uint32("/HeaderData/AcqParameters/LandmarkParameters/patientPosition"); + PatientPosition::OrientationValue orientation; + PatientPosition::RotationValue rotation; + switch (patientEntry) { + case AcqPatientEntries::ACQ_HEAD_FIRST: + orientation = PatientPosition::OrientationValue::head_in; + break; + case AcqPatientEntries::ACQ_FEET_FIRST: + orientation = PatientPosition::OrientationValue::feet_in; + break; + default: + orientation = PatientPosition::OrientationValue::unknown_orientation; + } + switch (patientPosition) { + case AcqPatientPositions::ACQ_SUPINE: + rotation = PatientPosition::RotationValue::supine; + break; + case AcqPatientPositions::ACQ_PRONE: + rotation = PatientPosition::RotationValue::prone; + break; + case AcqPatientPositions::ACQ_LEFT_DECUB: + rotation = PatientPosition::RotationValue::left; + break; + case AcqPatientPositions::ACQ_RIGHT_DECUB: + rotation = PatientPosition::RotationValue::right; + break; + default: + rotation = PatientPosition::RotationValue::unknown_rotation; + break; } - // PW Get the high and low energy threshold values from HDF5 header. - unsigned int low_energy_thres = 0; - unsigned int high_energy_thres = 0; + exam_info_sptr->patient_position = PatientPosition(orientation, rotation); + } + // PW Get the high and low energy threshold values from HDF5 header. + unsigned int low_energy_thres = 0; + unsigned int high_energy_thres = 0; + + H5::DataSet str_low_energy_thres = file.openDataSet("/HeaderData/AcqParameters/EDCATParameters/lower_energy_limit"); + H5::DataSet str_high_energy_thres = file.openDataSet("/HeaderData/AcqParameters/EDCATParameters/upper_energy_limit"); + + str_low_energy_thres.read(&low_energy_thres, H5::PredType::NATIVE_UINT32); + str_high_energy_thres.read(&high_energy_thres, H5::PredType::NATIVE_UINT32); + + // PW Set these values in exam_info_sptr. + exam_info_sptr->set_high_energy_thres(static_cast(high_energy_thres)); + exam_info_sptr->set_low_energy_thres(static_cast(low_energy_thres)); + + // read time since 1970 + std::uint32_t scanStartTime = 0; + H5::DataSet scanStartTime_dataset = file.openDataSet("/HeaderData/AcqStats/scanStartTime"); + scanStartTime_dataset.read(&scanStartTime, H5::PredType::NATIVE_UINT32); + exam_info_sptr->start_time_in_secs_since_1970 = double(scanStartTime); + + // get time frame + std::uint32_t frameStartTime = 0; + std::uint32_t frameDuration = 0; + H5::DataSet frameStartTime_dataset = file.openDataSet("/HeaderData/AcqStats/frameStartTime"); + H5::DataSet frameDuration_dataset = file.openDataSet("/HeaderData/AcqStats/frameDuration"); + + frameStartTime_dataset.read(&frameStartTime, H5::PredType::NATIVE_UINT32); + frameDuration_dataset.read(&frameDuration, H5::PredType::NATIVE_UINT32); + const double frame_start_time = double(frameStartTime - scanStartTime); + + std::vector> tf{{frame_start_time, frame_start_time + frameDuration / 1000}}; + + TimeFrameDefinitions tm(tf); + exam_info_sptr->set_time_frame_definitions(tm); +} - H5::DataSet str_low_energy_thres = file.openDataSet("/HeaderData/AcqParameters/EDCATParameters/lower_energy_limit"); - H5::DataSet str_high_energy_thres = file.openDataSet("/HeaderData/AcqParameters/EDCATParameters/upper_energy_limit"); +Succeeded +GEHDF5Wrapper::initialise_listmode_data() { + if (!is_list_file()) + error("The file provided is not listmode. Aborting"); + + if (rdf_ver == 9) { + m_address = "/ListData/listData"; + // These values are not in the file are come from info shared by GE. + m_size_of_record_signature = 6; + m_max_size_of_record = 16; + + unsigned int num_time_slices = 0; + H5::DataSet timeframe_dataspace = file.openDataSet("/HeaderData/SinglesHeader/numValidSamples"); + timeframe_dataspace.read(&num_time_slices, H5::PredType::NATIVE_UINT32); + if (num_time_slices == 0) { + error("Zero number of valid samples singles samples in data. Aborting"); + } - str_low_energy_thres.read(&low_energy_thres, H5::PredType::NATIVE_UINT32); - str_high_energy_thres.read(&high_energy_thres, H5::PredType::NATIVE_UINT32); + m_num_singles_samples = num_time_slices; - // PW Set these values in exam_info_sptr. - exam_info_sptr->set_high_energy_thres(static_cast(high_energy_thres)); - exam_info_sptr->set_low_energy_thres(static_cast(low_energy_thres)); + } else + return Succeeded::no; - // read time since 1970 - std::uint32_t scanStartTime = 0; - H5::DataSet scanStartTime_dataset = file.openDataSet("/HeaderData/AcqStats/scanStartTime"); - scanStartTime_dataset.read(&scanStartTime, H5::PredType::NATIVE_UINT32); - exam_info_sptr->start_time_in_secs_since_1970=double(scanStartTime); + m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address))); - // get time frame - std::uint32_t frameStartTime = 0; - std::uint32_t frameDuration = 0; - H5::DataSet frameStartTime_dataset = file.openDataSet("/HeaderData/AcqStats/frameStartTime"); - H5::DataSet frameDuration_dataset = file.openDataSet("/HeaderData/AcqStats/frameDuration"); + m_dataspace = m_dataset_sptr->getSpace(); + int dataset_list_Ndims = m_dataspace.getSimpleExtentNdims(); - frameStartTime_dataset.read(&frameStartTime, H5::PredType::NATIVE_UINT32); - frameDuration_dataset.read(&frameDuration, H5::PredType::NATIVE_UINT32); - const double frame_start_time = double(frameStartTime - scanStartTime); + // We allocate dims_out in the stack for efficiecy and safety but we need an error check just in case then + if (dataset_list_Ndims > m_max_dataset_dims) + error("Dataset dimensions (" + std::to_string(dataset_list_Ndims) + ") bigger than maximum of" + + std::to_string(m_max_dataset_dims) + ". This is unexpected, Aborting."); + hsize_t dims_out[m_max_dataset_dims]; - std::vector >tf{{frame_start_time,frame_start_time+frameDuration/1000}}; + m_dataspace.getSimpleExtentDims(dims_out, NULL); + m_list_size = dims_out[0]; + const hsize_t tmp_size_of_record_signature = m_size_of_record_signature; + m_memspace_ptr = new H5::DataSpace(dataset_list_Ndims, &tmp_size_of_record_signature); - TimeFrameDefinitions tm(tf); - exam_info_sptr->set_time_frame_definitions(tm); + return Succeeded::yes; } -Succeeded GEHDF5Wrapper::initialise_listmode_data() -{ - if(!is_list_file()) - error("The file provided is not listmode. Aborting"); - - if(rdf_ver==9) - { - m_address = "/ListData/listData"; - // These values are not in the file are come from info shared by GE. - m_size_of_record_signature = 6; - m_max_size_of_record = 16; - - unsigned int num_time_slices = 0; - H5::DataSet timeframe_dataspace = file.openDataSet("/HeaderData/SinglesHeader/numValidSamples"); - timeframe_dataspace.read(&num_time_slices, H5::PredType::NATIVE_UINT32); - if(num_time_slices==0) - { - error("Zero number of valid samples singles samples in data. Aborting"); - } - - m_num_singles_samples=num_time_slices; - - } - else - return Succeeded::no; +Succeeded +GEHDF5Wrapper::initialise_singles_data() { - m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address))); + if (!is_list_file() && !is_sino_file()) + error("The file provided is not listmode or sinogram data. Aborting"); + if (rdf_ver == 9) { + m_address = "/Singles/CrystalSingles/sample"; + // Get the DataSpace (metadata) corresponding to the DataSet that we want to read + m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address + "1"))); m_dataspace = m_dataset_sptr->getSpace(); - int dataset_list_Ndims = m_dataspace.getSimpleExtentNdims(); - - // We allocate dims_out in the stack for efficiecy and safety but we need an error check just in case then - if (dataset_list_Ndims>m_max_dataset_dims) - error("Dataset dimensions ("+ std::to_string(dataset_list_Ndims) + ") bigger than maximum of" + std::to_string(m_max_dataset_dims) + ". This is unexpected, Aborting."); - hsize_t dims_out[m_max_dataset_dims]; - - m_dataspace.getSimpleExtentDims( dims_out, NULL); - m_list_size=dims_out[0]; - const hsize_t tmp_size_of_record_signature = m_size_of_record_signature; - m_memspace_ptr = new H5::DataSpace( dataset_list_Ndims, - &tmp_size_of_record_signature); - - return Succeeded::yes; -} - -Succeeded GEHDF5Wrapper::initialise_singles_data() -{ - - if(!is_list_file() && !is_sino_file()) - error("The file provided is not listmode or sinogram data. Aborting"); - - if(rdf_ver==9) - { - m_address = "/Singles/CrystalSingles/sample"; - // Get the DataSpace (metadata) corresponding to the DataSet that we want to read - m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address + "1"))); - m_dataspace = m_dataset_sptr->getSpace(); - // Create an array to host the size of the dimensions - const int rank = m_dataspace.getSimpleExtentNdims(); - // We allocate dims in the stack for efficiecy and safety but we need an error check just in case then - if (rank>m_max_dataset_dims) - error("Dataset dimensions ("+ std::to_string(rank) + ") bigger than maximum of" + std::to_string(m_max_dataset_dims) + ". This is unexpected, Aborting."); - hsize_t dims[m_max_dataset_dims]; - // Read size of dimensions - m_dataspace.getSimpleExtentDims( dims, NULL); - - m_NX_SUB = dims[0]; // hyperslab dimensions - m_NY_SUB = dims[1]; - m_NZ_SUB = (rank==2)? 1 : dims[2]; // Signa has rank==2, but this stay shere just in case... - - - unsigned int num_time_slices = 0; - H5::DataSet timeframe_dataspace = file.openDataSet("/HeaderData/SinglesHeader/numValidSamples"); - timeframe_dataspace.read(&num_time_slices, H5::PredType::NATIVE_UINT32); - if(num_time_slices==0) - { - error("Zero number of valid samples singles samples in data. Aborting"); - } + // Create an array to host the size of the dimensions + const int rank = m_dataspace.getSimpleExtentNdims(); + // We allocate dims in the stack for efficiecy and safety but we need an error check just in case then + if (rank > m_max_dataset_dims) + error("Dataset dimensions (" + std::to_string(rank) + ") bigger than maximum of" + std::to_string(m_max_dataset_dims) + + ". This is unexpected, Aborting."); + hsize_t dims[m_max_dataset_dims]; + // Read size of dimensions + m_dataspace.getSimpleExtentDims(dims, NULL); + + m_NX_SUB = dims[0]; // hyperslab dimensions + m_NY_SUB = dims[1]; + m_NZ_SUB = (rank == 2) ? 1 : dims[2]; // Signa has rank==2, but this stay shere just in case... + + unsigned int num_time_slices = 0; + H5::DataSet timeframe_dataspace = file.openDataSet("/HeaderData/SinglesHeader/numValidSamples"); + timeframe_dataspace.read(&num_time_slices, H5::PredType::NATIVE_UINT32); + if (num_time_slices == 0) { + error("Zero number of valid samples singles samples in data. Aborting"); + } - m_num_singles_samples=num_time_slices; + m_num_singles_samples = num_time_slices; #if 0 m_NX = dims[0]; // output buffer dimensions m_NY = dims[1]; m_NZ = (rank==2)? 1 : dims[2]; #endif - } - else - return Succeeded::no; + } else + return Succeeded::no; - return Succeeded::yes; + return Succeeded::yes; } -Succeeded GEHDF5Wrapper::initialise_proj_data(const unsigned int view_num) -{ - if(!is_sino_file()) - error("The file provided is not sinogram data. Aborting"); +Succeeded +GEHDF5Wrapper::initialise_proj_data(const unsigned int view_num) { + if (!is_sino_file()) + error("The file provided is not sinogram data. Aborting"); - if(view_num == 0 || view_num > static_cast(this->get_scanner_sptr()->get_num_detectors_per_ring()/2)) - error("internal error in GE HDF5 code: view number "+ std::to_string(view_num) +" is incorrect"); + if (view_num == 0 || view_num > static_cast(this->get_scanner_sptr()->get_num_detectors_per_ring() / 2)) + error("internal error in GE HDF5 code: view number " + std::to_string(view_num) + " is incorrect"); - if(rdf_ver==9) - { - m_address = "/SegmentData/Segment2/3D_TOF_Sinogram/view" + std::to_string(view_num); - - m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address))); - m_dataspace = m_dataset_sptr->getSpace(); - // Create an array to host the size of the dimensions - const int rank = m_dataspace.getSimpleExtentNdims(); - // We allocate dims in the stack for efficiecy and safety but we need an error check just in case then - if (rank>m_max_dataset_dims) - error("Dataset dimensions ("+ std::to_string(rank) + ") bigger than maximum of" + std::to_string(m_max_dataset_dims) + ". This is unexpected, Aborting."); - hsize_t dims[m_max_dataset_dims]; - // Read size of dimensions - m_dataspace.getSimpleExtentDims( dims, NULL); - - // AB for signa, these where [1981,27,357] and [45,448,357] - m_NX_SUB = dims[0] ; // hyperslab dimensions - m_NY_SUB = dims[1]; - m_NZ_SUB = dims[2]; + if (rdf_ver == 9) { + m_address = "/SegmentData/Segment2/3D_TOF_Sinogram/view" + std::to_string(view_num); + + m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address))); + m_dataspace = m_dataset_sptr->getSpace(); + // Create an array to host the size of the dimensions + const int rank = m_dataspace.getSimpleExtentNdims(); + // We allocate dims in the stack for efficiecy and safety but we need an error check just in case then + if (rank > m_max_dataset_dims) + error("Dataset dimensions (" + std::to_string(rank) + ") bigger than maximum of" + std::to_string(m_max_dataset_dims) + + ". This is unexpected, Aborting."); + hsize_t dims[m_max_dataset_dims]; + // Read size of dimensions + m_dataspace.getSimpleExtentDims(dims, NULL); + + // AB for signa, these where [1981,27,357] and [45,448,357] + m_NX_SUB = dims[0]; // hyperslab dimensions + m_NY_SUB = dims[1]; + m_NZ_SUB = dims[2]; #if 0 // AB todo: ??? why are these different? m_NX = 45; // output buffer dimensions m_NY = 448; m_NZ = 357; #endif - } - else - return Succeeded::no; + } else + return Succeeded::no; - return Succeeded::yes; + return Succeeded::yes; } // PW The geo factors are stored in geo3d file under the file path called /SegmentData/Segment4/3D_Norm_correction/slice%d where // slice numbers go from 1 to 16. Here this path is initialised, along with the output buffer and hyperslab. // -Succeeded GEHDF5Wrapper::initialise_geo_factors_data(const unsigned int slice_num) -{ - if(!is_geo_file()) - error("The file provided is not geometry data. Aborting"); +Succeeded +GEHDF5Wrapper::initialise_geo_factors_data(const unsigned int slice_num) { + if (!is_geo_file()) + error("The file provided is not geometry data. Aborting"); - if(slice_num == 0) - error("internal error in GE HDF5 geo code: slice number "+ std::to_string(slice_num) +" is incorrect"); + if (slice_num == 0) + error("internal error in GE HDF5 geo code: slice number " + std::to_string(slice_num) + " is incorrect"); - if(rdf_ver==9) + if (rdf_ver == 9) { + m_address = "/SegmentData/Segment4/3D_Norm_Correction/slice"; { - m_address = "/SegmentData/Segment4/3D_Norm_Correction/slice"; - { - // Open Dataset and get Dataspace(metadata) - m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address + std::to_string(slice_num)))); - m_dataspace = m_dataset_sptr->getSpace(); - - // Read dimensions - const int rank = m_dataspace.getSimpleExtentNdims(); - // We allocate dims in the stack for efficiecy and safety but we need an error check just in case then - if (rank>m_max_dataset_dims) - error("Dataset dimensions ("+ std::to_string(rank) + ") bigger than maximum of" + std::to_string(m_max_dataset_dims) + ". This is unexpected, Aborting."); - hsize_t dims[m_max_dataset_dims]; - - m_dataspace.getSimpleExtentDims( dims, NULL); - - m_NX_SUB = dims[0]; // hyperslab dimensions - m_NY_SUB = dims[1]; - m_NZ_SUB = (rank==2)? 1 : dims[2]; // Signa has rank==2, but this stay shere just in case... + // Open Dataset and get Dataspace(metadata) + m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address + std::to_string(slice_num)))); + m_dataspace = m_dataset_sptr->getSpace(); + + // Read dimensions + const int rank = m_dataspace.getSimpleExtentNdims(); + // We allocate dims in the stack for efficiecy and safety but we need an error check just in case then + if (rank > m_max_dataset_dims) + error("Dataset dimensions (" + std::to_string(rank) + ") bigger than maximum of" + std::to_string(m_max_dataset_dims) + + ". This is unexpected, Aborting."); + hsize_t dims[m_max_dataset_dims]; + + m_dataspace.getSimpleExtentDims(dims, NULL); + + m_NX_SUB = dims[0]; // hyperslab dimensions + m_NY_SUB = dims[1]; + m_NZ_SUB = (rank == 2) ? 1 : dims[2]; // Signa has rank==2, but this stay shere just in case... #if 0 m_NX = dims[0]; // output buffer dimensions m_NY = dims[1]; m_NZ = (rank==2)? 1 : dims[2]; // Signa has rank==2, but this stay shere just in case... #endif - } } - else - return Succeeded::no; + } else + return Succeeded::no; - return Succeeded::yes; + return Succeeded::yes; } // This info is in norm3d file -Succeeded GEHDF5Wrapper::initialise_efficiency_factors() -{ - if(!is_norm_file()) - error("The file provided is not norm data. Aborting"); +Succeeded +GEHDF5Wrapper::initialise_efficiency_factors() { + if (!is_norm_file()) + error("The file provided is not norm data. Aborting"); - if(rdf_ver==9) - { - - m_address = "/3DCrystalEfficiency/crystalEfficiency"; - // Get the DataSpace (metadata) corresponding to the DataSet that we want to read - m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address))); - m_dataspace = m_dataset_sptr->getSpace(); - // Create an array to host the size of the dimensions - const int rank = m_dataspace.getSimpleExtentNdims(); - // We allocate dims in the stack for efficiecy and safety but we need an error check just in case then - if (rank>m_max_dataset_dims) - error("Dataset dimensions ("+ std::to_string(rank) + ") bigger than maximum of" + std::to_string(m_max_dataset_dims) + ". This is unexpected, Aborting."); - hsize_t dims[m_max_dataset_dims]; - // Read size of dimensions - m_dataspace.getSimpleExtentDims( dims, NULL); - - - m_NX_SUB = dims[0]; // hyperslab dimensions - // TODO: Why is this divided by 2?? - m_NY_SUB = dims[1]/2; // should be equal to scanner_sptr->get_num_detectors_per_ring(); - m_NZ_SUB = (rank==2)? 1 : dims[2]; + if (rdf_ver == 9) { + + m_address = "/3DCrystalEfficiency/crystalEfficiency"; + // Get the DataSpace (metadata) corresponding to the DataSet that we want to read + m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address))); + m_dataspace = m_dataset_sptr->getSpace(); + // Create an array to host the size of the dimensions + const int rank = m_dataspace.getSimpleExtentNdims(); + // We allocate dims in the stack for efficiecy and safety but we need an error check just in case then + if (rank > m_max_dataset_dims) + error("Dataset dimensions (" + std::to_string(rank) + ") bigger than maximum of" + std::to_string(m_max_dataset_dims) + + ". This is unexpected, Aborting."); + hsize_t dims[m_max_dataset_dims]; + // Read size of dimensions + m_dataspace.getSimpleExtentDims(dims, NULL); + + m_NX_SUB = dims[0]; // hyperslab dimensions + // TODO: Why is this divided by 2?? + m_NY_SUB = dims[1] / 2; // should be equal to scanner_sptr->get_num_detectors_per_ring(); + m_NZ_SUB = (rank == 2) ? 1 : dims[2]; #if 0 m_NX = dims[0]; // output buffer dimensions m_NY = dims[1]/2; // should be equal to scanner_sptr->get_num_detectors_per_ring(); m_NZ = (rank==2)? 1 : dims[2]; #endif - } - else - return Succeeded::no; - + } else + return Succeeded::no; - return Succeeded::yes; + return Succeeded::yes; } -float GEHDF5Wrapper::get_coincidence_time_window() const -{ - if(!is_list_file() && !is_sino_file()) - error("The file provided is not list or sino data. Aborting"); +float +GEHDF5Wrapper::get_coincidence_time_window() const { + if (!is_list_file() && !is_sino_file()) + error("The file provided is not list or sino data. Aborting"); - H5::DataSet ds_coincTimingPrecision = file.openDataSet("/HeaderData/AcqParameters/EDCATParameters/coincTimingPrecision"); - H5::DataSet ds_posCoincidenceWindow = file.openDataSet("/HeaderData/AcqParameters/EDCATParameters/posCoincidenceWindow"); - float coincTimingPrecision = 0; - int posCoincidenceWindow = 0; - ds_coincTimingPrecision.read(&coincTimingPrecision,H5::PredType::NATIVE_FLOAT); - ds_posCoincidenceWindow.read(&posCoincidenceWindow,H5::PredType::NATIVE_INT32); + H5::DataSet ds_coincTimingPrecision = file.openDataSet("/HeaderData/AcqParameters/EDCATParameters/coincTimingPrecision"); + H5::DataSet ds_posCoincidenceWindow = file.openDataSet("/HeaderData/AcqParameters/EDCATParameters/posCoincidenceWindow"); + float coincTimingPrecision = 0; + int posCoincidenceWindow = 0; + ds_coincTimingPrecision.read(&coincTimingPrecision, H5::PredType::NATIVE_FLOAT); + ds_posCoincidenceWindow.read(&posCoincidenceWindow, H5::PredType::NATIVE_INT32); - return (2*posCoincidenceWindow+1) *coincTimingPrecision*1e-9; + return (2 * posCoincidenceWindow + 1) * coincTimingPrecision * 1e-9; } - // Developed for listmode access -Succeeded GEHDF5Wrapper::read_list_data( char* output,std::streampos& current_offset, const hsize_t size) const -{ - if(!is_list_file()) - error("The file provided is not list data. Aborting"); - hsize_t pos = static_cast(current_offset); - m_dataspace.selectHyperslab( H5S_SELECT_SET, &size, &pos ); - m_dataset_sptr->read( output, H5::PredType::STD_U8LE, *m_memspace_ptr, m_dataspace ); - current_offset += static_cast(size); - - return Succeeded::yes; +Succeeded +GEHDF5Wrapper::read_list_data(char* output, std::streampos& current_offset, const hsize_t size) const { + if (!is_list_file()) + error("The file provided is not list data. Aborting"); + hsize_t pos = static_cast(current_offset); + m_dataspace.selectHyperslab(H5S_SELECT_SET, &size, &pos); + m_dataset_sptr->read(output, H5::PredType::STD_U8LE, *m_memspace_ptr, m_dataspace); + current_offset += static_cast(size); + + return Succeeded::yes; } // Developed for ProjData -Succeeded GEHDF5Wrapper::read_sinogram(Array<3, unsigned char> &output, - const std::array& offset, - const std::array& stride) -{ - // AB: this is only used for proj data, so for now lets ensure the file is sino. If its reused, we can change this. - if(!is_sino_file()) - error("File is not sinogram. Aborting"); - - if(offset[0] != 0 || offset[1] != 0 || offset[2] != 0) //AB there are other C++ ways of doing this, but this is the most readable really. - error("Only {0,0,0} offset supported. Aborting"); - if(stride[0] != 1 || stride[1] != 1 || stride[2] != 1) - error("Only {1,1,1} stride supported. Aborting"); - - // We know the size of the DataSpace - hsize_t str_dimsf[3] {m_NX_SUB, m_NY_SUB, m_NZ_SUB} ; - - - // get a temporary buffer here, - std::vector aux_buffer(m_NX_SUB*m_NY_SUB*m_NZ_SUB); - - m_dataspace.selectHyperslab(H5S_SELECT_SET, str_dimsf, offset.data()); - m_memspace_ptr= new H5::DataSpace(3, str_dimsf); - m_dataset_sptr->read(static_cast(aux_buffer.data()), H5::PredType::STD_U8LE, *m_memspace_ptr, m_dataspace); - - // the data is not in the correct size if its RDF9, so we will need to transpose the output of the data read. - if(rdf_ver==9) - { - output.resize(IndexRange3D(m_NZ_SUB,m_NY_SUB,m_NX_SUB)); - // now transpose the output. - // AB: todo - // todo 1: test - for(unsigned int i=0;i& output, const std::array& offset, + const std::array& stride) { + // AB: this is only used for proj data, so for now lets ensure the file is sino. If its reused, we can change this. + if (!is_sino_file()) + error("File is not sinogram. Aborting"); + + if (offset[0] != 0 || offset[1] != 0 || + offset[2] != 0) // AB there are other C++ ways of doing this, but this is the most readable really. + error("Only {0,0,0} offset supported. Aborting"); + if (stride[0] != 1 || stride[1] != 1 || stride[2] != 1) + error("Only {1,1,1} stride supported. Aborting"); + + // We know the size of the DataSpace + hsize_t str_dimsf[3]{m_NX_SUB, m_NY_SUB, m_NZ_SUB}; + + // get a temporary buffer here, + std::vector aux_buffer(m_NX_SUB * m_NY_SUB * m_NZ_SUB); + + m_dataspace.selectHyperslab(H5S_SELECT_SET, str_dimsf, offset.data()); + m_memspace_ptr = new H5::DataSpace(3, str_dimsf); + m_dataset_sptr->read(static_cast(aux_buffer.data()), H5::PredType::STD_U8LE, *m_memspace_ptr, m_dataspace); + + // the data is not in the correct size if its RDF9, so we will need to transpose the output of the data read. + if (rdf_ver == 9) { + output.resize(IndexRange3D(m_NZ_SUB, m_NY_SUB, m_NX_SUB)); + // now transpose the output. + // AB: todo + // todo 1: test + for (unsigned int i = 0; i < m_NZ_SUB; ++i) { + unsigned int ioffset = i * m_NX_SUB * m_NY_SUB; + for (unsigned int j = 0; j < m_NY_SUB; ++j) { + unsigned int joffset = j * m_NX_SUB; + for (unsigned int k = 0; k < m_NX_SUB; ++k) { + output[i][j][k] = aux_buffer[ioffset + joffset + k]; } - output.release_data_ptr(); + } } - + output.release_data_ptr(); + } - return Succeeded::yes; + return Succeeded::yes; } +// PW Developed for Geometric Correction Factors +Succeeded +GEHDF5Wrapper::read_geometric_factors(Array<1, unsigned int>& output, const std::array& offset, + const std::array& count, const std::array& stride) -//PW Developed for Geometric Correction Factors -Succeeded GEHDF5Wrapper::read_geometric_factors(Array<1, unsigned int> &output, - const std::array& offset, - const std::array& count, - const std::array& stride) - { - // AB: this is only used for geo data, so for now lets ensure the file is sino. If its reused, we can change this. - if(!is_geo_file()) - error("File is Geometry. Aborting"); - - if(count[0] == 0 || count[1] == 0) //AB there are other C++ ways of doing this, but this is the most readable really. - error("Requested zero data to read. Aborting"); - if(stride[0] != 1 || stride[1] != 1) - error("Only {1,1} stride supported. Aborting"); - - Array<1, unsigned int> aux_reader; - output.resize(count[0]*count[1]); - aux_reader.resize(count[0]*count[1]); - - m_dataspace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data()); - m_memspace_ptr= new H5::DataSpace(2, count.data()); - m_dataset_sptr->read(aux_reader.get_data_ptr(), H5::PredType::NATIVE_UINT32, *m_memspace_ptr, m_dataspace); - aux_reader.release_data_ptr(); - - // GE/RDF9 stores the tangetial axis reversed to STIR. Flip. - for(unsigned int ax=0;ax aux_reader; + output.resize(count[0] * count[1]); + aux_reader.resize(count[0] * count[1]); + + m_dataspace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data()); + m_memspace_ptr = new H5::DataSpace(2, count.data()); + m_dataset_sptr->read(aux_reader.get_data_ptr(), H5::PredType::NATIVE_UINT32, *m_memspace_ptr, m_dataspace); + aux_reader.release_data_ptr(); + + // GE/RDF9 stores the tangetial axis reversed to STIR. Flip. + for (unsigned int ax = 0; ax < count[0]; ++ax) + for (unsigned int tan = 0; tan < count[1]; ++tan) + output[ax * count[1] + ((count[1] - 1) - tan)] = aux_reader[ax * count[1] + tan]; + return Succeeded::yes; } -//PW Developed for Efficiency Factors -Succeeded GEHDF5Wrapper::read_efficiency_factors(Array<1, float> &output, - const std::array& offset, - const std::array& stride) - -{ - if(!is_norm_file()) - error("The file provided is not norm data. Aborting"); - - if(offset[0] != 0 || offset[1] != 0) //AB there are other C++ ways of doing this, but this is the most readable really. - error("Only {0,0} offset supported. Aborting"); - if(stride[0] != 1 || stride[1] != 1) - error("Only {1,1} stride supported. Aborting"); - - // We know the size of the DataSpace - hsize_t str_dimsf[2] {m_NX_SUB, m_NY_SUB} ; - Array<1, float> aux_reader; - output.resize(m_NX_SUB*m_NY_SUB); - aux_reader.resize(m_NX_SUB*m_NY_SUB); - - m_dataspace.selectHyperslab(H5S_SELECT_SET, str_dimsf, offset.data()); - m_memspace_ptr= new H5::DataSpace(2, str_dimsf); - m_dataset_sptr->read(aux_reader.get_data_ptr(), H5::PredType::NATIVE_FLOAT, *m_memspace_ptr, m_dataspace); - aux_reader.release_data_ptr(); - - // GE/RDF9 stores the tangetial axis reversed to STIR. Flip. - for(unsigned int ax=0;ax& output, const std::array& offset, + const std::array& stride) - return Succeeded::yes; +{ + if (!is_norm_file()) + error("The file provided is not norm data. Aborting"); + + if (offset[0] != 0 || offset[1] != 0) // AB there are other C++ ways of doing this, but this is the most readable really. + error("Only {0,0} offset supported. Aborting"); + if (stride[0] != 1 || stride[1] != 1) + error("Only {1,1} stride supported. Aborting"); + + // We know the size of the DataSpace + hsize_t str_dimsf[2]{m_NX_SUB, m_NY_SUB}; + Array<1, float> aux_reader; + output.resize(m_NX_SUB * m_NY_SUB); + aux_reader.resize(m_NX_SUB * m_NY_SUB); + + m_dataspace.selectHyperslab(H5S_SELECT_SET, str_dimsf, offset.data()); + m_memspace_ptr = new H5::DataSpace(2, str_dimsf); + m_dataset_sptr->read(aux_reader.get_data_ptr(), H5::PredType::NATIVE_FLOAT, *m_memspace_ptr, m_dataspace); + aux_reader.release_data_ptr(); + + // GE/RDF9 stores the tangetial axis reversed to STIR. Flip. + for (unsigned int ax = 0; ax < m_NX_SUB; ++ax) + for (unsigned int tan = 0; tan < m_NY_SUB; ++tan) + output[ax * m_NY_SUB + ((m_NY_SUB - 1) - tan)] = aux_reader[ax * m_NY_SUB + tan]; + + return Succeeded::yes; } // Developed for Singles -Succeeded GEHDF5Wrapper::read_singles(Array<1, unsigned int>& output, const unsigned int current_id) -{ - BOOST_STATIC_ASSERT(sizeof(unsigned int)==4); // Compilation time assert. - if(!is_list_file()&& !is_sino_file()) - error("The file provided is not listmode or sinogram data. Aborting"); +Succeeded +GEHDF5Wrapper::read_singles(Array<1, unsigned int>& output, const unsigned int current_id) { + BOOST_STATIC_ASSERT(sizeof(unsigned int) == 4); // Compilation time assert. + if (!is_list_file() && !is_sino_file()) + error("The file provided is not listmode or sinogram data. Aborting"); - if(current_id == 0 || current_id > this->m_num_singles_samples) - error("internal error in GE HDF5 code: singles slice_id "+ std::to_string(current_id) +" is incorrect"); + if (current_id == 0 || current_id > this->m_num_singles_samples) + error("internal error in GE HDF5 code: singles slice_id " + std::to_string(current_id) + " is incorrect"); - Array<1, unsigned int> aux_reader; - output.resize(m_NX_SUB*m_NY_SUB); - aux_reader.resize(m_NX_SUB*m_NY_SUB); + Array<1, unsigned int> aux_reader; + output.resize(m_NX_SUB * m_NY_SUB); + aux_reader.resize(m_NX_SUB * m_NY_SUB); - // AB: todo check if output allocated data size is correct. - m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address + std::to_string(current_id)))); - m_dataset_sptr->read(aux_reader.get_data_ptr(), H5::PredType::NATIVE_UINT32); - aux_reader.release_data_ptr(); + // AB: todo check if output allocated data size is correct. + m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address + std::to_string(current_id)))); + m_dataset_sptr->read(aux_reader.get_data_ptr(), H5::PredType::NATIVE_UINT32); + aux_reader.release_data_ptr(); - // GE/RDF9 stores the tangetial axis reversed to STIR. Flip. - for(unsigned int ax=0;axm_image_type=data_type_case; - this->MaxLength=num_voxels; - if(this->m_image_type == 64) - { - vData_f = new float[this->MaxLength]; - for (int i = 0; i < this->MaxLength; i++) - this->vData_f[i] = 0.F; - vData = NULL; - } - else if(this->m_image_type == 15) - { - vData = new short[this->MaxLength]; - for (int i = 0; i < this->MaxLength; i++) - this->vData[i] = 0; - vData_f = NULL; - } - else - { - vData = NULL; - vData_f = NULL; - } - vDownsample[0] = 1; - vDownsample[1] = 1; - vDownsample[2] = 1; - - vCenter[0] = 0; - vCenter[1] = 0; - vCenter[2] = 0; - vCenter[3] = 0; +Image::Image(const int num_voxels, const short data_type_case) { + this->m_image_type = data_type_case; + this->MaxLength = num_voxels; + if (this->m_image_type == 64) { + vData_f = new float[this->MaxLength]; + for (int i = 0; i < this->MaxLength; i++) + this->vData_f[i] = 0.F; + vData = NULL; + } else if (this->m_image_type == 15) { + vData = new short[this->MaxLength]; + for (int i = 0; i < this->MaxLength; i++) + this->vData[i] = 0; + vData_f = NULL; + } else { + vData = NULL; + vData_f = NULL; + } + vDownsample[0] = 1; + vDownsample[1] = 1; + vDownsample[2] = 1; + + vCenter[0] = 0; + vCenter[1] = 0; + vCenter[2] = 0; + vCenter[3] = 0; } // ------------------------------------------------------------------------- // Destructor // ------------------------------------------------------------------------- -Image::~Image() -{ - if (vData) - delete[] vData; - if (vData_f) - delete[] vData_f; +Image::~Image() { + if (vData) + delete[] vData; + if (vData_f) + delete[] vData_f; } // ------------------------------------------------------------------------- @@ -129,547 +121,532 @@ Image::~Image() // ------------------------------------------------------------------------- /** -* \brief Read data from GIPL filename. -* -* \param filename Input filename -*/ + * \brief Read data from GIPL filename. + * + * \param filename Input filename + */ // ------------------------------------------------------------------------- -void Image::GiplRead(char* filename) -{ - printf("Read %s\n",filename); - - // Open input binary file - std::fstream myFile(filename, std::ios_base::in | std::ios_base::binary); - - // Initialize image dimensions by zero - m_dim[0] = 0; - m_dim[1] = 0; - m_dim[2] = 0; - - // open file for reading - /*char *buf; - try { - buf = new char[512]; - if( buf == 0 ) - throw "Memory allocation failure!"; - } - catch( char * str ) { - cout << "Exception raised: " << str << '\n'; - }*/ - - // Read gipl header - ReadGiplHeader(&myFile); - - // Require big endian format - ByteSwapHeader(); - - // Length of the data to be read in - MaxLength = m_dim[0]*m_dim[1]*m_dim[2]; - - // File cannot be read, wrong path or filename - if (MaxLength == 0) - { - printf("Error: File %s cannot be found\n",filename); - exit(1); - } - - // Update image dimension - ImageDimension = 2; - if(m_dim[2]>1) ImageDimension = 3; - - // Update parameters dimension - ParametersDimension = ImageDimension*ImageDimension+ImageDimension; - - // Set offset vector - ImageOffset[0] = m_dim[0]; // XLen - ImageOffset[1] = m_dim[0]*m_dim[1]; // XLen*YLen - - // Set center of rotation of the image - for (int i = 0; i < ImageDimension; i++) - vCenter[i] = 0;//m_dim[i]/2.0*m_pixdim[i] - m_origin[i]; - - // Delete possible old data vectors - if (vData) - delete[] vData; - if (vData_f) - delete[] vData_f; - - - - // Check data type - switch(m_image_type) - { - case 15: // shorts (default) - - // Initialize image vector - vData = new short[MaxLength]; - - // Read image data - myFile.read((char*)vData, sizeof(short)*MaxLength); - - // Swap hi lo bytes - for( int i = 0; i < MaxLength; i++) - ByteSwap(&vData[i]); - - // Get min and max gray value - GetMinMaxValue(); - - break; - - case 64: // floats - - // Initialize image vector - vData_f = new float[MaxLength]; - - // Read image data - myFile.read((char*)vData_f, sizeof(float)*MaxLength); - - // Swap hi lo bytes - for( int i = 0; i < MaxLength; i++) - ByteSwap(&vData_f[i]); - - break; - - default: - break; - } - - //int SourceIndex = ((int)(5 + 10*ImageOffset[0] + 20*ImageOffset[1])); - //float test = vData_f[SourceIndex]; - - // Initially no downscaling - vDownsample[0] = 1; - vDownsample[1] = 1; - vDownsample[2] = 1; - - // Close file - myFile.close(); +void +Image::GiplRead(char* filename) { + printf("Read %s\n", filename); + + // Open input binary file + std::fstream myFile(filename, std::ios_base::in | std::ios_base::binary); + + // Initialize image dimensions by zero + m_dim[0] = 0; + m_dim[1] = 0; + m_dim[2] = 0; + + // open file for reading + /*char *buf; +try { +buf = new char[512]; +if( buf == 0 ) + throw "Memory allocation failure!"; +} +catch( char * str ) { +cout << "Exception raised: " << str << '\n'; +}*/ + + // Read gipl header + ReadGiplHeader(&myFile); + + // Require big endian format + ByteSwapHeader(); + + // Length of the data to be read in + MaxLength = m_dim[0] * m_dim[1] * m_dim[2]; + + // File cannot be read, wrong path or filename + if (MaxLength == 0) { + printf("Error: File %s cannot be found\n", filename); + exit(1); + } + + // Update image dimension + ImageDimension = 2; + if (m_dim[2] > 1) + ImageDimension = 3; + + // Update parameters dimension + ParametersDimension = ImageDimension * ImageDimension + ImageDimension; + + // Set offset vector + ImageOffset[0] = m_dim[0]; // XLen + ImageOffset[1] = m_dim[0] * m_dim[1]; // XLen*YLen + + // Set center of rotation of the image + for (int i = 0; i < ImageDimension; i++) + vCenter[i] = 0; // m_dim[i]/2.0*m_pixdim[i] - m_origin[i]; + + // Delete possible old data vectors + if (vData) + delete[] vData; + if (vData_f) + delete[] vData_f; + + // Check data type + switch (m_image_type) { + case 15: // shorts (default) + + // Initialize image vector + vData = new short[MaxLength]; + + // Read image data + myFile.read((char*)vData, sizeof(short) * MaxLength); + + // Swap hi lo bytes + for (int i = 0; i < MaxLength; i++) + ByteSwap(&vData[i]); + + // Get min and max gray value + GetMinMaxValue(); + + break; + + case 64: // floats + + // Initialize image vector + vData_f = new float[MaxLength]; + + // Read image data + myFile.read((char*)vData_f, sizeof(float) * MaxLength); + + // Swap hi lo bytes + for (int i = 0; i < MaxLength; i++) + ByteSwap(&vData_f[i]); + + break; + + default: + break; + } + + // int SourceIndex = ((int)(5 + 10*ImageOffset[0] + 20*ImageOffset[1])); + // float test = vData_f[SourceIndex]; + + // Initially no downscaling + vDownsample[0] = 1; + vDownsample[1] = 1; + vDownsample[2] = 1; + + // Close file + myFile.close(); } // ------------------------------------------------------------------------- /** -* \brief Get minimum and maximum gray values in image. -*/ + * \brief Get minimum and maximum gray values in image. + */ // ------------------------------------------------------------------------- -void Image::GetMinMaxValue() -{ - iMax = -16959; - iMin = +16959; - - // Check data type - if(m_image_type == 15) - { - for( int i = 0; i < MaxLength; i++) - { - if (vData[i] > iMax) - iMax = vData[i]; - if (vData[i] < iMin) - iMin = vData[i]; - } - } - if(m_image_type == 64) - { - for( int i = 0; i < MaxLength; i++) - { - if (vData_f[i] > iMax) - iMax = vData_f[i]; - if (vData_f[i] < iMin) - iMin = vData_f[i]; - } - } +void +Image::GetMinMaxValue() { + iMax = -16959; + iMin = +16959; + + // Check data type + if (m_image_type == 15) { + for (int i = 0; i < MaxLength; i++) { + if (vData[i] > iMax) + iMax = vData[i]; + if (vData[i] < iMin) + iMin = vData[i]; + } + } + if (m_image_type == 64) { + for (int i = 0; i < MaxLength; i++) { + if (vData_f[i] > iMax) + iMax = vData_f[i]; + if (vData_f[i] < iMin) + iMin = vData_f[i]; + } + } } // ------------------------------------------------------------------------- /** -* \brief Read GIPL header. -* -* \param myfile Input file -*/ + * \brief Read GIPL header. + * + * \param myfile Input file + */ // ------------------------------------------------------------------------- -void Image::ReadGiplHeader(std::fstream* myFile) -{ - int i; - for(i=0;i<4;i++) - myFile->read(reinterpret_cast < char * > (&m_dim[i]), sizeof(m_dim[i])); - myFile->read(reinterpret_cast < char * > (&m_image_type), sizeof(m_image_type)); - for(i=0;i<4;i++) - myFile->read(reinterpret_cast < char * > (&m_pixdim[i]), sizeof(m_pixdim[i])); - for(i=0;i<80;i++) - myFile->read(reinterpret_cast < char * > (&m_patDesc[i]), sizeof(m_patDesc[i])); - for(i=0;i<12;i++) - myFile->read(reinterpret_cast < char * > (&m_matrixElements[i]), sizeof(m_matrixElements[i])); - myFile->read(reinterpret_cast < char * > (&m_identifier), sizeof(m_identifier)); - for(i=0;i<28;i++) - myFile->read(reinterpret_cast < char * > (&m_spare[i]), sizeof(m_spare[i])); - myFile->read(reinterpret_cast < char * > (&m_orientationFlag), sizeof(m_orientationFlag)); - myFile->read(reinterpret_cast < char * > (&m_flag1), sizeof(m_flag1)); - myFile->read(reinterpret_cast < char * > (&m_min), sizeof(m_min)); - myFile->read(reinterpret_cast < char * > (&m_max), sizeof(m_max)); - for(i=0;i<4;i++) - myFile->read(reinterpret_cast < char * > (&m_origin[i]), sizeof(m_origin[i])); - myFile->read(reinterpret_cast < char * > (&m_pixval_offset), sizeof(m_pixval_offset)); - myFile->read(reinterpret_cast < char * > (&m_pixval_cal), sizeof(m_pixval_cal)); - myFile->read(reinterpret_cast < char * > (&m_user_def1), sizeof(m_user_def1)); - myFile->read(reinterpret_cast < char * > (&m_user_def2), sizeof(m_user_def2)); - myFile->read(reinterpret_cast < char * > (&m_magic_number), sizeof(m_magic_number)); - +void +Image::ReadGiplHeader(std::fstream* myFile) { + int i; + for (i = 0; i < 4; i++) + myFile->read(reinterpret_cast(&m_dim[i]), sizeof(m_dim[i])); + myFile->read(reinterpret_cast(&m_image_type), sizeof(m_image_type)); + for (i = 0; i < 4; i++) + myFile->read(reinterpret_cast(&m_pixdim[i]), sizeof(m_pixdim[i])); + for (i = 0; i < 80; i++) + myFile->read(reinterpret_cast(&m_patDesc[i]), sizeof(m_patDesc[i])); + for (i = 0; i < 12; i++) + myFile->read(reinterpret_cast(&m_matrixElements[i]), sizeof(m_matrixElements[i])); + myFile->read(reinterpret_cast(&m_identifier), sizeof(m_identifier)); + for (i = 0; i < 28; i++) + myFile->read(reinterpret_cast(&m_spare[i]), sizeof(m_spare[i])); + myFile->read(reinterpret_cast(&m_orientationFlag), sizeof(m_orientationFlag)); + myFile->read(reinterpret_cast(&m_flag1), sizeof(m_flag1)); + myFile->read(reinterpret_cast(&m_min), sizeof(m_min)); + myFile->read(reinterpret_cast(&m_max), sizeof(m_max)); + for (i = 0; i < 4; i++) + myFile->read(reinterpret_cast(&m_origin[i]), sizeof(m_origin[i])); + myFile->read(reinterpret_cast(&m_pixval_offset), sizeof(m_pixval_offset)); + myFile->read(reinterpret_cast(&m_pixval_cal), sizeof(m_pixval_cal)); + myFile->read(reinterpret_cast(&m_user_def1), sizeof(m_user_def1)); + myFile->read(reinterpret_cast(&m_user_def2), sizeof(m_user_def2)); + myFile->read(reinterpret_cast(&m_magic_number), sizeof(m_magic_number)); } // ------------------------------------------------------------------------- /** -* \brief Write image data to GIPL output file. -* -* \param filename Output filename -*/ + * \brief Write image data to GIPL output file. + * + * \param filename Output filename + */ // ------------------------------------------------------------------------- -void Image::GiplWrite(const char* filename) -{ - // Open file for writing - std::fstream myFile(filename, std::ios_base::out | std::ios_base::binary); - - // Require big endian format - ByteSwapHeader(); - - // Write gipl header - WriteGiplHeader(&myFile); - - // Go back to correct format - ByteSwapHeader(); - - // Check data type - switch(m_image_type) - { - case 15: // shorts (default) - - // Swap bytes of data vector before writing to file - for( int i = 0; i < MaxLength; i++) - ByteSwap(&vData[i]); - - // Read image data - myFile.write((char*)vData, sizeof(short)*MaxLength); - - // Swap hi lo bytes - for( int i = 0; i < MaxLength; i++) - ByteSwap(&vData[i]); - break; - - // Swap bytes back - for(int i = 0; i < MaxLength; i++) - ByteSwap(&vData[i]); - - case 64: // floats - - // Swap bytes of data vector before writing to file - for( int i = 0; i < MaxLength; i++) - ByteSwap(&vData_f[i]); - - // Read image data - myFile.write((char*)vData_f, sizeof(float)*MaxLength); - - // Swap hi lo bytes - for( int i = 0; i < MaxLength; i++) - ByteSwap(&vData_f[i]); - break; - - // Swap bytes back - for(int i = 0; i < MaxLength; i++) - ByteSwap(&vData_f[i]); - - default: - break; - } - - // Close file - myFile.close(); +void +Image::GiplWrite(const char* filename) { + // Open file for writing + std::fstream myFile(filename, std::ios_base::out | std::ios_base::binary); + + // Require big endian format + ByteSwapHeader(); + + // Write gipl header + WriteGiplHeader(&myFile); + + // Go back to correct format + ByteSwapHeader(); + + // Check data type + switch (m_image_type) { + case 15: // shorts (default) + + // Swap bytes of data vector before writing to file + for (int i = 0; i < MaxLength; i++) + ByteSwap(&vData[i]); + + // Read image data + myFile.write((char*)vData, sizeof(short) * MaxLength); + + // Swap hi lo bytes + for (int i = 0; i < MaxLength; i++) + ByteSwap(&vData[i]); + break; + + // Swap bytes back + for (int i = 0; i < MaxLength; i++) + ByteSwap(&vData[i]); + + case 64: // floats + + // Swap bytes of data vector before writing to file + for (int i = 0; i < MaxLength; i++) + ByteSwap(&vData_f[i]); + + // Read image data + myFile.write((char*)vData_f, sizeof(float) * MaxLength); + + // Swap hi lo bytes + for (int i = 0; i < MaxLength; i++) + ByteSwap(&vData_f[i]); + break; + + // Swap bytes back + for (int i = 0; i < MaxLength; i++) + ByteSwap(&vData_f[i]); + + default: + break; + } + + // Close file + myFile.close(); } // ------------------------------------------------------------------------- /** -* \brief Write GIPL header to output file. -* -* \param myfile Output file -*/ + * \brief Write GIPL header to output file. + * + * \param myfile Output file + */ // ------------------------------------------------------------------------- -void Image::WriteGiplHeader(fstream* myFile) -{ - int i; - for(i=0;i<4;i++) - myFile->write(reinterpret_cast < char * > (&m_dim[i]), sizeof(m_dim[i])); - myFile->write(reinterpret_cast < char * > (&m_image_type), sizeof(m_image_type)); - for(i=0;i<4;i++) - myFile->write(reinterpret_cast < char * > (&m_pixdim[i]), sizeof(m_pixdim[i])); - for(i=0;i<80;i++) - myFile->write(reinterpret_cast < char * > (&m_patDesc[i]), sizeof(m_patDesc[i])); - for(i=0;i<12;i++) - myFile->write(reinterpret_cast < char * > (&m_matrixElements[i]), sizeof(m_matrixElements[i])); - myFile->write(reinterpret_cast < char * > (&m_identifier), sizeof(m_identifier)); - for(i=0;i<28;i++) - myFile->write(reinterpret_cast < char * > (&m_spare[i]), sizeof(m_spare[i])); - myFile->write(reinterpret_cast < char * > (&m_orientationFlag), sizeof(m_orientationFlag)); - myFile->write(reinterpret_cast < char * > (&m_flag1), sizeof(m_flag1)); - myFile->write(reinterpret_cast < char * > (&m_min), sizeof(m_min)); - myFile->write(reinterpret_cast < char * > (&m_max), sizeof(m_max)); - for(i=0;i<4;i++) - myFile->write(reinterpret_cast < char * > (&m_origin[i]), sizeof(m_origin[i])); - myFile->write(reinterpret_cast < char * > (&m_pixval_offset), sizeof(m_pixval_offset)); - myFile->write(reinterpret_cast < char * > (&m_pixval_cal), sizeof(m_pixval_cal)); - myFile->write(reinterpret_cast < char * > (&m_user_def1), sizeof(m_user_def1)); - myFile->write(reinterpret_cast < char * > (&m_user_def2), sizeof(m_user_def2)); - myFile->write(reinterpret_cast < char * > (&m_magic_number), sizeof(m_magic_number)); +void +Image::WriteGiplHeader(fstream* myFile) { + int i; + for (i = 0; i < 4; i++) + myFile->write(reinterpret_cast(&m_dim[i]), sizeof(m_dim[i])); + myFile->write(reinterpret_cast(&m_image_type), sizeof(m_image_type)); + for (i = 0; i < 4; i++) + myFile->write(reinterpret_cast(&m_pixdim[i]), sizeof(m_pixdim[i])); + for (i = 0; i < 80; i++) + myFile->write(reinterpret_cast(&m_patDesc[i]), sizeof(m_patDesc[i])); + for (i = 0; i < 12; i++) + myFile->write(reinterpret_cast(&m_matrixElements[i]), sizeof(m_matrixElements[i])); + myFile->write(reinterpret_cast(&m_identifier), sizeof(m_identifier)); + for (i = 0; i < 28; i++) + myFile->write(reinterpret_cast(&m_spare[i]), sizeof(m_spare[i])); + myFile->write(reinterpret_cast(&m_orientationFlag), sizeof(m_orientationFlag)); + myFile->write(reinterpret_cast(&m_flag1), sizeof(m_flag1)); + myFile->write(reinterpret_cast(&m_min), sizeof(m_min)); + myFile->write(reinterpret_cast(&m_max), sizeof(m_max)); + for (i = 0; i < 4; i++) + myFile->write(reinterpret_cast(&m_origin[i]), sizeof(m_origin[i])); + myFile->write(reinterpret_cast(&m_pixval_offset), sizeof(m_pixval_offset)); + myFile->write(reinterpret_cast(&m_pixval_cal), sizeof(m_pixval_cal)); + myFile->write(reinterpret_cast(&m_user_def1), sizeof(m_user_def1)); + myFile->write(reinterpret_cast(&m_user_def2), sizeof(m_user_def2)); + myFile->write(reinterpret_cast(&m_magic_number), sizeof(m_magic_number)); } // ------------------------------------------------------------------------- /** -* \brief Swap bytes (little/big endian conversion). -*/ + * \brief Swap bytes (little/big endian conversion). + */ // ------------------------------------------------------------------------- -void Image::ByteSwapHeader() // for PC little endian -{ - int i; - for(i=0;i<4;i++) ByteSwap(&(m_dim[i])); +void +Image::ByteSwapHeader() // for PC little endian +{ + int i; + for (i = 0; i < 4; i++) + ByteSwap(&(m_dim[i])); - ByteSwap(&(m_image_type)); + ByteSwap(&(m_image_type)); - for(i=0;i<4;i++) ByteSwap(&(m_pixdim[i])); + for (i = 0; i < 4; i++) + ByteSwap(&(m_pixdim[i])); - for(i=0;i<12;i++) ByteSwap(&(m_matrixElements[i])); + for (i = 0; i < 12; i++) + ByteSwap(&(m_matrixElements[i])); - ByteSwap(&(m_min)); - ByteSwap(&(m_max)); + ByteSwap(&(m_min)); + ByteSwap(&(m_max)); - for(i=0;i<4;i++) ByteSwap(&(m_origin[i])); - - ByteSwap(&(m_pixval_offset)); - ByteSwap(&(m_pixval_cal)); - ByteSwap(&(m_user_def1)); - ByteSwap(&(m_user_def2)); - ByteSwap((int*)&(m_magic_number)); + for (i = 0; i < 4; i++) + ByteSwap(&(m_origin[i])); - return; + ByteSwap(&(m_pixval_offset)); + ByteSwap(&(m_pixval_cal)); + ByteSwap(&(m_user_def1)); + ByteSwap(&(m_user_def2)); + ByteSwap((int*)&(m_magic_number)); + + return; } // ------------------------------------------------------------------------- /** -* \brief Initialize zero image -* -* \param Input Input image -*/ + * \brief Initialize zero image + * + * \param Input Input image + */ // ------------------------------------------------------------------------- -void Image::Zeros(Image* Input, short iType) -{ - // Initialize image with dimensions - this->Initialize(Input, iType); - - if (iType == _SHORT) - { - // Initialize with zeros - for (int i = 0; i < this->MaxLength; i++) - this->vData[i] = 0; - - // Update min max values - //this->GetMinMaxValue(); - } - - if (iType == _FLOAT) - { - // Initialize with zeros - for (int i = 0; i < this->MaxLength; i++) - this->vData_f[i] = 0; - } - - iMin = 0; - iMax = 0; +void +Image::Zeros(Image* Input, short iType) { + // Initialize image with dimensions + this->Initialize(Input, iType); + + if (iType == _SHORT) { + // Initialize with zeros + for (int i = 0; i < this->MaxLength; i++) + this->vData[i] = 0; + + // Update min max values + // this->GetMinMaxValue(); + } + + if (iType == _FLOAT) { + // Initialize with zeros + for (int i = 0; i < this->MaxLength; i++) + this->vData_f[i] = 0; + } + + iMin = 0; + iMax = 0; } // ------------------------------------------------------------------------- /** -* \brief Initialize zero image -* -* \param Input Input image -*/ + * \brief Initialize zero image + * + * \param Input Input image + */ // ------------------------------------------------------------------------- -void Image::Zeros() -{ - // Set image to 0 - if (this->m_image_type == 15) - { - // Initialize with zeros - for (int i = 0; i < this->MaxLength; i++) - this->vData[i] = 0; - - // Update min max values - //this->GetMinMaxValue(); - } - - if (this->m_image_type == 64) - { - // Initialize with zeros - for (int i = 0; i < this->MaxLength; i++) - this->vData_f[i] = 0; - } - - iMin = 0; - iMax = 0; +void +Image::Zeros() { + // Set image to 0 + if (this->m_image_type == 15) { + // Initialize with zeros + for (int i = 0; i < this->MaxLength; i++) + this->vData[i] = 0; + + // Update min max values + // this->GetMinMaxValue(); + } + + if (this->m_image_type == 64) { + // Initialize with zeros + for (int i = 0; i < this->MaxLength; i++) + this->vData_f[i] = 0; + } + + iMin = 0; + iMax = 0; } // ------------------------------------------------------------------------- /** -* \brief Initialize one image -* -* \param Input Input image -*/ + * \brief Initialize one image + * + * \param Input Input image + */ // ------------------------------------------------------------------------- -void Image::Ones(Image* Input, short iType) -{ - // Initialize image with dimensions - this->Initialize(Input, iType); - - if (iType == _SHORT) - { - // Initialize with zeros - for (int i = 0; i < this->MaxLength; i++) - this->vData[i] = 1; - } - - if (iType == _FLOAT) - { - // Initialize with zeros - for (int i = 0; i < this->MaxLength; i++) - this->vData_f[i] = 1; - } - - iMax = 1; - iMin = 1; +void +Image::Ones(Image* Input, short iType) { + // Initialize image with dimensions + this->Initialize(Input, iType); + + if (iType == _SHORT) { + // Initialize with zeros + for (int i = 0; i < this->MaxLength; i++) + this->vData[i] = 1; + } + + if (iType == _FLOAT) { + // Initialize with zeros + for (int i = 0; i < this->MaxLength; i++) + this->vData_f[i] = 1; + } + + iMax = 1; + iMin = 1; } // ------------------------------------------------------------------------- /** -* \brief Initialize image data by with the dimension of the input image -* -* \param Input Input image -*/ + * \brief Initialize image data by with the dimension of the input image + * + * \param Input Input image + */ // ------------------------------------------------------------------------- -void Image::Initialize(Image* Input, short iType) -{ - // Set new data properties - for (int i = 0; i < 4; i++) - { - this->m_dim[i] = Input->m_dim[i]; - this->m_pixdim[i] = Input->m_pixdim[i]; - this->vCenter[i] = Input->vCenter[i]; - this->m_origin[i] = Input->m_origin[i]; - } - - this->m_orientationFlag = Input->m_orientationFlag; - this->m_flag1 = Input->m_flag1; - this->m_min = Input->m_min; - this->m_max = Input->m_max; - this->m_pixval_offset = Input->m_pixval_offset; - this->m_pixval_cal = Input->m_pixval_cal; - this->m_user_def1 = Input->m_user_def1; - this->m_user_def2 = Input->m_user_def2; - this->m_magic_number = Input->m_magic_number; - for (int i = 0; i < 2; i++) - this->ImageOffset[i] = Input->ImageOffset[i]; // XLen and XLen*YLen - this->MaxLength = Input->MaxLength; - - // Initialize data vactor - if (iType == _SHORT) - { - // Delete old vector and initialize data vector - if (this->vData) - delete[] this->vData; - - this->m_image_type = 15; - this->vData = new short[Input->MaxLength]; - } - - if (iType == _FLOAT) - { - // Delete old vector and initialize data vector - if (this->vData_f) - delete[] this->vData_f; - - this->m_image_type = 64; - this->vData_f = new float[Input->MaxLength]; - } +void +Image::Initialize(Image* Input, short iType) { + // Set new data properties + for (int i = 0; i < 4; i++) { + this->m_dim[i] = Input->m_dim[i]; + this->m_pixdim[i] = Input->m_pixdim[i]; + this->vCenter[i] = Input->vCenter[i]; + this->m_origin[i] = Input->m_origin[i]; + } + + this->m_orientationFlag = Input->m_orientationFlag; + this->m_flag1 = Input->m_flag1; + this->m_min = Input->m_min; + this->m_max = Input->m_max; + this->m_pixval_offset = Input->m_pixval_offset; + this->m_pixval_cal = Input->m_pixval_cal; + this->m_user_def1 = Input->m_user_def1; + this->m_user_def2 = Input->m_user_def2; + this->m_magic_number = Input->m_magic_number; + for (int i = 0; i < 2; i++) + this->ImageOffset[i] = Input->ImageOffset[i]; // XLen and XLen*YLen + this->MaxLength = Input->MaxLength; + + // Initialize data vactor + if (iType == _SHORT) { + // Delete old vector and initialize data vector + if (this->vData) + delete[] this->vData; + + this->m_image_type = 15; + this->vData = new short[Input->MaxLength]; + } + + if (iType == _FLOAT) { + // Delete old vector and initialize data vector + if (this->vData_f) + delete[] this->vData_f; + + this->m_image_type = 64; + this->vData_f = new float[Input->MaxLength]; + } } // ------------------------------------------------------------------------- /** -* \brief Initialize image data by with the dimension of the input image -* -* \param Input Input image -*/ + * \brief Initialize image data by with the dimension of the input image + * + * \param Input Input image + */ // ------------------------------------------------------------------------- -void Image::Initialize(Image* Input) -{ - // Set new data properties - for (int i = 0; i < 4; i++) - { - this->m_dim[i] = Input->m_dim[i]; - this->m_pixdim[i] = Input->m_pixdim[i]; - this->vCenter[i] = Input->vCenter[i]; - this->m_origin[i] = Input->m_origin[i]; - } - - this->m_orientationFlag = Input->m_orientationFlag; - this->m_flag1 = Input->m_flag1; - this->m_min = Input->m_min; - this->m_max = Input->m_max; - this->m_pixval_offset = Input->m_pixval_offset; - this->m_pixval_cal = Input->m_pixval_cal; - this->m_user_def1 = Input->m_user_def1; - this->m_user_def2 = Input->m_user_def2; - this->m_magic_number = Input->m_magic_number; - for (int i = 0; i < 2; i++) - this->ImageOffset[i] = Input->ImageOffset[i]; // XLen and XLen*YLen - this->MaxLength = Input->MaxLength; - - // Initialize data vactor - if (this->vData) - delete[] this->vData; - - if (this->vData_f) - delete[] this->vData_f; +void +Image::Initialize(Image* Input) { + // Set new data properties + for (int i = 0; i < 4; i++) { + this->m_dim[i] = Input->m_dim[i]; + this->m_pixdim[i] = Input->m_pixdim[i]; + this->vCenter[i] = Input->vCenter[i]; + this->m_origin[i] = Input->m_origin[i]; + } + + this->m_orientationFlag = Input->m_orientationFlag; + this->m_flag1 = Input->m_flag1; + this->m_min = Input->m_min; + this->m_max = Input->m_max; + this->m_pixval_offset = Input->m_pixval_offset; + this->m_pixval_cal = Input->m_pixval_cal; + this->m_user_def1 = Input->m_user_def1; + this->m_user_def2 = Input->m_user_def2; + this->m_magic_number = Input->m_magic_number; + for (int i = 0; i < 2; i++) + this->ImageOffset[i] = Input->ImageOffset[i]; // XLen and XLen*YLen + this->MaxLength = Input->MaxLength; + + // Initialize data vactor + if (this->vData) + delete[] this->vData; + + if (this->vData_f) + delete[] this->vData_f; } // ------------------------------------------------------------------------- /** -* \brief Copy image -* -* \param Input Input image -*/ + * \brief Copy image + * + * \param Input Input image + */ // ------------------------------------------------------------------------- -void Image::Copy(Image* Input, short iType) -{ - // Initialize image with dimensions - this->Initialize(Input, iType); - - if (iType == _SHORT) - { - // Initialize with zeros - for (int i = 0; i < Input->MaxLength; i++) - this->vData[i] = Input->vData[i]; - - // Update min max values - this->GetMinMaxValue(); - } - - if (iType == _FLOAT) - { - // Initialize with zeros - for (int i = 0; i < Input->MaxLength; i++) - this->vData_f[i] = Input->vData_f[i]; - } +void +Image::Copy(Image* Input, short iType) { + // Initialize image with dimensions + this->Initialize(Input, iType); + + if (iType == _SHORT) { + // Initialize with zeros + for (int i = 0; i < Input->MaxLength; i++) + this->vData[i] = Input->vData[i]; + + // Update min max values + this->GetMinMaxValue(); + } + + if (iType == _FLOAT) { + // Initialize with zeros + for (int i = 0; i < Input->MaxLength; i++) + this->vData_f[i] = Input->vData_f[i]; + } } // ------------------------------------------------------------------------- // Byte swap functions // ------------------------------------------------------------------------- -void Image::ByteSwap(int *i) // for PC little endian -{ +void +Image::ByteSwap(int* i) // for PC little endian +{ typedef struct { unsigned char byte1; unsigned char byte2; @@ -689,13 +666,14 @@ void Image::ByteSwap(int *i) // for PC little endian intUS.bytes.byte2 = intU.bytes.byte3; intUS.bytes.byte3 = intU.bytes.byte2; intUS.bytes.byte4 = intU.bytes.byte1; - + *i = intUS.integer; return; } -void Image::ByteSwap(short *s) // for PC little endian -{ +void +Image::ByteSwap(short* s) // for PC little endian +{ typedef struct { unsigned char byte1; unsigned char byte2; @@ -716,8 +694,9 @@ void Image::ByteSwap(short *s) // for PC little endian return; } -void Image::ByteSwap(float *f) // for PC little endian -{ +void +Image::ByteSwap(float* f) // for PC little endian +{ typedef struct { unsigned char byte1; unsigned char byte2; @@ -742,8 +721,9 @@ void Image::ByteSwap(float *f) // for PC little endian return; } -void Image::ByteSwap(double *d) // for PC little endian -{ +void +Image::ByteSwap(double* d) // for PC little endian +{ typedef struct { unsigned char byte1; unsigned char byte2; diff --git a/src/IO/IO_registries.cxx b/src/IO/IO_registries.cxx index c91ff0fe84..4111e8afb9 100644 --- a/src/IO/IO_registries.cxx +++ b/src/IO/IO_registries.cxx @@ -3,7 +3,7 @@ Copyright (C) 2012, Kris Thielemans Copyright (C) 2013, Institute for Bioengineering of Catalonia Copyright (C) 2013, University College London - + This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -41,43 +41,41 @@ #include "stir/IO/MultiParametricDiscretisedDensityInputFileFormat.h" #include "stir/IO/MultiParametricDiscretisedDensityOutputFileFormat.h" #ifdef HAVE_LLN_MATRIX -#include "stir/IO/ECAT6OutputFileFormat.h" -#include "stir/IO/ECAT7OutputFileFormat.h" -#include "stir/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.h" -#include "stir/IO/ECAT7ParametricDensityOutputFileFormat.h" -#include "stir/IO/ECAT7DynamicDiscretisedDensityInputFileFormat.h" +# include "stir/IO/ECAT6OutputFileFormat.h" +# include "stir/IO/ECAT7OutputFileFormat.h" +# include "stir/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.h" +# include "stir/IO/ECAT7ParametricDensityOutputFileFormat.h" +# include "stir/IO/ECAT7DynamicDiscretisedDensityInputFileFormat.h" #endif - #if 1 -#include "stir/IO/InputFileFormatRegistry.h" -#include "stir/IO/InterfileImageInputFileFormat.h" -#ifdef HAVE_LLN_MATRIX -#include "stir/IO/ECAT6ImageInputFileFormat.h" -#include "stir/IO/ECAT7ImageInputFileFormat.h" -#include "stir/IO/ECAT966ListmodeInputFileFormat.h" -#include "stir/IO/ECAT962ListmodeInputFileFormat.h" -#endif +# include "stir/IO/InputFileFormatRegistry.h" +# include "stir/IO/InterfileImageInputFileFormat.h" +# ifdef HAVE_LLN_MATRIX +# include "stir/IO/ECAT6ImageInputFileFormat.h" +# include "stir/IO/ECAT7ImageInputFileFormat.h" +# include "stir/IO/ECAT966ListmodeInputFileFormat.h" +# include "stir/IO/ECAT962ListmodeInputFileFormat.h" +# endif #endif #include "stir/IO/ECAT8_32bitListmodeInputFileFormat.h" #ifdef HAVE_HDF5 -#include "stir/IO/GEHDF5ListmodeInputFileFormat.h" +# include "stir/IO/GEHDF5ListmodeInputFileFormat.h" #endif - //! Addition for SAFIR listmode input file format #include "stir/IO/SAFIRCListmodeInputFileFormat.h" //! Addition for ROOT support - Nikos Efthimiou #ifdef HAVE_CERN_ROOT -#include "stir/IO/ROOTListmodeInputFileFormat.h" -#include "stir/IO/InputStreamFromROOTFileForCylindricalPET.h" -#include "stir/IO/InputStreamFromROOTFileForECATPET.h" +# include "stir/IO/ROOTListmodeInputFileFormat.h" +# include "stir/IO/InputStreamFromROOTFileForCylindricalPET.h" +# include "stir/IO/InputStreamFromROOTFileForECATPET.h" #endif #ifdef HAVE_ITK -#include "stir/IO/ITKOutputFileFormat.h" -#include "stir/IO/ITKImageInputFileFormat.h" +# include "stir/IO/ITKOutputFileFormat.h" +# include "stir/IO/ITKImageInputFileFormat.h" #endif START_NAMESPACE_STIR @@ -94,7 +92,6 @@ static MultiParametricDiscretisedDensityOutputFileFormat LMdummySAFIR(4); - //! //! \brief LMdummyROOT //! \author Nikos Efthimiou @@ -118,12 +115,11 @@ END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT #endif - static RegisterInputFileFormat idummy0(0); #ifdef HAVE_LLN_MATRIX static RegisterInputFileFormat idummy2(4); -// ECAT6 very low priority it doesn't have a signature +// ECAT6 very low priority it doesn't have a signature static RegisterInputFileFormat idummy4(100000); static RegisterInputFileFormat dynidummy(0); @@ -131,15 +127,14 @@ static RegisterInputFileFormat > > idummy6(10000); -static RegisterInputFileFormat > > > idummy7(10000); +static RegisterInputFileFormat>> idummy6(10000); +static RegisterInputFileFormat>>> idummy7(10000); #endif static RegisterInputFileFormat dyndummy_intf(1); static RegisterInputFileFormat paradummy_intf(1); static RegisterInputFileFormat dynim_dummy_multi(1); static RegisterInputFileFormat parim_dummy_multi(1); - /*************************** listmode data **********************/ #ifdef HAVE_LLN_MATRIX static RegisterInputFileFormat LMdummyECAT966(4); diff --git a/src/IO/ITKImageInputFileFormat.cxx b/src/IO/ITKImageInputFileFormat.cxx index 6cf84ffb52..ba7bf5c29f 100644 --- a/src/IO/ITKImageInputFileFormat.cxx +++ b/src/IO/ITKImageInputFileFormat.cxx @@ -53,73 +53,55 @@ START_NAMESPACE_STIR */ -typedef itk::Image ITKImageSingle; -typedef itk::VectorImage ITKImageMulti; -typedef DiscretisedDensity<3, float> STIRImageSingle; -typedef VoxelsOnCartesianGrid STIRImageSingleConcrete; -typedef DiscretisedDensity<3, CartesianCoordinate3D > STIRImageMulti; -typedef VoxelsOnCartesianGrid > STIRImageMultiConcrete; -typedef itk::MetaDataObject< std::string > MetaDataStringType; - -template -static -STIRImageType * -read_file_itk(const std::string &filename); +typedef itk::Image ITKImageSingle; +typedef itk::VectorImage ITKImageMulti; +typedef DiscretisedDensity<3, float> STIRImageSingle; +typedef VoxelsOnCartesianGrid STIRImageSingleConcrete; +typedef DiscretisedDensity<3, CartesianCoordinate3D> STIRImageMulti; +typedef VoxelsOnCartesianGrid> STIRImageMultiConcrete; +typedef itk::MetaDataObject MetaDataStringType; template -bool -ITKImageInputFileFormat::actual_can_read(const FileSignature& signature, - std::istream& input) const -{ +static STIRImageType* read_file_itk(const std::string& filename); + +template +bool +ITKImageInputFileFormat::actual_can_read(const FileSignature& signature, std::istream& input) const { return false; } template bool -ITKImageInputFileFormat::can_read(const FileSignature& signature, - std::istream& input) const -{ +ITKImageInputFileFormat::can_read(const FileSignature& signature, std::istream& input) const { return this->actual_can_read(signature, input); } template -bool -ITKImageInputFileFormat::can_read(const FileSignature& /*signature*/, - const std::string& filename) const -{ +bool +ITKImageInputFileFormat::can_read(const FileSignature& /*signature*/, const std::string& filename) const { typedef itk::ImageFileReader ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(filename); - try - { - reader->Update(); - return true; - } - catch( itk::ExceptionObject & /*err*/ ) - { - - return false; - } + try { + reader->Update(); + return true; + } catch (itk::ExceptionObject& /*err*/) { + + return false; + } } template unique_ptr -ITKImageInputFileFormat::read_from_file(std::istream& input) const -{ - error("read_from_file for ITK with istream not implemented %s:%d. Sorry", - __FILE__, __LINE__); - return - unique_ptr(); +ITKImageInputFileFormat::read_from_file(std::istream& input) const { + error("read_from_file for ITK with istream not implemented %s:%d. Sorry", __FILE__, __LINE__); + return unique_ptr(); } -template +template unique_ptr -ITKImageInputFileFormat:: -read_from_file(const std::string& filename) const -{ - return - unique_ptr - (read_file_itk< STIRImageType >(filename)); +ITKImageInputFileFormat::read_from_file(const std::string& filename) const { + return unique_ptr(read_file_itk(filename)); } /* Convert ITK (LPS) coordinates into STIR physical coordinates and @@ -129,32 +111,25 @@ read_from_file(const std::string& filename) const interpreted as being displacement vectors and hence the change of origin is ignored. */ -template -static inline -CartesianCoordinate3D -ITK_coordinates_to_STIR_physical_coordinates -(const ITKPointType &itk_coord, - const STIRImageType &stir_image, bool is_relative_coordinate=false) -{ +template +static inline CartesianCoordinate3D +ITK_coordinates_to_STIR_physical_coordinates(const ITKPointType& itk_coord, const STIRImageType& stir_image, + bool is_relative_coordinate = false) { // find STIR origin // Note: need to use - for z-coordinate because of different axis conventions - CartesianCoordinate3D stir_coord - = stir_image.get_physical_coordinates_for_LPS_coordinates - (CartesianCoordinate3D(static_cast(itk_coord[2]), - static_cast(itk_coord[1]), - static_cast(itk_coord[0]))); + CartesianCoordinate3D stir_coord = stir_image.get_physical_coordinates_for_LPS_coordinates(CartesianCoordinate3D( + static_cast(itk_coord[2]), static_cast(itk_coord[1]), static_cast(itk_coord[0]))); // The following is not required for displacement vectors, such as a displacement field, as // the coordinates are relative. - if (!is_relative_coordinate) - { + if (!is_relative_coordinate) { CartesianCoordinate3D stir_origin_index(0, 0, 0); // assuming we previously oriented the ITK image, min_indices is the // index where ITK origin points to in physical space - const CartesianCoordinate3D stir_origin_wrt_itk_origin - = stir_image.get_physical_coordinates_for_indices(stir_origin_index) - - stir_image.get_physical_coordinates_for_indices(stir_image.get_min_indices()); + const CartesianCoordinate3D stir_origin_wrt_itk_origin = + stir_image.get_physical_coordinates_for_indices(stir_origin_index) - + stir_image.get_physical_coordinates_for_indices(stir_image.get_min_indices()); stir_coord += stir_origin_wrt_itk_origin; } @@ -163,70 +138,52 @@ ITK_coordinates_to_STIR_physical_coordinates } /* Convert an ITK Pixel (i.e., float) to a STIR Pixel. */ -template -static inline -STIRPixelType -ITK_pixel_to_STIR_pixel(ITKPixelType itk_pixel, - const STIRImageType &stir_image, - bool) -{ +template +static inline STIRPixelType +ITK_pixel_to_STIR_pixel(ITKPixelType itk_pixel, const STIRImageType& stir_image, bool) { return static_cast(itk_pixel); } /* Specialisation if the pixel is a vector and we want a multi-image */ -template<> -inline -typename STIRImageMultiConcrete::full_value_type -ITK_pixel_to_STIR_pixel(typename ITKImageMulti::PixelType itk_pixel, - const STIRImageMultiConcrete &stir_image, - bool is_displacement_field) -{ +template <> +inline typename STIRImageMultiConcrete::full_value_type +ITK_pixel_to_STIR_pixel(typename ITKImageMulti::PixelType itk_pixel, const STIRImageMultiConcrete& stir_image, + bool is_displacement_field) { // ITK VariableLengthVector to ITK FixedArray // We know it is length 3 assert(itk_pixel.GetSize() == 3); // TODO: currently this is only for deformation/displacement images // However, dynamic images may be other lengths. typename ITKImageMulti::PointType itk_coord; - for (unsigned int i=0; i<3; ++i) + for (unsigned int i = 0; i < 3; ++i) itk_coord[i] = itk_pixel[i]; - return ITK_coordinates_to_STIR_physical_coordinates - (itk_coord, stir_image, is_displacement_field); + return ITK_coordinates_to_STIR_physical_coordinates(itk_coord, stir_image, is_displacement_field); } /* Calculate the STIR index range from an ITK image. */ -template -static inline -IndexRange<3> -calc_stir_index_range(const ITKImagePtrType itk_image) -{ +template +static inline IndexRange<3> +calc_stir_index_range(const ITKImagePtrType itk_image) { // find index range in usual STIR convention const int z_size = itk_image->GetLargestPossibleRegion().GetSize()[2]; const int y_size = itk_image->GetLargestPossibleRegion().GetSize()[1]; const int x_size = itk_image->GetLargestPossibleRegion().GetSize()[0]; - const BasicCoordinate<3, int> min_indices - = BasicCoordinate<3,int>(make_coordinate(0, -y_size/2, -x_size/2)); - const BasicCoordinate<3, int> max_indices - = min_indices + make_coordinate(z_size, y_size, x_size) - 1; + const BasicCoordinate<3, int> min_indices = BasicCoordinate<3, int>(make_coordinate(0, -y_size / 2, -x_size / 2)); + const BasicCoordinate<3, int> max_indices = min_indices + make_coordinate(z_size, y_size, x_size) - 1; return IndexRange<3>(min_indices, max_indices); } /* Calculate the STIR origin for a given voxel_size and index_range from an ITK image. */ -template -static inline -const CartesianCoordinate3D -calc_stir_origin(CartesianCoordinate3D voxel_size, - IndexRange<3> index_range, - const ITKImagePtrType itk_image) -{ +template +static inline const CartesianCoordinate3D +calc_stir_origin(CartesianCoordinate3D voxel_size, IndexRange<3> index_range, const ITKImagePtrType itk_image) { const CartesianCoordinate3D stir_origin_index(0, 0, 0); // dummy image that has minumum to be able to find ITK -> STIR origin vector - const VoxelsOnCartesianGrid dummy_image - (index_range, stir_origin_index, voxel_size); + const VoxelsOnCartesianGrid dummy_image(index_range, stir_origin_index, voxel_size); - return ITK_coordinates_to_STIR_physical_coordinates - (itk_image->GetOrigin(), dummy_image); + return ITK_coordinates_to_STIR_physical_coordinates(itk_image->GetOrigin(), dummy_image); } /* Constructs an exam info object from an ITK meta data dictionary. @@ -241,11 +198,9 @@ calc_stir_origin(CartesianCoordinate3D voxel_size, \todo This will only work for DICOM meta-data. Other fileformats store meta-data with different names. */ -static -shared_ptr -construct_exam_info_from_metadata_dictionary(itk::MetaDataDictionary dictionary) -{ - shared_ptr exam_info_sptr (new ExamInfo()); +static shared_ptr +construct_exam_info_from_metadata_dictionary(itk::MetaDataDictionary dictionary) { + shared_ptr exam_info_sptr(new ExamInfo()); #if 0 //example data to read @@ -278,26 +233,24 @@ construct_exam_info_from_metadata_dictionary(itk::MetaDataDictionary dictionary) series_datetime = DICOM_date_time_to_DT(series_date, series_time, TimezoneOffsetFromUTC); } itk::ExposeMetaData(dictionary, "0008|002a", acq_datetime); - if (acq_datetime.empty()) - { - std::string acq_date, acq_time; - itk::ExposeMetaData(dictionary, "0008|0022", acq_date); - itk::ExposeMetaData(dictionary, "0008|0032", acq_time); - if (!acq_date.empty() && !acq_time.empty()) - acq_datetime = DICOM_date_time_to_DT(acq_date, acq_time, TimezoneOffsetFromUTC); - } + if (acq_datetime.empty()) { + std::string acq_date, acq_time; + itk::ExposeMetaData(dictionary, "0008|0022", acq_date); + itk::ExposeMetaData(dictionary, "0008|0032", acq_time); + if (!acq_date.empty() && !acq_time.empty()) + acq_datetime = DICOM_date_time_to_DT(acq_date, acq_time, TimezoneOffsetFromUTC); + } itk::ExposeMetaData(dictionary, "0018|1242", actual_frame_duration); - if (!series_datetime.empty() && !acq_datetime.empty() && !actual_frame_duration.empty()) - { - std::vector start_times(1), durations(1); - start_times[0] = DICOM_datetime_to_secs_since_Unix_epoch(series_datetime, false) - DICOM_datetime_to_secs_since_Unix_epoch(acq_datetime, false); - durations[0] = boost::lexical_cast(actual_frame_duration)/1000.; - exam_info_sptr->set_time_frame_definitions(TimeFrameDefinitions(start_times, durations)); - } - if (!series_datetime.empty()) - { - exam_info_sptr->start_time_in_secs_since_1970 = DICOM_datetime_to_secs_since_Unix_epoch(series_datetime); - } + if (!series_datetime.empty() && !acq_datetime.empty() && !actual_frame_duration.empty()) { + std::vector start_times(1), durations(1); + start_times[0] = DICOM_datetime_to_secs_since_Unix_epoch(series_datetime, false) - + DICOM_datetime_to_secs_since_Unix_epoch(acq_datetime, false); + durations[0] = boost::lexical_cast(actual_frame_duration) / 1000.; + exam_info_sptr->set_time_frame_definitions(TimeFrameDefinitions(start_times, durations)); + } + if (!series_datetime.empty()) { + exam_info_sptr->start_time_in_secs_since_1970 = DICOM_datetime_to_secs_since_Unix_epoch(series_datetime); + } } #if 0 @@ -313,14 +266,11 @@ construct_exam_info_from_metadata_dictionary(itk::MetaDataDictionary dictionary) itk::ExposeMetaData(dictionary, "0018|5100", patient_position_str); // Now patient_positon_str is empty or the value, but is it a valid value? // If so, update patient_position - for (unsigned int position_idx = 0; - (position_idx < PatientPosition::unknown_position) - && (patient_position.get_position() == PatientPosition::unknown_position); + for (unsigned int position_idx = 0; (position_idx < PatientPosition::unknown_position) && + (patient_position.get_position() == PatientPosition::unknown_position); ++position_idx) { - PatientPosition possible_position - (static_cast(position_idx)); - if (patient_position_str.find(possible_position.get_position_as_string()) - != std::string::npos) { + PatientPosition possible_position(static_cast(position_idx)); + if (patient_position_str.find(possible_position.get_position_as_string()) != std::string::npos) { patient_position = possible_position; } } @@ -338,26 +288,20 @@ construct_exam_info_from_metadata_dictionary(itk::MetaDataDictionary dictionary) This method expects that itk_image is already oriented to be consistent with STIR x, y, z axes. */ -template -static inline -STIRImageType* -construct_empty_stir_image(const ITKImagePtrType itk_image, - shared_ptr exam_info_sptr) -{ +template +static inline STIRImageType* +construct_empty_stir_image(const ITKImagePtrType itk_image, shared_ptr exam_info_sptr) { // find voxel size - const CartesianCoordinate3D voxel_size - (static_cast(itk_image->GetSpacing()[2]), - static_cast(itk_image->GetSpacing()[1]), - static_cast(itk_image->GetSpacing()[0])); + const CartesianCoordinate3D voxel_size(static_cast(itk_image->GetSpacing()[2]), + static_cast(itk_image->GetSpacing()[1]), + static_cast(itk_image->GetSpacing()[0])); // find info STIR image geometrical metadata const IndexRange<3> index_range = calc_stir_index_range(itk_image); - const CartesianCoordinate3D stir_origin = calc_stir_origin - (voxel_size, index_range, itk_image); + const CartesianCoordinate3D stir_origin = calc_stir_origin(voxel_size, index_range, itk_image); // create STIR image - STIRImageType* image_ptr = new STIRImageType - (exam_info_sptr, index_range, stir_origin, voxel_size); + STIRImageType* image_ptr = new STIRImageType(exam_info_sptr, index_range, stir_origin, voxel_size); return image_ptr; } @@ -365,29 +309,24 @@ construct_empty_stir_image(const ITKImagePtrType itk_image, This method expects that itk_image is already oriented to be consistent with STIR x, y, z axes. */ -template -static inline -void copy_ITK_data_to_STIR_image(const typename ITKImageType::Pointer itk_image, - STIRImageType& stir_image, - bool is_displacement_field) -{ +template +static inline void +copy_ITK_data_to_STIR_image(const typename ITKImageType::Pointer itk_image, STIRImageType& stir_image, + bool is_displacement_field) { typename STIRImageType::full_iterator stir_iter = stir_image.begin_all(); typedef itk::ImageRegionConstIterator IteratorType; - IteratorType it (itk_image, itk_image->GetLargestPossibleRegion()); - for (it.GoToBegin(); !it.IsAtEnd(); ++it, ++stir_iter) - { - *stir_iter = ITK_pixel_to_STIR_pixel - - (it.Get(), stir_image, is_displacement_field); + IteratorType it(itk_image, itk_image->GetLargestPossibleRegion()); + for (it.GoToBegin(); !it.IsAtEnd(); ++it, ++stir_iter) { + *stir_iter = + ITK_pixel_to_STIR_pixel( + it.Get(), stir_image, is_displacement_field); } } -template +template typename ITKImageType::Pointer -orient_ITK_image(const typename ITKImageType::Pointer itk_image_orig, - const shared_ptr exam_info_sptr) -{ - typedef itk::OrientImageFilter OrienterType; +orient_ITK_image(const typename ITKImageType::Pointer itk_image_orig, const shared_ptr exam_info_sptr) { + typedef itk::OrientImageFilter OrienterType; typename OrienterType::Pointer orienter = OrienterType::New(); orienter->UseImageDirectionOn(); orienter->SetInput(itk_image_orig); @@ -400,29 +339,25 @@ orient_ITK_image(const typename ITKImageType::Pointer itk_image_orig, case PatientPosition::HFS: // HFS means currently in LPI // So origin is in RAS direction - orienter - ->SetDesiredCoordinateOrientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAS); + orienter->SetDesiredCoordinateOrientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAS); break; case PatientPosition::HFP: // HFP means currently in RAI // So origin is in LPS direction - orienter - ->SetDesiredCoordinateOrientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LPS); + orienter->SetDesiredCoordinateOrientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LPS); break; case PatientPosition::FFS: // FFS means currently in RPS // So origin is in LAI direction - orienter - ->SetDesiredCoordinateOrientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LAI); + orienter->SetDesiredCoordinateOrientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LAI); break; case PatientPosition::FFP: // FFP means currently in LAS // So origin is in RPI direction - orienter - ->SetDesiredCoordinateOrientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RPI); + orienter->SetDesiredCoordinateOrientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RPI); break; default: @@ -434,168 +369,142 @@ orient_ITK_image(const typename ITKImageType::Pointer itk_image_orig, } /* Convert an ITK image into an internal STIR one. */ -template -static inline -STIRImageType* -convert_ITK_to_STIR(const typename ITKImageType::Pointer itk_image, - bool is_displacement_field=false) -{ +template +static inline STIRImageType* +convert_ITK_to_STIR(const typename ITKImageType::Pointer itk_image, bool is_displacement_field = false) { // Construct extra metadata - const shared_ptr exam_info_sptr - = construct_exam_info_from_metadata_dictionary(itk_image->GetMetaDataDictionary()); + const shared_ptr exam_info_sptr = construct_exam_info_from_metadata_dictionary(itk_image->GetMetaDataDictionary()); // Reorient the ITK image to align with STIR axes - typename ITKImageType::Pointer reor_itk_image - = orient_ITK_image(itk_image, exam_info_sptr); + typename ITKImageType::Pointer reor_itk_image = orient_ITK_image(itk_image, exam_info_sptr); // Make the STIR Image - STIRImageType* stir_image_ptr = construct_empty_stir_image - (reor_itk_image, exam_info_sptr); + STIRImageType* stir_image_ptr = + construct_empty_stir_image(reor_itk_image, exam_info_sptr); // Copy the ITK image data into the STIR Image - copy_ITK_data_to_STIR_image - (reor_itk_image, *stir_image_ptr, is_displacement_field); + copy_ITK_data_to_STIR_image(reor_itk_image, *stir_image_ptr, is_displacement_field); return stir_image_ptr; } -//To read any file format via ITK -template<> -inline -STIRImageSingle* -read_file_itk(const std::string &filename) -{ - typedef itk::GDCMImageIO ImageIOType; +// To read any file format via ITK +template <> +inline STIRImageSingle* +read_file_itk(const std::string& filename) { + typedef itk::GDCMImageIO ImageIOType; ImageIOType::Pointer dicomIO = ImageIOType::New(); - try - { - if (!dicomIO->CanReadFile(filename.c_str())) - { - info("Reading " + filename + " via ITK non-DICOM IO",2); - // Not a DICOM file, so we just read a single image - typedef itk::ImageFileReader ReaderType; - ReaderType::Pointer reader = ReaderType::New(); - - reader->SetFileName(filename); - reader->Update(); - ITKImageSingle::Pointer itk_image = reader->GetOutput(); - - return convert_ITK_to_STIR - - (itk_image); - } - else - { - // It's a DICOM file (I hope). - info("Reading " + filename + " via ITK DICOM IO",2); - - // For this, we need to read all slices in a series. - // We use code from ITK's Examples/IO/DicomSeriesReadImageWrite2.cxx - // to do this. - // However, we change it to read the series which contains the filename that was passed. - - // find all series in the directory - // This is by default based on unique - // \item[0020 0011] Series Number - // \item[0018 0024] Sequence Name - // \item[0018 0050] Slice Thickness - // \item[0028 0010] Rows - // \item[0028 0011] Columns - typedef itk::GDCMSeriesFileNames NamesGeneratorType; - typename NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New(); - nameGenerator->SetUseSeriesDetails( true ); - // Reads complete series. - nameGenerator->AddSeriesRestriction("0008|0022" ); // AcquisitionDate - //nameGenerator->AddSeriesRestriction("0008|0032" ); // AcquisitionTime - //nameGenerator->AddSeriesRestriction("0018|1060" ); // TriggerTime - //nameGenerator->AddSeriesRestriction("0018|1063" ); // FrameTime - - const std::string dir_name = get_directory_name(filename); - nameGenerator->SetDirectory( dir_name.c_str() ); - typedef std::vector< std::string > SeriesIdContainer; - const SeriesIdContainer & seriesUIDs = nameGenerator->GetSeriesUIDs(); - - // We've found all "series" (i.e. different data-sets according to above restrictions). Now see which one we should read. - // We do this by checking which one contains the original filename. - typedef std::vector< std::string > FileNamesContainer; - FileNamesContainer fileNames; - // Loop through all "series" - for (SeriesIdContainer::const_iterator iter=seriesUIDs.begin(); iter!= seriesUIDs.end(); ++iter) - { - fileNames = nameGenerator->GetFileNames( iter->c_str() ); - // check if filename is present - if (std::find(fileNames.begin(), fileNames.end(), filename) != fileNames.end()) - break; // yes, get out of series-loop - } - - // ok. we know which filenames are in the same "series", so let's read them - typedef itk::ImageSeriesReader< ITKImageSingle > ReaderType; - ReaderType::Pointer reader = ReaderType::New(); - - reader->SetImageIO( dicomIO ); - reader->SetFileNames( fileNames ); - reader->Update(); - ITKImageSingle::Pointer itk_image = reader->GetOutput(); - - // Update custom patient position tag in metadata - itk_image->SetMetaDataDictionary(dicomIO->GetMetaDataDictionary()); - - // Finally, convert to STIR! - return convert_ITK_to_STIR - - (itk_image); - - } - } - catch (std::exception &ex) - { - error(ex.what()); - return 0; - } -} - -//To read any file format via ITK -template<> -inline -STIRImageMulti* -read_file_itk(const std::string &filename) -{ - try - { + try { + if (!dicomIO->CanReadFile(filename.c_str())) { + info("Reading " + filename + " via ITK non-DICOM IO", 2); // Not a DICOM file, so we just read a single image - typedef itk::ImageFileReader ReaderType; + typedef itk::ImageFileReader ReaderType; ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(filename); reader->Update(); + ITKImageSingle::Pointer itk_image = reader->GetOutput(); + + return convert_ITK_to_STIR(itk_image); + } else { + // It's a DICOM file (I hope). + info("Reading " + filename + " via ITK DICOM IO", 2); + + // For this, we need to read all slices in a series. + // We use code from ITK's Examples/IO/DicomSeriesReadImageWrite2.cxx + // to do this. + // However, we change it to read the series which contains the filename that was passed. + + // find all series in the directory + // This is by default based on unique + // \item[0020 0011] Series Number + // \item[0018 0024] Sequence Name + // \item[0018 0050] Slice Thickness + // \item[0028 0010] Rows + // \item[0028 0011] Columns + typedef itk::GDCMSeriesFileNames NamesGeneratorType; + typename NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New(); + nameGenerator->SetUseSeriesDetails(true); + // Reads complete series. + nameGenerator->AddSeriesRestriction("0008|0022"); // AcquisitionDate + // nameGenerator->AddSeriesRestriction("0008|0032" ); // AcquisitionTime + // nameGenerator->AddSeriesRestriction("0018|1060" ); // TriggerTime + // nameGenerator->AddSeriesRestriction("0018|1063" ); // FrameTime + + const std::string dir_name = get_directory_name(filename); + nameGenerator->SetDirectory(dir_name.c_str()); + typedef std::vector SeriesIdContainer; + const SeriesIdContainer& seriesUIDs = nameGenerator->GetSeriesUIDs(); + + // We've found all "series" (i.e. different data-sets according to above restrictions). Now see which one we should read. + // We do this by checking which one contains the original filename. + typedef std::vector FileNamesContainer; + FileNamesContainer fileNames; + // Loop through all "series" + for (SeriesIdContainer::const_iterator iter = seriesUIDs.begin(); iter != seriesUIDs.end(); ++iter) { + fileNames = nameGenerator->GetFileNames(iter->c_str()); + // check if filename is present + if (std::find(fileNames.begin(), fileNames.end(), filename) != fileNames.end()) + break; // yes, get out of series-loop + } + + // ok. we know which filenames are in the same "series", so let's read them + typedef itk::ImageSeriesReader ReaderType; + ReaderType::Pointer reader = ReaderType::New(); + + reader->SetImageIO(dicomIO); + reader->SetFileNames(fileNames); + reader->Update(); + ITKImageSingle::Pointer itk_image = reader->GetOutput(); - // Only support Nifti for now - if (strcmp(reader->GetImageIO()->GetNameOfClass(), "NiftiImageIO") != 0) { - error("read_file_itk: Only Nifti images are currently support for multicomponent images %s:%d.", - __FILE__, __LINE__); - return NULL; } + // Update custom patient position tag in metadata + itk_image->SetMetaDataDictionary(dicomIO->GetMetaDataDictionary()); - if (reader->GetImageIO()->GetPixelType() != -#if ITK_VERSION_MAJOR<5 || (ITK_VERSION_MAJOR==5 && ITK_VERSION_MINOR==0) - itk::ImageIOBase::VECTOR + // Finally, convert to STIR! + return convert_ITK_to_STIR(itk_image); + } + } catch (std::exception& ex) { + error(ex.what()); + return 0; + } +} + +// To read any file format via ITK +template <> +inline STIRImageMulti* +read_file_itk(const std::string& filename) { + try { + // Not a DICOM file, so we just read a single image + typedef itk::ImageFileReader ReaderType; + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(filename); + reader->Update(); + + // Only support Nifti for now + if (strcmp(reader->GetImageIO()->GetNameOfClass(), "NiftiImageIO") != 0) { + error("read_file_itk: Only Nifti images are currently support for multicomponent images %s:%d.", __FILE__, __LINE__); + return NULL; + } + + if (reader->GetImageIO()->GetPixelType() != +#if ITK_VERSION_MAJOR < 5 || (ITK_VERSION_MAJOR == 5 && ITK_VERSION_MINOR == 0) + itk::ImageIOBase::VECTOR #else - itk::IOPixelEnum::VECTOR + itk::IOPixelEnum::VECTOR #endif - ) { - error("read_file_itk: Image type should be vector %s:%d.", - __FILE__, __LINE__); - return NULL; } + ) { + error("read_file_itk: Image type should be vector %s:%d.", __FILE__, __LINE__); + return NULL; + } - warning("Only displacement fields are currently supported in STIR (not deformations). " - "There is no way of verifying this from the nifti_image metadata, so you need to " - "make sure that the image you are supplying is a displacement field image."); + warning("Only displacement fields are currently supported in STIR (not deformations). " + "There is no way of verifying this from the nifti_image metadata, so you need to " + "make sure that the image you are supplying is a displacement field image."); - ITKImageMulti::Pointer itk_image = reader->GetOutput(); + ITKImageMulti::Pointer itk_image = reader->GetOutput(); - return convert_ITK_to_STIR - (itk_image, true); + return convert_ITK_to_STIR(itk_image, true); - } - catch (std::exception &ex) - { - error(ex.what()); - return 0; - } + } catch (std::exception& ex) { + error(ex.what()); + return 0; + } } // explicit instantiations diff --git a/src/IO/ITKOutputFileFormat.cxx b/src/IO/ITKOutputFileFormat.cxx index 0c2986aa15..996d773fbb 100644 --- a/src/IO/ITKOutputFileFormat.cxx +++ b/src/IO/ITKOutputFileFormat.cxx @@ -37,161 +37,133 @@ START_NAMESPACE_STIR +const char* const ITKOutputFileFormat::registered_name = "ITK"; -const char * const -ITKOutputFileFormat::registered_name = "ITK"; - -ITKOutputFileFormat:: -ITKOutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) -{ +ITKOutputFileFormat::ITKOutputFileFormat(const NumericType& type, const ByteOrder& byte_order) { this->set_defaults(); this->set_type_of_numbers(type); this->set_byte_order(byte_order); } -void -ITKOutputFileFormat:: -set_defaults() -{ +void +ITKOutputFileFormat::set_defaults() { base_type::set_defaults(); this->default_extension = ".nhdr"; } -void -ITKOutputFileFormat:: -initialise_keymap() -{ +void +ITKOutputFileFormat::initialise_keymap() { parser.add_start_key("ITK Output File Format Parameters"); parser.add_key("default extension", &this->default_extension); parser.add_stop_key("End ITK Output File Format Parameters"); base_type::initialise_keymap(); } -bool -ITKOutputFileFormat:: -post_processing() -{ +bool +ITKOutputFileFormat::post_processing() { if (base_type::post_processing()) return true; return false; } // note 'warn' commented below to avoid compiler warning message about unused variables -ByteOrder -ITKOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool /* warn */) -{ +ByteOrder +ITKOutputFileFormat::set_byte_order(const ByteOrder& new_byte_order, const bool /* warn */) { this->file_byte_order = new_byte_order; return this->file_byte_order; } - - -Succeeded -ITKOutputFileFormat:: -actual_write_to_file(std::string& filename, - const DiscretisedDensity<3,float>& density) const -{ +Succeeded +ITKOutputFileFormat::actual_write_to_file(std::string& filename, const DiscretisedDensity<3, float>& density) const { #if 0 TODO use: this->type_of_numbers, this->scale_to_write_data, this->file_byte_order); #endif - try - { - add_extension(filename, this->default_extension); - - const VoxelsOnCartesianGrid& image = - dynamic_cast& >(density); - CartesianCoordinate3D min_indices; - CartesianCoordinate3D max_indices; - if (!density.get_regular_range(min_indices, max_indices)) - { - warning("ITK writer: can handle only regular index ranges."); - return Succeeded::no; - } - - typedef itk::Image< float, 3> ImageType; - typedef itk::ImageFileWriter WriterType; - WriterType::Pointer writer = WriterType::New(); - - // use 0 start indices in ITK - ImageType::IndexType start; - start[0] = 0; // first index on X - start[1] = 0; // first index on Y - start[2] = 0; // first index on Z - - // find ITK origin (i.e. coordinates of first voxel) - ImageType::PointType origin; - CartesianCoordinate3D stir_offset - = density.get_LPS_coordinates_for_indices(min_indices); - origin[0] = stir_offset.x(); - origin[1] = stir_offset.y(); - origin[2] = stir_offset.z(); - - // find ITK size - ImageType::SizeType size; - size[0] = image.get_x_size(); // size along X - size[1] = image.get_y_size(); // size along Y - size[2] = image.get_z_size(); // size along Z - - // find ITK voxel size - ImageType::SpacingType spacing; - spacing[0] = image.get_voxel_size().x(); // size along X - spacing[1] = image.get_voxel_size().y(); // size along Y - spacing[2] = image.get_voxel_size().z(); // size along Z - - // ITK Direction Matrix columns are unit vectors in axes LPS direction. - // NB: ITK Matrix is in row, column order - ImageType::DirectionType matrix; - for (unsigned int axis = 0; axis < 3; ++axis) { - CartesianCoordinate3D next_idx_along_this_axis(min_indices); - next_idx_along_this_axis[3 - axis] += 1; - const CartesianCoordinate3D next_coord_along_this_dim - = density.get_LPS_coordinates_for_indices(next_idx_along_this_axis); - const CartesianCoordinate3D axis_direction - = next_coord_along_this_dim - stir_offset; - for (unsigned int dim = 0; dim < 3; ++dim) { - matrix(dim, axis) = axis_direction[3 - dim] / norm(axis_direction); - } - } + try { + add_extension(filename, this->default_extension); + + const VoxelsOnCartesianGrid& image = dynamic_cast&>(density); + CartesianCoordinate3D min_indices; + CartesianCoordinate3D max_indices; + if (!density.get_regular_range(min_indices, max_indices)) { + warning("ITK writer: can handle only regular index ranges."); + return Succeeded::no; + } - ImageType::RegionType region; - region.SetSize( size ); - region.SetIndex( start ); - - //Creating the image - ImageType::Pointer itk_image = ImageType::New(); - - itk_image->SetSpacing(spacing); - itk_image->SetRegions( region ); - itk_image->SetOrigin(origin); - itk_image->SetDirection( matrix ); - itk_image->Allocate(); - - // copy data - typedef itk::ImageRegionIterator< ImageType > IteratorType; - IteratorType it (itk_image, itk_image->GetLargestPossibleRegion() ); - DiscretisedDensity<3,float>::const_full_iterator stir_iter = density.begin_all_const(); - for ( it.GoToBegin(); !it.IsAtEnd(); ++it, ++stir_iter ){ - it.Set(*stir_iter); + typedef itk::Image ImageType; + typedef itk::ImageFileWriter WriterType; + WriterType::Pointer writer = WriterType::New(); + + // use 0 start indices in ITK + ImageType::IndexType start; + start[0] = 0; // first index on X + start[1] = 0; // first index on Y + start[2] = 0; // first index on Z + + // find ITK origin (i.e. coordinates of first voxel) + ImageType::PointType origin; + CartesianCoordinate3D stir_offset = density.get_LPS_coordinates_for_indices(min_indices); + origin[0] = stir_offset.x(); + origin[1] = stir_offset.y(); + origin[2] = stir_offset.z(); + + // find ITK size + ImageType::SizeType size; + size[0] = image.get_x_size(); // size along X + size[1] = image.get_y_size(); // size along Y + size[2] = image.get_z_size(); // size along Z + + // find ITK voxel size + ImageType::SpacingType spacing; + spacing[0] = image.get_voxel_size().x(); // size along X + spacing[1] = image.get_voxel_size().y(); // size along Y + spacing[2] = image.get_voxel_size().z(); // size along Z + + // ITK Direction Matrix columns are unit vectors in axes LPS direction. + // NB: ITK Matrix is in row, column order + ImageType::DirectionType matrix; + for (unsigned int axis = 0; axis < 3; ++axis) { + CartesianCoordinate3D next_idx_along_this_axis(min_indices); + next_idx_along_this_axis[3 - axis] += 1; + const CartesianCoordinate3D next_coord_along_this_dim = + density.get_LPS_coordinates_for_indices(next_idx_along_this_axis); + const CartesianCoordinate3D axis_direction = next_coord_along_this_dim - stir_offset; + for (unsigned int dim = 0; dim < 3; ++dim) { + matrix(dim, axis) = axis_direction[3 - dim] / norm(axis_direction); } - - // write it! - writer->SetInput(itk_image); - writer->SetFileName(filename); - writer->Update(); - - return Succeeded::yes; } - catch (...) - { - return Succeeded::no; + + ImageType::RegionType region; + region.SetSize(size); + region.SetIndex(start); + + // Creating the image + ImageType::Pointer itk_image = ImageType::New(); + + itk_image->SetSpacing(spacing); + itk_image->SetRegions(region); + itk_image->SetOrigin(origin); + itk_image->SetDirection(matrix); + itk_image->Allocate(); + + // copy data + typedef itk::ImageRegionIterator IteratorType; + IteratorType it(itk_image, itk_image->GetLargestPossibleRegion()); + DiscretisedDensity<3, float>::const_full_iterator stir_iter = density.begin_all_const(); + for (it.GoToBegin(); !it.IsAtEnd(); ++it, ++stir_iter) { + it.Set(*stir_iter); } + // write it! + writer->SetInput(itk_image); + writer->SetFileName(filename); + writer->Update(); + + return Succeeded::yes; + } catch (...) { + return Succeeded::no; + } } END_NAMESPACE_STIR - - diff --git a/src/IO/InputFileFormatRegistry.cxx b/src/IO/InputFileFormatRegistry.cxx index 815305805b..08214c98ee 100644 --- a/src/IO/InputFileFormatRegistry.cxx +++ b/src/IO/InputFileFormatRegistry.cxx @@ -27,17 +27,17 @@ #include "stir/IO/InputFileFormatRegistry.txx" #include "stir/DiscretisedDensity.h" -#include "stir/modelling/ParametricDiscretisedDensity.h" -#include "stir/DynamicDiscretisedDensity.h" +#include "stir/modelling/ParametricDiscretisedDensity.h" +#include "stir/DynamicDiscretisedDensity.h" #include "stir/listmode/ListModeData.h" START_NAMESPACE_STIR // instantiations -template class InputFileFormatRegistry >; -template class InputFileFormatRegistry; +template class InputFileFormatRegistry>; +template class InputFileFormatRegistry; template class InputFileFormatRegistry; template class InputFileFormatRegistry; -template class InputFileFormatRegistry > >; +template class InputFileFormatRegistry>>; END_NAMESPACE_STIR diff --git a/src/IO/InputStreamFromROOTFile.cxx b/src/IO/InputStreamFromROOTFile.cxx index 3e9e183fe2..4808f33be1 100644 --- a/src/IO/InputStreamFromROOTFile.cxx +++ b/src/IO/InputStreamFromROOTFile.cxx @@ -10,6 +10,7 @@ * Copyright (C) 2015, 2016 University of Leeds Copyright (C) 2016, 2020 UCL Copyright (C) 2018 University of Hull + This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -37,11 +38,10 @@ START_NAMESPACE_STIR -InputStreamFromROOTFile:: -InputStreamFromROOTFile() -{ - set_defaults(); - reset(); +InputStreamFromROOTFile::InputStreamFromROOTFile() { + set_defaults(); + reset(); + least_significant_clock_bit = 1.0e+12; // TODO remove cst or rename } #if 0 // disabled as unused and incorrect @@ -62,131 +62,117 @@ InputStreamFromROOTFile(std::string filename, #endif void -InputStreamFromROOTFile::set_defaults() -{ - starting_stream_position = 0; - singles_readout_depth = -1; - exclude_scattered = false; - exclude_randoms = false; - low_energy_window = 0.f; - up_energy_window = 1000.f; - read_optional_root_fields=false; - crystal_repeater_x = -1; - crystal_repeater_y = -1; - crystal_repeater_z = -1; - num_virtual_axial_crystals_per_block = 0; - num_virtual_transaxial_crystals_per_block = 0; +InputStreamFromROOTFile::set_defaults() { + starting_stream_position = 0; + singles_readout_depth = -1; + exclude_scattered = false; + exclude_randoms = false; + low_energy_window = 0.f; + up_energy_window = 1000.f; + read_optional_root_fields = false; + crystal_repeater_x = -1; + crystal_repeater_y = -1; + crystal_repeater_z = -1; + num_virtual_axial_crystals_per_block = 0; + num_virtual_transaxial_crystals_per_block = 0; } void -InputStreamFromROOTFile::initialise_keymap() -{ - this->parser.add_key("name of data file", &this->filename); - this->parser.add_key("Singles readout depth", &this->singles_readout_depth); - this->parser.add_key("name of input TChain", &this->chain_name); - this->parser.add_key("exclude scattered events", &this->exclude_scattered); - this->parser.add_key("exclude random events", &this->exclude_randoms); - this->parser.add_key("offset (num of detectors)", &this->offset_dets); - this->parser.add_key("low energy window (keV)", &this->low_energy_window); - this->parser.add_key("upper energy window (keV)", &this->up_energy_window); - this->parser.add_key("read optional ROOT fields", &this->read_optional_root_fields); - - this->parser.add_key("number of crystals X", &this->crystal_repeater_x); - this->parser.add_key("number of crystals Y", &this->crystal_repeater_y); - this->parser.add_key("number of crystals Z", &this->crystal_repeater_z); +InputStreamFromROOTFile::initialise_keymap() { + this->parser.add_key("name of data file", &this->filename); + this->parser.add_key("Singles readout depth", &this->singles_readout_depth); + this->parser.add_key("name of input TChain", &this->chain_name); + this->parser.add_key("exclude scattered events", &this->exclude_scattered); + this->parser.add_key("exclude random events", &this->exclude_randoms); + this->parser.add_key("offset (num of detectors)", &this->offset_dets); + this->parser.add_key("low energy window (keV)", &this->low_energy_window); + this->parser.add_key("upper energy window (keV)", &this->up_energy_window); + this->parser.add_key("read optional ROOT fields", &this->read_optional_root_fields); + + this->parser.add_key("number of crystals X", &this->crystal_repeater_x); + this->parser.add_key("number of crystals Y", &this->crystal_repeater_y); + this->parser.add_key("number of crystals Z", &this->crystal_repeater_z); } bool -InputStreamFromROOTFile::post_processing() -{ - return false; +InputStreamFromROOTFile::post_processing() { + return false; } Succeeded -InputStreamFromROOTFile::set_up(const std::string & header_path) -{ - // check types, really should be compile time assert - if (!std::is_same::value || - !std::is_same::value || - !std::is_same::value) - error("Internal error: ROOT types are not what we think they are."); - - FilePath f(filename,false); - f.prepend_directory_name(header_path); - - const std::string fullfilename = f.get_as_string(); - // Read the 4 bytes to check whether this is a ROOT file. - FileSignature signature(fullfilename.c_str()); - if ( strncmp(signature.get_signature(), "root", 4) != 0) - { - error("InputStreamFromROOTFile: File '%s' is not a ROOT file! (first 4 bytes should say 'root')", - filename.c_str()); - } - - stream_ptr = new TChain(this->chain_name.c_str()); - stream_ptr->Add(fullfilename.c_str()); - stream_ptr->SetBranchAddress("time1", &time1); - stream_ptr->SetBranchAddress("time2", &time2); - stream_ptr->SetBranchAddress("eventID1",&eventID1); - stream_ptr->SetBranchAddress("eventID2",&eventID2); - stream_ptr->SetBranchAddress("energy1", &energy1); - stream_ptr->SetBranchAddress("energy2", &energy2); - stream_ptr->SetBranchAddress("comptonPhantom1", &comptonphantom1); - stream_ptr->SetBranchAddress("comptonPhantom2", &comptonphantom2); - - if (read_optional_root_fields) - { - stream_ptr->SetBranchAddress("axialPos",&axialPos); - stream_ptr->SetBranchAddress("globalPosX1",&globalPosX1); - stream_ptr->SetBranchAddress("globalPosX2",&globalPosX2); - stream_ptr->SetBranchAddress("globalPosY1",&globalPosY1); - stream_ptr->SetBranchAddress("globalPosY2",&globalPosY2); - stream_ptr->SetBranchAddress("globalPosZ1",&globalPosZ1); - stream_ptr->SetBranchAddress("globalPosZ2",&globalPosZ2); - stream_ptr->SetBranchAddress("rotationAngle",&rotation_angle); - stream_ptr->SetBranchAddress("runID",&runID); - stream_ptr->SetBranchAddress("sinogramS",&sinogramS); - stream_ptr->SetBranchAddress("sinogramTheta",&sinogramTheta); - stream_ptr->SetBranchAddress("sourceID1",&sourceID1); - stream_ptr->SetBranchAddress("sourceID2",&sourceID2); - stream_ptr->SetBranchAddress("sourcePosX1",&sourcePosX1); - stream_ptr->SetBranchAddress("sourcePosX2",&sourcePosX2); - stream_ptr->SetBranchAddress("sourcePosY1",&sourcePosY1); - stream_ptr->SetBranchAddress("sourcePosY2",&sourcePosY2); - stream_ptr->SetBranchAddress("sourcePosZ1",&sourcePosZ1); - stream_ptr->SetBranchAddress("sourcePosZ2",&sourcePosZ2); - } - - return Succeeded::yes; +InputStreamFromROOTFile::set_up(const std::string& header_path) { + // check types, really should be compile time assert + if (!std::is_same::value || !std::is_same::value || !std::is_same::value) + error("Internal error: ROOT types are not what we think they are."); + + FilePath f(filename, false); + f.prepend_directory_name(header_path); + + const std::string fullfilename = f.get_as_string(); + // Read the 4 bytes to check whether this is a ROOT file. + FileSignature signature(fullfilename.c_str()); + if (strncmp(signature.get_signature(), "root", 4) != 0) { + error("InputStreamFromROOTFile: File '%s' is not a ROOT file! (first 4 bytes should say 'root')", filename.c_str()); + } + + stream_ptr = new TChain(this->chain_name.c_str()); + stream_ptr->Add(fullfilename.c_str()); + stream_ptr->SetBranchAddress("time1", &time1); + stream_ptr->SetBranchAddress("time2", &time2); + stream_ptr->SetBranchAddress("eventID1", &eventID1); + stream_ptr->SetBranchAddress("eventID2", &eventID2); + stream_ptr->SetBranchAddress("energy1", &energy1); + stream_ptr->SetBranchAddress("energy2", &energy2); + stream_ptr->SetBranchAddress("comptonPhantom1", &comptonphantom1); + stream_ptr->SetBranchAddress("comptonPhantom2", &comptonphantom2); + + if (read_optional_root_fields) { + stream_ptr->SetBranchAddress("axialPos", &axialPos); + stream_ptr->SetBranchAddress("globalPosX1", &globalPosX1); + stream_ptr->SetBranchAddress("globalPosX2", &globalPosX2); + stream_ptr->SetBranchAddress("globalPosY1", &globalPosY1); + stream_ptr->SetBranchAddress("globalPosY2", &globalPosY2); + stream_ptr->SetBranchAddress("globalPosZ1", &globalPosZ1); + stream_ptr->SetBranchAddress("globalPosZ2", &globalPosZ2); + stream_ptr->SetBranchAddress("rotationAngle", &rotation_angle); + stream_ptr->SetBranchAddress("runID", &runID); + stream_ptr->SetBranchAddress("sinogramS", &sinogramS); + stream_ptr->SetBranchAddress("sinogramTheta", &sinogramTheta); + stream_ptr->SetBranchAddress("sourceID1", &sourceID1); + stream_ptr->SetBranchAddress("sourceID2", &sourceID2); + stream_ptr->SetBranchAddress("sourcePosX1", &sourcePosX1); + stream_ptr->SetBranchAddress("sourcePosX2", &sourcePosX2); + stream_ptr->SetBranchAddress("sourcePosY1", &sourcePosY1); + stream_ptr->SetBranchAddress("sourcePosY2", &sourcePosY2); + stream_ptr->SetBranchAddress("sourcePosZ1", &sourcePosZ1); + stream_ptr->SetBranchAddress("sourcePosZ2", &sourcePosZ2); + } + + return Succeeded::yes; } void -InputStreamFromROOTFile::set_crystal_repeater_x(int val) -{ - crystal_repeater_x = val; +InputStreamFromROOTFile::set_crystal_repeater_x(int val) { + crystal_repeater_x = val; } void -InputStreamFromROOTFile::set_crystal_repeater_y(int val) -{ - crystal_repeater_y = val; +InputStreamFromROOTFile::set_crystal_repeater_y(int val) { + crystal_repeater_y = val; } void -InputStreamFromROOTFile::set_crystal_repeater_z(int val) -{ - crystal_repeater_z = val; +InputStreamFromROOTFile::set_crystal_repeater_z(int val) { + crystal_repeater_z = val; } void -InputStreamFromROOTFile::set_num_virtual_axial_crystals_per_block(int val) -{ +InputStreamFromROOTFile::set_num_virtual_axial_crystals_per_block(int val) { num_virtual_axial_crystals_per_block = val; } void -InputStreamFromROOTFile::set_num_virtual_transaxial_crystals_per_block(int val) -{ +InputStreamFromROOTFile::set_num_virtual_transaxial_crystals_per_block(int val) { num_virtual_transaxial_crystals_per_block = val; } diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index 7e8093a709..e2f42d68a1 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -20,16 +20,9 @@ START_NAMESPACE_STIR -const char * const -InputStreamFromROOTFileForCylindricalPET::registered_name = - "GATE_Cylindrical_PET"; +const char* const InputStreamFromROOTFileForCylindricalPET::registered_name = "GATE_Cylindrical_PET"; -InputStreamFromROOTFileForCylindricalPET:: -InputStreamFromROOTFileForCylindricalPET(): - base_type() -{ - set_defaults(); -} +InputStreamFromROOTFileForCylindricalPET::InputStreamFromROOTFileForCylindricalPET() : base_type() { set_defaults(); } #if 0 // not used, so commented out (would need adapting since moving crystal_repeated_*) InputStreamFromROOTFileForCylindricalPET:: InputStreamFromROOTFileForCylindricalPET(std::string _filename, @@ -58,223 +51,202 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, up_energy_window = _up_energy_window; offset_dets = _offset_dets; - half_block = module_repeater_y * submodule_repeater_y * crystal_repeater_y / 2 - 1; + half_block = (module_repeater_y * submodule_repeater_y * crystal_repeater_y) / 2; if (half_block < 0 ) half_block = 0; } #endif Succeeded -InputStreamFromROOTFileForCylindricalPET:: -get_next_record(CListRecordROOT& record) -{ +InputStreamFromROOTFileForCylindricalPET::get_next_record(CListRecordROOT& record) { + + while (true) { + if (current_position == nentries) + return Succeeded::no; + + if (stream_ptr->GetEntry(static_cast(current_position)) == 0) + return Succeeded::no; + + current_position++; + + if ((this->comptonphantom1 > 0 || this->comptonphantom2 > 0) && this->exclude_scattered) + continue; + if ((this->eventID1 != this->eventID2) && this->exclude_randoms) + continue; + // multiply here by 1000 to convert the list mode energy from MeV to keV + if (this->get_energy1_in_keV() < this->low_energy_window || this->get_energy1_in_keV() > this->up_energy_window || + this->get_energy2_in_keV() < this->low_energy_window || this->get_energy2_in_keV() > this->up_energy_window) + continue; + + break; + } + + int ring1 = static_cast(crystalID1 / crystal_repeater_y) + + static_cast(submoduleID1 / submodule_repeater_y) * get_num_axial_crystals_per_block_v() + + static_cast(moduleID1 / module_repeater_y) * submodule_repeater_z * get_num_axial_crystals_per_block_v(); + + int ring2 = static_cast(crystalID2 / crystal_repeater_y) + + static_cast(submoduleID2 / submodule_repeater_y) * get_num_axial_crystals_per_block_v() + + static_cast(moduleID2 / module_repeater_y) * submodule_repeater_z * get_num_axial_crystals_per_block_v(); + + int crystal1 = rsectorID1 * module_repeater_y * submodule_repeater_y * get_num_transaxial_crystals_per_block_v() + + (moduleID1 % module_repeater_y) * submodule_repeater_y * get_num_transaxial_crystals_per_block_v() + + (submoduleID1 % submodule_repeater_y) * get_num_transaxial_crystals_per_block_v() + + (crystalID1 % crystal_repeater_y); - while(true) - { - if (current_position == nentries) - return Succeeded::no; - - - if (stream_ptr->GetEntry(static_cast(current_position)) == 0 ) - return Succeeded::no; - - current_position ++ ; - - if ( (this->comptonphantom1 > 0 || this->comptonphantom2 > 0) && this->exclude_scattered ) - continue; - if ( (this->eventID1 != this->eventID2) && this->exclude_randoms) - continue; - //multiply here by 1000 to convert the list mode energy from MeV to keV - if (this->get_energy1_in_keV() < this->low_energy_window || - this->get_energy1_in_keV() > this->up_energy_window || - this->get_energy2_in_keV() < this->low_energy_window || - this->get_energy2_in_keV() > this->up_energy_window) - continue; - - break; - } - - int ring1 = static_cast(crystalID1/crystal_repeater_y) - + static_cast(submoduleID1/submodule_repeater_y)*get_num_axial_crystals_per_block_v() - + static_cast(moduleID1/module_repeater_y)*submodule_repeater_z*get_num_axial_crystals_per_block_v(); - - int ring2 = static_cast(crystalID2/crystal_repeater_y) - + static_cast(submoduleID2/submodule_repeater_y)*get_num_axial_crystals_per_block_v() - + static_cast(moduleID2/module_repeater_y)*submodule_repeater_z*get_num_axial_crystals_per_block_v(); - - int crystal1 = rsectorID1 * module_repeater_y * submodule_repeater_y * get_num_transaxial_crystals_per_block_v() - + (moduleID1%module_repeater_y) * submodule_repeater_y * get_num_transaxial_crystals_per_block_v() - + (submoduleID1%submodule_repeater_y) * get_num_transaxial_crystals_per_block_v() - + (crystalID1%crystal_repeater_y); - - int crystal2 = rsectorID2 * module_repeater_y * submodule_repeater_y * get_num_transaxial_crystals_per_block_v() - + (moduleID2%module_repeater_y) * submodule_repeater_y * get_num_transaxial_crystals_per_block_v() - + (submoduleID2% submodule_repeater_y) * get_num_transaxial_crystals_per_block_v() - + (crystalID2%crystal_repeater_y); - - // GATE counts crystal ID =0 the most negative. Therefore - // ID = 0 should be negative, in Rsector 0 and the mid crystal ID be 0 . - crystal1 -= half_block; - crystal2 -= half_block; - - // Add offset - crystal1 += offset_dets; - crystal2 += offset_dets; - - return - record.init_from_data(ring1, ring2, - crystal1, crystal2, - time1, time2, - eventID1, eventID2); + int crystal2 = rsectorID2 * module_repeater_y * submodule_repeater_y * get_num_transaxial_crystals_per_block_v() + + (moduleID2 % module_repeater_y) * submodule_repeater_y * get_num_transaxial_crystals_per_block_v() + + (submoduleID2 % submodule_repeater_y) * get_num_transaxial_crystals_per_block_v() + + (crystalID2 % crystal_repeater_y); + + // GATE counts crystal ID =0 the most negative. Therefore + // ID = 0 should be negative, in Rsector 0 and the mid crystal ID be 0 . + // Moved to post_processings(). + // crystal1 -= half_block; + // crystal2 -= half_block; + + // Add offset + crystal1 += offset_dets; + crystal2 += offset_dets; + + double delta_timing_bin = (time2 - time1) * least_significant_clock_bit; + + return record.init_from_data(ring1, ring2, crystal1, crystal2, time1, delta_timing_bin, eventID1, eventID2); } std::string -InputStreamFromROOTFileForCylindricalPET:: -method_info() const -{ - std::ostringstream s; - s << this->registered_name; - return s.str(); +InputStreamFromROOTFileForCylindricalPET::method_info() const { + std::ostringstream s; + s << this->registered_name; + return s.str(); } void -InputStreamFromROOTFileForCylindricalPET::set_defaults() -{ - base_type::set_defaults(); - submodule_repeater_x = -1; - submodule_repeater_y = -1; - submodule_repeater_z = -1; - module_repeater_x = -1; - module_repeater_y = -1; - module_repeater_z = -1; - rsector_repeater = -1; +InputStreamFromROOTFileForCylindricalPET::set_defaults() { + base_type::set_defaults(); + submodule_repeater_x = -1; + submodule_repeater_y = -1; + submodule_repeater_z = -1; + module_repeater_x = -1; + module_repeater_y = -1; + module_repeater_z = -1; + rsector_repeater = -1; } void -InputStreamFromROOTFileForCylindricalPET::initialise_keymap() -{ - base_type::initialise_keymap(); - this->parser.add_start_key("GATE_Cylindrical_PET Parameters"); - this->parser.add_stop_key("End GATE_Cylindrical_PET Parameters"); - this->parser.add_key("number of Rsectors", &this->rsector_repeater); - this->parser.add_key("number of modules X", &this->module_repeater_x); - this->parser.add_key("number of modules Y", &this->module_repeater_y); - this->parser.add_key("number of modules Z", &this->module_repeater_z); - - this->parser.add_key("number of submodules X", &this->submodule_repeater_x); - this->parser.add_key("number of submodules Y", &this->submodule_repeater_y); - this->parser.add_key("number of submodules Z", &this->submodule_repeater_z); +InputStreamFromROOTFileForCylindricalPET::initialise_keymap() { + base_type::initialise_keymap(); + this->parser.add_start_key("GATE_Cylindrical_PET Parameters"); + this->parser.add_stop_key("End GATE_Cylindrical_PET Parameters"); + this->parser.add_key("number of Rsectors", &this->rsector_repeater); + this->parser.add_key("number of modules X", &this->module_repeater_x); + this->parser.add_key("number of modules Y", &this->module_repeater_y); + this->parser.add_key("number of modules Z", &this->module_repeater_z); + + this->parser.add_key("number of submodules X", &this->submodule_repeater_x); + this->parser.add_key("number of submodules Y", &this->submodule_repeater_y); + this->parser.add_key("number of submodules Z", &this->submodule_repeater_z); } -bool InputStreamFromROOTFileForCylindricalPET:: -post_processing() -{ - if (base_type::post_processing()) - return true; - return false; +bool +InputStreamFromROOTFileForCylindricalPET::post_processing() { + if (base_type::post_processing()) + return true; + return false; } Succeeded -InputStreamFromROOTFileForCylindricalPET:: -set_up(const std::string & header_path) -{ - if (base_type::set_up(header_path) == Succeeded::no) - return Succeeded::no; - - std::string missing_keywords; - if(!check_all_required_keywords_are_set(missing_keywords)) - { - warning(missing_keywords.c_str()); - return Succeeded::no; - } - - stream_ptr->SetBranchAddress("crystalID1",&crystalID1); - stream_ptr->SetBranchAddress("crystalID2",&crystalID2); - stream_ptr->SetBranchAddress("submoduleID1",&submoduleID1); - stream_ptr->SetBranchAddress("submoduleID2",&submoduleID2); - stream_ptr->SetBranchAddress("moduleID1",&moduleID1); - stream_ptr->SetBranchAddress("moduleID2",&moduleID2); - stream_ptr->SetBranchAddress("rsectorID1",&rsectorID1); - stream_ptr->SetBranchAddress("rsectorID2",&rsectorID2); - - nentries = static_cast(stream_ptr->GetEntries()); - if (nentries == 0) - error("InputStreamFromROOTFileForCylindricalPET: The total number of entries in the ROOT file is zero. Abort."); - - return Succeeded::yes; +InputStreamFromROOTFileForCylindricalPET::set_up(const std::string& header_path) { + if (base_type::set_up(header_path) == Succeeded::no) + return Succeeded::no; + + std::string missing_keywords; + if (!check_all_required_keywords_are_set(missing_keywords)) { + warning(missing_keywords.c_str()); + return Succeeded::no; + } + + stream_ptr->SetBranchAddress("crystalID1", &crystalID1); + stream_ptr->SetBranchAddress("crystalID2", &crystalID2); + stream_ptr->SetBranchAddress("submoduleID1", &submoduleID1); + stream_ptr->SetBranchAddress("submoduleID2", &submoduleID2); + stream_ptr->SetBranchAddress("moduleID1", &moduleID1); + stream_ptr->SetBranchAddress("moduleID2", &moduleID2); + stream_ptr->SetBranchAddress("rsectorID1", &rsectorID1); + stream_ptr->SetBranchAddress("rsectorID2", &rsectorID2); + + nentries = static_cast(stream_ptr->GetEntries()); + if (nentries == 0) + error("InputStreamFromROOTFileForCylindricalPET: The total number of entries in the ROOT file is zero. Abort."); + + half_block = (module_repeater_y * submodule_repeater_y * crystal_repeater_y) / 2; + if (half_block < 0) + half_block = 0; + + offset_dets -= half_block; + + return Succeeded::yes; } -bool InputStreamFromROOTFileForCylindricalPET:: -check_all_required_keywords_are_set(std::string& ret) const -{ - std::ostringstream stream("InputStreamFromROOTFileForCylindricalPET: Required keywords are missing! Check: "); - bool ok = true; - - if (crystal_repeater_x == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (crystal_repeater_y == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (crystal_repeater_z == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (submodule_repeater_x == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (submodule_repeater_y == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (submodule_repeater_z == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (module_repeater_x == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (module_repeater_y == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (module_repeater_z == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (rsector_repeater == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (!ok) - ret = stream.str(); - - return ok; +bool +InputStreamFromROOTFileForCylindricalPET::check_all_required_keywords_are_set(std::string& ret) const { + std::ostringstream stream("InputStreamFromROOTFileForCylindricalPET: Required keywords are missing! Check: "); + bool ok = true; + + if (crystal_repeater_x == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (crystal_repeater_y == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (crystal_repeater_z == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (submodule_repeater_x == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (submodule_repeater_y == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (submodule_repeater_z == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (module_repeater_x == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (module_repeater_y == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (module_repeater_z == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (rsector_repeater == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (!ok) + ret = stream.str(); + + return ok; } - END_NAMESPACE_STIR diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 24d6e5e741..0e325c30f5 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -21,16 +21,9 @@ START_NAMESPACE_STIR -const char * const -InputStreamFromROOTFileForECATPET::registered_name = - "GATE_ECAT_PET"; +const char* const InputStreamFromROOTFileForECATPET::registered_name = "GATE_ECAT_PET"; -InputStreamFromROOTFileForECATPET:: -InputStreamFromROOTFileForECATPET(): - base_type() -{ - set_defaults(); -} +InputStreamFromROOTFileForECATPET::InputStreamFromROOTFileForECATPET() : base_type() { set_defaults(); } #if 0 // not used, so commented out (would need adapting since moving crystal_repeated_*) InputStreamFromROOTFileForECATPET:: @@ -63,160 +56,137 @@ InputStreamFromROOTFileForECATPET(std::string _filename, #endif Succeeded -InputStreamFromROOTFileForECATPET:: -get_next_record(CListRecordROOT& record) -{ - while(true) - { - if (current_position == nentries) - return Succeeded::no; +InputStreamFromROOTFileForECATPET::get_next_record(CListRecordROOT& record) { + while (true) { + if (current_position == nentries) + return Succeeded::no; + if (stream_ptr->GetEntry(current_position) == 0) + return Succeeded::no; - if (stream_ptr->GetEntry(current_position) == 0 ) - return Succeeded::no; + current_position++; - current_position ++ ; + if ((comptonphantom1 > 0 || comptonphantom2 > 0) && exclude_scattered) + continue; + if (eventID1 != eventID2 && exclude_randoms) + continue; + // multiply here by 1000 to convert the list mode energy from MeV to keV + if (this->get_energy1_in_keV() < low_energy_window || this->get_energy1_in_keV() > up_energy_window || + this->get_energy2_in_keV() < low_energy_window || this->get_energy2_in_keV() > up_energy_window) + continue; - if ( (comptonphantom1 > 0 || comptonphantom2 > 0) && exclude_scattered ) - continue; - if ( eventID1 != eventID2 && exclude_randoms ) - continue; - //multiply here by 1000 to convert the list mode energy from MeV to keV - if (this->get_energy1_in_keV() < low_energy_window || - this->get_energy1_in_keV() > up_energy_window || - this->get_energy2_in_keV() < low_energy_window || - this->get_energy2_in_keV() > up_energy_window) - continue; + break; + } - break; - } + int ring1 = + static_cast(crystalID1 / crystal_repeater_y) + static_cast(blockID1 / block_repeater_y) * crystal_repeater_z; - int ring1 = static_cast(crystalID1/crystal_repeater_y) - + static_cast(blockID1/ block_repeater_y)*crystal_repeater_z; + int ring2 = + static_cast(crystalID2 / crystal_repeater_y) + static_cast(blockID2 / block_repeater_y) * crystal_repeater_z; - int ring2 = static_cast(crystalID2/crystal_repeater_y) - + static_cast(blockID2/block_repeater_y)*crystal_repeater_z; + int crystal1 = (blockID1 % block_repeater_y) * get_num_transaxial_crystals_per_block_v() + (crystalID1 % crystal_repeater_y); - int crystal1 = (blockID1%block_repeater_y) * get_num_transaxial_crystals_per_block_v() - + (crystalID1%crystal_repeater_y); + int crystal2 = (blockID2 % block_repeater_y) * get_num_transaxial_crystals_per_block_v() + (crystalID2 % crystal_repeater_y); - int crystal2 = (blockID2%block_repeater_y) * get_num_transaxial_crystals_per_block_v() - + (crystalID2%crystal_repeater_y); + // GATE counts crystal ID =0 the most negative. Therefore + // ID = 0 should be negative, in Rsector 0 and the mid crystal ID be 0 . + crystal1 -= half_block; + crystal2 -= half_block; - // GATE counts crystal ID =0 the most negative. Therefore - // ID = 0 should be negative, in Rsector 0 and the mid crystal ID be 0 . - crystal1 -= half_block; - crystal2 -= half_block; + // Add offset + crystal1 += offset_dets; + crystal2 += offset_dets; - // Add offset - crystal1 += offset_dets; - crystal2 += offset_dets; + double delta_timing_bin = (time2 - time1) * least_significant_clock_bit; - return - record.init_from_data(ring1, ring2, - crystal1, crystal2, - time1, time2, - eventID1, eventID2); + return record.init_from_data(ring1, ring2, crystal1, crystal2, time1, delta_timing_bin, eventID1, eventID2); } std::string -InputStreamFromROOTFileForECATPET:: -method_info() const -{ - std::ostringstream s; - s << this->registered_name; - return s.str(); +InputStreamFromROOTFileForECATPET::method_info() const { + std::ostringstream s; + s << this->registered_name; + return s.str(); } void -InputStreamFromROOTFileForECATPET::set_defaults() -{ - base_type::set_defaults(); - block_repeater_y = -1; - block_repeater_z = -1; +InputStreamFromROOTFileForECATPET::set_defaults() { + base_type::set_defaults(); + block_repeater_y = -1; + block_repeater_z = -1; } void -InputStreamFromROOTFileForECATPET::initialise_keymap() -{ - base_type::initialise_keymap(); - this->parser.add_start_key("GATE_ECAT_PET Parameters"); - this->parser.add_stop_key("End GATE_ECAT_PET Parameters"); - this->parser.add_key("number of blocks Y", &this->block_repeater_y); - this->parser.add_key("number of blocks Z", &this->block_repeater_z); +InputStreamFromROOTFileForECATPET::initialise_keymap() { + base_type::initialise_keymap(); + this->parser.add_start_key("GATE_ECAT_PET Parameters"); + this->parser.add_stop_key("End GATE_ECAT_PET Parameters"); + this->parser.add_key("number of blocks Y", &this->block_repeater_y); + this->parser.add_key("number of blocks Z", &this->block_repeater_z); } -bool InputStreamFromROOTFileForECATPET:: -post_processing() -{ - return false; +bool +InputStreamFromROOTFileForECATPET::post_processing() { + return false; } -Succeeded InputStreamFromROOTFileForECATPET:: -set_up(const std::string & header_path ) -{ - if (base_type::set_up(header_path) == Succeeded::no) - return Succeeded::no; - - std::string missing_keywords; - if(!check_all_required_keywords_are_set(missing_keywords)) - { - warning(missing_keywords.c_str()); - return Succeeded::no; - } - - stream_ptr->SetBranchAddress("crystalID1",&crystalID1); - stream_ptr->SetBranchAddress("crystalID2",&crystalID2); - stream_ptr->SetBranchAddress("blockID1",&blockID1); - stream_ptr->SetBranchAddress("blockID2",&blockID2); - - nentries = static_cast(stream_ptr->GetEntries()); - if (nentries == 0) - error("The total number of entries in the ROOT file is zero. Abort."); - - return Succeeded::yes; +Succeeded +InputStreamFromROOTFileForECATPET::set_up(const std::string& header_path) { + if (base_type::set_up(header_path) == Succeeded::no) + return Succeeded::no; + + std::string missing_keywords; + if (!check_all_required_keywords_are_set(missing_keywords)) { + warning(missing_keywords.c_str()); + return Succeeded::no; + } + + stream_ptr->SetBranchAddress("crystalID1", &crystalID1); + stream_ptr->SetBranchAddress("crystalID2", &crystalID2); + stream_ptr->SetBranchAddress("blockID1", &blockID1); + stream_ptr->SetBranchAddress("blockID2", &blockID2); + + nentries = static_cast(stream_ptr->GetEntries()); + if (nentries == 0) + error("The total number of entries in the ROOT file is zero. Abort."); + + return Succeeded::yes; } -bool InputStreamFromROOTFileForECATPET:: -check_all_required_keywords_are_set(std::string& ret) const -{ - std::ostringstream stream("InputStreamFromROOTFileForCylindricalPET: Required keywords are missing! Check: "); - bool ok = true; - - if (crystal_repeater_x == -1) - { - stream << "crystal_repeater_x, "; - ok = false; - } - - if (crystal_repeater_y == -1) - { - stream << "crystal_repeater_y, "; - ok = false; - } - - if (crystal_repeater_z == -1) - { - stream << "crystal_repeater_z, "; - ok = false; - } - - if (block_repeater_y == -1) - { - stream << "block_repeater_y, "; - ok = false; - } - - if (block_repeater_z == -1) - { - stream << "block_repeater_z, "; - ok = false; - } - - if (!ok) - ret = stream.str(); - - return ok; +bool +InputStreamFromROOTFileForECATPET::check_all_required_keywords_are_set(std::string& ret) const { + std::ostringstream stream("InputStreamFromROOTFileForCylindricalPET: Required keywords are missing! Check: "); + bool ok = true; + + if (crystal_repeater_x == -1) { + stream << "crystal_repeater_x, "; + ok = false; + } + + if (crystal_repeater_y == -1) { + stream << "crystal_repeater_y, "; + ok = false; + } + + if (crystal_repeater_z == -1) { + stream << "crystal_repeater_z, "; + ok = false; + } + + if (block_repeater_y == -1) { + stream << "block_repeater_y, "; + ok = false; + } + + if (block_repeater_z == -1) { + stream << "block_repeater_z, "; + ok = false; + } + + if (!ok) + ret = stream.str(); + + return ok; } END_NAMESPACE_STIR diff --git a/src/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.cxx b/src/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.cxx index 7bb7d1495f..1f28b41fa6 100644 --- a/src/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.cxx +++ b/src/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.cxx @@ -29,84 +29,63 @@ */ #include "stir/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.h" -#include "stir/DynamicDiscretisedDensity.h" +#include "stir/DynamicDiscretisedDensity.h" #include "stir/NumericType.h" #include "stir/Succeeded.h" #include "stir/IO/interfile.h" START_NAMESPACE_STIR -const char * const -InterfileDynamicDiscretisedDensityOutputFileFormat::registered_name = "Interfile"; +const char* const InterfileDynamicDiscretisedDensityOutputFileFormat::registered_name = "Interfile"; -InterfileDynamicDiscretisedDensityOutputFileFormat:: -InterfileDynamicDiscretisedDensityOutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) -{ +InterfileDynamicDiscretisedDensityOutputFileFormat::InterfileDynamicDiscretisedDensityOutputFileFormat( + const NumericType& type, const ByteOrder& byte_order) { base_type::set_defaults(); this->set_type_of_numbers(type); this->set_byte_order(byte_order); } -void -InterfileDynamicDiscretisedDensityOutputFileFormat:: -set_defaults() -{ +void +InterfileDynamicDiscretisedDensityOutputFileFormat::set_defaults() { base_type::set_defaults(); } -void -InterfileDynamicDiscretisedDensityOutputFileFormat:: -initialise_keymap() -{ +void +InterfileDynamicDiscretisedDensityOutputFileFormat::initialise_keymap() { this->parser.add_start_key("Interfile Output File Format Parameters"); this->parser.add_stop_key("End Interfile Output File Format Parameters"); base_type::initialise_keymap(); } -bool -InterfileDynamicDiscretisedDensityOutputFileFormat:: -post_processing() -{ +bool +InterfileDynamicDiscretisedDensityOutputFileFormat::post_processing() { if (base_type::post_processing()) return true; return false; } - -ByteOrder -InterfileDynamicDiscretisedDensityOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) -{ - if (!new_byte_order.is_native_order()) - { - if (warn) - warning("InterfileDynamicDiscretisedDensityOutputFileFormat: byte_order is currently fixed to the native format\n"); - this->file_byte_order = ByteOrder::native; - } - else +ByteOrder +InterfileDynamicDiscretisedDensityOutputFileFormat::set_byte_order(const ByteOrder& new_byte_order, const bool warn) { + if (!new_byte_order.is_native_order()) { + if (warn) + warning("InterfileDynamicDiscretisedDensityOutputFileFormat: byte_order is currently fixed to the native format\n"); + this->file_byte_order = ByteOrder::native; + } else this->file_byte_order = new_byte_order; - return this->file_byte_order; + return this->file_byte_order; } -Succeeded -InterfileDynamicDiscretisedDensityOutputFileFormat:: -actual_write_to_file(std::string& filename, - const DynamicDiscretisedDensity & density) const -{ - // TODO modify write_basic_interfile to return filename - Succeeded success = - write_basic_interfile(filename, density, - this->type_of_numbers, this->scale_to_write_data, - this->file_byte_order); - if (success == Succeeded::yes) - replace_extension(filename, ".hv"); - return success; +Succeeded +InterfileDynamicDiscretisedDensityOutputFileFormat::actual_write_to_file(std::string& filename, + const DynamicDiscretisedDensity& density) const { + // TODO modify write_basic_interfile to return filename + Succeeded success = + write_basic_interfile(filename, density, this->type_of_numbers, this->scale_to_write_data, this->file_byte_order); + if (success == Succeeded::yes) + replace_extension(filename, ".hv"); + return success; } - - -// class InterfileDynamicDiscretisedDensityOutputFileFormat; - +// class InterfileDynamicDiscretisedDensityOutputFileFormat; END_NAMESPACE_STIR diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index 3e0c3a224d..2d0ab04f38 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -18,8 +18,8 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup InterfileIO + \file + \ingroup InterfileIO \brief implementations for the stir::InterfileHeader class \author Kris Thielemans @@ -49,36 +49,28 @@ using std::vector; #endif START_NAMESPACE_STIR -const double -MinimalInterfileHeader:: -double_value_not_set = -12345.60789; +const double MinimalInterfileHeader::double_value_not_set = -12345.60789; shared_ptr -MinimalInterfileHeader::get_exam_info_sptr() const -{ +MinimalInterfileHeader::get_exam_info_sptr() const { return exam_info_sptr; } const ExamInfo& -MinimalInterfileHeader::get_exam_info() const -{ +MinimalInterfileHeader::get_exam_info() const { return *exam_info_sptr; } -MinimalInterfileHeader::MinimalInterfileHeader() - : KeyParser() -{ +MinimalInterfileHeader::MinimalInterfileHeader() : KeyParser() { exam_info_sptr.reset(new ExamInfo); // need to default to PET for backwards compatibility - //this->exam_info_sptr->imaging_modality = ImagingModality::PT; + // this->exam_info_sptr->imaging_modality = ImagingModality::PT; add_start_key("INTERFILE"); - add_key("imaging modality", - KeyArgument::ASCII, (KeywordProcessor)&MinimalInterfileHeader::set_imaging_modality, - &imaging_modality_as_string); - - add_key("version of keys", - KeyArgument::ASCII, (KeywordProcessor)&MinimalInterfileHeader::set_version_specific_keys, + add_key("imaging modality", KeyArgument::ASCII, (KeywordProcessor)&MinimalInterfileHeader::set_imaging_modality, + &imaging_modality_as_string); + + add_key("version of keys", KeyArgument::ASCII, (KeywordProcessor)&MinimalInterfileHeader::set_version_specific_keys, &version_of_keys); // support for siemens interfile @@ -86,38 +78,34 @@ MinimalInterfileHeader::MinimalInterfileHeader() add_stop_key("END OF INTERFILE"); } - - -void MinimalInterfileHeader::set_imaging_modality() -{ +void +MinimalInterfileHeader::set_imaging_modality() { set_variable(); this->exam_info_sptr->imaging_modality = ImagingModality(imaging_modality_as_string); } -void MinimalInterfileHeader::set_version_specific_keys() -{ +void +MinimalInterfileHeader::set_version_specific_keys() { set_variable(); } -InterfileHeader::InterfileHeader() - : MinimalInterfileHeader() -{ +InterfileHeader::InterfileHeader() : MinimalInterfileHeader() { number_format_values.push_back("bit"); number_format_values.push_back("ascii"); number_format_values.push_back("signed integer"); number_format_values.push_back("unsigned integer"); number_format_values.push_back("float"); - + byte_order_values.push_back("LITTLEENDIAN"); byte_order_values.push_back("BIGENDIAN"); - + PET_data_type_values.push_back("Emission"); PET_data_type_values.push_back("Transmission"); PET_data_type_values.push_back("Blank"); PET_data_type_values.push_back("AttenuationCorrection"); PET_data_type_values.push_back("Normalisation"); PET_data_type_values.push_back("Image"); - + type_of_data_values.push_back("Static"); type_of_data_values.push_back("Dynamic"); type_of_data_values.push_back("Tomographic"); @@ -125,42 +113,42 @@ InterfileHeader::InterfileHeader() type_of_data_values.push_back("ROI"); type_of_data_values.push_back("PET"); type_of_data_values.push_back("Other"); - + patient_orientation_values.push_back("head_in"); patient_orientation_values.push_back("feet_in"); patient_orientation_values.push_back("other"); - patient_orientation_values.push_back("unknown"); //default + patient_orientation_values.push_back("unknown"); // default patient_rotation_values.push_back("supine"); patient_rotation_values.push_back("prone"); patient_rotation_values.push_back("right"); patient_rotation_values.push_back("left"); patient_rotation_values.push_back("other"); - patient_rotation_values.push_back("unknown"); //default + patient_rotation_values.push_back("unknown"); // default // default values // KT 07/10/2002 added 2 new ones number_format_index = 3; // unsigned integer - bytes_per_pixel = -1; // standard does not provide a default + bytes_per_pixel = -1; // standard does not provide a default // KT 02/11/98 set default for correct variable - byte_order_index = 1;// file_byte_order = ByteOrder::big_endian; + byte_order_index = 1; // file_byte_order = ByteOrder::big_endian; - type_of_data_index = 6; // PET - PET_data_type_index = 5; // Image - patient_orientation_index = 3; //unknown - patient_rotation_index = 5; //unknown - num_dimensions = 2; // set to 2 to be compatible with Interfile version 3.3 (which doesn't have this keyword) + type_of_data_index = 6; // PET + PET_data_type_index = 5; // Image + patient_orientation_index = 3; // unknown + patient_rotation_index = 5; // unknown + num_dimensions = 2; // set to 2 to be compatible with Interfile version 3.3 (which doesn't have this keyword) matrix_labels.resize(num_dimensions); matrix_size.resize(num_dimensions); pixel_sizes.resize(num_dimensions, 1.); num_energy_windows = 1; lower_en_window_thresholds.resize(num_energy_windows); upper_en_window_thresholds.resize(num_energy_windows); - lower_en_window_thresholds[0]=-1.F; - upper_en_window_thresholds[0]=-1.F; + lower_en_window_thresholds[0] = -1.F; + upper_en_window_thresholds[0] = -1.F; num_time_frames = 1; image_scaling_factors.resize(num_time_frames); - for (int i=0; ioriginating_system); ignore_key("GENERAL DATA"); ignore_key("GENERAL IMAGE DATA"); - add_key("isotope name", &isotope_name); + add_key("isotope name", &isotope_name); add_key("study date", &study_date_time.date); add_key("study_time", &study_date_time.time); - add_key("type of data", - KeyArgument::ASCIIlist, - (KeywordProcessor)&InterfileHeader::set_type_of_data, - &type_of_data_index, + add_key("type of data", KeyArgument::ASCIIlist, (KeywordProcessor)&InterfileHeader::set_type_of_data, &type_of_data_index, &type_of_data_values); - add_key("patient orientation", - &patient_orientation_index, - &patient_orientation_values); - add_key("patient rotation", - &patient_rotation_index, - &patient_rotation_values); + add_key("patient orientation", &patient_orientation_index, &patient_orientation_values); + add_key("patient rotation", &patient_rotation_index, &patient_rotation_values); + add_key("imagedata byte order", &byte_order_index, &byte_order_values); - add_key("imagedata byte order", - &byte_order_index, - &byte_order_values); - ignore_key("data format"); - add_key("number format", - &number_format_index, - &number_format_values); + add_key("number format", &number_format_index, &number_format_values); add_key("number of bytes per pixel", &bytes_per_pixel); - add_key("number of dimensions", - KeyArgument::INT, (KeywordProcessor)&InterfileHeader::read_matrix_info,&num_dimensions); + add_key("number of dimensions", KeyArgument::INT, (KeywordProcessor)&InterfileHeader::read_matrix_info, &num_dimensions); add_vectorised_key("matrix size", &matrix_size); add_vectorised_key("matrix axis label", &matrix_labels); add_vectorised_key("scaling factor (mm/pixel)", &pixel_sizes); - add_key("number of time frames", - KeyArgument::INT, (KeywordProcessor)&InterfileHeader::read_frames_info,&num_time_frames); + add_key("number of time frames", KeyArgument::INT, (KeywordProcessor)&InterfileHeader::read_frames_info, &num_time_frames); add_vectorised_key("image relative start time (sec)", &image_relative_start_times); add_vectorised_key("image duration (sec)", &image_durations); - //image start time[] := + // image start time[] := // ignore these as we'll never use them ignore_key("maximum pixel count"); @@ -222,8 +193,8 @@ InterfileHeader::InterfileHeader() // support for Louvain la Neuve's extension of 3.3 add_key("quantification units", &lln_quantification_units); - add_key("number of energy windows", - KeyArgument::INT, (KeywordProcessor)&InterfileHeader::read_num_energy_windows,&num_energy_windows); + add_key("number of energy windows", KeyArgument::INT, (KeywordProcessor)&InterfileHeader::read_num_energy_windows, + &num_energy_windows); add_vectorised_key("energy window lower level", &lower_en_window_thresholds); add_vectorised_key("energy window upper level", &upper_en_window_thresholds); @@ -233,226 +204,190 @@ InterfileHeader::InterfileHeader() add_key("start vertical bed position (mm)", &bed_position_vertical); } -void InterfileHeader::set_version_specific_keys() -{ +void +InterfileHeader::set_version_specific_keys() { MinimalInterfileHeader::set_version_specific_keys(); - if (this->version_of_keys == "STIR3.0") - { - info("Setting energy window keys as in STIR3.0"); - // only a single energy window, and non-vectorised - remove_key("energy window lower level"); - remove_key("energy window upper level"); - add_key("energy window lower level", &lower_en_window_thresholds[0]); - add_key("energy window upper level", &upper_en_window_thresholds[0]); - } + if (this->version_of_keys == "STIR3.0") { + info("Setting energy window keys as in STIR3.0"); + // only a single energy window, and non-vectorised + remove_key("energy window lower level"); + remove_key("energy window upper level"); + add_key("energy window lower level", &lower_en_window_thresholds[0]); + add_key("energy window upper level", &upper_en_window_thresholds[0]); + } } // MJ 17/05/2000 made bool -bool InterfileHeader::post_processing() -{ - if(type_of_data_index<0) - { - warning("Interfile Warning: 'type_of_data' keyword required"); - return true; - } +bool +InterfileHeader::post_processing() { + if (type_of_data_index < 0) { + warning("Interfile Warning: 'type_of_data' keyword required"); + return true; + } - if (!study_date_time.date.empty() && !study_date_time.time.empty()) - { - try - { - exam_info_sptr->start_time_in_secs_since_1970 = - Interfile_datetime_to_secs_since_Unix_epoch(study_date_time); - } - catch(...) - {} + if (!study_date_time.date.empty() && !study_date_time.time.empty()) { + try { + exam_info_sptr->start_time_in_secs_since_1970 = Interfile_datetime_to_secs_since_Unix_epoch(study_date_time); + } catch (...) { } - - if (!isotope_name.empty()){ - this->exam_info_sptr->set_radionuclide(isotope_name); } - - if (patient_orientation_index<0 || patient_rotation_index<0) + + if (!isotope_name.empty()) { + this->exam_info_sptr->set_radionuclide(isotope_name); + } + + if (patient_orientation_index < 0 || patient_rotation_index < 0) return true; // warning: relies on index taking same values as enums in PatientPosition exam_info_sptr->patient_position.set_rotation(static_cast(patient_rotation_index)); exam_info_sptr->patient_position.set_orientation(static_cast(patient_orientation_index)); - if (number_format_index<0 || - static_cast(number_format_index)>=number_format_values.size()) - { + if (number_format_index < 0 || static_cast(number_format_index) >= number_format_values.size()) { warning("Interfile internal error: 'number_format_index' out of range\n"); return true; } // KT 07/10/2002 new // check if bytes_per_pixel is set if the data type is not 'bit' - if (number_format_index!=0 && bytes_per_pixel<=0) - { + if (number_format_index != 0 && bytes_per_pixel <= 0) { warning("Interfile error: 'number of bytes per pixel' keyword should be set\n to a number > 0"); return true; } type_of_numbers = NumericType(number_format_values[number_format_index], bytes_per_pixel); - - file_byte_order = byte_order_index==0 ? - ByteOrder::little_endian : ByteOrder::big_endian; - + + file_byte_order = byte_order_index == 0 ? ByteOrder::little_endian : ByteOrder::big_endian; + // KT 07/10/2002 more extensive error checking for matrix_size keyword - if (matrix_size.size()==0) - { + if (matrix_size.size() == 0) { warning("Interfile error: no matrix size keywords present\n"); return true; } - if (matrix_size[matrix_size.size()-1].size()!=1) - { + if (matrix_size[matrix_size.size() - 1].size() != 1) { warning("Interfile error: last dimension (%d) of 'matrix size' cannot be a list of numbers\n", - matrix_size[matrix_size.size()-1].size()); + matrix_size[matrix_size.size() - 1].size()); return true; } - for (unsigned int dim=0; dim != matrix_size.size(); ++dim) - { - if (matrix_size[dim].size()==0) - { + for (unsigned int dim = 0; dim != matrix_size.size(); ++dim) { + if (matrix_size[dim].size() == 0) { warning("Interfile error: dimension (%d) of 'matrix size' not present\n", dim); return true; } - for (unsigned int i=0; i != matrix_size[dim].size(); ++i) - { - if (matrix_size[dim][i]<=0) - { + for (unsigned int i = 0; i != matrix_size[dim].size(); ++i) { + if (matrix_size[dim][i] <= 0) { warning("Interfile error: dimension (%d) of 'matrix size' has a number <= 0 at position\n", dim, i); return true; } } } - for (int frame=0; frameget_num_datasets(); frame++) - { - if (image_scaling_factors[frame].size() == 1) - { + for (int frame = 0; frame < this->get_num_datasets(); frame++) { + if (image_scaling_factors[frame].size() == 1) { // use the only value for every scaling factor - image_scaling_factors[frame].resize(matrix_size[matrix_size.size()-1][0]); - for (unsigned int i=1; i(image_scaling_factors[frame].size()) != matrix_size[matrix_size.size()-1][0]) - { + image_scaling_factors[frame].resize(matrix_size[matrix_size.size() - 1][0]); + for (unsigned int i = 1; i < image_scaling_factors[frame].size(); i++) + image_scaling_factors[frame][i] = image_scaling_factors[frame][0]; + } else if (static_cast(image_scaling_factors[frame].size()) != matrix_size[matrix_size.size() - 1][0]) { warning("Interfile error: wrong number of image scaling factors\n"); return true; } } - + // KT 07/10/2002 new // support for non-standard key // TODO as there's currently no way to find out if a key was used in the header, we just rely on the // fact that the default didn't change. This isn't good enough, but it has to do for now. - if (lln_quantification_units!=1.) - { - const bool all_one = image_scaling_factors[0][0] == 1.; - for (int frame=0; frameget_num_datasets(); frame++) - for (unsigned int i=0; iget_num_datasets(); frame++) + for (unsigned int i = 0; i < image_scaling_factors[frame].size(); i++) { + // check if all image_scaling_factors are equal to 1 (i.e. the image_scaling_factors keyword // probably never occured) or lln_quantification_units if ((all_one && image_scaling_factors[frame][i] != 1.) || - (!all_one && image_scaling_factors[frame][i] != lln_quantification_units)) - { - warning("Interfile error: key 'quantification units' can only be used when either " - "image_scaling_factors[] keywords are not present, or have identical values.\n"); - return true; - } + (!all_one && image_scaling_factors[frame][i] != lln_quantification_units)) { + warning("Interfile error: key 'quantification units' can only be used when either " + "image_scaling_factors[] keywords are not present, or have identical values.\n"); + return true; + } // if they're all 1, we set the value to lln_quantification_units if (all_one) image_scaling_factors[frame][i] = lln_quantification_units; } - if (all_one) - { - warning("Interfile warning: non-standard key 'quantification_units' used to set 'image_scaling_factors' to %g\n", - lln_quantification_units); - } + if (all_one) { + warning("Interfile warning: non-standard key 'quantification_units' used to set 'image_scaling_factors' to %g\n", + lln_quantification_units); + } } // lln_quantification_units - if (num_energy_windows>0) - { - if (num_energy_windows>1) - warning("Currently only reading the first energy window."); - if (upper_en_window_thresholds[0] > 0 && lower_en_window_thresholds[0] > 0 ) - { - exam_info_sptr->set_high_energy_thres(upper_en_window_thresholds[0]); - exam_info_sptr->set_low_energy_thres(lower_en_window_thresholds[0]); - } + if (num_energy_windows > 0) { + if (num_energy_windows > 1) + warning("Currently only reading the first energy window."); + if (upper_en_window_thresholds[0] > 0 && lower_en_window_thresholds[0] > 0) { + exam_info_sptr->set_high_energy_thres(upper_en_window_thresholds[0]); + exam_info_sptr->set_low_energy_thres(lower_en_window_thresholds[0]); } + } - exam_info_sptr->time_frame_definitions = - TimeFrameDefinitions(image_relative_start_times, image_durations); + exam_info_sptr->time_frame_definitions = TimeFrameDefinitions(image_relative_start_times, image_durations); return false; - } -void InterfileHeader::read_matrix_info() -{ +void +InterfileHeader::read_matrix_info() { set_variable(); matrix_labels.resize(num_dimensions); matrix_size.resize(num_dimensions); pixel_sizes.resize(num_dimensions, 1.); - } -void InterfileHeader::read_num_energy_windows() -{ +void +InterfileHeader::read_num_energy_windows() { set_variable(); - upper_en_window_thresholds.resize(num_energy_windows,-1.); - lower_en_window_thresholds.resize(num_energy_windows,-1.); + upper_en_window_thresholds.resize(num_energy_windows, -1.); + lower_en_window_thresholds.resize(num_energy_windows, -1.); } -void InterfileHeader::set_type_of_data() -{ +void +InterfileHeader::set_type_of_data() { set_variable(); - + if (this->type_of_data_index == -1) error("Interfile parsing: type_of_data needs to be set to supported value"); const string type_of_data = this->type_of_data_values[this->type_of_data_index]; - if (type_of_data == "PET") - { - ignore_key("PET STUDY (Emission data)"); - ignore_key("PET STUDY (Image data)"); - ignore_key("PET STUDY (General)"); - add_key("PET data type", - &PET_data_type_index, - &PET_data_type_values); - ignore_key("process status"); - ignore_key("IMAGE DATA DESCRIPTION"); - // TODO rename keyword - add_vectorised_key("data offset in bytes", &data_offset_each_dataset); + if (type_of_data == "PET") { + ignore_key("PET STUDY (Emission data)"); + ignore_key("PET STUDY (Image data)"); + ignore_key("PET STUDY (General)"); + add_key("PET data type", &PET_data_type_index, &PET_data_type_values); + ignore_key("process status"); + ignore_key("IMAGE DATA DESCRIPTION"); + // TODO rename keyword + add_vectorised_key("data offset in bytes", &data_offset_each_dataset); - } - else if (type_of_data == "Tomographic") - { - ignore_key("SPECT STUDY (General)" ); - ignore_key("SPECT STUDY (acquired data)"); + } else if (type_of_data == "Tomographic") { + ignore_key("SPECT STUDY (General)"); + ignore_key("SPECT STUDY (acquired data)"); - process_status_values.push_back("Reconstructed"); - process_status_values.push_back("Acquired"); - add_key("process status", - &process_status_index, - &process_status_values); + process_status_values.push_back("Reconstructed"); + process_status_values.push_back("Acquired"); + add_key("process status", &process_status_index, &process_status_values); #if 0 // overwrite vectored-value, as v3.3 had a scalar add_key("data offset in bytes", &data_offset); #endif - } + } } -void InterfileHeader::read_frames_info() -{ +void +InterfileHeader::read_frames_info() { set_variable(); const int num_datasets = this->get_num_datasets(); image_scaling_factors.resize(num_datasets); - for (int i=0; iget_num_datasets(); image_scaling_factors.resize(num_datasets); - for (int i=0; ifirst_pixel_offsets.resize(num_dimensions); - std::fill(this->first_pixel_offsets.begin(), this->first_pixel_offsets.end(), - base_type::double_value_not_set); + std::fill(this->first_pixel_offsets.begin(), this->first_pixel_offsets.end(), base_type::double_value_not_set); } // MJ 17/05/2000 made bool -bool InterfileImageHeader::post_processing() -{ +bool +InterfileImageHeader::post_processing() { if (InterfileHeader::post_processing() == true) return true; - + this->exam_info_sptr->set_calibration_factor(calibration_factor); - - if (PET_data_type_values[PET_data_type_index] != "Image") - { warning("Interfile error: expecting an image\n"); return true; } - - if (num_dimensions != 3) - { warning("Interfile error: expecting 3D image\n"); return true; } - if ( (matrix_size[0].size() != 1) || - (matrix_size[1].size() != 1) || - (matrix_size[2].size() != 1) ) - { warning("Interfile error: only handling image with homogeneous dimensions\n"); return true; } + if (PET_data_type_values[PET_data_type_index] != "Image") { + warning("Interfile error: expecting an image\n"); + return true; + } + + if (num_dimensions != 3) { + warning("Interfile error: expecting 3D image\n"); + return true; + } + + if ((matrix_size[0].size() != 1) || (matrix_size[1].size() != 1) || (matrix_size[2].size() != 1)) { + warning("Interfile error: only handling image with homogeneous dimensions\n"); + return true; + } // KT 09/10/98 changed order z,y,x->x,y,z // KT 09/10/98 allow no labels at all - if (matrix_labels[0].length()>0 - && (matrix_labels[0]!="x" || matrix_labels[1]!="y" || - matrix_labels[2]!="z")) - { - warning("Interfile: only supporting x,y,z order of coordinates now.\n"); - return true; - } - std::vector first_pixel_offsets; + if (matrix_labels[0].length() > 0 && (matrix_labels[0] != "x" || matrix_labels[1] != "y" || matrix_labels[2] != "z")) { + warning("Interfile: only supporting x,y,z order of coordinates now.\n"); + return true; + } + std::vector first_pixel_offsets; return false; } /**********************************************************************/ -//KT 26/10/98 +// KT 26/10/98 // KT 13/11/98 moved stream arg from constructor to parse() -InterfilePDFSHeader::InterfilePDFSHeader() - : InterfileHeader() -{ +InterfilePDFSHeader::InterfilePDFSHeader() : InterfileHeader() { num_segments = -1; - add_key("minimum ring difference per segment", - KeyArgument::LIST_OF_INTS, - (KeywordProcessor)&InterfilePDFSHeader::resize_segments_and_set, - &min_ring_difference); - add_key("maximum ring difference per segment", - KeyArgument::LIST_OF_INTS, - (KeywordProcessor)&InterfilePDFSHeader::resize_segments_and_set, - &max_ring_difference); - - + add_key("minimum ring difference per segment", KeyArgument::LIST_OF_INTS, + (KeywordProcessor)&InterfilePDFSHeader::resize_segments_and_set, &min_ring_difference); + add_key("maximum ring difference per segment", KeyArgument::LIST_OF_INTS, + (KeywordProcessor)&InterfilePDFSHeader::resize_segments_and_set, &max_ring_difference); + // warning these keys should match what is in Scanner::parameter_info() // TODO get Scanner to parse these ignore_key("Scanner parameters"); @@ -560,147 +483,141 @@ InterfilePDFSHeader::InterfilePDFSHeader() // first set to some crazy values num_rings = -1; - add_key("number of rings", - &num_rings); + add_key("number of rings", &num_rings); num_detectors_per_ring = -1; - add_key("number of detectors per ring", - &num_detectors_per_ring); + add_key("number of detectors per ring", &num_detectors_per_ring); transaxial_FOV_diameter_in_cm = -1; - add_key("transaxial FOV diameter (cm)", - &transaxial_FOV_diameter_in_cm); + add_key("transaxial FOV diameter (cm)", &transaxial_FOV_diameter_in_cm); inner_ring_diameter_in_cm = -1; - add_key("inner ring diameter (cm)", - &inner_ring_diameter_in_cm); + add_key("inner ring diameter (cm)", &inner_ring_diameter_in_cm); average_depth_of_interaction_in_cm = -1; - add_key("average depth of interaction (cm)", - &average_depth_of_interaction_in_cm); + add_key("average depth of interaction (cm)", &average_depth_of_interaction_in_cm); distance_between_rings_in_cm = -1; - add_key("distance between rings (cm)", - &distance_between_rings_in_cm); + add_key("distance between rings (cm)", &distance_between_rings_in_cm); default_bin_size_in_cm = -1; - add_key("default bin size (cm)", - &default_bin_size_in_cm); + add_key("default bin size (cm)", &default_bin_size_in_cm); // this is a good default value view_offset_in_degrees = 0; - add_key("view offset (degrees)", - &view_offset_in_degrees); - max_num_non_arccorrected_bins=0; - default_num_arccorrected_bins=0; - add_key("Maximum number of non-arc-corrected bins", - &max_num_non_arccorrected_bins); - add_key("Default number of arc-corrected bins", - &default_num_arccorrected_bins); + add_key("view offset (degrees)", &view_offset_in_degrees); + max_num_non_arccorrected_bins = 0; + default_num_arccorrected_bins = 0; + add_key("Maximum number of non-arc-corrected bins", &max_num_non_arccorrected_bins); + add_key("Default number of arc-corrected bins", &default_num_arccorrected_bins); num_axial_blocks_per_bucket = 0; - add_key("number of blocks_per_bucket in axial direction", - &num_axial_blocks_per_bucket); + add_key("number of blocks_per_bucket in axial direction", &num_axial_blocks_per_bucket); num_transaxial_blocks_per_bucket = 0; - add_key("number of blocks_per_bucket in transaxial direction", - &num_transaxial_blocks_per_bucket); + add_key("number of blocks_per_bucket in transaxial direction", &num_transaxial_blocks_per_bucket); num_axial_crystals_per_block = 0; - add_key("number of crystals_per_block in axial direction", - &num_axial_crystals_per_block); + add_key("number of crystals_per_block in axial direction", &num_axial_crystals_per_block); num_transaxial_crystals_per_block = 0; - add_key("number of crystals_per_block in transaxial direction", - &num_transaxial_crystals_per_block); + add_key("number of crystals_per_block in transaxial direction", &num_transaxial_crystals_per_block); num_axial_crystals_per_singles_unit = -1; - add_key("number of crystals_per_singles_unit in axial direction", - &num_axial_crystals_per_singles_unit); + add_key("number of crystals_per_singles_unit in axial direction", &num_axial_crystals_per_singles_unit); num_transaxial_crystals_per_singles_unit = -1; - add_key("number of crystals_per_singles_unit in transaxial direction", - &num_transaxial_crystals_per_singles_unit); + add_key("number of crystals_per_singles_unit in transaxial direction", &num_transaxial_crystals_per_singles_unit); // sensible default num_detector_layers = 1; - add_key("number of detector layers", - &num_detector_layers); + add_key("number of detector layers", &num_detector_layers); energy_resolution = -1.f; - add_key("Energy resolution", - &energy_resolution); + add_key("Energy resolution", &energy_resolution); reference_energy = -1.f; - add_key("Reference energy (in keV)", - &reference_energy); + add_key("Reference energy (in keV)", &reference_energy); + + tof_mash_factor = -1; + add_key("%TOF mashing factor", &tof_mash_factor); + max_num_timing_poss = -1; + add_key("Number of TOF time bins", &max_num_timing_poss); + size_of_timing_pos = -1.f; + add_key("Size of timing bin (ps)", &size_of_timing_pos); + timing_resolution = -1.f; + add_key("Timing resolution (ps)", &timing_resolution); ignore_key("end scanner parameters"); - + effective_central_bin_size_in_cm = -1; - add_key("effective central bin size (cm)", - &effective_central_bin_size_in_cm); + add_key("effective central bin size (cm)", &effective_central_bin_size_in_cm); add_key("applied corrections", &applied_corrections); } -void InterfilePDFSHeader::resize_segments_and_set() -{ +void +InterfilePDFSHeader::resize_segments_and_set() { // find_storage_order returns true if already found (or error) - if (num_segments < 0 && !find_storage_order()) - { + if (num_segments < 0 && !find_storage_order()) { min_ring_difference.resize(num_segments); max_ring_difference.resize(num_segments); - } - + if (num_segments >= 0) set_variable(); - } -int InterfilePDFSHeader::find_storage_order() -{ +int +InterfilePDFSHeader::find_storage_order() { /* if(type_of_data_values[type_of_data_index] != "PET") - { - - warning("Interfile error: expecting PET study "); - stop_parsing(); - return true; + { + + warning("Interfile error: expecting PET study "); + stop_parsing(); + return true; - } + } */ - if (num_dimensions != 4) - { - warning("Interfile error: expecting 4D structure "); + if (num_dimensions != 4 && num_dimensions != 5) { + warning("Interfile error: expecting 4D structure or 5D in case of TOF information "); stop_parsing(); - return true; + return true; } - if (matrix_labels[0] != "tangential coordinate") - { + if (matrix_labels[0] != "tangential coordinate") { // use error message with index [1] as that is what the user sees. - warning("Interfile error: expecting 'matrix axis label[1] := tangential coordinate'\n"); + warning("Interfile error: expecting 'matrix axis label[1] := tangential coordinate'\n"); stop_parsing(); - return true; + return true; } num_bins = matrix_size[0][0]; - - if (matrix_labels[3] == "segment") - { + + if (matrix_labels[3] == "segment") { num_segments = matrix_size[3][0]; - - if (matrix_labels[1] == "axial coordinate" && matrix_labels[2] == "view") - { - storage_order =ProjDataFromStream::Segment_View_AxialPos_TangPos; - num_views = matrix_size[2][0]; + + if (matrix_labels[1] == "axial coordinate" && matrix_labels[2] == "view") { + // If TOF information is in there + if (matrix_labels.size() > 4) { + if (matrix_labels[4] == "timing positions") { + num_timing_poss = matrix_size[4][0]; + storage_order = ProjDataFromStream::Timing_Segment_View_AxialPos_TangPos; + num_views = matrix_size[2][0]; +#ifdef _MSC_VER + num_rings_per_segment.assign(matrix_size[1].begin(), matrix_size[1].end()); +#else + num_rings_per_segment = matrix_size[1]; +#endif + } + } else { + storage_order = ProjDataFromStream::Segment_View_AxialPos_TangPos; + num_views = matrix_size[2][0]; #ifdef _MSC_VER - num_rings_per_segment.assign(matrix_size[1].begin(), matrix_size[1].end()); -#else - num_rings_per_segment = matrix_size[1]; + num_rings_per_segment.assign(matrix_size[1].begin(), matrix_size[1].end()); +#else + num_rings_per_segment = matrix_size[1]; #endif - } - else if (matrix_labels[1] == "view" && matrix_labels[2] == "axial coordinate") - { + } + } else if (matrix_labels[1] == "view" && matrix_labels[2] == "axial coordinate") { storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; num_views = matrix_size[1][0]; #ifdef _MSC_VER - + num_rings_per_segment.assign(matrix_size[2].begin(), matrix_size[2].end()); - + #else num_rings_per_segment = matrix_size[2]; #endif } - + } /* - else if (matrix_labels[3] == "view" && + else if (matrix_labels[3] == "view" && matrix_labels[2] == "segment" && matrix_labels[1] == "axial coordinate") { storage_order = ProjDataFromStream::View_Segment_AxialPos_TangPos; @@ -711,54 +628,40 @@ int InterfilePDFSHeader::find_storage_order() #else num_rings_per_segment = matrix_size[1]; #endif - + } */ - else - { - warning("Interfile error: matrix labels not in expected (or supported) format\n"); + else { + warning("Interfile error: matrix labels not in expected (or supported) format\n"); stop_parsing(); - return true; + return true; } - + return false; - } // definition for using sort() below. -// This is a function object that allows comparing the first elements of 2 +// This is a function object that allows comparing the first elements of 2 // pairs. template -class compare_first : -public binary_function -{ +class compare_first : public binary_function { public: - bool operator()(const pair& p1, const pair& p2) const - { - return p1.first < p2.first; - } + bool operator()(const pair& p1, const pair& p2) const { return p1.first < p2.first; } }; - -// This function assigns segment numbers by sorting the average -// ring differences. It returns a list of the segment numbers +// This function assigns segment numbers by sorting the average +// ring differences. It returns a list of the segment numbers // in the same order as the min/max_ring_difference vectors void -find_segment_sequence(vector& segment_sequence, - VectorWithOffset& sorted_num_rings_per_segment, - VectorWithOffset& sorted_min_ring_diff, - VectorWithOffset& sorted_max_ring_diff, - vector& num_rings_per_segment, - const vector& min_ring_difference, - const vector& max_ring_difference) -{ +find_segment_sequence(vector& segment_sequence, VectorWithOffset& sorted_num_rings_per_segment, + VectorWithOffset& sorted_min_ring_diff, VectorWithOffset& sorted_max_ring_diff, + vector& num_rings_per_segment, const vector& min_ring_difference, + const vector& max_ring_difference) { const int num_segments = static_cast(min_ring_difference.size()); - assert(num_segments%2 == 1); - - - vector< pair > sum_and_location(num_segments); - for (int i=0; i> sum_and_location(num_segments); + for (int i = 0; i < num_segments; i++) { sum_and_location[i].first = static_cast(min_ring_difference[i] + max_ring_difference[i]); sum_and_location[i].second = i; } @@ -778,11 +681,10 @@ find_segment_sequence(vector& segment_sequence, cerr<< sum_and_location[i].second<<" "; } cerr<()); + std::sort(sum_and_location.begin(), sum_and_location.end(), compare_first()); #if 0 cerr<<"display sum_sorted"<& segment_sequence, cerr<< sum_and_location[i].first<<" "; } cerr< 1E-3) - { - error("This data does not seem to contain segment 0. \n" - "We can't handle this at the moment. Sorry."); + + if (segment_zero_num == num_segments || sum_and_location[segment_zero_num].first > 1E-3) { + error("This data does not seem to contain segment 0. \n" + "We can't handle this at the moment. Sorry."); } - - vector< pair > location_and_segment_num(num_segments); - for (int i=0; i> location_and_segment_num(num_segments); + for (int i = 0; i < num_segments; i++) { location_and_segment_num[i].first = sum_and_location[i].second; location_and_segment_num[i].second = i - segment_zero_num; } @@ -828,30 +725,24 @@ find_segment_sequence(vector& segment_sequence, } cerr<(ceil(num_segments/2 )); - - sorted_min_ring_diff = VectorWithOffset(min_segment_num,max_segment_num); - sorted_max_ring_diff = VectorWithOffset(min_segment_num,max_segment_num); - sorted_num_rings_per_segment= VectorWithOffset(min_segment_num,max_segment_num); - - - for (int i=0; i(ceil(num_segments/2 )); + + sorted_min_ring_diff = VectorWithOffset(min_segment_num, max_segment_num); + sorted_max_ring_diff = VectorWithOffset(min_segment_num, max_segment_num); + sorted_num_rings_per_segment = VectorWithOffset(min_segment_num, max_segment_num); + + for (int i = 0; i < num_segments; i++) { + sorted_min_ring_diff[(location_and_segment_num[i].second)] = min_ring_difference[(location_and_segment_num[i].first)]; + + sorted_max_ring_diff[(location_and_segment_num[i].second)] = max_ring_difference[(location_and_segment_num[i].first)]; + + sorted_num_rings_per_segment[(location_and_segment_num[i].second)] = + num_rings_per_segment[(location_and_segment_num[i].first)]; } #if 0 @@ -879,16 +770,13 @@ find_segment_sequence(vector& segment_sequence, cerr<()); - + sort(location_and_segment_num.begin(), location_and_segment_num.end(), compare_first()); + + segment_sequence.resize(num_segments); + for (int i = 0; i < num_segments; i++) + segment_sequence[i] = location_and_segment_num[i].second; - segment_sequence.resize(num_segments); - for (int i=0; i& segment_sequence, cerr<(num_segments)) - { - warning("Interfile error: per-segment information is inconsistent: min_ring_difference\n"); + + { + warning(boost::format( + "Interfile error: expecting emission data, got %s\n") + % PET_data_type_values[PET_data_type_index]); return true; } - if (max_ring_difference.size() != static_cast(num_segments)) - { - warning("Interfile error: per-segment information is inconsistent: max_ring_difference\n"); + + if (min_ring_difference.size() != static_cast(num_segments)) { + warning("Interfile error: per-segment information is inconsistent: min_ring_difference\n"); return true; } - if (num_rings_per_segment.size()!= static_cast(num_segments)) - { - warning("Interfile error: per-segment information is inconsistent: num_rings_per_segment\n"); + if (max_ring_difference.size() != static_cast(num_segments)) { + warning("Interfile error: per-segment information is inconsistent: max_ring_difference\n"); return true; } - + if (num_rings_per_segment.size() != static_cast(num_segments)) { + warning("Interfile error: per-segment information is inconsistent: num_rings_per_segment\n"); + return true; + } + // check for arc-correction - if (applied_corrections.size() == 0) - { + if (applied_corrections.size() == 0) { warning("\nParsing Interfile header for projection data: \n" "\t'applied corrections' keyword not found. Assuming arc-corrected data\n"); is_arccorrected = true; - } - else - { + } else { is_arccorrected = false; for ( #ifndef STIR_NO_NAMESPACES - std:: + std:: #endif - vector::const_iterator iter = applied_corrections.begin(); - iter != applied_corrections.end(); - ++iter) - { + vector::const_iterator iter = applied_corrections.begin(); + iter != applied_corrections.end(); ++iter) { const string correction = standardise_keyword(*iter); - if(correction == "arc correction" || correction == "arc corrected") - { + if (correction == "arc correction" || correction == "arc corrected") { is_arccorrected = true; break; - } - else if (correction != "none") - warning("\nParsing Interfile header for projection data: \n" - "\t value '%s' for keyword 'applied corrections' ignored\n", - correction.c_str()); - + } else if (correction != "none") + warning("\nParsing Interfile header for projection data: \n" + "\t value '%s' for keyword 'applied corrections' ignored\n", + correction.c_str()); } - } - + VectorWithOffset sorted_min_ring_diff; VectorWithOffset sorted_max_ring_diff; VectorWithOffset sorted_num_rings_per_segment; - - find_segment_sequence( segment_sequence,sorted_num_rings_per_segment, - sorted_min_ring_diff,sorted_max_ring_diff, - num_rings_per_segment, - min_ring_difference, max_ring_difference); + + find_segment_sequence(segment_sequence, sorted_num_rings_per_segment, sorted_min_ring_diff, sorted_max_ring_diff, + num_rings_per_segment, min_ring_difference, max_ring_difference); #if 0 cerr << "PDFS data read inferred header :\n"; cerr << "Segment sequence :"; @@ -988,280 +864,250 @@ bool InterfilePDFSHeader::post_processing() cerr << sorted_num_rings_per_segment[i] << " "; cerr << endl; cerr << "Total number of planes :" - << -#ifndef STIR_NO_NAMESPACES // stupid work-around for VC + << +# ifndef STIR_NO_NAMESPACES // stupid work-around for VC std::accumulate -#else +# else accumulate -#endif +# endif (num_rings_per_segment.begin(), num_rings_per_segment.end(), 0) << endl; #endif - + // handle scanner shared_ptr guessed_scanner_ptr(Scanner::get_scanner_from_name(get_exam_info().originating_system)); - bool originating_system_was_recognised = - guessed_scanner_ptr->get_type() != Scanner::Unknown_scanner; - if (!originating_system_was_recognised) - { + bool originating_system_was_recognised = guessed_scanner_ptr->get_type() != Scanner::Unknown_scanner; + if (!originating_system_was_recognised) { // feable attempt to guess the system by checking the num_views etc - char const * warning_msg = 0; - if (num_detectors_per_ring < 1) - { - num_detectors_per_ring = num_views*2; + char const* warning_msg = 0; + if (num_detectors_per_ring < 1) { + num_detectors_per_ring = num_views * 2; warning_msg = "\nInterfile warning: I don't recognise 'originating system' value.\n" - "\tI guessed %s from 'num_views' (note: this guess is wrong for mashed data)\n" - " and 'number of rings'\n"; - } - else - { + "\tI guessed %s from 'num_views' (note: this guess is wrong for mashed data)\n" + " and 'number of rings'\n"; + } else { warning_msg = "\nInterfile warning: I don't recognise 'originating system' value.\n" - "I guessed %s from 'number of detectors per ring' and 'number of rings'\n"; + "I guessed %s from 'number of detectors per ring' and 'number of rings'\n"; } - - - switch (num_detectors_per_ring) - { - case 192*2: - guessed_scanner_ptr.reset(new Scanner( Scanner::E953)); + + switch (num_detectors_per_ring) { + case 192 * 2: + guessed_scanner_ptr.reset(new Scanner(Scanner::E953)); warning(warning_msg, "ECAT 953"); break; - case 336*2: - guessed_scanner_ptr.reset(new Scanner( Scanner::Advance)); + case 336 * 2: + guessed_scanner_ptr.reset(new Scanner(Scanner::Advance)); warning(warning_msg, "Advance"); break; - case 288*2: - if(num_rings == 104) - { //added by Dylan Togane - guessed_scanner_ptr.reset(new Scanner( Scanner::HRRT)); - warning(warning_msg, "HRRT"); - } - else if (num_rings == 48) - { - guessed_scanner_ptr.reset(new Scanner( Scanner::E966)); - warning(warning_msg, "ECAT 966"); - } - else if (num_rings == 32) - { - guessed_scanner_ptr.reset(new Scanner( Scanner::E962)); - warning(warning_msg, "ECAT 962"); + case 288 * 2: + if (num_rings == 104) { // added by Dylan Togane + guessed_scanner_ptr.reset(new Scanner(Scanner::HRRT)); + warning(warning_msg, "HRRT"); + } else if (num_rings == 48) { + guessed_scanner_ptr.reset(new Scanner(Scanner::E966)); + warning(warning_msg, "ECAT 966"); + } else if (num_rings == 32) { + guessed_scanner_ptr.reset(new Scanner(Scanner::E962)); + warning(warning_msg, "ECAT 962"); } break; // Dylan Togane [dtogane@camhpet.on.ca] 30/07/2002 bug fix: added break - case 256*2: - guessed_scanner_ptr.reset(new Scanner( Scanner::E951)); + case 256 * 2: + guessed_scanner_ptr.reset(new Scanner(Scanner::E951)); warning(warning_msg, "ECAT 951"); break; } if (guessed_scanner_ptr->get_type() == Scanner::Unknown_scanner) warning("\nInterfile warning: I did not recognise the scanner neither from \n" - "'originating_system' or 'number of detectors per ring' and 'number of rings'.\n"); + "'originating_system' or 'number of detectors per ring' and 'number of rings'.\n"); } bool mismatch_between_header_and_guess = false; - + if (guessed_scanner_ptr->get_type() != Scanner::Unknown_scanner && - guessed_scanner_ptr->get_type() != Scanner::User_defined_scanner) - { - // fill in values which are not in the Interfile header - + guessed_scanner_ptr->get_type() != Scanner::User_defined_scanner) { + // fill in values which are not in the Interfile header + if (num_rings < 1) num_rings = guessed_scanner_ptr->get_num_rings(); if (num_detectors_per_ring < 1) - num_detectors_per_ring = guessed_scanner_ptr->get_max_num_views()*2; + num_detectors_per_ring = guessed_scanner_ptr->get_max_num_views() * 2; #if 0 if (transaxial_FOV_diameter_in_cm < 0) transaxial_FOV_diameter_in_cm = guessed_scanner_ptr->FOV_radius*2/10.; #endif if (inner_ring_diameter_in_cm < 0) - inner_ring_diameter_in_cm = guessed_scanner_ptr->get_inner_ring_radius()*2/10.; + inner_ring_diameter_in_cm = guessed_scanner_ptr->get_inner_ring_radius() * 2 / 10.; if (average_depth_of_interaction_in_cm < 0) - average_depth_of_interaction_in_cm = guessed_scanner_ptr->get_average_depth_of_interaction()/10; + average_depth_of_interaction_in_cm = guessed_scanner_ptr->get_average_depth_of_interaction() / 10; if (distance_between_rings_in_cm < 0) - distance_between_rings_in_cm = guessed_scanner_ptr->get_ring_spacing()/10; + distance_between_rings_in_cm = guessed_scanner_ptr->get_ring_spacing() / 10; if (default_bin_size_in_cm < 0) - default_bin_size_in_cm = - guessed_scanner_ptr->get_default_bin_size()/10; + default_bin_size_in_cm = guessed_scanner_ptr->get_default_bin_size() / 10; if (max_num_non_arccorrected_bins <= 0) max_num_non_arccorrected_bins = guessed_scanner_ptr->get_max_num_non_arccorrected_bins(); if (default_num_arccorrected_bins <= 0) default_num_arccorrected_bins = guessed_scanner_ptr->get_default_num_arccorrected_bins(); - - if (num_axial_blocks_per_bucket<=0) + if (num_axial_blocks_per_bucket <= 0) num_axial_blocks_per_bucket = guessed_scanner_ptr->get_num_axial_blocks_per_bucket(); - if (num_transaxial_blocks_per_bucket<=0) + if (num_transaxial_blocks_per_bucket <= 0) num_transaxial_blocks_per_bucket = guessed_scanner_ptr->get_num_transaxial_blocks_per_bucket(); - if (num_axial_crystals_per_block<=0) + if (num_axial_crystals_per_block <= 0) num_axial_crystals_per_block = guessed_scanner_ptr->get_num_axial_crystals_per_block(); - if (num_transaxial_crystals_per_block<=0) + if (num_transaxial_crystals_per_block <= 0) num_transaxial_crystals_per_block = guessed_scanner_ptr->get_num_transaxial_crystals_per_block(); - if (num_axial_crystals_per_singles_unit < 0) - num_axial_crystals_per_singles_unit = - guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit(); - if (num_transaxial_crystals_per_singles_unit < 0) - num_transaxial_crystals_per_singles_unit = - guessed_scanner_ptr->get_num_transaxial_crystals_per_singles_unit(); - if (num_detector_layers<=0) + if (num_axial_crystals_per_singles_unit < 0) + num_axial_crystals_per_singles_unit = guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit(); + if (num_transaxial_crystals_per_singles_unit < 0) + num_transaxial_crystals_per_singles_unit = guessed_scanner_ptr->get_num_transaxial_crystals_per_singles_unit(); + if (num_detector_layers <= 0) num_detector_layers = guessed_scanner_ptr->get_num_detector_layers(); if (energy_resolution < 0) - energy_resolution = guessed_scanner_ptr->get_energy_resolution(); + energy_resolution = guessed_scanner_ptr->get_energy_resolution(); if (reference_energy < 0) - reference_energy = guessed_scanner_ptr->get_reference_energy(); - + reference_energy = guessed_scanner_ptr->get_reference_energy(); + // consistency check with values of the guessed_scanner_ptr we guessed above - if (num_rings != guessed_scanner_ptr->get_num_rings()) - { - warning("Interfile warning: 'number of rings' (%d) is expected to be %d.\n", - num_rings, guessed_scanner_ptr->get_num_rings()); - mismatch_between_header_and_guess = true; - } - if (num_detectors_per_ring != guessed_scanner_ptr->get_num_detectors_per_ring()) - { - warning("Interfile warning: 'number of detectors per ring' (%d) is expected to be %d.\n", - num_detectors_per_ring, guessed_scanner_ptr->get_num_detectors_per_ring()); - mismatch_between_header_and_guess = true; - } - if (fabs(inner_ring_diameter_in_cm - guessed_scanner_ptr->get_inner_ring_radius()*2/10.) > .001) - { - warning("Interfile warning: 'inner ring diameter (cm)' (%f) is expected to be %f.\n", - inner_ring_diameter_in_cm, guessed_scanner_ptr->get_inner_ring_radius()*2/10.); - mismatch_between_header_and_guess = true; - } - if (fabs(average_depth_of_interaction_in_cm - - guessed_scanner_ptr->get_average_depth_of_interaction()/10) > .001) - { - warning("Interfile warning: 'average depth of interaction (cm)' (%f) is expected to be %f.\n", - average_depth_of_interaction_in_cm, - guessed_scanner_ptr->get_average_depth_of_interaction()/10); - mismatch_between_header_and_guess = true; - } - if (fabs(distance_between_rings_in_cm-guessed_scanner_ptr->get_ring_spacing()/10) > .001) - { - warning("Interfile warning: 'distance between rings (cm)' (%f) is expected to be %f.\n", - distance_between_rings_in_cm, guessed_scanner_ptr->get_ring_spacing()/10); - mismatch_between_header_and_guess = true; - } - if (fabs(default_bin_size_in_cm-guessed_scanner_ptr->get_default_bin_size()/10) > .001) - { - warning("Interfile warning: 'default bin size (cm)' (%f) is expected to be %f.\n", - default_bin_size_in_cm, guessed_scanner_ptr->get_default_bin_size()/10); - mismatch_between_header_and_guess = true; - } - if (max_num_non_arccorrected_bins - guessed_scanner_ptr->get_max_num_non_arccorrected_bins()) - { - warning("Interfile warning: 'max_num_non_arccorrected_bins' (%d) is expected to be %d", - max_num_non_arccorrected_bins, guessed_scanner_ptr->get_max_num_non_arccorrected_bins()); - mismatch_between_header_and_guess = true; - } - if (default_num_arccorrected_bins - guessed_scanner_ptr->get_default_num_arccorrected_bins()) - { - warning("Interfile warning: 'default_num_arccorrected_bins' (%d) is expected to be %d", - default_num_arccorrected_bins, guessed_scanner_ptr->get_default_num_arccorrected_bins()); - mismatch_between_header_and_guess = true; - } - if ( - guessed_scanner_ptr->get_num_transaxial_blocks_per_bucket()>0 && - num_transaxial_blocks_per_bucket != guessed_scanner_ptr->get_num_transaxial_blocks_per_bucket()) - { - warning("Interfile warning: num_transaxial_blocks_per_bucket (%d) is expected to be %d.\n", - num_transaxial_blocks_per_bucket, guessed_scanner_ptr->get_num_transaxial_blocks_per_bucket()); - mismatch_between_header_and_guess = true; - } - if ( - guessed_scanner_ptr->get_num_axial_blocks_per_bucket()>0 && - num_axial_blocks_per_bucket != guessed_scanner_ptr->get_num_axial_blocks_per_bucket()) - { - warning("Interfile warning: num_axial_blocks_per_bucket (%d) is expected to be %d.\n", - num_axial_blocks_per_bucket, guessed_scanner_ptr->get_num_axial_blocks_per_bucket()); - mismatch_between_header_and_guess = true; - } - if ( - guessed_scanner_ptr->get_num_axial_crystals_per_block()>0 && - num_axial_crystals_per_block!= guessed_scanner_ptr->get_num_axial_crystals_per_block()) - { - warning("Interfile warning: num_axial_crystals_per_block (%d) is expected to be %d.\n", - num_axial_crystals_per_block, guessed_scanner_ptr->get_num_axial_crystals_per_block()); - mismatch_between_header_and_guess = true; - } - if ( - guessed_scanner_ptr->get_num_transaxial_crystals_per_block()>0 && - num_transaxial_crystals_per_block!= guessed_scanner_ptr->get_num_transaxial_crystals_per_block()) - { - warning("Interfile warning: num_transaxial_crystals_per_block (%d) is expected to be %d.\n", - num_transaxial_crystals_per_block, guessed_scanner_ptr->get_num_transaxial_crystals_per_block()); - mismatch_between_header_and_guess = true; - } - if ( guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit() > 0 && - num_axial_crystals_per_singles_unit != - guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit() ) - { - warning("Interfile warning: axial crystals per singles unit (%d) is expected to be %d.\n", - num_axial_crystals_per_singles_unit, - guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit()); - mismatch_between_header_and_guess = true; - } - if ( guessed_scanner_ptr->get_num_transaxial_crystals_per_singles_unit() > 0 && - num_transaxial_crystals_per_singles_unit != - guessed_scanner_ptr->get_num_transaxial_crystals_per_singles_unit() ) - { - warning("Interfile warning: transaxial crystals per singles unit (%d) is expected to be %d.\n", - num_transaxial_crystals_per_singles_unit, - guessed_scanner_ptr->get_num_transaxial_crystals_per_singles_unit()); - mismatch_between_header_and_guess = true; - } - if ( - guessed_scanner_ptr->get_num_detector_layers()>0 && - num_detector_layers != guessed_scanner_ptr->get_num_detector_layers()) - { - warning("Interfile warning: num_detector_layers (%d) is expected to be %d.\n", - num_detector_layers, guessed_scanner_ptr->get_num_detector_layers()); - mismatch_between_header_and_guess = true; - } + if (num_rings != guessed_scanner_ptr->get_num_rings()) { + warning("Interfile warning: 'number of rings' (%d) is expected to be %d.\n", num_rings, + guessed_scanner_ptr->get_num_rings()); + mismatch_between_header_and_guess = true; + } + if (num_detectors_per_ring != guessed_scanner_ptr->get_num_detectors_per_ring()) { + warning("Interfile warning: 'number of detectors per ring' (%d) is expected to be %d.\n", num_detectors_per_ring, + guessed_scanner_ptr->get_num_detectors_per_ring()); + mismatch_between_header_and_guess = true; + } + if (fabs(inner_ring_diameter_in_cm - guessed_scanner_ptr->get_inner_ring_radius() * 2 / 10.) > .001) { + warning("Interfile warning: 'inner ring diameter (cm)' (%f) is expected to be %f.\n", inner_ring_diameter_in_cm, + guessed_scanner_ptr->get_inner_ring_radius() * 2 / 10.); + mismatch_between_header_and_guess = true; + } + if (fabs(average_depth_of_interaction_in_cm - guessed_scanner_ptr->get_average_depth_of_interaction() / 10) > .001) { + warning("Interfile warning: 'average depth of interaction (cm)' (%f) is expected to be %f.\n", + average_depth_of_interaction_in_cm, guessed_scanner_ptr->get_average_depth_of_interaction() / 10); + mismatch_between_header_and_guess = true; + } + if (fabs(distance_between_rings_in_cm - guessed_scanner_ptr->get_ring_spacing() / 10) > .001) { + warning("Interfile warning: 'distance between rings (cm)' (%f) is expected to be %f.\n", distance_between_rings_in_cm, + guessed_scanner_ptr->get_ring_spacing() / 10); + mismatch_between_header_and_guess = true; + } + if (fabs(default_bin_size_in_cm - guessed_scanner_ptr->get_default_bin_size() / 10) > .001) { + warning("Interfile warning: 'default bin size (cm)' (%f) is expected to be %f.\n", default_bin_size_in_cm, + guessed_scanner_ptr->get_default_bin_size() / 10); + mismatch_between_header_and_guess = true; + } + if (max_num_non_arccorrected_bins - guessed_scanner_ptr->get_max_num_non_arccorrected_bins()) { + warning("Interfile warning: 'max_num_non_arccorrected_bins' (%d) is expected to be %d", max_num_non_arccorrected_bins, + guessed_scanner_ptr->get_max_num_non_arccorrected_bins()); + mismatch_between_header_and_guess = true; + } + if (default_num_arccorrected_bins - guessed_scanner_ptr->get_default_num_arccorrected_bins()) { + warning("Interfile warning: 'default_num_arccorrected_bins' (%d) is expected to be %d", default_num_arccorrected_bins, + guessed_scanner_ptr->get_default_num_arccorrected_bins()); + mismatch_between_header_and_guess = true; + } + if (guessed_scanner_ptr->get_num_transaxial_blocks_per_bucket() > 0 && + num_transaxial_blocks_per_bucket != guessed_scanner_ptr->get_num_transaxial_blocks_per_bucket()) { + warning("Interfile warning: num_transaxial_blocks_per_bucket (%d) is expected to be %d.\n", + num_transaxial_blocks_per_bucket, guessed_scanner_ptr->get_num_transaxial_blocks_per_bucket()); + mismatch_between_header_and_guess = true; + } + if (guessed_scanner_ptr->get_num_axial_blocks_per_bucket() > 0 && + num_axial_blocks_per_bucket != guessed_scanner_ptr->get_num_axial_blocks_per_bucket()) { + warning("Interfile warning: num_axial_blocks_per_bucket (%d) is expected to be %d.\n", num_axial_blocks_per_bucket, + guessed_scanner_ptr->get_num_axial_blocks_per_bucket()); + mismatch_between_header_and_guess = true; + } + if (guessed_scanner_ptr->get_num_axial_crystals_per_block() > 0 && + num_axial_crystals_per_block != guessed_scanner_ptr->get_num_axial_crystals_per_block()) { + warning("Interfile warning: num_axial_crystals_per_block (%d) is expected to be %d.\n", num_axial_crystals_per_block, + guessed_scanner_ptr->get_num_axial_crystals_per_block()); + mismatch_between_header_and_guess = true; + } + if (guessed_scanner_ptr->get_num_transaxial_crystals_per_block() > 0 && + num_transaxial_crystals_per_block != guessed_scanner_ptr->get_num_transaxial_crystals_per_block()) { + warning("Interfile warning: num_transaxial_crystals_per_block (%d) is expected to be %d.\n", + num_transaxial_crystals_per_block, guessed_scanner_ptr->get_num_transaxial_crystals_per_block()); + mismatch_between_header_and_guess = true; + } + if (guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit() > 0 && + num_axial_crystals_per_singles_unit != guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit()) { + warning("Interfile warning: axial crystals per singles unit (%d) is expected to be %d.\n", + num_axial_crystals_per_singles_unit, guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit()); + mismatch_between_header_and_guess = true; + } + if (guessed_scanner_ptr->get_num_transaxial_crystals_per_singles_unit() > 0 && + num_transaxial_crystals_per_singles_unit != guessed_scanner_ptr->get_num_transaxial_crystals_per_singles_unit()) { + warning("Interfile warning: transaxial crystals per singles unit (%d) is expected to be %d.\n", + num_transaxial_crystals_per_singles_unit, guessed_scanner_ptr->get_num_transaxial_crystals_per_singles_unit()); + mismatch_between_header_and_guess = true; + } + if (guessed_scanner_ptr->get_num_detector_layers() > 0 && + num_detector_layers != guessed_scanner_ptr->get_num_detector_layers()) { + warning("Interfile warning: num_detector_layers (%d) is expected to be %d.\n", num_detector_layers, + guessed_scanner_ptr->get_num_detector_layers()); + mismatch_between_header_and_guess = true; + } // // 06/16: N.E: Currently, the energy resolution and the reference energy, are used only in the // scatter correction. Therefore a waring is displayed but they don't trigger // a mismatch. I assume that the user will handle this. This is in accordance with the // scanner '==' operator, which displays a warning message for these two parameters // but continues as usual. - if (energy_resolution > 0) - { - if (energy_resolution != guessed_scanner_ptr->get_energy_resolution()) - { - warning("Interfile warning: 'energy resolution' (%4.3f) is expected to be %4.3f. " - "Currently, the energy resolution and the reference energy, are used only in" - " scatter correction.", - energy_resolution, guessed_scanner_ptr->get_energy_resolution()); -// mismatch_between_header_and_guess = true; + if (energy_resolution > 0) { + if (energy_resolution != guessed_scanner_ptr->get_energy_resolution()) { + warning("Interfile warning: 'energy resolution' (%4.3f) is expected to be %4.3f. " + "Currently, the energy resolution and the reference energy, are used only in" + " scatter correction.", + energy_resolution, guessed_scanner_ptr->get_energy_resolution()); + // mismatch_between_header_and_guess = true; } - if (reference_energy != guessed_scanner_ptr->get_reference_energy()) - { - warning("Interfile warning: 'reference energy' (%4.3f) is expected to be %4.3f." - "Currently, the energy resolution and the reference energy, are used only in" - " scatter correction.", - reference_energy, guessed_scanner_ptr->get_reference_energy()); -// mismatch_between_header_and_guess = true; + if (reference_energy != guessed_scanner_ptr->get_reference_energy()) { + warning("Interfile warning: 'reference energy' (%4.3f) is expected to be %4.3f." + "Currently, the energy resolution and the reference energy, are used only in" + " scatter correction.", + reference_energy, guessed_scanner_ptr->get_reference_energy()); + // mismatch_between_header_and_guess = true; } } - // end of checks. If they failed, we ignore the guess - if (mismatch_between_header_and_guess) - { - warning("Interfile warning: I have used all explicit settings for the scanner\n" - "\tfrom the Interfile header, and remaining fields set from the\n" - "\t%s model.\n", - guessed_scanner_ptr->get_name().c_str()); - if (!originating_system_was_recognised) - guessed_scanner_ptr.reset(new Scanner( Scanner::Unknown_scanner)); + if (guessed_scanner_ptr->is_tof_ready()) { + if (max_num_timing_poss != guessed_scanner_ptr->get_max_num_timing_poss()) { + warning("Interfile warning: 'Number of TOF time bins' (%d) is expected to be %d.", max_num_timing_poss, + guessed_scanner_ptr->get_max_num_timing_poss()); + mismatch_between_header_and_guess = true; + } + if (size_of_timing_pos != guessed_scanner_ptr->get_size_of_timing_pos()) { + warning("Interfile warning: 'Size of timing bin (ps)' (%f) is expected to be %f.", size_of_timing_pos, + guessed_scanner_ptr->get_size_of_timing_pos()); + mismatch_between_header_and_guess = true; + } + if (timing_resolution != guessed_scanner_ptr->get_timing_resolution()) { + warning("Interfile warning: 'Timing resolution (ps)' (%f) is expected to be %f.", timing_resolution, + guessed_scanner_ptr->get_timing_resolution()); + mismatch_between_header_and_guess = true; } } + // end of checks. If they failed, we ignore the guess + if (mismatch_between_header_and_guess) { + warning("Interfile warning: I have used all explicit settings for the scanner\n" + "\tfrom the Interfile header, and remaining fields set from the\n" + "\t%s model.\n", + guessed_scanner_ptr->get_name().c_str()); + if (!originating_system_was_recognised) + guessed_scanner_ptr.reset(new Scanner(Scanner::Unknown_scanner)); + } + } + if (guessed_scanner_ptr->get_type() == Scanner::Unknown_scanner || - guessed_scanner_ptr->get_type() == Scanner::User_defined_scanner) - { + guessed_scanner_ptr->get_type() == Scanner::User_defined_scanner) { // warn if the Interfile header does not provide enough info if (num_rings < 1) @@ -1284,94 +1130,57 @@ bool InterfilePDFSHeader::post_processing() warning("Interfile warning: 'axial crystals per singles unit' invalid.\n"); if (num_transaxial_crystals_per_singles_unit <= 0) warning("Interfile warning: 'transaxial crystals per singles unit' invalid.\n"); - } // finally, we construct a new scanner object with // data from the Interfile header (or the guessed scanner). - shared_ptr scanner_ptr_from_file( - new Scanner(guessed_scanner_ptr->get_type(), - get_exam_info().originating_system, - num_detectors_per_ring, - num_rings, - max_num_non_arccorrected_bins, - default_num_arccorrected_bins, - static_cast(inner_ring_diameter_in_cm*10./2), - static_cast(average_depth_of_interaction_in_cm*10), - static_cast(distance_between_rings_in_cm*10.), - static_cast(default_bin_size_in_cm*10), - static_cast(view_offset_in_degrees*_PI/180), - num_axial_blocks_per_bucket, - num_transaxial_blocks_per_bucket, - num_axial_crystals_per_block, - num_transaxial_crystals_per_block, - num_axial_crystals_per_singles_unit, - num_transaxial_crystals_per_singles_unit, - num_detector_layers, - energy_resolution, - reference_energy)); - - bool is_consistent = - scanner_ptr_from_file->check_consistency() == Succeeded::yes; - if (scanner_ptr_from_file->get_type() == Scanner::Unknown_scanner || - scanner_ptr_from_file->get_type() == Scanner::User_defined_scanner || - mismatch_between_header_and_guess || - !is_consistent) - { - warning("Interfile parsing ended up with the following scanner:\n%s\n", - scanner_ptr_from_file->parameter_info().c_str()); - } - - + + shared_ptr scanner_sptr_from_file; + + scanner_sptr_from_file.reset(new Scanner( + guessed_scanner_ptr->get_type(), get_exam_info_sptr()->originating_system, num_detectors_per_ring, num_rings, + max_num_non_arccorrected_bins, default_num_arccorrected_bins, static_cast(inner_ring_diameter_in_cm * 10. / 2), + static_cast(average_depth_of_interaction_in_cm * 10), static_cast(distance_between_rings_in_cm * 10.), + static_cast(default_bin_size_in_cm * 10), static_cast(view_offset_in_degrees * _PI / 180), + num_axial_blocks_per_bucket, num_transaxial_blocks_per_bucket, num_axial_crystals_per_block, + num_transaxial_crystals_per_block, num_axial_crystals_per_singles_unit, num_transaxial_crystals_per_singles_unit, + num_detector_layers, energy_resolution, reference_energy, max_num_timing_poss, size_of_timing_pos, timing_resolution)); + + bool is_consistent = scanner_sptr_from_file->check_consistency() == Succeeded::yes; + if (scanner_sptr_from_file->get_type() == Scanner::Unknown_scanner || + scanner_sptr_from_file->get_type() == Scanner::User_defined_scanner || mismatch_between_header_and_guess || + !is_consistent) { + warning("Interfile parsing ended up with the following scanner:\n%s\n", scanner_sptr_from_file->parameter_info().c_str()); + } + // float azimuthal_angle_sampling =_PI/num_views; - - - - - if (is_arccorrected) - { - if (effective_central_bin_size_in_cm <= 0) - effective_central_bin_size_in_cm = - scanner_ptr_from_file->get_default_bin_size()/10; - else if (fabs(effective_central_bin_size_in_cm - - scanner_ptr_from_file->get_default_bin_size()/10)>.001) - warning("Interfile warning: unexpected effective_central_bin_size_in_cm\n" - "Value in header is %g while the default for the scanner is %g\n" - "Using value from header.", - effective_central_bin_size_in_cm, - scanner_ptr_from_file->get_default_bin_size()/10); - - data_info_sptr.reset( - new ProjDataInfoCylindricalArcCorr ( - scanner_ptr_from_file, - float(effective_central_bin_size_in_cm*10.), - sorted_num_rings_per_segment, - sorted_min_ring_diff, - sorted_max_ring_diff, - num_views,num_bins)); - } - else - { - data_info_sptr.reset( - new ProjDataInfoCylindricalNoArcCorr ( - scanner_ptr_from_file, - sorted_num_rings_per_segment, - sorted_min_ring_diff, - sorted_max_ring_diff, - num_views,num_bins)); - if (effective_central_bin_size_in_cm>0 && - fabs(effective_central_bin_size_in_cm - - data_info_sptr->get_sampling_in_s(Bin(0,0,0,0))/10.)>.01) - { - warning("Interfile warning: inconsistent effective_central_bin_size_in_cm\n" - "Value in header is %g while I expect %g from the inner ring radius etc\n" - "Ignoring value in header", - effective_central_bin_size_in_cm, - data_info_sptr->get_sampling_in_s(Bin(0,0,0,0))/10.); - } + + if (is_arccorrected) { + if (effective_central_bin_size_in_cm <= 0) + effective_central_bin_size_in_cm = scanner_sptr_from_file->get_default_bin_size() / 10; + else if (fabs(effective_central_bin_size_in_cm - scanner_sptr_from_file->get_default_bin_size() / 10) > .001) + warning("Interfile warning: unexpected effective_central_bin_size_in_cm\n" + "Value in header is %g while the default for the scanner is %g\n" + "Using value from header.", + effective_central_bin_size_in_cm, scanner_sptr_from_file->get_default_bin_size() / 10); + + data_info_sptr.reset(new ProjDataInfoCylindricalArcCorr(scanner_sptr_from_file, float(effective_central_bin_size_in_cm * 10.), + sorted_num_rings_per_segment, sorted_min_ring_diff, + sorted_max_ring_diff, num_views, num_bins, tof_mash_factor)); + } else { + data_info_sptr.reset(new ProjDataInfoCylindricalNoArcCorr(scanner_sptr_from_file, sorted_num_rings_per_segment, + sorted_min_ring_diff, sorted_max_ring_diff, num_views, num_bins, + tof_mash_factor)); + if (effective_central_bin_size_in_cm > 0 && + fabs(effective_central_bin_size_in_cm - data_info_sptr->get_sampling_in_s(Bin(0, 0, 0, 0)) / 10.) > .01) { + warning("Interfile warning: inconsistent effective_central_bin_size_in_cm\n" + "Value in header is %g while I expect %g from the inner ring radius etc\n" + "Ignoring value in header", + effective_central_bin_size_in_cm, data_info_sptr->get_sampling_in_s(Bin(0, 0, 0, 0)) / 10.); } - //cerr << data_info_ptr->parameter_info() << endl; - + } + // cerr << data_info_ptr->parameter_info() << endl; + // Set the bed position data_info_sptr->set_bed_position_horizontal(bed_position_horizontal); data_info_sptr->set_bed_position_vertical(bed_position_vertical); diff --git a/src/IO/InterfileHeaderSiemens.cxx b/src/IO/InterfileHeaderSiemens.cxx index 840576cea8..3712d29d98 100644 --- a/src/IO/InterfileHeaderSiemens.cxx +++ b/src/IO/InterfileHeaderSiemens.cxx @@ -19,8 +19,8 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup InterfileIO + \file + \ingroup InterfileIO \brief implementations for the stir::InterfileHeaderSiemens class \author Kris Thielemans @@ -50,33 +50,30 @@ using std::vector; START_NAMESPACE_STIR -InterfileHeaderSiemens::InterfileHeaderSiemens() - : InterfileHeader() -{ +InterfileHeaderSiemens::InterfileHeaderSiemens() : InterfileHeader() { // always PET exam_info_sptr->imaging_modality = ImagingModality::PT; - + byte_order_values.push_back("LITTLEENDIAN"); byte_order_values.push_back("BIGENDIAN"); - + PET_data_type_values.push_back("Emission"); PET_data_type_values.push_back("Transmission"); PET_data_type_values.push_back("Blank"); PET_data_type_values.push_back("AttenuationCorrection"); PET_data_type_values.push_back("Normalisation"); PET_data_type_values.push_back("Image"); - - for (int patient_position_idx = 0; patient_position_idx <= PatientPosition::unknown_position; ++patient_position_idx) - { - PatientPosition pos((PatientPosition::PositionValue)patient_position_idx); - patient_position_values.push_back(pos.get_position_as_string()); - } - patient_position_index = static_cast(patient_position_values.size()); //unknown - byte_order_index = 1;// file_byte_order = ByteOrder::big_endian; + + for (int patient_position_idx = 0; patient_position_idx <= PatientPosition::unknown_position; ++patient_position_idx) { + PatientPosition pos((PatientPosition::PositionValue)patient_position_idx); + patient_position_values.push_back(pos.get_position_as_string()); + } + patient_position_index = static_cast(patient_position_values.size()); // unknown + byte_order_index = 1; // file_byte_order = ByteOrder::big_endian; // need to default to PET for backwards compatibility this->exam_info_sptr->imaging_modality = ImagingModality::PT; - //type_of_data_index = 6; // PET + // type_of_data_index = 6; // PET PET_data_type_index = 5; // Image num_dimensions = 2; // set to 2 to be compatible with Interfile version 3.3 (which doesn't have this keyword) @@ -88,23 +85,15 @@ InterfileHeaderSiemens::InterfileHeaderSiemens() data_offset = 0UL; - // use this as opposed to InterfileHeader::set_type_of_data() to cope with specifics for Siemens remove_key("type of data"); - add_key("type of data", - KeyArgument::ASCIIlist, - (KeywordProcessor)&InterfileHeaderSiemens::set_type_of_data, - &type_of_data_index, - &type_of_data_values); - - add_key("%patient orientation", - &patient_position_index, - &patient_position_values); - - add_key("image data byte order", - &byte_order_index, - &byte_order_values); - + add_key("type of data", KeyArgument::ASCIIlist, (KeywordProcessor)&InterfileHeaderSiemens::set_type_of_data, + &type_of_data_index, &type_of_data_values); + + add_key("%patient orientation", &patient_position_index, &patient_position_values); + + add_key("image data byte order", &byte_order_index, &byte_order_values); + add_vectorised_key("scale factor (mm/pixel)", &pixel_sizes); // only a single time frame supported by Siemens currently @@ -119,8 +108,8 @@ InterfileHeaderSiemens::InterfileHeaderSiemens() add_key("image duration (sec)", &image_durations[0]); } -bool InterfileHeaderSiemens::post_processing() -{ +bool +InterfileHeaderSiemens::post_processing() { if (InterfileHeader::post_processing() == true) return true; @@ -131,20 +120,19 @@ bool InterfileHeaderSiemens::post_processing() return true; }*/ - if (patient_position_index<0 ) + if (patient_position_index < 0) return true; // note: has to be done after InterfileHeader::post_processing as that sets it as well exam_info_sptr->patient_position = PatientPosition((PatientPosition::PositionValue)patient_position_index); - file_byte_order = byte_order_index==0 ? - ByteOrder::little_endian : ByteOrder::big_endian; + file_byte_order = byte_order_index == 0 ? ByteOrder::little_endian : ByteOrder::big_endian; return false; } -void InterfileHeaderSiemens::set_type_of_data() -{ +void +InterfileHeaderSiemens::set_type_of_data() { set_variable(); if (this->type_of_data_index == -1) @@ -152,9 +140,8 @@ void InterfileHeaderSiemens::set_type_of_data() const string type_of_data = this->type_of_data_values[this->type_of_data_index]; - if (type_of_data == "PET") - { - // already done in constructor + if (type_of_data == "PET") { + // already done in constructor #if 0 add_key("PET data type", &PET_data_type_index, @@ -162,19 +149,14 @@ void InterfileHeaderSiemens::set_type_of_data() ignore_key("process status"); ignore_key("IMAGE DATA DESCRIPTION"); #endif - } - else - { - warning("Interfile parsing of Siemens listmode: unexpected 'type of data:=" + type_of_data + "' (expected PET). Continuing"); - } + } else { + warning("Interfile parsing of Siemens listmode: unexpected 'type of data:=" + type_of_data + "' (expected PET). Continuing"); + } } - /**********************************************************************/ -InterfileRawDataHeaderSiemens::InterfileRawDataHeaderSiemens() - : InterfileHeaderSiemens() -{ +InterfileRawDataHeaderSiemens::InterfileRawDataHeaderSiemens() : InterfileHeaderSiemens() { // first set to some crazy values num_segments = -1; num_rings = -1; @@ -183,19 +165,17 @@ InterfileRawDataHeaderSiemens::InterfileRawDataHeaderSiemens() add_key("number of rings", &num_rings); add_key("%axial compression", &axial_compression); - add_key("%maximum ring difference", &maximum_ring_difference); + add_key("%maximum ring difference", &maximum_ring_difference); add_key("%number of segments", &num_segments); add_key("%segment table", &segment_table); add_key("%number of tof time bins", &num_tof_bins); - + add_vectorised_key("%energy window lower level (keV)", &lower_en_window_thresholds); add_vectorised_key("%energy window upper level (keV)", &upper_en_window_thresholds); remove_key("PET data type"); - add_key("PET data type", - &PET_data_type_index, - &PET_data_type_values); + add_key("PET data type", &PET_data_type_index, &PET_data_type_values); // TODO should add data format:=CoincidenceList|sinogram and then check its value remove_key("process status"); @@ -245,47 +225,39 @@ InterfileRawDataHeaderSiemens::InterfileRawDataHeaderSiemens() ignore_key("%pdr loss fraction"); ignore_key("%detector block singles"); ignore_key("%total uncorrected singles rate"); - } -bool InterfileRawDataHeaderSiemens::post_processing() -{ +bool +InterfileRawDataHeaderSiemens::post_processing() { if (InterfileHeaderSiemens::post_processing() == true) return true; - const std::string PET_data_type = - standardise_interfile_keyword(PET_data_type_values[PET_data_type_index]); - if (PET_data_type != "emission" && PET_data_type != "transmission") - { error("Interfile error: expecting emission or transmission for 'PET data type'"); } + const std::string PET_data_type = standardise_interfile_keyword(PET_data_type_values[PET_data_type_index]); + if (PET_data_type != "emission" && PET_data_type != "transmission") { + error("Interfile error: expecting emission or transmission for 'PET data type'"); + } // handle scanner shared_ptr scanner_sptr(Scanner::get_scanner_from_name(get_exam_info().originating_system)); - if (scanner_sptr->get_type() == Scanner::Unknown_scanner) - { - error("scanner not recognised from originating system"); - } + if (scanner_sptr->get_type() == Scanner::Unknown_scanner) { + error("scanner not recognised from originating system"); + } // consistency check with values of the scanner - if ((num_rings >= 0) && (num_rings != scanner_sptr->get_num_rings())) - { - error("Interfile warning: 'number of rings' (%d) is expected to be %d.\n", - num_rings, scanner_sptr->get_num_rings()); - } + if ((num_rings >= 0) && (num_rings != scanner_sptr->get_num_rings())) { + error("Interfile warning: 'number of rings' (%d) is expected to be %d.\n", num_rings, scanner_sptr->get_num_rings()); + } - data_info_ptr = - ProjDataInfo::construct_proj_data_info(scanner_sptr, - axial_compression, maximum_ring_difference, - num_views, num_bins, - is_arccorrected); + data_info_ptr = ProjDataInfo::construct_proj_data_info(scanner_sptr, axial_compression, maximum_ring_difference, num_views, + num_bins, is_arccorrected); // handle segments { - if (static_cast(num_segments) != segment_table.size()) - { - error("Interfile warning: 'number of segments' and length of 'segment table' are not consistent"); - } + if (static_cast(num_segments) != segment_table.size()) { + error("Interfile warning: 'number of segments' and length of 'segment table' are not consistent"); + } segment_sequence = ecat::find_segment_sequence(*data_info_ptr); - //XXX check if order here and segment_table are consistent + // XXX check if order here and segment_table are consistent } // Set the bed position @@ -295,16 +267,12 @@ bool InterfileRawDataHeaderSiemens::post_processing() return false; } - - /**********************************************************************/ -InterfilePDFSHeaderSiemens::InterfilePDFSHeaderSiemens() - : InterfileRawDataHeaderSiemens() -{ +InterfilePDFSHeaderSiemens::InterfilePDFSHeaderSiemens() : InterfileRawDataHeaderSiemens() { remove_key("scan data type description"); - add_key("number of scan data types", - KeyArgument::INT, (KeywordProcessor)&InterfilePDFSHeaderSiemens::read_scan_data_types, &num_scan_data_types); + add_key("number of scan data types", KeyArgument::INT, (KeywordProcessor)&InterfilePDFSHeaderSiemens::read_scan_data_types, + &num_scan_data_types); // scan data type size depends on the previous field // scan data type description[1]: = prompts // scan data type description[2] : = randoms @@ -324,104 +292,81 @@ InterfilePDFSHeaderSiemens::InterfilePDFSHeaderSiemens() // add_key(%tof mashing factor", &tof_mashing_factor); ignore_key("total number of data sets"); - add_key("%number of buckets", - KeyArgument::INT, (KeywordProcessor)&InterfilePDFSHeaderSiemens::read_bucket_singles_rates, &num_buckets); + add_key("%number of buckets", KeyArgument::INT, (KeywordProcessor)&InterfilePDFSHeaderSiemens::read_bucket_singles_rates, + &num_buckets); add_vectorised_key("%bucket singles rate", &bucket_singles_rates); - - } - -void InterfilePDFSHeaderSiemens::read_scan_data_types() -{ +void +InterfilePDFSHeaderSiemens::read_scan_data_types() { set_variable(); scan_data_types.resize(num_scan_data_types); data_offset_each_dataset.resize(num_scan_data_types); - } -void InterfilePDFSHeaderSiemens::read_bucket_singles_rates() -{ +void +InterfilePDFSHeaderSiemens::read_bucket_singles_rates() { set_variable(); bucket_singles_rates.resize(num_buckets); } -int InterfilePDFSHeaderSiemens::find_storage_order() -{ +int +InterfilePDFSHeaderSiemens::find_storage_order() { - if (num_dimensions != 3) - { + if (num_dimensions != 3) { warning("Interfile error: expecting 3D data "); stop_parsing(); return true; - } + } - if ((matrix_size[0].size() != 1) || - (matrix_size[1].size() != 1) || - (matrix_size[2].size() != 1)) - { + if ((matrix_size[0].size() != 1) || (matrix_size[1].size() != 1) || (matrix_size[2].size() != 1)) { error("Interfile error: strange values for the matrix_size keyword(s)"); - } + } if (matrix_labels[0] != "bin" && matrix_labels[0] != "x") // x is used for arccorrected data (ACF) - { + { // use error message with index [1] as that is what the user sees. error("Interfile error: expecting 'matrix axis label[1] := bin' or 'x'"); - } + } num_bins = matrix_size[0][0]; - if ((matrix_labels[1] == "projection" && matrix_labels[2] == "plane") || // used for emission + if ((matrix_labels[1] == "projection" && matrix_labels[2] == "plane") || // used for emission (matrix_labels[1] == "sinogram views" && matrix_labels[2] == "number of sinograms") // used for ACF - ) - { + ) { storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; num_views = matrix_size[1][0]; - } - else - { + } else { error("Interfile error: matrix labels not in expected (or supported) format"); - } + } return false; - } - -bool InterfilePDFSHeaderSiemens::post_processing() -{ +bool +InterfilePDFSHeaderSiemens::post_processing() { // check for arc-correction - if (applied_corrections.size() == 0) - { + if (applied_corrections.size() == 0) { warning("Parsing Interfile header for projection data: \n" - "\t'applied corrections' keyword not found or empty. Assuming non-arc-corrected data"); + "\t'applied corrections' keyword not found or empty. Assuming non-arc-corrected data"); is_arccorrected = false; - } - else - { + } else { is_arccorrected = false; - for ( - std::vector::const_iterator iter = applied_corrections.begin(); - iter != applied_corrections.end(); - ++iter) - { - const string correction = standardise_keyword(*iter); - if (correction == "radial arc-correction" || correction == "arc correction" || correction == "arc corrected") - { - is_arccorrected = true; - break; - } - else if (correction != "none") - warning("\nParsing Interfile header for projection data: \n" - "\t value '%s' for keyword 'applied corrections' ignored\n", - correction.c_str()); - } + for (std::vector::const_iterator iter = applied_corrections.begin(); iter != applied_corrections.end(); ++iter) { + const string correction = standardise_keyword(*iter); + if (correction == "radial arc-correction" || correction == "arc correction" || correction == "arc corrected") { + is_arccorrected = true; + break; + } else if (correction != "none") + warning("\nParsing Interfile header for projection data: \n" + "\t value '%s' for keyword 'applied corrections' ignored\n", + correction.c_str()); } + } - if (find_storage_order()) - { - error("Interfile error determining storage order"); - } + if (find_storage_order()) { + error("Interfile error determining storage order"); + } // can only do this now after the previous things were set if (InterfileRawDataHeaderSiemens::post_processing() == true) @@ -434,49 +379,46 @@ bool InterfilePDFSHeaderSiemens::post_processing() /**********************************************************************/ -InterfileListmodeHeaderSiemens::InterfileListmodeHeaderSiemens() - : InterfileRawDataHeaderSiemens() -{ +InterfileListmodeHeaderSiemens::InterfileListmodeHeaderSiemens() : InterfileRawDataHeaderSiemens() { // need to set this to construct the correct proj_data_info is_arccorrected = false; // need to set this for InterfileHeader::post_processing() // but will otherwise be ignored bytes_per_pixel = 4; - for (unsigned int dim = 0; dim != matrix_size.size(); ++dim) - { - matrix_size[dim].resize(1, 1); - } -/* - keywords different from a sinogram header (in alphabetical order) -< %LM event and tag words format (bits):=32 -< %SMS-MI header name space:=PETLINK bin address - -< %number of projections:=344 -< %number of views:=252 -< %preset type:=time -< %preset unit:=seconds -< %preset value:=900 -< %singles polling interval (sec):=2 -< %singles polling method:=instantaneous -< %singles scale factor:=8 -< %time_sync:=25934299 -< %timing tagwords interval (msec):=1 -< %total listmode word counts:=331257106 -< %total number of singles blocks:=224 -< PET scanner type:=cylindrical -< bin size (cm):=0.20445 - -< data format:=CoincidenceList - -< distance between rings (cm):=0.40625 -< end horizontal bed position (mm):=0 -< gantry crystal radius (cm):=32.8 -< gantry tilt angle (degrees):=0 - -> gantry tilt angle (degrees):=0.0 -< septa state:=none -< transaxial FOV diameter (cm):=59.6 -*/ + for (unsigned int dim = 0; dim != matrix_size.size(); ++dim) { + matrix_size[dim].resize(1, 1); + } + /* + keywords different from a sinogram header (in alphabetical order) + < %LM event and tag words format (bits):=32 + < %SMS-MI header name space:=PETLINK bin address + + < %number of projections:=344 + < %number of views:=252 + < %preset type:=time + < %preset unit:=seconds + < %preset value:=900 + < %singles polling interval (sec):=2 + < %singles polling method:=instantaneous + < %singles scale factor:=8 + < %time_sync:=25934299 + < %timing tagwords interval (msec):=1 + < %total listmode word counts:=331257106 + < %total number of singles blocks:=224 + < PET scanner type:=cylindrical + < bin size (cm):=0.20445 + + < data format:=CoincidenceList + + < distance between rings (cm):=0.40625 + < end horizontal bed position (mm):=0 + < gantry crystal radius (cm):=32.8 + < gantry tilt angle (degrees):=0 + + > gantry tilt angle (degrees):=0.0 + < septa state:=none + < transaxial FOV diameter (cm):=59.6 + */ add_key("%number of projections", &num_bins); add_key("%number of views", &num_views); @@ -505,32 +447,38 @@ InterfileListmodeHeaderSiemens::InterfileListmodeHeaderSiemens() ignore_key("%total number of singles blocks"); ignore_key("%time sync"); ignore_key("%comment"); - } +} -int InterfileListmodeHeaderSiemens::find_storage_order() -{ +int +InterfileListmodeHeaderSiemens::find_storage_order() { // always... storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; - + return false; } -int InterfileListmodeHeaderSiemens::get_axial_compression() const -{return axial_compression;} -int InterfileListmodeHeaderSiemens::get_maximum_ring_difference() const -{return maximum_ring_difference;} -int InterfileListmodeHeaderSiemens::get_num_views() const -{return num_views;} -int InterfileListmodeHeaderSiemens::get_num_projections() const -{return num_bins;} - +int +InterfileListmodeHeaderSiemens::get_axial_compression() const { + return axial_compression; +} +int +InterfileListmodeHeaderSiemens::get_maximum_ring_difference() const { + return maximum_ring_difference; +} +int +InterfileListmodeHeaderSiemens::get_num_views() const { + return num_views; +} +int +InterfileListmodeHeaderSiemens::get_num_projections() const { + return num_bins; +} -bool InterfileListmodeHeaderSiemens::post_processing() -{ - if (find_storage_order()) - { - error("Interfile error determining storage order"); - } +bool +InterfileListmodeHeaderSiemens::post_processing() { + if (find_storage_order()) { + error("Interfile error determining storage order"); + } // can only do this now after the previous things were set if (InterfileRawDataHeaderSiemens::post_processing() == true) @@ -539,5 +487,4 @@ bool InterfileListmodeHeaderSiemens::post_processing() return false; } - END_NAMESPACE_STIR diff --git a/src/IO/InterfileOutputFileFormat.cxx b/src/IO/InterfileOutputFileFormat.cxx index a9ae13f3dc..fc45577bcf 100644 --- a/src/IO/InterfileOutputFileFormat.cxx +++ b/src/IO/InterfileOutputFileFormat.cxx @@ -31,71 +31,49 @@ START_NAMESPACE_STIR +const char* const InterfileOutputFileFormat::registered_name = "Interfile"; -const char * const -InterfileOutputFileFormat::registered_name = "Interfile"; - -InterfileOutputFileFormat:: -InterfileOutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) -{ +InterfileOutputFileFormat::InterfileOutputFileFormat(const NumericType& type, const ByteOrder& byte_order) { base_type::set_defaults(); set_type_of_numbers(type); set_byte_order(byte_order); } -void -InterfileOutputFileFormat:: -set_defaults() -{ +void +InterfileOutputFileFormat::set_defaults() { base_type::set_defaults(); } -void -InterfileOutputFileFormat:: -initialise_keymap() -{ +void +InterfileOutputFileFormat::initialise_keymap() { parser.add_start_key("Interfile Output File Format Parameters"); parser.add_stop_key("End Interfile Output File Format Parameters"); base_type::initialise_keymap(); } -bool -InterfileOutputFileFormat:: -post_processing() -{ +bool +InterfileOutputFileFormat::post_processing() { if (base_type::post_processing()) return true; return false; } // note 'warn' commented below to avoid compiler warning message about unused variables -ByteOrder -InterfileOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool /* warn */) -{ +ByteOrder +InterfileOutputFileFormat::set_byte_order(const ByteOrder& new_byte_order, const bool /* warn */) { this->file_byte_order = new_byte_order; return this->file_byte_order; } - - -Succeeded -InterfileOutputFileFormat:: -actual_write_to_file(std::string& filename, - const DiscretisedDensity<3,float>& density) const -{ +Succeeded +InterfileOutputFileFormat::actual_write_to_file(std::string& filename, const DiscretisedDensity<3, float>& density) const { // TODO modify write_basic_interfile to return filename - + Succeeded success = - write_basic_interfile(filename, density, - this->type_of_numbers, this->scale_to_write_data, - this->file_byte_order); + write_basic_interfile(filename, density, this->type_of_numbers, this->scale_to_write_data, this->file_byte_order); if (success == Succeeded::yes) replace_extension(filename, ".hv"); return success; }; END_NAMESPACE_STIR - - diff --git a/src/IO/InterfilePDFSHeaderSPECT.cxx b/src/IO/InterfilePDFSHeaderSPECT.cxx index 6012292fee..4f8807a6c8 100644 --- a/src/IO/InterfilePDFSHeaderSPECT.cxx +++ b/src/IO/InterfilePDFSHeaderSPECT.cxx @@ -15,7 +15,7 @@ See STIR/LICENSE.txt for details */ -/*! +/*! \file \ingroup InterfileIO \brief This file implements the classes stir::InterfilePDFSHeaderSPECT @@ -40,38 +40,30 @@ using std::endl; START_NAMESPACE_STIR -//KT 26/10/98 +// KT 26/10/98 // KT 13/11/98 moved stream arg from constructor to parse() -InterfilePDFSHeaderSPECT::InterfilePDFSHeaderSPECT() -: InterfileHeader() -{ +InterfilePDFSHeaderSPECT::InterfilePDFSHeaderSPECT() : InterfileHeader() { num_segments = 1; num_views = -1; - add_key("number of projections", - &num_views); - start_angle=0; - add_key("start angle", - &start_angle); - direction_of_rotation="cw"; - add_key("direction of rotation", - &direction_of_rotation); - extent_of_rotation=double_value_not_set; - add_key("extent of rotation", - &extent_of_rotation); + add_key("number of projections", &num_views); + start_angle = 0; + add_key("start angle", &start_angle); + direction_of_rotation = "cw"; + add_key("direction of rotation", &direction_of_rotation); + extent_of_rotation = double_value_not_set; + add_key("extent of rotation", &extent_of_rotation); // TODO convert to ASCIIlist orbit = "circular"; - add_key("orbit", - &orbit); + add_key("orbit", &orbit); radius_of_rotation = double_value_not_set; - add_key("radius",&radius_of_rotation); - add_key("radii",&radii_of_rotation); // for non-circular orbits + add_key("radius", &radius_of_rotation); + add_key("radii", &radii_of_rotation); // for non-circular orbits // overwrite vectored-value, as v3.3 had a scalar add_key("data offset in bytes", &data_offset); - } -bool InterfilePDFSHeaderSPECT::post_processing() -{ +bool +InterfilePDFSHeaderSPECT::post_processing() { if (InterfileHeader::post_processing() == true) return true; @@ -80,79 +72,70 @@ bool InterfilePDFSHeaderSPECT::post_processing() data_offset_each_dataset[0] = data_offset; // SPECT v3.3 doesn't really define matrix_labels. We just check that if they're present, they are as in PET - if (matrix_labels[0].size()>0 && matrix_labels[0] != "bin coordinate") - { - // use error message with index [1] as that is what the user sees. - warning("Interfile error: expecting 'matrix axis label[1] := bin coordinate'"); - return true; - } - if (matrix_labels[1].size()>0 && matrix_labels[1] != "axial coordinate" ) - { - // use error message with index [2] as that is what the user sees. - warning("Interfile error: expecting 'matrix axis label[2] := axial coordinate'"); - return true; - } + if (matrix_labels[0].size() > 0 && matrix_labels[0] != "bin coordinate") { + // use error message with index [1] as that is what the user sees. + warning("Interfile error: expecting 'matrix axis label[1] := bin coordinate'"); + return true; + } + if (matrix_labels[1].size() > 0 && matrix_labels[1] != "axial coordinate") { + // use error message with index [2] as that is what the user sees. + warning("Interfile error: expecting 'matrix axis label[2] := axial coordinate'"); + return true; + } - if (extent_of_rotation == double_value_not_set) - { - warning("Interfile error: extent of rotation needs to be set"); - return true; - } + if (extent_of_rotation == double_value_not_set) { + warning("Interfile error: extent of rotation needs to be set"); + return true; + } num_bins = matrix_size[0][0]; - bin_size_in_cm = pixel_sizes[0]/10.; + bin_size_in_cm = pixel_sizes[0] / 10.; - storage_order =ProjDataFromStream::Segment_View_AxialPos_TangPos; - num_axial_poss= matrix_size[1][0]; - const double z_spacing_in_cm = pixel_sizes[1]/10.; + storage_order = ProjDataFromStream::Segment_View_AxialPos_TangPos; + num_axial_poss = matrix_size[1][0]; + const double z_spacing_in_cm = pixel_sizes[1] / 10.; - //Fill the radius depending on the type of orbit (just two orbits are supported) + // Fill the radius depending on the type of orbit (just two orbits are supported) // will be in mm (SPECT Interfile uses mm) - VectorWithOffset radii(0, num_views-1); - orbit=standardise_keyword(orbit); - if (orbit == "circular") - { - if (radius_of_rotation == double_value_not_set) - { - warning("Interfile error: radius not set"); - return true; - } - for ( int i = 0 ; i < num_views ; i++ ) radii[ i ] = static_cast(radius_of_rotation); - } - else if (orbit == "non-circular") - { - - if ( radii_of_rotation.size() != static_cast(num_views)) - { - warning("Interfile error: number of projections must be consistent with radius vector length"); - return true; - } - for ( int i = 0 ; i < num_views ; i++ ) radii[ i ] = static_cast(radii_of_rotation[i]); + VectorWithOffset radii(0, num_views - 1); + orbit = standardise_keyword(orbit); + if (orbit == "circular") { + if (radius_of_rotation == double_value_not_set) { + warning("Interfile error: radius not set"); + return true; } - else - { - warning("Interfile error: only circular or non-circular orbits are supported"); - return true; + for (int i = 0; i < num_views; i++) + radii[i] = static_cast(radius_of_rotation); + } else if (orbit == "non-circular") { + + if (radii_of_rotation.size() != static_cast(num_views)) { + warning("Interfile error: number of projections must be consistent with radius vector length"); + return true; } - + for (int i = 0; i < num_views; i++) + radii[i] = static_cast(radii_of_rotation[i]); + } else { + warning("Interfile error: only circular or non-circular orbits are supported"); + return true; + } // somewhat strange values to be compatible with PET - VectorWithOffset sorted_min_ring_diff(0,0); - VectorWithOffset sorted_max_ring_diff(0,0); - VectorWithOffset sorted_num_axial_poss_per_segment(0,0); - sorted_min_ring_diff[0]=0; - sorted_max_ring_diff[0]=0; - sorted_num_axial_poss_per_segment[0]=num_axial_poss; + VectorWithOffset sorted_min_ring_diff(0, 0); + VectorWithOffset sorted_max_ring_diff(0, 0); + VectorWithOffset sorted_num_axial_poss_per_segment(0, 0); + sorted_min_ring_diff[0] = 0; + sorted_max_ring_diff[0] = 0; + sorted_num_axial_poss_per_segment[0] = num_axial_poss; // we construct a new scanner object with // data from the Interfile header (or the guessed scanner). // Initialize the scanner values (most are not used in SPECT reconstruction) const int num_rings = sorted_num_axial_poss_per_segment[0]; - const int num_detectors_per_ring = -1;//num_views*2; + const int num_detectors_per_ring = -1; // num_views*2; const double average_depth_of_interaction_in_cm = 0; const double distance_between_rings_in_cm = z_spacing_in_cm; - double default_bin_size_in_cm = bin_size_in_cm ; + double default_bin_size_in_cm = bin_size_in_cm; const double view_offset_in_degrees = start_angle; const int max_num_non_arccorrected_bins = num_bins; const int default_num_arccorrected_bins = num_bins; @@ -163,27 +146,21 @@ bool InterfilePDFSHeaderSPECT::post_processing() const int num_axial_crystals_per_singles_unit = -1; const int num_transaxial_crystals_per_singles_unit = -1; const int num_detector_layers = 1; - + const float energy_resolution = -1.f; + const float reference_energy = -1.f; + const short int max_num_of_timing_poss = 1; + const float size_timing_pos = -1.f; + const float timing_resolution = -1.f; + shared_ptr guessed_scanner_ptr(Scanner::get_scanner_from_name(get_exam_info().originating_system)); - shared_ptr scanner_ptr_from_file( - new Scanner(guessed_scanner_ptr->get_type(), - get_exam_info().originating_system, - num_detectors_per_ring, - num_rings, - max_num_non_arccorrected_bins, - default_num_arccorrected_bins, - static_cast(radii[0]), - static_cast(average_depth_of_interaction_in_cm*10), - static_cast(distance_between_rings_in_cm*10.), - static_cast(default_bin_size_in_cm*10), - static_cast(view_offset_in_degrees*_PI/180), - num_axial_blocks_per_bucket, - num_transaxial_blocks_per_bucket, - num_axial_crystals_per_block, - num_transaxial_crystals_per_block, - num_axial_crystals_per_singles_unit, - num_transaxial_crystals_per_singles_unit, - num_detector_layers)); + shared_ptr scanner_ptr_from_file(new Scanner( + guessed_scanner_ptr->get_type(), get_exam_info_sptr()->originating_system, num_detectors_per_ring, num_rings, + max_num_non_arccorrected_bins, default_num_arccorrected_bins, static_cast(radii[0]), + static_cast(average_depth_of_interaction_in_cm * 10), static_cast(distance_between_rings_in_cm * 10.), + static_cast(default_bin_size_in_cm * 10), static_cast(view_offset_in_degrees * _PI / 180), + num_axial_blocks_per_bucket, num_transaxial_blocks_per_bucket, num_axial_crystals_per_block, + num_transaxial_crystals_per_block, num_axial_crystals_per_singles_unit, num_transaxial_crystals_per_singles_unit, + num_detector_layers, energy_resolution, reference_energy, max_num_of_timing_poss, size_timing_pos, timing_resolution)); #if 0 if (default_bin_size_in_cm <= 0) default_bin_size_in_cm = @@ -194,38 +171,27 @@ bool InterfilePDFSHeaderSPECT::post_processing() bin_size_in_cm, scanner_ptr_from_file->get_default_bin_size()/10); #endif - ProjDataInfoCylindricalArcCorr* my_data_info_ptr = - new ProjDataInfoCylindricalArcCorr ( - scanner_ptr_from_file, - float(bin_size_in_cm*10.), - sorted_num_axial_poss_per_segment, - sorted_min_ring_diff, - sorted_max_ring_diff, - num_views,num_bins); - - my_data_info_ptr->set_ring_radii_for_all_views ( radii); - - direction_of_rotation = standardise_keyword(direction_of_rotation); - const float angle_sampling = float (extent_of_rotation)/num_views * float(_PI/180); - if(direction_of_rotation=="cw") - { - my_data_info_ptr->set_azimuthal_angle_sampling(-angle_sampling); - } - else if(direction_of_rotation=="ccw") - { - my_data_info_ptr->set_azimuthal_angle_sampling(angle_sampling); - } - else - { - warning("direction of rotation has to be CW or CCW"); - return true; - } + ProjDataInfoCylindricalArcCorr* my_data_info_ptr = + new ProjDataInfoCylindricalArcCorr(scanner_ptr_from_file, float(bin_size_in_cm * 10.), sorted_num_axial_poss_per_segment, + sorted_min_ring_diff, sorted_max_ring_diff, num_views, num_bins); + + my_data_info_ptr->set_ring_radii_for_all_views(radii); + + direction_of_rotation = standardise_keyword(direction_of_rotation); + const float angle_sampling = float(extent_of_rotation) / num_views * float(_PI / 180); + if (direction_of_rotation == "cw") { + my_data_info_ptr->set_azimuthal_angle_sampling(-angle_sampling); + } else if (direction_of_rotation == "ccw") { + my_data_info_ptr->set_azimuthal_angle_sampling(angle_sampling); + } else { + warning("direction of rotation has to be CW or CCW"); + return true; + } this->data_info_sptr.reset(my_data_info_ptr); - //cerr << data_info_ptr->parameter_info() << endl; + // cerr << data_info_ptr->parameter_info() << endl; return false; } - END_NAMESPACE_STIR diff --git a/src/IO/InterfileParametricDiscretisedDensityOutputFileFormat.cxx b/src/IO/InterfileParametricDiscretisedDensityOutputFileFormat.cxx index 133cbf3414..f2f367f29e 100644 --- a/src/IO/InterfileParametricDiscretisedDensityOutputFileFormat.cxx +++ b/src/IO/InterfileParametricDiscretisedDensityOutputFileFormat.cxx @@ -42,16 +42,12 @@ START_NAMESPACE_STIR //#define InterfileParamDiscDensity InterfileParametricDiscretisedDensityOutputFileFormat #define InterfileParamDiscDensity InterfileParametricDiscretisedDensityOutputFileFormat - TEMPLATE -const char * const -InterfileParamDiscDensity::registered_name = "Interfile"; +const char* const InterfileParamDiscDensity::registered_name = "Interfile"; TEMPLATE -InterfileParamDiscDensity:: -InterfileParametricDiscretisedDensityOutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) -{ +InterfileParamDiscDensity::InterfileParametricDiscretisedDensityOutputFileFormat(const NumericType& type, + const ByteOrder& byte_order) { base_type::set_defaults(); this->set_type_of_numbers(type); this->set_byte_order(byte_order); @@ -59,64 +55,47 @@ InterfileParametricDiscretisedDensityOutputFileFormat(const NumericType& type, TEMPLATE void -InterfileParamDiscDensity:: -set_defaults() -{ +InterfileParamDiscDensity::set_defaults() { base_type::set_defaults(); } TEMPLATE void -InterfileParamDiscDensity:: -initialise_keymap() -{ +InterfileParamDiscDensity::initialise_keymap() { this->parser.add_start_key("Interfile Output File Format Parameters"); - this->parser.add_stop_key("End Interfile Output File Format Parameters"); + this->parser.add_stop_key("End Interfile Output File Format Parameters"); base_type::initialise_keymap(); } TEMPLATE bool -InterfileParamDiscDensity:: -post_processing() -{ +InterfileParamDiscDensity::post_processing() { if (base_type::post_processing()) return true; return false; } - TEMPLATE ByteOrder -InterfileParamDiscDensity:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) -{ - if (!new_byte_order.is_native_order()) - { +InterfileParamDiscDensity::set_byte_order(const ByteOrder& new_byte_order, const bool warn) { + if (!new_byte_order.is_native_order()) { if (warn) warning("InterfileParametricDiscretisedDensityOutputFileFormat: byte_order is currently fixed to the native format\n"); - this->file_byte_order = ByteOrder::native; - } - else - this->file_byte_order = new_byte_order; - return this->file_byte_order; + this->file_byte_order = ByteOrder::native; + } else + this->file_byte_order = new_byte_order; + return this->file_byte_order; } - - TEMPLATE Succeeded -InterfileParamDiscDensity:: -actual_write_to_file(std::string& filename, - const ParametricDiscretisedDensity& density) const -{ +InterfileParamDiscDensity::actual_write_to_file(std::string& filename, + const ParametricDiscretisedDensity& density) const { // TODO modify write_basic_interfile to return filename Succeeded success = - write_basic_interfile(filename, density, - this->type_of_numbers, this->scale_to_write_data, - this->file_byte_order); + write_basic_interfile(filename, density, this->type_of_numbers, this->scale_to_write_data, this->file_byte_order); if (success == Succeeded::yes) - replace_extension(filename, ".hv"); + replace_extension(filename, ".hv"); return success; } @@ -125,5 +104,4 @@ actual_write_to_file(std::string& filename, template class InterfileParametricDiscretisedDensityOutputFileFormat; - END_NAMESPACE_STIR diff --git a/src/IO/MultiDynamicDiscretisedDensityOutputFileFormat.cxx b/src/IO/MultiDynamicDiscretisedDensityOutputFileFormat.cxx index 07d89553c2..66002aa2b4 100644 --- a/src/IO/MultiDynamicDiscretisedDensityOutputFileFormat.cxx +++ b/src/IO/MultiDynamicDiscretisedDensityOutputFileFormat.cxx @@ -29,7 +29,7 @@ */ #include "stir/IO/MultiDynamicDiscretisedDensityOutputFileFormat.h" -#include "stir/DynamicDiscretisedDensity.h" +#include "stir/DynamicDiscretisedDensity.h" #include "stir/NumericType.h" #include "stir/Succeeded.h" #include "stir/FilePath.h" @@ -37,92 +37,75 @@ START_NAMESPACE_STIR -const char * const -MultiDynamicDiscretisedDensityOutputFileFormat::registered_name = "Multi"; +const char* const MultiDynamicDiscretisedDensityOutputFileFormat::registered_name = "Multi"; -MultiDynamicDiscretisedDensityOutputFileFormat:: -MultiDynamicDiscretisedDensityOutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) -{ +MultiDynamicDiscretisedDensityOutputFileFormat::MultiDynamicDiscretisedDensityOutputFileFormat(const NumericType& type, + const ByteOrder& byte_order) { this->set_defaults(); this->set_type_of_numbers(type); this->set_byte_order(byte_order); } -void -MultiDynamicDiscretisedDensityOutputFileFormat:: -set_defaults() -{ +void +MultiDynamicDiscretisedDensityOutputFileFormat::set_defaults() { base_type::set_defaults(); this->set_type_of_numbers(NumericType::FLOAT); this->set_byte_order(ByteOrder::native); - this->individual_output_type_sptr = OutputFileFormat >::default_sptr(); + this->individual_output_type_sptr = OutputFileFormat>::default_sptr(); } -void -MultiDynamicDiscretisedDensityOutputFileFormat:: -initialise_keymap() -{ +void +MultiDynamicDiscretisedDensityOutputFileFormat::initialise_keymap() { this->parser.add_start_key("Multi Output File Format Parameters"); this->parser.add_stop_key("End Multi Output File Format Parameters"); - this->parser.add_parsing_key("individual output file format type",&individual_output_type_sptr); + this->parser.add_parsing_key("individual output file format type", &individual_output_type_sptr); base_type::initialise_keymap(); } -bool -MultiDynamicDiscretisedDensityOutputFileFormat:: -post_processing() -{ +bool +MultiDynamicDiscretisedDensityOutputFileFormat::post_processing() { if (base_type::post_processing()) return true; return false; } - -ByteOrder -MultiDynamicDiscretisedDensityOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) -{ - if (!new_byte_order.is_native_order()) - { - if (warn) - warning("MultiDynamicDiscretisedDensityOutputFileFormat: byte_order is currently fixed to the native format\n"); - this->file_byte_order = ByteOrder::native; - } - else +ByteOrder +MultiDynamicDiscretisedDensityOutputFileFormat::set_byte_order(const ByteOrder& new_byte_order, const bool warn) { + if (!new_byte_order.is_native_order()) { + if (warn) + warning("MultiDynamicDiscretisedDensityOutputFileFormat: byte_order is currently fixed to the native format\n"); + this->file_byte_order = ByteOrder::native; + } else this->file_byte_order = new_byte_order; - return this->file_byte_order; + return this->file_byte_order; } -Succeeded -MultiDynamicDiscretisedDensityOutputFileFormat:: -actual_write_to_file(std::string& filename, - const DynamicDiscretisedDensity & density) const -{ - { - FilePath file_path(filename, false); // create object without checking if a fo;e exists already - if (!file_path.get_extension().empty()) - error("MultiDynamicDiscretisedDensityOutputFileFormat: currently needs an output filename without extension. sorry"); - } - // Create all the filenames - VectorWithOffset individual_filenames(1,int(density.get_num_time_frames())); - for (int i=1; i<=int(density.get_num_time_frames()); i++) - individual_filenames[i] = filename + "_" + boost::lexical_cast(i); - - // Write each individual image - for (int i=1; i<=int(density.get_num_time_frames()); i++) { - Succeeded success = individual_output_type_sptr->write_to_file(individual_filenames[i],density.get_density(unsigned(i))); - if (success != Succeeded::yes) - warning("MultiDynamicDiscretisedDensity error: Failed to write \"" + individual_filenames[i] + "\".\n"); - } - - // Write some multi header info - filename = filename + ".txt"; - MultipleDataSetHeader::write_header(filename, individual_filenames); - return Succeeded::yes; +Succeeded +MultiDynamicDiscretisedDensityOutputFileFormat::actual_write_to_file(std::string& filename, + const DynamicDiscretisedDensity& density) const { + { + FilePath file_path(filename, false); // create object without checking if a fo;e exists already + if (!file_path.get_extension().empty()) + error("MultiDynamicDiscretisedDensityOutputFileFormat: currently needs an output filename without extension. sorry"); + } + // Create all the filenames + VectorWithOffset individual_filenames(1, int(density.get_num_time_frames())); + for (int i = 1; i <= int(density.get_num_time_frames()); i++) + individual_filenames[i] = filename + "_" + boost::lexical_cast(i); + + // Write each individual image + for (int i = 1; i <= int(density.get_num_time_frames()); i++) { + Succeeded success = individual_output_type_sptr->write_to_file(individual_filenames[i], density.get_density(unsigned(i))); + if (success != Succeeded::yes) + warning("MultiDynamicDiscretisedDensity error: Failed to write \"" + individual_filenames[i] + "\".\n"); + } + + // Write some multi header info + filename = filename + ".txt"; + MultipleDataSetHeader::write_header(filename, individual_filenames); + return Succeeded::yes; } -// class MultiDynamicDiscretisedDensityOutputFileFormat; - +// class MultiDynamicDiscretisedDensityOutputFileFormat; END_NAMESPACE_STIR diff --git a/src/IO/MultiParametricDiscretisedDensityOutputFileFormat.cxx b/src/IO/MultiParametricDiscretisedDensityOutputFileFormat.cxx index 24d34ed991..16a2c74ad6 100644 --- a/src/IO/MultiParametricDiscretisedDensityOutputFileFormat.cxx +++ b/src/IO/MultiParametricDiscretisedDensityOutputFileFormat.cxx @@ -31,7 +31,7 @@ /* largely a copy of the dynamic case. sorry */ #include "stir/IO/MultiParametricDiscretisedDensityOutputFileFormat.h" -#include "stir/modelling/ParametricDiscretisedDensity.h" +#include "stir/modelling/ParametricDiscretisedDensity.h" #include "stir/NumericType.h" #include "stir/Succeeded.h" #include "stir/FilePath.h" @@ -44,24 +44,19 @@ START_NAMESPACE_STIR #define ParamDiscDensityOutputFileFormat MultiParametricDiscretisedDensityOutputFileFormat TEMPLATE -const char * const -ParamDiscDensityOutputFileFormat::registered_name = "Multi"; +const char* const ParamDiscDensityOutputFileFormat::registered_name = "Multi"; TEMPLATE -ParamDiscDensityOutputFileFormat:: -MultiParametricDiscretisedDensityOutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) -{ +ParamDiscDensityOutputFileFormat::MultiParametricDiscretisedDensityOutputFileFormat(const NumericType& type, + const ByteOrder& byte_order) { this->set_defaults(); this->set_type_of_numbers(type); this->set_byte_order(byte_order); } TEMPLATE -void -ParamDiscDensityOutputFileFormat:: -set_defaults() -{ +void +ParamDiscDensityOutputFileFormat::set_defaults() { base_type::set_defaults(); this->set_type_of_numbers(NumericType::FLOAT); this->set_byte_order(ByteOrder::native); @@ -69,69 +64,60 @@ set_defaults() } TEMPLATE -void -ParamDiscDensityOutputFileFormat:: -initialise_keymap() -{ +void +ParamDiscDensityOutputFileFormat::initialise_keymap() { this->parser.add_start_key("Multi Output File Format Parameters"); this->parser.add_stop_key("End Multi Output File Format Parameters"); - this->parser.add_parsing_key("individual output file format type",&this->individual_output_type_sptr); + this->parser.add_parsing_key("individual output file format type", &this->individual_output_type_sptr); base_type::initialise_keymap(); } TEMPLATE -bool -ParamDiscDensityOutputFileFormat:: -post_processing() -{ +bool +ParamDiscDensityOutputFileFormat::post_processing() { if (base_type::post_processing()) return true; return false; } TEMPLATE -ByteOrder -ParamDiscDensityOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) -{ - if (!new_byte_order.is_native_order()) - { - if (warn) - warning("MultiParametricDiscretisedDensityOutputFileFormat: byte_order is currently fixed to the native format\n"); - this->file_byte_order = ByteOrder::native; - } - else +ByteOrder +ParamDiscDensityOutputFileFormat::set_byte_order(const ByteOrder& new_byte_order, const bool warn) { + if (!new_byte_order.is_native_order()) { + if (warn) + warning("MultiParametricDiscretisedDensityOutputFileFormat: byte_order is currently fixed to the native format\n"); + this->file_byte_order = ByteOrder::native; + } else this->file_byte_order = new_byte_order; - return this->file_byte_order; + return this->file_byte_order; } TEMPLATE -Succeeded -ParamDiscDensityOutputFileFormat:: -actual_write_to_file(std::string& filename, - const ParametricDiscretisedDensity & density) const -{ - { - FilePath file_path(filename, false); // create object without checking if a fo;e exists already - if (!file_path.get_extension().empty()) - error("MultiParametricDiscretisedDensityOutputFileFormat: currently needs an output filename without extension. sorry"); - } - // Create all the filenames - VectorWithOffset individual_filenames(1,int(density.get_num_params())); - for (int i=1; i<=int(density.get_num_params()); i++) - individual_filenames[i] = filename + "_" + boost::lexical_cast(i); - - // Write each individual image - for (int i=1; i<=int(density.get_num_params()); i++) { - Succeeded success = this->individual_output_type_sptr->write_to_file(individual_filenames[i],density.construct_single_density(unsigned(i))); - if (success != Succeeded::yes) - warning("MultiParametricDiscretisedDensity error: Failed to write \"" + individual_filenames[i] + "\".\n"); - } - - // Write some multi header info - filename = filename + ".txt"; - MultipleDataSetHeader::write_header(filename, individual_filenames); - return Succeeded::yes; +Succeeded +ParamDiscDensityOutputFileFormat::actual_write_to_file(std::string& filename, + const ParametricDiscretisedDensity& density) const { + { + FilePath file_path(filename, false); // create object without checking if a fo;e exists already + if (!file_path.get_extension().empty()) + error("MultiParametricDiscretisedDensityOutputFileFormat: currently needs an output filename without extension. sorry"); + } + // Create all the filenames + VectorWithOffset individual_filenames(1, int(density.get_num_params())); + for (int i = 1; i <= int(density.get_num_params()); i++) + individual_filenames[i] = filename + "_" + boost::lexical_cast(i); + + // Write each individual image + for (int i = 1; i <= int(density.get_num_params()); i++) { + Succeeded success = + this->individual_output_type_sptr->write_to_file(individual_filenames[i], density.construct_single_density(unsigned(i))); + if (success != Succeeded::yes) + warning("MultiParametricDiscretisedDensity error: Failed to write \"" + individual_filenames[i] + "\".\n"); + } + + // Write some multi header info + filename = filename + ".txt"; + MultipleDataSetHeader::write_header(filename, individual_filenames); + return Succeeded::yes; } #undef ParamDiscDensity @@ -139,5 +125,4 @@ actual_write_to_file(std::string& filename, template class MultiParametricDiscretisedDensityOutputFileFormat; - END_NAMESPACE_STIR diff --git a/src/IO/OutputFileFormat.cxx b/src/IO/OutputFileFormat.cxx index 1b946ab4fa..6c7e642c7f 100644 --- a/src/IO/OutputFileFormat.cxx +++ b/src/IO/OutputFileFormat.cxx @@ -18,27 +18,25 @@ /*! \file \ingroup IO - - \brief Instantiations of the stir::OutputFileFormat class - \author Kris Thielemans + + \brief Instantiations of the stir::OutputFileFormat class + \author Kris Thielemans */ #include "stir/IO/OutputFileFormat.txx" #include "stir/DiscretisedDensity.h" #include "stir/DynamicDiscretisedDensity.h" -#include "stir/modelling/ParametricDiscretisedDensity.h" -#include "stir/modelling/KineticParameters.h" +#include "stir/modelling/ParametricDiscretisedDensity.h" +#include "stir/modelling/KineticParameters.h" #ifdef _MSC_VER -#pragma warning (disable : 4661) +# pragma warning(disable : 4661) #endif START_NAMESPACE_STIR - -template class OutputFileFormat >; -template class OutputFileFormat; -template class OutputFileFormat; +template class OutputFileFormat>; +template class OutputFileFormat; +template class OutputFileFormat; END_NAMESPACE_STIR - diff --git a/src/IO/OutputFileFormat_default.cxx b/src/IO/OutputFileFormat_default.cxx index 526e5159a4..df97bb8f3c 100644 --- a/src/IO/OutputFileFormat_default.cxx +++ b/src/IO/OutputFileFormat_default.cxx @@ -21,30 +21,29 @@ \ingroup IO \brief initialisation of the stir::OutputFileFormat::_default_sptr member \author Kris Thielemans - + */ #include "stir/IO/InterfileOutputFileFormat.h" #include "stir/DiscretisedDensity.h" -#include "stir/modelling/ParametricDiscretisedDensity.h" -#include "stir/DynamicDiscretisedDensity.h" +#include "stir/modelling/ParametricDiscretisedDensity.h" +#include "stir/DynamicDiscretisedDensity.h" #ifdef HAVE_LLN_MATRIX -#include "stir/IO/ECAT7ParametricDensityOutputFileFormat.h" -#include "stir/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.h" +# include "stir/IO/ECAT7ParametricDensityOutputFileFormat.h" +# include "stir/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.h" #else -#include "stir/modelling/KineticParameters.h" -#include "stir/IO/InterfileParametricDiscretisedDensityOutputFileFormat.h" -#include "stir/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.h" -#include "stir/IO/MultiDynamicDiscretisedDensityOutputFileFormat.h" +# include "stir/modelling/KineticParameters.h" +# include "stir/IO/InterfileParametricDiscretisedDensityOutputFileFormat.h" +# include "stir/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.h" +# include "stir/IO/MultiDynamicDiscretisedDensityOutputFileFormat.h" #endif START_NAMESPACE_STIR template <> -shared_ptr > > -OutputFileFormat >::_default_sptr(new InterfileOutputFileFormat); - +shared_ptr>> + OutputFileFormat>::_default_sptr(new InterfileOutputFileFormat); #if 0 template <> @@ -52,31 +51,24 @@ OutputFileFormat >::_default_sptr(new InterfileOutpu OutputFileFormat > >::_default_sptr = new InterfileParametricDiscretisedDensityOutputFileFormat<3,KineticParameters<2,float> >; #else - template <> - shared_ptr > - OutputFileFormat::_default_sptr( -#ifdef HAVE_LLN_MATRIX - new ecat::ecat7::ECAT7ParametricDensityOutputFileFormat -#else - new InterfileParametricDiscretisedDensityOutputFileFormat -#endif - ); +template <> +shared_ptr> OutputFileFormat::_default_sptr( +# ifdef HAVE_LLN_MATRIX + new ecat::ecat7::ECAT7ParametricDensityOutputFileFormat +# else + new InterfileParametricDiscretisedDensityOutputFileFormat +# endif +); #endif #if 1 - template <> - shared_ptr > - OutputFileFormat:: - _default_sptr( -#ifdef HAVE_LLN_MATRIX - new ecat::ecat7::ECAT7DynamicDiscretisedDensityOutputFileFormat -#else - new InterfileDynamicDiscretisedDensityOutputFileFormat -#endif - ); +template <> +shared_ptr> OutputFileFormat::_default_sptr( +# ifdef HAVE_LLN_MATRIX + new ecat::ecat7::ECAT7DynamicDiscretisedDensityOutputFileFormat +# else + new InterfileDynamicDiscretisedDensityOutputFileFormat +# endif +); #endif END_NAMESPACE_STIR - - - - diff --git a/src/IO/RegisteredObject.cxx b/src/IO/RegisteredObject.cxx index 9ee5d8b564..33fc714045 100644 --- a/src/IO/RegisteredObject.cxx +++ b/src/IO/RegisteredObject.cxx @@ -33,16 +33,15 @@ #ifdef __STIR_REGISTRY_NOT_INLINE -#pragma message("instantiating RegisteredObject") -#include "stir/IO/OutputFileFormat.h" +# pragma message("instantiating RegisteredObject") +# include "stir/IO/OutputFileFormat.h" // add here all roots of hierarchies based on RegisteredObject START_NAMESPACE_STIR template -RegisteredObject::RegistryType& -RegisteredObject::registry () -{ +RegisteredObject::RegistryType& +RegisteredObject::registry() { static RegistryType the_registry("None", 0); return the_registry; } @@ -50,10 +49,10 @@ RegisteredObject::registry () # ifdef _MSC_VER // prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) +# pragma warning(disable : 4660) # endif -template RegisteredObject; +template RegisteredObject; // add here all roots of hierarchies based on RegisteredObject END_NAMESPACE_STIR diff --git a/src/IO/ecat6_utils.cxx b/src/IO/ecat6_utils.cxx index 6142426a16..64565623f2 100644 --- a/src/IO/ecat6_utils.cxx +++ b/src/IO/ecat6_utils.cxx @@ -1,8 +1,7 @@ // // - -/*! +/*! \file \ingroup ECAT @@ -10,8 +9,8 @@ \author Kris Thielemans (conversions from/to VAX floats, longs) \author PARAPET project - \warning This file relies on ByteOrderDefine.h to find out if it - has to byteswap. This ideally would be changed to use the class stir::ByteOrder. + \warning This file relies on ByteOrderDefine.h to find out if it + has to byteswap. This ideally would be changed to use the class stir::ByteOrder. Make sure you run test/test_ByteOrder. */ @@ -43,14 +42,14 @@ - added support for data types different from 16 bit ints. - added a bit more diagonistics for file IO errors - KT 11/01/2001 - - added cti_read_norm_subheader,get_normheaders and removed get_attndata + KT 11/01/2001 + - added cti_read_norm_subheader,get_normheaders and removed get_attndata as it was identical to get_scandata KT 10/09/2004 - removed aliasing bugs in get_vax_float etc - KT 13/01/2008 + KT 13/01/2008 replace original CTI code with calls to LLN matrix library: - introduced mhead_ptr in various functions - have #define STIR_ORIGINAL_ECAT6 to be able to switch between old and new version @@ -59,15 +58,15 @@ removed CTI-derived code */ #include "stir/IO/stir_ecat_common.h" -#include "stir/IO/ecat6_utils.h" +#include "stir/IO/ecat6_utils.h" #ifndef STIR_ORIGINAL_ECAT6 // we will need file_data_to_host which is declared in machine_indep.h // However, that file has a problem with the definition of swab on some systems // so we declare it here //#include "machine_indep.h" -extern "C" int file_data_to_host(char *dptr, int nblks, int dtype); -extern "C" FILE *mat_create(char *fname, Main_header *mhead); +extern "C" int file_data_to_host(char* dptr, int nblks, int dtype); +extern "C" FILE* mat_create(char* fname, Main_header* mhead); #endif #include "stir/ByteOrder.h" @@ -84,510 +83,514 @@ extern "C" FILE *mat_create(char *fname, Main_header *mhead); // replace bcopy with memcpy #define bcopy(src, dest, length) memcpy(dest, src, length) -#define toblocks(x) ((x + (MatBLKSIZE - 1))/MatBLKSIZE) - -BOOST_STATIC_ASSERT(sizeof(unsigned short)==2); - +#define toblocks(x) ((x + (MatBLKSIZE - 1)) / MatBLKSIZE) +BOOST_STATIC_ASSERT(sizeof(unsigned short) == 2); START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT6 +int +get_scanheaders(FILE* fptr, long matnum, ECAT6_Main_header* mhead, Scan_subheader* shead, ScanInfoRec* scanParams) { + int status; + MatDir entry; -int get_scanheaders (FILE *fptr, long matnum, ECAT6_Main_header *mhead, - Scan_subheader *shead, ScanInfoRec *scanParams) -{ - int status; - MatDir entry; - - // check the header - status = cti_read_ECAT6_Main_header (fptr, mhead); - if (status != EXIT_SUCCESS) return EXIT_FAILURE; - - if (mhead->file_type != matScanFile) { - printf ("\n- file is not a scan file, type = %d\n", mhead->file_type); + // check the header + status = cti_read_ECAT6_Main_header(fptr, mhead); + if (status != EXIT_SUCCESS) + return EXIT_FAILURE; + + if (mhead->file_type != matScanFile) { + printf("\n- file is not a scan file, type = %d\n", mhead->file_type); #ifdef STIR_ORIGINAL_ECAT6 - dump_ECAT6_Main_header (0, mhead); + dump_ECAT6_Main_header(0, mhead); #endif - return EXIT_FAILURE; - } + return EXIT_FAILURE; + } - // look up matnum in scan file - if (!cti_lookup (fptr, mhead, matnum, &entry)) { - printf ("\n- specified matrix not in scan file\n"); + // look up matnum in scan file + if (!cti_lookup(fptr, mhead, matnum, &entry)) { + printf("\n- specified matrix not in scan file\n"); #ifdef STIR_ORIGINAL_ECAT6 - dump_ECAT6_Main_header (0, mhead); + dump_ECAT6_Main_header(0, mhead); #endif - return EXIT_FAILURE; - } - - // read scan subheader - status = cti_read_scan_subheader (fptr, mhead, entry.strtblk, shead); - if (status != EXIT_SUCCESS) { - printf ("\n- error reading scan subheader\n"); - return EXIT_FAILURE; - } - - scanParams->strtblk = entry.strtblk + 1; - scanParams->nblks = entry.endblk - entry.strtblk; + return EXIT_FAILURE; + } + + // read scan subheader + status = cti_read_scan_subheader(fptr, mhead, entry.strtblk, shead); + if (status != EXIT_SUCCESS) { + printf("\n- error reading scan subheader\n"); + return EXIT_FAILURE; + } + + scanParams->strtblk = entry.strtblk + 1; + scanParams->nblks = entry.endblk - entry.strtblk; #ifndef STIR_ORIGINAL_ECAT6 - scanParams->nprojs = shead->num_r_elements; - scanParams->nviews = shead->num_angles; + scanParams->nprojs = shead->num_r_elements; + scanParams->nviews = shead->num_angles; #else - scanParams->nprojs = shead->dimension_1; - scanParams->nviews = shead->dimension_2; + scanParams->nprojs = shead->dimension_1; + scanParams->nviews = shead->dimension_2; #endif - scanParams->data_type = shead->data_type; + scanParams->data_type = shead->data_type; #ifdef STIR_ORIGINAL_ECAT6 - if (shead->data_type != mhead->data_type) - printf("\nget_scanheader warning: \n" -"data types differ between main header (%d) and subheader (%d)\n" -"Using value from subheader\n", mhead->data_type, shead->data_type); + if (shead->data_type != mhead->data_type) + printf("\nget_scanheader warning: \n" + "data types differ between main header (%d) and subheader (%d)\n" + "Using value from subheader\n", + mhead->data_type, shead->data_type); #endif - return EXIT_SUCCESS; + return EXIT_SUCCESS; } -int get_scandata (FILE *fptr, char *scan, ScanInfoRec *scanParams) -{ - int status; +int +get_scandata(FILE* fptr, char* scan, ScanInfoRec* scanParams) { + int status; - // read data from scan file - if (!scan) return EXIT_FAILURE; + // read data from scan file + if (!scan) + return EXIT_FAILURE; - status= cti_rblk(fptr, scanParams->strtblk, (char *) scan, scanParams->nblks); - if (status != EXIT_SUCCESS) - return EXIT_FAILURE; - return - file_data_to_host(scan, scanParams->nblks,scanParams->data_type); + status = cti_rblk(fptr, scanParams->strtblk, (char*)scan, scanParams->nblks); + if (status != EXIT_SUCCESS) + return EXIT_FAILURE; + return file_data_to_host(scan, scanParams->nblks, scanParams->data_type); } +int +get_attnheaders(FILE* fptr, long matnum, ECAT6_Main_header* mhead, Attn_subheader* shead, ScanInfoRec* attnParams) { + int status; + MatDir entry; -int get_attnheaders (FILE *fptr, long matnum, ECAT6_Main_header *mhead, - Attn_subheader *shead, ScanInfoRec *attnParams) -{ - int status; - MatDir entry; - - // check the header - status = cti_read_ECAT6_Main_header (fptr, mhead); - if (status != EXIT_SUCCESS) return EXIT_FAILURE; - - if (mhead->file_type != matAttenFile) { - printf ("\n- file is not a attn file, type = %d\n", mhead->file_type); + // check the header + status = cti_read_ECAT6_Main_header(fptr, mhead); + if (status != EXIT_SUCCESS) + return EXIT_FAILURE; + + if (mhead->file_type != matAttenFile) { + printf("\n- file is not a attn file, type = %d\n", mhead->file_type); #ifdef STIR_ORIGINAL_ECAT6 - dump_ECAT6_Main_header (0, mhead); + dump_ECAT6_Main_header(0, mhead); #endif - return EXIT_FAILURE; - } + return EXIT_FAILURE; + } - // look up matnum in attn file - if (!cti_lookup (fptr, mhead, matnum, &entry)) { - printf ("\n- specified matrix not in attn file\n"); + // look up matnum in attn file + if (!cti_lookup(fptr, mhead, matnum, &entry)) { + printf("\n- specified matrix not in attn file\n"); #ifdef STIR_ORIGINAL_ECAT6 - dump_ECAT6_Main_header (0, mhead); + dump_ECAT6_Main_header(0, mhead); #endif - return EXIT_FAILURE; - } - - // read attn subheader - status = cti_read_attn_subheader (fptr, mhead, entry.strtblk, shead); - if (status != EXIT_SUCCESS) { - printf ("\n- error reading attn subheader\n"); - return EXIT_FAILURE; - } - - attnParams->strtblk = entry.strtblk + 1; - attnParams->nblks = entry.endblk - entry.strtblk; + return EXIT_FAILURE; + } + + // read attn subheader + status = cti_read_attn_subheader(fptr, mhead, entry.strtblk, shead); + if (status != EXIT_SUCCESS) { + printf("\n- error reading attn subheader\n"); + return EXIT_FAILURE; + } + + attnParams->strtblk = entry.strtblk + 1; + attnParams->nblks = entry.endblk - entry.strtblk; #ifndef STIR_ORIGINAL_ECAT6 - attnParams->nprojs = shead->num_r_elements; - attnParams->nviews = shead->num_angles; + attnParams->nprojs = shead->num_r_elements; + attnParams->nviews = shead->num_angles; #else - attnParams->nprojs = shead->dimension_1; - attnParams->nviews = shead->dimension_2; + attnParams->nprojs = shead->dimension_1; + attnParams->nviews = shead->dimension_2; #endif - attnParams->data_type = shead->data_type; + attnParams->data_type = shead->data_type; #ifdef STIR_ORIGINAL_ECAT6 - if (shead->data_type != mhead->data_type) - printf("\nget_attnheader warning: \n" -"data types differ between main header (%d) and subheader (%d)\n" -"Using value from subheader\n", mhead->data_type, shead->data_type); + if (shead->data_type != mhead->data_type) + printf("\nget_attnheader warning: \n" + "data types differ between main header (%d) and subheader (%d)\n" + "Using value from subheader\n", + mhead->data_type, shead->data_type); #endif - return EXIT_SUCCESS; + return EXIT_SUCCESS; } +int +get_normheaders(FILE* fptr, long matnum, ECAT6_Main_header* mhead, Norm_subheader* shead, ScanInfoRec* normParams) { + int status; + MatDir entry; + // check the header + status = cti_read_ECAT6_Main_header(fptr, mhead); + if (status != EXIT_SUCCESS) + return EXIT_FAILURE; -int get_normheaders (FILE *fptr, long matnum, ECAT6_Main_header *mhead, - Norm_subheader *shead, ScanInfoRec *normParams) -{ - int status; - MatDir entry; - - // check the header - status = cti_read_ECAT6_Main_header (fptr, mhead); - if (status != EXIT_SUCCESS) return EXIT_FAILURE; - - if (mhead->file_type != matNormFile) { - printf ("\n- file is not a norm file, type = %d\n", mhead->file_type); + if (mhead->file_type != matNormFile) { + printf("\n- file is not a norm file, type = %d\n", mhead->file_type); #ifdef STIR_ORIGINAL_ECAT6 - dump_ECAT6_Main_header (0, mhead); + dump_ECAT6_Main_header(0, mhead); #endif - return EXIT_FAILURE; - } + return EXIT_FAILURE; + } - // look up matnum in norm file - if (!cti_lookup (fptr, mhead, matnum, &entry)) { - printf ("\n- specified matrix not in norm file\n"); + // look up matnum in norm file + if (!cti_lookup(fptr, mhead, matnum, &entry)) { + printf("\n- specified matrix not in norm file\n"); #ifdef STIR_ORIGINAL_ECAT6 - dump_ECAT6_Main_header (0, mhead); + dump_ECAT6_Main_header(0, mhead); #endif - return EXIT_FAILURE; - } - - // read norm subheader - status = cti_read_norm_subheader (fptr, mhead, entry.strtblk, shead); - if (status != EXIT_SUCCESS) { - printf ("\n- error reading norm subheader\n"); - return EXIT_FAILURE; - } - - normParams->strtblk = entry.strtblk + 1; - normParams->nblks = entry.endblk - entry.strtblk; + return EXIT_FAILURE; + } + + // read norm subheader + status = cti_read_norm_subheader(fptr, mhead, entry.strtblk, shead); + if (status != EXIT_SUCCESS) { + printf("\n- error reading norm subheader\n"); + return EXIT_FAILURE; + } + + normParams->strtblk = entry.strtblk + 1; + normParams->nblks = entry.endblk - entry.strtblk; #ifndef STIR_ORIGINAL_ECAT6 - normParams->nprojs = shead->num_r_elements; - normParams->nviews = shead->num_angles; + normParams->nprojs = shead->num_r_elements; + normParams->nviews = shead->num_angles; #else - normParams->nprojs = shead->dimension_1; - normParams->nviews = shead->dimension_2; + normParams->nprojs = shead->dimension_1; + normParams->nviews = shead->dimension_2; #endif - normParams->data_type = shead->data_type; + normParams->data_type = shead->data_type; #ifdef STIR_ORIGINAL_ECAT6 - if (shead->data_type != mhead->data_type) - printf("\nget_normheader warning: \n" -"data types differ between main header (%d) and subheader (%d)\n" -"Using value from subheader\n", mhead->data_type, shead->data_type); + if (shead->data_type != mhead->data_type) + printf("\nget_normheader warning: \n" + "data types differ between main header (%d) and subheader (%d)\n" + "Using value from subheader\n", + mhead->data_type, shead->data_type); #endif - return EXIT_SUCCESS; + return EXIT_SUCCESS; } #ifndef STIR_ORIGINAL_ECAT6 FILE* -cti_create(const char * const fname, const Main_header *mhead) -{ - return mat_create(const_cast(fname), const_cast(mhead)); +cti_create(const char* const fname, const Main_header* mhead) { + return mat_create(const_cast(fname), const_cast(mhead)); } -int cti_read_ECAT6_Main_header (FILE *fptr, ECAT6_Main_header *h) -{ +int +cti_read_ECAT6_Main_header(FILE* fptr, ECAT6_Main_header* h) { const int cti_status = mat_read_main_header(fptr, h); - return cti_status==0 ? EXIT_SUCCESS : EXIT_FAILURE; + return cti_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -long cti_numcod (int frame, int plane, int gate, int data, int bed) -{ +long +cti_numcod(int frame, int plane, int gate, int data, int bed) { return mat_numcod(frame, plane, gate, data, bed); } -void cti_numdoc (long matnum, Matval *matval) -{ +void +cti_numdoc(long matnum, Matval* matval) { mat_numdoc(matnum, matval); } -int cti_rblk (FILE *fptr, int blkno, void *bufr, int nblks) -{ - const int cti_status = mat_rblk(fptr, blkno, reinterpret_cast(bufr), nblks); - return cti_status==0 ? EXIT_SUCCESS : EXIT_FAILURE; +int +cti_rblk(FILE* fptr, int blkno, void* bufr, int nblks) { + const int cti_status = mat_rblk(fptr, blkno, reinterpret_cast(bufr), nblks); + return cti_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -int cti_wblk (FILE *fptr, int blkno, void *bufr, int nblks) -{ - const int cti_status = mat_wblk (fptr, blkno, reinterpret_cast(bufr), nblks); - return cti_status==0 ? EXIT_SUCCESS : EXIT_FAILURE; +int +cti_wblk(FILE* fptr, int blkno, void* bufr, int nblks) { + const int cti_status = mat_wblk(fptr, blkno, reinterpret_cast(bufr), nblks); + return cti_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -int cti_enter (FILE *fptr, const ECAT6_Main_header* mhead_ptr, long matnum, int nblks) -{ +int +cti_enter(FILE* fptr, const ECAT6_Main_header* mhead_ptr, long matnum, int nblks) { return mat_enter(fptr, const_cast(mhead_ptr), matnum, nblks); } -int cti_lookup (FILE *fptr, const ECAT6_Main_header* mhead_ptr, long matnum, MatDir *entry) -{ +int +cti_lookup(FILE* fptr, const ECAT6_Main_header* mhead_ptr, long matnum, MatDir* entry) { return mat_lookup(fptr, const_cast(mhead_ptr), matnum, entry); } -int cti_read_image_subheader (FILE *fptr, const ECAT6_Main_header *h, int blknum, Image_subheader *header_ptr) -{ - const int cti_status = mat_read_image_subheader (fptr, const_cast(h), blknum, header_ptr); - return cti_status==0 ? EXIT_SUCCESS : EXIT_FAILURE; +int +cti_read_image_subheader(FILE* fptr, const ECAT6_Main_header* h, int blknum, Image_subheader* header_ptr) { + const int cti_status = mat_read_image_subheader(fptr, const_cast(h), blknum, header_ptr); + return cti_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -int cti_read_scan_subheader (FILE *fptr, const ECAT6_Main_header *h, int blknum, Scan_subheader *header_ptr) -{ - const int cti_status = mat_read_scan_subheader (fptr, const_cast(h), blknum, header_ptr); - return cti_status==0 ? EXIT_SUCCESS : EXIT_FAILURE; +int +cti_read_scan_subheader(FILE* fptr, const ECAT6_Main_header* h, int blknum, Scan_subheader* header_ptr) { + const int cti_status = mat_read_scan_subheader(fptr, const_cast(h), blknum, header_ptr); + return cti_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -int cti_read_attn_subheader (FILE *fptr, const ECAT6_Main_header *h, int blknum, Attn_subheader *header_ptr) -{ - const int cti_status = mat_read_attn_subheader (fptr, const_cast(h), blknum, header_ptr); - return cti_status==0 ? EXIT_SUCCESS : EXIT_FAILURE; +int +cti_read_attn_subheader(FILE* fptr, const ECAT6_Main_header* h, int blknum, Attn_subheader* header_ptr) { + const int cti_status = mat_read_attn_subheader(fptr, const_cast(h), blknum, header_ptr); + return cti_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -int cti_read_norm_subheader (FILE *fptr, const ECAT6_Main_header *h, int blknum, Norm_subheader *header_ptr) -{ - const int cti_status = mat_read_norm_subheader (fptr, const_cast(h), blknum, header_ptr); - return cti_status==0 ? EXIT_SUCCESS : EXIT_FAILURE; +int +cti_read_norm_subheader(FILE* fptr, const ECAT6_Main_header* h, int blknum, Norm_subheader* header_ptr) { + const int cti_status = mat_read_norm_subheader(fptr, const_cast(h), blknum, header_ptr); + return cti_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -int cti_write_image_subheader (FILE *fptr, const ECAT6_Main_header *h, int blknum, const Image_subheader *header_ptr) -{ - const int cti_status = mat_write_image_subheader (fptr, const_cast(h), blknum, const_cast(header_ptr)); - return cti_status==0 ? EXIT_SUCCESS : EXIT_FAILURE; +int +cti_write_image_subheader(FILE* fptr, const ECAT6_Main_header* h, int blknum, const Image_subheader* header_ptr) { + const int cti_status = + mat_write_image_subheader(fptr, const_cast(h), blknum, const_cast(header_ptr)); + return cti_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -int cti_write_scan_subheader (FILE *fptr, const ECAT6_Main_header *h, int blknum, const Scan_subheader *header_ptr) -{ - const int cti_status = mat_write_scan_subheader (fptr, const_cast(h), blknum, const_cast(header_ptr)); - return cti_status==0 ? EXIT_SUCCESS : EXIT_FAILURE; +int +cti_write_scan_subheader(FILE* fptr, const ECAT6_Main_header* h, int blknum, const Scan_subheader* header_ptr) { + const int cti_status = + mat_write_scan_subheader(fptr, const_cast(h), blknum, const_cast(header_ptr)); + return cti_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -int file_data_to_host(char *dptr, int nblks, int dtype) -{ +int +file_data_to_host(char* dptr, int nblks, int dtype) { const int cti_status = ::file_data_to_host(dptr, nblks, dtype); - return cti_status==0 ? EXIT_SUCCESS : EXIT_FAILURE; + return cti_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -#else// STIR_ORIGINAL_ECAT6 +#else // STIR_ORIGINAL_ECAT6 -#error Original ECAT6 code removed +# error Original ECAT6 code removed #endif // STIR_ORIGINAL_ECAT6 -int cti_rings2plane (short nrings, short ring0, short ring1) +int +cti_rings2plane(short nrings, short ring0, short ring1) { - int d = (int) (ring0 / (nrings/2)); + int d = (int)(ring0 / (nrings / 2)); - return (ring1 * nrings/2 + ring0 % (nrings/2) + - nrings/2 * nrings * d + 1); + return (ring1 * nrings / 2 + ring0 % (nrings / 2) + nrings / 2 * nrings * d + 1); } #ifdef STIR_ORIGINAL_ECAT6 #endif // STIR_ORIGINAL_ECAT6 -int cti_write_idata (FILE *fptr, int blk, const short *data, int ibytes) -{ - unsigned int nblks; - char *dataptr; - int status; - - if (ibytes%MatBLKSIZE != 0) - { - warning("Error writing ECAT6 data: data_size should be a multiple of %d.\nNo Data written to file.", - MatBLKSIZE); - return (EXIT_FAILURE); - } +int +cti_write_idata(FILE* fptr, int blk, const short* data, int ibytes) { + unsigned int nblks; + char* dataptr; + int status; + + if (ibytes % MatBLKSIZE != 0) { + warning("Error writing ECAT6 data: data_size should be a multiple of %d.\nNo Data written to file.", MatBLKSIZE); + return (EXIT_FAILURE); + } #if STIRIsNativeByteOrderBigEndian - char bufr[MatBLKSIZE]; - - dataptr = (char *) data; // point into data buffer - - // we'll use cti_wblk to write the data via another buffer. - // this way, if we need to transform the data as we went, we can do it. - nblks = toblocks (ibytes); - for (unsigned int i=0; i * +static VoxelsOnCartesianGrid* create_image_and_header_from(InterfileImageHeader& hdr, - char * full_data_file_name, // preallocated - istream& input, - const string& directory_for_data) -{ - if (!hdr.parse(input)) - { - return 0; //KT 10/12/2001 do not call ask_parameters anymore - } - + char* full_data_file_name, // preallocated + istream& input, const string& directory_for_data) { + if (!hdr.parse(input)) { + return 0; // KT 10/12/2001 do not call ask_parameters anymore + } + // prepend directory_for_data to the data_file_name from the header strcpy(full_data_file_name, hdr.data_file_name.c_str()); - prepend_directory_name(full_data_file_name, directory_for_data.c_str()); - - - CartesianCoordinate3D voxel_size(static_cast(hdr.pixel_sizes[2]), - static_cast(hdr.pixel_sizes[1]), - static_cast(hdr.pixel_sizes[0])); - - const int z_size = hdr.matrix_size[2][0]; - const int y_size = hdr.matrix_size[1][0]; - const int x_size = hdr.matrix_size[0][0]; - const BasicCoordinate<3,int> min_indices = - make_coordinate(0, -y_size/2, -x_size/2); - const BasicCoordinate<3,int> max_indices = - min_indices + make_coordinate(z_size, y_size, x_size) - 1; - - CartesianCoordinate3D origin(0,0,0); - if (hdr.first_pixel_offsets[2] != InterfileHeader::double_value_not_set) - { - // make sure that origin is such that - // first_pixel_offsets = min_indices*voxel_size + origin - origin = - make_coordinate(float(hdr.first_pixel_offsets[2]), - float(hdr.first_pixel_offsets[1]), - float(hdr.first_pixel_offsets[0])) - - voxel_size * BasicCoordinate<3,float>(min_indices); - } + prepend_directory_name(full_data_file_name, directory_for_data.c_str()); + + CartesianCoordinate3D voxel_size(static_cast(hdr.pixel_sizes[2]), static_cast(hdr.pixel_sizes[1]), + static_cast(hdr.pixel_sizes[0])); + + const int z_size = hdr.matrix_size[2][0]; + const int y_size = hdr.matrix_size[1][0]; + const int x_size = hdr.matrix_size[0][0]; + const BasicCoordinate<3, int> min_indices = make_coordinate(0, -y_size / 2, -x_size / 2); + const BasicCoordinate<3, int> max_indices = min_indices + make_coordinate(z_size, y_size, x_size) - 1; + + CartesianCoordinate3D origin(0, 0, 0); + if (hdr.first_pixel_offsets[2] != InterfileHeader::double_value_not_set) { + // make sure that origin is such that + // first_pixel_offsets = min_indices*voxel_size + origin + origin = + make_coordinate(float(hdr.first_pixel_offsets[2]), float(hdr.first_pixel_offsets[1]), float(hdr.first_pixel_offsets[0])) - + voxel_size * BasicCoordinate<3, float>(min_indices); + } - return - new VoxelsOnCartesianGrid - (hdr.get_exam_info_sptr(), - IndexRange<3>(min_indices, max_indices), - origin, - voxel_size); + return new VoxelsOnCartesianGrid(hdr.get_exam_info_sptr(), IndexRange<3>(min_indices, max_indices), origin, voxel_size); } -VoxelsOnCartesianGrid * -read_interfile_image(istream& input, - const string& directory_for_data) -{ +VoxelsOnCartesianGrid* +read_interfile_image(istream& input, const string& directory_for_data) { InterfileImageHeader hdr; char full_data_file_name[max_filename_length]; - VoxelsOnCartesianGrid * image_ptr = - create_image_and_header_from(hdr, - full_data_file_name, - input, - directory_for_data); - + VoxelsOnCartesianGrid* image_ptr = create_image_and_header_from(hdr, full_data_file_name, input, directory_for_data); + ifstream data_in; open_read_binary(data_in, full_data_file_name); data_in.seekg(hdr.data_offset_each_dataset[0]); - if (hdr.data_offset_each_dataset[0]>0) + if (hdr.data_offset_each_dataset[0] > 0) data_in.seekg(hdr.data_offset_each_dataset[0]); // read into image_sptr first float scale = float(1); - if (read_data(data_in, *image_ptr, hdr.type_of_numbers, scale, hdr.file_byte_order) - == Succeeded::no - || scale != 1) - { - warning("read_interfile_image: error reading data or scale factor returned by read_data not equal to 1\n"); - return 0; - } - - for (int i=0; i< hdr.matrix_size[2][0]; i++) - if (hdr.image_scaling_factors[0][i]!= 1) + if (read_data(data_in, *image_ptr, hdr.type_of_numbers, scale, hdr.file_byte_order) == Succeeded::no || scale != 1) { + warning("read_interfile_image: error reading data or scale factor returned by read_data not equal to 1\n"); + return 0; + } + + for (int i = 0; i < hdr.matrix_size[2][0]; i++) + if (hdr.image_scaling_factors[0][i] != 1) (*image_ptr)[i] *= static_cast(hdr.image_scaling_factors[0][i]); // Check number of time frames if (image_ptr->get_exam_info().get_time_frame_definitions().get_num_frames() > 1) { - warning(str(boost::format("Discretised density should contain 1 time frame, but this image contains %1%. " - "Only the first will be kept, and the rest discarded.") - % image_ptr->get_exam_info().get_time_frame_definitions().get_num_frames())); - ExamInfo exam_info = image_ptr->get_exam_info(); - exam_info.time_frame_definitions.set_num_time_frames(1); - image_ptr->set_exam_info(exam_info); - } - else if (image_ptr->get_exam_info().get_time_frame_definitions().get_num_frames() == 0) - warning("DiscretisedDensity does not contain any time frames. This might cause an error."); - + warning(str(boost::format("Discretised density should contain 1 time frame, but this image contains %1%. " + "Only the first will be kept, and the rest discarded.") % + image_ptr->get_exam_info().get_time_frame_definitions().get_num_frames())); + ExamInfo exam_info = image_ptr->get_exam_info(); + exam_info.time_frame_definitions.set_num_time_frames(1); + image_ptr->set_exam_info(exam_info); + } else if (image_ptr->get_exam_info().get_time_frame_definitions().get_num_frames() == 0) + warning("DiscretisedDensity does not contain any time frames. This might cause an error."); return image_ptr; } DynamicDiscretisedDensity* -read_interfile_dynamic_image(istream& input, - const string& directory_for_data) -{ +read_interfile_dynamic_image(istream& input, const string& directory_for_data) { InterfileImageHeader hdr; char full_data_file_name[max_filename_length]; - shared_ptr > - image_sptr(create_image_and_header_from(hdr, - full_data_file_name, - input, - directory_for_data)); + shared_ptr> image_sptr( + create_image_and_header_from(hdr, full_data_file_name, input, directory_for_data)); if (is_null_ptr(image_sptr)) error("Error parsing dynamic image"); shared_ptr scanner_sptr(Scanner::get_scanner_from_name(hdr.get_exam_info().originating_system)); - DynamicDiscretisedDensity * dynamic_dens_ptr = - new DynamicDiscretisedDensity(hdr.get_exam_info().time_frame_definitions, - hdr.get_exam_info().start_time_in_secs_since_1970, - scanner_sptr, - image_sptr); + DynamicDiscretisedDensity* dynamic_dens_ptr = new DynamicDiscretisedDensity( + hdr.get_exam_info().time_frame_definitions, hdr.get_exam_info().start_time_in_secs_since_1970, scanner_sptr, image_sptr); ifstream data_in; open_read_binary(data_in, full_data_file_name); @@ -218,64 +178,50 @@ read_interfile_dynamic_image(istream& input, data_in.seekg(hdr.data_offset_each_dataset[0]); ExamInfo _exam_info(hdr.get_exam_info()); - for (unsigned int frame_num=1; frame_num <= dynamic_dens_ptr->get_num_time_frames(); ++frame_num) - { - data_in.seekg(hdr.data_offset_each_dataset[frame_num-1]); - - // read into image_sptr first - float scale = float(1); - if (read_data(data_in, *image_sptr, hdr.type_of_numbers, scale, hdr.file_byte_order) - == Succeeded::no - || fabs(scale-float(1))>float(1e-10)) - { - warning("read_interfile_dynamic_image: error reading data or scale factor returned by read_data not equal to 1"); - return 0; - } - - for (int i=0; i< hdr.matrix_size[2][0]; i++) - if (fabs(hdr.image_scaling_factors[frame_num-1][i]-double(1))>double(1e-10)) - (*image_sptr)[i] *= static_cast(hdr.image_scaling_factors[frame_num-1][i]); + for (unsigned int frame_num = 1; frame_num <= dynamic_dens_ptr->get_num_time_frames(); ++frame_num) { + data_in.seekg(hdr.data_offset_each_dataset[frame_num - 1]); + + // read into image_sptr first + float scale = float(1); + if (read_data(data_in, *image_sptr, hdr.type_of_numbers, scale, hdr.file_byte_order) == Succeeded::no || + fabs(scale - float(1)) > float(1e-10)) { + warning("read_interfile_dynamic_image: error reading data or scale factor returned by read_data not equal to 1"); + return 0; + } - // Set the time frame of the individual frame - _exam_info.time_frame_definitions = - TimeFrameDefinitions(hdr.get_exam_info().time_frame_definitions,frame_num); - image_sptr->set_exam_info(_exam_info); + for (int i = 0; i < hdr.matrix_size[2][0]; i++) + if (fabs(hdr.image_scaling_factors[frame_num - 1][i] - double(1)) > double(1e-10)) + (*image_sptr)[i] *= static_cast(hdr.image_scaling_factors[frame_num - 1][i]); - // now stick into the dynamic image - dynamic_dens_ptr->set_density(*image_sptr,frame_num); + // Set the time frame of the individual frame + _exam_info.time_frame_definitions = TimeFrameDefinitions(hdr.get_exam_info().time_frame_definitions, frame_num); + image_sptr->set_exam_info(_exam_info); - } + // now stick into the dynamic image + dynamic_dens_ptr->set_density(*image_sptr, frame_num); + } return dynamic_dens_ptr; } ParametricVoxelsOnCartesianGrid* -read_interfile_parametric_image(istream& input, - const string& directory_for_data) -{ +read_interfile_parametric_image(istream& input, const string& directory_for_data) { InterfileImageHeader hdr; char full_data_file_name[max_filename_length]; - shared_ptr > - image_sptr(create_image_and_header_from(hdr, - full_data_file_name, - input, - directory_for_data)); + shared_ptr> image_sptr( + create_image_and_header_from(hdr, full_data_file_name, input, directory_for_data)); if (is_null_ptr(image_sptr)) error("Error parsing parametric image"); shared_ptr scanner_sptr(Scanner::get_scanner_from_name(hdr.get_exam_info().originating_system)); - BasicCoordinate<3,float> voxel_size; + BasicCoordinate<3, float> voxel_size; voxel_size[1] = hdr.pixel_sizes[2]; voxel_size[2] = hdr.pixel_sizes[1]; voxel_size[3] = hdr.pixel_sizes[0]; ParametricVoxelsOnCartesianGrid* parametric_dens_ptr = - new ParametricVoxelsOnCartesianGrid( - ParametricVoxelsOnCartesianGridBaseType( - hdr.get_exam_info_sptr(), - image_sptr->get_index_range(), - image_sptr->get_origin(), - voxel_size)); + new ParametricVoxelsOnCartesianGrid(ParametricVoxelsOnCartesianGridBaseType( + hdr.get_exam_info_sptr(), image_sptr->get_index_range(), image_sptr->get_origin(), voxel_size)); ifstream data_in; open_read_binary(data_in, full_data_file_name); @@ -283,67 +229,61 @@ read_interfile_parametric_image(istream& input, data_in.seekg(hdr.data_offset_each_dataset[0]); // loop over each of the parametric image types (e.g., slope, intercept) - for (int kin_param=1; kin_param<=hdr.num_image_data_types; kin_param++) { - - data_in.seekg(hdr.data_offset_each_dataset[kin_param-1]); - - // read into image_sptr first - float scale = float(1); - if (read_data(data_in, *image_sptr, hdr.type_of_numbers, scale, hdr.file_byte_order) - == Succeeded::no - || scale != 1) - { - warning("read_interfile_parametric_image: error reading data or scale factor returned by read_data not equal to 1"); - return 0; - } + for (int kin_param = 1; kin_param <= hdr.num_image_data_types; kin_param++) { + + data_in.seekg(hdr.data_offset_each_dataset[kin_param - 1]); - for (int i=0; i< hdr.matrix_size[2][0]; i++) - if (hdr.image_scaling_factors[kin_param-1][i]!= 1) - (*image_sptr)[i] *= static_cast(hdr.image_scaling_factors[kin_param-1][i]); + // read into image_sptr first + float scale = float(1); + if (read_data(data_in, *image_sptr, hdr.type_of_numbers, scale, hdr.file_byte_order) == Succeeded::no || scale != 1) { + warning("read_interfile_parametric_image: error reading data or scale factor returned by read_data not equal to 1"); + return 0; + } + + for (int i = 0; i < hdr.matrix_size[2][0]; i++) + if (hdr.image_scaling_factors[kin_param - 1][i] != 1) + (*image_sptr)[i] *= static_cast(hdr.image_scaling_factors[kin_param - 1][i]); - // Check that we're dealing with VoxelsOnCartesianGrid - if (dynamic_cast * >(image_sptr.get())==0) - error("ParametricDiscretisedDensity::read_from_file only supports VoxelsOnCartesianGrid"); + // Check that we're dealing with VoxelsOnCartesianGrid + if (dynamic_cast*>(image_sptr.get()) == 0) + error("ParametricDiscretisedDensity::read_from_file only supports VoxelsOnCartesianGrid"); - // Set the image for the given kinetic parameter - ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType::const_full_iterator single_density_iter = + // Set the image for the given kinetic parameter + ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType::const_full_iterator single_density_iter = image_sptr->begin_all(); - ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType::const_full_iterator end_single_density_iter = + ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType::const_full_iterator end_single_density_iter = image_sptr->end_all(); - ParametricVoxelsOnCartesianGrid::full_densel_iterator parametric_density_iter = - parametric_dens_ptr->begin_all_densel(); + ParametricVoxelsOnCartesianGrid::full_densel_iterator parametric_density_iter = parametric_dens_ptr->begin_all_densel(); - while (single_density_iter!=end_single_density_iter) - { - (*parametric_density_iter)[kin_param] = *single_density_iter; - ++single_density_iter; ++parametric_density_iter; - } + while (single_density_iter != end_single_density_iter) { + (*parametric_density_iter)[kin_param] = *single_density_iter; + ++single_density_iter; + ++parametric_density_iter; + } } return parametric_dens_ptr; } -VoxelsOnCartesianGrid* read_interfile_image(const string& filename) -{ +VoxelsOnCartesianGrid* +read_interfile_image(const string& filename) { ifstream image_stream(filename.c_str()); - if (!image_stream) - { - error("read_interfile_image: couldn't open file %s\n", filename.c_str()); - } + if (!image_stream) { + error("read_interfile_image: couldn't open file %s\n", filename.c_str()); + } char directory_name[max_filename_length]; get_directory_name(directory_name, filename.c_str()); - + return read_interfile_image(image_stream, directory_name); } -DynamicDiscretisedDensity* read_interfile_dynamic_image(const string& filename) -{ +DynamicDiscretisedDensity* +read_interfile_dynamic_image(const string& filename) { ifstream image_stream(filename.c_str()); - if (!image_stream) - { - error("read_interfile_dynamic_image: couldn't open file %s\n", filename.c_str()); - } + if (!image_stream) { + error("read_interfile_dynamic_image: couldn't open file %s\n", filename.c_str()); + } char directory_name[max_filename_length]; get_directory_name(directory_name, filename.c_str()); @@ -352,13 +292,11 @@ DynamicDiscretisedDensity* read_interfile_dynamic_image(const string& filename) } ParametricVoxelsOnCartesianGrid* -read_interfile_parametric_image(const string& filename) -{ +read_interfile_parametric_image(const string& filename) { ifstream image_stream(filename.c_str()); - if (!image_stream) - { - error("read_interfile_parametric_image: couldn't open file %s\n", filename.c_str()); - } + if (!image_stream) { + error("read_interfile_parametric_image: couldn't open file %s\n", filename.c_str()); + } char directory_name[max_filename_length]; get_directory_name(directory_name, filename.c_str()); @@ -386,159 +324,144 @@ compute_file_offsets(int number_of_time_frames, to write in the header. It tries to cut the directory part of data_file_name if it's the same as the directory part of the header. */ -static -string -interfile_get_data_file_name_in_header(const string& header_file_name, - const string& data_file_name) -{ - const string dir_name_of_binary_data = - get_directory_name(data_file_name); - if (dir_name_of_binary_data.size() == 0) - { - // data_dirname is empty - return data_file_name; - } - const string dir_name_of_header = - get_directory_name(header_file_name); - if (dir_name_of_header == dir_name_of_binary_data) - { - // dirnames are the same, so strip from data_file_name - return - string(data_file_name, - find_pos_of_filename(data_file_name), - string::npos); - } - else - { - // just copy, what else to do? - return data_file_name; - } +static string +interfile_get_data_file_name_in_header(const string& header_file_name, const string& data_file_name) { + const string dir_name_of_binary_data = get_directory_name(data_file_name); + if (dir_name_of_binary_data.size() == 0) { + // data_dirname is empty + return data_file_name; + } + const string dir_name_of_header = get_directory_name(header_file_name); + if (dir_name_of_header == dir_name_of_binary_data) { + // dirnames are the same, so strip from data_file_name + return string(data_file_name, find_pos_of_filename(data_file_name), string::npos); + } else { + // just copy, what else to do? + return data_file_name; + } } //// some static helper functions for writing // probably should be moved to InterfileHeader -static void write_interfile_patient_position(std::ostream& output_header, const ExamInfo& exam_info) -{ +static void +write_interfile_patient_position(std::ostream& output_header, const ExamInfo& exam_info) { string orientation; - switch (exam_info.patient_position.get_orientation()) - { - case PatientPosition::head_in: orientation="head_in";break; - case PatientPosition::feet_in: orientation="feet_in";break; - case PatientPosition::other_orientation: orientation="other";break; - default: orientation="unknown"; break; - } + switch (exam_info.patient_position.get_orientation()) { + case PatientPosition::head_in: + orientation = "head_in"; + break; + case PatientPosition::feet_in: + orientation = "feet_in"; + break; + case PatientPosition::other_orientation: + orientation = "other"; + break; + default: + orientation = "unknown"; + break; + } string rotation; - switch (exam_info.patient_position.get_rotation()) - { - case PatientPosition::prone: rotation="prone";break; - case PatientPosition::supine: rotation="supine";break; - case PatientPosition::other_rotation: - case PatientPosition::left: - case PatientPosition::right: - rotation="other";break; - default: rotation="unknown"; break; - } - if (orientation!="unknown") + switch (exam_info.patient_position.get_rotation()) { + case PatientPosition::prone: + rotation = "prone"; + break; + case PatientPosition::supine: + rotation = "supine"; + break; + case PatientPosition::other_rotation: + case PatientPosition::left: + case PatientPosition::right: + rotation = "other"; + break; + default: + rotation = "unknown"; + break; + } + if (orientation != "unknown") output_header << "patient orientation := " << orientation << '\n'; - if (rotation!="unknown") + if (rotation != "unknown") output_header << "patient rotation := " << rotation << '\n'; } -static void write_interfile_time_frame_definitions(std::ostream& output_header, const ExamInfo& exam_info) - // TODO this is according to the proposed interfile standard for PET. Interfile 3.3 is different +static void +write_interfile_time_frame_definitions(std::ostream& output_header, const ExamInfo& exam_info) +// TODO this is according to the proposed interfile standard for PET. Interfile 3.3 is different { const TimeFrameDefinitions& frame_defs(exam_info.time_frame_definitions); - if (frame_defs.get_num_time_frames()>0) - { - output_header << "number of time frames := " << frame_defs.get_num_time_frames() << '\n'; - for (unsigned int frame_num=1; frame_num<=frame_defs.get_num_time_frames(); ++frame_num) - { - if (frame_defs.get_duration(frame_num)>0) - { - output_header << "image duration (sec)[" << frame_num << "] := " - << frame_defs.get_duration(frame_num) << '\n'; - output_header << "image relative start time (sec)[" << frame_num << "] := " - << frame_defs.get_start_time(frame_num) << '\n'; - } - } - } - else - { - // need to write this anyway to allow vectored keys below - output_header << "number of time frames := 1\n"; + if (frame_defs.get_num_time_frames() > 0) { + output_header << "number of time frames := " << frame_defs.get_num_time_frames() << '\n'; + for (unsigned int frame_num = 1; frame_num <= frame_defs.get_num_time_frames(); ++frame_num) { + if (frame_defs.get_duration(frame_num) > 0) { + output_header << "image duration (sec)[" << frame_num << "] := " << frame_defs.get_duration(frame_num) << '\n'; + output_header << "image relative start time (sec)[" << frame_num << "] := " << frame_defs.get_start_time(frame_num) + << '\n'; + } } + } else { + // need to write this anyway to allow vectored keys below + output_header << "number of time frames := 1\n"; + } } // Write energy window lower and upper thresholds, if they are not -1 -static void write_interfile_energy_windows(std::ostream& output_header, const ExamInfo& exam_info) -{ - if (exam_info.get_high_energy_thres() > 0 && - exam_info.get_low_energy_thres() >= 0) - { - output_header << "number of energy windows := 1\n"; - output_header << "energy window lower level[1] := " << - exam_info.get_low_energy_thres() << '\n'; - output_header << "energy window upper level[1] := " << - exam_info.get_high_energy_thres() << '\n'; - } +static void +write_interfile_energy_windows(std::ostream& output_header, const ExamInfo& exam_info) { + if (exam_info.get_high_energy_thres() > 0 && exam_info.get_low_energy_thres() >= 0) { + output_header << "number of energy windows := 1\n"; + output_header << "energy window lower level[1] := " << exam_info.get_low_energy_thres() << '\n'; + output_header << "energy window upper level[1] := " << exam_info.get_high_energy_thres() << '\n'; + } } // Write data type descriptions (if there are any) -static void write_interfile_image_data_descriptions(std::ostream& output_header, const std::vector& data_type_descriptions) -{ - if (data_type_descriptions.size() == 0) return; - - output_header << "number of image data types := " << data_type_descriptions.size() << '\n'; - output_header << "index nesting level := {data type}\n"; - for (int i=0; i& data_type_descriptions) { + if (data_type_descriptions.size() == 0) + return; + + output_header << "number of image data types := " << data_type_descriptions.size() << '\n'; + output_header << "index nesting level := {data type}\n"; + for (int i = 0; i < data_type_descriptions.size(); i++) + output_header << "image data type description[" << i + 1 << "] := " << data_type_descriptions[i] << "\n"; } -static void write_interfile_modality(std::ostream& output_header, const ExamInfo& exam_info) -{ +static void +write_interfile_modality(std::ostream& output_header, const ExamInfo& exam_info) { /* // default modality is PET ImagingModality imaging_modality(ImagingModality::PT); if (!is_null_ptr(exam_info_ptr)) imaging_modality=exam_info_ptr->imaging_modality; */ - if (exam_info. - imaging_modality.get_modality() != ImagingModality::Unknown) + if (exam_info.imaging_modality.get_modality() != ImagingModality::Unknown) output_header << "!imaging modality := " << exam_info.imaging_modality.get_name() << '\n'; } -static void interfile_create_filenames(const std::string& filename, std::string& data_name, std::string& header_name) -{ - data_name=filename; - string::size_type pos=find_pos_of_extension(filename); - if (pos!=string::npos && filename.substr(pos)==".hv") +static void +interfile_create_filenames(const std::string& filename, std::string& data_name, std::string& header_name) { + data_name = filename; + string::size_type pos = find_pos_of_extension(filename); + if (pos != string::npos && filename.substr(pos) == ".hv") replace_extension(data_name, ".v"); else add_extension(data_name, ".v"); - header_name=filename; + header_name = filename; replace_extension(header_name, ".hv"); } ////// end static functions -Succeeded -write_basic_interfile_image_header(const string& header_file_name, - const string& image_file_name, - const ExamInfo& exam_info, - const IndexRange<3>& index_range, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& origin, - const NumericType output_type, - const ByteOrder byte_order, - const VectorWithOffset& scaling_factors, - const VectorWithOffset& file_offsets, - const std::vector& data_type_descriptions) -{ +Succeeded +write_basic_interfile_image_header(const string& header_file_name, const string& image_file_name, const ExamInfo& exam_info, + const IndexRange<3>& index_range, const CartesianCoordinate3D& voxel_size, + const CartesianCoordinate3D& origin, const NumericType output_type, + const ByteOrder byte_order, const VectorWithOffset& scaling_factors, + const VectorWithOffset& file_offsets, + const std::vector& data_type_descriptions) { CartesianCoordinate3D min_indices; CartesianCoordinate3D max_indices; - if (!index_range.get_regular_range(min_indices, max_indices)) - { + if (!index_range.get_regular_range(min_indices, max_indices)) { warning("write_basic_interfile: can handle only regular index ranges\n. No output\n"); return Succeeded::no; } @@ -546,26 +469,23 @@ write_basic_interfile_image_header(const string& header_file_name, string header_name = header_file_name; add_extension(header_name, ".hv"); ofstream output_header(header_name.c_str(), ios::out); - if (!output_header.good()) - { - warning("Error opening Interfile header '%s' for writing\n", - header_name.c_str()); - return Succeeded::no; - } - + if (!output_header.good()) { + warning("Error opening Interfile header '%s' for writing\n", header_name.c_str()); + return Succeeded::no; + } + // handle directory names - const string data_file_name_in_header = - interfile_get_data_file_name_in_header(header_file_name, image_file_name); - + const string data_file_name_in_header = interfile_get_data_file_name_in_header(header_file_name, image_file_name); + output_header << "!INTERFILE :=\n"; const bool is_spect = exam_info.imaging_modality.get_modality() == ImagingModality::NM; if (!is_spect && exam_info.imaging_modality.get_modality() != ImagingModality::PT) - warning("Writing interfile header for a modality that is neither PET nor SPECT. This isn't really defined. There will be some PET keywords anyway."); + warning("Writing interfile header for a modality that is neither PET nor SPECT. This isn't really defined. There will be " + "some PET keywords anyway."); write_interfile_modality(output_header, exam_info); if (!exam_info.originating_system.empty()) - output_header << "originating system := " - << exam_info.originating_system << endl; + output_header << "originating system := " << exam_info.originating_system << endl; #if 0 //we don't have a conformant implementation of Interfile 3.3, even for SPECT @@ -581,113 +501,84 @@ write_basic_interfile_image_header(const string& header_file_name, output_header << "!GENERAL DATA :=\n"; write_interfile_patient_position(output_header, exam_info); output_header << "!GENERAL IMAGE DATA :=\n"; - if (exam_info.start_time_in_secs_since_1970>0) - { - const DateTimeStrings dt = - secs_since_Unix_epoch_to_Interfile_datetime(exam_info.start_time_in_secs_since_1970); - output_header << "study date := " << dt.date << '\n'; - output_header << "study time := " << dt.time << '\n'; - } + if (exam_info.start_time_in_secs_since_1970 > 0) { + const DateTimeStrings dt = secs_since_Unix_epoch_to_Interfile_datetime(exam_info.start_time_in_secs_since_1970); + output_header << "study date := " << dt.date << '\n'; + output_header << "study time := " << dt.time << '\n'; + } output_header << "!type of data := " << (is_spect ? "Tomographic" : "PET") << '\n'; - output_header << "imagedata byte order := " << - (byte_order == ByteOrder::little_endian - ? "LITTLEENDIAN" - : "BIGENDIAN") - << endl; - - if (exam_info.get_calibration_factor()>0.F) - output_header << "calibration factor := " - < 0.F) + output_header << "calibration factor := " << exam_info.get_calibration_factor() << endl; + if (!exam_info.get_radionuclide().empty()) - output_header << "isotope name := " - < 1300) template #else -#define elemT float +# define elemT float #endif -Succeeded -write_basic_interfile(const string& filename, - const Array<3,elemT>& image, - const NumericType output_type, - const float scale, - const ByteOrder byte_order) -{ +Succeeded +write_basic_interfile(const string& filename, const Array<3, elemT>& image, const NumericType output_type, const float scale, + const ByteOrder byte_order) { CartesianCoordinate3D origin; origin.fill(static_cast(InterfileHeader::double_value_not_set)); - return - write_basic_interfile(filename, - image, - CartesianCoordinate3D(1,1,1), - origin, - output_type, - scale, - byte_order); + return write_basic_interfile(filename, image, CartesianCoordinate3D(1, 1, 1), origin, output_type, scale, byte_order); } #if defined(_MSC_VER) && (_MSC_VER <= 1300) -#undef elemT +# undef elemT #endif template -Succeeded write_basic_interfile(const string& filename, - const ExamInfo& exam_info, - const Array<3,NUMBER>& image, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& origin, - const NumericType output_type, - const float scale, - const ByteOrder byte_order) -{ - std::string data_name, header_name; - interfile_create_filenames(filename, data_name, header_name); - - ofstream output_data; - open_write_binary(output_data, data_name.c_str()); - - float scale_to_use = scale; - write_data(output_data, image, output_type, scale_to_use, - byte_order); - VectorWithOffset scaling_factors(1); - scaling_factors.fill(scale_to_use); - VectorWithOffset file_offsets(1); - file_offsets.fill(0); - - const Succeeded success = - write_basic_interfile_image_header(header_name, - data_name, - exam_info, - image.get_index_range(), - voxel_size, - origin, - output_type, - byte_order, - scaling_factors, - file_offsets); - #if 0 +Succeeded +write_basic_interfile(const string& filename, const ExamInfo& exam_info, const Array<3, NUMBER>& image, + const CartesianCoordinate3D& voxel_size, const CartesianCoordinate3D& origin, + const NumericType output_type, const float scale, const ByteOrder byte_order) { + std::string data_name, header_name; + interfile_create_filenames(filename, data_name, header_name); + + ofstream output_data; + open_write_binary(output_data, data_name.c_str()); + + float scale_to_use = scale; + write_data(output_data, image, output_type, scale_to_use, byte_order); + VectorWithOffset scaling_factors(1); + scaling_factors.fill(scale_to_use); + VectorWithOffset file_offsets(1); + file_offsets.fill(0); + + const Succeeded success = + write_basic_interfile_image_header(header_name, data_name, exam_info, image.get_index_range(), voxel_size, origin, + output_type, byte_order, scaling_factors, file_offsets); +#if 0 delete[] header_name; delete[] data_name; - #endif - return success; +#endif + return success; } template -Succeeded write_basic_interfile(const string& filename, - const Array<3,NUMBER>& image, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& origin, - const NumericType output_type, - const float scale, - const ByteOrder byte_order) -{ +Succeeded +write_basic_interfile(const string& filename, const Array<3, NUMBER>& image, const CartesianCoordinate3D& voxel_size, + const CartesianCoordinate3D& origin, const NumericType output_type, const float scale, + const ByteOrder byte_order) { - return write_basic_interfile(filename, - ExamInfo(), - image, - voxel_size, - origin, - output_type, - scale, - byte_order); + return write_basic_interfile(filename, ExamInfo(), image, voxel_size, origin, output_type, scale, byte_order); } Succeeded -write_basic_interfile(const string& filename, - const VoxelsOnCartesianGrid& image, - const NumericType output_type, - const float scale, - const ByteOrder byte_order) -{ - return - write_basic_interfile(filename, - image.get_exam_info(), - image, // use automatic reference to base class - image.get_grid_spacing(), - image.get_origin(), - output_type, - scale, - byte_order); +write_basic_interfile(const string& filename, const VoxelsOnCartesianGrid& image, const NumericType output_type, + const float scale, const ByteOrder byte_order) { + return write_basic_interfile(filename, image.get_exam_info(), + image, // use automatic reference to base class + image.get_grid_spacing(), image.get_origin(), output_type, scale, byte_order); } -Succeeded -write_basic_interfile(const string& filename, - const DiscretisedDensity<3,float>& image, - const NumericType output_type, - const float scale, - const ByteOrder byte_order) -{ +Succeeded +write_basic_interfile(const string& filename, const DiscretisedDensity<3, float>& image, const NumericType output_type, + const float scale, const ByteOrder byte_order) { // dynamic_cast will throw an exception when it's not valid - return - write_basic_interfile(filename, - dynamic_cast& >(image), - output_type, - scale, byte_order); + return write_basic_interfile(filename, dynamic_cast&>(image), output_type, scale, + byte_order); } Succeeded -write_basic_interfile(const string& filename, - const ParametricVoxelsOnCartesianGrid &image, - const NumericType output_type, - const float scale, - const ByteOrder byte_order) -{ +write_basic_interfile(const string& filename, const ParametricVoxelsOnCartesianGrid& image, const NumericType output_type, + const float scale, const ByteOrder byte_order) { - std::string data_name, header_name; - interfile_create_filenames(filename, data_name, header_name); + std::string data_name, header_name; + interfile_create_filenames(filename, data_name, header_name); - ofstream output_data; - open_write_binary(output_data, data_name.c_str()); + ofstream output_data; + open_write_binary(output_data, data_name.c_str()); - VectorWithOffset file_offsets(image.get_num_params()); - VectorWithOffset scaling_factors(image.get_num_params()); - for (int i=1; i<=image.get_num_params(); i++) { - float scale_to_use = scale; - file_offsets[i-1] = output_data.tellp(); - write_data(output_data, image.construct_single_density(i), output_type, scale_to_use, - byte_order); - scaling_factors[i-1]=(scale_to_use); - } + VectorWithOffset file_offsets(image.get_num_params()); + VectorWithOffset scaling_factors(image.get_num_params()); + for (int i = 1; i <= image.get_num_params(); i++) { + float scale_to_use = scale; + file_offsets[i - 1] = output_data.tellp(); + write_data(output_data, image.construct_single_density(i), output_type, scale_to_use, byte_order); + scaling_factors[i - 1] = (scale_to_use); + } + + // Tell it what the different kinetic parameters mean + std::vector data_type_descriptions; + data_type_descriptions.push_back("slope"); + data_type_descriptions.push_back("intercept"); - // Tell it what the different kinetic parameters mean - std::vector data_type_descriptions; - data_type_descriptions.push_back("slope"); - data_type_descriptions.push_back("intercept"); - - const Succeeded success = - write_basic_interfile_image_header(header_name, - data_name, - image.get_exam_info(), - image.get_index_range(), - image.get_voxel_size(), - image.get_origin(), - output_type, - byte_order, - scaling_factors, - file_offsets, - data_type_descriptions); - #if 0 + const Succeeded success = write_basic_interfile_image_header( + header_name, data_name, image.get_exam_info(), image.get_index_range(), image.get_voxel_size(), image.get_origin(), + output_type, byte_order, scaling_factors, file_offsets, data_type_descriptions); +#if 0 delete[] header_name; delete[] data_name; - #endif - return success; +#endif + return success; } - Succeeded -write_basic_interfile(const string& filename, - const DynamicDiscretisedDensity &image, - const NumericType output_type, - const float scale, - const ByteOrder byte_order) -{ +write_basic_interfile(const string& filename, const DynamicDiscretisedDensity& image, const NumericType output_type, + const float scale, const ByteOrder byte_order) { - std::string data_name, header_name; - interfile_create_filenames(filename, data_name, header_name); + std::string data_name, header_name; + interfile_create_filenames(filename, data_name, header_name); - ofstream output_data; - open_write_binary(output_data, data_name.c_str()); + ofstream output_data; + open_write_binary(output_data, data_name.c_str()); - VectorWithOffset file_offsets(image.get_num_time_frames()); - VectorWithOffset scaling_factors(image.get_num_time_frames()); - for (int i=1; i<=image.get_num_time_frames(); i++) -{ - float scale_to_use = scale; - file_offsets[i-1] = output_data.tellp(); - write_data(output_data, image.get_density(i), output_type, scale_to_use, - byte_order); - scaling_factors[i-1]=(scale_to_use); -} + VectorWithOffset file_offsets(image.get_num_time_frames()); + VectorWithOffset scaling_factors(image.get_num_time_frames()); + for (int i = 1; i <= image.get_num_time_frames(); i++) { + float scale_to_use = scale; + file_offsets[i - 1] = output_data.tellp(); + write_data(output_data, image.get_density(i), output_type, scale_to_use, byte_order); + scaling_factors[i - 1] = (scale_to_use); + } - const Succeeded success = - write_basic_interfile_image_header(header_name, - data_name, - image.get_exam_info(), - image.get_density(1).get_index_range(), - dynamic_cast& >(image.get_density(1)).get_grid_spacing(), - image.get_density(1).get_origin(), - output_type, - byte_order, - scaling_factors, - file_offsets); - #if 0 + const Succeeded success = write_basic_interfile_image_header( + header_name, data_name, image.get_exam_info(), image.get_density(1).get_index_range(), + dynamic_cast&>(image.get_density(1)).get_grid_spacing(), + image.get_density(1).get_origin(), output_type, byte_order, scaling_factors, file_offsets); +#if 0 delete[] header_name; delete[] data_name; - #endif - return success; +#endif + return success; } -static ProjDataFromStream* -read_interfile_PDFS_SPECT(istream& input, - const string& directory_for_data, - const ios::openmode open_mode) -{ - - InterfilePDFSHeaderSPECT hdr; - if (!hdr.parse(input)) - { - return 0; // KT 10122001 do not call ask_parameters anymore - } +static ProjDataFromStream* +read_interfile_PDFS_SPECT(istream& input, const string& directory_for_data, const ios::openmode open_mode) { + + InterfilePDFSHeaderSPECT hdr; + if (!hdr.parse(input)) { + return 0; // KT 10122001 do not call ask_parameters anymore + } char full_data_file_name[max_filename_length]; strcpy(full_data_file_name, hdr.data_file_name.c_str()); - prepend_directory_name(full_data_file_name, directory_for_data.c_str()); - - vector segment_sequence(1); - segment_sequence[0]=0; - - for (unsigned int i=1; i data_in(new fstream (full_data_file_name, open_mode | ios::binary)); - if (!data_in->good()) - { - warning("interfile parsing: error opening file %s",full_data_file_name); - return 0; - } + vector segment_sequence(1); + segment_sequence[0] = 0; - return new ProjDataFromStream(hdr.get_exam_info_sptr(), - hdr.data_info_sptr, - data_in, - hdr.data_offset_each_dataset[0], - segment_sequence, - hdr.storage_order, - hdr.type_of_numbers, - hdr.file_byte_order, - static_cast(hdr.image_scaling_factors[0][0])); + for (unsigned int i = 1; i < hdr.image_scaling_factors[0].size(); i++) + if (hdr.image_scaling_factors[0][0] != hdr.image_scaling_factors[0][i]) { + error("Interfile error: all image scaling factors should be equal at the moment."); + } + assert(!is_null_ptr(hdr.data_info_sptr)); -} + shared_ptr data_in(new fstream(full_data_file_name, open_mode | ios::binary)); + if (!data_in->good()) { + warning("interfile parsing: error opening file %s", full_data_file_name); + return 0; + } + return new ProjDataFromStream(hdr.get_exam_info_sptr(), hdr.data_info_sptr, data_in, hdr.data_offset_each_dataset[0], + segment_sequence, hdr.storage_order, hdr.type_of_numbers, hdr.file_byte_order, + static_cast(hdr.image_scaling_factors[0][0])); +} ProjDataFromStream* -read_interfile_PDFS_Siemens(istream& input, - const string& directory_for_data, - const ios::openmode open_mode) -{ +read_interfile_PDFS_Siemens(istream& input, const string& directory_for_data, const ios::openmode open_mode) { InterfilePDFSHeaderSiemens hdr; - if (!hdr.parse(input)) - { - warning("Interfile parsing of Siemens Interfile projection data failed"); - return 0; - } + if (!hdr.parse(input)) { + warning("Interfile parsing of Siemens Interfile projection data failed"); + return 0; + } // KT 14/01/2000 added directory capability // prepend directory_for_data to the data_file_name from the header @@ -1054,137 +826,102 @@ read_interfile_PDFS_Siemens(istream& input, prepend_directory_name(full_data_file_name, directory_for_data.c_str()); shared_ptr data_in(new fstream(full_data_file_name, open_mode | ios::binary)); - if (!data_in->good()) - { + if (!data_in->good()) { warning("interfile parsing: error opening file %s", full_data_file_name); return 0; - } + } if (hdr.compression) warning("Siemens projection data is compressed. Reading of raw data will fail."); - return new ProjDataFromStream(hdr.get_exam_info_sptr(), - hdr.data_info_ptr->create_shared_clone(), - data_in, - hdr.data_offset_each_dataset[0], - hdr.segment_sequence, - hdr.storage_order, - hdr.type_of_numbers, - hdr.file_byte_order, - 1.); - + return new ProjDataFromStream(hdr.get_exam_info_sptr(), hdr.data_info_ptr->create_shared_clone(), data_in, + hdr.data_offset_each_dataset[0], hdr.segment_sequence, hdr.storage_order, hdr.type_of_numbers, + hdr.file_byte_order, 1.); } -ProjDataFromStream* -read_interfile_PDFS(istream& input, - const string& directory_for_data, - const ios::openmode open_mode) -{ - +ProjDataFromStream* +read_interfile_PDFS(istream& input, const string& directory_for_data, const ios::openmode open_mode) { + { - MinimalInterfileHeader hdr; + MinimalInterfileHeader hdr; std::ios::off_type offset = input.tellg(); if (!hdr.parse(input, false)) // parse without warnings - { - warning("Interfile parsing failed"); - return 0; - } + { + warning("Interfile parsing failed"); + return 0; + } input.clear(); // clear EOF or other flags before we proceed input.seekg(offset); - if (hdr.get_exam_info().imaging_modality.get_modality() == - ImagingModality::NM) - { - // spect data - return read_interfile_PDFS_SPECT(input, directory_for_data, open_mode); - } - if (!hdr.siemens_mi_version.empty()) - { - return read_interfile_PDFS_Siemens(input, directory_for_data, open_mode); - } + if (hdr.get_exam_info().imaging_modality.get_modality() == ImagingModality::NM) { + // spect data + return read_interfile_PDFS_SPECT(input, directory_for_data, open_mode); + } + if (!hdr.siemens_mi_version.empty()) { + return read_interfile_PDFS_Siemens(input, directory_for_data, open_mode); + } } - + // if we get here, it's PET - InterfilePDFSHeader hdr; - if (!hdr.parse(input)) - { - warning("Interfile parsing of PET projection data failed"); - return 0; - } + InterfilePDFSHeader hdr; + if (!hdr.parse(input)) { + warning("Interfile parsing of PET projection data failed"); + return 0; + } // KT 14/01/2000 added directory capability // prepend directory_for_data to the data_file_name from the header char full_data_file_name[max_filename_length]; strcpy(full_data_file_name, hdr.data_file_name.c_str()); - prepend_directory_name(full_data_file_name, directory_for_data.c_str()); - - for (unsigned int i=1; i data_in(new fstream (full_data_file_name, open_mode | ios::binary)); - if (!data_in->good()) - { - warning("interfile parsing: error opening file %s",full_data_file_name); - return 0; - } + for (unsigned int i = 1; i < hdr.image_scaling_factors[0].size(); i++) + if (hdr.image_scaling_factors[0][0] != hdr.image_scaling_factors[0][i]) { + warning("Interfile warning: all image scaling factors should be equal \n" + "at the moment. Using the first scale factor only.\n"); + break; + } - return new ProjDataFromStream(hdr.get_exam_info_sptr(), - hdr.data_info_sptr->create_shared_clone(), - data_in, - hdr.data_offset_each_dataset[0], - hdr.segment_sequence, - hdr.storage_order, - hdr.type_of_numbers, - hdr.file_byte_order, - static_cast(hdr.image_scaling_factors[0][0])); + assert(!is_null_ptr(hdr.data_info_sptr)); + shared_ptr data_in(new fstream(full_data_file_name, open_mode | ios::binary)); + if (!data_in->good()) { + warning("interfile parsing: error opening file %s", full_data_file_name); + return 0; + } + return new ProjDataFromStream(hdr.get_exam_info_sptr(), hdr.data_info_sptr->create_shared_clone(), data_in, + hdr.data_offset_each_dataset[0], hdr.segment_sequence, hdr.storage_order, hdr.type_of_numbers, + hdr.file_byte_order, static_cast(hdr.image_scaling_factors[0][0])); } - ProjDataFromStream* -read_interfile_PDFS(const string& filename, - const ios::openmode open_mode) -{ +read_interfile_PDFS(const string& filename, const ios::openmode open_mode) { ifstream image_stream(filename.c_str()); - if (!image_stream) - { - error("read_interfile_PDFS: couldn't open file %s\n", filename.c_str()); - } - + if (!image_stream) { + error("read_interfile_PDFS: couldn't open file %s\n", filename.c_str()); + } + char directory_name[max_filename_length]; get_directory_name(directory_name, filename.c_str()); - + return read_interfile_PDFS(image_stream, directory_name, open_mode); } -Succeeded -write_basic_interfile_PDFS_header(const string& header_file_name, - const string& data_file_name, - const ProjDataFromStream& pdfs) -{ +Succeeded +write_basic_interfile_PDFS_header(const string& header_file_name, const string& data_file_name, const ProjDataFromStream& pdfs) { string header_name = header_file_name; add_extension(header_name, ".hs"); ofstream output_header(header_name.c_str(), ios::out); - if (!output_header.good()) - { - warning("Error opening Interfile header '%s' for writing\n", - header_name.c_str()); - return Succeeded::no; - } + if (!output_header.good()) { + warning("Error opening Interfile header '%s' for writing\n", header_name.c_str()); + return Succeeded::no; + } // handle directory names - const string data_file_name_in_header = - interfile_get_data_file_name_in_header(header_file_name, data_file_name); + const string data_file_name_in_header = interfile_get_data_file_name_in_header(header_file_name, data_file_name); const vector segment_sequence = pdfs.get_segment_sequence_in_stream(); @@ -1193,12 +930,12 @@ write_basic_interfile_PDFS_header(const string& header_file_name, const float angle_first_view = pdfs.get_proj_data_info_sptr()->get_phi(Bin(0,0,0,0)) * float(180/_PI); #else - const float angle_first_view = - pdfs.get_proj_data_info_sptr()->get_scanner_ptr()->get_default_intrinsic_tilt() * float(180/_PI); + const float angle_first_view = + pdfs.get_proj_data_info_sptr()->get_scanner_ptr()->get_default_intrinsic_tilt() * float(180 / _PI); #endif - const float angle_increment = - (pdfs.get_proj_data_info_sptr()->get_phi(Bin(0,1,0,0)) - - pdfs.get_proj_data_info_sptr()->get_phi(Bin(0,0,0,0))) * float(180/_PI); + const float angle_increment = + (pdfs.get_proj_data_info_sptr()->get_phi(Bin(0, 1, 0, 0)) - pdfs.get_proj_data_info_sptr()->get_phi(Bin(0, 0, 0, 0))) * + float(180 / _PI); output_header << "!INTERFILE :=\n"; @@ -1209,7 +946,7 @@ write_basic_interfile_PDFS_header(const string& header_file_name, output_header << "name of data file := " << data_file_name_in_header << endl; output_header << "originating system := "; - output_header <get_scanner_ptr()->get_name() << endl; + output_header << pdfs.get_proj_data_info_sptr()->get_scanner_ptr()->get_name() << endl; if (is_spect) output_header << "!version of keys := 3.3\n"; @@ -1221,34 +958,27 @@ write_basic_interfile_PDFS_header(const string& header_file_name, output_header << "!type of data := " << (is_spect ? "Tomographic" : "PET") << '\n'; // output patient position - // note: strictly speaking this should come after "!SPECT STUDY (general)" but + // note: strictly speaking this should come after "!SPECT STUDY (general)" but // that's strange as these keys would be useful for all other cases as well write_interfile_patient_position(output_header, pdfs.get_exam_info()); - output_header << "imagedata byte order := " << - (pdfs.get_byte_order_in_stream() == ByteOrder::little_endian - ? "LITTLEENDIAN" - : "BIGENDIAN") - << endl; + output_header << "imagedata byte order := " + << (pdfs.get_byte_order_in_stream() == ByteOrder::little_endian ? "LITTLEENDIAN" : "BIGENDIAN") << endl; - - if (is_spect) + if (is_spect) { + // output_header << "number of energy windows :=1\n"; + output_header << "!SPECT STUDY (General) :=\n"; + } else { + output_header << "!PET STUDY (General) :=\n"; + output_header << "!PET data type := Emission\n"; { - // output_header << "number of energy windows :=1\n"; - output_header << "!SPECT STUDY (General) :=\n"; - } - else - { - output_header << "!PET STUDY (General) :=\n"; - output_header << "!PET data type := Emission\n"; - { - // KT 10/12/2001 write applied corrections keyword - if(!is_null_ptr(dynamic_pointer_cast (pdfs.get_proj_data_info_sptr()))) - output_header << "applied corrections := {arc correction}\n"; - else - output_header << "applied corrections := {None}\n"; - } + // KT 10/12/2001 write applied corrections keyword + if (!is_null_ptr(dynamic_pointer_cast(pdfs.get_proj_data_info_sptr()))) + output_header << "applied corrections := {arc correction}\n"; + else + output_header << "applied corrections := {None}\n"; } + } { string number_format; size_t size_in_bytes; @@ -1260,200 +990,196 @@ write_basic_interfile_PDFS_header(const string& header_file_name, output_header << "!number of bytes per pixel := " << size_in_bytes << "\n"; } - if (is_spect) - { - output_header << "!number of projections := " << pdfs.get_num_views() << '\n'; - output_header << "!extent of rotation := " << pdfs.get_num_views() * fabs(angle_increment) << '\n'; - output_header << "process status := acquired\n"; - output_header << "!SPECT STUDY (acquired data):=\n"; + if (is_spect) { + output_header << "!number of projections := " << pdfs.get_num_views() << '\n'; + output_header << "!extent of rotation := " << pdfs.get_num_views() * fabs(angle_increment) << '\n'; + output_header << "process status := acquired\n"; + output_header << "!SPECT STUDY (acquired data):=\n"; - output_header << "!direction of rotation := " - << (angle_increment>0 ? "CCW" : "CW") - << '\n'; - output_header << "start angle := " << angle_first_view << '\n'; + output_header << "!direction of rotation := " << (angle_increment > 0 ? "CCW" : "CW") << '\n'; + output_header << "start angle := " << angle_first_view << '\n'; - const shared_ptr proj_data_info_cyl_sptr = + const shared_ptr proj_data_info_cyl_sptr = dynamic_pointer_cast(pdfs.get_proj_data_info_sptr()); - VectorWithOffset ring_radii = proj_data_info_cyl_sptr->get_ring_radii_for_all_views(); - if (*std::min_element(ring_radii.begin(),ring_radii.end()) == - *std::max_element(ring_radii.begin(),ring_radii.end())) - { - output_header << "orbit := Circular\n"; - output_header << "Radius := " << *ring_radii.begin() << '\n'; - } - else - { - output_header << "orbit := Non-circular\n"; - output_header << "Radii := " << ring_radii << '\n'; - } - - output_header << "!matrix size [1] := " - <get_num_tangential_poss() << '\n'; - output_header << "!scaling factor (mm/pixel) [1] := " - <get_tangential_sampling() << '\n'; - output_header << "!matrix size [2] := " - <get_num_axial_poss(0) << '\n'; - output_header << "!scaling factor (mm/pixel) [2] := " - <get_axial_sampling(0) << '\n'; - - if (pdfs.get_offset_in_stream()) - output_header<<"data offset in bytes := " - < ring_radii = proj_data_info_cyl_sptr->get_ring_radii_for_all_views(); + if (*std::min_element(ring_radii.begin(), ring_radii.end()) == *std::max_element(ring_radii.begin(), ring_radii.end())) { + output_header << "orbit := Circular\n"; + output_header << "Radius := " << *ring_radii.begin() << '\n'; + } else { + output_header << "orbit := Non-circular\n"; + output_header << "Radii := " << ring_radii << '\n'; } + output_header << "!matrix size [1] := " << proj_data_info_cyl_sptr->get_num_tangential_poss() << '\n'; + output_header << "!scaling factor (mm/pixel) [1] := " << proj_data_info_cyl_sptr->get_tangential_sampling() << '\n'; + output_header << "!matrix size [2] := " << proj_data_info_cyl_sptr->get_num_axial_poss(0) << '\n'; + output_header << "!scaling factor (mm/pixel) [2] := " << proj_data_info_cyl_sptr->get_axial_sampling(0) << '\n'; + + if (pdfs.get_offset_in_stream()) + output_header << "data offset in bytes := " << pdfs.get_offset_in_stream() << '\n'; + ; + output_header << "!END OF INTERFILE :=\n"; + + return Succeeded::yes; + } + // it's PET data if we get here + // N.E. Added timing locations + pdfs.get_proj_data_info_sptr()->get_num_tof_poss() > 1 ? output_header << "number of dimensions := 5\n" + : output_header << "number of dimensions := 4\n"; - output_header << "number of dimensions := 4\n"; - - // TODO support more ? + // TODO support more ? { // default to Segment_View_AxialPos_TangPos int order_of_segment = 4; int order_of_view = 3; int order_of_z = 2; int order_of_bin = 1; - switch(pdfs.get_storage_order()) - /* - { - case ProjDataFromStream::ViewSegmentRingBin: - { - order_of_segment = 2; - order_of_view = 1; - order_of_z = 3; - break; - } - */ + int order_of_timing_poss = 0; + switch (pdfs.get_storage_order()) + /* + { + case ProjDataFromStream::ViewSegmentRingBin: + { + order_of_segment = 2; + order_of_view = 1; + order_of_z = 3; + break; + } + */ { - case ProjDataFromStream::Segment_View_AxialPos_TangPos: - { - order_of_segment = 4; - order_of_view = 3; - order_of_z = 2; - break; - } - case ProjDataFromStream::Segment_AxialPos_View_TangPos: - { - order_of_segment = 4; - order_of_view = 2; - order_of_z = 3; - break; - } - default: - { - error("write_interfile_PSOV_header: unsupported storage order, " - "defaulting to Segment_View_AxialPos_TangPos.\n Please correct by hand !"); - } - } - - output_header << "matrix axis label [" << order_of_segment - << "] := segment\n"; - output_header << "!matrix size [" << order_of_segment << "] := " - << pdfs.get_segment_sequence_in_stream().size()<< "\n"; + case ProjDataFromStream::Segment_View_AxialPos_TangPos: { + order_of_segment = 4; + order_of_view = 3; + order_of_z = 2; + break; + } + case ProjDataFromStream::Segment_AxialPos_View_TangPos: { + order_of_segment = 4; + order_of_view = 2; + order_of_z = 3; + break; + } + case ProjDataFromStream::Timing_Segment_View_AxialPos_TangPos: { + order_of_timing_poss = 5; + order_of_segment = 4; + order_of_view = 3; + order_of_z = 2; + break; + } + default: { + error("write_interfile_PSOV_header: unsupported storage order, " + "defaulting to Segment_View_AxialPos_TangPos.\n Please correct by hand !"); + } + } + + if (order_of_timing_poss > 0) { + output_header << "matrix axis label [" << order_of_timing_poss << "] := timing positions\n"; + output_header << "!matrix size [" << order_of_timing_poss << "] := " << pdfs.get_timing_poss_sequence_in_stream().size() + << "\n"; + } + + output_header << "matrix axis label [" << order_of_segment << "] := segment\n"; + output_header << "!matrix size [" << order_of_segment << "] := " << pdfs.get_segment_sequence_in_stream().size() << "\n"; output_header << "matrix axis label [" << order_of_view << "] := view\n"; - output_header << "!matrix size [" << order_of_view << "] := " - << pdfs.get_proj_data_info_sptr()->get_num_views() << "\n"; - + output_header << "!matrix size [" << order_of_view << "] := " << pdfs.get_proj_data_info_sptr()->get_num_views() << "\n"; + output_header << "matrix axis label [" << order_of_z << "] := axial coordinate\n"; output_header << "!matrix size [" << order_of_z << "] := "; // tedious way to print a list of numbers { std::vector::const_iterator seg = segment_sequence.begin(); - output_header << "{ " <get_num_axial_poss(*seg); + output_header << "{ " << pdfs.get_proj_data_info_sptr()->get_num_axial_poss(*seg); for (seg++; seg != segment_sequence.end(); seg++) - output_header << "," << pdfs.get_proj_data_info_sptr()->get_num_axial_poss(*seg); + output_header << "," << pdfs.get_proj_data_info_sptr()->get_num_axial_poss(*seg); output_header << "}\n"; } output_header << "matrix axis label [" << order_of_bin << "] := tangential coordinate\n"; - output_header << "!matrix size [" << order_of_bin << "] := " - <get_num_tangential_poss() << "\n"; + output_header << "!matrix size [" << order_of_bin << "] := " << pdfs.get_proj_data_info_sptr()->get_num_tangential_poss() + << "\n"; + + // If TOF is supported; add this in the header. + if (pdfs.get_proj_data_info_sptr()->get_scanner_ptr()->is_tof_ready() && + pdfs.get_proj_data_info_sptr()->get_num_tof_poss() > 1) { + // Moved in scanner section + // output_header << "%number of TOF time bins :=" << + // pdfs.get_proj_data_info_ptr()->get_scanner_ptr()->get_num_max_of_timing_bins() << "\n"; + output_header << "%TOF mashing factor := " << pdfs.get_proj_data_info_sptr()->get_tof_mash_factor() << "\n"; + } } const shared_ptr proj_data_info_sptr = - dynamic_pointer_cast(pdfs.get_proj_data_info_sptr()); + dynamic_pointer_cast(pdfs.get_proj_data_info_sptr()); - if (!is_null_ptr(proj_data_info_sptr)) - { - // cylindrical scanners - - output_header << "minimum ring difference per segment := "; - { - std::vector::const_iterator seg = segment_sequence.begin(); - output_header << "{ " << proj_data_info_sptr->get_min_ring_difference(*seg); - for (seg++; seg != segment_sequence.end(); seg++) - output_header << "," <get_min_ring_difference(*seg); - output_header << "}\n"; - } - - output_header << "maximum ring difference per segment := "; - { - std::vector::const_iterator seg = segment_sequence.begin(); - output_header << "{ " <get_max_ring_difference(*seg); - for (seg++; seg != segment_sequence.end(); seg++) - output_header << "," <get_max_ring_difference(*seg); - output_header << "}\n"; - } - - const Scanner& scanner = *proj_data_info_sptr->get_scanner_ptr(); - if (fabs(proj_data_info_sptr->get_ring_radius()- - scanner.get_effective_ring_radius()) > .1) - warning("write_basic_interfile_PDFS_header: inconsistent effective ring radius:\n" - "\tproj_data_info has %g, scanner has %g.\n" - "\tThis really should not happen and signifies a bug.\n" - "\tYou will have a problem reading this data back in.", - proj_data_info_sptr->get_ring_radius(), - scanner.get_effective_ring_radius()); - if (fabs(proj_data_info_sptr->get_ring_spacing()- - scanner.get_ring_spacing()) > .1) - warning("write_basic_interfile_PDFS_header: inconsistent ring spacing:\n" - "\tproj_data_info has %g, scanner has %g.\n" - "\tThis really should not happen and signifies a bug.\n" - "\tYou will have a problem reading this data back in.", - proj_data_info_sptr->get_ring_spacing(), - scanner.get_ring_spacing()); - - output_header << scanner.parameter_info(); - - output_header << "effective central bin size (cm) := " - << proj_data_info_sptr->get_sampling_in_s(Bin(0,0,0,0))/10. << endl; - - } // end of cylindrical scanner - else + if (!is_null_ptr(proj_data_info_sptr)) { + // cylindrical scanners + + output_header << "minimum ring difference per segment := "; + { + std::vector::const_iterator seg = segment_sequence.begin(); + output_header << "{ " << proj_data_info_sptr->get_min_ring_difference(*seg); + for (seg++; seg != segment_sequence.end(); seg++) + output_header << "," << proj_data_info_sptr->get_min_ring_difference(*seg); + output_header << "}\n"; + } + + output_header << "maximum ring difference per segment := "; { - // TODO something here + std::vector::const_iterator seg = segment_sequence.begin(); + output_header << "{ " << proj_data_info_sptr->get_max_ring_difference(*seg); + for (seg++; seg != segment_sequence.end(); seg++) + output_header << "," << proj_data_info_sptr->get_max_ring_difference(*seg); + output_header << "}\n"; } + const Scanner& scanner = *proj_data_info_sptr->get_scanner_ptr(); + if (fabs(proj_data_info_sptr->get_ring_radius() - scanner.get_effective_ring_radius()) > .1) + warning("write_basic_interfile_PDFS_header: inconsistent effective ring radius:\n" + "\tproj_data_info has %g, scanner has %g.\n" + "\tThis really should not happen and signifies a bug.\n" + "\tYou will have a problem reading this data back in.", + proj_data_info_sptr->get_ring_radius(), scanner.get_effective_ring_radius()); + if (fabs(proj_data_info_sptr->get_ring_spacing() - scanner.get_ring_spacing()) > .1) + warning("write_basic_interfile_PDFS_header: inconsistent ring spacing:\n" + "\tproj_data_info has %g, scanner has %g.\n" + "\tThis really should not happen and signifies a bug.\n" + "\tYou will have a problem reading this data back in.", + proj_data_info_sptr->get_ring_spacing(), scanner.get_ring_spacing()); + + output_header << scanner.parameter_info(); + + output_header << "effective central bin size (cm) := " << proj_data_info_sptr->get_sampling_in_s(Bin(0, 0, 0, 0)) / 10. + << endl; + + } // end of cylindrical scanner + else { + // TODO something here + } - // write time frame info and energy windows - write_interfile_time_frame_definitions(output_header, pdfs.get_exam_info()); - write_interfile_energy_windows(output_header, pdfs.get_exam_info()); + // write time frame info and energy windows + write_interfile_time_frame_definitions(output_header, pdfs.get_exam_info()); + write_interfile_energy_windows(output_header, pdfs.get_exam_info()); - if (pdfs.get_scale_factor()!=1.F) - output_header <<"image scaling factor[1] := " - <(const string& filename, const Array<3, signed short>&, + const CartesianCoordinate3D& voxel_size, + const CartesianCoordinate3D& origin, const NumericType output_type, + const float scale, const ByteOrder byte_order); +template Succeeded write_basic_interfile<>(const string& filename, const Array<3, unsigned short>&, + const CartesianCoordinate3D& voxel_size, + const CartesianCoordinate3D& origin, const NumericType output_type, + const float scale, const ByteOrder byte_order); -template -Succeeded -write_basic_interfile<>(const string& filename, - const Array<3,signed short>&, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& origin, - const NumericType output_type, - const float scale, - const ByteOrder byte_order); -template -Succeeded -write_basic_interfile<>(const string& filename, - const Array<3,unsigned short>&, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& origin, - const NumericType output_type, - const float scale, - const ByteOrder byte_order); - -template -Succeeded -write_basic_interfile<>(const string& filename, - const Array<3,float>&, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& origin, - const NumericType output_type, - const float scale, - const ByteOrder byte_order); +template Succeeded write_basic_interfile<>(const string& filename, const Array<3, float>&, + const CartesianCoordinate3D& voxel_size, + const CartesianCoordinate3D& origin, const NumericType output_type, + const float scale, const ByteOrder byte_order); #if !defined(_MSC_VER) || (_MSC_VER > 1300) -template -Succeeded -write_basic_interfile<>(const string& filename, - const Array<3,signed short>& image, - const NumericType output_type, - const float scale, - const ByteOrder byte_order); - -template -Succeeded -write_basic_interfile<>(const string& filename, - const Array<3,unsigned short>& image, - const NumericType output_type, - const float scale, - const ByteOrder byte_order); - -template -Succeeded -write_basic_interfile<>(const string& filename, - const Array<3,float>& image, - const NumericType output_type, - const float scale, - const ByteOrder byte_order); +template Succeeded write_basic_interfile<>(const string& filename, const Array<3, signed short>& image, + const NumericType output_type, const float scale, const ByteOrder byte_order); + +template Succeeded write_basic_interfile<>(const string& filename, const Array<3, unsigned short>& image, + const NumericType output_type, const float scale, const ByteOrder byte_order); + +template Succeeded write_basic_interfile<>(const string& filename, const Array<3, float>& image, const NumericType output_type, + const float scale, const ByteOrder byte_order); #endif END_NAMESPACE_STIR diff --git a/src/IO/stir_AVW.cxx b/src/IO/stir_AVW.cxx index 685379ac29..3f7249cf6b 100644 --- a/src/IO/stir_AVW.cxx +++ b/src/IO/stir_AVW.cxx @@ -21,143 +21,104 @@ \file \ingroup IO \brief routines to convert AVW data structures to STIR -\author Kris Thielemans +\author Kris Thielemans */ #ifdef HAVE_AVW -#include "stir/IO/stir_AVW.h" -#include "stir/IndexRange3D.h" -#include "stir/VoxelsOnCartesianGrid.h" -#include "stir/CartesianCoordinate3D.h" - +# include "stir/IO/stir_AVW.h" +# include "stir/IndexRange3D.h" +# include "stir/VoxelsOnCartesianGrid.h" +# include "stir/CartesianCoordinate3D.h" START_NAMESPACE_STIR -namespace AVW -{ +namespace AVW { template -static -void -AVW_Volume_to_VoxelsOnCartesianGrid_help(VoxelsOnCartesianGrid& image, - elemT const* avw_data, - const bool flip_z) -{ +static void +AVW_Volume_to_VoxelsOnCartesianGrid_help(VoxelsOnCartesianGrid& image, elemT const* avw_data, const bool flip_z) { // std::copy(avw_data, avw_data+avw_volume->VoxelsPerVolume, image->begin_all()); - + // AVW data seems to be y-flipped - for (int z=image.get_min_z(); z<=image.get_max_z(); ++z) - { - const int out_z = - !flip_z ? z : image.get_max_z() - z + image.get_min_z(); - for (int y=image.get_max_y(); y>=image.get_min_y(); --y) - { - for (int x=image.get_min_x(); x<=image.get_max_x(); ++x) + for (int z = image.get_min_z(); z <= image.get_max_z(); ++z) { + const int out_z = !flip_z ? z : image.get_max_z() - z + image.get_min_z(); + for (int y = image.get_max_y(); y >= image.get_min_y(); --y) { + for (int x = image.get_min_x(); x <= image.get_max_x(); ++x) image[out_z][y][x] = static_cast(*avw_data++); - //std::copy(avw_data, avw_data + image.get_x_size(), image[z][y].begin()); - //avw_data += image.get_x_size(); + // std::copy(avw_data, avw_data + image.get_x_size(), image[z][y].begin()); + // avw_data += image.get_x_size(); } } } - -VoxelsOnCartesianGrid * -AVW_Volume_to_VoxelsOnCartesianGrid(AVW_Volume const* const avw_volume, - const bool flip_z) -{ - // find sizes et al +VoxelsOnCartesianGrid* +AVW_Volume_to_VoxelsOnCartesianGrid(AVW_Volume const* const avw_volume, const bool flip_z) { + // find sizes et al const int size_x = avw_volume->Width; const int size_y = avw_volume->Height; const int size_z = avw_volume->Depth; - IndexRange3D range(0, size_z-1, - -(size_y/2), -(size_y/2)+size_y-1, - -(size_x/2), -(size_x/2)+size_x-1); + IndexRange3D range(0, size_z - 1, -(size_y / 2), -(size_y / 2) + size_y - 1, -(size_x / 2), -(size_x / 2) + size_x - 1); CartesianCoordinate3D voxel_size; - voxel_size.x() = - static_cast(AVW_GetNumericInfo("VoxelWidth", avw_volume->Info)); - if (voxel_size.x()==0) - { + voxel_size.x() = static_cast(AVW_GetNumericInfo("VoxelWidth", avw_volume->Info)); + if (voxel_size.x() == 0) { warning("AVW_Volume_to_VoxelsOnCartesianGrid: VoxelWidth not found or 0"); } - - voxel_size.y() = - static_cast(AVW_GetNumericInfo("VoxelHeight", avw_volume->Info)); - if (voxel_size.y()==0) - { + + voxel_size.y() = static_cast(AVW_GetNumericInfo("VoxelHeight", avw_volume->Info)); + if (voxel_size.y() == 0) { warning("AVW_Volume_to_VoxelsOnCartesianGrid: VoxelHeight not found or 0"); } - - voxel_size.z() = - static_cast(AVW_GetNumericInfo("VoxelDepth", avw_volume->Info)); - if (voxel_size.z()==0) - { + + voxel_size.z() = static_cast(AVW_GetNumericInfo("VoxelDepth", avw_volume->Info)); + if (voxel_size.z() == 0) { warning("AVW_Volume_to_VoxelsOnCartesianGrid: VoxelDepth not found or 0"); } // construct VoxelsOnCartesianGrid - VoxelsOnCartesianGrid * volume_ptr = - new VoxelsOnCartesianGrid(range, - CartesianCoordinate3D(0,0,0), - voxel_size); - - // fill in data - switch(avw_volume->DataType) - { - case AVW_SIGNED_CHAR: - { - AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, - reinterpret_cast(avw_volume->Mem), flip_z); - break; - } - case AVW_UNSIGNED_CHAR: - { - AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, - reinterpret_cast(avw_volume->Mem), flip_z); - break; - } - case AVW_UNSIGNED_SHORT: - { - AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, - reinterpret_cast(avw_volume->Mem), flip_z); - break; - } - case AVW_SIGNED_SHORT: - { - AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, - reinterpret_cast(avw_volume->Mem), flip_z); - break; - } - case AVW_UNSIGNED_INT: - { - AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, - reinterpret_cast(avw_volume->Mem), flip_z); - break; - } - case AVW_SIGNED_INT: - { - AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, - reinterpret_cast(avw_volume->Mem), flip_z); - break; - } - case AVW_FLOAT: - { - AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, - reinterpret_cast(avw_volume->Mem), flip_z); - break; - } - default: - { - warning("AVW_Volume_to_VoxelsOnCartesianGrid: unsupported data type %d\n", - avw_volume->DataType); - delete volume_ptr; - return 0; - } + VoxelsOnCartesianGrid* volume_ptr = + new VoxelsOnCartesianGrid(range, CartesianCoordinate3D(0, 0, 0), voxel_size); + + // fill in data + switch (avw_volume->DataType) { + case AVW_SIGNED_CHAR: { + AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, reinterpret_cast(avw_volume->Mem), flip_z); + break; + } + case AVW_UNSIGNED_CHAR: { + AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, reinterpret_cast(avw_volume->Mem), flip_z); + break; + } + case AVW_UNSIGNED_SHORT: { + AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, reinterpret_cast(avw_volume->Mem), flip_z); + break; + } + case AVW_SIGNED_SHORT: { + AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, reinterpret_cast(avw_volume->Mem), flip_z); + break; + } + case AVW_UNSIGNED_INT: { + AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, reinterpret_cast(avw_volume->Mem), flip_z); + break; } - + case AVW_SIGNED_INT: { + AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, reinterpret_cast(avw_volume->Mem), flip_z); + break; + } + case AVW_FLOAT: { + AVW_Volume_to_VoxelsOnCartesianGrid_help(*volume_ptr, reinterpret_cast(avw_volume->Mem), flip_z); + break; + } + default: { + warning("AVW_Volume_to_VoxelsOnCartesianGrid: unsupported data type %d\n", avw_volume->DataType); + delete volume_ptr; + return 0; + } + } + return volume_ptr; } diff --git a/src/IO/stir_ecat6.cxx b/src/IO/stir_ecat6.cxx index 4d0daf489f..47d5c5489d 100644 --- a/src/IO/stir_ecat6.cxx +++ b/src/IO/stir_ecat6.cxx @@ -2,7 +2,7 @@ \file \ingroup ECAT - \brief Implementation of routines which convert CTI things into our + \brief Implementation of routines which convert CTI things into our building blocks and vice versa. \author Kris Thielemans @@ -27,7 +27,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/IO/interfile.h" #include "stir/ExamInfo.h" #include "stir/Sinogram.h" @@ -43,17 +42,17 @@ #include "stir/IndexRange2D.h" #include "stir/utilities.h" -#include "stir/Scanner.h" +#include "stir/Scanner.h" #include "stir/ExamInfo.h" #include "stir/IO/ecat6_utils.h" #include "stir/IO/stir_ecat6.h" #ifndef STIR_ORIGINAL_ECAT6 -#include "stir/IO/stir_ecat7.h" +# include "stir/IO/stir_ecat7.h" #endif -#include "boost/cstdint.hpp" -#include "boost/static_assert.hpp" -#include "boost/scoped_array.hpp" +#include "boost/cstdint.hpp" +#include "boost/static_assert.hpp" +#include "boost/scoped_array.hpp" #include #include #include @@ -70,9 +69,7 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT6 -static void cti_data_to_float_Array(Array<2,float>&out, - char const * const buffer, const float scale_factor, int dtype); - +static void cti_data_to_float_Array(Array<2, float>& out, char const* const buffer, const float scale_factor, int dtype); /* \brief reads data from a CTI file into a Sinogram object @@ -82,205 +79,169 @@ static void cti_data_to_float_Array(Array<2,float>&out, \warning \a buffer has to be allocated with a size at least as large as the multiple of MatBLKSIZE that fits the whole sinogram (because it uses cti_wblk). */ -static void read_sinogram(Sinogram& sino_2D, - char *buffer, - FILE*fptr, - int mat_index, - int frame, int gate, int data, int bed); - -static bool is_ECAT6_file(ECAT6_Main_header& mhead, const std::string& filename) -{ - //check if it's ECAT 6 - FILE * cti_fptr=fopen(filename.c_str(), "rb"); - - if(!cti_fptr) +static void read_sinogram(Sinogram& sino_2D, char* buffer, FILE* fptr, int mat_index, int frame, int gate, int data, + int bed); + +static bool +is_ECAT6_file(ECAT6_Main_header& mhead, const std::string& filename) { + // check if it's ECAT 6 + FILE* cti_fptr = fopen(filename.c_str(), "rb"); + + if (!cti_fptr) return false; // we first need to check if the file size is large enough, due to a bug // in the LLN MATRIX library (it will only read a buffer large enough // for the data, but use 512 bytes of that buffer anyway). // we suppose that any sensible file will be larger than 2048+512 bytes - // Because of some undefined behaviour of fseek and ftell when you try to + // Because of some undefined behaviour of fseek and ftell when you try to // beyond the file size, our tests is 3 staged: // fseek, ftell, fread. All of these should work. { - int ret= fseek(cti_fptr, 2048L, SEEK_SET); - long pos=ftell(cti_fptr); - if (ret || pos != 2048L) - { - // not enough bytes, so not ECAT6 - fclose(cti_fptr); - return false; - } - - char buffer[512]; - ret=fread(buffer,1, 512, cti_fptr); - if (ret != 512) - { - // failure to read - fclose(cti_fptr); - return false; - } - } - // seek back to start - fseek(cti_fptr, 0L, SEEK_SET); - - if(cti_read_ECAT6_Main_header(cti_fptr, &mhead)!=EXIT_SUCCESS) - { - // this is funny as it's just reading a bunch of bytes. anyway. we'll assume it isn't ECAT6 + int ret = fseek(cti_fptr, 2048L, SEEK_SET); + long pos = ftell(cti_fptr); + if (ret || pos != 2048L) { + // not enough bytes, so not ECAT6 fclose(cti_fptr); return false; } - else - { + + char buffer[512]; + ret = fread(buffer, 1, 512, cti_fptr); + if (ret != 512) { + // failure to read fclose(cti_fptr); - // do some checks on the main header - return - mhead.sw_version>=0 && mhead.sw_version<=69 && - ( mhead.file_type == matScanFile || - mhead.file_type == matImageFile || - mhead.file_type == matAttenFile || - mhead.file_type == matNormFile) && - mhead.num_frames>0; + return false; } + } + // seek back to start + fseek(cti_fptr, 0L, SEEK_SET); + + if (cti_read_ECAT6_Main_header(cti_fptr, &mhead) != EXIT_SUCCESS) { + // this is funny as it's just reading a bunch of bytes. anyway. we'll assume it isn't ECAT6 + fclose(cti_fptr); + return false; + } else { + fclose(cti_fptr); + // do some checks on the main header + return mhead.sw_version >= 0 && mhead.sw_version <= 69 && + (mhead.file_type == matScanFile || mhead.file_type == matImageFile || mhead.file_type == matAttenFile || + mhead.file_type == matNormFile) && + mhead.num_frames > 0; + } } - -bool is_ECAT6_file(const std::string& filename) -{ +bool +is_ECAT6_file(const std::string& filename) { ECAT6_Main_header mhead; return is_ECAT6_file(mhead, filename); } -bool is_ECAT6_image_file(const std::string& filename) -{ +bool +is_ECAT6_image_file(const std::string& filename) { ECAT6_Main_header mhead; - return is_ECAT6_file(mhead, filename) && - mhead.file_type ==matImageFile; + return is_ECAT6_file(mhead, filename) && mhead.file_type == matImageFile; } - -bool is_ECAT6_emission_file(const std::string& filename) -{ +bool +is_ECAT6_emission_file(const std::string& filename) { ECAT6_Main_header mhead; - return is_ECAT6_file(mhead, filename) && - mhead.file_type ==matScanFile; + return is_ECAT6_file(mhead, filename) && mhead.file_type == matScanFile; } - -bool is_ECAT6_attenuation_file(const std::string& filename) -{ +bool +is_ECAT6_attenuation_file(const std::string& filename) { ECAT6_Main_header mhead; - return is_ECAT6_file(mhead, filename) && - mhead.file_type ==matAttenFile; + return is_ECAT6_file(mhead, filename) && mhead.file_type == matAttenFile; } - - -Scanner* find_scanner_from_ECAT6_Main_header(const ECAT6_Main_header& mhead) -{ +Scanner* +find_scanner_from_ECAT6_Main_header(const ECAT6_Main_header& mhead) { // we could do more effort here by checking some values of other fields than system_type. // TODO - - Scanner * scanner_ptr = - find_scanner_from_ECAT_system_type(mhead.system_type); + Scanner* scanner_ptr = find_scanner_from_ECAT_system_type(mhead.system_type); return scanner_ptr; } -void make_ECAT6_Main_header(ECAT6_Main_header& mhead, - Scanner const& scanner, - const std::string& orig_name, - ExamInfo const& exam_info - ) -{ +void +make_ECAT6_Main_header(ECAT6_Main_header& mhead, Scanner const& scanner, const std::string& orig_name, + ExamInfo const& exam_info) { #ifndef STIR_ORIGINAL_ECAT6 ecat::ecat7::make_ECAT7_main_header(mhead, scanner, orig_name, exam_info); strcpy(mhead.magic_number, "MATRIX6.4"); - mhead.sw_version= 64; + mhead.sw_version = 64; #else warning("Exam_info currently ignored when creating an ECAT6 file"); - mhead= main_zero_fill(); + mhead = main_zero_fill(); mhead.calibration_factor = 1.F; - + // other header parameters - + strncpy(mhead.original_file_name, orig_name.c_str(), 20); - mhead.num_frames= 1; //hdr.num_time_frames; + mhead.num_frames = 1; // hdr.num_time_frames; // cti_utils routines always write data as VAX short - mhead.data_type= ECAT_I2_little_endian_data_type; - - mhead.system_type= find_ECAT_system_type(scanner); - mhead.axial_fov= scanner.get_num_rings()*scanner.get_ring_spacing()/10; - mhead.transaxial_fov= scanner.get_default_num_arccorrected_bins()*scanner.get_default_bin_size()/10; - - mhead.plane_separation= scanner.get_ring_spacing()/2/10; - //WRONG mhead.gantry_tilt= scanner.get_default_intrinsic_tilt(); + mhead.data_type = ECAT_I2_little_endian_data_type; + + mhead.system_type = find_ECAT_system_type(scanner); + mhead.axial_fov = scanner.get_num_rings() * scanner.get_ring_spacing() / 10; + mhead.transaxial_fov = scanner.get_default_num_arccorrected_bins() * scanner.get_default_bin_size() / 10; + + mhead.plane_separation = scanner.get_ring_spacing() / 2 / 10; + // WRONG mhead.gantry_tilt= scanner.get_default_intrinsic_tilt(); #endif // STIR_ORIGINAL_ECAT6 } -void make_ECAT6_Main_header(ECAT6_Main_header& mhead, - Scanner const& scanner, - const std::string& orig_name, - DiscretisedDensity<3,float> const & density - ) -{ +void +make_ECAT6_Main_header(ECAT6_Main_header& mhead, Scanner const& scanner, const std::string& orig_name, + DiscretisedDensity<3, float> const& density) { make_ECAT6_Main_header(mhead, scanner, orig_name, density.get_exam_info()); - - DiscretisedDensityOnCartesianGrid<3,float> const & image = - dynamic_cast const&>(density); - + DiscretisedDensityOnCartesianGrid<3, float> const& image = + dynamic_cast const&>(density); + // extra main parameters that depend on data type - mhead.file_type= matImageFile; - mhead.num_planes=image.get_length(); - mhead.plane_separation=image.get_grid_spacing()[1]/10; // convert to cm + mhead.file_type = matImageFile; + mhead.num_planes = image.get_length(); + mhead.plane_separation = image.get_grid_spacing()[1] / 10; // convert to cm } -void make_ECAT6_Main_header(ECAT6_Main_header& mhead, - const std::string& orig_name, - ProjDataInfo const & proj_data_info - ) -{ +void +make_ECAT6_Main_header(ECAT6_Main_header& mhead, const std::string& orig_name, ProjDataInfo const& proj_data_info) { warning("Exam_info currently ignored when creating an ECAT6 raw-data file"); ExamInfo dummy_exam_info; make_ECAT6_Main_header(mhead, *proj_data_info.get_scanner_sptr(), orig_name, dummy_exam_info); - + // extra main parameters that depend on data type - mhead.file_type= matScanFile; - + mhead.file_type = matScanFile; + mhead.num_planes = 0; - for(int segment_num=proj_data_info.get_min_segment_num(); - segment_num <= proj_data_info.get_max_segment_num(); - ++segment_num) - mhead.num_planes+= proj_data_info.get_num_axial_poss(segment_num); - - mhead.plane_separation=proj_data_info.get_scanner_sptr()->get_ring_spacing()/10/2; + for (int segment_num = proj_data_info.get_min_segment_num(); segment_num <= proj_data_info.get_max_segment_num(); ++segment_num) + mhead.num_planes += proj_data_info.get_num_axial_poss(segment_num); + + mhead.plane_separation = proj_data_info.get_scanner_sptr()->get_ring_spacing() / 10 / 2; } -VoxelsOnCartesianGrid * -ECAT6_to_VoxelsOnCartesianGrid(const int frame_num, const int gate_num, const int data_num, const int bed_num, - FILE *cti_fptr, const ECAT6_Main_header & mhead) -{ +VoxelsOnCartesianGrid* +ECAT6_to_VoxelsOnCartesianGrid(const int frame_num, const int gate_num, const int data_num, const int bed_num, FILE* cti_fptr, + const ECAT6_Main_header& mhead) { MatDir entry; Image_subheader ihead; + VoxelsOnCartesianGrid* image_ptr = 0; - VoxelsOnCartesianGrid * image_ptr = 0; - // read first subheader to find dimensions { - long matnum = cti_numcod(frame_num, 1,gate_num, data_num, bed_num); - - if(!cti_lookup(cti_fptr, &mhead, matnum, &entry)) { // get entry - error("\nCouldn't find matnum %d in specified file.\n", matnum); + long matnum = cti_numcod(frame_num, 1, gate_num, data_num, bed_num); + + if (!cti_lookup(cti_fptr, &mhead, matnum, &entry)) { // get entry + error("\nCouldn't find matnum %d in specified file.\n", matnum); + } + if (cti_read_image_subheader(cti_fptr, &mhead, entry.strtblk, &ihead) != EXIT_SUCCESS) { + error("\nUnable to look up image subheader\n"); } - if(cti_read_image_subheader(cti_fptr, &mhead, entry.strtblk, &ihead)!=EXIT_SUCCESS) - { - error("\nUnable to look up image subheader\n"); - } } - + #ifndef STIR_ORIGINAL_ECAT6 const int x_size = ihead.x_dimension; const int y_size = ihead.y_dimension; @@ -289,71 +250,63 @@ ECAT6_to_VoxelsOnCartesianGrid(const int frame_num, const int gate_num, const in const int y_size = ihead.dimension_2; #endif const int z_size = mhead.num_planes; - const int min_z = 0; - - IndexRange3D range_3D (0,z_size-1, - -y_size/2,(-y_size/2)+y_size-1, - -x_size/2,(-x_size/2)+x_size-1); - + const int min_z = 0; + + IndexRange3D range_3D(0, z_size - 1, -y_size / 2, (-y_size / 2) + y_size - 1, -x_size / 2, (-x_size / 2) + x_size - 1); + #ifndef STIR_ORIGINAL_ECAT6 - CartesianCoordinate3D - voxel_size(ihead.z_pixel_size*10,ihead.y_pixel_size*10,ihead.x_pixel_size*10); - CartesianCoordinate3D - origin(ihead.z_offset, ihead.y_offset*10, ihead.x_offset*10); + CartesianCoordinate3D voxel_size(ihead.z_pixel_size * 10, ihead.y_pixel_size * 10, ihead.x_pixel_size * 10); + CartesianCoordinate3D origin(ihead.z_offset, ihead.y_offset * 10, ihead.x_offset * 10); #else - CartesianCoordinate3D - voxel_size(ihead.slice_width*10,ihead.pixel_size*10,ihead.pixel_size*10); - CartesianCoordinate3D - origin(0, ihead.y_origin*10, ihead.x_origin*10); + CartesianCoordinate3D voxel_size(ihead.slice_width * 10, ihead.pixel_size * 10, ihead.pixel_size * 10); + CartesianCoordinate3D origin(0, ihead.y_origin * 10, ihead.x_origin * 10); #endif - - - image_ptr = new VoxelsOnCartesianGrid (range_3D, origin, voxel_size); - + + image_ptr = new VoxelsOnCartesianGrid(range_3D, origin, voxel_size); + NumericType type; ByteOrder byte_order; find_type_from_ECAT_data_type(type, byte_order, ihead.data_type); - // allocation for buffer. Provide enough space for a multiple of MatBLKSIZE - const size_t cti_data_size = x_size*y_size*type.size_in_bytes()+ MatBLKSIZE; - char * cti_data= new char[cti_data_size]; - - for(int z=0; z sub_head_origin(ihead.z_offset, ihead.y_offset*10, ihead.x_offset*10); -#else // STIR_ORIGINAL_ECAT6 - const CartesianCoordinate3D sub_head_origin(0, ihead.y_origin*10, ihead.x_origin*10); + const CartesianCoordinate3D sub_head_origin(ihead.z_offset, ihead.y_offset * 10, ihead.x_offset * 10); +#else // STIR_ORIGINAL_ECAT6 + const CartesianCoordinate3D sub_head_origin(0, ihead.y_origin * 10, ihead.x_origin * 10); #endif // STIR_ORIGINAL_ECAT6 - { - if (norm(image_ptr->get_origin() - sub_head_origin) > .01F) - { - warning("ECAT6_to_VoxelsOnCartesianGrid: x,y offset in subheader of plane %d does not agree with plane 1. Ignoring it...\n", - z+1); - } + { + if (norm(image_ptr->get_origin() - sub_head_origin) > .01F) { + warning( + "ECAT6_to_VoxelsOnCartesianGrid: x,y offset in subheader of plane %d does not agree with plane 1. Ignoring it...\n", + z + 1); } + } #ifndef STIR_ORIGINAL_ECAT6 - float scale_factor = ihead.scale_factor; + float scale_factor = ihead.scale_factor; #else // STIR_ORIGINAL_ECAT6 - float scale_factor = ihead.quant_scale; + float scale_factor = ihead.quant_scale; #endif - if(cti_rblk (cti_fptr, entry.strtblk+1, cti_data, entry.endblk-entry.strtblk)!=EXIT_SUCCESS) { // get data - error("\nUnable to read data\n"); - } - if (file_data_to_host(cti_data, entry.endblk-entry.strtblk, ihead.data_type)!=EXIT_SUCCESS) - error("\nerror converting to host data format\n"); - cti_data_to_float_Array((*image_ptr)[z+min_z],cti_data, scale_factor, ihead.data_type); + if (cti_rblk(cti_fptr, entry.strtblk + 1, cti_data, entry.endblk - entry.strtblk) != EXIT_SUCCESS) { // get data + error("\nUnable to read data\n"); + } + if (file_data_to_host(cti_data, entry.endblk - entry.strtblk, ihead.data_type) != EXIT_SUCCESS) + error("\nerror converting to host data format\n"); + cti_data_to_float_Array((*image_ptr)[z + min_z], cti_data, scale_factor, ihead.data_type); #if 0 NumericType type; ByteOrder byte_order; @@ -365,134 +318,112 @@ ECAT6_to_VoxelsOnCartesianGrid(const int frame_num, const int gate_num, const in (*image_ptr)[z+min_z][y+min_y][x+min_x]=scale_factor*cti_data[y*x_size+x]; } #endif - } // end loop on planes - + } // end loop on planes + delete[] cti_data; return image_ptr; } -void ECAT6_to_PDFS(const int frame_num, const int gate_num, const int data_num, const int bed_num, - int max_ring_diff, bool arccorrected, - const std::string& data_name, FILE *cti_fptr, const ECAT6_Main_header &mhead) -{ +void +ECAT6_to_PDFS(const int frame_num, const int gate_num, const int data_num, const int bed_num, int max_ring_diff, + bool arccorrected, const std::string& data_name, FILE* cti_fptr, const ECAT6_Main_header& mhead) { shared_ptr scanner_ptr(find_scanner_from_ECAT6_Main_header(mhead)); cout << "Scanner determined from ECAT6_Main_header: " << scanner_ptr->get_name() << endl; - if (scanner_ptr->get_type() == Scanner::Unknown_scanner || - scanner_ptr->get_type() == Scanner::User_defined_scanner) - { + if (scanner_ptr->get_type() == Scanner::Unknown_scanner || scanner_ptr->get_type() == Scanner::User_defined_scanner) { warning("ECAT6_to_PDFS: Couldn't determine the scanner \n" - "(Main_header.system_type=%d), defaulting to 953.\n" - "This will give dramatic problems when the number of rings of your scanner is NOT 16.\n", - mhead.system_type); + "(Main_header.system_type=%d), defaulting to 953.\n" + "This will give dramatic problems when the number of rings of your scanner is NOT 16.\n", + mhead.system_type); scanner_ptr.reset(new Scanner(Scanner::E953)); } - const int num_rings = scanner_ptr->get_num_rings(); // ECAT 6 does not have a flag for 3D vs. 2D, so we guess it first from num_planes - bool is_3D_file = (mhead.num_planes > 2*num_rings-1); - if (!is_3D_file) - { + bool is_3D_file = (mhead.num_planes > 2 * num_rings - 1); + if (!is_3D_file) { // better make sure by checking if plane (5,5) is not in its '3D' place MatDir entry; - const int mat_index= cti_rings2plane(num_rings, 5,5); - const long matnum= cti_numcod(frame_num, mat_index,gate_num, data_num, bed_num); + const int mat_index = cti_rings2plane(num_rings, 5, 5); + const long matnum = cti_numcod(frame_num, mat_index, gate_num, data_num, bed_num); // KT 18/08/2000 add !=0 to prevent compiler warning on conversion from int to bool - is_3D_file = cti_lookup (cti_fptr, &mhead, matnum, &entry)!=0; + is_3D_file = cti_lookup(cti_fptr, &mhead, matnum, &entry) != 0; } int span = 1; - if (!is_3D_file) - { + if (!is_3D_file) { warning("I'm guessing this is a stack of 2D sinograms\n"); - if(mhead.num_planes == 2*num_rings-1) - { - span=3; + if (mhead.num_planes == 2 * num_rings - 1) { + span = 3; max_ring_diff = 1; - } - else if (mhead.num_planes == num_rings) - { - span=1; + } else if (mhead.num_planes == num_rings) { + span = 1; max_ring_diff = 0; - } - else - { + } else { error("Impossible num_planes: %d\n", mhead.num_planes); } - } - else - { - if (max_ring_diff < 0) - max_ring_diff = num_rings-1; - const int num_sinos = - (2*max_ring_diff+1) * num_rings - (max_ring_diff+1)*max_ring_diff; - + } else { + if (max_ring_diff < 0) + max_ring_diff = num_rings - 1; + const int num_sinos = (2 * max_ring_diff + 1) * num_rings - (max_ring_diff + 1) * max_ring_diff; + if (num_sinos > mhead.num_planes) - warning("\n\aWarning: header says not enough planes in the file: %d (expected %d)." - "Continuing anyway...", mhead.num_planes, num_sinos); + warning("\n\aWarning: header says not enough planes in the file: %d (expected %d)." + "Continuing anyway...", + mhead.num_planes, num_sinos); } - + // construct a ProjDataFromStream object - shared_ptr proj_data; + shared_ptr proj_data; ScanInfoRec scanParams; - { + { // read first subheader for dimensions - { + { // use temporary copy to avoid overwriting mhead argument ECAT6_Main_header mhead_copy; - long matnum= cti_numcod(frame_num, 1,gate_num, data_num, bed_num); - switch(mhead.file_type) - { - case matScanFile: - { - Scan_subheader shead; - if (get_scanheaders(cti_fptr, matnum, &mhead_copy, &shead, &scanParams)!= EXIT_SUCCESS) - error("Error reading matnum %d\n", matnum); - break; - } - case matAttenFile: - { - Attn_subheader shead; - if(get_attnheaders (cti_fptr, matnum, &mhead_copy, - &shead, &scanParams)!= EXIT_SUCCESS) - error("Error reading matnum %d\n", matnum); - break; - } - case matNormFile: - { - Norm_subheader shead; - if(get_normheaders (cti_fptr, matnum, &mhead_copy, - &shead, &scanParams)!= EXIT_SUCCESS) - error("Error reading matnum %d\n", matnum); - break; - } - + long matnum = cti_numcod(frame_num, 1, gate_num, data_num, bed_num); + switch (mhead.file_type) { + case matScanFile: { + Scan_subheader shead; + if (get_scanheaders(cti_fptr, matnum, &mhead_copy, &shead, &scanParams) != EXIT_SUCCESS) + error("Error reading matnum %d\n", matnum); + break; + } + case matAttenFile: { + Attn_subheader shead; + if (get_attnheaders(cti_fptr, matnum, &mhead_copy, &shead, &scanParams) != EXIT_SUCCESS) + error("Error reading matnum %d\n", matnum); + break; + } + case matNormFile: { + Norm_subheader shead; + if (get_normheaders(cti_fptr, matnum, &mhead_copy, &shead, &scanParams) != EXIT_SUCCESS) + error("Error reading matnum %d\n", matnum); + break; + } + default: - error("ECAT6_to_PDFS: unsupported file type %d\n",mhead.file_type); + error("ECAT6_to_PDFS: unsupported file type %d\n", mhead.file_type); } } const int num_views = scanParams.nviews; - const int num_tangential_poss = scanParams.nprojs; - - + const int num_tangential_poss = scanParams.nprojs; + shared_ptr p_data_info( - ProjDataInfo::ProjDataInfoCTI(scanner_ptr,span,max_ring_diff,num_views,num_tangential_poss,arccorrected)); - - - ProjDataFromStream::StorageOrder storage_order= - ProjDataFromStream::Segment_AxialPos_View_TangPos; - + ProjDataInfo::ProjDataInfoCTI(scanner_ptr, span, max_ring_diff, num_views, num_tangential_poss, arccorrected)); + + ProjDataFromStream::StorageOrder storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; + #if 1 - std::string actual_data_name=data_name; + std::string actual_data_name = data_name; { - std::string::size_type pos=find_pos_of_extension(data_name); - if (pos!=std::string::npos && data_name.substr(pos)==".hs") - replace_extension(actual_data_name, ".s"); + std::string::size_type pos = find_pos_of_extension(data_name); + if (pos != std::string::npos && data_name.substr(pos) == ".hs") + replace_extension(actual_data_name, ".s"); else - add_extension(actual_data_name, ".s"); + add_extension(actual_data_name, ".s"); } #else // TODO replace these char* things with string based extension stuff @@ -500,582 +431,481 @@ void ECAT6_to_PDFS(const int frame_num, const int gate_num, const int data_num, strcpy(actual_data_name.get(), data_name.c_str()); // KT 30/05/2002 make sure that a filename ending on .hs is treated correctly { - const char * const extension = strchr(find_filename(actual_data_name.get()),'.'); - if (extension!=NULL && strcmp(extension, ".hs")==0) + const char* const extension = strchr(find_filename(actual_data_name.get()), '.'); + if (extension != NULL && strcmp(extension, ".hs") == 0) replace_extension(actual_data_name.get(), ".s"); else add_extension(actual_data_name.get(), ".s"); } #endif - shared_ptr sino_stream( - new fstream (actual_data_name.c_str(), ios::out| ios::binary)); - - if (!sino_stream->good()) - { - error("ECAT6cti_to_PDFS: error opening file %s\n",actual_data_name.c_str()); + shared_ptr sino_stream(new fstream(actual_data_name.c_str(), ios::out | ios::binary)); + + if (!sino_stream->good()) { + error("ECAT6cti_to_PDFS: error opening file %s\n", actual_data_name.c_str()); } - + shared_ptr exam_info_sptr(new ExamInfo); - proj_data.reset( - new ProjDataFromStream(exam_info_sptr,p_data_info,sino_stream, std::streamoff(0), storage_order)); - + proj_data.reset(new ProjDataFromStream(exam_info_sptr, p_data_info, sino_stream, std::streamoff(0), storage_order)); + write_basic_interfile_PDFS_header(actual_data_name, *proj_data); } - // write to proj_data { NumericType type; ByteOrder byte_order; find_type_from_ECAT_data_type(type, byte_order, scanParams.data_type); - // allocation for buffer. Provide enough space for a multiple of MatBLKSIZE - const size_t cti_data_size = - proj_data->get_num_tangential_poss()*proj_data->get_num_views()*type.size_in_bytes()+ MatBLKSIZE; - //use scoped_array to auto-delete the memory + // allocation for buffer. Provide enough space for a multiple of MatBLKSIZE + const size_t cti_data_size = + proj_data->get_num_tangential_poss() * proj_data->get_num_views() * type.size_in_bytes() + MatBLKSIZE; + // use scoped_array to auto-delete the memory boost::scoped_array cti_data_sptr(new char[cti_data_size]); - char * cti_data= cti_data_sptr.get(); - - cout<<"\nProcessing segment number:"; - - if (is_3D_file) - { - for(int w=0; w<=max_ring_diff; w++) - { // loop on segment number - + char* cti_data = cti_data_sptr.get(); + + cout << "\nProcessing segment number:"; + + if (is_3D_file) { + for (int w = 0; w <= max_ring_diff; w++) { // loop on segment number + // positive ring difference - cout<<" "< sino_2D = proj_data->get_empty_sinogram(ring1,w); - //TODO remove as will be set below - proj_data->set_sinogram(sino_2D); - read_sinogram(sino_2D, cti_data, cti_fptr, mat_index, - frame_num, gate_num, data_num, bed_num); - proj_data->set_sinogram(sino_2D); + cout << " " << w; + int num_axial_poss = num_rings - w; + + for (int ring1 = 0; ring1 < num_axial_poss; ring1++) { // ring order: 0-0,1-1,..,15-15 then 0-1,1-2,..,14-15 + int ring2 = ring1 + w; // ring1<=ring2 + int mat_index = cti_rings2plane(num_rings, ring1, ring2); + Sinogram sino_2D = proj_data->get_empty_sinogram(ring1, w); + // TODO remove as will be set below + proj_data->set_sinogram(sino_2D); + read_sinogram(sino_2D, cti_data, cti_fptr, mat_index, frame_num, gate_num, data_num, bed_num); + proj_data->set_sinogram(sino_2D); } - + // negative ring difference - if(w>0) { - cout<<" "<<-w; - for(int ring2=0; ring2ring2 - int mat_index= cti_rings2plane(num_rings, ring1, ring2); - Sinogram sino_2D = proj_data->get_empty_sinogram(ring2,-w,false); - read_sinogram(sino_2D, cti_data, - cti_fptr, mat_index, - frame_num, gate_num, data_num, bed_num); - - proj_data->set_sinogram(sino_2D); + if (w > 0) { + cout << " " << -w; + for (int ring2 = 0; ring2 < num_axial_poss; ring2++) { // ring order: 0-1,2-1,..,15-14 then 2-0,3-1,..,15-13 + int ring1 = ring2 + w; // ring1>ring2 + int mat_index = cti_rings2plane(num_rings, ring1, ring2); + Sinogram sino_2D = proj_data->get_empty_sinogram(ring2, -w, false); + read_sinogram(sino_2D, cti_data, cti_fptr, mat_index, frame_num, gate_num, data_num, bed_num); + + proj_data->set_sinogram(sino_2D); } } } // end of loop on segment number - } // end of 3D case - else - { + } // end of 3D case + else { // 2D case cout << "0\n"; - for(int z=0; zget_num_axial_poss(0); z++) - { - Sinogram sino_2D = proj_data->get_empty_sinogram(z,0,false); - read_sinogram(sino_2D, cti_data, cti_fptr, z+1, - frame_num, gate_num, data_num, bed_num); - proj_data->set_sinogram(sino_2D); + for (int z = 0; z < proj_data->get_num_axial_poss(0); z++) { + Sinogram sino_2D = proj_data->get_empty_sinogram(z, 0, false); + read_sinogram(sino_2D, cti_data, cti_fptr, z + 1, frame_num, gate_num, data_num, bed_num); + proj_data->set_sinogram(sino_2D); } - + } // end of 2D case - - cout<& sino_2D, - char *buffer, - FILE*fptr, - int mat_index, - int frame, int gate, int data, int bed) -{ +void +read_sinogram(Sinogram& sino_2D, char* buffer, FILE* fptr, int mat_index, int frame, int gate, int data, int bed) { ECAT6_Main_header mhead; ScanInfoRec scanParams; - const long matnum= - cti_numcod (frame,mat_index,gate,data,bed); - if (cti_read_ECAT6_Main_header (fptr, &mhead) != EXIT_SUCCESS) + const long matnum = cti_numcod(frame, mat_index, gate, data, bed); + if (cti_read_ECAT6_Main_header(fptr, &mhead) != EXIT_SUCCESS) error("read_sinogram: error reading ECAT6_Main_header"); - + float scale_factor = 0; // intialised to avoid compiler warnings - switch(mhead.file_type) - { - case matScanFile: - { - Scan_subheader shead; - - if(get_scanheaders (fptr, matnum, &mhead, - &shead, &scanParams)!= EXIT_SUCCESS) - error("Error reading matnum %d\n", matnum); - - scale_factor = shead.scale_factor; - if (shead.loss_correction_fctr>0) - scale_factor *= shead.loss_correction_fctr; - else - warning("\nread_sinogram warning: loss_correction_fctr invalid, using 1\n"); - break; - } - case matAttenFile: - { - Attn_subheader shead; - - if(get_attnheaders (fptr, matnum, &mhead, - &shead, &scanParams)!= EXIT_SUCCESS) - error("Error reading matnum %d\n", matnum); - - scale_factor = shead.scale_factor; - break; - } - case matNormFile: - { - Norm_subheader shead; - - if(get_normheaders (fptr, matnum, &mhead, - &shead, &scanParams)!= EXIT_SUCCESS) - error("Error reading matnum %d\n", matnum); - - scale_factor = shead.scale_factor; - break; - } - default: - error("read_sinogram: unsupported format"); + switch (mhead.file_type) { + case matScanFile: { + Scan_subheader shead; + + if (get_scanheaders(fptr, matnum, &mhead, &shead, &scanParams) != EXIT_SUCCESS) + error("Error reading matnum %d\n", matnum); + + scale_factor = shead.scale_factor; + if (shead.loss_correction_fctr > 0) + scale_factor *= shead.loss_correction_fctr; + else + warning("\nread_sinogram warning: loss_correction_fctr invalid, using 1\n"); + break; } - if(get_scandata (fptr, buffer, &scanParams)!= EXIT_SUCCESS) - error("Error reading matnum %d\n", matnum); + case matAttenFile: { + Attn_subheader shead; - cti_data_to_float_Array(sino_2D, buffer, scale_factor, scanParams.data_type); + if (get_attnheaders(fptr, matnum, &mhead, &shead, &scanParams) != EXIT_SUCCESS) + error("Error reading matnum %d\n", matnum); -} + scale_factor = shead.scale_factor; + break; + } + case matNormFile: { + Norm_subheader shead; + + if (get_normheaders(fptr, matnum, &mhead, &shead, &scanParams) != EXIT_SUCCESS) + error("Error reading matnum %d\n", matnum); + scale_factor = shead.scale_factor; + break; + } + default: + error("read_sinogram: unsupported format"); + } + if (get_scandata(fptr, buffer, &scanParams) != EXIT_SUCCESS) + error("Error reading matnum %d\n", matnum); -Succeeded -DiscretisedDensity_to_ECAT6(FILE *fptr, - DiscretisedDensity<3,float> const & density, - const ECAT6_Main_header& mhead, - const int frame_num, const int gate_num, const int data_num, const int bed_num) -{ - + cti_data_to_float_Array(sino_2D, buffer, scale_factor, scanParams.data_type); +} - DiscretisedDensityOnCartesianGrid<3,float> const & image = - dynamic_cast const&>(density); +Succeeded +DiscretisedDensity_to_ECAT6(FILE* fptr, DiscretisedDensity<3, float> const& density, const ECAT6_Main_header& mhead, + const int frame_num, const int gate_num, const int data_num, const int bed_num) { - - if (mhead.file_type!= matImageFile) - { + DiscretisedDensityOnCartesianGrid<3, float> const& image = + dynamic_cast const&>(density); + + if (mhead.file_type != matImageFile) { warning("DiscretisedDensity_to_ECAT6: converting (f%d, g%d, d%d, b%d)\n" "Main header.file_type should be ImageFile\n", frame_num, gate_num, data_num, bed_num); return Succeeded::no; } - if (mhead.num_planes!=image.get_length()) - { + if (mhead.num_planes != image.get_length()) { warning("DiscretisedDensity_to_ECAT6: converting (f%d, g%d, d%d, b%d)\n" "Main header.num_planes should be %d\n", - frame_num, gate_num, data_num, bed_num,image.get_length()); + frame_num, gate_num, data_num, bed_num, image.get_length()); return Succeeded::no; } - const float voxel_size_z = image.get_grid_spacing()[1]/10;// convert to cm - //const float voxel_size_y = image.get_grid_spacing()[2]/10; - const float voxel_size_x = image.get_grid_spacing()[3]/10; - if (fabs(mhead.plane_separation - voxel_size_z) > 1.E-4) - { + const float voxel_size_z = image.get_grid_spacing()[1] / 10; // convert to cm + // const float voxel_size_y = image.get_grid_spacing()[2]/10; + const float voxel_size_x = image.get_grid_spacing()[3] / 10; + if (fabs(mhead.plane_separation - voxel_size_z) > 1.E-4) { warning("DiscretisedDensity_to_ECAT6: converting (f%d, g%d, d%d, b%d)\n" "Main header.plane_separation should be %g\n", - frame_num, gate_num, data_num, bed_num,voxel_size_z); + frame_num, gate_num, data_num, bed_num, voxel_size_z); return Succeeded::no; } - - - Image_subheader ihead= img_zero_fill(); - - const int min_z= image.get_min_index(); - const int min_y= image[min_z].get_min_index(); - const int min_x= image[min_z][min_y].get_min_index(); - - const int z_size= image.get_length(); - const int y_size= image[min_z].get_length(); - const int x_size= image[min_z][min_y].get_length(); - - const int plane_size= y_size * x_size; - + + Image_subheader ihead = img_zero_fill(); + + const int min_z = image.get_min_index(); + const int min_y = image[min_z].get_min_index(); + const int min_x = image[min_z][min_y].get_min_index(); + + const int z_size = image.get_length(); + const int y_size = image[min_z].get_length(); + const int x_size = image[min_z][min_y].get_length(); + + const int plane_size = y_size * x_size; + // Setup subheader params #ifndef STIR_ORIGINAL_ECAT6 - ihead.data_type=ECAT_I2_little_endian_data_type; - ihead.x_dimension= x_size; - ihead.y_dimension= y_size; - ihead.z_dimension= z_size; - ihead.x_pixel_size= voxel_size_x; - ihead.y_pixel_size= voxel_size_x; - ihead.z_pixel_size= voxel_size_z; - - ihead.num_dimensions= 3; + ihead.data_type = ECAT_I2_little_endian_data_type; + ihead.x_dimension = x_size; + ihead.y_dimension = y_size; + ihead.z_dimension = z_size; + ihead.x_pixel_size = voxel_size_x; + ihead.y_pixel_size = voxel_size_x; + ihead.z_pixel_size = voxel_size_z; + + ihead.num_dimensions = 3; // STIR origin depends on the index range, but the index range is lost // after writing to file. // ECAT6 origin is somewhere in the middle of the image // WARNING this has to be consistent with reading - if (image[0][0].get_min_index() != -(x_size/2) || - image[0][0].get_max_index() != -(x_size/2) + x_size - 1 || - image[0].get_min_index() != -(y_size/2) || - image[0].get_max_index() != -(y_size/2) + y_size - 1 || - image.get_min_index() != 0) - { - warning("DiscretisedDensity_to_ECAT6 is currently limited to input images in the standard STIR index range.\n" - "Data not written."); - return Succeeded::no; - } - ihead.x_offset= image.get_origin().x()/10; - ihead.y_offset= image.get_origin().y()/10; - ihead.z_offset= image.get_origin().z()/10; + if (image[0][0].get_min_index() != -(x_size / 2) || image[0][0].get_max_index() != -(x_size / 2) + x_size - 1 || + image[0].get_min_index() != -(y_size / 2) || image[0].get_max_index() != -(y_size / 2) + y_size - 1 || + image.get_min_index() != 0) { + warning("DiscretisedDensity_to_ECAT6 is currently limited to input images in the standard STIR index range.\n" + "Data not written."); + return Succeeded::no; + } + ihead.x_offset = image.get_origin().x() / 10; + ihead.y_offset = image.get_origin().y() / 10; + ihead.z_offset = image.get_origin().z() / 10; shared_ptr scanner_ptr(find_scanner_from_ECAT6_Main_header(mhead)); const float depth_of_interaction_factor = - 1 + - scanner_ptr->get_average_depth_of_interaction() / - scanner_ptr->get_inner_ring_radius(); + 1 + scanner_ptr->get_average_depth_of_interaction() / scanner_ptr->get_inner_ring_radius(); // note: CTI uses shead.x_resolution instead of mhead.bin_size - // but we don't have access to the sinogram here, and these 2 fields + // but we don't have access to the sinogram here, and these 2 fields // should be equal anyway. - ihead.recon_zoom= - mhead.bin_size/voxel_size_x * - scanner_ptr->get_default_num_arccorrected_bins()/ - float(image[0].size()) * - depth_of_interaction_factor; - - ihead.decay_corr_fctr= 1; -#else // STIR_ORIGINAL_ECAT6 - ihead.data_type= mhead.data_type; - ihead.dimension_1= x_size; - ihead.dimension_2= y_size; - ihead.slice_width= mhead.plane_separation; - ihead.pixel_size= voxel_size_x; - - ihead.num_dimensions= 2; - ihead.x_origin= image.get_origin().x()/10; - ihead.y_origin= image.get_origin().y()/10; - ihead.recon_scale= 1; - ihead.decay_corr_fctr= 1; - ihead.loss_corr_fctr= 1; - ihead.ecat_calibration_fctr= 1; - ihead.well_counter_cal_fctr=1; + ihead.recon_zoom = mhead.bin_size / voxel_size_x * scanner_ptr->get_default_num_arccorrected_bins() / float(image[0].size()) * + depth_of_interaction_factor; + + ihead.decay_corr_fctr = 1; +#else // STIR_ORIGINAL_ECAT6 + ihead.data_type = mhead.data_type; + ihead.dimension_1 = x_size; + ihead.dimension_2 = y_size; + ihead.slice_width = mhead.plane_separation; + ihead.pixel_size = voxel_size_x; + + ihead.num_dimensions = 2; + ihead.x_origin = image.get_origin().x() / 10; + ihead.y_origin = image.get_origin().y() / 10; + ihead.recon_scale = 1; + ihead.decay_corr_fctr = 1; + ihead.loss_corr_fctr = 1; + ihead.ecat_calibration_fctr = 1; + ihead.well_counter_cal_fctr = 1; #endif // STIR_ORIGINAL_ECAT6 - + // make sure we have a large enough multiple of MatBLKSIZE - int cti_data_size = plane_size*2; - if (cti_data_size%MatBLKSIZE != 0) - cti_data_size = ((cti_data_size/MatBLKSIZE)+1)*MatBLKSIZE; - short *cti_data= new short[cti_data_size/2]; - Array<2,short> plane(image[min_z].get_index_range()); - - for(int z=0; z plane(image[min_z].get_index_range()); + + for (int z = 0; z < z_size; z++) { // loop on planes float scale_factor = 0; - convert_array(plane, scale_factor, image[z+min_z]); - ihead.image_min= plane.find_min(); - ihead.image_max= plane.find_max(); + convert_array(plane, scale_factor, image[z + min_z]); + ihead.image_min = plane.find_min(); + ihead.image_max = plane.find_max(); #ifndef STIR_ORIGINAL_ECAT6 - ihead.scale_factor= scale_factor==0 ? 1.F : scale_factor; + ihead.scale_factor = scale_factor == 0 ? 1.F : scale_factor; #else - ihead.quant_scale= scale_factor==0 ? 1.F : scale_factor; + ihead.quant_scale = scale_factor == 0 ? 1.F : scale_factor; #endif // STIR_ORIGINAL_ECAT6 - - for(int y=0; y const & density, - std::string const & cti_name, std::string const&orig_name, - const Scanner& scanner, - const int frame_num, const int gate_num, const int data_num, const int bed_num) -{ +Succeeded +DiscretisedDensity_to_ECAT6(DiscretisedDensity<3, float> const& density, std::string const& cti_name, + std::string const& orig_name, const Scanner& scanner, const int frame_num, const int gate_num, + const int data_num, const int bed_num) { ECAT6_Main_header mhead; make_ECAT6_Main_header(mhead, scanner, orig_name, density); - - FILE *fptr= cti_create (cti_name.c_str(), &mhead); - Succeeded result = - DiscretisedDensity_to_ECAT6(fptr, - density, - mhead, - frame_num, gate_num,data_num, bed_num); - - fclose(fptr); + FILE* fptr = cti_create(cti_name.c_str(), &mhead); + Succeeded result = DiscretisedDensity_to_ECAT6(fptr, density, mhead, frame_num, gate_num, data_num, bed_num); + + fclose(fptr); return result; } -Succeeded -ProjData_to_ECAT6(FILE *fptr, ProjData const& proj_data, const ECAT6_Main_header& mhead, - const int frame_num, const int gate_num, const int data_num, const int bed_num, - const bool write_2D_sinograms) -{ - if (mhead.file_type!= matScanFile) - { +Succeeded +ProjData_to_ECAT6(FILE* fptr, ProjData const& proj_data, const ECAT6_Main_header& mhead, const int frame_num, const int gate_num, + const int data_num, const int bed_num, const bool write_2D_sinograms) { + if (mhead.file_type != matScanFile) { warning("ProjData_to_ECAT6: converting (f%d, g%d, d%d, b%d)\n" "Main header.file_type should be ImageFile\n", frame_num, gate_num, data_num, bed_num); return Succeeded::no; } - const int max_segment_num = - write_2D_sinograms - ? 0 - : - min(proj_data.get_max_segment_num(), -proj_data.get_min_segment_num()) -; - const int min_segment_num = - max_segment_num; + const int max_segment_num = write_2D_sinograms ? 0 : min(proj_data.get_max_segment_num(), -proj_data.get_min_segment_num()); + const int min_segment_num = -max_segment_num; { int num_planes = 0; - for(int segment_num=min_segment_num; - segment_num <= max_segment_num; - ++segment_num) - num_planes+= proj_data.get_num_axial_poss(segment_num); - - if (mhead.num_planes!=num_planes) - { - warning("ProjData_to_ECAT6: converting (f%d, g%d, d%d, b%d)\n" - "Main header.num_planes should be %d, but is %d\n", - frame_num, gate_num, data_num, bed_num,num_planes, mhead.num_planes); - if (mhead.num_planes - (proj_data.get_proj_data_info_sptr().get()); - if (proj_data_info_cyl_ptr==NULL) - { + ProjDataInfoCylindricalArcCorr const* const proj_data_info_cyl_ptr = + dynamic_cast(proj_data.get_proj_data_info_sptr().get()); + if (proj_data_info_cyl_ptr == NULL) { warning("This is not arc-corrected data. Filling in default_bin_size from scanner \n"); #ifndef STIR_ORIGINAL_ECAT6 - shead.x_resolution= + shead.x_resolution = #else - shead.sample_distance= + shead.sample_distance = #endif - proj_data.get_proj_data_info_sptr()->get_scanner_sptr()->get_default_bin_size()/10; - } - else - { + proj_data.get_proj_data_info_sptr()->get_scanner_sptr()->get_default_bin_size() / 10; + } else { #ifndef STIR_ORIGINAL_ECAT6 - shead.x_resolution= + shead.x_resolution = #else - shead.sample_distance= + shead.sample_distance = #endif - proj_data_info_cyl_ptr->get_tangential_sampling()/10; + proj_data_info_cyl_ptr->get_tangential_sampling() / 10; } } - + // find num_rings and check span int num_rings = proj_data.get_num_axial_poss(0); { - ProjDataInfoCylindrical const * const - proj_data_info_cyl_ptr = - dynamic_cast - (proj_data.get_proj_data_info_sptr().get()); - if (proj_data_info_cyl_ptr!=NULL) - { - // check if spanned data in segment 0 - if (proj_data_info_cyl_ptr->get_min_ring_difference(0) < - proj_data_info_cyl_ptr->get_max_ring_difference(0)) - { - if (write_2D_sinograms) - num_rings = (proj_data.get_num_axial_poss(0)+1)/2; - else - { - warning("Can only handle span==1 data. Exiting\n"); - return Succeeded::no; - } - } + ProjDataInfoCylindrical const* const proj_data_info_cyl_ptr = + dynamic_cast(proj_data.get_proj_data_info_sptr().get()); + if (proj_data_info_cyl_ptr != NULL) { + // check if spanned data in segment 0 + if (proj_data_info_cyl_ptr->get_min_ring_difference(0) < proj_data_info_cyl_ptr->get_max_ring_difference(0)) { + if (write_2D_sinograms) + num_rings = (proj_data.get_num_axial_poss(0) + 1) / 2; + else { + warning("Can only handle span==1 data. Exiting\n"); + return Succeeded::no; + } } + } } - - if (num_rings != proj_data.get_proj_data_info_sptr()->get_scanner_sptr()->get_num_rings()) -{ + if (num_rings != proj_data.get_proj_data_info_sptr()->get_scanner_sptr()->get_num_rings()) { warning("Expected %d num_rings from scanner while segment 0 implies %d rings\n", proj_data.get_proj_data_info_sptr()->get_scanner_sptr()->get_num_rings(), num_rings); -} - - short *cti_data= new short[plane_size]; - Array<2,short> short_sinogram(IndexRange2D(min_view,proj_data.get_max_view_num(), - min_bin,proj_data.get_max_tangential_pos_num())); - - cout< short_sinogram( + IndexRange2D(min_view, proj_data.get_max_view_num(), min_bin, proj_data.get_max_tangential_pos_num())); + + cout << endl << "Processing segment number:"; + + for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) { + cout << " " << segment_num; + + const int num_axial_poss = proj_data.get_num_axial_poss(segment_num); + const int min_axial_poss = proj_data.get_min_axial_pos_num(segment_num); + + if (!write_2D_sinograms && num_axial_poss != num_rings - abs(segment_num)) { warning("Can only handle span==1 data. Number of sinograms in this segment " - "should be %d. Exiting\n", num_rings - abs(segment_num)); + "should be %d. Exiting\n", + num_rings - abs(segment_num)); delete[] cti_data; return Succeeded::no; } - - for(int z=0; z float_sinogram= proj_data.get_sinogram(z+min_axial_poss,segment_num,false); - + + for (int z = 0; z < num_axial_poss; z++) { // loop on planes + Sinogram float_sinogram = proj_data.get_sinogram(z + min_axial_poss, segment_num, false); + float scale_factor = 0; convert_array(short_sinogram, scale_factor, float_sinogram); - - - shead.scan_min= short_sinogram.find_min(); - shead.scan_max= short_sinogram.find_max(); - shead.scale_factor= scale_factor==0 ? 1.F : scale_factor; - - for(int y=0; y=0) - { ring1= z; ring2= z+segment_num; } - else - { ring1= z+abs(segment_num); ring2= z; } - - const int indexcod= - write_2D_sinograms - ? z+1 - : cti_rings2plane( num_rings, ring1, ring2); // change indexation into CTI - const long matnum= cti_numcod(frame_num, indexcod, gate_num, data_num, bed_num); - if(cti_write_scan(fptr, matnum, &mhead, &shead, cti_data, plane_size*sizeof(short))!=EXIT_SUCCESS) - { - warning("Unable to write short_sinogram for rings %d,%d to file, exiting.\n",ring1,ring2); + if (segment_num >= 0) { + ring1 = z; + ring2 = z + segment_num; + } else { + ring1 = z + abs(segment_num); + ring2 = z; + } + + const int indexcod = write_2D_sinograms ? z + 1 : cti_rings2plane(num_rings, ring1, ring2); // change indexation into CTI + const long matnum = cti_numcod(frame_num, indexcod, gate_num, data_num, bed_num); + if (cti_write_scan(fptr, matnum, &mhead, &shead, cti_data, plane_size * sizeof(short)) != EXIT_SUCCESS) { + warning("Unable to write short_sinogram for rings %d,%d to file, exiting.\n", ring1, ring2); delete[] cti_data; return Succeeded::no; } } // end of loop on planes - } // end of loop on segments - cout<&out, - char const * const buffer, const float scale_factor, int dtype) -{ +void +cti_data_to_float_Array(Array<2, float>& out, char const* const buffer, const float scale_factor, int dtype) { - BOOST_STATIC_ASSERT(sizeof(float)==4); + BOOST_STATIC_ASSERT(sizeof(float) == 4); - switch (dtype) - { - case ECAT_Byte_data_type: - { - signed char const * cti_data = - reinterpret_cast(buffer); - for(int y=out.get_min_index(); y<=out.get_max_index(); y++) - for(int x=out[y].get_min_index(); x<=out[y].get_max_index(); x++) - out[y][x]=scale_factor*(*cti_data++); + switch (dtype) { + case ECAT_Byte_data_type: { + signed char const* cti_data = reinterpret_cast(buffer); + for (int y = out.get_min_index(); y <= out.get_max_index(); y++) + for (int x = out[y].get_min_index(); x <= out[y].get_max_index(); x++) + out[y][x] = scale_factor * (*cti_data++); break; } case ECAT_I2_little_endian_data_type: - case ECAT_I2_big_endian_data_type: - { - boost::int16_t const * cti_data = - reinterpret_cast(buffer); - for(int y=out.get_min_index(); y<=out.get_max_index(); y++) - for(int x=out[y].get_min_index(); x<=out[y].get_max_index(); x++) - out[y][x]=scale_factor*(*cti_data++); + case ECAT_I2_big_endian_data_type: { + boost::int16_t const* cti_data = reinterpret_cast(buffer); + for (int y = out.get_min_index(); y <= out.get_max_index(); y++) + for (int x = out[y].get_min_index(); x <= out[y].get_max_index(); x++) + out[y][x] = scale_factor * (*cti_data++); break; } case ECAT_I4_little_endian_data_type: - case ECAT_I4_big_endian_data_type: - { - boost::int32_t const * cti_data = - reinterpret_cast(buffer); - for(int y=out.get_min_index(); y<=out.get_max_index(); y++) - for(int x=out[y].get_min_index(); x<=out[y].get_max_index(); x++) - out[y][x]=scale_factor*(*cti_data++); + case ECAT_I4_big_endian_data_type: { + boost::int32_t const* cti_data = reinterpret_cast(buffer); + for (int y = out.get_min_index(); y <= out.get_max_index(); y++) + for (int x = out[y].get_min_index(); x <= out[y].get_max_index(); x++) + out[y][x] = scale_factor * (*cti_data++); break; } case ECAT_R4_VAX_data_type: - case ECAT_R4_IEEE_big_endian_data_type: - { - float const * cti_data = - reinterpret_cast(buffer); - for(int y=out.get_min_index(); y<=out.get_max_index(); y++) - for(int x=out[y].get_min_index(); x<=out[y].get_max_index(); x++) - out[y][x]=scale_factor*(*cti_data++); + case ECAT_R4_IEEE_big_endian_data_type: { + float const* cti_data = reinterpret_cast(buffer); + for (int y = out.get_min_index(); y <= out.get_max_index(); y++) + for (int x = out[y].get_min_index(); x <= out[y].get_max_index(); x++) + out[y][x] = scale_factor * (*cti_data++); break; } } diff --git a/src/IO/stir_ecat7.cxx b/src/IO/stir_ecat7.cxx index f8ad79f12f..721d1c2bbc 100644 --- a/src/IO/stir_ecat7.cxx +++ b/src/IO/stir_ecat7.cxx @@ -19,20 +19,19 @@ \file \ingroup ECAT - \brief Implementation of routines which convert ECAT7 things into our + \brief Implementation of routines which convert ECAT7 things into our building blocks and vice versa. \author Kris Thielemans \author Cristina de Oliveira (stir::ecat::ecat7::offset_in_ECAT_file function) \warning This only works with some CTI file_types. In particular, it does NOT - work with the ECAT6-like files_types, as then there are subheaders 'in' the + work with the ECAT6-like files_types, as then there are subheaders 'in' the datasets. - + \warning Implementation uses the Louvain la Neuve Ecat library. So, it will only work on systems where this library works properly. */ - #include "stir/ProjDataInfo.h" #include "stir/ProjDataFromStream.h" #include "stir/ExamInfo.h" @@ -52,9 +51,9 @@ #include "stir/ProjDataInfoCylindricalArcCorr.h" #include "stir/SegmentByView.h" #include "stir/IndexRange2D.h" -#include "stir/Scanner.h" -#include "stir/Bin.h" -#include "stir/Succeeded.h" +#include "stir/Scanner.h" +#include "stir/Bin.h" +#include "stir/Succeeded.h" #include "stir/convert_array.h" #include "stir/NumericInfo.h" #include "stir/IO/stir_ecat7.h" @@ -91,384 +90,318 @@ START_NAMESPACE_ECAT7 /* ------------------------------------ * print_debug * ------------------------------------*/ -static int print_debug (char const * const fname, char const * const format, ...) -{ - va_list ap; - char *fmt; - int len; +static int +print_debug(char const* const fname, char const* const format, ...) { + va_list ap; + char* fmt; + int len; + if (0) // flagged (fname) != NULL) + { - if (0)//flagged (fname) != NULL) - { - - len = strlen (fname) + strlen (format) + 5; - if ((fmt = (char *)calloc ((long)len, sizeof (char))) == NULL) - return (1); - sprintf (fmt, "%s%s%s", fname, " :: ", format); - - va_start (ap, format); - vfprintf (stderr, fmt, ap); + len = strlen(fname) + strlen(format) + 5; + if ((fmt = (char*)calloc((long)len, sizeof(char))) == NULL) + return (1); + sprintf(fmt, "%s%s%s", fname, " :: ", format); - free (fmt); - va_end (ap); - - } + va_start(ap, format); + vfprintf(stderr, fmt, ap); - return (0); + free(fmt); + va_end(ap); + } + return (0); } - -Succeeded read_ECAT7_main_header(Main_header& mhead, const string& filename) -{ - FILE * cti_fptr=fopen(filename.c_str(), "rb"); +Succeeded +read_ECAT7_main_header(Main_header& mhead, const string& filename) { + FILE* cti_fptr = fopen(filename.c_str(), "rb"); if (!cti_fptr) return Succeeded::no; - // first check 'magic_number' before going into LLN routines + // first check 'magic_number' before going into LLN routines // to avoid crashes and error messages there // an ECAT7 file should start with MATRIX7 { char magic[7]; - if (fread(magic, 1, 7, cti_fptr) != 7 || - strncmp(magic, "MATRIX7",7)!=0) - { - fclose(cti_fptr); - return Succeeded::no; - } - } - if(mat_read_main_header(cti_fptr, &mhead)!=0) - { + if (fread(magic, 1, 7, cti_fptr) != 7 || strncmp(magic, "MATRIX7", 7) != 0) { fclose(cti_fptr); - // this is funny as it's just reading a bunch of bytes. anyway. we'll assume it isn't ECAT7 return Succeeded::no; } - else - { - // do some checks on the main header - fclose(cti_fptr); - if (mhead.sw_version>=70 && mhead.sw_version<=79 && - ( mhead.file_type >= 1 && mhead.file_type <= Float3dSinogram) && - mhead.num_frames>0) - return Succeeded::yes; - else - return Succeeded::no; - } + } + if (mat_read_main_header(cti_fptr, &mhead) != 0) { + fclose(cti_fptr); + // this is funny as it's just reading a bunch of bytes. anyway. we'll assume it isn't ECAT7 + return Succeeded::no; + } else { + // do some checks on the main header + fclose(cti_fptr); + if (mhead.sw_version >= 70 && mhead.sw_version <= 79 && (mhead.file_type >= 1 && mhead.file_type <= Float3dSinogram) && + mhead.num_frames > 0) + return Succeeded::yes; + else + return Succeeded::no; + } } -static bool is_ECAT7_file(Main_header& mhead, const string& filename) -{ +static bool +is_ECAT7_file(Main_header& mhead, const string& filename) { return read_ECAT7_main_header(mhead, filename) == Succeeded::yes; } -bool is_ECAT7_file(const string& filename) -{ +bool +is_ECAT7_file(const string& filename) { Main_header mhead; return is_ECAT7_file(mhead, filename); } -bool is_ECAT7_image_file(const string& filename) -{ +bool +is_ECAT7_image_file(const string& filename) { Main_header mhead; return is_ECAT7_file(mhead, filename) && - (mhead.file_type == PetImage || - mhead.file_type ==ByteVolume || mhead.file_type == PetVolume); + (mhead.file_type == PetImage || mhead.file_type == ByteVolume || mhead.file_type == PetVolume); } - -bool is_ECAT7_emission_file(const string& filename) -{ +bool +is_ECAT7_emission_file(const string& filename) { Main_header mhead; - return is_ECAT7_file(mhead, filename) && - (mhead.file_type == CTISinogram || mhead.file_type == Byte3dSinogram|| - mhead.file_type == Short3dSinogram || mhead.file_type == Float3dSinogram); + return is_ECAT7_file(mhead, filename) && (mhead.file_type == CTISinogram || mhead.file_type == Byte3dSinogram || + mhead.file_type == Short3dSinogram || mhead.file_type == Float3dSinogram); } - -bool is_ECAT7_attenuation_file(const string& filename) -{ +bool +is_ECAT7_attenuation_file(const string& filename) { Main_header mhead; - return is_ECAT7_file(mhead, filename) && - mhead.file_type ==AttenCor; + return is_ECAT7_file(mhead, filename) && mhead.file_type == AttenCor; } - - -void find_scanner(shared_ptr & scanner_ptr,const Main_header& mhead) -{ +void +find_scanner(shared_ptr& scanner_ptr, const Main_header& mhead) { scanner_ptr.reset(find_scanner_from_ECAT_system_type(mhead.system_type)); } - -short find_ECAT_data_type(const NumericType& type, const ByteOrder& byte_order) -{ +short +find_ECAT_data_type(const NumericType& type, const ByteOrder& byte_order) { if (!type.signed_type()) warning("find_ECAT_data_type: CTI data support only signed types. Using the signed equivalent\n"); - if (type.integer_type()) - { - switch(type.size_in_bytes()) - { + if (type.integer_type()) { + switch (type.size_in_bytes()) { case 1: return ByteData; case 2: - return byte_order==ByteOrder::big_endian ? SunShort : VAX_Ix2; + return byte_order == ByteOrder::big_endian ? SunShort : VAX_Ix2; case 4: - return byte_order==ByteOrder::big_endian ? SunLong : VAX_Ix4; - default: - { - // write error message below - } + return byte_order == ByteOrder::big_endian ? SunLong : VAX_Ix4; + default: { + // write error message below } - } - else - { - switch(type.size_in_bytes()) - { + } + } else { + switch (type.size_in_bytes()) { case 4: - return byte_order==ByteOrder::big_endian ? IeeeFloat : VAX_Rx4; - default: - { - // write error message below - } + return byte_order == ByteOrder::big_endian ? IeeeFloat : VAX_Rx4; + default: { + // write error message below + } } } string number_format; size_t size_in_bytes; type.get_Interfile_info(number_format, size_in_bytes); - warning("find_ECAT_data_type: CTI does not support data type '%s' of %d bytes.\n", - number_format.c_str(), size_in_bytes); + warning("find_ECAT_data_type: CTI does not support data type '%s' of %d bytes.\n", number_format.c_str(), size_in_bytes); return short(0); } /* ------------------------------------------- -* o f f s e t -* ------------------------------------------- -*/ -static long offset_in_ECAT_file (MatrixFile *mptr, int frame, int plane, int gate, int data, - int bed, int segment, int *plane_size_ptr = NULL) -{ - + * o f f s e t + * ------------------------------------------- + */ +static long +offset_in_ECAT_file(MatrixFile* mptr, int frame, int plane, int gate, int data, int bed, int segment, + int* plane_size_ptr = NULL) { + int el_size[15], matnum, strtblk, group = abs(segment), i; - long plane_size = 0, off; + long plane_size = 0, off; struct MatDir matdir; Scan_subheader scansub; Image_subheader imagesub; Norm_subheader normsub; Attn_subheader attnsub; Scan3D_subheader scan3dsub; - const char * const prog = "offset_in_ECAT_file"; + const char* const prog = "offset_in_ECAT_file"; /* set_debug (prog); */ el_size[ByteData] = 1; el_size[VAX_Ix2] = el_size[SunShort] = 2; el_size[VAX_Ix4] = el_size[VAX_Rx4] = el_size[IeeeFloat] = el_size[SunLong] = 4; - + if (mptr->mhptr->sw_version < V7) - matnum = mat_numcod (frame, plane, gate, data, bed); + matnum = mat_numcod(frame, plane, gate, data, bed); else - matnum = mat_numcod (frame, 1, gate, data, bed); - print_debug (prog, "matnum = %d\n", matnum); - - if (matrix_find (mptr, matnum, &matdir) != 0) + matnum = mat_numcod(frame, 1, gate, data, bed); + print_debug(prog, "matnum = %d\n", matnum); + + if (matrix_find(mptr, matnum, &matdir) != 0) return -1; - + strtblk = matdir.strtblk; - print_debug (prog, "strtblk = %d\n", strtblk); - - + print_debug(prog, "strtblk = %d\n", strtblk); + off = (strtblk + 1) * MatBLKSIZE; - - switch (mptr->mhptr->file_type) - { + + switch (mptr->mhptr->file_type) { #ifndef STIR_NO_NAMESPACES case ::Sinogram: #else case CTISinogram: #endif - { - // KT 14/05/2002 added error check. - if (mat_read_scan_subheader (mptr->fptr, mptr->mhptr, strtblk, &scansub)) - { - if (ferror(mptr->fptr)) - perror("offset_in_ECAT_file: error in reading subheader"); - return -1; - } - plane_size = scansub.num_r_elements * - scansub.num_angles * - el_size[scansub.data_type]; - - if (mptr->mhptr->sw_version < V7) - off = strtblk*MatBLKSIZE; - else - off = (strtblk + 1) * MatBLKSIZE + (plane-1) * plane_size; - break; + { + // KT 14/05/2002 added error check. + if (mat_read_scan_subheader(mptr->fptr, mptr->mhptr, strtblk, &scansub)) { + if (ferror(mptr->fptr)) + perror("offset_in_ECAT_file: error in reading subheader"); + return -1; } + plane_size = scansub.num_r_elements * scansub.num_angles * el_size[scansub.data_type]; + + if (mptr->mhptr->sw_version < V7) + off = strtblk * MatBLKSIZE; + else + off = (strtblk + 1) * MatBLKSIZE + (plane - 1) * plane_size; + break; + } case PetImage: case ByteVolume: - case PetVolume: - { - // KT 14/05/2002 added error check. - if (mat_read_image_subheader (mptr->fptr, mptr->mhptr, strtblk, &imagesub)) - { - if (ferror(mptr->fptr)) - perror("offset_in_ECAT_file: error in reading subheader"); - return -1; - } - - off = strtblk*MatBLKSIZE; - plane_size = imagesub.x_dimension * - imagesub.y_dimension * - el_size[imagesub.data_type]; - - if (mptr->mhptr->sw_version >= V7) - off += (plane-1) * plane_size; - break; - + case PetVolume: { + // KT 14/05/2002 added error check. + if (mat_read_image_subheader(mptr->fptr, mptr->mhptr, strtblk, &imagesub)) { + if (ferror(mptr->fptr)) + perror("offset_in_ECAT_file: error in reading subheader"); + return -1; } - - case AttenCor: - { - off = strtblk * MatBLKSIZE; - print_debug (prog, "off = %d\n", off); - - if (mptr->mhptr->sw_version >= V7) - { - print_debug (prog, "AttenCor\n"); - // KT 14/05/2002 added error check. - if (mat_read_attn_subheader (mptr->fptr, mptr->mhptr, strtblk, &attnsub)) - { + + off = strtblk * MatBLKSIZE; + plane_size = imagesub.x_dimension * imagesub.y_dimension * el_size[imagesub.data_type]; + + if (mptr->mhptr->sw_version >= V7) + off += (plane - 1) * plane_size; + break; + } + + case AttenCor: { + off = strtblk * MatBLKSIZE; + print_debug(prog, "off = %d\n", off); + + if (mptr->mhptr->sw_version >= V7) { + print_debug(prog, "AttenCor\n"); + // KT 14/05/2002 added error check. + if (mat_read_attn_subheader(mptr->fptr, mptr->mhptr, strtblk, &attnsub)) { if (ferror(mptr->fptr)) perror("offset_in_ECAT_file: error in reading subheader"); return -1; } - - - switch (attnsub.storage_order) - { - case ElVwAxRd: - plane_size = attnsub.num_r_elements * - attnsub.num_angles * - el_size[attnsub.data_type]; - - if (group) - for (i = 0; i < group; i++) - off += plane_size * attnsub.z_elements[i]; - // KT 25/10/2000 swapped segment order - if (segment > 0) - off += plane_size * attnsub.z_elements[group]/2; - off += (plane - 1) * plane_size; - break; - - case ElAxVwRd: - print_debug (prog, "group %d, plane %d\n", group, plane); - if (group) - for (i = 0; i < group; i++) - { - plane_size = attnsub.num_r_elements * - attnsub.z_elements[i] * - el_size[attnsub.data_type]; - off += plane_size * attnsub.num_angles; - } - plane_size = attnsub.num_r_elements * - attnsub.z_elements[group] * - el_size[attnsub.data_type]; - if (group) - plane_size /=2; - // KT 25/10/2000 swapped segment order - if (segment > 0) - off += plane_size*attnsub.num_angles; - - off += (plane - 1) *plane_size; - - break; - } - + + switch (attnsub.storage_order) { + case ElVwAxRd: + plane_size = attnsub.num_r_elements * attnsub.num_angles * el_size[attnsub.data_type]; + + if (group) + for (i = 0; i < group; i++) + off += plane_size * attnsub.z_elements[i]; + // KT 25/10/2000 swapped segment order + if (segment > 0) + off += plane_size * attnsub.z_elements[group] / 2; + off += (plane - 1) * plane_size; + break; + + case ElAxVwRd: + print_debug(prog, "group %d, plane %d\n", group, plane); + if (group) + for (i = 0; i < group; i++) { + plane_size = attnsub.num_r_elements * attnsub.z_elements[i] * el_size[attnsub.data_type]; + off += plane_size * attnsub.num_angles; + } + plane_size = attnsub.num_r_elements * attnsub.z_elements[group] * el_size[attnsub.data_type]; + if (group) + plane_size /= 2; + // KT 25/10/2000 swapped segment order + if (segment > 0) + off += plane_size * attnsub.num_angles; + + off += (plane - 1) * plane_size; + + break; } - break; } - - - case Normalization: - { - - // KT 14/05/2002 added error check. - if (mat_read_norm_subheader (mptr->fptr, mptr->mhptr, strtblk, &normsub)) - { - if (ferror(mptr->fptr)) - perror("offset_in_ECAT_file: error in reading subheader"); - return -1; - } - off = strtblk*MatBLKSIZE; - plane_size = normsub.num_r_elements * - normsub.num_angles * - el_size[normsub.data_type]; - if (mptr->mhptr->sw_version >= V7) - off += (plane-1) * plane_size; - break; + break; + } + + case Normalization: { + + // KT 14/05/2002 added error check. + if (mat_read_norm_subheader(mptr->fptr, mptr->mhptr, strtblk, &normsub)) { + if (ferror(mptr->fptr)) + perror("offset_in_ECAT_file: error in reading subheader"); + return -1; } + off = strtblk * MatBLKSIZE; + plane_size = normsub.num_r_elements * normsub.num_angles * el_size[normsub.data_type]; + if (mptr->mhptr->sw_version >= V7) + off += (plane - 1) * plane_size; + break; + } case ByteProjection: case PetProjection: - case PolarMap: - { - fprintf (stderr, "Not implemented for this file type\n"); - off = -1; - break; - } + case PolarMap: { + fprintf(stderr, "Not implemented for this file type\n"); + off = -1; + break; + } case Byte3dSinogram: case Short3dSinogram: - case Float3dSinogram : - { - off = (strtblk+1) * MatBLKSIZE; - print_debug (prog, "off = %d\n", off); + case Float3dSinogram: { + off = (strtblk + 1) * MatBLKSIZE; + print_debug(prog, "off = %d\n", off); + + // KT 14/05/2002 added error check. + if (mat_read_Scan3D_subheader(mptr->fptr, mptr->mhptr, strtblk, &scan3dsub)) { + if (ferror(mptr->fptr)) + perror("offset_in_ECAT_file: error in reading subheader"); + return -1; + } - // KT 14/05/2002 added error check. - if (mat_read_Scan3D_subheader (mptr->fptr, mptr->mhptr, strtblk, &scan3dsub)) - { - if (ferror(mptr->fptr)) - perror("offset_in_ECAT_file: error in reading subheader"); - return -1; - } - - switch (scan3dsub.storage_order) - { - case ElVwAxRd: - plane_size = scan3dsub.num_r_elements * - scan3dsub.num_angles * - el_size[scan3dsub.data_type]; - print_debug (prog, "xdim = %d (num_r_elements)\n", scan3dsub.num_r_elements); - print_debug (prog, "ydim = %d (num_angles) \n", scan3dsub.num_angles); - print_debug (prog, "plane_size = %d \n", plane_size); - if (group) - for (i = 0; i < group; i++) - off += (plane_size * scan3dsub.num_z_elements[i]); - // KT 25/10/2000 swapped segment order - if (segment > 0) - off += plane_size * scan3dsub.num_z_elements[group]/2; - - - print_debug (prog, "num_z_elements[group] = %d\n", scan3dsub.num_z_elements[group]); - print_debug (prog, "plane-1 = %d\n", plane-1); - - off += ((plane - 1) * plane_size); - print_debug (prog, "off = %d\n", off); - break; - - case ElAxVwRd: - if (group) - for (i = 0; i < group; i++) - { - plane_size = scan3dsub.num_r_elements * - scan3dsub.num_z_elements[i] * - el_size[scan3dsub.data_type]; - off += plane_size * scan3dsub.num_angles; - } - plane_size = scan3dsub.num_r_elements * - scan3dsub.num_z_elements[group] * - el_size[scan3dsub.data_type]; - // KT 14/05/2002 corrected. It seems that the convention of planes was different - // now it's the same as for AttenCor + switch (scan3dsub.storage_order) { + case ElVwAxRd: + plane_size = scan3dsub.num_r_elements * scan3dsub.num_angles * el_size[scan3dsub.data_type]; + print_debug(prog, "xdim = %d (num_r_elements)\n", scan3dsub.num_r_elements); + print_debug(prog, "ydim = %d (num_angles) \n", scan3dsub.num_angles); + print_debug(prog, "plane_size = %d \n", plane_size); + if (group) + for (i = 0; i < group; i++) + off += (plane_size * scan3dsub.num_z_elements[i]); + // KT 25/10/2000 swapped segment order + if (segment > 0) + off += plane_size * scan3dsub.num_z_elements[group] / 2; + + print_debug(prog, "num_z_elements[group] = %d\n", scan3dsub.num_z_elements[group]); + print_debug(prog, "plane-1 = %d\n", plane - 1); + + off += ((plane - 1) * plane_size); + print_debug(prog, "off = %d\n", off); + break; + + case ElAxVwRd: + if (group) + for (i = 0; i < group; i++) { + plane_size = scan3dsub.num_r_elements * scan3dsub.num_z_elements[i] * el_size[scan3dsub.data_type]; + off += plane_size * scan3dsub.num_angles; + } + plane_size = scan3dsub.num_r_elements * scan3dsub.num_z_elements[group] * el_size[scan3dsub.data_type]; + // KT 14/05/2002 corrected. It seems that the convention of planes was different + // now it's the same as for AttenCor #if 0 if (group) { @@ -481,115 +414,99 @@ static long offset_in_ECAT_file (MatrixFile *mptr, int frame, int plane, int gat else off += (plane - 1) *plane_size; #else - if (group) - plane_size /=2; - // KT 25/10/2000 swapped segment order - if (segment > 0) - off += plane_size*scan3dsub.num_angles; - off += (plane - 1) *plane_size; + if (group) + plane_size /= 2; + // KT 25/10/2000 swapped segment order + if (segment > 0) + off += plane_size * scan3dsub.num_angles; + off += (plane - 1) * plane_size; #endif - break; - } - break; - } - case Norm3d: - { - fprintf (stderr, "Not implemented yet\n"); - off = 1; break; } + break; } - + case Norm3d: { + fprintf(stderr, "Not implemented yet\n"); + off = 1; + break; + } + } + if (plane_size_ptr != NULL) *plane_size_ptr = plane_size; - - return (off); + return (off); } - -static void fill_string (char *str, int len) -{ - for (int i=0; i -read_ECAT7_exam_info(MatrixFile *mptr) -{ - - const int num_frames = std::max(static_cast( mptr->mhptr->num_frames),1); +read_ECAT7_exam_info(MatrixFile* mptr) { + + const int num_frames = std::max(static_cast(mptr->mhptr->num_frames), 1); // funnily enough, num_bed_pos seems to be offset with 1 - // (That's to say, in a singled bed study, num_bed_pos==0) + // (That's to say, in a singled bed study, num_bed_pos==0) // TODO maybe not true for multi-bed studies - const int num_bed_poss = static_cast( mptr->mhptr->num_bed_pos) + 1; + const int num_bed_poss = static_cast(mptr->mhptr->num_bed_pos) + 1; // const int num_gates = std::max(static_cast( mptr->mhptr->num_gates),1); int min_frame_num = 1; int max_frame_num = num_frames; const int min_bed_num = 0; - const int max_bed_num = num_bed_poss-1; + const int max_bed_num = num_bed_poss - 1; const int gate_num = 1; const int data_num = 0; - std::vector > frame_times; + std::vector> frame_times; - for (int frame_num=min_frame_num; frame_num<=max_frame_num;++frame_num) - for (int bed_num=min_bed_num; bed_num<=max_bed_num;++bed_num) - { - const int matnum = mat_numcod (frame_num, 1, gate_num, data_num, bed_num); - MatrixData* matrix = matrix_read( mptr, matnum, MAT_SUB_HEADER); - - if (matrix==NULL) - { - warning("TimeFrameDefinitions: Matrix not found at \"%d,1,%d,%d,%d\" in file \"%s\"\n.", - frame_num, 1, gate_num, data_num, bed_num, mptr->fname); - continue; - } - - switch (mptr->mhptr->file_type) - { - case PetImage: - case ByteVolume: - case PetVolume: - { - Image_subheader *sheader_ptr= - reinterpret_cast(matrix->shptr); - frame_times.push_back(std::make_pair(sheader_ptr->frame_start_time/1000., - sheader_ptr->frame_start_time/1000. - + sheader_ptr->frame_duration/1000.)); - - break; - } - case Byte3dSinogram: - case Short3dSinogram: - case Float3dSinogram : - { - Scan3D_subheader *sheader_ptr= - reinterpret_cast(matrix->shptr); - frame_times.push_back(std::make_pair(sheader_ptr->frame_start_time/1000., - sheader_ptr->frame_start_time/1000. - + sheader_ptr->frame_duration/1000.)); - - break; - } - case CTISinogram : - { - Scan_subheader *sheader_ptr= - reinterpret_cast(matrix->shptr); - frame_times.push_back(std::make_pair(sheader_ptr->frame_start_time/1000., - sheader_ptr->frame_start_time/1000. - + sheader_ptr->frame_duration/1000.)); - - break; - } - default: - { - // can't do anything here - } - } - free_matrix_data(matrix); + for (int frame_num = min_frame_num; frame_num <= max_frame_num; ++frame_num) + for (int bed_num = min_bed_num; bed_num <= max_bed_num; ++bed_num) { + const int matnum = mat_numcod(frame_num, 1, gate_num, data_num, bed_num); + MatrixData* matrix = matrix_read(mptr, matnum, MAT_SUB_HEADER); + + if (matrix == NULL) { + warning("TimeFrameDefinitions: Matrix not found at \"%d,1,%d,%d,%d\" in file \"%s\"\n.", frame_num, 1, gate_num, data_num, + bed_num, mptr->fname); + continue; + } + + switch (mptr->mhptr->file_type) { + case PetImage: + case ByteVolume: + case PetVolume: { + Image_subheader* sheader_ptr = reinterpret_cast(matrix->shptr); + frame_times.push_back(std::make_pair(sheader_ptr->frame_start_time / 1000., + sheader_ptr->frame_start_time / 1000. + sheader_ptr->frame_duration / 1000.)); + + break; + } + case Byte3dSinogram: + case Short3dSinogram: + case Float3dSinogram: { + Scan3D_subheader* sheader_ptr = reinterpret_cast(matrix->shptr); + frame_times.push_back(std::make_pair(sheader_ptr->frame_start_time / 1000., + sheader_ptr->frame_start_time / 1000. + sheader_ptr->frame_duration / 1000.)); + + break; } + case CTISinogram: { + Scan_subheader* sheader_ptr = reinterpret_cast(matrix->shptr); + frame_times.push_back(std::make_pair(sheader_ptr->frame_start_time / 1000., + sheader_ptr->frame_start_time / 1000. + sheader_ptr->frame_duration / 1000.)); + + break; + } + default: { + // can't do anything here + } + } + free_matrix_data(matrix); + } TimeFrameDefinitions time_frame_defs(frame_times); ExamInfo exam_info; @@ -597,75 +514,76 @@ read_ECAT7_exam_info(MatrixFile *mptr) exam_info.set_time_frame_definitions(time_frame_defs); exam_info.start_time_in_secs_since_1970 = double(mptr->mhptr->scan_start_time); - switch(mptr->mhptr->patient_orientation) - { - case FeetFirstProne: - exam_info.patient_position = PatientPosition(PatientPosition::FFP); break; - case HeadFirstProne: - exam_info.patient_position = PatientPosition(PatientPosition::HFP); break; - case FeetFirstSupine: - exam_info.patient_position = PatientPosition(PatientPosition::FFS); break; - case HeadFirstSupine: - exam_info.patient_position = PatientPosition(PatientPosition::HFS); break; - case FeetFirstRight: - exam_info.patient_position = PatientPosition(PatientPosition::FFDR); break; - case HeadFirstRight: - exam_info.patient_position = PatientPosition(PatientPosition::HFDR); break; - case FeetFirstLeft: - exam_info.patient_position = PatientPosition(PatientPosition::FFDL); break; - case HeadFirstLeft: - exam_info.patient_position = PatientPosition(PatientPosition::HFDL); break; - case UnknownOrientation: - default: - exam_info.patient_position = PatientPosition(PatientPosition::unknown_position); break; - } + switch (mptr->mhptr->patient_orientation) { + case FeetFirstProne: + exam_info.patient_position = PatientPosition(PatientPosition::FFP); + break; + case HeadFirstProne: + exam_info.patient_position = PatientPosition(PatientPosition::HFP); + break; + case FeetFirstSupine: + exam_info.patient_position = PatientPosition(PatientPosition::FFS); + break; + case HeadFirstSupine: + exam_info.patient_position = PatientPosition(PatientPosition::HFS); + break; + case FeetFirstRight: + exam_info.patient_position = PatientPosition(PatientPosition::FFDR); + break; + case HeadFirstRight: + exam_info.patient_position = PatientPosition(PatientPosition::HFDR); + break; + case FeetFirstLeft: + exam_info.patient_position = PatientPosition(PatientPosition::FFDL); + break; + case HeadFirstLeft: + exam_info.patient_position = PatientPosition(PatientPosition::HFDL); + break; + case UnknownOrientation: + default: + exam_info.patient_position = PatientPosition(PatientPosition::unknown_position); + break; + } shared_ptr exam_info_sptr(new ExamInfo(exam_info)); return exam_info_sptr; } shared_ptr -read_ECAT7_exam_info(const string& filename) -{ - MatrixFile * const mptr = - matrix_open( filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); - if (!mptr) - { - matrix_perror( filename.c_str()); - error("Error reading ECAT7 file"); - } +read_ECAT7_exam_info(const string& filename) { + MatrixFile* const mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); + if (!mptr) { + matrix_perror(filename.c_str()); + error("Error reading ECAT7 file"); + } shared_ptr exam_info_sptr(read_ECAT7_exam_info(mptr)); matrix_close(mptr); return exam_info_sptr; } -void make_ECAT7_main_header(Main_header& mhead, - Scanner const& scanner, - const string& orig_name, - ExamInfo const& exam_info - ) -{ +void +make_ECAT7_main_header(Main_header& mhead, Scanner const& scanner, const string& orig_name, ExamInfo const& exam_info) { // first set to default (sometimes nonsensical) values strcpy(mhead.magic_number, "MATRIX7.0"); // TODO check fill_string(mhead.original_file_name, 32); - mhead.sw_version= V7; - mhead.system_type= -1; - mhead.file_type= -1; - fill_string(mhead.serial_number,10); - mhead.scan_start_time= 0; + mhead.sw_version = V7; + mhead.system_type = -1; + mhead.file_type = -1; + fill_string(mhead.serial_number, 10); + mhead.scan_start_time = 0; fill_string(mhead.isotope_code, 8); - mhead.isotope_halflife= 0.F; + mhead.isotope_halflife = 0.F; fill_string(mhead.radiopharmaceutical, 32); - mhead.gantry_tilt= 0.F; - mhead.gantry_rotation= 0.F; - mhead.bed_elevation= 0.F; + mhead.gantry_tilt = 0.F; + mhead.gantry_rotation = 0.F; + mhead.bed_elevation = 0.F; mhead.intrinsic_tilt = 0; - mhead.wobble_speed= 0; - mhead.transm_source_type= -1; + mhead.wobble_speed = 0; + mhead.transm_source_type = -1; mhead.distance_scanned = -1.F; - mhead.transaxial_fov= -1.F; + mhead.transaxial_fov = -1.F; mhead.angular_compression = -1; - mhead.calibration_factor= 0.F; + mhead.calibration_factor = 0.F; mhead.calibration_units = 0; mhead.calibration_units_label = 0; mhead.compression_code = 0; @@ -677,157 +595,143 @@ void make_ECAT7_main_header(Main_header& mhead, mhead.patient_age = 0.F; mhead.patient_height = 0.F; mhead.patient_weight = 0.F; - mhead.patient_birth_date=1; - fill_string(mhead.physician_name,32); - fill_string(mhead.operator_name,32); - fill_string(mhead.study_description,32); - mhead.acquisition_type = 0; + mhead.patient_birth_date = 1; + fill_string(mhead.physician_name, 32); + fill_string(mhead.operator_name, 32); + fill_string(mhead.study_description, 32); + mhead.acquisition_type = 0; mhead.coin_samp_mode = 0; // default to net_trues - mhead.axial_samp_mode= 0; + mhead.axial_samp_mode = 0; mhead.patient_orientation = HeadFirstSupine; fill_string(mhead.facility_name, 20); - mhead.num_planes= 0; - mhead.num_frames= 1; // used for matnum, so set coherent default values - mhead.num_gates= 1; - mhead.num_bed_pos= 0; - mhead.init_bed_position= -1.F; - for (int i=0; i<15; i++) mhead.bed_offset[i]= 0.F; - mhead.plane_separation= -1.F; - mhead.lwr_sctr_thres= 0; // WARNING: default setup for the 966 - mhead.lwr_true_thres= 350; // WARNING: default setup for the 966 - mhead.upr_true_thres= 650; // WARNING: default setup for the 966 + mhead.num_planes = 0; + mhead.num_frames = 1; // used for matnum, so set coherent default values + mhead.num_gates = 1; + mhead.num_bed_pos = 0; + mhead.init_bed_position = -1.F; + for (int i = 0; i < 15; i++) + mhead.bed_offset[i] = 0.F; + mhead.plane_separation = -1.F; + mhead.lwr_sctr_thres = 0; // WARNING: default setup for the 966 + mhead.lwr_true_thres = 350; // WARNING: default setup for the 966 + mhead.upr_true_thres = 650; // WARNING: default setup for the 966 fill_string(mhead.user_process_code, 10); - mhead.acquisition_mode= 0; // default to NORMAL + mhead.acquisition_mode = 0; // default to NORMAL mhead.bin_size = -1.F; mhead.branching_fraction = -1.F; mhead.dose_start_time = 0; mhead.dosage = 0.F; mhead.well_counter_factor = 1.F; - fill_string(mhead.data_units,32); - mhead.septa_state= -1; - + fill_string(mhead.data_units, 32); + mhead.septa_state = -1; + // now fill in what we can mhead.calibration_factor = 1.F; - mhead.well_counter_factor=1.F; + mhead.well_counter_factor = 1.F; strncpy(mhead.original_file_name, orig_name.c_str(), 31); - mhead.original_file_name[31]='\0'; - mhead.num_frames= 1; - - mhead.system_type= find_ECAT_system_type(scanner); - mhead.transaxial_fov= - scanner.get_inner_ring_radius()*2* - static_cast(sin(_PI/scanner.get_num_detectors_per_ring()* - scanner.get_max_num_non_arccorrected_bins()/2.)/10); + mhead.original_file_name[31] = '\0'; + mhead.num_frames = 1; + + mhead.system_type = find_ECAT_system_type(scanner); + mhead.transaxial_fov = + scanner.get_inner_ring_radius() * 2 * + static_cast(sin(_PI / scanner.get_num_detectors_per_ring() * scanner.get_max_num_non_arccorrected_bins() / 2.) / 10); mhead.intrinsic_tilt = scanner.get_default_intrinsic_tilt(); - mhead.bin_size = scanner.get_default_bin_size()/10; - mhead.plane_separation= scanner.get_ring_spacing()/2/10; + mhead.bin_size = scanner.get_default_bin_size() / 10; + mhead.plane_separation = scanner.get_ring_spacing() / 2 / 10; mhead.intrinsic_tilt = scanner.get_default_intrinsic_tilt(); - - mhead.distance_scanned= - mhead.plane_separation * scanner.get_num_rings()*2; + + mhead.distance_scanned = mhead.plane_separation * scanner.get_num_rings() * 2; mhead.num_frames = exam_info.time_frame_definitions.get_num_frames(); mhead.scan_start_time = static_cast(floor(exam_info.start_time_in_secs_since_1970)); - switch(exam_info.patient_position.get_position()) - { - case PatientPosition::FFP: - mhead.patient_orientation = FeetFirstProne; break; - case PatientPosition::HFP: - mhead.patient_orientation = HeadFirstProne; break; - case PatientPosition::FFS: - mhead.patient_orientation = FeetFirstSupine; break; - case PatientPosition::HFS: - mhead.patient_orientation = HeadFirstSupine; break; - case PatientPosition::FFDR: - mhead.patient_orientation = FeetFirstRight; break; - case PatientPosition::HFDR: - mhead.patient_orientation = HeadFirstRight; break; - case PatientPosition::FFDL: - mhead.patient_orientation = FeetFirstLeft; break; - case PatientPosition::HFDL: - mhead.patient_orientation = HeadFirstLeft; break; - default: - mhead.patient_orientation = UnknownOrientation; break; - } - + switch (exam_info.patient_position.get_position()) { + case PatientPosition::FFP: + mhead.patient_orientation = FeetFirstProne; + break; + case PatientPosition::HFP: + mhead.patient_orientation = HeadFirstProne; + break; + case PatientPosition::FFS: + mhead.patient_orientation = FeetFirstSupine; + break; + case PatientPosition::HFS: + mhead.patient_orientation = HeadFirstSupine; + break; + case PatientPosition::FFDR: + mhead.patient_orientation = FeetFirstRight; + break; + case PatientPosition::HFDR: + mhead.patient_orientation = HeadFirstRight; + break; + case PatientPosition::FFDL: + mhead.patient_orientation = FeetFirstLeft; + break; + case PatientPosition::HFDL: + mhead.patient_orientation = HeadFirstLeft; + break; + default: + mhead.patient_orientation = UnknownOrientation; + break; + } } -void make_ECAT7_main_header(Main_header& mhead, - Scanner const& scanner, - const string& orig_name, - DiscretisedDensity<3,float> const & density - ) -{ +void +make_ECAT7_main_header(Main_header& mhead, Scanner const& scanner, const string& orig_name, + DiscretisedDensity<3, float> const& density) { make_ECAT7_main_header(mhead, scanner, orig_name, density.get_exam_info()); - - DiscretisedDensityOnCartesianGrid<3,float> const & image = - dynamic_cast const&>(density); - - // extra main parameters that depend on data type - mhead.file_type= PetVolume; - mhead.num_planes=image.get_length(); - mhead.plane_separation=image.get_grid_spacing()[1]/10; // convert to cm + DiscretisedDensityOnCartesianGrid<3, float> const& image = + dynamic_cast const&>(density); + // extra main parameters that depend on data type + mhead.file_type = PetVolume; + mhead.num_planes = image.get_length(); + mhead.plane_separation = image.get_grid_spacing()[1] / 10; // convert to cm } -static short find_angular_compression(const ProjDataInfo& proj_data_info) -{ +static short +find_angular_compression(const ProjDataInfo& proj_data_info) { // try to convert to cylindrical ProjDataInfo // use pointer such that we can check if it worked (without catching exceptions) - ProjDataInfoCylindrical const * const proj_data_info_cyl_ptr = - dynamic_cast(&proj_data_info); - if (proj_data_info_cyl_ptr!=0) - { - const int mash_factor = - proj_data_info_cyl_ptr->get_view_mashing_factor(); - if (mash_factor>1 && mash_factor%2==1) - { - warning("ECAT7::find_angular_compression: odd mash factor %d is not supported by CTI header. " - "Using a value of 0\n", mash_factor); - return static_cast(0); - } - else - return static_cast(mash_factor/2); - } - else - { - warning("ECAT7::find_angular_compression: proj data info does not correspond to a cylindrical scanner. " - "Using a value of 0\n"); + ProjDataInfoCylindrical const* const proj_data_info_cyl_ptr = dynamic_cast(&proj_data_info); + if (proj_data_info_cyl_ptr != 0) { + const int mash_factor = proj_data_info_cyl_ptr->get_view_mashing_factor(); + if (mash_factor > 1 && mash_factor % 2 == 1) { + warning("ECAT7::find_angular_compression: odd mash factor %d is not supported by CTI header. " + "Using a value of 0\n", + mash_factor); return static_cast(0); - } - + } else + return static_cast(mash_factor / 2); + } else { + warning("ECAT7::find_angular_compression: proj data info does not correspond to a cylindrical scanner. " + "Using a value of 0\n"); + return static_cast(0); + } } -static short find_axial_compression(const ProjDataInfo& proj_data_info) -{ +static short +find_axial_compression(const ProjDataInfo& proj_data_info) { int axial_compression = 0; // try to convert to cylindrical ProjDataInfo // use pointer such that we can check if it worked (without catching exceptions) - ProjDataInfoCylindrical const * const proj_data_info_cyl_ptr = - dynamic_cast(&proj_data_info); - if (proj_data_info_cyl_ptr!=0) - { + ProjDataInfoCylindrical const* const proj_data_info_cyl_ptr = dynamic_cast(&proj_data_info); + if (proj_data_info_cyl_ptr != 0) { axial_compression = - proj_data_info_cyl_ptr->get_max_ring_difference(0) - - proj_data_info_cyl_ptr->get_min_ring_difference(0) + 1; - for (int segment_num = proj_data_info.get_min_segment_num(); - segment_num <= proj_data_info.get_max_segment_num(); - ++segment_num) - { - const int this_segments_axial_compression = - proj_data_info_cyl_ptr->get_max_ring_difference(segment_num) - - proj_data_info_cyl_ptr->get_min_ring_difference(segment_num) + 1; + proj_data_info_cyl_ptr->get_max_ring_difference(0) - proj_data_info_cyl_ptr->get_min_ring_difference(0) + 1; + for (int segment_num = proj_data_info.get_min_segment_num(); segment_num <= proj_data_info.get_max_segment_num(); + ++segment_num) { + const int this_segments_axial_compression = proj_data_info_cyl_ptr->get_max_ring_difference(segment_num) - + proj_data_info_cyl_ptr->get_min_ring_difference(segment_num) + 1; if (axial_compression != this_segments_axial_compression) error("ECAT 7 file format does not support data with non-uniform angular compression. " "Segment %d has angular compression %d while segment 0 has %d\n", segment_num, this_segments_axial_compression, axial_compression); } - } - else - { + } else { axial_compression = 1; warning("ECAT 7 file format used with non-cylindrical ProjDataInfo type. " "I set axial_compression to 1, but who knows what will happen?"); @@ -835,105 +739,83 @@ static short find_axial_compression(const ProjDataInfo& proj_data_info) return static_cast(axial_compression); } +NumericType +make_ECAT7_main_header(Main_header& mhead, const string& orig_name, ExamInfo const& exam_info, ProjDataInfo const& proj_data_info, + const bool write_as_attenuation, NumericType output_type) { -NumericType -make_ECAT7_main_header(Main_header& mhead, - const string& orig_name, - ExamInfo const & exam_info, - ProjDataInfo const & proj_data_info, - const bool write_as_attenuation, - NumericType output_type - ) -{ - make_ECAT7_main_header(mhead, *proj_data_info.get_scanner_ptr(), orig_name, exam_info); - - mhead.acquisition_type = - mhead.num_frames>1 ? DynamicEmission : StaticEmission; - // extra main parameters that depend on data type - - mhead.num_planes = 0; - for(int segment_num=proj_data_info.get_min_segment_num(); - segment_num <= proj_data_info.get_max_segment_num(); - ++segment_num) - mhead.num_planes+= proj_data_info.get_num_axial_poss(segment_num); - - - const float natural_bin_size = - proj_data_info.get_sampling_in_s(Bin(0,0,0,0)); - const float default_bin_size = - proj_data_info.get_scanner_ptr()->get_default_bin_size(); + mhead.acquisition_type = mhead.num_frames > 1 ? DynamicEmission : StaticEmission; - if (fabs(natural_bin_size - default_bin_size)>.02 && - dynamic_cast(&proj_data_info) == 0) - { - warning("CTI default bin size (%g) differs from STIR sampling in s (%g)\n" - "for this data. Using default bin size for field main header anyway.\n" - "However, you better check this out, especially for arc-corrected data.", - default_bin_size, natural_bin_size); - } - mhead.bin_size = default_bin_size/10; + // extra main parameters that depend on data type + mhead.num_planes = 0; + for (int segment_num = proj_data_info.get_min_segment_num(); segment_num <= proj_data_info.get_max_segment_num(); ++segment_num) + mhead.num_planes += proj_data_info.get_num_axial_poss(segment_num); + + const float natural_bin_size = proj_data_info.get_sampling_in_s(Bin(0, 0, 0, 0)); + const float default_bin_size = proj_data_info.get_scanner_ptr()->get_default_bin_size(); + + if (fabs(natural_bin_size - default_bin_size) > .02 && + dynamic_cast(&proj_data_info) == 0) { + warning("CTI default bin size (%g) differs from STIR sampling in s (%g)\n" + "for this data. Using default bin size for field main header anyway.\n" + "However, you better check this out, especially for arc-corrected data.", + default_bin_size, natural_bin_size); + } + mhead.bin_size = default_bin_size / 10; mhead.angular_compression = find_angular_compression(proj_data_info); // guess septa state // assume that if it has more than 1 segment, it's a 3D scan... // except for some scanners without septa - switch(proj_data_info.get_scanner_ptr()->get_type()) - { - case Scanner::E966: - case Scanner::E925: - case Scanner::RATPET: - mhead.septa_state= NoSeptaInstalled; - break; - default: - mhead.septa_state= - proj_data_info.get_num_segments()==1 - ? SeptaExtended - : SeptaRetracted; - } - + switch (proj_data_info.get_scanner_ptr()->get_type()) { + case Scanner::E966: + case Scanner::E925: + case Scanner::RATPET: + mhead.septa_state = NoSeptaInstalled; + break; + default: + mhead.septa_state = proj_data_info.get_num_segments() == 1 ? SeptaExtended : SeptaRetracted; + } - if (write_as_attenuation) - { - mhead.file_type = AttenCor; - mhead.acquisition_type = TransmissionScan; - if (output_type != NumericType::FLOAT) - { - warning("make_ECAT7_main_header: attenuation file will be written as floats " - "to avoid problems with CTI utilities"); - output_type = NumericType::FLOAT; - } - + if (write_as_attenuation) { + mhead.file_type = AttenCor; + mhead.acquisition_type = TransmissionScan; + if (output_type != NumericType::FLOAT) { + warning("make_ECAT7_main_header: attenuation file will be written as floats " + "to avoid problems with CTI utilities"); + output_type = NumericType::FLOAT; } - else - { - mhead.acquisition_type = StaticEmission; - switch (output_type.id) - { - case NumericType::FLOAT: - mhead.file_type = Float3dSinogram; break; - case NumericType::SHORT: - mhead.file_type = Short3dSinogram; break; - case NumericType::SCHAR: - mhead.file_type = Byte3dSinogram; break; - default: - warning("make_ECAT7_main_header: output type is not supported by ECAT7 format. Will use floats"); - mhead.file_type = Float3dSinogram; - output_type = NumericType::FLOAT; - break; - } + + } else { + mhead.acquisition_type = StaticEmission; + switch (output_type.id) { + case NumericType::FLOAT: + mhead.file_type = Float3dSinogram; + break; + case NumericType::SHORT: + mhead.file_type = Short3dSinogram; + break; + case NumericType::SCHAR: + mhead.file_type = Byte3dSinogram; + break; + default: + warning("make_ECAT7_main_header: output type is not supported by ECAT7 format. Will use floats"); + mhead.file_type = Float3dSinogram; + output_type = NumericType::FLOAT; + break; } + } return output_type; } // A utility function only called by scan_subheader_zero_fill /* - \internal + \internal - Most of the names of the variables we need are the same in the + Most of the names of the variables we need are the same in the Scan3D or Attn subheader, except num_z_elements and span. So, instead of writing essentially the same function twice, we use a templated version. Note that this takes care of the @@ -942,9 +824,9 @@ make_ECAT7_main_header(Main_header& mhead, */ template -static void scan_subheader_zero_fill_aux(Subheader& shead) -{ - shead.data_type= -1; +static void +scan_subheader_zero_fill_aux(Subheader& shead) { + shead.data_type = -1; shead.num_dimensions = -1; shead.num_r_elements = -1; shead.num_angles = -1; @@ -953,42 +835,44 @@ static void scan_subheader_zero_fill_aux(Subheader& shead) shead.x_resolution = -1.F; shead.z_resolution = -1.F; shead.w_resolution = -1.F; - shead.scale_factor= -1.F; + shead.scale_factor = -1.F; } -void scan_subheader_zero_fill(Scan3D_subheader& shead) -{ +void +scan_subheader_zero_fill(Scan3D_subheader& shead) { scan_subheader_zero_fill_aux(shead); shead.v_resolution = -1.F; shead.corrections_applied = 0; - for (int i=0; i<64; ++i) shead.num_z_elements[i] = -1; + for (int i = 0; i < 64; ++i) + shead.num_z_elements[i] = -1; shead.axial_compression = -1; - shead.gate_duration= 0; - shead.r_wave_offset= -1; + shead.gate_duration = 0; + shead.r_wave_offset = -1; shead.num_accepted_beats = -1; - shead.scan_min= -1; - shead.scan_max= -1; - shead.prompts= -1; - shead.delayed= -1; - shead.multiples= -1; - shead.net_trues= -1; - shead.tot_avg_cor= -1.F; - shead.tot_avg_uncor= -1.F; - shead.total_coin_rate= -1; - shead.frame_start_time= 0; - shead.frame_duration= 0; + shead.scan_min = -1; + shead.scan_max = -1; + shead.prompts = -1; + shead.delayed = -1; + shead.multiples = -1; + shead.net_trues = -1; + shead.tot_avg_cor = -1.F; + shead.tot_avg_uncor = -1.F; + shead.total_coin_rate = -1; + shead.frame_start_time = 0; + shead.frame_duration = 0; shead.loss_correction_fctr = -1.F; - for(int i=0;i<128;++i) shead.uncor_singles[i] = -1.F; - + for (int i = 0; i < 128; ++i) + shead.uncor_singles[i] = -1.F; } -void scan_subheader_zero_fill(Attn_subheader& shead) -{ +void +scan_subheader_zero_fill(Attn_subheader& shead) { scan_subheader_zero_fill_aux(shead); shead.y_resolution = -1.F; shead.attenuation_type = 1; // default to measured shead.num_z_elements = -1; - for (int i=0; i<64; ++i) shead.z_elements[i] = -1; + for (int i = 0; i < 64; ++i) + shead.z_elements[i] = -1; shead.span = -1; shead.x_offset = -1.F; shead.y_offset = -1.F; @@ -1000,29 +884,30 @@ void scan_subheader_zero_fill(Attn_subheader& shead) shead.attenuation_max = -1.F; shead.skull_thickness = -1.F; shead.num_additional_atten_coeff = -1; - for (int i=0; i<8; ++i) shead.additional_atten_coeff[i] = -1.F; + for (int i = 0; i < 8; ++i) + shead.additional_atten_coeff[i] = -1.F; shead.edge_finding_threshold = -1.F; } -void img_subheader_zero_fill(Image_subheader & ihead) -{ - ihead.data_type= -1; - ihead.num_dimensions= 3; - ihead.x_dimension= -1; - ihead.y_dimension= -1; - ihead.z_dimension= -1; - ihead.x_offset= 0.F; - ihead.y_offset= 0.F; - ihead.z_offset= 0.F; - ihead.recon_zoom= -1.F; - ihead.scale_factor= -1.F; - ihead.image_min= -1; - ihead.image_max= -1; - ihead.x_pixel_size= -1.F; - ihead.y_pixel_size= -1.F; - ihead.z_pixel_size= -1.F; - ihead.frame_duration= 0; - ihead.frame_start_time= 0; +void +img_subheader_zero_fill(Image_subheader& ihead) { + ihead.data_type = -1; + ihead.num_dimensions = 3; + ihead.x_dimension = -1; + ihead.y_dimension = -1; + ihead.z_dimension = -1; + ihead.x_offset = 0.F; + ihead.y_offset = 0.F; + ihead.z_offset = 0.F; + ihead.recon_zoom = -1.F; + ihead.scale_factor = -1.F; + ihead.image_min = -1; + ihead.image_max = -1; + ihead.x_pixel_size = -1.F; + ihead.y_pixel_size = -1.F; + ihead.z_pixel_size = -1.F; + ihead.frame_duration = 0; + ihead.frame_start_time = 0; ihead.filter_code = -1; ihead.x_resolution = -1.F; ihead.y_resolution = -1.F; @@ -1030,8 +915,8 @@ void img_subheader_zero_fill(Image_subheader & ihead) ihead.num_r_elements = -1; ihead.num_angles = -1; ihead.z_rotation_angle = -1; - ihead.decay_corr_fctr= -1.F; - ihead.processing_code= -1; + ihead.decay_corr_fctr = -1.F; + ihead.processing_code = -1; ihead.gate_duration = 0; ihead.r_wave_offset = -1; ihead.num_accepted_beats = -1; @@ -1064,12 +949,12 @@ void img_subheader_zero_fill(Image_subheader & ihead) ihead.scatter_type = -1; ihead.recon_type = -1; ihead.recon_views = -1; - fill_string(ihead.annotation, 40); + fill_string(ihead.annotation, 40); } //! A utility function to set time frame info in a subheader /*! - \internal + \internal Names of the variables for time frame info in the subheaders are the same. So, instead of writing essentially the same function twice, we @@ -1081,26 +966,20 @@ void img_subheader_zero_fill(Image_subheader & ihead) where the subheader is written). */ template -static void set_time_frame_info(SUBHEADERPTR sub_header_ptr, - const Main_header& mhead, - const ExamInfo& exam_info, - const unsigned frame_num) -{ - const double frame_start_time = - exam_info.get_time_frame_definitions().get_start_time(frame_num) - + exam_info.start_time_in_secs_since_1970 - mhead.scan_start_time; - const double frame_duration = - exam_info.get_time_frame_definitions().get_duration(frame_num); - sub_header_ptr->frame_start_time = static_cast(round(frame_start_time*1000.)); - sub_header_ptr->frame_duration = static_cast(round(frame_duration*1000.)); +static void +set_time_frame_info(SUBHEADERPTR sub_header_ptr, const Main_header& mhead, const ExamInfo& exam_info, const unsigned frame_num) { + const double frame_start_time = exam_info.get_time_frame_definitions().get_start_time(frame_num) + + exam_info.start_time_in_secs_since_1970 - mhead.scan_start_time; + const double frame_duration = exam_info.get_time_frame_definitions().get_duration(frame_num); + sub_header_ptr->frame_start_time = static_cast(round(frame_start_time * 1000.)); + sub_header_ptr->frame_duration = static_cast(round(frame_duration * 1000.)); } - //! A utility function only called by make_subheader_for_ECAT7(..., ProjDataInfo&) /*! - \internal + \internal - Most of the names of the variables we need are the same in the + Most of the names of the variables we need are the same in the Scan3D or Attn subheader, except num_z_elements and span. So, instead of writing essentially the same function twice, we use a templated version. Note that this takes care of the @@ -1111,142 +990,92 @@ static void set_time_frame_info(SUBHEADERPTR sub_header_ptr, */ template static void -make_subheader_for_ECAT7_aux(SUBHEADERPTR sub_header_ptr, - short * num_z_elements, - short& span, - const Main_header& mhead, - const ProjDataInfo& proj_data_info - ) -{ +make_subheader_for_ECAT7_aux(SUBHEADERPTR sub_header_ptr, short* num_z_elements, short& span, const Main_header& mhead, + const ProjDataInfo& proj_data_info) { scan_subheader_zero_fill(*sub_header_ptr); sub_header_ptr->num_dimensions = 4; sub_header_ptr->num_r_elements = proj_data_info.get_num_tangential_poss(); sub_header_ptr->num_angles = proj_data_info.get_num_views(); - - if (proj_data_info.get_max_segment_num() != - -proj_data_info.get_min_segment_num()) + + if (proj_data_info.get_max_segment_num() != -proj_data_info.get_min_segment_num()) error("ECAT 7 file format can only handle data with max_segment_num == -min_segment_num\n"); span = find_axial_compression(proj_data_info); - + if (proj_data_info.get_max_segment_num() > 64) error("ECAT 7 file format supports only a maximum segment number of 64 while this data has %d\n", proj_data_info.get_max_segment_num()); num_z_elements[0] = static_cast(proj_data_info.get_num_axial_poss(0)); - for (int segment_num=1; segment_num<=proj_data_info.get_max_segment_num(); ++segment_num) - { - num_z_elements[segment_num] = - static_cast(2*proj_data_info.get_num_axial_poss(segment_num)); + for (int segment_num = 1; segment_num <= proj_data_info.get_max_segment_num(); ++segment_num) { + num_z_elements[segment_num] = static_cast(2 * proj_data_info.get_num_axial_poss(segment_num)); } - for (int i=proj_data_info.get_max_segment_num()+1; i<64; ++i) + for (int i = proj_data_info.get_max_segment_num() + 1; i < 64; ++i) num_z_elements[i] = 0; - + // try to convert to cylindrical ProjDataInfo // use pointer such that we can check if it worked (without catching exceptions) - const ProjDataInfoCylindrical * const proj_data_info_cyl_ptr = - dynamic_cast(&proj_data_info); - if (proj_data_info_cyl_ptr!=0) - { - sub_header_ptr->ring_difference = - proj_data_info_cyl_ptr->get_max_ring_difference(proj_data_info.get_max_segment_num()); + const ProjDataInfoCylindrical* const proj_data_info_cyl_ptr = + dynamic_cast(&proj_data_info); + if (proj_data_info_cyl_ptr != 0) { + sub_header_ptr->ring_difference = proj_data_info_cyl_ptr->get_max_ring_difference(proj_data_info.get_max_segment_num()); + } else { + sub_header_ptr->ring_difference = -1; } - else - { - sub_header_ptr->ring_difference = -1; - } - float x_resolution; - const Scanner& scanner = - *proj_data_info.get_scanner_ptr(); - if (dynamic_cast(&proj_data_info) != 0) - { - const float depth_of_interaction_factor = - 1 + - scanner.get_average_depth_of_interaction() / - scanner.get_inner_ring_radius(); - x_resolution = - proj_data_info.get_sampling_in_s(Bin(0,0,0,0))/ - depth_of_interaction_factor; - if (fabs(x_resolution - scanner.get_default_bin_size()) > .01) - { - warning("ECAT7 IO: Bin size derived from data (%g) does not agree with expected value %g\n" - "for scanner %s. Using default bin size for header.x_resolution...", - x_resolution, - scanner.get_default_bin_size(), - scanner.get_name().c_str()); - } - // always use default because there's a small discrepancy between the - // default bin size and the value derived from the ring radius etc - x_resolution = scanner.get_default_bin_size(); + const Scanner& scanner = *proj_data_info.get_scanner_ptr(); + if (dynamic_cast(&proj_data_info) != 0) { + const float depth_of_interaction_factor = 1 + scanner.get_average_depth_of_interaction() / scanner.get_inner_ring_radius(); + x_resolution = proj_data_info.get_sampling_in_s(Bin(0, 0, 0, 0)) / depth_of_interaction_factor; + if (fabs(x_resolution - scanner.get_default_bin_size()) > .01) { + warning("ECAT7 IO: Bin size derived from data (%g) does not agree with expected value %g\n" + "for scanner %s. Using default bin size for header.x_resolution...", + x_resolution, scanner.get_default_bin_size(), scanner.get_name().c_str()); } - else - { - x_resolution = - proj_data_info.get_sampling_in_s(Bin(0,0,0,0)); - if (fabs(x_resolution - scanner.get_default_bin_size()) > .01) - { - warning("ECAT7 IO: Bin size derived from data (%g) does not agree with expected value %g\n" - "for scanner %s. Using data-derived value for header.x_resolution...", - x_resolution, - scanner.get_default_bin_size(), - scanner.get_name().c_str()); - } + // always use default because there's a small discrepancy between the + // default bin size and the value derived from the ring radius etc + x_resolution = scanner.get_default_bin_size(); + } else { + x_resolution = proj_data_info.get_sampling_in_s(Bin(0, 0, 0, 0)); + if (fabs(x_resolution - scanner.get_default_bin_size()) > .01) { + warning("ECAT7 IO: Bin size derived from data (%g) does not agree with expected value %g\n" + "for scanner %s. Using data-derived value for header.x_resolution...", + x_resolution, scanner.get_default_bin_size(), scanner.get_name().c_str()); } - sub_header_ptr->x_resolution = x_resolution/10; + } + sub_header_ptr->x_resolution = x_resolution / 10; sub_header_ptr->storage_order = ElAxVwRd; - - } - // WARNING data_type has still to be set void -make_subheader_for_ECAT7(Attn_subheader& shead, - const Main_header& mhead, - const ProjDataInfo& proj_data_info - ) -{ - make_subheader_for_ECAT7_aux(&shead, shead.z_elements, shead.span, - mhead, proj_data_info); - if (dynamic_cast(&proj_data_info)) - { +make_subheader_for_ECAT7(Attn_subheader& shead, const Main_header& mhead, const ProjDataInfo& proj_data_info) { + make_subheader_for_ECAT7_aux(&shead, shead.z_elements, shead.span, mhead, proj_data_info); + if (dynamic_cast(&proj_data_info)) { warning("make_subheader_for_ECAT7: data is not arc-corrected but info is not available in CTI attenuation subheader\n"); } } - + // WARNING data_type has to be set void -make_subheader_for_ECAT7(Scan3D_subheader& shead, - const Main_header& mhead, - const ProjDataInfo& proj_data_info - ) -{ - make_subheader_for_ECAT7_aux(&shead, shead.num_z_elements, shead.axial_compression, - mhead, proj_data_info); +make_subheader_for_ECAT7(Scan3D_subheader& shead, const Main_header& mhead, const ProjDataInfo& proj_data_info) { + make_subheader_for_ECAT7_aux(&shead, shead.num_z_elements, shead.axial_compression, mhead, proj_data_info); // try to convert to cylindrical ProjDataInfo to check if it's arccorrected // use pointer such that we can check if it worked (without catching exceptions) - if (dynamic_cast(&proj_data_info)) - { + if (dynamic_cast(&proj_data_info)) { shead.corrections_applied = static_cast(ArcPrc); - } - else if (dynamic_cast(&proj_data_info)) - { + } else if (dynamic_cast(&proj_data_info)) { shead.corrections_applied = 0; - } - else - { + } else { warning("make_subheader_for_ECAT7: unknown type of proj_data_info. Setting data to arc-corrected anyway\n"); shead.corrections_applied = static_cast(ArcPrc); } - } - //! A utility function only called by make_pdfs_matrix() /*! - \internal + \internal - Most of the names of the variables we need are the same in the + Most of the names of the variables we need are the same in the Scan3D or Attn subheader, except num_z_elements and span. So, instead of writing essentially the same function twice, we use a templated version. Note that this takes care of the @@ -1256,34 +1085,24 @@ make_subheader_for_ECAT7(Scan3D_subheader& shead, Extra parameters are used when the names of the variables do not match. */ template -static -ProjDataFromStream * -make_pdfs_from_matrix_aux(SUBHEADERPTR sub_header_ptr, - short const * num_z_elements, - const int span, - const bool arc_corrected, - unsigned int frame_start_time, - unsigned int frame_duration, - MatrixFile * const mptr, - MatrixData * const matrix, - const ExamInfo& exam_info_whole_file, - const shared_ptr& stream_ptr) -{ +static ProjDataFromStream* +make_pdfs_from_matrix_aux(SUBHEADERPTR sub_header_ptr, short const* num_z_elements, const int span, const bool arc_corrected, + unsigned int frame_start_time, unsigned int frame_duration, MatrixFile* const mptr, + MatrixData* const matrix, const ExamInfo& exam_info_whole_file, + const shared_ptr& stream_ptr) { shared_ptr scanner_ptr; - find_scanner(scanner_ptr, *(mptr->mhptr)); - if (scanner_ptr->get_type() == Scanner::Unknown_scanner) - { + find_scanner(scanner_ptr, *(mptr->mhptr)); + if (scanner_ptr->get_type() == Scanner::Unknown_scanner) { warning("ECAT7 IO: Couldn't determine the scanner \n" - "(Main_header.system_type=%d), defaulting to 962.\n" - "This might give dramatic problems.\n", - mptr->mhptr->system_type); + "(Main_header.system_type=%d), defaulting to 962.\n" + "This might give dramatic problems.\n", + mptr->mhptr->system_type); scanner_ptr.reset(new Scanner(Scanner::E962)); } #ifdef B_JOINT_STIRGATE // zlong, 08-04-2004, add support for Unknown_scanner // we have no idea about the geometry, so, ask user. - if(scanner_ptr->get_type() == Scanner::Unknown_scanner) - { + if (scanner_ptr->get_type() == Scanner::Unknown_scanner) { warning("Joint Gate Stir project warning:\n"); warning("I have no idea about your scanner, please give me the scanner info.\n"); scanner_ptr.reset(Scanner::ask_parameters()); @@ -1291,48 +1110,41 @@ make_pdfs_from_matrix_aux(SUBHEADERPTR sub_header_ptr, #endif shared_ptr exam_info_sptr(new ExamInfo(exam_info_whole_file)); - if (frame_duration>0) - { - std::vector > frame_times; - frame_times.push_back(std::make_pair(frame_start_time/1000., - frame_start_time/1000. - + frame_duration/1000.)); - TimeFrameDefinitions time_frame_defs(frame_times); - exam_info_sptr->set_time_frame_definitions(time_frame_defs); - exam_info_sptr->start_time_in_secs_since_1970 = double(mptr->mhptr->scan_start_time); - } + if (frame_duration > 0) { + std::vector> frame_times; + frame_times.push_back(std::make_pair(frame_start_time / 1000., frame_start_time / 1000. + frame_duration / 1000.)); + TimeFrameDefinitions time_frame_defs(frame_times); + exam_info_sptr->set_time_frame_definitions(time_frame_defs); + exam_info_sptr->start_time_in_secs_since_1970 = double(mptr->mhptr->scan_start_time); + } - if(sub_header_ptr->num_dimensions != 4) + if (sub_header_ptr->num_dimensions != 4) warning("ECAT7 IO: Expected subheader.num_dimensions==4. Continuing..."); const int num_tangential_poss = sub_header_ptr->num_r_elements; const int num_views = sub_header_ptr->num_angles; // find maximum segment int max_segment_num = 0; - while(max_segment_num<64 && num_z_elements[max_segment_num+1] != 0) + while (max_segment_num < 64 && num_z_elements[max_segment_num + 1] != 0) ++max_segment_num; - - VectorWithOffset num_axial_poss_per_seg(-max_segment_num,max_segment_num); - + + VectorWithOffset num_axial_poss_per_seg(-max_segment_num, max_segment_num); + num_axial_poss_per_seg[0] = num_z_elements[0]; - for (int segment_num=1; segment_num<=max_segment_num; ++segment_num) - { - num_axial_poss_per_seg[-segment_num] = - num_axial_poss_per_seg[segment_num] = - num_z_elements[segment_num]/2; + for (int segment_num = 1; segment_num <= max_segment_num; ++segment_num) { + num_axial_poss_per_seg[-segment_num] = num_axial_poss_per_seg[segment_num] = num_z_elements[segment_num] / 2; } - + const int max_delta = sub_header_ptr->ring_difference; const float bin_size = sub_header_ptr->x_resolution * 10; // convert to mm const float scale_factor = sub_header_ptr->scale_factor; - + ProjDataFromStream::StorageOrder storage_order; - switch (sub_header_ptr->storage_order) - { + switch (sub_header_ptr->storage_order) { case ElVwAxRd: storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; break; - + case ElAxVwRd: storage_order = ProjDataFromStream::Segment_View_AxialPos_TangPos; break; @@ -1344,177 +1156,121 @@ make_pdfs_from_matrix_aux(SUBHEADERPTR sub_header_ptr, ByteOrder byte_order; find_type_from_ECAT_data_type(data_type, byte_order, sub_header_ptr->data_type); - if (fabs(bin_size - scanner_ptr->get_default_bin_size())>.01) - { + if (fabs(bin_size - scanner_ptr->get_default_bin_size()) > .01) { warning("ECAT7 IO: Bin size from header.x_resolution (%g) does not agree with expected value %g\n" - "for scanner %s. Using bin size from header...", - bin_size, - scanner_ptr->get_default_bin_size(), - scanner_ptr->get_name().c_str()); + "for scanner %s. Using bin size from header...", + bin_size, scanner_ptr->get_default_bin_size(), scanner_ptr->get_name().c_str()); scanner_ptr->set_default_bin_size(bin_size); } // TODO more checks on FOV etc. int span_to_use = span; - if (span == 0) - { - if (num_z_elements[0] == scanner_ptr->get_num_rings()) - { - warning("\nECAT7 subheader says span=0, while span should be odd.\n" - "However, num_z_elements[0]==num_rings, so we'll asssume it's span=1\n"); - span_to_use = 1; - } - else - { - error("\nECAT7 subheader says span=0, while span should be odd.\n" - "Moreover, num_z_elements[0] (%d)!=num_rings (%d), so, I give up.\n", - num_z_elements[0], scanner_ptr->get_num_rings()); - } + if (span == 0) { + if (num_z_elements[0] == scanner_ptr->get_num_rings()) { + warning("\nECAT7 subheader says span=0, while span should be odd.\n" + "However, num_z_elements[0]==num_rings, so we'll asssume it's span=1\n"); + span_to_use = 1; + } else { + error("\nECAT7 subheader says span=0, while span should be odd.\n" + "Moreover, num_z_elements[0] (%d)!=num_rings (%d), so, I give up.\n", + num_z_elements[0], scanner_ptr->get_num_rings()); } - + } + shared_ptr pdi_ptr( - ProjDataInfo::ProjDataInfoCTI(scanner_ptr, span_to_use, max_delta, - num_views, num_tangential_poss, - arc_corrected)); - + ProjDataInfo::ProjDataInfoCTI(scanner_ptr, span_to_use, max_delta, num_views, num_tangential_poss, arc_corrected)); + pdi_ptr->set_num_axial_poss_per_segment(num_axial_poss_per_seg); - - std::vector segment_sequence_in_stream = - find_segment_sequence(*pdi_ptr); - + + std::vector segment_sequence_in_stream = find_segment_sequence(*pdi_ptr); + Matval matval; mat_numdoc(matrix->matnum, &matval); - const long offset_in_file = - offset_in_ECAT_file(mptr, - matval.frame, 1, matval.gate, matval.data, matval.bed, - 0, NULL); + const long offset_in_file = offset_in_ECAT_file(mptr, matval.frame, 1, matval.gate, matval.data, matval.bed, 0, NULL); // KT 14/05/2002 added error check - if (offset_in_ECAT_file<0) + if (offset_in_ECAT_file < 0) return 0; - - return new ProjDataFromStream (exam_info_sptr, pdi_ptr, stream_ptr, offset_in_file, - segment_sequence_in_stream, - storage_order, - data_type, - byte_order, - scale_factor); + return new ProjDataFromStream(exam_info_sptr, pdi_ptr, stream_ptr, offset_in_file, segment_sequence_in_stream, storage_order, + data_type, byte_order, scale_factor); } - -ProjDataFromStream * -make_pdfs_from_matrix(MatrixFile * const mptr, - MatrixData * const matrix, - const shared_ptr& stream_ptr) -{ +ProjDataFromStream* +make_pdfs_from_matrix(MatrixFile* const mptr, MatrixData* const matrix, const shared_ptr& stream_ptr) { shared_ptr exam_info_sptr(read_ECAT7_exam_info(mptr)); - switch (mptr->mhptr->file_type) - { - case AttenCor: - { - Attn_subheader const *sub_header_ptr= - reinterpret_cast(matrix->shptr); - - // CTI does not provide corrections_applied to check if the data - // is arc-corrected. Presumably its attenuation data is always - // arccorrected - const bool arc_corrected = true; - warning("Assuming data is arc-corrected (info not available in CTI attenuation subheader)\n"); - return - make_pdfs_from_matrix_aux(sub_header_ptr, - sub_header_ptr->z_elements, - sub_header_ptr->span, - arc_corrected, - 0U, 0U, // pass invalid frame_duration - mptr, matrix, *exam_info_sptr, stream_ptr); - } - case Byte3dSinogram: - case Short3dSinogram: - case Float3dSinogram : - { - Scan3D_subheader const * sub_header_ptr= - reinterpret_cast(matrix->shptr); - - ProcessingCode cti_processing_code = - static_cast(sub_header_ptr->corrections_applied); - - const bool arc_corrected = - (cti_processing_code & ArcPrc) != 0; - - return - make_pdfs_from_matrix_aux(sub_header_ptr, - sub_header_ptr->num_z_elements, - sub_header_ptr->axial_compression, - arc_corrected, - sub_header_ptr->frame_start_time, - sub_header_ptr->frame_duration, - mptr, matrix, *exam_info_sptr, stream_ptr); - } - default: - { - warning ("make_pdfs_from_matrix: unsupported file_type %d\n", - mptr->mhptr->file_type); - return NULL; - } - } + switch (mptr->mhptr->file_type) { + case AttenCor: { + Attn_subheader const* sub_header_ptr = reinterpret_cast(matrix->shptr); + + // CTI does not provide corrections_applied to check if the data + // is arc-corrected. Presumably its attenuation data is always + // arccorrected + const bool arc_corrected = true; + warning("Assuming data is arc-corrected (info not available in CTI attenuation subheader)\n"); + return make_pdfs_from_matrix_aux(sub_header_ptr, sub_header_ptr->z_elements, sub_header_ptr->span, arc_corrected, 0U, + 0U, // pass invalid frame_duration + mptr, matrix, *exam_info_sptr, stream_ptr); + } + case Byte3dSinogram: + case Short3dSinogram: + case Float3dSinogram: { + Scan3D_subheader const* sub_header_ptr = reinterpret_cast(matrix->shptr); + + ProcessingCode cti_processing_code = static_cast(sub_header_ptr->corrections_applied); + + const bool arc_corrected = (cti_processing_code & ArcPrc) != 0; + + return make_pdfs_from_matrix_aux(sub_header_ptr, sub_header_ptr->num_z_elements, sub_header_ptr->axial_compression, + arc_corrected, sub_header_ptr->frame_start_time, sub_header_ptr->frame_duration, mptr, + matrix, *exam_info_sptr, stream_ptr); + } + default: { + warning("make_pdfs_from_matrix: unsupported file_type %d\n", mptr->mhptr->file_type); + return NULL; + } + } } -static -Succeeded -get_ECAT7_image_info(shared_ptr& exam_info_sptr, - CartesianCoordinate3D& dimensions, - CartesianCoordinate3D& voxel_size, - Coordinate3D& origin, - float& scale_factor, - NumericType& type_of_numbers, - ByteOrder& byte_order, - long& offset_in_file, - - const string& ECAT7_filename, - const int frame_num, const int gate_num, const int data_num, const int bed_num, - const char * const warning_prefix, - const char * const warning_suffix) -{ - MatrixFile * const mptr = - matrix_open( ECAT7_filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); +static Succeeded +get_ECAT7_image_info(shared_ptr& exam_info_sptr, CartesianCoordinate3D& dimensions, + CartesianCoordinate3D& voxel_size, Coordinate3D& origin, float& scale_factor, + NumericType& type_of_numbers, ByteOrder& byte_order, long& offset_in_file, + + const string& ECAT7_filename, const int frame_num, const int gate_num, const int data_num, const int bed_num, + const char* const warning_prefix, const char* const warning_suffix) { + MatrixFile* const mptr = matrix_open(ECAT7_filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); if (!mptr) { - matrix_perror( ECAT7_filename.c_str()); + matrix_perror(ECAT7_filename.c_str()); + return Succeeded::no; + } + if (mptr->mhptr->sw_version < V7) { + matrix_close(mptr); + warning("%s: %s seems to be an ECAT 6 file. " + "%s", + warning_prefix, ECAT7_filename.c_str(), warning_suffix); return Succeeded::no; } - if (mptr->mhptr->sw_version < V7) - { - matrix_close(mptr); - warning("%s: %s seems to be an ECAT 6 file. " - "%s", - warning_prefix, ECAT7_filename.c_str(), warning_suffix); - return Succeeded::no; - } - //case PetImage: TODO this probably has subheaders? - if (mptr->mhptr->file_type != ByteVolume && - mptr->mhptr->file_type != PetVolume) - { - matrix_close(mptr); - warning("%s: %s has the wrong file type to be read as an image." - "%s", - warning_prefix, ECAT7_filename.c_str(), warning_suffix); - return Succeeded::no; - } - - const int matnum = mat_numcod (frame_num, 1, gate_num, data_num, bed_num); - MatrixData* matrix = matrix_read( mptr, matnum, MAT_SUB_HEADER); - - if (matrix==NULL) - { - matrix_close(mptr); - warning("%s: Matrix not found at \"%d,1,%d,%d,%d\" in file %s\n." - "%s", - warning_prefix, - frame_num, gate_num, data_num, bed_num, ECAT7_filename.c_str(), - warning_suffix); - return Succeeded::no; - } + // case PetImage: TODO this probably has subheaders? + if (mptr->mhptr->file_type != ByteVolume && mptr->mhptr->file_type != PetVolume) { + matrix_close(mptr); + warning("%s: %s has the wrong file type to be read as an image." + "%s", + warning_prefix, ECAT7_filename.c_str(), warning_suffix); + return Succeeded::no; + } + + const int matnum = mat_numcod(frame_num, 1, gate_num, data_num, bed_num); + MatrixData* matrix = matrix_read(mptr, matnum, MAT_SUB_HEADER); + + if (matrix == NULL) { + matrix_close(mptr); + warning("%s: Matrix not found at \"%d,1,%d,%d,%d\" in file %s\n." + "%s", + warning_prefix, frame_num, gate_num, data_num, bed_num, ECAT7_filename.c_str(), warning_suffix); + return Succeeded::no; + } exam_info_sptr = read_ECAT7_exam_info(mptr); { @@ -1522,61 +1278,46 @@ get_ECAT7_image_info(shared_ptr& exam_info_sptr, exam_info_sptr->set_time_frame_definitions(time_frame_defs); } - Image_subheader const * const sub_header_ptr= - reinterpret_cast(matrix->shptr); + Image_subheader const* const sub_header_ptr = reinterpret_cast(matrix->shptr); - if(sub_header_ptr->num_dimensions != 3) + if (sub_header_ptr->num_dimensions != 3) warning("%s: while reading matrix \"%d,1,%d,%d,%d\" in file %s:\n" - "Expected subheader_ptr->num_dimensions==3. Continuing\n", - warning_prefix, - frame_num, gate_num, data_num, bed_num, ECAT7_filename.c_str()); - dimensions = - CartesianCoordinate3D(matrix->zdim, - matrix->ydim, - matrix->xdim); - voxel_size = - CartesianCoordinate3D(matrix->z_size * 10, - matrix->y_size * 10, - matrix->pixel_size * 10); // convert to mm + "Expected subheader_ptr->num_dimensions==3. Continuing\n", + warning_prefix, frame_num, gate_num, data_num, bed_num, ECAT7_filename.c_str()); + dimensions = CartesianCoordinate3D(matrix->zdim, matrix->ydim, matrix->xdim); + voxel_size = CartesianCoordinate3D(matrix->z_size * 10, matrix->y_size * 10, + matrix->pixel_size * 10); // convert to mm // TODO: next line assumes that the index-range for the image is contracted in a particular way. We'd really need to check that. // At present, it will only be detected by test_OutputFileFormat - origin = - Coordinate3D(matrix->z_origin, - matrix->y_origin, - matrix->x_origin) * 10; // convert to mm - - + origin = Coordinate3D(matrix->z_origin, matrix->y_origin, + matrix->x_origin) * 10; // convert to mm + scale_factor = matrix->scale_factor; - + find_type_from_ECAT_data_type(type_of_numbers, byte_order, matrix->data_type); - - offset_in_file = - offset_in_ECAT_file(mptr, frame_num, 1, gate_num, data_num, bed_num, 0, NULL); - if (offset_in_ECAT_file<0) - { - free_matrix_data(matrix); - matrix_close(mptr); - warning("%s: while reading matrix \"%d,1,%d,%d,%d\" in file %s:\n" - "Error in determining offset into ECAT7 file %s.\n" - "%s", - warning_prefix, - frame_num, gate_num, data_num, bed_num, ECAT7_filename.c_str(), - warning_suffix); - return Succeeded::no; - } - + + offset_in_file = offset_in_ECAT_file(mptr, frame_num, 1, gate_num, data_num, bed_num, 0, NULL); + if (offset_in_ECAT_file < 0) { + free_matrix_data(matrix); + matrix_close(mptr); + warning("%s: while reading matrix \"%d,1,%d,%d,%d\" in file %s:\n" + "Error in determining offset into ECAT7 file %s.\n" + "%s", + warning_prefix, frame_num, gate_num, data_num, bed_num, ECAT7_filename.c_str(), warning_suffix); + return Succeeded::no; + } + free_matrix_data(matrix); matrix_close(mptr); return Succeeded::yes; } -VoxelsOnCartesianGrid * -ECAT7_to_VoxelsOnCartesianGrid(const string& ECAT7_filename, - const int frame_num, const int gate_num, const int data_num, const int bed_num) -{ - const char * const warning_prefix = "ECAT7_to_VoxelsOnCartesianGrid"; - const char * const warning_suffix = "I'm not reading any data...\n"; +VoxelsOnCartesianGrid* +ECAT7_to_VoxelsOnCartesianGrid(const string& ECAT7_filename, const int frame_num, const int gate_num, const int data_num, + const int bed_num) { + const char* const warning_prefix = "ECAT7_to_VoxelsOnCartesianGrid"; + const char* const warning_suffix = "I'm not reading any data...\n"; shared_ptr exam_info_sptr; CartesianCoordinate3D dimensions; @@ -1586,322 +1327,265 @@ ECAT7_to_VoxelsOnCartesianGrid(const string& ECAT7_filename, NumericType type_of_numbers; ByteOrder byte_order; long offset_in_file; - if (get_ECAT7_image_info(exam_info_sptr, - dimensions, voxel_size, origin, - scale_factor, type_of_numbers, byte_order, offset_in_file, - - ECAT7_filename, - frame_num, gate_num, data_num, bed_num, - warning_prefix, - warning_suffix) == - Succeeded::no) - { - return 0; - } + if (get_ECAT7_image_info( + exam_info_sptr, dimensions, voxel_size, origin, scale_factor, type_of_numbers, byte_order, offset_in_file, + + ECAT7_filename, frame_num, gate_num, data_num, bed_num, warning_prefix, warning_suffix) == Succeeded::no) { + return 0; + } // WARNING: this has to be consistent with the writing // in write_basic_interfile_header_for_ECAT7 and DiscretisedDensity_to_ECAT7 - const IndexRange3D range_3D (0,dimensions.z()-1, - -dimensions.y()/2,(-dimensions.y()/2)+dimensions.y()-1, - -dimensions.x()/2,(-dimensions.x()/2)+dimensions.x()-1); - VoxelsOnCartesianGrid* image_ptr = - new VoxelsOnCartesianGrid (exam_info_sptr, range_3D, origin, voxel_size); - + const IndexRange3D range_3D(0, dimensions.z() - 1, -dimensions.y() / 2, (-dimensions.y() / 2) + dimensions.y() - 1, + -dimensions.x() / 2, (-dimensions.x() / 2) + dimensions.x() - 1); + VoxelsOnCartesianGrid* image_ptr = new VoxelsOnCartesianGrid(exam_info_sptr, range_3D, origin, voxel_size); + std::ifstream data_in(ECAT7_filename.c_str(), ios::in | ios::binary); - if (!data_in) - { - warning("%s: cannot open %s using C++ ifstream.\n" - "%s", - warning_prefix, ECAT7_filename.c_str(), warning_suffix); - delete image_ptr; - return 0; - } + if (!data_in) { + warning("%s: cannot open %s using C++ ifstream.\n" + "%s", + warning_prefix, ECAT7_filename.c_str(), warning_suffix); + delete image_ptr; + return 0; + } data_in.seekg(static_cast(offset_in_file)); - if (!data_in) - { + if (!data_in) { + warning("%s: while reading %s:\n" + "error seeking to position of data.\n" + "%s", + warning_prefix, ECAT7_filename.c_str(), warning_suffix); + delete image_ptr; + return 0; + } + + { + float scale = float(1); + read_data(data_in, *image_ptr, type_of_numbers, scale, byte_order); + if (scale != 1) { warning("%s: while reading %s:\n" - "error seeking to position of data.\n" - "%s", - warning_prefix, ECAT7_filename.c_str(), warning_suffix); + "error in reading data with convertion to floats.\n", + "%s", warning_prefix, ECAT7_filename.c_str(), warning_suffix); delete image_ptr; return 0; } - - { - float scale = float(1); - read_data(data_in, *image_ptr, type_of_numbers, scale, byte_order); - if (scale != 1) - { - warning("%s: while reading %s:\n" - "error in reading data with convertion to floats.\n", - "%s", - warning_prefix, ECAT7_filename.c_str(), warning_suffix); - delete image_ptr; - return 0; - } } *image_ptr *= scale_factor; - + return image_ptr; } ProjDataFromStream* -ECAT7_to_PDFS(const string& ECAT7_filename, - const int frame_num, const int gate_num, const int data_num, const int bed_num) -{ - MatrixFile * const mptr = matrix_open( ECAT7_filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); +ECAT7_to_PDFS(const string& ECAT7_filename, const int frame_num, const int gate_num, const int data_num, const int bed_num) { + MatrixFile* const mptr = matrix_open(ECAT7_filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); if (!mptr) { - matrix_perror( ECAT7_filename.c_str()); + matrix_perror(ECAT7_filename.c_str()); return 0; } - const char * const warning_prefix = "ECAT7_to_PDFS"; - const char * const warning_suffix = "I'm not reading any data...\n"; + const char* const warning_prefix = "ECAT7_to_PDFS"; + const char* const warning_suffix = "I'm not reading any data...\n"; - if (mptr->mhptr->sw_version < V7) - { - warning("%s: %s seems to be an ECAT 6 file. " - "%s", warning_prefix, ECAT7_filename.c_str(), warning_suffix); - return 0; - } - const int matnum = mat_numcod (frame_num, 1, gate_num, data_num, bed_num); - MatrixData* matrix = matrix_read( mptr, matnum, MAT_SUB_HEADER); - - if (matrix==NULL) - { - matrix_close(mptr); - warning("%s: Matrix not found at \"%d,1,%d,%d,%d\" in file %s\n." - "%s", - warning_prefix, - frame_num, gate_num, data_num, bed_num, - ECAT7_filename.c_str(), warning_suffix); - return 0; - } - - shared_ptr stream_ptr( - new fstream(ECAT7_filename.c_str(), ios::in | ios::binary)); - - ProjDataFromStream * pdfs_ptr = - make_pdfs_from_matrix(mptr, matrix, stream_ptr); + if (mptr->mhptr->sw_version < V7) { + warning("%s: %s seems to be an ECAT 6 file. " + "%s", + warning_prefix, ECAT7_filename.c_str(), warning_suffix); + return 0; + } + const int matnum = mat_numcod(frame_num, 1, gate_num, data_num, bed_num); + MatrixData* matrix = matrix_read(mptr, matnum, MAT_SUB_HEADER); + + if (matrix == NULL) { + matrix_close(mptr); + warning("%s: Matrix not found at \"%d,1,%d,%d,%d\" in file %s\n." + "%s", + warning_prefix, frame_num, gate_num, data_num, bed_num, ECAT7_filename.c_str(), warning_suffix); + return 0; + } + + shared_ptr stream_ptr(new fstream(ECAT7_filename.c_str(), ios::in | ios::binary)); + + ProjDataFromStream* pdfs_ptr = make_pdfs_from_matrix(mptr, matrix, stream_ptr); free_matrix_data(matrix); matrix_close(mptr); return pdfs_ptr; } +Succeeded +write_basic_interfile_header_for_ECAT7(string& interfile_header_filename, const string& ECAT7_filename, const int frame_num, + const int gate_num, const int data_num, const int bed_num) { -Succeeded -write_basic_interfile_header_for_ECAT7(string& interfile_header_filename, - const string& ECAT7_filename, - const int frame_num, const int gate_num, const int data_num, const int bed_num) -{ - - MatrixFile * const mptr = matrix_open( ECAT7_filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); + MatrixFile* const mptr = matrix_open(ECAT7_filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); if (!mptr) { - matrix_perror( ECAT7_filename.c_str()); + matrix_perror(ECAT7_filename.c_str()); return Succeeded::no; } - const char * const warning_prefix = "write_basic_interfile_header_for_ECAT7"; - const char * const warning_suffix = "I'm not writing an Interfile header...\n"; + const char* const warning_prefix = "write_basic_interfile_header_for_ECAT7"; + const char* const warning_suffix = "I'm not writing an Interfile header...\n"; - if (mptr->mhptr->sw_version < V7) - { + if (mptr->mhptr->sw_version < V7) { warning("%s: '%s' seems to be an ECAT 6 file. " - "%s", warning_prefix, ECAT7_filename.c_str(), warning_suffix); - return Succeeded::no; + "%s", + warning_prefix, ECAT7_filename.c_str(), warning_suffix); + return Succeeded::no; } - - char *header_filename = new char[ECAT7_filename.size() + 100]; + char* header_filename = new char[ECAT7_filename.size() + 100]; { strcpy(header_filename, ECAT7_filename.c_str()); // keep extension, just in case we would have conflicts otherwise // but replace the . with a _ - const char * dot_ptr = strchr(find_filename(header_filename),'.'); + const char* dot_ptr = strchr(find_filename(header_filename), '.'); if (dot_ptr != NULL) header_filename[dot_ptr - header_filename] = '_'; // now add stuff to say which frame, gate, bed, data this was - sprintf(header_filename+strlen(header_filename), "_f%dg%dd%db%d", - frame_num, gate_num, data_num, bed_num); + sprintf(header_filename + strlen(header_filename), "_f%dg%dd%db%d", frame_num, gate_num, data_num, bed_num); } - - switch (mptr->mhptr->file_type) - { - //case PetImage: // TODO this probably has subheaders? + + switch (mptr->mhptr->file_type) { + // case PetImage: // TODO this probably has subheaders? case ByteVolume: - case PetVolume: - { - shared_ptr exam_info_sptr; - CartesianCoordinate3D dimensions; - CartesianCoordinate3D voxel_size; - Coordinate3D origin; - float scale_factor; - NumericType type_of_numbers; - ByteOrder byte_order; - long offset_in_file; - if (get_ECAT7_image_info(exam_info_sptr, - dimensions, voxel_size, origin, - scale_factor, type_of_numbers, byte_order, offset_in_file, - - ECAT7_filename, - frame_num, gate_num, data_num, bed_num, - warning_prefix, - warning_suffix) == - Succeeded::no) - { - matrix_close(mptr); - return Succeeded::no; - } - - VectorWithOffset scaling_factors(1); - VectorWithOffset file_offsets(1); - scaling_factors[0] = scale_factor; - file_offsets[0] = static_cast(offset_in_file); - strcat(header_filename, ".hv"); - interfile_header_filename = header_filename; - // WARNING: this has to be consistent with the reading - // in ECAT7_to_VoxelsOnCartesianGrid - const IndexRange3D range_3D (0,dimensions.z()-1, - -dimensions.y()/2,(-dimensions.y()/2)+dimensions.y()-1, - -dimensions.x()/2,(-dimensions.x()/2)+dimensions.x()-1); - write_basic_interfile_image_header(header_filename, ECAT7_filename, - *exam_info_sptr, - range_3D, voxel_size, origin, - type_of_numbers, byte_order, - scaling_factors, - file_offsets); - break; + case PetVolume: { + shared_ptr exam_info_sptr; + CartesianCoordinate3D dimensions; + CartesianCoordinate3D voxel_size; + Coordinate3D origin; + float scale_factor; + NumericType type_of_numbers; + ByteOrder byte_order; + long offset_in_file; + if (get_ECAT7_image_info( + exam_info_sptr, dimensions, voxel_size, origin, scale_factor, type_of_numbers, byte_order, offset_in_file, + + ECAT7_filename, frame_num, gate_num, data_num, bed_num, warning_prefix, warning_suffix) == Succeeded::no) { + matrix_close(mptr); + return Succeeded::no; } - - case AttenCor: + + VectorWithOffset scaling_factors(1); + VectorWithOffset file_offsets(1); + scaling_factors[0] = scale_factor; + file_offsets[0] = static_cast(offset_in_file); + strcat(header_filename, ".hv"); + interfile_header_filename = header_filename; + // WARNING: this has to be consistent with the reading + // in ECAT7_to_VoxelsOnCartesianGrid + const IndexRange3D range_3D(0, dimensions.z() - 1, -dimensions.y() / 2, (-dimensions.y() / 2) + dimensions.y() - 1, + -dimensions.x() / 2, (-dimensions.x() / 2) + dimensions.x() - 1); + write_basic_interfile_image_header(header_filename, ECAT7_filename, *exam_info_sptr, range_3D, voxel_size, origin, + type_of_numbers, byte_order, scaling_factors, file_offsets); + break; + } + + case AttenCor: case Byte3dSinogram: case Short3dSinogram: - case Float3dSinogram : - { - const int matnum = mat_numcod (frame_num, 1, gate_num, data_num, bed_num); - MatrixData* matrix = matrix_read( mptr, matnum, MAT_SUB_HEADER); - - if (matrix==NULL) - { - matrix_close(mptr); - warning("%s: Matrix not found at \"%d,1,%d,%d,%d\" in file '%s'.\n" - "%s", - warning_prefix, - frame_num, gate_num, data_num, bed_num, - ECAT7_filename.c_str(), warning_suffix); - return Succeeded::no; - } - - shared_ptr stream_ptr( - new fstream(ECAT7_filename.c_str(), ios::in | ios::binary)); - - shared_ptr pdfs_ptr(make_pdfs_from_matrix(mptr, matrix, stream_ptr)); - free_matrix_data(matrix); - - if (is_null_ptr(pdfs_ptr)) - { - matrix_close(mptr); - return Succeeded::no; - } - strcat(header_filename, ".hs"); - interfile_header_filename = header_filename; - write_basic_interfile_PDFS_header(header_filename, ECAT7_filename, *pdfs_ptr); + case Float3dSinogram: { + const int matnum = mat_numcod(frame_num, 1, gate_num, data_num, bed_num); + MatrixData* matrix = matrix_read(mptr, matnum, MAT_SUB_HEADER); + + if (matrix == NULL) { + matrix_close(mptr); + warning("%s: Matrix not found at \"%d,1,%d,%d,%d\" in file '%s'.\n" + "%s", + warning_prefix, frame_num, gate_num, data_num, bed_num, ECAT7_filename.c_str(), warning_suffix); + return Succeeded::no; + } + + shared_ptr stream_ptr(new fstream(ECAT7_filename.c_str(), ios::in | ios::binary)); + + shared_ptr pdfs_ptr(make_pdfs_from_matrix(mptr, matrix, stream_ptr)); + free_matrix_data(matrix); + + if (is_null_ptr(pdfs_ptr)) { + matrix_close(mptr); + return Succeeded::no; + } + strcat(header_filename, ".hs"); + interfile_header_filename = header_filename; + write_basic_interfile_PDFS_header(header_filename, ECAT7_filename, *pdfs_ptr); + + break; + } - break; - } - default: matrix_close(mptr); warning("%s: File type not handled for file '%s'.\n" - "%s", - warning_prefix, ECAT7_filename.c_str(), warning_suffix); + "%s", + warning_prefix, ECAT7_filename.c_str(), warning_suffix); return Succeeded::no; } - + delete[] header_filename; matrix_close(mptr); return Succeeded::yes; } +Succeeded +DiscretisedDensity_to_ECAT7(MatrixFile* mptr, DiscretisedDensity<3, float> const& density, const int frame_num, + const int gate_num, const int data_num, const int bed_num) { -Succeeded -DiscretisedDensity_to_ECAT7(MatrixFile *mptr, - DiscretisedDensity<3,float> const & density, - const int frame_num, const int gate_num, const int data_num, const int bed_num) -{ - const Main_header& mhead = *(mptr->mhptr); - DiscretisedDensityOnCartesianGrid<3,float> const & image = - dynamic_cast const&>(density); + DiscretisedDensityOnCartesianGrid<3, float> const& image = + dynamic_cast const&>(density); - - if (mhead.file_type!= PetVolume) - { + if (mhead.file_type != PetVolume) { warning("DiscretisedDensity_to_ECAT7: converting (f%d, g%d, d%d, b%d)\n" "Main header.file_type should be ImageFile\n", frame_num, gate_num, data_num, bed_num); return Succeeded::no; } - if (mhead.num_planes!=image.get_length()) - { + if (mhead.num_planes != image.get_length()) { warning("DiscretisedDensity_to_ECAT7: converting (f%d, g%d, d%d, b%d)\n" "Main header.num_planes should be %d\n", - frame_num, gate_num, data_num, bed_num,image.get_length()); + frame_num, gate_num, data_num, bed_num, image.get_length()); return Succeeded::no; } - const float voxel_size_z = image.get_grid_spacing()[1]/10;// convert to cm - const float voxel_size_y = image.get_grid_spacing()[2]/10; - const float voxel_size_x = image.get_grid_spacing()[3]/10; - if (fabs(mhead.plane_separation - voxel_size_z) > 1.E-4) - { + const float voxel_size_z = image.get_grid_spacing()[1] / 10; // convert to cm + const float voxel_size_y = image.get_grid_spacing()[2] / 10; + const float voxel_size_x = image.get_grid_spacing()[3] / 10; + if (fabs(mhead.plane_separation - voxel_size_z) > 1.E-4) { warning("DiscretisedDensity_to_ECAT7: converting (f%d, g%d, d%d, b%d)\n" "Main header.plane_separation should be %g\n", - frame_num, gate_num, data_num, bed_num,voxel_size_z); + frame_num, gate_num, data_num, bed_num, voxel_size_z); return Succeeded::no; } - - + Image_subheader ihead; img_subheader_zero_fill(ihead); - - const int z_size= image.get_length(); - const int y_size= image[0].get_length(); - const int x_size= image[0][0].get_length(); - + + const int z_size = image.get_length(); + const int y_size = image[0].get_length(); + const int x_size = image[0][0].get_length(); + // Setup subheader params // ihead.data_type set by save_volume7; - ihead.x_dimension= x_size; - ihead.y_dimension= y_size; - ihead.z_dimension= z_size; - ihead.x_pixel_size= voxel_size_x; - ihead.y_pixel_size= voxel_size_y; - ihead.z_pixel_size= voxel_size_z; - - ihead.num_dimensions= 3; - // ECAT7 origin is somewhere in the middle of the image. + ihead.x_dimension = x_size; + ihead.y_dimension = y_size; + ihead.z_dimension = z_size; + ihead.x_pixel_size = voxel_size_x; + ihead.y_pixel_size = voxel_size_y; + ihead.z_pixel_size = voxel_size_z; + + ihead.num_dimensions = 3; + // ECAT7 origin is somewhere in the middle of the image. // It seems at present consistent with the STIR origin. // WARNING this has to be consistent with reading (get_ECAT7_image_info) - const CartesianCoordinate3D ecat_origin = - image.get_physical_coordinates_for_indices(make_coordinate(0.F,0.F,0.F)); - ihead.x_offset= ecat_origin.x()/10; - ihead.y_offset= ecat_origin.y()/10; - ihead.z_offset= ecat_origin.z()/10; + const CartesianCoordinate3D ecat_origin = image.get_physical_coordinates_for_indices(make_coordinate(0.F, 0.F, 0.F)); + ihead.x_offset = ecat_origin.x() / 10; + ihead.y_offset = ecat_origin.y() / 10; + ihead.z_offset = ecat_origin.z() / 10; shared_ptr scanner_ptr; find_scanner(scanner_ptr, mhead); const float depth_of_interaction_factor = - 1 + - scanner_ptr->get_average_depth_of_interaction() / - scanner_ptr->get_inner_ring_radius(); + 1 + scanner_ptr->get_average_depth_of_interaction() / scanner_ptr->get_inner_ring_radius(); // note: CTI uses shead.x_resolution instead of mhead.bin_size - // but we don't have access to the sinogram here, and these 2 fields + // but we don't have access to the sinogram here, and these 2 fields // should be equal anyway. - ihead.recon_zoom= - mhead.bin_size/voxel_size_x * - scanner_ptr->get_default_num_arccorrected_bins()/ - float(image[0].size()) * - depth_of_interaction_factor; + ihead.recon_zoom = mhead.bin_size / voxel_size_x * scanner_ptr->get_default_num_arccorrected_bins() / float(image[0].size()) * + depth_of_interaction_factor; - ihead.decay_corr_fctr= 1; + ihead.decay_corr_fctr = 1; // set frame info (using the first frame in exam_info as we're writing that single image) set_time_frame_info(&ihead, mhead, density.get_exam_info(), 1U); @@ -1937,338 +1621,250 @@ DiscretisedDensity_to_ECAT7(MatrixFile *mptr, // use LLN function // easy, but wasteful: we need to copy the data first to a float buffer // then save_volume7 makes a short buffer... - const unsigned int buffer_size = - static_cast(x_size)* - static_cast(y_size)* - static_cast(z_size); + const unsigned int buffer_size = + static_cast(x_size) * static_cast(y_size) * static_cast(z_size); unique_ptr float_buffer(new float[buffer_size]); // save_volume7 does a swap in z, so we can't use the following - //copy(density.begin_all(), density.end_all(), float_buffer.get()); + // copy(density.begin_all(), density.end_all(), float_buffer.get()); { - float * current_buffer_pos = float_buffer.get(); - const unsigned int plane_size = - static_cast(x_size)* - static_cast(y_size); - for (int z=density.get_max_index(); z>= density.get_min_index(); --z) - { + float* current_buffer_pos = float_buffer.get(); + const unsigned int plane_size = static_cast(x_size) * static_cast(y_size); + for (int z = density.get_max_index(); z >= density.get_min_index(); --z) { copy(density[z].begin_all(), density[z].end_all(), current_buffer_pos); current_buffer_pos += plane_size; } } - if (save_volume7(mptr, &ihead, float_buffer.get(), - frame_num, gate_num,data_num, bed_num) != 0) - { + if (save_volume7(mptr, &ihead, float_buffer.get(), frame_num, gate_num, data_num, bed_num) != 0) { warning("Error writing image to ECAT7 file.\n" "No data written for frame %d, gate %d, data %d, bed %d\n", - frame_num, gate_num,data_num, bed_num); + frame_num, gate_num, data_num, bed_num); return Succeeded::no; - } - else - { + } else { return Succeeded::yes; } #endif } - -Succeeded -DiscretisedDensity_to_ECAT7(DiscretisedDensity<3,float> const & density, - string const & cti_name, string const&orig_name, - const Scanner& scanner, - const int frame_num, const int gate_num, const int data_num, const int bed_num) -{ +Succeeded +DiscretisedDensity_to_ECAT7(DiscretisedDensity<3, float> const& density, string const& cti_name, string const& orig_name, + const Scanner& scanner, const int frame_num, const int gate_num, const int data_num, + const int bed_num) { Main_header mhead; make_ECAT7_main_header(mhead, scanner, orig_name, density); - - MatrixFile* mptr= matrix_create (cti_name.c_str(), MAT_CREATE, &mhead); + MatrixFile* mptr = matrix_create(cti_name.c_str(), MAT_CREATE, &mhead); if (mptr == 0) return Succeeded::no; - Succeeded result = - DiscretisedDensity_to_ECAT7(mptr, - density, - frame_num, gate_num,data_num, bed_num); - - matrix_close(mptr); + Succeeded result = DiscretisedDensity_to_ECAT7(mptr, density, frame_num, gate_num, data_num, bed_num); + + matrix_close(mptr); return result; } - Succeeded -update_ECAT7_subheader(MatrixFile *mptr, Scan_subheader& shead, - const MatDir& matdir) -{ - const int ERROR=-1; +update_ECAT7_subheader(MatrixFile* mptr, Scan_subheader& shead, const MatDir& matdir) { + const int ERROR = -1; if (mptr->mhptr->file_type != #ifndef STIR_NO_NAMESPACES ::Sinogram #else CTISinogram #endif - ) + ) return Succeeded::no; - return - mat_write_scan_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, - &shead) == ERROR ? - Succeeded::no : Succeeded::yes; + return mat_write_scan_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, &shead) == ERROR ? Succeeded::no : Succeeded::yes; } - Succeeded -update_ECAT7_subheader(MatrixFile *mptr, Norm_subheader& shead, const MatDir& matdir) -{ - const int ERROR=-1; +update_ECAT7_subheader(MatrixFile* mptr, Norm_subheader& shead, const MatDir& matdir) { + const int ERROR = -1; if (mptr->mhptr->file_type != Normalization) return Succeeded::no; - return - mat_write_norm_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, - &shead) == ERROR ? - Succeeded::no : Succeeded::yes; + return mat_write_norm_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, &shead) == ERROR ? Succeeded::no : Succeeded::yes; } - Succeeded -update_ECAT7_subheader(MatrixFile *mptr, Image_subheader& shead, const MatDir& matdir) -{ - const int ERROR=-1; - if (!(mptr->mhptr->file_type == PetImage || - mptr->mhptr->file_type == ByteVolume || - mptr->mhptr->file_type == PetVolume)) +update_ECAT7_subheader(MatrixFile* mptr, Image_subheader& shead, const MatDir& matdir) { + const int ERROR = -1; + if (!(mptr->mhptr->file_type == PetImage || mptr->mhptr->file_type == ByteVolume || mptr->mhptr->file_type == PetVolume)) return Succeeded::no; - return - mat_write_image_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, - &shead) == ERROR ? - Succeeded::no : Succeeded::yes; + return mat_write_image_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, &shead) == ERROR ? Succeeded::no : Succeeded::yes; } Succeeded -update_ECAT7_subheader(MatrixFile *mptr, Attn_subheader& shead, const MatDir& matdir) -{ - const int ERROR=-1; +update_ECAT7_subheader(MatrixFile* mptr, Attn_subheader& shead, const MatDir& matdir) { + const int ERROR = -1; if (mptr->mhptr->file_type != AttenCor) return Succeeded::no; - return - mat_write_attn_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, - &shead) == ERROR ? - Succeeded::no : Succeeded::yes; + return mat_write_attn_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, &shead) == ERROR ? Succeeded::no : Succeeded::yes; } Succeeded -update_ECAT7_subheader(MatrixFile *mptr, Scan3D_subheader& shead, const MatDir& matdir) -{ - const int ERROR=-1; - if (!(mptr->mhptr->file_type == Byte3dSinogram || - mptr->mhptr->file_type == Short3dSinogram || - mptr->mhptr->file_type == Float3dSinogram)) +update_ECAT7_subheader(MatrixFile* mptr, Scan3D_subheader& shead, const MatDir& matdir) { + const int ERROR = -1; + if (!(mptr->mhptr->file_type == Byte3dSinogram || mptr->mhptr->file_type == Short3dSinogram || + mptr->mhptr->file_type == Float3dSinogram)) return Succeeded::no; - return - mat_write_Scan3D_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, - &shead) == ERROR ? - Succeeded::no : Succeeded::yes; + return mat_write_Scan3D_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, &shead) == ERROR ? Succeeded::no : Succeeded::yes; } template Succeeded -update_ECAT7_subheader(MatrixFile *mptr, SUBHEADER_TYPE& shead, - const int frame_num, const int gate_num, const int data_num, const int bed_num) -{ - const int ERROR=-1; - const int matnum = mat_numcod (frame_num, 1, gate_num, data_num, bed_num); - MatDir matdir; - if (matrix_find(mptr, matnum, &matdir) == ERROR) - return Succeeded::no; - - return update_ECAT7_subheader(mptr, shead, matdir); +update_ECAT7_subheader(MatrixFile* mptr, SUBHEADER_TYPE& shead, const int frame_num, const int gate_num, const int data_num, + const int bed_num) { + const int ERROR = -1; + const int matnum = mat_numcod(frame_num, 1, gate_num, data_num, bed_num); + MatDir matdir; + if (matrix_find(mptr, matnum, &matdir) == ERROR) + return Succeeded::no; + + return update_ECAT7_subheader(mptr, shead, matdir); } -namespace detail -{ +namespace detail { template -Succeeded -static -ProjData_to_ECAT7_help(MatrixFile *mptr, const NumericInfo& output_type_info, - ProjData const& proj_data, - const int frame_num, const int gate_num, - const int data_num, const int bed_num, - float scale_factor) -{ +Succeeded static ProjData_to_ECAT7_help(MatrixFile* mptr, const NumericInfo& output_type_info, + ProjData const& proj_data, const int frame_num, const int gate_num, const int data_num, + const int bed_num, float scale_factor) { const ByteOrder output_byte_order = - // output_type_info.integer_type() ? ByteOrder::get_native_order() : ByteOrder::big_endian; -ByteOrder::big_endian; + // output_type_info.integer_type() ? ByteOrder::get_native_order() : ByteOrder::big_endian; + ByteOrder::big_endian; - const short int cti_data_type = - find_ECAT_data_type(output_type_info.type_id(), output_byte_order); - if (cti_data_type==0) + const short int cti_data_type = find_ECAT_data_type(output_type_info.type_id(), output_byte_order); + if (cti_data_type == 0) return Succeeded::no; const Main_header& mhead = *(mptr->mhptr); { int num_planes = 0; - for(int segment_num=proj_data.get_min_segment_num(); - segment_num <= proj_data.get_max_segment_num(); - ++segment_num) - num_planes+= proj_data.get_num_axial_poss(segment_num); - - if (mhead.num_planes!=num_planes) // TODO check if this is the usual convention + for (int segment_num = proj_data.get_min_segment_num(); segment_num <= proj_data.get_max_segment_num(); ++segment_num) + num_planes += proj_data.get_num_axial_poss(segment_num); + + if (mhead.num_planes != num_planes) // TODO check if this is the usual convention { warning("ProjData_to_ECAT7: converting (f%d, g%d, d%d, b%d)\n" "Main header.num_planes should be %d", - frame_num, gate_num, data_num, bed_num,num_planes); + frame_num, gate_num, data_num, bed_num, num_planes); return Succeeded::no; } - } - + } // If scale_factor is not set (=0) then calculate the scale factor to apply. - if ( scale_factor == 0.0 ) { + if (scale_factor == 0.0) { scale_factor = 1; - + // If a integers are being written, and the suppress_scaling // find scale factor in case we're not writing floats - if (output_type_info.integer_type()) - { - scale_factor = 0;// set first to 0 to use maximum range of output type - for(int segment_num=proj_data.get_min_segment_num(); - segment_num <= proj_data.get_max_segment_num(); - ++segment_num) - { - const SegmentByView segment = - proj_data.get_segment_by_view(segment_num); - - find_scale_factor(scale_factor, - segment, - NumericInfo()); - } + if (output_type_info.integer_type()) { + scale_factor = 0; // set first to 0 to use maximum range of output type + for (int segment_num = proj_data.get_min_segment_num(); segment_num <= proj_data.get_max_segment_num(); ++segment_num) { + const SegmentByView segment = proj_data.get_segment_by_view(segment_num); + + find_scale_factor(scale_factor, segment, NumericInfo()); } + } } - + cout << "\nProjData_to_ECAT7: Will use scale factor " << scale_factor; - Scan3D_subheader scan3d_shead; + Scan3D_subheader scan3d_shead; Attn_subheader attn_shead; - if (mhead.file_type == AttenCor) - { + if (mhead.file_type == AttenCor) { make_subheader_for_ECAT7(attn_shead, mhead, *proj_data.get_proj_data_info_sptr()); // Setup remaining subheader params - attn_shead.data_type= cti_data_type; - attn_shead.scale_factor= scale_factor; + attn_shead.data_type = cti_data_type; + attn_shead.scale_factor = scale_factor; attn_shead.storage_order = ElAxVwRd; - } - else - { + } else { make_subheader_for_ECAT7(scan3d_shead, mhead, *proj_data.get_proj_data_info_sptr()); // Setup remaining subheader params - scan3d_shead.data_type= cti_data_type; - scan3d_shead.loss_correction_fctr= 1.F; - scan3d_shead.scale_factor= scale_factor; + scan3d_shead.data_type = cti_data_type; + scan3d_shead.loss_correction_fctr = 1.F; + scan3d_shead.scale_factor = scale_factor; scan3d_shead.storage_order = ElAxVwRd; // do frame times. - if (mhead.num_bed_pos>1) - { - // TODO not sure how to handle this - warning("Not filling in frame-start/duration for multi-bed position data in ECAT7 subheader"); - } - else - { - // set frame info (using the first frame in exam_info as we're writing that single proj_data) - set_time_frame_info(&scan3d_shead, mhead, proj_data.get_exam_info(), 1U); - } + if (mhead.num_bed_pos > 1) { + // TODO not sure how to handle this + warning("Not filling in frame-start/duration for multi-bed position data in ECAT7 subheader"); + } else { + // set frame info (using the first frame in exam_info as we're writing that single proj_data) + set_time_frame_info(&scan3d_shead, mhead, proj_data.get_exam_info(), 1U); + } } // allocate space in file, and write subheader { - const int ERROR=-1; - const int plane_size= proj_data.get_num_tangential_poss() * proj_data.get_num_views(); - + const int ERROR = -1; + const int plane_size = proj_data.get_num_tangential_poss() * proj_data.get_num_views(); + // TODO only ok if main_header.num_planes is set as above - int nblks = (mhead.num_planes*plane_size*sizeof(OutputType)+511)/512; - + int nblks = (mhead.num_planes * plane_size * sizeof(OutputType) + 511) / 512; + /* 3D sinograms subheader use one more block */ - if (mptr->mhptr->file_type == Byte3dSinogram || - mptr->mhptr->file_type == Short3dSinogram || - mptr->mhptr->file_type == Float3dSinogram) nblks += 1; - - int matnum = mat_numcod (frame_num, 1, gate_num, data_num, bed_num); + if (mptr->mhptr->file_type == Byte3dSinogram || mptr->mhptr->file_type == Short3dSinogram || + mptr->mhptr->file_type == Float3dSinogram) + nblks += 1; + + int matnum = mat_numcod(frame_num, 1, gate_num, data_num, bed_num); struct MatDir matdir; - if (matrix_find(mptr, matnum, &matdir) == ERROR) - { - int blkno = mat_enter(mptr->fptr, mptr->mhptr, matnum, nblks) ; - if( blkno == ERROR ) return( Succeeded::no ); - matdir.matnum = matnum ; - matdir.strtblk = blkno ; - matdir.endblk = matdir.strtblk + nblks - 1 ; - matdir.matstat = 1 ; - insert_mdir(matdir, mptr->dirlist) ; - } - - if (mhead.file_type == AttenCor) - { - if (mat_write_attn_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, - &attn_shead) == ERROR) - return Succeeded::no; + if (matrix_find(mptr, matnum, &matdir) == ERROR) { + int blkno = mat_enter(mptr->fptr, mptr->mhptr, matnum, nblks); + if (blkno == ERROR) + return (Succeeded::no); + matdir.matnum = matnum; + matdir.strtblk = blkno; + matdir.endblk = matdir.strtblk + nblks - 1; + matdir.matstat = 1; + insert_mdir(matdir, mptr->dirlist); } - else - { - if (mat_write_Scan3D_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, - &scan3d_shead) == ERROR) - return Succeeded::no; + + if (mhead.file_type == AttenCor) { + if (mat_write_attn_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, &attn_shead) == ERROR) + return Succeeded::no; + } else { + if (mat_write_Scan3D_subheader(mptr->fptr, mptr->mhptr, matdir.strtblk, &scan3d_shead) == ERROR) + return Succeeded::no; } - } - cout<<"\nProcessing segment number:"; - - for(int segment_num=proj_data.get_min_segment_num(); - segment_num <= proj_data.get_max_segment_num(); - ++segment_num) - { - cout<<" "< segment = - proj_data.get_segment_by_view(segment_num); + const SegmentByView segment = proj_data.get_segment_by_view(segment_num); - const long offset_in_file = - offset_in_ECAT_file(mptr, - frame_num, 1, gate_num, data_num, bed_num, - segment_num, NULL); + const long offset_in_file = offset_in_ECAT_file(mptr, frame_num, 1, gate_num, data_num, bed_num, segment_num, NULL); - if (offset_in_file<0) - { + if (offset_in_file < 0) { warning("ProjData_to_ECAT7: Error in determining offset into ECAT file for segment %d (f%d, g%d, d%d, b%d)\n" - "Maybe the file is too big?\n" - "No data written for this segment and all remaining segments", - segment_num, frame_num, gate_num, data_num, bed_num); - return Succeeded::no; + "Maybe the file is too big?\n" + "No data written for this segment and all remaining segments", + segment_num, frame_num, gate_num, data_num, bed_num); + return Succeeded::no; } - if (fseek(mptr->fptr, offset_in_file, SEEK_SET)) - { + if (fseek(mptr->fptr, offset_in_file, SEEK_SET)) { warning("\nProjData_to_ECAT7: error in fseek for segment %d (f%d, g%d, d%d, b%d)\n" - "No data written for this segment and all remaining segments\n", - segment_num, frame_num, gate_num, data_num, bed_num); + "No data written for this segment and all remaining segments\n", + segment_num, frame_num, gate_num, data_num, bed_num); return Succeeded::no; } - for (int view_num=proj_data.get_min_view_num(); view_num<=proj_data.get_max_view_num(); ++view_num) - for (int ax_pos_num=proj_data.get_min_axial_pos_num(segment_num); ax_pos_num <= proj_data.get_max_axial_pos_num(segment_num); ++ax_pos_num) - { - if (write_data_with_fixed_scale_factor(mptr->fptr, - segment[view_num][ax_pos_num], - output_type_info, - scale_factor, - output_byte_order, - /*can_corrupt_data=*/true) - == Succeeded::no) - { - warning("ProjData_to_ECAT7: error in writing segment %d (f%d, g%d, d%d, b%d)\n" - "Not all data written for this segment and none for all remaining segments\n", - segment_num, frame_num, gate_num, data_num, bed_num); - return Succeeded::no; - } + for (int view_num = proj_data.get_min_view_num(); view_num <= proj_data.get_max_view_num(); ++view_num) + for (int ax_pos_num = proj_data.get_min_axial_pos_num(segment_num); + ax_pos_num <= proj_data.get_max_axial_pos_num(segment_num); ++ax_pos_num) { + if (write_data_with_fixed_scale_factor(mptr->fptr, segment[view_num][ax_pos_num], output_type_info, scale_factor, + output_byte_order, + /*can_corrupt_data=*/true) == Succeeded::no) { + warning("ProjData_to_ECAT7: error in writing segment %d (f%d, g%d, d%d, b%d)\n" + "Not all data written for this segment and none for all remaining segments\n", + segment_num, frame_num, gate_num, data_num, bed_num); + return Succeeded::no; + } } // end of loop over ax_pos_num - - + } // end of loop on segments cout << endl; @@ -2277,64 +1873,47 @@ ByteOrder::big_endian; } // end of namespace detail -Succeeded -ProjData_to_ECAT7(MatrixFile *mptr, ProjData const& proj_data, - const int frame_num, const int gate_num, - const int data_num, const int bed_num, - float scale_factor) -{ - switch (mptr->mhptr->file_type) - { - case AttenCor: - // always use float to prevent problems with CTI utilities - return - detail::ProjData_to_ECAT7_help(mptr, NumericInfo(), proj_data, - frame_num, gate_num,data_num, bed_num, scale_factor); - case Float3dSinogram: - return - detail::ProjData_to_ECAT7_help(mptr, NumericInfo(), proj_data, - frame_num, gate_num,data_num, bed_num, scale_factor); - case Short3dSinogram: - // Note: this relies on sizeof(short)==2. However, find_ECAT_data_type will find out later if this is not true - return - detail::ProjData_to_ECAT7_help(mptr, NumericInfo(), proj_data, - frame_num, gate_num,data_num, bed_num, scale_factor); - case Byte3dSinogram: - return - detail::ProjData_to_ECAT7_help(mptr, NumericInfo(), proj_data, - frame_num, gate_num,data_num, bed_num, scale_factor); - default: - warning("ProjData_to_ECAT7: unsupported file type %d. No data written.", - mptr->mhptr->file_type); - return Succeeded::no; - } - +Succeeded +ProjData_to_ECAT7(MatrixFile* mptr, ProjData const& proj_data, const int frame_num, const int gate_num, const int data_num, + const int bed_num, float scale_factor) { + switch (mptr->mhptr->file_type) { + case AttenCor: + // always use float to prevent problems with CTI utilities + return detail::ProjData_to_ECAT7_help(mptr, NumericInfo(), proj_data, frame_num, gate_num, data_num, bed_num, + scale_factor); + case Float3dSinogram: + return detail::ProjData_to_ECAT7_help(mptr, NumericInfo(), proj_data, frame_num, gate_num, data_num, bed_num, + scale_factor); + case Short3dSinogram: + // Note: this relies on sizeof(short)==2. However, find_ECAT_data_type will find out later if this is not true + return detail::ProjData_to_ECAT7_help(mptr, NumericInfo(), proj_data, frame_num, gate_num, data_num, bed_num, + scale_factor); + case Byte3dSinogram: + return detail::ProjData_to_ECAT7_help(mptr, NumericInfo(), proj_data, frame_num, gate_num, data_num, bed_num, + scale_factor); + default: + warning("ProjData_to_ECAT7: unsupported file type %d. No data written.", mptr->mhptr->file_type); + return Succeeded::no; + } } -Succeeded -ProjData_to_ECAT7(ProjData const& proj_data, NumericType output_type, - string const & cti_name, string const & orig_name, - const int frame_num, const int gate_num, const int data_num, const int bed_num, - const bool write_as_attenuation, - float scale_factor) -{ +Succeeded +ProjData_to_ECAT7(ProjData const& proj_data, NumericType output_type, string const& cti_name, string const& orig_name, + const int frame_num, const int gate_num, const int data_num, const int bed_num, const bool write_as_attenuation, + float scale_factor) { Main_header mhead; - make_ECAT7_main_header(mhead, orig_name, - proj_data.get_exam_info(), - *proj_data.get_proj_data_info_sptr(), - write_as_attenuation, output_type); + make_ECAT7_main_header(mhead, orig_name, proj_data.get_exam_info(), *proj_data.get_proj_data_info_sptr(), write_as_attenuation, + output_type); - MatrixFile *mptr= matrix_create(cti_name.c_str(), MAT_CREATE, &mhead); + MatrixFile* mptr = matrix_create(cti_name.c_str(), MAT_CREATE, &mhead); - Succeeded result = - ProjData_to_ECAT7(mptr, proj_data, frame_num, gate_num,data_num, bed_num, scale_factor); - - matrix_close(mptr); + Succeeded result = ProjData_to_ECAT7(mptr, proj_data, frame_num, gate_num, data_num, bed_num, scale_factor); + + matrix_close(mptr); return result; } - END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT END_NAMESPACE_STIR diff --git a/src/IO/stir_ecat_common.cxx b/src/IO/stir_ecat_common.cxx index 3e3b2a1e02..6596bc7034 100644 --- a/src/IO/stir_ecat_common.cxx +++ b/src/IO/stir_ecat_common.cxx @@ -4,7 +4,7 @@ \file \ingroup ECAT - \brief Implementation of routines which convert ECAT6, ECAT7 and ECAT8 things into our building blocks and vice versa. + \brief Implementation of routines which convert ECAT6, ECAT7 and ECAT8 things into our building blocks and vice versa. \author Kris Thielemans \author PARAPET project @@ -31,25 +31,23 @@ #include "stir/ByteOrder.h" #include "stir/NumericType.h" -#include "stir/Scanner.h" +#include "stir/Scanner.h" #include "stir/ProjDataInfo.h" #include "stir/IO/stir_ecat_common.h" START_NAMESPACE_STIR START_NAMESPACE_ECAT - -void find_type_from_ECAT_data_type(NumericType& type, ByteOrder& byte_order, const short data_type) -{ - switch(data_type) - { +void +find_type_from_ECAT_data_type(NumericType& type, ByteOrder& byte_order, const short data_type) { + switch (data_type) { case ECAT_Byte_data_type: type = NumericType("signed integer", 1); - byte_order=ByteOrder::little_endian; + byte_order = ByteOrder::little_endian; return; case ECAT_I2_little_endian_data_type: type = NumericType("signed integer", 2); - byte_order=ByteOrder::little_endian; + byte_order = ByteOrder::little_endian; return; case ECAT_I2_big_endian_data_type: type = NumericType("signed integer", 2); @@ -57,20 +55,20 @@ void find_type_from_ECAT_data_type(NumericType& type, ByteOrder& byte_order, con return; case ECAT_R4_VAX_data_type: type = NumericType("float", 4); - byte_order=ByteOrder::little_endian; + byte_order = ByteOrder::little_endian; return; case ECAT_R4_IEEE_big_endian_data_type: type = NumericType("float", 4); - byte_order=ByteOrder::big_endian; + byte_order = ByteOrder::big_endian; return; case ECAT_I4_little_endian_data_type: type = NumericType("signed integer", 4); - byte_order=ByteOrder::little_endian; + byte_order = ByteOrder::little_endian; return; case ECAT_I4_big_endian_data_type: type = NumericType("signed integer", 4); - byte_order=ByteOrder::big_endian; - return; + byte_order = ByteOrder::big_endian; + return; default: error("find_type_from_ecat_data_type: unsupported data_type: %d", data_type); // just to avoid compiler warnings @@ -78,62 +76,53 @@ void find_type_from_ECAT_data_type(NumericType& type, ByteOrder& byte_order, con } } -short find_ECAT_data_type(const NumericType& type, const ByteOrder& byte_order) -{ +short +find_ECAT_data_type(const NumericType& type, const ByteOrder& byte_order) { if (!type.signed_type()) warning("find_ecat_data_type: ecat data support only signed types. Using the signed equivalent\n"); - if (type.integer_type()) - { - switch(type.size_in_bytes()) - { + if (type.integer_type()) { + switch (type.size_in_bytes()) { case 1: return ECAT_Byte_data_type; case 2: - return byte_order==ByteOrder::big_endian ? ECAT_I2_big_endian_data_type : ECAT_I2_little_endian_data_type; + return byte_order == ByteOrder::big_endian ? ECAT_I2_big_endian_data_type : ECAT_I2_little_endian_data_type; case 4: - return byte_order==ByteOrder::big_endian ? ECAT_I4_big_endian_data_type : ECAT_I4_little_endian_data_type; - default: - { - // write error message below - } + return byte_order == ByteOrder::big_endian ? ECAT_I4_big_endian_data_type : ECAT_I4_little_endian_data_type; + default: { + // write error message below } - } - else - { - switch(type.size_in_bytes()) - { + } + } else { + switch (type.size_in_bytes()) { case 4: - return byte_order==ByteOrder::big_endian ? ECAT_R4_IEEE_big_endian_data_type : ECAT_R4_VAX_data_type; - default: - { - // write error message below - } + return byte_order == ByteOrder::big_endian ? ECAT_R4_IEEE_big_endian_data_type : ECAT_R4_VAX_data_type; + default: { + // write error message below + } } } std::string number_format; std::size_t size_in_bytes; type.get_Interfile_info(number_format, size_in_bytes); - error("find_ecat_data_type: ecat does not support data type '%s' of %d bytes.\n", - number_format.c_str(), size_in_bytes); + error("find_ecat_data_type: ecat does not support data type '%s' of %d bytes.\n", number_format.c_str(), size_in_bytes); // just to satisfy compilers return short(0); } -short find_ECAT_system_type(const Scanner& scanner) -{ - switch(scanner.get_type()) - { +short +find_ECAT_system_type(const Scanner& scanner) { + switch (scanner.get_type()) { case Scanner::E921: - return 921; + return 921; case Scanner::E925: - return 925; - + return 925; + case Scanner::E931: - return 931; - + return 931; + case Scanner::E951: - return 951; - + return 951; + case Scanner::E953: return 953; @@ -141,8 +130,8 @@ short find_ECAT_system_type(const Scanner& scanner) return 961; case Scanner::E962: - return 962; - + return 962; + case Scanner::E966: return 966; @@ -153,54 +142,50 @@ short find_ECAT_system_type(const Scanner& scanner) return 42; default: - warning("\nfind_ecat_system_type: scanner \"%s\" currently unsupported. Returning 0.\n", - scanner.get_name().c_str()); + warning("\nfind_ecat_system_type: scanner \"%s\" currently unsupported. Returning 0.\n", scanner.get_name().c_str()); return 0; } } -Scanner* find_scanner_from_ECAT_system_type(const short system_type) -{ - switch(system_type) - { - case 128 : +Scanner* +find_scanner_from_ECAT_system_type(const short system_type) { + switch (system_type) { + case 128: return new Scanner(Scanner::RPT); - case 921 : + case 921: return new Scanner(Scanner::E921); - case 925 : + case 925: return new Scanner(Scanner::E925); - case 931 : - case 12 : + case 931: + case 12: return new Scanner(Scanner::E931); - case 951 : + case 951: return new Scanner(Scanner::E951); - case 953 : + case 953: return new Scanner(Scanner::E953); - case 961 : + case 961: return new Scanner(Scanner::E961); - case 962 : + case 962: return new Scanner(Scanner::E962); - case 966 : + case 966: return new Scanner(Scanner::E966); case 42: return new Scanner(Scanner::RATPET); - default : + default: return new Scanner(Scanner::Unknown_scanner); } } std::vector -find_segment_sequence(const ProjDataInfo& pdi) -{ +find_segment_sequence(const ProjDataInfo& pdi) { const int max_segment_num = pdi.get_max_segment_num(); - std::vector segment_sequence(2*max_segment_num+1); + std::vector segment_sequence(2 * max_segment_num + 1); // KT 25/10/2000 swapped segment order // ECAT 7 always stores segments as 0, -1, +1, ... segment_sequence[0] = 0; - for (int segment_num = 1; segment_num<=max_segment_num; ++segment_num) - { - segment_sequence[2*segment_num-1] = -segment_num; - segment_sequence[2*segment_num] = segment_num; + for (int segment_num = 1; segment_num <= max_segment_num; ++segment_num) { + segment_sequence[2 * segment_num - 1] = -segment_num; + segment_sequence[2 * segment_num] = segment_num; } return segment_sequence; } diff --git a/src/Shape_buildblock/Box3D.cxx b/src/Shape_buildblock/Box3D.cxx index 32f6a7c026..3be69018fe 100644 --- a/src/Shape_buildblock/Box3D.cxx +++ b/src/Shape_buildblock/Box3D.cxx @@ -30,12 +30,10 @@ START_NAMESPACE_STIR -const char * const -Box3D::registered_name = "Box3D"; +const char* const Box3D::registered_name = "Box3D"; -void -Box3D::initialise_keymap() -{ +void +Box3D::initialise_keymap() { parser.add_start_key("box parameters"); parser.add_key("length-x (in mm)", &length_x); parser.add_key("length-y (in mm)", &length_y); @@ -45,58 +43,42 @@ Box3D::initialise_keymap() } void -Box3D::set_defaults() -{ +Box3D::set_defaults() { Shape3DWithOrientation::set_defaults(); - length_x=0; - length_y=0; - length_z=0; + length_x = 0; + length_y = 0; + length_z = 0; } bool -Box3D:: -post_processing() -{ - if (Shape3DWithOrientation::post_processing()==true) +Box3D::post_processing() { + if (Shape3DWithOrientation::post_processing() == true) return true; - if (length_x <= 0) - { - warning("length_x should be positive, but is %g\n", length_x); - return true; - } - if (length_y <= 0) - { - warning("length_y should be positive, but is %g\n", length_y); - return true; - } - if (length_z <= 0) - { - warning("length_z should be positive, but is %g\n", length_z); - return true; - } + if (length_x <= 0) { + warning("length_x should be positive, but is %g\n", length_x); + return true; + } + if (length_y <= 0) { + warning("length_y should be positive, but is %g\n", length_y); + return true; + } + if (length_z <= 0) { + warning("length_z should be positive, but is %g\n", length_z); + return true; + } return false; } -Box3D::Box3D() -{ - set_defaults(); -} +Box3D::Box3D() { set_defaults(); } -Box3D::Box3D(const float length_xv, - const float length_yv, - const float length_zv, - const CartesianCoordinate3D& centre_v, - const Array<2,float>& direction_vectors) - : - length_x(length_xv), - length_y(length_yv), - length_z(length_zv) -{ +Box3D::Box3D(const float length_xv, const float length_yv, const float length_zv, const CartesianCoordinate3D& centre_v, + const Array<2, float>& direction_vectors) + : length_x(length_xv), length_y(length_yv), length_z(length_zv) { this->set_origin(centre_v); if (this->set_direction_vectors(direction_vectors) == Succeeded::no) error("Box3D constructor called with wrong direction_vectors"); -} +} #if 0 Box3D::Box3D(const float length_xv, @@ -117,28 +99,22 @@ Box3D::Box3D(const float length_xv, #endif -bool Box3D::is_inside_shape(const CartesianCoordinate3D& coord) const -{ - const CartesianCoordinate3D r = - this->transform_to_shape_coords(coord); - - const float distance_along_x_axis= r.x(); - const float distance_along_y_axis= r.y(); - const float distance_along_z_axis= r.z(); - - return - fabs(distance_along_x_axis)& coord) const { + const CartesianCoordinate3D r = this->transform_to_shape_coords(coord); -float -Box3D:: -get_geometric_volume()const -{ - return static_cast(length_x*length_y*length_z) / this->get_volume_of_unit_cell(); + const float distance_along_x_axis = r.x(); + const float distance_along_y_axis = r.y(); + const float distance_along_z_axis = r.z(); + + return fabs(distance_along_x_axis) < length_x / 2 && fabs(distance_along_y_axis) < length_y / 2 && + fabs(distance_along_z_axis) < length_z / 2; } +float +Box3D::get_geometric_volume() const { + return static_cast(length_x * length_y * length_z) / this->get_volume_of_unit_cell(); +} #if 0 // doesn't take scaling into account @@ -151,34 +127,22 @@ get_geometric_area()const } #endif -Shape3D* -Box3D:: -clone() const -{ - return static_cast(new Box3D(*this)); +Shape3D* +Box3D::clone() const { + return static_cast(new Box3D(*this)); } bool -Box3D:: -operator==(const Box3D& box) const -{ - const float tolerance = - std::min(length_z, std::min(length_x, length_y))/1000; - return - std::fabs(this->length_x - box.length_x) < tolerance - && std::fabs(this->length_y - box.length_y) < tolerance - && std::fabs(this->length_z - box.length_z) < tolerance - && Shape3DWithOrientation::operator==(box); +Box3D::operator==(const Box3D& box) const { + const float tolerance = std::min(length_z, std::min(length_x, length_y)) / 1000; + return std::fabs(this->length_x - box.length_x) < tolerance && std::fabs(this->length_y - box.length_y) < tolerance && + std::fabs(this->length_z - box.length_z) < tolerance && Shape3DWithOrientation::operator==(box); } bool -Box3D:: -operator==(const Shape3D& shape) const -{ - Box3D const * box_ptr = - dynamic_cast(&shape); - return - box_ptr != 0 && (*this == *box_ptr); +Box3D::operator==(const Shape3D& shape) const { + Box3D const* box_ptr = dynamic_cast(&shape); + return box_ptr != 0 && (*this == *box_ptr); } END_NAMESPACE_STIR diff --git a/src/Shape_buildblock/DiscretisedShape3D.cxx b/src/Shape_buildblock/DiscretisedShape3D.cxx index 1163800da2..da40e1da08 100644 --- a/src/Shape_buildblock/DiscretisedShape3D.cxx +++ b/src/Shape_buildblock/DiscretisedShape3D.cxx @@ -32,150 +32,109 @@ START_NAMESPACE_STIR void -DiscretisedShape3D:: -set_origin(const CartesianCoordinate3D& new_origin) -{ +DiscretisedShape3D::set_origin(const CartesianCoordinate3D& new_origin) { assert(this->get_origin() == density_sptr->get_origin()); Shape3D::set_origin(new_origin); density_sptr->set_origin(new_origin); } // TODO check code -float -DiscretisedShape3D:: -get_voxel_weight( - const CartesianCoordinate3D& voxel_centre, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& num_samples) const -{ +float +DiscretisedShape3D::get_voxel_weight(const CartesianCoordinate3D& voxel_centre, + const CartesianCoordinate3D& voxel_size, + const CartesianCoordinate3D& num_samples) const { assert(this->get_origin() == density_sptr->get_origin()); assert(voxel_size == image().get_voxel_size()); - const CartesianCoordinate3D r = - this->density_sptr->get_index_coordinates_for_physical_coordinates(voxel_centre); + const CartesianCoordinate3D r = this->density_sptr->get_index_coordinates_for_physical_coordinates(voxel_centre); const int x = round(r.x()); const int y = round(r.y()); const int z = round(r.z()); // check that r points to the middle of a voxel - assert(fabs(x-r.x())<=1E-6); - assert(fabs(y-r.y())<=1E-6); - assert(fabs(z-r.z())<=1E-6); - if ( z <= image().get_max_z() && z >= image().get_min_z() && - y <= image().get_max_y() && y >= image().get_min_y() && - x <= image().get_max_x() && x >= image().get_min_x()) + assert(fabs(x - r.x()) <= 1E-6); + assert(fabs(y - r.y()) <= 1E-6); + assert(fabs(z - r.z()) <= 1E-6); + if (z <= image().get_max_z() && z >= image().get_min_z() && y <= image().get_max_y() && y >= image().get_min_y() && + x <= image().get_max_x() && x >= image().get_min_x()) return image()[z][y][x]; else return 0.F; } -bool -DiscretisedShape3D:: -is_inside_shape(const CartesianCoordinate3D& coord) const -{ +bool +DiscretisedShape3D::is_inside_shape(const CartesianCoordinate3D& coord) const { assert(this->get_origin() == density_sptr->get_origin()); - return - get_voxel_weight(coord, - image().get_voxel_size(), - CartesianCoordinate3D(1,1,1)) > 0; + return get_voxel_weight(coord, image().get_voxel_size(), CartesianCoordinate3D(1, 1, 1)) > 0; } -void -DiscretisedShape3D:: -construct_volume(VoxelsOnCartesianGrid &new_image, const CartesianCoordinate3D& num_samples) const -{ +void +DiscretisedShape3D::construct_volume(VoxelsOnCartesianGrid& new_image, + const CartesianCoordinate3D& num_samples) const { zoom_image(new_image, this->image(), ZoomOptions::preserve_values); } -Shape3D* -DiscretisedShape3D:: -clone() const -{ +Shape3D* +DiscretisedShape3D::clone() const { assert(this->get_origin() == density_sptr->get_origin()); return new DiscretisedShape3D(*this); } -DiscretisedDensity<3,float>& -DiscretisedShape3D:: -get_discretised_density() -{ +DiscretisedDensity<3, float>& +DiscretisedShape3D::get_discretised_density() { return *density_sptr; } -const DiscretisedDensity<3,float>& -DiscretisedShape3D:: -get_discretised_density() const -{ +const DiscretisedDensity<3, float>& +DiscretisedShape3D::get_discretised_density() const { return *density_sptr; } -DiscretisedShape3D:: -DiscretisedShape3D() -{ - set_defaults(); -} +DiscretisedShape3D::DiscretisedShape3D() { set_defaults(); } -DiscretisedShape3D:: -DiscretisedShape3D(const VoxelsOnCartesianGrid& image_v) - : density_sptr(image_v.clone()) -{ +DiscretisedShape3D::DiscretisedShape3D(const VoxelsOnCartesianGrid& image_v) : density_sptr(image_v.clone()) { this->set_origin(image_v.get_origin()); this->filename = "FROM MEMORY"; } - - -DiscretisedShape3D:: -DiscretisedShape3D(const shared_ptr >& density_sptr_v) - : density_sptr(density_sptr_v->clone()) -{ - if(dynamic_cast *>(density_sptr.get()) == NULL) - { - error("DiscretisedShape3D can currently only handle images of type VoxelsOnCartesianGrid.\n"); +DiscretisedShape3D::DiscretisedShape3D(const shared_ptr>& density_sptr_v) + : density_sptr(density_sptr_v->clone()) { + if (dynamic_cast*>(density_sptr.get()) == NULL) { + error("DiscretisedShape3D can currently only handle images of type VoxelsOnCartesianGrid.\n"); } this->set_origin(density_sptr_v->get_origin()); this->filename = "FROM MEMORY"; } - -void -DiscretisedShape3D::initialise_keymap() -{ +void +DiscretisedShape3D::initialise_keymap() { Shape3D::initialise_keymap(); parser.add_start_key("Discretised Shape3D Parameters"); parser.add_key("input filename", &filename); parser.add_stop_key("END"); } - - void -DiscretisedShape3D::set_defaults() -{ +DiscretisedShape3D::set_defaults() { Shape3D::set_defaults(); } bool -DiscretisedShape3D:: -post_processing() -{ - if (Shape3D::post_processing()==true) +DiscretisedShape3D::post_processing() { + if (Shape3D::post_processing() == true) return true; - density_sptr = read_from_file >(filename); - if (!is_null_ptr(density_sptr)) - { - if (this->get_origin() != density_sptr->get_origin()) - { - warning("DiscretisedShape3D: Shape3D::origin and image origin are inconsistent. Using origin from image\n"); - this->set_origin(density_sptr->get_origin()); - } + density_sptr = read_from_file>(filename); + if (!is_null_ptr(density_sptr)) { + if (this->get_origin() != density_sptr->get_origin()) { + warning("DiscretisedShape3D: Shape3D::origin and image origin are inconsistent. Using origin from image\n"); + this->set_origin(density_sptr->get_origin()); } + } return is_null_ptr(density_sptr); } -const char * const -DiscretisedShape3D::registered_name = "Discretised Shape3D"; +const char* const DiscretisedShape3D::registered_name = "Discretised Shape3D"; END_NAMESPACE_STIR diff --git a/src/Shape_buildblock/Ellipsoid.cxx b/src/Shape_buildblock/Ellipsoid.cxx index 22ac330b79..a303c73689 100644 --- a/src/Shape_buildblock/Ellipsoid.cxx +++ b/src/Shape_buildblock/Ellipsoid.cxx @@ -31,13 +31,10 @@ START_NAMESPACE_STIR -const char * const -Ellipsoid::registered_name = "Ellipsoid"; +const char* const Ellipsoid::registered_name = "Ellipsoid"; - -void -Ellipsoid::initialise_keymap() -{ +void +Ellipsoid::initialise_keymap() { parser.add_start_key("Ellipsoid Parameters"); parser.add_key("radius-x (in mm)", &radii.x()); parser.add_key("radius-y (in mm)", &radii.y()); @@ -46,74 +43,57 @@ Ellipsoid::initialise_keymap() Shape3DWithOrientation::initialise_keymap(); } - - void -Ellipsoid::set_defaults() -{ +Ellipsoid::set_defaults() { Shape3DWithOrientation::set_defaults(); radii.fill(0); } - bool -Ellipsoid:: -post_processing() -{ - if (Shape3DWithOrientation::post_processing()==true) +Ellipsoid::post_processing() { + if (Shape3DWithOrientation::post_processing() == true) return true; - if (radii.x() <= 0) - { - warning("radii.x() should be positive, but is %g\n", radii.x()); - return true; - } - if (radii.y() <= 0) - { - warning("radii.y() should be positive, but is %g\n", radii.y()); - return true; - } - if (radii.z() <= 0) - { - warning("radii.z() should be positive, but is %g\n", radii.z()); - return true; - } + if (radii.x() <= 0) { + warning("radii.x() should be positive, but is %g\n", radii.x()); + return true; + } + if (radii.y() <= 0) { + warning("radii.y() should be positive, but is %g\n", radii.y()); + return true; + } + if (radii.z() <= 0) { + warning("radii.z() should be positive, but is %g\n", radii.z()); + return true; + } return false; } -Ellipsoid::Ellipsoid() -{ - set_defaults(); -} +Ellipsoid::Ellipsoid() { set_defaults(); } -Ellipsoid::Ellipsoid(const CartesianCoordinate3D& radii_v, - const CartesianCoordinate3D& centre_v, - const Array<2,float>& direction_vectors) - : - radii(radii_v) -{ +Ellipsoid::Ellipsoid(const CartesianCoordinate3D& radii_v, const CartesianCoordinate3D& centre_v, + const Array<2, float>& direction_vectors) + : radii(radii_v) { assert(radii.x() > 0); assert(radii.y() > 0); assert(radii.z() > 0); this->set_origin(centre_v); if (this->set_direction_vectors(direction_vectors) == Succeeded::no) error("Ellipsoid constructor called with wrong direction_vectors"); -} - +} + void -Ellipsoid:: -set_radii(const CartesianCoordinate3D& new_radii) -{ - radii = new_radii; +Ellipsoid::set_radii(const CartesianCoordinate3D& new_radii) { + radii = new_radii; assert(radii.x() > 0); assert(radii.y() > 0); assert(radii.z() > 0); } -float Ellipsoid::get_geometric_volume() const - { - return static_cast((4*radii.x()*radii.y()*radii.z()*_PI)/3) / get_volume_of_unit_cell(); - } +float +Ellipsoid::get_geometric_volume() const { + return static_cast((4 * radii.x() * radii.y() * radii.z() * _PI) / 3) / get_volume_of_unit_cell(); +} #if 0 // formula is incorrect except when it's a sphere @@ -126,47 +106,36 @@ get_geometric_area()const } #endif -bool Ellipsoid::is_inside_shape(const CartesianCoordinate3D& coord) const +bool +Ellipsoid::is_inside_shape(const CartesianCoordinate3D& coord) const { - const CartesianCoordinate3D r = - this->transform_to_shape_coords(coord); - - if (norm_squared(r / this->radii)<=1) - return true; - else - return false; + const CartesianCoordinate3D r = this->transform_to_shape_coords(coord); + + if (norm_squared(r / this->radii) <= 1) + return true; + else + return false; } - -Shape3D* Ellipsoid:: clone() const -{ - return static_cast(new Ellipsoid(*this)); +Shape3D* +Ellipsoid::clone() const { + return static_cast(new Ellipsoid(*this)); } bool -Ellipsoid:: -operator==(const Ellipsoid& cylinder) const -{ - const float tolerance = - std::min(radii.z(), std::min(radii.x(), radii.y()))/1000; - return - std::fabs(this->radii.x() - cylinder.radii.x()) < tolerance - && std::fabs(this->radii.y() - cylinder.radii.y()) < tolerance - && std::fabs(this->radii.z() - cylinder.radii.z()) < tolerance - && Shape3DWithOrientation::operator==(cylinder); -; +Ellipsoid::operator==(const Ellipsoid& cylinder) const { + const float tolerance = std::min(radii.z(), std::min(radii.x(), radii.y())) / 1000; + return std::fabs(this->radii.x() - cylinder.radii.x()) < tolerance && + std::fabs(this->radii.y() - cylinder.radii.y()) < tolerance && + std::fabs(this->radii.z() - cylinder.radii.z()) < tolerance && Shape3DWithOrientation::operator==(cylinder); + ; } bool -Ellipsoid:: -operator==(const Shape3D& shape) const -{ - Ellipsoid const * cylinder_ptr = - dynamic_cast(&shape); - return - cylinder_ptr != 0 && (*this == *cylinder_ptr); +Ellipsoid::operator==(const Shape3D& shape) const { + Ellipsoid const* cylinder_ptr = dynamic_cast(&shape); + return cylinder_ptr != 0 && (*this == *cylinder_ptr); } - END_NAMESPACE_STIR diff --git a/src/Shape_buildblock/EllipsoidalCylinder.cxx b/src/Shape_buildblock/EllipsoidalCylinder.cxx index 6c8a87525f..93ae4a4784 100644 --- a/src/Shape_buildblock/EllipsoidalCylinder.cxx +++ b/src/Shape_buildblock/EllipsoidalCylinder.cxx @@ -24,8 +24,8 @@ \author Sanida Mustafovic \author Kris Thielemans - \author C. Ross Schmidtlein (Added new parsing commands and functions so that a - sector of a cylinder can be defined and updated the + \author C. Ross Schmidtlein (Added new parsing commands and functions so that a + sector of a cylinder can be defined and updated the associated tests and volume and area calculations.)_ */ @@ -37,12 +37,10 @@ START_NAMESPACE_STIR -const char * const -EllipsoidalCylinder::registered_name = "Ellipsoidal Cylinder"; +const char* const EllipsoidalCylinder::registered_name = "Ellipsoidal Cylinder"; -void -EllipsoidalCylinder::initialise_keymap() -{ +void +EllipsoidalCylinder::initialise_keymap() { parser.add_start_key("Ellipsoidal Cylinder Parameters"); parser.add_key("radius-x (in mm)", &radius_x); parser.add_key("radius-y (in mm)", &radius_y); @@ -54,219 +52,166 @@ EllipsoidalCylinder::initialise_keymap() } void -EllipsoidalCylinder::set_defaults() -{ +EllipsoidalCylinder::set_defaults() { Shape3DWithOrientation::set_defaults(); - radius_x=0; - radius_y=0; - length=0; - theta_1=0.0; - theta_2=360.0; + radius_x = 0; + radius_y = 0; + length = 0; + theta_1 = 0.0; + theta_2 = 360.0; } bool -EllipsoidalCylinder:: -post_processing() -{ - if (Shape3DWithOrientation::post_processing()==true) +EllipsoidalCylinder::post_processing() { + if (Shape3DWithOrientation::post_processing() == true) return true; - if (radius_x <= 0) - { - warning("radius_x should be positive, but is %g\n", radius_x); - return true; - } - if (radius_y <= 0) - { - warning("radius_y should be positive, but is %g\n", radius_y); - return true; - } - if (length <= 0) - { - warning("length-z should be positive, but is %g\n", length); - return true; - } - if ((theta_1 < 0)||(theta_1>=360)) - { - warning("initial theta should be positive or less than 360 deg., but is %g\n", theta_1); - return true; - } - if ((theta_2 < 0)||(theta_2>360)) - { - warning("final theta should be positive or less than 360 deg., but is %g\n", theta_2); - return true; - } + if (radius_x <= 0) { + warning("radius_x should be positive, but is %g\n", radius_x); + return true; + } + if (radius_y <= 0) { + warning("radius_y should be positive, but is %g\n", radius_y); + return true; + } + if (length <= 0) { + warning("length-z should be positive, but is %g\n", length); + return true; + } + if ((theta_1 < 0) || (theta_1 >= 360)) { + warning("initial theta should be positive or less than 360 deg., but is %g\n", theta_1); + return true; + } + if ((theta_2 < 0) || (theta_2 > 360)) { + warning("final theta should be positive or less than 360 deg., but is %g\n", theta_2); + return true; + } return false; } +EllipsoidalCylinder::EllipsoidalCylinder() { set_defaults(); } +EllipsoidalCylinder::EllipsoidalCylinder(const float length_v, const float radius_xv, const float radius_yv, + const CartesianCoordinate3D& centre_v, const Array<2, float>& direction_vectors) + : length(length_v), radius_x(radius_xv), radius_y(radius_yv), theta_1(0.0F), theta_2(360.0F) -EllipsoidalCylinder::EllipsoidalCylinder() -{ - set_defaults(); -} - -EllipsoidalCylinder::EllipsoidalCylinder(const float length_v, - const float radius_xv, - const float radius_yv, - const CartesianCoordinate3D& centre_v, - const Array<2,float>& direction_vectors) - : - length(length_v), - radius_x(radius_xv), - radius_y(radius_yv), - theta_1(0.0F), - theta_2(360.0F) - - { - assert(length>0); - assert(radius_x>0); - assert(radius_y>0); + assert(length > 0); + assert(radius_x > 0); + assert(radius_y > 0); this->set_origin(centre_v); if (this->set_direction_vectors(direction_vectors) == Succeeded::no) error("Ellipsoid constructor called with wrong direction_vectors"); -} - -EllipsoidalCylinder::EllipsoidalCylinder(const float length_v, - const float radius_xv, - const float radius_yv, - const float theta_1v, - const float theta_2v, - const CartesianCoordinate3D& centre_v, - const Array<2,float>& direction_vectors) - : - length(length_v), - radius_x(radius_xv), - radius_y(radius_yv), - theta_1(theta_1v), - theta_2(theta_2v) - - +} + +EllipsoidalCylinder::EllipsoidalCylinder(const float length_v, const float radius_xv, const float radius_yv, const float theta_1v, + const float theta_2v, const CartesianCoordinate3D& centre_v, + const Array<2, float>& direction_vectors) + : length(length_v), radius_x(radius_xv), radius_y(radius_yv), theta_1(theta_1v), theta_2(theta_2v) + { - assert(length>0); - assert(radius_x>0); - assert(radius_y>0); + assert(length > 0); + assert(radius_x > 0); + assert(radius_y > 0); this->set_origin(centre_v); if (this->set_direction_vectors(direction_vectors) == Succeeded::no) error("Ellipsoid constructor called with wrong direction_vectors"); -} +} void -EllipsoidalCylinder:: -set_length(const float new_length) -{ - assert(new_length>0); +EllipsoidalCylinder::set_length(const float new_length) { + assert(new_length > 0); length = new_length; } void -EllipsoidalCylinder:: -set_radius_x(const float new_radius_x) -{ - assert(new_radius_x>0); +EllipsoidalCylinder::set_radius_x(const float new_radius_x) { + assert(new_radius_x > 0); radius_x = new_radius_x; } void -EllipsoidalCylinder:: -set_radius_y(const float new_radius_y) -{ - assert(new_radius_y>0); +EllipsoidalCylinder::set_radius_y(const float new_radius_y) { + assert(new_radius_y > 0); radius_y = new_radius_y; } - - -bool EllipsoidalCylinder::is_inside_shape(const CartesianCoordinate3D& coord) const +bool +EllipsoidalCylinder::is_inside_shape(const CartesianCoordinate3D& coord) const { - const CartesianCoordinate3D r = - this->transform_to_shape_coords(coord); - - const float distance_along_axis= r.z(); - - if (fabs(distance_along_axis)(_PI*theta_1/180.0); - const float phi_2 = - static_cast(_PI*theta_2/180.0); - // Adding theta cuts for partial cylinders from theta_1 to theta_2 - float theta_r = atan2(y_pos,x_pos); - if (theta_r < 0.0) - theta_r = static_cast(2.0 * _PI + theta_r); - return - (((phi_1 < phi_2)&&((theta_r >= phi_1)&&(theta_r <= phi_2))) || - ((phi_1 > phi_2)&&((theta_r >= phi_1)||(theta_r <= phi_2)))); - } - else + const CartesianCoordinate3D r = this->transform_to_shape_coords(coord); + + const float distance_along_axis = r.z(); + + if (fabs(distance_along_axis) < length / 2) { + if (square(r.x() / radius_x) + square(r.y() / radius_y) <= 1) { + const float x_pos = r.x(); + const float y_pos = r.y(); + const float phi_1 = static_cast(_PI * theta_1 / 180.0); + const float phi_2 = static_cast(_PI * theta_2 / 180.0); + // Adding theta cuts for partial cylinders from theta_1 to theta_2 + float theta_r = atan2(y_pos, x_pos); + if (theta_r < 0.0) + theta_r = static_cast(2.0 * _PI + theta_r); + return (((phi_1 < phi_2) && ((theta_r >= phi_1) && (theta_r <= phi_2))) || + ((phi_1 > phi_2) && ((theta_r >= phi_1) || (theta_r <= phi_2)))); + } else return false; - } - else return false; + } else + return false; } -float -EllipsoidalCylinder:: -get_geometric_volume()const - { - const float volume_of_unit_cell = this->get_volume_of_unit_cell(); - float A1=0, A2=0; - float T1 = theta_1; - float T2 = theta_2; - if (theta_1 == theta_2) - { - T1 = 0.0; - T2 = 360.0; - } - if (theta_1 == 360.0) T1 = 0.0; - if (theta_2 == 0.0) T2 = 360.0; - const float phi_1 = static_cast(T1*_PI/180.0); - const float phi_2 = static_cast(T2*_PI/180.0); - - // Begin Volume Calculation - if (T1 == 0.0 && T2 == 360.0) - return static_cast(_PI*radius_x*radius_y*length/volume_of_unit_cell); - if (radius_x == radius_y) - { - if (T1 < T2) - return static_cast(_PI*radius_x*radius_y*length* - (T2-T1)/360.0/volume_of_unit_cell); - else - return static_cast(_PI*radius_x*radius_y*length* - (360.0-T1+T2)/360.0/volume_of_unit_cell); - } - - if (T2 >= 0.0 && T2 < 90.0) //branch one - A2 = static_cast(atan2(radius_x / radius_y * fabs(tan(phi_2)), 1)); - if (T2 >= 90.0 && T2 < 180.0) //branch two - A2 = static_cast(atan2(radius_x / radius_y * fabs(tan(phi_2)), -1)); - if (T2 >= 180.0 && T2 < 270.0) //branch three - A2 = static_cast(2*_PI + atan2(-radius_x/radius_y * fabs(tan(phi_2)),-1)); - if (T2 >= 270.0 && T2 <= 360.0) //branch four - A2 = static_cast(2*_PI + atan2(-radius_x/radius_y * fabs(tan(phi_2)),1)); - - if (T1 >= 0.0 && T1 < 90.0) //branch one - A1 = static_cast(atan2(radius_x/radius_y * fabs(tan(phi_1)),1)); - if (T1 >= 90.0 && T1 < 180.0) //branch two - A1 = static_cast(atan2(radius_x/radius_y * fabs(tan(phi_1)),-1)); - if (T1 >= 180.0 && T1 < 270.0) //branch three - A1 = static_cast(2*_PI + atan2(-radius_x/radius_y * fabs(tan(phi_1)),-1)); - if (T1 >= 270.0 && T1 <= 360.0) //branch four - A1 = static_cast(2*_PI + atan2(-radius_x/radius_y * fabs(tan(phi_1)),1)); - - if (T1 > T2) - return static_cast(radius_x*radius_y/2.0* - (2.0*_PI - A2 + A1)*length/volume_of_unit_cell); - - return static_cast(radius_x*radius_y/2.0*(A2-A1)*length/volume_of_unit_cell); - } +float +EllipsoidalCylinder::get_geometric_volume() const { + const float volume_of_unit_cell = this->get_volume_of_unit_cell(); + float A1 = 0, A2 = 0; + float T1 = theta_1; + float T2 = theta_2; + if (theta_1 == theta_2) { + T1 = 0.0; + T2 = 360.0; + } + if (theta_1 == 360.0) + T1 = 0.0; + if (theta_2 == 0.0) + T2 = 360.0; + const float phi_1 = static_cast(T1 * _PI / 180.0); + const float phi_2 = static_cast(T2 * _PI / 180.0); + + // Begin Volume Calculation + if (T1 == 0.0 && T2 == 360.0) + return static_cast(_PI * radius_x * radius_y * length / volume_of_unit_cell); + if (radius_x == radius_y) { + if (T1 < T2) + return static_cast(_PI * radius_x * radius_y * length * (T2 - T1) / 360.0 / volume_of_unit_cell); + else + return static_cast(_PI * radius_x * radius_y * length * (360.0 - T1 + T2) / 360.0 / volume_of_unit_cell); + } + + if (T2 >= 0.0 && T2 < 90.0) // branch one + A2 = static_cast(atan2(radius_x / radius_y * fabs(tan(phi_2)), 1)); + if (T2 >= 90.0 && T2 < 180.0) // branch two + A2 = static_cast(atan2(radius_x / radius_y * fabs(tan(phi_2)), -1)); + if (T2 >= 180.0 && T2 < 270.0) // branch three + A2 = static_cast(2 * _PI + atan2(-radius_x / radius_y * fabs(tan(phi_2)), -1)); + if (T2 >= 270.0 && T2 <= 360.0) // branch four + A2 = static_cast(2 * _PI + atan2(-radius_x / radius_y * fabs(tan(phi_2)), 1)); + + if (T1 >= 0.0 && T1 < 90.0) // branch one + A1 = static_cast(atan2(radius_x / radius_y * fabs(tan(phi_1)), 1)); + if (T1 >= 90.0 && T1 < 180.0) // branch two + A1 = static_cast(atan2(radius_x / radius_y * fabs(tan(phi_1)), -1)); + if (T1 >= 180.0 && T1 < 270.0) // branch three + A1 = static_cast(2 * _PI + atan2(-radius_x / radius_y * fabs(tan(phi_1)), -1)); + if (T1 >= 270.0 && T1 <= 360.0) // branch four + A1 = static_cast(2 * _PI + atan2(-radius_x / radius_y * fabs(tan(phi_1)), 1)); + + if (T1 > T2) + return static_cast(radius_x * radius_y / 2.0 * (2.0 * _PI - A2 + A1) * length / volume_of_unit_cell); + + return static_cast(radius_x * radius_y / 2.0 * (A2 - A1) * length / volume_of_unit_cell); +} #if 0 // scaling of axes does not simply scale area @@ -340,38 +285,25 @@ get_geometric_area()const } #endif -Shape3D* -EllipsoidalCylinder:: -clone() const -{ - return static_cast(new EllipsoidalCylinder(*this)); +Shape3D* +EllipsoidalCylinder::clone() const { + return static_cast(new EllipsoidalCylinder(*this)); } bool -EllipsoidalCylinder:: -operator==(const EllipsoidalCylinder& cylinder) const -{ - const float tolerance = - std::min(length, std::min(radius_x, radius_y))/1000; - return - std::fabs(this->length - cylinder.length) < tolerance - && std::fabs(this->radius_x - cylinder.radius_x) < tolerance - && std::fabs(this->radius_y - cylinder.radius_y) < tolerance - && std::fabs(theta_1 - cylinder.theta_1) < .1F - && std::fabs(theta_2 - cylinder.theta_2) < .1F - && Shape3DWithOrientation::operator==(cylinder); - -; +EllipsoidalCylinder::operator==(const EllipsoidalCylinder& cylinder) const { + const float tolerance = std::min(length, std::min(radius_x, radius_y)) / 1000; + return std::fabs(this->length - cylinder.length) < tolerance && std::fabs(this->radius_x - cylinder.radius_x) < tolerance && + std::fabs(this->radius_y - cylinder.radius_y) < tolerance && std::fabs(theta_1 - cylinder.theta_1) < .1F && + std::fabs(theta_2 - cylinder.theta_2) < .1F && Shape3DWithOrientation::operator==(cylinder); + + ; } bool -EllipsoidalCylinder:: -operator==(const Shape3D& shape) const -{ - EllipsoidalCylinder const * cylinder_ptr = - dynamic_cast(&shape); - return - cylinder_ptr != 0 && (*this == *cylinder_ptr); +EllipsoidalCylinder::operator==(const Shape3D& shape) const { + EllipsoidalCylinder const* cylinder_ptr = dynamic_cast(&shape); + return cylinder_ptr != 0 && (*this == *cylinder_ptr); } END_NAMESPACE_STIR diff --git a/src/Shape_buildblock/RegisteredObject.cxx b/src/Shape_buildblock/RegisteredObject.cxx index 000beadb7c..6995d8842e 100644 --- a/src/Shape_buildblock/RegisteredObject.cxx +++ b/src/Shape_buildblock/RegisteredObject.cxx @@ -32,27 +32,26 @@ #ifdef __STIR_REGISTRY_NOT_INLINE -#pragma message("instantiating RegisteredObject") -#include "stir/Shape/Shape3D.h" +# pragma message("instantiating RegisteredObject") +# include "stir/Shape/Shape3D.h" // and others START_NAMESPACE_STIR template -RegisteredObject::RegistryType& -RegisteredObject::registry () -{ +RegisteredObject::RegistryType& +RegisteredObject::registry() { static RegistryType the_registry("None", 0); return the_registry; } # ifdef _MSC_VER -// prevent warning message on reinstantiation, +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) +# pragma warning(disable : 4660) # endif -template RegisteredObject; +template RegisteredObject; END_NAMESPACE_STIR diff --git a/src/Shape_buildblock/Shape3D.cxx b/src/Shape_buildblock/Shape3D.cxx index cfec8b9772..45aa215a82 100644 --- a/src/Shape_buildblock/Shape3D.cxx +++ b/src/Shape_buildblock/Shape3D.cxx @@ -36,7 +36,6 @@ using std::cerr; using std::endl; #endif - // Check the sampled elements of the voxel START_NAMESPACE_STIR @@ -44,30 +43,23 @@ START_NAMESPACE_STIR Shape3D* Shape3D::read_from_file(const string& filename) { // at the moment only this one - return new + return new DiscretisedShape3D(DiscretisedDensity<3,float>::read_from_file(filename)); } */ void -Shape3D:: -set_origin(const CartesianCoordinate3D& new_origin) -{ +Shape3D::set_origin(const CartesianCoordinate3D& new_origin) { this->origin = new_origin; } - void -Shape3D:: -translate(const CartesianCoordinate3D& direction) -{ - this->set_origin(this->get_origin() + direction); +Shape3D::translate(const CartesianCoordinate3D& direction) { + this->set_origin(this->get_origin() + direction); } -float -Shape3D:: -get_geometric_volume() const -{ +float +Shape3D::get_geometric_volume() const { return -1.F; } @@ -80,37 +72,23 @@ get_geometric_area() const } #endif -float -Shape3D:: -get_voxel_weight( - const CartesianCoordinate3D& voxel_centre, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& num_samples) const -{ - int value=0; - - for (float zsmall = -float(num_samples.z()-1)/num_samples.z()/2.F; - zsmall<=0.5F; - zsmall+=1.F/num_samples.z()) - { - for (float ysmall =-float(num_samples.y()-1)/num_samples.y()/2.F; - ysmall<=0.5F; - ysmall+=1.F/num_samples.y()) - { - for(float xsmall=-float(num_samples.x()-1)/num_samples.x()/2.F; - xsmall<=0.5F; - xsmall+=1.F/num_samples.x()) - { - { - const CartesianCoordinate3D r(zsmall,ysmall,xsmall); - if(is_inside_shape(voxel_centre+r*voxel_size)) - value += 1; - } +float +Shape3D::get_voxel_weight(const CartesianCoordinate3D& voxel_centre, const CartesianCoordinate3D& voxel_size, + const CartesianCoordinate3D& num_samples) const { + int value = 0; + + for (float zsmall = -float(num_samples.z() - 1) / num_samples.z() / 2.F; zsmall <= 0.5F; zsmall += 1.F / num_samples.z()) { + for (float ysmall = -float(num_samples.y() - 1) / num_samples.y() / 2.F; ysmall <= 0.5F; ysmall += 1.F / num_samples.y()) { + for (float xsmall = -float(num_samples.x() - 1) / num_samples.x() / 2.F; xsmall <= 0.5F; xsmall += 1.F / num_samples.x()) { + { + const CartesianCoordinate3D r(zsmall, ysmall, xsmall); + if (is_inside_shape(voxel_centre + r * voxel_size)) + value += 1; + } } } - } - return float(value)/(num_samples.z()*num_samples.y()*num_samples.x()); + return float(value) / (num_samples.z() * num_samples.y() * num_samples.x()); } /* Construct the volume- use the convexity, e.g @@ -119,13 +97,11 @@ get_voxel_weight( \bug Objects which are only at the edge of the image can be missed */ -void -Shape3D::construct_volume(VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& num_samples) const -{ - const CartesianCoordinate3D& voxel_size= image.get_voxel_size(); - const CartesianCoordinate3D& origin= image.get_origin(); - //if (norm(origin)>.00001) +void +Shape3D::construct_volume(VoxelsOnCartesianGrid& image, const CartesianCoordinate3D& num_samples) const { + const CartesianCoordinate3D& voxel_size = image.get_voxel_size(); + const CartesianCoordinate3D& origin = image.get_origin(); + // if (norm(origin)>.00001) // error("Shape3D::construct_volume currently ignores image origin (not shape origin)\n"); const int min_z = image.get_min_z(); const int min_y = image.get_min_y(); @@ -134,67 +110,50 @@ Shape3D::construct_volume(VoxelsOnCartesianGrid &image, const int max_y = image.get_max_y(); const int max_x = image.get_max_x(); - CartesianCoordinate3D crude_num_samples(1,1,1); + CartesianCoordinate3D crude_num_samples(1, 1, 1); + + for (int z = min_z; z <= max_z; z++) { + for (int y = min_y; y <= max_y; y++) + for (int x = min_x; x <= max_x; x++) - for(int z = min_z;z<=max_z;z++) - { - for(int y =min_y;y<=max_y;y++) - for(int x=min_x;x<=max_x;x++) - { - const CartesianCoordinate3D - current_index(static_cast(z), - static_cast(y), - static_cast(x)); - - //image[z][y][x] = get_voxel_weight(current_point,voxel_size,crude_num_samples); - - image[z][y][x] = - (is_inside_shape(current_index*voxel_size+origin)) - ? 1.F : 0.F; + const CartesianCoordinate3D current_index(static_cast(z), static_cast(y), static_cast(x)); + + // image[z][y][x] = get_voxel_weight(current_point,voxel_size,crude_num_samples); + + image[z][y][x] = (is_inside_shape(current_index * voxel_size + origin)) ? 1.F : 0.F; } } - - if (num_samples.x() == 1 && num_samples.y() == 1 && num_samples.z() == 1) + + if (num_samples.x() == 1 && num_samples.y() == 1 && num_samples.z() == 1) return; int num_recomputed = 0; - for(int z =min_z;z<=max_z;z++) - for(int y =min_y;y<=max_y;y++) - for(int x=min_x;x<= max_x;x++) - { - const float current_value = image[z][y][x]; - - // first check if we're already at an edge voxel - // Note: this allow fuzzy boundaries - bool recompute = current_value<.999F && current_value>.00F; - if (!recompute) - { - // check neighbour values. If they are all equal, we'll assume it's ok. - for(int i = z-1;!recompute && (i<=z+1);i++) - for(int j= y-1;!recompute && (j<=y+1);j++) - for(int k=x-1;!recompute && (k<=x+1);k++) - { - const float value_of_neighbour = - ((i < min_z) || (i> max_z) || - (j < min_y) || (j> max_y) || - (k < min_x) || (k> max_x) - ) ? 0 : image[i][j][k]; - recompute = (value_of_neighbour!=current_value); - } - } - if (recompute) - { - num_recomputed++; - const CartesianCoordinate3D - current_index(static_cast(z), - static_cast(y), - static_cast(x)); - image[z][y][x] = get_voxel_weight(current_index*voxel_size+origin,voxel_size,num_samples); - } + for (int z = min_z; z <= max_z; z++) + for (int y = min_y; y <= max_y; y++) + for (int x = min_x; x <= max_x; x++) { + const float current_value = image[z][y][x]; + + // first check if we're already at an edge voxel + // Note: this allow fuzzy boundaries + bool recompute = current_value < .999F && current_value > .00F; + if (!recompute) { + // check neighbour values. If they are all equal, we'll assume it's ok. + for (int i = z - 1; !recompute && (i <= z + 1); i++) + for (int j = y - 1; !recompute && (j <= y + 1); j++) + for (int k = x - 1; !recompute && (k <= x + 1); k++) { + const float value_of_neighbour = + ((i < min_z) || (i > max_z) || (j < min_y) || (j > max_y) || (k < min_x) || (k > max_x)) ? 0 : image[i][j][k]; + recompute = (value_of_neighbour != current_value); + } + } + if (recompute) { + num_recomputed++; + const CartesianCoordinate3D current_index(static_cast(z), static_cast(y), static_cast(x)); + image[z][y][x] = get_voxel_weight(current_index * voxel_size + origin, voxel_size, num_samples); + } } info(boost::format("Number of voxels recomputed with finer sampling : %1%") % num_recomputed); - } #if 0 @@ -222,28 +181,22 @@ void Shape3D::construct_slice(PixelsOnCartesianGrid &plane, plane[y][x]= get_voxel_weight(current_point,voxel_size, num_samples); } } - + #endif -void -Shape3D:: -set_defaults() -{ - origin[3] = origin[2] = origin[1] =0; +void +Shape3D::set_defaults() { + origin[3] = origin[2] = origin[1] = 0; } -void -Shape3D:: -initialise_keymap() -{ +void +Shape3D::initialise_keymap() { this->parser.add_key("origin (in mm)", &origin); } -std::string -Shape3D::parameter_info() -{ +std::string +Shape3D::parameter_info() { return ParsingObject::parameter_info(); } - END_NAMESPACE_STIR diff --git a/src/Shape_buildblock/Shape3DWithOrientation.cxx b/src/Shape_buildblock/Shape3DWithOrientation.cxx index 029a92401e..0001657bea 100644 --- a/src/Shape_buildblock/Shape3DWithOrientation.cxx +++ b/src/Shape_buildblock/Shape3DWithOrientation.cxx @@ -33,7 +33,6 @@ START_NAMESPACE_STIR - #if 0 void Shape3DWithOrientation:: @@ -69,69 +68,51 @@ set_directions_from_Euler_angles( } #endif - - -Shape3DWithOrientation::Shape3DWithOrientation() -{} - +Shape3DWithOrientation::Shape3DWithOrientation() {} Shape3DWithOrientation::Shape3DWithOrientation(const CartesianCoordinate3D& origin, - const Array<2,float>& direction_vectors) -: Shape3D(origin) -{ + const Array<2, float>& direction_vectors) + : Shape3D(origin) { if (this->set_direction_vectors(direction_vectors) == Succeeded::no) error("Shaped3DWithOrientation constructor called with wrong direction_vectors"); } Succeeded -Shape3DWithOrientation:: -set_direction_vectors(const Array<2,float>& directions) -{ +Shape3DWithOrientation::set_direction_vectors(const Array<2, float>& directions) { this->_directions = directions; if (this->_directions.size() != 3) return Succeeded::no; // set index offset to 1, such that matrix_multiply can be used with BasicCoordinate this->_directions.set_min_index(1); - for (int i=1; i<=this->_directions.get_max_index(); ++i) - { - this->_directions[i].set_min_index(1); - if (this->_directions[i].size() != 3) - return Succeeded::no; - } + for (int i = 1; i <= this->_directions.get_max_index(); ++i) { + this->_directions[i].set_min_index(1); + if (this->_directions[i].size() != 3) + return Succeeded::no; + } return Succeeded::yes; } bool -Shape3DWithOrientation:: -operator==(const Shape3DWithOrientation& s) const -{ +Shape3DWithOrientation::operator==(const Shape3DWithOrientation& s) const { const float tolerance = .001F; - return - norm(this->get_origin() - s.get_origin()) < tolerance - && norm(this->_directions[1] - s._directions[1]) < tolerance - && norm(this->_directions[2] - s._directions[2]) < tolerance - && norm(this->_directions[3] - s._directions[3]) < tolerance - && base_type::operator==(s); + return norm(this->get_origin() - s.get_origin()) < tolerance && norm(this->_directions[1] - s._directions[1]) < tolerance && + norm(this->_directions[2] - s._directions[2]) < tolerance && norm(this->_directions[3] - s._directions[3]) < tolerance && + base_type::operator==(s); } -float -Shape3DWithOrientation:: -get_volume_of_unit_cell() const -{ +float +Shape3DWithOrientation::get_volume_of_unit_cell() const { return std::fabs(determinant(this->get_direction_vectors())); } CartesianCoordinate3D -Shape3DWithOrientation:: -transform_to_shape_coords(const CartesianCoordinate3D& coord) const -{ - return - matrix_multiply(this->get_direction_vectors(), coord - this->get_origin()); +Shape3DWithOrientation::transform_to_shape_coords(const CartesianCoordinate3D& coord) const { + return matrix_multiply(this->get_direction_vectors(), coord - this->get_origin()); } -void Shape3DWithOrientation::scale(const CartesianCoordinate3D& scale3D) -{ +void +Shape3DWithOrientation::scale(const CartesianCoordinate3D& scale3D) { this->_directions[1] /= scale3D[1]; this->_directions[2] /= scale3D[2]; this->_directions[3] /= scale3D[3]; @@ -155,13 +136,11 @@ float Shape3DWithOrientation::get_angle_gamma()const return atan2(-dir_y.z(),_directions.x().z()); } #endif - -void -Shape3DWithOrientation:: -set_defaults() -{ + +void +Shape3DWithOrientation::set_defaults() { Shape3D::set_defaults(); - this->set_direction_vectors(diagonal_matrix(3,1.F)); + this->set_direction_vectors(diagonal_matrix(3, 1.F)); #if 0 // set alpha,beta,gamma to non-sensical values for parsing @@ -171,10 +150,8 @@ set_defaults() #endif } -void -Shape3DWithOrientation:: -initialise_keymap() -{ +void +Shape3DWithOrientation::initialise_keymap() { Shape3D::initialise_keymap(); #if 0 parser.add_key("Euler angle alpha (in degrees)", &alpha_in_degrees); @@ -185,9 +162,7 @@ initialise_keymap() } bool -Shape3DWithOrientation:: -post_processing() -{ +Shape3DWithOrientation::post_processing() { #if 0 if (alpha_in_degrees != 10000000.F || beta_in_degrees != 10000000.F @@ -212,19 +187,16 @@ post_processing() } #endif // make sure that indices etc are ok - if (this->set_direction_vectors(_directions) == Succeeded::no) - { - warning("Direction vectors should be a 3x3 matrix"); - return true; - } + if (this->set_direction_vectors(_directions) == Succeeded::no) { + warning("Direction vectors should be a 3x3 matrix"); + return true; + } return Shape3D::post_processing(); } void -Shape3DWithOrientation:: -set_key_values() -{ +Shape3DWithOrientation::set_key_values() { base_type::set_key_values(); #if 0 alpha_in_degrees = static_cast(get_angle_alpha()*180./_PI); diff --git a/src/Shape_buildblock/Shape_buildblock_registries.cxx b/src/Shape_buildblock/Shape_buildblock_registries.cxx index 576dba1f93..e123833a7e 100644 --- a/src/Shape_buildblock/Shape_buildblock_registries.cxx +++ b/src/Shape_buildblock/Shape_buildblock_registries.cxx @@ -25,7 +25,7 @@ \author Kris Thielemans \author C. Ross Schmidtlein (added stir::Box3D Shape class) - + */ #include "stir/Shape/Ellipsoid.h" diff --git a/src/SimSET/conv_SimSET_projdata_to_STIR.cxx b/src/SimSET/conv_SimSET_projdata_to_STIR.cxx index a682478d4f..f024d82308 100644 --- a/src/SimSET/conv_SimSET_projdata_to_STIR.cxx +++ b/src/SimSET/conv_SimSET_projdata_to_STIR.cxx @@ -15,8 +15,8 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup SimSET + \file + \ingroup SimSET \brief This program converts SimSET 3D sinograms to STIR format This program should normally be called from the conv_SimSET_projdata_to_STIR.sh script. @@ -24,7 +24,7 @@ \author Pablo Aguiar \author Charalampos Tsoumpas - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/ProjDataInterfile.h" @@ -42,50 +42,48 @@ #include #define NUMARG 12 - -int main(int argc,char **argv) -{ +int +main(int argc, char** argv) { using namespace stir; - static const char * const options[]={ - "argv[1] SimSET file\n", - "argv[2] SimSET file format\n", - "argv[3] Angles in SimSET file\n", - "argv[4] Bins in SimSET filele\n", - "argv[5] Axial slices in SimSET file\n", - "argv[6] FOV_radius in cm as given to simset binning module (max_td)\n", - "argv[7] range on Z value in cm as given to simset binning module\n", - "argv[8] STIR scanner name\n", - "argv[9] maximum ring difference to use for writing\n", - "argv[10] index of 3d-sinogram in file (0-based)\n", - "argv[11] STIR file name\n" - }; - if (argc!=NUMARG){ + static const char* const options[] = {"argv[1] SimSET file\n", + "argv[2] SimSET file format\n", + "argv[3] Angles in SimSET file\n", + "argv[4] Bins in SimSET filele\n", + "argv[5] Axial slices in SimSET file\n", + "argv[6] FOV_radius in cm as given to simset binning module (max_td)\n", + "argv[7] range on Z value in cm as given to simset binning module\n", + "argv[8] STIR scanner name\n", + "argv[9] maximum ring difference to use for writing\n", + "argv[10] index of 3d-sinogram in file (0-based)\n", + "argv[11] STIR file name\n"}; + if (argc != NUMARG) { std::cerr << "\n\nConvert SimSET to STIR\n\n"; std::cerr << "Not enough arguments !!! ..\n"; - for (int i=1;i(atof(argv[6])*10); // times 10 for mm - const float scanner_length = static_cast(atof(argv[7])*10); // times 10 for mm - const char * const scanner_name = argv[8]; - const int max_ring_difference=atoi(argv[9]); + const char* const simset_filename = argv[1]; + const char* const input_data_type = argv[2]; + const int num_views = atoi(argv[3]); + const int num_tangential_poss = atoi(argv[4]); + const int num_rings = atoi(argv[5]); + const float FOV_radius = static_cast(atof(argv[6]) * 10); // times 10 for mm + const float scanner_length = static_cast(atof(argv[7]) * 10); // times 10 for mm + const char* const scanner_name = argv[8]; + const int max_ring_difference = atoi(argv[9]); const int dataset_num = atoi(argv[10]); - const char * const stir_filename = argv[11]; - const int nitems=num_views*num_tangential_poss; + const char* const stir_filename = argv[11]; + const int nitems = num_views * num_tangential_poss; - if (num_tangential_poss%2 != 1) + if (num_tangential_poss % 2 != 1) warning("STIR can at present not handle simset data with an even " - "number of tangential positions.\n" - "Proceed at your own risk (but you will get artifacts in the images"); - FILE *file; - if( (file=fopen(simset_filename,"rb")) ==NULL){ + "number of tangential positions.\n" + "Proceed at your own risk (but you will get artifacts in the images"); + FILE* file; + if ((file = fopen(simset_filename, "rb")) == NULL) { error("Cannot open the simset file %s", simset_filename); } shared_ptr scanner_sptr(Scanner::get_scanner_from_name(scanner_name)); @@ -93,100 +91,75 @@ int main(int argc,char **argv) error("Scanner '%s' is not a valid name", scanner_name); { - const float STIR_scanner_length = - scanner_sptr->get_num_rings() * scanner_sptr->get_ring_spacing(); - if (fabs(STIR_scanner_length - scanner_length)>1.0) - { - warning("scanner length from SimSET %g does not match STIR scanner length %g.\n" - "Continuing anyway, but this is bad.", - scanner_length, STIR_scanner_length); - } + const float STIR_scanner_length = scanner_sptr->get_num_rings() * scanner_sptr->get_ring_spacing(); + if (fabs(STIR_scanner_length - scanner_length) > 1.0) { + warning("scanner length from SimSET %g does not match STIR scanner length %g.\n" + "Continuing anyway, but this is bad.", + scanner_length, STIR_scanner_length); + } } scanner_sptr->set_num_rings(num_rings); - scanner_sptr->set_ring_spacing(scanner_length/num_rings); - scanner_sptr->set_num_detectors_per_ring(num_views*2); - shared_ptr proj_data_info_sptr( - ProjDataInfo::ProjDataInfoCTI( scanner_sptr, - /*span=*/1, - /*max_delta=*/max_ring_difference, - num_views, - num_tangential_poss, - /*arc_corrected =*/ true)); - dynamic_cast(*proj_data_info_sptr). - set_tangential_sampling(2*FOV_radius/num_tangential_poss); + scanner_sptr->set_ring_spacing(scanner_length / num_rings); + scanner_sptr->set_num_detectors_per_ring(num_views * 2); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/1, + /*max_delta=*/max_ring_difference, num_views, + num_tangential_poss, + /*arc_corrected =*/true)); + dynamic_cast(*proj_data_info_sptr) + .set_tangential_sampling(2 * FOV_radius / num_tangential_poss); shared_ptr exam_info_sptr(new ExamInfo); - ProjDataInterfile proj_data(exam_info_sptr, proj_data_info_sptr, - stir_filename, std::ios::out); - - - if(strncmp(input_data_type,"fl",2)==0) - { - } - else - { - error("file format %s not valid. Only fl at present", input_data_type); - } + ProjDataInterfile proj_data(exam_info_sptr, proj_data_info_sptr, stir_filename, std::ios::out); + if (strncmp(input_data_type, "fl", 2) == 0) { + } else { + error("file format %s not valid. Only fl at present", input_data_type); + } // skip simset header - const long offset = 32768 + dataset_num*num_rings*(long(num_rings*nitems*4)); + const long offset = 32768 + dataset_num * num_rings * (long(num_rings * nitems * 4)); if (fseek(file, offset, SEEK_SET) != 0) - error("Error while skipping simset header and data sets (%ld). Maybe file too short?", offset); - Array<1,float> seq(0,(num_rings*num_rings*nitems)-1); + error("Error while skipping simset header and data sets (%ld). Maybe file too short?", offset); + Array<1, float> seq(0, (num_rings * num_rings * nitems) - 1); read_data(file, seq /*, byteorder */); - int i_ring_difference=0; - int n=0; - while(i_ring_difference<=max_ring_difference) + int i_ring_difference = 0; + int n = 0; + while (i_ring_difference <= max_ring_difference) { + int lim_down = 0; + int lim_up = lim_down + ((num_rings - i_ring_difference - 1) * (num_rings + 1)); + for (n = lim_down; n <= lim_up;) // Extraccion de los sinogramas de una serie !!! { - int lim_down=0; - int lim_up=lim_down+((num_rings-i_ring_difference-1)*(num_rings+1)); - for(n=lim_down;n<=lim_up;) //Extraccion de los sinogramas de una serie !!! - { - - Sinogram pos_sino = proj_data.get_empty_sinogram((n-lim_down)/(num_rings+1), i_ring_difference); - Sinogram neg_sino = proj_data.get_empty_sinogram((n-lim_down)/(num_rings+1), -i_ring_difference); - Sinogram::full_iterator pos_sino_iter = pos_sino.begin_all(); - Sinogram::full_iterator neg_sino_iter = neg_sino.begin_all(); - - int ii=nitems-1; - const int i_r1r2=(n + i_ring_difference)*nitems; - const int i_r2r1=(n + i_ring_difference*num_rings)*nitems; - - // get 2 sinograms from simset data - for(int i=0;i pos_sino = proj_data.get_empty_sinogram((n - lim_down) / (num_rings + 1), i_ring_difference); + Sinogram neg_sino = proj_data.get_empty_sinogram((n - lim_down) / (num_rings + 1), -i_ring_difference); + Sinogram::full_iterator pos_sino_iter = pos_sino.begin_all(); + Sinogram::full_iterator neg_sino_iter = neg_sino.begin_all(); + + int ii = nitems - 1; + const int i_r1r2 = (n + i_ring_difference) * nitems; + const int i_r2r1 = (n + i_ring_difference * num_rings) * nitems; + + // get 2 sinograms from simset data + for (int i = 0; i < nitems / 2; ++i) { + *pos_sino_iter++ = seq[i_r1r2 + ii]; + *neg_sino_iter++ = seq[i_r2r1 + ii]; + ii = ii - 1; + } + for (int i = nitems / 2; i < nitems; ++i) { + *neg_sino_iter++ = seq[i_r1r2 + ii]; + *pos_sino_iter++ = seq[i_r2r1 + ii]; + ii = ii - 1; + } + n = n + num_rings + 1; + proj_data.set_sinogram(pos_sino); + proj_data.set_sinogram(neg_sino); } + i_ring_difference = i_ring_difference + 1; + } fclose(file); return EXIT_SUCCESS; } - - - - - - - - - - - - diff --git a/src/SimSET/conv_to_SimSET_att_image.cxx b/src/SimSET/conv_to_SimSET_att_image.cxx index fa173ef38c..8cb69348c9 100644 --- a/src/SimSET/conv_to_SimSET_att_image.cxx +++ b/src/SimSET/conv_to_SimSET_att_image.cxx @@ -9,12 +9,12 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! @@ -24,16 +24,16 @@ \author Charalampos Tsoumpas \author Kris Thielemans - - + + \par Usage: \code conv_to_SimSET_image [SimSET_image_filename][original_image] \endcode - Output: "SimSET_image_filename".hv AND "SimSET_image_filename".v + Output: "SimSET_image_filename".hv AND "SimSET_image_filename".v - This is a utility program converts a transmission image (in units of cm^-1 and - for 511 keV) into a SimSET attenuation input file with index values + This is a utility program converts a transmission image (in units of cm^-1 and + for 511 keV) into a SimSET attenuation input file with index values from the table below (http://depts.washington.edu/simset/html/user_guide/user_guide_index.html). This is done by a very simple segmentation of the transmission image. \verbatim @@ -42,8 +42,8 @@ Air 0 //Implemented Water 1 //Implemented Blood 2 //implemented - Bone 3 //Implemented - Brain 4 + Bone 3 //Implemented + Brain 4 Heart 5 Lung 6 //Implemented Muscle 7 @@ -63,16 +63,16 @@ Tungsten 21 Liver 22 Fat 23 - LaBr3 24 - Low viscosity polycarbonate 25 - NEMA polyethylene 26 - Polymethyl methylcrylate 27 - Polystyrene fibers 28 + LaBr3 24 + Low viscosity polycarbonate 25 + NEMA polyethylene 26 + Polymethyl methylcrylate 27 + Polystyrene fibers 28 \endverbatim See the SimSET documentation for more details. - - If at least one attenuation value in the transmission image is not segmented either - implement the new attenuation indices or change the input image. + + If at least one attenuation value in the transmission image is not segmented either + implement the new attenuation indices or change the input image. HINT: If the image is produced by the STIR utility: generate_image, the subsampling parameters should be set to 1 when small voxels sizes are used. */ @@ -81,60 +81,52 @@ #include "stir/IO/interfile.h" #include "stir/IO/read_from_file.h" #include "stir/Succeeded.h" -#include -/***********************************************************/ -int main(int argc, char *argv[]) -{ +#include +/***********************************************************/ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR; - if (argc!=3) - { - std::cerr << "Usage:" << argv[0] - << " SimSET_image_filename original_image\n"; - return EXIT_FAILURE; - } - shared_ptr< DiscretisedDensity<3,float> > - input_image_sptr(read_from_file >(argv[2])); + if (argc != 3) { + std::cerr << "Usage:" << argv[0] << " SimSET_image_filename original_image\n"; + return EXIT_FAILURE; + } + shared_ptr> input_image_sptr(read_from_file>(argv[2])); std::string output_image_filename(argv[1]); - shared_ptr > - output_image_sptr(input_image_sptr->clone()); - bool is_implemented=true; - DiscretisedDensity<3,float>::full_iterator out_iter = output_image_sptr->begin_all(); - DiscretisedDensity<3,float>::const_full_iterator in_iter = input_image_sptr->begin_all_const(); - while( in_iter != input_image_sptr->end_all_const()) - { - // values from standard Simset file at 511keV - if (fabs(*in_iter-0.096)<0.004) // Water - *out_iter = 1.F; - else if (fabs(*in_iter-0.102)<0.004) // Blood - *out_iter = 2.F; - else if (fabs(*in_iter-0.01)<0.010001) // Air - *out_iter = 0.F; - else if (fabs(*in_iter-0.19669)<0.004) // Bone - *out_iter = 3.F; - else if (fabs(*in_iter-0.02468)<0.005) // Lung - *out_iter = 6.F; - else if (fabs(*in_iter-0.0011)<0.005) // air - *out_iter = 30.F; - else if (fabs(*in_iter-0.22548)<0.005) // Aluminum - *out_iter = 20.F; - else - { - is_implemented=false; - std::cerr << "\t" << *in_iter ; - } - ++in_iter; ++out_iter; + shared_ptr> output_image_sptr(input_image_sptr->clone()); + bool is_implemented = true; + DiscretisedDensity<3, float>::full_iterator out_iter = output_image_sptr->begin_all(); + DiscretisedDensity<3, float>::const_full_iterator in_iter = input_image_sptr->begin_all_const(); + while (in_iter != input_image_sptr->end_all_const()) { + // values from standard Simset file at 511keV + if (fabs(*in_iter - 0.096) < 0.004) // Water + *out_iter = 1.F; + else if (fabs(*in_iter - 0.102) < 0.004) // Blood + *out_iter = 2.F; + else if (fabs(*in_iter - 0.01) < 0.010001) // Air + *out_iter = 0.F; + else if (fabs(*in_iter - 0.19669) < 0.004) // Bone + *out_iter = 3.F; + else if (fabs(*in_iter - 0.02468) < 0.005) // Lung + *out_iter = 6.F; + else if (fabs(*in_iter - 0.0011) < 0.005) // air + *out_iter = 30.F; + else if (fabs(*in_iter - 0.22548) < 0.005) // Aluminum + *out_iter = 20.F; + else { + is_implemented = false; + std::cerr << "\t" << *in_iter; } + ++in_iter; + ++out_iter; + } - if(is_implemented==false) + if (is_implemented == false) std::cerr << "\nAt least one attenuation value (shown above) does not" - << "\ncorrespond to a SimSET attenuation index in the segmentation table." - << "\nImplement the new attenuation indices or change the input image. \n" - << "HINT: If produced by generate_image set the subsampling parameters to 1, \n." - << "when small voxels sizes are used.\n"; + << "\ncorrespond to a SimSET attenuation index in the segmentation table." + << "\nImplement the new attenuation indices or change the input image. \n" + << "HINT: If produced by generate_image set the subsampling parameters to 1, \n." + << "when small voxels sizes are used.\n"; // write to file as 1 byte without changing the scale - Succeeded success = - write_basic_interfile(output_image_filename, *output_image_sptr, - NumericType::UCHAR, 1.F); + Succeeded success = write_basic_interfile(output_image_filename, *output_image_sptr, NumericType::UCHAR, 1.F); return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } - diff --git a/src/SimSET/write_phg_image_info.c b/src/SimSET/write_phg_image_info.c index f3d6688604..8c9dc915a5 100644 --- a/src/SimSET/write_phg_image_info.c +++ b/src/SimSET/write_phg_image_info.c @@ -16,7 +16,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup simset \brief Write object-spec for PHG parameter file for SimSET \author Pablo Aguiar @@ -24,81 +24,77 @@ */ #include -#include +#include #include - + #define N_INPUTS 10 /* parse cmd-line and convert to cm */ -void assign_inputs(char **arg,int *nslices,int *xbins,int *ybins, - float *xMin,float *xMax,float *yMin,float *yMax, - float *zMin, float *zMax); +void assign_inputs(char** arg, int* nslices, int* xbins, int* ybins, float* xMin, float* xMax, float* yMin, float* yMax, + float* zMin, float* zMax); -int main(int argc,char **argv) -{ +int +main(int argc, char** argv) { int i; - double dz; - int nslices,xbins,ybins; - float xMin,xMax,yMin,yMax,zMin,zMax; + double dz; + int nslices, xbins, ybins; + float xMin, xMax, yMin, yMax, zMin, zMax; - char *inputs[]={ - "Number slices in object", - "Number of pixels in x-direction", - "Number of pixels in y-direction", - "xMin (mm)", - "xMax (mm)", - "yMin (mm)", - "yMax (mm)", - "zMin (mm)", - "zMax (mm)" - }; + char* inputs[] = {"Number slices in object", + "Number of pixels in x-direction", + "Number of pixels in y-direction", + "xMin (mm)", + "xMax (mm)", + "yMin (mm)", + "yMax (mm)", + "zMin (mm)", + "zMax (mm)"}; - if (argc==N_INPUTS) assign_inputs (argv,&nslices,&xbins,&ybins,&xMin,&xMax,&yMin,&yMax,&zMin,&zMax); - else - { - fprintf(stderr,"\nThis program writes the object-spec to stdout to\nhelp constructing a PHG parameter file for SimSET.\n"); - fprintf(stderr,"\nUsage:\nwrite_phg_image_info"); - for(i=0;i1?argv[1]:""); +int +Main(int argc, char** argv) { + FBP2DReconstruction reconstruction_object(argc > 1 ? argv[1] : ""); - return reconstruction_object.reconstruct() == Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; -} - - + return reconstruction_object.reconstruct() == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/analytic/FBP2D/FBP2DReconstruction.cxx b/src/analytic/FBP2D/FBP2DReconstruction.cxx index f734618498..78602558f9 100644 --- a/src/analytic/FBP2D/FBP2DReconstruction.cxx +++ b/src/analytic/FBP2D/FBP2DReconstruction.cxx @@ -46,61 +46,53 @@ #include #ifdef STIR_OPENMP -#include +# include #endif #include "stir/num_threads.h" START_NAMESPACE_STIR -const char * const -FBP2DReconstruction::registered_name = - "FBP2D"; +const char* const FBP2DReconstruction::registered_name = "FBP2D"; -void -FBP2DReconstruction:: -set_defaults() -{ +void +FBP2DReconstruction::set_defaults() { base_type::set_defaults(); alpha_ramp = 1; fc_ramp = 0.5; - pad_in_s=1; - display_level=0; // no display + pad_in_s = 1; + display_level = 0; // no display num_segments_to_combine = -1; back_projector_sptr.reset(new BackProjectorByBinUsingInterpolation( - /*use_piecewise_linear_interpolation = */true, - /*use_exact_Jacobian = */ false)); - + /*use_piecewise_linear_interpolation = */ true, + /*use_exact_Jacobian = */ false)); } -void -FBP2DReconstruction::initialise_keymap() -{ +void +FBP2DReconstruction::initialise_keymap() { base_type::initialise_keymap(); parser.add_start_key("FBP2DParameters"); parser.add_stop_key("End"); parser.add_key("num_segments_to_combine with SSRB", &num_segments_to_combine); - parser.add_key("Alpha parameter for Ramp filter", &alpha_ramp); - parser.add_key("Cut-off for Ramp filter (in cycles)",&fc_ramp); + parser.add_key("Alpha parameter for Ramp filter", &alpha_ramp); + parser.add_key("Cut-off for Ramp filter (in cycles)", &fc_ramp); parser.add_key("Transaxial extension for FFT", &pad_in_s); - parser.add_key("Display level",&display_level); + parser.add_key("Display level", &display_level); parser.add_parsing_key("Back projector type", &back_projector_sptr); } -void -FBP2DReconstruction:: -ask_parameters() -{ - +void +FBP2DReconstruction::ask_parameters() { + base_type::ask_parameters(); - num_segments_to_combine = ask_num("num_segments_to_combine (must be odd)",-1,101,-1); - alpha_ramp = ask_num(" Alpha parameter for Ramp filter ? ",0.,1., 1.); - fc_ramp = ask_num(" Cut-off frequency for Ramp filter ? ",0.,.5, 0.5); - pad_in_s = ask_num(" Transaxial extension for FFT : ",0,1, 1); - display_level = ask_num("Which images would you like to display \n\t(0: None, 1: Final, 2: filtered viewgrams) ? ", 0,2,0); + num_segments_to_combine = ask_num("num_segments_to_combine (must be odd)", -1, 101, -1); + alpha_ramp = ask_num(" Alpha parameter for Ramp filter ? ", 0., 1., 1.); + fc_ramp = ask_num(" Cut-off frequency for Ramp filter ? ", 0., .5, 0.5); + pad_in_s = ask_num(" Transaxial extension for FFT : ", 0, 1, 1); + display_level = ask_num("Which images would you like to display \n\t(0: None, 1: Final, 2: filtered viewgrams) ? ", 0, 2, 0); #if 0 // do not ask the user for the projectors to prevent them entering @@ -111,55 +103,48 @@ ask_parameters() BackProjectorByBin::ask_type_and_parameters(); } #endif - } -bool FBP2DReconstruction::post_processing() -{ +bool +FBP2DReconstruction::post_processing() { return base_type::post_processing(); } Succeeded -FBP2DReconstruction:: -set_up(shared_ptr const& target_data_sptr) -{ +FBP2DReconstruction::set_up(shared_ptr const& target_data_sptr) { if (base_type::set_up(target_data_sptr) == Succeeded::no) return Succeeded::no; - if (fc_ramp<=0 || fc_ramp>.5000000001) + if (fc_ramp <= 0 || fc_ramp > .5000000001) error(boost::format("Cut-off frequency has to be between 0 and .5 but is %g") % fc_ramp); - if (alpha_ramp<=0 || alpha_ramp>1.000000001) + if (alpha_ramp <= 0 || alpha_ramp > 1.000000001) error(boost::format("Alpha parameter for ramp has to be between 0 and 1 but is %g") % alpha_ramp); - if (pad_in_s<0 || pad_in_s>2) + if (pad_in_s < 0 || pad_in_s > 2) error(boost::format("padding factor has to be between 0 and 2 but is %d") % pad_in_s); - if (pad_in_s<1) + if (pad_in_s < 1) warning("Transaxial extension for FFT:=0 should ONLY be used when the non-zero data\n" "occupy only half of the FOV. Otherwise aliasing will occur!"); - if (num_segments_to_combine>=0 && num_segments_to_combine%2==0) + if (num_segments_to_combine >= 0 && num_segments_to_combine % 2 == 0) error(boost::format("num_segments_to_combine has to be odd (or -1), but is %d") % num_segments_to_combine); - if (num_segments_to_combine==-1) - { - const shared_ptr proj_data_info_cyl_sptr = - dynamic_pointer_cast(proj_data_ptr->get_proj_data_info_sptr()); + if (num_segments_to_combine == -1) { + const shared_ptr proj_data_info_cyl_sptr = + dynamic_pointer_cast(proj_data_ptr->get_proj_data_info_sptr()); - if (is_null_ptr(proj_data_info_cyl_sptr)) - num_segments_to_combine = 1; //cannot SSRB non-cylindrical data yet + if (is_null_ptr(proj_data_info_cyl_sptr)) + num_segments_to_combine = 1; // cannot SSRB non-cylindrical data yet + else { + if (proj_data_info_cyl_sptr->get_min_ring_difference(0) != proj_data_info_cyl_sptr->get_max_ring_difference(0) || + proj_data_info_cyl_sptr->get_num_segments() == 1) + num_segments_to_combine = 1; else - { - if (proj_data_info_cyl_sptr->get_min_ring_difference(0) != - proj_data_info_cyl_sptr->get_max_ring_difference(0) - || - proj_data_info_cyl_sptr->get_num_segments()==1) - num_segments_to_combine = 1; - else - num_segments_to_combine = 3; - } + num_segments_to_combine = 3; } + } if (is_null_ptr(back_projector_sptr)) error("Back projector not set."); @@ -167,31 +152,20 @@ set_up(shared_ptr const& target_data_sptr) return Succeeded::yes; } -std::string FBP2DReconstruction::method_info() const -{ +std::string +FBP2DReconstruction::method_info() const { return "FBP2D"; } -FBP2DReconstruction:: -FBP2DReconstruction(const std::string& parameter_filename) -{ +FBP2DReconstruction::FBP2DReconstruction(const std::string& parameter_filename) { initialise(parameter_filename); info(boost::format("%1%") % parameter_info()); } -FBP2DReconstruction::FBP2DReconstruction() -{ - set_defaults(); -} +FBP2DReconstruction::FBP2DReconstruction() { set_defaults(); } -FBP2DReconstruction:: -FBP2DReconstruction(const shared_ptr& proj_data_ptr_v, - const double alpha_ramp_v, - const double fc_ramp_v, - const int pad_in_s_v, - const int num_segments_to_combine_v -) -{ +FBP2DReconstruction::FBP2DReconstruction(const shared_ptr& proj_data_ptr_v, const double alpha_ramp_v, + const double fc_ramp_v, const int pad_in_s_v, const int num_segments_to_combine_v) { set_defaults(); alpha_ramp = alpha_ramp_v; @@ -201,44 +175,33 @@ FBP2DReconstruction(const shared_ptr& proj_data_ptr_v, proj_data_ptr = proj_data_ptr_v; } -Succeeded -FBP2DReconstruction:: -actual_reconstruct(shared_ptr > const & density_ptr) -{ +Succeeded +FBP2DReconstruction::actual_reconstruct(shared_ptr> const& density_ptr) { // perform SSRB - if (num_segments_to_combine>1) - { - const ProjDataInfoCylindrical& proj_data_info_cyl = - dynamic_cast - (*proj_data_ptr->get_proj_data_info_sptr()); - - // full_log << "SSRB combining " << num_segments_to_combine - // << " segments in input file to a new segment 0\n" << std::endl; - - shared_ptr - ssrb_info_sptr(SSRB(proj_data_info_cyl, - num_segments_to_combine, - 1, 0, - (num_segments_to_combine-1)/2 )); - shared_ptr - proj_data_to_FBP_ptr(new ProjDataInMemory (proj_data_ptr->get_exam_info_sptr(), ssrb_info_sptr)); - SSRB(*proj_data_to_FBP_ptr, *proj_data_ptr); - proj_data_ptr = proj_data_to_FBP_ptr; - } - else - { - // just use the proj_data_ptr we have already - } + if (num_segments_to_combine > 1) { + const ProjDataInfoCylindrical& proj_data_info_cyl = + dynamic_cast(*proj_data_ptr->get_proj_data_info_sptr()); + + // full_log << "SSRB combining " << num_segments_to_combine + // << " segments in input file to a new segment 0\n" << std::endl; + + shared_ptr ssrb_info_sptr( + SSRB(proj_data_info_cyl, num_segments_to_combine, 1, 0, (num_segments_to_combine - 1) / 2)); + shared_ptr proj_data_to_FBP_ptr(new ProjDataInMemory(proj_data_ptr->get_exam_info_sptr(), ssrb_info_sptr)); + SSRB(*proj_data_to_FBP_ptr, *proj_data_ptr); + proj_data_ptr = proj_data_to_FBP_ptr; + } else { + // just use the proj_data_ptr we have already + } // check if segment 0 has direct sinograms { - const float tan_theta = proj_data_ptr->get_proj_data_info_sptr()->get_tantheta(Bin(0,0,0,0)); - if(fabs(tan_theta ) > 1.E-4) - { - warning("FBP2D: segment 0 has non-zero tan(theta) %g", tan_theta); - return Succeeded::no; - } + const float tan_theta = proj_data_ptr->get_proj_data_info_sptr()->get_tantheta(Bin(0, 0, 0, 0)); + if (fabs(tan_theta) > 1.E-4) { + warning("FBP2D: segment 0 has non-zero tan(theta) %g", tan_theta); + return Succeeded::no; + } } float tangential_sampling; @@ -249,145 +212,113 @@ actual_reconstruct(shared_ptr > const & density_ptr) // arc-correction if necessary ArcCorrection arc_correction; bool do_arc_correction = false; - if (!is_null_ptr(dynamic_pointer_cast - (proj_data_ptr->get_proj_data_info_sptr()))) - { - // it's already arc-corrected - arc_corrected_proj_data_info_sptr = - proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(); - tangential_sampling = - dynamic_cast - (*proj_data_ptr->get_proj_data_info_sptr()).get_tangential_sampling(); - } - else - { - // TODO arc-correct to voxel_size - if (arc_correction.set_up(proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone()) == - Succeeded::no) - return Succeeded::no; - do_arc_correction = true; - // TODO full_log - warning("FBP2D will arc-correct data first"); - arc_corrected_proj_data_info_sptr = - arc_correction.get_arc_corrected_proj_data_info_sptr(); - tangential_sampling = - arc_correction.get_arc_corrected_proj_data_info().get_tangential_sampling(); - } - //ProjDataInterfile ramp_filtered_proj_data(arc_corrected_proj_data_info_sptr,"ramp_filtered"); - - VoxelsOnCartesianGrid& image = - dynamic_cast&>(*density_ptr); + if (!is_null_ptr(dynamic_pointer_cast(proj_data_ptr->get_proj_data_info_sptr()))) { + // it's already arc-corrected + arc_corrected_proj_data_info_sptr = proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(); + tangential_sampling = + dynamic_cast(*proj_data_ptr->get_proj_data_info_sptr()).get_tangential_sampling(); + } else { + // TODO arc-correct to voxel_size + if (arc_correction.set_up(proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone()) == Succeeded::no) + return Succeeded::no; + do_arc_correction = true; + // TODO full_log + warning("FBP2D will arc-correct data first"); + arc_corrected_proj_data_info_sptr = arc_correction.get_arc_corrected_proj_data_info_sptr(); + tangential_sampling = arc_correction.get_arc_corrected_proj_data_info().get_tangential_sampling(); + } + // ProjDataInterfile ramp_filtered_proj_data(arc_corrected_proj_data_info_sptr,"ramp_filtered"); + VoxelsOnCartesianGrid& image = dynamic_cast&>(*density_ptr); // set projector to be used for the calculations - back_projector_sptr->set_up(arc_corrected_proj_data_info_sptr, - density_ptr); - + back_projector_sptr->set_up(arc_corrected_proj_data_info_sptr, density_ptr); // set ramp filter with appropriate sizes - const int fft_size = - round(pow(2., ceil(log((double)(pad_in_s + 1)* arc_corrected_proj_data_info_sptr->get_num_tangential_poss()) / log(2.)))); - - RampFilter filter(tangential_sampling, - fft_size, - float(alpha_ramp), float(fc_ramp)); + const int fft_size = + round(pow(2., ceil(log((double)(pad_in_s + 1) * arc_corrected_proj_data_info_sptr->get_num_tangential_poss()) / log(2.)))); + + RampFilter filter(tangential_sampling, fft_size, float(alpha_ramp), float(fc_ramp)); back_projector_sptr->start_accumulating_in_new_target(); - shared_ptr - symmetries_sptr(back_projector_sptr->get_symmetries_used()->clone()); - + shared_ptr symmetries_sptr(back_projector_sptr->get_symmetries_used()->clone()); + set_num_threads(); { #ifdef STIR_OPENMP -#pragma omp for schedule(runtime) +# pragma omp for schedule(runtime) #endif - for (int view_num=proj_data_ptr->get_min_view_num(); view_num <= proj_data_ptr->get_max_view_num(); ++view_num) - { - const ViewSegmentNumbers vs_num(view_num, 0); - + for (int view_num = proj_data_ptr->get_min_view_num(); view_num <= proj_data_ptr->get_max_view_num(); ++view_num) { + const ViewSegmentNumbers vs_num(view_num, 0); + #ifndef NDEBUG -#ifdef STIR_OPENMP - info(boost::format("Thread %1% calculating view_num: %2%") % omp_get_thread_num() % view_num); -#endif +# ifdef STIR_OPENMP + info(boost::format("Thread %1% calculating view_num: %2%") % omp_get_thread_num() % view_num); +# endif #endif - - if (!symmetries_sptr->is_basic(vs_num)) - continue; - RelatedViewgrams viewgrams; + if (!symmetries_sptr->is_basic(vs_num)) + continue; + + RelatedViewgrams viewgrams; #ifdef STIR_OPENMP -#pragma omp critical(FBP2D_get_viewgrams) +# pragma omp critical(FBP2D_get_viewgrams) #endif - { - viewgrams = - proj_data_ptr->get_related_viewgrams(vs_num, symmetries_sptr); - } - - if (do_arc_correction) - viewgrams = - arc_correction.do_arc_correction(viewgrams); - - // now filter - for (RelatedViewgrams::iterator viewgram_iter = viewgrams.begin(); - viewgram_iter != viewgrams.end(); - ++viewgram_iter) - { + { viewgrams = proj_data_ptr->get_related_viewgrams(vs_num, symmetries_sptr); } + + if (do_arc_correction) + viewgrams = arc_correction.do_arc_correction(viewgrams); + + // now filter + for (RelatedViewgrams::iterator viewgram_iter = viewgrams.begin(); viewgram_iter != viewgrams.end(); + ++viewgram_iter) { #ifdef NRFFT - filter.apply(*viewgram_iter); + filter.apply(*viewgram_iter); #else - std::for_each(viewgram_iter->begin(), viewgram_iter->end(), - filter); + std::for_each(viewgram_iter->begin(), viewgram_iter->end(), filter); #endif - } - // ramp_filtered_proj_data.set_related_viewgrams(viewgrams); + } + // ramp_filtered_proj_data.set_related_viewgrams(viewgrams); - if(display_level>1) - display( viewgrams,viewgrams.find_max(),"Ramp filter"); + if (display_level > 1) + display(viewgrams, viewgrams.find_max(), "Ramp filter"); - // and backproject - back_projector_sptr->back_project(viewgrams); - } + // and backproject + back_projector_sptr->back_project(viewgrams); + } } // end of OPENMP pragma back_projector_sptr->get_output(*density_ptr); - + // Normalise the image const ProjDataInfoCylindrical& proj_data_info_cyl = - dynamic_cast - (*proj_data_ptr->get_proj_data_info_sptr()); + dynamic_cast(*proj_data_ptr->get_proj_data_info_sptr()); float magic_number = 1.F; - if (dynamic_cast(back_projector_sptr.get()) != 0) - { - // KT & Darren Hogg 17/05/2000 finally found the scale factor! - // TODO remove magic, is a scale factor in the backprojector - magic_number=2*proj_data_info_cyl.get_ring_radius()*proj_data_info_cyl.get_num_views()/proj_data_info_cyl.get_ring_spacing(); - } - else - { - if (proj_data_info_cyl.get_min_ring_difference(0)!= - proj_data_info_cyl.get_max_ring_difference(0)) - { - magic_number=.5F; - } + if (dynamic_cast(back_projector_sptr.get()) != 0) { + // KT & Darren Hogg 17/05/2000 finally found the scale factor! + // TODO remove magic, is a scale factor in the backprojector + magic_number = + 2 * proj_data_info_cyl.get_ring_radius() * proj_data_info_cyl.get_num_views() / proj_data_info_cyl.get_ring_spacing(); + } else { + if (proj_data_info_cyl.get_min_ring_difference(0) != proj_data_info_cyl.get_max_ring_difference(0)) { + magic_number = .5F; } + } #ifdef NEWSCALE // added binsize etc here to get units ok // only do this when the forward projector units are appropriate - image *= magic_number / proj_data_ptr->get_num_views() * - tangential_sampling/ - (image.get_voxel_size().x()*image.get_voxel_size().y()); + image *= magic_number / proj_data_ptr->get_num_views() * tangential_sampling / + (image.get_voxel_size().x() * image.get_voxel_size().y()); #else image *= magic_number / proj_data_ptr->get_num_views(); #endif - if (display_level>0) + if (display_level > 0) display(image, image.find_max(), "FBP image"); return Succeeded::yes; } - - END_NAMESPACE_STIR diff --git a/src/analytic/FBP2D/RampFilter.cxx b/src/analytic/FBP2D/RampFilter.cxx index 62c7cce4e7..95c6751daa 100644 --- a/src/analytic/FBP2D/RampFilter.cxx +++ b/src/analytic/FBP2D/RampFilter.cxx @@ -36,9 +36,9 @@ #include #include #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif #include @@ -52,77 +52,61 @@ START_NAMESPACE_STIR // by computing the analytic inverse Fourier transform of a cut-off ramp // times a Hamming window. -static inline float -ramp_filter_in_space(const int n, - const float sampledist, - const int length, - const float alpha, - const float fc) -{ - const double x = n*2*fc; +static inline float +ramp_filter_in_space(const int n, const float sampledist, const int length, const float alpha, const float fc) { + const double x = n * 2 * fc; // KT&Darren Hogg 17/05/2000 removed square(sampledist) as this introduced a scaling factor in the reconstructions - if (n==0) - return - static_cast((2*square(fc)*(-4 + alpha*(4 + square(_PI))))/(_PI/* *square(sampledist) */)); - else if (fabs(fabs(x)-1) < 1E-6) - return - static_cast( - -(square(2*fc)*(8*alpha + (-1 + alpha)*square(_PI)))/ - (4*_PI/* *square(sampledist) */)); + if (n == 0) + return static_cast((2 * square(fc) * (-4 + alpha * (4 + square(_PI)))) / (_PI /* *square(sampledist) */)); + else if (fabs(fabs(x) - 1) < 1E-6) + return static_cast(-(square(2 * fc) * (8 * alpha + (-1 + alpha) * square(_PI))) / (4 * _PI /* *square(sampledist) */)); else - return - static_cast( - square(2*fc)*( - -alpha - square(x) + 3*alpha*square(x) - square(square(x)) + - _PI*x*sin(_PI*x)*(-1 + square(x))* - (-alpha + (-1 + 2*alpha)*square(x)) + - cos(_PI*x)*(alpha - (1 + alpha)*square(x) + - (-1 + 2*alpha)*square(square(x))) - )/ - (_PI/* *square(sampledist) */*square(-1 + x)*square(x)*square(1 + x)) - ); + return static_cast(square(2 * fc) * + (-alpha - square(x) + 3 * alpha * square(x) - square(square(x)) + + _PI * x * sin(_PI * x) * (-1 + square(x)) * (-alpha + (-1 + 2 * alpha) * square(x)) + + cos(_PI * x) * (alpha - (1 + alpha) * square(x) + (-1 + 2 * alpha) * square(square(x)))) / + (_PI /* *square(sampledist) */ * square(-1 + x) * square(x) * square(1 + x))); } // KT&CL 03/08/99 insert max value for fc -RampFilter::RampFilter(float sampledist_v, int length , float alpha_v, float fc_v) - : +RampFilter::RampFilter(float sampledist_v, int length, float alpha_v, float fc_v) + : #ifdef NRFFT - Filter1D (length), + Filter1D(length), #endif - fc(std::min(fc_v, .5F)), alpha(alpha_v), sampledist(sampledist_v) -{ + fc(std::min(fc_v, .5F)), alpha(alpha_v), sampledist(sampledist_v) { start_timers(); // Necessary exit for the silly case when length==0 - if (length==0) + if (length == 0) return; #ifdef OLDRAMP - /* This is the straightforward implementation: - define it in complex space as abs(frequency). - This has a well-known problem that DC values are wrong. This is essentially because - the ramp filter is a continuous filter. Discrete convolution should be done - with the samples of the continuous fourier transform of the ramp. - */ - // KT&DH 17/05/2000 TODO: highly suspect that the scale factor is inappropriate -#error check scale factor in ramp filter! -/* As realft uses only positive frequencies, the filter needs to be defined - only for those frequencies, so it has length/2 elements. - However, in general the values are complex, so the numbers of - real numbers is 2*length/2==length. - */ - float f = 0.0; + /* This is the straightforward implementation: + define it in complex space as abs(frequency). + This has a well-known problem that DC values are wrong. This is essentially because + the ramp filter is a continuous filter. Discrete convolution should be done + with the samples of the continuous fourier transform of the ramp. + */ + // KT&DH 17/05/2000 TODO: highly suspect that the scale factor is inappropriate +# error check scale factor in ramp filter! + /* As realft uses only positive frequencies, the filter needs to be defined + only for those frequencies, so it has length/2 elements. + However, in general the values are complex, so the numbers of + real numbers is 2*length/2==length. + */ + float f = 0.0; for (Int i = 1; i <= length - 1; i += 2) { - f = (float) ((float) 0.5 * (i - 1) / length); - float nu_a = f ; + f = (float)((float)0.5 * (i - 1) / length); + float nu_a = f; if (f <= fc) filter[i] = nu_a * (alpha + (1. - alpha) * cos(_PI * f / fc)); else filter[i] = 0.0; - filter[i + 1] = 0.0; /* imaginary part */ + filter[i + 1] = 0.0; /* imaginary part */ } - if (0.5 <= fc) /* see realft for an explanation:data[2]=last real */ + if (0.5 <= fc) /* see realft for an explanation:data[2]=last real */ filter[2] = (0.5) * (alpha + (1. - alpha) * cos(_PI * f / fc)); else filter[2] = 0.; @@ -132,71 +116,63 @@ RampFilter::RampFilter(float sampledist_v, int length , float alpha_v, float fc_ - perform a discrete FT to find values in the frequency domain This gives better agreement with the filtering of a band-limited function with the analytic ramp (with cut-off). - In particular, it solves a problem with the DC component of the - filter. Sampling the ramp in the frequency domain gives 0 for + In particular, it solves a problem with the DC component of the + filter. Sampling the ramp in the frequency domain gives 0 for DC component, resulting in images with negative tails. */ - assert(length%2==0); + assert(length % 2 == 0); // first construct filter in 'real' space -#ifdef NRFFT +# ifdef NRFFT filter.set_offset(0); -#else - Array<1,float> filter(length); -#endif +# else + Array<1, float> filter(length); +# endif filter[0] = ramp_filter_in_space(0, sampledist, length, alpha, fc); // note: filter[length/2] is set twice for even length, but that's fine - for (int n = 1; n <= length/2; n += 1) - { + for (int n = 1; n <= length / 2; n += 1) { filter[n] = ramp_filter_in_space(n, sampledist, length, alpha, fc); - filter[length-n] = filter[n]; + filter[length - n] = filter[n]; } - //std::cerr <<"Ramp filter in real space = " < -#include +# include "stir/display.h" +# include "stir/IO/write_data.h" +# include +# include #endif #include #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif START_NAMESPACE_STIR -std::string ColsherFilter::parameter_info() const -{ +std::string +ColsherFilter::parameter_info() const { #ifdef BOOST_NO_STRINGSTREAM // dangerous for out-of-range, but 'old-style' ostrstream seems to need this char str[2000]; ostrstream s(str, 2000); #else std::ostringstream s; -#endif - s << "\nColsherFilter Parameters :=" +#endif + s << "\nColsherFilter Parameters :=" #ifdef NRFFT - << "\nFilter height := "<< height - << "\nFilter width := "<< width + << "\nFilter height := " << height << "\nFilter width := " << width #endif - << "\nMaximum aperture (theta_max) := "<< theta_max - << "\nCut-off in cycles along planar direction:= "<< fc_planar - << "\nCut-off in cycles along axial direction:= "<< fc_axial - << "\nAlpha parameter along planar direction := "< theta_max + .001F) { + warning("ColsherFilter::set_up called with theta %g larger than theta_max %g", theta, theta_max); + return Succeeded::no; + } start_timers(); - //*********** first construct filter on large grid + //*********** first construct filter on large grid /* - The Colsher filter is real-valued and symmetric. As we use - fourier_for_real_data, we have to arrange it in wrap-around order in the - axial dimension, but we need only the positive frequencies in + The Colsher filter is real-valued and symmetric. As we use + fourier_for_real_data, we have to arrange it in wrap-around order in the + axial dimension, but we need only the positive frequencies in tangential direction. */ - Array<2,std::complex > filter(IndexRange2D(height,width/2+1)); + Array<2, std::complex> filter(IndexRange2D(height, width / 2 + 1)); - // KT&Darren Hogg 03/07/2001 inserted correct scale factor + // KT&Darren Hogg 03/07/2001 inserted correct scale factor // TODO this assumes current value for the magic_number in backprojector - const float scale_factor = static_cast(4*_PI*d_a); - - for (int j = 0; j <= height/2; ++j) - { - const float fb = static_cast(j) / height; - const float nu_b = fb / d_b; - for (int k = 0; k <= width/2; ++k) - { - const float fa = (float) k / width; - const float nu_a = fa / d_a; - - float fil = 0; - if (fa < fc_planar && fb < fc_axial) - { - /* Colsher filter */ - const float omega = atan2(nu_b, nu_a); - const float psi = acos(sin(omega) * cos(theta)); - const float mod_nu = sqrt(nu_a * nu_a + nu_b * nu_b); - - if (cos(psi) >= cos(theta_max)) - fil = static_cast(mod_nu / 2. / _PI); - else - fil = static_cast(mod_nu / 4. / asin(sin(theta_max) / sin(psi))); - /* Apodizing Hanning window */; - fil *= - static_cast( - (alpha_planar + (1. - alpha_planar) * cos(_PI * fa / fc_planar)) - *(alpha_axial + (1. - alpha_axial)* cos(_PI * fb / fc_axial))); - fil *= scale_factor; - } - filter[j][k] = fil; - if (j>0) - filter[height-j][k] = fil; - } + const float scale_factor = static_cast(4 * _PI * d_a); + + for (int j = 0; j <= height / 2; ++j) { + const float fb = static_cast(j) / height; + const float nu_b = fb / d_b; + for (int k = 0; k <= width / 2; ++k) { + const float fa = (float)k / width; + const float nu_a = fa / d_a; + + float fil = 0; + if (fa < fc_planar && fb < fc_axial) { + /* Colsher filter */ + const float omega = atan2(nu_b, nu_a); + const float psi = acos(sin(omega) * cos(theta)); + const float mod_nu = sqrt(nu_a * nu_a + nu_b * nu_b); + + if (cos(psi) >= cos(theta_max)) + fil = static_cast(mod_nu / 2. / _PI); + else + fil = static_cast(mod_nu / 4. / asin(sin(theta_max) / sin(psi))); + /* Apodizing Hanning window */; + fil *= static_cast((alpha_planar + (1. - alpha_planar) * cos(_PI * fa / fc_planar)) * + (alpha_axial + (1. - alpha_axial) * cos(_PI * fb / fc_axial))); + fil *= scale_factor; + } + filter[j][k] = fil; + if (j > 0) + filter[height - j][k] = fil; } + } //*********** now find it on normal grid by passing to 'real' space - if (stretch_factor_planar>1 || stretch_factor_axial>1) - { - Array<2,float > colsher_real= - inverse_fourier_for_real_data_corrupting_input(filter); - // cut out tails. unfortunately that's a bit complicated because of wrap-around - colsher_real.resize(IndexRange2D(target_height,target_width)); - for (int j = 0; j < target_height/2; ++j) - { - for (int k = 0; k < target_width/2; k++) - { - if (j!=0) colsher_real[target_height-j][k] = colsher_real[j][k]; - if (j!=0 &&k!=0) colsher_real[target_height-j][target_width-k] = colsher_real[j][k]; - if (k!=0) colsher_real[j][target_width-k] = colsher_real[j][k]; - } - } - filter = fourier_for_real_data(colsher_real); + if (stretch_factor_planar > 1 || stretch_factor_axial > 1) { + Array<2, float> colsher_real = inverse_fourier_for_real_data_corrupting_input(filter); + // cut out tails. unfortunately that's a bit complicated because of wrap-around + colsher_real.resize(IndexRange2D(target_height, target_width)); + for (int j = 0; j < target_height / 2; ++j) { + for (int k = 0; k < target_width / 2; k++) { + if (j != 0) + colsher_real[target_height - j][k] = colsher_real[j][k]; + if (j != 0 && k != 0) + colsher_real[target_height - j][target_width - k] = colsher_real[j][k]; + if (k != 0) + colsher_real[j][target_width - k] = colsher_real[j][k]; + } } + filter = fourier_for_real_data(colsher_real); + } //*********** set kernel used for filtering - const Succeeded success= set_kernel_in_frequency_space(filter); + const Succeeded success = set_kernel_in_frequency_space(filter); stop_timers(); -#ifdef __DEBUG_COLSHER +# ifdef __DEBUG_COLSHER { // write to file /* a bit complicated because we can only write Array's of real numbers. Luckily, the Colsher filter is real in frequency space, so we can copy its real part into an Array of floats. */ - Array<2,float > real_filter(IndexRange2D(target_height,target_width/2+1)); - std::transform(filter.begin_all(), filter.end_all(), real_filter.begin_all(), - real_part/*std::real >*/); + Array<2, float> real_filter(IndexRange2D(target_height, target_width / 2 + 1)); + std::transform(filter.begin_all(), filter.end_all(), real_filter.begin_all(), real_part /*std::real >*/); char file[200]; - sprintf(file,"%s_%d_%d_%g.dat","new_colsher",target_width,target_height,theta); + sprintf(file, "%s_%d_%d_%g.dat", "new_colsher", target_width, target_height, theta); std::cout << "Saving filter : " << file << std::endl; std::ofstream s(file); - write_data(s,real_filter); + write_data(s, real_filter); } -#endif -#ifdef __DEBUG_COLSHER +# endif +# ifdef __DEBUG_COLSHER { - Array<2,float > PSF(IndexRange2D(-0,target_height/3,-target_width/3,target_width/3)); + Array<2, float> PSF(IndexRange2D(-0, target_height / 3, -target_width / 3, target_width / 3)); PSF.fill(0); - PSF[0][0]=1; + PSF[0][0] = 1; this->operator()(PSF); - display(PSF,"PSF",PSF.find_max()/20); + display(PSF, "PSF", PSF.find_max() / 20); } -#endif +# endif return success; } - -#else //NRFFT - -ColsherFilter::ColsherFilter(int height_v, int width_v, float gamma_v, float theta_max_v, - float d_a_v, float d_b_v, - float alpha_colsher_axial_v, float fc_colsher_axial_v, - float alpha_colsher_planar_v, float fc_colsher_planar_v) - : Filter2D(height_v, width_v),gamma(gamma_v), theta_max(theta_max_v), d_a(d_a_v), d_b(d_b_v), - alpha_axial(alpha_colsher_axial_v), fc_axial(fc_colsher_axial_v), - alpha_planar(alpha_colsher_planar_v), fc_planar(fc_colsher_planar_v) -{ - - if (height==0 || width==0) + +#else // NRFFT + +ColsherFilter::ColsherFilter(int height_v, int width_v, float gamma_v, float theta_max_v, float d_a_v, float d_b_v, + float alpha_colsher_axial_v, float fc_colsher_axial_v, float alpha_colsher_planar_v, + float fc_colsher_planar_v) + : Filter2D(height_v, width_v), gamma(gamma_v), theta_max(theta_max_v), d_a(d_a_v), d_b(d_b_v), + alpha_axial(alpha_colsher_axial_v), fc_axial(fc_colsher_axial_v), alpha_planar(alpha_colsher_planar_v), + fc_planar(fc_colsher_planar_v) { + + if (height == 0 || width == 0) return; - int k, j; - float fa, fb, omega, psi; - float mod_nu, nu_a, nu_b; - double fil; - /* - * The Colsher filter is real-valued, so it has only height*width elements, - * going from [1..height*width]. It is arranged in wrap-around order - * in both dimensions, see Num.Rec.C, page 523 - */ - - int ii = 1;//float fmax = 0.F; - - // TODO don't use 0.5* for upper boundary - for (j = 0; j <= 0.5 * height; j++) { - fb = (float) j / height; - nu_b = fb / d_b; - for (k = 0; k <= 0.5 * width; k++) { - fa = (float) k / width; - nu_a = fa / d_a; - if (fa == 0. && fb == 0.) { - filter[ii++] = 0.F; - continue; - } - - omega = atan2(nu_b, nu_a); - psi = acos(sin(omega) * sin(gamma)); - mod_nu = sqrt(nu_a * nu_a + nu_b * nu_b); - - /* Colsher formula = fil = mod_nu / 4. / asin(sin(theta_max) / sin(psi)); */ - if (cos(psi) >= cos(theta_max)) - fil = mod_nu / 2. / _PI; - else - fil = mod_nu / 4. / asin(sin(theta_max) / sin(psi)); - - - /* Apodizing Hanning window */; - //CL 250899 In order to make similar to the CTI program, we use a damping window - //for both planar and axial direction - - if (fa < fc_planar && fb < fc_axial) - filter[ii++] = - static_cast( - fil * (alpha_planar + (1. - alpha_planar) * cos(_PI * fa / fc_planar)) - *(alpha_axial + (1. - alpha_axial)* cos(_PI * fb / fc_axial))); - else - filter[ii++] = 0.F; - - } - - - for (k = int (-0.5 * width) + 1; k <= -1; k++) { - fa = (float) k / width; - nu_a = fa / d_a; - omega = atan2(nu_b, -nu_a); - psi = acos(sin(omega) * sin(gamma)); - - - mod_nu = sqrt(nu_a * nu_a + nu_b * nu_b); - - if (cos(psi) >= cos(theta_max)) - fil = mod_nu / 2. / _PI; - else - fil = mod_nu / 4. / asin(sin(theta_max) / sin(psi)); - - - if (-fa < fc_planar && fb < fc_axial) - filter[ii++] = - static_cast(fil * (alpha_planar + (1. - alpha_planar) * cos(_PI * (-fa) / fc_planar)) - *(alpha_axial + (1. - alpha_axial)* cos(_PI * fb / fc_axial))); - else - filter[ii++] = 0.F; - - } + int k, j; + float fa, fb, omega, psi; + float mod_nu, nu_a, nu_b; + double fil; + /* + * The Colsher filter is real-valued, so it has only height*width elements, + * going from [1..height*width]. It is arranged in wrap-around order + * in both dimensions, see Num.Rec.C, page 523 + */ + + int ii = 1; // float fmax = 0.F; + + // TODO don't use 0.5* for upper boundary + for (j = 0; j <= 0.5 * height; j++) { + fb = (float)j / height; + nu_b = fb / d_b; + for (k = 0; k <= 0.5 * width; k++) { + fa = (float)k / width; + nu_a = fa / d_a; + if (fa == 0. && fb == 0.) { + filter[ii++] = 0.F; + continue; + } + + omega = atan2(nu_b, nu_a); + psi = acos(sin(omega) * sin(gamma)); + mod_nu = sqrt(nu_a * nu_a + nu_b * nu_b); + + /* Colsher formula = fil = mod_nu / 4. / asin(sin(theta_max) / sin(psi)); */ + if (cos(psi) >= cos(theta_max)) + fil = mod_nu / 2. / _PI; + else + fil = mod_nu / 4. / asin(sin(theta_max) / sin(psi)); + + /* Apodizing Hanning window */; + // CL 250899 In order to make similar to the CTI program, we use a damping window + // for both planar and axial direction + + if (fa < fc_planar && fb < fc_axial) + filter[ii++] = static_cast(fil * (alpha_planar + (1. - alpha_planar) * cos(_PI * fa / fc_planar)) * + (alpha_axial + (1. - alpha_axial) * cos(_PI * fb / fc_axial))); + else + filter[ii++] = 0.F; } - - for (j = int (-0.5 * height) + 1; j <= -1; j++) { - fb = (float) j / height; - nu_b = fb / d_b; - for (k = 0; k <= 0.5 * width; k++) { - fa = (float) k / width; - nu_a = fa / d_a; - omega = atan2(-nu_b, nu_a); - psi = acos(sin(omega) * sin(gamma)); - - mod_nu = sqrt(nu_a * nu_a + nu_b * nu_b); - - if (cos(psi) >= cos(theta_max)) - fil = mod_nu / 2. / _PI; - else - fil = mod_nu / 4. / asin(sin(theta_max) / sin(psi)); - - - if (fa < fc_planar && -fb < fc_axial) - filter[ii++] = - static_cast(fil * (alpha_planar + (1. - alpha_planar) * cos(_PI * fa / fc_planar)) - *(alpha_axial + (1. - alpha_axial)* cos(_PI * (-fb) / fc_axial))); - else - filter[ii++] = 0.F; - - } - - for (k = int (-0.5 * width) + 1; k <= -1; k++) { - fa = (float) k / width; - nu_a = fa / d_a; - omega = atan2(-nu_b, -nu_a); - psi = acos(sin(omega) * sin(gamma)); - - mod_nu = sqrt(nu_a * nu_a + nu_b * nu_b); - - if (cos(psi) >= cos(theta_max)) - fil = mod_nu / 2. / _PI; - else - fil = mod_nu / 4. / asin(sin(theta_max) / sin(psi)); - - if (-fa < fc_planar && -fb < fc_axial) - filter[ii++] = - static_cast(fil * (alpha_planar + (1. - alpha_planar) * cos(_PI * (-fa) / fc_planar)) - *(alpha_axial + (1. - alpha_axial)* cos(_PI * (-fb) / fc_axial))); - else - filter[ii++] = 0.F; - - - } + + for (k = int(-0.5 * width) + 1; k <= -1; k++) { + fa = (float)k / width; + nu_a = fa / d_a; + omega = atan2(nu_b, -nu_a); + psi = acos(sin(omega) * sin(gamma)); + + mod_nu = sqrt(nu_a * nu_a + nu_b * nu_b); + + if (cos(psi) >= cos(theta_max)) + fil = mod_nu / 2. / _PI; + else + fil = mod_nu / 4. / asin(sin(theta_max) / sin(psi)); + + if (-fa < fc_planar && fb < fc_axial) + filter[ii++] = static_cast(fil * (alpha_planar + (1. - alpha_planar) * cos(_PI * (-fa) / fc_planar)) * + (alpha_axial + (1. - alpha_axial) * cos(_PI * fb / fc_axial))); + else + filter[ii++] = 0.F; } + } - // KT&Darren Hogg 03/07/2001 inserted correct scale factor - // TODO this assumes current value for the magic_number in backprojector - filter *= static_cast(4*_PI*d_a); + for (j = int(-0.5 * height) + 1; j <= -1; j++) { + fb = (float)j / height; + nu_b = fb / d_b; + for (k = 0; k <= 0.5 * width; k++) { + fa = (float)k / width; + nu_a = fa / d_a; + omega = atan2(-nu_b, nu_a); + psi = acos(sin(omega) * sin(gamma)); + + mod_nu = sqrt(nu_a * nu_a + nu_b * nu_b); + + if (cos(psi) >= cos(theta_max)) + fil = mod_nu / 2. / _PI; + else + fil = mod_nu / 4. / asin(sin(theta_max) / sin(psi)); + + if (fa < fc_planar && -fb < fc_axial) + filter[ii++] = static_cast(fil * (alpha_planar + (1. - alpha_planar) * cos(_PI * fa / fc_planar)) * + (alpha_axial + (1. - alpha_axial) * cos(_PI * (-fb) / fc_axial))); + else + filter[ii++] = 0.F; + } - -#ifdef __DEBUG_COLSHER + for (k = int(-0.5 * width) + 1; k <= -1; k++) { + fa = (float)k / width; + nu_a = fa / d_a; + omega = atan2(-nu_b, -nu_a); + psi = acos(sin(omega) * sin(gamma)); + + mod_nu = sqrt(nu_a * nu_a + nu_b * nu_b); + + if (cos(psi) >= cos(theta_max)) + fil = mod_nu / 2. / _PI; + else + fil = mod_nu / 4. / asin(sin(theta_max) / sin(psi)); + + if (-fa < fc_planar && -fb < fc_axial) + filter[ii++] = static_cast(fil * (alpha_planar + (1. - alpha_planar) * cos(_PI * (-fa) / fc_planar)) * + (alpha_axial + (1. - alpha_axial) * cos(_PI * (-fb) / fc_axial))); + else + filter[ii++] = 0.F; + } + } + + // KT&Darren Hogg 03/07/2001 inserted correct scale factor + // TODO this assumes current value for the magic_number in backprojector + filter *= static_cast(4 * _PI * d_a); + +# ifdef __DEBUG_COLSHER { char file[200]; - sprintf(file,"%s_%d_%d_%g.dat","old_colsher",width,height,_PI/2-gamma); + sprintf(file, "%s_%d_%d_%g.dat", "old_colsher", width, height, _PI / 2 - gamma); std::cout << "Saving filter : " << file << std::endl; std::ofstream s(file); - write_data(s,filter); + write_data(s, filter); } -#endif +# endif } -void Filter_proj_Colsher(Viewgram & view_i, - Viewgram & view_i1, - ColsherFilter& CFilter, - int PadS, int PadZ) -{ +void +Filter_proj_Colsher(Viewgram& view_i, Viewgram& view_i1, ColsherFilter& CFilter, int PadS, int PadZ) { // start_timers(); - + const int rmin = view_i.get_min_axial_pos_num(); const int rmax = view_i.get_max_axial_pos_num(); - int nrings = rmax - rmin + 1; + int nrings = rmax - rmin + 1; int nprojs = view_i.get_num_tangential_poss(); - - int width = (int) pow(2, ((int) ceil(log((PadS + 1.) * nprojs) / log(2.)))); - int height = (int) pow(2, ((int) ceil(log((PadZ + 1.) * nrings) / log(2.)))); - + + int width = (int)pow(2, ((int)ceil(log((PadS + 1.) * nprojs) / log(2.)))); + int height = (int)pow(2, ((int)ceil(log((PadZ + 1.) * nrings) / log(2.)))); + const int maxproj = view_i.get_max_tangential_pos_num(); const int minproj = view_i.get_min_tangential_pos_num(); - - int roffset = -rmin * width *2; - Array<1,float> data(1,2 * height * width); - - - for (int j = rmin; j <= rmax; j++) - { + + int roffset = -rmin * width * 2; + Array<1, float> data(1, 2 * height * width); + + for (int j = rmin; j <= rmax; j++) { for (int k = minproj; k <= maxproj; k++) { data[roffset + 2 * j * width + 2 * (k - minproj) + 1] = view_i[j][k]; data[roffset + 2 * j * width + 2 * (k - minproj) + 2] = view_i1[j][k]; } } - { - - CFilter.apply(data); - } - - - - - for (int j = rmin; j <= rmax; j++) - { - for (int k = minproj; k <= maxproj; k++) - { + { CFilter.apply(data); } + + for (int j = rmin; j <= rmax; j++) { + for (int k = minproj; k <= maxproj; k++) { view_i[j][k] = data[roffset + 2 * j * width + 2 * (k - minproj) + 1]; - view_i1[j][k] =data[roffset + 2 * j * width + 2 * (k - minproj) + 2]; + view_i1[j][k] = data[roffset + 2 * j * width + 2 * (k - minproj) + 2]; } } - + // stop_timers(); - } -#endif //NRFFT +#endif // NRFFT END_NAMESPACE_STIR diff --git a/src/analytic/FBP3DRP/FBP3DRP.cxx b/src/analytic/FBP3DRP/FBP3DRP.cxx index a21749f65e..e221d23c2f 100644 --- a/src/analytic/FBP3DRP/FBP3DRP.cxx +++ b/src/analytic/FBP3DRP/FBP3DRP.cxx @@ -1,9 +1,9 @@ // // -/*! - \file +/*! + \file \ingroup reconstructors - \brief Main program for FBP3DRP reconstruction + \brief Main program for FBP3DRP reconstruction \author Claire LABBE \author PARAPET project */ @@ -29,26 +29,21 @@ #include "stir/analytic/FBP3DRP/FBP3DRPReconstruction.h" #ifndef PARALLEL -#define Main main +# define Main main #else -#define Main master_main +# define Main master_main #endif #ifndef STIR_NO_NAMESPACE using std::endl; using std::cerr; -#endif +#endif USING_NAMESPACE_STIR - -int Main(int argc, char **argv) -{ - FBP3DRPReconstruction - reconstruction_object(argc>1?argv[1]:""); - - return reconstruction_object.reconstruct() == Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; -} - +int +Main(int argc, char** argv) { + FBP3DRPReconstruction reconstruction_object(argc > 1 ? argv[1] : ""); + return reconstruction_object.reconstruct() == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/analytic/FBP3DRP/FBP3DRPReconstruction.cxx b/src/analytic/FBP3DRP/FBP3DRPReconstruction.cxx index dfea6caed1..b64d6fbad1 100644 --- a/src/analytic/FBP3DRP/FBP3DRPReconstruction.cxx +++ b/src/analytic/FBP3DRP/FBP3DRPReconstruction.cxx @@ -1,5 +1,5 @@ -/*! - \file +/*! + \file \ingroup FBP3DRP \brief FBP3DRP reconstruction implementation \author Kris Thielemans @@ -33,9 +33,9 @@ KT 05/10/2003 - decrease dependency on symmetries by using symmetries_ptr->is_basic(). - Before this, we relied explicitly on the range + Before this, we relied explicitly on the range 0<=segment_num, 0<=view_num<=num_views()/4 - This range was fine when using the interpolating backprojector + This range was fine when using the interpolating backprojector and x and y voxel size are equal. - moved some 2D-reconstruction stuff to FBP2DReconstruction class. - merged Parameter class into Reconstruction class @@ -46,11 +46,11 @@ - corrected bug in virtual_ring_offset in case of images with an even number of planes - some adjustements to allow for even number of planes - - make sure that everything works when there are no missing projections + - make sure that everything works when there are no missing projections in the data (i.e. rmin>rmin_orig) KT 11/04/2000 - removed (old!) bug by adjusting range for rmin (and hence rmax) - to use 'floor' instead of 'ceil'. Result was that sometimes 1 + to use 'floor' instead of 'ceil'. Result was that sometimes 1 missing projection was not filled in. So, better axial uniformity now. - moved rmin,rmax determination to a separate function, as this is now more complicated They are now determined in virtual_ring_units, even for the span case. span case @@ -64,12 +64,12 @@ - approximate analytic integral over delta by having a 1/2 in the backprojection of the last segment */ -//CL 1st June 1999 +// CL 1st June 1999 // DIstinguish the alpha and Nyquist parameters from RAmp and Colsher filter // by alpha_ramp and alpha_colsher (i.e for fc) -//CL 15 MARCH 1999 -//NOW DONE: +// CL 15 MARCH 1999 +// NOW DONE: // 1. Remove the write_PSOV_interfile_header as it is not needed // 2. Change the defaut value of mashing to 1 instead of 0 // 3. Change the fovrad formula for calculating rmin and rmax @@ -86,7 +86,7 @@ #include "stir/Coordinate3D.h" #include "stir/Succeeded.h" -#include "stir/analytic/FBP3DRP/ColsherFilter.h" +#include "stir/analytic/FBP3DRP/ColsherFilter.h" #include "stir/display.h" //#include "stir/recon_buildblock/distributable.h" //#include "stir/FBP3DRP/process_viewgrams.h" @@ -104,7 +104,7 @@ #include #include #include -#include +#include // for asctime() #include @@ -120,77 +120,63 @@ using std::ios; START_NAMESPACE_STIR - - // should be private member, TODO static ofstream full_log; // terribly ugly. can be replaced using LORCoordinates stuff (TODO) -static void find_rmin_rmax(int& rmin, int& rmax, - const ProjDataInfoCylindrical& proj_data_info_cyl, - const int seg_num, - const VoxelsOnCartesianGrid& image) -{ - - const float fovrad = - proj_data_info_cyl.get_s(Bin(0,0,0,proj_data_info_cyl.get_num_tangential_poss()/2 - 1)); +static void +find_rmin_rmax(int& rmin, int& rmax, const ProjDataInfoCylindrical& proj_data_info_cyl, const int seg_num, + const VoxelsOnCartesianGrid& image) { + + const float fovrad = proj_data_info_cyl.get_s(Bin(0, 0, 0, proj_data_info_cyl.get_num_tangential_poss() / 2 - 1)); // Compute minimum and maximum rings of 'missing' projections - - const float delta=proj_data_info_cyl.get_average_ring_difference(seg_num); - + + const float delta = proj_data_info_cyl.get_average_ring_difference(seg_num); + // find correspondence between ring coordinates and image coordinates: // z = num_planes_per_virtual_ring * ring + virtual_ring_offset - // compute the offset by matching up the centre of the scanner + // compute the offset by matching up the centre of the scanner // in the 2 coordinate systems // TODO get all this from ProjDataInfo or so const int num_planes_per_virtual_ring = - (proj_data_info_cyl.get_max_ring_difference(seg_num) == proj_data_info_cyl.get_min_ring_difference(seg_num)) ? 2 : 1; + (proj_data_info_cyl.get_max_ring_difference(seg_num) == proj_data_info_cyl.get_min_ring_difference(seg_num)) ? 2 : 1; const int num_virtual_rings_per_physical_ring = - (proj_data_info_cyl.get_max_ring_difference(seg_num) == proj_data_info_cyl.get_min_ring_difference(seg_num)) ? 1 : 2; - - - const float virtual_ring_offset = - (image.get_max_z() + image.get_min_z())/2.F - - num_planes_per_virtual_ring - *(proj_data_info_cyl.get_max_axial_pos_num(seg_num)+ num_virtual_rings_per_physical_ring*delta - + proj_data_info_cyl.get_min_axial_pos_num(seg_num))/2; - - + (proj_data_info_cyl.get_max_ring_difference(seg_num) == proj_data_info_cyl.get_min_ring_difference(seg_num)) ? 1 : 2; + + const float virtual_ring_offset = + (image.get_max_z() + image.get_min_z()) / 2.F - + num_planes_per_virtual_ring * + (proj_data_info_cyl.get_max_axial_pos_num(seg_num) + num_virtual_rings_per_physical_ring * delta + + proj_data_info_cyl.get_min_axial_pos_num(seg_num)) / + 2; + // we first consider the LOR at s=0, phi=0 which goes through z=0,y=0, x=fovrad // later on, we will shift it to the 'left'most edge of the FOV. - - // find z position of intersection of this LOR with the detector radius + + // find z position of intersection of this LOR with the detector radius // (i.e. y=0, x=-ring_radius) // use image coordinates first - float z_in_image_coordinates = - -fabs(delta)*num_planes_per_virtual_ring*num_virtual_rings_per_physical_ring* - (fovrad + proj_data_info_cyl.get_ring_radius())/(2*proj_data_info_cyl.get_ring_radius()); - // now shift it to the edge of the FOV + float z_in_image_coordinates = -fabs(delta) * num_planes_per_virtual_ring * num_virtual_rings_per_physical_ring * + (fovrad + proj_data_info_cyl.get_ring_radius()) / (2 * proj_data_info_cyl.get_ring_radius()); + // now shift it to the edge of the FOV // (taking into account that z==get_min_z() is in the middle of the voxel) z_in_image_coordinates += image.get_min_z() - .5F; - + // now convert to virtual_ring_coordinates using z = num_planes_per_virtual_ring * ring + virtual_ring_offset - const float z_in_virtual_ring_coordinates = - (z_in_image_coordinates - virtual_ring_offset)/num_planes_per_virtual_ring; + const float z_in_virtual_ring_coordinates = (z_in_image_coordinates - virtual_ring_offset) / num_planes_per_virtual_ring; // finally find the 'ring' number rmin = static_cast(floor(z_in_virtual_ring_coordinates)); - - - // rmax is determined by using symmetry: at both ends there are just as many missing rings - rmax = proj_data_info_cyl.get_max_axial_pos_num(seg_num) + (proj_data_info_cyl.get_min_axial_pos_num(seg_num) - rmin); -} + // rmax is determined by using symmetry: at both ends there are just as many missing rings + rmax = proj_data_info_cyl.get_max_axial_pos_num(seg_num) + (proj_data_info_cyl.get_min_axial_pos_num(seg_num) - rmin); +} -const char * const -FBP3DRPReconstruction::registered_name = - "FBP3DRP"; +const char* const FBP3DRPReconstruction::registered_name = "FBP3DRP"; -void -FBP3DRPReconstruction:: -set_defaults() -{ +void +FBP3DRPReconstruction::set_defaults() { base_type::set_defaults(); alpha_colsher_axial = 1; @@ -199,29 +185,26 @@ set_defaults() fc_colsher_planar = 0.5; alpha_ramp = 1; fc_ramp = 0.5; - + num_segments_to_combine = -1; PadS = 1; PadZ = 1; - colsher_stretch_factor_planar=2; - colsher_stretch_factor_axial=2; - - display_level=0; - save_intermediate_files=0; - - forward_projector_sptr. - reset(new ForwardProjectorByBinUsingRayTracing); - back_projector_sptr. - reset(new BackProjectorByBinUsingInterpolation( - /*use_piecewise_linear_interpolation = */false, - /*use_exact_Jacobian = */ false)); + colsher_stretch_factor_planar = 2; + colsher_stretch_factor_axial = 2; + + display_level = 0; + save_intermediate_files = 0; + + forward_projector_sptr.reset(new ForwardProjectorByBinUsingRayTracing); + back_projector_sptr.reset(new BackProjectorByBinUsingInterpolation( + /*use_piecewise_linear_interpolation = */ false, + /*use_exact_Jacobian = */ false)); } -void -FBP3DRPReconstruction::initialise_keymap() -{ +void +FBP3DRPReconstruction::initialise_keymap() { base_type::initialise_keymap(); parser.add_start_key("FBP3DRPParameters"); @@ -233,81 +216,70 @@ FBP3DRPReconstruction::initialise_keymap() // TODO move to 2D recon parser.add_key("num_segments_to_combine with SSRB", &num_segments_to_combine); - parser.add_key("Alpha parameter for Ramp filter", &alpha_ramp); - parser.add_key("Cut-off for Ramp filter (in cycles)",&fc_ramp); - + parser.add_key("Alpha parameter for Ramp filter", &alpha_ramp); + parser.add_key("Cut-off for Ramp filter (in cycles)", &fc_ramp); + parser.add_key("Transaxial extension for FFT", &PadS); parser.add_key("Axial extension for FFT", &PadZ); - - parser.add_key("Alpha parameter for Colsher filter in axial direction", - &alpha_colsher_axial); - parser.add_key("Cut-off for Colsher filter in axial direction (in cycles)", - &fc_colsher_axial); - parser.add_key("Alpha parameter for Colsher filter in planar direction", - &alpha_colsher_planar); - parser.add_key("Cut-off for Colsher filter in planar direction (in cycles)", - &fc_colsher_planar); - parser.add_key("Stretch factor for Colsher filter definition in axial direction", - &colsher_stretch_factor_axial); - parser.add_key("Stretch factor for Colsher filter definition in planar direction", - &colsher_stretch_factor_planar); + + parser.add_key("Alpha parameter for Colsher filter in axial direction", &alpha_colsher_axial); + parser.add_key("Cut-off for Colsher filter in axial direction (in cycles)", &fc_colsher_axial); + parser.add_key("Alpha parameter for Colsher filter in planar direction", &alpha_colsher_planar); + parser.add_key("Cut-off for Colsher filter in planar direction (in cycles)", &fc_colsher_planar); + parser.add_key("Stretch factor for Colsher filter definition in axial direction", &colsher_stretch_factor_axial); + parser.add_key("Stretch factor for Colsher filter definition in planar direction", &colsher_stretch_factor_planar); parser.add_parsing_key("Back projector type", &back_projector_sptr); parser.add_parsing_key("Forward projector type", &forward_projector_sptr); parser.add_key("Save intermediate images", &save_intermediate_files); - parser.add_key("Display level",&display_level); + parser.add_key("Display level", &display_level); } +void +FBP3DRPReconstruction::ask_parameters() { - -void -FBP3DRPReconstruction::ask_parameters() -{ - base_type::ask_parameters(); - - // bool on_disk = !ask("(1) Read data into memory all at once ?", false); -// TODO move to Reconstruction - -// PARAMETERS => DISPLAY_LEVEL - - display_level = ask_num("Which images would you like to display \n\t(0: None, 1: Final, 2: intermediate, 3: after each view) ? ", 0,3,0); + // bool on_disk = !ask("(1) Read data into memory all at once ?", false); + // TODO move to Reconstruction - save_intermediate_files =ask_num("Would you like to save all the intermediate images ? ",0,1,0 ); + // PARAMETERS => DISPLAY_LEVEL - image_for_reprojection_filename = - ask_string("filename of image to be reprojected (empty for using FBP):"); + display_level = + ask_num("Which images would you like to display \n\t(0: None, 1: Final, 2: intermediate, 3: after each view) ? ", 0, 3, 0); -// PARAMETERS => ZEROES-PADDING IN FFT (PADS, PADZ) - cerr << "\nFilter parameters for 2D and 3D reconstruction"; + save_intermediate_files = ask_num("Would you like to save all the intermediate images ? ", 0, 1, 0); + + image_for_reprojection_filename = ask_string("filename of image to be reprojected (empty for using FBP):"); + + // PARAMETERS => ZEROES-PADDING IN FFT (PADS, PADZ) + cerr << "\nFilter parameters for 2D and 3D reconstruction"; #if 0 PadS = ask_num(" Transaxial extension for FFT : ",0,2, 1); PadZ = ask_num(" Axial extension for FFT :",0,2, 1); #endif -// PARAMETERS => 2D RECONSTRUCTION RAMP FILTER (ALPHA, FC) - cerr << endl << "For 2D reconstruction filtering (Ramp filter) : " ; + // PARAMETERS => 2D RECONSTRUCTION RAMP FILTER (ALPHA, FC) + cerr << endl << "For 2D reconstruction filtering (Ramp filter) : "; + + num_segments_to_combine = ask_num( + "num_segments_to_combine (must be odd).\nDefault means 1 or 3 depending on axial compression of input", -1, 101, -1); + // TODO check odd + alpha_ramp = ask_num(" Alpha parameter for Ramp filter ? ", 0., 1., 1.); + + fc_ramp = ask_num(" Cut-off frequency for Ramp filter ? ", 0., .5, 0.5); + + // PARAMETERS => 3D RECONSTRUCTION COLSHER FILTER (ALPHA, FC) + cerr << "\nFor 3D reconstruction filtering (Colsher filter) : "; - num_segments_to_combine = ask_num("num_segments_to_combine (must be odd).\nDefault means 1 or 3 depending on axial compression of input",-1,101,-1); - // TODO check odd - alpha_ramp = ask_num(" Alpha parameter for Ramp filter ? ",0.,1., 1.); - - fc_ramp = ask_num(" Cut-off frequency for Ramp filter ? ",0.,.5, 0.5); + alpha_colsher_axial = ask_num(" Alpha parameter for Colsher filter in axial direction ? ", 0., 1., 1.); -// PARAMETERS => 3D RECONSTRUCTION COLSHER FILTER (ALPHA, FC) - cerr << "\nFor 3D reconstruction filtering (Colsher filter) : "; - - alpha_colsher_axial = ask_num(" Alpha parameter for Colsher filter in axial direction ? ",0.,1., 1.); - - fc_colsher_axial = ask_num(" Cut-off frequency for Colsher filter in axial direction ? ",0.,.5, 0.5); + fc_colsher_axial = ask_num(" Cut-off frequency for Colsher filter in axial direction ? ", 0., .5, 0.5); - - alpha_colsher_planar = ask_num(" Alpha parameter for Colsher filter in planar direction ? ",0.,1., 1.); - - fc_colsher_planar = ask_num(" Cut-off frequency fo Colsher filter in planar direction ? ",0.,.5, 0.5); + alpha_colsher_planar = ask_num(" Alpha parameter for Colsher filter in planar direction ? ", 0., 1., 1.); + fc_colsher_planar = ask_num(" Cut-off frequency fo Colsher filter in planar direction ? ", 0., .5, 0.5); #if 0 // do not ask the user for the projectors to prevent entering silly things @@ -327,58 +299,43 @@ FBP3DRPReconstruction::ask_parameters() } std::string -FBP3DRPReconstruction:: -method_info() const -{ return("FBP3DRP"); } +FBP3DRPReconstruction::method_info() const { + return ("FBP3DRP"); +} -FBP3DRPReconstruction::~FBP3DRPReconstruction() -{} +FBP3DRPReconstruction::~FBP3DRPReconstruction() {} -VoxelsOnCartesianGrid& -FBP3DRPReconstruction::estimated_image() -{ +VoxelsOnCartesianGrid& +FBP3DRPReconstruction::estimated_image() { return static_cast&>(*image_estimate_density_ptr); } -const VoxelsOnCartesianGrid& -FBP3DRPReconstruction::estimated_image() const -{ +const VoxelsOnCartesianGrid& +FBP3DRPReconstruction::estimated_image() const { return static_cast&>(*image_estimate_density_ptr); } -const ProjDataInfoCylindrical& -FBP3DRPReconstruction::input_proj_data_info_cyl() const -{ - return - static_cast - (*proj_data_ptr->get_proj_data_info_sptr()); +const ProjDataInfoCylindrical& +FBP3DRPReconstruction::input_proj_data_info_cyl() const { + return static_cast(*proj_data_ptr->get_proj_data_info_sptr()); } -FBP3DRPReconstruction:: -FBP3DRPReconstruction(const std::string& parameter_filename) -{ - initialise(parameter_filename); -} +FBP3DRPReconstruction::FBP3DRPReconstruction(const std::string& parameter_filename) { initialise(parameter_filename); } -FBP3DRPReconstruction::FBP3DRPReconstruction() -{ - set_defaults(); -} +FBP3DRPReconstruction::FBP3DRPReconstruction() { set_defaults(); } Succeeded -FBP3DRPReconstruction:: -set_up(shared_ptr > const& target_image_sptr) -{ +FBP3DRPReconstruction::set_up(shared_ptr> const& target_image_sptr) { if (base_type::set_up(target_image_sptr) == Succeeded::no) return Succeeded::no; - if (dynamic_cast (proj_data_ptr->get_proj_data_info_sptr().get()) == 0) + if (dynamic_cast(proj_data_ptr->get_proj_data_info_sptr().get()) == 0) error("FBP3DRP currently needs cylindrical projection data. Sorry"); - if (colsher_stretch_factor_planar<1 || colsher_stretch_factor_axial<1) + if (colsher_stretch_factor_planar < 1 || colsher_stretch_factor_axial < 1) error("stretch factors for Colsher filter have to be at least 1"); - if (PadS<1 || PadZ<1) + if (PadS < 1 || PadZ < 1) warning("Transaxial extension for FFT:=0 (or axial) should \n" "ONLY be used when the non-zero data\n" "occupy only half of the FOV. Otherwise aliasing will occur!"); @@ -391,21 +348,18 @@ set_up(shared_ptr > const& target_image_sptr) return Succeeded::yes; } -Succeeded -FBP3DRPReconstruction:: -actual_reconstruct(shared_ptr > const& target_image_ptr) -{ +Succeeded +FBP3DRPReconstruction::actual_reconstruct(shared_ptr> const& target_image_ptr) { this->check(*target_image_ptr); - VoxelsOnCartesianGrid& image = - dynamic_cast &>(*target_image_ptr); + VoxelsOnCartesianGrid& image = dynamic_cast&>(*target_image_ptr); // set default values such that it will work also in the case of already_2D_recon alpha_fit = 1.0F; beta_fit = 0.0F; start_timers(); { - //char file[max_filename_length]; - //sprintf(file,"%s.full_log",output_filename_prefix.c_str()); + // char file[max_filename_length]; + // sprintf(file,"%s.full_log",output_filename_prefix.c_str()); std::string file = output_filename_prefix; file += ".full_log"; full_log.open(file.c_str(), ios::out); @@ -415,39 +369,31 @@ actual_reconstruct(shared_ptr > const& target_image_ full_log << parameter_info(); full_log << "\n\n********** PROCESSING FBP3DRP RECONSTRUCTION *************" << endl; - + const int old_max_segment_num_to_process = max_segment_num_to_process; - + // Use funny convention that -1 means 'use maximum available' - if (max_segment_num_to_process<0) + if (max_segment_num_to_process < 0) max_segment_num_to_process = proj_data_ptr->get_max_segment_num(); - else if (max_segment_num_to_process>proj_data_ptr->get_max_segment_num()) - { - warning("max_segment_num_to_process was too large (%d) for this data, setting it to %d", - max_segment_num_to_process, - proj_data_ptr->get_max_segment_num()); - max_segment_num_to_process = proj_data_ptr->get_max_segment_num(); - } + else if (max_segment_num_to_process > proj_data_ptr->get_max_segment_num()) { + warning("max_segment_num_to_process was too large (%d) for this data, setting it to %d", max_segment_num_to_process, + proj_data_ptr->get_max_segment_num()); + max_segment_num_to_process = proj_data_ptr->get_max_segment_num(); + } #ifndef NRFFT - const float theta_max = - atan(proj_data_ptr->get_proj_data_info_sptr()-> - get_tantheta(Bin(max_segment_num_to_process,0,0,0))); - - colsher_filter = - ColsherFilter(theta_max, - static_cast(alpha_colsher_axial), static_cast(fc_colsher_axial), - static_cast(alpha_colsher_planar), static_cast(fc_colsher_planar), - colsher_stretch_factor_planar, - colsher_stretch_factor_axial); + const float theta_max = atan(proj_data_ptr->get_proj_data_info_sptr()->get_tantheta(Bin(max_segment_num_to_process, 0, 0, 0))); + + colsher_filter = ColsherFilter(theta_max, static_cast(alpha_colsher_axial), static_cast(fc_colsher_axial), + static_cast(alpha_colsher_planar), static_cast(fc_colsher_planar), + colsher_stretch_factor_planar, colsher_stretch_factor_axial); #else warning("Using NRFFT"); #endif - - if(image_for_reprojection_filename == "") - { + + if (image_for_reprojection_filename == "") { do_2D_reconstruction(); - + #if 0 if (fit_projections==1){//Fitting between measured and estimaed sinograms full_log << " - Fitting projections" << endl; //CL 010699 Forward project measured sinograms and fitting with alpha and beta @@ -488,11 +434,9 @@ actual_reconstruct(shared_ptr > const& target_image_ }else{ alpha_fit = 1.F; beta_fit = 0.F; - } + } #endif - } - else - { + } else { do_read_image2D(); // TODO set fit parameters } @@ -500,57 +444,41 @@ actual_reconstruct(shared_ptr > const& target_image_ // find out if arc-correction if necessary // and initialise proj_data_info_with_missing_data_sptr accordingly { - if (!is_null_ptr(dynamic_pointer_cast - (proj_data_ptr->get_proj_data_info_sptr()))) - { - // it's already arc-corrected - arc_correction_sptr.reset(); // just rest to make sure in case we run the reconstruction twice - proj_data_info_with_missing_data_sptr = - proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(); - } - else - { - arc_correction_sptr.reset(new ArcCorrection); - // TODO arc-correct to voxel_size - if (arc_correction_sptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone()) == - Succeeded::no) - return Succeeded::no; - - full_log << "FBP3DRP will arc-correct data first\n"; - // warning: need to use clone() as we're modifying it later on - proj_data_info_with_missing_data_sptr = - arc_correction_sptr->get_arc_corrected_proj_data_info_sptr()->create_shared_clone(); - } + if (!is_null_ptr(dynamic_pointer_cast(proj_data_ptr->get_proj_data_info_sptr()))) { + // it's already arc-corrected + arc_correction_sptr.reset(); // just rest to make sure in case we run the reconstruction twice + proj_data_info_with_missing_data_sptr = proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(); + } else { + arc_correction_sptr.reset(new ArcCorrection); + // TODO arc-correct to voxel_size + if (arc_correction_sptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone()) == Succeeded::no) + return Succeeded::no; + + full_log << "FBP3DRP will arc-correct data first\n"; + // warning: need to use clone() as we're modifying it later on + proj_data_info_with_missing_data_sptr = arc_correction_sptr->get_arc_corrected_proj_data_info_sptr()->create_shared_clone(); + } } - // make space for missing data + // make space for missing data { - proj_data_info_with_missing_data_sptr-> - reduce_segment_range(-max_segment_num_to_process, - max_segment_num_to_process); - for (int segment_num= proj_data_info_with_missing_data_sptr->get_min_segment_num(); - segment_num<= proj_data_info_with_missing_data_sptr->get_max_segment_num(); - ++segment_num) - { - // note: initialisation to 0 to avoid compiler warnings, - // but will be set by find_rmin_rmax - int new_min_axial_pos_num = 0; - int new_max_axial_pos_num = 0; - find_rmin_rmax(new_min_axial_pos_num, new_max_axial_pos_num, - input_proj_data_info_cyl(), segment_num, image); - proj_data_info_with_missing_data_sptr-> - set_min_axial_pos_num(new_min_axial_pos_num, segment_num); - proj_data_info_with_missing_data_sptr-> - set_max_axial_pos_num(new_max_axial_pos_num, segment_num); - } + proj_data_info_with_missing_data_sptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); + for (int segment_num = proj_data_info_with_missing_data_sptr->get_min_segment_num(); + segment_num <= proj_data_info_with_missing_data_sptr->get_max_segment_num(); ++segment_num) { + // note: initialisation to 0 to avoid compiler warnings, + // but will be set by find_rmin_rmax + int new_min_axial_pos_num = 0; + int new_max_axial_pos_num = 0; + find_rmin_rmax(new_min_axial_pos_num, new_max_axial_pos_num, input_proj_data_info_cyl(), segment_num, image); + proj_data_info_with_missing_data_sptr->set_min_axial_pos_num(new_min_axial_pos_num, segment_num); + proj_data_info_with_missing_data_sptr->set_max_axial_pos_num(new_max_axial_pos_num, segment_num); + } } { // set projectors to be used for the calculations - forward_projector_sptr->set_up(proj_data_info_with_missing_data_sptr, - image_estimate_density_ptr); - back_projector_sptr->set_up(proj_data_info_with_missing_data_sptr, - target_image_ptr); + forward_projector_sptr->set_up(proj_data_info_with_missing_data_sptr, image_estimate_density_ptr); + back_projector_sptr->set_up(proj_data_info_with_missing_data_sptr, target_image_ptr); #if 0 do when enabling callbacks set_projectors_and_symmetries(forward_projector_sptr, @@ -559,234 +487,199 @@ actual_reconstruct(shared_ptr > const& target_image_ #endif } - if(max_segment_num_to_process!=0) - do_3D_Reconstruction(image ); - else - { - // TODO - warning("\nOutput image will NOT be zoomed.\n"); - image = estimated_image(); - } - if(display_level>0) + if (max_segment_num_to_process != 0) + do_3D_Reconstruction(image); + else { + // TODO + warning("\nOutput image will NOT be zoomed.\n"); + image = estimated_image(); + } + if (display_level > 0) display(image, image.find_max(), "Final image"); stop_timers(); do_log_file(image); full_log.close(); - + // restore max_segment_num_to_process to its original value, // just in case someone wants to use the reconstruction object twice max_segment_num_to_process = old_max_segment_num_to_process; return Succeeded::yes; } - - - -void FBP3DRPReconstruction::do_2D_reconstruction() -{ // SSRB+2D FBP with ramp filter +void +FBP3DRPReconstruction::do_2D_reconstruction() { // SSRB+2D FBP with ramp filter full_log << "\n---------------------------------------------------------\n"; - full_log << "2D FBP OF DIRECT SINOGRAMS (=> IMAGE_ESTIMATE)\n" << endl; - - + full_log << "2D FBP OF DIRECT SINOGRAMS (=> IMAGE_ESTIMATE)\n" << endl; + // image_estimate should have 'default' dimensions, origin and voxel_size - image_estimate_density_ptr. - reset(new VoxelsOnCartesianGrid(*proj_data_ptr->get_proj_data_info_sptr())); - - { - FBP2DReconstruction recon2d(proj_data_ptr, - alpha_ramp, fc_ramp, PadS, - num_segments_to_combine); + image_estimate_density_ptr.reset(new VoxelsOnCartesianGrid(*proj_data_ptr->get_proj_data_info_sptr())); + + { + FBP2DReconstruction recon2d(proj_data_ptr, alpha_ramp, fc_ramp, PadS, num_segments_to_combine); full_log << "Parameters of the 2D FBP reconstruction" << endl; - full_log << recon2d.parameter_info()<< endl; + full_log << recon2d.parameter_info() << endl; recon2d.set_up(image_estimate_density_ptr); recon2d.reconstruct(image_estimate_density_ptr); } - full_log << " - min and max in SSRB+FBP image " << estimated_image().find_min() - << " " << estimated_image().find_max() << " SUM= " << estimated_image().sum() << endl; - - if(display_level>1) { + full_log << " - min and max in SSRB+FBP image " << estimated_image().find_min() << " " << estimated_image().find_max() + << " SUM= " << estimated_image().sum() << endl; + + if (display_level > 1) { full_log << " - Displaying estimated image" << endl; - display(estimated_image(),estimated_image().find_max(), "Image estimate"); + display(estimated_image(), estimated_image().find_max(), "Image estimate"); } - - if (save_intermediate_files && !_disable_output) - { - char file[max_filename_length]; - sprintf(file,"%s_estimated",output_filename_prefix.c_str()); - do_save_img(file,estimated_image() ); - } -} + if (save_intermediate_files && !_disable_output) { + char file[max_filename_length]; + sprintf(file, "%s_estimated", output_filename_prefix.c_str()); + do_save_img(file, estimated_image()); + } +} - +void +FBP3DRPReconstruction::do_save_img(const char* file, const VoxelsOnCartesianGrid& data) const { + full_log << " - Saving " << file << endl; + output_file_format_ptr->write_to_file(file, data); + full_log << " Min= " << data.find_min() << " Max = " << data.find_max() << " Sum = " << data.sum() << endl; +} -void FBP3DRPReconstruction::do_save_img(const char *file, const VoxelsOnCartesianGrid &data) const -{ - full_log <<" - Saving " << file << endl; - output_file_format_ptr->write_to_file( file, data); - full_log << " Min= " << data.find_min() - << " Max = " << data.find_max() - << " Sum = " << data.sum() << endl; +void +FBP3DRPReconstruction::do_read_image2D() { + full_log << " - Reading estimated image : " << image_for_reprojection_filename << endl; -} - -void FBP3DRPReconstruction::do_read_image2D() -{ - full_log <<" - Reading estimated image : "<< image_for_reprojection_filename << endl; - - image_estimate_density_ptr = - read_from_file >(image_for_reprojection_filename.c_str() ); + image_estimate_density_ptr = read_from_file>(image_for_reprojection_filename.c_str()); - // TODO do scale checks - + // TODO do scale checks } - - -void FBP3DRPReconstruction::do_3D_Reconstruction( - VoxelsOnCartesianGrid &image) -{ +void +FBP3DRPReconstruction::do_3D_Reconstruction(VoxelsOnCartesianGrid& image) { full_log << "\n---------------------------------------------------------\n"; full_log << "3D PROCESSING\n" << endl; - + do_byview_initialise(image); // TODO check if forward projector and back projector have compatible symmetries - shared_ptr symmetries_sptr( - back_projector_sptr->get_symmetries_used()->clone()); + shared_ptr symmetries_sptr(back_projector_sptr->get_symmetries_used()->clone()); forward_projector_sptr->set_input(estimated_image()); back_projector_sptr->start_accumulating_in_new_target(); - for (int seg_num= -max_segment_num_to_process; seg_num <= max_segment_num_to_process; seg_num++) - { + for (int seg_num = -max_segment_num_to_process; seg_num <= max_segment_num_to_process; seg_num++) { // a bool value that will be used to determine if we are starting processing for this segment bool first_view_in_segment = true; - + const int orig_min_axial_pos_num = proj_data_ptr->get_min_axial_pos_num(seg_num); const int orig_max_axial_pos_num = proj_data_ptr->get_max_axial_pos_num(seg_num); - - for (int view_num=proj_data_ptr->get_min_view_num(); view_num <= proj_data_ptr->get_max_view_num(); ++view_num) { + + for (int view_num = proj_data_ptr->get_min_view_num(); view_num <= proj_data_ptr->get_max_view_num(); ++view_num) { const ViewSegmentNumbers vs_num(view_num, seg_num); if (!symmetries_sptr->is_basic(vs_num)) - continue; - - const int new_min_axial_pos_num = - proj_data_info_with_missing_data_sptr->get_min_axial_pos_num(seg_num); - const int new_max_axial_pos_num = - proj_data_info_with_missing_data_sptr->get_max_axial_pos_num(seg_num); - - if (first_view_in_segment) - { - full_log << "\n--------------------------------\n"; - full_log << "PROCESSING SEGMENT No " << seg_num << endl ; - - full_log << "Average delta= " << input_proj_data_info_cyl().get_average_ring_difference(seg_num) - << " with span= " << input_proj_data_info_cyl().get_max_ring_difference(seg_num) - input_proj_data_info_cyl().get_min_ring_difference(seg_num) +1 - << " and extended axial position numbers: min= " << new_min_axial_pos_num << " and max= " << new_max_axial_pos_num <get_min_axial_pos_num(seg_num); + const int new_max_axial_pos_num = proj_data_info_with_missing_data_sptr->get_max_axial_pos_num(seg_num); + + if (first_view_in_segment) { + full_log << "\n--------------------------------\n"; + full_log << "PROCESSING SEGMENT No " << seg_num << endl; + + full_log << "Average delta= " << input_proj_data_info_cyl().get_average_ring_difference(seg_num) << " with span= " + << input_proj_data_info_cyl().get_max_ring_difference(seg_num) - + input_proj_data_info_cyl().get_min_ring_difference(seg_num) + 1 + << " and extended axial position numbers: min= " << new_min_axial_pos_num + << " and max= " << new_max_axial_pos_num << endl; + + first_view_in_segment = false; + } full_log << "\n*************************************************************"; - full_log << "\n Processing view " << vs_num.view_num() - << " of segment " << vs_num.segment_num() << endl; - - full_log << "\n - Getting related viewgrams" << endl; - - RelatedViewgrams viewgrams = - proj_data_ptr->get_related_viewgrams(vs_num, symmetries_sptr); - - do_process_viewgrams( - viewgrams, - new_min_axial_pos_num, new_max_axial_pos_num, orig_min_axial_pos_num, orig_max_axial_pos_num); - - - } + full_log << "\n Processing view " << vs_num.view_num() << " of segment " << vs_num.segment_num() << endl; + + full_log << "\n - Getting related viewgrams" << endl; + + RelatedViewgrams viewgrams = proj_data_ptr->get_related_viewgrams(vs_num, symmetries_sptr); + + do_process_viewgrams(viewgrams, new_min_axial_pos_num, new_max_axial_pos_num, orig_min_axial_pos_num, + orig_max_axial_pos_num); + } // do some logging etc, but only when this segment had any processing // (some segment_nums might not because of the symmetries) - if (!first_view_in_segment) - { - full_log << "\n*************************************************************"; - full_log << "\nEnd of this segment. Current image values:\n" - << "Min= " << image.find_min() - << " Max = " << image.find_max() - << " Sum = " << image.sum() << endl; + if (!first_view_in_segment) { + full_log << "\n*************************************************************"; + full_log << "\nEnd of this segment. Current image values:\n" + << "Min= " << image.find_min() << " Max = " << image.find_max() << " Sum = " << image.sum() << endl; #ifndef PARALLEL - if(save_intermediate_files && !_disable_output){ - char *file = new char[output_filename_prefix.size() + 20]; - sprintf(file,"%s_afterseg%d",output_filename_prefix.c_str(),seg_num); - back_projector_sptr->get_output(image); - do_save_img(file, image); - delete[] file; - } + if (save_intermediate_files && !_disable_output) { + char* file = new char[output_filename_prefix.size() + 20]; + sprintf(file, "%s_afterseg%d", output_filename_prefix.c_str(), seg_num); + back_projector_sptr->get_output(image); + do_save_img(file, image); + delete[] file; } -#endif + } +#endif } back_projector_sptr->get_output(image); // Normalise the image - if (dynamic_cast(back_projector_sptr.get()) == 0) - { - // TODO remove magic, is a scale factor in the interpolating backprojector (for which we compensate in the Colsher filter) - const float magic_number=2*input_proj_data_info_cyl().get_ring_radius()*input_proj_data_info_cyl().get_num_views()/input_proj_data_info_cyl().get_ring_spacing(); - image /= magic_number; - } + if (dynamic_cast(back_projector_sptr.get()) == 0) { + // TODO remove magic, is a scale factor in the interpolating backprojector (for which we compensate in the Colsher filter) + const float magic_number = 2 * input_proj_data_info_cyl().get_ring_radius() * input_proj_data_info_cyl().get_num_views() / + input_proj_data_info_cyl().get_ring_spacing(); + image /= magic_number; + } do_byview_finalise(image); - - } - // CL 010699 NEW function -void FBP3DRPReconstruction::do_best_fit(const Sinogram &sino_measured,const Sinogram &sino_calculated) -{ +void +FBP3DRPReconstruction::do_best_fit(const Sinogram& sino_measured, const Sinogram& sino_calculated) { float meas_calc = 0.F; - float meas_square = 0.F; + float meas_square = 0.F; float calc_square = 0.F; float sigma_square = 0.F; full_log << " - Fitting estimated sinograms with the measured ones (Max in measured sino = " << sino_measured.find_max() - << " Max in fwd sino = " << sino_calculated.find_max() << ")" <forward_project(viewgrams, - new_min_axial_pos_num ,orig_min_axial_pos_num-1); + forward_projector_sptr->forward_project(viewgrams, new_min_axial_pos_num, orig_min_axial_pos_num - 1); + } - } + if (orig_max_axial_pos_num + 1 <= new_max_axial_pos_num) { + full_log << " - Forward projection from ring No " << orig_max_axial_pos_num + 1 << " to " << new_max_axial_pos_num << endl; - if (orig_max_axial_pos_num+1 <= new_max_axial_pos_num) - { - full_log << " - Forward projection from ring No " - << orig_max_axial_pos_num+1 - << " to " << new_max_axial_pos_num << endl; - - forward_projector_sptr->forward_project(viewgrams, - orig_max_axial_pos_num+1, new_max_axial_pos_num); - - } + forward_projector_sptr->forward_project(viewgrams, orig_max_axial_pos_num + 1, new_max_axial_pos_num); + } #if 0 if (fit_projections) { @@ -854,194 +733,158 @@ void FBP3DRPReconstruction::do_forward_project_view(RelatedViewgrams & vi } #endif - if(display_level>2) { - display( viewgrams,viewgrams.find_max(),"Original+Forward projected"); + if (display_level > 2) { + display(viewgrams, viewgrams.find_max(), "Original+Forward projected"); } } - - -void FBP3DRPReconstruction::do_colsher_filter_view( RelatedViewgrams & viewgrams) -{ - assert(!is_null_ptr(dynamic_pointer_cast - (viewgrams.get_proj_data_info_sptr()))); +void +FBP3DRPReconstruction::do_colsher_filter_view(RelatedViewgrams& viewgrams) { + + assert(!is_null_ptr(dynamic_pointer_cast(viewgrams.get_proj_data_info_sptr()))); // TODO make into object member instead of static - static int prev_seg_num = viewgrams.get_proj_data_info_sptr()->get_min_segment_num()-1; + static int prev_seg_num = viewgrams.get_proj_data_info_sptr()->get_min_segment_num() - 1; #ifdef NRFFT - static ColsherFilter colsher_filter(0,0,0,0,0,0,0,0,0,0); + static ColsherFilter colsher_filter(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); #endif const int seg_num = viewgrams.get_basic_segment_num(); - if (prev_seg_num != seg_num) - { + if (prev_seg_num != seg_num) { prev_seg_num = seg_num; full_log << " - Constructing Colsher filter for this segment\n"; - const int nrings = viewgrams.get_num_axial_poss(); + const int nrings = viewgrams.get_num_axial_poss(); const int nprojs = viewgrams.get_num_tangential_poss(); - - const int width = (int) pow(2., ((int) ceil(log((PadS + 1.) * nprojs) / log(2.)))); - const int height = (int) pow(2., ((int) ceil(log((PadZ + 1.) * nrings) / log(2.)))); - - - const float theta_max = atan(viewgrams.get_proj_data_info_sptr()->get_tantheta(Bin(max_segment_num_to_process,0,0,0))); - - const float theta = - static_cast(atan(viewgrams.get_proj_data_info_sptr()->get_tantheta(Bin(seg_num,0,0,0)))); - - const float sampling_in_s = - viewgrams.get_proj_data_info_sptr()->get_sampling_in_s(Bin(seg_num,0,0,0)); - const float sampling_in_t = - viewgrams.get_proj_data_info_sptr()->get_sampling_in_t(Bin(seg_num,0,0,0)); - full_log << "Colsher filter theta_max = " << theta_max << " theta = " << theta - << " d_a = " << sampling_in_s - << " d_b = " << sampling_in_t << endl; - - + + const int width = (int)pow(2., ((int)ceil(log((PadS + 1.) * nprojs) / log(2.)))); + const int height = (int)pow(2., ((int)ceil(log((PadZ + 1.) * nrings) / log(2.)))); + + const float theta_max = atan(viewgrams.get_proj_data_info_sptr()->get_tantheta(Bin(max_segment_num_to_process, 0, 0, 0))); + + const float theta = static_cast(atan(viewgrams.get_proj_data_info_sptr()->get_tantheta(Bin(seg_num, 0, 0, 0)))); + + const float sampling_in_s = viewgrams.get_proj_data_info_sptr()->get_sampling_in_s(Bin(seg_num, 0, 0, 0)); + const float sampling_in_t = viewgrams.get_proj_data_info_sptr()->get_sampling_in_t(Bin(seg_num, 0, 0, 0)); + full_log << "Colsher filter theta_max = " << theta_max << " theta = " << theta << " d_a = " << sampling_in_s + << " d_b = " << sampling_in_t << endl; + #ifdef NRFFT - colsher_filter = - ColsherFilter(height, width, _PI/2 - theta, theta_max, - sampling_in_s, - sampling_in_t, - alpha_colsher_axial, fc_colsher_axial, - alpha_colsher_planar, fc_colsher_planar); + colsher_filter = ColsherFilter(height, width, _PI / 2 - theta, theta_max, sampling_in_s, sampling_in_t, alpha_colsher_axial, + fc_colsher_axial, alpha_colsher_planar, fc_colsher_planar); #else - if (colsher_filter.set_up(height, width, - theta, - sampling_in_s, - sampling_in_t) - != Succeeded::yes) - error("Exiting"); + if (colsher_filter.set_up(height, width, theta, sampling_in_s, sampling_in_t) != Succeeded::yes) + error("Exiting"); #endif } full_log << " - Apply Colsher filter to complete oblique sinograms" << endl; #ifdef NRFFT - assert(viewgrams.get_num_viewgrams()%2 == 0); - + assert(viewgrams.get_num_viewgrams() % 2 == 0); + RelatedViewgrams::iterator viewgram_iter = viewgrams.begin(); - for (; viewgram_iter != viewgrams.end(); viewgram_iter+=2) - Filter_proj_Colsher(*viewgram_iter, *(viewgram_iter+1), - colsher_filter, - PadS, PadZ); + for (; viewgram_iter != viewgrams.end(); viewgram_iter += 2) + Filter_proj_Colsher(*viewgram_iter, *(viewgram_iter + 1), colsher_filter, PadS, PadZ); #else - // do not use std::for_each. at present on gcc it copies the filter for every viewgram - // std::for_each(viewgrams.begin(), viewgrams.end(), - // colsher_filter); - RelatedViewgrams::iterator viewgram_iter = viewgrams.begin(); - for (; viewgram_iter != viewgrams.end(); ++viewgram_iter) - colsher_filter(*viewgram_iter); + // do not use std::for_each. at present on gcc it copies the filter for every viewgram + // std::for_each(viewgrams.begin(), viewgrams.end(), + // colsher_filter); + RelatedViewgrams::iterator viewgram_iter = viewgrams.begin(); + for (; viewgram_iter != viewgrams.end(); ++viewgram_iter) + colsher_filter(*viewgram_iter); #endif /* If the segment is really an amalgam of different ring differences, - we have to multiply it with the number of ring differences + we have to multiply it with the number of ring differences in the segment. - This is to assure that backprojecting each ring difference + This is to assure that backprojecting each ring difference on its own would give roughly the same result. TODO: should this be put in the backprojector itself ? - */ - { - const int num_ring_differences = - input_proj_data_info_cyl().get_max_ring_difference(seg_num) - - input_proj_data_info_cyl().get_min_ring_difference(seg_num) + 1; - full_log << " - Multiplying filtered projections by " << num_ring_differences << endl; - if (num_ring_differences != 1){ - viewgrams *= static_cast(num_ring_differences); - } - - } - if(display_level>2) { - display( viewgrams,viewgrams.find_max(), "Colsher filtered"); + */ + { + const int num_ring_differences = input_proj_data_info_cyl().get_max_ring_difference(seg_num) - + input_proj_data_info_cyl().get_min_ring_difference(seg_num) + 1; + full_log << " - Multiplying filtered projections by " << num_ring_differences << endl; + if (num_ring_differences != 1) { + viewgrams *= static_cast(num_ring_differences); } + } + if (display_level > 2) { + display(viewgrams, viewgrams.find_max(), "Colsher filtered"); + } } +void +FBP3DRPReconstruction::do_3D_backprojection_view(const RelatedViewgrams& viewgrams, int new_min_axial_pos_num, + int new_max_axial_pos_num) { + full_log << " - Backproject the filtered Colsher complete sinograms" << endl; -void FBP3DRPReconstruction::do_3D_backprojection_view(const RelatedViewgrams & viewgrams, - int new_min_axial_pos_num, int new_max_axial_pos_num) -{ - full_log << " - Backproject the filtered Colsher complete sinograms" << endl; - - back_projector_sptr->back_project(viewgrams,new_min_axial_pos_num, new_max_axial_pos_num); - + back_projector_sptr->back_project(viewgrams, new_min_axial_pos_num, new_max_axial_pos_num); } +void +FBP3DRPReconstruction::do_log_file(const VoxelsOnCartesianGrid& image) { + char file[max_filename_length]; + sprintf(file, "%s.log", output_filename_prefix.c_str()); - -void FBP3DRPReconstruction::do_log_file(const VoxelsOnCartesianGrid &image) -{ - char file[max_filename_length]; - sprintf(file,"%s.log",output_filename_prefix.c_str()); - - full_log << endl << "- WRITE LOGFILE (" - << file << ")" << endl; - - ofstream logfile(file); - - if (logfile.fail() || logfile.bad()) { - warning("Error opening log file\n"); - return; - } - full_log << endl ; + full_log << endl << "- WRITE LOGFILE (" << file << ")" << endl; + + ofstream logfile(file); + + if (logfile.fail() || logfile.bad()) { + warning("Error opening log file\n"); + return; + } + full_log << endl; - const time_t now = time(NULL); + const time_t now = time(NULL); - logfile << "Date of the image reconstruction : " << asctime(localtime(&now)) - << parameter_info() ; - + logfile << "Date of the image reconstruction : " << asctime(localtime(&now)) << parameter_info(); #ifndef PARALLEL - logfile << "\n\n TIMING RESULTS :\n" - << "Total CPU time : " << get_CPU_timer_value() << '\n' - << "forward projection CPU time : " << forward_projector_sptr->get_CPU_timer_value() << '\n' - << "back projection CPU time : " << back_projector_sptr->get_CPU_timer_value() << '\n' -#ifndef NRFFT - << "Colsher filter set-up CPU time : " << colsher_filter.get_CPU_timer_value() << '\n' -#endif + logfile << "\n\n TIMING RESULTS :\n" + << "Total CPU time : " << get_CPU_timer_value() << '\n' + << "forward projection CPU time : " << forward_projector_sptr->get_CPU_timer_value() << '\n' + << "back projection CPU time : " << back_projector_sptr->get_CPU_timer_value() << '\n' +# ifndef NRFFT + << "Colsher filter set-up CPU time : " << colsher_filter.get_CPU_timer_value() << '\n' +# endif ; -#endif +#endif } +void +FBP3DRPReconstruction::do_process_viewgrams(RelatedViewgrams& viewgrams, int new_min_axial_pos_num, + int new_max_axial_pos_num, int orig_min_axial_pos_num, int orig_max_axial_pos_num) { + do_arc_correction(viewgrams); + + do_grow3D_viewgram(viewgrams, new_min_axial_pos_num, new_max_axial_pos_num); + + do_forward_project_view(viewgrams, new_min_axial_pos_num, new_max_axial_pos_num, orig_min_axial_pos_num, + orig_max_axial_pos_num); + + do_colsher_filter_view(viewgrams); + + /* The backprojection here is really an approximation of a continuous integral + over delta and phi, where + -max_delta <= delta <= max_delta + 0 <= phi < pi + We discretise the integral over delta by summing values + at discrete ring differences. However, we include the boundary points. + The appropriate formula for the integral is then + f(-max_delta)/2 + f(-max_delta+1) + ... f(max_delta-1) + f(max_delta/2) + Note the factors 1/2 at the boundary. + These are inserted below + */ + if (abs(viewgrams.get_basic_segment_num()) == max_segment_num_to_process) { + viewgrams /= 2; + } -void FBP3DRPReconstruction::do_process_viewgrams(RelatedViewgrams & viewgrams, - int new_min_axial_pos_num, int new_max_axial_pos_num, - int orig_min_axial_pos_num, int orig_max_axial_pos_num) -{ - do_arc_correction(viewgrams); - - do_grow3D_viewgram(viewgrams, new_min_axial_pos_num, new_max_axial_pos_num); - - do_forward_project_view(viewgrams, - new_min_axial_pos_num, new_max_axial_pos_num, orig_min_axial_pos_num, orig_max_axial_pos_num); - - do_colsher_filter_view(viewgrams); - - - - /* The backprojection here is really an approximation of a continuous integral - over delta and phi, where - -max_delta <= delta <= max_delta - 0 <= phi < pi - We discretise the integral over delta by summing values - at discrete ring differences. However, we include the boundary points. - The appropriate formula for the integral is then - f(-max_delta)/2 + f(-max_delta+1) + ... f(max_delta-1) + f(max_delta/2) - Note the factors 1/2 at the boundary. - These are inserted below - */ - if (abs(viewgrams.get_basic_segment_num()) == max_segment_num_to_process) - { - viewgrams /= 2; - } - - do_3D_backprojection_view(viewgrams, - new_min_axial_pos_num, new_max_axial_pos_num); - + do_3D_backprojection_view(viewgrams, new_min_axial_pos_num, new_max_axial_pos_num); } - END_NAMESPACE_STIR diff --git a/src/buildblock/ArcCorrection.cxx b/src/buildblock/ArcCorrection.cxx index f6bfa42174..3f3accd90e 100644 --- a/src/buildblock/ArcCorrection.cxx +++ b/src/buildblock/ArcCorrection.cxx @@ -40,259 +40,170 @@ #include START_NAMESPACE_STIR -ArcCorrection:: -ArcCorrection() -{} +ArcCorrection::ArcCorrection() {} const ProjDataInfoCylindricalNoArcCorr& -ArcCorrection:: -get_not_arc_corrected_proj_data_info() const -{ - return - static_cast(*_noarc_corr_proj_data_info_sptr); +ArcCorrection::get_not_arc_corrected_proj_data_info() const { + return static_cast(*_noarc_corr_proj_data_info_sptr); } const ProjDataInfoCylindricalArcCorr& -ArcCorrection:: -get_arc_corrected_proj_data_info() const -{ - return - static_cast(*_arc_corr_proj_data_info_sptr); +ArcCorrection::get_arc_corrected_proj_data_info() const { + return static_cast(*_arc_corr_proj_data_info_sptr); } -shared_ptr -ArcCorrection:: -get_arc_corrected_proj_data_info_sptr() const -{ +shared_ptr +ArcCorrection::get_arc_corrected_proj_data_info_sptr() const { return _arc_corr_proj_data_info_sptr; } -shared_ptr -ArcCorrection:: -get_not_arc_corrected_proj_data_info_sptr() const -{ +shared_ptr +ArcCorrection::get_not_arc_corrected_proj_data_info_sptr() const { return _noarc_corr_proj_data_info_sptr; } - Succeeded -ArcCorrection:: -set_up(const shared_ptr& noarc_corr_proj_data_info_sptr, - const int num_arccorrected_tangential_poss, - const float bin_size) -{ - if (dynamic_cast - (noarc_corr_proj_data_info_sptr.get()) == 0) - { - // give friendly warning message - if (dynamic_cast - (noarc_corr_proj_data_info_sptr.get()) != 0) - warning("ArcCorrection called with arc-corrected proj_data_info"); - else - warning("ArcCorrection called with proj_data_info of the wrong type:\n\t%s", - typeid(*noarc_corr_proj_data_info_sptr).name()); - return Succeeded::no; - } +ArcCorrection::set_up(const shared_ptr& noarc_corr_proj_data_info_sptr, + const int num_arccorrected_tangential_poss, const float bin_size) { + if (dynamic_cast(noarc_corr_proj_data_info_sptr.get()) == 0) { + // give friendly warning message + if (dynamic_cast(noarc_corr_proj_data_info_sptr.get()) != 0) + warning("ArcCorrection called with arc-corrected proj_data_info"); + else + warning("ArcCorrection called with proj_data_info of the wrong type:\n\t%s", + typeid(*noarc_corr_proj_data_info_sptr).name()); + return Succeeded::no; + } _noarc_corr_proj_data_info_sptr = noarc_corr_proj_data_info_sptr; - const int min_segment_num = - _noarc_corr_proj_data_info_sptr->get_min_segment_num(); - const int max_segment_num = - _noarc_corr_proj_data_info_sptr->get_max_segment_num(); - - VectorWithOffset min_ring_diff(min_segment_num, max_segment_num); + const int min_segment_num = _noarc_corr_proj_data_info_sptr->get_min_segment_num(); + const int max_segment_num = _noarc_corr_proj_data_info_sptr->get_max_segment_num(); + + VectorWithOffset min_ring_diff(min_segment_num, max_segment_num); VectorWithOffset max_ring_diff(min_segment_num, max_segment_num); VectorWithOffset num_axial_pos_per_segment(min_segment_num, max_segment_num); - for (int segment_num=min_segment_num; segment_num<=max_segment_num; ++segment_num) - { - min_ring_diff[segment_num] = - get_not_arc_corrected_proj_data_info().get_min_ring_difference(segment_num); - max_ring_diff[segment_num] = - get_not_arc_corrected_proj_data_info().get_max_ring_difference(segment_num); - num_axial_pos_per_segment[segment_num] = - _noarc_corr_proj_data_info_sptr->get_num_axial_poss(segment_num); - } + for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) { + min_ring_diff[segment_num] = get_not_arc_corrected_proj_data_info().get_min_ring_difference(segment_num); + max_ring_diff[segment_num] = get_not_arc_corrected_proj_data_info().get_max_ring_difference(segment_num); + num_axial_pos_per_segment[segment_num] = _noarc_corr_proj_data_info_sptr->get_num_axial_poss(segment_num); + } // create new scanner shared_ptr to avoid unexpected problems with people // modifying the scanner_sptr of the old/new object shared_ptr new_scanner_sptr(new Scanner(*_noarc_corr_proj_data_info_sptr->get_scanner_ptr())); _arc_corr_proj_data_info_sptr.reset( - new ProjDataInfoCylindricalArcCorr( - new_scanner_sptr, - bin_size, - num_axial_pos_per_segment, - min_ring_diff, - max_ring_diff, - noarc_corr_proj_data_info_sptr->get_num_views(), - num_arccorrected_tangential_poss)); - - tangential_sampling = - get_arc_corrected_proj_data_info().get_tangential_sampling(); + new ProjDataInfoCylindricalArcCorr(new_scanner_sptr, bin_size, num_axial_pos_per_segment, min_ring_diff, max_ring_diff, + noarc_corr_proj_data_info_sptr->get_num_views(), num_arccorrected_tangential_poss)); + + tangential_sampling = get_arc_corrected_proj_data_info().get_tangential_sampling(); _noarccorr_coords.resize(_noarc_corr_proj_data_info_sptr->get_min_tangential_pos_num(), - _noarc_corr_proj_data_info_sptr->get_max_tangential_pos_num()+1); + _noarc_corr_proj_data_info_sptr->get_max_tangential_pos_num() + 1); _noarccorr_bin_sizes.resize(_noarc_corr_proj_data_info_sptr->get_min_tangential_pos_num(), - _noarc_corr_proj_data_info_sptr->get_max_tangential_pos_num()); - { - const float angular_increment = - get_not_arc_corrected_proj_data_info().get_angular_increment(); - const float ring_radius = - get_not_arc_corrected_proj_data_info().get_ring_radius(); + _noarc_corr_proj_data_info_sptr->get_max_tangential_pos_num()); + { + const float angular_increment = get_not_arc_corrected_proj_data_info().get_angular_increment(); + const float ring_radius = get_not_arc_corrected_proj_data_info().get_ring_radius(); int tang_pos_num = _noarc_corr_proj_data_info_sptr->get_min_tangential_pos_num(); - _noarccorr_coords[tang_pos_num] = - ring_radius * sin((tang_pos_num-.5F)*angular_increment); - for (; - tang_pos_num <= _noarc_corr_proj_data_info_sptr->get_max_tangential_pos_num(); - ++tang_pos_num) - { - _noarccorr_coords[tang_pos_num+1] = - ring_radius * sin((tang_pos_num+.5F)*angular_increment); - _noarccorr_bin_sizes[tang_pos_num] = - _noarccorr_coords[tang_pos_num+1] - - _noarccorr_coords[tang_pos_num]; - } + _noarccorr_coords[tang_pos_num] = ring_radius * sin((tang_pos_num - .5F) * angular_increment); + for (; tang_pos_num <= _noarc_corr_proj_data_info_sptr->get_max_tangential_pos_num(); ++tang_pos_num) { + _noarccorr_coords[tang_pos_num + 1] = ring_radius * sin((tang_pos_num + .5F) * angular_increment); + _noarccorr_bin_sizes[tang_pos_num] = _noarccorr_coords[tang_pos_num + 1] - _noarccorr_coords[tang_pos_num]; + } } _arccorr_coords.resize(_arc_corr_proj_data_info_sptr->get_min_tangential_pos_num(), - _arc_corr_proj_data_info_sptr->get_max_tangential_pos_num()+1); + _arc_corr_proj_data_info_sptr->get_max_tangential_pos_num() + 1); { int tang_pos_num; for (tang_pos_num = _arc_corr_proj_data_info_sptr->get_min_tangential_pos_num(); - tang_pos_num <= _arc_corr_proj_data_info_sptr->get_max_tangential_pos_num(); - ++tang_pos_num) - { - _arccorr_coords[tang_pos_num] = - (tang_pos_num-.5F)*tangential_sampling; - } - _arccorr_coords[tang_pos_num] = - (tang_pos_num+.5F)*tangential_sampling; + tang_pos_num <= _arc_corr_proj_data_info_sptr->get_max_tangential_pos_num(); ++tang_pos_num) { + _arccorr_coords[tang_pos_num] = (tang_pos_num - .5F) * tangential_sampling; + } + _arccorr_coords[tang_pos_num] = (tang_pos_num + .5F) * tangential_sampling; } return Succeeded::yes; } - + Succeeded -ArcCorrection:: - set_up(const shared_ptr& noarc_corr_proj_data_info_sptr, - const int num_arccorrected_tangential_poss) -{ - float tangential_sampling = - noarc_corr_proj_data_info_sptr->get_scanner_ptr()->get_default_bin_size(); - if (tangential_sampling<=0) - { - tangential_sampling = - noarc_corr_proj_data_info_sptr-> - get_sampling_in_s(Bin(0,0,0,0)); - warning("ArcCorrection::set_up called for a scanner with default\n" - "tangential sampling (aka bin size) equal to 0.\n" - "Using the central bin size %g.", - tangential_sampling); - } - return - set_up(noarc_corr_proj_data_info_sptr, - num_arccorrected_tangential_poss, - tangential_sampling); +ArcCorrection::set_up(const shared_ptr& noarc_corr_proj_data_info_sptr, + const int num_arccorrected_tangential_poss) { + float tangential_sampling = noarc_corr_proj_data_info_sptr->get_scanner_ptr()->get_default_bin_size(); + if (tangential_sampling <= 0) { + tangential_sampling = noarc_corr_proj_data_info_sptr->get_sampling_in_s(Bin(0, 0, 0, 0)); + warning("ArcCorrection::set_up called for a scanner with default\n" + "tangential sampling (aka bin size) equal to 0.\n" + "Using the central bin size %g.", + tangential_sampling); + } + return set_up(noarc_corr_proj_data_info_sptr, num_arccorrected_tangential_poss, tangential_sampling); } - Succeeded -ArcCorrection:: -set_up(const shared_ptr& noarc_corr_proj_data_info_sptr) -{ - float tangential_sampling = - noarc_corr_proj_data_info_sptr->get_scanner_ptr()->get_default_bin_size(); - if (tangential_sampling<=0) - { - tangential_sampling = - noarc_corr_proj_data_info_sptr-> - get_sampling_in_s(Bin(0,0,0,0)); - warning("ArcCorrection::set_up called for a scanner with default\n" - "tangential sampling (aka bin size) equal to 0.\n" - "Using the central bin size %g.", - tangential_sampling); - } - const float max_s = - std::max( - noarc_corr_proj_data_info_sptr-> - get_s(Bin(0,0,0, - noarc_corr_proj_data_info_sptr-> - get_max_tangential_pos_num()+2)), - -noarc_corr_proj_data_info_sptr-> - get_s(Bin(0,0,0, - noarc_corr_proj_data_info_sptr-> - get_min_tangential_pos_num()-2)) - ); - const int max_arccorr_tangential_pos_num = - static_cast(ceil(max_s/tangential_sampling)); - return - set_up(noarc_corr_proj_data_info_sptr, - 2*max_arccorr_tangential_pos_num+1, - tangential_sampling); +ArcCorrection::set_up(const shared_ptr& noarc_corr_proj_data_info_sptr) { + float tangential_sampling = noarc_corr_proj_data_info_sptr->get_scanner_ptr()->get_default_bin_size(); + if (tangential_sampling <= 0) { + tangential_sampling = noarc_corr_proj_data_info_sptr->get_sampling_in_s(Bin(0, 0, 0, 0)); + warning("ArcCorrection::set_up called for a scanner with default\n" + "tangential sampling (aka bin size) equal to 0.\n" + "Using the central bin size %g.", + tangential_sampling); + } + const float max_s = std::max( + noarc_corr_proj_data_info_sptr->get_s(Bin(0, 0, 0, noarc_corr_proj_data_info_sptr->get_max_tangential_pos_num() + 2)), + -noarc_corr_proj_data_info_sptr->get_s(Bin(0, 0, 0, noarc_corr_proj_data_info_sptr->get_min_tangential_pos_num() - 2))); + const int max_arccorr_tangential_pos_num = static_cast(ceil(max_s / tangential_sampling)); + return set_up(noarc_corr_proj_data_info_sptr, 2 * max_arccorr_tangential_pos_num + 1, tangential_sampling); } -void -ArcCorrection:: -do_arc_correction(Array<1,float>& out, const Array<1,float>& in) const -{ +void +ArcCorrection::do_arc_correction(Array<1, float>& out, const Array<1, float>& in) const { assert(in.get_index_range() == _noarccorr_bin_sizes.get_index_range()); assert(out.get_min_index() == _arccorr_coords.get_min_index()); - assert(out.get_max_index() == _arccorr_coords.get_max_index()-1); + assert(out.get_max_index() == _arccorr_coords.get_max_index() - 1); - overlap_interpolate(out.begin(), out.end(), - _arccorr_coords.begin(), _arccorr_coords.end(), - in.begin(), in.end(), - _noarccorr_coords.begin(), _noarccorr_coords.end()); + overlap_interpolate(out.begin(), out.end(), _arccorr_coords.begin(), _arccorr_coords.end(), in.begin(), in.end(), + _noarccorr_coords.begin(), _noarccorr_coords.end()); out /= tangential_sampling; } void -ArcCorrection:: -do_arc_correction(Sinogram& out, const Sinogram& in) const -{ +ArcCorrection::do_arc_correction(Sinogram& out, const Sinogram& in) const { assert(*in.get_proj_data_info_sptr() == *_noarc_corr_proj_data_info_sptr); assert(*out.get_proj_data_info_sptr() == *_arc_corr_proj_data_info_sptr); assert(out.get_axial_pos_num() == in.get_axial_pos_num()); assert(out.get_segment_num() == in.get_segment_num()); - for (int view_num=in.get_min_view_num(); view_num<=in.get_max_view_num(); ++view_num) + assert(out.get_timing_pos_num() == in.get_timing_pos_num()); + for (int view_num = in.get_min_view_num(); view_num <= in.get_max_view_num(); ++view_num) do_arc_correction(out[view_num], in[view_num]); } Sinogram -ArcCorrection:: -do_arc_correction(const Sinogram& in) const -{ - Sinogram out(_arc_corr_proj_data_info_sptr, - in.get_axial_pos_num(), - in.get_segment_num()); +ArcCorrection::do_arc_correction(const Sinogram& in) const { + Sinogram out(_arc_corr_proj_data_info_sptr, in.get_axial_pos_num(), in.get_segment_num(), in.get_timing_pos_num()); do_arc_correction(out, in); return out; } void -ArcCorrection:: -do_arc_correction(Viewgram& out, const Viewgram& in) const -{ +ArcCorrection::do_arc_correction(Viewgram& out, const Viewgram& in) const { assert(*in.get_proj_data_info_sptr() == *_noarc_corr_proj_data_info_sptr); assert(*out.get_proj_data_info_sptr() == *_arc_corr_proj_data_info_sptr); assert(out.get_view_num() == in.get_view_num()); assert(out.get_segment_num() == in.get_segment_num()); - for (int axial_pos_num=in.get_min_axial_pos_num(); axial_pos_num<=in.get_max_axial_pos_num(); ++axial_pos_num) + assert(out.get_timing_pos_num() == in.get_timing_pos_num()); + for (int axial_pos_num = in.get_min_axial_pos_num(); axial_pos_num <= in.get_max_axial_pos_num(); ++axial_pos_num) do_arc_correction(out[axial_pos_num], in[axial_pos_num]); } Viewgram -ArcCorrection:: -do_arc_correction(const Viewgram& in) const -{ - Viewgram out(_arc_corr_proj_data_info_sptr, - in.get_view_num(), - in.get_segment_num()); +ArcCorrection::do_arc_correction(const Viewgram& in) const { + Viewgram out(_arc_corr_proj_data_info_sptr, in.get_view_num(), in.get_segment_num(), in.get_timing_pos_num()); do_arc_correction(out, in); return out; } void -ArcCorrection:: -do_arc_correction(RelatedViewgrams& out, const RelatedViewgrams& in) const -{ +ArcCorrection::do_arc_correction(RelatedViewgrams& out, const RelatedViewgrams& in) const { RelatedViewgrams::iterator out_iter = out.begin(); RelatedViewgrams::const_iterator in_iter = in.begin(); for (; out_iter != out.end(); ++out_iter, ++in_iter) @@ -300,81 +211,64 @@ do_arc_correction(RelatedViewgrams& out, const RelatedViewgrams& i } RelatedViewgrams -ArcCorrection:: -do_arc_correction(const RelatedViewgrams& in) const -{ - RelatedViewgrams out = - _arc_corr_proj_data_info_sptr->get_empty_related_viewgrams(in.get_basic_view_segment_num(), - in.get_symmetries_sptr()); +ArcCorrection::do_arc_correction(const RelatedViewgrams& in) const { + RelatedViewgrams out = _arc_corr_proj_data_info_sptr->get_empty_related_viewgrams( + in.get_basic_view_segment_num(), in.get_symmetries_sptr(), false, in.get_basic_timing_pos_num()); do_arc_correction(out, in); return out; } void -ArcCorrection:: -do_arc_correction(SegmentBySinogram& out, const SegmentBySinogram& in) const -{ +ArcCorrection::do_arc_correction(SegmentBySinogram& out, const SegmentBySinogram& in) const { assert(*in.get_proj_data_info_sptr() == *_noarc_corr_proj_data_info_sptr); assert(*out.get_proj_data_info_sptr() == *_arc_corr_proj_data_info_sptr); assert(out.get_segment_num() == in.get_segment_num()); - for (int axial_pos_num=in.get_min_axial_pos_num(); axial_pos_num<=in.get_max_axial_pos_num(); ++axial_pos_num) - for (int view_num=in.get_min_view_num(); view_num<=in.get_max_view_num(); ++view_num) + assert(out.get_timing_pos_num() == in.get_timing_pos_num()); + for (int axial_pos_num = in.get_min_axial_pos_num(); axial_pos_num <= in.get_max_axial_pos_num(); ++axial_pos_num) + for (int view_num = in.get_min_view_num(); view_num <= in.get_max_view_num(); ++view_num) do_arc_correction(out[axial_pos_num][view_num], in[axial_pos_num][view_num]); } -SegmentBySinogram -ArcCorrection:: -do_arc_correction(const SegmentBySinogram& in) const -{ - SegmentBySinogram out(_arc_corr_proj_data_info_sptr, - in.get_segment_num()); +SegmentBySinogram +ArcCorrection::do_arc_correction(const SegmentBySinogram& in) const { + SegmentBySinogram out(_arc_corr_proj_data_info_sptr, in.get_segment_num(), in.get_timing_pos_num()); do_arc_correction(out, in); return out; } - void -ArcCorrection:: -do_arc_correction(SegmentByView& out, const SegmentByView& in) const -{ +ArcCorrection::do_arc_correction(SegmentByView& out, const SegmentByView& in) const { assert(*in.get_proj_data_info_sptr() == *_noarc_corr_proj_data_info_sptr); assert(*out.get_proj_data_info_sptr() == *_arc_corr_proj_data_info_sptr); assert(out.get_segment_num() == in.get_segment_num()); - for (int view_num=in.get_min_view_num(); view_num<=in.get_max_view_num(); ++view_num) - for (int axial_pos_num=in.get_min_axial_pos_num(); axial_pos_num<=in.get_max_axial_pos_num(); ++axial_pos_num) + assert(out.get_timing_pos_num() == in.get_timing_pos_num()); + for (int view_num = in.get_min_view_num(); view_num <= in.get_max_view_num(); ++view_num) + for (int axial_pos_num = in.get_min_axial_pos_num(); axial_pos_num <= in.get_max_axial_pos_num(); ++axial_pos_num) do_arc_correction(out[view_num][axial_pos_num], in[view_num][axial_pos_num]); } - -SegmentByView -ArcCorrection:: -do_arc_correction(const SegmentByView& in) const -{ - SegmentByView out(_arc_corr_proj_data_info_sptr, - in.get_segment_num()); +SegmentByView +ArcCorrection::do_arc_correction(const SegmentByView& in) const { + SegmentByView out(_arc_corr_proj_data_info_sptr, in.get_segment_num(), in.get_timing_pos_num()); do_arc_correction(out, in); return out; } - Succeeded -ArcCorrection:: -do_arc_correction(ProjData& out, const ProjData& in) const -{ +ArcCorrection::do_arc_correction(ProjData& out, const ProjData& in) const { assert(*in.get_proj_data_info_sptr() == *_noarc_corr_proj_data_info_sptr); assert(*out.get_proj_data_info_sptr() == *_arc_corr_proj_data_info_sptr); // Declare temporary viewgram out of the loop to avoid reallocation // There is no default constructor, so we need to set it to some junk first. - Viewgram viewgram = - _arc_corr_proj_data_info_sptr->get_empty_viewgram(in.get_min_view_num(), in.get_min_segment_num()); - for (int segment_num=in.get_min_segment_num(); segment_num<=in.get_max_segment_num(); ++segment_num) - for (int view_num=in.get_min_view_num(); view_num<=in.get_max_view_num(); ++view_num) - { - viewgram = - _arc_corr_proj_data_info_sptr->get_empty_viewgram(view_num, segment_num); - do_arc_correction(viewgram, in.get_viewgram(view_num, segment_num)); - if (out.set_viewgram(viewgram) == Succeeded::no) - return Succeeded::no; + Viewgram viewgram = _arc_corr_proj_data_info_sptr->get_empty_viewgram(in.get_min_view_num(), in.get_min_segment_num(), + in.get_min_tof_pos_num()); + for (int timing_pos_num = in.get_min_tof_pos_num(); timing_pos_num <= in.get_max_tof_pos_num(); ++timing_pos_num) + for (int segment_num = in.get_min_segment_num(); segment_num <= in.get_max_segment_num(); ++segment_num) + for (int view_num = in.get_min_view_num(); view_num <= in.get_max_view_num(); ++view_num) { + viewgram = _arc_corr_proj_data_info_sptr->get_empty_viewgram(view_num, segment_num, false, timing_pos_num); + do_arc_correction(viewgram, in.get_viewgram(view_num, segment_num, false, timing_pos_num)); + if (out.set_viewgram(viewgram) == Succeeded::no) + return Succeeded::no; } return Succeeded::yes; } diff --git a/src/buildblock/Array.cxx b/src/buildblock/Array.cxx index 5781bebbcf..1d769fc740 100644 --- a/src/buildblock/Array.cxx +++ b/src/buildblock/Array.cxx @@ -16,17 +16,17 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup Array - \brief non-inline implementations for the Array class + \file + \ingroup Array + \brief non-inline implementations for the Array class - \author Kris Thielemans + \author Kris Thielemans \author PARAPET project This file could be empty. However, it contains - contains instantiations for some common cases. + contains instantiations for some common cases. This might reduce the size of the executable a bit if the compiler cannot inline certain functions. */ @@ -35,31 +35,30 @@ START_NAMESPACE_STIR - /************************************************** instantiations **************************************************/ #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // add any other types you need -template class Array<1,signed char>; -template class Array<1,short>; -template class Array<1,unsigned short>; -template class Array<1,float>; +template class Array<1, signed char>; +template class Array<1, short>; +template class Array<1, unsigned short>; +template class Array<1, float>; #endif -template class Array<2,signed char>; -template class Array<2,short>; -template class Array<2,unsigned short>; -template class Array<2,float>; +template class Array<2, signed char>; +template class Array<2, short>; +template class Array<2, unsigned short>; +template class Array<2, float>; template class Array<3, signed char>; template class Array<3, short>; -template class Array<3,unsigned short>; -template class Array<3,float>; +template class Array<3, unsigned short>; +template class Array<3, float>; template class Array<4, short>; -template class Array<4,unsigned short>; -template class Array<4,float>; +template class Array<4, unsigned short>; +template class Array<4, float>; END_NAMESPACE_STIR diff --git a/src/buildblock/ArrayFilter1DUsingConvolution.cxx b/src/buildblock/ArrayFilter1DUsingConvolution.cxx index cb607c8811..06563ddc6a 100644 --- a/src/buildblock/ArrayFilter1DUsingConvolution.cxx +++ b/src/buildblock/ArrayFilter1DUsingConvolution.cxx @@ -39,179 +39,138 @@ using std::max; START_NAMESPACE_STIR template -ArrayFilter1DUsingConvolution:: -ArrayFilter1DUsingConvolution() - : filter_coefficients(), _bc(BoundaryConditions::zero) -{ - -} +ArrayFilter1DUsingConvolution::ArrayFilter1DUsingConvolution() : filter_coefficients(), _bc(BoundaryConditions::zero) {} template -ArrayFilter1DUsingConvolution:: -ArrayFilter1DUsingConvolution(const VectorWithOffset &filter_coefficients_v, const BoundaryConditions::BC bc) - : filter_coefficients(filter_coefficients_v), _bc(bc) -{ +ArrayFilter1DUsingConvolution::ArrayFilter1DUsingConvolution(const VectorWithOffset& filter_coefficients_v, + const BoundaryConditions::BC bc) + : filter_coefficients(filter_coefficients_v), _bc(bc) { // TODO: remove 0 elements at the outside } - template -bool -ArrayFilter1DUsingConvolution:: -is_trivial() const -{ - return - filter_coefficients.get_length() == 0 || - (filter_coefficients.get_length()==1 && filter_coefficients.get_min_index()==0 && - filter_coefficients[0] == 1); +bool +ArrayFilter1DUsingConvolution::is_trivial() const { + return filter_coefficients.get_length() == 0 || + (filter_coefficients.get_length() == 1 && filter_coefficients.get_min_index() == 0 && filter_coefficients[0] == 1); } - template -Succeeded -ArrayFilter1DUsingConvolution:: -get_influencing_indices(IndexRange<1>& influencing_index_range, - const IndexRange<1>& input_index_range) const -{ - influencing_index_range = - (filter_coefficients.get_length() == 0) - ? input_index_range - : IndexRange<1>(input_index_range.get_min_index() - filter_coefficients.get_max_index(), - input_index_range.get_max_index() - filter_coefficients.get_min_index()); +Succeeded +ArrayFilter1DUsingConvolution::get_influencing_indices(IndexRange<1>& influencing_index_range, + const IndexRange<1>& input_index_range) const { + influencing_index_range = (filter_coefficients.get_length() == 0) + ? input_index_range + : IndexRange<1>(input_index_range.get_min_index() - filter_coefficients.get_max_index(), + input_index_range.get_max_index() - filter_coefficients.get_min_index()); return Succeeded::yes; } template -Succeeded -ArrayFilter1DUsingConvolution:: -get_influenced_indices(IndexRange<1>& influenced_index_range, - const IndexRange<1>& input_index_range) const -{ - influenced_index_range = - (filter_coefficients.get_length() == 0) - ? input_index_range - : IndexRange<1>(input_index_range.get_min_index() + filter_coefficients.get_min_index(), - input_index_range.get_max_index() + filter_coefficients.get_max_index()); +Succeeded +ArrayFilter1DUsingConvolution::get_influenced_indices(IndexRange<1>& influenced_index_range, + const IndexRange<1>& input_index_range) const { + influenced_index_range = (filter_coefficients.get_length() == 0) + ? input_index_range + : IndexRange<1>(input_index_range.get_min_index() + filter_coefficients.get_min_index(), + input_index_range.get_max_index() + filter_coefficients.get_max_index()); return Succeeded::yes; } template void -ArrayFilter1DUsingConvolution:: -do_it(Array<1,elemT>& out_array, const Array<1,elemT>& in_array) const -{ +ArrayFilter1DUsingConvolution::do_it(Array<1, elemT>& out_array, const Array<1, elemT>& in_array) const { const int in_min = in_array.get_min_index(); const int in_max = in_array.get_max_index(); const int out_min = out_array.get_min_index(); const int out_max = out_array.get_max_index(); - if (is_trivial()) - { - int i=out_min; - - switch (this->_bc) - { - case BoundaryConditions::zero: - { - for (; i<=min(in_min-1,out_max); ++i) - out_array[i] = 0; - break; - } - case BoundaryConditions::constant: - { - for (; i<=min(in_min-1,out_max); ++i) - out_array[i] = in_array[in_min]; - break; - } - default: - { - error("ArrayFilter1DUsingConvolution: cannot handle this boundary condition yet. sorry"); - } - } + if (is_trivial()) { + int i = out_min; + + switch (this->_bc) { + case BoundaryConditions::zero: { + for (; i <= min(in_min - 1, out_max); ++i) + out_array[i] = 0; + break; + } + case BoundaryConditions::constant: { + for (; i <= min(in_min - 1, out_max); ++i) + out_array[i] = in_array[in_min]; + break; + } + default: { + error("ArrayFilter1DUsingConvolution: cannot handle this boundary condition yet. sorry"); + } + } { - for (; i<=min(in_max,out_max); ++i) - { - out_array[i] = in_array[i]; - } - } - switch (this->_bc) - { - case BoundaryConditions::zero: - { - for (; i<=out_max; ++i) - out_array[i] = 0; - break; - } - case BoundaryConditions::constant: - { - for (; i<=out_max; ++i) - out_array[i] = in_array[in_max]; - break; - } - default: - { - // should never get here, but without default: the compiler might issue a warning - } + for (; i <= min(in_max, out_max); ++i) { + out_array[i] = in_array[i]; } + } + switch (this->_bc) { + case BoundaryConditions::zero: { + for (; i <= out_max; ++i) + out_array[i] = 0; + break; + } + case BoundaryConditions::constant: { + for (; i <= out_max; ++i) + out_array[i] = in_array[in_max]; + break; + } + default: { + // should never get here, but without default: the compiler might issue a warning + } + } return; } const int j_min = filter_coefficients.get_min_index(); const int j_max = filter_coefficients.get_max_index(); - - for (int i=out_min; i<=out_max; i++) - { + for (int i = out_min; i <= out_max; i++) { out_array[i] = 0; - int j=j_min; + int j = j_min; // first do right edge - switch (this->_bc) - { - case BoundaryConditions::zero: - { - j=max(j_min, i-in_max); - break; - } - case BoundaryConditions::constant: - { - //i_in=i-j> in_max, hence j< i-in_max - for (; j< min(j_max+1, i-in_max); ++j) - out_array[i] += filter_coefficients[j]*in_array[in_max /*i-j*/]; - break; - } - default: - error("ArrayFilter1DUsingConvolution: unsupported boundary condition"); - } + switch (this->_bc) { + case BoundaryConditions::zero: { + j = max(j_min, i - in_max); + break; + } + case BoundaryConditions::constant: { + // i_in=i-j> in_max, hence j< i-in_max + for (; j < min(j_max + 1, i - in_max); ++j) + out_array[i] += filter_coefficients[j] * in_array[in_max /*i-j*/]; + break; + } + default: + error("ArrayFilter1DUsingConvolution: unsupported boundary condition"); + } // region unaffected by boundary { - for (; j<=min(j_max, i-in_min); ++j) - out_array[i] += filter_coefficients[j]*in_array[i-j]; + for (; j <= min(j_max, i - in_min); ++j) + out_array[i] += filter_coefficients[j] * in_array[i - j]; } // left edge - switch (this->_bc) - { - case BoundaryConditions::zero: - { - // nothing to do - break; - } - case BoundaryConditions::constant: - { - //i_in=i-j< in_min, hence j> i-in_min - for (; j<= j_max; ++j) - out_array[i] += filter_coefficients[j]*in_array[in_min /*i-j*/]; - break; - } - default: - { - // should never get here, but without default: the compiler might issue a warning - } - } + switch (this->_bc) { + case BoundaryConditions::zero: { + // nothing to do + break; + } + case BoundaryConditions::constant: { + // i_in=i-j< in_min, hence j> i-in_min + for (; j <= j_max; ++j) + out_array[i] += filter_coefficients[j] * in_array[in_min /*i-j*/]; + break; + } + default: { + // should never get here, but without default: the compiler might issue a warning + } + } } - } // instantiation template class ArrayFilter1DUsingConvolution; END_NAMESPACE_STIR - diff --git a/src/buildblock/ArrayFilter1DUsingConvolutionSymmetricKernel.cxx b/src/buildblock/ArrayFilter1DUsingConvolutionSymmetricKernel.cxx index 417faa3dd6..1c1d09ff3c 100644 --- a/src/buildblock/ArrayFilter1DUsingConvolutionSymmetricKernel.cxx +++ b/src/buildblock/ArrayFilter1DUsingConvolutionSymmetricKernel.cxx @@ -8,7 +8,7 @@ \author Kris Thielemans \author Sanida Mustafovic - + */ /* Copyright (C) 2000- 2009, Hammersmith Imanet Ltd @@ -36,39 +36,28 @@ using std::min; START_NAMESPACE_STIR template -ArrayFilter1DUsingConvolutionSymmetricKernel:: -ArrayFilter1DUsingConvolutionSymmetricKernel(const VectorWithOffset &filter_coefficients_v) -: filter_coefficients(filter_coefficients_v) -{ +ArrayFilter1DUsingConvolutionSymmetricKernel::ArrayFilter1DUsingConvolutionSymmetricKernel( + const VectorWithOffset& filter_coefficients_v) + : filter_coefficients(filter_coefficients_v) { // TODO: remove 0 elements at the outside - assert(filter_coefficients.get_length() == 0 || - filter_coefficients.get_min_index()==0); + assert(filter_coefficients.get_length() == 0 || filter_coefficients.get_min_index() == 0); } - template -bool -ArrayFilter1DUsingConvolutionSymmetricKernel:: -is_trivial() const -{ - return - filter_coefficients.get_length() == 0 || - (filter_coefficients.get_length()==1 && - filter_coefficients[0] == 1); +bool +ArrayFilter1DUsingConvolutionSymmetricKernel::is_trivial() const { + return filter_coefficients.get_length() == 0 || (filter_coefficients.get_length() == 1 && filter_coefficients[0] == 1); } // TODO generalise to arbitrary index ranges template void -ArrayFilter1DUsingConvolutionSymmetricKernel:: -do_it(Array<1,elemT>& out_array, const Array<1,elemT>& in_array) const -{ +ArrayFilter1DUsingConvolutionSymmetricKernel::do_it(Array<1, elemT>& out_array, const Array<1, elemT>& in_array) const { assert(out_array.get_min_index() == in_array.get_min_index()); assert(out_array.get_max_index() == in_array.get_max_index()); - if (is_trivial()) - { + if (is_trivial()) { out_array = in_array; return; } @@ -77,29 +66,27 @@ do_it(Array<1,elemT>& out_array, const Array<1,elemT>& in_array) const const int in_max = in_array.get_max_index(); const int j_max = filter_coefficients.get_max_index(); - for (int i=in_array.get_min_index(); - i<=in_array.get_max_index(); i++) - { - out_array[i] = filter_coefficients[0]*in_array[i]; - int j=1; + for (int i = in_array.get_min_index(); i <= in_array.get_max_index(); i++) { + out_array[i] = filter_coefficients[0] * in_array[i]; + int j = 1; // first do range where both i-j and i+j indices are valid for in_array - for (; j<=min(j_max,min(in_max-i, i-in_min)); j++) - out_array[i] += filter_coefficients[j]*(in_array[i-j]+in_array[i+j]); - //if (j>j_max) return; + for (; j <= min(j_max, min(in_max - i, i - in_min)); j++) + out_array[i] += filter_coefficients[j] * (in_array[i - j] + in_array[i + j]); + // if (j>j_max) return; // now do rest of i+j separate // next conditional is not necessary - //if (i-in_min < in_max-i) + // if (i-in_min < in_max-i) { - for (; j<=min(j_max,in_max-i); j++) - out_array[i] += filter_coefficients[j]*(in_array[i+j]); + for (; j <= min(j_max, in_max - i); j++) + out_array[i] += filter_coefficients[j] * (in_array[i + j]); } // now do rest of i-j separate // next conditional is not necessary - //else + // else { - for (; j<=min(j_max,i-in_min); j++) - out_array[i] += filter_coefficients[j]*(in_array[i-j]); + for (; j <= min(j_max, i - in_min); j++) + out_array[i] += filter_coefficients[j] * (in_array[i - j]); } } #if 0 @@ -161,7 +148,6 @@ do_it(Array<1,elemT>& out_array, const Array<1,elemT>& in_array) const #endif } - #if 0 template static void @@ -179,4 +165,3 @@ cir_shift_to_right(VectorWithOffset&output,const VectorWithOffset& template class ArrayFilter1DUsingConvolutionSymmetricKernel; END_NAMESPACE_STIR - diff --git a/src/buildblock/ArrayFilter2DUsingConvolution.cxx b/src/buildblock/ArrayFilter2DUsingConvolution.cxx index 8c15a8f221..616a5191fa 100644 --- a/src/buildblock/ArrayFilter2DUsingConvolution.cxx +++ b/src/buildblock/ArrayFilter2DUsingConvolution.cxx @@ -28,119 +28,84 @@ using std::min; START_NAMESPACE_STIR template -ArrayFilter2DUsingConvolution:: -ArrayFilter2DUsingConvolution() -: filter_coefficients() -{ - -} +ArrayFilter2DUsingConvolution::ArrayFilter2DUsingConvolution() : filter_coefficients() {} template -ArrayFilter2DUsingConvolution:: -ArrayFilter2DUsingConvolution(const Array <2, float> &filter_coefficients_v) -: filter_coefficients(filter_coefficients_v) -{ +ArrayFilter2DUsingConvolution::ArrayFilter2DUsingConvolution(const Array<2, float>& filter_coefficients_v) + : filter_coefficients(filter_coefficients_v) { // TODO: remove 0 elements at the outside } - template -bool -ArrayFilter2DUsingConvolution:: -is_trivial() const -{ - return - filter_coefficients.get_length() == 0 || - (filter_coefficients.get_length()==1 && filter_coefficients.get_min_index()==0 && - filter_coefficients[0][0] == 1); +bool +ArrayFilter2DUsingConvolution::is_trivial() const { + return filter_coefficients.get_length() == 0 || + (filter_coefficients.get_length() == 1 && filter_coefficients.get_min_index() == 0 && filter_coefficients[0][0] == 1); } - template -Succeeded -ArrayFilter2DUsingConvolution:: -get_influencing_indices(IndexRange<1>& influencing_index_range, - const IndexRange<1>& input_index_range) const -{ - influencing_index_range = - (filter_coefficients.get_length() == 0) - ? input_index_range - : IndexRange<1>(input_index_range.get_min_index() - filter_coefficients.get_max_index(), - input_index_range.get_max_index() - filter_coefficients.get_min_index()); +Succeeded +ArrayFilter2DUsingConvolution::get_influencing_indices(IndexRange<1>& influencing_index_range, + const IndexRange<1>& input_index_range) const { + influencing_index_range = (filter_coefficients.get_length() == 0) + ? input_index_range + : IndexRange<1>(input_index_range.get_min_index() - filter_coefficients.get_max_index(), + input_index_range.get_max_index() - filter_coefficients.get_min_index()); return Succeeded::yes; } template -Succeeded -ArrayFilter2DUsingConvolution:: -get_influenced_indices(IndexRange<1>& influenced_index_range, - const IndexRange<1>& output_index_range) const -{ - influenced_index_range = - (filter_coefficients.get_length() == 0) - ? output_index_range - : IndexRange<1>(output_index_range.get_min_index() + filter_coefficients.get_min_index(), - output_index_range.get_max_index() + filter_coefficients.get_max_index()); +Succeeded +ArrayFilter2DUsingConvolution::get_influenced_indices(IndexRange<1>& influenced_index_range, + const IndexRange<1>& output_index_range) const { + influenced_index_range = (filter_coefficients.get_length() == 0) + ? output_index_range + : IndexRange<1>(output_index_range.get_min_index() + filter_coefficients.get_min_index(), + output_index_range.get_max_index() + filter_coefficients.get_max_index()); return Succeeded::yes; } - template void -ArrayFilter2DUsingConvolution:: -do_it(Array<2,elemT>& out_array, const Array<2,elemT>& in_array) const -{ +ArrayFilter2DUsingConvolution::do_it(Array<2, elemT>& out_array, const Array<2, elemT>& in_array) const { const int in_min_y = in_array.get_min_index(); const int in_max_y = in_array.get_max_index(); const int in_min_x = in_array[in_min_y].get_min_index(); const int in_max_x = in_array[in_min_y].get_max_index(); - - + const int out_min_y = out_array.get_min_index(); const int out_max_y = out_array.get_max_index(); const int out_min_x = out_array[out_min_y].get_min_index(); const int out_max_x = out_array[out_min_y].get_max_index(); - - - - if (is_trivial()) - { - for (int y=out_min_y; y<=out_max_y; y++) - for (int x=out_min_x; x<=out_max_x; x++) - - { - out_array[y][x] = ((y>=in_min_y && y <= in_max_y ) && - (x>=in_min_x && x <= in_max_x ) ? in_array[y][x] : 0); - } - return; + + if (is_trivial()) { + for (int y = out_min_y; y <= out_max_y; y++) + for (int x = out_min_x; x <= out_max_x; x++) + + { + out_array[y][x] = ((y >= in_min_y && y <= in_max_y) && (x >= in_min_x && x <= in_max_x) ? in_array[y][x] : 0); + } + return; } - + const int j_min = filter_coefficients.get_min_index(); const int j_max = filter_coefficients.get_max_index(); const int i_min = filter_coefficients[j_min].get_min_index(); const int i_max = filter_coefficients[j_min].get_max_index(); - - - - for (int y=out_min_y; y<=out_max_y; y++) - for (int x=out_min_x; x<=out_max_x; x++) - { - out_array[y][x] = 0; - - for (int j=max(j_min, y-in_max_y); j<=min(j_max, y-in_min_y); j++) - for (int i=max(i_min, x-in_max_x); i<=min(i_max, x-in_min_x); i++) - - out_array[y][x] += filter_coefficients[j][i]*in_array[y-j][x-i]; - } - - -} + for (int y = out_min_y; y <= out_max_y; y++) + for (int x = out_min_x; x <= out_max_x; x++) { + out_array[y][x] = 0; + + for (int j = max(j_min, y - in_max_y); j <= min(j_max, y - in_min_y); j++) + for (int i = max(i_min, x - in_max_x); i <= min(i_max, x - in_min_x); i++) + out_array[y][x] += filter_coefficients[j][i] * in_array[y - j][x - i]; + } +} // instantiation template class ArrayFilter2DUsingConvolution; END_NAMESPACE_STIR - diff --git a/src/buildblock/ArrayFilter3DUsingConvolution.cxx b/src/buildblock/ArrayFilter3DUsingConvolution.cxx index 0bea260c1e..f477b7bde8 100644 --- a/src/buildblock/ArrayFilter3DUsingConvolution.cxx +++ b/src/buildblock/ArrayFilter3DUsingConvolution.cxx @@ -37,72 +37,50 @@ using std::cerr; using std::endl; #endif - START_NAMESPACE_STIR template -ArrayFilter3DUsingConvolution:: -ArrayFilter3DUsingConvolution() -: filter_coefficients() -{ - -} +ArrayFilter3DUsingConvolution::ArrayFilter3DUsingConvolution() : filter_coefficients() {} template -ArrayFilter3DUsingConvolution:: -ArrayFilter3DUsingConvolution(const Array <3, float> &filter_coefficients_v) -: filter_coefficients(filter_coefficients_v) -{ +ArrayFilter3DUsingConvolution::ArrayFilter3DUsingConvolution(const Array<3, float>& filter_coefficients_v) + : filter_coefficients(filter_coefficients_v) { // TODO: remove 0 elements at the outside } - template -bool -ArrayFilter3DUsingConvolution:: -is_trivial() const -{ - return - filter_coefficients.get_length() == 0 || - (filter_coefficients.get_length()==1 && filter_coefficients.get_min_index()==0 && - filter_coefficients[0][0][0] == 1); +bool +ArrayFilter3DUsingConvolution::is_trivial() const { + return filter_coefficients.get_length() == 0 || + (filter_coefficients.get_length() == 1 && filter_coefficients.get_min_index() == 0 && filter_coefficients[0][0][0] == 1); } - template -Succeeded -ArrayFilter3DUsingConvolution:: -get_influencing_indices(IndexRange<1>& influencing_index_range, - const IndexRange<1>& input_index_range) const -{ - influencing_index_range = - (filter_coefficients.get_length() == 0) - ? input_index_range - : IndexRange<1>(input_index_range.get_min_index() - filter_coefficients.get_max_index(), - input_index_range.get_max_index() - filter_coefficients.get_min_index()); +Succeeded +ArrayFilter3DUsingConvolution::get_influencing_indices(IndexRange<1>& influencing_index_range, + const IndexRange<1>& input_index_range) const { + influencing_index_range = (filter_coefficients.get_length() == 0) + ? input_index_range + : IndexRange<1>(input_index_range.get_min_index() - filter_coefficients.get_max_index(), + input_index_range.get_max_index() - filter_coefficients.get_min_index()); return Succeeded::yes; } template -Succeeded -ArrayFilter3DUsingConvolution:: -get_influenced_indices(IndexRange<1>& influenced_index_range, - const IndexRange<1>& output_index_range) const -{ - influenced_index_range = - (filter_coefficients.get_length() == 0) - ? output_index_range - : IndexRange<1>(output_index_range.get_min_index() + filter_coefficients.get_min_index(), - output_index_range.get_max_index() + filter_coefficients.get_max_index()); +Succeeded +ArrayFilter3DUsingConvolution::get_influenced_indices(IndexRange<1>& influenced_index_range, + const IndexRange<1>& output_index_range) const { + influenced_index_range = (filter_coefficients.get_length() == 0) + ? output_index_range + : IndexRange<1>(output_index_range.get_min_index() + filter_coefficients.get_min_index(), + output_index_range.get_max_index() + filter_coefficients.get_max_index()); return Succeeded::yes; } #if 1 template void -ArrayFilter3DUsingConvolution:: -do_it(Array<3,elemT>& out_array, const Array<3,elemT>& in_array) const -{ +ArrayFilter3DUsingConvolution::do_it(Array<3, elemT>& out_array, const Array<3, elemT>& in_array) const { const int in_min_z = in_array.get_min_index(); const int in_max_z = in_array.get_max_index(); @@ -110,69 +88,62 @@ do_it(Array<3,elemT>& out_array, const Array<3,elemT>& in_array) const const int in_max_y = in_array[in_min_z].get_max_index(); const int in_min_x = in_array[in_min_z][in_min_y].get_min_index(); const int in_max_x = in_array[in_min_z][in_min_y].get_max_index(); - - + const int out_min_z = out_array.get_min_index(); const int out_max_z = out_array.get_max_index(); const int out_min_y = out_array[out_min_z].get_min_index(); const int out_max_y = out_array[out_min_z].get_max_index(); const int out_min_x = out_array[out_min_z][out_min_y].get_min_index(); const int out_max_x = out_array[out_min_z][out_min_y].get_max_index(); - - if (is_trivial()) - { - for (int z=out_min_z; z<=out_max_z; z++) - for (int y=out_min_y; y<=out_max_y; y++) - for (int x=out_min_x; x<=out_max_x; x++) - - { - out_array[z][y][x] = ((z>=in_min_z && z <= in_max_z ) && (y>=in_min_y && y <= in_max_y ) && - (x>=in_min_x && x <= in_max_x ) ? in_array[z][y][x] : 0); - } - return; - } - + + if (is_trivial()) { + for (int z = out_min_z; z <= out_max_z; z++) + for (int y = out_min_y; y <= out_max_y; y++) + for (int x = out_min_x; x <= out_max_x; x++) + + { + out_array[z][y][x] = + ((z >= in_min_z && z <= in_max_z) && (y >= in_min_y && y <= in_max_y) && (x >= in_min_x && x <= in_max_x) + ? in_array[z][y][x] + : 0); + } + return; + } + const int k_min = filter_coefficients.get_min_index(); const int k_max = filter_coefficients.get_max_index(); - + const int j_min = filter_coefficients[k_min].get_min_index(); const int j_max = filter_coefficients[k_min].get_max_index(); const int i_min = filter_coefficients[k_min][j_min].get_min_index(); const int i_max = filter_coefficients[k_min][j_min].get_max_index(); - - - if (true)//k_min != k_max) - { - - for (int z=out_min_z; z<=out_max_z; z++) - for (int y=out_min_y; y<=out_max_y; y++) - for (int x=out_min_x; x<=out_max_x; x++) - { - out_array[z][y][x] = 0; - - for (int k=max(k_min, z-in_max_z); k<=min(k_max, z-in_min_z); k++) - for (int j=max(j_min, y-in_max_y); j<=min(j_max, y-in_min_y); j++) - for (int i=max(i_min, x-in_max_x); i<=min(i_max, x-in_min_x); i++) - - out_array[z][y][x] += filter_coefficients[k][j][i]*in_array[z-k][y-j][x-i]; - } - - } - else + + if (true) // k_min != k_max) { - if (out_min_y!= out_max_y || out_min_x!=out_max_x) + + for (int z = out_min_z; z <= out_max_z; z++) + for (int y = out_min_y; y <= out_max_y; y++) + for (int x = out_min_x; x <= out_max_x; x++) { + out_array[z][y][x] = 0; + + for (int k = max(k_min, z - in_max_z); k <= min(k_max, z - in_min_z); k++) + for (int j = max(j_min, y - in_max_y); j <= min(j_max, y - in_min_y); j++) + for (int i = max(i_min, x - in_max_x); i <= min(i_max, x - in_min_x); i++) + + out_array[z][y][x] += filter_coefficients[k][j][i] * in_array[z - k][y - j][x - i]; + } + + } else { + if (out_min_y != out_max_y || out_min_x != out_max_x) error("3D convolution. check code\n"); - Array<2,float> array_out_tmp (IndexRange2D(out_min_y,out_max_y,out_min_x,out_max_x)); + Array<2, float> array_out_tmp(IndexRange2D(out_min_y, out_max_y, out_min_x, out_max_x)); do_it_2d(array_out_tmp, in_array[out_min_z]); - out_array[out_min_z][out_min_y][out_min_x] = array_out_tmp[out_min_y][out_min_x]; - + out_array[out_min_z][out_min_y][out_min_x] = array_out_tmp[out_min_y][out_min_x]; } - } #endif - #if 0 template void @@ -234,65 +205,49 @@ do_it(Array<3,elemT>& out_array, const Array<3,elemT>& in_array) const #endif - template void -ArrayFilter3DUsingConvolution:: -do_it_2d(Array<2,elemT>& out_array, const Array<2,elemT>& in_array) const -{ +ArrayFilter3DUsingConvolution::do_it_2d(Array<2, elemT>& out_array, const Array<2, elemT>& in_array) const { const int in_min_y = in_array.get_min_index(); const int in_max_y = in_array.get_max_index(); const int in_min_x = in_array[in_min_y].get_min_index(); const int in_max_x = in_array[in_min_y].get_max_index(); - - + const int out_min_y = out_array.get_min_index(); const int out_max_y = out_array.get_max_index(); const int out_min_x = out_array[out_min_y].get_min_index(); const int out_max_x = out_array[out_min_y].get_max_index(); - - - - if (is_trivial()) - { - for (int y=out_min_y; y<=out_max_y; y++) - for (int x=out_min_x; x<=out_max_x; x++) - + + if (is_trivial()) { + for (int y = out_min_y; y <= out_max_y; y++) + for (int x = out_min_x; x <= out_max_x; x++) + { - out_array[y][x] = ((y>=in_min_y && y <= in_max_y ) && - (x>=in_min_x && x <= in_max_x ) ? in_array[y][x] : 0); + out_array[y][x] = ((y >= in_min_y && y <= in_max_y) && (x >= in_min_x && x <= in_max_x) ? in_array[y][x] : 0); } - return; + return; } - - + const int k_min = filter_coefficients.get_min_index(); - //const int k_max = filter_coefficients.get_max_index(); + // const int k_max = filter_coefficients.get_max_index(); const int j_min = filter_coefficients[k_min].get_min_index(); const int j_max = filter_coefficients[k_min].get_max_index(); const int i_min = filter_coefficients[k_min][j_min].get_min_index(); const int i_max = filter_coefficients[k_min][j_min].get_max_index(); - - - - for (int y=out_min_y; y<=out_max_y; y++) - for (int x=out_min_x; x<=out_max_x; x++) - { + + for (int y = out_min_y; y <= out_max_y; y++) + for (int x = out_min_x; x <= out_max_x; x++) { out_array[y][x] = 0; - - for (int j=max(j_min, y-in_max_y); j<=min(j_max, y-in_min_y); j++) - for (int i=max(i_min, x-in_max_x); i<=min(i_max, x-in_min_x); i++) - - out_array[y][x] += filter_coefficients[filter_coefficients.get_min_index()][j][i]*in_array[y-j][x-i]; + + for (int j = max(j_min, y - in_max_y); j <= min(j_max, y - in_min_y); j++) + for (int i = max(i_min, x - in_max_x); i <= min(i_max, x - in_min_x); i++) + + out_array[y][x] += filter_coefficients[filter_coefficients.get_min_index()][j][i] * in_array[y - j][x - i]; } - - } - // instantiation template class ArrayFilter3DUsingConvolution; END_NAMESPACE_STIR - diff --git a/src/buildblock/ArrayFilterUsingRealDFTWithPadding.cxx b/src/buildblock/ArrayFilterUsingRealDFTWithPadding.cxx index a2e2b3320d..7d4202055b 100644 --- a/src/buildblock/ArrayFilterUsingRealDFTWithPadding.cxx +++ b/src/buildblock/ArrayFilterUsingRealDFTWithPadding.cxx @@ -34,141 +34,110 @@ #include "stir/modulo.h" #include - START_NAMESPACE_STIR template -ArrayFilterUsingRealDFTWithPadding:: -ArrayFilterUsingRealDFTWithPadding() -{} +ArrayFilterUsingRealDFTWithPadding::ArrayFilterUsingRealDFTWithPadding() {} template -ArrayFilterUsingRealDFTWithPadding:: -ArrayFilterUsingRealDFTWithPadding(const Array& real_filter_kernel) -{ - if (set_kernel(real_filter_kernel) == Succeeded::no) +ArrayFilterUsingRealDFTWithPadding::ArrayFilterUsingRealDFTWithPadding( + const Array& real_filter_kernel) { + if (set_kernel(real_filter_kernel) == Succeeded::no) error("Error constructing ArrayFilterUsingRealDFTWithPadding\n"); } #ifndef __stir_ArrayFilterUsingRealDFTWithPadding_no_complex_kernel__ template -ArrayFilterUsingRealDFTWithPadding:: -ArrayFilterUsingRealDFTWithPadding(const Array >& kernel_in_frequency_space) -{ - if (set_kernel_in_frequency_space(kernel_in_frequency_space) == Succeeded::no) +ArrayFilterUsingRealDFTWithPadding::ArrayFilterUsingRealDFTWithPadding( + const Array>& kernel_in_frequency_space) { + if (set_kernel_in_frequency_space(kernel_in_frequency_space) == Succeeded::no) error("Error constructing ArrayFilterUsingRealDFTWithPadding\n"); } #endif template Succeeded -ArrayFilterUsingRealDFTWithPadding:: -set_padding_range() -{ +ArrayFilterUsingRealDFTWithPadding::set_padding_range() { BasicCoordinate min_indices, max_indices; if (!kernel_in_frequency_space.get_regular_range(min_indices, max_indices)) return Succeeded::no; // check if kernel_in_frequency_space is 0-based, as currently required by fourier // TODO we could wrap-around if not - for (int d=1; d<=num_dimensions; ++d) - { - if (min_indices[d]!=0) - return Succeeded::no; - } - max_indices[num_dimensions] = 2*max_indices[num_dimensions] - 1; - this->padding_range = IndexRange(min_indices, max_indices); - this->padded_sizes = max_indices - min_indices +1; + for (int d = 1; d <= num_dimensions; ++d) { + if (min_indices[d] != 0) + return Succeeded::no; + } + max_indices[num_dimensions] = 2 * max_indices[num_dimensions] - 1; + this->padding_range = IndexRange(min_indices, max_indices); + this->padded_sizes = max_indices - min_indices + 1; return Succeeded::yes; } template -Succeeded -ArrayFilterUsingRealDFTWithPadding:: -set_kernel(const Array& real_filter_kernel) -{ +Succeeded +ArrayFilterUsingRealDFTWithPadding::set_kernel(const Array& real_filter_kernel) { BasicCoordinate min_indices, max_indices; if (!real_filter_kernel.get_regular_range(min_indices, max_indices)) return Succeeded::no; // check if we need to use wrap-around - if (norm(min_indices)<.01) // i.e. min_indices==0 - { - kernel_in_frequency_space = - fourier_for_real_data(real_filter_kernel); - }\ - else - { - // copy data to new kernel using wrap-around - const BasicCoordinate sizes = - max_indices - min_indices + 1; - const IndexRange range(sizes); - Array real_filter_kernel_from_0(range); - transform_array_to_periodic_indices(real_filter_kernel_from_0, - real_filter_kernel); - - // do DFT on this array - kernel_in_frequency_space = - fourier_for_real_data(real_filter_kernel_from_0); - } + if (norm(min_indices) < .01) // i.e. min_indices==0 + { + kernel_in_frequency_space = fourier_for_real_data(real_filter_kernel); + } else { + // copy data to new kernel using wrap-around + const BasicCoordinate sizes = max_indices - min_indices + 1; + const IndexRange range(sizes); + Array real_filter_kernel_from_0(range); + transform_array_to_periodic_indices(real_filter_kernel_from_0, real_filter_kernel); + + // do DFT on this array + kernel_in_frequency_space = fourier_for_real_data(real_filter_kernel_from_0); + } return this->set_padding_range(); } template Succeeded -ArrayFilterUsingRealDFTWithPadding:: -set_kernel_in_frequency_space(const Array >& kernel_in_frequency_space_v) -{ +ArrayFilterUsingRealDFTWithPadding::set_kernel_in_frequency_space( + const Array>& kernel_in_frequency_space_v) { kernel_in_frequency_space = kernel_in_frequency_space_v; return this->set_padding_range(); } template -bool ArrayFilterUsingRealDFTWithPadding:: -is_trivial() const -{ - return - kernel_in_frequency_space.size_all()==0 || - (kernel_in_frequency_space.size_all()==1 && - (*kernel_in_frequency_space.begin_all()) == std::complex(1,0)); +bool +ArrayFilterUsingRealDFTWithPadding::is_trivial() const { + return kernel_in_frequency_space.size_all() == 0 || + (kernel_in_frequency_space.size_all() == 1 && (*kernel_in_frequency_space.begin_all()) == std::complex(1, 0)); } - template -void -ArrayFilterUsingRealDFTWithPadding:: -do_it(Array& out_array, const Array& in_array) const -{ - if (in_array.get_index_range() == this->padding_range && - out_array.get_index_range() == this->padding_range) - { - // convolution using DFT - { - Array > tmp = - fourier_for_real_data(in_array); - tmp *= kernel_in_frequency_space; - out_array = inverse_fourier_for_real_data_corrupting_input(tmp); - } - } - else +void +ArrayFilterUsingRealDFTWithPadding::do_it(Array& out_array, + const Array& in_array) const { + if (in_array.get_index_range() == this->padding_range && out_array.get_index_range() == this->padding_range) { + // convolution using DFT { - // copy input into padded_array using wrap-around - - Array padded_array(this->padding_range); - transform_array_to_periodic_indices(padded_array, in_array); - // call do_it with padded_array - do_it(padded_array, padded_array); - // Now copy result in out_array using wrap-around - transform_array_from_periodic_indices(out_array, padded_array); + Array> tmp = fourier_for_real_data(in_array); + tmp *= kernel_in_frequency_space; + out_array = inverse_fourier_for_real_data_corrupting_input(tmp); } + } else { + // copy input into padded_array using wrap-around + + Array padded_array(this->padding_range); + transform_array_to_periodic_indices(padded_array, in_array); + // call do_it with padded_array + do_it(padded_array, padded_array); + // Now copy result in out_array using wrap-around + transform_array_from_periodic_indices(out_array, padded_array); + } } -template class ArrayFilterUsingRealDFTWithPadding<1,float>; -template class ArrayFilterUsingRealDFTWithPadding<2,float>; -template class ArrayFilterUsingRealDFTWithPadding<3,float>; +template class ArrayFilterUsingRealDFTWithPadding<1, float>; +template class ArrayFilterUsingRealDFTWithPadding<2, float>; +template class ArrayFilterUsingRealDFTWithPadding<3, float>; END_NAMESPACE_STIR - - - diff --git a/src/buildblock/ByteOrder.cxx b/src/buildblock/ByteOrder.cxx index e1934737c2..c43f92256b 100644 --- a/src/buildblock/ByteOrder.cxx +++ b/src/buildblock/ByteOrder.cxx @@ -1,7 +1,7 @@ // // /*! - \file + \file \ingroup buildblock \brief This file initialises ByteOrder::native_order. @@ -37,7 +37,6 @@ START_NAMESPACE_STIR - /* A somewhat complicated way to determine the byteorder. The advantage is that it doesn't need ntohs (and so any compiler specific definitions, libraries or whatever). @@ -45,22 +44,19 @@ START_NAMESPACE_STIR by casting its address as a char *. The reinterpret_cash is to make it typesafe for C++. - First we do a (paranoid) check : + First we do a (paranoid) check : sizeof(unsigned long) - sizeof(unsigned char) > 0 - This is done via a 'compile-time assertion', i.e. it breaks + This is done via a 'compile-time assertion', i.e. it breaks at compile time when the assertion is false. The line below relies on the fact that you cannot have an array with zero (or less) elements. */ -typedef char - assert_unsigned_long_size[sizeof(unsigned long) - sizeof(unsigned char)]; +typedef char assert_unsigned_long_size[sizeof(unsigned long) - sizeof(unsigned char)]; static const unsigned long magic = 1; const ByteOrder::Order ByteOrder::native_order = - *(reinterpret_cast(&magic) ) == 1 ? - little_endian : big_endian; - + *(reinterpret_cast(&magic)) == 1 ? little_endian : big_endian; END_NAMESPACE_STIR diff --git a/src/buildblock/ChainedDataProcessor.cxx b/src/buildblock/ChainedDataProcessor.cxx index c8bfc1fa2e..88f192a1b7 100644 --- a/src/buildblock/ChainedDataProcessor.cxx +++ b/src/buildblock/ChainedDataProcessor.cxx @@ -26,93 +26,67 @@ */ #include "stir/ChainedDataProcessor.h" #include "stir/DiscretisedDensity.h" -#include "stir/modelling/ParametricDiscretisedDensity.h" -#include "stir/modelling/KineticParameters.h" +#include "stir/modelling/ParametricDiscretisedDensity.h" +#include "stir/modelling/KineticParameters.h" #include "stir/is_null_ptr.h" #include #include "stir/unique_ptr.h" START_NAMESPACE_STIR - template Succeeded -ChainedDataProcessor:: -virtual_set_up(const DataT& data) -{ - if (!is_null_ptr(this->apply_first)) - { - // note that we cannot really build the filter for the 2nd - // as we don't know what the first will do to the dimensions etc. of the data - return this->apply_first->set_up(data); - } - else if (!is_null_ptr(this->apply_second)) +ChainedDataProcessor::virtual_set_up(const DataT& data) { + if (!is_null_ptr(this->apply_first)) { + // note that we cannot really build the filter for the 2nd + // as we don't know what the first will do to the dimensions etc. of the data + return this->apply_first->set_up(data); + } else if (!is_null_ptr(this->apply_second)) return this->apply_second->set_up(data); else - return Succeeded::yes; + return Succeeded::yes; } - template void -ChainedDataProcessor:: -virtual_apply(DataT& data) const -{ +ChainedDataProcessor::virtual_apply(DataT& data) const { if (!is_null_ptr(this->apply_first)) this->apply_first->apply(data); if (!is_null_ptr(this->apply_second)) this->apply_second->apply(data); } - template void -ChainedDataProcessor:: -virtual_apply(DataT& out_data, - const DataT& in_data) const -{ - if (!is_null_ptr(this->apply_first)) - { - if (!is_null_ptr(this->apply_second)) - { - // a bit complicated because we need a temporary data copy - unique_ptr< DataT> temp_data_ptr - (in_data.get_empty_copy()); - this->apply_first->apply(*temp_data_ptr, in_data); - this->apply_second->apply(out_data, *temp_data_ptr); - } - else - this->apply_first->apply(out_data, in_data); - } - else - if (!is_null_ptr(this->apply_second)) - this->apply_second->apply(out_data, in_data); - +ChainedDataProcessor::virtual_apply(DataT& out_data, const DataT& in_data) const { + if (!is_null_ptr(this->apply_first)) { + if (!is_null_ptr(this->apply_second)) { + // a bit complicated because we need a temporary data copy + unique_ptr temp_data_ptr(in_data.get_empty_copy()); + this->apply_first->apply(*temp_data_ptr, in_data); + this->apply_second->apply(out_data, *temp_data_ptr); + } else + this->apply_first->apply(out_data, in_data); + } else if (!is_null_ptr(this->apply_second)) + this->apply_second->apply(out_data, in_data); } template -ChainedDataProcessor:: -ChainedDataProcessor(shared_ptr > apply_first_v, - shared_ptr > apply_second_v) - : apply_first(apply_first_v), - apply_second(apply_second_v) -{ +ChainedDataProcessor::ChainedDataProcessor(shared_ptr> apply_first_v, + shared_ptr> apply_second_v) + : apply_first(apply_first_v), apply_second(apply_second_v) { this->set_defaults(); } template void -ChainedDataProcessor:: -set_defaults() -{ +ChainedDataProcessor::set_defaults() { base_type::set_defaults(); } template -void -ChainedDataProcessor:: -initialise_keymap() -{ +void +ChainedDataProcessor::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Chained Data Processor Parameters"); this->parser.add_parsing_key("Data Processor to apply first", &this->apply_first); @@ -120,29 +94,19 @@ initialise_keymap() this->parser.add_stop_key("END Chained Data Processor Parameters"); } - - template -const char * const -ChainedDataProcessor::registered_name = - "Chained Data Processor"; - +const char* const ChainedDataProcessor::registered_name = "Chained Data Processor"; -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif // Register this class in the DataProcessor registry // static ChainedDataProcessor::RegisterIt dummy; // have the above variable in a separate file, which you need to pass at link time -template class ChainedDataProcessor >; -template class ChainedDataProcessor; +template class ChainedDataProcessor>; +template class ChainedDataProcessor; END_NAMESPACE_STIR - - - - - diff --git a/src/buildblock/DataSymmetriesForViewSegmentNumbers.cxx b/src/buildblock/DataSymmetriesForViewSegmentNumbers.cxx index a40108d255..6adb57fd35 100644 --- a/src/buildblock/DataSymmetriesForViewSegmentNumbers.cxx +++ b/src/buildblock/DataSymmetriesForViewSegmentNumbers.cxx @@ -17,7 +17,7 @@ */ /*! \file - \ingroup projdata + \ingroup projdata \brief Implementations for class stir::DataSymmetriesForViewSegmentNumbers \author Kris Thielemans @@ -32,50 +32,34 @@ using std::vector; START_NAMESPACE_STIR -DataSymmetriesForViewSegmentNumbers:: -~DataSymmetriesForViewSegmentNumbers() -{} +DataSymmetriesForViewSegmentNumbers::~DataSymmetriesForViewSegmentNumbers() {} /*! Default implementation always returns \c true. Needs to be overloaded. */ bool -DataSymmetriesForViewSegmentNumbers:: -blindly_equals(const root_type * const) const -{ +DataSymmetriesForViewSegmentNumbers::blindly_equals(const root_type* const) const { return true; } bool -DataSymmetriesForViewSegmentNumbers:: -operator ==(const root_type& that) const -{ - return - typeid(*this) == typeid(that) && - (this == &that || - this->blindly_equals(&that) - ); +DataSymmetriesForViewSegmentNumbers::operator==(const root_type& that) const { + return typeid(*this) == typeid(that) && (this == &that || this->blindly_equals(&that)); } bool -DataSymmetriesForViewSegmentNumbers:: -operator !=(const root_type& that) const -{ +DataSymmetriesForViewSegmentNumbers::operator!=(const root_type& that) const { return !((*this) == that); } - int -DataSymmetriesForViewSegmentNumbers::num_related_view_segment_numbers(const ViewSegmentNumbers& vs) const -{ +DataSymmetriesForViewSegmentNumbers::num_related_view_segment_numbers(const ViewSegmentNumbers& vs) const { vector rel_vs; get_related_view_segment_numbers(rel_vs, vs); return static_cast(rel_vs.size()); } bool -DataSymmetriesForViewSegmentNumbers:: -is_basic(const ViewSegmentNumbers& v_s) const -{ +DataSymmetriesForViewSegmentNumbers::is_basic(const ViewSegmentNumbers& v_s) const { ViewSegmentNumbers copy = v_s; return !find_basic_view_segment_numbers(copy); } diff --git a/src/buildblock/DiscretisedDensity.cxx b/src/buildblock/DiscretisedDensity.cxx index 704452ff4e..e1c457c326 100644 --- a/src/buildblock/DiscretisedDensity.cxx +++ b/src/buildblock/DiscretisedDensity.cxx @@ -2,12 +2,12 @@ // /*! - \file + \file \ingroup densitydata - + \brief Implementations of non-inline functions of class stir::DiscretisedDensity - \author Kris Thielemans + \author Kris Thielemans \author Ashley Gillman \author PARAPET project @@ -33,19 +33,19 @@ */ #include "stir/DiscretisedDensity.h" #if 1 -#include "stir/IO/read_from_file.h" +# include "stir/IO/read_from_file.h" #else -#include "stir/IO/interfile.h" -#ifdef HAVE_LLN_MATRIX -#include "stir/IO/ecat6_utils.h" -#include "stir/IO/stir_ecat6.h" -#include "stir/IO/stir_ecat7.h" -#endif -#include "stir/VoxelsOnCartesianGrid.h" -#include "stir/is_null_ptr.h" -#ifdef STIR_USE_GE_IO -#include "stir_experimental/IO/GE/niff.h" -#endif +# include "stir/IO/interfile.h" +# ifdef HAVE_LLN_MATRIX +# include "stir/IO/ecat6_utils.h" +# include "stir/IO/stir_ecat6.h" +# include "stir/IO/stir_ecat7.h" +# endif +# include "stir/VoxelsOnCartesianGrid.h" +# include "stir/is_null_ptr.h" +# ifdef STIR_USE_GE_IO +# include "stir_experimental/IO/GE/niff.h" +# endif #endif #include @@ -62,35 +62,33 @@ START_NAMESPACE_STIR // sadly, gcc 2.95.* does not support local namespaces as used below // This is slightly funny as it does work in ProjData.cxx. // Maybe because here it's in a template? -# if __GNUC__ == 2 -#ifdef HAVE_LLN_MATRIX +# if __GNUC__ == 2 +# ifdef HAVE_LLN_MATRIX USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 USING_NAMESPACE_ECAT6 -#endif -#endif +# endif +# endif #endif -/*! +/*! \deprecated This function just calls stir::read_from_file. */ -template -DiscretisedDensity * -DiscretisedDensity:: - read_from_file(const string& filename) -{ +template +DiscretisedDensity* +DiscretisedDensity::read_from_file(const string& filename) { #if 1 - unique_ptr > density_aptr - (stir::read_from_file >(filename)); + unique_ptr> density_aptr( + stir::read_from_file>(filename)); return density_aptr.release(); #else if (num_dimensions != 3 || typeid(elemT) != typeid(float)) error("DiscretisedDensity::read_from_file currently only supports 3d float images\n"); - const int max_length=300; + const int max_length = 300; char signature[max_length]; // read signature @@ -98,144 +96,118 @@ DiscretisedDensity:: fstream input(filename.c_str(), ios::in | ios::binary); if (!input) error("DiscretisedDensity::read_from_file: error opening file %s\n", filename.c_str()); - + input.read(signature, max_length); - signature[max_length-1]='\0'; + signature[max_length - 1] = '\0'; } // Interfile - if (is_interfile_signature(signature)) - { -#ifndef NDEBUG - warning("DiscretisedDensity::read_from_file trying to read %s as Interfile\n", - filename.c_str()); -#endif - DiscretisedDensity * density_ptr = - read_interfile_image(filename); + if (is_interfile_signature(signature)) { +# ifndef NDEBUG + warning("DiscretisedDensity::read_from_file trying to read %s as Interfile\n", filename.c_str()); +# endif + DiscretisedDensity* density_ptr = read_interfile_image(filename); if (!is_null_ptr(density_ptr)) return density_ptr; } - - -#ifdef HAVE_LLN_MATRIX - if (strncmp(signature, "MATRIX", 6) == 0) - { -#ifndef NDEBUG +# ifdef HAVE_LLN_MATRIX + if (strncmp(signature, "MATRIX", 6) == 0) { +# ifndef NDEBUG warning("DiscretisedDensity::read_from_file trying to read %s as ECAT7\n", filename.c_str()); -#endif +# endif USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 - if (is_ECAT7_image_file(filename)) - { - warning("\nReading frame 1, gate 1, data 0, bed 0 from file %s\n", - filename.c_str()); - DiscretisedDensity * density_ptr = - ECAT7_to_VoxelsOnCartesianGrid(filename, - /*frame_num, gate_num, data_num, bed_num*/1,1,0,0); + if (is_ECAT7_image_file(filename)) { + warning("\nReading frame 1, gate 1, data 0, bed 0 from file %s\n", filename.c_str()); + DiscretisedDensity* density_ptr = + ECAT7_to_VoxelsOnCartesianGrid(filename, + /*frame_num, gate_num, data_num, bed_num*/ 1, 1, 0, 0); if (!is_null_ptr(density_ptr)) - return density_ptr; - } - else - { + return density_ptr; + } else { if (is_ECAT7_file(filename)) - warning("DiscretisedDensity::read_from_file ECAT7 file %s is of unsupported file type\n", filename.c_str()); + warning("DiscretisedDensity::read_from_file ECAT7 file %s is of unsupported file type\n", filename.c_str()); } - } -#endif // HAVE_LLN_MATRIX +# endif // HAVE_LLN_MATRIX -#ifdef STIR_USE_GE_IO +# ifdef STIR_USE_GE_IO // NIFF file format (a simple almost raw format from GE) { using namespace GE_IO; - if (Niff::isReadableNiffFile(filename)) + if (Niff::isReadableNiffFile(filename)) { + Niff::Niff input_niff(filename, std::ios::in | std::ios::out); + if (input_niff.get_num_dimensions() != 3) { + warning("DiscretisedDensity::read_from_file:\n" + "File %s is a NIFF file but has %d dimensions (should be 3)", + filename.c_str(), input_niff.get_num_dimensions()); + return 0; + } + CartesianCoordinate3D voxel_size; + { + std::vector pixel_spacing = input_niff.get_pixel_spacing(); + std::copy(pixel_spacing.begin(), pixel_spacing.end(), voxel_size.begin()); + } + Array<3, float> data; { - Niff::Niff input_niff(filename, std::ios::in | std::ios::out); - if (input_niff.get_num_dimensions() != 3) - { - warning("DiscretisedDensity::read_from_file:\n" - "File %s is a NIFF file but has %d dimensions (should be 3)", - filename.c_str(), input_niff.get_num_dimensions()); - return 0; - } - CartesianCoordinate3D voxel_size; - { - std::vector pixel_spacing = input_niff.get_pixel_spacing(); - std::copy(pixel_spacing.begin(), pixel_spacing.end(), voxel_size.begin()); - } - Array<3, float> data; - { - input_niff.fill_array(data); - // change sizes to standard STIR convention - for (int z=data.get_min_index(); z<= data.get_max_index(); ++z) - { - data[z].set_min_index(-(data[z].get_length()/2)); - for (int y=data[z].get_min_index(); y<= data[z].get_max_index(); ++y) - { - data[z][y].set_min_index(-(data[z][y].get_length()/2)); - } - } - } - CartesianCoordinate3D origin; - origin.fill(0); - - return - new VoxelsOnCartesianGrid(data, - origin, - voxel_size); + input_niff.fill_array(data); + // change sizes to standard STIR convention + for (int z = data.get_min_index(); z <= data.get_max_index(); ++z) { + data[z].set_min_index(-(data[z].get_length() / 2)); + for (int y = data[z].get_min_index(); y <= data[z].get_max_index(); ++y) { + data[z][y].set_min_index(-(data[z][y].get_length() / 2)); + } + } } + CartesianCoordinate3D origin; + origin.fill(0); + + return new VoxelsOnCartesianGrid(data, origin, voxel_size); + } } -#endif +# endif -#ifdef HAVE_LLN_MATRIX +# ifdef HAVE_LLN_MATRIX { // Try ECAT6 // ECAT6 does not have a signature -#ifndef NDEBUG +# ifndef NDEBUG warning("DiscretisedDensity::read_from_file trying to read %s as ECAT6\n", filename.c_str()); -#endif +# endif USING_NAMESPACE_ECAT; USING_NAMESPACE_ECAT6; - if (is_ECAT6_image_file(filename)) - { - ECAT6_Main_header mhead; - FILE * cti_fptr=fopen(filename.c_str(), "rb"); - if(cti_read_ECAT6_Main_header(cti_fptr, &mhead)!=EXIT_SUCCESS) - { - if (cti_fptr!=NULL) - fclose(cti_fptr); - error ("error reading main header in ECAT 6 file %s\n", filename.c_str()); - } - - warning("\nReading frame 1, gate 1, data 0, bed 0 from file %s\n", - filename.c_str()); - VoxelsOnCartesianGrid * tmp = - ECAT6_to_VoxelsOnCartesianGrid(/*frame_num, gate_num, data_num, bed_num*/1,1,0,0, - cti_fptr, mhead); - fclose(cti_fptr); - return tmp; + if (is_ECAT6_image_file(filename)) { + ECAT6_Main_header mhead; + FILE* cti_fptr = fopen(filename.c_str(), "rb"); + if (cti_read_ECAT6_Main_header(cti_fptr, &mhead) != EXIT_SUCCESS) { + if (cti_fptr != NULL) + fclose(cti_fptr); + error("error reading main header in ECAT 6 file %s\n", filename.c_str()); } - } -#endif // HAVE_LLN_MATRIX + warning("\nReading frame 1, gate 1, data 0, bed 0 from file %s\n", filename.c_str()); + VoxelsOnCartesianGrid* tmp = + ECAT6_to_VoxelsOnCartesianGrid(/*frame_num, gate_num, data_num, bed_num*/ 1, 1, 0, 0, cti_fptr, mhead); + fclose(cti_fptr); + return tmp; + } + } +# endif // HAVE_LLN_MATRIX - error("DiscretisedDensity::read_from_file: %s seems to be in an unsupported file format\n", - filename.c_str()); + error("DiscretisedDensity::read_from_file: %s seems to be in an unsupported file format\n", filename.c_str()); return 0; #endif - } - /****************************** instantiations *****************************/ #ifdef _MSC_VER // disable warning on pure virtuals which are not defined -#pragma warning(disable: 4661) +# pragma warning(disable : 4661) #endif -template class DiscretisedDensity<3,float>; +template class DiscretisedDensity<3, float>; END_NAMESPACE_STIR diff --git a/src/buildblock/DynamicDiscretisedDensity.cxx b/src/buildblock/DynamicDiscretisedDensity.cxx index a2f24a568d..4b89211f3d 100644 --- a/src/buildblock/DynamicDiscretisedDensity.cxx +++ b/src/buildblock/DynamicDiscretisedDensity.cxx @@ -7,7 +7,7 @@ \author Kris Thielemans \author Charalampos Tsoumpas \author Richard Brown - + */ /* Copyright (C) 2005- 2011, Hammersmith Imanet Ltd @@ -44,191 +44,165 @@ using std::string; START_NAMESPACE_STIR -DynamicDiscretisedDensity:: -DynamicDiscretisedDensity(const DynamicDiscretisedDensity& argument) -{ - (*this) = argument; -} +DynamicDiscretisedDensity::DynamicDiscretisedDensity(const DynamicDiscretisedDensity& argument) { (*this) = argument; } DynamicDiscretisedDensity& -DynamicDiscretisedDensity:: -operator=(const DynamicDiscretisedDensity& argument) -{ +DynamicDiscretisedDensity::operator=(const DynamicDiscretisedDensity& argument) { this->set_exam_info(argument.get_exam_info()); this->_densities.resize(argument._densities.size()); - for (unsigned int i=0; i_densities[i].reset(argument._densities[i]->clone()); this->_scanner_sptr = argument._scanner_sptr; -// this->exam_info_sptr->set_calibration_factor(argument.get_calibration_factor()); + // this->exam_info_sptr->set_calibration_factor(argument.get_calibration_factor()); this->_isotope_halflife = argument._isotope_halflife; this->_is_decay_corrected = argument._is_decay_corrected; return *this; } -void -DynamicDiscretisedDensity:: -set_density(const DiscretisedDensity<3,float>& density, - const unsigned int frame_num) -{ - // scan start should be the same - if (fabs(this->get_exam_info().start_time_in_secs_since_1970 - - density.get_exam_info().start_time_in_secs_since_1970) > .5) - error("DynamicDiscretisedDensity::set_density: Density should have same start_time_secs"); - // The added density should only contain 1 time frame - if(density.get_exam_info().time_frame_definitions.get_num_time_frames() != 1) - error("DynamicDiscretisedDensity::set_density: Density should contain 1 time frame"); - if(this->get_exam_info_sptr()->time_frame_definitions.get_num_time_frames() < frame_num) - error("DynamicDiscretisedDensity::set_density: Set DynamicDiscretisedDensity time frame definition before using set_density"); - - // Check the starts and ends match - double dyn_start = this->exam_info_sptr->time_frame_definitions.get_start_time(frame_num); - double dis_start = density.get_exam_info().time_frame_definitions.get_start_time(1); - double dyn_end = this->exam_info_sptr->time_frame_definitions.get_end_time(frame_num); - double dis_end = density.get_exam_info().time_frame_definitions.get_end_time(1); - - if (fabs(dyn_start - dis_start) > 1e-10) - error(boost::format("DynamicDiscretisedDensity::set_density: Time frame start should match (is %1% but expected %2%)") - % dis_start % dyn_start); - - if (fabs(dyn_end - dis_end) > 1e-10) - error(boost::format("DynamicDiscretisedDensity::set_density: Time frame end should match (is %1% but expected %2%)") - % dis_end % dyn_end); - - this->_densities.at(frame_num-1).reset(density.clone()); -} - -const std::vector > > & -DynamicDiscretisedDensity:: -get_densities() const -{ return this->_densities ; } - -const DiscretisedDensity<3,float> & -DynamicDiscretisedDensity:: -get_density(const unsigned int frame_num) const -{ return *this->_densities.at(frame_num-1) ; } - -DiscretisedDensity<3,float> & -DynamicDiscretisedDensity:: -get_density(const unsigned int frame_num) -{ return *this->_densities.at(frame_num-1) ; } - -const float -DynamicDiscretisedDensity:: -get_isotope_halflife() const -{ return this->_isotope_halflife; } - -const float -DynamicDiscretisedDensity:: -get_scanner_default_bin_size() const -{ +void +DynamicDiscretisedDensity::set_density(const DiscretisedDensity<3, float>& density, const unsigned int frame_num) { + // scan start should be the same + if (fabs(this->get_exam_info().start_time_in_secs_since_1970 - density.get_exam_info().start_time_in_secs_since_1970) > .5) + error("DynamicDiscretisedDensity::set_density: Density should have same start_time_secs"); + // The added density should only contain 1 time frame + if (density.get_exam_info().time_frame_definitions.get_num_time_frames() != 1) + error("DynamicDiscretisedDensity::set_density: Density should contain 1 time frame"); + if (this->get_exam_info_sptr()->time_frame_definitions.get_num_time_frames() < frame_num) + error("DynamicDiscretisedDensity::set_density: Set DynamicDiscretisedDensity time frame definition before using set_density"); + + // Check the starts and ends match + double dyn_start = this->exam_info_sptr->time_frame_definitions.get_start_time(frame_num); + double dis_start = density.get_exam_info().time_frame_definitions.get_start_time(1); + double dyn_end = this->exam_info_sptr->time_frame_definitions.get_end_time(frame_num); + double dis_end = density.get_exam_info().time_frame_definitions.get_end_time(1); + + if (fabs(dyn_start - dis_start) > 1e-10) + error(boost::format("DynamicDiscretisedDensity::set_density: Time frame start should match (is %1% but expected %2%)") % + dis_start % dyn_start); + + if (fabs(dyn_end - dis_end) > 1e-10) + error(boost::format("DynamicDiscretisedDensity::set_density: Time frame end should match (is %1% but expected %2%)") % + dis_end % dyn_end); + + this->_densities.at(frame_num - 1).reset(density.clone()); +} + +const std::vector>>& +DynamicDiscretisedDensity::get_densities() const { + return this->_densities; +} + +const DiscretisedDensity<3, float>& +DynamicDiscretisedDensity::get_density(const unsigned int frame_num) const { + return *this->_densities.at(frame_num - 1); +} + +DiscretisedDensity<3, float>& +DynamicDiscretisedDensity::get_density(const unsigned int frame_num) { + return *this->_densities.at(frame_num - 1); +} + +const float +DynamicDiscretisedDensity::get_isotope_halflife() const { + return this->_isotope_halflife; +} + +const float +DynamicDiscretisedDensity::get_scanner_default_bin_size() const { if (!this->_scanner_sptr) error("DynamicDiscretisedDensity::get_scanner_default_bin_size(): scanner not set"); return this->_scanner_sptr->get_default_bin_size(); } - float -DynamicDiscretisedDensity:: -get_calibration_factor() const -{ return this->exam_info_sptr->get_calibration_factor(); } - -const TimeFrameDefinitions & -DynamicDiscretisedDensity:: -get_time_frame_definitions() const -{ return this->get_exam_info().get_time_frame_definitions(); } +float +DynamicDiscretisedDensity::get_calibration_factor() const { + return this->exam_info_sptr->get_calibration_factor(); +} +const TimeFrameDefinitions& +DynamicDiscretisedDensity::get_time_frame_definitions() const { + return this->get_exam_info().get_time_frame_definitions(); +} const double -DynamicDiscretisedDensity:: -get_start_time_in_secs_since_1970() const -{ return this->get_exam_info().start_time_in_secs_since_1970; } +DynamicDiscretisedDensity::get_start_time_in_secs_since_1970() const { + return this->get_exam_info().start_time_in_secs_since_1970; +} DynamicDiscretisedDensity* -DynamicDiscretisedDensity:: -read_from_file(const string& filename) // The written image is read in respect to its center as origin!!! +DynamicDiscretisedDensity::read_from_file( + const string& filename) // The written image is read in respect to its center as origin!!! { - unique_ptr dyn_sptr - (stir::read_from_file(filename)); + unique_ptr dyn_sptr(stir::read_from_file(filename)); return dyn_sptr.release(); } -Succeeded -DynamicDiscretisedDensity:: -write_to_ecat7(const string& filename) const -{ +Succeeded +DynamicDiscretisedDensity::write_to_ecat7(const string& filename) const { #ifndef HAVE_LLN_MATRIX return Succeeded::no; #else Main_header mhead; - ecat::ecat7::make_ECAT7_main_header(mhead, *_scanner_sptr, filename, get_density(1) ); + ecat::ecat7::make_ECAT7_main_header(mhead, *_scanner_sptr, filename, get_density(1)); mhead.num_frames = get_time_frame_definitions().get_num_frames(); - mhead.acquisition_type = - mhead.num_frames>1 ? DynamicEmission : StaticEmission; - mhead.calibration_factor=_calibration_factor; - mhead.isotope_halflife=_isotope_halflife; + mhead.acquisition_type = mhead.num_frames > 1 ? DynamicEmission : StaticEmission; + mhead.calibration_factor = _calibration_factor; + mhead.isotope_halflife = _isotope_halflife; round_to(mhead.scan_start_time, floor(this->get_start_time_in_secs_since_1970())); - MatrixFile* mptr= matrix_create (filename.c_str(), MAT_CREATE, &mhead); - if (mptr == 0) - { - warning("DynamicDiscretisedDensity::write_to_ecat7 cannot write output file %s\n", filename.c_str()); + MatrixFile* mptr = matrix_create(filename.c_str(), MAT_CREATE, &mhead); + if (mptr == 0) { + warning("DynamicDiscretisedDensity::write_to_ecat7 cannot write output file %s\n", filename.c_str()); + return Succeeded::no; + } + for (unsigned int frame_num = 1; frame_num <= get_time_frame_definitions().get_num_frames(); ++frame_num) { + if (ecat::ecat7::DiscretisedDensity_to_ECAT7(mptr, get_density(frame_num), frame_num) == Succeeded::no) { + matrix_close(mptr); return Succeeded::no; } - for ( unsigned int frame_num = 1 ; frame_num<=get_time_frame_definitions().get_num_frames() ; ++frame_num ) - { - if (ecat::ecat7::DiscretisedDensity_to_ECAT7(mptr, - get_density(frame_num), - frame_num) - == Succeeded::no) - { - matrix_close(mptr); - return Succeeded::no; - } - } + } matrix_close(mptr); return Succeeded::yes; #endif // end of HAVE_LLN_MATRIX } - void DynamicDiscretisedDensity:: - calibrate_frames() const -{ - for ( unsigned int frame_num = 1 ; frame_num<=get_time_frame_definitions().get_num_frames() ; ++frame_num ) - { - *(_densities[frame_num-1])*=exam_info_sptr->get_calibration_factor(); - } +void +DynamicDiscretisedDensity::calibrate_frames() const { + for (unsigned int frame_num = 1; frame_num <= get_time_frame_definitions().get_num_frames(); ++frame_num) { + *(_densities[frame_num - 1]) *= exam_info_sptr->get_calibration_factor(); + } } -void DynamicDiscretisedDensity:: -set_calibration_factor(const float calibration_factor) -{ - auto new_exam_info_sptr = std::make_shared(this->get_exam_info()); - new_exam_info_sptr->set_calibration_factor(calibration_factor); - this->set_exam_info(*new_exam_info_sptr); +void +DynamicDiscretisedDensity::set_calibration_factor(const float calibration_factor) { + auto new_exam_info_sptr = std::make_shared(this->get_exam_info()); + new_exam_info_sptr->set_calibration_factor(calibration_factor); + this->set_exam_info(*new_exam_info_sptr); } -void DynamicDiscretisedDensity:: -set_if_decay_corrected(const bool is_decay_corrected) -{ this->_is_decay_corrected=is_decay_corrected; } +void +DynamicDiscretisedDensity::set_if_decay_corrected(const bool is_decay_corrected) { + this->_is_decay_corrected = is_decay_corrected; +} -void DynamicDiscretisedDensity:: -set_isotope_halflife(const float isotope_halflife) -{ _isotope_halflife=isotope_halflife; } +void +DynamicDiscretisedDensity::set_isotope_halflife(const float isotope_halflife) { + _isotope_halflife = isotope_halflife; +} - void DynamicDiscretisedDensity:: - decay_correct_frames() -{ - if (_is_decay_corrected==true) +void +DynamicDiscretisedDensity::decay_correct_frames() { + if (_is_decay_corrected == true) warning("DynamicDiscretisedDensity is already decay corrected"); - else - { - for ( unsigned int frame_num = 1 ; frame_num<=get_time_frame_definitions().get_num_frames() ; ++frame_num ) - { - *(_densities[frame_num-1])*= - static_cast(decay_correction_factor(_isotope_halflife,get_time_frame_definitions().get_start_time(frame_num),get_time_frame_definitions().get_end_time(frame_num))); - } - _is_decay_corrected=true; + else { + for (unsigned int frame_num = 1; frame_num <= get_time_frame_definitions().get_num_frames(); ++frame_num) { + *(_densities[frame_num - 1]) *= + static_cast(decay_correction_factor(_isotope_halflife, get_time_frame_definitions().get_start_time(frame_num), + get_time_frame_definitions().get_end_time(frame_num))); } + _is_decay_corrected = true; + } } END_NAMESPACE_STIR diff --git a/src/buildblock/DynamicProjData.cxx b/src/buildblock/DynamicProjData.cxx index 056df7be88..64f486896d 100644 --- a/src/buildblock/DynamicProjData.cxx +++ b/src/buildblock/DynamicProjData.cxx @@ -53,49 +53,41 @@ using std::istream; START_NAMESPACE_STIR // declaration of helper function -static -DynamicProjData* -read_interfile_DPDFS(const string& filename, - const std::ios::openmode open_mode = std::ios::in); +static DynamicProjData* read_interfile_DPDFS(const string& filename, const std::ios::openmode open_mode = std::ios::in); const double -DynamicProjData:: -get_start_time_in_secs_since_1970() const -{ return this->get_exam_info().start_time_in_secs_since_1970; } - -void -DynamicProjData:: -set_start_time_in_secs_since_1970(const double start_time) -{ +DynamicProjData::get_start_time_in_secs_since_1970() const { + return this->get_exam_info().start_time_in_secs_since_1970; +} + +void +DynamicProjData::set_start_time_in_secs_since_1970(const double start_time) { shared_ptr sptr = this->exam_info_sptr->create_shared_clone(); - sptr->start_time_in_secs_since_1970=start_time; + sptr->start_time_in_secs_since_1970 = start_time; this->exam_info_sptr = sptr; } void -DynamicProjData:: -set_time_frame_definitions(const TimeFrameDefinitions& time_frame_definitions) -{ +DynamicProjData::set_time_frame_definitions(const TimeFrameDefinitions& time_frame_definitions) { shared_ptr sptr = this->exam_info_sptr->create_shared_clone(); - sptr->time_frame_definitions=time_frame_definitions; + sptr->time_frame_definitions = time_frame_definitions; this->exam_info_sptr = sptr; } -const TimeFrameDefinitions& -DynamicProjData:: -get_time_frame_definitions() const -{ return this->exam_info_sptr->time_frame_definitions; } +const TimeFrameDefinitions& +DynamicProjData::get_time_frame_definitions() const { + return this->exam_info_sptr->time_frame_definitions; +} unique_ptr -DynamicProjData:: -read_from_file(const string& filename) // The written projection data is read in respect to its center as origin!!! +DynamicProjData::read_from_file( + const string& filename) // The written projection data is read in respect to its center as origin!!! { const FileSignature file_signature(filename); - const char * signature = file_signature.get_signature(); + const char* signature = file_signature.get_signature(); // Interfile - if (is_interfile_signature(signature)) - { + if (is_interfile_signature(signature)) { #ifndef NDEBUG info(boost::format("DynamicProjData::read_from_file trying to read %s as Interfile") % filename); #endif @@ -107,109 +99,89 @@ read_from_file(const string& filename) // The written projection data is read in } #ifdef HAVE_LLN_MATRIX - if (strncmp(signature, "MATRIX", 6) == 0) - { -#ifndef NDEBUG + if (strncmp(signature, "MATRIX", 6) == 0) { +# ifndef NDEBUG warning("DynamicProjData::read_from_file trying to read '%s' as ECAT7", filename.c_str()); -#endif +# endif USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 - if (is_ECAT7_emission_file(filename)) - { + if (is_ECAT7_emission_file(filename)) { Main_header mhead; - if (read_ECAT7_main_header(mhead, filename) == Succeeded::no) - { - warning("DynamicProjData::read_from_file cannot read '%s' as ECAT7", filename.c_str()); - return unique_ptr(); - } + if (read_ECAT7_main_header(mhead, filename) == Succeeded::no) { + warning("DynamicProjData::read_from_file cannot read '%s' as ECAT7", filename.c_str()); + return unique_ptr(); + } shared_ptr exam_info_sptr(read_ECAT7_exam_info(filename)); unique_ptr dynamic_proj_data_ptr(new DynamicProjData(exam_info_sptr)); // we no longer have a _scanner_sptr member, so next lines are commented out - //dynamic_proj_data_ptr->_scanner_sptr.reset( + // dynamic_proj_data_ptr->_scanner_sptr.reset( // find_scanner_from_ECAT_system_type(mhead.system_type)); - const unsigned int num_frames = - static_cast(mhead.num_frames); - dynamic_proj_data_ptr->_proj_datas.resize(num_frames); - - for (unsigned int frame_num=1; frame_num <= num_frames; ++ frame_num) - { - dynamic_proj_data_ptr->_proj_datas[frame_num-1].reset( - ECAT7_to_PDFS(filename, - frame_num, - /*gate*/1, - /* data_num, bed_num, */ 0,0)); - } + const unsigned int num_frames = static_cast(mhead.num_frames); + dynamic_proj_data_ptr->_proj_datas.resize(num_frames); + + for (unsigned int frame_num = 1; frame_num <= num_frames; ++frame_num) { + dynamic_proj_data_ptr->_proj_datas[frame_num - 1].reset(ECAT7_to_PDFS(filename, frame_num, + /*gate*/ 1, + /* data_num, bed_num, */ 0, 0)); + } if (is_null_ptr(dynamic_proj_data_ptr->_proj_datas[0])) - error("DynamicProjData: No frame available\n"); + error("DynamicProjData: No frame available\n"); return dynamic_proj_data_ptr; + } else { + if (is_ECAT7_file(filename)) { + warning("DynamicProjData::read_from_file ECAT7 file '%s' should be projection data.", filename.c_str()); + return unique_ptr(); + } } - else - { - if (is_ECAT7_file(filename)) - { - warning("DynamicProjData::read_from_file ECAT7 file '%s' should be projection data.", filename.c_str()); - return unique_ptr(); - } - } + } else { + warning( + "DynamicProjData::read_from_file '%s' seems to correspond to ECAT projection data, but not ECAT7. I cannot read this.", + filename.c_str()); + return unique_ptr(); } - else - { - warning("DynamicProjData::read_from_file '%s' seems to correspond to ECAT projection data, but not ECAT7. I cannot read this.", filename.c_str()); - return unique_ptr(); - } #endif // end of HAVE_LLN_MATRIX if (strncmp(signature, "Multi", 5) == 0) { #ifndef NDEBUG - info(boost::format("DynamicProjData::read_from_file trying to read %s as a Multi file.") % filename); + info(boost::format("DynamicProjData::read_from_file trying to read %s as a Multi file.") % filename); #endif - unique_ptr multi_proj_data(MultipleProjData::read_from_file(filename)); - unique_ptr dynamic_proj_data(new DynamicProjData(*multi_proj_data)); + unique_ptr multi_proj_data(MultipleProjData::read_from_file(filename)); + unique_ptr dynamic_proj_data(new DynamicProjData(*multi_proj_data)); - return dynamic_proj_data; + return dynamic_proj_data; } - + // return a zero pointer if we get here warning(boost::format("DynamicProjData::read_from_file cannot read '%s'. Unsupported file format?") % filename); return unique_ptr(); } -Succeeded -DynamicProjData:: -write_to_ecat7(const string& filename) const -{ +Succeeded +DynamicProjData::write_to_ecat7(const string& filename) const { #ifndef HAVE_LLN_MATRIX return Succeeded::no; #else Main_header mhead; - ecat::ecat7::make_ECAT7_main_header(mhead, filename, - get_exam_info(), - *get_proj_data(1).get_proj_data_info_sptr() ); - - MatrixFile* mptr= matrix_create (filename.c_str(), MAT_CREATE, &mhead); - if (mptr == 0) - { - warning("DynamicProjData::write_to_ecat7 cannot write output file %s\n", filename.c_str()); + ecat::ecat7::make_ECAT7_main_header(mhead, filename, get_exam_info(), *get_proj_data(1).get_proj_data_info_sptr()); + + MatrixFile* mptr = matrix_create(filename.c_str(), MAT_CREATE, &mhead); + if (mptr == 0) { + warning("DynamicProjData::write_to_ecat7 cannot write output file %s\n", filename.c_str()); + return Succeeded::no; + } + for (unsigned int frame_num = 1; frame_num <= this->get_num_frames(); ++frame_num) { + if (ecat::ecat7::ProjData_to_ECAT7(mptr, get_proj_data(frame_num), frame_num) == Succeeded::no) { + matrix_close(mptr); return Succeeded::no; } - for ( unsigned int frame_num = 1 ; frame_num<=this->get_num_frames() ; ++frame_num ) - { - if (ecat::ecat7::ProjData_to_ECAT7(mptr, - get_proj_data(frame_num), - frame_num) - == Succeeded::no) - { - matrix_close(mptr); - return Succeeded::no; - } - } + } matrix_close(mptr); return Succeeded::yes; #endif // end of HAVE_LLN_MATRIX @@ -218,132 +190,100 @@ write_to_ecat7(const string& filename) const // local helper function to read the data from Interfile // It is largely a copy of read_interfile_PDFS (for a single time frame) // This needs to be merged of course. -static -DynamicProjData* -read_interfile_DPDFS(istream& input, - const string& directory_for_data, - const std::ios::openmode open_mode) -{ - - InterfilePDFSHeader hdr; +static DynamicProjData* +read_interfile_DPDFS(istream& input, const string& directory_for_data, const std::ios::openmode open_mode) { - if (!hdr.parse(input)) - { - return 0; // KT 10122001 do not call ask_parameters anymore - } + InterfilePDFSHeader hdr; + + if (!hdr.parse(input)) { + return 0; // KT 10122001 do not call ask_parameters anymore + } // KT 14/01/2000 added directory capability // prepend directory_for_data to the data_file_name from the header char full_data_file_name[max_filename_length]; strcpy(full_data_file_name, hdr.data_file_name.c_str()); - prepend_directory_name(full_data_file_name, directory_for_data.c_str()); - - for (unsigned int i=1; i data_in(new std::fstream(full_data_file_name, open_mode | std::ios::binary)); + if (!data_in->good()) { + warning("interfile parsing: error opening file %s", full_data_file_name); + return 0; + } + shared_ptr proj_data_info_sptr(hdr.data_info_sptr->create_shared_clone()); + unsigned long data_offset = hdr.data_offset_each_dataset[0]; + // offset in file between time frames + unsigned long data_offset_increment = 0UL; // we will find it below + DynamicProjData* dynamic_proj_data_ptr = new DynamicProjData(hdr.get_exam_info_sptr()); + if (is_null_ptr(dynamic_proj_data_ptr)) { + error(boost::format("DynamicProjData: error allocating memory for new object (for file \"%1%\")") % full_data_file_name); + } + dynamic_proj_data_ptr->resize(hdr.get_exam_info().time_frame_definitions.get_num_time_frames()); + + // now set all proj_data_sptrs + for (unsigned int frame_num = 1; frame_num <= dynamic_proj_data_ptr->get_num_frames(); ++frame_num) { + info(boost::format("Using data offset %1% for frame %2% in file %3%\n") % data_offset % frame_num % full_data_file_name); + shared_ptr current_exam_info_sptr(new ExamInfo(*hdr.get_exam_info_sptr())); + std::vector> frame_times; + frame_times.push_back(std::make_pair(hdr.get_exam_info().time_frame_definitions.get_start_time(frame_num), + hdr.get_exam_info().time_frame_definitions.get_end_time(frame_num))); + TimeFrameDefinitions time_frame_defs(frame_times); + current_exam_info_sptr->set_time_frame_definitions(time_frame_defs); + + shared_ptr proj_data_sptr(new ProjDataFromStream( + current_exam_info_sptr, proj_data_info_sptr, data_in, data_offset, hdr.segment_sequence, hdr.storage_order, + hdr.type_of_numbers, hdr.file_byte_order, static_cast(hdr.image_scaling_factors[0][0]))); + if (is_null_ptr(proj_data_sptr)) { + error(boost::format("DynamicProjData: error reading frame %1% from file '%2%'") % frame_num % full_data_file_name); + } + + dynamic_proj_data_ptr->set_proj_data_sptr(proj_data_sptr, frame_num); + + // TODO, move offset code to InterfileHeader.cxx + // find data offset increment + if (frame_num == 1) { + int num_sinos = 0; + for (int s = proj_data_info_sptr->get_min_segment_num(); s <= proj_data_info_sptr->get_max_segment_num(); ++s) { + num_sinos += proj_data_info_sptr->get_num_axial_poss(s); } - - assert(!is_null_ptr(hdr.data_info_sptr)); - - shared_ptr data_in(new std::fstream (full_data_file_name, open_mode | std::ios::binary)); - if (!data_in->good()) - { - warning("interfile parsing: error opening file %s",full_data_file_name); - return 0; - } - shared_ptr proj_data_info_sptr(hdr.data_info_sptr->create_shared_clone()); - unsigned long data_offset = hdr.data_offset_each_dataset[0]; - // offset in file between time frames - unsigned long data_offset_increment = 0UL; // we will find it below - DynamicProjData * dynamic_proj_data_ptr = new DynamicProjData(hdr.get_exam_info_sptr()); - if (is_null_ptr(dynamic_proj_data_ptr)) - { - error(boost::format("DynamicProjData: error allocating memory for new object (for file \"%1%\")") - % full_data_file_name); - } - dynamic_proj_data_ptr->resize(hdr.get_exam_info().time_frame_definitions.get_num_time_frames()); - - // now set all proj_data_sptrs - for (unsigned int frame_num=1; frame_num <= dynamic_proj_data_ptr->get_num_frames(); ++frame_num) - { - info(boost::format("Using data offset %1% for frame %2% in file %3%\n") % data_offset % frame_num % full_data_file_name); - shared_ptr current_exam_info_sptr(new ExamInfo(*hdr.get_exam_info_sptr())); - std::vector > frame_times; - frame_times.push_back(std::make_pair(hdr.get_exam_info().time_frame_definitions.get_start_time(frame_num), - hdr.get_exam_info().time_frame_definitions.get_end_time(frame_num))); - TimeFrameDefinitions time_frame_defs(frame_times); - current_exam_info_sptr->set_time_frame_definitions(time_frame_defs); - - shared_ptr - proj_data_sptr(new ProjDataFromStream(current_exam_info_sptr, - proj_data_info_sptr, - data_in, - data_offset, - hdr.segment_sequence, - hdr.storage_order, - hdr.type_of_numbers, - hdr.file_byte_order, - static_cast(hdr.image_scaling_factors[0][0]))); - if (is_null_ptr(proj_data_sptr)) - { - error(boost::format("DynamicProjData: error reading frame %1% from file '%2%'") - % frame_num % full_data_file_name); - } - - dynamic_proj_data_ptr->set_proj_data_sptr(proj_data_sptr, frame_num); - - // TODO, move offset code to InterfileHeader.cxx - // find data offset increment - if (frame_num==1) - { - int num_sinos = 0; - for (int s=proj_data_info_sptr->get_min_segment_num(); - s<=proj_data_info_sptr->get_max_segment_num(); - ++s) - { - num_sinos += proj_data_info_sptr->get_num_axial_poss(s); - } - data_offset_increment = - static_cast(num_sinos * - proj_data_info_sptr->get_num_tangential_poss() * proj_data_info_sptr->get_num_views() * - hdr.type_of_numbers.size_in_bytes()); - } - - // find offset of next frame - if (frame_num < dynamic_proj_data_ptr->get_num_frames()) - { - // note that hdr.data_offset uses zero-based indexing, so next line finds the offset for frame frame_num+1 - if (hdr.data_offset_each_dataset[frame_num]>0) - { - if (fabs(static_cast(data_offset) - hdr.data_offset_each_dataset[frame_num]) < data_offset_increment) - { - error(boost::format("data offset for frame %1% is too small. Difference in offsets needs to be at least %2%") - % (frame_num+1) % data_offset_increment); - } - data_offset = hdr.data_offset_each_dataset[frame_num]; - } - else - data_offset += data_offset_increment; - } - } // end loop over frames - - return dynamic_proj_data_ptr; + data_offset_increment = + static_cast(num_sinos * proj_data_info_sptr->get_num_tangential_poss() * + proj_data_info_sptr->get_num_views() * hdr.type_of_numbers.size_in_bytes()); + } + + // find offset of next frame + if (frame_num < dynamic_proj_data_ptr->get_num_frames()) { + // note that hdr.data_offset uses zero-based indexing, so next line finds the offset for frame frame_num+1 + if (hdr.data_offset_each_dataset[frame_num] > 0) { + if (fabs(static_cast(data_offset) - hdr.data_offset_each_dataset[frame_num]) < data_offset_increment) { + error(boost::format("data offset for frame %1% is too small. Difference in offsets needs to be at least %2%") % + (frame_num + 1) % data_offset_increment); + } + data_offset = hdr.data_offset_each_dataset[frame_num]; + } else + data_offset += data_offset_increment; + } + } // end loop over frames + + return dynamic_proj_data_ptr; } -static -DynamicProjData* -read_interfile_DPDFS(const string& filename, - const std::ios::openmode open_mode) -{ +static DynamicProjData* +read_interfile_DPDFS(const string& filename, const std::ios::openmode open_mode) { std::ifstream image_stream(filename.c_str(), open_mode); - if (!image_stream) - { - error(boost::format("DynamicProjData: couldn't open file '%s'") % filename); - } - + if (!image_stream) { + error(boost::format("DynamicProjData: couldn't open file '%s'") % filename); + } + return read_interfile_DPDFS(image_stream, get_directory_name(filename), open_mode); } diff --git a/src/buildblock/ExamData.cxx b/src/buildblock/ExamData.cxx index fb1389eb1b..628446cfe6 100644 --- a/src/buildblock/ExamData.cxx +++ b/src/buildblock/ExamData.cxx @@ -23,45 +23,32 @@ */ #include "stir/ExamData.h" - #include START_NAMESPACE_STIR -ExamData:: -ExamData(): - exam_info_sptr(new ExamInfo()) -{} - - -ExamData::ExamData(const shared_ptr &_this_exam) : - exam_info_sptr(_this_exam) -{} +ExamData::ExamData() : exam_info_sptr(new ExamInfo()) {} +ExamData::ExamData(const shared_ptr& _this_exam) : exam_info_sptr(_this_exam) {} -ExamData::~ExamData() -{} +ExamData::~ExamData() {} void -ExamData::set_exam_info(ExamInfo const& new_exam_info) -{ +ExamData::set_exam_info(ExamInfo const& new_exam_info) { this->exam_info_sptr.reset(new ExamInfo(new_exam_info)); } void -ExamData::set_exam_info_sptr(shared_ptr new_exam_info_sptr) -{ - this->exam_info_sptr=new_exam_info_sptr; +ExamData::set_exam_info_sptr(shared_ptr new_exam_info_sptr) { + this->exam_info_sptr = new_exam_info_sptr; } const ExamInfo& -ExamData::get_exam_info() const -{ +ExamData::get_exam_info() const { return *exam_info_sptr.get(); } shared_ptr -ExamData::get_exam_info_sptr() const -{ +ExamData::get_exam_info_sptr() const { return exam_info_sptr; } diff --git a/src/buildblock/ExamInfo.cxx b/src/buildblock/ExamInfo.cxx index 82db666a9f..a2853d2caa 100644 --- a/src/buildblock/ExamInfo.cxx +++ b/src/buildblock/ExamInfo.cxx @@ -25,16 +25,15 @@ #include "stir/date_time_functions.h" #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif START_NAMESPACE_STIR std::string -ExamInfo::parameter_info() const -{ +ExamInfo::parameter_info() const { #ifdef BOOST_NO_STRINGSTREAM // dangerous for out-of-range, but 'old-style' ostrstream seems to need this char str[30000]; @@ -47,29 +46,19 @@ ExamInfo::parameter_info() const s << "Radionuclide: " << this->radionuclide << '\n'; s << "Patient position: " << this->patient_position.get_position_as_string() << '\n'; s << "Scan start time: " << this->start_time_in_secs_since_1970 << '\n'; - if (this->start_time_in_secs_since_1970>0) - { - DateTimeStrings time = secs_since_Unix_epoch_to_Interfile_datetime(this->start_time_in_secs_since_1970); - s << " which is " << time.date << " " << time.time << '\n'; - } - if (this->time_frame_definitions.get_num_time_frames() == 1) - { - s << "Time frame start - end (duration), all in secs: " - << this->time_frame_definitions.get_start_time(1) - << " - " - << this->time_frame_definitions.get_end_time(1) - << " (" - << this->time_frame_definitions.get_duration(1) - << ")\n"; - } + if (this->start_time_in_secs_since_1970 > 0) { + DateTimeStrings time = secs_since_Unix_epoch_to_Interfile_datetime(this->start_time_in_secs_since_1970); + s << " which is " << time.date << " " << time.time << '\n'; + } + if (this->time_frame_definitions.get_num_time_frames() == 1) { + s << "Time frame start - end (duration), all in secs: " << this->time_frame_definitions.get_start_time(1) << " - " + << this->time_frame_definitions.get_end_time(1) << " (" << this->time_frame_definitions.get_duration(1) << ")\n"; + } s << "number of energy windows:=1\n" - << "energy window lower level[1] := " - << this->get_low_energy_thres() << '\n' - << "energy window upper level[1] := " - << this->get_high_energy_thres() << '\n'; - + << "energy window lower level[1] := " << this->get_low_energy_thres() << '\n' + << "energy window upper level[1] := " << this->get_high_energy_thres() << '\n'; + return s.str(); } - END_NAMESPACE_STIR diff --git a/src/buildblock/FilePath.cxx b/src/buildblock/FilePath.cxx index a6cc07d577..4737b609d4 100644 --- a/src/buildblock/FilePath.cxx +++ b/src/buildblock/FilePath.cxx @@ -43,359 +43,321 @@ #include #if defined(__OS_WIN__) - #include - #include // required for stat.h - #include +# include +# include // required for stat.h +# include #else - #include +# include #endif #include START_NAMESPACE_STIR -FilePath::FilePath(){ - initSeparator(); -} +FilePath::FilePath() { initSeparator(); } -FilePath::FilePath(const std::string &__str, bool _run_checks) -{ - if(__str.size() == 0) - error(boost::format("FilePath: Cannot initialise empty path.")); +FilePath::FilePath(const std::string& __str, bool _run_checks) { + if (__str.size() == 0) + error(boost::format("FilePath: Cannot initialise empty path.")); - my_string = __str; + my_string = __str; - initSeparator(); + initSeparator(); - run_checks = _run_checks; + run_checks = _run_checks; - // Checks - checks(); + // Checks + checks(); } -bool FilePath::is_directory() const -{ +bool +FilePath::is_directory() const { #if defined(__OS_WIN__) - DWORD dwAttrib = GetFileAttributes(my_string.c_str()); + DWORD dwAttrib = GetFileAttributes(my_string.c_str()); - return (dwAttrib != INVALID_FILE_ATTRIBUTES && - dwAttrib & FILE_ATTRIBUTE_DIRECTORY); + return (dwAttrib != INVALID_FILE_ATTRIBUTES && dwAttrib & FILE_ATTRIBUTE_DIRECTORY); #else - struct stat info; + struct stat info; - if( stat( my_string.c_str(), &info ) != 0 ) - error(boost::format("FilePath: Cannot access %1%.")%my_string); - else if( info.st_mode & S_IFDIR ) - return true; + if (stat(my_string.c_str(), &info) != 0) + error(boost::format("FilePath: Cannot access %1%.") % my_string); + else if (info.st_mode & S_IFDIR) + return true; #endif - return false; + return false; } - -bool FilePath::is_regular_file() const -{ +bool +FilePath::is_regular_file() const { #if defined(__OS_WIN__) - DWORD dwAttrib = GetFileAttributes(my_string.c_str()); + DWORD dwAttrib = GetFileAttributes(my_string.c_str()); - return (dwAttrib != INVALID_FILE_ATTRIBUTES && - (dwAttrib & FILE_ATTRIBUTE_NORMAL)); + return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_NORMAL)); #else - struct stat info; + struct stat info; - if( stat( my_string.c_str(), &info ) != 0 ) - error(boost::format("FilePath: Cannot access %1%.")%my_string); - else if( info.st_mode & S_IFREG ) - return true; + if (stat(my_string.c_str(), &info) != 0) + error(boost::format("FilePath: Cannot access %1%.") % my_string); + else if (info.st_mode & S_IFREG) + return true; #endif - return false; + return false; } -bool FilePath::is_writable() const -{ +bool +FilePath::is_writable() const { #if defined(__OS_WIN__) - DWORD dwAttrib = GetFileAttributes(my_string.c_str()); + DWORD dwAttrib = GetFileAttributes(my_string.c_str()); - return (dwAttrib != INVALID_FILE_ATTRIBUTES); -#else - if( access(my_string.c_str(), 0) == 0 ) - return true; - else - return false; + return (dwAttrib != INVALID_FILE_ATTRIBUTES); +#else + if (access(my_string.c_str(), 0) == 0) + return true; + else + return false; #endif } -bool FilePath::exists(const std::string& s) -{ +bool +FilePath::exists(const std::string& s) { #if defined(__OS_WIN__) - DWORD dwAttrib = GetFileAttributes(s.c_str()); + DWORD dwAttrib = GetFileAttributes(s.c_str()); - return (dwAttrib != INVALID_FILE_ATTRIBUTES); + return (dwAttrib != INVALID_FILE_ATTRIBUTES); #else - struct stat info; - - if (s.size()>0) - { - if (stat(s.c_str(), &info) != 0) - return false; - else - return true; - } - return false; + struct stat info; + + if (s.size() > 0) { + if (stat(s.c_str(), &info) != 0) + return false; + else + return true; + } + return false; #endif } -FilePath FilePath::append(const FilePath &p) -{ - return append(p.get_path()); +FilePath +FilePath::append(const FilePath& p) { + return append(p.get_path()); } -FilePath FilePath::append(const std::string &p) -{ - // Check permissions - if (!is_writable()) - error(boost::format("FilePath: %1% is not writable.")%my_string); - - std::string new_path = my_string; - - //Check if this a directory or it contains a filename, too - if(!is_directory()) - { - if(!is_regular_file()) - { - error(boost::format("FilePath: Cannot find a directory in %1%.")%my_string); - } - else - { - new_path = get_path(); - } +FilePath +FilePath::append(const std::string& p) { + // Check permissions + if (!is_writable()) + error(boost::format("FilePath: %1% is not writable.") % my_string); + + std::string new_path = my_string; + + // Check if this a directory or it contains a filename, too + if (!is_directory()) { + if (!is_regular_file()) { + error(boost::format("FilePath: Cannot find a directory in %1%.") % my_string); + } else { + new_path = get_path(); } + } + + // Try to accomondate multiple sub paths + // Find if string p has more than one levels and store them in a vector. + std::vector v = split(p, separator.c_str()); + + // Run over the vector creating the subfolders recrusively. + for (unsigned int i = 0; i < v.size(); i++) { + new_path = merge(new_path, v.at(i)); + FilePath::append_separator(new_path); - // Try to accomondate multiple sub paths - // Find if string p has more than one levels and store them in a vector. - std::vector v = split(p, separator.c_str()); - - // Run over the vector creating the subfolders recrusively. - for (unsigned int i = 0; i < v.size(); i++) - { - new_path = merge(new_path, v.at(i)); - FilePath::append_separator(new_path); - - // if current level already exists move to the next. - if (FilePath::exists(new_path) == true) - { - warning(boost::format("FilePath: Path %1% already exists.")%new_path); - continue; - } - int nError; + // if current level already exists move to the next. + if (FilePath::exists(new_path) == true) { + warning(boost::format("FilePath: Path %1% already exists.") % new_path); + continue; + } + int nError; #if defined(__OS_WIN__) - nError = _mkdir(new_path.c_str()); + nError = _mkdir(new_path.c_str()); #else - nError = mkdir(new_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + nError = mkdir(new_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); #endif - if (-1 == nError) - { - error("FilePath: Error creating directory!"); - } + if (-1 == nError) { + error("FilePath: Error creating directory!"); } - return FilePath(new_path); + } + return FilePath(new_path); } void -FilePath::add_extension(const std::string &e) -{ - std::string::size_type pos = find_pos_of_extension(); - if (pos == std::string::npos) - my_string += e; +FilePath::add_extension(const std::string& e) { + std::string::size_type pos = find_pos_of_extension(); + if (pos == std::string::npos) + my_string += e; } void -FilePath::replace_extension(const std::string& e) -{ - std::string::size_type pos = find_pos_of_extension(); - if (pos != std::string::npos) - { - my_string.erase(pos); - my_string += e; - } +FilePath::replace_extension(const std::string& e) { + std::string::size_type pos = find_pos_of_extension(); + if (pos != std::string::npos) { + my_string.erase(pos); + my_string += e; + } } - std::string -FilePath::get_path() const -{ - std::size_t i = my_string.rfind(separator, my_string.length()); - if (i != std::string::npos) - { - return(my_string.substr(0, i+1)); - } +FilePath::get_path() const { + std::size_t i = my_string.rfind(separator, my_string.length()); + if (i != std::string::npos) { + return (my_string.substr(0, i + 1)); + } - return(my_string); + return (my_string); } std::string -FilePath::get_path_only() const -{ - std::size_t i = my_string.rfind(separator, my_string.length()); - if (i != std::string::npos) - { - return(my_string.substr(0, i+1)); - } - - std::string empty; - return empty; +FilePath::get_path_only() const { + std::size_t i = my_string.rfind(separator, my_string.length()); + if (i != std::string::npos) { + return (my_string.substr(0, i + 1)); + } + + std::string empty; + return empty; } - std::string -FilePath::get_filename() const -{ - std::size_t i = 0; +FilePath::get_filename() const { + std::size_t i = 0; #if defined(__OS_WIN__) - i = my_string.rfind(separator, my_string.length()); - if (i == std::string::npos) - i = my_string.rfind('/', my_string.length()); - if (i == std::string::npos) - i = my_string.rfind(':', my_string.length()); + i = my_string.rfind(separator, my_string.length()); + if (i == std::string::npos) + i = my_string.rfind('/', my_string.length()); + if (i == std::string::npos) + i = my_string.rfind(':', my_string.length()); #else - i = my_string.rfind(separator, my_string.length()); + i = my_string.rfind(separator, my_string.length()); #endif - if (i != std::string::npos) - { - return(my_string.substr(i+1, my_string.length() - i)); - } - return(my_string); + if (i != std::string::npos) { + return (my_string.substr(i + 1, my_string.length() - i)); + } + return (my_string); } std::string -FilePath::get_filename_no_extension() const -{ - std::string ret = get_filename(); - - std::size_t i = find_pos_of_extension(); - if (i != std::string::npos) - { - return(ret.substr(0, i)); - } - return(""); - +FilePath::get_filename_no_extension() const { + std::string ret = get_filename(); + + std::size_t i = find_pos_of_extension(); + if (i != std::string::npos) { + return (ret.substr(0, i)); + } + return (""); } std::string -FilePath::get_extension() const -{ - std::size_t i = find_pos_of_extension(); - if (i != std::string::npos) - { - return(my_string.substr(i+1, my_string.length() - i)); - } - return(""); +FilePath::get_extension() const { + std::size_t i = find_pos_of_extension(); + if (i != std::string::npos) { + return (my_string.substr(i + 1, my_string.length() - i)); + } + return (""); } std::string -FilePath::get_as_string() const -{ - return my_string; +FilePath::get_as_string() const { + return my_string; } -void FilePath::checks() const -{ - if (!run_checks) - return; +void +FilePath::checks() const { + if (!run_checks) + return; #if defined(__OS_WIN__) - DWORD dwAttrib = GetFileAttributes(my_string.c_str()); + DWORD dwAttrib = GetFileAttributes(my_string.c_str()); - if (dwAttrib != INVALID_FILE_ATTRIBUTES && - !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) - { - error(boost::format("FilePath: File %1% is neither a directory nor a file")%my_string); - } + if (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { + error(boost::format("FilePath: File %1% is neither a directory nor a file") % my_string); + } #else - struct stat s; - if( stat(my_string.c_str(),&s) == 0 ) - { - if ((s.st_mode & S_IFDIR ) && - ( s.st_mode & S_IFREG ) ) - { - error(boost::format("FilePath: File %1% is neither a directory nor a file")%my_string); - } - } - else - { - error(boost::format("FilePath: Maybe %1% does not exist?")%my_string); + struct stat s; + if (stat(my_string.c_str(), &s) == 0) { + if ((s.st_mode & S_IFDIR) && (s.st_mode & S_IFREG)) { + error(boost::format("FilePath: File %1% is neither a directory nor a file") % my_string); } + } else { + error(boost::format("FilePath: Maybe %1% does not exist?") % my_string); + } #endif } -//On Windows there's GetCurrentDirectory -std::string FilePath::get_current_working_directory() -{ - char buffer[max_filename_length]; - char *ptr = getcwd(buffer, sizeof(buffer)); - std::string s_cwd; - if (ptr) - s_cwd = ptr; - - return s_cwd; +// On Windows there's GetCurrentDirectory +std::string +FilePath::get_current_working_directory() { + char buffer[max_filename_length]; + char* ptr = getcwd(buffer, sizeof(buffer)); + std::string s_cwd; + if (ptr) + s_cwd = ptr; + + return s_cwd; } -const std::vector FilePath::split(const std::string& s, const char* c) -{ - std::string buff = ""; - std::vector v; +const std::vector +FilePath::split(const std::string& s, const char* c) { + std::string buff = ""; + std::vector v; - if (strlen(c) == 0) - c = separator.c_str(); + if (strlen(c) == 0) + c = separator.c_str(); - for(unsigned int i = 0; i < s.size(); i++) - { - char n = s.at(i); + for (unsigned int i = 0; i < s.size(); i++) { + char n = s.at(i); - if(n != *c) buff+=n; else - if(n == *c && buff != "") { v.push_back(buff); buff = ""; } + if (n != *c) + buff += n; + else if (n == *c && buff != "") { + v.push_back(buff); + buff = ""; } - if(buff != "") v.push_back(buff); + } + if (buff != "") + v.push_back(buff); - return v; + return v; } std::string::size_type -FilePath::find_pos_of_filename() const -{ - std::string::size_type pos; +FilePath::find_pos_of_filename() const { + std::string::size_type pos; #if defined(__OS_VAX__) - pos = my_string.find_last_of( ']'); - if (pos==std::string::npos) - pos = my_string.find_last_of(separator); + pos = my_string.find_last_of(']'); + if (pos == std::string::npos) + pos = my_string.find_last_of(separator); #elif defined(__OS_WIN__) - pos = my_string.find_last_of( '\\'); - if (pos==std::string::npos) - pos = my_string.find_last_of( '/'); - if (pos==std::string::npos) - pos = my_string.find_last_of( ':'); + pos = my_string.find_last_of('\\'); + if (pos == std::string::npos) + pos = my_string.find_last_of('/'); + if (pos == std::string::npos) + pos = my_string.find_last_of(':'); #else - pos = my_string.find_last_of(separator); + pos = my_string.find_last_of(separator); #endif - if (pos != std::string::npos) - return pos+1; - else - return 0; + if (pos != std::string::npos) + return pos + 1; + else + return 0; } std::string::size_type -FilePath::find_pos_of_extension() const -{ - std::string::size_type pos_of_dot = - my_string.find_last_of('.'); - std::string::size_type pos_of_filename = - find_pos_of_filename(); +FilePath::find_pos_of_extension() const { + std::string::size_type pos_of_dot = my_string.find_last_of('.'); + std::string::size_type pos_of_filename = find_pos_of_filename(); if (pos_of_dot >= pos_of_filename) return pos_of_dot; @@ -403,133 +365,119 @@ FilePath::find_pos_of_extension() const return std::string::npos; } -void FilePath::append_separator(std::string& s) -{ +void +FilePath::append_separator(std::string& s) { #if defined(__OS_VAX__) - s += ":"; + s += ":"; #elif defined(__OS_WIN__) - s += "\\"; + s += "\\"; #elif defined(__OS_MAC__) - s += ":" ; + s += ":"; #else // defined(__OS_UNIX__) - s += "/" ; + s += "/"; #endif } bool -FilePath::is_absolute(const std::string& _filename_with_directory) -{ - const char* filename_with_directory = _filename_with_directory.c_str(); +FilePath::is_absolute(const std::string& _filename_with_directory) { + const char* filename_with_directory = _filename_with_directory.c_str(); #if defined(__OS_VAX__) - // relative names either contain no '[', or have '[.' - const char * const ptr = strchr(filename_with_directory,'['); - if (ptr==NULL) - return false; - else - return *(ptr+1) != '.'; + // relative names either contain no '[', or have '[.' + const char* const ptr = strchr(filename_with_directory, '['); + if (ptr == NULL) + return false; + else + return *(ptr + 1) != '.'; #elif defined(__OS_WIN__) - // relative names do not start with '\' or '?:\' - if (filename_with_directory[0] == '\\' || - filename_with_directory[0] == '/') - return true; - else - return (strlen(filename_with_directory)>3 && - filename_with_directory[1] == ':' && - (filename_with_directory[2] == '\\' || - filename_with_directory[2] == '/') - ); + // relative names do not start with '\' or '?:\' + if (filename_with_directory[0] == '\\' || filename_with_directory[0] == '/') + return true; + else + return (strlen(filename_with_directory) > 3 && filename_with_directory[1] == ':' && + (filename_with_directory[2] == '\\' || filename_with_directory[2] == '/')); #elif defined(__OS_MAC__) - // relative names either have no ':' or do not start with ':' - const char * const ptr = strchr(filename_with_directory,':'); - if (ptr == NULL) - return false; - else - return ptr != filename_with_directory; + // relative names either have no ':' or do not start with ':' + const char* const ptr = strchr(filename_with_directory, ':'); + if (ptr == NULL) + return false; + else + return ptr != filename_with_directory; #else // defined(__OS_UNIX__) - // absolute names start with '/' - return filename_with_directory[0] == '/'; + // absolute names start with '/' + return filename_with_directory[0] == '/'; #endif } -void FilePath::prepend_directory_name(const std::string &p) -{ +void +FilePath::prepend_directory_name(const std::string& p) { - if (FilePath::is_absolute(my_string) || - p.size() == 0) - return; + if (FilePath::is_absolute(my_string) || p.size() == 0) + return; - std::string new_name; + std::string new_name; #if defined(__OS_VAX__) - // relative names either contain no '[', or have '[.' - if (my_string[0] != '[' || - p[p.length()-1] != ']') - else - { - // peel of the ][ pair - p.erase[p.length()-1]; + // relative names either contain no '[', or have '[.' + if (my_string[0] != '[' || p[p.length() - 1] != ']') + else { + // peel of the ][ pair + p.erase[p.length() - 1]; } - new_name = p + separator + my_string; + new_name = p + separator + my_string; #elif defined(__OS_WIN__) - new_name = merge(p, my_string); + new_name = merge(p, my_string); #elif defined(__OS_MAC__) - // relative names either have no ':' or do not start with ':' - // append : if necessary - if (p[p.length()-1] != ':') - p.push_back(":"); - // do not copy starting ':' of filename - if (my_string[0] == ':') - my_string.erase(0); - new_name = p + separator + my_string; + // relative names either have no ':' or do not start with ':' + // append : if necessary + if (p[p.length() - 1] != ':') + p.push_back(":"); + // do not copy starting ':' of filename + if (my_string[0] == ':') + my_string.erase(0); + new_name = p + separator + my_string; #else // defined(__OS_UNIX__) - // append / if necessary - new_name = merge(p, my_string); + // append / if necessary + new_name = merge(p, my_string); #endif - my_string = new_name; + my_string = new_name; } -std::string FilePath::merge(const std::string &first, const std::string &sec) -{ - std::string sep = separator; +std::string +FilePath::merge(const std::string& first, const std::string& sec) { + std::string sep = separator; #if defined(__OS_WIN__) - //Check for the appropriate separator. - // Again, in utilies when windows all separators are checked. - if (first[first.length() - 1] != *sep.c_str()) - { - if (first[first.length() - 1] == '/') - sep = '/'; - if (first[first.length() - 1] == ':') - sep = ':'; - } - - if (sec[0] != *sep.c_str()) - { - if (sec[0] == '/') - sep = '/'; - if (sec[0] == ':') - sep = ':'; - } + // Check for the appropriate separator. + // Again, in utilies when windows all separators are checked. + if (first[first.length() - 1] != *sep.c_str()) { + if (first[first.length() - 1] == '/') + sep = '/'; + if (first[first.length() - 1] == ':') + sep = ':'; + } + + if (sec[0] != *sep.c_str()) { + if (sec[0] == '/') + sep = '/'; + if (sec[0] == ':') + sep = ':'; + } #endif - // Just append a separator - if (sec.size() == 0) - return first + sep; + // Just append a separator + if (sec.size() == 0) + return first + sep; - if (first[first.length()-1] == *sep.c_str() && sec[0] == *sep.c_str()) - { - return first.substr(0, first.length()-1) + sec; - } - else if ((first[first.length()-1] == *sep.c_str() && sec[0] != *sep.c_str()) || - (first[first.length()-1] != *sep.c_str() && sec[0] == *sep.c_str())) - { - return first + sec; - } - else /*( (first.back() != separator + if (first[first.length() - 1] == *sep.c_str() && sec[0] == *sep.c_str()) { + return first.substr(0, first.length() - 1) + sec; + } else if ((first[first.length() - 1] == *sep.c_str() && sec[0] != *sep.c_str()) || + (first[first.length() - 1] != *sep.c_str() && sec[0] == *sep.c_str())) { + return first + sec; + } else /*( (first.back() != separator && sec.front() != separator))*/ - { - return first + sep + sec; - } + { + return first + sep + sec; + } } END_NAMESPACE_STIR diff --git a/src/buildblock/GatedDiscretisedDensity.cxx b/src/buildblock/GatedDiscretisedDensity.cxx index 87f1aad230..0541a34afd 100644 --- a/src/buildblock/GatedDiscretisedDensity.cxx +++ b/src/buildblock/GatedDiscretisedDensity.cxx @@ -3,26 +3,26 @@ Copyright (C) 2005- 2009, Hammersmith Imanet Ltd Copyright (C) 2009- 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup buildblock \brief Implementation of class stir::GatedDiscretisedDensity \author Charalampos Tsoumpas \author Kris Thielemans - + */ #include "stir/GatedDiscretisedDensity.h" @@ -43,164 +43,143 @@ using std::string; START_NAMESPACE_STIR -GatedDiscretisedDensity:: -GatedDiscretisedDensity(const GatedDiscretisedDensity& argument) -{ - (*this) = argument; -} +GatedDiscretisedDensity::GatedDiscretisedDensity(const GatedDiscretisedDensity& argument) { (*this) = argument; } GatedDiscretisedDensity& -GatedDiscretisedDensity:: -operator=(const GatedDiscretisedDensity& argument) -{ +GatedDiscretisedDensity::operator=(const GatedDiscretisedDensity& argument) { this->_time_gate_definitions = argument._time_gate_definitions; this->_densities.resize(argument._densities.size()); - for (unsigned int i=0; i_densities[i].reset(argument._densities[i]->clone()); return *this; } -GatedDiscretisedDensity:: -GatedDiscretisedDensity(const string& filename) -{ - const string gdef_filename=filename+".gdef"; +GatedDiscretisedDensity::GatedDiscretisedDensity(const string& filename) { + const string gdef_filename = filename + ".gdef"; std::cout << "GatedDiscretisedDensity: Reading gate definitions " << gdef_filename.c_str() << std::endl; this->_time_gate_definitions.read_gdef_file(gdef_filename); this->_densities.resize(this->_time_gate_definitions.get_num_gates()); - for ( unsigned int num = 1 ; num<=(this->_time_gate_definitions).get_num_gates() ; ++num ) - { - std::stringstream gate_num_stream; - gate_num_stream << this->_time_gate_definitions.get_gate_num(num); - const string input_filename=filename+"_g"+gate_num_stream.str()+".hv"; - // const shared_ptr > read_sptr = new VoxelsOnCartesianGrid ; - std::cout << "GatedDiscretisedDensity: Reading gate file: " << input_filename.c_str() << std::endl; - this->_densities[num-1].reset(DiscretisedDensity<3,float>::read_from_file(input_filename)); - } + for (unsigned int num = 1; num <= (this->_time_gate_definitions).get_num_gates(); ++num) { + std::stringstream gate_num_stream; + gate_num_stream << this->_time_gate_definitions.get_gate_num(num); + const string input_filename = filename + "_g" + gate_num_stream.str() + ".hv"; + // const shared_ptr > read_sptr = new VoxelsOnCartesianGrid ; + std::cout << "GatedDiscretisedDensity: Reading gate file: " << input_filename.c_str() << std::endl; + this->_densities[num - 1].reset(DiscretisedDensity<3, float>::read_from_file(input_filename)); + } } -GatedDiscretisedDensity:: -GatedDiscretisedDensity(const shared_ptr >& density_sptr, - const unsigned int num_gates) -{ +GatedDiscretisedDensity::GatedDiscretisedDensity(const shared_ptr>& density_sptr, + const unsigned int num_gates) { this->_densities.resize(num_gates); - for ( unsigned int num = 1 ; num<=num_gates; ++num ) - this->_densities[num-1].reset(density_sptr->get_empty_discretised_density()); + for (unsigned int num = 1; num <= num_gates; ++num) + this->_densities[num - 1].reset(density_sptr->get_empty_discretised_density()); } +void +GatedDiscretisedDensity::set_density_sptr(const shared_ptr>& density_sptr, + const unsigned int gate_num) { + this->_densities[gate_num - 1] = density_sptr; +} -void -GatedDiscretisedDensity:: -set_density_sptr(const shared_ptr >& density_sptr, - const unsigned int gate_num) -{ this->_densities[gate_num-1]=density_sptr; } - -const std::vector > > & -GatedDiscretisedDensity:: -get_densities() const -{ return this->_densities ; } +const std::vector>>& +GatedDiscretisedDensity::get_densities() const { + return this->_densities; +} -const DiscretisedDensity<3,float> & -GatedDiscretisedDensity:: -get_density(const unsigned int gate_num) const -{ return *this->_densities[gate_num-1] ; } +const DiscretisedDensity<3, float>& +GatedDiscretisedDensity::get_density(const unsigned int gate_num) const { + return *this->_densities[gate_num - 1]; +} -DiscretisedDensity<3,float> & -GatedDiscretisedDensity:: -get_density(const unsigned int gate_num) -{ return *this->_densities[gate_num-1] ; } +DiscretisedDensity<3, float>& +GatedDiscretisedDensity::get_density(const unsigned int gate_num) { + return *this->_densities[gate_num - 1]; +} -const TimeGateDefinitions & -GatedDiscretisedDensity:: -get_time_gate_definitions() const -{ return this->_time_gate_definitions; } +const TimeGateDefinitions& +GatedDiscretisedDensity::get_time_gate_definitions() const { + return this->_time_gate_definitions; +} -void GatedDiscretisedDensity:: -fill_with_zero() -{ - for (unsigned int gate_num=0; gate_num_time_gate_definitions.get_num_gates(); ++gate_num) +void +GatedDiscretisedDensity::fill_with_zero() { + for (unsigned int gate_num = 0; gate_num < this->_time_gate_definitions.get_num_gates(); ++gate_num) this->_densities[gate_num].reset((this->_densities[gate_num])->get_empty_discretised_density()); } GatedDiscretisedDensity* -GatedDiscretisedDensity:: -read_from_files(const string& filename) // The written image is read in respect to its center as origin!!! +GatedDiscretisedDensity::read_from_files( + const string& filename) // The written image is read in respect to its center as origin!!! { - const string gdef_filename=filename+".gdef"; + const string gdef_filename = filename + ".gdef"; std::cout << "GatedDiscretisedDensity: Reading gate definitions " << gdef_filename.c_str() << std::endl; - GatedDiscretisedDensity * gated_image_ptr = 0; + GatedDiscretisedDensity* gated_image_ptr = 0; gated_image_ptr = new GatedDiscretisedDensity; gated_image_ptr->_time_gate_definitions.read_gdef_file(gdef_filename); gated_image_ptr->_densities.resize(gated_image_ptr->_time_gate_definitions.get_num_gates()); - for ( unsigned int num = 1 ; num<=(gated_image_ptr->_time_gate_definitions).get_num_gates() ; ++num ) - { - std::stringstream gate_num_stream; - gate_num_stream << gated_image_ptr->_time_gate_definitions.get_gate_num(num); - const string input_filename=filename+"_g"+gate_num_stream.str()+".hv"; - const shared_ptr > read_sptr(new VoxelsOnCartesianGrid ); - std::cout << "GatedDiscretisedDensity: Reading gate file: " << input_filename.c_str() << std::endl; - gated_image_ptr->_densities[num-1].reset(DiscretisedDensity<3,float>::read_from_file(input_filename)); - } + for (unsigned int num = 1; num <= (gated_image_ptr->_time_gate_definitions).get_num_gates(); ++num) { + std::stringstream gate_num_stream; + gate_num_stream << gated_image_ptr->_time_gate_definitions.get_gate_num(num); + const string input_filename = filename + "_g" + gate_num_stream.str() + ".hv"; + const shared_ptr> read_sptr(new VoxelsOnCartesianGrid); + std::cout << "GatedDiscretisedDensity: Reading gate file: " << input_filename.c_str() << std::endl; + gated_image_ptr->_densities[num - 1].reset(DiscretisedDensity<3, float>::read_from_file(input_filename)); + } return gated_image_ptr; } GatedDiscretisedDensity* -GatedDiscretisedDensity:: -read_from_files(const string& filename,const string& suffix) // The written image is read in respect to its center as origin!!! +GatedDiscretisedDensity::read_from_files(const string& filename, + const string& suffix) // The written image is read in respect to its center as origin!!! { - const string gdef_filename=filename+".gdef"; + const string gdef_filename = filename + ".gdef"; std::cout << "GatedDiscretisedDensity: Reading gate definitions " << gdef_filename.c_str() << std::endl; - GatedDiscretisedDensity * gated_image_ptr = 0; + GatedDiscretisedDensity* gated_image_ptr = 0; gated_image_ptr = new GatedDiscretisedDensity; gated_image_ptr->_time_gate_definitions.read_gdef_file(gdef_filename); gated_image_ptr->_densities.resize(gated_image_ptr->_time_gate_definitions.get_num_gates()); - for ( unsigned int num = 1 ; num<=(gated_image_ptr->_time_gate_definitions).get_num_gates() ; ++num ) - { - std::stringstream gate_num_stream; - gate_num_stream << gated_image_ptr->_time_gate_definitions.get_gate_num(num); - const string input_filename=filename+"_g"+gate_num_stream.str()+suffix+".hv"; - // const shared_ptr > read_sptr = new VoxelsOnCartesianGrid ; - std::cout << "GatedDiscretisedDensity: Reading gate file: " << input_filename.c_str() << std::endl; - gated_image_ptr->_densities[num-1].reset(DiscretisedDensity<3,float>::read_from_file(input_filename)); - } + for (unsigned int num = 1; num <= (gated_image_ptr->_time_gate_definitions).get_num_gates(); ++num) { + std::stringstream gate_num_stream; + gate_num_stream << gated_image_ptr->_time_gate_definitions.get_gate_num(num); + const string input_filename = filename + "_g" + gate_num_stream.str() + suffix + ".hv"; + // const shared_ptr > read_sptr = new VoxelsOnCartesianGrid ; + std::cout << "GatedDiscretisedDensity: Reading gate file: " << input_filename.c_str() << std::endl; + gated_image_ptr->_densities[num - 1].reset(DiscretisedDensity<3, float>::read_from_file(input_filename)); + } return gated_image_ptr; } -Succeeded -GatedDiscretisedDensity:: -write_to_files(const string& filename) const -{ - for ( unsigned int num = 1 ; num<=(_time_gate_definitions).get_num_gates() ; ++num ) - { - std::stringstream gate_num_stream; - gate_num_stream << _time_gate_definitions.get_gate_num(num); - const string output_filename=filename+"_g"+gate_num_stream.str()+".hv"; - std::cout << "GatedDiscretisedDensity: Writing new gate file: " << output_filename.c_str() << std::endl; - if(OutputFileFormat >::default_sptr()->write_to_file(output_filename, this->get_density(num)) - == Succeeded::no) - return Succeeded::no; - } - if((this->_time_gate_definitions).get_num_gates()==0) - std::cout << "GatedDiscretisedDensity: No gates to write, please check!!" << std::endl; - return Succeeded::yes; +Succeeded +GatedDiscretisedDensity::write_to_files(const string& filename) const { + for (unsigned int num = 1; num <= (_time_gate_definitions).get_num_gates(); ++num) { + std::stringstream gate_num_stream; + gate_num_stream << _time_gate_definitions.get_gate_num(num); + const string output_filename = filename + "_g" + gate_num_stream.str() + ".hv"; + std::cout << "GatedDiscretisedDensity: Writing new gate file: " << output_filename.c_str() << std::endl; + if (OutputFileFormat>::default_sptr()->write_to_file(output_filename, this->get_density(num)) == + Succeeded::no) + return Succeeded::no; + } + if ((this->_time_gate_definitions).get_num_gates() == 0) + std::cout << "GatedDiscretisedDensity: No gates to write, please check!!" << std::endl; + return Succeeded::yes; } -Succeeded -GatedDiscretisedDensity:: -write_to_files(const string& filename,const string& suffix) const -{ - for ( unsigned int num = 1 ; num<=(_time_gate_definitions).get_num_gates() ; ++num ) - { - std::stringstream gate_num_stream; - gate_num_stream << _time_gate_definitions.get_gate_num(num); - const string output_filename=filename+"_g"+gate_num_stream.str()+suffix+".hv"; - std::cout << "GatedDiscretisedDensity: Writing new gate file: " << output_filename.c_str() << std::endl; - if(OutputFileFormat >::default_sptr()->write_to_file(output_filename, this->get_density(num)) - == Succeeded::no) - return Succeeded::no; - } - if((this->_time_gate_definitions).get_num_gates()==0) - std::cout << "GatedDiscretisedDensity: No gates to write, please check!!" << std::endl; - return Succeeded::yes; +Succeeded +GatedDiscretisedDensity::write_to_files(const string& filename, const string& suffix) const { + for (unsigned int num = 1; num <= (_time_gate_definitions).get_num_gates(); ++num) { + std::stringstream gate_num_stream; + gate_num_stream << _time_gate_definitions.get_gate_num(num); + const string output_filename = filename + "_g" + gate_num_stream.str() + suffix + ".hv"; + std::cout << "GatedDiscretisedDensity: Writing new gate file: " << output_filename.c_str() << std::endl; + if (OutputFileFormat>::default_sptr()->write_to_file(output_filename, this->get_density(num)) == + Succeeded::no) + return Succeeded::no; + } + if ((this->_time_gate_definitions).get_num_gates() == 0) + std::cout << "GatedDiscretisedDensity: No gates to write, please check!!" << std::endl; + return Succeeded::yes; } END_NAMESPACE_STIR diff --git a/src/buildblock/GatedProjData.cxx b/src/buildblock/GatedProjData.cxx index 57ffa20747..71ac97e91a 100644 --- a/src/buildblock/GatedProjData.cxx +++ b/src/buildblock/GatedProjData.cxx @@ -41,176 +41,143 @@ using std::string; START_NAMESPACE_STIR unique_ptr -GatedProjData:: -read_from_file(const string& filename) // The written image is read in respect to its center as origin!!! +GatedProjData::read_from_file(const string& filename) // The written image is read in respect to its center as origin!!! { std::fstream input(filename.c_str(), std::ios::in | std::ios::binary); - if (!input) - { - warning("GatedProjData::read_from_file cannot read file '%s'. Will now attempt to append .gdef", filename.c_str()); - return unique_ptr(read_from_gdef(filename)); - } + if (!input) { + warning("GatedProjData::read_from_file cannot read file '%s'. Will now attempt to append .gdef", filename.c_str()); + return unique_ptr(read_from_gdef(filename)); + } const FileSignature file_signature(input); - const char * signature = file_signature.get_signature(); + const char* signature = file_signature.get_signature(); unique_ptr gated_proj_data_sptr; #ifdef HAVE_LLN_MATRIX - if (strncmp(signature, "MATRIX", 6) == 0) - { -#ifndef NDEBUG + if (strncmp(signature, "MATRIX", 6) == 0) { +# ifndef NDEBUG warning("GatedProjData::read_from_file trying to read %s as ECAT7\n", filename.c_str()); -#endif +# endif USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 - if (is_ECAT7_emission_file(filename)) - { + if (is_ECAT7_emission_file(filename)) { Main_header mhead; - if (read_ECAT7_main_header(mhead, filename) == Succeeded::no) - { - warning("GatedProjData::read_from_file cannot read %s as ECAT7\n", filename.c_str()); - return unique_ptr(); - } + if (read_ECAT7_main_header(mhead, filename) == Succeeded::no) { + warning("GatedProjData::read_from_file cannot read %s as ECAT7\n", filename.c_str()); + return unique_ptr(); + } gated_proj_data_sptr.reset(new GatedProjData); - const unsigned int num_gates = - static_cast(mhead.num_gates); // TODO +1? - gated_proj_data_sptr->_proj_datas.resize(num_gates); + const unsigned int num_gates = static_cast(mhead.num_gates); // TODO +1? + gated_proj_data_sptr->_proj_datas.resize(num_gates); - for (unsigned int gate_num=1; gate_num <= num_gates; ++ gate_num) - { - gated_proj_data_sptr->_proj_datas[gate_num-1].reset( - ECAT7_to_PDFS(filename, - 1, - gate_num, - /* data_num, bed_num, */ 0,0)); - } + for (unsigned int gate_num = 1; gate_num <= num_gates; ++gate_num) { + gated_proj_data_sptr->_proj_datas[gate_num - 1].reset(ECAT7_to_PDFS(filename, 1, gate_num, + /* data_num, bed_num, */ 0, 0)); + } if (is_null_ptr(gated_proj_data_sptr->_proj_datas[0])) - error("GatedProjData: No gate available\n"); + error("GatedProjData: No gate available\n"); // Get the exam info (from the first ProjData) - if (num_gates>0) + if (num_gates > 0) gated_proj_data_sptr->set_exam_info(gated_proj_data_sptr->_proj_datas[0]->get_exam_info()); - } - else - { + } else { if (is_ECAT7_file(filename)) - warning("GatedProjData::read_from_file ECAT7 file %s should be an emission sinogram\n", filename.c_str()); + warning("GatedProjData::read_from_file ECAT7 file %s should be an emission sinogram\n", filename.c_str()); } - } - else + } else #endif // end of HAVE_LLN_MATRIX - if (strncmp(signature, "Multigate", 9) == 0) - { - //#ifndef NDEBUG - warning("GatedProjData::read_from_file trying to read %s as Multigate", filename.c_str()); - //#endif - //return read_multi_gated_proj_data(filename); - - std::vector filenames; - KeyParser parser; - parser.add_start_key("Multigate"); - parser.add_stop_key("end"); - parser.add_key("filenames", &filenames); - if (parser.parse(filename.c_str()) == false) - { - warning("GatedProjData:::read_from_file: Error parsing %s", filename.c_str()); - return unique_ptr(); - } - - gated_proj_data_sptr.reset(new GatedProjData); - const unsigned int num_gates = - static_cast(filenames.size()); - gated_proj_data_sptr->_proj_datas.resize(num_gates); - - for (unsigned int gate_num=1; gate_num <= num_gates; ++ gate_num) - { - std::cerr<<" Reading " << filenames[gate_num-1]<<'\n'; - gated_proj_data_sptr->_proj_datas[gate_num-1] = - ProjData::read_from_file(filenames[gate_num-1]); - } - // Get the exam info (from the first ProjData) - if (num_gates>0) - gated_proj_data_sptr->set_exam_info(gated_proj_data_sptr->_proj_datas[0]->get_exam_info()); - return gated_proj_data_sptr; - } + if (strncmp(signature, "Multigate", 9) == 0) { + //#ifndef NDEBUG + warning("GatedProjData::read_from_file trying to read %s as Multigate", filename.c_str()); + //#endif + // return read_multi_gated_proj_data(filename); + + std::vector filenames; + KeyParser parser; + parser.add_start_key("Multigate"); + parser.add_stop_key("end"); + parser.add_key("filenames", &filenames); + if (parser.parse(filename.c_str()) == false) { + warning("GatedProjData:::read_from_file: Error parsing %s", filename.c_str()); + return unique_ptr(); + } + + gated_proj_data_sptr.reset(new GatedProjData); + const unsigned int num_gates = static_cast(filenames.size()); + gated_proj_data_sptr->_proj_datas.resize(num_gates); + + for (unsigned int gate_num = 1; gate_num <= num_gates; ++gate_num) { + std::cerr << " Reading " << filenames[gate_num - 1] << '\n'; + gated_proj_data_sptr->_proj_datas[gate_num - 1] = ProjData::read_from_file(filenames[gate_num - 1]); + } + // Get the exam info (from the first ProjData) + if (num_gates > 0) + gated_proj_data_sptr->set_exam_info(gated_proj_data_sptr->_proj_datas[0]->get_exam_info()); + return gated_proj_data_sptr; + } if (strncmp(signature, "Multi", 5) == 0) { #ifndef NDEBUG - info(boost::format("GatedProjData::read_from_file trying to read %s as a Multi file.") % filename); + info(boost::format("GatedProjData::read_from_file trying to read %s as a Multi file.") % filename); #endif - unique_ptr multi_proj_data(MultipleProjData::read_from_file(filename)); - gated_proj_data_sptr.reset(new GatedProjData(*multi_proj_data)); + unique_ptr multi_proj_data(MultipleProjData::read_from_file(filename)); + gated_proj_data_sptr.reset(new GatedProjData(*multi_proj_data)); } - + if (is_null_ptr(gated_proj_data_sptr)) - error("GatedProjData::read_from_file unrecognised file format for file '%s'", - filename.c_str()); + error("GatedProjData::read_from_file unrecognised file format for file '%s'", filename.c_str()); return gated_proj_data_sptr; } -GatedProjData* -GatedProjData::read_from_gdef(const string& filename) -{ - const string gdef_filename=filename+".gdef"; +GatedProjData* +GatedProjData::read_from_gdef(const string& filename) { + const string gdef_filename = filename + ".gdef"; std::cout << "GatedProjData: Reading gate definitions " << gdef_filename.c_str() << std::endl; - GatedProjData * gated_proj_data_ptr = new GatedProjData; + GatedProjData* gated_proj_data_ptr = new GatedProjData; gated_proj_data_ptr->_time_gate_definitions.read_gdef_file(gdef_filename); gated_proj_data_ptr->_proj_datas.resize(gated_proj_data_ptr->_time_gate_definitions.get_num_gates()); - for ( unsigned int num = 1 ; num<=(gated_proj_data_ptr->_time_gate_definitions).get_num_gates() ; ++num ) - { - std::stringstream gate_num_stream; - gate_num_stream << gated_proj_data_ptr->_time_gate_definitions.get_gate_num(num); - const string input_filename=filename+"_g"+gate_num_stream.str()+".hs"; - std::cout << "GatedProjData: Reading gate projection file: " << input_filename.c_str() << std::endl; - gated_proj_data_ptr->_proj_datas[num-1] = ProjData::read_from_file(input_filename); - } - if (is_null_ptr(gated_proj_data_ptr)) - error("GatedProjData::read_from_file unrecognised file format for projection files with prefix '%s'", - filename.c_str()); + for (unsigned int num = 1; num <= (gated_proj_data_ptr->_time_gate_definitions).get_num_gates(); ++num) { + std::stringstream gate_num_stream; + gate_num_stream << gated_proj_data_ptr->_time_gate_definitions.get_gate_num(num); + const string input_filename = filename + "_g" + gate_num_stream.str() + ".hs"; + std::cout << "GatedProjData: Reading gate projection file: " << input_filename.c_str() << std::endl; + gated_proj_data_ptr->_proj_datas[num - 1] = ProjData::read_from_file(input_filename); + } + if (is_null_ptr(gated_proj_data_ptr)) + error("GatedProjData::read_from_file unrecognised file format for projection files with prefix '%s'", filename.c_str()); // Get the exam info (from the first ProjData) - if (gated_proj_data_ptr->get_num_gates()>0) - gated_proj_data_ptr->set_exam_info(gated_proj_data_ptr->_proj_datas[0]->get_exam_info()); - return gated_proj_data_ptr; + if (gated_proj_data_ptr->get_num_gates() > 0) + gated_proj_data_ptr->set_exam_info(gated_proj_data_ptr->_proj_datas[0]->get_exam_info()); + return gated_proj_data_ptr; } -Succeeded -GatedProjData:: -write_to_ecat7(const string& filename) const -{ +Succeeded +GatedProjData::write_to_ecat7(const string& filename) const { #ifndef HAVE_LLN_MATRIX return Succeeded::no; #else Main_header mhead; - ecat::ecat7::make_ECAT7_main_header(mhead, filename, - get_proj_data(1).get_exam_info(), - *get_proj_data(1).get_proj_data_info_sptr() ); + ecat::ecat7::make_ECAT7_main_header(mhead, filename, get_proj_data(1).get_exam_info(), + *get_proj_data(1).get_proj_data_info_sptr()); mhead.num_gates = 1; mhead.num_gates = this->get_num_gates(); - mhead.acquisition_type = - mhead.num_gates>1 ? DynamicEmission : StaticEmission; + mhead.acquisition_type = mhead.num_gates > 1 ? DynamicEmission : StaticEmission; - MatrixFile* mptr= matrix_create (filename.c_str(), MAT_CREATE, &mhead); - if (mptr == 0) - { - warning("GatedProjData::write_to_ecat7 cannot write output file %s\n", filename.c_str()); + MatrixFile* mptr = matrix_create(filename.c_str(), MAT_CREATE, &mhead); + if (mptr == 0) { + warning("GatedProjData::write_to_ecat7 cannot write output file %s\n", filename.c_str()); + return Succeeded::no; + } + for (unsigned int gate_num = 1; gate_num <= this->get_num_gates(); ++gate_num) { + if (ecat::ecat7::ProjData_to_ECAT7(mptr, get_proj_data(gate_num), 1, gate_num) == Succeeded::no) { + matrix_close(mptr); return Succeeded::no; } - for ( unsigned int gate_num = 1 ; gate_num<=this->get_num_gates() ; ++gate_num ) - { - if (ecat::ecat7::ProjData_to_ECAT7(mptr, - get_proj_data(gate_num), - 1, - gate_num) - == Succeeded::no) - { - matrix_close(mptr); - return Succeeded::no; - } - } + } matrix_close(mptr); return Succeeded::yes; #endif // end of HAVE_LLN_MATRIX diff --git a/src/buildblock/GeneralisedPoissonNoiseGenerator.cxx b/src/buildblock/GeneralisedPoissonNoiseGenerator.cxx index c21065a472..7adcf711af 100644 --- a/src/buildblock/GeneralisedPoissonNoiseGenerator.cxx +++ b/src/buildblock/GeneralisedPoissonNoiseGenerator.cxx @@ -18,7 +18,7 @@ /*! \file - \ingroup buildblock + \ingroup buildblock \brief Implements stir::GeneralisedPoissonNoiseGenerator \author Kris Thielemans \author Sanida Mustafovic @@ -38,38 +38,29 @@ START_NAMESPACE_STIR GeneralisedPoissonNoiseGenerator::base_generator_type GeneralisedPoissonNoiseGenerator::generator; -GeneralisedPoissonNoiseGenerator:: -GeneralisedPoissonNoiseGenerator(const float scaling_factor, - const bool preserve_mean) - : scaling_factor(scaling_factor), - preserve_mean(preserve_mean) -{ +GeneralisedPoissonNoiseGenerator::GeneralisedPoissonNoiseGenerator(const float scaling_factor, const bool preserve_mean) + : scaling_factor(scaling_factor), preserve_mean(preserve_mean) { this->seed(43u); } void -GeneralisedPoissonNoiseGenerator:: -seed(unsigned int value) -{ - if (value==unsigned(0)) - error("Seed value has to be non-zero"); +GeneralisedPoissonNoiseGenerator::seed(unsigned int value) { + if (value == unsigned(0)) + error("Seed value has to be non-zero"); this->generator.seed(static_cast(value)); } // function that generates a Poisson noise realisation, i.e. without // using the scaling_factor unsigned int -GeneralisedPoissonNoiseGenerator:: -generate_poisson_random(const float mu) -{ +GeneralisedPoissonNoiseGenerator::generate_poisson_random(const float mu) { static boost::uniform_01 random01(generator); // normal distribution with mean=0 and sigma=1 static boost::normal_distribution normal_distrib01(0., 1.); // check if mu is large. If so, use the normal distribution // note: the threshold must be such that exp(threshold) is still a floating point number - if (mu > 60.F) - { + if (mu > 60.F) { // get random number of normal distribution of mean=mu and sigma=sqrt(mu) // get random with mean=0, sigma=1 and use scaling with sqrt(mu) and addition of mu @@ -77,71 +68,55 @@ generate_poisson_random(const float mu) // object every time. This will speed things up, especially because the // normal_distribution is implemented using with a polar method that calls // generator::operator() twice only on 'odd'- number of invocations - const double random=normal_distrib01(random01)*sqrt(mu) + mu; + const double random = normal_distrib01(random01) * sqrt(mu) + mu; - return static_cast(random<=0 ? 0 : round(random)); - } - else - { + return static_cast(random <= 0 ? 0 : round(random)); + } else { double u = random01(); - - // prevent problems of n growing too large (or even to infinity) + + // prevent problems of n growing too large (or even to infinity) // when u is very close to 1 - if (u>1-1.E-6) - u = 1-1.E-6; - - const double upper = exp(mu)*u; + if (u > 1 - 1.E-6) + u = 1 - 1.E-6; + + const double upper = exp(mu) * u; double accum = 1.; - double term = 1.; + double term = 1.; unsigned int n = 1; - - while(accum (random_poisson); +GeneralisedPoissonNoiseGenerator::generate_scaled_poisson_random(const float mu, const float scaling_factor, + const bool preserve_mean) { + const unsigned int random_poisson = generate_poisson_random(mu * scaling_factor); + return preserve_mean ? random_poisson / scaling_factor : static_cast(random_poisson); } float -GeneralisedPoissonNoiseGenerator:: -generate_random(const float mu) -{ - return - generate_scaled_poisson_random(mu, scaling_factor, preserve_mean); +GeneralisedPoissonNoiseGenerator::generate_random(const float mu) { + return generate_scaled_poisson_random(mu, scaling_factor, preserve_mean); } - -void -GeneralisedPoissonNoiseGenerator:: -generate_random(ProjData& output_projdata, - const ProjData& input_projdata) -{ - for (int seg= input_projdata.get_min_segment_num(); - seg<=input_projdata.get_max_segment_num(); - seg++) - { - SegmentByView seg_output= - output_projdata.get_empty_segment_by_view(seg); - - this->generate_random(seg_output, input_projdata.get_segment_by_view(seg)); - if (output_projdata.set_segment(seg_output) == Succeeded::no) - error("Problem writing to projection data"); +void +GeneralisedPoissonNoiseGenerator::generate_random(ProjData& output_projdata, const ProjData& input_projdata) { + for (int seg = input_projdata.get_min_segment_num(); seg <= input_projdata.get_max_segment_num(); seg++) { + for (int timing_pos_num = input_projdata.get_min_tof_pos_num(); timing_pos_num <= input_projdata.get_max_tof_pos_num(); + ++timing_pos_num) { + SegmentByView seg_output = output_projdata.get_empty_segment_by_view(seg, false, timing_pos_num); + + this->generate_random(seg_output, input_projdata.get_segment_by_view(seg, timing_pos_num)); + if (output_projdata.set_segment(seg_output) == Succeeded::no) + error("Problem writing to projection data"); + } } } END_NAMESPACE_STIR - diff --git a/src/buildblock/HUToMuImageProcessor.cxx b/src/buildblock/HUToMuImageProcessor.cxx index 337db22b51..f3ee9c471a 100644 --- a/src/buildblock/HUToMuImageProcessor.cxx +++ b/src/buildblock/HUToMuImageProcessor.cxx @@ -1,12 +1,12 @@ /*! \file - \ingroup ImageProcessor + \ingroup ImageProcessor \brief Implementation of class stir::HUToMuImageProcessor - + \author Kris Thielemans \author Benjamin A. Thomas - + */ /* Copyright (C) 2019, 2020, UCL @@ -33,49 +33,37 @@ START_NAMESPACE_STIR template -HUToMuImageProcessor:: -HUToMuImageProcessor() -{ +HUToMuImageProcessor::HUToMuImageProcessor() { this->set_defaults(); } template void -HUToMuImageProcessor:: -set_slope_filename(const std::string& arg) -{ +HUToMuImageProcessor::set_slope_filename(const std::string& arg) { this->filename = arg; } template void -HUToMuImageProcessor:: -set_manufacturer_name(const std::string& arg) -{ +HUToMuImageProcessor::set_manufacturer_name(const std::string& arg) { this->manufacturer_name = arg; } template void -HUToMuImageProcessor:: -set_kilovoltage_peak(const float arg) -{ +HUToMuImageProcessor::set_kilovoltage_peak(const float arg) { this->kilovoltage_peak = arg; } template void -HUToMuImageProcessor:: -set_target_photon_energy(const float arg) -{ +HUToMuImageProcessor::set_target_photon_energy(const float arg) { this->target_photon_energy = arg; } template void -HUToMuImageProcessor:: -set_defaults() -{ +HUToMuImageProcessor::set_defaults() { base_type::set_defaults(); manufacturer_name = "GENERIC"; kilovoltage_peak = 120.F; @@ -84,9 +72,7 @@ set_defaults() template void -HUToMuImageProcessor:: -initialise_keymap() -{ +HUToMuImageProcessor::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key(std::string(this->registered_name) + " Parameters"); this->parser.add_stop_key(std::string("End ") + this->registered_name + " Parameters"); @@ -98,75 +84,68 @@ initialise_keymap() template bool -HUToMuImageProcessor:: -post_processing() -{ +HUToMuImageProcessor::post_processing() { return base_type::post_processing(); } template Succeeded -HUToMuImageProcessor:: -virtual_set_up(const TargetT& image) -{ +HUToMuImageProcessor::virtual_set_up(const TargetT& image) { this->get_record_from_json(); return Succeeded::yes; } template void -HUToMuImageProcessor:: -get_record_from_json() -{ +HUToMuImageProcessor::get_record_from_json() { if (this->filename.empty()) error("HUToMu: no filename set for the slope info"); if (this->manufacturer_name.empty()) error("HUToMu: no manufacturer set for the slope info"); - //Read slope file + // Read slope file std::ifstream slope_json_file_stream(this->filename); nlohmann::json slope_json; slope_json_file_stream >> slope_json; - if (slope_json.find("scale") == slope_json.end()) - { - error("HUToMu: No or incorrect JSON slopes set (could not find \"scale\" in file \"" - + filename + "\")"); - } - //Put user-specified manufacturer into upper case. + if (slope_json.find("scale") == slope_json.end()) { + error("HUToMu: No or incorrect JSON slopes set (could not find \"scale\" in file \"" + filename + "\")"); + } + // Put user-specified manufacturer into upper case. std::string manufacturer_upper_case = this->manufacturer_name; std::locale loc; - for (std::string::size_type i=0; itarget_photon_energy); - //Get desired kVp as integer value + // Get desired kVp as integer value const int kVp = stir::round(this->kilovoltage_peak); - stir::info(boost::format("HUToMu: finding record with manufacturer: '%s', keV=%d, kVp=%d in file '%s'") - % manufacturer_upper_case % keV % kVp % this->filename, 2); + stir::info(boost::format("HUToMu: finding record with manufacturer: '%s', keV=%d, kVp=%d in file '%s'") % + manufacturer_upper_case % keV % kVp % this->filename, + 2); - //Extract appropriate chunk of JSON file for given manufacturer. + // Extract appropriate chunk of JSON file for given manufacturer. nlohmann::json target = slope_json["scale"][manufacturer_upper_case]["transform"]; int location = -1; int pos = 0; - for (auto entry : target){ - if ( (stir::round(float(entry["kev"])) == keV) && (stir::round(float(entry["kvp"])) == kVp) ) + for (auto entry : target) { + if ((stir::round(float(entry["kev"])) == keV) && (stir::round(float(entry["kvp"])) == kVp)) location = pos; pos++; } - if (location == -1){ + if (location == -1) { stir::error("HUToMu: Desired slope not found!"); } - //Extract transform for specific keV and kVp. + // Extract transform for specific keV and kVp. nlohmann::json transform = target[location]; { std::stringstream str; str << transform.dump(4); - info("HUToMu: JSON record found:" + str.str(),2); + info("HUToMu: JSON record found:" + str.str(), 2); } this->a1 = transform["a1"]; this->b1 = transform["b1"]; @@ -176,63 +155,51 @@ get_record_from_json() this->breakPoint = transform["break"]; - //std::cout << transform.dump(4); + // std::cout << transform.dump(4); } template void -HUToMuImageProcessor:: -apply_scaling_to_HU(TargetT& output_image, - const TargetT& input_image) const -{ +HUToMuImageProcessor::apply_scaling_to_HU(TargetT& output_image, const TargetT& input_image) const { auto out_iter = output_image.begin_all(); auto in_iter = input_image.begin_all(); + while (in_iter != input_image.end_all()) { + if (*in_iter < breakPoint) { + const float mu = a1 + b1 * (*in_iter); + *out_iter = (mu < 0.0f) ? 0.0f : mu; + } else { + *out_iter = a2 + b2 * (*in_iter); + } - while( in_iter != input_image.end_all()) - { - if (*in_iter < breakPoint) - { - const float mu = a1 + b1 *(*in_iter); - *out_iter = (mu < 0.0f) ? 0.0f : mu; - } else - { - *out_iter = a2 + b2 * (*in_iter); - } - - ++in_iter; ++out_iter; + ++in_iter; + ++out_iter; } } template void -HUToMuImageProcessor:: -virtual_apply(TargetT& out_density, const TargetT& in_density) const -{ +HUToMuImageProcessor::virtual_apply(TargetT& out_density, const TargetT& in_density) const { this->apply_scaling_to_HU(out_density, in_density); } template void -HUToMuImageProcessor:: - virtual_apply(TargetT& density) const -{ - shared_ptr copy_sptr(density.clone()); +HUToMuImageProcessor::virtual_apply(TargetT& density) const { + shared_ptr copy_sptr(density.clone()); this->apply_scaling_to_HU(density, *copy_sptr); } -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif // Register this class in the ImageProcessor registry // static HUToMuImageProcessor>::RegisterIt dummy; // have the above variable in a separate file, which you need to pass at link time -template class HUToMuImageProcessor>; +template class HUToMuImageProcessor>; END_NAMESPACE_STIR - - diff --git a/src/buildblock/IndexRange.cxx b/src/buildblock/IndexRange.cxx index 6b7f6f750a..e66ff3b513 100644 --- a/src/buildblock/IndexRange.cxx +++ b/src/buildblock/IndexRange.cxx @@ -1,8 +1,8 @@ // // /*! - \file - \ingroup Array + \file + \ingroup Array \brief implementations for the stir::IndexRange class \author Kris Thielemans @@ -34,24 +34,20 @@ START_NAMESPACE_STIR #ifndef STIR_NO_MUTABLE - template bool -IndexRange::get_regular_range( - BasicCoordinate& min, - BasicCoordinate& max) const -{ - // check if empty range - if (base_type::begin() == base_type::end()) - { -#ifndef STIR_NO_NAMESPACES +IndexRange::get_regular_range(BasicCoordinate& min, + BasicCoordinate& max) const { + // check if empty range + if (base_type::begin() == base_type::end()) { +# ifndef STIR_NO_NAMESPACES std::fill(min.begin(), min.end(), 0); - std::fill(max.begin(), max.end(),-1); -#else + std::fill(max.begin(), max.end(), -1); +# else // gcc 2.8.1 needs ::fill, otherwise it gets confused with VectorWithOffset::fill ::fill(min.begin(), min.end(), 0); - ::fill(max.begin(), max.end(),-1); -#endif + ::fill(max.begin(), max.end(), -1); +# endif return true; } @@ -59,59 +55,56 @@ IndexRange::get_regular_range( if (is_regular_range == regular_false) return false; - typename base_type::const_iterator iter=base_type::begin(); + typename base_type::const_iterator iter = base_type::begin(); - BasicCoordinate lower_dim_min; - BasicCoordinate lower_dim_max; + BasicCoordinate lower_dim_min; + BasicCoordinate lower_dim_max; if (!iter->get_regular_range(lower_dim_min, lower_dim_max)) return false; - if (is_regular_range == regular_to_do) - { - // check if all lower dimensional ranges have same regular range - BasicCoordinate lower_dim_min_try; - BasicCoordinate lower_dim_max_try; - - for (++iter; iter != base_type::end(); ++iter) - { - if (!iter->get_regular_range(lower_dim_min_try, lower_dim_max_try)) - { - is_regular_range = regular_false; - return false; + if (is_regular_range == regular_to_do) { + // check if all lower dimensional ranges have same regular range + BasicCoordinate lower_dim_min_try; + BasicCoordinate lower_dim_max_try; + + for (++iter; iter != base_type::end(); ++iter) { + if (!iter->get_regular_range(lower_dim_min_try, lower_dim_max_try)) { + is_regular_range = regular_false; + return false; } -#ifndef STIR_NO_NAMESPACES +# ifndef STIR_NO_NAMESPACES if (!std::equal(lower_dim_min.begin(), lower_dim_min.end(), lower_dim_min_try.begin()) || - !std::equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) -#else - if (!equal(lower_dim_min.begin(), lower_dim_min.end(), lower_dim_min_try.begin()) || - !equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) -#endif + !std::equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) +# else + if (!equal(lower_dim_min.begin(), lower_dim_min.end(), lower_dim_min_try.begin()) || + !equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) +# endif { - is_regular_range = regular_false; - return false; + is_regular_range = regular_false; + return false; } } // yes, they do is_regular_range = regular_true; } -#if defined(_MSC_VER) && _MSC_VER<1200 +# if defined(_MSC_VER) && _MSC_VER < 1200 // bug in VC++ 5.0, needs explicit template args - min = join(base_type::get_min_index(), lower_dim_min); - max = join(base_type::get_max_index(), lower_dim_max); -#elif defined( __GNUC__) && (__GNUC__ == 2 && __GNUC_MINOR__ < 9) - // work around gcc 2.8.1 bug. + min = join(base_type::get_min_index(), lower_dim_min); + max = join(base_type::get_max_index(), lower_dim_max); +# elif defined(__GNUC__) && (__GNUC__ == 2 && __GNUC_MINOR__ < 9) + // work around gcc 2.8.1 bug. // It cannot call 'join' (it generates a bad mangled name for the function) // So, we explicitly insert the code here *min.begin() = base_type::get_min_index(); - copy(lower_dim_min.begin(), lower_dim_min.end(), min.begin()+1); + copy(lower_dim_min.begin(), lower_dim_min.end(), min.begin() + 1); *max.begin() = base_type::get_max_index(); - copy(lower_dim_max.begin(), lower_dim_max.end(), max.begin()+1); -#else - // lines for good compilers... + copy(lower_dim_max.begin(), lower_dim_max.end(), max.begin() + 1); +# else + // lines for good compilers... min = join(base_type::get_min_index(), lower_dim_min); - max = join(base_type::get_max_index(), lower_dim_max); -#endif + max = join(base_type::get_max_index(), lower_dim_max); +# endif return true; } @@ -119,20 +112,17 @@ IndexRange::get_regular_range( template bool -IndexRange::get_regular_range( - BasicCoordinate& min, - BasicCoordinate& max) const -{ - // check if empty range - if (base_type::begin() == base_type::end()) - { -#ifndef STIR_NO_NAMESPACES +IndexRange::get_regular_range(BasicCoordinate& min, + BasicCoordinate& max) const { + // check if empty range + if (base_type::begin() == base_type::end()) { +# ifndef STIR_NO_NAMESPACES std::fill(min.begin(), min.end(), 0); - std::fill(max.begin(), max.end(),-1); -#else - fill(min,base_type::begin(), min.end(), 0); - fill(max,base_type::begin(), max.end(),-1); -#endif + std::fill(max.begin(), max.end(), -1); +# else + fill(min, base_type::begin(), min.end(), 0); + fill(max, base_type::begin(), max.end(), -1); +# endif return true; } @@ -140,69 +130,63 @@ IndexRange::get_regular_range( if (is_regular_range == regular_false) return false; - base_type::const_iterator iter=base_type::begin(); + base_type::const_iterator iter = base_type::begin(); - BasicCoordinate lower_dim_min; - BasicCoordinate lower_dim_max; + BasicCoordinate lower_dim_min; + BasicCoordinate lower_dim_max; if (!iter->get_regular_range(lower_dim_min, lower_dim_max)) return false; - if (is_regular_range == regular_to_do) - { - // check if all lower dimensional ranges have same regular range - BasicCoordinate lower_dim_min_try; - BasicCoordinate lower_dim_max_try; - - for (++iter; iter != base_type::end(); ++iter) - { - if (!iter->get_regular_range(lower_dim_min_try, lower_dim_max_try)) - { - //is_regular_range = regular_false; - return false; + if (is_regular_range == regular_to_do) { + // check if all lower dimensional ranges have same regular range + BasicCoordinate lower_dim_min_try; + BasicCoordinate lower_dim_max_try; + + for (++iter; iter != base_type::end(); ++iter) { + if (!iter->get_regular_range(lower_dim_min_try, lower_dim_max_try)) { + // is_regular_range = regular_false; + return false; } -#ifndef STIR_NO_NAMESPACES +# ifndef STIR_NO_NAMESPACES if (!std::equal(lower_dim_min.begin(), lower_dim_min.end(), lower_dim_min_try.begin()) || - !std::equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) -#else - if (!equal(lower_dim_min.begin(), lower_dim_min.end(), lower_dim_min_try.begin()) || - !equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) -#endif + !std::equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) +# else + if (!equal(lower_dim_min.begin(), lower_dim_min.end(), lower_dim_min_try.begin()) || + !equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) +# endif { - //is_regular_range = regular_false; - return false; + // is_regular_range = regular_false; + return false; } } // yes, they do - //is_regular_range = regular_true; + // is_regular_range = regular_true; } -#if defined(_MSC_VER) && _MSC_VER<1200 +# if defined(_MSC_VER) && _MSC_VER < 1200 // bug in VC++ 5.0, needs explicit template args - min = join(base_type::get_min_index(), lower_dim_min); - max = join(base_type::get_max_index(), lower_dim_max); -#else + min = join(base_type::get_min_index(), lower_dim_min); + max = join(base_type::get_max_index(), lower_dim_max); +# else min = join(base_type::get_min_index(), lower_dim_min); max = join(base_type::get_max_index(), lower_dim_max); -#endif +# endif return true; } template bool -IndexRange::get_regular_range( - BasicCoordinate& min, - BasicCoordinate& max) -{ - // check if empty range - if (base_type::begin() == base_type::end()) - { -#ifndef STIR_NO_NAMESPACES +IndexRange::get_regular_range(BasicCoordinate& min, + BasicCoordinate& max) { + // check if empty range + if (base_type::begin() == base_type::end()) { +# ifndef STIR_NO_NAMESPACES std::fill(min.begin(), min.end(), 0); - std::fill(max.begin(), max.end(),-1); -#else + std::fill(max.begin(), max.end(), -1); +# else fill(min.begin(), min.end(), 0); - fill(max.begin(), max.end(),-1); -#endif + fill(max.begin(), max.end(), -1); +# endif return true; } @@ -210,56 +194,52 @@ IndexRange::get_regular_range( if (is_regular_range == regular_false) return false; - base_type::iterator iter=base_type::begin(); + base_type::iterator iter = base_type::begin(); - BasicCoordinate lower_dim_min; - BasicCoordinate lower_dim_max; + BasicCoordinate lower_dim_min; + BasicCoordinate lower_dim_max; if (!iter->get_regular_range(lower_dim_min, lower_dim_max)) return false; - if (is_regular_range == regular_to_do) - { - // check if all lower dimensional ranges have same regular range - BasicCoordinate lower_dim_min_try; - BasicCoordinate lower_dim_max_try; - - for (++iter; iter != base_type::end(); ++iter) - { - if (!iter->get_regular_range(lower_dim_min_try, lower_dim_max_try)) - { - is_regular_range = regular_false; - return false; + if (is_regular_range == regular_to_do) { + // check if all lower dimensional ranges have same regular range + BasicCoordinate lower_dim_min_try; + BasicCoordinate lower_dim_max_try; + + for (++iter; iter != base_type::end(); ++iter) { + if (!iter->get_regular_range(lower_dim_min_try, lower_dim_max_try)) { + is_regular_range = regular_false; + return false; } -#ifndef STIR_NO_NAMESPACES +# ifndef STIR_NO_NAMESPACES if (!std::equal(lower_dim_min.begin(), lower_dim_min.end(), lower_dim_min_try.begin()) || - !std::equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) -#else - if (!equal(lower_dim_min.begin(), lower_dim_min.end(), lower_dim_min_try.begin()) || - !equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) -#endif + !std::equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) +# else + if (!equal(lower_dim_min.begin(), lower_dim_min.end(), lower_dim_min_try.begin()) || + !equal(lower_dim_max.begin(), lower_dim_max.end(), lower_dim_max_try.begin())) +# endif { - is_regular_range = regular_false; - return false; + is_regular_range = regular_false; + return false; } } // yes, they do is_regular_range = regular_true; } -#if defined(_MSC_VER) && _MSC_VER<1200 +# if defined(_MSC_VER) && _MSC_VER < 1200 // bug in VC++ 5.0, needs explicit template args - min = join(base_type::get_min_index(), lower_dim_min); - max = join(base_type::get_max_index(), lower_dim_max); -#else + min = join(base_type::get_min_index(), lower_dim_min); + max = join(base_type::get_max_index(), lower_dim_max); +# else min = join(base_type::get_min_index(), lower_dim_min); max = join(base_type::get_max_index(), lower_dim_max); -#endif +# endif return true; } #endif // STIR_NO_MUTABLE - /*************************************************** instantiations ***************************************************/ diff --git a/src/buildblock/KeyParser.cxx b/src/buildblock/KeyParser.cxx index f77e858f96..e5c211a461 100644 --- a/src/buildblock/KeyParser.cxx +++ b/src/buildblock/KeyParser.cxx @@ -39,14 +39,16 @@ #include #include #include -# ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::getenv; } -# endif +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::getenv; +} +#endif #include #ifndef BOOST_NO_STRINGSTREAM -#include +# include #endif #ifndef STIR_NO_NAMESPACES @@ -59,7 +61,7 @@ using std::istrstream; using std::ostrstream; using std::vector; using std::string; -//using std::map; +// using std::map; using std::list; using std::pair; using std::istream; @@ -81,222 +83,162 @@ START_NAMESPACE_STIR This function should be moved somewhere else as it might be useful to someone else as well. (TODO) */ -static void read_line(istream& input, string& line, - const char continuation_char = '\\') -{ +static void +read_line(istream& input, string& line, const char continuation_char = '\\') { line.resize(0); if (!input) return; string thisline; - while(true) - { + while (true) { #ifndef _MSC_VER - std::getline(input, thisline); + std::getline(input, thisline); #else - /* VC 6.0 getline does not work properly when input==cin. - It only returns after a 2nd CR is entered. (The entered input is - used for the next getline, so that the input is indeed ok. Problem is - if that in a sequence - getline(cin,...); - cout << "prompt"; - getline(cin,...); - the user sees the 'prompt' only after the 2nd CR. - So, we replace getline(stream,string) with our own mess... - */ - { - const size_t buf_size=512; // arbitrary number here. we'll check if the line was too long below - char buf[buf_size]; - thisline.resize(0); - bool more_chars = false; - do - { - buf[0]='\0'; - input.getline(buf,buf_size); - thisline += buf; - if (input.fail() && !input.bad() && !input.eof()) - { - // either no characters (end-of-line somehow) or buf_size-1 or end-of-file - input.clear(); - more_chars = strlen(buf)==buf_size-1; - } - else - more_chars = false; - } - while (more_chars); - } + /* VC 6.0 getline does not work properly when input==cin. + It only returns after a 2nd CR is entered. (The entered input is + used for the next getline, so that the input is indeed ok. Problem is + if that in a sequence + getline(cin,...); + cout << "prompt"; + getline(cin,...); + the user sees the 'prompt' only after the 2nd CR. + So, we replace getline(stream,string) with our own mess... + */ + { + const size_t buf_size = 512; // arbitrary number here. we'll check if the line was too long below + char buf[buf_size]; + thisline.resize(0); + bool more_chars = false; + do { + buf[0] = '\0'; + input.getline(buf, buf_size); + thisline += buf; + if (input.fail() && !input.bad() && !input.eof()) { + // either no characters (end-of-line somehow) or buf_size-1 or end-of-file + input.clear(); + more_chars = strlen(buf) == buf_size - 1; + } else + more_chars = false; + } while (more_chars); + } #endif - // check if last character is \r, - // in case this is a DOS file, but not a DOS/Windows host - if (thisline.size() != 0) - { - string::size_type position_of_last_char = - thisline.size()-1; - if (thisline[position_of_last_char] == '\r') - thisline.erase(position_of_last_char, 1); - } - // TODO handle the case of a Mac file on a non-Mac host (EOL on Mac is \r) - - line += thisline; - - // check for continuation - if (line.size() != 0) - { - string::size_type position_of_last_char = - line.size()-1; - if (line[position_of_last_char] == continuation_char) - { - line.erase(position_of_last_char, 1); - // now the while loop will keep on reading - } - else - { - // exit the loop - break; - } - } - else - { - // exit the loop - break; - } + // check if last character is \r, + // in case this is a DOS file, but not a DOS/Windows host + if (thisline.size() != 0) { + string::size_type position_of_last_char = thisline.size() - 1; + if (thisline[position_of_last_char] == '\r') + thisline.erase(position_of_last_char, 1); } + // TODO handle the case of a Mac file on a non-Mac host (EOL on Mac is \r) + + line += thisline; + + // check for continuation + if (line.size() != 0) { + string::size_type position_of_last_char = line.size() - 1; + if (line[position_of_last_char] == continuation_char) { + line.erase(position_of_last_char, 1); + // now the while loop will keep on reading + } else { + // exit the loop + break; + } + } else { + // exit the loop + break; + } + } // replace ${text} with value of environment variable { string::size_type start_of_env_string; - while ((start_of_env_string = line.find("${")) != string::npos) - { - const string::size_type end_of_env_string = line.find('}',start_of_env_string+2); - if (end_of_env_string == string::npos) - break; - const string::size_type size_of_env_string = - end_of_env_string-start_of_env_string+1; - const string name_of_env_variable = line.substr(start_of_env_string+2, size_of_env_string-3); - const char * const value_of_env_variable = std::getenv(name_of_env_variable.c_str()); - if (value_of_env_variable == 0) - { - warning("KeyParser: environment variable '%s' not found. Replaced by empty string.\n" - "This happened while parsing the following line:\n%s", - name_of_env_variable.c_str(), - line.c_str()); - line.erase(start_of_env_string, size_of_env_string); - } - else - { - line.replace(start_of_env_string, - size_of_env_string, - value_of_env_variable); - } + while ((start_of_env_string = line.find("${")) != string::npos) { + const string::size_type end_of_env_string = line.find('}', start_of_env_string + 2); + if (end_of_env_string == string::npos) + break; + const string::size_type size_of_env_string = end_of_env_string - start_of_env_string + 1; + const string name_of_env_variable = line.substr(start_of_env_string + 2, size_of_env_string - 3); + const char* const value_of_env_variable = std::getenv(name_of_env_variable.c_str()); + if (value_of_env_variable == 0) { + warning("KeyParser: environment variable '%s' not found. Replaced by empty string.\n" + "This happened while parsing the following line:\n%s", + name_of_env_variable.c_str(), line.c_str()); + line.erase(start_of_env_string, size_of_env_string); + } else { + line.replace(start_of_env_string, size_of_env_string, value_of_env_variable); } + } } } // map_element implementation; map_element::map_element() - : - type(KeyArgument::NONE), - p_object_member(0), - p_object_variable(0), - vectorised_key_level(0), - p_object_list_of_values(0) + : type(KeyArgument::NONE), p_object_member(0), p_object_variable(0), vectorised_key_level(0), p_object_list_of_values(0) {} + +map_element::map_element(KeyArgument::type t, KeyParser::KeywordProcessor pom, void* pov, const int vectorised_key_level_v, + const ASCIIlist_type* list_of_values) + : type(t), p_object_member(pom), p_object_variable(pov), vectorised_key_level(vectorised_key_level_v), + p_object_list_of_values(list_of_values) {} + +map_element::map_element(void (KeyParser::*pom)(), RegisteredObjectBase** pov, Parser* parser) + : type(KeyArgument::PARSINGOBJECT), p_object_member(pom), p_object_variable(pov), vectorised_key_level(0), + p_object_list_of_values(0), parser(parser) // static_cast(parser)) {} -map_element::map_element(KeyArgument::type t, - KeyParser::KeywordProcessor pom, - void* pov, - const int vectorised_key_level_v, - const ASCIIlist_type *list_of_values) - : - type(t), - p_object_member(pom), - p_object_variable(pov), - vectorised_key_level(vectorised_key_level_v), - p_object_list_of_values(list_of_values) +map_element::map_element(void (KeyParser::*pom)(), shared_ptr* pov, Parser* parser) + : type(KeyArgument::SHARED_PARSINGOBJECT), p_object_member(pom), p_object_variable(pov), vectorised_key_level(0), + p_object_list_of_values(0), parser(parser) // static_cast(parser)) {} -map_element::map_element(void (KeyParser::*pom)(), - RegisteredObjectBase** pov, - Parser* parser) - : - type(KeyArgument::PARSINGOBJECT), - p_object_member(pom), - p_object_variable(pov), - vectorised_key_level(0), - p_object_list_of_values(0), - parser(parser)//static_cast(parser)) - {} - -map_element::map_element(void (KeyParser::*pom)(), - shared_ptr* pov, - Parser* parser) - : - type(KeyArgument::SHARED_PARSINGOBJECT), - p_object_member(pom), - p_object_variable(pov), - vectorised_key_level(0), - p_object_list_of_values(0), - parser(parser)//static_cast(parser)) - {} - -map_element::~map_element() -{ -} - - -map_element& map_element::operator=(const map_element& me) -{ - type=me.type; - p_object_member=me.p_object_member; - p_object_variable=me.p_object_variable; - vectorised_key_level=me.vectorised_key_level; - p_object_list_of_values=me.p_object_list_of_values; +map_element::~map_element() {} + +map_element& +map_element::operator=(const map_element& me) { + type = me.type; + p_object_member = me.p_object_member; + p_object_variable = me.p_object_variable; + vectorised_key_level = me.vectorised_key_level; + p_object_list_of_values = me.p_object_list_of_values; parser = me.parser; return *this; } // KeyParser implementation +KeyParser::KeyParser() { -KeyParser::KeyParser() -{ - - current_index=-1; - status=end_parsing; - current=0;//KTnew map_element(); + current_index = -1; + status = end_parsing; + current = 0; // KTnew map_element(); } -KeyParser::~KeyParser() -{ -} +KeyParser::~KeyParser() {} -bool KeyParser::parse(const char * const filename, const bool write_warning) -{ - ifstream hdr_stream(filename); - if (!hdr_stream) - { - warning("KeyParser::parse: couldn't open file %s\n", filename); - return false; - } - return parse(hdr_stream, write_warning); +bool +KeyParser::parse(const char* const filename, const bool write_warning) { + ifstream hdr_stream(filename); + if (!hdr_stream) { + warning("KeyParser::parse: couldn't open file %s\n", filename); + return false; + } + return parse(hdr_stream, write_warning); } -bool KeyParser::parse(istream& f, const bool write_warning) -{ +bool +KeyParser::parse(istream& f, const bool write_warning) { // print_keywords_to_stream(cerr); - input=&f; - return (parse_header(write_warning)==Succeeded::yes && post_processing()==false); + input = &f; + return (parse_header(write_warning) == Succeeded::yes && post_processing() == false); } - // KT 10/07/2000 new function /*! This follows Interfile 3.3 conventions:
  • The characters \c space, \c tab, \c underscore, \c ! are all - treated as white space and ignored. + treated as white space and ignored.
  • Case is ignored.
Note: in this implementation 'ignoring' white space means 'trimming' @@ -304,389 +246,310 @@ bool KeyParser::parse(istream& f, const bool write_warning) with a single space. */ -string -KeyParser::standardise_keyword(const string& keyword) const -{ +string +KeyParser::standardise_keyword(const string& keyword) const { return standardise_interfile_keyword(keyword); } // KT 07/10/2002 moved here from Line -string -KeyParser::get_keyword(const string& line) const -{ - // keyword stops at either := or an index [] +string +KeyParser::get_keyword(const string& line) const { + // keyword stops at either := or an index [] // TODO should check that = follows : to allow keywords with colons in there - const string::size_type eok = line.find_first_of(":[",0); - return line.substr(0,eok); + const string::size_type eok = line.find_first_of(":[", 0); + return line.substr(0, eok); } -map_element* KeyParser::find_in_keymap(const string& keyword) -{ - for (Keymap::iterator iter = kmap.begin(); - iter != kmap.end(); - ++iter) - { - if (iter->first == keyword) - return &(iter->second); +map_element* +KeyParser::find_in_keymap(const string& keyword) { + for (Keymap::iterator iter = kmap.begin(); iter != kmap.end(); ++iter) { + if (iter->first == keyword) + return &(iter->second); } // it wasn't there return 0; } bool -KeyParser::remove_key(const string& keyword) -{ - for (Keymap::iterator iter = kmap.begin(); - iter != kmap.end(); - ++iter) - { - if (iter->first == keyword) - { - kmap.erase(iter); - return true; - } +KeyParser::remove_key(const string& keyword) { + for (Keymap::iterator iter = kmap.begin(); iter != kmap.end(); ++iter) { + if (iter->first == keyword) { + kmap.erase(iter); + return true; + } } // it wasn't there return false; } -void -KeyParser::add_in_keymap(const string& keyword, const map_element& new_element) -{ +void +KeyParser::add_in_keymap(const string& keyword, const map_element& new_element) { const string standardised_keyword = standardise_keyword(keyword); - map_element * elem_ptr = find_in_keymap(standardised_keyword); - if (elem_ptr != 0) - { + map_element* elem_ptr = find_in_keymap(standardised_keyword); + if (elem_ptr != 0) { warning(boost::format("KeyParser: keyword '%s' already registered for parsing, overwriting previous value") % keyword); *elem_ptr = new_element; - } - else - kmap.push_back(pair(standardised_keyword, new_element)); + } else + kmap.push_back(pair(standardised_keyword, new_element)); } void -KeyParser::add_key(const string& keyword, float * variable) - { - add_key(keyword, KeyArgument::FLOAT, variable); - } +KeyParser::add_key(const string& keyword, float* variable) { + add_key(keyword, KeyArgument::FLOAT, variable); +} void -KeyParser::add_vectorised_key(const string& keyword, vector * variable) - { - add_key(keyword, KeyArgument::FLOAT, variable, 1); - } +KeyParser::add_vectorised_key(const string& keyword, vector* variable) { + add_key(keyword, KeyArgument::FLOAT, variable, 1); +} void -KeyParser::add_key(const string& keyword, double * variable) - { - add_key(keyword, KeyArgument::DOUBLE, variable); - } +KeyParser::add_key(const string& keyword, double* variable) { + add_key(keyword, KeyArgument::DOUBLE, variable); +} void -KeyParser::add_vectorised_key(const string& keyword, vector * variable) - { - add_key(keyword, KeyArgument::DOUBLE, variable, 1); - } +KeyParser::add_vectorised_key(const string& keyword, vector* variable) { + add_key(keyword, KeyArgument::DOUBLE, variable, 1); +} void -KeyParser::add_vectorised_key(const string& keyword, vector > * variable) - { - add_key(keyword, KeyArgument::LIST_OF_DOUBLES, variable, 1); - } +KeyParser::add_vectorised_key(const string& keyword, vector>* variable) { + add_key(keyword, KeyArgument::LIST_OF_DOUBLES, variable, 1); +} void -KeyParser::add_key(const string& keyword, int * variable) - { - add_key(keyword, KeyArgument::INT, variable); - } +KeyParser::add_key(const string& keyword, int* variable) { + add_key(keyword, KeyArgument::INT, variable); +} void -KeyParser::add_key(const string& keyword, vector * variable) - { - add_key(keyword, KeyArgument::LIST_OF_INTS, variable); - } +KeyParser::add_key(const string& keyword, vector* variable) { + add_key(keyword, KeyArgument::LIST_OF_INTS, variable); +} void -KeyParser::add_vectorised_key(const string& keyword, vector * variable) - { - add_key(keyword, KeyArgument::INT, variable, 1); - } +KeyParser::add_vectorised_key(const string& keyword, vector* variable) { + add_key(keyword, KeyArgument::INT, variable, 1); +} void -KeyParser::add_vectorised_key(const string& keyword, vector > * variable) - { - add_key(keyword, KeyArgument::LIST_OF_INTS, variable, 1); - } +KeyParser::add_vectorised_key(const string& keyword, vector>* variable) { + add_key(keyword, KeyArgument::LIST_OF_INTS, variable, 1); +} void -KeyParser::add_key(const string& keyword, unsigned int * variable) - { - add_key(keyword, KeyArgument::UINT, variable); - } +KeyParser::add_key(const string& keyword, unsigned int* variable) { + add_key(keyword, KeyArgument::UINT, variable); +} void -KeyParser::add_vectorised_key(const string& keyword, vector * variable) - { - add_key(keyword, KeyArgument::UINT, variable, 1); - } +KeyParser::add_vectorised_key(const string& keyword, vector* variable) { + add_key(keyword, KeyArgument::UINT, variable, 1); +} void -KeyParser::add_key(const string& keyword, long int * variable) - { - add_key(keyword, KeyArgument::LONG, variable); - } +KeyParser::add_key(const string& keyword, long int* variable) { + add_key(keyword, KeyArgument::LONG, variable); +} void -KeyParser::add_key(const string& keyword, unsigned long * variable) - { - add_key(keyword, KeyArgument::ULONG, variable); - } +KeyParser::add_key(const string& keyword, unsigned long* variable) { + add_key(keyword, KeyArgument::ULONG, variable); +} void -KeyParser::add_vectorised_key(const string& keyword, vector * variable) - { - add_key(keyword, KeyArgument::ULONG, variable, 1); - } +KeyParser::add_vectorised_key(const string& keyword, vector* variable) { + add_key(keyword, KeyArgument::ULONG, variable, 1); +} void -KeyParser::add_key(const string& keyword, bool * variable) - { - add_key(keyword, KeyArgument::BOOL, variable); - } +KeyParser::add_key(const string& keyword, bool* variable) { + add_key(keyword, KeyArgument::BOOL, variable); +} void -KeyParser::add_key(const string& keyword, vector* variable) - { - add_key(keyword, KeyArgument::LIST_OF_DOUBLES, variable); - } +KeyParser::add_key(const string& keyword, vector* variable) { + add_key(keyword, KeyArgument::LIST_OF_DOUBLES, variable); +} void -KeyParser::add_key(const string& keyword, vector* variable) - { - add_key(keyword, KeyArgument::LIST_OF_ASCII, variable); - } +KeyParser::add_key(const string& keyword, vector* variable) { + add_key(keyword, KeyArgument::LIST_OF_ASCII, variable); +} void -KeyParser::add_key(const string& keyword, Array<2,float>* variable) - { - add_key(keyword, KeyArgument::ARRAY2D_OF_FLOATS, variable); - } +KeyParser::add_key(const string& keyword, Array<2, float>* variable) { + add_key(keyword, KeyArgument::ARRAY2D_OF_FLOATS, variable); +} void -KeyParser::add_key(const string& keyword, Array<3,float>* variable) - { - add_key(keyword, KeyArgument::ARRAY3D_OF_FLOATS, variable); - } +KeyParser::add_key(const string& keyword, Array<3, float>* variable) { + add_key(keyword, KeyArgument::ARRAY3D_OF_FLOATS, variable); +} void -KeyParser::add_key(const string& keyword, BasicCoordinate<3,float>* variable) - { - add_key(keyword, KeyArgument::BASICCOORDINATE3D_OF_FLOATS, variable); - } +KeyParser::add_key(const string& keyword, BasicCoordinate<3, float>* variable) { + add_key(keyword, KeyArgument::BASICCOORDINATE3D_OF_FLOATS, variable); +} void -KeyParser::add_key(const string& keyword, BasicCoordinate<3,Array<3,float> >* variable) - { - add_key(keyword, KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS, variable); - } +KeyParser::add_key(const string& keyword, BasicCoordinate<3, Array<3, float>>* variable) { + add_key(keyword, KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS, variable); +} void -KeyParser::add_key(const string& keyword, string * variable) - { - add_key(keyword, KeyArgument::ASCII, variable); - } - +KeyParser::add_key(const string& keyword, string* variable) { + add_key(keyword, KeyArgument::ASCII, variable); +} void -KeyParser::add_vectorised_key(const string& keyword, vector * variable) - { - add_key(keyword, KeyArgument::ASCII, variable, 1); - } +KeyParser::add_vectorised_key(const string& keyword, vector* variable) { + add_key(keyword, KeyArgument::ASCII, variable, 1); +} void -KeyParser::add_key(const string& keyword, int * variable, - const ASCIIlist_type * list_of_values_ptr) - { - add_key(keyword, KeyArgument::ASCIIlist, variable, list_of_values_ptr); - } - +KeyParser::add_key(const string& keyword, int* variable, const ASCIIlist_type* list_of_values_ptr) { + add_key(keyword, KeyArgument::ASCIIlist, variable, list_of_values_ptr); +} + void -KeyParser::ignore_key(const string& keyword) - { - add_key(keyword, KeyArgument::NONE, &KeyParser::do_nothing); - } +KeyParser::ignore_key(const string& keyword) { + add_key(keyword, KeyArgument::NONE, &KeyParser::do_nothing); +} void -KeyParser::add_start_key(const string& keyword) - { - add_key(keyword, KeyArgument::NONE, &KeyParser::start_parsing); - } +KeyParser::add_start_key(const string& keyword) { + add_key(keyword, KeyArgument::NONE, &KeyParser::start_parsing); +} void -KeyParser::add_stop_key(const string& keyword) - { - add_key(keyword, KeyArgument::NONE, &KeyParser::stop_parsing); - } - - - +KeyParser::add_stop_key(const string& keyword) { + add_key(keyword, KeyArgument::NONE, &KeyParser::stop_parsing); +} -void KeyParser::add_key(const string& keyword, - KeyArgument::type t, - KeywordProcessor function, - void* variable, - const ASCIIlist_type * const list_of_values) -{ +void +KeyParser::add_key(const string& keyword, KeyArgument::type t, KeywordProcessor function, void* variable, + const ASCIIlist_type* const list_of_values) { add_in_keymap(keyword, map_element(t, function, variable, 0, list_of_values)); } -void KeyParser::add_key(const string& keyword, - KeyArgument::type t, - KeywordProcessor function, - void* variable, - const int vectorised_key_level, - const ASCIIlist_type * const list_of_values) -{ +void +KeyParser::add_key(const string& keyword, KeyArgument::type t, KeywordProcessor function, void* variable, + const int vectorised_key_level, const ASCIIlist_type* const list_of_values) { add_in_keymap(keyword, map_element(t, function, variable, vectorised_key_level, list_of_values)); } -void KeyParser::add_key(const string& keyword, - KeyArgument::type t, - void* variable, - const ASCIIlist_type * const list_of_values) -{ +void +KeyParser::add_key(const string& keyword, KeyArgument::type t, void* variable, const ASCIIlist_type* const list_of_values) { add_in_keymap(keyword, map_element(t, &KeyParser::set_variable, variable, 0, list_of_values)); } -void KeyParser::add_key(const string& keyword, - KeyArgument::type t, - void* variable, - const int vectorised_key_level, - const ASCIIlist_type * const list_of_values) -{ +void +KeyParser::add_key(const string& keyword, KeyArgument::type t, void* variable, const int vectorised_key_level, + const ASCIIlist_type* const list_of_values) { add_in_keymap(keyword, map_element(t, &KeyParser::set_variable, variable, vectorised_key_level, list_of_values)); } - void -KeyParser::print_keywords_to_stream(ostream& out) const -{ - for (Keymap::const_iterator key = kmap.begin(); key != kmap.end(); ++key) - { +KeyParser::print_keywords_to_stream(ostream& out) const { + for (Keymap::const_iterator key = kmap.begin(); key != kmap.end(); ++key) { out << key->first << '\n'; } out << endl; } - -Succeeded KeyParser::parse_header(const bool write_warning) -{ - - if (read_and_parse_line(false) == Succeeded::yes) +Succeeded +KeyParser::parse_header(const bool write_warning) { + + if (read_and_parse_line(false) == Succeeded::yes) process_key(); - if (status != parsing) - { + if (status != parsing) { // something's wrong. We're finding data, but we're not supposed to be // parsing. We'll exit with an error, but first write a warning. // The warning will say that we miss the "start parsing" keyword (if we can find it in the map) // find starting keyword string start_keyword; - for (Keymap::const_iterator i=kmap.begin(); i!= kmap.end(); ++i) - { + for (Keymap::const_iterator i = kmap.begin(); i != kmap.end(); ++i) { if (i->second.p_object_member == &KeyParser::start_parsing) - start_keyword = i->first; - } - if (start_keyword.length()>0) - { - warning("KeyParser error: required first keyword \"%s\" not found\n", - start_keyword.c_str()); + start_keyword = i->first; } - else - { - // there doesn't seem to be a start_parsing keyword, so we cannot include it - // in the warning. (it could be a side-effect of another key, so we're + if (start_keyword.length() > 0) { + warning("KeyParser error: required first keyword \"%s\" not found\n", start_keyword.c_str()); + } else { + // there doesn't seem to be a start_parsing keyword, so we cannot include it + // in the warning. (it could be a side-effect of another key, so we're // not sure if the map is correct or not) warning("KeyParser error: data found, but KeyParser status is \"not parsing\". Keymap possibly incorrect"); } - return Succeeded::no; + return Succeeded::no; } - while(status==parsing) - { - if(read_and_parse_line(write_warning) == Succeeded::yes) - process_key(); - if (input->eof()) { - status = end_parsing; - } + while (status == parsing) { + if (read_and_parse_line(write_warning) == Succeeded::yes) + process_key(); + if (input->eof()) { + status = end_parsing; + } } - - + return Succeeded::yes; - -} +} -Succeeded KeyParser::read_and_parse_line(const bool write_warning) -{ - string line; +Succeeded +KeyParser::read_and_parse_line(const bool write_warning) { + string line; // we keep reading a line until it's either non-empty, or we're at the end of the input - while (true) - { - if (!input->good()) - { - warning("KeyParser warning: early EOF or bad file"); - stop_parsing(); - return Succeeded::no; - } - - read_line(*input, line); - // check if only white-space, if not, get out of the loop to continue - std::size_t pos = line.find_first_not_of(" \t"); - if ( pos != string::npos) - break; - // check if empty line - if (line.size() == 0) - break; + while (true) { + if (!input->good()) { + warning("KeyParser warning: early EOF or bad file"); + stop_parsing(); + return Succeeded::no; } + read_line(*input, line); + // check if only white-space, if not, get out of the loop to continue + std::size_t pos = line.find_first_not_of(" \t"); + if (pos != string::npos) + break; + // check if empty line + if (line.size() == 0) + break; + } + // gets keyword - keyword=standardise_keyword(get_keyword(line)); + keyword = standardise_keyword(get_keyword(line)); return parse_value_in_line(line, write_warning); } - // functions that get arbitrary type parameters from a string (after '=') // unfortunately, the string type needs special case as istream::operator>> stops a string at white space // we also do special things for vectors // they all return Succeeded::yes when there was a parameter template -static -Succeeded -get_param_from_string(T& param, const string& s) -{ - const string::size_type cp=s.find('=',0); - if(cp==string::npos) +static Succeeded +get_param_from_string(T& param, const string& s) { + const string::size_type cp = s.find('=', 0); + if (cp == string::npos) return Succeeded::no; - istrstream str(s.c_str()+cp+1); + istrstream str(s.c_str() + cp + 1); str >> param; return str.fail() ? Succeeded::no : Succeeded::yes; } template <> Succeeded -get_param_from_string(string& param, const string& s) -{ - const string::size_type cp = s.find('=',0); - if(cp!=string::npos) - { +get_param_from_string(string& param, const string& s) { + const string::size_type cp = s.find('=', 0); + if (cp != string::npos) { // skip starting white space - const string::size_type sok=s.find_first_not_of(" \t",cp+1); // KT 07/10/2002 now also skips tabs - if(sok!=string::npos) - { + const string::size_type sok = s.find_first_not_of(" \t", cp + 1); // KT 07/10/2002 now also skips tabs + if (sok != string::npos) { // strip trailing white space - const string::size_type eok=s.find_last_not_of(" \t",s.length()); - param=s.substr(sok,eok-sok+1); + const string::size_type eok = s.find_last_not_of(" \t", s.length()); + param = s.substr(sok, eok - sok + 1); return Succeeded::yes; } } @@ -697,23 +560,18 @@ get_param_from_string(string& param, const string& s) // this is currently only used for the matrix_size keywords in InterfileHeader. template -static -Succeeded -get_vparam_from_string(vector& param, const string& s) -{ - const string::size_type cp = s.find('=',0); - if(cp!=string::npos) - { +static Succeeded +get_vparam_from_string(vector& param, const string& s) { + const string::size_type cp = s.find('=', 0); + if (cp != string::npos) { // skip starting white space - const string::size_type start=s.find_first_not_of(" \t",cp+1); // KT 07/10/2002 now also skips tabs - if(start!=string::npos) - { - istrstream str(s.c_str()+start); - + const string::size_type start = s.find_first_not_of(" \t", cp + 1); // KT 07/10/2002 now also skips tabs + if (start != string::npos) { + istrstream str(s.c_str() + start); + if (s[start] == '{') str >> param; - else - { + else { param.resize(1); str >> param[0]; } @@ -724,25 +582,20 @@ get_vparam_from_string(vector& param, const string& s) } template -static -Succeeded -get_vparam_from_string(VectorWithOffset& param, const string& s) -{ - const string::size_type cp = s.find('=',0); - if(cp!=string::npos) - { +static Succeeded +get_vparam_from_string(VectorWithOffset& param, const string& s) { + const string::size_type cp = s.find('=', 0); + if (cp != string::npos) { // skip starting white space - const string::size_type start=s.find_first_not_of(" \t",cp+1); // KT 07/10/2002 now also skips tabs - if(start!=string::npos) - { - istrstream str(s.c_str()+start); - + const string::size_type start = s.find_first_not_of(" \t", cp + 1); // KT 07/10/2002 now also skips tabs + if (start != string::npos) { + istrstream str(s.c_str() + start); + if (s[start] == '{') str >> param; - else - { + else { param = VectorWithOffset(); // TODO will NOT work with multi-dimensional arrays - param.grow(0,0); + param.grow(0, 0); str >> param[0]; } return str.fail() ? Succeeded::no : Succeeded::yes; @@ -754,47 +607,36 @@ get_vparam_from_string(VectorWithOffset& param, const string& s) // vectors of strings are also special as we need to split the string up if there are commas template <> Succeeded -get_vparam_from_string(vector& param, const string& s) -{ - string::size_type cp = s.find('=',0); - if(cp!=string::npos) - { +get_vparam_from_string(vector& param, const string& s) { + string::size_type cp = s.find('=', 0); + if (cp != string::npos) { // skip starting white space - const string::size_type start=s.find_first_not_of(" \t",cp+1); // KT 07/10/2002 now also skips tabs - if(start!=string::npos) - { - if (s[start] == '{') - { - bool end=false; - cp = start+1; - while (!end) - { - cp=s.find_first_not_of("},",cp); - cp=s.find_first_not_of(" \t",cp); - - if(cp==string::npos) - { - end=true; - } - else - { - string::size_type eop=s.find_first_of(",}",cp); - if(eop==string::npos) - { - end=true; - eop=s.length(); + const string::size_type start = s.find_first_not_of(" \t", cp + 1); // KT 07/10/2002 now also skips tabs + if (start != string::npos) { + if (s[start] == '{') { + bool end = false; + cp = start + 1; + while (!end) { + cp = s.find_first_not_of("},", cp); + cp = s.find_first_not_of(" \t", cp); + + if (cp == string::npos) { + end = true; + } else { + string::size_type eop = s.find_first_of(",}", cp); + if (eop == string::npos) { + end = true; + eop = s.length(); } // trim ending white space - const string::size_type eop2 = s.find_last_not_of(" \t",eop); - param.push_back(s.substr(cp,eop2-cp)); - cp=eop+1; + const string::size_type eop2 = s.find_last_not_of(" \t", eop); + param.push_back(s.substr(cp, eop2 - cp)); + cp = eop + 1; } } - } - else - { - param.resize(1); - param[0] = s.substr(start, s.find_last_not_of(" \t",s.size())); + } else { + param.resize(1); + param[0] = s.substr(start, s.find_last_not_of(" \t", s.size())); } return Succeeded::yes; } @@ -803,26 +645,23 @@ get_vparam_from_string(vector& param, const string& s) } // function that finds the current_index. work to do here! -static int get_index(const string& line) -{ +static int +get_index(const string& line) { // we take 0 as a default value for the index - int in=0; + int in = 0; // make sure that the index is part of the key (i.e. before :=) - const string::size_type cp=line.find_first_of(":[",0); - if(cp!=string::npos && line[cp] == '[') - { - const string::size_type sok=cp+1; - const string::size_type eok=line.find_first_of(']',cp); + const string::size_type cp = line.find_first_of(":[", 0); + if (cp != string::npos && line[cp] == '[') { + const string::size_type sok = cp + 1; + const string::size_type eok = line.find_first_of(']', cp); // check if closing bracket really there - if (eok == string::npos) - { + if (eok == string::npos) { // TODO do something more graceful - warning("Interfile warning: invalid vectorised key in line \n'%s'.\n%s", - line.c_str(), - "Assuming this is not a vectorised key."); + warning("Interfile warning: invalid vectorised key in line \n'%s'.\n%s", line.c_str(), + "Assuming this is not a vectorised key."); return 0; } - in=atoi(line.substr(sok,eok-sok).c_str()); + in = atoi(line.substr(sok, eok - sok).c_str()); } return in; } @@ -831,113 +670,93 @@ static int get_index(const string& line) // this class comes from "Modern C++ Design" by Andrei Alexandrescu template -struct Type2Type -{ +struct Type2Type { typedef T type; }; template -static -Succeeded -get_any_param_from_string(boost::any& parameter, Type2Type, const string& s) -{ +static Succeeded +get_any_param_from_string(boost::any& parameter, Type2Type, const string& s) { parameter = T(); // note: don't use cast to reference as it might break VC 6.0 - return - get_param_from_string(*boost::any_cast(¶meter), s); + return get_param_from_string(*boost::any_cast(¶meter), s); } template -static -Succeeded -get_any_vparam_from_string(boost::any& parameter, Type2Type, const string& s) -{ +static Succeeded +get_any_vparam_from_string(boost::any& parameter, Type2Type, const string& s) { parameter = T(); // note: don't use cast to reference as it might break VC 6.0 - return - get_vparam_from_string(*boost::any_cast(¶meter), s); + return get_vparam_from_string(*boost::any_cast(¶meter), s); } -Succeeded KeyParser::parse_value_in_line(const string& line, const bool write_warning) -{ +Succeeded +KeyParser::parse_value_in_line(const string& line, const bool write_warning) { // KT 07/10/2002 use return value of get_param to detect if a value was present at all - current_index=get_index(line); - + current_index = get_index(line); + // maps keyword to appropriate map_element (sets current) - if(map_keyword(keyword)==Succeeded::yes) - { - switch(current->type) // depending on the par_type, gets the correct value from the line - { // and sets the right temporary variable - case KeyArgument::NONE : + if (map_keyword(keyword) == Succeeded::yes) { + switch (current->type) // depending on the par_type, gets the correct value from the line + { // and sets the right temporary variable + case KeyArgument::NONE: keyword_has_a_value = false; break; - case KeyArgument::ASCII : - case KeyArgument::ASCIIlist : + case KeyArgument::ASCII: + case KeyArgument::ASCIIlist: // KT 07/02/2001 new case KeyArgument::PARSINGOBJECT: case KeyArgument::SHARED_PARSINGOBJECT: - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; + keyword_has_a_value = get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; break; - case KeyArgument::INT : - case KeyArgument::BOOL : - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; + case KeyArgument::INT: + case KeyArgument::BOOL: + keyword_has_a_value = get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; break; - case KeyArgument::UINT : - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; + case KeyArgument::UINT: + keyword_has_a_value = get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; break; - case KeyArgument::ULONG : - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; - break; - case KeyArgument::LONG : - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; + case KeyArgument::ULONG: + keyword_has_a_value = get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; break; - case KeyArgument::DOUBLE : - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; + case KeyArgument::LONG: + keyword_has_a_value = get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; break; - case KeyArgument::FLOAT : - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; + case KeyArgument::DOUBLE: + keyword_has_a_value = get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; break; - case KeyArgument::LIST_OF_INTS : - keyword_has_a_value = - get_any_vparam_from_string(this->parameter, Type2Type >(), line) == Succeeded::yes; + case KeyArgument::FLOAT: + keyword_has_a_value = get_any_param_from_string(this->parameter, Type2Type(), line) == Succeeded::yes; break; - case KeyArgument::LIST_OF_DOUBLES : - keyword_has_a_value = - get_any_vparam_from_string(this->parameter, Type2Type >(), line) == Succeeded::yes; + case KeyArgument::LIST_OF_INTS: + keyword_has_a_value = get_any_vparam_from_string(this->parameter, Type2Type>(), line) == Succeeded::yes; break; - case KeyArgument::LIST_OF_ASCII : + case KeyArgument::LIST_OF_DOUBLES: + keyword_has_a_value = get_any_vparam_from_string(this->parameter, Type2Type>(), line) == Succeeded::yes; + break; + case KeyArgument::LIST_OF_ASCII: // TODO enforce {} by writing get_param_from_string for vector - keyword_has_a_value = - get_any_vparam_from_string(this->parameter, Type2Type >(), line) == Succeeded::yes; + keyword_has_a_value = + get_any_vparam_from_string(this->parameter, Type2Type>(), line) == Succeeded::yes; break; case KeyArgument::ARRAY2D_OF_FLOATS: - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type >(), line) == Succeeded::yes; + keyword_has_a_value = get_any_param_from_string(this->parameter, Type2Type>(), line) == Succeeded::yes; break; case KeyArgument::ARRAY3D_OF_FLOATS: - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type >(), line) == Succeeded::yes; + keyword_has_a_value = get_any_param_from_string(this->parameter, Type2Type>(), line) == Succeeded::yes; break; case KeyArgument::BASICCOORDINATE3D_OF_FLOATS: - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type >(), line) == Succeeded::yes; + keyword_has_a_value = + get_any_param_from_string(this->parameter, Type2Type>(), line) == Succeeded::yes; break; case KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS: - keyword_has_a_value = - get_any_param_from_string(this->parameter, Type2Type > >(), line) == Succeeded::yes; + keyword_has_a_value = + get_any_param_from_string(this->parameter, Type2Type>>(), line) == Succeeded::yes; break; - default : + default: // KT 07/10/2002 now exit with error - error ("KeyParser internal error: keyword '%s' has unsupported type of parameters\n", - keyword.c_str()); - return Succeeded::no; // just a line to avoid compiler warnings + error("KeyParser internal error: keyword '%s' has unsupported type of parameters\n", keyword.c_str()); + return Succeeded::no; // just a line to avoid compiler warnings } return Succeeded::yes; } @@ -950,443 +769,406 @@ Succeeded KeyParser::parse_value_in_line(const string& line, const bool write_wa return Succeeded::no; } -void KeyParser::start_parsing() -{ - status=parsing; +void +KeyParser::start_parsing() { + status = parsing; } -void KeyParser::stop_parsing() -{ - status=end_parsing; +void +KeyParser::stop_parsing() { + status = end_parsing; } // KT 07/02/2001 new -void KeyParser::set_parsing_object() -{ +void +KeyParser::set_parsing_object() { // KT 07/10/2002 new if (!keyword_has_a_value) return; // TODO this does not handle the vectorised key convention - + // current_index is set to 0 when there was no index - if(current_index!=0) + if (current_index != 0) error("KeyParser::PARSINGOBJECT can't handle vectorised keys yet\n"); const std::string& par_ascii = *boost::any_cast(&this->parameter); - *reinterpret_cast(current->p_object_variable) = - (*current->parser)(input, par_ascii); + *reinterpret_cast(current->p_object_variable) = (*current->parser)(input, par_ascii); } - // KT 20/08/2001 new -void KeyParser::set_shared_parsing_object() -{ +void +KeyParser::set_shared_parsing_object() { // KT 07/10/2002 new if (!keyword_has_a_value) return; - + // TODO this does not handle the vectorised key convention - + // current_index is set to 0 when there was no index - if(current_index!=0) + if (current_index != 0) error("KeyParser::SHARED_PARSINGOBJECT can't handle vectorised keys yet"); const std::string& par_ascii = *boost::any_cast(&this->parameter); - reinterpret_cast *>(current->p_object_variable)-> - reset((*current->parser)(input, par_ascii)); + reinterpret_cast*>(current->p_object_variable)->reset((*current->parser)(input, par_ascii)); } // local function to be used in set_variable below template -void static -assign_to_list(T1& mylist, const T2& value, const int current_index, - const string& keyword) -{ - if(mylist.size() < static_cast(current_index)) - { - error("KeyParser: the list corresponding to the keyword \"%s\" has to be resized " - "to size %d. This means you have a problem in the keyword values.", - keyword.c_str(), current_index); - // mylist.resize(current_index); - } - mylist[current_index-1] = value; +void static assign_to_list(T1& mylist, const T2& value, const int current_index, const string& keyword) { + if (mylist.size() < static_cast(current_index)) { + error("KeyParser: the list corresponding to the keyword \"%s\" has to be resized " + "to size %d. This means you have a problem in the keyword values.", + keyword.c_str(), current_index); + // mylist.resize(current_index); + } + mylist[current_index - 1] = value; } -void KeyParser::set_variable() -{ +void +KeyParser::set_variable() { if (!keyword_has_a_value) return; // TODO this does not handle the vectorised key convention - + // current_index is set to 0 when there was no index - if(!current_index) - { - if (current->vectorised_key_level>0) - error(boost::format("Error parsing: expected a vectorised key as in \"%1%[1]\", but no bracket found") % keyword); - - switch(current->type) - { -#define KP_case_assign(KeyArgumentValue, type) \ - case KeyArgumentValue : \ - *reinterpret_cast(current->p_object_variable) = \ - * boost::any_cast(&this->parameter); break - - case KeyArgument::BOOL : - { - const int par_int = * boost::any_cast(¶meter); - if (par_int !=0 && par_int != 1) - warning("KeyParser: keyword %s expects a bool value which should be 0 or 1\n" - " (actual value is %d). A non-zero value will be assumed to mean 'true'\n", - keyword.c_str(), par_int); - bool* p_bool=(bool*)current->p_object_variable; // performs the required casting - *p_bool=par_int != 0; - break; - } - KP_case_assign(KeyArgument::INT, int); - KP_case_assign(KeyArgument::UINT, unsigned int); - KP_case_assign(KeyArgument::ULONG,unsigned long); - KP_case_assign(KeyArgument::LONG,long); - KP_case_assign(KeyArgument::DOUBLE,double); - KP_case_assign(KeyArgument::FLOAT,float); - KP_case_assign(KeyArgument::ASCII, std::string); - - case KeyArgument::ASCIIlist : - { - const std::string& par_ascii = *boost::any_cast(&this->parameter); - const int index = - find_in_ASCIIlist(par_ascii, *(current->p_object_list_of_values)); - *((int *)current->p_object_variable) = index; - if (index == -1) - { - // it was not in the list - // TODO we should use warning() instead - cerr << "KeyParser warning : value of keyword \"" - << keyword << "\" is \"" - << par_ascii - << "\"\n\tshould have been one of:"; - for (unsigned int i=0; ip_object_list_of_values->size(); i++) - cerr << "\n\t" << (*current->p_object_list_of_values)[i]; - cerr << '\n' << endl; - } - break; - } - KP_case_assign(KeyArgument::LIST_OF_INTS, IntVect); - KP_case_assign(KeyArgument::LIST_OF_DOUBLES, DoubleVect); - // sigh... macro expansion fails of type contain commas.... - // Work-around: use typedefs. - typedef Array<2,float> KP_array2d; - typedef Array<3,float> KP_array3d; - typedef BasicCoordinate<3,float> KP_coord; - typedef BasicCoordinate<3,Array<3,float> > KP_coord_array3d; - KP_case_assign(KeyArgument::ARRAY2D_OF_FLOATS, KP_array2d); - KP_case_assign(KeyArgument::ARRAY3D_OF_FLOATS, KP_array3d); - KP_case_assign(KeyArgument::BASICCOORDINATE3D_OF_FLOATS, KP_coord); - KP_case_assign(KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS,KP_coord_array3d); - KP_case_assign(KeyArgument::LIST_OF_ASCII, std::vector); - default : - warning("KeyParser error: unknown type. Implementation error"); - break; - } -#undef KP_case_assign + if (!current_index) { + if (current->vectorised_key_level > 0) + error(boost::format("Error parsing: expected a vectorised key as in \"%1%[1]\", but no bracket found") % keyword); + + switch (current->type) { +#define KP_case_assign(KeyArgumentValue, type) \ + case KeyArgumentValue: \ + *reinterpret_cast(current->p_object_variable) = *boost::any_cast(&this->parameter); \ + break + + case KeyArgument::BOOL: { + const int par_int = *boost::any_cast(¶meter); + if (par_int != 0 && par_int != 1) + warning("KeyParser: keyword %s expects a bool value which should be 0 or 1\n" + " (actual value is %d). A non-zero value will be assumed to mean 'true'\n", + keyword.c_str(), par_int); + bool* p_bool = (bool*)current->p_object_variable; // performs the required casting + *p_bool = par_int != 0; + break; + } + KP_case_assign(KeyArgument::INT, int); + KP_case_assign(KeyArgument::UINT, unsigned int); + KP_case_assign(KeyArgument::ULONG, unsigned long); + KP_case_assign(KeyArgument::LONG, long); + KP_case_assign(KeyArgument::DOUBLE, double); + KP_case_assign(KeyArgument::FLOAT, float); + KP_case_assign(KeyArgument::ASCII, std::string); + + case KeyArgument::ASCIIlist: { + const std::string& par_ascii = *boost::any_cast(&this->parameter); + const int index = find_in_ASCIIlist(par_ascii, *(current->p_object_list_of_values)); + *((int*)current->p_object_variable) = index; + if (index == -1) { + // it was not in the list + // TODO we should use warning() instead + cerr << "KeyParser warning : value of keyword \"" << keyword << "\" is \"" << par_ascii + << "\"\n\tshould have been one of:"; + for (unsigned int i = 0; i < current->p_object_list_of_values->size(); i++) + cerr << "\n\t" << (*current->p_object_list_of_values)[i]; + cerr << '\n' << endl; + } + break; + } + KP_case_assign(KeyArgument::LIST_OF_INTS, IntVect); + KP_case_assign(KeyArgument::LIST_OF_DOUBLES, DoubleVect); + // sigh... macro expansion fails of type contain commas.... + // Work-around: use typedefs. + typedef Array<2, float> KP_array2d; + typedef Array<3, float> KP_array3d; + typedef BasicCoordinate<3, float> KP_coord; + typedef BasicCoordinate<3, Array<3, float>> KP_coord_array3d; + KP_case_assign(KeyArgument::ARRAY2D_OF_FLOATS, KP_array2d); + KP_case_assign(KeyArgument::ARRAY3D_OF_FLOATS, KP_array3d); + KP_case_assign(KeyArgument::BASICCOORDINATE3D_OF_FLOATS, KP_coord); + KP_case_assign(KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS, KP_coord_array3d); + KP_case_assign(KeyArgument::LIST_OF_ASCII, std::vector); + default: + warning("KeyParser error: unknown type. Implementation error"); + break; } - else // Sets vector elements using current_index - { - if (current->vectorised_key_level==0) - error(boost::format("Error parsing: encountered unexpected \"vectorisation\" of key: \"%1%[%2%]\"") % keyword % current_index); - - switch(current->type) - { -#define KP_case_assign(KeyArgumentValue, type) \ - case KeyArgumentValue : \ - assign_to_list(*reinterpret_cast *>(current->p_object_variable), \ - * boost::any_cast(&this->parameter), current_index, keyword); \ - break - - KP_case_assign(KeyArgument::INT, int); - KP_case_assign(KeyArgument::UINT,unsigned int); - KP_case_assign(KeyArgument::LONG,long); - KP_case_assign(KeyArgument::ULONG,unsigned long); - KP_case_assign(KeyArgument::DOUBLE,double); - KP_case_assign(KeyArgument::FLOAT,float); - KP_case_assign(KeyArgument::ASCII, std::string); - case KeyArgument::ASCIIlist : - { - const std::string& par_ascii = *boost::any_cast(&this->parameter); - const int index_in_asciilist = - find_in_ASCIIlist(par_ascii, *(current->p_object_list_of_values)); - assign_to_list(*(IntVect*)current->p_object_variable, - index_in_asciilist, current_index, keyword); - if (index_in_asciilist == -1) - { - // it was not in the list - // TODO we should use warning() instead - cerr << "KeyParser warning : value of keyword \"" - << keyword << "\" is \"" - << par_ascii - << "\"\n\tshould have been one of:"; - for (unsigned int i=0; ip_object_list_of_values->size(); i++) - cerr << "\n\t" << (*current->p_object_list_of_values)[i]; - } - break; - } - KP_case_assign(KeyArgument::LIST_OF_INTS, IntVect); - KP_case_assign(KeyArgument::LIST_OF_DOUBLES, DoubleVect); - default : - - warning("KeyParser error: unknown type. Implementation error"); - break; - } #undef KP_case_assign + } else // Sets vector elements using current_index + { + if (current->vectorised_key_level == 0) + error(boost::format("Error parsing: encountered unexpected \"vectorisation\" of key: \"%1%[%2%]\"") % keyword % + current_index); + + switch (current->type) { +#define KP_case_assign(KeyArgumentValue, type) \ + case KeyArgumentValue: \ + assign_to_list(*reinterpret_cast*>(current->p_object_variable), *boost::any_cast(&this->parameter), \ + current_index, keyword); \ + break + + KP_case_assign(KeyArgument::INT, int); + KP_case_assign(KeyArgument::UINT, unsigned int); + KP_case_assign(KeyArgument::LONG, long); + KP_case_assign(KeyArgument::ULONG, unsigned long); + KP_case_assign(KeyArgument::DOUBLE, double); + KP_case_assign(KeyArgument::FLOAT, float); + KP_case_assign(KeyArgument::ASCII, std::string); + case KeyArgument::ASCIIlist: { + const std::string& par_ascii = *boost::any_cast(&this->parameter); + const int index_in_asciilist = find_in_ASCIIlist(par_ascii, *(current->p_object_list_of_values)); + assign_to_list(*(IntVect*)current->p_object_variable, index_in_asciilist, current_index, keyword); + if (index_in_asciilist == -1) { + // it was not in the list + // TODO we should use warning() instead + cerr << "KeyParser warning : value of keyword \"" << keyword << "\" is \"" << par_ascii + << "\"\n\tshould have been one of:"; + for (unsigned int i = 0; i < current->p_object_list_of_values->size(); i++) + cerr << "\n\t" << (*current->p_object_list_of_values)[i]; + } + break; + } + KP_case_assign(KeyArgument::LIST_OF_INTS, IntVect); + KP_case_assign(KeyArgument::LIST_OF_DOUBLES, DoubleVect); + default: + + warning("KeyParser error: unknown type. Implementation error"); + break; } +#undef KP_case_assign + } } -int KeyParser::find_in_ASCIIlist(const string& par_ascii, const ASCIIlist_type& list_of_values) -{ +int +KeyParser::find_in_ASCIIlist(const string& par_ascii, const ASCIIlist_type& list_of_values) { { // TODO, once we know for sure type of ASCIIlist_type, we could use STL find() - // TODO it would be more efficient to call standardise_keyword on the + // TODO it would be more efficient to call standardise_keyword on the // list_of_values in add_key() - for (unsigned int i=0; ip_object_member!=0) - { - (this->*(current->p_object_member))(); //calls appropriate member function + if (current->p_object_member != 0) { + (this->*(current->p_object_member))(); // calls appropriate member function } } -namespace detail -{ - /* A local helper function, essentially equivalent to operator<<(ostream&, const T& var). - However, it will insert \ characters in front of end-of-line. - This is used for types for which operator<< can result in multi-line strings. - If this is not fixed, it would mean that the output of parameter_info() is - not immediatelly suitable for parsing back. - Example: suppose there's a keyword that needs a 2d array. If at parsing we have - my array:={{1,2},{3}} - then parameter_info would give - my_array:={{1,2} - , {3} - } - and this would not follow standard syntax. When using the following function - in parameter_info(), the output will be - my_array:={{1,2}\ - , {3}\ - } - */ - template - static void to_stream(ostream& s, const T& var, const char continuation_char = '\\') - { - // we will first write everything to a temporary stringstream - // and then read it back, inserting the backslash +namespace detail { +/* A local helper function, essentially equivalent to operator<<(ostream&, const T& var). + However, it will insert \ characters in front of end-of-line. + This is used for types for which operator<< can result in multi-line strings. + If this is not fixed, it would mean that the output of parameter_info() is + not immediatelly suitable for parsing back. + Example: suppose there's a keyword that needs a 2d array. If at parsing we have + my array:={{1,2},{3}} + then parameter_info would give + my_array:={{1,2} + , {3} + } + and this would not follow standard syntax. When using the following function + in parameter_info(), the output will be + my_array:={{1,2}\ + , {3}\ + } +*/ +template +static void +to_stream(ostream& s, const T& var, const char continuation_char = '\\') { + // we will first write everything to a temporary stringstream + // and then read it back, inserting the backslash #ifdef BOOST_NO_STRINGSTREAM - // dangerous for out-of-range, but 'old-style' ostrstream seems to need this - char str[100000]; - strstream stemp(str, 100000); + // dangerous for out-of-range, but 'old-style' ostrstream seems to need this + char str[100000]; + strstream stemp(str, 100000); #else - std::stringstream stemp; + std::stringstream stemp; #endif - // write to stemp - stemp << var; - - // now read it back, character by character - while (true) - { - char c; - stemp.get(c); - if (!stemp) - break; - if (c == '\n') - s << continuation_char; // insert continuation character - s << c; - } + // write to stemp + stemp << var; + + // now read it back, character by character + while (true) { + char c; + stemp.get(c); + if (!stemp) + break; + if (c == '\n') + s << continuation_char; // insert continuation character + s << c; } } +} // namespace detail -string KeyParser::parameter_info() const -{ +string +KeyParser::parameter_info() const { #ifdef BOOST_NO_STRINGSTREAM - // dangerous for out-of-range, but 'old-style' ostrstream seems to need this - char str[100000]; - ostrstream s(str, 100000); + // dangerous for out-of-range, but 'old-style' ostrstream seems to need this + char str[100000]; + ostrstream s(str, 100000); #else - std::ostringstream s; + std::ostringstream s; #endif - // first find start key - for (Keymap::const_iterator i=kmap.begin(); i!= kmap.end(); ++i) - { - if (i->second.p_object_member == &KeyParser::start_parsing) + // first find start key + for (Keymap::const_iterator i = kmap.begin(); i != kmap.end(); ++i) { + if (i->second.p_object_member == &KeyParser::start_parsing) s << i->first << " :=\n"; - } + } - for (Keymap::const_iterator i=kmap.begin(); i!= kmap.end(); ++i) - { - if (i->second.p_object_member == &KeyParser::start_parsing || - i->second.p_object_member == &KeyParser::stop_parsing) - continue; - - if (i->second.vectorised_key_level > 0) - { - warning("KeyParser: cannot handle vectorised key yet");//TODO - continue; - } - s << i->first << " := "; - switch(i->second.type) - { - // TODO will break with vectorised keys - case KeyArgument::DOUBLE: - s << *reinterpret_cast(i->second.p_object_variable); break; - case KeyArgument::FLOAT: - s << *reinterpret_cast(i->second.p_object_variable); break; - case KeyArgument::INT: - s << *reinterpret_cast(i->second.p_object_variable); break; - case KeyArgument::BOOL: - s << (*reinterpret_cast(i->second.p_object_variable) ? 1 : 0); break; - case KeyArgument::UINT: - s << *reinterpret_cast(i->second.p_object_variable); break; - case KeyArgument::ULONG: - s << *reinterpret_cast(i->second.p_object_variable); break; - case KeyArgument::LONG: - s << *reinterpret_cast(i->second.p_object_variable); break; - case KeyArgument::NONE: - break; - case KeyArgument::ASCII : - s << *reinterpret_cast(i->second.p_object_variable); break; - case KeyArgument::ASCIIlist : - { - const int index = *reinterpret_cast(i->second.p_object_variable); - s << (index == -1 ? - "UNALLOWED VALUE" : - (*i->second.p_object_list_of_values)[index]); - break; - } - case KeyArgument::PARSINGOBJECT: - { - RegisteredObjectBase* parsing_object_ptr = - *reinterpret_cast(i->second.p_object_variable); - if (parsing_object_ptr!=0) - { - s << parsing_object_ptr->get_registered_name() << endl; - s << parsing_object_ptr->parameter_info() << endl; - } - else - s << "None"; - break; - } - case KeyArgument::SHARED_PARSINGOBJECT: - { + for (Keymap::const_iterator i = kmap.begin(); i != kmap.end(); ++i) { + if (i->second.p_object_member == &KeyParser::start_parsing || i->second.p_object_member == &KeyParser::stop_parsing) + continue; + + if (i->second.vectorised_key_level > 0) { + warning("KeyParser: cannot handle vectorised key yet"); // TODO + continue; + } + s << i->first << " := "; + switch (i->second.type) { + // TODO will break with vectorised keys + case KeyArgument::DOUBLE: + s << *reinterpret_cast(i->second.p_object_variable); + break; + case KeyArgument::FLOAT: + s << *reinterpret_cast(i->second.p_object_variable); + break; + case KeyArgument::INT: + s << *reinterpret_cast(i->second.p_object_variable); + break; + case KeyArgument::BOOL: + s << (*reinterpret_cast(i->second.p_object_variable) ? 1 : 0); + break; + case KeyArgument::UINT: + s << *reinterpret_cast(i->second.p_object_variable); + break; + case KeyArgument::ULONG: + s << *reinterpret_cast(i->second.p_object_variable); + break; + case KeyArgument::LONG: + s << *reinterpret_cast(i->second.p_object_variable); + break; + case KeyArgument::NONE: + break; + case KeyArgument::ASCII: + s << *reinterpret_cast(i->second.p_object_variable); + break; + case KeyArgument::ASCIIlist: { + const int index = *reinterpret_cast(i->second.p_object_variable); + s << (index == -1 ? "UNALLOWED VALUE" : (*i->second.p_object_list_of_values)[index]); + break; + } + case KeyArgument::PARSINGOBJECT: { + RegisteredObjectBase* parsing_object_ptr = *reinterpret_cast(i->second.p_object_variable); + if (parsing_object_ptr != 0) { + s << parsing_object_ptr->get_registered_name() << endl; + s << parsing_object_ptr->parameter_info() << endl; + } else + s << "None"; + break; + } + case KeyArgument::SHARED_PARSINGOBJECT: { #if defined(__GNUC__) && __GNUC__ < 3 - s << "COMPILED WITH GNU C++ (prior to version 3.0), CANNOT INSERT VALUE"; + s << "COMPILED WITH GNU C++ (prior to version 3.0), CANNOT INSERT VALUE"; #else - shared_ptr parsing_object_ptr = - (*reinterpret_cast*>(i->second.p_object_variable)); - - if (!is_null_ptr(parsing_object_ptr)) - { - //std::cerr << "\nBefore *parsing_object_ptr" << endl; - //std::cerr << "\ntypename *parsing_object_ptr " << typeid(*parsing_object_ptr).name() <get_registered_name() << endl; - s << parsing_object_ptr->parameter_info(); - } - else - s << "None"; + shared_ptr parsing_object_ptr = + (*reinterpret_cast*>(i->second.p_object_variable)); + + if (!is_null_ptr(parsing_object_ptr)) { + // std::cerr << "\nBefore *parsing_object_ptr" << endl; + // std::cerr << "\ntypename *parsing_object_ptr " << typeid(*parsing_object_ptr).name() <get_registered_name() << endl; + s << parsing_object_ptr->parameter_info(); + } else + s << "None"; #endif - break; - } - - case KeyArgument::LIST_OF_DOUBLES: - s << *reinterpret_cast(i->second.p_object_variable); break; - case KeyArgument::LIST_OF_INTS: - s << *reinterpret_cast(i->second.p_object_variable); break; - case KeyArgument::ARRAY2D_OF_FLOATS: - detail::to_stream(s, *reinterpret_cast*>(i->second.p_object_variable)); break; - case KeyArgument::ARRAY3D_OF_FLOATS: - detail::to_stream(s, *reinterpret_cast*>(i->second.p_object_variable)); break; - case KeyArgument::BASICCOORDINATE3D_OF_FLOATS: - { - typedef BasicCoordinate<3,float> type; - s << *reinterpret_cast(i->second.p_object_variable); - break; - } - case KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS: - { - typedef BasicCoordinate<3,Array<3,float> > type; - detail::to_stream(s, *reinterpret_cast(i->second.p_object_variable)); - break; - } - case KeyArgument::LIST_OF_ASCII: - s << *reinterpret_cast*>(i->second.p_object_variable); break; - default : - warning("KeyParser error: unknown type. Implementation error\n"); - break; + break; + } - } - s << endl; + case KeyArgument::LIST_OF_DOUBLES: + s << *reinterpret_cast(i->second.p_object_variable); + break; + case KeyArgument::LIST_OF_INTS: + s << *reinterpret_cast(i->second.p_object_variable); + break; + case KeyArgument::ARRAY2D_OF_FLOATS: + detail::to_stream(s, *reinterpret_cast*>(i->second.p_object_variable)); + break; + case KeyArgument::ARRAY3D_OF_FLOATS: + detail::to_stream(s, *reinterpret_cast*>(i->second.p_object_variable)); + break; + case KeyArgument::BASICCOORDINATE3D_OF_FLOATS: { + typedef BasicCoordinate<3, float> type; + s << *reinterpret_cast(i->second.p_object_variable); + break; } - // finally, find stop key - for (Keymap::const_iterator i=kmap.begin(); i!= kmap.end(); ++i) - { - if (i->second.p_object_member == &KeyParser::stop_parsing) - s << i->first << " := \n"; + case KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS: { + typedef BasicCoordinate<3, Array<3, float>> type; + detail::to_stream(s, *reinterpret_cast(i->second.p_object_variable)); + break; } - - return s.str(); + case KeyArgument::LIST_OF_ASCII: + s << *reinterpret_cast*>(i->second.p_object_variable); + break; + default: + warning("KeyParser error: unknown type. Implementation error\n"); + break; + } + s << endl; + } + // finally, find stop key + for (Keymap::const_iterator i = kmap.begin(); i != kmap.end(); ++i) { + if (i->second.p_object_member == &KeyParser::stop_parsing) + s << i->first << " := \n"; } -void KeyParser::ask_parameters() -{ - // This is necessary for set_parsing_object. It will allow the + return s.str(); +} + +void +KeyParser::ask_parameters() { + // This is necessary for set_parsing_object. It will allow the // 'recursive' parser to see it's being called interactively. input = 0; - while(true) - { + while (true) { string line; - - for (Keymap::const_iterator i=kmap.begin(); i!= kmap.end(); ++i) - { - - if (i->second.p_object_member == &KeyParser::do_nothing || - i->second.p_object_member == &KeyParser::start_parsing || + + for (Keymap::const_iterator i = kmap.begin(); i != kmap.end(); ++i) { + + if (i->second.p_object_member == &KeyParser::do_nothing || i->second.p_object_member == &KeyParser::start_parsing || i->second.p_object_member == &KeyParser::stop_parsing) - continue; + continue; - if (i->second.vectorised_key_level > 0) - { - warning("KeyParser: cannot handle vectorised key yet");//TODO - continue; - } + if (i->second.vectorised_key_level > 0) { + warning("KeyParser: cannot handle vectorised key yet"); // TODO + continue; + } keyword = i->first; cout << keyword << " := "; { - read_line(cin, line); - // prepend ":=" such that parse_value_in_line can work properly - line.insert(0, ":= "); + read_line(cin, line); + // prepend ":=" such that parse_value_in_line can work properly + line.insert(0, ":= "); } if (parse_value_in_line(line, false) == Succeeded::yes) - process_key(); + process_key(); } - if (post_processing()) - cout << " Asking all questions again! (Sorry)\n"; + if (post_processing()) + cout << " Asking all questions again! (Sorry)\n"; else return; } diff --git a/src/buildblock/ML_norm.cxx b/src/buildblock/ML_norm.cxx index 2f1d265a34..ff22fc679f 100644 --- a/src/buildblock/ML_norm.cxx +++ b/src/buildblock/ML_norm.cxx @@ -38,287 +38,235 @@ using std::max; START_NAMESPACE_STIR -DetPairData::DetPairData() -{} +DetPairData::DetPairData() {} -DetPairData::DetPairData(const IndexRange<2>& range) -:base_type(range), num_detectors(range.get_length()) -{ -} +DetPairData::DetPairData(const IndexRange<2>& range) : base_type(range), num_detectors(range.get_length()) {} -DetPairData& -DetPairData::operator=(const DetPairData& other) -{ +DetPairData& +DetPairData::operator=(const DetPairData& other) { base_type::operator=(other); num_detectors = other.num_detectors; return *this; } -float & DetPairData::operator()(const int a, const int b) -{ - return (*this)[a][b=get_min_index(a)) - return b<=get_max_index(a); +bool +DetPairData::is_in_data(const int a, const int b) const { + if (b >= get_min_index(a)) + return b <= get_max_index(a); else - return b+num_detectors<=get_max_index(a); + return b + num_detectors <= get_max_index(a); } -void DetPairData::fill(const float d) -{ +void +DetPairData::fill(const float d) { base_type::fill(d); } -void DetPairData::grow(const IndexRange<2>& range) -{ +void +DetPairData::grow(const IndexRange<2>& range) { base_type::grow(range); - num_detectors=range.get_length(); + num_detectors = range.get_length(); } -int DetPairData::get_min_index() const -{ +int +DetPairData::get_min_index() const { return base_type::get_min_index(); } -int DetPairData::get_max_index() const -{ +int +DetPairData::get_max_index() const { return base_type::get_max_index(); } -int DetPairData::get_min_index(const int a) const -{ +int +DetPairData::get_min_index(const int a) const { return (*this)[a].get_min_index(); } -int DetPairData::get_max_index(const int a) const -{ +int +DetPairData::get_max_index(const int a) const { return (*this)[a].get_max_index(); } -float DetPairData::sum() const -{ +float +DetPairData::sum() const { return base_type::sum(); } -float DetPairData::sum(const int a) const -{ +float +DetPairData::sum(const int a) const { return (*this)[a].sum(); } -float DetPairData::find_max() const -{ +float +DetPairData::find_max() const { return base_type::find_max(); } -float DetPairData::find_min() const -{ +float +DetPairData::find_min() const { return base_type::find_min(); } -int DetPairData::get_num_detectors() const -{ +int +DetPairData::get_num_detectors() const { return num_detectors; } -void make_det_pair_data(DetPairData& det_pair_data, - const ProjDataInfo& proj_data_info_general_type, - const int segment_num, - const int ax_pos_num) -{ +void +make_det_pair_data(DetPairData& det_pair_data, const ProjDataInfo& proj_data_info_general_type, const int segment_num, + const int ax_pos_num) { const ProjDataInfoCylindricalNoArcCorr& proj_data_info = - dynamic_cast(proj_data_info_general_type); + dynamic_cast(proj_data_info_general_type); - const int num_detectors = - proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); - const int fan_size = - 2*max(proj_data_info.get_max_tangential_pos_num(), - -proj_data_info.get_min_tangential_pos_num()) + 1; + const int num_detectors = proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); + const int fan_size = 2 * max(proj_data_info.get_max_tangential_pos_num(), -proj_data_info.get_min_tangential_pos_num()) + 1; // fan will range from -half_fan_size to +half_fan_size (i.e. an odd number of elements) - const int half_fan_size = fan_size/2; + const int half_fan_size = fan_size / 2; IndexRange<2> fan_indices; - fan_indices.grow(0,num_detectors-1); - for (int a = 0; a < num_detectors; ++a) - { - fan_indices[a] = - IndexRange<1>(a+num_detectors/2-half_fan_size, - a+num_detectors/2+half_fan_size); + fan_indices.grow(0, num_detectors - 1); + for (int a = 0; a < num_detectors; ++a) { + fan_indices[a] = IndexRange<1>(a + num_detectors / 2 - half_fan_size, a + num_detectors / 2 + half_fan_size); } det_pair_data.grow(fan_indices); det_pair_data.fill(0); } -void make_det_pair_data(DetPairData& det_pair_data, - const ProjData& proj_data, - const int segment_num, - const int ax_pos_num) -{ - make_det_pair_data(det_pair_data, - *proj_data.get_proj_data_info_sptr(), - segment_num, - ax_pos_num); - const int num_detectors = - det_pair_data.get_num_detectors(); +void +make_det_pair_data(DetPairData& det_pair_data, const ProjData& proj_data, const int segment_num, const int ax_pos_num) { + make_det_pair_data(det_pair_data, *proj_data.get_proj_data_info_sptr(), segment_num, ax_pos_num); + const int num_detectors = det_pair_data.get_num_detectors(); const ProjDataInfoCylindricalNoArcCorr& proj_data_info = - dynamic_cast(*proj_data.get_proj_data_info_sptr()); + dynamic_cast(*proj_data.get_proj_data_info_sptr()); - shared_ptr > - pos_sino_ptr(new Sinogram(proj_data.get_sinogram(ax_pos_num,segment_num))); - shared_ptr > neg_sino_ptr; + shared_ptr> pos_sino_ptr(new Sinogram(proj_data.get_sinogram(ax_pos_num, segment_num))); + shared_ptr> neg_sino_ptr; if (segment_num == 0) neg_sino_ptr = pos_sino_ptr; else - neg_sino_ptr. - reset(new Sinogram(proj_data.get_sinogram(ax_pos_num,-segment_num))); - - - for (int view_num = 0; view_num < num_detectors/2; view_num++) - for (int tang_pos_num = proj_data.get_min_tangential_pos_num(); - tang_pos_num <= proj_data.get_max_tangential_pos_num(); - ++tang_pos_num) - { - int det_num_a = 0; - int det_num_b = 0; + neg_sino_ptr.reset(new Sinogram(proj_data.get_sinogram(ax_pos_num, -segment_num))); - proj_data_info.get_det_num_pair_for_view_tangential_pos_num(det_num_a, det_num_b, view_num, tang_pos_num); + for (int view_num = 0; view_num < num_detectors / 2; view_num++) + for (int tang_pos_num = proj_data.get_min_tangential_pos_num(); tang_pos_num <= proj_data.get_max_tangential_pos_num(); + ++tang_pos_num) { + int det_num_a = 0; + int det_num_b = 0; - det_pair_data(det_num_a,det_num_b) = - (*pos_sino_ptr)[view_num][tang_pos_num]; - det_pair_data(det_num_b,det_num_a) = - (*neg_sino_ptr)[view_num][tang_pos_num]; - } + proj_data_info.get_det_num_pair_for_view_tangential_pos_num(det_num_a, det_num_b, view_num, tang_pos_num); + + det_pair_data(det_num_a, det_num_b) = (*pos_sino_ptr)[view_num][tang_pos_num]; + det_pair_data(det_num_b, det_num_a) = (*neg_sino_ptr)[view_num][tang_pos_num]; + } } -void set_det_pair_data(ProjData& proj_data, - const DetPairData& det_pair_data, - const int segment_num, - const int ax_pos_num) -{ - const shared_ptr proj_data_info_sptr = - proj_data.get_proj_data_info_sptr(); +void +set_det_pair_data(ProjData& proj_data, const DetPairData& det_pair_data, const int segment_num, const int ax_pos_num) { + const shared_ptr proj_data_info_sptr = proj_data.get_proj_data_info_sptr(); const ProjDataInfoCylindricalNoArcCorr& proj_data_info = - dynamic_cast(*proj_data_info_sptr); + dynamic_cast(*proj_data_info_sptr); const int num_detectors = det_pair_data.get_num_detectors(); assert(proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring() == num_detectors); - shared_ptr > - pos_sino_ptr(new Sinogram(proj_data.get_empty_sinogram(ax_pos_num,segment_num))); - shared_ptr > neg_sino_ptr; + shared_ptr> pos_sino_ptr(new Sinogram(proj_data.get_empty_sinogram(ax_pos_num, segment_num))); + shared_ptr> neg_sino_ptr; if (segment_num != 0) - neg_sino_ptr. - reset(new Sinogram(proj_data.get_empty_sinogram(ax_pos_num,-segment_num))); - - - for (int view_num = 0; view_num < num_detectors/2; view_num++) - for (int tang_pos_num = proj_data.get_min_tangential_pos_num(); - tang_pos_num <= proj_data.get_max_tangential_pos_num(); - ++tang_pos_num) - { - int det_num_a = 0; - int det_num_b = 0; + neg_sino_ptr.reset(new Sinogram(proj_data.get_empty_sinogram(ax_pos_num, -segment_num))); - proj_data_info.get_det_num_pair_for_view_tangential_pos_num(det_num_a, det_num_b, view_num, tang_pos_num); + for (int view_num = 0; view_num < num_detectors / 2; view_num++) + for (int tang_pos_num = proj_data.get_min_tangential_pos_num(); tang_pos_num <= proj_data.get_max_tangential_pos_num(); + ++tang_pos_num) { + int det_num_a = 0; + int det_num_b = 0; - (*pos_sino_ptr)[view_num][tang_pos_num] = - det_pair_data(det_num_a,det_num_b); - if (segment_num!=0) - (*neg_sino_ptr)[view_num][tang_pos_num] = - det_pair_data(det_num_b,det_num_a); - } + proj_data_info.get_det_num_pair_for_view_tangential_pos_num(det_num_a, det_num_b, view_num, tang_pos_num); + + (*pos_sino_ptr)[view_num][tang_pos_num] = det_pair_data(det_num_a, det_num_b); + if (segment_num != 0) + (*neg_sino_ptr)[view_num][tang_pos_num] = det_pair_data(det_num_b, det_num_a); + } proj_data.set_sinogram(*pos_sino_ptr); if (segment_num != 0) proj_data.set_sinogram(*neg_sino_ptr); } - -void apply_block_norm(DetPairData& det_pair_data, const BlockData& block_data, const bool apply) -{ +void +apply_block_norm(DetPairData& det_pair_data, const BlockData& block_data, const bool apply) { const int num_detectors = det_pair_data.get_num_detectors(); const int num_blocks = block_data.get_length(); - const int num_crystals_per_block = num_detectors/num_blocks; + const int num_crystals_per_block = num_detectors / num_blocks; assert(num_blocks * num_crystals_per_block == num_detectors); - + for (int a = det_pair_data.get_min_index(); a <= det_pair_data.get_max_index(); ++a) - for (int b = det_pair_data.get_min_index(a); b <= det_pair_data.get_max_index(a); ++b) - { - // note: add 2*num_detectors to newb to avoid using mod with negative numbers - if (det_pair_data(a,b) == 0) - continue; - if (apply) - det_pair_data(a,b) *= - block_data[a/num_crystals_per_block][(b/num_crystals_per_block)%num_blocks]; - else - det_pair_data(a,b) /= - block_data[a/num_crystals_per_block][(b/num_crystals_per_block)%num_blocks]; - } + for (int b = det_pair_data.get_min_index(a); b <= det_pair_data.get_max_index(a); ++b) { + // note: add 2*num_detectors to newb to avoid using mod with negative numbers + if (det_pair_data(a, b) == 0) + continue; + if (apply) + det_pair_data(a, b) *= block_data[a / num_crystals_per_block][(b / num_crystals_per_block) % num_blocks]; + else + det_pair_data(a, b) /= block_data[a / num_crystals_per_block][(b / num_crystals_per_block) % num_blocks]; + } } -void apply_geo_norm(DetPairData& det_pair_data, const GeoData& geo_data, const bool apply) -{ +void +apply_geo_norm(DetPairData& det_pair_data, const GeoData& geo_data, const bool apply) { const int num_detectors = det_pair_data.get_num_detectors(); - const int num_crystals_per_block = geo_data.get_length()*2; + const int num_crystals_per_block = geo_data.get_length() * 2; for (int a = det_pair_data.get_min_index(); a <= det_pair_data.get_max_index(); ++a) - for (int b = det_pair_data.get_min_index(a); b <= det_pair_data.get_max_index(a); ++b) - { - if (det_pair_data(a,b) == 0) - continue; - int newa = a % num_crystals_per_block; - int newb = b - (a - newa); - if (newa > num_crystals_per_block - 1 - newa) - { - newa = num_crystals_per_block - 1 - newa; - newb = - newb + num_crystals_per_block - 1; - } - // note: add 2*num_detectors to newb to avoid using mod with negative numbers - if (apply) - det_pair_data(a,b) *= - geo_data[newa][(2*num_detectors + newb)%num_detectors]; - else - det_pair_data(a,b) /= - geo_data[newa][(2*num_detectors + newb)%num_detectors]; + for (int b = det_pair_data.get_min_index(a); b <= det_pair_data.get_max_index(a); ++b) { + if (det_pair_data(a, b) == 0) + continue; + int newa = a % num_crystals_per_block; + int newb = b - (a - newa); + if (newa > num_crystals_per_block - 1 - newa) { + newa = num_crystals_per_block - 1 - newa; + newb = -newb + num_crystals_per_block - 1; } + // note: add 2*num_detectors to newb to avoid using mod with negative numbers + if (apply) + det_pair_data(a, b) *= geo_data[newa][(2 * num_detectors + newb) % num_detectors]; + else + det_pair_data(a, b) /= geo_data[newa][(2 * num_detectors + newb) % num_detectors]; + } } -void apply_efficiencies(DetPairData& det_pair_data, const Array<1,float>& efficiencies, const bool apply) -{ +void +apply_efficiencies(DetPairData& det_pair_data, const Array<1, float>& efficiencies, const bool apply) { const int num_detectors = det_pair_data.get_num_detectors(); for (int a = det_pair_data.get_min_index(); a <= det_pair_data.get_max_index(); ++a) - for (int b = det_pair_data.get_min_index(a); b <= det_pair_data.get_max_index(a); ++b) - { - if (det_pair_data(a,b) == 0) - continue; - if (apply) - det_pair_data(a,b) *= - efficiencies[a]*efficiencies[b%num_detectors]; - else - det_pair_data(a,b) /= - efficiencies[a]*efficiencies[b%num_detectors]; - } + for (int b = det_pair_data.get_min_index(a); b <= det_pair_data.get_max_index(a); ++b) { + if (det_pair_data(a, b) == 0) + continue; + if (apply) + det_pair_data(a, b) *= efficiencies[a] * efficiencies[b % num_detectors]; + else + det_pair_data(a, b) /= efficiencies[a] * efficiencies[b % num_detectors]; + } } - -void make_fan_sum_data(Array<1,float>& data_fan_sums, const DetPairData& det_pair_data) -{ +void +make_fan_sum_data(Array<1, float>& data_fan_sums, const DetPairData& det_pair_data) { for (int a = det_pair_data.get_min_index(); a <= det_pair_data.get_max_index(); ++a) data_fan_sums[a] = det_pair_data.sum(a); } -void make_geo_data(GeoData& geo_data, const DetPairData& det_pair_data) -{ +void +make_geo_data(GeoData& geo_data, const DetPairData& det_pair_data) { const int num_detectors = det_pair_data.get_num_detectors(); - const int num_crystals_per_block = geo_data.get_length()*2; + const int num_crystals_per_block = geo_data.get_length() * 2; const int num_blocks = num_detectors / num_crystals_per_block; assert(num_blocks * num_crystals_per_block == num_detectors); @@ -327,174 +275,145 @@ void make_geo_data(GeoData& geo_data, const DetPairData& det_pair_data) work.fill(0); for (int a = det_pair_data.get_min_index(); a <= det_pair_data.get_max_index(); ++a) - for (int b = det_pair_data.get_min_index(a); b <= det_pair_data.get_max_index(a); ++b) - { - // mirror symmetry - work(a,b) = - det_pair_data(a,b) + - det_pair_data(num_detectors-1-a,(2*num_detectors-1-b)%num_detectors); - } + for (int b = det_pair_data.get_min_index(a); b <= det_pair_data.get_max_index(a); ++b) { + // mirror symmetry + work(a, b) = det_pair_data(a, b) + det_pair_data(num_detectors - 1 - a, (2 * num_detectors - 1 - b) % num_detectors); + } geo_data.fill(0); - for (int crystal_num_a = 0; crystal_num_a < num_crystals_per_block/2; ++crystal_num_a) - for (int det_num_b = det_pair_data.get_min_index(crystal_num_a); det_num_b <= det_pair_data.get_max_index(crystal_num_a); ++det_num_b) - { - for (int block_num = 0; block_num& efficiencies, - const Array<1,float>& data_fan_sums, - const DetPairData& model) -{ + +void +iterate_efficiencies(Array<1, float>& efficiencies, const Array<1, float>& data_fan_sums, const DetPairData& model) { const int num_detectors = efficiencies.get_length(); - for (int a = 0; a < num_detectors; ++a) - { - if (data_fan_sums[a] == 0) - efficiencies[a] = 0; - else - { - //const float denominator = inner_product(efficiencies,model[a]); - float denominator = 0; - for (int b = model.get_min_index(a); b <= model.get_max_index(a); ++b) - denominator += efficiencies[b%num_detectors]*model(a,b); - efficiencies[a] = data_fan_sums[a] / denominator; - } + for (int a = 0; a < num_detectors; ++a) { + if (data_fan_sums[a] == 0) + efficiencies[a] = 0; + else { + // const float denominator = inner_product(efficiencies,model[a]); + float denominator = 0; + for (int b = model.get_min_index(a); b <= model.get_max_index(a); ++b) + denominator += efficiencies[b % num_detectors] * model(a, b); + efficiencies[a] = data_fan_sums[a] / denominator; } + } } -void iterate_geo_norm(GeoData& norm_geo_data, - const GeoData& measured_geo_data, - const DetPairData& model) -{ +void +iterate_geo_norm(GeoData& norm_geo_data, const GeoData& measured_geo_data, const DetPairData& model) { make_geo_data(norm_geo_data, model); - //norm_geo_data = measured_geo_data / norm_geo_data; + // norm_geo_data = measured_geo_data / norm_geo_data; const int num_detectors = model.get_num_detectors(); - const int num_crystals_per_block = measured_geo_data.get_length()*2; - const float threshold = measured_geo_data.find_max()/10000.F; - for (int a = 0; a < num_crystals_per_block/2; ++a) - for (int b = 0; b < num_detectors; ++b) - { - norm_geo_data[a][b] = - (measured_geo_data[a][b]>=threshold || - measured_geo_data[a][b] < 10000*norm_geo_data[a][b]) - ? measured_geo_data[a][b] / norm_geo_data[a][b] - : 0; - } + const int num_crystals_per_block = measured_geo_data.get_length() * 2; + const float threshold = measured_geo_data.find_max() / 10000.F; + for (int a = 0; a < num_crystals_per_block / 2; ++a) + for (int b = 0; b < num_detectors; ++b) { + norm_geo_data[a][b] = (measured_geo_data[a][b] >= threshold || measured_geo_data[a][b] < 10000 * norm_geo_data[a][b]) + ? measured_geo_data[a][b] / norm_geo_data[a][b] + : 0; + } } - -void iterate_block_norm(BlockData& norm_block_data, - const BlockData& measured_block_data, - const DetPairData& model) -{ + +void +iterate_block_norm(BlockData& norm_block_data, const BlockData& measured_block_data, const DetPairData& model) { make_block_data(norm_block_data, model); - //norm_block_data = measured_block_data / norm_block_data; + // norm_block_data = measured_block_data / norm_block_data; const int num_blocks = norm_block_data.get_length(); - const float threshold = measured_block_data.find_max()/10000.F; + const float threshold = measured_block_data.find_max() / 10000.F; for (int a = 0; a < num_blocks; ++a) - for (int b = 0; b < num_blocks; ++b) - { - norm_block_data[a][b] = - (measured_block_data[a][b]>=threshold || - measured_block_data[a][b] < 10000*norm_block_data[a][b]) - ? measured_block_data[a][b] / norm_block_data[a][b] - : 0; - } + for (int b = 0; b < num_blocks; ++b) { + norm_block_data[a][b] = + (measured_block_data[a][b] >= threshold || measured_block_data[a][b] < 10000 * norm_block_data[a][b]) + ? measured_block_data[a][b] / norm_block_data[a][b] + : 0; + } } -double KL(const DetPairData& d1, const DetPairData& d2, const double threshold) -{ - double sum=0; - for (int a = d1.get_min_index(); a <= d1.get_max_index(); ++a) - { - double bsum=0; - for (int b = d1.get_min_index(a); b <= d1.get_max_index(a); ++b) - bsum += KL(d1(a,b), d2(a,b), threshold); - sum += bsum; - } +double +KL(const DetPairData& d1, const DetPairData& d2, const double threshold) { + double sum = 0; + for (int a = d1.get_min_index(); a <= d1.get_max_index(); ++a) { + double bsum = 0; + for (int b = d1.get_min_index(a); b <= d1.get_max_index(a); ++b) + bsum += KL(d1(a, b), d2(a, b), threshold); + sum += bsum; + } return static_cast(sum); } - ////////// ******* GeoData3D ******** ////// -GeoData3D::GeoData3D() -{} +GeoData3D::GeoData3D() {} -GeoData3D::~GeoData3D() -{} +GeoData3D::~GeoData3D() {} +GeoData3D::GeoData3D(const int num_axial_crystals_per_block, const int half_num_transaxial_crystals_per_block, + const int num_rings, const int num_detectors_per_ring) + : num_axial_crystals_per_block(num_axial_crystals_per_block), + half_num_transaxial_crystals_per_block(half_num_transaxial_crystals_per_block), num_rings(num_rings), + num_detectors_per_ring(num_detectors_per_ring) { -GeoData3D:: -GeoData3D(const int num_axial_crystals_per_block, const int half_num_transaxial_crystals_per_block, const int num_rings, const int num_detectors_per_ring) -:num_axial_crystals_per_block(num_axial_crystals_per_block), half_num_transaxial_crystals_per_block(half_num_transaxial_crystals_per_block), -num_rings(num_rings), num_detectors_per_ring(num_detectors_per_ring) -{ - - // assert(max_ring_diff= (num_axial_crystals_per_block -1) + // assert(max_ring_diff= (num_axial_crystals_per_block -1) - - IndexRange<4> fan_indices; - fan_indices.grow(0,num_axial_crystals_per_block-1); - for (int ra = 0; ra < num_axial_crystals_per_block; ++ra) - { - const int min_rb = ra; - const int max_rb = num_rings-1; // I assumed max ring diff is num_ring_1 - fan_indices[ra].grow(0,half_num_transaxial_crystals_per_block-1); - for (int a = 0; a < half_num_transaxial_crystals_per_block; ++a) - { - // store only 1 half of data as ra,a,rb,b = rb,b,ra,a - fan_indices[ra][a].grow(min_rb, max_rb); - for (int rb = min_rb; rb <= max_rb; ++rb) - fan_indices[ra][a][rb] = - IndexRange<1>(a, - a+num_detectors_per_ring -1); // I assumed fan size is number of detector per ring - 2 - } + IndexRange<4> fan_indices; + fan_indices.grow(0, num_axial_crystals_per_block - 1); + for (int ra = 0; ra < num_axial_crystals_per_block; ++ra) { + const int min_rb = ra; + const int max_rb = num_rings - 1; // I assumed max ring diff is num_ring_1 + fan_indices[ra].grow(0, half_num_transaxial_crystals_per_block - 1); + for (int a = 0; a < half_num_transaxial_crystals_per_block; ++a) { + // store only 1 half of data as ra,a,rb,b = rb,b,ra,a + fan_indices[ra][a].grow(min_rb, max_rb); + for (int rb = min_rb; rb <= max_rb; ++rb) + fan_indices[ra][a][rb] = + IndexRange<1>(a, + a + num_detectors_per_ring - 1); // I assumed fan size is number of detector per ring - 2 } - grow(fan_indices); - fill(0); + } + grow(fan_indices); + fill(0); } GeoData3D& -GeoData3D::operator=(const GeoData3D& other) -{ - base_type::operator=(other); - num_axial_crystals_per_block = other.num_axial_crystals_per_block; - half_num_transaxial_crystals_per_block = other.half_num_transaxial_crystals_per_block; - num_rings = other.num_rings; - num_detectors_per_ring = other.num_detectors_per_ring; - return *this; +GeoData3D::operator=(const GeoData3D& other) { + base_type::operator=(other); + num_axial_crystals_per_block = other.num_axial_crystals_per_block; + half_num_transaxial_crystals_per_block = other.half_num_transaxial_crystals_per_block; + num_rings = other.num_rings; + num_detectors_per_ring = other.num_detectors_per_ring; + return *this; } /*float & GeoData3D::operator()(const int ra, const int a, const int rb, const int b) @@ -504,7 +423,8 @@ GeoData3D::operator=(const GeoData3D& other) return ra=0); - assert(b>=0); - return +float& +GeoData3D::operator()(const int ra, const int a, const int rb, const int b) { + assert(a >= 0); + assert(b >= 0); + return - (*this)[ra][a%num_detectors_per_ring][rb][b=0); - assert(b>=0); - return +float +GeoData3D::operator()(const int ra, const int a, const int rb, const int b) const { + assert(a >= 0); + assert(b >= 0); + return - (*this)[ra][a%num_detectors_per_ring][rb][b=0); - assert(b>=0); - if (rb<(*this)[ra][a].get_min_index() || rb >(*this)[ra][a].get_max_index()) - return false; - if (b>=get_min_b(a)) - return b<=get_max_b(a); - else - return b+num_detectors_per_ring<=get_max_b(a); -} -void GeoData3D::fill(const float d) -{ - base_type::fill(d); +GeoData3D::is_in_data(const int ra, const int a, const int rb, const int b) const { + assert(a >= 0); + assert(b >= 0); + if (rb < (*this)[ra][a].get_min_index() || rb > (*this)[ra][a].get_max_index()) + return false; + if (b >= get_min_b(a)) + return b <= get_max_b(a); + else + return b + num_detectors_per_ring <= get_max_b(a); } - - -int GeoData3D::get_min_ra() const -{ - return base_type::get_min_index(); +void +GeoData3D::fill(const float d) { + base_type::fill(d); } -int GeoData3D::get_max_ra() const -{ - return base_type::get_max_index(); +int +GeoData3D::get_min_ra() const { + return base_type::get_min_index(); } - -int GeoData3D::get_min_a() const -{ - return (*this)[get_min_index()].get_min_index(); +int +GeoData3D::get_max_ra() const { + return base_type::get_max_index(); } -int GeoData3D::get_max_a() const -{ - return (*this)[get_min_index()].get_max_index(); +int +GeoData3D::get_min_a() const { + return (*this)[get_min_index()].get_min_index(); } - -int GeoData3D::get_min_rb(const int ra) const -{ - return 0; - // next is no longer true because we store only half the data - //return (*this)[ra][(*this)[ra].get_min_index()].get_min_index(); +int +GeoData3D::get_max_a() const { + return (*this)[get_min_index()].get_max_index(); } - -int GeoData3D::get_max_rb(const int ra) const -{ - return (*this)[ra][(*this)[ra].get_min_index()].get_max_index(); +int +GeoData3D::get_min_rb(const int ra) const { + return 0; + // next is no longer true because we store only half the data + // return (*this)[ra][(*this)[ra].get_min_index()].get_min_index(); } -int GeoData3D::get_min_b(const int a) const -{ - return (*this)[get_min_index()][a][(*this)[get_min_index()][a].get_min_index()].get_min_index(); +int +GeoData3D::get_max_rb(const int ra) const { + return (*this)[ra][(*this)[ra].get_min_index()].get_max_index(); } -int GeoData3D::get_max_b(const int a) const -{ - return (*this)[get_min_index()][a][(*this)[get_min_index()][a].get_min_index()].get_max_index(); +int +GeoData3D::get_min_b(const int a) const { + return (*this)[get_min_index()][a][(*this)[get_min_index()][a].get_min_index()].get_min_index(); } - -float GeoData3D::sum() const -{ - //return base_type::sum(); - float sum = 0; - for (int ra=get_min_ra(); ra <= get_max_ra(); ++ra) - for (int a = get_min_a(); a <= get_max_a(); ++a) - sum += this->sum(ra,a); - return sum; +int +GeoData3D::get_max_b(const int a) const { + return (*this)[get_min_index()][a][(*this)[get_min_index()][a].get_min_index()].get_max_index(); } -float GeoData3D::sum(const int ra, const int a) const -{ - //return (*this)[ra][a].sum(); - float sum = 0; - for (int rb=get_min_rb(ra); rb <= get_max_rb(ra); ++rb) - for (int b = get_min_b(a); b <= get_max_b(a); ++b) - sum += (*this)(ra,a,rb,b%num_detectors_per_ring); - return sum; +float +GeoData3D::sum() const { + // return base_type::sum(); + float sum = 0; + for (int ra = get_min_ra(); ra <= get_max_ra(); ++ra) + for (int a = get_min_a(); a <= get_max_a(); ++a) + sum += this->sum(ra, a); + return sum; } -float GeoData3D::find_max() const -{ - return base_type::find_max(); +float +GeoData3D::sum(const int ra, const int a) const { + // return (*this)[ra][a].sum(); + float sum = 0; + for (int rb = get_min_rb(ra); rb <= get_max_rb(ra); ++rb) + for (int b = get_min_b(a); b <= get_max_b(a); ++b) + sum += (*this)(ra, a, rb, b % num_detectors_per_ring); + return sum; } -float GeoData3D::find_min() const -{ - return base_type::find_min(); +float +GeoData3D::find_max() const { + return base_type::find_max(); } -int GeoData3D::get_num_axial_crystals_per_block() const -{ - return num_axial_crystals_per_block; +float +GeoData3D::find_min() const { + return base_type::find_min(); } -int GeoData3D::get_half_num_transaxial_crystals_per_block() const -{ - return half_num_transaxial_crystals_per_block; +int +GeoData3D::get_num_axial_crystals_per_block() const { + return num_axial_crystals_per_block; } +int +GeoData3D::get_half_num_transaxial_crystals_per_block() const { + return half_num_transaxial_crystals_per_block; +} -std::ostream& operator<<(std::ostream& s, const GeoData3D& geo_data) -{ - return s << static_cast(geo_data); +std::ostream& +operator<<(std::ostream& s, const GeoData3D& geo_data) { + return s << static_cast(geo_data); } -std::istream& operator>>(std::istream& s, GeoData3D& geo_data) -{ - s >> static_cast(geo_data); - if (!s) - return s; - geo_data.half_num_transaxial_crystals_per_block = geo_data.get_max_a() - geo_data.get_min_a() + 1; - geo_data.num_axial_crystals_per_block = geo_data.get_max_ra() - geo_data.get_min_ra() + 1; - - - const int max_delta = geo_data[0][0].get_length()-1; - const int num_detectors_per_ring = - geo_data[0][0][0].get_length(); - geo_data.num_detectors_per_ring = num_detectors_per_ring; - geo_data.num_rings = max_delta+1; - - - - - for (int ra = 0; ra < geo_data.num_axial_crystals_per_block; ++ra) - +std::istream& +operator>>(std::istream& s, GeoData3D& geo_data) { + s >> static_cast(geo_data); + if (!s) + return s; + geo_data.half_num_transaxial_crystals_per_block = geo_data.get_max_a() - geo_data.get_min_a() + 1; + geo_data.num_axial_crystals_per_block = geo_data.get_max_ra() - geo_data.get_min_ra() + 1; - { - const int min_rb = ra; - const int max_rb = geo_data.num_rings-1; - for (int a = 0; a < geo_data.half_num_transaxial_crystals_per_block; ++a) - { + const int max_delta = geo_data[0][0].get_length() - 1; + const int num_detectors_per_ring = geo_data[0][0][0].get_length(); + geo_data.num_detectors_per_ring = num_detectors_per_ring; + geo_data.num_rings = max_delta + 1; - if (geo_data[ra][a].get_length() != max_rb - max(ra,min_rb) + 1) - { - warning("Reading GeoData3D: inconsistent length %d for rb at ra=%d, a=%d, " - "Expected length %d\n", - geo_data[ra][a].get_length(), ra, a, max_rb - max(ra,min_rb) + 1); - } - geo_data[ra][a].set_offset(max(ra,min_rb)); - for (int rb = geo_data[ra][a].get_min_index(); rb <= geo_data[ra][a].get_max_index(); ++rb) - { - if (geo_data[ra][a][rb].get_length() != num_detectors_per_ring) - { - warning("Reading GeoData3D: inconsistent length %d for b at ra=%d, a=%d, rb=%d\n" - "Expected length %d\n", - geo_data[ra][a][rb].get_length(), ra, a, rb, num_detectors_per_ring); - } - geo_data[ra][a][rb].set_offset(a); - } + for (int ra = 0; ra < geo_data.num_axial_crystals_per_block; ++ra) + + { + const int min_rb = ra; + const int max_rb = geo_data.num_rings - 1; + for (int a = 0; a < geo_data.half_num_transaxial_crystals_per_block; ++a) { + + if (geo_data[ra][a].get_length() != max_rb - max(ra, min_rb) + 1) { + warning("Reading GeoData3D: inconsistent length %d for rb at ra=%d, a=%d, " + "Expected length %d\n", + geo_data[ra][a].get_length(), ra, a, max_rb - max(ra, min_rb) + 1); + } + geo_data[ra][a].set_offset(max(ra, min_rb)); + for (int rb = geo_data[ra][a].get_min_index(); rb <= geo_data[ra][a].get_max_index(); ++rb) { + if (geo_data[ra][a][rb].get_length() != num_detectors_per_ring) { + warning("Reading GeoData3D: inconsistent length %d for b at ra=%d, a=%d, rb=%d\n" + "Expected length %d\n", + geo_data[ra][a][rb].get_length(), ra, a, rb, num_detectors_per_ring); } + geo_data[ra][a][rb].set_offset(a); + } } - - return s; -} + } + return s; +} //////////////////////////////////////////////////// +FanProjData::FanProjData() {} - - -FanProjData::FanProjData() -{} - -FanProjData::~FanProjData() -{} +FanProjData::~FanProjData() {} #if 0 FanProjData::FanProjData(const IndexRange<4>& range) @@ -718,39 +614,33 @@ FanProjData::FanProjData(const IndexRange<4>& range) } #endif -FanProjData:: -FanProjData(const int num_rings, const int num_detectors_per_ring, const int max_ring_diff, const int fan_size) -: num_rings(num_rings), num_detectors_per_ring(num_detectors_per_ring), - max_ring_diff(max_ring_diff), half_fan_size(fan_size/2) -{ - assert(num_detectors_per_ring%2 == 0); - assert(max_ring_diff fan_indices; - fan_indices.grow(0,num_rings-1); - for (int ra = 0; ra < num_rings; ++ra) - { - const int min_rb = max(ra-max_ring_diff, 0); - const int max_rb = min(ra+max_ring_diff, num_rings-1); - fan_indices[ra].grow(0,num_detectors_per_ring-1); - for (int a = 0; a < num_detectors_per_ring; ++a) - { + fan_indices.grow(0, num_rings - 1); + for (int ra = 0; ra < num_rings; ++ra) { + const int min_rb = max(ra - max_ring_diff, 0); + const int max_rb = min(ra + max_ring_diff, num_rings - 1); + fan_indices[ra].grow(0, num_detectors_per_ring - 1); + for (int a = 0; a < num_detectors_per_ring; ++a) { // store only 1 half of data as ra,a,rb,b = rb,b,ra,a - fan_indices[ra][a].grow(max(ra,min_rb), max_rb); - for (int rb = max(ra,min_rb); rb <= max_rb; ++rb) - fan_indices[ra][a][rb] = - IndexRange<1>(a+num_detectors_per_ring/2-half_fan_size, - a+num_detectors_per_ring/2+half_fan_size); + fan_indices[ra][a].grow(max(ra, min_rb), max_rb); + for (int rb = max(ra, min_rb); rb <= max_rb; ++rb) + fan_indices[ra][a][rb] = + IndexRange<1>(a + num_detectors_per_ring / 2 - half_fan_size, a + num_detectors_per_ring / 2 + half_fan_size); } } grow(fan_indices); fill(0); } -FanProjData& -FanProjData::operator=(const FanProjData& other) -{ +FanProjData& +FanProjData::operator=(const FanProjData& other) { base_type::operator=(other); num_detectors_per_ring = other.num_detectors_per_ring; num_rings = other.num_rings; @@ -759,42 +649,38 @@ FanProjData::operator=(const FanProjData& other) return *this; } -float & FanProjData::operator()(const int ra, const int a, const int rb, const int b) -{ - assert(a>=0); - assert(b>=0); - return - ra= 0); + assert(b >= 0); + return ra < rb ? (*this)[ra][a % num_detectors_per_ring][rb][b < get_min_b(a) ? b + num_detectors_per_ring : b] + : (*this)[rb][b % num_detectors_per_ring][ra] + [a < get_min_b(b % num_detectors_per_ring) ? a + num_detectors_per_ring : a]; } -float FanProjData::operator()(const int ra, const int a, const int rb, const int b) const -{ - assert(a>=0); - assert(b>=0); - return - ra= 0); + assert(b >= 0); + return ra < rb ? (*this)[ra][a % num_detectors_per_ring][rb][b < get_min_b(a) ? b + num_detectors_per_ring : b] + : (*this)[rb][b % num_detectors_per_ring][ra] + [a < get_min_b(b % num_detectors_per_ring) ? a + num_detectors_per_ring : a]; } -bool -FanProjData:: -is_in_data(const int ra, const int a, const int rb, const int b) const -{ - assert(a>=0); - assert(b>=0); - if (rb<(*this)[ra][a].get_min_index() || rb >(*this)[ra][a].get_max_index()) +bool +FanProjData::is_in_data(const int ra, const int a, const int rb, const int b) const { + assert(a >= 0); + assert(b >= 0); + if (rb < (*this)[ra][a].get_min_index() || rb > (*this)[ra][a].get_max_index()) return false; - if (b>=get_min_b(a)) - return b<=get_max_b(a); + if (b >= get_min_b(a)) + return b <= get_max_b(a); else - return b+num_detectors_per_ring<=get_max_b(a); + return b + num_detectors_per_ring <= get_max_b(a); } -void FanProjData::fill(const float d) -{ +void +FanProjData::fill(const float d) { base_type::fill(d); } @@ -807,136 +693,126 @@ void FanProjData::grow(const IndexRange<4>& range) } #endif -int FanProjData::get_min_ra() const -{ +int +FanProjData::get_min_ra() const { return base_type::get_min_index(); } -int FanProjData::get_max_ra() const -{ +int +FanProjData::get_max_ra() const { return base_type::get_max_index(); } - -int FanProjData::get_min_a() const -{ +int +FanProjData::get_min_a() const { return (*this)[get_min_index()].get_min_index(); } -int FanProjData::get_max_a() const -{ +int +FanProjData::get_max_a() const { return (*this)[get_min_index()].get_max_index(); } - -int FanProjData::get_min_rb(const int ra) const -{ - return max(ra-max_ring_diff, 0); +int +FanProjData::get_min_rb(const int ra) const { + return max(ra - max_ring_diff, 0); // next is no longer true because we store only half the data - //return (*this)[ra][(*this)[ra].get_min_index()].get_min_index(); + // return (*this)[ra][(*this)[ra].get_min_index()].get_min_index(); } -int FanProjData::get_max_rb(const int ra) const -{ +int +FanProjData::get_max_rb(const int ra) const { return (*this)[ra][(*this)[ra].get_min_index()].get_max_index(); } -int FanProjData::get_min_b(const int a) const -{ +int +FanProjData::get_min_b(const int a) const { return (*this)[get_min_index()][a][(*this)[get_min_index()][a].get_min_index()].get_min_index(); } -int FanProjData::get_max_b(const int a) const -{ +int +FanProjData::get_max_b(const int a) const { return (*this)[get_min_index()][a][(*this)[get_min_index()][a].get_min_index()].get_max_index(); } - -float FanProjData::sum() const -{ - //return base_type::sum(); +float +FanProjData::sum() const { + // return base_type::sum(); float sum = 0; - for (int ra=get_min_ra(); ra <= get_max_ra(); ++ra) - for (int a = get_min_a(); a <= get_max_a(); ++a) - sum += this->sum(ra,a); + for (int ra = get_min_ra(); ra <= get_max_ra(); ++ra) + for (int a = get_min_a(); a <= get_max_a(); ++a) + sum += this->sum(ra, a); return sum; } -float FanProjData::sum(const int ra, const int a) const -{ - //return (*this)[ra][a].sum(); +float +FanProjData::sum(const int ra, const int a) const { + // return (*this)[ra][a].sum(); float sum = 0; - for (int rb=get_min_rb(ra); rb <= get_max_rb(ra); ++rb) - for (int b = get_min_b(a); b <= get_max_b(a); ++b) - sum += (*this)(ra,a,rb,b%num_detectors_per_ring); + for (int rb = get_min_rb(ra); rb <= get_max_rb(ra); ++rb) + for (int b = get_min_b(a); b <= get_max_b(a); ++b) + sum += (*this)(ra, a, rb, b % num_detectors_per_ring); return sum; } -float FanProjData::find_max() const -{ +float +FanProjData::find_max() const { return base_type::find_max(); } -float FanProjData::find_min() const -{ +float +FanProjData::find_min() const { return base_type::find_min(); } -int FanProjData::get_num_detectors_per_ring() const -{ +int +FanProjData::get_num_detectors_per_ring() const { return num_detectors_per_ring; } - -int FanProjData::get_num_rings() const -{ +int +FanProjData::get_num_rings() const { return num_rings; } -std::ostream& operator<<(std::ostream& s, const FanProjData& fan_data) -{ +std::ostream& +operator<<(std::ostream& s, const FanProjData& fan_data) { return s << static_cast(fan_data); } -std::istream& operator>>(std::istream& s, FanProjData& fan_data) -{ +std::istream& +operator>>(std::istream& s, FanProjData& fan_data) { s >> static_cast(fan_data); if (!s) return s; fan_data.num_detectors_per_ring = fan_data.get_max_a() - fan_data.get_min_a() + 1; fan_data.num_rings = fan_data.get_max_ra() - fan_data.get_min_ra() + 1; - - //int max_delta = 0; - //for (int ra = 0; ra < fan_data.num_rings; ++ra) + + // int max_delta = 0; + // for (int ra = 0; ra < fan_data.num_rings; ++ra) // max_delta = max(max_delta,fan_data[ra][0].get_length()-1); - const int max_delta = fan_data[0][0].get_length()-1; - const int half_fan_size = - fan_data[0][0][0].get_length()/2; + const int max_delta = fan_data[0][0].get_length() - 1; + const int half_fan_size = fan_data[0][0][0].get_length() / 2; fan_data.half_fan_size = half_fan_size; fan_data.max_ring_diff = max_delta; - for (int ra = 0; ra < fan_data.num_rings; ++ra) - { - const int min_rb = max(ra-max_delta, 0); - const int max_rb = min(ra+max_delta, fan_data.num_rings-1); - for (int a = 0; a < fan_data.num_detectors_per_ring; ++a) - { - if (fan_data[ra][a].get_length() != max_rb - max(ra,min_rb) + 1) - { + for (int ra = 0; ra < fan_data.num_rings; ++ra) { + const int min_rb = max(ra - max_delta, 0); + const int max_rb = min(ra + max_delta, fan_data.num_rings - 1); + for (int a = 0; a < fan_data.num_detectors_per_ring; ++a) { + if (fan_data[ra][a].get_length() != max_rb - max(ra, min_rb) + 1) { warning("Reading FanProjData: inconsistent length %d for rb at ra=%d, a=%d, " - "Expected length %d\n", - fan_data[ra][a].get_length(), ra, a, max_rb - max(ra,min_rb) + 1); + "Expected length %d\n", + fan_data[ra][a].get_length(), ra, a, max_rb - max(ra, min_rb) + 1); } - fan_data[ra][a].set_offset(max(ra,min_rb)); - for (int rb = fan_data[ra][a].get_min_index(); rb <= fan_data[ra][a].get_max_index(); ++rb) - { - if (fan_data[ra][a][rb].get_length() != 2*half_fan_size+1) - { + fan_data[ra][a].set_offset(max(ra, min_rb)); + for (int rb = fan_data[ra][a].get_min_index(); rb <= fan_data[ra][a].get_max_index(); ++rb) { + if (fan_data[ra][a][rb].get_length() != 2 * half_fan_size + 1) { warning("Reading FanProjData: inconsistent length %d for b at ra=%d, a=%d, rb=%d\n" - "Expected length %d\n", - fan_data[ra][a][rb].get_length(), ra, a, rb, 2*half_fan_size+1); + "Expected length %d\n", + fan_data[ra][a][rb].get_length(), ra, a, rb, 2 * half_fan_size + 1); } - fan_data[ra][a][rb].set_offset(a+fan_data.num_detectors_per_ring/2-half_fan_size); + fan_data[ra][a][rb].set_offset(a + fan_data.num_detectors_per_ring / 2 - half_fan_size); } } } @@ -945,312 +821,274 @@ std::istream& operator>>(std::istream& s, FanProjData& fan_data) } shared_ptr -get_fan_info(int& num_rings, int& num_detectors_per_ring, - int& max_ring_diff, int& fan_size, - const ProjDataInfo& proj_data_info) -{ - const ProjDataInfoCylindricalNoArcCorr * const proj_data_info_ptr = - dynamic_cast(&proj_data_info); - if (proj_data_info_ptr == 0) - { +get_fan_info(int& num_rings, int& num_detectors_per_ring, int& max_ring_diff, int& fan_size, const ProjDataInfo& proj_data_info) { + const ProjDataInfoCylindricalNoArcCorr* const proj_data_info_ptr = + dynamic_cast(&proj_data_info); + if (proj_data_info_ptr == 0) { error("Can only process not arc-corrected data\n"); } - if (proj_data_info_ptr->get_view_mashing_factor()>1) - { + if (proj_data_info_ptr->get_view_mashing_factor() > 1) { error("Can only process data without mashing of views\n"); } - if (proj_data_info_ptr->get_max_ring_difference(0)>0) - { + if (proj_data_info_ptr->get_max_ring_difference(0) > 0) { error("Can only process data without axial compression (i.e. span=1)\n"); } - num_rings = - proj_data_info.get_scanner_ptr()->get_num_rings(); - num_detectors_per_ring = - proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); - const int half_fan_size = - min(proj_data_info.get_max_tangential_pos_num(), - -proj_data_info.get_min_tangential_pos_num()); - fan_size = 2*half_fan_size+1; + num_rings = proj_data_info.get_scanner_ptr()->get_num_rings(); + num_detectors_per_ring = proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); + const int half_fan_size = min(proj_data_info.get_max_tangential_pos_num(), -proj_data_info.get_min_tangential_pos_num()); + fan_size = 2 * half_fan_size + 1; max_ring_diff = proj_data_info_ptr->get_max_segment_num(); - shared_ptr - ret_value(dynamic_cast(proj_data_info_ptr->clone())); + shared_ptr ret_value( + dynamic_cast(proj_data_info_ptr->clone())); return ret_value; - } -void make_fan_data(FanProjData& fan_data, - const ProjData& proj_data) -{ +void +make_fan_data(FanProjData& fan_data, const ProjData& proj_data) { int num_rings; int num_detectors_per_ring; int fan_size; int max_delta; + + if (proj_data.get_proj_data_info_sptr()->is_tof_data()) + error("make_fan_data: Incompatible with TOF data. Abort."); + shared_ptr proj_data_info_ptr = - get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, - *proj_data.get_proj_data_info_sptr()); - const int half_fan_size = fan_size/2; - fan_data = FanProjData(num_rings, num_detectors_per_ring, max_delta, 2*half_fan_size+1); + get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data.get_proj_data_info_sptr()); - shared_ptr > segment_ptr; + const int half_fan_size = fan_size / 2; + fan_data = FanProjData(num_rings, num_detectors_per_ring, max_delta, 2 * half_fan_size + 1); + + shared_ptr> segment_ptr; Bin bin; - for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); ++ bin.segment_num()) - { - segment_ptr.reset(new SegmentBySinogram(proj_data.get_segment_by_sinogram(bin.segment_num()))); - - for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - for (bin.view_num() = 0; bin.view_num() < num_detectors_per_ring/2; bin.view_num()++) - for (bin.tangential_pos_num() = -half_fan_size; - bin.tangential_pos_num() <= half_fan_size; - ++bin.tangential_pos_num()) - { + for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); + ++bin.segment_num()) { + // for (bin.timing_pos_num() = proj_data.get_min_tof_pos_num(); bin.timing_pos_num() <= proj_data.get_max_tof_pos_num(); ++ + // bin.timing_pos_num()) + { + segment_ptr.reset( + new SegmentBySinogram(proj_data.get_segment_by_sinogram(bin.segment_num() /*,bin.timing_pos_num()*/))); + + for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + for (bin.view_num() = 0; bin.view_num() < num_detectors_per_ring / 2; bin.view_num()++) + for (bin.tangential_pos_num() = -half_fan_size; bin.tangential_pos_num() <= half_fan_size; ++bin.tangential_pos_num()) { int ra = 0, a = 0; int rb = 0, b = 0; - + proj_data_info_ptr->get_det_pair_for_bin(a, ra, b, rb, bin); - - fan_data(ra, a, rb, b) = - fan_data(rb, b, ra, a) = - (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()]; + + fan_data(ra, a, rb, b) = fan_data(rb, b, ra, a) = + (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()]; } + } } } /// **** This function make fan_data from projecion file while removing the intermodule gaps **** //// /// *** fan_data doesn't have gaps, proj_data has gaps *** /// -void make_fan_data_remove_gaps(FanProjData& fan_data, - const ProjData& proj_data) -{ - int num_rings; - int num_detectors_per_ring; - int fan_size; - int max_delta; - shared_ptr proj_data_info_ptr = - get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, - *proj_data.get_proj_data_info_sptr()); - - const int half_fan_size = fan_size/2; - - - // **** Added by me **** // - - - const int num_transaxial_blocks = - proj_data_info_ptr ->get_scanner_sptr()-> - get_num_transaxial_blocks(); - const int num_axial_blocks = - proj_data_info_ptr->get_scanner_sptr()-> - get_num_axial_blocks(); - const int num_transaxial_crystals_per_block = - proj_data_info_ptr->get_scanner_sptr()-> - get_num_transaxial_crystals_per_block(); - const int num_axial_crystals_per_block = - proj_data_info_ptr->get_scanner_sptr()-> - get_num_axial_crystals_per_block(); - - - - const int num_transaxial_blocks_in_fansize = fan_size/num_transaxial_crystals_per_block; - const int new_fan_size = fan_size - num_transaxial_blocks_in_fansize; - const int new_half_fan_size = new_fan_size/2; - const int num_axial_blocks_in_max_delta = max_delta/num_axial_crystals_per_block; - const int new_max_delta = max_delta - num_axial_blocks_in_max_delta - 1; - const int new_num_detectors_per_ring = num_detectors_per_ring - num_transaxial_blocks; - const int new_num_rings = num_rings - num_axial_blocks; - - // **** End **** // - - fan_data = FanProjData(new_num_rings, new_num_detectors_per_ring, new_max_delta, 2*new_half_fan_size+1); - - - shared_ptr > segment_ptr; - Bin bin; - - for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); ++ bin.segment_num()) - { - segment_ptr.reset(new SegmentBySinogram(proj_data.get_segment_by_sinogram(bin.segment_num()))); - - for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - for (bin.view_num() = 0; bin.view_num() < num_detectors_per_ring/2; bin.view_num()++) - for (bin.tangential_pos_num() = -half_fan_size; - bin.tangential_pos_num() <= half_fan_size; - ++bin.tangential_pos_num()) - { - int ra = 0, a = 0; - int rb = 0, b = 0; - - proj_data_info_ptr->get_det_pair_for_bin(a, ra, b, rb, bin); - int new_a = a - a/num_transaxial_crystals_per_block; - int new_b = b - b/num_transaxial_crystals_per_block; - int new_ra = ra - ra/ num_axial_crystals_per_block; - int new_rb = rb - rb/num_axial_crystals_per_block; - - if ((ra == num_rings -1) || (rb == num_rings -1) || (a == num_detectors_per_ring-1) || (b == num_detectors_per_ring-1)) continue; - - - fan_data(new_ra, new_a, new_rb, new_b) = - fan_data(new_rb, new_b, new_ra, new_a) = - (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()]; - } - } -} +void +make_fan_data_remove_gaps(FanProjData& fan_data, const ProjData& proj_data) { + int num_rings; + int num_detectors_per_ring; + int fan_size; + int max_delta; + shared_ptr proj_data_info_ptr = + get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data.get_proj_data_info_sptr()); + const int half_fan_size = fan_size / 2; -void set_fan_data(ProjData& proj_data, - const FanProjData& fan_data) -{ + // **** Added by me **** // + + const int num_transaxial_blocks = proj_data_info_ptr->get_scanner_sptr()->get_num_transaxial_blocks(); + const int num_axial_blocks = proj_data_info_ptr->get_scanner_sptr()->get_num_axial_blocks(); + const int num_transaxial_crystals_per_block = proj_data_info_ptr->get_scanner_sptr()->get_num_transaxial_crystals_per_block(); + const int num_axial_crystals_per_block = proj_data_info_ptr->get_scanner_sptr()->get_num_axial_crystals_per_block(); + + const int num_transaxial_blocks_in_fansize = fan_size / num_transaxial_crystals_per_block; + const int new_fan_size = fan_size - num_transaxial_blocks_in_fansize; + const int new_half_fan_size = new_fan_size / 2; + const int num_axial_blocks_in_max_delta = max_delta / num_axial_crystals_per_block; + const int new_max_delta = max_delta - num_axial_blocks_in_max_delta - 1; + const int new_num_detectors_per_ring = num_detectors_per_ring - num_transaxial_blocks; + const int new_num_rings = num_rings - num_axial_blocks; + + // **** End **** // + + fan_data = FanProjData(new_num_rings, new_num_detectors_per_ring, new_max_delta, 2 * new_half_fan_size + 1); + + shared_ptr> segment_ptr; + Bin bin; + + for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); + ++bin.segment_num()) { + segment_ptr.reset(new SegmentBySinogram(proj_data.get_segment_by_sinogram(bin.segment_num()))); + + for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + for (bin.view_num() = 0; bin.view_num() < num_detectors_per_ring / 2; bin.view_num()++) + for (bin.tangential_pos_num() = -half_fan_size; bin.tangential_pos_num() <= half_fan_size; ++bin.tangential_pos_num()) { + int ra = 0, a = 0; + int rb = 0, b = 0; + + proj_data_info_ptr->get_det_pair_for_bin(a, ra, b, rb, bin); + int new_a = a - a / num_transaxial_crystals_per_block; + int new_b = b - b / num_transaxial_crystals_per_block; + int new_ra = ra - ra / num_axial_crystals_per_block; + int new_rb = rb - rb / num_axial_crystals_per_block; + + if ((ra == num_rings - 1) || (rb == num_rings - 1) || (a == num_detectors_per_ring - 1) || + (b == num_detectors_per_ring - 1)) + continue; + + fan_data(new_ra, new_a, new_rb, new_b) = fan_data(new_rb, new_b, new_ra, new_a) = + (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()]; + } + } +} + +void +set_fan_data(ProjData& proj_data, const FanProjData& fan_data) { int num_rings; int num_detectors_per_ring; int fan_size; int max_delta; + + if (proj_data.get_proj_data_info_sptr()->is_tof_data()) + error("make_fan_data: Incompatible with TOF data. Abort."); + shared_ptr proj_data_info_ptr = - get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, - *proj_data.get_proj_data_info_sptr()); - const int half_fan_size = fan_size/2; + get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data.get_proj_data_info_sptr()); + + const int half_fan_size = fan_size / 2; assert(num_rings == fan_data.get_num_rings()); assert(num_detectors_per_ring == fan_data.get_num_detectors_per_ring()); Bin bin; - shared_ptr > segment_ptr; - - for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); ++ bin.segment_num()) - { - segment_ptr.reset(new SegmentBySinogram(proj_data.get_empty_segment_by_sinogram(bin.segment_num()))); - - for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - for (bin.view_num() = 0; bin.view_num() < num_detectors_per_ring/2; bin.view_num()++) - for (bin.tangential_pos_num() = -half_fan_size; - bin.tangential_pos_num() <= half_fan_size; - ++bin.tangential_pos_num()) - { + shared_ptr> segment_ptr; + + for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); + ++bin.segment_num()) { + // for (bin.timing_pos_num() = proj_data.get_min_tof_pos_num(); bin.timing_pos_num() <= proj_data.get_max_tof_pos_num(); ++ + // bin.timing_pos_num()) + { + segment_ptr.reset( + new SegmentBySinogram(proj_data.get_empty_segment_by_sinogram(bin.segment_num() /*,bin.timing_pos_num()*/))); + + for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + for (bin.view_num() = 0; bin.view_num() < num_detectors_per_ring / 2; bin.view_num()++) + for (bin.tangential_pos_num() = -half_fan_size; bin.tangential_pos_num() <= half_fan_size; ++bin.tangential_pos_num()) { int ra = 0, a = 0; int rb = 0, b = 0; - + proj_data_info_ptr->get_det_pair_for_bin(a, ra, b, rb, bin); - - (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()] = - fan_data(ra, a, rb, b); + + (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()] = fan_data(ra, a, rb, b); } - proj_data.set_segment(*segment_ptr); + proj_data.set_segment(*segment_ptr); + } } } /// **** This function make proj_data from fan_data while adding the intermodule gaps **** //// /// *** fan_data doesn't have gaps, proj_data has gaps *** /// -void set_fan_data_add_gaps(ProjData& proj_data, - const FanProjData& fan_data) -{ - int num_rings; - int num_detectors_per_ring; - int fan_size; - int max_delta; - shared_ptr proj_data_info_ptr = - get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, - *proj_data.get_proj_data_info_sptr()); - - const int half_fan_size = fan_size/2; - //assert(num_rings == fan_data.get_num_rings()); - //assert(num_detectors_per_ring == fan_data.get_num_detectors_per_ring()); - - - // **** Added by Tahereh Nikjenad **** // - - const int num_transaxial_crystals_per_block = - proj_data_info_ptr->get_scanner_sptr()-> - get_num_transaxial_crystals_per_block(); - const int num_axial_crystals_per_block = - proj_data_info_ptr->get_scanner_sptr()-> - get_num_axial_crystals_per_block(); - - // const int num_axial_detectors = fan_data.get_num_rings(); // Number of ring in fan data (w/o gaps) - // const int num_transaxial_detectors = fan_data.get_num_detectors_per_ring(); // number of detector per ring in fan data w/o gaps - - // const int num_axial_crystals_per_block = num_axial_detectors/num_axial_blocks; // number of axial detector per block in fan_data w/o gaps - // const int num_transaxial_crystals_per_block = num_transaxial_detectors/num_transaxial_blocks; // number of transaxial detector per block in fan_data w/o gaps - - - // **** End **** // - - Bin bin; - shared_ptr > segment_ptr; - - for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); ++ bin.segment_num()) - { - segment_ptr.reset(new SegmentBySinogram(proj_data.get_empty_segment_by_sinogram(bin.segment_num()))); - - for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - for (bin.view_num() = 0; bin.view_num() < num_detectors_per_ring/2; bin.view_num()++) - for (bin.tangential_pos_num() = -half_fan_size; - bin.tangential_pos_num() <= half_fan_size; - ++bin.tangential_pos_num()) - { - int ra = 0, a = 0; - int rb = 0, b = 0; - - proj_data_info_ptr->get_det_pair_for_bin(a, ra, b, rb, bin); - - (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()] = 1e20; - - - if ((ra+1)% num_axial_crystals_per_block == 0) continue; - if ((rb+1)% num_axial_crystals_per_block == 0) continue; - if ((a+1)% num_transaxial_crystals_per_block == 0) continue; - if ((b+1)% num_transaxial_crystals_per_block == 0) continue; - - int new_a = a - a/num_transaxial_crystals_per_block; - int new_b = b - b/num_transaxial_crystals_per_block; - int new_ra = ra - ra/ num_axial_crystals_per_block; - int new_rb = rb - rb/num_axial_crystals_per_block; - - - (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()] = - fan_data(new_ra, new_a, new_rb, new_b); - } - proj_data.set_segment(*segment_ptr); - } -} +void +set_fan_data_add_gaps(ProjData& proj_data, const FanProjData& fan_data) { + int num_rings; + int num_detectors_per_ring; + int fan_size; + int max_delta; + shared_ptr proj_data_info_ptr = + get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data.get_proj_data_info_sptr()); + const int half_fan_size = fan_size / 2; + // assert(num_rings == fan_data.get_num_rings()); + // assert(num_detectors_per_ring == fan_data.get_num_detectors_per_ring()); -void apply_block_norm(FanProjData& fan_data, const BlockData3D& block_data, const bool apply) -{ + // **** Added by Tahereh Nikjenad **** // + + const int num_transaxial_crystals_per_block = proj_data_info_ptr->get_scanner_sptr()->get_num_transaxial_crystals_per_block(); + const int num_axial_crystals_per_block = proj_data_info_ptr->get_scanner_sptr()->get_num_axial_crystals_per_block(); + + // const int num_axial_detectors = fan_data.get_num_rings(); // Number of ring in fan data (w/o gaps) + // const int num_transaxial_detectors = fan_data.get_num_detectors_per_ring(); // number of detector per ring in fan data w/o + // gaps + + // const int num_axial_crystals_per_block = num_axial_detectors/num_axial_blocks; // number of axial detector per block in + // fan_data w/o gaps const int num_transaxial_crystals_per_block = num_transaxial_detectors/num_transaxial_blocks; // number of + // transaxial detector per block in fan_data w/o gaps + + // **** End **** // + + Bin bin; + shared_ptr> segment_ptr; + + for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); + ++bin.segment_num()) { + segment_ptr.reset(new SegmentBySinogram(proj_data.get_empty_segment_by_sinogram(bin.segment_num()))); + + for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + for (bin.view_num() = 0; bin.view_num() < num_detectors_per_ring / 2; bin.view_num()++) + for (bin.tangential_pos_num() = -half_fan_size; bin.tangential_pos_num() <= half_fan_size; ++bin.tangential_pos_num()) { + int ra = 0, a = 0; + int rb = 0, b = 0; + + proj_data_info_ptr->get_det_pair_for_bin(a, ra, b, rb, bin); + + (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()] = 1e20; + + if ((ra + 1) % num_axial_crystals_per_block == 0) + continue; + if ((rb + 1) % num_axial_crystals_per_block == 0) + continue; + if ((a + 1) % num_transaxial_crystals_per_block == 0) + continue; + if ((b + 1) % num_transaxial_crystals_per_block == 0) + continue; + + int new_a = a - a / num_transaxial_crystals_per_block; + int new_b = b - b / num_transaxial_crystals_per_block; + int new_ra = ra - ra / num_axial_crystals_per_block; + int new_rb = rb - rb / num_axial_crystals_per_block; + + (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()] = fan_data(new_ra, new_a, new_rb, new_b); + } + proj_data.set_segment(*segment_ptr); + } +} + +void +apply_block_norm(FanProjData& fan_data, const BlockData3D& block_data, const bool apply) { const int num_axial_detectors = fan_data.get_num_rings(); const int num_tangential_detectors = fan_data.get_num_detectors_per_ring(); const int num_axial_blocks = block_data.get_num_rings(); const int num_tangential_blocks = block_data.get_num_detectors_per_ring(); - const int num_axial_crystals_per_block = num_axial_detectors/num_axial_blocks; + const int num_axial_crystals_per_block = num_axial_detectors / num_axial_blocks; assert(num_axial_blocks * num_axial_crystals_per_block == num_axial_detectors); - const int num_tangential_crystals_per_block = num_tangential_detectors/num_tangential_blocks; + const int num_tangential_crystals_per_block = num_tangential_detectors / num_tangential_blocks; assert(num_tangential_blocks * num_tangential_crystals_per_block == num_tangential_detectors); - + for (int ra = fan_data.get_min_ra(); ra <= fan_data.get_max_ra(); ++ra) for (int a = fan_data.get_min_a(); a <= fan_data.get_max_a(); ++a) // loop rb from ra to avoid double counting - for (int rb = max(ra,fan_data.get_min_rb(ra)); rb <= fan_data.get_max_rb(ra); ++rb) - for (int b = fan_data.get_min_b(a); b <= fan_data.get_max_b(a); ++b) - { - // note: add 2*num_detectors_per_ring to newb to avoid using mod with negative numbers - if (fan_data(ra,a,rb,b) == 0) - continue; - if (apply) - fan_data(ra,a,rb,b) *= - block_data(ra/num_axial_crystals_per_block,a/num_tangential_crystals_per_block, - rb/num_axial_crystals_per_block,b/num_tangential_crystals_per_block); - else - fan_data(ra,a,rb,b) /= - block_data(ra/num_axial_crystals_per_block,a/num_tangential_crystals_per_block, - rb/num_axial_crystals_per_block,b/num_tangential_crystals_per_block); - } + for (int rb = max(ra, fan_data.get_min_rb(ra)); rb <= fan_data.get_max_rb(ra); ++rb) + for (int b = fan_data.get_min_b(a); b <= fan_data.get_max_b(a); ++b) { + // note: add 2*num_detectors_per_ring to newb to avoid using mod with negative numbers + if (fan_data(ra, a, rb, b) == 0) + continue; + if (apply) + fan_data(ra, a, rb, b) *= block_data(ra / num_axial_crystals_per_block, a / num_tangential_crystals_per_block, + rb / num_axial_crystals_per_block, b / num_tangential_crystals_per_block); + else + fan_data(ra, a, rb, b) /= block_data(ra / num_axial_crystals_per_block, a / num_tangential_crystals_per_block, + rb / num_axial_crystals_per_block, b / num_tangential_crystals_per_block); + } } #if 0 @@ -1283,416 +1121,366 @@ void apply_geo_norm(FanProjData& fan_data, const GeoData& geo_data, const bool a } #endif -void apply_geo_norm(FanProjData& fan_data, const GeoData3D& geo_data, const bool apply) -{ - - const int num_axial_detectors = fan_data.get_num_rings(); - const int num_transaxial_detectors = fan_data.get_num_detectors_per_ring(); - const int num_axial_crystals_per_block = geo_data.get_num_axial_crystals_per_block(); - const int num_transaxial_crystals_per_block = geo_data.get_half_num_transaxial_crystals_per_block()*2; - - const int num_transaxial_blocks = num_transaxial_detectors/num_transaxial_crystals_per_block; - const int num_axial_blocks = num_axial_detectors/num_axial_crystals_per_block; - - FanProjData work = fan_data; - work.fill(0); - - - for (int ra = 0; ra < num_axial_crystals_per_block; ++ra) - for (int a = 0; a < num_transaxial_crystals_per_block /2; ++a) - // loop rb from ra to avoid double counting - for (int rb = max(ra,fan_data.get_min_rb(ra)); rb <= fan_data.get_max_rb(ra); ++rb) - for (int b = fan_data.get_min_b(a); b <= fan_data.get_max_b(a); ++b) - { - - - // rotation - - for (int axial_block_num = 0; axial_block_num& data_fan_sums, const FanProjData& fan_data) -{ +void +make_fan_sum_data(Array<2, float>& data_fan_sums, const FanProjData& fan_data) { for (int ra = fan_data.get_min_ra(); ra <= fan_data.get_max_ra(); ++ra) for (int a = fan_data.get_min_a(); a <= fan_data.get_max_a(); ++a) - data_fan_sums[ra][a] = fan_data.sum(ra,a); + data_fan_sums[ra][a] = fan_data.sum(ra, a); } -void make_fan_sum_data(Array<2,float>& data_fan_sums, - const ProjData& proj_data) -{ +void +make_fan_sum_data(Array<2, float>& data_fan_sums, const ProjData& proj_data) { int num_rings; int num_detectors_per_ring; int fan_size; int max_delta; + + if (proj_data.get_proj_data_info_sptr()->is_tof_data()) + error("make_fan_data: Incompatible with TOF data. Abort."); + shared_ptr proj_data_info_ptr = - get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, - *proj_data.get_proj_data_info_sptr()); - const int half_fan_size = fan_size/2; + + get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data.get_proj_data_info_sptr()); + const int half_fan_size = fan_size / 2; data_fan_sums.fill(0); - shared_ptr > segment_ptr; + shared_ptr> segment_ptr; Bin bin; - for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); ++ bin.segment_num()) - { - segment_ptr.reset(new SegmentBySinogram(proj_data.get_segment_by_sinogram(bin.segment_num()))); - - for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - for (bin.view_num() = 0; bin.view_num() < num_detectors_per_ring/2; bin.view_num()++) - for (bin.tangential_pos_num() = -half_fan_size; - bin.tangential_pos_num() <= half_fan_size; - ++bin.tangential_pos_num()) - { + for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); + ++bin.segment_num()) { + // for (bin.timing_pos_num() = proj_data.get_min_tof_pos_num(); bin.timing_pos_num() <= proj_data.get_max_tof_pos_num(); ++ + // bin.timing_pos_num()) + { + segment_ptr.reset( + new SegmentBySinogram(proj_data.get_segment_by_sinogram(bin.segment_num() /*,bin.timing_pos_num()*/))); + + for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + for (bin.view_num() = 0; bin.view_num() < num_detectors_per_ring / 2; bin.view_num()++) + for (bin.tangential_pos_num() = -half_fan_size; bin.tangential_pos_num() <= half_fan_size; ++bin.tangential_pos_num()) { int ra = 0, a = 0; int rb = 0, b = 0; - + proj_data_info_ptr->get_det_pair_for_bin(a, ra, b, rb, bin); - const float value = - (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()]; - data_fan_sums[ra][a] += value; - data_fan_sums[rb][b] += value; + const float value = (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()]; + data_fan_sums[ra][a] += value; + data_fan_sums[rb][b] += value; } + } } } -void make_fan_sum_data(Array<2,float>& data_fan_sums, - const DetectorEfficiencies& efficiencies, - const int max_ring_diff, const int half_fan_size) -{ +void +make_fan_sum_data(Array<2, float>& data_fan_sums, const DetectorEfficiencies& efficiencies, const int max_ring_diff, + const int half_fan_size) { const int num_rings = data_fan_sums.get_length(); - assert(data_fan_sums.get_min_index()==0); - const int num_detectors_per_ring = - data_fan_sums[0].get_length(); + assert(data_fan_sums.get_min_index() == 0); + const int num_detectors_per_ring = data_fan_sums[0].get_length(); for (int ra = data_fan_sums.get_min_index(); ra <= data_fan_sums.get_max_index(); ++ra) - for (int a = data_fan_sums[ra].get_min_index(); a <= data_fan_sums[ra].get_max_index(); ++a) - { - float fan_sum = 0; - for (int rb = max(ra-max_ring_diff, 0); rb <= min(ra+max_ring_diff, num_rings-1); ++rb) - for (int b = a+num_detectors_per_ring/2-half_fan_size; b <= a+num_detectors_per_ring/2+half_fan_size; ++b) - fan_sum += efficiencies[rb][b%num_detectors_per_ring]; - data_fan_sums[ra][a] = efficiencies[ra][a]*fan_sum; - } + for (int a = data_fan_sums[ra].get_min_index(); a <= data_fan_sums[ra].get_max_index(); ++a) { + float fan_sum = 0; + for (int rb = max(ra - max_ring_diff, 0); rb <= min(ra + max_ring_diff, num_rings - 1); ++rb) + for (int b = a + num_detectors_per_ring / 2 - half_fan_size; b <= a + num_detectors_per_ring / 2 + half_fan_size; ++b) + fan_sum += efficiencies[rb][b % num_detectors_per_ring]; + data_fan_sums[ra][a] = efficiencies[ra][a] * fan_sum; + } } +void +make_geo_data(GeoData3D& geo_data, const FanProjData& fan_data) { -void make_geo_data(GeoData3D& geo_data, const FanProjData& fan_data) -{ - - const int num_axial_detectors = fan_data.get_num_rings(); - const int num_transaxial_detectors = fan_data.get_num_detectors_per_ring(); - const int num_axial_crystals_per_block = geo_data.get_num_axial_crystals_per_block(); - const int num_transaxial_crystals_per_block = geo_data.get_half_num_transaxial_crystals_per_block()*2; - const int num_transaxial_blocks = num_transaxial_detectors/num_transaxial_crystals_per_block; - const int num_axial_blocks = num_axial_detectors/num_axial_crystals_per_block; - - - // transaxial and axial mirroring - - FanProjData work = fan_data; - work.fill(0); - - for (int ra = fan_data.get_min_ra(); ra <= fan_data.get_max_ra(); ++ra) - for (int a = fan_data.get_min_a(); a <= fan_data.get_max_a(); ++a) - //1// for (int rb = fan_data.get_min_ra(); rb <= fan_data.get_max_ra(); ++rb) - for (int rb = max(ra,fan_data.get_min_rb(ra)); rb <= fan_data.get_max_rb(ra); ++rb) - for (int b = fan_data.get_min_b(a); b <= fan_data.get_max_b(a); ++b) - { - - const int ma = num_transaxial_detectors-1-a; - const int mb = (2*num_transaxial_detectors-1-b)%num_transaxial_detectors; - const int mra = num_axial_detectors-1-ra; - const int mrb = (num_axial_detectors-1-rb); - - - if (ra!=mra && rb !=mrb) - work(ra,a,rb,b)= fan_data(ra,a,rb,b) + fan_data(ra,ma,rb,mb) + fan_data(mra,a,mrb,b) + fan_data(mra,ma,mrb,mb); - else - work(ra,a,rb,b)= fan_data(ra,a,rb,b) + fan_data(ra,ma,rb,mb); - - } - - - geo_data.fill(0); - - - for (int ra = 0; ra < num_axial_crystals_per_block; ++ra) - // for (int a = 0; a <= num_transaxial_detectors/2; ++a) - for (int a = 0; a & data_fan_sums, - const FanProjData& model) -{ +void +iterate_efficiencies(DetectorEfficiencies& efficiencies, const Array<2, float>& data_fan_sums, const FanProjData& model) { const int num_detectors_per_ring = model.get_num_detectors_per_ring(); - + assert(model.get_min_ra() == data_fan_sums.get_min_index()); assert(model.get_max_ra() == data_fan_sums.get_max_index()); assert(model.get_min_a() == data_fan_sums[data_fan_sums.get_min_index()].get_min_index()); assert(model.get_max_a() == data_fan_sums[data_fan_sums.get_min_index()].get_max_index()); for (int ra = model.get_min_ra(); ra <= model.get_max_ra(); ++ra) - for (int a = model.get_min_a(); a <= model.get_max_a(); ++a) - { + for (int a = model.get_min_a(); a <= model.get_max_a(); ++a) { if (data_fan_sums[ra][a] == 0) - efficiencies[ra][a] = 0; - else - { - float denominator = 0; - for (int rb = model.get_min_rb(ra); rb <= model.get_max_rb(ra); ++rb) - for (int b = model.get_min_b(a); b <= model.get_max_b(a); ++b) - denominator += efficiencies[rb][b%num_detectors_per_ring]*model(ra,a,rb,b); - efficiencies[ra][a] = data_fan_sums[ra][a] / denominator; - } + efficiencies[ra][a] = 0; + else { + float denominator = 0; + for (int rb = model.get_min_rb(ra); rb <= model.get_max_rb(ra); ++rb) + for (int b = model.get_min_b(a); b <= model.get_max_b(a); ++b) + denominator += efficiencies[rb][b % num_detectors_per_ring] * model(ra, a, rb, b); + efficiencies[ra][a] = data_fan_sums[ra][a] / denominator; + } } } // version without model -void iterate_efficiencies(DetectorEfficiencies& efficiencies, - const Array<2,float>& data_fan_sums, - const int max_ring_diff, const int half_fan_size) -{ +void +iterate_efficiencies(DetectorEfficiencies& efficiencies, const Array<2, float>& data_fan_sums, const int max_ring_diff, + const int half_fan_size) { const int num_rings = data_fan_sums.get_length(); const int num_detectors_per_ring = data_fan_sums[data_fan_sums.get_min_index()].get_length(); #ifdef WRITE_ALL static int sub_iter_num = 0; #endif for (int ra = data_fan_sums.get_min_index(); ra <= data_fan_sums.get_max_index(); ++ra) - for (int a = data_fan_sums[ra].get_min_index(); a <= data_fan_sums[ra].get_max_index(); ++a) - { + for (int a = data_fan_sums[ra].get_min_index(); a <= data_fan_sums[ra].get_max_index(); ++a) { if (data_fan_sums[ra][a] == 0) - efficiencies[ra][a] = 0; - else - { - float denominator = 0; - for (int rb = max(ra-max_ring_diff, 0); rb <= min(ra+max_ring_diff, num_rings-1); ++rb) - for (int b = a+num_detectors_per_ring/2-half_fan_size; b <= a+num_detectors_per_ring/2+half_fan_size; ++b) - denominator += efficiencies[rb][b%num_detectors_per_ring]; - efficiencies[ra][a] = data_fan_sums[ra][a] / denominator; - } + efficiencies[ra][a] = 0; + else { + float denominator = 0; + for (int rb = max(ra - max_ring_diff, 0); rb <= min(ra + max_ring_diff, num_rings - 1); ++rb) + for (int b = a + num_detectors_per_ring / 2 - half_fan_size; b <= a + num_detectors_per_ring / 2 + half_fan_size; ++b) + denominator += efficiencies[rb][b % num_detectors_per_ring]; + efficiencies[ra][a] = data_fan_sums[ra][a] / denominator; + } #ifdef WRITE_ALL - { - char out_filename[100]; - sprintf(out_filename, "MLresult_subiter_eff_1_%d.out", - sub_iter_num++); - ofstream out(out_filename); - if (!out) - { - warning("Error opening output file %s\n", out_filename); - exit(EXIT_FAILURE); - } - out << efficiencies; - if (!out) - { - warning("Error writing data to output file %s\n", out_filename); - exit(EXIT_FAILURE); - } - } + { + char out_filename[100]; + sprintf(out_filename, "MLresult_subiter_eff_1_%d.out", sub_iter_num++); + ofstream out(out_filename); + if (!out) { + warning("Error opening output file %s\n", out_filename); + exit(EXIT_FAILURE); + } + out << efficiencies; + if (!out) { + warning("Error writing data to output file %s\n", out_filename); + exit(EXIT_FAILURE); + } + } #endif } } -void iterate_geo_norm(GeoData3D& norm_geo_data, - const GeoData3D& measured_geo_data, - const FanProjData& model) -{ - make_geo_data(norm_geo_data, model); - //norm_geo_data = measured_geo_data / norm_geo_data; - - const int num_axial_crystals_per_block = measured_geo_data.get_num_axial_crystals_per_block(); - const int num_transaxial_crystals_per_block = measured_geo_data.get_half_num_transaxial_crystals_per_block()*2; - - const float threshold = measured_geo_data.find_max()/10000.F; - - for (int ra = 0; ra < num_axial_crystals_per_block; ++ra) - for (int a = 0; a =threshold || measured_geo_data(ra,a,rb,b) < 10000*norm_geo_data(ra,a,rb,b))? measured_geo_data(ra,a,rb,b) / norm_geo_data(ra,a,rb,b) - : 0; - } +void +iterate_geo_norm(GeoData3D& norm_geo_data, const GeoData3D& measured_geo_data, const FanProjData& model) { + make_geo_data(norm_geo_data, model); + // norm_geo_data = measured_geo_data / norm_geo_data; + + const int num_axial_crystals_per_block = measured_geo_data.get_num_axial_crystals_per_block(); + const int num_transaxial_crystals_per_block = measured_geo_data.get_half_num_transaxial_crystals_per_block() * 2; + + const float threshold = measured_geo_data.find_max() / 10000.F; + + for (int ra = 0; ra < num_axial_crystals_per_block; ++ra) + for (int a = 0; a < num_transaxial_crystals_per_block / 2; ++a) + // loop rb from ra to avoid double counting + // for (int rb = model.get_min_ra(); rb <= model.get_max_ra(); ++rb) + for (int rb = max(ra, model.get_min_rb(ra)); rb <= model.get_max_rb(ra); ++rb) + for (int b = model.get_min_b(a); b <= model.get_max_b(a); ++b) { + + norm_geo_data(ra, a, rb, b) = (measured_geo_data(ra, a, rb, b) >= threshold || + measured_geo_data(ra, a, rb, b) < 10000 * norm_geo_data(ra, a, rb, b)) + ? measured_geo_data(ra, a, rb, b) / norm_geo_data(ra, a, rb, b) + : 0; + } } -void iterate_block_norm(BlockData3D& norm_block_data, - const BlockData3D& measured_block_data, - const FanProjData& model) -{ +void +iterate_block_norm(BlockData3D& norm_block_data, const BlockData3D& measured_block_data, const FanProjData& model) { make_block_data(norm_block_data, model); - //norm_block_data = measured_block_data / norm_block_data; - const float threshold = measured_block_data.find_max()/10000.F; + // norm_block_data = measured_block_data / norm_block_data; + const float threshold = measured_block_data.find_max() / 10000.F; for (int ra = norm_block_data.get_min_ra(); ra <= norm_block_data.get_max_ra(); ++ra) for (int a = norm_block_data.get_min_a(); a <= norm_block_data.get_max_a(); ++a) // loop rb from ra to avoid double counting - for (int rb = max(ra,norm_block_data.get_min_rb(ra)); rb <= norm_block_data.get_max_rb(ra); ++rb) - for (int b = norm_block_data.get_min_b(a); b <= norm_block_data.get_max_b(a); ++b) - { - norm_block_data(ra,a,rb,b) = - (measured_block_data(ra,a,rb,b)>=threshold || - measured_block_data(ra,a,rb,b) < 10000*norm_block_data(ra,a,rb,b)) - ? measured_block_data(ra,a,rb,b) / norm_block_data(ra,a,rb,b) - : 0; - } + for (int rb = max(ra, norm_block_data.get_min_rb(ra)); rb <= norm_block_data.get_max_rb(ra); ++rb) + for (int b = norm_block_data.get_min_b(a); b <= norm_block_data.get_max_b(a); ++b) { + norm_block_data(ra, a, rb, b) = (measured_block_data(ra, a, rb, b) >= threshold || + measured_block_data(ra, a, rb, b) < 10000 * norm_block_data(ra, a, rb, b)) + ? measured_block_data(ra, a, rb, b) / norm_block_data(ra, a, rb, b) + : 0; + } } - -double KL(const FanProjData& d1, const FanProjData& d2, const double threshold) -{ - double sum=0; - for (int ra = d1.get_min_ra(); ra <= d1.get_max_ra(); ++ra) - { - double asum=0; - for (int a = d1.get_min_a(); a <= d1.get_max_a(); ++a) - { - double rbsum=0; - for (int rb = max(ra,d1.get_min_rb(ra)); rb <= d1.get_max_rb(ra); ++rb) - { - double bsum=0; - for (int b = d1.get_min_b(a); b <= d1.get_max_b(a); ++b) - bsum += static_cast(KL(d1(ra,a,rb,b), d2(ra,a,rb,b), threshold)); - rbsum += bsum; - } - asum += rbsum; - } - sum += asum; +double +KL(const FanProjData& d1, const FanProjData& d2, const double threshold) { + double sum = 0; + for (int ra = d1.get_min_ra(); ra <= d1.get_max_ra(); ++ra) { + double asum = 0; + for (int a = d1.get_min_a(); a <= d1.get_max_a(); ++a) { + double rbsum = 0; + for (int rb = max(ra, d1.get_min_rb(ra)); rb <= d1.get_max_rb(ra); ++rb) { + double bsum = 0; + for (int b = d1.get_min_b(a); b <= d1.get_max_b(a); ++b) + bsum += static_cast(KL(d1(ra, a, rb, b), d2(ra, a, rb, b), threshold)); + rbsum += bsum; + } + asum += rbsum; } + sum += asum; + } return static_cast(sum); } @@ -1704,19 +1492,19 @@ double KL(const FanProjData& d1, const FanProjData& d2, const double threshold) const int num_transaxial_crystals_per_block = d1.get_half_num_transaxial_crystals_per_block()*2; double sum=0; - + for (int ra = 0; ra < num_axial_crystals_per_block; ++ra) - { - double asum=0; - for (int a = 0; a (KL(d1(ra,a,rb,b), d2(ra,a,rb,b), threshold)); rbsum += bsum; } @@ -1727,6 +1515,5 @@ double KL(const FanProjData& d1, const FanProjData& d2, const double threshold) return static_cast(sum); } */ - END_NAMESPACE_STIR diff --git a/src/buildblock/MaximalArrayFilter3D.cxx b/src/buildblock/MaximalArrayFilter3D.cxx index 8dad72e64a..f5addc5a59 100644 --- a/src/buildblock/MaximalArrayFilter3D.cxx +++ b/src/buildblock/MaximalArrayFilter3D.cxx @@ -2,17 +2,17 @@ Copyright (C) 2006 - 2007, Hammersmith Imanet Ltd Copyright (C) 2010 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! @@ -32,16 +32,14 @@ START_NAMESPACE_STIR template -MaximalArrayFilter3D::MaximalArrayFilter3D(const Coordinate3D& mask_radius) -{ +MaximalArrayFilter3D::MaximalArrayFilter3D(const Coordinate3D& mask_radius) { this->mask_radius_x = mask_radius[3]; this->mask_radius_y = mask_radius[2]; this->mask_radius_z = mask_radius[1]; } template -MaximalArrayFilter3D::MaximalArrayFilter3D() -{ +MaximalArrayFilter3D::MaximalArrayFilter3D() { this->mask_radius_x = 0; this->mask_radius_y = 0; this->mask_radius_z = 0; @@ -49,61 +47,50 @@ MaximalArrayFilter3D::MaximalArrayFilter3D() template int -MaximalArrayFilter3D:: -extract_neighbours(Array<1,elemT>& neigbours,const Array<3,elemT>& in_array,const Coordinate3D& c_pixel) const -{ - int index=0; - - for (int zi =-mask_radius_z;zi<= mask_radius_z;++zi) - { - const int z = c_pixel[1]+zi; - if (z in_array.get_max_index()) - continue; - for (int yi =-mask_radius_y;yi<= mask_radius_y;++yi) - { - const int y = c_pixel[2]+yi; - if (y in_array[z].get_max_index()) - continue; - for( int xi=-mask_radius_x;xi<= mask_radius_x;++xi) - { - const int x = c_pixel[3]+xi; - if (x in_array[z][y].get_max_index()) - continue; - neigbours[index++] = in_array[z][y][x]; - } - } +MaximalArrayFilter3D::extract_neighbours(Array<1, elemT>& neigbours, const Array<3, elemT>& in_array, + const Coordinate3D& c_pixel) const { + int index = 0; + + for (int zi = -mask_radius_z; zi <= mask_radius_z; ++zi) { + const int z = c_pixel[1] + zi; + if (z < in_array.get_min_index() || z > in_array.get_max_index()) + continue; + for (int yi = -mask_radius_y; yi <= mask_radius_y; ++yi) { + const int y = c_pixel[2] + yi; + if (y < in_array[z].get_min_index() || y > in_array[z].get_max_index()) + continue; + for (int xi = -mask_radius_x; xi <= mask_radius_x; ++xi) { + const int x = c_pixel[3] + xi; + if (x < in_array[z][y].get_min_index() || x > in_array[z][y].get_max_index()) + continue; + neigbours[index++] = in_array[z][y][x]; + } } + } return index; } template void -MaximalArrayFilter3D:: -do_it(Array<3,elemT>& out_array, const Array<3,elemT>& in_array) const -{ +MaximalArrayFilter3D::do_it(Array<3, elemT>& out_array, const Array<3, elemT>& in_array) const { assert(out_array.get_index_range() == in_array.get_index_range()); - Array<1,elemT> neighbours (0,(2*mask_radius_x+1)*(2*mask_radius_y+1)*(2*mask_radius_z+1)-1); - - for (int z=out_array.get_min_index();z<= out_array.get_max_index();++z) - for (int y=out_array[z].get_min_index();y <= out_array[z].get_max_index();++y) - for (int x=out_array[z][y].get_min_index();x <= out_array[z][y].get_max_index();++x) - { - const int num_neighbours = - extract_neighbours(neighbours,in_array,Coordinate3D(z,y,x)); - if (num_neighbours==0) - continue; - out_array[z][y][x] = - *std::max_element(neighbours.begin(), neighbours.begin() + num_neighbours); - } + Array<1, elemT> neighbours(0, (2 * mask_radius_x + 1) * (2 * mask_radius_y + 1) * (2 * mask_radius_z + 1) - 1); + + for (int z = out_array.get_min_index(); z <= out_array.get_max_index(); ++z) + for (int y = out_array[z].get_min_index(); y <= out_array[z].get_max_index(); ++y) + for (int x = out_array[z][y].get_min_index(); x <= out_array[z][y].get_max_index(); ++x) { + const int num_neighbours = extract_neighbours(neighbours, in_array, Coordinate3D(z, y, x)); + if (num_neighbours == 0) + continue; + out_array[z][y][x] = *std::max_element(neighbours.begin(), neighbours.begin() + num_neighbours); + } } template bool -MaximalArrayFilter3D:: -is_trivial() const -{ - if (mask_radius_x!=1 &&mask_radius_y !=1 &&mask_radius_z!=1) +MaximalArrayFilter3D::is_trivial() const { + if (mask_radius_x != 1 && mask_radius_y != 1 && mask_radius_z != 1) return true; else return false; diff --git a/src/buildblock/MaximalImageFilter3D.cxx b/src/buildblock/MaximalImageFilter3D.cxx index 3513efe420..fc2b16fe45 100644 --- a/src/buildblock/MaximalImageFilter3D.cxx +++ b/src/buildblock/MaximalImageFilter3D.cxx @@ -2,24 +2,24 @@ Copyright (C) 2006 - 2007, Hammersmith Imanet Ltd Copyright (C) 2010 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! \file \ingroup ImageProcessor \brief Implementations for class stir::MaximalImageFilter3D - + \author Charalampos Tsoumpas \author Kris Thielemans @@ -29,56 +29,48 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/DiscretisedDensity.h" - START_NAMESPACE_STIR template -MaximalImageFilter3D:: MaximalImageFilter3D(const CartesianCoordinate3D& mask_radius) -{ +MaximalImageFilter3D::MaximalImageFilter3D(const CartesianCoordinate3D& mask_radius) { mask_radius_x = mask_radius.x(); mask_radius_y = mask_radius.y(); mask_radius_z = mask_radius.z(); } template -MaximalImageFilter3D:: MaximalImageFilter3D() -{ +MaximalImageFilter3D::MaximalImageFilter3D() { set_defaults(); } template Succeeded -MaximalImageFilter3D::virtual_set_up (const DiscretisedDensity<3,elemT>& density) -{ +MaximalImageFilter3D::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { /* if (consistency_check(density) == Succeeded::no) return Succeeded::no;*/ - maximal_filter = - MaximalArrayFilter3D(Coordinate3D - (mask_radius_z, mask_radius_y, mask_radius_x)); + maximal_filter = MaximalArrayFilter3D(Coordinate3D(mask_radius_z, mask_radius_y, mask_radius_x)); return Succeeded::yes; } template void -MaximalImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const -{ - //assert(consistency_check(density) == Succeeded::yes); - maximal_filter(density); +MaximalImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const { + // assert(consistency_check(density) == Succeeded::yes); + maximal_filter(density); } template void -MaximalImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& out_density, const DiscretisedDensity<3, elemT>& in_density) const -{ - //assert(consistency_check(in_density) == Succeeded::yes); - maximal_filter(out_density,in_density); +MaximalImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { + // assert(consistency_check(in_density) == Succeeded::yes); + maximal_filter(out_density, in_density); } template void -MaximalImageFilter3D::set_defaults() -{ +MaximalImageFilter3D::set_defaults() { base_type::set_defaults(); mask_radius_x = 0; @@ -87,9 +79,8 @@ MaximalImageFilter3D::set_defaults() } template -void -MaximalImageFilter3D::initialise_keymap() -{ +void +MaximalImageFilter3D::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Maximal Filter Parameters"); this->parser.add_key("mask radius x", &mask_radius_x); @@ -99,16 +90,13 @@ MaximalImageFilter3D::initialise_keymap() } template <> -const char * const -MaximalImageFilter3D::registered_name = - "Maximal"; - +const char* const MaximalImageFilter3D::registered_name = "Maximal"; -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif template class MaximalImageFilter3D; diff --git a/src/buildblock/MedianArrayFilter3D.cxx b/src/buildblock/MedianArrayFilter3D.cxx index e7aba4a3c6..599ce6a995 100644 --- a/src/buildblock/MedianArrayFilter3D.cxx +++ b/src/buildblock/MedianArrayFilter3D.cxx @@ -28,7 +28,7 @@ */ /* History: SM first version - KT 19/03/2002 + KT 19/03/2002 change handling of edges (they were not filtered before) correct bug in case output and input array size were not the same */ @@ -43,102 +43,83 @@ using std::nth_element; START_NAMESPACE_STIR - template -MedianArrayFilter3D::MedianArrayFilter3D(const Coordinate3D& mask_radius) -{ +MedianArrayFilter3D::MedianArrayFilter3D(const Coordinate3D& mask_radius) { this->mask_radius_x = mask_radius[3]; this->mask_radius_y = mask_radius[2]; this->mask_radius_z = mask_radius[1]; - /* assert(mask_radius_x>0); - assert(mask_radius_x%2 == 1); - assert(mask_radius_y>0); - assert(mask_radius_y%2 == 1); - assert(mask_radius_z>0); - assert(mask_radius_z%2 == 1);*/ + /* assert(mask_radius_x>0); + assert(mask_radius_x%2 == 1); + assert(mask_radius_y>0); + assert(mask_radius_y%2 == 1); + assert(mask_radius_z>0); + assert(mask_radius_z%2 == 1);*/ } template -MedianArrayFilter3D::MedianArrayFilter3D() -{ +MedianArrayFilter3D::MedianArrayFilter3D() { this->mask_radius_x = 0; this->mask_radius_y = 0; this->mask_radius_z = 0; } - template int -MedianArrayFilter3D:: -extract_neighbours(Array<1,elemT>& neigbours,const Array<3,elemT>& in_array,const Coordinate3D& c_pixel) const -{ - int index=0; - - for (int zi =-mask_radius_z;zi<= mask_radius_z;++zi) - { - const int z = c_pixel[1]+zi; - if (z in_array.get_max_index()) - continue; - for (int yi =-mask_radius_y;yi<= mask_radius_y;++yi) - { - const int y = c_pixel[2]+yi; - if (y in_array[z].get_max_index()) - continue; - for( int xi=-mask_radius_x;xi<= mask_radius_x;++xi) - { - const int x = c_pixel[3]+xi; - if (x in_array[z][y].get_max_index()) - continue; - neigbours[index++] = in_array[z][y][x]; - } - } +MedianArrayFilter3D::extract_neighbours(Array<1, elemT>& neigbours, const Array<3, elemT>& in_array, + const Coordinate3D& c_pixel) const { + int index = 0; + + for (int zi = -mask_radius_z; zi <= mask_radius_z; ++zi) { + const int z = c_pixel[1] + zi; + if (z < in_array.get_min_index() || z > in_array.get_max_index()) + continue; + for (int yi = -mask_radius_y; yi <= mask_radius_y; ++yi) { + const int y = c_pixel[2] + yi; + if (y < in_array[z].get_min_index() || y > in_array[z].get_max_index()) + continue; + for (int xi = -mask_radius_x; xi <= mask_radius_x; ++xi) { + const int x = c_pixel[3] + xi; + if (x < in_array[z][y].get_min_index() || x > in_array[z][y].get_max_index()) + continue; + neigbours[index++] = in_array[z][y][x]; + } } + } return index; } template void -MedianArrayFilter3D:: -do_it(Array<3,elemT>& out_array, const Array<3,elemT>& in_array) const -{ +MedianArrayFilter3D::do_it(Array<3, elemT>& out_array, const Array<3, elemT>& in_array) const { assert(out_array.get_index_range() == in_array.get_index_range()); - Array<1,elemT> neighbours (0,(2*mask_radius_x+1)*(2*mask_radius_y+1)*(2*mask_radius_z+1)-1); - - for (int z=out_array.get_min_index();z<= out_array.get_max_index();++z) - for (int y=out_array[z].get_min_index();y <= out_array[z].get_max_index();++y) - for (int x=out_array[z][y].get_min_index();x <= out_array[z][y].get_max_index();++x) - { - const int num_neighbours = - extract_neighbours(neighbours,in_array,Coordinate3D(z,y,x)); - if (num_neighbours==0) - continue; - nth_element(neighbours.begin(), neighbours.begin()+num_neighbours/2, neighbours.end()); - if (num_neighbours%2==1) - out_array[z][y][x] = neighbours[num_neighbours/2]; - else - out_array[z][y][x] = (neighbours[num_neighbours/2]+ - neighbours[num_neighbours/2 - 1])/2; - } + Array<1, elemT> neighbours(0, (2 * mask_radius_x + 1) * (2 * mask_radius_y + 1) * (2 * mask_radius_z + 1) - 1); + + for (int z = out_array.get_min_index(); z <= out_array.get_max_index(); ++z) + for (int y = out_array[z].get_min_index(); y <= out_array[z].get_max_index(); ++y) + for (int x = out_array[z][y].get_min_index(); x <= out_array[z][y].get_max_index(); ++x) { + const int num_neighbours = extract_neighbours(neighbours, in_array, Coordinate3D(z, y, x)); + if (num_neighbours == 0) + continue; + nth_element(neighbours.begin(), neighbours.begin() + num_neighbours / 2, neighbours.end()); + if (num_neighbours % 2 == 1) + out_array[z][y][x] = neighbours[num_neighbours / 2]; + else + out_array[z][y][x] = (neighbours[num_neighbours / 2] + neighbours[num_neighbours / 2 - 1]) / 2; + } } - template bool -MedianArrayFilter3D:: -is_trivial() const -{ - if (mask_radius_x!=1 &&mask_radius_y !=1 &&mask_radius_z!=1) +MedianArrayFilter3D::is_trivial() const { + if (mask_radius_x != 1 && mask_radius_y != 1 && mask_radius_z != 1) return true; else return false; - } - // instantiation template class MedianArrayFilter3D; END_NAMESPACE_STIR - diff --git a/src/buildblock/MedianImageFilter3D.cxx b/src/buildblock/MedianImageFilter3D.cxx index 7ae3a7a07e..045e7f7602 100644 --- a/src/buildblock/MedianImageFilter3D.cxx +++ b/src/buildblock/MedianImageFilter3D.cxx @@ -30,57 +30,49 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/DiscretisedDensity.h" - START_NAMESPACE_STIR template -MedianImageFilter3D:: MedianImageFilter3D(const CartesianCoordinate3D& mask_radius) -{ +MedianImageFilter3D::MedianImageFilter3D(const CartesianCoordinate3D& mask_radius) { mask_radius_x = mask_radius.x(); mask_radius_y = mask_radius.y(); mask_radius_z = mask_radius.z(); } template -MedianImageFilter3D:: MedianImageFilter3D() -{ +MedianImageFilter3D::MedianImageFilter3D() { set_defaults(); } template Succeeded -MedianImageFilter3D::virtual_set_up (const DiscretisedDensity<3,elemT>& density) -{ +MedianImageFilter3D::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { -/* if (consistency_check(density) == Succeeded::no) - return Succeeded::no;*/ - median_filter = - MedianArrayFilter3D(Coordinate3D - (mask_radius_z, mask_radius_y, mask_radius_x)); + /* if (consistency_check(density) == Succeeded::no) + return Succeeded::no;*/ + median_filter = MedianArrayFilter3D(Coordinate3D(mask_radius_z, mask_radius_y, mask_radius_x)); - return Succeeded::yes; + return Succeeded::yes; } template void -MedianImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const -{ - //assert(consistency_check(density) == Succeeded::yes); - median_filter(density); +MedianImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const { + // assert(consistency_check(density) == Succeeded::yes); + median_filter(density); } template void -MedianImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& out_density, const DiscretisedDensity<3, elemT>& in_density) const -{ - //assert(consistency_check(in_density) == Succeeded::yes); - median_filter(out_density,in_density); +MedianImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { + // assert(consistency_check(in_density) == Succeeded::yes); + median_filter(out_density, in_density); } template void -MedianImageFilter3D::set_defaults() -{ +MedianImageFilter3D::set_defaults() { base_type::set_defaults(); mask_radius_x = 0; @@ -89,9 +81,8 @@ MedianImageFilter3D::set_defaults() } template -void -MedianImageFilter3D::initialise_keymap() -{ +void +MedianImageFilter3D::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Median Filter Parameters"); this->parser.add_key("mask radius x", &mask_radius_x); @@ -101,20 +92,16 @@ MedianImageFilter3D::initialise_keymap() } template <> -const char * const -MedianImageFilter3D::registered_name = - "Median"; +const char* const MedianImageFilter3D::registered_name = "Median"; - -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif - +# pragma warning(disable : 4660) +#endif // Register this class in the ImageProcessor registry -//static MedianImageFilter3D::RegisterIt dummy; +// static MedianImageFilter3D::RegisterIt dummy; template class MedianImageFilter3D; diff --git a/src/buildblock/MinimalArrayFilter3D.cxx b/src/buildblock/MinimalArrayFilter3D.cxx index 656454320f..1d40db4efa 100644 --- a/src/buildblock/MinimalArrayFilter3D.cxx +++ b/src/buildblock/MinimalArrayFilter3D.cxx @@ -33,16 +33,14 @@ START_NAMESPACE_STIR template -MinimalArrayFilter3D::MinimalArrayFilter3D(const Coordinate3D& mask_radius) -{ +MinimalArrayFilter3D::MinimalArrayFilter3D(const Coordinate3D& mask_radius) { this->mask_radius_x = mask_radius[3]; this->mask_radius_y = mask_radius[2]; this->mask_radius_z = mask_radius[1]; } template -MinimalArrayFilter3D::MinimalArrayFilter3D() -{ +MinimalArrayFilter3D::MinimalArrayFilter3D() { this->mask_radius_x = 0; this->mask_radius_y = 0; this->mask_radius_z = 0; @@ -50,65 +48,53 @@ MinimalArrayFilter3D::MinimalArrayFilter3D() template int -MinimalArrayFilter3D:: -extract_neighbours(Array<1,elemT>& neigbours,const Array<3,elemT>& in_array,const Coordinate3D& c_pixel) const -{ - int index=0; - - for (int zi =-mask_radius_z;zi<= mask_radius_z;++zi) - { - const int z = c_pixel[1]+zi; - if (z in_array.get_max_index()) - continue; - for (int yi =-mask_radius_y;yi<= mask_radius_y;++yi) - { - const int y = c_pixel[2]+yi; - if (y in_array[z].get_max_index()) - continue; - for( int xi=-mask_radius_x;xi<= mask_radius_x;++xi) - { - const int x = c_pixel[3]+xi; - if (x in_array[z][y].get_max_index()) - continue; - neigbours[index++] = in_array[z][y][x]; - } - } +MinimalArrayFilter3D::extract_neighbours(Array<1, elemT>& neigbours, const Array<3, elemT>& in_array, + const Coordinate3D& c_pixel) const { + int index = 0; + + for (int zi = -mask_radius_z; zi <= mask_radius_z; ++zi) { + const int z = c_pixel[1] + zi; + if (z < in_array.get_min_index() || z > in_array.get_max_index()) + continue; + for (int yi = -mask_radius_y; yi <= mask_radius_y; ++yi) { + const int y = c_pixel[2] + yi; + if (y < in_array[z].get_min_index() || y > in_array[z].get_max_index()) + continue; + for (int xi = -mask_radius_x; xi <= mask_radius_x; ++xi) { + const int x = c_pixel[3] + xi; + if (x < in_array[z][y].get_min_index() || x > in_array[z][y].get_max_index()) + continue; + neigbours[index++] = in_array[z][y][x]; + } } + } return index; } template void -MinimalArrayFilter3D:: -do_it(Array<3,elemT>& out_array, const Array<3,elemT>& in_array) const -{ +MinimalArrayFilter3D::do_it(Array<3, elemT>& out_array, const Array<3, elemT>& in_array) const { assert(out_array.get_index_range() == in_array.get_index_range()); - Array<1,elemT> neighbours (0,(2*mask_radius_x+1)*(2*mask_radius_y+1)*(2*mask_radius_z+1)-1); - - for (int z=out_array.get_min_index();z<= out_array.get_max_index();++z) - for (int y=out_array[z].get_min_index();y <= out_array[z].get_max_index();++y) - for (int x=out_array[z][y].get_min_index();x <= out_array[z][y].get_max_index();++x) - { - const int num_neighbours = - extract_neighbours(neighbours,in_array,Coordinate3D(z,y,x)); - if (num_neighbours==0) - continue; - out_array[z][y][x] = - *std::min_element(neighbours.begin(), neighbours.begin() + num_neighbours); - } + Array<1, elemT> neighbours(0, (2 * mask_radius_x + 1) * (2 * mask_radius_y + 1) * (2 * mask_radius_z + 1) - 1); + + for (int z = out_array.get_min_index(); z <= out_array.get_max_index(); ++z) + for (int y = out_array[z].get_min_index(); y <= out_array[z].get_max_index(); ++y) + for (int x = out_array[z][y].get_min_index(); x <= out_array[z][y].get_max_index(); ++x) { + const int num_neighbours = extract_neighbours(neighbours, in_array, Coordinate3D(z, y, x)); + if (num_neighbours == 0) + continue; + out_array[z][y][x] = *std::min_element(neighbours.begin(), neighbours.begin() + num_neighbours); + } } template bool -MinimalArrayFilter3D:: -is_trivial() const -{ - if (mask_radius_x!=1 &&mask_radius_y !=1 &&mask_radius_z!=1) +MinimalArrayFilter3D::is_trivial() const { + if (mask_radius_x != 1 && mask_radius_y != 1 && mask_radius_z != 1) return true; else return false; - } // instantiation diff --git a/src/buildblock/MinimalImageFilter3D.cxx b/src/buildblock/MinimalImageFilter3D.cxx index 5c0ecff61e..443399c64e 100644 --- a/src/buildblock/MinimalImageFilter3D.cxx +++ b/src/buildblock/MinimalImageFilter3D.cxx @@ -30,57 +30,49 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/DiscretisedDensity.h" - START_NAMESPACE_STIR template -MinimalImageFilter3D:: MinimalImageFilter3D(const CartesianCoordinate3D& mask_radius) -{ +MinimalImageFilter3D::MinimalImageFilter3D(const CartesianCoordinate3D& mask_radius) { mask_radius_x = mask_radius.x(); mask_radius_y = mask_radius.y(); mask_radius_z = mask_radius.z(); } template -MinimalImageFilter3D:: MinimalImageFilter3D() -{ +MinimalImageFilter3D::MinimalImageFilter3D() { set_defaults(); } template Succeeded -MinimalImageFilter3D::virtual_set_up (const DiscretisedDensity<3,elemT>& density) -{ +MinimalImageFilter3D::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { -/* if (consistency_check(density) == Succeeded::no) - return Succeeded::no;*/ - minimal_filter = - MinimalArrayFilter3D(Coordinate3D - (mask_radius_z, mask_radius_y, mask_radius_x)); + /* if (consistency_check(density) == Succeeded::no) + return Succeeded::no;*/ + minimal_filter = MinimalArrayFilter3D(Coordinate3D(mask_radius_z, mask_radius_y, mask_radius_x)); - return Succeeded::yes; + return Succeeded::yes; } template void -MinimalImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const -{ - //assert(consistency_check(density) == Succeeded::yes); - minimal_filter(density); +MinimalImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const { + // assert(consistency_check(density) == Succeeded::yes); + minimal_filter(density); } template void -MinimalImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& out_density, const DiscretisedDensity<3, elemT>& in_density) const -{ - //assert(consistency_check(in_density) == Succeeded::yes); - minimal_filter(out_density,in_density); +MinimalImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { + // assert(consistency_check(in_density) == Succeeded::yes); + minimal_filter(out_density, in_density); } template void -MinimalImageFilter3D::set_defaults() -{ +MinimalImageFilter3D::set_defaults() { base_type::set_defaults(); mask_radius_x = 0; @@ -89,9 +81,8 @@ MinimalImageFilter3D::set_defaults() } template -void -MinimalImageFilter3D::initialise_keymap() -{ +void +MinimalImageFilter3D::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Minimal Filter Parameters"); this->parser.add_key("mask radius x", &mask_radius_x); @@ -101,16 +92,13 @@ MinimalImageFilter3D::initialise_keymap() } template <> -const char * const -MinimalImageFilter3D::registered_name = - "Minimal"; - +const char* const MinimalImageFilter3D::registered_name = "Minimal"; -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif template class MinimalImageFilter3D; diff --git a/src/buildblock/MultipleDataSetHeader.cxx b/src/buildblock/MultipleDataSetHeader.cxx index cc8dfcce93..d3fba8e40b 100644 --- a/src/buildblock/MultipleDataSetHeader.cxx +++ b/src/buildblock/MultipleDataSetHeader.cxx @@ -22,7 +22,7 @@ \ingroup data_buildblock \brief Implementation of class stir::MultipleDataSetHeader \author Richard Brown - + */ #include "stir/MultipleDataSetHeader.h" @@ -30,54 +30,45 @@ START_NAMESPACE_STIR -const char * const MultipleDataSetHeader:: -registered_name = "MultipleDataSetHeader"; +const char* const MultipleDataSetHeader::registered_name = "MultipleDataSetHeader"; -MultipleDataSetHeader:: -MultipleDataSetHeader() -{ - this->set_defaults(); - this->initialise_keymap(); +MultipleDataSetHeader::MultipleDataSetHeader() { + this->set_defaults(); + this->initialise_keymap(); } -void MultipleDataSetHeader:: -set_defaults() -{ - _num_data_sets = 0; +void +MultipleDataSetHeader::set_defaults() { + _num_data_sets = 0; } -void MultipleDataSetHeader:: -initialise_keymap() -{ - this->add_start_key("Multi"); - this->add_stop_key("End"); +void +MultipleDataSetHeader::initialise_keymap() { + this->add_start_key("Multi"); + this->add_stop_key("End"); - this->add_key("total number of data sets", - KeyArgument::INT, - static_cast(&MultipleDataSetHeader::read_num_data_sets), - &_num_data_sets); - this->add_vectorised_key("data set", &_filenames); + this->add_key("total number of data sets", KeyArgument::INT, + static_cast(&MultipleDataSetHeader::read_num_data_sets), &_num_data_sets); + this->add_vectorised_key("data set", &_filenames); } -bool MultipleDataSetHeader:: -post_processing() -{ - bool empty_filenames = false; - for (int i=0; i<_num_data_sets; ++i) { - if (_filenames[i].size() == unsigned(0)) { - warning(boost::format("MultipleDataSetHeader: Data set[%1%] is empty.") % i); - empty_filenames = true; - } +bool +MultipleDataSetHeader::post_processing() { + bool empty_filenames = false; + for (int i = 0; i < _num_data_sets; ++i) { + if (_filenames[i].size() == unsigned(0)) { + warning(boost::format("MultipleDataSetHeader: Data set[%1%] is empty.") % i); + empty_filenames = true; } + } - return empty_filenames; + return empty_filenames; } -void MultipleDataSetHeader:: -read_num_data_sets() -{ - set_variable(); - _filenames.resize(_num_data_sets); +void +MultipleDataSetHeader::read_num_data_sets() { + set_variable(); + _filenames.resize(_num_data_sets); } END_NAMESPACE_STIR diff --git a/src/buildblock/MultipleProjData.cxx b/src/buildblock/MultipleProjData.cxx index e29afa06dc..c23462c706 100644 --- a/src/buildblock/MultipleProjData.cxx +++ b/src/buildblock/MultipleProjData.cxx @@ -23,7 +23,7 @@ \brief Implementation of class stir::MultipleProjData \author Kris Thielemans \author Richard Brown - + */ #include "stir/MultipleProjData.h" @@ -37,66 +37,56 @@ START_NAMESPACE_STIR const shared_ptr -MultipleProjData:: -get_proj_data_info_sptr() const -{ +MultipleProjData::get_proj_data_info_sptr() const { if (get_num_gates() == 0) return shared_ptr(); else return _proj_datas[0]->get_proj_data_info_sptr(); } -void -MultipleProjData:: -set_proj_data_sptr(const shared_ptr& proj_data_sptr, - const unsigned int gate_num) -{ - this->_proj_datas[gate_num-1]=proj_data_sptr; -} +void +MultipleProjData::set_proj_data_sptr(const shared_ptr& proj_data_sptr, const unsigned int gate_num) { + this->_proj_datas[gate_num - 1] = proj_data_sptr; +} -MultipleProjData:: -MultipleProjData(const shared_ptr& exam_info_sptr, - const int num_gates) : - ExamData(exam_info_sptr) -{ - this->_proj_datas.resize(num_gates); +MultipleProjData::MultipleProjData(const shared_ptr& exam_info_sptr, const int num_gates) + : ExamData(exam_info_sptr) { + this->_proj_datas.resize(num_gates); } unique_ptr -MultipleProjData:: -read_from_file(const std::string ¶meter_file) -{ - MultipleDataSetHeader header; - - if (header.parse(parameter_file.c_str()) == false) - error(boost::format("MultipleProjData::read_from_file: Error parsing %1%") % parameter_file); - - const int num_data_sets = header.get_num_data_sets(); - - if (num_data_sets == 0) - error("MultipleProjData::read_from_file: no data sets provided"); - - // Create the multiple proj data - unique_ptr multiple_proj_data( new MultipleProjData ); - - // Read the projdata - for (int i=0; i_proj_datas.push_back(ProjData::read_from_file(header.get_filename(i))); - } - - // Get the exam info (from the first ProjData) - ExamInfo exam_info = multiple_proj_data->_proj_datas.at(0)->get_exam_info(); - - // Update the time definitions based on each individual frame - exam_info.time_frame_definitions.set_num_time_frames(num_data_sets); - for (int i=0; i_proj_datas[i]->get_exam_info().time_frame_definitions; - exam_info.time_frame_definitions.set_time_frame(i+1, tdef.get_start_time(1), tdef.get_end_time(1)); - } - multiple_proj_data->set_exam_info(exam_info); - return multiple_proj_data; +MultipleProjData::read_from_file(const std::string& parameter_file) { + MultipleDataSetHeader header; + + if (header.parse(parameter_file.c_str()) == false) + error(boost::format("MultipleProjData::read_from_file: Error parsing %1%") % parameter_file); + + const int num_data_sets = header.get_num_data_sets(); + + if (num_data_sets == 0) + error("MultipleProjData::read_from_file: no data sets provided"); + + // Create the multiple proj data + unique_ptr multiple_proj_data(new MultipleProjData); + + // Read the projdata + for (int i = 0; i < num_data_sets; ++i) { + info(boost::format("MultipleProjData::read_from_file: Reading %1%") % header.get_filename(i)); + // Create each of the individual proj datas + multiple_proj_data->_proj_datas.push_back(ProjData::read_from_file(header.get_filename(i))); + } + + // Get the exam info (from the first ProjData) + ExamInfo exam_info = multiple_proj_data->_proj_datas.at(0)->get_exam_info(); + + // Update the time definitions based on each individual frame + exam_info.time_frame_definitions.set_num_time_frames(num_data_sets); + for (int i = 0; i < num_data_sets; ++i) { + const TimeFrameDefinitions& tdef = multiple_proj_data->_proj_datas[i]->get_exam_info().time_frame_definitions; + exam_info.time_frame_definitions.set_time_frame(i + 1, tdef.get_start_time(1), tdef.get_end_time(1)); + } + multiple_proj_data->set_exam_info(exam_info); + return multiple_proj_data; } #if 0 diff --git a/src/buildblock/NonseparableConvolutionUsingRealDFTImageFilter.cxx b/src/buildblock/NonseparableConvolutionUsingRealDFTImageFilter.cxx index e8657890aa..8ce30e1c00 100644 --- a/src/buildblock/NonseparableConvolutionUsingRealDFTImageFilter.cxx +++ b/src/buildblock/NonseparableConvolutionUsingRealDFTImageFilter.cxx @@ -20,7 +20,7 @@ \file \ingroup ImageProcessor \brief Implementations for class stir::NonseparableConvolutionUsingRealDFTImageFilter - + \author Sanida Mustafovic \author Kris Thielemans */ @@ -32,137 +32,117 @@ #include "stir/Array_complex_numbers.h" #include "stir/IO/read_from_file.h" - START_NAMESPACE_STIR // fixed to 3D at present static const int num_dimensions = 3; template -NonseparableConvolutionUsingRealDFTImageFilter:: -NonseparableConvolutionUsingRealDFTImageFilter() -{ +NonseparableConvolutionUsingRealDFTImageFilter::NonseparableConvolutionUsingRealDFTImageFilter() { this->set_defaults(); } template -NonseparableConvolutionUsingRealDFTImageFilter:: -NonseparableConvolutionUsingRealDFTImageFilter( const Array<3,elemT>& filter_coefficients ) -{ - this->_filter_coefficients = filter_coefficients; +NonseparableConvolutionUsingRealDFTImageFilter::NonseparableConvolutionUsingRealDFTImageFilter( + const Array<3, elemT>& filter_coefficients) { + this->_filter_coefficients = filter_coefficients; } template -Succeeded -NonseparableConvolutionUsingRealDFTImageFilter:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) -{ +Succeeded +NonseparableConvolutionUsingRealDFTImageFilter::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { BasicCoordinate min_indices, max_indices; if (!density.get_regular_range(min_indices, max_indices)) return Succeeded::no; - BasicCoordinate padded_sizes = max_indices - min_indices +1; + BasicCoordinate padded_sizes = max_indices - min_indices + 1; if (!this->_filter_coefficients.get_regular_range(min_indices, max_indices)) return Succeeded::no; - padded_sizes += max_indices - min_indices +1; + padded_sizes += max_indices - min_indices + 1; // remove 1 to be accurate - padded_sizes -= 1; + padded_sizes -= 1; // need to make it a power of 2 for the DFT implementation - for (int d=1; d<= num_dimensions; ++d) - { - padded_sizes[d] = - static_cast(round(pow(2., ceil(log(static_cast(padded_sizes[d])) / log(2.))))); - } + for (int d = 1; d <= num_dimensions; ++d) { + padded_sizes[d] = static_cast(round(pow(2., ceil(log(static_cast(padded_sizes[d])) / log(2.))))); + } IndexRange padding_range(padded_sizes); Array padded_filter_coefficients(padding_range); transform_array_to_periodic_indices(padded_filter_coefficients, this->_filter_coefficients); - this->_array_filter_sptr.reset( - new ArrayFilterUsingRealDFTWithPadding(padded_filter_coefficients)); - return Succeeded::yes; + this->_array_filter_sptr.reset(new ArrayFilterUsingRealDFTWithPadding(padded_filter_coefficients)); + return Succeeded::yes; } template void -NonseparableConvolutionUsingRealDFTImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, const DiscretisedDensity<3,elemT>& in_density) const -{ +NonseparableConvolutionUsingRealDFTImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { (*this->_array_filter_sptr)(out_density, in_density); } template void -NonseparableConvolutionUsingRealDFTImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const -{ +NonseparableConvolutionUsingRealDFTImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& density) const { // should use scoped_ptr but don't have it yet - shared_ptr > tmp_density_sptr(density.clone()); + shared_ptr> tmp_density_sptr(density.clone()); this->virtual_apply(density, *tmp_density_sptr); } - template void -NonseparableConvolutionUsingRealDFTImageFilter::set_defaults() -{ - this->_kernel_filename=""; +NonseparableConvolutionUsingRealDFTImageFilter::set_defaults() { + this->_kernel_filename = ""; this->_filter_coefficients.fill(0.F); } - + template void -NonseparableConvolutionUsingRealDFTImageFilter:: initialise_keymap() -{ +NonseparableConvolutionUsingRealDFTImageFilter::initialise_keymap() { this->parser.add_start_key("Nonseparable Convolution Using Real DFT Image Filter"); this->parser.add_key("filter kernel", &this->_kernel_filename); this->parser.add_stop_key("END Nonseparable Convolution Using Real DFT Image Filter"); } - + template -bool -NonseparableConvolutionUsingRealDFTImageFilter:: -post_processing() -{ - if (this->_kernel_filename.length() == 0) - { warning("You need to specify a kernel file"); return true; } - else - this->_kernel_sptr = read_from_file >(this->_kernel_filename); - const DiscretisedDensity<3,elemT>& kernel = *this->_kernel_sptr; +bool +NonseparableConvolutionUsingRealDFTImageFilter::post_processing() { + if (this->_kernel_filename.length() == 0) { + warning("You need to specify a kernel file"); + return true; + } else + this->_kernel_sptr = read_from_file>(this->_kernel_filename); + const DiscretisedDensity<3, elemT>& kernel = *this->_kernel_sptr; BasicCoordinate min_indices, max_indices; if (!kernel.get_regular_range(min_indices, max_indices)) return true; const BasicCoordinate sizes = max_indices - min_indices + 1; - - if (sizes[1]%2==0 || sizes[2]%2==0 || sizes[3]%2==0) - warning("Parsing Nonseparable Convolution Using Real DFT Image Filter\n" - "Even number of filter coefficients for at least one of the dimensions." - "I'll (effectively) append a 0 at the end.\n"); - const BasicCoordinate new_min_indices = (sizes/2)*(-1); + if (sizes[1] % 2 == 0 || sizes[2] % 2 == 0 || sizes[3] % 2 == 0) + warning("Parsing Nonseparable Convolution Using Real DFT Image Filter\n" + "Even number of filter coefficients for at least one of the dimensions." + "I'll (effectively) append a 0 at the end.\n"); + + const BasicCoordinate new_min_indices = (sizes / 2) * (-1); + + this->_filter_coefficients.grow(IndexRange(new_min_indices, new_min_indices + sizes - 1)); - this->_filter_coefficients.grow(IndexRange(new_min_indices, new_min_indices + sizes - 1 )); - BasicCoordinate index = get_min_indices(this->_filter_coefficients); - do - { - this->_filter_coefficients[index] = kernel[index - new_min_indices + min_indices]; - } - while(next(index, this->_filter_coefficients)); + do { + this->_filter_coefficients[index] = kernel[index - new_min_indices + min_indices]; + } while (next(index, this->_filter_coefficients)); return false; } -template<> -const char * const -NonseparableConvolutionUsingRealDFTImageFilter::registered_name = -"Nonseparable Convolution Using Real DFT Image Filter"; - -# ifdef _MSC_VER - // prevent warning message on reinstantiation, - // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +template <> +const char* const NonseparableConvolutionUsingRealDFTImageFilter::registered_name = + "Nonseparable Convolution Using Real DFT Image Filter"; + +#ifdef _MSC_VER +// prevent warning message on reinstantiation, +// note that we get a linking error if we don't have the explicit instantiation below +# pragma warning(disable : 4660) +#endif template class NonseparableConvolutionUsingRealDFTImageFilter; - + END_NAMESPACE_STIR - diff --git a/src/buildblock/NumericType.cxx b/src/buildblock/NumericType.cxx index bf73b62c5d..1e8319a6c9 100644 --- a/src/buildblock/NumericType.cxx +++ b/src/buildblock/NumericType.cxx @@ -1,6 +1,6 @@ /*! - \file - + \file + \brief implementations for the stir::NumericType class \author Kris Thielemans @@ -23,7 +23,7 @@ See STIR/LICENSE.txt for details */ -/* +/* History: - first version Kris Thielemans @@ -39,178 +39,161 @@ using std::string; START_NAMESPACE_STIR -NumericType::NumericType(const string& number_format, const size_t size_in_bytes) -{ +NumericType::NumericType(const string& number_format, const size_t size_in_bytes) { bool it_is_signed; bool it_is_integral; - - if (number_format == "signed integer") - { + + if (number_format == "signed integer") { it_is_signed = true; it_is_integral = true; - } - else if (number_format == "unsigned integer") - { + } else if (number_format == "unsigned integer") { it_is_signed = false; it_is_integral = true; - } - else if (number_format == "float") - { + } else if (number_format == "float") { it_is_signed = true; it_is_integral = false; } - - else if (number_format == "bit") - { + + else if (number_format == "bit") { id = BIT; return; - } - else - { + } else { // set to some values which are guaranteed to break later on it_is_signed = false; it_is_integral = false; } - + // set up default value id = UNKNOWN_TYPE; - + // rely on enum<->int conversions - for (int t=1; t < (int)UNKNOWN_TYPE; t++) - { + for (int t = 1; t < (int)UNKNOWN_TYPE; t++) { const NumericType type = (Type)t; - if (it_is_signed == type.signed_type() && - it_is_integral == type.integer_type() && - size_in_bytes == type.size_in_bytes()) - { + if (it_is_signed == type.signed_type() && it_is_integral == type.integer_type() && size_in_bytes == type.size_in_bytes()) { id = (Type)t; return; } } - -} - +} -void -NumericType::get_Interfile_info(string& number_format, - size_t& size_in_bytes_v) const -{ +void +NumericType::get_Interfile_info(string& number_format, size_t& size_in_bytes_v) const { size_in_bytes_v = size_in_bytes(); - - switch(id) - { + + switch (id) { case BIT: - number_format = "bit"; break; - case SCHAR: - case SHORT: - case INT: - case LONG: - number_format = "signed integer"; break; - case UCHAR: - case USHORT: - case UINT: - case ULONG: - number_format = "unsigned integer"; break; - case FLOAT: - case DOUBLE: - number_format = "float"; break; + number_format = "bit"; + break; + case SCHAR: + case SHORT: + case INT: + case LONG: + number_format = "signed integer"; + break; + case UCHAR: + case USHORT: + case UINT: + case ULONG: + number_format = "unsigned integer"; + break; + case FLOAT: + case DOUBLE: + number_format = "float"; + break; case UNKNOWN_TYPE: - number_format = "unknown"; break; + number_format = "unknown"; + break; } } - - -size_t NumericType::size_in_bytes() const - { +size_t +NumericType::size_in_bytes() const { // KT TODO pretty awful way of doings things, but I'm not sure how to handle it - switch(id) - { - case BIT: - // TODO sensible value ? - return 0; -#define CASE(NUMERICTYPE) \ - case NUMERICTYPE : \ - return NumericInfo::type>().size_in_bytes(); - - // now list cases that we want - CASE(NumericType::SCHAR); - CASE(NumericType::UCHAR); - CASE(NumericType::SHORT); - CASE(NumericType::USHORT); - CASE(NumericType::INT); - CASE(NumericType::UINT); - CASE(NumericType::LONG); - CASE(NumericType::ULONG); - CASE(NumericType::FLOAT); - CASE(NumericType::DOUBLE); + switch (id) { + case BIT: + // TODO sensible value ? + return 0; +#define CASE(NUMERICTYPE) \ + case NUMERICTYPE: \ + return NumericInfo::type>().size_in_bytes(); + + // now list cases that we want + CASE(NumericType::SCHAR); + CASE(NumericType::UCHAR); + CASE(NumericType::SHORT); + CASE(NumericType::USHORT); + CASE(NumericType::INT); + CASE(NumericType::UINT); + CASE(NumericType::LONG); + CASE(NumericType::ULONG); + CASE(NumericType::FLOAT); + CASE(NumericType::DOUBLE); #undef CASE - case UNKNOWN_TYPE: - return 0; - } - // we never get here, but VC++ wants a return nevertheless - return 0; - } + case UNKNOWN_TYPE: + return 0; + } + // we never get here, but VC++ wants a return nevertheless + return 0; +} -size_t NumericType::size_in_bits() const - { return CHAR_BIT * size_in_bytes(); } - -bool NumericType::signed_type() const - { - switch(id) - { - case BIT: - return false; -#define CASE(NUMERICTYPE) \ - case NUMERICTYPE : \ - return NumericInfo::type>().signed_type(); - - // now list cases that we want - CASE(NumericType::SCHAR); - CASE(NumericType::UCHAR); - CASE(NumericType::SHORT); - CASE(NumericType::USHORT); - CASE(NumericType::INT); - CASE(NumericType::UINT); - CASE(NumericType::LONG); - CASE(NumericType::ULONG); - CASE(NumericType::FLOAT); - CASE(NumericType::DOUBLE); -#undef CASE - case UNKNOWN_TYPE: - return false; - } - // we never get here, but VC++ wants a return nevertheless - return false; - } +size_t +NumericType::size_in_bits() const { + return CHAR_BIT * size_in_bytes(); +} -bool NumericType::integer_type() const - { - switch(id) - { - case BIT: - return true; -#define CASE(NUMERICTYPE) \ - case NUMERICTYPE : \ - return NumericInfo::type>().integer_type(); - - // now list cases that we want - CASE(NumericType::SCHAR); - CASE(NumericType::UCHAR); - CASE(NumericType::SHORT); - CASE(NumericType::USHORT); - CASE(NumericType::INT); - CASE(NumericType::UINT); - CASE(NumericType::LONG); - CASE(NumericType::ULONG); - CASE(NumericType::FLOAT); - CASE(NumericType::DOUBLE); +bool +NumericType::signed_type() const { + switch (id) { + case BIT: + return false; +#define CASE(NUMERICTYPE) \ + case NUMERICTYPE: \ + return NumericInfo::type>().signed_type(); + + // now list cases that we want + CASE(NumericType::SCHAR); + CASE(NumericType::UCHAR); + CASE(NumericType::SHORT); + CASE(NumericType::USHORT); + CASE(NumericType::INT); + CASE(NumericType::UINT); + CASE(NumericType::LONG); + CASE(NumericType::ULONG); + CASE(NumericType::FLOAT); + CASE(NumericType::DOUBLE); #undef CASE - case UNKNOWN_TYPE: - return false; + case UNKNOWN_TYPE: + return false; + } + // we never get here, but VC++ wants a return nevertheless + return false; +} - } - // we never get here, but VC++ wants a return nevertheless - return false; - } +bool +NumericType::integer_type() const { + switch (id) { + case BIT: + return true; +#define CASE(NUMERICTYPE) \ + case NUMERICTYPE: \ + return NumericInfo::type>().integer_type(); + + // now list cases that we want + CASE(NumericType::SCHAR); + CASE(NumericType::UCHAR); + CASE(NumericType::SHORT); + CASE(NumericType::USHORT); + CASE(NumericType::INT); + CASE(NumericType::UINT); + CASE(NumericType::LONG); + CASE(NumericType::ULONG); + CASE(NumericType::FLOAT); + CASE(NumericType::DOUBLE); +#undef CASE + case UNKNOWN_TYPE: + return false; + } + // we never get here, but VC++ wants a return nevertheless + return false; +} END_NAMESPACE_STIR diff --git a/src/buildblock/ParseDiscretisedDensityParameters.cxx b/src/buildblock/ParseDiscretisedDensityParameters.cxx index e779bd5797..4f2f7be73c 100644 --- a/src/buildblock/ParseDiscretisedDensityParameters.cxx +++ b/src/buildblock/ParseDiscretisedDensityParameters.cxx @@ -1,32 +1,32 @@ /* Copyright (C) 2000 PARAPET partners - Copyright (C) 2000- 2007, Hammersmith Imanet Ltd + Copyright (C) 2000- 2007, Hammersmith Imanet Ltd Copyright (C) 2019, University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! \file - \ingroup densitydata - + \ingroup densitydata + \brief Implementation of the stir::ParseDiscretisedDensityParameters class - + \author Kris Thielemans \author Matthew Jacobson \author Claire Labbe \author PARAPET project - + */ #include "stir/KeyParser.h" #include "stir/ParseDiscretisedDensityParameters.h" @@ -35,29 +35,25 @@ START_NAMESPACE_STIR -void -ParseDiscretisedDensityParameters:: -set_defaults() -{ - //base_type::set_defaults(); - output_image_size_xy=-1; - output_image_size_z=-1; - zoom_xy=1.F; - zoom_z=1.F; +void +ParseDiscretisedDensityParameters::set_defaults() { + // base_type::set_defaults(); + output_image_size_xy = -1; + output_image_size_z = -1; + zoom_xy = 1.F; + zoom_z = 1.F; offset.fill(0.F); } void -ParseDiscretisedDensityParameters:: -add_to_keymap(KeyParser& parser) -{ - //base_type::initialise_keymap(); +ParseDiscretisedDensityParameters::add_to_keymap(KeyParser& parser) { + // base_type::initialise_keymap(); parser.add_key("zoom", &zoom_xy); parser.add_key("Z zoom", &zoom_z); - parser.add_key("XY output image size (in pixels)",&output_image_size_xy); - parser.add_key("Z output image size (in pixels)",&output_image_size_z); - //parser.add_key("X offset (in mm)", &offset.x()); // KT 10122001 added spaces - //parser.add_key("Y offset (in mm)", &offset.y()); + parser.add_key("XY output image size (in pixels)", &output_image_size_xy); + parser.add_key("Z output image size (in pixels)", &output_image_size_z); + // parser.add_key("X offset (in mm)", &offset.x()); // KT 10122001 added spaces + // parser.add_key("Y offset (in mm)", &offset.y()); parser.add_key("Z offset (in mm)", &offset.z()); } @@ -75,8 +71,8 @@ ask_parameters() -1, 4*static_cast(proj_data_ptr->get_num_tangential_poss()*zoom), -1); - -#if 0 + +# if 0 // This section enables you to position a reconstructed image // along x (horizontal), y (vertical) and/or z (transverse) axes // The default values is in the center of the FOV, @@ -88,75 +84,78 @@ ask_parameters() cout << endl << " Enter offset Xoff, Yoff (in pixels) :"; Xoffset = ask_num(" X offset ",-old_size/2, old_size/2, 0); Yoffset = ask_num(" Y offset ",-old_size/2, old_size/2, 0); -#endif +# endif } #endif // ask_parameters disabled - void -ParseDiscretisedDensityParameters:: -check_values() const -{ - if (zoom_xy <= 0) - { error("zoom should be positive"); } - if (zoom_z <= 0) - { error("z zoom should be positive"); } - - if (output_image_size_xy!=-1 && output_image_size_xy<1) // KT 10122001 appended_xy - { error("output image size xy must be positive (or -1 as default)"); } - if (output_image_size_z!=-1 && output_image_size_z<1) // KT 10122001 new - { error("output image size z must be positive (or -1 as default)"); } +ParseDiscretisedDensityParameters::check_values() const { + if (zoom_xy <= 0) { + error("zoom should be positive"); + } + if (zoom_z <= 0) { + error("z zoom should be positive"); + } + + if (output_image_size_xy != -1 && output_image_size_xy < 1) // KT 10122001 appended_xy + { + error("output image size xy must be positive (or -1 as default)"); + } + if (output_image_size_z != -1 && output_image_size_z < 1) // KT 10122001 new + { + error("output image size z must be positive (or -1 as default)"); + } } int -ParseDiscretisedDensityParameters:: -get_output_image_size_xy() const -{ return this->output_image_size_xy; } +ParseDiscretisedDensityParameters::get_output_image_size_xy() const { + return this->output_image_size_xy; +} void -ParseDiscretisedDensityParameters:: -set_output_image_size_xy(int v) -{ this->output_image_size_xy = v; } +ParseDiscretisedDensityParameters::set_output_image_size_xy(int v) { + this->output_image_size_xy = v; +} int -ParseDiscretisedDensityParameters:: -get_output_image_size_z() const -{ return this->output_image_size_z; } +ParseDiscretisedDensityParameters::get_output_image_size_z() const { + return this->output_image_size_z; +} void -ParseDiscretisedDensityParameters:: -set_output_image_size_z(int v) -{ this->output_image_size_z = v; } +ParseDiscretisedDensityParameters::set_output_image_size_z(int v) { + this->output_image_size_z = v; +} float -ParseDiscretisedDensityParameters:: -get_zoom_xy() const -{ return this->zoom_xy; } +ParseDiscretisedDensityParameters::get_zoom_xy() const { + return this->zoom_xy; +} void -ParseDiscretisedDensityParameters:: -set_zoom_xy(float v) -{ this->zoom_xy = v; } +ParseDiscretisedDensityParameters::set_zoom_xy(float v) { + this->zoom_xy = v; +} float -ParseDiscretisedDensityParameters:: -get_zoom_z() const -{ return this->zoom_z; } +ParseDiscretisedDensityParameters::get_zoom_z() const { + return this->zoom_z; +} void -ParseDiscretisedDensityParameters:: -set_zoom_z(float v) -{ this->zoom_z = v; } +ParseDiscretisedDensityParameters::set_zoom_z(float v) { + this->zoom_z = v; +} const CartesianCoordinate3D& -ParseDiscretisedDensityParameters:: -get_offset() const -{ return this->offset; } +ParseDiscretisedDensityParameters::get_offset() const { + return this->offset; +} void -ParseDiscretisedDensityParameters:: -set_offset(const CartesianCoordinate3D& v) -{ this->offset = v; } +ParseDiscretisedDensityParameters::set_offset(const CartesianCoordinate3D& v) { + this->offset = v; +} END_NAMESPACE_STIR diff --git a/src/buildblock/ParsingObject.cxx b/src/buildblock/ParsingObject.cxx index 55abf892fa..bc8d669614 100644 --- a/src/buildblock/ParsingObject.cxx +++ b/src/buildblock/ParsingObject.cxx @@ -35,81 +35,56 @@ using std::ifstream; START_NAMESPACE_STIR -ParsingObject::ParsingObject() -: - keymap_is_initialised(false) -{} - - - - -ParsingObject::ParsingObject(const ParsingObject& par) -: - keymap_is_initialised(false) - {} +ParsingObject::ParsingObject() : keymap_is_initialised(false) {} +ParsingObject::ParsingObject(const ParsingObject& par) : keymap_is_initialised(false) {} ParsingObject& -ParsingObject::operator =(const ParsingObject& par) -{ - if (&par == this) return *this; +ParsingObject::operator=(const ParsingObject& par) { + if (&par == this) + return *this; keymap_is_initialised = false; return *this; } -void -ParsingObject:: -set_defaults() -{} +void +ParsingObject::set_defaults() {} void -ParsingObject:: -initialise_keymap() -{} +ParsingObject::initialise_keymap() {} -bool -ParsingObject:: -post_processing() -{ return false; } +bool +ParsingObject::post_processing() { + return false; +} -void -ParsingObject:: -set_key_values() -{} +void +ParsingObject::set_key_values() {} -//void +// void bool -ParsingObject:: parse(std::istream& in) -{ +ParsingObject::parse(std::istream& in) { // potentially remove the if() and always call initialise_keymap - if (!keymap_is_initialised) - { - initialise_keymap(); + if (!keymap_is_initialised) { + initialise_keymap(); keymap_is_initialised = true; } set_key_values(); - if (!parser.parse(in)) - { - warning("Error parsing.\n"); + if (!parser.parse(in)) { + warning("Error parsing.\n"); return false; - } - else if (post_processing()==true) - { - warning("Error post processing keyword values.\n"); - return false; - } - else + } else if (post_processing() == true) { + warning("Error post processing keyword values.\n"); + return false; + } else return true; } - -//void +// void bool -ParsingObject::parse(const char * const filename) -{ +ParsingObject::parse(const char* const filename) { ifstream hdr_stream(filename); - if (!hdr_stream) - { + if (!hdr_stream) { error("ParsingObject::parse: couldn't open file %s\n", filename); return false; } @@ -117,41 +92,34 @@ ParsingObject::parse(const char * const filename) } void -ParsingObject::ask_parameters() -{ +ParsingObject::ask_parameters() { // potentially remove the if() and always call initialise_keymap - if (!keymap_is_initialised) - { - initialise_keymap(); + if (!keymap_is_initialised) { + initialise_keymap(); keymap_is_initialised = true; } // TODO drop next line set_defaults(); set_key_values(); - while(true) - { + while (true) { parser.ask_parameters(); - if (post_processing()==true) - { - warning("\nError post processing keyword values. Doing it all over again...\n"); - } - else + if (post_processing() == true) { + warning("\nError post processing keyword values. Doing it all over again...\n"); + } else return; } } std::string -ParsingObject::parameter_info() -{ - if (!keymap_is_initialised) - { - initialise_keymap(); +ParsingObject::parameter_info() { + if (!keymap_is_initialised) { + initialise_keymap(); keymap_is_initialised = true; } set_key_values(); - return parser.parameter_info(); + return parser.parameter_info(); } END_NAMESPACE_STIR diff --git a/src/buildblock/PatientPosition.cxx b/src/buildblock/PatientPosition.cxx index a95431302e..03354146df 100644 --- a/src/buildblock/PatientPosition.cxx +++ b/src/buildblock/PatientPosition.cxx @@ -28,63 +28,80 @@ START_NAMESPACE_STIR -PatientPosition::PatientPosition(PatientPosition::PositionValue position) -{ - switch(position) - { - case FFP: - orientation=feet_in; rotation=prone; break; - case HFP: - orientation=head_in; rotation=prone; break; - case FFS: - orientation=feet_in; rotation=supine; break; - case HFS: - orientation=head_in; rotation=supine; break; - case FFDR: - orientation=feet_in; rotation=right; break; - case HFDR: - orientation=head_in; rotation=right; break; - case FFDL: - orientation=feet_in; rotation=left; break; - case HFDL: - orientation=head_in; rotation=left; break; - case unknown_position: - orientation=unknown_orientation; rotation=unknown_rotation; break; - } +PatientPosition::PatientPosition(PatientPosition::PositionValue position) { + switch (position) { + case FFP: + orientation = feet_in; + rotation = prone; + break; + case HFP: + orientation = head_in; + rotation = prone; + break; + case FFS: + orientation = feet_in; + rotation = supine; + break; + case HFS: + orientation = head_in; + rotation = supine; + break; + case FFDR: + orientation = feet_in; + rotation = right; + break; + case HFDR: + orientation = head_in; + rotation = right; + break; + case FFDL: + orientation = feet_in; + rotation = left; + break; + case HFDL: + orientation = head_in; + rotation = left; + break; + case unknown_position: + orientation = unknown_orientation; + rotation = unknown_rotation; + break; + } } PatientPosition::PositionValue -PatientPosition::get_position() const -{ +PatientPosition::get_position() const { // make use of order of enum's - if (orientation<=feet_in && rotation<=left) - { - return static_cast(orientation*4 + rotation); - } - else - { - return unknown_position; - } + if (orientation <= feet_in && rotation <= left) { + return static_cast(orientation * 4 + rotation); + } else { + return unknown_position; + } } -const char * const -PatientPosition:: -get_position_as_string() const -{ - switch (this->get_position()) - { - case HFP: return "HFP"; - case HFS: return "HFS"; - case HFDR: return "HFDR"; - case HFDL: return "HFDL"; - case FFDR: return "FFDR"; - case FFDL: return "FFDL"; - case FFP: return "FFP"; - case FFS: return "FFS"; - case unknown_position: - default: - return "unknown"; - } +const char* const +PatientPosition::get_position_as_string() const { + switch (this->get_position()) { + case HFP: + return "HFP"; + case HFS: + return "HFS"; + case HFDR: + return "HFDR"; + case HFDL: + return "HFDL"; + case FFDR: + return "FFDR"; + case FFDL: + return "FFDL"; + case FFP: + return "FFP"; + case FFS: + return "FFS"; + case unknown_position: + default: + return "unknown"; + } } END_NAMESPACE_STIR diff --git a/src/buildblock/ProjData.cxx b/src/buildblock/ProjData.cxx index 19ff7b58c7..3ad44cec99 100644 --- a/src/buildblock/ProjData.cxx +++ b/src/buildblock/ProjData.cxx @@ -2,6 +2,7 @@ Copyright (C) 2000 PARAPET partners Copyright (C) 2000 - 2010-10-15, Hammersmith Imanet Ltd Copyright (C) 2011-07-01 -2013, Kris Thielemans + Copyright (C) 2016, University of Hull Copyright (C) 2015, 2020 University College London This file is part of STIR. @@ -19,10 +20,11 @@ */ /*! \file - \ingroup projdata + \ingroup projdata \brief Implementations for non-inline functions of class stir::ProjData + \author Nikos Efthimiou \author Kris Thielemans \author PARAPET project */ @@ -41,20 +43,20 @@ #include "stir/ProjDataFromStream.h" // needed for converting ProjDataFromStream* to ProjData* #ifndef STIR_USE_GE_IO -#include "stir/ProjDataGEAdvance.h" +# include "stir/ProjDataGEAdvance.h" #else -#include "stir_experimental/IO/GE/ProjDataVOLPET.h" -#ifdef HAVE_RDF -#include "stir_experimental/IO/GE/stir_RDF.h" -#include "stir_experimental/IO/GE/ProjDataRDF.h" -#endif +# include "stir_experimental/IO/GE/ProjDataVOLPET.h" +# ifdef HAVE_RDF +# include "stir_experimental/IO/GE/stir_RDF.h" +# include "stir_experimental/IO/GE/ProjDataRDF.h" +# endif #endif // STIR_USE_GE_IO #ifdef HAVE_IE -#include "stir_experimental/IO/GE/ProjDataIE.h" +# include "stir_experimental/IO/GE/ProjDataIE.h" #endif #ifdef HAVE_HDF5 -#include "stir/ProjDataGEHDF5.h" -#include "stir/IO/GEHDF5Wrapper.h" +# include "stir/ProjDataGEHDF5.h" +# include "stir/IO/GEHDF5Wrapper.h" #endif #include "stir/IO/stir_ecat7.h" #include "stir/ViewSegmentNumbers.h" @@ -73,9 +75,9 @@ using std::vector; START_NAMESPACE_STIR -/*! +/*! This function will attempt to determine the type of projection data in the file, - construct an object of the appropriate type, and return a pointer to + construct an object of the appropriate type, and return a pointer to the object. The return value is a shared_ptr, to make sure that the caller will @@ -90,102 +92,86 @@ START_NAMESPACE_STIR
  • GE VOLPET data (via class ProjDataVOLPET)
  • Interfile (using read_interfile_PDFS()) -
  • ECAT 7 3D sinograms and attenuation files +
  • ECAT 7 3D sinograms and attenuation files
Developer's note: ideally the return value would be an stir::unique_ptr. */ -shared_ptr -ProjData:: -read_from_file(const string& filename, - const std::ios::openmode openmode) -{ +shared_ptr +ProjData::read_from_file(const string& filename, const std::ios::openmode openmode) { std::string actual_filename = filename; // parse filename to see if it's like filename,options { const std::size_t comma_pos = filename.find(','); - if (comma_pos != std::string::npos) - { - actual_filename.resize(comma_pos); - } + if (comma_pos != std::string::npos) { + actual_filename.resize(comma_pos); + } } - fstream * input = new fstream(actual_filename.c_str(), openmode | ios::binary); - if (! *input) + fstream* input = new fstream(actual_filename.c_str(), openmode | ios::binary); + if (!*input) error("ProjData::read_from_file: error opening file %s", actual_filename.c_str()); const FileSignature file_signature(actual_filename); - const char * signature = file_signature.get_signature(); + const char* signature = file_signature.get_signature(); // GE Advance - if (strncmp(signature, "2D3D", 4) == 0) - { + if (strncmp(signature, "2D3D", 4) == 0) { // if (ask("Read with old code (Y) or new (N)?",false)) -#ifndef STIR_USE_GE_IO - { -#ifndef NDEBUG - warning("ProjData::read_from_file trying to read %s as GE Advance file", - filename.c_str()); -#endif - return shared_ptr( new ProjDataGEAdvance(input) ); - } - //else +#ifndef STIR_USE_GE_IO + { +# ifndef NDEBUG + warning("ProjData::read_from_file trying to read %s as GE Advance file", filename.c_str()); +# endif + return shared_ptr(new ProjDataGEAdvance(input)); + } + // else #else // use VOLPET - { -#ifndef NDEBUG - warning("ProjData::read_from_file trying to read %s as GE VOLPET file", - filename.c_str()); -#endif - delete input;// TODO no longer use pointer after getting rid of ProjDataGEAdvance - return shared_ptr( new GE_IO::ProjDataVOLPET(filename, openmode) ); - } + { +# ifndef NDEBUG + warning("ProjData::read_from_file trying to read %s as GE VOLPET file", filename.c_str()); +# endif + delete input; // TODO no longer use pointer after getting rid of ProjDataGEAdvance + return shared_ptr(new GE_IO::ProjDataVOLPET(filename, openmode)); + } #endif // STIR_USE_GE_IO to differentiate between Advance and VOLPET code } - delete input;// TODO no longer use pointer after getting rid of ProjDataGEAdvance + delete input; // TODO no longer use pointer after getting rid of ProjDataGEAdvance #ifdef HAVE_IE - // GE IE file format - if (GE_IO::is_IE_signature(signature)) - { -#ifndef NDEBUG - warning("ProjData::read_from_file trying to read %s as GE IE file", - filename.c_str()); -#endif - return shared_ptr( new GE_IO::ProjDataIE(filename) ); - } + // GE IE file format + if (GE_IO::is_IE_signature(signature)) { +# ifndef NDEBUG + warning("ProjData::read_from_file trying to read %s as GE IE file", filename.c_str()); +# endif + return shared_ptr(new GE_IO::ProjDataIE(filename)); + } #endif // HAVE_IE - #ifdef HAVE_LLN_MATRIX // ECAT 7 - if (strncmp(signature, "MATRIX", 6) == 0) - { -#ifndef NDEBUG + if (strncmp(signature, "MATRIX", 6) == 0) { +# ifndef NDEBUG warning("ProjData::read_from_file trying to read %s as ECAT7", filename.c_str()); -#endif +# endif USING_NAMESPACE_ECAT; USING_NAMESPACE_ECAT7; - if (is_ECAT7_emission_file(actual_filename) || is_ECAT7_attenuation_file(actual_filename)) - { - warning("\nReading frame 1, gate 1, data 0, bed 0 from file %s", - actual_filename.c_str()); - shared_ptr proj_data_sptr(ECAT7_to_PDFS(filename, /*frame_num, gate_num, data_num, bed_num*/1,1,0,0)); + if (is_ECAT7_emission_file(actual_filename) || is_ECAT7_attenuation_file(actual_filename)) { + warning("\nReading frame 1, gate 1, data 0, bed 0 from file %s", actual_filename.c_str()); + shared_ptr proj_data_sptr(ECAT7_to_PDFS(filename, /*frame_num, gate_num, data_num, bed_num*/ 1, 1, 0, 0)); return proj_data_sptr; - } - else - { + } else { if (is_ECAT7_file(actual_filename)) - warning("ProjData::read_from_file ECAT7 file %s is of unsupported file type", actual_filename.c_str()); + warning("ProjData::read_from_file ECAT7 file %s is of unsupported file type", actual_filename.c_str()); } } #endif // HAVE_LLN_MATRIX // Interfile - if (is_interfile_signature(signature)) - { + if (is_interfile_signature(signature)) { #ifndef NDEBUG warning("ProjData::read_from_file trying to read %s as Interfile", filename.c_str()); #endif @@ -194,126 +180,116 @@ read_from_file(const string& filename, return ptr; } - #if defined(STIR_USE_GE_IO) && defined(HAVE_RDF) - if (GE_IO::is_RDF_file(actual_filename)) - { -#ifndef NDEBUG - warning("ProjData::read_from_file trying to read %s as RDF", filename.c_str()); -#endif - shared_ptr ptr(new GE_IO::ProjDataRDF(filename)); - if (!is_null_ptr(ptr)) - return ptr; + if (GE_IO::is_RDF_file(actual_filename)) { +# ifndef NDEBUG + warning("ProjData::read_from_file trying to read %s as RDF", filename.c_str()); +# endif + shared_ptr ptr(new GE_IO::ProjDataRDF(filename)); + if (!is_null_ptr(ptr)) + return ptr; } #endif // RDF - + #ifdef HAVE_HDF5 - if (GE::RDF_HDF5::GEHDF5Wrapper::check_GE_signature(actual_filename)) - { -#ifndef NDEBUG - warning("ProjData::read_from_file trying to read %s as GE HDF5", filename.c_str()); -#endif - shared_ptr ptr(new GE::RDF_HDF5::ProjDataGEHDF5(filename)); - if (!is_null_ptr(ptr)) - return ptr; + if (GE::RDF_HDF5::GEHDF5Wrapper::check_GE_signature(actual_filename)) { +# ifndef NDEBUG + warning("ProjData::read_from_file trying to read %s as GE HDF5", filename.c_str()); +# endif + shared_ptr ptr(new GE::RDF_HDF5::ProjDataGEHDF5(filename)); + if (!is_null_ptr(ptr)) + return ptr; } #endif // GE HDF5 error("\nProjData::read_from_file could not read projection data %s.\n" - "Unsupported file format? Aborting.", - filename.c_str()); + "Unsupported file format? Aborting.", + filename.c_str()); // need to return something to satisfy the compiler, but we never get here shared_ptr null_ptr; return null_ptr; } -//void -//ProjData::set_exam_info(ExamInfo const& new_exam_info) +// void +// ProjData::set_exam_info(ExamInfo const& new_exam_info) //{ // this->exam_info_sptr.reset(new ExamInfo(new_exam_info)); //} - -Viewgram -ProjData::get_empty_viewgram(const int view_num, const int segment_num, - const bool make_num_tangential_poss_odd) const -{ - return - proj_data_info_sptr->get_empty_viewgram(view_num, segment_num, make_num_tangential_poss_odd); +Viewgram +ProjData::get_empty_viewgram(const int view_num, const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos) const { + return proj_data_info_sptr->get_empty_viewgram(view_num, segment_num, make_num_tangential_poss_odd, timing_pos); } Sinogram -ProjData::get_empty_sinogram(const int ax_pos_num, const int segment_num, - const bool make_num_tangential_poss_odd) const -{ - return - proj_data_info_sptr->get_empty_sinogram(ax_pos_num, segment_num, make_num_tangential_poss_odd); +ProjData::get_empty_sinogram(const int ax_pos_num, const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos) const { + return proj_data_info_sptr->get_empty_sinogram(ax_pos_num, segment_num, make_num_tangential_poss_odd, timing_pos); } - SegmentBySinogram -ProjData::get_empty_segment_by_sinogram(const int segment_num, - const bool make_num_tangential_poss_odd) const -{ - return - proj_data_info_sptr->get_empty_segment_by_sinogram(segment_num, make_num_tangential_poss_odd); -} - +ProjData::get_empty_segment_by_sinogram(const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos) const { + return proj_data_info_sptr->get_empty_segment_by_sinogram(segment_num, make_num_tangential_poss_odd, timing_pos); +} SegmentByView -ProjData::get_empty_segment_by_view(const int segment_num, - const bool make_num_tangential_poss_odd) const -{ - return - proj_data_info_sptr->get_empty_segment_by_view(segment_num, make_num_tangential_poss_odd); - +ProjData::get_empty_segment_by_view(const int segment_num, const bool make_num_tangential_poss_odd, const int timing_pos) const { + return proj_data_info_sptr->get_empty_segment_by_view(segment_num, make_num_tangential_poss_odd, timing_pos); } -RelatedViewgrams +RelatedViewgrams ProjData::get_empty_related_viewgrams(const ViewSegmentNumbers& view_segmnet_num, - //const int view_num, const int segment_num, - const shared_ptr& symmetries_used, - const bool make_num_tangential_poss_odd) const -{ - return - proj_data_info_sptr->get_empty_related_viewgrams(view_segmnet_num, symmetries_used, make_num_tangential_poss_odd); + // const int view_num, const int segment_num, + const shared_ptr& symmetries_used, + const bool make_num_tangential_poss_odd, const int timing_pos) const { + return proj_data_info_sptr->get_empty_related_viewgrams(view_segmnet_num, symmetries_used, make_num_tangential_poss_odd, + timing_pos); } - -RelatedViewgrams -ProjData::get_related_viewgrams(const ViewSegmentNumbers& view_segmnet_num, - //const int view_num, const int segment_num, - const shared_ptr& symmetries_used, - const bool make_num_bins_odd) const -{ +RelatedViewgrams +ProjData::get_related_viewgrams(const ViewSegmentNumbers& view_segment_num, + // const int view_num, const int segment_num, + const shared_ptr& symmetries_used, + const bool make_num_bins_odd, const int timing_pos) const { vector pairs; symmetries_used->get_related_view_segment_numbers( - pairs, - ViewSegmentNumbers(view_segmnet_num.view_num(),view_segmnet_num.segment_num()) - ); + pairs, ViewSegmentNumbers(view_segment_num.view_num(), view_segment_num.segment_num())); - vector > viewgrams; + vector> viewgrams; viewgrams.reserve(pairs.size()); - for (unsigned int i=0; i(viewgrams, symmetries_used); } +// std::vector +// ProjData::get_related_bin_values(const std::vector& r_bins) const +//{ + +// std::vector values; +// values.reserve(r_bins.size()); -Succeeded -ProjData::set_related_viewgrams( const RelatedViewgrams& viewgrams) -{ +// for (std::vector ::const_iterator r_bins_iterator = r_bins.begin(); +// r_bins_iterator != r_bins.end(); ++r_bins_iterator) +// { +// values.push_back(this->get_bin_value(*r_bins_iterator)); +// } + +// return values; +//} + +Succeeded +ProjData::set_related_viewgrams(const RelatedViewgrams& viewgrams) { RelatedViewgrams::const_iterator r_viewgrams_iter = viewgrams.begin(); - while( r_viewgrams_iter!=viewgrams.end()) - { - if (set_viewgram(*r_viewgrams_iter)== Succeeded::no) + while (r_viewgrams_iter != viewgrams.end()) { + if (set_viewgram(*r_viewgrams_iter) == Succeeded::no) return Succeeded::no; ++r_viewgrams_iter; } @@ -330,191 +306,147 @@ ProjData::set_related_viewgrams( const RelatedViewgrams& viewgrams) } #endif -SegmentBySinogram ProjData::get_segment_by_sinogram(const int segment_num) const -{ - SegmentBySinogram segment = - proj_data_info_sptr->get_empty_segment_by_sinogram(segment_num,false); +SegmentBySinogram +ProjData::get_segment_by_sinogram(const int segment_num, const int timing_pos) const { + SegmentBySinogram segment = proj_data_info_sptr->get_empty_segment_by_sinogram(segment_num, false, timing_pos); // TODO optimise to get shared proj_data_info_ptr for (int view_num = get_min_view_num(); view_num <= get_max_view_num(); ++view_num) - segment.set_viewgram(get_viewgram(view_num, segment_num, false)); - + segment.set_viewgram(get_viewgram(view_num, segment_num, false, timing_pos)); return segment; } -SegmentByView ProjData::get_segment_by_view(const int segment_num) const -{ - SegmentByView segment = - proj_data_info_sptr->get_empty_segment_by_view(segment_num,false); +SegmentByView +ProjData::get_segment_by_view(const int segment_num, const int timing_pos) const { + SegmentByView segment = proj_data_info_sptr->get_empty_segment_by_view(segment_num, false, timing_pos); // TODO optimise to get shared proj_data_info_ptr for (int view_num = get_min_view_num(); view_num <= get_max_view_num(); ++view_num) - segment.set_viewgram(get_viewgram(view_num, segment_num, false)); - + segment.set_viewgram(get_viewgram(view_num, segment_num, false, timing_pos)); return segment; } -Succeeded -ProjData::set_segment(const SegmentBySinogram& segment) -{ - for (int view_num = get_min_view_num(); view_num <= get_max_view_num(); ++view_num) - { - if(set_viewgram(segment.get_viewgram(view_num)) - == Succeeded::no) - return Succeeded::no; +Succeeded +ProjData::set_segment(const SegmentBySinogram& segment) { + for (int view_num = get_min_view_num(); view_num <= get_max_view_num(); ++view_num) { + if (set_viewgram(segment.get_viewgram(view_num)) == Succeeded::no) + return Succeeded::no; } return Succeeded::yes; } -Succeeded -ProjData::set_segment(const SegmentByView& segment) -{ - for (int view_num = get_min_view_num(); view_num <= get_max_view_num(); ++view_num) - { - if(set_viewgram(segment.get_viewgram(view_num)) - == Succeeded::no) - return Succeeded::no; +Succeeded +ProjData::set_segment(const SegmentByView& segment) { + for (int view_num = get_min_view_num(); view_num <= get_max_view_num(); ++view_num) { + if (set_viewgram(segment.get_viewgram(view_num)) == Succeeded::no) + return Succeeded::no; } return Succeeded::yes; } - -void -ProjData::fill(const float value) -{ - for (int segment_num = this->get_min_segment_num(); segment_num <= this->get_max_segment_num(); ++segment_num) - { - SegmentByView segment(this->get_empty_segment_by_view(segment_num)); - segment.fill(value); - if(this->set_segment(segment) == Succeeded::no) - error("Error setting segment of projection data"); +void +ProjData::fill(const float value) { + for (int timing_pos_num = this->get_min_tof_pos_num(); timing_pos_num <= this->get_max_tof_pos_num(); ++timing_pos_num) { + for (int segment_num = this->get_min_segment_num(); segment_num <= this->get_max_segment_num(); ++segment_num) { + SegmentByView segment(this->get_empty_segment_by_view(segment_num, false, timing_pos_num)); + segment.fill(value); + if (this->set_segment(segment) == Succeeded::no) + error("Error setting segment of projection data"); + } } } -void -ProjData::fill(const ProjData& proj_data) -{ +void +ProjData::fill(const ProjData& proj_data) { shared_ptr source_proj_data_info_sptr = proj_data.get_proj_data_info_sptr()->create_shared_clone(); source_proj_data_info_sptr->reduce_segment_range(std::max(this->get_min_segment_num(), proj_data.get_min_segment_num()), std::min(this->get_max_segment_num(), proj_data.get_max_segment_num())); if ((*this->get_proj_data_info_sptr()) != (*source_proj_data_info_sptr)) - error("Filling projection data from incompatible source"); + error("Filling projection data from incompatible source"); - for (int segment_num = this->get_min_segment_num(); segment_num <= this->get_max_segment_num(); ++segment_num) - { - if(this->set_segment(proj_data.get_segment_by_view(segment_num)) - == Succeeded::no) - error("Error setting segment of projection data"); + for (int segment_num = this->get_min_segment_num(); segment_num <= this->get_max_segment_num(); ++segment_num) { + for (int timing_pos_num = this->get_min_tof_pos_num(); timing_pos_num <= this->get_max_tof_pos_num(); ++timing_pos_num) { + if (this->set_segment(proj_data.get_segment_by_view(segment_num, timing_pos_num)) == Succeeded::no) + error("Error setting segment of projection data"); + } } } -ProjData:: ProjData() - :ExamData() -{} +ProjData::ProjData() : ExamData() {} -ProjData::ProjData(const shared_ptr& exam_info_sptr, - const shared_ptr& proj_data_info_sptr) - :ExamData(exam_info_sptr), proj_data_info_sptr(proj_data_info_sptr) -{} +ProjData::ProjData(const shared_ptr& exam_info_sptr, const shared_ptr& proj_data_info_sptr) + : ExamData(exam_info_sptr), proj_data_info_sptr(proj_data_info_sptr) {} Succeeded -ProjData:: -write_to_file(const string& output_filename) const -{ +ProjData::write_to_file(const string& output_filename) const { - ProjDataInterfile out_projdata(get_exam_info_sptr(), - this->proj_data_info_sptr, output_filename, ios::out); + ProjDataInterfile out_projdata(get_exam_info_sptr(), this->proj_data_info_sptr, output_filename, ios::out); - Succeeded success=Succeeded::yes; - for (int segment_num = proj_data_info_sptr->get_min_segment_num(); - segment_num <= proj_data_info_sptr->get_max_segment_num(); - ++segment_num) - { - Succeeded success_this_segment = - out_projdata.set_segment(get_segment_by_view(segment_num)); - if (success==Succeeded::yes) + Succeeded success = Succeeded::yes; + for (int segment_num = proj_data_info_sptr->get_min_segment_num(); segment_num <= proj_data_info_sptr->get_max_segment_num(); + ++segment_num) { + Succeeded success_this_segment = out_projdata.set_segment(get_segment_by_view(segment_num)); + if (success == Succeeded::yes) success = success_this_segment; } return success; - } void -ProjData:: -axpby( const float a, const ProjData& x, - const float b, const ProjData& y) -{ - xapyb(x,a,y,b); +ProjData::axpby(const float a, const ProjData& x, const float b, const ProjData& y) { + xapyb(x, a, y, b); } void -ProjData:: -xapyb(const ProjData& x, const float a, - const ProjData& y, const float b) -{ - if (*get_proj_data_info_sptr() != *x.get_proj_data_info_sptr() || - *get_proj_data_info_sptr() != *y.get_proj_data_info_sptr()) - error("ProjData::xapyb: ProjDataInfo don't match"); - - const int n_min = get_min_segment_num(); - const int n_max = get_max_segment_num(); - - for (int s=n_min; s<=n_max; ++s) - { - SegmentBySinogram seg = get_empty_segment_by_sinogram(s); - const SegmentBySinogram sx = x.get_segment_by_sinogram(s); - const SegmentBySinogram sy = y.get_segment_by_sinogram(s); - seg.xapyb(sx, a, sy, b); - set_segment(seg); - } +ProjData::xapyb(const ProjData& x, const float a, const ProjData& y, const float b) { + if (*get_proj_data_info_sptr() != *x.get_proj_data_info_sptr() || *get_proj_data_info_sptr() != *y.get_proj_data_info_sptr()) + error("ProjData::xapyb: ProjDataInfo don't match"); + + const int n_min = get_min_segment_num(); + const int n_max = get_max_segment_num(); + + for (int s = n_min; s <= n_max; ++s) { + SegmentBySinogram seg = get_empty_segment_by_sinogram(s); + const SegmentBySinogram sx = x.get_segment_by_sinogram(s); + const SegmentBySinogram sy = y.get_segment_by_sinogram(s); + seg.xapyb(sx, a, sy, b); + set_segment(seg); + } } void -ProjData:: -xapyb(const ProjData& x, const ProjData& a, - const ProjData& y, const ProjData& b) -{ - if (*get_proj_data_info_sptr() != *x.get_proj_data_info_sptr() || - *get_proj_data_info_sptr() != *y.get_proj_data_info_sptr() || - *get_proj_data_info_sptr() != *a.get_proj_data_info_sptr() || - *get_proj_data_info_sptr() != *b.get_proj_data_info_sptr()) - error("ProjData::xapyb: ProjDataInfo don't match"); - - const int n_min = get_min_segment_num(); - const int n_max = get_max_segment_num(); - - for (int s=n_min; s<=n_max; ++s) - { - SegmentBySinogram seg = get_empty_segment_by_sinogram(s); - const SegmentBySinogram sx = x.get_segment_by_sinogram(s); - const SegmentBySinogram sy = y.get_segment_by_sinogram(s); - const SegmentBySinogram sa = a.get_segment_by_sinogram(s); - const SegmentBySinogram sb = b.get_segment_by_sinogram(s); - - seg.xapyb(sx, sa, sy, sb); - set_segment(seg); - } +ProjData::xapyb(const ProjData& x, const ProjData& a, const ProjData& y, const ProjData& b) { + if (*get_proj_data_info_sptr() != *x.get_proj_data_info_sptr() || *get_proj_data_info_sptr() != *y.get_proj_data_info_sptr() || + *get_proj_data_info_sptr() != *a.get_proj_data_info_sptr() || *get_proj_data_info_sptr() != *b.get_proj_data_info_sptr()) + error("ProjData::xapyb: ProjDataInfo don't match"); + + const int n_min = get_min_segment_num(); + const int n_max = get_max_segment_num(); + + for (int s = n_min; s <= n_max; ++s) { + SegmentBySinogram seg = get_empty_segment_by_sinogram(s); + const SegmentBySinogram sx = x.get_segment_by_sinogram(s); + const SegmentBySinogram sy = y.get_segment_by_sinogram(s); + const SegmentBySinogram sa = a.get_segment_by_sinogram(s); + const SegmentBySinogram sb = b.get_segment_by_sinogram(s); + + seg.xapyb(sx, sa, sy, sb); + set_segment(seg); + } } void -ProjData:: -sapyb(const float a, const ProjData& y, const float b) -{ - this->xapyb(*this,a,y,b); +ProjData::sapyb(const float a, const ProjData& y, const float b) { + this->xapyb(*this, a, y, b); } void -ProjData:: -sapyb(const ProjData& a, const ProjData& y,const ProjData& b) -{ - this->xapyb(*this,a,y,b); +ProjData::sapyb(const ProjData& a, const ProjData& y, const ProjData& b) { + this->xapyb(*this, a, y, b); } - std::vector -ProjData:: -standard_segment_sequence(const ProjDataInfo& pdi) -{ +ProjData::standard_segment_sequence(const ProjDataInfo& pdi) { std::vector segment_sequence(pdi.get_num_segments()); - if (pdi.get_num_segments()==0) + if (pdi.get_num_segments() == 0) return segment_sequence; const int max_segment_num = pdi.get_max_segment_num(); @@ -522,11 +454,10 @@ standard_segment_sequence(const ProjDataInfo& pdi) segment_sequence[0] = 0; unsigned idx = 1; int segment_num = 1; - while (idx < segment_sequence.size()) - { - if (segment_num<=max_segment_num) + while (idx < segment_sequence.size()) { + if (segment_num <= max_segment_num) segment_sequence[idx++] = segment_num; - if (-segment_num>=min_segment_num) + if (-segment_num >= min_segment_num) segment_sequence[idx++] = -segment_num; ++segment_num; } diff --git a/src/buildblock/ProjDataFromStream.cxx b/src/buildblock/ProjDataFromStream.cxx index baffea24d3..9088e290ef 100644 --- a/src/buildblock/ProjDataFromStream.cxx +++ b/src/buildblock/ProjDataFromStream.cxx @@ -3,6 +3,7 @@ \ingroup projdata \brief Implementations for non-inline functions of class stir::ProjDataFromStream + \author Nikos Efthimiou \author Sanida Mustafovic \author Kris Thielemans \author Claire Labbe @@ -12,7 +13,8 @@ Copyright (C) 2000 PARAPET partners Copyright (C) 2000 - 2011-12-21, Hammersmith Imanet Ltd Copyright (C) 2011-2012, Kris Thielemans - Copyright (C) 2013, University College London + Copyright (C) 2013, 2017 University College London + Copyright (C) 2016, University of Hull This file is part of STIR. @@ -61,9 +63,9 @@ using std::vector; #ifdef _MSC_VER // work-around for compiler bug: VC messes up std namespace -#define FIND std::find +# define FIND std::find #else -#define FIND find +# define FIND find #endif START_NAMESPACE_STIR @@ -72,341 +74,315 @@ START_NAMESPACE_STIR //--------------------------------------------------------- ProjDataFromStream::ProjDataFromStream(shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, - shared_ptr const& s, const streamoff offs, - const vector& segment_sequence_in_stream_v, - StorageOrder o, - NumericType data_type, - ByteOrder byte_order, - float scale_factor) - - : - ProjData(exam_info_sptr, proj_data_info_ptr), - sino_stream(s), offset(offs), - segment_sequence(segment_sequence_in_stream_v), - storage_order(o), - on_disk_data_type(data_type), - on_disk_byte_order(byte_order), - scale_factor(scale_factor) -{ + shared_ptr const& proj_data_info_sptr, shared_ptr const& s, + const streamoff offs, const vector& segment_sequence_in_stream_v, StorageOrder o, + NumericType data_type, ByteOrder byte_order, float scale_factor) + + : ProjData(exam_info_sptr, proj_data_info_sptr), sino_stream(s), offset(offs), segment_sequence(segment_sequence_in_stream_v), + storage_order(o), on_disk_data_type(data_type), on_disk_byte_order(byte_order), scale_factor(scale_factor) { assert(storage_order != Unsupported); assert(!(data_type == NumericType::UNKNOWN_TYPE)); + + if (proj_data_info_sptr->get_num_tof_poss() > 1) + activate_TOF(); } ProjDataFromStream::ProjDataFromStream(shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, - shared_ptr const& s, const streamoff offs, - StorageOrder o, - NumericType data_type, - ByteOrder byte_order, - float scale_factor) - : - ProjData(exam_info_sptr, proj_data_info_ptr), - sino_stream(s), offset(offs), - storage_order(o), - on_disk_data_type(data_type), - on_disk_byte_order(byte_order), - scale_factor(scale_factor) -{ + shared_ptr const& proj_data_info_sptr, shared_ptr const& s, + const streamoff offs, StorageOrder o, NumericType data_type, ByteOrder byte_order, + float scale_factor) + : ProjData(exam_info_sptr, proj_data_info_sptr), sino_stream(s), offset(offs), storage_order(o), on_disk_data_type(data_type), + on_disk_byte_order(byte_order), scale_factor(scale_factor) { assert(storage_order != Unsupported); assert(!(data_type == NumericType::UNKNOWN_TYPE)); - segment_sequence.resize(proj_data_info_ptr->get_num_segments()); + segment_sequence.resize(proj_data_info_sptr->get_num_segments()); + // N.E. Take this opportunity to calculate the size of the complete -full- 3D sinogram. + // We will need that to skip timing positions int segment_num, i; - for (i= 0, segment_num = proj_data_info_ptr->get_min_segment_num(); - segment_num<=proj_data_info_ptr->get_max_segment_num(); - ++i, ++segment_num) - { - segment_sequence[i] =segment_num; + + for (i = 0, segment_num = proj_data_info_sptr->get_min_segment_num(); segment_num <= proj_data_info_sptr->get_max_segment_num(); + ++i, ++segment_num) { + segment_sequence[i] = segment_num; } + + if (proj_data_info_sptr->get_num_tof_poss() > 1) + activate_TOF(); } -Viewgram -ProjDataFromStream::get_viewgram(const int view_num, const int segment_num, - const bool make_num_tangential_poss_odd) const -{ - if (is_null_ptr(sino_stream)) - { +void +ProjDataFromStream::activate_TOF() { + int sum = 0; + for (int segment_num = proj_data_info_sptr->get_min_segment_num(); segment_num <= proj_data_info_sptr->get_max_segment_num(); + ++segment_num) { + sum += get_num_axial_poss(segment_num) * get_num_views() * get_num_tangential_poss(); + } + + offset_3d_data = static_cast(sum * on_disk_data_type.size_in_bytes()); + + // Now, lets initialise a TOF stream - Similarly to segments + storage_order = Timing_Segment_View_AxialPos_TangPos; + + timing_poss_sequence.resize(proj_data_info_sptr->get_num_tof_poss()); + + for (int i = 0, timing_pos_num = proj_data_info_sptr->get_min_tof_pos_num(); + timing_pos_num <= proj_data_info_sptr->get_max_tof_pos_num(); ++i, ++timing_pos_num) { + timing_poss_sequence[i] = timing_pos_num; + } +} + +Viewgram +ProjDataFromStream::get_viewgram(const int view_num, const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos) const { + if (is_null_ptr(sino_stream)) { error("ProjDataFromStream::get_viewgram: stream ptr is 0\n"); } - if (! *sino_stream) - { + if (!*sino_stream) { error("ProjDataFromStream::get_viewgram: error in stream state before reading\n"); } - - vector offsets = get_offsets(view_num,segment_num); - + + vector offsets = get_offsets(view_num, segment_num, timing_pos); + const streamoff segment_offset = offsets[0]; const streamoff beg_view_offset = offsets[1]; const streamoff intra_views_offset = offsets[2]; - - Viewgram viewgram(proj_data_info_sptr, view_num, segment_num); + + Viewgram viewgram(proj_data_info_sptr, view_num, segment_num, timing_pos); float scale = float(1); Succeeded succeeded = Succeeded::yes; - + #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif { - sino_stream->seekg(segment_offset, ios::beg); // start of segment + sino_stream->seekg(segment_offset, ios::beg); // start of segment sino_stream->seekg(beg_view_offset, ios::cur); // start of view within segment - - if (! *sino_stream) - { - warning("ProjDataFromStream::get_viewgram: error after seekg"); - succeeded = Succeeded::no; + + if (!*sino_stream) { + warning("ProjDataFromStream::get_viewgram: error after seekg"); + succeeded = Succeeded::no; + } else if (get_storage_order() == + Segment_AxialPos_View_TangPos) //|| get_storage_order() == Timing_Segment_AxialPos_View_TangPos) + { + for (int ax_pos_num = get_min_axial_pos_num(segment_num); ax_pos_num <= get_max_axial_pos_num(segment_num); ax_pos_num++) { + if (read_data(*sino_stream, viewgram[ax_pos_num], on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no) { + succeeded = Succeeded::no; + break; + } else if (scale != 1) { + warning("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1"); + succeeded = Succeeded::no; + break; + } + // seek to next line unless it was the last we need to read + if (ax_pos_num != get_max_axial_pos_num(segment_num)) + sino_stream->seekg(intra_views_offset, ios::cur); } - else if (get_storage_order() == Segment_AxialPos_View_TangPos) - { - for (int ax_pos_num = get_min_axial_pos_num(segment_num); ax_pos_num <= get_max_axial_pos_num(segment_num); ax_pos_num++) - { - if (read_data(*sino_stream, viewgram[ax_pos_num], on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no) - { - succeeded = Succeeded::no; - break; - } - else if(scale != 1) - { - warning("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1"); - succeeded = Succeeded::no; - break; - } - // seek to next line unless it was the last we need to read - if(ax_pos_num != get_max_axial_pos_num(segment_num)) - sino_stream->seekg(intra_views_offset, ios::cur); - } - } - else if (get_storage_order() == Segment_View_AxialPos_TangPos) - { - if(read_data(*sino_stream, viewgram, on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no) - { - succeeded = Succeeded::no; - } - else if(scale != 1) - { - warning("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1"); - succeeded = Succeeded::no; - } + } else if (get_storage_order() == Segment_View_AxialPos_TangPos || + get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { + if (read_data(*sino_stream, viewgram, on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no) { + succeeded = Succeeded::no; + } else if (scale != 1) { + warning("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1"); + succeeded = Succeeded::no; } + } } // end of critical section if (succeeded == Succeeded::no) error("ProjDataFromStream: error reading data"); viewgram *= scale_factor; - if (make_num_tangential_poss_odd &&(get_num_tangential_poss()%2==0)) - { - const int new_max_tangential_pos = get_max_tangential_pos_num() + 1; - - viewgram.grow( - IndexRange2D(get_min_axial_pos_num(segment_num), - get_max_axial_pos_num(segment_num), - - get_min_tangential_pos_num(), - new_max_tangential_pos)); - } - return viewgram; + if (make_num_tangential_poss_odd && (get_num_tangential_poss() % 2 == 0)) + + { + const int new_max_tangential_pos = get_max_tangential_pos_num() + 1; + + viewgram.grow(IndexRange2D(get_min_axial_pos_num(segment_num), get_max_axial_pos_num(segment_num), + + get_min_tangential_pos_num(), new_max_tangential_pos)); + } + return viewgram; } float -ProjDataFromStream::get_bin_value(const Bin& this_bin) const -{ - if (is_null_ptr(sino_stream)) - { - error("ProjDataFromStream::get_bin_value: stream ptr is 0\n"); - } - if (! *sino_stream) - { - error("ProjDataFromStream::get_bin_value: error in stream state before reading\n"); - } +ProjDataFromStream::get_bin_value(const Bin& this_bin) const { + if (is_null_ptr(sino_stream)) { + error("ProjDataFromStream::get_bin_value: stream ptr is 0\n"); + } + if (!*sino_stream) { + error("ProjDataFromStream::get_bin_value: error in stream state before reading\n"); + } - vector offsets = get_offsets_bin(this_bin); + vector offsets = get_offsets_bin(this_bin); - const streamoff total_offset = offsets[0]; + const streamoff total_offset = offsets[0]; - sino_stream->seekg(0 , ios::beg); // reset file - sino_stream->seekg(total_offset, ios::cur); // start of view within segment + sino_stream->seekg(0, ios::beg); // reset file + sino_stream->seekg(total_offset, ios::cur); // start of view within segment - if (! *sino_stream) - { - error("ProjDataFromStream::get_bin_value: error after seekg."); - } + if (!*sino_stream) { + error("ProjDataFromStream::get_bin_value: error after seekg."); + } - Array< 1, float> value(1); - float scale = float(1); + Array<1, float> value(1); + float scale = float(1); - // Now the storage order is not more important. Just read. - if (read_data(*sino_stream, value, on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no) - error("ProjDataFromStream: error reading data\n"); - if(scale != 1.f) - error("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1\n"); + // Now the storage order is not more important. Just read. + if (read_data(*sino_stream, value, on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no) + error("ProjDataFromStream: error reading data\n"); + if (scale != 1.f) + error("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1\n"); - value *= scale_factor; + value *= scale_factor; - return value[0]; + return value[0]; } void -ProjDataFromStream::set_bin_value(const Bin& this_bin) -{ - if (is_null_ptr(sino_stream)) - { - error("ProjDataFromStream::set_bin_value: stream ptr is 0\n"); - } - if (! *sino_stream) - { - error("ProjDataFromStream::set_bin_value: error in stream state before writing"); - } +ProjDataFromStream::set_bin_value(const Bin& this_bin) { + if (is_null_ptr(sino_stream)) { + error("ProjDataFromStream::set_bin_value: stream ptr is 0\n"); + } + if (!*sino_stream) { + error("ProjDataFromStream::set_bin_value: error in stream state before writing"); + } - vector offsets = get_offsets_bin(this_bin); + vector offsets = get_offsets_bin(this_bin); - const streamoff total_offset = offsets[0]; + const streamoff total_offset = offsets[0]; - sino_stream->seekp(0 , ios::beg); // reset file - sino_stream->seekp(total_offset, ios::cur); // start of view within segment + sino_stream->seekp(0, ios::beg); // reset file + sino_stream->seekp(total_offset, ios::cur); // start of view within segment - if (! *sino_stream) - { - error("ProjDataFromStream::set_bin_value: error after seekp."); - } + if (!*sino_stream) { + error("ProjDataFromStream::set_bin_value: error after seekp."); + } - Array< 1, float> value(1); - value[0]=this_bin.get_bin_value(); - float scale = float(1); - // Now the storage order is not more important. Just read. - if (write_data(*sino_stream, value, on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no) - error("ProjDataFromStream: error writing data\n"); - if(scale != 1.f) - error("ProjDataFromStream: error writing data: scale factor returned by write_data should be 1\n"); + Array<1, float> value(1); + value[0] = this_bin.get_bin_value(); + float scale = float(1); + // Now the storage order is not more important. Just read. + if (write_data(*sino_stream, value, on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no) + error("ProjDataFromStream: error writing data\n"); + if (scale != 1.f) + error("ProjDataFromStream: error writing data: scale factor returned by write_data should be 1\n"); } vector -ProjDataFromStream::get_offsets(const int view_num, const int segment_num) const +ProjDataFromStream::get_offsets(const int view_num, const int segment_num, const int timing_num) const { - if (!(segment_num >= get_min_segment_num() && - segment_num <= get_max_segment_num())) + if (!(segment_num >= get_min_segment_num() && segment_num <= get_max_segment_num())) error("ProjDataFromStream::get_offsets: segment_num out of range : %d", segment_num); - if (!(view_num >= get_min_view_num() && - view_num <= get_max_view_num())) + if (!(view_num >= get_min_view_num() && view_num <= get_max_view_num())) error("ProjDataFromStream::get_offsets: view_num out of range : %d", view_num); + // cout<<"get_offsets"<(FIND(segment_sequence.begin(), segment_sequence.end(), segment_num) - segment_sequence.begin()); - const int index = - static_cast(FIND(segment_sequence.begin(), segment_sequence.end(), segment_num) - - segment_sequence.begin()); - streamoff num_axial_pos_offset = 0; - for (int i=0; i(num_axial_pos_offset* - get_num_tangential_poss() * - get_num_views() * - on_disk_data_type.size_in_bytes()); - - if (get_storage_order() == Segment_AxialPos_View_TangPos) - { - - + for (int i = 0; i < index; i++) + num_axial_pos_offset += get_num_axial_poss(segment_sequence[i]); + + streamoff segment_offset = offset + static_cast(num_axial_pos_offset * get_num_tangential_poss() * get_num_views() * + on_disk_data_type.size_in_bytes()); + + if (get_storage_order() == Segment_AxialPos_View_TangPos) { + const streamoff beg_view_offset = - (view_num - get_min_view_num()) *get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - - const streamoff intra_views_offset = - (get_num_views() -1) *get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + (view_num - get_min_view_num()) * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + + const streamoff intra_views_offset = (get_num_views() - 1) * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); vector temp(3); temp[0] = segment_offset; temp[1] = beg_view_offset; temp[2] = intra_views_offset; - + return temp; - } - else //if (get_storage_order() == Segment_View_AxialPos_TangPos) - { - const streamoff beg_view_offset = - (view_num - get_min_view_num()) - * get_num_axial_poss(segment_num) - * get_num_tangential_poss() - * on_disk_data_type.size_in_bytes(); - - + } else if (get_storage_order() == Segment_View_AxialPos_TangPos) { + const streamoff beg_view_offset = (view_num - get_min_view_num()) * get_num_axial_poss(segment_num) * + get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + + vector temp(3); + temp[0] = segment_offset; + temp[1] = beg_view_offset; + temp[2] = 0; + return temp; + } else if (get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { + // The timing offset will be added to the segment offset. This approach we minimise the + // changes + if (!(timing_num >= get_min_tof_pos_num() && timing_num <= get_max_tof_pos_num())) + error("ProjDataFromStream::get_offsets: timing_num out of range : %d", timing_num); + + const int timing_index = static_cast(FIND(timing_poss_sequence.begin(), timing_poss_sequence.end(), timing_num) - + timing_poss_sequence.begin()); + + assert(offset_3d_data > 0); + segment_offset += static_cast(timing_index) * offset_3d_data; + + const streamoff beg_view_offset = (view_num - get_min_view_num()) * get_num_axial_poss(segment_num) * + get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + vector temp(3); - temp[0] =segment_offset; - temp[1]= beg_view_offset; + temp[0] = segment_offset; + temp[1] = beg_view_offset; temp[2] = 0; return temp; - + } else { + error("ProjDataFromStream::get_offsets: unsupported storage_order"); + return vector(); // return something to avoid compiler warning } } Succeeded -ProjDataFromStream::set_viewgram(const Viewgram& v) -{ - if (is_null_ptr(sino_stream)) - { +ProjDataFromStream::set_viewgram(const Viewgram& v) { + if (is_null_ptr(sino_stream)) { warning("ProjDataFromStream::set_viewgram: stream ptr is 0\n"); return Succeeded::no; } - if (! *sino_stream) - { + if (!*sino_stream) { warning("ProjDataFromStream::set_viewgram: error in stream state before writing\n"); return Succeeded::no; } // KT 03/07/2001 modified handling of scale_factor etc. - if (on_disk_data_type.id != NumericType::FLOAT) - { + if (on_disk_data_type.id != NumericType::FLOAT) { warning("ProjDataFromStream::set_viewgram: non-float output uses original " "scale factor %g which might not be appropriate for the current data\n", - scale_factor); + scale_factor); } - if (get_num_tangential_poss() != v.get_proj_data_info_sptr()->get_num_tangential_poss()) - { - warning("ProjDataFromStream::set_viewgram: num_bins is not correct\n"); + if (get_num_tangential_poss() != v.get_proj_data_info_sptr()->get_num_tangential_poss()) { + warning("ProjDataFromStream::set_viewgram: num_bins is not correct\n"); return Succeeded::no; } - if (get_num_axial_poss(v.get_segment_num()) != v.get_num_axial_poss()) - { - warning("ProjDataFromStream::set_viewgram: number of axial positions is not correct\n"); + if (get_num_axial_poss(v.get_segment_num()) != v.get_num_axial_poss()) { + warning("ProjDataFromStream::set_viewgram: number of axial positions is not correct\n"); return Succeeded::no; } - - - if (*get_proj_data_info_sptr() != *(v.get_proj_data_info_sptr())) - { + if (*get_proj_data_info_sptr() != *(v.get_proj_data_info_sptr())) { warning("ProjDataFromStream::set_viewgram: viewgram has incompatible ProjDataInfo member\n" "Original ProjDataInfo: %s\n" "ProjDataInfo From viewgram: %s", - this->get_proj_data_info_sptr()->parameter_info().c_str(), - v.get_proj_data_info_sptr()->parameter_info().c_str() - ); + this->get_proj_data_info_sptr()->parameter_info().c_str(), v.get_proj_data_info_sptr()->parameter_info().c_str()); - return Succeeded::no; + return Succeeded::no; } - int segment_num = v.get_segment_num(); + int segment_num = v.get_segment_num(); int view_num = v.get_view_num(); + int timing_pos = v.get_timing_pos_num(); - - vector offsets = get_offsets(view_num,segment_num); + vector offsets = get_offsets(view_num, segment_num, timing_pos); const streamoff segment_offset = offsets[0]; const streamoff beg_view_offset = offsets[1]; const streamoff intra_views_offset = offsets[2]; @@ -414,350 +390,334 @@ ProjDataFromStream::set_viewgram(const Viewgram& v) Succeeded succeeded = Succeeded::yes; #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif { - sino_stream->seekp(segment_offset, ios::beg); // start of segment + sino_stream->seekp(segment_offset, ios::beg); // start of segment sino_stream->seekp(beg_view_offset, ios::cur); // start of view within segment - - if (! *sino_stream) - { - warning("ProjDataFromStream::set_viewgram: error after seekp"); - succeeded = Succeeded::no; - } - else if (get_storage_order() == Segment_AxialPos_View_TangPos) - { - for (int ax_pos_num = get_min_axial_pos_num(segment_num); ax_pos_num <= get_max_axial_pos_num(segment_num); ax_pos_num++) - { - - if (write_data(*sino_stream, v[ax_pos_num], on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no - || scale != scale_factor) - { - warning("ProjDataFromStream::set_viewgram: viewgram (view=%d, segment=%d)" - " corrupted due to problems with writing or the scale factor \n", - view_num, segment_num); - succeeded = Succeeded::no; - break; - } - // seek to next line unless it was the last we need to read - if(ax_pos_num != get_max_axial_pos_num(segment_num)) - sino_stream->seekp(intra_views_offset, ios::cur); - } - - // flush the stream, see the class documentation - sino_stream->flush(); + + if (!*sino_stream) { + warning("ProjDataFromStream::set_viewgram: error after seekp"); + succeeded = Succeeded::no; + } else if (get_storage_order() == Segment_AxialPos_View_TangPos) { + for (int ax_pos_num = get_min_axial_pos_num(segment_num); ax_pos_num <= get_max_axial_pos_num(segment_num); ax_pos_num++) { + + if (write_data(*sino_stream, v[ax_pos_num], on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no || + scale != scale_factor) { + warning("ProjDataFromStream::set_viewgram: viewgram (view=%d, segment=%d)" + " corrupted due to problems with writing or the scale factor \n", + view_num, segment_num); + succeeded = Succeeded::no; + break; + } + // seek to next line unless it was the last we need to read + if (ax_pos_num != get_max_axial_pos_num(segment_num)) + sino_stream->seekp(intra_views_offset, ios::cur); } - else if (get_storage_order() == Segment_View_AxialPos_TangPos) - { - if (write_data(*sino_stream, v, on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no - || scale != scale_factor) - { - warning("ProjDataFromStream::set_viewgram: viewgram (view=%d, segment=%d)" - " corrupted due to problems with writing or the scale factor \n", - view_num, segment_num); - succeeded = Succeeded::no; - } - // flush the stream, see the class documentation - sino_stream->flush(); - succeeded = Succeeded::yes; + // flush the stream, see the class documentation + sino_stream->flush(); + } else if (get_storage_order() == Segment_View_AxialPos_TangPos) { + if (write_data(*sino_stream, v, on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no || scale != scale_factor) { + warning("ProjDataFromStream::set_viewgram: viewgram (view=%d, segment=%d)" + " corrupted due to problems with writing or the scale factor \n", + view_num, segment_num); + succeeded = Succeeded::no; } - else - { - warning("ProjDataFromStream::set_viewgram: unsupported storage order\n"); + // flush the stream, see the class documentation + sino_stream->flush(); + } else if (get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { + if (write_data(*sino_stream, v, on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no || scale != scale_factor) { + warning("ProjDataFromStream::set_viewgram: viewgram (view=%d, segment=%d)" + " corrupted due to problems with writing or the scale factor \n", + view_num, segment_num); succeeded = Succeeded::no; } + // flush the stream, see the class documentation + sino_stream->flush(); + } else { + warning("ProjDataFromStream::set_viewgram: unsupported storage order\n"); + succeeded = Succeeded::no; + } } // end of critical section return succeeded; } - std::vector -ProjDataFromStream::get_offsets_bin(const Bin this_bin) const -{ +ProjDataFromStream::get_offsets_bin(const Bin this_bin) const { - if (!(this_bin.segment_num() >= get_min_segment_num() && - this_bin.segment_num() <= get_max_segment_num())) - error("ProjDataFromStream::get_offsets: segment_num out of range : %d", this_bin.segment_num()); + if (!(this_bin.segment_num() >= get_min_segment_num() && this_bin.segment_num() <= get_max_segment_num())) + error("ProjDataFromStream::get_offsets: segment_num out of range : %d", this_bin.segment_num()); - if (!(this_bin.axial_pos_num() >= get_min_axial_pos_num(this_bin.segment_num()) && - this_bin.axial_pos_num() <= get_max_axial_pos_num(this_bin.segment_num()))) - error("ProjDataFromStream::get_offsets: axial_pos_num out of range : %d", this_bin.axial_pos_num()); + if (!(this_bin.axial_pos_num() >= get_min_axial_pos_num(this_bin.segment_num()) && + this_bin.axial_pos_num() <= get_max_axial_pos_num(this_bin.segment_num()))) + error("ProjDataFromStream::get_offsets: axial_pos_num out of range : %d", this_bin.axial_pos_num()); + const int index = + static_cast(FIND(segment_sequence.begin(), segment_sequence.end(), this_bin.segment_num()) - segment_sequence.begin()); - const int index = - static_cast(FIND(segment_sequence.begin(), segment_sequence.end(), this_bin.segment_num()) - - segment_sequence.begin()); + streamoff num_axial_pos_offset = 0; - streamoff num_axial_pos_offset = 0; + for (int i = 0; i < index; i++) + num_axial_pos_offset += get_num_axial_poss(segment_sequence[i]); - for (int i=0; i(num_axial_pos_offset * get_num_tangential_poss() * get_num_views() * + on_disk_data_type.size_in_bytes()); - const streamoff segment_offset = - offset + - static_cast(num_axial_pos_offset* - get_num_tangential_poss() * - get_num_views() * - on_disk_data_type.size_in_bytes()); - - // Now we are just in front of the correct segment - if (get_storage_order() == Segment_AxialPos_View_TangPos) - { - // skip axial positions - const streamoff ax_pos_offset = - (this_bin.axial_pos_num() - get_min_axial_pos_num(this_bin.segment_num()))* - get_num_views() * - get_num_tangential_poss()* - on_disk_data_type.size_in_bytes(); + // Now we are just in front of the correct segment + if (get_storage_order() == Segment_AxialPos_View_TangPos) { + // skip axial positions + const streamoff ax_pos_offset = (this_bin.axial_pos_num() - get_min_axial_pos_num(this_bin.segment_num())) * get_num_views() * + get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - // sinogram location + // sinogram location - //find view - const streamoff view_offset = - (this_bin.view_num() - get_min_view_num()) - * get_num_tangential_poss() - * on_disk_data_type.size_in_bytes(); + // find view + const streamoff view_offset = + (this_bin.view_num() - get_min_view_num()) * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - // find tang pos - const streamoff tang_offset = - (this_bin.tangential_pos_num() - get_min_tangential_pos_num()) * on_disk_data_type.size_in_bytes(); + // find tang pos + const streamoff tang_offset = + (this_bin.tangential_pos_num() - get_min_tangential_pos_num()) * on_disk_data_type.size_in_bytes(); - vector temp(1); - temp[0] = segment_offset + ax_pos_offset + view_offset +tang_offset; + vector temp(1); + temp[0] = segment_offset + ax_pos_offset + view_offset + tang_offset; - return temp; - } - else //if (get_storage_order() == Segment_View_AxialPos_TangPos) - { + return temp; + } else if (get_storage_order() == Segment_View_AxialPos_TangPos) { - // Skip views - const streamoff view_offset = - (this_bin.view_num() - get_min_view_num())* - get_num_axial_poss(this_bin.segment_num()) * - get_num_tangential_poss()* - on_disk_data_type.size_in_bytes(); + // Skip views + const streamoff view_offset = (this_bin.view_num() - get_min_view_num()) * get_num_axial_poss(this_bin.segment_num()) * + get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + // find axial pos + const streamoff ax_pos_offset = (this_bin.axial_pos_num() - get_min_axial_pos_num(this_bin.segment_num())) * + get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - // find axial pos - const streamoff ax_pos_offset = - (this_bin.axial_pos_num() - get_min_axial_pos_num(this_bin.segment_num())) * - get_num_tangential_poss()* - on_disk_data_type.size_in_bytes(); + // find tang pos + const streamoff tang_offset = + (this_bin.tangential_pos_num() - get_min_tangential_pos_num()) * on_disk_data_type.size_in_bytes(); - // find tang pos - const streamoff tang_offset = - (this_bin.tangential_pos_num() - get_min_tangential_pos_num()) * on_disk_data_type.size_in_bytes(); + vector temp(1); + temp[0] = segment_offset + ax_pos_offset + view_offset + tang_offset; - vector temp(1); - temp[0] = segment_offset + ax_pos_offset +view_offset + tang_offset; + return temp; + } else if (get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { + // The timing offset will be added to the segment offset. This approach we minimise the + // changes + if (!(this_bin.timing_pos_num() >= get_min_tof_pos_num() && this_bin.timing_pos_num() <= get_max_tof_pos_num())) + error("ProjDataFromStream::get_offsets_bin: timing_num out of range : %d", this_bin.timing_pos_num()); - return temp; - } + const int timing_index = static_cast( + FIND(timing_poss_sequence.begin(), timing_poss_sequence.end(), this_bin.timing_pos_num()) - timing_poss_sequence.begin()); + + assert(offset_3d_data > 0); + segment_offset += static_cast(timing_index) * offset_3d_data; + + // Skip views + const streamoff view_offset = (this_bin.view_num() - get_min_view_num()) * get_num_axial_poss(this_bin.segment_num()) * + get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + + // find axial pos + const streamoff ax_pos_offset = (this_bin.axial_pos_num() - get_min_axial_pos_num(this_bin.segment_num())) * + get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + + // find tang pos + const streamoff tang_offset = + (this_bin.tangential_pos_num() - get_min_tangential_pos_num()) * on_disk_data_type.size_in_bytes(); + + vector temp(1); + temp[0] = segment_offset + ax_pos_offset + view_offset + tang_offset; + + return temp; + } else { + error("ProjDataFromStream::get_offsets_bin: unsupported storage order"); + return vector(); // return something to avoid compiler warning + } } // get offsets for the sino data vector -ProjDataFromStream::get_offsets_sino(const int ax_pos_num, const int segment_num) const -{ - if (!(segment_num >= get_min_segment_num() && - segment_num <= get_max_segment_num())) +ProjDataFromStream::get_offsets_sino(const int ax_pos_num, const int segment_num, const int timing_num) const { + if (!(segment_num >= get_min_segment_num() && segment_num <= get_max_segment_num())) error("ProjDataFromStream::get_offsets: segment_num out of range : %d", segment_num); - if (!(ax_pos_num >= get_min_axial_pos_num(segment_num) && - ax_pos_num <= get_max_axial_pos_num(segment_num))) + if (!(ax_pos_num >= get_min_axial_pos_num(segment_num) && ax_pos_num <= get_max_axial_pos_num(segment_num))) error("ProjDataFromStream::get_offsets: axial_pos_num out of range : %d", ax_pos_num); - const int index = - static_cast(FIND(segment_sequence.begin(), segment_sequence.end(), segment_num) - - segment_sequence.begin()); - - + const int index = + static_cast(FIND(segment_sequence.begin(), segment_sequence.end(), segment_num) - segment_sequence.begin()); + streamoff num_axial_pos_offset = 0; - for (int i=0; i(num_axial_pos_offset* - get_num_tangential_poss() * - get_num_views() * - on_disk_data_type.size_in_bytes()); - - if (get_storage_order() == Segment_AxialPos_View_TangPos) - { - - const streamoff beg_ax_pos_offset = - (ax_pos_num - get_min_axial_pos_num(segment_num))* - get_num_views() * - get_num_tangential_poss()* - on_disk_data_type.size_in_bytes(); + for (int i = 0; i < index; i++) + num_axial_pos_offset += get_num_axial_poss(segment_sequence[i]); + + streamoff segment_offset = offset + static_cast(num_axial_pos_offset * get_num_tangential_poss() * get_num_views() * + on_disk_data_type.size_in_bytes()); + + if (get_storage_order() == Segment_AxialPos_View_TangPos) { + + const streamoff beg_ax_pos_offset = (ax_pos_num - get_min_axial_pos_num(segment_num)) * get_num_views() * + get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); vector temp(3); temp[0] = segment_offset; temp[1] = beg_ax_pos_offset; temp[2] = 0; - + return temp; - } - else //if (get_storage_order() == Segment_View_AxialPos_TangPos) - { + } else if (get_storage_order() == Segment_View_AxialPos_TangPos) { + + const streamoff beg_ax_pos_offset = + (ax_pos_num - get_min_axial_pos_num(segment_num)) * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + + const streamoff intra_ax_pos_offset = + (get_num_axial_poss(segment_num) - 1) * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + vector temp(3); + temp[0] = segment_offset; + temp[1] = beg_ax_pos_offset; + temp[2] = intra_ax_pos_offset; + return temp; + } else if (get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { + // The timing offset will be added to the segment offset. This approach we minimise the + // changes + if (!(timing_num >= get_min_tof_pos_num() && timing_num <= get_max_tof_pos_num())) + error("ProjDataFromStream::get_offsets: timing_num out of range : %d", timing_num); + + const int timing_index = static_cast(FIND(timing_poss_sequence.begin(), timing_poss_sequence.end(), timing_num) - + timing_poss_sequence.begin()); + + assert(offset_3d_data > 0); + segment_offset += static_cast(timing_index) * offset_3d_data; const streamoff beg_ax_pos_offset = - (ax_pos_num - get_min_axial_pos_num(segment_num)) *get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - - const streamoff intra_ax_pos_offset = - (get_num_axial_poss(segment_num) -1) *get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - - + (ax_pos_num - get_min_axial_pos_num(segment_num)) * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + + const streamoff intra_ax_pos_offset = + (get_num_axial_poss(segment_num) - 1) * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + vector temp(3); - temp[0] =segment_offset; - temp[1]= beg_ax_pos_offset; - temp[2] =intra_ax_pos_offset; + temp[0] = segment_offset; + temp[1] = beg_ax_pos_offset; + temp[2] = intra_ax_pos_offset; return temp; - + } else { + error("ProjDataFromStream::get_offsets_sino: unsupported storage order"); + return vector(); // return something to avoid compiler warning } } Sinogram -ProjDataFromStream::get_sinogram(const int ax_pos_num, const int segment_num, - const bool make_num_tangential_poss_odd) const -{ - if (is_null_ptr(sino_stream)) - { +ProjDataFromStream::get_sinogram(const int ax_pos_num, const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos) const { + if (is_null_ptr(sino_stream)) { error("ProjDataFromStream::get_sinogram: stream ptr is 0\n"); } - if (! *sino_stream) - { + if (!*sino_stream) { error("ProjDataFromStream::get_sinogram: error in stream state before reading\n"); } - + // Call the get_offset to calculate the offsets, e.g // segment offset + view_offset + intra_view_offsets - vector offsets = get_offsets_sino(ax_pos_num,segment_num); - + vector offsets = get_offsets_sino(ax_pos_num, segment_num, timing_pos); + const streamoff segment_offset = offsets[0]; const streamoff beg_ax_pos_offset = offsets[1]; const streamoff intra_ax_pos_offset = offsets[2]; - Sinogram sinogram(proj_data_info_sptr, ax_pos_num, segment_num); + + Sinogram sinogram(proj_data_info_sptr, ax_pos_num, segment_num, timing_pos); float scale = float(1); Succeeded succeeded = Succeeded::yes; - if (get_storage_order() == Segment_AxialPos_View_TangPos) - { + if (get_storage_order() == Segment_AxialPos_View_TangPos) { #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif - { - sino_stream->seekg(segment_offset, ios::beg); // start of segment - sino_stream->seekg(beg_ax_pos_offset, ios::cur); // start of view within segment - if (! *sino_stream) - { - warning("ProjDataFromStream::get_sinogram: error after seekg"); - succeeded = Succeeded::no; - } - else - { - succeeded = read_data(*sino_stream, sinogram, on_disk_data_type, scale, on_disk_byte_order); - } - } // end of critical section - if (succeeded == Succeeded::no) - error("ProjDataFromStream: error reading data"); - if(scale != 1) - error("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1"); - } - else if (get_storage_order() == Segment_View_AxialPos_TangPos) - { + { + sino_stream->seekg(segment_offset, ios::beg); // start of segment + sino_stream->seekg(beg_ax_pos_offset, ios::cur); // start of view within segment + if (!*sino_stream) { + warning("ProjDataFromStream::get_sinogram: error after seekg"); + succeeded = Succeeded::no; + } else { + succeeded = read_data(*sino_stream, sinogram, on_disk_data_type, scale, on_disk_byte_order); + } + } // end of critical section + if (succeeded == Succeeded::no) + error("ProjDataFromStream: error reading data"); + if (scale != 1) + error("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1"); + } else if (get_storage_order() == Segment_View_AxialPos_TangPos || + get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif - { - sino_stream->seekg(segment_offset, ios::beg); // start of segment - sino_stream->seekg(beg_ax_pos_offset, ios::cur); // start of view within segment - if (! *sino_stream) - { - warning("ProjDataFromStream::get_sinogram: error after seekg"); - succeeded = Succeeded::no; - } - for (int view = get_min_view_num(); view <= get_max_view_num(); view++) - { - if (read_data(*sino_stream, sinogram[view], on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no) - { - succeeded = Succeeded::no; - break; - } - else if(scale != 1) - { - warning("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1"); - succeeded = Succeeded::no; - break; - } - // seek to next line unless it was the last we need to read - if(view != get_max_view_num()) - sino_stream->seekg(intra_ax_pos_offset, ios::cur); - } - } // end of critical section + { + sino_stream->seekg(segment_offset, ios::beg); // start of segment + sino_stream->seekg(beg_ax_pos_offset, ios::cur); // start of view within segment + if (!*sino_stream) { + warning("ProjDataFromStream::get_sinogram: error after seekg"); + succeeded = Succeeded::no; + } + for (int view = get_min_view_num(); view <= get_max_view_num(); view++) { + if (read_data(*sino_stream, sinogram[view], on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no) { + succeeded = Succeeded::no; + break; + } else if (scale != 1) { + warning("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1"); + succeeded = Succeeded::no; + break; + } + // seek to next line unless it was the last we need to read + if (view != get_max_view_num()) + sino_stream->seekg(intra_ax_pos_offset, ios::cur); } + } // end of critical section + } if (succeeded == Succeeded::no) error("ProjDataFromStream: error reading data"); + sinogram *= scale_factor; - if (make_num_tangential_poss_odd&&(get_num_tangential_poss()%2==0)) - { - int new_max_tangential_pos = get_max_tangential_pos_num() + 1; + if (make_num_tangential_poss_odd && (get_num_tangential_poss() % 2 == 0)) { + int new_max_tangential_pos = get_max_tangential_pos_num() + 1; - sinogram.grow(IndexRange2D(get_min_view_num(), - get_max_view_num(), - get_min_tangential_pos_num(), - new_max_tangential_pos)); - } + sinogram.grow(IndexRange2D(get_min_view_num(), get_max_view_num(), get_min_tangential_pos_num(), new_max_tangential_pos)); + } return sinogram; } Succeeded -ProjDataFromStream::set_sinogram(const Sinogram& s) -{ - if (is_null_ptr(sino_stream)) - { +ProjDataFromStream::set_sinogram(const Sinogram& s) { + if (is_null_ptr(sino_stream)) { warning("ProjDataFromStream::set_sinogram: stream ptr is 0\n"); return Succeeded::no; } - if (! *sino_stream) - { + if (!*sino_stream) { warning("ProjDataFromStream::set_sinogram: error in stream state before writing\n"); return Succeeded::no; } // KT 03/07/2001 modified handling of scale_factor etc. - if (on_disk_data_type.id != NumericType::FLOAT) - { + if (on_disk_data_type.id != NumericType::FLOAT) { warning("ProjDataFromStream::set_sinogram: non-float output uses original " "scale factor %g which might not be appropriate for the current data\n", - scale_factor); + scale_factor); } - - if (*get_proj_data_info_sptr() != *(s.get_proj_data_info_sptr())) - { + + if (*get_proj_data_info_sptr() != *(s.get_proj_data_info_sptr())) { warning("ProjDataFromStream::set_sinogram: Sinogram has incompatible ProjDataInfo member.\n" "Original ProjDataInfo: %s\n" "ProjDataInfo from sinogram: %s", - this->get_proj_data_info_sptr()->parameter_info().c_str(), - s.get_proj_data_info_sptr()->parameter_info().c_str() - ); + this->get_proj_data_info_sptr()->parameter_info().c_str(), s.get_proj_data_info_sptr()->parameter_info().c_str()); return Succeeded::no; } - int segment_num = s.get_segment_num(); + int segment_num = s.get_segment_num(); int ax_pos_num = s.get_axial_pos_num(); - - - vector offsets = get_offsets_sino(ax_pos_num,segment_num); + int timing_pos = s.get_timing_pos_num(); + + vector offsets = get_offsets_sino(ax_pos_num, segment_num, timing_pos); const streamoff segment_offset = offsets[0]; const streamoff beg_ax_pos_offset = offsets[1]; const streamoff intra_ax_pos_offset = offsets[2]; @@ -765,359 +725,320 @@ ProjDataFromStream::set_sinogram(const Sinogram& s) Succeeded succeeded = Succeeded::yes; #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif { - sino_stream->seekp(segment_offset, ios::beg); // start of segment + sino_stream->seekp(segment_offset, ios::beg); // start of segment sino_stream->seekp(beg_ax_pos_offset, ios::cur); // start of view within segment - - if (! *sino_stream) - { - warning("ProjDataFromStream::set_sinogram: error after seekg\n"); + + if (!*sino_stream) { + warning("ProjDataFromStream::set_sinogram: error after seekg\n"); + succeeded = Succeeded::no; + } + + if (get_storage_order() == Segment_AxialPos_View_TangPos) { + if (write_data(*sino_stream, s, on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no || scale != scale_factor) { + warning("ProjDataFromStream::set_sinogram: sinogram (ax_pos=%d, segment=%d)" + " corrupted due to problems with writing or the scale factor \n", + ax_pos_num, segment_num); succeeded = Succeeded::no; - } - - if (get_storage_order() == Segment_AxialPos_View_TangPos) - - { - if (write_data(*sino_stream, s, on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no - || scale != scale_factor) - { - warning("ProjDataFromStream::set_sinogram: sinogram (ax_pos=%d, segment=%d)" - " corrupted due to problems with writing or the scale factor \n", - ax_pos_num, segment_num); - succeeded = Succeeded::no; - } - // flush the stream, see the class documentation - sino_stream->flush(); - } - - else if (get_storage_order() == Segment_View_AxialPos_TangPos) - { - for (int view = get_min_view_num();view <= get_max_view_num(); view++) - { - if (write_data(*sino_stream, s[view], on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no - || scale != scale_factor) - { - warning("ProjDataFromStream::set_sinogram: sinogram (ax_pos=%d, segment=%d)" - " corrupted due to problems with writing or the scale factor \n", - ax_pos_num, segment_num); - succeeded = Succeeded::no; - break; - } - // seek to next line unless it was the last we need to read - if(view != get_max_view_num()) - sino_stream->seekp(intra_ax_pos_offset, ios::cur); - } - // flush the stream, see the class documentation - sino_stream->flush(); } - else - { - warning("ProjDataFromStream::set_sinogram: unsupported storage order"); - succeeded = Succeeded::no; + // flush the stream, see the class documentation + sino_stream->flush(); + } + + else if (get_storage_order() == Segment_View_AxialPos_TangPos || + get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { + for (int view = get_min_view_num(); view <= get_max_view_num(); view++) { + if (write_data(*sino_stream, s[view], on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no || + scale != scale_factor) { + warning("ProjDataFromStream::set_sinogram: sinogram (ax_pos=%d, segment=%d)" + " corrupted due to problems with writing or the scale factor \n", + ax_pos_num, segment_num); + succeeded = Succeeded::no; + break; + } + // seek to next line unless it was the last we need to read + if (view != get_max_view_num()) + sino_stream->seekp(intra_ax_pos_offset, ios::cur); } + // flush the stream, see the class documentation + sino_stream->flush(); + } else { + warning("ProjDataFromStream::set_sinogram: unsupported storage order"); + succeeded = Succeeded::no; + } } // end of critical section return succeeded; } streamoff -ProjDataFromStream::get_offset_segment(const int segment_num) const -{ - assert(segment_num >= get_min_segment_num() && - segment_num <= get_max_segment_num()); - { - const int index = - static_cast(FIND(segment_sequence.begin(), segment_sequence.end(), segment_num) - - segment_sequence.begin()); - - streamoff num_axial_pos_offset = 0; - for (int i=0; i= get_min_segment_num() && segment_num <= get_max_segment_num()); + { + const int index = + static_cast(FIND(segment_sequence.begin(), segment_sequence.end(), segment_num) - segment_sequence.begin()); + + streamoff num_axial_pos_offset = 0; + for (int i = 0; i < index; i++) + num_axial_pos_offset += get_num_axial_poss(segment_sequence[i]); + + const streamoff segment_offset = + offset + num_axial_pos_offset * get_num_tangential_poss() * get_num_views() * on_disk_data_type.size_in_bytes(); + return segment_offset; } - } +std::streamoff +ProjDataFromStream::get_offset_timing(const int timing_num) const { + + const int index = + static_cast(FIND(timing_poss_sequence.begin(), timing_poss_sequence.end(), timing_num) - timing_poss_sequence.begin()); + + assert(timing_num >= get_min_tof_pos_num() && timing_num <= get_max_tof_pos_num()); + { + if (offset_3d_data < 0) // Calculate the full 3D sinogram size - Very slow + { + long long sum = 0; + + for (int segment_num = proj_data_info_sptr->get_min_segment_num(); + segment_num <= proj_data_info_sptr->get_max_segment_num(); ++segment_num) { + sum += get_num_axial_poss(segment_num) * get_num_views() * get_num_tangential_poss(); + } + return static_cast(sum * index * on_disk_data_type.size_in_bytes()); + } else + return static_cast(offset_3d_data * index); + } +} // TODO the segment version could be written in terms of the above. // -> No need for get_offset_segment SegmentBySinogram -ProjDataFromStream::get_segment_by_sinogram(const int segment_num) const -{ - if(is_null_ptr(sino_stream)) - { +ProjDataFromStream::get_segment_by_sinogram(const int segment_num, const int timing_num) const { + if (is_null_ptr(sino_stream)) { error("ProjDataFromStream::get_segment_by_sinogram: stream ptr is 0\n"); } - if (! *sino_stream) - { + if (!*sino_stream) { error("ProjDataFromStream::get_segment_by_sinogram: error in stream state before reading\n"); } - - streamoff segment_offset = get_offset_segment(segment_num); - if (get_storage_order() == Segment_AxialPos_View_TangPos) - { - SegmentBySinogram segment(proj_data_info_sptr,segment_num); - float scale = float(1); - Succeeded succeeded = Succeeded::yes; + + streamoff segment_offset = get_offset_segment(segment_num); + // Go to the right timing full 3D sinogram + segment_offset += get_offset_timing(timing_num); + + if (get_storage_order() == Segment_AxialPos_View_TangPos) { + SegmentBySinogram segment(proj_data_info_sptr, segment_num, timing_num); + float scale = float(1); + Succeeded succeeded = Succeeded::yes; #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif - { - sino_stream->seekg(segment_offset, ios::beg); - if (! *sino_stream) - { - warning("ProjDataFromStream::get_segment_by_sinogram: error after seekg"); - succeeded = Succeeded::no; - } - else - { - succeeded = read_data(*sino_stream, segment, on_disk_data_type, scale, on_disk_byte_order); - } - } // end of critical section + { + sino_stream->seekg(segment_offset, ios::beg); + if (!*sino_stream) { + warning("ProjDataFromStream::get_segment_by_sinogram: error after seekg"); + succeeded = Succeeded::no; + } else { + succeeded = read_data(*sino_stream, segment, on_disk_data_type, scale, on_disk_byte_order); + } + } // end of critical section if (succeeded == Succeeded::no) error("ProjDataFromStream: error reading data\n"); - if(scale != 1) + if (scale != 1) error("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1\n"); - segment *= scale_factor; - return segment; - } - else - { - // TODO rewrite in terms of get_viewgram - return SegmentBySinogram (get_segment_by_view(segment_num)); - } + segment *= scale_factor; + return segment; + } else { + // TODO rewrite in terms of get_viewgram + return SegmentBySinogram(get_segment_by_view(segment_num, timing_num)); + } } SegmentByView -ProjDataFromStream::get_segment_by_view(const int segment_num) const -{ - - if(is_null_ptr(sino_stream)) - { +ProjDataFromStream::get_segment_by_view(const int segment_num, const int timing_pos) const { + if (is_null_ptr(sino_stream)) { error("ProjDataFromStream::get_segment_by_view: stream ptr is 0\n"); } - if (! *sino_stream) - { + if (!*sino_stream) { error("ProjDataFromStream::get_segment_by_view: error in stream state before reading\n"); } - if (get_storage_order() == Segment_View_AxialPos_TangPos) - { - SegmentByView segment(proj_data_info_sptr,segment_num); + + if (get_storage_order() == Segment_View_AxialPos_TangPos || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { + SegmentByView segment(proj_data_info_sptr, segment_num, timing_pos); streamoff segment_offset = get_offset_segment(segment_num); + // Go to the right timing full 3D sinogram + segment_offset += get_offset_timing(timing_pos); float scale = float(1); - Succeeded succeeded = Succeeded::yes; + Succeeded succeeded = Succeeded::yes; #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif { - sino_stream->seekg(segment_offset, ios::beg); - if (! *sino_stream) - { - warning("ProjDataFromStream::get_segment_by_sinogram: error after seekg"); - succeeded = Succeeded::no; - } - else - { - succeeded = read_data(*sino_stream, segment, on_disk_data_type, scale, on_disk_byte_order); - } + sino_stream->seekg(segment_offset, ios::beg); + if (!*sino_stream) { + warning("ProjDataFromStream::get_segment_by_sinogram: error after seekg"); + succeeded = Succeeded::no; + } else { + succeeded = read_data(*sino_stream, segment, on_disk_data_type, scale, on_disk_byte_order); + } } // end of critical section if (succeeded == Succeeded::no) error("ProjDataFromStream: error reading data"); - if(scale != 1) + if (scale != 1) error("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1\n"); segment *= scale_factor; return segment; - } - else + } else // TODO rewrite in terms of get_sinogram as this doubles memory temporarily - return SegmentByView (get_segment_by_sinogram(segment_num)); + return SegmentByView(get_segment_by_sinogram(segment_num, timing_pos)); } Succeeded -ProjDataFromStream::set_segment(const SegmentBySinogram& segmentbysinogram_v) -{ - if(is_null_ptr(sino_stream)) - { +ProjDataFromStream::set_segment(const SegmentBySinogram& segmentbysinogram_v) { + if (is_null_ptr(sino_stream)) { error("ProjDataFromStream::set_segment: stream ptr is 0\n"); } - if (! *sino_stream) - { + if (!*sino_stream) { error("ProjDataFromStream::set_segment: error in stream state before writing\n"); } - - if (get_num_tangential_poss() != segmentbysinogram_v.get_num_tangential_poss()) - { - warning("ProjDataFromStream::set_segmen: num_bins is not correct\n"); + + if (get_num_tangential_poss() != segmentbysinogram_v.get_num_tangential_poss()) { + warning("ProjDataFromStream::set_segmen: num_bins is not correct\n"); return Succeeded::no; } - if (get_num_views() != segmentbysinogram_v.get_num_views()) - { - warning("ProjDataFromStream::set_segment: num_views is not correct\n"); + if (get_num_views() != segmentbysinogram_v.get_num_views()) { + warning("ProjDataFromStream::set_segment: num_views is not correct\n"); return Succeeded::no; } - + int segment_num = segmentbysinogram_v.get_segment_num(); streamoff segment_offset = get_offset_segment(segment_num); - - - if (get_storage_order() == Segment_AxialPos_View_TangPos) - { - // KT 03/07/2001 handle scale_factor appropriately - if (on_disk_data_type.id != NumericType::FLOAT) - { - warning("ProjDataFromStream::set_segment: non-float output uses original " - "scale factor %g which might not be appropriate for the current data\n", - scale_factor); - } - float scale = scale_factor; - Succeeded succeeded = Succeeded::yes; + // Go to the right timing full 3D sinogram + segment_offset += get_offset_timing(segmentbysinogram_v.get_timing_pos_num()); + + if (get_storage_order() == Segment_AxialPos_View_TangPos) { + // KT 03/07/2001 handle scale_factor appropriately + if (on_disk_data_type.id != NumericType::FLOAT) { + warning("ProjDataFromStream::set_segment: non-float output uses original " + "scale factor %g which might not be appropriate for the current data\n", + scale_factor); + } + float scale = scale_factor; + Succeeded succeeded = Succeeded::yes; #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif - { - sino_stream->seekp(segment_offset,ios::beg); - if (! *sino_stream) - { - warning("ProjDataFromStream::set_segment: error after seekp\n"); - succeeded = Succeeded::no; - } - else if (write_data(*sino_stream, segmentbysinogram_v, on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no - || scale != scale_factor) - { - warning("ProjDataFromStream::set_segment: segment (%d)" - " corrupted due to problems with writing or the scale factor \n", - segment_num); - succeeded = Succeeded::no; - } - // flush the stream, see the class documentation - sino_stream->flush(); - } // end of critical section - return succeeded; - } - else { - // TODO rewrite in terms of set_viewgram - const SegmentByView segmentbyview= - SegmentByView(segmentbysinogram_v); + sino_stream->seekp(segment_offset, ios::beg); + if (!*sino_stream) { + warning("ProjDataFromStream::set_segment: error after seekp\n"); + succeeded = Succeeded::no; + } else if (write_data(*sino_stream, segmentbysinogram_v, on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no || + scale != scale_factor) { + warning("ProjDataFromStream::set_segment: segment (%d) tof bin (%d)" + " corrupted due to problems with writing or the scale factor \n", + segment_num, segmentbysinogram_v.get_timing_pos_num()); + succeeded = Succeeded::no; + } + // flush the stream, see the class documentation + sino_stream->flush(); + } // end of critical section + return succeeded; + } else { + // TODO rewrite in terms of set_viewgram + const SegmentByView segmentbyview = SegmentByView(segmentbysinogram_v); - return set_segment(segmentbyview); - } + return set_segment(segmentbyview); + } } - Succeeded -ProjDataFromStream::set_segment(const SegmentByView& segmentbyview_v) -{ - if(is_null_ptr(sino_stream)) - { +ProjDataFromStream::set_segment(const SegmentByView& segmentbyview_v) { + if (is_null_ptr(sino_stream)) { error("ProjDataFromStream::set_segment: stream ptr is 0\n"); } - if (! *sino_stream) - { + if (!*sino_stream) { error("ProjDataFromStream::set_segment: error in stream state before writing\n"); } - - - if (get_num_tangential_poss() != segmentbyview_v.get_num_tangential_poss()) - { - warning("ProjDataFromStream::set_segment: num_bins is not correct\n"); + + if (get_num_tangential_poss() != segmentbyview_v.get_num_tangential_poss()) { + warning("ProjDataFromStream::set_segment: num_bins is not correct\n"); return Succeeded::no; } - if (get_num_views() != segmentbyview_v.get_num_views()) - { - warning("ProjDataFromStream::set_segment: num_views is not correct\n"); + if (get_num_views() != segmentbyview_v.get_num_views()) { + warning("ProjDataFromStream::set_segment: num_views is not correct\n"); return Succeeded::no; } - + int segment_num = segmentbyview_v.get_segment_num(); streamoff segment_offset = get_offset_segment(segment_num); - - if (get_storage_order() == Segment_View_AxialPos_TangPos) - { - // KT 03/07/2001 handle scale_factor appropriately - if (on_disk_data_type.id != NumericType::FLOAT) - { - warning("ProjDataFromStream::set_segment: non-float output uses original " - "scale factor %g which might not be appropriate for the current data\n", - scale_factor); - } - float scale = scale_factor; - Succeeded succeeded = Succeeded::yes; + // Go to the right timing full 3D sinogram + segment_offset += get_offset_timing(segmentbyview_v.get_timing_pos_num()); + + if (get_storage_order() == Segment_View_AxialPos_TangPos || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { + // KT 03/07/2001 handle scale_factor appropriately + if (on_disk_data_type.id != NumericType::FLOAT) { + warning("ProjDataFromStream::set_segment: non-float output uses original " + "scale factor %g which might not be appropriate for the current data\n", + scale_factor); + } + float scale = scale_factor; + Succeeded succeeded = Succeeded::yes; #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif - { - sino_stream->seekp(segment_offset,ios::beg); - if (! *sino_stream) - { - warning("ProjDataFromStream::set_segment: error after seekp"); - succeeded = Succeeded::no; - } - else if (write_data(*sino_stream, segmentbyview_v, on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no - || scale != scale_factor) - { - warning("ProjDataFromStream::set_segment: segment (%d)" - " corrupted due to problems with writing or the scale factor \n", - segment_num); - succeeded = Succeeded::no; - } - // flush the stream, see the class documentation - sino_stream->flush(); - } // end of critical section - return succeeded; - } - else { - // TODO rewrite in terms of set_sinogram - const SegmentBySinogram segmentbysinogram = - SegmentBySinogram(segmentbyview_v); - return set_segment(segmentbysinogram); - } + sino_stream->seekp(segment_offset, ios::beg); + if (!*sino_stream) { + warning("ProjDataFromStream::set_segment: error after seekp"); + succeeded = Succeeded::no; + } else if (write_data(*sino_stream, segmentbyview_v, on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no || + scale != scale_factor) { + warning("ProjDataFromStream::set_segment: segment (%d) tof bin (%d)" + " corrupted due to problems with writing or the scale factor \n", + segment_num, segmentbyview_v.get_timing_pos_num()); + succeeded = Succeeded::no; + } + // flush the stream, see the class documentation + sino_stream->flush(); + } // end of critical section + return succeeded; + } else { + // TODO rewrite in terms of set_sinogram + const SegmentBySinogram segmentbysinogram = SegmentBySinogram(segmentbyview_v); + return set_segment(segmentbysinogram); + } } - #if 0 ProjDataFromStream* ProjDataFromStream::ask_parameters(const bool on_disk) { - + shared_ptr p_in_stream; - - + + char filename[256]; - + ask_filename_with_extension( - filename, + filename, "Enter file name of 3D sinogram data : ", ".scn"); // KT 03/07/2001 initialise to avoid compiler warnings - ios::openmode open_mode=ios::in; + ios::openmode open_mode=ios::in; switch(ask_num("Read (1), Create and write(2), Read/Write (3) : ", 1,3,1)) { case 1: open_mode=ios::in; break; case 2: open_mode=ios::out; break; case 3: open_mode=ios::in | ios::out; break; } - + if (on_disk) { - + //fstream * p_fstream = new fstream; p_in_stream.reset(new fstream (filename, open_mode | ios::binary)); if (!p_in_stream->good()) @@ -1128,48 +1049,48 @@ ProjDataFromStream* ProjDataFromStream::ask_parameters(const bool on_disk) //p_in_stream = p_fstream; } else - { + { streamsize file_size = 0; char *memory = 0; - { + { fstream input; open_read_binary(input, filename); memory = (char *)read_stream_in_memory(input, file_size); } - -#ifdef BOOST_NO_STRINGSTREAM + +# ifdef BOOST_NO_STRINGSTREAM // This is the old implementation of the strstream class. // The next constructor should work according to the doc, but it doesn't in gcc 2.8.1. //strstream in_stream(memory, file_size, ios::in | ios::binary); - // Reason: in_stream contains an internal strstreambuf which is + // Reason: in_stream contains an internal strstreambuf which is // initialised as buffer(memory, file_size, memory), which prevents // reading from it. - + strstreambuf * buffer = new strstreambuf(memory, file_size, memory+file_size); p_in_stream.reset(new iostream(buffer)); -#else +# else // TODO this does allocate and copy 2 times // TODO file_size could be longer than what size_t allows, but string doesn't take anything longer - p_in_stream.reset(new std::stringstream (string(memory, std::size_t(file_size)), + p_in_stream.reset(new std::stringstream (string(memory, std::size_t(file_size)), open_mode | ios::binary)); - + delete[] memory; -#endif - - } // else 'on_disk' +# endif - - // KT 03/07/2001 initialise to avoid compiler warnings + } // else 'on_disk' + + + // KT 03/07/2001 initialise to avoid compiler warnings ProjDataFromStream::StorageOrder storage_order = Segment_AxialPos_View_TangPos; { int data_org = ask_num("Type of data organisation:\n\ - 0: Segment_AxialPos_View_TangPos, 1: Segment_View_AxialPos_TangPos", + 0: Segment_AxialPos_View_TangPos, 1: Segment_View_AxialPos_TangPos", 0, 1,0); - + switch (data_org) - { + { case 0: storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; break; @@ -1178,13 +1099,13 @@ ProjDataFromStream* ProjDataFromStream::ask_parameters(const bool on_disk) break; } } - + NumericType data_type; { int data_type_sel = ask_num("Type of data :\n\ 0: signed 16bit int, 1: unsigned 16bit int, 2: 4bit float ", 0,2,2); switch (data_type_sel) - { + { case 0: data_type = NumericType::SHORT; break; @@ -1196,81 +1117,71 @@ ProjDataFromStream* ProjDataFromStream::ask_parameters(const bool on_disk) break; } } - - + + ByteOrder byte_order; - { - byte_order = + { + byte_order = ask("Little endian byte order ?", ByteOrder::get_native_order() == ByteOrder::little_endian) ? ByteOrder::little_endian : ByteOrder::big_endian; } - + std::streamoff offset_in_file ; { // find file size - p_in_stream->seekg(static_cast(0), ios::beg); + p_in_stream->seekg(static_cast(0), ios::beg); streamsize file_size = find_remaining_size(*p_in_stream); - - offset_in_file = ask_num("Offset in file (in bytes)", + + offset_in_file = ask_num("Offset in file (in bytes)", static_cast(0), - static_cast(file_size), + static_cast(file_size), static_cast(0)); } float scale_factor =1; - + shared_ptr data_info_ptr(ProjDataInfo::ask_parameters()); - - vector segment_sequence_in_stream; - segment_sequence_in_stream = vector(data_info_ptr->get_num_segments()); - segment_sequence_in_stream[0] = 0; - + + vector segment_sequence_in_stream; + segment_sequence_in_stream = vector(data_info_ptr->get_num_segments()); + segment_sequence_in_stream[0] = 0; + for (int i=1; i<= data_info_ptr->get_num_segments()/2; i++) - { + { segment_sequence_in_stream[2*i-1] = i; segment_sequence_in_stream[2*i] = -i; } - - + + cerr << "Segment sequence :"; for (unsigned int i=0; i scanner_sptr(new Scanner(Scanner::Advance)); - proj_data_info_sptr.reset( - ProjDataInfo::ProjDataInfoGE(scanner_sptr, max_delta, - scanner_sptr->get_max_num_views(), - scanner_sptr->get_default_num_arccorrected_bins())); - - + proj_data_info_sptr.reset(ProjDataInfo::ProjDataInfoGE(scanner_sptr, max_delta, scanner_sptr->get_max_num_views(), + scanner_sptr->get_default_num_arccorrected_bins())); + const int min_view = proj_data_info_sptr->get_min_view_num(); const int max_view = proj_data_info_sptr->get_max_view_num(); view_scaling_factor.grow(min_view, max_view); - + const int offset_begin = 256; - sino_stream->seekg(offset, ios::beg); // overall offset + sino_stream->seekg(offset, ios::beg); // overall offset sino_stream->seekg(offset_begin, ios::cur); // "breakfile" offset - + // reads the views_scaling_factors { float scale = float(1); // KT 18/10/99 added on_disk_byte_order - if (read_data(*sino_stream, view_scaling_factor, - NumericType::FLOAT, - scale, - on_disk_byte_order) == Succeeded::no - || scale != 1) + if (read_data(*sino_stream, view_scaling_factor, NumericType::FLOAT, scale, on_disk_byte_order) == Succeeded::no || + scale != 1) error("ProjDataGEAdvance: error reading scale factors from header\n"); - + // for ( int k=min_view ; k <= max_view ; k++) // { - // cout << "view_scaling_factor[" << k << "] = " + // cout << "view_scaling_factor[" << k << "] = " // << view_scaling_factor[k] << endl; // } } - + //============================================================= // parameters as in the unsorted case (help to access the file) //============================================================= //------------------------------------------------------------- // WARNING: this construction works only with odd max_delta //------------------------------------------------------------- - - int num_segments_orig = proj_data_info_sptr->get_max_segment_num()+1; - //(int) get_max_average_ring_difference(); - + + int num_segments_orig = proj_data_info_sptr->get_max_segment_num() + 1; + //(int) get_max_average_ring_difference(); + num_rings_orig.resize(num_segments_orig); segment_sequence_orig.resize(num_segments_orig); - - + const int num_rings = proj_data_info_sptr->get_scanner_ptr()->get_num_rings(); - num_rings_orig[0]=(2*num_rings-1); - + num_rings_orig[0] = (2 * num_rings - 1); + { - for (unsigned int i=1; i<= num_rings_orig.size()/2; i++) - { - num_rings_orig[2*i-1]=(2*num_rings-1) - 4*i; - num_rings_orig[2*i]=(2*num_rings-1) - 4*i; + for (unsigned int i = 1; i <= num_rings_orig.size() / 2; i++) { + num_rings_orig[2 * i - 1] = (2 * num_rings - 1) - 4 * i; + num_rings_orig[2 * i] = (2 * num_rings - 1) - 4 * i; // cout << "num_rings_orig[" << 2*i-1 << "] = " << num_rings_orig[2*i-1] << endl; // cout << "num_rings_orig[" << 2*i << "] = " << num_rings_orig[2*i] << endl; } } - - - + // segment sequence in the unsorted data format - - segment_sequence_orig[0]=0; - + + segment_sequence_orig[0] = 0; + { - for (unsigned int i=1; i<= segment_sequence_orig.size()/2; i++) - { - segment_sequence_orig[2*i-1] = static_cast(i); - segment_sequence_orig[2*i] = -static_cast(i); + for (unsigned int i = 1; i <= segment_sequence_orig.size() / 2; i++) { + segment_sequence_orig[2 * i - 1] = static_cast(i); + segment_sequence_orig[2 * i] = -static_cast(i); // cout << "segment_sequence_orig[" << 2*i-1 << "] = " << segment_sequence_orig[2*i-1] << endl; // cout << "segment_sequence_orig[" << 2*i << "] = " << segment_sequence_orig[2*i] << endl; } } - } - + Viewgram -ProjDataGEAdvance:: -get_viewgram(const int view_num, const int segment_num, - const bool make_num_tangential_poss_odd) const - { - // -------------------------------------------------------- - // -------------------------------------------------------- - // Advance GE format reader with sort of the segments - // -------------------------------------------------------- - // -------------------------------------------------------- - // - // segment_num 0 +1 -1 +2 -2 +3 -3 ....... - // ave_ring_diff 0 +2 -2 +3 -3 +4 -4 ....... - // max_ring_diff +1 +2 -2 +3 -3 +4 -4 ....... - // min_ring_diff -1 +2 -2 +3 -3 +4 -4 ....... - - - streamoff odd_ring_segment_offset; - streamoff num_rings_offset; - streamoff segment_offset; - streamoff jump_size; - streamoff jump_ring; - - - //---------------------------------------------------------------- - // data with delta ring = +1 and -1 are contained in segment 0: - // for this reason there is not a segment +1 and a segment -1 - //---------------------------------------------------------------- - - // segment number in the unsorted data format - // (no problem for segments +1 and -1) - - const int sign_segment_num = (segment_num == 0) ? 0 : ( (segment_num > 0) ? 1 : -1 ); - const int segment_num_orig = (int) ((segment_num+sign_segment_num) / 2); - - // cout << "segment_num_orig " << segment_num_orig << endl; - - // segment index in the unsorted data format - - const int index_orig = - static_cast(find(segment_sequence_orig.begin(), - segment_sequence_orig.end(), segment_num_orig) - - segment_sequence_orig.begin()); - - // cout << "index_orig " << index_orig << endl; - - - //--------------------------------------------------------------- - // OFFSETS - //--------------------------------------------------------------- - - const streamoff offset_begin = 256; - - // offset in rings for the odd sorted segments (value 0 or 1) - - odd_ring_segment_offset = abs((segment_num+sign_segment_num) % 2); - - // cout << "odd_ring_segment_offset " << odd_ring_segment_offset << endl; - - // offset in rings in the unsorted data format - - num_rings_offset = - accumulate(num_rings_orig.begin(), - num_rings_orig.begin() + index_orig, 0) + - odd_ring_segment_offset; - - // cout << "num_rings_offset " << num_rings_offset << endl; - - // offset to the first data in the first view_num of the segment chosen - - segment_offset = - num_rings_offset * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - - // cout << "segment_offset " << segment_offset << endl; - - // size of the jump to the first record of the following view_num - if (segment_num == 0) - { - jump_size = - ( - accumulate(num_rings_orig.begin(), num_rings_orig.end(), 0) - - num_rings_orig[index_orig] + - + 2 * odd_ring_segment_offset - ) * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - } - else - { - jump_size = - ( - accumulate(num_rings_orig.begin(), num_rings_orig.end(), 0) - - num_rings_orig[index_orig] - - 1 // offset to balance the jump_ring in the cycle - + 2 * odd_ring_segment_offset - ) * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - } - // cout << "jump_size " << jump_size << endl; - - // size of the jump between two rings of the same view_num and of the same - // segment - if (segment_num == 0) - jump_ring = 0; - else - jump_ring = get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - - streamoff ring_offset = get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); - - // jumps the initial offset - - sino_stream->seekg(offset, ios::beg); // overall offset - sino_stream->seekg(offset_begin, ios::cur); // "breakfile" offset - sino_stream->seekg(get_num_views() * sizeof(float), ios::cur); // skip view scaling factors - - // jumps at the beginning of the chosen segment - - sino_stream->seekg(segment_offset, ios::cur); - - // jump to the right Viewgram - - streamoff jump_ini = (view_num - get_min_view_num())* - (ring_offset*get_num_axial_poss(segment_num) - + jump_ring*get_num_axial_poss(segment_num) - + jump_size); - - // cout << "ring_offset " << ring_offset << endl; - // cout << "jump_ring " << jump_ring << endl; - // cout << "jump_size " << jump_size << endl; - // cout << " jump_ini " << jump_ini << endl; - - sino_stream->seekg(jump_ini, ios::cur); - - Viewgram data = get_empty_viewgram(view_num, segment_num,false); - - for (int ring =get_min_axial_pos_num(segment_num) ; ring <= get_max_axial_pos_num(segment_num); ring++) +ProjDataGEAdvance::get_viewgram(const int view_num, const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos) const { + // -------------------------------------------------------- + // -------------------------------------------------------- + // Advance GE format reader with sort of the segments + // -------------------------------------------------------- + // -------------------------------------------------------- + // + // segment_num 0 +1 -1 +2 -2 +3 -3 ....... + // ave_ring_diff 0 +2 -2 +3 -3 +4 -4 ....... + // max_ring_diff +1 +2 -2 +3 -3 +4 -4 ....... + // min_ring_diff -1 +2 -2 +3 -3 +4 -4 ....... + + streamoff odd_ring_segment_offset; + streamoff num_rings_offset; + streamoff segment_offset; + streamoff jump_size; + streamoff jump_ring; + + //---------------------------------------------------------------- + // data with delta ring = +1 and -1 are contained in segment 0: + // for this reason there is not a segment +1 and a segment -1 + //---------------------------------------------------------------- + + // segment number in the unsorted data format + // (no problem for segments +1 and -1) + + const int sign_segment_num = (segment_num == 0) ? 0 : ((segment_num > 0) ? 1 : -1); + const int segment_num_orig = (int)((segment_num + sign_segment_num) / 2); + + // cout << "segment_num_orig " << segment_num_orig << endl; + + // segment index in the unsorted data format + + const int index_orig = static_cast(find(segment_sequence_orig.begin(), segment_sequence_orig.end(), segment_num_orig) - + segment_sequence_orig.begin()); + + // cout << "index_orig " << index_orig << endl; + + //--------------------------------------------------------------- + // OFFSETS + //--------------------------------------------------------------- + + const streamoff offset_begin = 256; + + // offset in rings for the odd sorted segments (value 0 or 1) + + odd_ring_segment_offset = abs((segment_num + sign_segment_num) % 2); + + // cout << "odd_ring_segment_offset " << odd_ring_segment_offset << endl; + + // offset in rings in the unsorted data format + + num_rings_offset = accumulate(num_rings_orig.begin(), num_rings_orig.begin() + index_orig, 0) + odd_ring_segment_offset; + + // cout << "num_rings_offset " << num_rings_offset << endl; + + // offset to the first data in the first view_num of the segment chosen + + segment_offset = num_rings_offset * get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + + // cout << "segment_offset " << segment_offset << endl; + + // size of the jump to the first record of the following view_num + if (segment_num == 0) { + jump_size = (accumulate(num_rings_orig.begin(), num_rings_orig.end(), 0) - num_rings_orig[index_orig] + + +2 * odd_ring_segment_offset) * + get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + } else { + jump_size = (accumulate(num_rings_orig.begin(), num_rings_orig.end(), 0) - num_rings_orig[index_orig] - + 1 // offset to balance the jump_ring in the cycle + + 2 * odd_ring_segment_offset) * + get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + } + // cout << "jump_size " << jump_size << endl; + + // size of the jump between two rings of the same view_num and of the same + // segment + if (segment_num == 0) + jump_ring = 0; + else + jump_ring = get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + + streamoff ring_offset = get_num_tangential_poss() * on_disk_data_type.size_in_bytes(); + + // jumps the initial offset + + sino_stream->seekg(offset, ios::beg); // overall offset + sino_stream->seekg(offset_begin, ios::cur); // "breakfile" offset + sino_stream->seekg(get_num_views() * sizeof(float), ios::cur); // skip view scaling factors + + // jumps at the beginning of the chosen segment + + sino_stream->seekg(segment_offset, ios::cur); + + // jump to the right Viewgram + + streamoff jump_ini = (view_num - get_min_view_num()) * + (ring_offset * get_num_axial_poss(segment_num) + jump_ring * get_num_axial_poss(segment_num) + jump_size); + + // cout << "ring_offset " << ring_offset << endl; + // cout << "jump_ring " << jump_ring << endl; + // cout << "jump_size " << jump_size << endl; + // cout << " jump_ini " << jump_ini << endl; + + sino_stream->seekg(jump_ini, ios::cur); + + Viewgram data = get_empty_viewgram(view_num, segment_num, false); + + for (int ring = get_min_axial_pos_num(segment_num); ring <= get_max_axial_pos_num(segment_num); ring++) { { - { - float scale = float(1); - if (read_data(*sino_stream, data[ring], - on_disk_data_type, - scale, - on_disk_byte_order) == Succeeded::no - || scale != 1) - error("ProjDataGEAdvance: error reading data\n"); - } - sino_stream->seekg(jump_ring, ios::cur); + float scale = float(1); + if (read_data(*sino_stream, data[ring], on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no || scale != 1) + error("ProjDataGEAdvance: error reading data\n"); } - - // scales the Viewgram - data *= view_scaling_factor[view_num]; - - if (make_num_tangential_poss_odd && get_num_tangential_poss()%2==0) - { - const int new_max_tangential_pos = get_max_tangential_pos_num() + 1; - data.grow( - IndexRange2D(get_min_axial_pos_num(segment_num), - get_max_axial_pos_num(segment_num), - get_min_tangential_pos_num(), - new_max_tangential_pos)); - } - - return data; -} + sino_stream->seekg(jump_ring, ios::cur); + } + // scales the Viewgram + data *= view_scaling_factor[view_num]; + + if (make_num_tangential_poss_odd && get_num_tangential_poss() % 2 == 0) { + const int new_max_tangential_pos = get_max_tangential_pos_num() + 1; + data.grow(IndexRange2D(get_min_axial_pos_num(segment_num), get_max_axial_pos_num(segment_num), get_min_tangential_pos_num(), + new_max_tangential_pos)); + } -Succeeded ProjDataGEAdvance::set_viewgram(const Viewgram& v) -{ + return data; +} + +Succeeded +ProjDataGEAdvance::set_viewgram(const Viewgram& v) { // TODO // but this is difficult: how to adjust the scale factors when writing only 1 viewgram ? warning("ProjDataGEAdvance::set_viewgram not implemented yet\n"); return Succeeded::no; } -Sinogram ProjDataGEAdvance::get_sinogram(const int ax_pos_num, const int segment_num,const bool make_num_tangential_poss_odd) const -{ +Sinogram +ProjDataGEAdvance::get_sinogram(const int ax_pos_num, const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos) const { // TODO - error("ProjDataGEAdvance::get_sinogram not implemented yet\n"); - return get_empty_sinogram(ax_pos_num, segment_num);} + error("ProjDataGEAdvance::get_sinogram not implemented yet\n"); + return get_empty_sinogram(ax_pos_num, segment_num); +} -Succeeded ProjDataGEAdvance::set_sinogram(const Sinogram& s) -{ +Succeeded +ProjDataGEAdvance::set_sinogram(const Sinogram& s) { // TODO warning("ProjDataGEAdvance::set_sinogram not implemented yet\n"); return Succeeded::no; diff --git a/src/buildblock/ProjDataGEHDF5.cxx b/src/buildblock/ProjDataGEHDF5.cxx index c1cf35dd92..95d3d9398f 100644 --- a/src/buildblock/ProjDataGEHDF5.cxx +++ b/src/buildblock/ProjDataGEHDF5.cxx @@ -28,8 +28,6 @@ See STIR/LICENSE.txt for details */ - - #include "stir/ProjDataGEHDF5.h" #include "stir/IndexRange.h" #include "stir/IndexRange3D.h" @@ -49,115 +47,101 @@ START_NAMESPACE_STIR namespace GE { namespace RDF_HDF5 { -ProjDataGEHDF5::ProjDataGEHDF5(const std::string& input_filename) : - ProjData() -{ - this->m_input_hdf5_sptr.reset(new GEHDF5Wrapper(input_filename)); - this->initialise_from_wrapper(); +ProjDataGEHDF5::ProjDataGEHDF5(const std::string& input_filename) : ProjData() { + this->m_input_hdf5_sptr.reset(new GEHDF5Wrapper(input_filename)); + this->initialise_from_wrapper(); } -ProjDataGEHDF5::ProjDataGEHDF5(shared_ptr input_hdf5_sptr) : - ProjData(), - m_input_hdf5_sptr(input_hdf5_sptr) -{ - this->initialise_from_wrapper(); +ProjDataGEHDF5::ProjDataGEHDF5(shared_ptr input_hdf5_sptr) : ProjData(), m_input_hdf5_sptr(input_hdf5_sptr) { + this->initialise_from_wrapper(); } -void ProjDataGEHDF5::initialise_from_wrapper() -{ - this->exam_info_sptr = this->m_input_hdf5_sptr->get_exam_info_sptr(); - this->proj_data_info_sptr = this->m_input_hdf5_sptr->get_proj_data_info_sptr()->create_shared_clone(); - this->initialise_segment_sequence(); - this->initialise_ax_pos_offset(); - this->initialise_viewgram_buffer(); +void +ProjDataGEHDF5::initialise_from_wrapper() { + this->exam_info_sptr = this->m_input_hdf5_sptr->get_exam_info_sptr(); + this->proj_data_info_sptr = this->m_input_hdf5_sptr->get_proj_data_info_sptr()->create_shared_clone(); + this->initialise_segment_sequence(); + this->initialise_ax_pos_offset(); + this->initialise_viewgram_buffer(); } -void ProjDataGEHDF5::initialise_viewgram_buffer() -{ +void +ProjDataGEHDF5::initialise_viewgram_buffer() { if (!this->tof_data.empty()) error("there is already data loaded. Aborting"); tof_data.reserve(get_num_views()); - Array<3,unsigned char> buffer; + Array<3, unsigned char> buffer; - for (int view_num = get_min_view_num(); view_num <= get_max_view_num(); view_num++) - { - // view numbering for initialise_proj_data starts from 1 - m_input_hdf5_sptr->initialise_proj_data(view_num - get_min_view_num() + 1); + for (int view_num = get_min_view_num(); view_num <= get_max_view_num(); view_num++) { + // view numbering for initialise_proj_data starts from 1 + m_input_hdf5_sptr->initialise_proj_data(view_num - get_min_view_num() + 1); - m_input_hdf5_sptr->read_sinogram(buffer); - this->tof_data.push_back(buffer); + m_input_hdf5_sptr->read_sinogram(buffer); + this->tof_data.push_back(buffer); } - } -void ProjDataGEHDF5::initialise_segment_sequence() -{ - segment_sequence.resize(2*get_max_segment_num()+1); - segment_sequence[0] = 0; -// PW Flipped the segments, segment sequence is now as: 0,1,-1 and so on. - for (int segment_num = 1; segment_num<=get_max_segment_num(); ++segment_num) - { - segment_sequence[2*segment_num-1] = segment_num; - segment_sequence[2*segment_num] = -segment_num; - } +void +ProjDataGEHDF5::initialise_segment_sequence() { + segment_sequence.resize(2 * get_max_segment_num() + 1); + segment_sequence[0] = 0; + // PW Flipped the segments, segment sequence is now as: 0,1,-1 and so on. + for (int segment_num = 1; segment_num <= get_max_segment_num(); ++segment_num) { + segment_sequence[2 * segment_num - 1] = segment_num; + segment_sequence[2 * segment_num] = -segment_num; + } } -void ProjDataGEHDF5::initialise_ax_pos_offset() -{ +void +ProjDataGEHDF5::initialise_ax_pos_offset() { seg_ax_offset.resize(get_num_segments()); seg_ax_offset[0] = 0; unsigned int previous_value = 0; - for (int i_seg = 1; i_seg < get_num_segments(); ++i_seg) - { - const int segment_num = segment_sequence[i_seg-1]; + for (int i_seg = 1; i_seg < get_num_segments(); ++i_seg) { + const int segment_num = segment_sequence[i_seg - 1]; - seg_ax_offset[i_seg] = static_cast(get_num_axial_poss(segment_num)) + - previous_value; - previous_value = seg_ax_offset[i_seg]; + seg_ax_offset[i_seg] = static_cast(get_num_axial_poss(segment_num)) + previous_value; + previous_value = seg_ax_offset[i_seg]; } } Viewgram -ProjDataGEHDF5:: -get_viewgram(const int view_num, const int segment_num, - const bool make_num_tangential_poss_odd) const -{ - if (make_num_tangential_poss_odd) - error("make_num_tangential_poss_odd not supported by ProjDataGEHDF5"); - Viewgram ret_viewgram = get_empty_viewgram(view_num, segment_num); - // not necessary - // ret_viewgram.fill(0.0); - - // find num TOF bins - BasicCoordinate<3, int> min_index, max_index; - tof_data[0].get_regular_range(min_index,max_index); - const int num_tof_poss = max_index[2] - min_index[2] + 1; - if (num_tof_poss <= 0) - error("ProjDataGEHDF5: internal error on TOF data dimension"); - if (proj_data_info_sptr->get_scanner_ptr()->get_type() == Scanner::PETMR_Signa) - if (num_tof_poss != 27) +ProjDataGEHDF5::get_viewgram(const int view_num, const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos) const { + if (make_num_tangential_poss_odd) + error("make_num_tangential_poss_odd not supported by ProjDataGEHDF5"); + Viewgram ret_viewgram = get_empty_viewgram(view_num, segment_num); + // not necessary + // ret_viewgram.fill(0.0); + + // find num TOF bins + BasicCoordinate<3, int> min_index, max_index; + tof_data[0].get_regular_range(min_index, max_index); + const int num_tof_poss = max_index[2] - min_index[2] + 1; + if (num_tof_poss <= 0) + error("ProjDataGEHDF5: internal error on TOF data dimension"); + if (proj_data_info_sptr->get_scanner_ptr()->get_type() == Scanner::PETMR_Signa) + if (num_tof_poss != 27) error("ProjDataGEHDF5: internal error on TOF data dimension for GE Signa"); - - // PW flip the tangential and view numbers. The TOF bins are added below to return non TOF viewgram. - if (get_min_view_num() != 0) - error("ProjDataGEHDF5: internal error on views"); - if (get_max_tangential_pos_num()+get_min_tangential_pos_num() != 0) - error("ProjDataGEHDF5: internal error on tangential positions"); - for (int tang_pos = ret_viewgram.get_min_tangential_pos_num(), i_tang = 0; - tang_pos <= ret_viewgram.get_max_tangential_pos_num(); - ++tang_pos, ++i_tang) - for(int i_axial=get_min_axial_pos_num(segment_num), axial_pos = seg_ax_offset[find_segment_index_in_sequence(segment_num)]; - i_axial<=get_max_axial_pos_num(segment_num); - i_axial++, axial_pos++) - for (int tof_poss = 0; tof_poss <= num_tof_poss-1; tof_poss++) - { - ret_viewgram[i_axial][-tang_pos] += static_cast (tof_data[get_max_view_num()-view_num][i_tang][tof_poss][axial_pos]); - } + + // PW flip the tangential and view numbers. The TOF bins are added below to return non TOF viewgram. + if (get_min_view_num() != 0) + error("ProjDataGEHDF5: internal error on views"); + if (get_max_tangential_pos_num() + get_min_tangential_pos_num() != 0) + error("ProjDataGEHDF5: internal error on tangential positions"); + for (int tang_pos = ret_viewgram.get_min_tangential_pos_num(), i_tang = 0; + tang_pos <= ret_viewgram.get_max_tangential_pos_num(); ++tang_pos, ++i_tang) + for (int i_axial = get_min_axial_pos_num(segment_num), axial_pos = seg_ax_offset[find_segment_index_in_sequence(segment_num)]; + i_axial <= get_max_axial_pos_num(segment_num); i_axial++, axial_pos++) + for (int tof_poss = 0; tof_poss <= num_tof_poss - 1; tof_poss++) { + ret_viewgram[i_axial][-tang_pos] += + static_cast(tof_data[get_max_view_num() - view_num][i_tang][tof_poss][axial_pos]); + } #if 0 ofstream write_tof_data; @@ -183,51 +167,48 @@ get_viewgram(const int view_num, const int segment_num, write_ret_viewgram_data << std::endl; } #endif - return ret_viewgram; + return ret_viewgram; } - -Succeeded ProjDataGEHDF5::set_viewgram(const Viewgram& v) -{ - // but this is difficult: how to adjust the scale factors when writing only 1 viewgram ? - error("ProjDataFromGEHDF5::set_viewgram not implemented yet"); - return Succeeded::no; +Succeeded +ProjDataGEHDF5::set_viewgram(const Viewgram& v) { + // but this is difficult: how to adjust the scale factors when writing only 1 viewgram ? + error("ProjDataFromGEHDF5::set_viewgram not implemented yet"); + return Succeeded::no; } -Sinogram ProjDataGEHDF5::get_sinogram(const int ax_pos_num, const int segment_num,const bool make_num_tangential_poss_odd) const -{ - // TODO - error("ProjDataGEHDF5::get_sinogram not implemented yet"); - return get_empty_sinogram(ax_pos_num, segment_num); +Sinogram +ProjDataGEHDF5::get_sinogram(const int ax_pos_num, const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos) const { + // TODO + error("ProjDataGEHDF5::get_sinogram not implemented yet"); + return get_empty_sinogram(ax_pos_num, segment_num); } -Succeeded ProjDataGEHDF5::set_sinogram(const Sinogram& s) -{ - error("ProjDataGEHDF5::set_sinogram not implemented yet"); - return Succeeded::no; +Succeeded +ProjDataGEHDF5::set_sinogram(const Sinogram& s) { + error("ProjDataGEHDF5::set_sinogram not implemented yet"); + return Succeeded::no; } unsigned int -ProjDataGEHDF5::find_segment_index_in_sequence(const int segment_num) const -{ +ProjDataGEHDF5::find_segment_index_in_sequence(const int segment_num) const { #ifndef STIR_NO_NAMESPACES - std::vector::const_iterator iter = - std::find(segment_sequence.begin(), segment_sequence.end(), segment_num); + std::vector::const_iterator iter = std::find(segment_sequence.begin(), segment_sequence.end(), segment_num); #else - vector::const_iterator iter = - find(segment_sequence.begin(), segment_sequence.end(), segment_num); + vector::const_iterator iter = find(segment_sequence.begin(), segment_sequence.end(), segment_num); #endif // TODO do some proper error handling here - assert(iter != segment_sequence.end()); + assert(iter != segment_sequence.end()); return static_cast(iter - segment_sequence.begin()); } std::vector -ProjDataGEHDF5::get_segment_sequence_in_hdf5() const -{ return segment_sequence; } - - -} // namespace +ProjDataGEHDF5::get_segment_sequence_in_hdf5() const { + return segment_sequence; } + +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR diff --git a/src/buildblock/ProjDataInMemory.cxx b/src/buildblock/ProjDataInMemory.cxx index 4a9fb91f02..757acbb5ed 100644 --- a/src/buildblock/ProjDataInMemory.cxx +++ b/src/buildblock/ProjDataInMemory.cxx @@ -4,9 +4,11 @@ \ingroup projdata \brief Implementations for non-inline functions of class stir::ProjDataInMemory + \author Nikos Efthimiou \author Kris Thielemans */ /* + * Copyright (C) 2016, UCL Copyright (C) 2002 - 2011-02-23, Hammersmith Imanet Ltd Copyright (C) 2011, Kris Thielemans Copyright (C) 2019, 2020, UCL @@ -25,7 +27,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/ProjDataInMemory.h" #include "stir/shared_ptr.h" #include "stir/Succeeded.h" @@ -36,71 +37,63 @@ #include #ifdef STIR_USE_OLD_STRSTREAM -#include +# include #else -#include +# include #endif #ifndef STIR_NO_NAMESPACES using std::fstream; using std::iostream; using std::ios; -#ifdef STIR_USE_OLD_STRSTREAM +# ifdef STIR_USE_OLD_STRSTREAM using std::strstream; -#endif +# endif using std::string; #endif START_NAMESPACE_STIR -ProjDataInMemory:: -~ProjDataInMemory() -{ +ProjDataInMemory::~ProjDataInMemory() { // release such that it can deallocate safely this->buffer.release_data_ptr(); } -ProjDataInMemory:: -ProjDataInMemory(shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, const bool initialise_with_0) - : - ProjDataFromStream(exam_info_sptr, proj_data_info_ptr, shared_ptr(), // trick: first initialise sino_stream_ptr to 0 - std::streamoff(0), - ProjData::standard_segment_sequence(*proj_data_info_ptr), - Segment_AxialPos_View_TangPos) -{ +ProjDataInMemory::ProjDataInMemory(shared_ptr const& exam_info_sptr, + shared_ptr const& proj_data_info_ptr, const bool initialise_with_0) + : ProjDataFromStream( + exam_info_sptr, proj_data_info_ptr, shared_ptr(), // trick: first initialise sino_stream_ptr to 0 + std::streamoff(0), ProjData::standard_segment_sequence(*proj_data_info_ptr), Segment_AxialPos_View_TangPos) { this->create_buffer(initialise_with_0); this->create_stream(); } void -ProjDataInMemory:: -create_buffer(const bool initialise_with_0) -{ +ProjDataInMemory::create_buffer(const bool initialise_with_0) { #if 0 float *b = new float[this->get_size_of_buffer_in_bytes()/sizeof(float)]; if (initialise_with_0) memset(b, 0, this->get_size_of_buffer_in_bytes()); return b; #else - this->buffer = Array<1,float>(0, static_cast(this->get_size_of_buffer_in_bytes()/sizeof(float))-1); + this->buffer = Array<1, float>(0, static_cast(this->get_size_of_buffer_in_bytes() / sizeof(float)) - 1); #endif } void -ProjDataInMemory:: -create_stream() -{ +ProjDataInMemory::create_stream() { shared_ptr output_stream_sptr; #ifdef STIR_USE_OLD_STRSTREAM - output_stream_sptr.reset(new strstream(buffer.get_data_ptr(), this->get_size_of_buffer_in_bytes(), ios::in | ios::out | ios::binary)); + output_stream_sptr.reset( + new strstream(buffer.get_data_ptr(), this->get_size_of_buffer_in_bytes(), ios::in | ios::out | ios::binary)); #else // Use boost::bufferstream to avoid reallocate. // For std::stringstream, the only way to do this is by passing a string of the appropriate size // However, if basic_string doesn't do reference counting, we would have // temporarily 2 strings of a (potentially large) size in memory. - output_stream_sptr.reset - (new boost::interprocess::bufferstream(reinterpret_cast(this->buffer.get_data_ptr()), this->get_size_of_buffer_in_bytes(), ios::in | ios::out | ios::binary)); + output_stream_sptr.reset(new boost::interprocess::bufferstream(reinterpret_cast(this->buffer.get_data_ptr()), + this->get_size_of_buffer_in_bytes(), + ios::in | ios::out | ios::binary)); #endif if (!*output_stream_sptr) @@ -109,36 +102,26 @@ create_stream() this->sino_stream = output_stream_sptr; } - void -ProjDataInMemory::fill(const float value) -{ +ProjDataInMemory::fill(const float value) { std::fill(begin_all(), end_all(), value); } void -ProjDataInMemory::fill(const ProjData& proj_data) -{ - auto pdm_ptr = dynamic_cast(&proj_data); - if (!is_null_ptr(pdm_ptr) && - (*this->get_proj_data_info_sptr()) == (*proj_data.get_proj_data_info_sptr())) - { - std::copy(pdm_ptr->begin_all(), pdm_ptr->end_all(), begin_all()); - } - else - { - return ProjData::fill(proj_data); - } -} - -ProjDataInMemory:: -ProjDataInMemory(const ProjData& proj_data) - : ProjDataFromStream(proj_data.get_exam_info_sptr(), - proj_data.get_proj_data_info_sptr()->create_shared_clone(), shared_ptr(), - std::streamoff(0), - ProjData::standard_segment_sequence(*proj_data.get_proj_data_info_sptr()), - Segment_AxialPos_View_TangPos) -{ +ProjDataInMemory::fill(const ProjData& proj_data) { + auto pdm_ptr = dynamic_cast(&proj_data); + if (!is_null_ptr(pdm_ptr) && (*this->get_proj_data_info_sptr()) == (*proj_data.get_proj_data_info_sptr())) { + std::copy(pdm_ptr->begin_all(), pdm_ptr->end_all(), begin_all()); + } else { + return ProjData::fill(proj_data); + } +} + +ProjDataInMemory::ProjDataInMemory(const ProjData& proj_data) + : ProjDataFromStream(proj_data.get_exam_info_sptr(), proj_data.get_proj_data_info_sptr()->create_shared_clone(), + shared_ptr(), std::streamoff(0), + ProjData::standard_segment_sequence(*proj_data.get_proj_data_info_sptr()), + Segment_AxialPos_View_TangPos) { this->create_buffer(); this->create_stream(); @@ -146,81 +129,64 @@ ProjDataInMemory(const ProjData& proj_data) this->fill(proj_data); } -ProjDataInMemory:: -ProjDataInMemory (const ProjDataInMemory& proj_data) - : ProjDataFromStream(proj_data.get_exam_info_sptr(), - proj_data.get_proj_data_info_sptr()->create_shared_clone(), shared_ptr(), - std::streamoff(0), +ProjDataInMemory::ProjDataInMemory(const ProjDataInMemory& proj_data) + : ProjDataFromStream(proj_data.get_exam_info_sptr(), proj_data.get_proj_data_info_sptr()->create_shared_clone(), + shared_ptr(), std::streamoff(0), ProjData::standard_segment_sequence(*proj_data.get_proj_data_info_sptr()), - Segment_AxialPos_View_TangPos) -{ + Segment_AxialPos_View_TangPos) { this->create_buffer(); this->create_stream(); // copy data std::copy(proj_data.begin_all(), proj_data.end_all(), begin_all()); - //this->fill(proj_data); + // this->fill(proj_data); } size_t -ProjDataInMemory:: -get_size_of_buffer_in_bytes() const -{ +ProjDataInMemory::get_size_of_buffer_in_bytes() const { return size_all() * sizeof(float); } -float -ProjDataInMemory::get_bin_value(Bin& bin) -{ - // first find offset in the stream - std::vector offsets = get_offsets_bin(bin); - const std::streamoff total_offset = offsets[0]; - // now convert to index in the buffer - const int index = static_cast(total_offset/sizeof(float)); - return buffer[index]; +float +ProjDataInMemory::get_bin_value(Bin& bin) { + // Viewgram viewgram = get_viewgram(bin.view_num(),bin.segment_num()); + // return viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]; + return ProjDataFromStream::get_bin_value(bin); } -void -ProjDataInMemory::set_bin_value(const Bin& bin) -{ +void +ProjDataInMemory::set_bin_value(const Bin& bin) { // first find offset in the stream std::vector offsets = get_offsets_bin(bin); const std::streamoff total_offset = offsets[0]; // now convert to index in the buffer - const int index = static_cast(total_offset/sizeof(float)); - - buffer[index]=bin.get_bin_value(); + const int index = static_cast(total_offset / sizeof(float)); + + buffer[index] = bin.get_bin_value(); } void -ProjDataInMemory:: -axpby( const float a, const ProjData& x, - const float b, const ProjData& y) -{ - xapyb(x,a,y,b); +ProjDataInMemory::axpby(const float a, const ProjData& x, const float b, const ProjData& y) { + xapyb(x, a, y, b); } void -ProjDataInMemory:: -xapyb(const ProjData& x, const float a, - const ProjData& y, const float b) -{ - // To use this method, we require that all three proj data be ProjDataInMemory - // So cast them. If any null pointers, fall back to default functionality - const ProjDataInMemory *x_pdm = dynamic_cast(&x); - const ProjDataInMemory *y_pdm = dynamic_cast(&y); - // At least one is not ProjDataInMemory, fall back to default - if (is_null_ptr(x_pdm) || is_null_ptr(y_pdm)) { - ProjData::xapyb(x,a,y,b); - return; - } - - // Else, all are ProjDataInMemory - - // First check that info match - if (*get_proj_data_info_sptr() != *x.get_proj_data_info_sptr() || - *get_proj_data_info_sptr() != *y.get_proj_data_info_sptr()) - error("ProjDataInMemory::xapyb: ProjDataInfo don't match"); +ProjDataInMemory::xapyb(const ProjData& x, const float a, const ProjData& y, const float b) { + // To use this method, we require that all three proj data be ProjDataInMemory + // So cast them. If any null pointers, fall back to default functionality + const ProjDataInMemory* x_pdm = dynamic_cast(&x); + const ProjDataInMemory* y_pdm = dynamic_cast(&y); + // At least one is not ProjDataInMemory, fall back to default + if (is_null_ptr(x_pdm) || is_null_ptr(y_pdm)) { + ProjData::xapyb(x, a, y, b); + return; + } + + // Else, all are ProjDataInMemory + + // First check that info match + if (*get_proj_data_info_sptr() != *x.get_proj_data_info_sptr() || *get_proj_data_info_sptr() != *y.get_proj_data_info_sptr()) + error("ProjDataInMemory::xapyb: ProjDataInfo don't match"); #if 0 // Get number of elements @@ -233,38 +199,31 @@ xapyb(const ProjData& x, const float a, for (unsigned i=0; ibuffer.xapyb(x_pdm->buffer, a, y_pdm->buffer, b); + this->buffer.xapyb(x_pdm->buffer, a, y_pdm->buffer, b); #endif } - + void -ProjDataInMemory:: -xapyb(const ProjData& x, const ProjData& a, - const ProjData& y, const ProjData& b) -{ - // To use this method, we require that all three proj data be ProjDataInMemory - // So cast them. If any null pointers, fall back to default functionality - const ProjDataInMemory *x_pdm = dynamic_cast(&x); - const ProjDataInMemory *y_pdm = dynamic_cast(&y); - const ProjDataInMemory *a_pdm = dynamic_cast(&a); - const ProjDataInMemory *b_pdm = dynamic_cast(&b); - - - // At least one is not ProjDataInMemory, fall back to default - if (is_null_ptr(x_pdm) || is_null_ptr(y_pdm) || - is_null_ptr(a_pdm) || is_null_ptr(b_pdm)) { - ProjData::xapyb(x,a,y,b); - return; - } - - // Else, all are ProjDataInMemory - - // First check that info match - if (*get_proj_data_info_sptr() != *x.get_proj_data_info_sptr() || - *get_proj_data_info_sptr() != *y.get_proj_data_info_sptr() || - *get_proj_data_info_sptr() != *a.get_proj_data_info_sptr() || - *get_proj_data_info_sptr() != *b.get_proj_data_info_sptr()) - error("ProjDataInMemory::xapyb: ProjDataInfo don't match"); +ProjDataInMemory::xapyb(const ProjData& x, const ProjData& a, const ProjData& y, const ProjData& b) { + // To use this method, we require that all three proj data be ProjDataInMemory + // So cast them. If any null pointers, fall back to default functionality + const ProjDataInMemory* x_pdm = dynamic_cast(&x); + const ProjDataInMemory* y_pdm = dynamic_cast(&y); + const ProjDataInMemory* a_pdm = dynamic_cast(&a); + const ProjDataInMemory* b_pdm = dynamic_cast(&b); + + // At least one is not ProjDataInMemory, fall back to default + if (is_null_ptr(x_pdm) || is_null_ptr(y_pdm) || is_null_ptr(a_pdm) || is_null_ptr(b_pdm)) { + ProjData::xapyb(x, a, y, b); + return; + } + + // Else, all are ProjDataInMemory + + // First check that info match + if (*get_proj_data_info_sptr() != *x.get_proj_data_info_sptr() || *get_proj_data_info_sptr() != *y.get_proj_data_info_sptr() || + *get_proj_data_info_sptr() != *a.get_proj_data_info_sptr() || *get_proj_data_info_sptr() != *b.get_proj_data_info_sptr()) + error("ProjDataInMemory::xapyb: ProjDataInfo don't match"); #if 0 // Get number of elements @@ -279,22 +238,18 @@ xapyb(const ProjData& x, const ProjData& a, for (unsigned i=0; ibuffer.xapyb(x_pdm->buffer, a_pdm->buffer, y_pdm->buffer, b_pdm->buffer); + this->buffer.xapyb(x_pdm->buffer, a_pdm->buffer, y_pdm->buffer, b_pdm->buffer); #endif } void -ProjDataInMemory:: -sapyb(const float a, const ProjData& y, const float b) -{ - this->xapyb(*this,a,y,b); +ProjDataInMemory::sapyb(const float a, const ProjData& y, const float b) { + this->xapyb(*this, a, y, b); } void -ProjDataInMemory:: -sapyb(const ProjData& a, const ProjData& y,const ProjData& b) -{ - this->xapyb(*this,a,y,b); +ProjDataInMemory::sapyb(const ProjData& a, const ProjData& y, const ProjData& b) { + this->xapyb(*this, a, y, b); } END_NAMESPACE_STIR diff --git a/src/buildblock/ProjDataInfo.cxx b/src/buildblock/ProjDataInfo.cxx index 60d7a36ff6..0f497a8904 100644 --- a/src/buildblock/ProjDataInfo.cxx +++ b/src/buildblock/ProjDataInfo.cxx @@ -4,8 +4,9 @@ Copyright (C) 2000 PARAPET partners Copyright (C) 2000 - 2009-05-13, Hammersmith Imanet Ltd Copyright (C) 2011-07-01 - 2011, Kris Thielemans - Copyright (C) 2018, University College London Copyright (C) 2018, University of Leeds + Copyright (C) 2018, University College London + Copyright (C) 2016, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -25,6 +26,7 @@ \brief Implementation of non-inline functions of class stir::ProjDataInfo + \author Nikos Efthimiou \author Sanida Mustafovic \author Kris Thielemans \author PARAPET project @@ -53,10 +55,12 @@ #include #include #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif +#include "stir/info.h" +#include "boost/foreach.hpp" #include "boost/format.hpp" #ifndef STIR_NO_NAMESPACES @@ -70,117 +74,206 @@ using std::equal; START_NAMESPACE_STIR +float +ProjDataInfo::get_k(const Bin& bin) const { + if (!(num_tof_bins % 2)) + return bin.timing_pos_num() * tof_increament_in_mm + tof_increament_in_mm / 2.f; + else + return (bin.timing_pos_num() * tof_increament_in_mm); +} -float -ProjDataInfo::get_sampling_in_t(const Bin& bin) const -{ - return - (get_t(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num()+1,bin.tangential_pos_num())) - - get_t(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num()-1,bin.tangential_pos_num())) - )/2; +double +ProjDataInfo::get_tof_delta_time(const Bin& bin) const { + return mm_to_tof_delta_time(get_k(bin)); // get_k gives "left" edge N.E: corrected returns the center. } -float -ProjDataInfo::get_sampling_in_m(const Bin& bin) const -{ - return - (get_m(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num()+1,bin.tangential_pos_num())) - - get_m(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num()-1,bin.tangential_pos_num())) - )/2; +float +ProjDataInfo::get_sampling_in_k(const Bin& bin) const { + return (get_k(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num(), bin.timing_pos_num() + 1)) - + get_k( + Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num(), bin.timing_pos_num() - 1))) / + 2.f; } +float +ProjDataInfo::get_sampling_in_t(const Bin& bin) const { + return (get_t(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num() + 1, bin.tangential_pos_num())) - + get_t(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num() - 1, bin.tangential_pos_num()))) / + 2; +} -float -ProjDataInfo::get_sampling_in_s(const Bin& bin) const -{ - return - (get_s(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num(),bin.tangential_pos_num()+1)) - - get_s(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num(),bin.tangential_pos_num()-1)) - )/2; +float +ProjDataInfo::get_sampling_in_m(const Bin& bin) const { + return (get_m(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num() + 1, bin.tangential_pos_num())) - + get_m(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num() - 1, bin.tangential_pos_num()))) / + 2; } -void -ProjDataInfo::set_num_views(const int num_views) -{ +float +ProjDataInfo::get_sampling_in_s(const Bin& bin) const { + return (get_s(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num() + 1)) - + get_s(Bin(bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num() - 1))) / + 2; +} + +void +ProjDataInfo::set_num_views(const int num_views) { min_view_num = 0; - max_view_num = num_views-1; + max_view_num = num_views - 1; } -void -ProjDataInfo::set_num_tangential_poss(const int num_tang_poss) -{ +void +ProjDataInfo::set_num_tangential_poss(const int num_tang_poss) { - min_tangential_pos_num = -(num_tang_poss/2); - max_tangential_pos_num = min_tangential_pos_num + num_tang_poss-1; + min_tangential_pos_num = -(num_tang_poss / 2); + max_tangential_pos_num = min_tangential_pos_num + num_tang_poss - 1; } /*! Sets min_axial_pos_per_seg to 0 */ -void -ProjDataInfo::set_num_axial_poss_per_segment(const VectorWithOffset& num_axial_poss_per_segment) -{ - // first do assignments to make the members the correct size +void +ProjDataInfo::set_num_axial_poss_per_segment(const VectorWithOffset& num_axial_poss_per_segment) { + // first do assignments to make the members the correct size // (data will be overwritten) - min_axial_pos_per_seg= num_axial_poss_per_segment; - max_axial_pos_per_seg= num_axial_poss_per_segment; - - for (int i=num_axial_poss_per_segment.get_min_index(); - i<=num_axial_poss_per_segment.get_max_index(); - i++) - { - min_axial_pos_per_seg[i]=0; - max_axial_pos_per_seg[i]=num_axial_poss_per_segment[i]-1; + min_axial_pos_per_seg = num_axial_poss_per_segment; + max_axial_pos_per_seg = num_axial_poss_per_segment; + + for (int i = num_axial_poss_per_segment.get_min_index(); i <= num_axial_poss_per_segment.get_max_index(); i++) { + min_axial_pos_per_seg[i] = 0; + max_axial_pos_per_seg[i] = num_axial_poss_per_segment[i] - 1; } - } /*! No checks are done on validity of the min_ax_pos_num argument */ -void -ProjDataInfo::set_min_axial_pos_num(const int min_ax_pos_num, const int segment_num) -{ +void +ProjDataInfo::set_min_axial_pos_num(const int min_ax_pos_num, const int segment_num) { min_axial_pos_per_seg[segment_num] = min_ax_pos_num; } /*! No checks are done on validity of the max_ax_pos_num argument */ -void -ProjDataInfo::set_max_axial_pos_num(const int max_ax_pos_num, const int segment_num) -{ +void +ProjDataInfo::set_max_axial_pos_num(const int max_ax_pos_num, const int segment_num) { max_axial_pos_per_seg[segment_num] = max_ax_pos_num; } - void -ProjDataInfo::set_min_tangential_pos_num(const int min_tang_poss) -{ +ProjDataInfo::set_min_tangential_pos_num(const int min_tang_poss) { min_tangential_pos_num = min_tang_poss; } void -ProjDataInfo::set_max_tangential_pos_num(const int max_tang_poss) -{ +ProjDataInfo::set_max_tangential_pos_num(const int max_tang_poss) { max_tangential_pos_num = max_tang_poss; } +//! \todo N.E: This function is very ugly and unnessesary complicated. Could be much better. +void +ProjDataInfo::set_tof_mash_factor(const int new_num) { + if (scanner_ptr->is_tof_ready() && new_num > 0) { + if (tof_mash_factor < 0 || tof_mash_factor > scanner_ptr->get_max_num_timing_poss()) + error("ProjDataInfo: TOF mashing factor must be positive and smaller or equal than" + "the scanner's number of max timing bins. Abort."); + tof_mash_factor = new_num; + + tof_increament_in_mm = tof_delta_time_to_mm(scanner_ptr->get_size_of_timing_pos()); + min_unmashed_tof_pos_num = -(scanner_ptr->get_max_num_timing_poss()) / 2; + max_unmashed_tof_pos_num = min_unmashed_tof_pos_num + (scanner_ptr->get_max_num_timing_poss()) - 1; + + // Upper and lower boundaries of the timing poss; + tof_bin_unmashed_boundaries_mm.grow(min_unmashed_tof_pos_num, max_unmashed_tof_pos_num); + tof_bin_unmashed_boundaries_ps.grow(min_unmashed_tof_pos_num, max_unmashed_tof_pos_num); + + // Silently intialise the unmashed TOF bins. + for (int k = min_unmashed_tof_pos_num; k <= max_unmashed_tof_pos_num; ++k) { + Bin bin; + bin.timing_pos_num() = k; + + float cur_low = get_k(bin) - get_sampling_in_k(bin) / 2.f; + float cur_high = get_k(bin) + get_sampling_in_k(bin) / 2.f; + + tof_bin_unmashed_boundaries_mm[k].low_lim = cur_low; + tof_bin_unmashed_boundaries_mm[k].high_lim = cur_high; + tof_bin_unmashed_boundaries_ps[k].low_lim = + static_cast(mm_to_tof_delta_time(tof_bin_unmashed_boundaries_mm[k].low_lim)); + tof_bin_unmashed_boundaries_ps[k].high_lim = + static_cast(mm_to_tof_delta_time(tof_bin_unmashed_boundaries_mm[k].high_lim)); + } + + // Now, initialise the mashed TOF bins. + tof_increament_in_mm = tof_delta_time_to_mm(tof_mash_factor * scanner_ptr->get_size_of_timing_pos()); + + min_tof_pos_num = -(scanner_ptr->get_max_num_timing_poss() / tof_mash_factor) / 2; + max_tof_pos_num = min_tof_pos_num + (scanner_ptr->get_max_num_timing_poss() / tof_mash_factor) - 1; + + min_unmashed_tof_pos_num = -(scanner_ptr->get_max_num_timing_poss()) / 2; + max_unmashed_tof_pos_num = min_tof_pos_num + (scanner_ptr->get_max_num_timing_poss()) - 1; -ProjDataInfo::ProjDataInfo() - : bed_position_horizontal(0.F), bed_position_vertical(0.F) -{} + num_tof_bins = max_tof_pos_num - min_tof_pos_num + 1; + // Ensure that we have a central tof bin. + if (num_tof_bins % 2 == 0) + error("ProjDataInfo: Number of TOF bins should be an odd number. Abort."); + // Upper and lower boundaries of the timing poss; + tof_bin_boundaries_mm.grow(min_tof_pos_num, max_tof_pos_num); + tof_bin_boundaries_ps.grow(min_tof_pos_num, max_tof_pos_num); -ProjDataInfo::ProjDataInfo(const shared_ptr& scanner_ptr_v, - const VectorWithOffset& num_axial_pos_per_segment_v, - const int num_views_v, - const int num_tangential_poss_v) - : scanner_ptr(scanner_ptr_v), bed_position_horizontal(0.F), bed_position_vertical(0.F) -{ + for (int k = min_tof_pos_num; k <= max_tof_pos_num; ++k) { + Bin bin; + bin.timing_pos_num() = k; + + float cur_low = get_k(bin) - get_sampling_in_k(bin) / 2.f; + float cur_high = get_k(bin) + get_sampling_in_k(bin) / 2.f; + + tof_bin_boundaries_mm[k].low_lim = cur_low; + tof_bin_boundaries_mm[k].high_lim = cur_high; + tof_bin_boundaries_ps[k].low_lim = static_cast(mm_to_tof_delta_time(tof_bin_boundaries_mm[k].low_lim)); + tof_bin_boundaries_ps[k].high_lim = static_cast(mm_to_tof_delta_time(tof_bin_boundaries_mm[k].high_lim)); + // I could imagine a better printing. + info(boost::format("Tbin %1%: %2% - %3% mm (%4% - %5% ps) = %6%") % k % tof_bin_boundaries_mm[k].low_lim % + tof_bin_boundaries_mm[k].high_lim % tof_bin_boundaries_ps[k].low_lim % tof_bin_boundaries_ps[k].high_lim % + get_sampling_in_k(bin)); + } + } else if ((scanner_ptr->is_tof_ready() && new_num <= 0) || + !scanner_ptr->is_tof_ready()) // Case new_num <=, will produce non-TOF data for a TOF compatible scanner + { + num_tof_bins = 1; + tof_mash_factor = 0; + min_tof_pos_num = 0; + max_tof_pos_num = 0; + // we assume TOF mashing factor = 0 means non-TOF and the projecter won't use any boundary conditions + } +} + +ProjDataInfo::ProjDataInfo() : bed_position_horizontal(0.F), bed_position_vertical(0.F) {} + +ProjDataInfo::ProjDataInfo(const shared_ptr& scanner_ptr_v, const VectorWithOffset& num_axial_pos_per_segment_v, + const int num_views_v, const int num_tangential_poss_v) + : scanner_ptr(scanner_ptr_v), bed_position_horizontal(0.F), bed_position_vertical(0.F) { set_num_views(num_views_v); set_num_tangential_poss(num_tangential_poss_v); set_num_axial_poss_per_segment(num_axial_pos_per_segment_v); + // Initialise the TOF elements to non-used. + min_tof_pos_num = 0; + max_tof_pos_num = 0; + tof_increament_in_mm = 0.f; + tof_mash_factor = 0; + num_tof_bins = 1; } -string -ProjDataInfo::parameter_info() const +// TOF version. +ProjDataInfo::ProjDataInfo(const shared_ptr& scanner_ptr_v, const VectorWithOffset& num_axial_pos_per_segment_v, + const int num_views_v, const int num_tangential_poss_v, const int tof_mash_factor_v) + : scanner_ptr(scanner_ptr_v) + { + set_tof_mash_factor(tof_mash_factor_v); + set_num_views(num_views_v); + set_num_tangential_poss(num_tangential_poss_v); + set_num_axial_poss_per_segment(num_axial_pos_per_segment_v); +} + +string +ProjDataInfo::parameter_info() const { #ifdef BOOST_NO_STRINGSTREAM // dangerous for out-of-range, but 'old-style' ostrstream seems to need this @@ -191,272 +284,219 @@ ProjDataInfo::parameter_info() const #endif s << scanner_ptr->parameter_info(); s << "\n"; - s << "start vertical bed position (mm) := " - << get_bed_position_vertical() << endl; - s << "start horizontal bed position (mm) := " - << get_bed_position_horizontal() << endl; - s << "\nSegment_num range: (" - << get_min_segment_num() - << ", " << get_max_segment_num() << ")\n"; + s << "start vertical bed position (mm) := " << get_bed_position_vertical() << endl; + s << "start horizontal bed position (mm) := " << get_bed_position_horizontal() << endl; + s << "\nNumber of TOF positions in data: " << get_num_tof_poss() << '\n'; + s << "\nSegment_num range: (" << get_min_segment_num() << ", " << get_max_segment_num() << ")\n"; s << "Number of Views: " << get_num_views() << endl; s << "Number of axial positions per seg: {"; - for (int seg_num=get_min_segment_num(); seg_num <= get_max_segment_num(); ++seg_num) + for (int seg_num = get_min_segment_num(); seg_num <= get_max_segment_num(); ++seg_num) s << get_num_axial_poss(seg_num) << " "; s << "}\n"; s << "Number of tangential positions: " << get_num_tangential_poss() << endl; return s.str(); - } - void -ProjDataInfo:: -reduce_segment_range(const int min_segment_num, const int max_segment_num) -{ +ProjDataInfo::reduce_segment_range(const int min_segment_num, const int max_segment_num) { assert(min_segment_num >= get_min_segment_num()); assert(max_segment_num <= get_max_segment_num()); - VectorWithOffset new_min_axial_pos_per_seg(min_segment_num, max_segment_num); + VectorWithOffset new_min_axial_pos_per_seg(min_segment_num, max_segment_num); VectorWithOffset new_max_axial_pos_per_seg(min_segment_num, max_segment_num); - for (int segment_num = min_segment_num; segment_num<= max_segment_num; ++segment_num) - { - new_min_axial_pos_per_seg[segment_num] = - min_axial_pos_per_seg[segment_num]; - new_max_axial_pos_per_seg[segment_num] = - max_axial_pos_per_seg[segment_num]; + for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) { + new_min_axial_pos_per_seg[segment_num] = min_axial_pos_per_seg[segment_num]; + new_max_axial_pos_per_seg[segment_num] = max_axial_pos_per_seg[segment_num]; } min_axial_pos_per_seg = new_min_axial_pos_per_seg; max_axial_pos_per_seg = new_max_axial_pos_per_seg; - } - -Viewgram -ProjDataInfo::get_empty_viewgram(const int view_num, - const int segment_num, - const bool make_num_tangential_poss_odd) const -{ +Viewgram +ProjDataInfo::get_empty_viewgram(const int view_num, const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos_num) const { // we can't access the shared ptr, so we have to clone 'this'. - shared_ptr proj_data_info_sptr(this->clone()); - - if (make_num_tangential_poss_odd && (get_num_tangential_poss()%2==0)) + shared_ptr proj_data_info_sptr(this->clone()); + + if (make_num_tangential_poss_odd && (get_num_tangential_poss() % 2 == 0)) proj_data_info_sptr->set_max_tangential_pos_num(get_max_tangential_pos_num() + 1); - - Viewgram v(proj_data_info_sptr, view_num, segment_num); - + + Viewgram v(proj_data_info_sptr, view_num, segment_num, timing_pos_num); + return v; } - Sinogram -ProjDataInfo::get_empty_sinogram(const int axial_pos_num, const int segment_num, - const bool make_num_tangential_poss_odd) const -{ +ProjDataInfo::get_empty_sinogram(const int axial_pos_num, const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos_num) const { // we can't access the shared ptr, so we have to clone 'this'. - shared_ptr proj_data_info_sptr(this->clone()); - - if (make_num_tangential_poss_odd && (get_num_tangential_poss()%2==0)) + shared_ptr proj_data_info_sptr(this->clone()); + + if (make_num_tangential_poss_odd && (get_num_tangential_poss() % 2 == 0)) proj_data_info_sptr->set_max_tangential_pos_num(get_max_tangential_pos_num() + 1); - Sinogram s(proj_data_info_sptr, axial_pos_num, segment_num); - + Sinogram s(proj_data_info_sptr, axial_pos_num, segment_num, timing_pos_num); + return s; } SegmentBySinogram -ProjDataInfo::get_empty_segment_by_sinogram(const int segment_num, - const bool make_num_tangential_poss_odd) const -{ +ProjDataInfo::get_empty_segment_by_sinogram(const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos_num) const { assert(segment_num >= get_min_segment_num()); assert(segment_num <= get_max_segment_num()); - + // we can't access the shared ptr, so we have to clone 'this'. - shared_ptr proj_data_info_sptr(this->clone()); - - if (make_num_tangential_poss_odd && (get_num_tangential_poss()%2==0)) + shared_ptr proj_data_info_sptr(this->clone()); + + if (make_num_tangential_poss_odd && (get_num_tangential_poss() % 2 == 0)) proj_data_info_sptr->set_max_tangential_pos_num(get_max_tangential_pos_num() + 1); - SegmentBySinogram s(proj_data_info_sptr, segment_num); + SegmentBySinogram s(proj_data_info_sptr, segment_num, timing_pos_num); return s; -} - +} SegmentByView -ProjDataInfo::get_empty_segment_by_view(const int segment_num, - const bool make_num_tangential_poss_odd) const -{ +ProjDataInfo::get_empty_segment_by_view(const int segment_num, const bool make_num_tangential_poss_odd, + const int timing_pos_num) const { assert(segment_num >= get_min_segment_num()); assert(segment_num <= get_max_segment_num()); - // we can't access the shared ptr, so we have to clone 'this'. - shared_ptr proj_data_info_sptr(this->clone()); - - if (make_num_tangential_poss_odd && (get_num_tangential_poss()%2==0)) + // we can't access the shared ptr, so we have to clone 'this'. + shared_ptr proj_data_info_sptr(this->clone()); + + if (make_num_tangential_poss_odd && (get_num_tangential_poss() % 2 == 0)) proj_data_info_sptr->set_max_tangential_pos_num(get_max_tangential_pos_num() + 1); - - SegmentByView s(proj_data_info_sptr, segment_num); + + SegmentByView s(proj_data_info_sptr, segment_num, timing_pos_num); return s; } -RelatedViewgrams -ProjDataInfo::get_empty_related_viewgrams(const ViewSegmentNumbers& view_segmnet_num, - //const int view_num, const int segment_num, - const shared_ptr& symmetries_used, - const bool make_num_tangential_poss_odd) const -{ +RelatedViewgrams +ProjDataInfo::get_empty_related_viewgrams(const ViewSegmentNumbers& view_segment_num, + // const int view_num, const int segment_num, + const shared_ptr& symmetries_used, + const bool make_num_tangential_poss_odd, const int timing_pos_num) const { vector pairs; symmetries_used->get_related_view_segment_numbers( - pairs, - ViewSegmentNumbers(view_segmnet_num.view_num(),view_segmnet_num.segment_num()) - ); + pairs, ViewSegmentNumbers(view_segment_num.view_num(), view_segment_num.segment_num())); - vector > viewgrams; + vector> viewgrams; viewgrams.reserve(pairs.size()); - for (unsigned int i=0; i(viewgrams, symmetries_used); } - /****************** static members **********************/ ProjDataInfo* -ProjDataInfo::ProjDataInfoCTI(const shared_ptr& scanner, - const int span, const int max_delta, - const int num_views, const int num_tangential_poss, - const bool arc_corrected) -{ +ProjDataInfo::ProjDataInfoCTI(const shared_ptr& scanner, const int span, const int max_delta, const int num_views, + const int num_tangential_poss, const bool arc_corrected, const int tof_mash_factor) { const int num_ring = scanner->get_num_rings(); if (max_delta > num_ring - 1) - error(boost::format("construct_proj_data_info: max_ring_difference %d is too large, number of rings is %d") - % max_delta % num_ring); - if (span < 1) + error(boost::format("construct_proj_data_info: max_ring_difference %d is too large, number of rings is %d") % max_delta % + num_ring); + if (span < 1) error(boost::format("construct_proj_data_info: span %d has to be larger than 0") % span); if (span > 2 * num_ring - 1) - error(boost::format("construct_proj_data_info: span %d is too large for a scanner with %d rings") - % span % num_ring); - if (max_delta<(span-1)/2) - error(boost::format("construct_proj_data_info: max_ring_difference %d has to be at least (span-1)/2, span is %d") - % max_delta % span); - - // Construct first a temporary list of min and max ring diff per segment (0,1,2,3...) - vector RDmintmp(num_ring); - vector RDmaxtmp(num_ring); - - if (span%2 == 1) - { - RDmintmp[0] = -((span-1)/2); - RDmaxtmp[0] = RDmintmp[0] + span - 1; - } - else - { - RDmintmp[0] = -(span/2); - RDmaxtmp[0] = RDmintmp[0] + span; - } + error(boost::format("construct_proj_data_info: span %d is too large for a scanner with %d rings") % span % num_ring); + if (max_delta < (span - 1) / 2) + error(boost::format("construct_proj_data_info: max_ring_difference %d has to be at least (span-1)/2, span is %d") % + max_delta % span); + + // Construct first a temporary list of min and max ring diff per segment (0,1,2,3...) + vector RDmintmp(num_ring); + vector RDmaxtmp(num_ring); + + if (span % 2 == 1) { + RDmintmp[0] = -((span - 1) / 2); + RDmaxtmp[0] = RDmintmp[0] + span - 1; + } else { + RDmintmp[0] = -(span / 2); + RDmaxtmp[0] = RDmintmp[0] + span; + } - int seg_num =0; - while (RDmaxtmp[seg_num] < max_delta) - { + int seg_num = 0; + while (RDmaxtmp[seg_num] < max_delta) { seg_num++; - RDmintmp[seg_num] = RDmaxtmp[seg_num-1] + 1; + RDmintmp[seg_num] = RDmaxtmp[seg_num - 1] + 1; RDmaxtmp[seg_num] = RDmintmp[seg_num] + span - 1; } // check if we went one too far - if (RDmaxtmp[seg_num] > max_delta) - { - if (max_delta < num_ring-1) - warning(boost::format("Creation of ProjDataInfo with span=%1% and max_delta=%2% leads to a 'smaller' last segment than the others (did you mean to set max_delta=%3%?).\n" - "This is fine, but note that in previous versions of STIR this last segment was dropped.") - % span % max_delta % RDmaxtmp[seg_num]); + if (RDmaxtmp[seg_num] > max_delta) { + if (max_delta < num_ring - 1) + warning(boost::format("Creation of ProjDataInfo with span=%1% and max_delta=%2% leads to a 'smaller' last segment than the " + "others (did you mean to set max_delta=%3%?).\n" + "This is fine, but note that in previous versions of STIR this last segment was dropped.") % + span % max_delta % RDmaxtmp[seg_num]); // Palak Wadwha changed this to max_delta to accomodate GE scanners, it is more general anyway. RDmaxtmp[seg_num] = max_delta; } const int max_seg_num = seg_num; - - VectorWithOffset num_axial_pos_per_segment(-max_seg_num,max_seg_num); - VectorWithOffset min_ring_difference(-max_seg_num,max_seg_num); - VectorWithOffset max_ring_difference(-max_seg_num,max_seg_num); - + + VectorWithOffset num_axial_pos_per_segment(-max_seg_num, max_seg_num); + VectorWithOffset min_ring_difference(-max_seg_num, max_seg_num); + VectorWithOffset max_ring_difference(-max_seg_num, max_seg_num); + min_ring_difference[0] = RDmintmp[0]; - max_ring_difference[0]= RDmaxtmp[0]; - - for(int i=1; i<=max_seg_num; i++) - { + max_ring_difference[0] = RDmaxtmp[0]; + + for (int i = 1; i <= max_seg_num; i++) { // KT 28/06/2001 make sure max_ring_diff>min_ring_diff for negative segments - max_ring_difference[-i]= -RDmintmp[i]; - max_ring_difference[i]= RDmaxtmp[i]; - min_ring_difference[-i]= -RDmaxtmp[i]; - min_ring_difference[i]= RDmintmp[i]; + max_ring_difference[-i] = -RDmintmp[i]; + max_ring_difference[i] = RDmaxtmp[i]; + min_ring_difference[-i] = -RDmaxtmp[i]; + min_ring_difference[i] = RDmintmp[i]; } - - if (span==1) - { + + if (span == 1) { num_axial_pos_per_segment[0] = num_ring; - for(int i=1; i<=max_seg_num; i++) - { - num_axial_pos_per_segment[i]= - num_axial_pos_per_segment[-i] = num_ring -i; + for (int i = 1; i <= max_seg_num; i++) { + num_axial_pos_per_segment[i] = num_axial_pos_per_segment[-i] = num_ring - i; + } + } else { + num_axial_pos_per_segment[0] = 2 * num_ring - 1; + for (int i = 1; i <= max_seg_num; i++) { + num_axial_pos_per_segment[i] = num_axial_pos_per_segment[-i] = (2 * num_ring - 1 - 2 * RDmintmp[i]); } } - else - { - num_axial_pos_per_segment[0] = 2*num_ring -1 ; - for( int i=1; i<=max_seg_num; i++) - { - num_axial_pos_per_segment[i] = - num_axial_pos_per_segment[-i] = (2*num_ring -1 - 2*RDmintmp[i]); - } - } - + const float bin_size = scanner->get_default_bin_size(); - - + if (arc_corrected) - return - new ProjDataInfoCylindricalArcCorr(scanner,bin_size, - num_axial_pos_per_segment, - min_ring_difference, - max_ring_difference, - num_views,num_tangential_poss); + return new ProjDataInfoCylindricalArcCorr(scanner, bin_size, num_axial_pos_per_segment, min_ring_difference, + max_ring_difference, num_views, num_tangential_poss, tof_mash_factor); else - return - new ProjDataInfoCylindricalNoArcCorr(scanner, - num_axial_pos_per_segment, - min_ring_difference, - max_ring_difference, - num_views,num_tangential_poss); - + return new ProjDataInfoCylindricalNoArcCorr(scanner, num_axial_pos_per_segment, min_ring_difference, max_ring_difference, + num_views, num_tangential_poss, tof_mash_factor); } unique_ptr -ProjDataInfo::construct_proj_data_info(const shared_ptr& scanner_sptr, - const int span, const int max_delta, - const int num_views, const int num_tangential_poss, - const bool arc_corrected) -{ - unique_ptr pdi(ProjDataInfoCTI(scanner_sptr, span, max_delta, num_views, num_tangential_poss, arc_corrected)); +ProjDataInfo::construct_proj_data_info(const shared_ptr& scanner_sptr, const int span, const int max_delta, + const int num_views, const int num_tangential_poss, const bool arc_corrected, + const int tof_mash_factor) { + unique_ptr pdi( + ProjDataInfoCTI(scanner_sptr, span, max_delta, num_views, num_tangential_poss, arc_corrected, tof_mash_factor)); return pdi; } // KT 28/06/2001 added arc_corrected flag +// NE 28/12/2016 added the tof_mash_factor ProjDataInfo* -ProjDataInfo::ProjDataInfoGE(const shared_ptr& scanner, - const int max_delta, - const int num_views, const int num_tangential_poss, - const bool arc_corrected) - - +ProjDataInfo::ProjDataInfoGE(const shared_ptr& scanner, const int max_delta, const int num_views, + const int num_tangential_poss, const bool arc_corrected, const int tof_mash_factor) + { /* mixed span case: segment 0 has ring diff -1,0,1, @@ -464,153 +504,113 @@ ProjDataInfo::ProjDataInfoGE(const shared_ptr& scanner, */ const int num_rings = scanner->get_num_rings(); const float bin_size = scanner->get_default_bin_size(); - - if(max_delta<1) + + if (max_delta < 1) error("ProjDataInfo::ProjDataInfoGE: can only handle max_delta>=1\n"); - const int max_segment_num = - max_delta==0? 0 : max_delta-1; - - VectorWithOffset num_axial_pos_per_segment(-max_segment_num,max_segment_num); - - VectorWithOffset min_ring_difference(-max_segment_num,max_segment_num); - VectorWithOffset max_ring_difference(-max_segment_num,max_segment_num); - - num_axial_pos_per_segment[0] = 2*num_rings-1; - min_ring_difference[0] = -1; + const int max_segment_num = max_delta == 0 ? 0 : max_delta - 1; + + VectorWithOffset num_axial_pos_per_segment(-max_segment_num, max_segment_num); + + VectorWithOffset min_ring_difference(-max_segment_num, max_segment_num); + VectorWithOffset max_ring_difference(-max_segment_num, max_segment_num); + + num_axial_pos_per_segment[0] = 2 * num_rings - 1; + min_ring_difference[0] = -1; max_ring_difference[0] = 1; - - for (int i=1; i<=max_segment_num; i++) - - { - num_axial_pos_per_segment[i]= - num_axial_pos_per_segment[-i]=num_rings-i-1; - - max_ring_difference[i]= - min_ring_difference[i]= i+1; - max_ring_difference[-i]= - min_ring_difference[-i]= -i-1; - + + for (int i = 1; i <= max_segment_num; i++) + + { + num_axial_pos_per_segment[i] = num_axial_pos_per_segment[-i] = num_rings - i - 1; + + max_ring_difference[i] = min_ring_difference[i] = i + 1; + max_ring_difference[-i] = min_ring_difference[-i] = -i - 1; } - - - + if (arc_corrected) - return - new ProjDataInfoCylindricalArcCorr(scanner,bin_size, - num_axial_pos_per_segment, - min_ring_difference, - max_ring_difference, - num_views,num_tangential_poss); + return new ProjDataInfoCylindricalArcCorr(scanner, bin_size, num_axial_pos_per_segment, min_ring_difference, + max_ring_difference, num_views, num_tangential_poss, tof_mash_factor); else - return - new ProjDataInfoCylindricalNoArcCorr(scanner, - num_axial_pos_per_segment, - min_ring_difference, - max_ring_difference, - num_views,num_tangential_poss); + return new ProjDataInfoCylindricalNoArcCorr(scanner, num_axial_pos_per_segment, min_ring_difference, max_ring_difference, + num_views, num_tangential_poss, tof_mash_factor); } - -ProjDataInfo* ProjDataInfo::ask_parameters() -{ +ProjDataInfo* +ProjDataInfo::ask_parameters() { shared_ptr scanner_ptr(Scanner::ask_parameters()); - - const bool is_Advance = - scanner_ptr->get_type() == Scanner::Advance || - scanner_ptr->get_type() == Scanner::DiscoveryLS; - const bool is_DiscoveryST = - scanner_ptr->get_type() == Scanner::DiscoveryST; - const bool is_GE = - is_Advance || is_DiscoveryST; - - const int num_views = scanner_ptr->get_max_num_views()/ - ask_num("Mash factor for views",1, scanner_ptr->get_max_num_views(),1); - - const bool arc_corrected = - ask("Is the data arc-corrected?",true); - - const int num_tangential_poss= - ask_num("Number of tangential positions",1, - scanner_ptr->get_max_num_non_arccorrected_bins(), - arc_corrected - ? scanner_ptr->get_default_num_arccorrected_bins() - : scanner_ptr->get_max_num_non_arccorrected_bins()); - - int span = is_GE ? 0 : 1; - span = - ask_num("Span value (use 0 for mixed-span case of the Advance) : ", 0,scanner_ptr->get_num_rings()-1,span); - - - const int max_delta = ask_num("Max. ring difference acquired : ", - 0, - scanner_ptr->get_num_rings()-1, - is_Advance ? 11 : scanner_ptr->get_num_rings()-1); - - - ProjDataInfo * pdi_ptr = - span==0 - ? ProjDataInfoGE(scanner_ptr,max_delta,num_views,num_tangential_poss,arc_corrected) - : ProjDataInfoCTI(scanner_ptr,span,max_delta,num_views,num_tangential_poss,arc_corrected); - - cout << pdi_ptr->parameter_info() <get_type() == Scanner::Advance || scanner_ptr->get_type() == Scanner::DiscoveryLS; + const bool is_DiscoveryST = scanner_ptr->get_type() == Scanner::DiscoveryST; + const bool is_GE = is_Advance || is_DiscoveryST; + + const int num_views = + scanner_ptr->get_max_num_views() / ask_num("Mash factor for views", 1, scanner_ptr->get_max_num_views(), 1); + + const int tof_mash_factor = + scanner_ptr->is_tof_ready() ? ask_num("Time-of-flight mash factor:", 0, scanner_ptr->get_max_num_timing_poss(), 25) : 0; + + const bool arc_corrected = ask("Is the data arc-corrected?", true); + + const int num_tangential_poss = ask_num("Number of tangential positions", 1, scanner_ptr->get_max_num_non_arccorrected_bins(), + arc_corrected ? scanner_ptr->get_default_num_arccorrected_bins() + : scanner_ptr->get_max_num_non_arccorrected_bins()); + + int span = is_GE ? 0 : 1; + span = ask_num("Span value (use 0 for mixed-span case of the Advance) : ", 0, scanner_ptr->get_num_rings() - 1, span); + + const int max_delta = ask_num("Max. ring difference acquired : ", 0, scanner_ptr->get_num_rings() - 1, + is_Advance ? 11 : scanner_ptr->get_num_rings() - 1); + + ProjDataInfo* pdi_ptr = + span == 0 ? ProjDataInfoGE(scanner_ptr, max_delta, num_views, num_tangential_poss, arc_corrected, tof_mash_factor) + : ProjDataInfoCTI(scanner_ptr, span, max_delta, num_views, num_tangential_poss, arc_corrected, tof_mash_factor); + + cout << pdi_ptr->parameter_info() << endl; return pdi_ptr; - } /*! Default implementation checks common variables. Needs to be overloaded. */ bool -ProjDataInfo:: -blindly_equals(const root_type * const that) const -{ - const root_type & proj = *that; - - return - (get_min_segment_num()==proj.get_min_segment_num()) && - (get_max_segment_num()==proj.get_max_segment_num()) && - (get_min_view_num()==proj.get_min_view_num()) && - (get_max_view_num()==proj.get_max_view_num()) && - (get_min_tangential_pos_num() ==proj.get_min_tangential_pos_num())&& - (get_max_tangential_pos_num() ==proj.get_max_tangential_pos_num())&& - equal(min_axial_pos_per_seg.begin(), min_axial_pos_per_seg.end(), proj.min_axial_pos_per_seg.begin())&& - equal(max_axial_pos_per_seg.begin(), max_axial_pos_per_seg.end(), proj.max_axial_pos_per_seg.begin())&& - (*get_scanner_ptr()== *(proj.get_scanner_ptr()))&& - (get_bed_position_horizontal()==proj.get_bed_position_horizontal())&& - (get_bed_position_vertical()==proj.get_bed_position_vertical()); +ProjDataInfo::blindly_equals(const root_type* const that) const { + const root_type& proj = *that; + + return (get_min_segment_num() == proj.get_min_segment_num()) && (get_max_segment_num() == proj.get_max_segment_num()) && + (get_min_view_num() == proj.get_min_view_num()) && (get_max_view_num() == proj.get_max_view_num()) && + (get_min_tangential_pos_num() == proj.get_min_tangential_pos_num()) && + (get_max_tangential_pos_num() == proj.get_max_tangential_pos_num()) && + (proj.is_tof_data() && is_tof_data() + ? (get_min_tof_pos_num() == proj.get_min_tof_pos_num()) && (get_max_tof_pos_num() == proj.get_max_tof_pos_num()) + : true) && + equal(min_axial_pos_per_seg.begin(), min_axial_pos_per_seg.end(), proj.min_axial_pos_per_seg.begin()) && + equal(max_axial_pos_per_seg.begin(), max_axial_pos_per_seg.end(), proj.max_axial_pos_per_seg.begin()) && + (*get_scanner_ptr() == *(proj.get_scanner_ptr())) && + (get_bed_position_horizontal() == proj.get_bed_position_horizontal()) && + (get_bed_position_vertical() == proj.get_bed_position_vertical()); } bool -ProjDataInfo:: -operator ==(const root_type& that) const -{ - return - typeid(*this) == typeid(that) && - (this == &that || - this->blindly_equals(&that) - ); +ProjDataInfo::operator==(const root_type& that) const { + return typeid(*this) == typeid(that) && (this == &that || this->blindly_equals(&that)); } bool -ProjDataInfo:: -operator !=(const root_type& that) const -{ +ProjDataInfo::operator!=(const root_type& that) const { return !((*this) == that); } /*! \return \c true only if the types are the same, they are equal, or the range for the - segments, axial and tangential positions is at least as large. + TOF, segments, axial and tangential positions is at least as large. \warning Currently view ranges have to be identical. */ bool -ProjDataInfo:: -operator>=(const ProjDataInfo& proj_data_info) const -{ +ProjDataInfo::operator>=(const ProjDataInfo& proj_data_info) const { if (typeid(*this) != typeid(proj_data_info)) return false; @@ -622,37 +622,37 @@ operator>=(const ProjDataInfo& proj_data_info) const if (proj_data_info.get_max_segment_num() > larger_proj_data_info.get_max_segment_num() || proj_data_info.get_min_segment_num() < larger_proj_data_info.get_min_segment_num() || proj_data_info.get_max_tangential_pos_num() > larger_proj_data_info.get_max_tangential_pos_num() || - proj_data_info.get_min_tangential_pos_num() < larger_proj_data_info.get_min_tangential_pos_num()) + proj_data_info.get_min_tangential_pos_num() < larger_proj_data_info.get_min_tangential_pos_num() || + ((proj_data_info.get_min_tof_pos_num() < larger_proj_data_info.get_min_tof_pos_num() || + proj_data_info.get_max_tof_pos_num() > larger_proj_data_info.get_max_tof_pos_num()) && + (proj_data_info.is_tof_data() && larger_proj_data_info.is_tof_data()))) return false; - for (int segment_num=proj_data_info.get_min_segment_num(); - segment_num<=proj_data_info.get_max_segment_num(); - ++segment_num) - { - if (proj_data_info.get_max_axial_pos_num(segment_num) > larger_proj_data_info.get_max_axial_pos_num(segment_num) || - proj_data_info.get_min_axial_pos_num(segment_num) < larger_proj_data_info.get_min_axial_pos_num(segment_num)) - return false; - } + for (int segment_num = proj_data_info.get_min_segment_num(); segment_num <= proj_data_info.get_max_segment_num(); + ++segment_num) { + if (proj_data_info.get_max_axial_pos_num(segment_num) > larger_proj_data_info.get_max_axial_pos_num(segment_num) || + proj_data_info.get_min_axial_pos_num(segment_num) < larger_proj_data_info.get_min_axial_pos_num(segment_num)) + return false; + } // now check all the rest. That's a bit hard, so what we'll do is reduce the sizes of the larger one // to the ones from proj_data_info (which we can safely do as we've checked that they're smaller) // and then check for equality. // This will check stuff like scanners etc etc... shared_ptr smaller_proj_data_info_sptr(larger_proj_data_info.clone()); - smaller_proj_data_info_sptr->reduce_segment_range(proj_data_info.get_min_segment_num(), proj_data_info.get_max_segment_num()); + smaller_proj_data_info_sptr->reduce_segment_range(proj_data_info.get_min_segment_num(), proj_data_info.get_max_segment_num()); smaller_proj_data_info_sptr->set_min_tangential_pos_num(proj_data_info.get_min_tangential_pos_num()); smaller_proj_data_info_sptr->set_max_tangential_pos_num(proj_data_info.get_max_tangential_pos_num()); + // smaller_proj_data_info_sptr->set_min_tof_pos_num(proj_data_info.get_min_tof_pos_num()); + // smaller_proj_data_info_sptr->set_max_tof_pos_num(proj_data_info.get_max_tof_pos_num()); - for (int segment_num=proj_data_info.get_min_segment_num(); - segment_num<=proj_data_info.get_max_segment_num(); - ++segment_num) - { - smaller_proj_data_info_sptr->set_min_axial_pos_num(proj_data_info.get_min_axial_pos_num(segment_num), segment_num); - smaller_proj_data_info_sptr->set_max_axial_pos_num(proj_data_info.get_max_axial_pos_num(segment_num), segment_num); - } + for (int segment_num = proj_data_info.get_min_segment_num(); segment_num <= proj_data_info.get_max_segment_num(); + ++segment_num) { + smaller_proj_data_info_sptr->set_min_axial_pos_num(proj_data_info.get_min_axial_pos_num(segment_num), segment_num); + smaller_proj_data_info_sptr->set_max_axial_pos_num(proj_data_info.get_max_axial_pos_num(segment_num), segment_num); + } return (proj_data_info == *smaller_proj_data_info_sptr); } END_NAMESPACE_STIR - diff --git a/src/buildblock/ProjDataInfoCylindrical.cxx b/src/buildblock/ProjDataInfoCylindrical.cxx index ef6bb8ee2e..0d3ecf5e9e 100644 --- a/src/buildblock/ProjDataInfoCylindrical.cxx +++ b/src/buildblock/ProjDataInfoCylindrical.cxx @@ -2,7 +2,8 @@ Copyright (C) 2000 PARAPET partners Copyright (C) 2000 - 2009-10-18 Hammersmith Imanet Ltd Copyright (C) 2011, Kris Thielemans - Copyright (C) 2013, 2018, University College London + Copyright (C) 2013, 2017, 2018, University College London + Copyright (C) 2016, University of Hull This file is part of STIR. @@ -25,6 +26,7 @@ \brief Non-inline implementations of stir::ProjDataInfoCylindrical + \author Nikos Efthimiou \author Kris Thielemans \author Sanida Mustafovic \author PARAPET project @@ -35,9 +37,9 @@ #include "stir/Array.h" #include #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif #include "stir/round.h" @@ -58,92 +60,73 @@ using std::vector; START_NAMESPACE_STIR -ProjDataInfoCylindrical:: -ProjDataInfoCylindrical() -{} - - -ProjDataInfoCylindrical:: -ProjDataInfoCylindrical(const shared_ptr& scanner_ptr, - const VectorWithOffset& num_axial_pos_per_segment, - const VectorWithOffset& min_ring_diff_v, - const VectorWithOffset& max_ring_diff_v, - const int num_views,const int num_tangential_poss) - :ProjDataInfo(scanner_ptr,num_axial_pos_per_segment, - num_views,num_tangential_poss), - min_ring_diff(min_ring_diff_v), - max_ring_diff(max_ring_diff_v) -{ - - azimuthal_angle_sampling = static_cast(_PI/num_views); - ring_radius.resize(0,0); +ProjDataInfoCylindrical::ProjDataInfoCylindrical() {} + +ProjDataInfoCylindrical::ProjDataInfoCylindrical(const shared_ptr& scanner_ptr, + const VectorWithOffset& num_axial_pos_per_segment, + const VectorWithOffset& min_ring_diff_v, + const VectorWithOffset& max_ring_diff_v, const int num_views, + const int num_tangential_poss) + : ProjDataInfo(scanner_ptr, num_axial_pos_per_segment, num_views, num_tangential_poss), min_ring_diff(min_ring_diff_v), + max_ring_diff(max_ring_diff_v) { + + azimuthal_angle_sampling = static_cast(_PI / num_views); + ring_radius.resize(0, 0); ring_radius[0] = get_scanner_ptr()->get_effective_ring_radius(); - ring_spacing= get_scanner_ptr()->get_ring_spacing() ; + ring_spacing = get_scanner_ptr()->get_ring_spacing(); // TODO this info should probably be provided via the constructor, or at // least by Scanner. - sampling_corresponds_to_physical_rings = - scanner_ptr->get_type() != Scanner::HiDAC; - + sampling_corresponds_to_physical_rings = scanner_ptr->get_type() != Scanner::HiDAC; assert(min_ring_diff.get_length() == max_ring_diff.get_length()); assert(min_ring_diff.get_length() == num_axial_pos_per_segment.get_length()); // check min,max ring diff { - for (int segment_num=get_min_segment_num(); segment_num<=get_max_segment_num(); ++segment_num) - if (min_ring_diff[segment_num]> max_ring_diff[segment_num]) - { + for (int segment_num = get_min_segment_num(); segment_num <= get_max_segment_num(); ++segment_num) + if (min_ring_diff[segment_num] > max_ring_diff[segment_num]) { warning("ProjDataInfoCylindrical: min_ring_difference %d is larger than max_ring_difference %d for segment %d. " - "Swapping them around", - min_ring_diff[segment_num], max_ring_diff[segment_num], segment_num); + "Swapping them around", + min_ring_diff[segment_num], max_ring_diff[segment_num], segment_num); swap(min_ring_diff[segment_num], max_ring_diff[segment_num]); } } - initialise_ring_diff_arrays(); + initialise_ring_diff_arrays(); } void -ProjDataInfoCylindrical:: -initialise_ring_diff_arrays() const -{ +ProjDataInfoCylindrical::initialise_ring_diff_arrays() const { // check min,max ring diff { // check is necessary here again because of set_min_ring_difference() // we do not swap here because that would require the min/max_ring_diff arrays to be mutable as well - for (int segment_num=get_min_segment_num(); segment_num<=get_max_segment_num(); ++segment_num) - if (min_ring_diff[segment_num]> max_ring_diff[segment_num]) - { + for (int segment_num = get_min_segment_num(); segment_num <= get_max_segment_num(); ++segment_num) + if (min_ring_diff[segment_num] > max_ring_diff[segment_num]) { error("ProjDataInfoCylindrical: min_ring_difference %d is larger than " - "max_ring_difference %d for segment %d.", - min_ring_diff[segment_num], max_ring_diff[segment_num], segment_num); + "max_ring_difference %d for segment %d.", + min_ring_diff[segment_num], max_ring_diff[segment_num], segment_num); } } - // initialise m_offset - { - m_offset = - VectorWithOffset(get_min_segment_num(),get_max_segment_num()); - + // initialise m_offset + { + m_offset = VectorWithOffset(get_min_segment_num(), get_max_segment_num()); + /* m_offsets are found by requiring get_m(..., min_axial_pos_num,...) == - get_m(..., max_axial_pos_num,...) */ - for (int segment_num=get_min_segment_num(); segment_num<=get_max_segment_num(); ++segment_num) - { + for (int segment_num = get_min_segment_num(); segment_num <= get_max_segment_num(); ++segment_num) { m_offset[segment_num] = - ((get_max_axial_pos_num(segment_num) + get_min_axial_pos_num(segment_num)) - *get_axial_sampling(segment_num) - )/2; + ((get_max_axial_pos_num(segment_num) + get_min_axial_pos_num(segment_num)) * get_axial_sampling(segment_num)) / 2; } } - // initialise ax_pos_num_offset - if (sampling_corresponds_to_physical_rings) - { + // initialise ax_pos_num_offset + if (sampling_corresponds_to_physical_rings) { const int num_rings = get_scanner_ptr()->get_num_rings(); - ax_pos_num_offset = - VectorWithOffset(get_min_segment_num(),get_max_segment_num()); - + ax_pos_num_offset = VectorWithOffset(get_min_segment_num(), get_max_segment_num()); + /* ax_pos_num will be determined by looking at ring1+ring2. This also works for axially compressed data (i.e. span) as ring1+ring2 is constant for all ring-pairs combined into 1 @@ -155,90 +138,75 @@ initialise_ring_diff_arrays() const ring1 = get_m(bin)/ring_spacing - ring_diff/2 + (num_rings-1)/2 This follows from the fact that get_m() returns the z position in millimeter of the middle of the LOR w.r.t. the middle of the scanner. - The (num_rings-1)/2 shifts the origin such that the first ring has + The (num_rings-1)/2 shifts the origin such that the first ring has ring_num==0. From the above, it follows that ring1+ring2=2*get_m(bin)/ring_spacing + (num_rings-1) Finally, we use the formula for get_m to obtain ring1+ring2=2*ax_pos_num/get_num_axial_poss_per_ring_inc(segment_num) - -2*m_offset[segment_num]/ring_spacing + (num_rings-1) + -2*m_offset[segment_num]/ring_spacing + (num_rings-1) Solving this for ax_pos_num: ax_pos_num = (ring1+ring2-(num_rings-1) + 2*m_offset[segment_num]/ring_spacing - ) * get_num_axial_poss_per_ring_inc(segment_num)/2 + ) * get_num_axial_poss_per_ring_inc(segment_num)/2 We could plug m_offset in to obtain ax_pos_num = (ring1+ring2-(num_rings-1) - ) * get_num_axial_poss_per_ring_inc(segment_num)/2. + ) * get_num_axial_poss_per_ring_inc(segment_num)/2. + - (get_max_axial_pos_num(segment_num) - + get_min_axial_pos_num(segment_num) )/2. + (get_max_axial_pos_num(segment_num) + + get_min_axial_pos_num(segment_num) )/2. this formula is easy to understand, but we don't use it as at some point somebody might change m_offset - and forget to change this code... + and forget to change this code... (also, the form above would need float division and then rounding) */ - for (int segment_num=get_min_segment_num(); segment_num<=get_max_segment_num(); ++segment_num) - { - ax_pos_num_offset[segment_num] = - round((num_rings-1) - 2*m_offset[segment_num]/ring_spacing); + for (int segment_num = get_min_segment_num(); segment_num <= get_max_segment_num(); ++segment_num) { + ax_pos_num_offset[segment_num] = round((num_rings - 1) - 2 * m_offset[segment_num] / ring_spacing); // check that it was integer - if (fabs(ax_pos_num_offset[segment_num] - - ((num_rings-1) - 2*m_offset[segment_num]/ring_spacing)) > 1E-4) - { - error("ProjDataInfoCylindrical: in segment %d, the axial positions\n" - "do not correspond to the usual locations between physical rings.\n" - "This is suspicious and can make things go wrong in STIR, so I abort.\n" - "Check the number of axial positions in this segment.", - segment_num); - } - - if (get_num_axial_poss_per_ring_inc(segment_num)==1) - { - // check that we'll get an integer ax_pos_num, i.e. - // (ring1+ring2 - ax_pos_num_offset) has to be even, for any - // ring1,ring2 in the segment, i.e ring1-ring2 = ring_diff, so - // ring1+ring2 = 2*ring2 + ring_diff - assert(get_min_ring_difference(segment_num) == - get_max_ring_difference(segment_num)); - if ((get_max_ring_difference(segment_num) - - ax_pos_num_offset[segment_num]) % 2 != 0) - warning("ProjDataInfoCylindrical: the number of axial positions in " - "segment %d is such that current conventions will place " - "the LORs shifted with respect to the physical rings.", - segment_num); + if (fabs(ax_pos_num_offset[segment_num] - ((num_rings - 1) - 2 * m_offset[segment_num] / ring_spacing)) > 1E-4) { + error("ProjDataInfoCylindrical: in segment %d, the axial positions\n" + "do not correspond to the usual locations between physical rings.\n" + "This is suspicious and can make things go wrong in STIR, so I abort.\n" + "Check the number of axial positions in this segment.", + segment_num); + } + + if (get_num_axial_poss_per_ring_inc(segment_num) == 1) { + // check that we'll get an integer ax_pos_num, i.e. + // (ring1+ring2 - ax_pos_num_offset) has to be even, for any + // ring1,ring2 in the segment, i.e ring1-ring2 = ring_diff, so + // ring1+ring2 = 2*ring2 + ring_diff + assert(get_min_ring_difference(segment_num) == get_max_ring_difference(segment_num)); + if ((get_max_ring_difference(segment_num) - ax_pos_num_offset[segment_num]) % 2 != 0) + warning("ProjDataInfoCylindrical: the number of axial positions in " + "segment %d is such that current conventions will place " + "the LORs shifted with respect to the physical rings.", + segment_num); } } } // initialise ring_diff_to_segment_num - if (sampling_corresponds_to_physical_rings) - { - const int min_ring_difference = - *min_element(min_ring_diff.begin(), min_ring_diff.end()); - const int max_ring_difference = - *max_element(max_ring_diff.begin(), max_ring_diff.end()); + if (sampling_corresponds_to_physical_rings) { + const int min_ring_difference = *min_element(min_ring_diff.begin(), min_ring_diff.end()); + const int max_ring_difference = *max_element(max_ring_diff.begin(), max_ring_diff.end()); // set ring_diff_to_segment_num to appropriate size - // in principle, the max ring difference would be scanner.num_rings-1, but - // in case someone is up to strange things, we take the max of this value + // in principle, the max ring difference would be scanner.num_rings-1, but + // in case someone is up to strange things, we take the max of this value // with the max_ring_difference as given in the file - ring_diff_to_segment_num = - VectorWithOffset(min(min_ring_difference, -(get_scanner_ptr()->get_num_rings()-1)), - max(max_ring_difference, get_scanner_ptr()->get_num_rings()-1)); + ring_diff_to_segment_num = VectorWithOffset(min(min_ring_difference, -(get_scanner_ptr()->get_num_rings() - 1)), + max(max_ring_difference, get_scanner_ptr()->get_num_rings() - 1)); // first set all to impossible value // warning: get_segment_num_for_ring_difference relies on the fact that this value // is larger than get_max_segment_num() - ring_diff_to_segment_num.fill(get_max_segment_num()+1); + ring_diff_to_segment_num.fill(get_max_segment_num() + 1); - for(int ring_diff=min_ring_difference; ring_diff <= max_ring_difference; ++ring_diff) - { + for (int ring_diff = min_ring_difference; ring_diff <= max_ring_difference; ++ring_diff) { int segment_num; - for (segment_num=get_min_segment_num(); segment_num<=get_max_segment_num(); ++segment_num) - { - if (ring_diff >= min_ring_diff[segment_num] && - ring_diff <= max_ring_diff[segment_num]) - { + for (segment_num = get_min_segment_num(); segment_num <= get_max_segment_num(); ++segment_num) { + if (ring_diff >= min_ring_diff[segment_num] && ring_diff <= max_ring_diff[segment_num]) { #if 0 std::cerr << "ring diff " << ring_diff << " stored in s:" << segment_num << std::endl; #endif @@ -246,33 +214,25 @@ initialise_ring_diff_arrays() const break; } } - if (segment_num>get_max_segment_num()) - { - warning("ProjDataInfoCylindrical: ring difference %d does not belong to a segment", - ring_diff); + if (segment_num > get_max_segment_num()) { + warning("ProjDataInfoCylindrical: ring difference %d does not belong to a segment", ring_diff); } } } // initialise segment_axial_pos_to_ring1_plus_ring2 - if (sampling_corresponds_to_physical_rings) - { - segment_axial_pos_to_ring1_plus_ring2 = - VectorWithOffset >(get_min_segment_num(), get_max_segment_num()); - for (int s_num=get_min_segment_num(); s_num<=get_max_segment_num(); ++s_num) - { + if (sampling_corresponds_to_physical_rings) { + segment_axial_pos_to_ring1_plus_ring2 = VectorWithOffset>(get_min_segment_num(), get_max_segment_num()); + for (int s_num = get_min_segment_num(); s_num <= get_max_segment_num(); ++s_num) { const int min_ax_pos_num = get_min_axial_pos_num(s_num); const int max_ax_pos_num = get_max_axial_pos_num(s_num); segment_axial_pos_to_ring1_plus_ring2[s_num].grow(min_ax_pos_num, max_ax_pos_num); - for (int ax_pos_num=min_ax_pos_num; ax_pos_num<=max_ax_pos_num; ++ax_pos_num) - { - // see documentation above for formulas - const float ring1_plus_ring2_float = - 2*ax_pos_num/get_num_axial_poss_per_ring_inc(s_num) - -2*m_offset[s_num]/ring_spacing + (get_scanner_ptr()->get_num_rings()-1); - const int ring1_plus_ring2 = - round(ring1_plus_ring2_float); + for (int ax_pos_num = min_ax_pos_num; ax_pos_num <= max_ax_pos_num; ++ax_pos_num) { + // see documentation above for formulas + const float ring1_plus_ring2_float = 2 * ax_pos_num / get_num_axial_poss_per_ring_inc(s_num) - + 2 * m_offset[s_num] / ring_spacing + (get_scanner_ptr()->get_num_rings() - 1); + const int ring1_plus_ring2 = round(ring1_plus_ring2_float); // check that it was integer - assert(fabs(ring1_plus_ring2 - ring1_plus_ring2_float) < 1E-4) ; + assert(fabs(ring1_plus_ring2 - ring1_plus_ring2_float) < 1E-4); segment_axial_pos_to_ring1_plus_ring2[s_num][ax_pos_num] = ring1_plus_ring2; } } @@ -284,33 +244,24 @@ initialise_ring_diff_arrays() const ring_diff_arrays_computed = true; } -/*! Default implementation checks common variables. Needs to be overloaded. +/*! Default implementation checks common variables. Needs to be overloaded. */ bool -ProjDataInfoCylindrical:: -blindly_equals(const root_type * const that) const -{ +ProjDataInfoCylindrical::blindly_equals(const root_type* const that) const { if (!base_type::blindly_equals(that)) return false; const self_type& proj_data_info = static_cast(*that); - const Array<1,float> tmp(this->ring_radius - proj_data_info.ring_radius); - return - fabs(this->azimuthal_angle_sampling - proj_data_info.azimuthal_angle_sampling) < 0.05F && - norm(tmp) < 0.05F && - this->sampling_corresponds_to_physical_rings == proj_data_info.sampling_corresponds_to_physical_rings && - fabs(this->ring_spacing - proj_data_info.ring_spacing) < 0.05F && - this->min_ring_diff == proj_data_info.min_ring_diff && - this->max_ring_diff == proj_data_info.max_ring_diff; + const Array<1, float> tmp(this->ring_radius - proj_data_info.ring_radius); + return fabs(this->azimuthal_angle_sampling - proj_data_info.azimuthal_angle_sampling) < 0.05F && norm(tmp) < 0.05F && + this->sampling_corresponds_to_physical_rings == proj_data_info.sampling_corresponds_to_physical_rings && + fabs(this->ring_spacing - proj_data_info.ring_spacing) < 0.05F && this->min_ring_diff == proj_data_info.min_ring_diff && + this->max_ring_diff == proj_data_info.max_ring_diff; } void -ProjDataInfoCylindrical:: -get_ring_pair_for_segment_axial_pos_num(int& ring1, - int& ring2, - const int segment_num, - const int axial_pos_num) const -{ +ProjDataInfoCylindrical::get_ring_pair_for_segment_axial_pos_num(int& ring1, int& ring2, const int segment_num, + const int axial_pos_num) const { if (!sampling_corresponds_to_physical_rings) error("ProjDataInfoCylindrical::get_ring_pair_for_segment_axial_pos_num does not work for this type of sampled data"); // can do only span=1 at the moment @@ -320,106 +271,81 @@ get_ring_pair_for_segment_axial_pos_num(int& ring1, this->initialise_ring_diff_arrays_if_not_done_yet(); const int ring_diff = get_max_ring_difference(segment_num); - const int ring1_plus_ring2= segment_axial_pos_to_ring1_plus_ring2[segment_num][axial_pos_num]; + const int ring1_plus_ring2 = segment_axial_pos_to_ring1_plus_ring2[segment_num][axial_pos_num]; // KT 01/08/2002 swapped rings - ring1 = (ring1_plus_ring2 - ring_diff)/2; - ring2 = (ring1_plus_ring2 + ring_diff)/2; - assert((ring1_plus_ring2 + ring_diff)%2 == 0); - assert((ring1_plus_ring2 - ring_diff)%2 == 0); + ring1 = (ring1_plus_ring2 - ring_diff) / 2; + ring2 = (ring1_plus_ring2 + ring_diff) / 2; + assert((ring1_plus_ring2 + ring_diff) % 2 == 0); + assert((ring1_plus_ring2 - ring_diff) % 2 == 0); } - void -ProjDataInfoCylindrical:: -set_azimuthal_angle_sampling(const float angle_v) -{ - azimuthal_angle_sampling = angle_v; +ProjDataInfoCylindrical::set_azimuthal_angle_sampling(const float angle_v) { + azimuthal_angle_sampling = angle_v; } -//void -//ProjDataInfoCylindrical:: -//set_axial_sampling(const float samp_v, int segment_num) +// void +// ProjDataInfoCylindrical:: +// set_axial_sampling(const float samp_v, int segment_num) //{axial_sampling = samp_v;} - void -ProjDataInfoCylindrical:: -set_num_views(const int new_num_views) -{ - const float old_azimuthal_angle_range = - this->get_azimuthal_angle_sampling() * this->get_num_views(); +ProjDataInfoCylindrical::set_num_views(const int new_num_views) { + const float old_azimuthal_angle_range = this->get_azimuthal_angle_sampling() * this->get_num_views(); base_type::set_num_views(new_num_views); - this->azimuthal_angle_sampling = old_azimuthal_angle_range/this->get_num_views(); + this->azimuthal_angle_sampling = old_azimuthal_angle_range / this->get_num_views(); } void -ProjDataInfoCylindrical:: -set_min_ring_difference( int min_ring_diff_v, int segment_num) -{ +ProjDataInfoCylindrical::set_min_ring_difference(int min_ring_diff_v, int segment_num) { ring_diff_arrays_computed = false; min_ring_diff[segment_num] = min_ring_diff_v; } void -ProjDataInfoCylindrical:: -set_max_ring_difference( int max_ring_diff_v, int segment_num) -{ +ProjDataInfoCylindrical::set_max_ring_difference(int max_ring_diff_v, int segment_num) { ring_diff_arrays_computed = false; max_ring_diff[segment_num] = max_ring_diff_v; } void -ProjDataInfoCylindrical:: -set_ring_spacing(float ring_spacing_v) -{ +ProjDataInfoCylindrical::set_ring_spacing(float ring_spacing_v) { ring_diff_arrays_computed = false; ring_spacing = ring_spacing_v; } void -ProjDataInfoCylindrical:: -allocate_segment_axial_pos_to_ring_pair() const -{ - segment_axial_pos_to_ring_pair = - VectorWithOffset > > - (get_min_segment_num(), get_max_segment_num()); - - for (int segment_num = get_min_segment_num(); - segment_num <= get_max_segment_num(); - ++segment_num) - { - segment_axial_pos_to_ring_pair[segment_num].grow(get_min_axial_pos_num(segment_num), - get_max_axial_pos_num(segment_num)); - } +ProjDataInfoCylindrical::allocate_segment_axial_pos_to_ring_pair() const { + segment_axial_pos_to_ring_pair = + VectorWithOffset>>(get_min_segment_num(), get_max_segment_num()); + + for (int segment_num = get_min_segment_num(); segment_num <= get_max_segment_num(); ++segment_num) { + segment_axial_pos_to_ring_pair[segment_num].grow(get_min_axial_pos_num(segment_num), get_max_axial_pos_num(segment_num)); + } } void -ProjDataInfoCylindrical:: -compute_segment_axial_pos_to_ring_pair(const int segment_num, const int axial_pos_num) const -{ +ProjDataInfoCylindrical::compute_segment_axial_pos_to_ring_pair(const int segment_num, const int axial_pos_num) const { shared_ptr new_el(new RingNumPairs); segment_axial_pos_to_ring_pair[segment_num][axial_pos_num] = new_el; - - RingNumPairs& table = - *segment_axial_pos_to_ring_pair[segment_num][axial_pos_num]; - table.reserve(get_max_ring_difference(segment_num) - - get_min_ring_difference(segment_num) + 1); + + RingNumPairs& table = *segment_axial_pos_to_ring_pair[segment_num][axial_pos_num]; + table.reserve(get_max_ring_difference(segment_num) - get_min_ring_difference(segment_num) + 1); /* We compute the lookup-table in a fancy way. - We could just as well have a simple loop over all ring pairs and check - if it belongs to this segment/axial_pos. + We could just as well have a simple loop over all ring pairs and check + if it belongs to this segment/axial_pos. The current way is a lot faster though. */ const int min_ring_diff = get_min_ring_difference(segment_num); const int max_ring_diff = get_max_ring_difference(segment_num); const int num_rings = get_scanner_ptr()->get_num_rings(); - /* ring1_plus_ring2 is the same for any ring pair that contributes to + /* ring1_plus_ring2 is the same for any ring pair that contributes to this particular segment_num, axial_pos_num. */ - const int ring1_plus_ring2= - segment_axial_pos_to_ring1_plus_ring2[segment_num][axial_pos_num]; + const int ring1_plus_ring2 = segment_axial_pos_to_ring1_plus_ring2[segment_num][axial_pos_num]; /* The ring_difference increments with 2 as the other ring differences do @@ -430,121 +356,164 @@ compute_segment_axial_pos_to_ring_pair(const int segment_num, const int axial_po is satisfied. You can check it by noting that the start_ring_diff%2 == (min_ring_diff + (min_ring_diff+ring1_plus_ring2)%2)%2 - == (2*min_ring_diff+ring1_plus_ring2)%2 - == ring1_plus_ring2%2 + == (2*min_ring_diff+ring1_plus_ring2)%2 + == ring1_plus_ring2%2 */ - for(int ring_diff = min_ring_diff + (min_ring_diff+ring1_plus_ring2)%2; - ring_diff <= max_ring_diff; - ring_diff+=2 ) - { - const int ring1 = (ring1_plus_ring2 - ring_diff)/2; - const int ring2 = (ring1_plus_ring2 + ring_diff)/2; - if (ring1<0 || ring2 < 0 || ring1>=num_rings || ring2 >= num_rings) - continue; - assert((ring1_plus_ring2 + ring_diff)%2 == 0); - assert((ring1_plus_ring2 - ring_diff)%2 == 0); - table.push_back(pair(ring1, ring2)); + for (int ring_diff = min_ring_diff + (min_ring_diff + ring1_plus_ring2) % 2; ring_diff <= max_ring_diff; ring_diff += 2) { + const int ring1 = (ring1_plus_ring2 - ring_diff) / 2; + const int ring2 = (ring1_plus_ring2 + ring_diff) / 2; + if (ring1 < 0 || ring2 < 0 || ring1 >= num_rings || ring2 >= num_rings) + continue; + assert((ring1_plus_ring2 + ring_diff) % 2 == 0); + assert((ring1_plus_ring2 - ring_diff) % 2 == 0); + table.push_back(pair(ring1, ring2)); #ifndef NDEBUG - int check_segment_num = 0, check_axial_pos_num = 0; - assert(get_segment_axial_pos_num_for_ring_pair(check_segment_num, - check_axial_pos_num, - ring1, - ring2) == - Succeeded::yes); - assert(check_segment_num == segment_num); - assert(check_axial_pos_num == axial_pos_num); + int check_segment_num = 0, check_axial_pos_num = 0; + assert(get_segment_axial_pos_num_for_ring_pair(check_segment_num, check_axial_pos_num, ring1, ring2) == Succeeded::yes); + assert(check_segment_num == segment_num); + assert(check_axial_pos_num == axial_pos_num); #endif - } + } +} + +void +ProjDataInfoCylindrical::set_tof_mash_factor(const int new_num) { + base_type::set_tof_mash_factor(new_num); + //! \todo N.E. Would be nice to have all the points of the scanner in cache. + // initialise_uncompressed_lor_as_point1point2(); } -void -ProjDataInfoCylindrical:: -set_num_axial_poss_per_segment(const VectorWithOffset& num_axial_poss_per_segment) -{ +void +ProjDataInfoCylindrical::set_num_axial_poss_per_segment(const VectorWithOffset& num_axial_poss_per_segment) { ProjDataInfo::set_num_axial_poss_per_segment(num_axial_poss_per_segment); ring_diff_arrays_computed = false; } -void -ProjDataInfoCylindrical:: -set_min_axial_pos_num(const int min_ax_pos_num, const int segment_num) -{ +void +ProjDataInfoCylindrical::set_min_axial_pos_num(const int min_ax_pos_num, const int segment_num) { ProjDataInfo::set_min_axial_pos_num(min_ax_pos_num, segment_num); ring_diff_arrays_computed = false; } - -void ProjDataInfoCylindrical:: -set_max_axial_pos_num(const int max_ax_pos_num, const int segment_num) -{ +void +ProjDataInfoCylindrical::set_max_axial_pos_num(const int max_ax_pos_num, const int segment_num) { ProjDataInfo::set_max_axial_pos_num(max_ax_pos_num, segment_num); ring_diff_arrays_computed = false; } void -ProjDataInfoCylindrical:: -reduce_segment_range(const int min_segment_num, const int max_segment_num) -{ +ProjDataInfoCylindrical::reduce_segment_range(const int min_segment_num, const int max_segment_num) { ProjDataInfo::reduce_segment_range(min_segment_num, max_segment_num); // reduce ring_diff arrays to new valid size - VectorWithOffset new_min_ring_diff(min_segment_num, max_segment_num); + VectorWithOffset new_min_ring_diff(min_segment_num, max_segment_num); VectorWithOffset new_max_ring_diff(min_segment_num, max_segment_num); - for (int segment_num = min_segment_num; segment_num<= max_segment_num; ++segment_num) - { + for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) { new_min_ring_diff[segment_num] = this->min_ring_diff[segment_num]; new_max_ring_diff[segment_num] = this->max_ring_diff[segment_num]; } this->min_ring_diff = new_min_ring_diff; this->max_ring_diff = new_max_ring_diff; - + // make sure other arrays will be updated if/when necessary this->ring_diff_arrays_computed = false; } - void -ProjDataInfoCylindrical:: -get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& lor, - const Bin& bin) const -{ +ProjDataInfoCylindrical::get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& lor, const Bin& bin) const { const float s_in_mm = get_s(bin); const float m_in_mm = get_m(bin); const float tantheta = get_tantheta(bin); const float phi = get_phi(bin); /* parametrisation of LOR is - X= s*cphi + a*sphi, - Y= s*sphi - a*cphi, + X= s*cphi + a*sphi, + Y= s*sphi - a*cphi, Z= m - a*tantheta find now min_a, max_a such that end-points intersect the ring - */ + */ assert(fabs(s_in_mm) < get_ring_radius()); - // a has to be such that X^2+Y^2 == R^2 - const float max_a = sqrt(square(get_ring_radius()) - square(s_in_mm)); - const float min_a = -max_a; - + // a has to be such that X^2+Y^2 == R^2 + const float max_a = sqrt(square(get_ring_radius()) - square(s_in_mm)); + const float min_a = -max_a; + /* start_point.x() = (s_in_mm*cphi + max_a*sphi); - start_point.y() = (s_in_mm*sphi - max_a*cphi); - start_point.z() = (m_in_mm - max_a*tantheta); - stop_point.x() = (s_in_mm*cphi + min_a*sphi); - stop_point.y() = (s_in_mm*sphi - min_a*cphi); - stop_point.z() = (m_in_mm - min_a*tantheta); + start_point.y() = (s_in_mm*sphi - max_a*cphi); + start_point.z() = (m_in_mm - max_a*tantheta); + stop_point.x() = (s_in_mm*cphi + min_a*sphi); + stop_point.y() = (s_in_mm*sphi - min_a*cphi); + stop_point.z() = (m_in_mm - min_a*tantheta); */ - const float z1 = (m_in_mm - max_a*tantheta); - const float z2 = (m_in_mm - min_a*tantheta); - - - lor = - LORInAxialAndNoArcCorrSinogramCoordinates(z1, z2, - phi, - asin(s_in_mm/get_ring_radius()), - get_ring_radius()); -} - + const float z1 = (m_in_mm - max_a * tantheta); + const float z2 = (m_in_mm - min_a * tantheta); + + lor = LORInAxialAndNoArcCorrSinogramCoordinates(z1, z2, phi, asin(s_in_mm / get_ring_radius()), get_ring_radius(), + false); // needs to set "swapped" to false given above code +} + +void +ProjDataInfoCylindrical::get_LOR_as_two_points(CartesianCoordinate3D& coord_1, CartesianCoordinate3D& coord_2, + const Bin& bin) const { + const float s_in_mm = get_s(bin); + const float m_in_mm = get_m(bin); + const float tantheta = get_tantheta(bin); + const float phi = get_phi(bin); + /* parametrisation of LOR is + X= s*cphi + a*sphi, + Y= s*sphi - a*cphi, + Z= m - a*tantheta + find now min_a, max_a such that end-points intersect the ring +*/ + assert(fabs(s_in_mm) < get_ring_radius()); + // a has to be such that X^2+Y^2 == R^2 + const float max_a = sqrt(square(get_ring_radius()) - square(s_in_mm)); + const float min_a = -max_a; + + coord_1.x() = s_in_mm * cos(phi) + min_a * sin(phi); + coord_1.y() = s_in_mm * sin(phi) - max_a * cos(phi); + coord_1.z() = m_in_mm - max_a * tantheta; + + coord_2.x() = s_in_mm * cos(phi) + max_a * sin(phi); + coord_2.y() = s_in_mm * sin(phi) - min_a * cos(phi); + coord_2.z() = m_in_mm - min_a * tantheta; + + if (bin.timing_pos_num() < 0) + std::swap(coord_1, coord_2); +} + +void +ProjDataInfoCylindrical::get_LOR_as_two_points_alt(CartesianCoordinate3D& coord_1, CartesianCoordinate3D& coord_2, + const int det1, const int det2, const int ring1, const int ring2, + const int timing_pos) const { + const int num_detectors_per_ring = get_scanner_ptr()->get_num_detectors_per_ring(); + + float h_scanner_height = ((get_scanner_ptr()->get_ring_spacing() - 1) * get_scanner_ptr()->get_num_rings()) / 2.F; + + // although code maybe doesn't really need the following, + // asserts in the LOR code will break if these conditions are not satisfied. + assert(0 <= det1); + assert(det1 < num_detectors_per_ring); + assert(0 <= det2); + assert(det2 < num_detectors_per_ring); + + LORInCylinderCoordinates cyl_coords(get_scanner_ptr()->get_inner_ring_radius()); + + cyl_coords.p1().psi() = static_cast((2. * _PI / num_detectors_per_ring) * (det1)); + cyl_coords.p2().psi() = static_cast((2. * _PI / num_detectors_per_ring) * (det2)); + + cyl_coords.p1().z() = ring1 * get_scanner_ptr()->get_ring_spacing() - h_scanner_height; + cyl_coords.p2().z() = ring2 * get_scanner_ptr()->get_ring_spacing() - h_scanner_height; + + LORAs2Points lor(cyl_coords); + coord_1 = lor.p1(); + coord_2 = lor.p2(); + + if (timing_pos < 0) + std::swap(coord_1, coord_2); +} + string -ProjDataInfoCylindrical::parameter_info() const -{ +ProjDataInfoCylindrical::parameter_info() const { #ifdef BOOST_NO_STRINGSTREAM // dangerous for out-of-range, but 'old-style' ostrstream seems to need this @@ -552,15 +521,14 @@ ProjDataInfoCylindrical::parameter_info() const ostrstream s(str, 30000); #else std::ostringstream s; -#endif +#endif s << ProjDataInfo::parameter_info(); - s << "Azimuthal angle increment (deg): " << get_azimuthal_angle_sampling()*180/_PI << '\n'; - s << "Azimuthal angle extent (deg): " << fabs(get_azimuthal_angle_sampling())*get_num_views()*180/_PI << '\n'; + s << "Azimuthal angle increment (deg): " << get_azimuthal_angle_sampling() * 180 / _PI << '\n'; + s << "Azimuthal angle extent (deg): " << fabs(get_azimuthal_angle_sampling()) * get_num_views() * 180 / _PI << '\n'; s << "ring differences per segment: \n"; - for (int segment_num=get_min_segment_num(); segment_num<=get_max_segment_num(); ++segment_num) - { - s << '(' << min_ring_diff[segment_num] << ',' << max_ring_diff[segment_num] <<')'; + for (int segment_num = get_min_segment_num(); segment_num <= get_max_segment_num(); ++segment_num) { + s << '(' << min_ring_diff[segment_num] << ',' << max_ring_diff[segment_num] << ')'; } s << std::endl; return s.str(); diff --git a/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx b/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx index 6a14f7953a..75d19792da 100644 --- a/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx +++ b/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx @@ -23,7 +23,7 @@ \file \ingroup projdata - \brief Implementation of non-inline functions of class + \brief Implementation of non-inline functions of class stir::ProjDataInfoCylindricalArcCorr \author Sanida Mustafovic @@ -38,9 +38,9 @@ #include "stir/round.h" #include "stir/LORCoordinates.h" #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif #ifndef STIR_NO_NAMESPACES @@ -49,60 +49,48 @@ using std::ends; using std::string; #endif - START_NAMESPACE_STIR -ProjDataInfoCylindricalArcCorr:: ProjDataInfoCylindricalArcCorr() -{} - -ProjDataInfoCylindricalArcCorr:: ProjDataInfoCylindricalArcCorr(const shared_ptr scanner_ptr,float bin_size_v, - const VectorWithOffset& num_axial_pos_per_segment, - const VectorWithOffset& min_ring_diff_v, - const VectorWithOffset& max_ring_diff_v, - const int num_views,const int num_tangential_poss) - :ProjDataInfoCylindrical(scanner_ptr, - num_axial_pos_per_segment, - min_ring_diff_v, max_ring_diff_v, - num_views, num_tangential_poss), - bin_size(bin_size_v) - -{} - +ProjDataInfoCylindricalArcCorr::ProjDataInfoCylindricalArcCorr() {} -void -ProjDataInfoCylindricalArcCorr::set_tangential_sampling(const float new_tangential_sampling) -{bin_size = new_tangential_sampling;} +ProjDataInfoCylindricalArcCorr::ProjDataInfoCylindricalArcCorr(const shared_ptr scanner_ptr, float bin_size_v, + const VectorWithOffset& num_axial_pos_per_segment, + const VectorWithOffset& min_ring_diff_v, + const VectorWithOffset& max_ring_diff_v, const int num_views, + const int num_tangential_poss, const int tof_mash_factor) + : ProjDataInfoCylindrical(scanner_ptr, num_axial_pos_per_segment, min_ring_diff_v, max_ring_diff_v, num_views, + num_tangential_poss), + bin_size(bin_size_v) +{ + if (scanner_ptr->is_tof_ready()) + set_tof_mash_factor(tof_mash_factor); +} +void +ProjDataInfoCylindricalArcCorr::set_tangential_sampling(const float new_tangential_sampling) { + bin_size = new_tangential_sampling; +} ProjDataInfo* -ProjDataInfoCylindricalArcCorr::clone() const -{ +ProjDataInfoCylindricalArcCorr::clone() const { return static_cast(new ProjDataInfoCylindricalArcCorr(*this)); } - bool -ProjDataInfoCylindricalArcCorr:: -operator==(const self_type& that) const -{ +ProjDataInfoCylindricalArcCorr::operator==(const self_type& that) const { if (!base_type::blindly_equals(&that)) return false; - return - fabs(this->bin_size - that.bin_size) < 0.05F; + return fabs(this->bin_size - that.bin_size) < 0.05F; } bool -ProjDataInfoCylindricalArcCorr:: -blindly_equals(const root_type * const that_ptr) const -{ - assert(dynamic_cast(that_ptr) != 0); - return - this->operator==(static_cast(*that_ptr)); +ProjDataInfoCylindricalArcCorr::blindly_equals(const root_type* const that_ptr) const { + assert(dynamic_cast(that_ptr) != 0); + return this->operator==(static_cast(*that_ptr)); } string -ProjDataInfoCylindricalArcCorr::parameter_info() const -{ +ProjDataInfoCylindricalArcCorr::parameter_info() const { #ifdef BOOST_NO_STRINGSTREAM // dangerous for out-of-range, but 'old-style' ostrstream seems to need this @@ -110,7 +98,7 @@ ProjDataInfoCylindricalArcCorr::parameter_info() const ostrstream s(str, 50000); #else std::ostringstream s; -#endif +#endif s << "ProjDataInfoCylindricalArcCorr := \n"; s << ProjDataInfoCylindrical::parameter_info(); s << "tangential sampling := " << get_tangential_sampling() << endl; @@ -118,41 +106,39 @@ ProjDataInfoCylindricalArcCorr::parameter_info() const return s.str(); } - Bin -ProjDataInfoCylindricalArcCorr:: -get_bin(const LOR& lor) const +ProjDataInfoCylindricalArcCorr::get_bin(const LOR& lor, const double delta_time) const { + if (delta_time != 0) { + error("TODO NO TOF YET"); + } + Bin bin; LORInAxialAndSinogramCoordinates lor_coords; - if (lor.change_representation(lor_coords, get_ring_radius()) == Succeeded::no) - { - bin.set_bin_value(-1); - return bin; - } + if (lor.change_representation(lor_coords, get_ring_radius()) == Succeeded::no) { + bin.set_bin_value(-1); + return bin; + } - // first find view + // first find view // unfortunately, phi ranges from [0,Pi[, but the rounding can // map this to a view which corresponds to Pi anyway. bin.view_num() = round(lor_coords.phi() / get_azimuthal_angle_sampling()); - assert(bin.view_num()>=0); - assert(bin.view_num()<=get_num_views()); - const bool swap_direction = - bin.view_num() > get_max_view_num(); + assert(bin.view_num() >= 0); + assert(bin.view_num() <= get_num_views()); + const bool swap_direction = bin.view_num() > get_max_view_num(); if (swap_direction) - bin.view_num()-=get_num_views(); + bin.view_num() -= get_num_views(); bin.tangential_pos_num() = round(lor_coords.s() / get_tangential_sampling()); if (swap_direction) bin.tangential_pos_num() *= -1; - if (bin.tangential_pos_num() < get_min_tangential_pos_num() || - bin.tangential_pos_num() > get_max_tangential_pos_num()) - { - bin.set_bin_value(-1); - return bin; - } + if (bin.tangential_pos_num() < get_min_tangential_pos_num() || bin.tangential_pos_num() > get_max_tangential_pos_num()) { + bin.set_bin_value(-1); + return bin; + } #if 0 const int num_rings = @@ -185,63 +171,51 @@ get_bin(const LOR& lor) const // find nearest segment { const float delta = - (swap_direction - ? lor_coords.z1()-lor_coords.z2() - : lor_coords.z2()-lor_coords.z1() - )/get_ring_spacing(); + (swap_direction ? lor_coords.z1() - lor_coords.z2() : lor_coords.z2() - lor_coords.z1()) / get_ring_spacing(); // check if out of acquired range // note the +1 or -1, which takes the size of the rings into account - if (delta>get_max_ring_difference(get_max_segment_num())+1 || - delta=0) - { - for (bin.segment_num()=0; bin.segment_num() get_max_ring_difference(get_max_segment_num()) + 1 || + delta < get_min_ring_difference(get_min_segment_num()) - 1) { + bin.set_bin_value(-1); + return bin; + } + if (delta >= 0) { + for (bin.segment_num() = 0; bin.segment_num() < get_max_segment_num(); ++bin.segment_num()) { + if (delta < get_max_ring_difference(bin.segment_num()) + .5) + break; } - else - { - // delta<0 - for (bin.segment_num()=0; bin.segment_num()>get_min_segment_num(); --bin.segment_num()) - { - if (delta > get_min_ring_difference(bin.segment_num())-.5) - break; - } + } else { + // delta<0 + for (bin.segment_num() = 0; bin.segment_num() > get_min_segment_num(); --bin.segment_num()) { + if (delta > get_min_ring_difference(bin.segment_num()) - .5) + break; } + } } // now find nearest axial position { - const float m = (lor_coords.z2()+lor_coords.z1())/2; -#if 0 + const float m = (lor_coords.z2() + lor_coords.z1()) / 2; +# if 0 // this uses private member of ProjDataInfoCylindrical // enable when moved initialise_ring_diff_arrays_if_not_done_yet(); -#ifndef NDEBUG +# ifndef NDEBUG bin.axial_pos_num()=0; assert(get_m(bin)==- m_offset[bin.segment_num()]); -#endif +# endif bin.axial_pos_num() = round((m + m_offset[bin.segment_num()])/ get_axial_sampling(bin.segment_num())); -#else - bin.axial_pos_num()=0; - bin.axial_pos_num() = - round((m - get_m(bin))/ - get_axial_sampling(bin.segment_num())); -#endif +# else + bin.axial_pos_num() = 0; + bin.axial_pos_num() = round((m - get_m(bin)) / get_axial_sampling(bin.segment_num())); +# endif if (bin.axial_pos_num() < get_min_axial_pos_num(bin.segment_num()) || - bin.axial_pos_num() > get_max_axial_pos_num(bin.segment_num())) - { - bin.set_bin_value(-1); - return bin; - } + bin.axial_pos_num() > get_max_axial_pos_num(bin.segment_num())) { + bin.set_bin_value(-1); + return bin; + } } #endif @@ -249,4 +223,3 @@ get_bin(const LOR& lor) const return bin; } END_NAMESPACE_STIR - diff --git a/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx b/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx index 86d5cddee4..294c10ae63 100644 --- a/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx +++ b/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx @@ -3,7 +3,8 @@ /* Copyright (C) 2000- 2007-10-08, Hammersmith Imanet Ltd Copyright (C) 2011-07-01 - 2011, Kris Thielemans - Copyright (C) 2018, University College London + Copyright (C) 2016, University of Hull + Copyright (C) 2017, 2018, University College London This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -22,9 +23,10 @@ \file \ingroup projdata - \brief Implementation of non-inline functions of class + \brief Implementation of non-inline functions of class stir::ProjDataInfoCylindricalNoArcCorr + \author Nikos Efthimiou \author Kris Thielemans */ @@ -34,11 +36,11 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/LORCoordinates.h" #include "stir/round.h" - +#include #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif #include @@ -52,83 +54,63 @@ using std::vector; #endif START_NAMESPACE_STIR -ProjDataInfoCylindricalNoArcCorr:: -ProjDataInfoCylindricalNoArcCorr() -{} - -ProjDataInfoCylindricalNoArcCorr:: -ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_ptr, - const float ring_radius_v, const float angular_increment_v, - const VectorWithOffset& num_axial_pos_per_segment, - const VectorWithOffset& min_ring_diff_v, - const VectorWithOffset& max_ring_diff_v, - const int num_views,const int num_tangential_poss) -: ProjDataInfoCylindrical(scanner_ptr, - num_axial_pos_per_segment, - min_ring_diff_v, max_ring_diff_v, - num_views, num_tangential_poss), - ring_radius(ring_radius_v), - angular_increment(angular_increment_v) -{ +ProjDataInfoCylindricalNoArcCorr::ProjDataInfoCylindricalNoArcCorr() {} + +ProjDataInfoCylindricalNoArcCorr::ProjDataInfoCylindricalNoArcCorr( + const shared_ptr scanner_ptr, const float ring_radius_v, const float angular_increment_v, + const VectorWithOffset& num_axial_pos_per_segment, const VectorWithOffset& min_ring_diff_v, + const VectorWithOffset& max_ring_diff_v, const int num_views, const int num_tangential_poss, const int tof_mash_factor) + : ProjDataInfoCylindrical(scanner_ptr, num_axial_pos_per_segment, min_ring_diff_v, max_ring_diff_v, num_views, + num_tangential_poss), + ring_radius(ring_radius_v), angular_increment(angular_increment_v) { uncompressed_view_tangpos_to_det1det2_initialised = false; det1det2_to_uncompressed_view_tangpos_initialised = false; - //this->initialise_uncompressed_view_tangpos_to_det1det2(); - //this->initialise_det1det2_to_uncompressed_view_tangpos(); + if (scanner_ptr->is_tof_ready()) + set_tof_mash_factor(tof_mash_factor); + // this->initialise_uncompressed_view_tangpos_to_det1det2(); + // this->initialise_det1det2_to_uncompressed_view_tangpos(); } -ProjDataInfoCylindricalNoArcCorr:: -ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_ptr, - const VectorWithOffset& num_axial_pos_per_segment, - const VectorWithOffset& min_ring_diff_v, - const VectorWithOffset& max_ring_diff_v, - const int num_views,const int num_tangential_poss) -: ProjDataInfoCylindrical(scanner_ptr, - num_axial_pos_per_segment, - min_ring_diff_v, max_ring_diff_v, - num_views, num_tangential_poss) -{ +ProjDataInfoCylindricalNoArcCorr::ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_ptr, + const VectorWithOffset& num_axial_pos_per_segment, + const VectorWithOffset& min_ring_diff_v, + const VectorWithOffset& max_ring_diff_v, + const int num_views, const int num_tangential_poss, + const int tof_mash_factor) + : ProjDataInfoCylindrical(scanner_ptr, num_axial_pos_per_segment, min_ring_diff_v, max_ring_diff_v, num_views, + num_tangential_poss) { assert(!is_null_ptr(scanner_ptr)); ring_radius = scanner_ptr->get_effective_ring_radius(); - angular_increment = static_cast(_PI/scanner_ptr->get_num_detectors_per_ring()); + angular_increment = static_cast(_PI / scanner_ptr->get_num_detectors_per_ring()); uncompressed_view_tangpos_to_det1det2_initialised = false; det1det2_to_uncompressed_view_tangpos_initialised = false; - //this->initialise_uncompressed_view_tangpos_to_det1det2(); - //this->initialise_det1det2_to_uncompressed_view_tangpos(); -} - - + if (scanner_ptr->is_tof_ready()) + set_tof_mash_factor(tof_mash_factor); + // this->initialise_uncompressed_view_tangpos_to_det1det2(); + // this->initialise_det1det2_to_uncompressed_view_tangpos(); +} ProjDataInfo* -ProjDataInfoCylindricalNoArcCorr::clone() const -{ +ProjDataInfoCylindricalNoArcCorr::clone() const { return static_cast(new ProjDataInfoCylindricalNoArcCorr(*this)); } bool -ProjDataInfoCylindricalNoArcCorr:: -operator==(const self_type& that) const -{ +ProjDataInfoCylindricalNoArcCorr::operator==(const self_type& that) const { if (!base_type::blindly_equals(&that)) return false; - return - fabs(this->ring_radius - that.ring_radius) < 0.05F && - fabs(this->angular_increment - that.angular_increment) < 0.05F; + return fabs(this->ring_radius - that.ring_radius) < 0.05F && fabs(this->angular_increment - that.angular_increment) < 0.05F; } bool -ProjDataInfoCylindricalNoArcCorr:: -blindly_equals(const root_type * const that_ptr) const -{ - assert(dynamic_cast(that_ptr) != 0); - return - this->operator==(static_cast(*that_ptr)); +ProjDataInfoCylindricalNoArcCorr::blindly_equals(const root_type* const that_ptr) const { + assert(dynamic_cast(that_ptr) != 0); + return this->operator==(static_cast(*that_ptr)); } - string -ProjDataInfoCylindricalNoArcCorr::parameter_info() const -{ +ProjDataInfoCylindricalNoArcCorr::parameter_info() const { #ifdef BOOST_NO_STRINGSTREAM // dangerous for out-of-range, but 'old-style' ostrstream seems to need this @@ -136,7 +118,7 @@ ProjDataInfoCylindricalNoArcCorr::parameter_info() const ostrstream s(str, 50000); #else std::ostringstream s; -#endif +#endif s << "ProjDataInfoCylindricalNoArcCorr := \n"; s << ProjDataInfoCylindrical::parameter_info(); s << "End :=\n"; @@ -172,87 +154,71 @@ ProjDataInfoCylindricalNoArcCorr::parameter_info() const - angles have to be defined modulo 2 Pi (so num_detectors) - interleaving */ -void -ProjDataInfoCylindricalNoArcCorr:: -initialise_uncompressed_view_tangpos_to_det1det2() const -{ +void +ProjDataInfoCylindricalNoArcCorr::initialise_uncompressed_view_tangpos_to_det1det2() const { BOOST_STATIC_ASSERT(-1 >> 1 == -1); BOOST_STATIC_ASSERT(-2 >> 1 == -1); - const int num_detectors = - get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_detectors = get_scanner_ptr()->get_num_detectors_per_ring(); - assert(num_detectors%2 == 0); + assert(num_detectors % 2 == 0); // check views range from 0 to Pi - assert(fabs(get_phi(Bin(0,0,0,0))) < 1.E-4); - assert(fabs(get_phi(Bin(0,get_num_views(),0,0)) - _PI) < 1.E-4); - const int min_tang_pos_num = -(num_detectors/2)+1; - const int max_tang_pos_num = -(num_detectors/2)+num_detectors; - - if (this->get_min_tangential_pos_num() < min_tang_pos_num || - this->get_max_tangential_pos_num() > max_tang_pos_num) - { - error("The tangential_pos range (%d to %d) for this projection data is too large.\n" - "Maximum supported range is from %d to %d", - this->get_min_tangential_pos_num(), this->get_max_tangential_pos_num(), - min_tang_pos_num, max_tang_pos_num); - } + assert(fabs(get_phi(Bin(0, 0, 0, 0))) < 1.E-4); + assert(fabs(get_phi(Bin(0, get_num_views(), 0, 0)) - _PI) < 1.E-4); + const int min_tang_pos_num = -(num_detectors / 2) + 1; + const int max_tang_pos_num = -(num_detectors / 2) + num_detectors; + + if (this->get_min_tangential_pos_num() < min_tang_pos_num || this->get_max_tangential_pos_num() > max_tang_pos_num) { + error("The tangential_pos range (%d to %d) for this projection data is too large.\n" + "Maximum supported range is from %d to %d", + this->get_min_tangential_pos_num(), this->get_max_tangential_pos_num(), min_tang_pos_num, max_tang_pos_num); + } - uncompressed_view_tangpos_to_det1det2.grow(0,num_detectors/2-1); - for (int v_num=0; v_num<=num_detectors/2-1; ++v_num) - { + uncompressed_view_tangpos_to_det1det2.grow(0, num_detectors / 2 - 1); + for (int v_num = 0; v_num <= num_detectors / 2 - 1; ++v_num) { uncompressed_view_tangpos_to_det1det2[v_num].grow(min_tang_pos_num, max_tang_pos_num); - for (int tp_num=min_tang_pos_num; tp_num<=max_tang_pos_num; ++tp_num) - { + for (int tp_num = min_tang_pos_num; tp_num <= max_tang_pos_num; ++tp_num) { /* adapted from CTI code Note for implementation: avoid using % with negative numbers so add num_detectors before doing modulo num_detectors) */ - uncompressed_view_tangpos_to_det1det2[v_num][tp_num].det1_num = - (v_num + (tp_num >> 1) + num_detectors) % num_detectors; - uncompressed_view_tangpos_to_det1det2[v_num][tp_num].det2_num = - (v_num - ( (tp_num + 1) >> 1 ) + num_detectors/2) % num_detectors; + uncompressed_view_tangpos_to_det1det2[v_num][tp_num].det1_num = (v_num + (tp_num >> 1) + num_detectors) % num_detectors; + uncompressed_view_tangpos_to_det1det2[v_num][tp_num].det2_num = + (v_num - ((tp_num + 1) >> 1) + num_detectors / 2) % num_detectors; } } uncompressed_view_tangpos_to_det1det2_initialised = true; } -void -ProjDataInfoCylindricalNoArcCorr:: -initialise_det1det2_to_uncompressed_view_tangpos() const -{ +void +ProjDataInfoCylindricalNoArcCorr::initialise_det1det2_to_uncompressed_view_tangpos() const { BOOST_STATIC_ASSERT(-1 >> 1 == -1); BOOST_STATIC_ASSERT(-2 >> 1 == -1); - const int num_detectors = - get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_detectors = get_scanner_ptr()->get_num_detectors_per_ring(); - if (num_detectors%2 != 0) - { - error("Number of detectors per ring should be even but is %d", num_detectors); - } - if (this->get_min_view_num() != 0) - { - error("Minimum view number should currently be zero to be able to use get_view_tangential_pos_num_for_det_num_pair()"); - } + if (num_detectors % 2 != 0) { + error("Number of detectors per ring should be even but is %d", num_detectors); + } + if (this->get_min_view_num() != 0) { + error("Minimum view number should currently be zero to be able to use get_view_tangential_pos_num_for_det_num_pair()"); + } // check views range from 0 to Pi - assert(fabs(get_phi(Bin(0,0,0,0))) < 1.E-4); - assert(fabs(get_phi(Bin(0,get_max_view_num()+1,0,0)) - _PI) < 1.E-4); - //const int min_tang_pos_num = -(num_detectors/2); - //const int max_tang_pos_num = -(num_detectors/2)+num_detectors; - const int max_num_views = num_detectors/2; - - det1det2_to_uncompressed_view_tangpos.grow(0,num_detectors-1); - for (int det1_num=0; det1_num> 1) + num_detectors) % num_detectors; - + int tang_pos_num = (det1_num - det2_num + 3 * num_detectors / 2) % num_detectors; + int view_num = (det1_num - (tang_pos_num >> 1) + num_detectors) % num_detectors; + /* Now adjust ranges for view_num, tang_pos_num. The next lines go only wrong in the singular (and irrelevant) case det_num1 == det_num2 (when tang_pos_num == num_detectors - tang_pos_num) - + We use the combinations of the following 'symmetries' of (tang_pos_num, view_num) == (tang_pos_num+2*num_views, view_num + num_views) == (-tang_pos_num, view_num + num_views) @@ -279,99 +245,86 @@ initialise_det1det2_to_uncompressed_view_tangpos() const as well. So, we keep track of this in swap_detectors, and return its final value. */ - if (view_num < max_num_views) - { - if (tang_pos_num >= max_num_views) - { + if (view_num < max_num_views) { + if (tang_pos_num >= max_num_views) { tang_pos_num = num_detectors - tang_pos_num; swap_detectors = 1; - } - else - { + } else { swap_detectors = 0; } - } - else - { + } else { view_num -= max_num_views; - if (tang_pos_num >= max_num_views) - { + if (tang_pos_num >= max_num_views) { tang_pos_num -= num_detectors; swap_detectors = 0; - } - else - { + } else { tang_pos_num *= -1; swap_detectors = 1; } } - + det1det2_to_uncompressed_view_tangpos[det1_num][det2_num].view_num = view_num; det1det2_to_uncompressed_view_tangpos[det1_num][det2_num].tang_pos_num = tang_pos_num; - det1det2_to_uncompressed_view_tangpos[det1_num][det2_num].swap_detectors = swap_detectors==0; + det1det2_to_uncompressed_view_tangpos[det1_num][det2_num].swap_detectors = swap_detectors == 0; } } det1det2_to_uncompressed_view_tangpos_initialised = true; } unsigned int -ProjDataInfoCylindricalNoArcCorr:: -get_num_det_pos_pairs_for_bin(const Bin& bin) const -{ - return - get_num_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), - bin.axial_pos_num())* - get_view_mashing_factor(); +ProjDataInfoCylindricalNoArcCorr::get_num_det_pos_pairs_for_bin(const Bin& bin) const { + return get_num_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), bin.axial_pos_num()) * get_view_mashing_factor() * + std::max(1, get_tof_mash_factor()); } void -ProjDataInfoCylindricalNoArcCorr:: -get_all_det_pos_pairs_for_bin(vector >& dps, - const Bin& bin) const -{ +ProjDataInfoCylindricalNoArcCorr::get_all_det_pos_pairs_for_bin(vector>& dps, const Bin& bin) const { this->initialise_uncompressed_view_tangpos_to_det1det2_if_not_done_yet(); dps.resize(get_num_det_pos_pairs_for_bin(bin)); const ProjDataInfoCylindrical::RingNumPairs& ring_pairs = - get_all_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), - bin.axial_pos_num()); + get_all_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), bin.axial_pos_num()); // not sure how to handle mashing with non-zero view offset... - assert(get_min_view_num()==0); - - unsigned int current_dp_num=0; - for (int uncompressed_view_num=bin.view_num()*get_view_mashing_factor(); - uncompressed_view_num<(bin.view_num()+1)*get_view_mashing_factor(); - ++uncompressed_view_num) - { - const int det1_num = - uncompressed_view_tangpos_to_det1det2[uncompressed_view_num][bin.tangential_pos_num()].det1_num; - const int det2_num = - uncompressed_view_tangpos_to_det1det2[uncompressed_view_num][bin.tangential_pos_num()].det2_num; - for (ProjDataInfoCylindrical::RingNumPairs::const_iterator rings_iter = ring_pairs.begin(); - rings_iter != ring_pairs.end(); - ++rings_iter) - { - assert(current_dp_num < get_num_det_pos_pairs_for_bin(bin)); - dps[current_dp_num].pos1().tangential_coord() = det1_num; - dps[current_dp_num].pos1().axial_coord() = rings_iter->first; - dps[current_dp_num].pos2().tangential_coord() = det2_num; - dps[current_dp_num].pos2().axial_coord() = rings_iter->second; - ++current_dp_num; - } + assert(get_min_view_num() == 0); + // not sure how to handle even tof mashing + assert(!is_tof_data() || (get_tof_mash_factor() % 2 == 1)); + unsigned int current_dp_num = 0; + for (int uncompressed_view_num = bin.view_num() * get_view_mashing_factor(); + uncompressed_view_num < (bin.view_num() + 1) * get_view_mashing_factor(); ++uncompressed_view_num) { + const int det1_num = uncompressed_view_tangpos_to_det1det2[uncompressed_view_num][bin.tangential_pos_num()].det1_num; + const int det2_num = uncompressed_view_tangpos_to_det1det2[uncompressed_view_num][bin.tangential_pos_num()].det2_num; + for (ProjDataInfoCylindrical::RingNumPairs::const_iterator rings_iter = ring_pairs.begin(); rings_iter != ring_pairs.end(); + ++rings_iter) { + for (int uncompressed_timing_pos_num = bin.timing_pos_num() * get_tof_mash_factor() - (get_tof_mash_factor() / 2); + uncompressed_timing_pos_num <= bin.timing_pos_num() * get_tof_mash_factor() + (get_tof_mash_factor() / 2); + ++uncompressed_timing_pos_num) { + assert(current_dp_num < get_num_det_pos_pairs_for_bin(bin)); + dps[current_dp_num].pos1().tangential_coord() = det1_num; + dps[current_dp_num].pos1().axial_coord() = rings_iter->first; + dps[current_dp_num].pos2().tangential_coord() = det2_num; + dps[current_dp_num].pos2().axial_coord() = rings_iter->second; + // need to keep dp.timing_pos positive + if (uncompressed_timing_pos_num > 0) { + dps[current_dp_num].timing_pos() = static_cast(uncompressed_timing_pos_num); + } else { + std::swap(dps[current_dp_num].pos1(), dps[current_dp_num].pos2()); + dps[current_dp_num].timing_pos() = static_cast(-uncompressed_timing_pos_num); + } + ++current_dp_num; + } } + } assert(current_dp_num == get_num_det_pos_pairs_for_bin(bin)); } Succeeded -ProjDataInfoCylindricalNoArcCorr:: -find_scanner_coordinates_given_cartesian_coordinates(int& det1, int& det2, int& ring1, int& ring2, - const CartesianCoordinate3D& c1, - const CartesianCoordinate3D& c2) const -{ - const int num_detectors=get_scanner_ptr()->get_num_detectors_per_ring(); - const float ring_spacing=get_scanner_ptr()->get_ring_spacing(); - const float ring_radius=get_scanner_ptr()->get_effective_ring_radius(); +ProjDataInfoCylindricalNoArcCorr::find_scanner_coordinates_given_cartesian_coordinates( + int& det1, int& det2, int& ring1, int& ring2, const CartesianCoordinate3D& c1, + const CartesianCoordinate3D& c2) const { + const int num_detectors = get_scanner_ptr()->get_num_detectors_per_ring(); + const float ring_spacing = get_scanner_ptr()->get_ring_spacing(); + const float ring_radius = get_scanner_ptr()->get_effective_ring_radius(); #if 0 const CartesianCoordinate3D d = c2 - c1; @@ -407,59 +360,61 @@ find_scanner_coordinates_given_cartesian_coordinates(int& det1, int& det2, int& ring2 = round(coord_det2.z()/ring_spacing); #else LORInCylinderCoordinates cyl_coords; - if (find_LOR_intersections_with_cylinder(cyl_coords, - LORAs2Points(c1, c2), - ring_radius) - == Succeeded::no) + if (find_LOR_intersections_with_cylinder(cyl_coords, LORAs2Points(c1, c2), ring_radius) == Succeeded::no) return Succeeded::no; - det1 = modulo(round(cyl_coords.p1().psi()/(2.*_PI/num_detectors)), num_detectors); - det2 = modulo(round(cyl_coords.p2().psi()/(2.*_PI/num_detectors)), num_detectors); - ring1 = round(cyl_coords.p1().z()/ring_spacing); - ring2 = round(cyl_coords.p2().z()/ring_spacing); + det1 = modulo(round(cyl_coords.p1().psi() / (2. * _PI / num_detectors)), num_detectors); + det2 = modulo(round(cyl_coords.p2().psi() / (2. * _PI / num_detectors)), num_detectors); + ring1 = round(cyl_coords.p1().z() / ring_spacing); + ring2 = round(cyl_coords.p2().z() / ring_spacing); #endif - assert(det1 >=0 && det1get_num_detectors_per_ring()); - assert(det2 >=0 && det2get_num_detectors_per_ring()); + assert(det1 >= 0 && det1 < get_scanner_ptr()->get_num_detectors_per_ring()); + assert(det2 >= 0 && det2 < get_scanner_ptr()->get_num_detectors_per_ring()); - return - (ring1 >=0 && ring1get_num_rings() && - ring2 >=0 && ring2get_num_rings()) - ? Succeeded::yes : Succeeded::no; + return (ring1 >= 0 && ring1 < get_scanner_ptr()->get_num_rings() && ring2 >= 0 && ring2 < get_scanner_ptr()->get_num_rings()) + ? Succeeded::yes + : Succeeded::no; } - -void -ProjDataInfoCylindricalNoArcCorr:: -find_cartesian_coordinates_of_detection( - CartesianCoordinate3D& coord_1, - CartesianCoordinate3D& coord_2, - const Bin& bin) const -{ - // find detectors +void +ProjDataInfoCylindricalNoArcCorr::find_cartesian_coordinates_of_detection(CartesianCoordinate3D& coord_1, + CartesianCoordinate3D& coord_2, + const Bin& bin) const { + // find detectors int det_num_a; int det_num_b; int ring_a; int ring_b; - get_det_pair_for_bin(det_num_a, ring_a, - det_num_b, ring_b, bin); - + get_det_pair_for_bin(det_num_a, ring_a, det_num_b, ring_b, bin); + // find corresponding cartesian coordinates - find_cartesian_coordinates_given_scanner_coordinates(coord_1,coord_2, - ring_a,ring_b,det_num_a,det_num_b); + find_cartesian_coordinates_given_scanner_coordinates(coord_1, coord_2, ring_a, ring_b, det_num_a, det_num_b); } - void -ProjDataInfoCylindricalNoArcCorr:: -find_cartesian_coordinates_given_scanner_coordinates (CartesianCoordinate3D& coord_1, - CartesianCoordinate3D& coord_2, - const int Ring_A,const int Ring_B, - const int det1, const int det2) const -{ - const int num_detectors_per_ring = - get_scanner_ptr()->get_num_detectors_per_ring(); +ProjDataInfoCylindricalNoArcCorr::find_cartesian_coordinates_given_scanner_coordinates(CartesianCoordinate3D& coord_1, + CartesianCoordinate3D& coord_2, + const int Ring_A, const int Ring_B, + const int det1, const int det2) const { + const int num_detectors_per_ring = get_scanner_ptr()->get_num_detectors_per_ring(); + + int d1, d2, r1, r2; + + this->initialise_det1det2_to_uncompressed_view_tangpos_if_not_done_yet(); + + if (!det1det2_to_uncompressed_view_tangpos[det1][det2].swap_detectors) { + d1 = det2; + d2 = det1; + r1 = Ring_B; + r2 = Ring_A; + } else { + d1 = det1; + d2 = det2; + r1 = Ring_A; + r2 = Ring_B; + } #if 0 const float df1 = (2.*_PI/num_detectors_per_ring)*(det1); @@ -477,140 +432,141 @@ find_cartesian_coordinates_given_scanner_coordinates (CartesianCoordinate3D cyl_coords(get_scanner_ptr()->get_effective_ring_radius()); - cyl_coords.p1().psi() = static_cast((2.*_PI/num_detectors_per_ring)*(det1)); - cyl_coords.p2().psi() = static_cast((2.*_PI/num_detectors_per_ring)*(det2)); - cyl_coords.p1().z() = Ring_A*get_scanner_ptr()->get_ring_spacing(); - cyl_coords.p2().z() = Ring_B*get_scanner_ptr()->get_ring_spacing(); - LORAs2Points lor(cyl_coords); + cyl_coords.p1().psi() = static_cast((2. * _PI / num_detectors_per_ring) * (d1)); + cyl_coords.p2().psi() = static_cast((2. * _PI / num_detectors_per_ring) * (d2)); + cyl_coords.p1().z() = r1 * get_scanner_ptr()->get_ring_spacing(); + cyl_coords.p2().z() = r2 * get_scanner_ptr()->get_ring_spacing(); + LORAs2Points lor(cyl_coords); coord_1 = lor.p1(); coord_2 = lor.p2(); - + #endif } +//! \obsolete I don't see any reason why to keep having this function. +void +ProjDataInfoCylindricalNoArcCorr::find_cartesian_coordinates_given_scanner_coordinates_of_the_front_surface( + CartesianCoordinate3D& coord_1, CartesianCoordinate3D& coord_2, const int Ring_A, const int Ring_B, + const int det1, const int det2) const { + const int num_detectors_per_ring = get_scanner_ptr()->get_num_detectors_per_ring(); + + // float h_scanner_height = ( (get_scanner_ptr()->get_ring_spacing() -1) * get_scanner_ptr()->get_num_rings())/2.F; + + // although code maybe doesn't really need the following, + // asserts in the LOR code will break if these conditions are not satisfied. + assert(0 <= det1); + assert(det1 < num_detectors_per_ring); + assert(0 <= det2); + assert(det2 < num_detectors_per_ring); + + LORInCylinderCoordinates cyl_coords(get_scanner_ptr()->get_inner_ring_radius()); -void -ProjDataInfoCylindricalNoArcCorr:: -find_bin_given_cartesian_coordinates_of_detection(Bin& bin, - const CartesianCoordinate3D& coord_1, - const CartesianCoordinate3D& coord_2) const -{ + cyl_coords.p1().psi() = static_cast((2. * _PI / num_detectors_per_ring) * (det1)); + cyl_coords.p2().psi() = static_cast((2. * _PI / num_detectors_per_ring) * (det2)); + + // cyl_coords.p1().z() = Ring_A*get_scanner_ptr()->get_ring_spacing() - h_scanner_height; + // cyl_coords.p2().z() = Ring_B*get_scanner_ptr()->get_ring_spacing() - h_scanner_height; + + LORAs2Points lor(cyl_coords); + coord_1 = lor.p1(); + coord_2 = lor.p2(); +} + +void +ProjDataInfoCylindricalNoArcCorr::find_bin_given_cartesian_coordinates_of_detection( + Bin& bin, const CartesianCoordinate3D& coord_1, const CartesianCoordinate3D& coord_2) const { int det_num_a; int det_num_b; int ring_a; int ring_b; - - // given two CartesianCoordinates find the intersection - if (find_scanner_coordinates_given_cartesian_coordinates(det_num_a,det_num_b, - ring_a, ring_b, - coord_1, - coord_2) == - Succeeded::no) - { + + // given two CartesianCoordinates find the intersection + if (find_scanner_coordinates_given_cartesian_coordinates(det_num_a, det_num_b, ring_a, ring_b, coord_1, coord_2) == + Succeeded::no) { bin.set_bin_value(-1); return; } // check rings are in valid range // this should have been done by find_scanner_coordinates_given_cartesian_coordinates - assert(!(ring_a<0 || - ring_a>=get_scanner_ptr()->get_num_rings() || - ring_b<0 || - ring_b>=get_scanner_ptr()->get_num_rings())); - - if (get_bin_for_det_pair(bin, - det_num_a, ring_a, - det_num_b, ring_b) == Succeeded::no || - bin.tangential_pos_num() < get_min_tangential_pos_num() || - bin.tangential_pos_num() > get_max_tangential_pos_num()) + assert(!(ring_a < 0 || ring_a >= get_scanner_ptr()->get_num_rings() || ring_b < 0 || + ring_b >= get_scanner_ptr()->get_num_rings())); + + if (get_bin_for_det_pair(bin, det_num_a, ring_a, det_num_b, ring_b) == Succeeded::no || + bin.tangential_pos_num() < get_min_tangential_pos_num() || bin.tangential_pos_num() > get_max_tangential_pos_num()) bin.set_bin_value(-1); } Bin -ProjDataInfoCylindricalNoArcCorr:: -get_bin(const LOR& lor) const -{ +ProjDataInfoCylindricalNoArcCorr::get_bin(const LOR& lor, const double delta_time) const { Bin bin; #ifndef STIR_DEVEL // find nearest bin by going to nearest detectors first LORInCylinderCoordinates cyl_coords; - if (lor.change_representation(cyl_coords, get_ring_radius()) == Succeeded::no) - { - bin.set_bin_value(-1); - return bin; - } - const int num_detectors_per_ring = - get_scanner_ptr()->get_num_detectors_per_ring(); - const int num_rings = - get_scanner_ptr()->get_num_rings(); + if (lor.change_representation(cyl_coords, get_ring_radius()) == Succeeded::no) { + bin.set_bin_value(-1); + return bin; + } + const int num_detectors_per_ring = get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_rings = get_scanner_ptr()->get_num_rings(); - const int det1 = modulo(round(cyl_coords.p1().psi()/(2.*_PI/num_detectors_per_ring)),num_detectors_per_ring); - const int det2 = modulo(round(cyl_coords.p2().psi()/(2.*_PI/num_detectors_per_ring)),num_detectors_per_ring); + const int det1 = modulo(round(cyl_coords.p1().psi() / (2. * _PI / num_detectors_per_ring)), num_detectors_per_ring); + const int det2 = modulo(round(cyl_coords.p2().psi() / (2. * _PI / num_detectors_per_ring)), num_detectors_per_ring); // TODO WARNING LOR coordinates are w.r.t. centre of scanner, but the rings are numbered with the first ring at 0 - const int ring1 = round(cyl_coords.p1().z()/get_ring_spacing() + (num_rings-1)/2.F); - const int ring2 = round(cyl_coords.p2().z()/get_ring_spacing() + (num_rings-1)/2.F); - - assert(det1 >=0 && det1=0 && det2=0 && ring1=0 && ring2= get_min_tangential_pos_num() && - bin.tangential_pos_num() <= get_max_tangential_pos_num()) - { - bin.set_bin_value(1); - return bin; - } - else - { - bin.set_bin_value(-1); - return bin; - } - + const int ring1 = round(cyl_coords.p1().z() / get_ring_spacing() + (num_rings - 1) / 2.F); + const int ring2 = round(cyl_coords.p2().z() / get_ring_spacing() + (num_rings - 1) / 2.F); + + assert(det1 >= 0 && det1 < num_detectors_per_ring); + assert(det2 >= 0 && det2 < num_detectors_per_ring); + + if (ring1 >= 0 && ring1 < num_rings && ring2 >= 0 && ring2 < num_rings && + get_bin_for_det_pair(bin, det1, ring1, det2, ring2, (cyl_coords.is_swapped() ? -1 : 1) * get_tof_bin(delta_time)) == + Succeeded::yes && + bin.tangential_pos_num() >= get_min_tangential_pos_num() && bin.tangential_pos_num() <= get_max_tangential_pos_num()) { + bin.set_bin_value(1); + return bin; + } else { + bin.set_bin_value(-1); + return bin; + } #else LORInAxialAndNoArcCorrSinogramCoordinates lor_coords; - if (lor.change_representation(lor_coords, get_ring_radius()) == Succeeded::no) - { - bin.set_bin_value(-1); - return bin; - } + if (lor.change_representation(lor_coords, get_ring_radius()) == Succeeded::no) { + bin.set_bin_value(-1); + return bin; + } - // first find view + // first find view // unfortunately, phi ranges from [0,Pi[, but the rounding can // map this to a view which corresponds to Pi anyway. bin.view_num() = round(lor_coords.phi() / get_azimuthal_angle_sampling()); - assert(bin.view_num()>=0); - assert(bin.view_num()<=get_num_views()); - const bool swap_direction = - bin.view_num() > get_max_view_num(); + assert(bin.view_num() >= 0); + assert(bin.view_num() <= get_num_views()); + const bool swap_direction = bin.view_num() > get_max_view_num(); if (swap_direction) - bin.view_num()-=get_num_views(); + bin.view_num() -= get_num_views(); bin.tangential_pos_num() = round(lor_coords.beta() / angular_increment); if (swap_direction) bin.tangential_pos_num() *= -1; - if (bin.tangential_pos_num() < get_min_tangential_pos_num() || - bin.tangential_pos_num() > get_max_tangential_pos_num()) - { - bin.set_bin_value(-1); - return bin; - } + if (bin.tangential_pos_num() < get_min_tangential_pos_num() || bin.tangential_pos_num() > get_max_tangential_pos_num()) { + bin.set_bin_value(-1); + return bin; + } -#if 0 +# if 0 const int num_rings = get_scanner_ptr()->get_num_rings(); // TODO WARNING LOR coordinates are w.r.t. centre of scanner, but the rings are numbered with the first ring at 0 @@ -637,75 +593,64 @@ get_bin(const LOR& lor) const bin.set_bin_value(-1); return bin; } -#else +# else // find nearest segment { + if (delta_time != 0) { + error("TODO TOF"); + } const float delta = - (swap_direction - ? lor_coords.z1()-lor_coords.z2() - : lor_coords.z2()-lor_coords.z1() - )/get_ring_spacing(); + (swap_direction ? lor_coords.z1() - lor_coords.z2() : lor_coords.z2() - lor_coords.z1()) / get_ring_spacing(); // check if out of acquired range // note the +1 or -1, which takes the size of the rings into account - if (delta>get_max_ring_difference(get_max_segment_num())+1 || - delta=0) - { - for (bin.segment_num()=0; bin.segment_num() get_max_ring_difference(get_max_segment_num()) + 1 || + delta < get_min_ring_difference(get_min_segment_num()) - 1) { + bin.set_bin_value(-1); + return bin; + } + if (delta >= 0) { + for (bin.segment_num() = 0; bin.segment_num() < get_max_segment_num(); ++bin.segment_num()) { + if (delta < get_max_ring_difference(bin.segment_num()) + .5) + break; } - else - { - // delta<0 - for (bin.segment_num()=0; bin.segment_num()>get_min_segment_num(); --bin.segment_num()) - { - if (delta > get_min_ring_difference(bin.segment_num())-.5) - break; - } + } else { + // delta<0 + for (bin.segment_num() = 0; bin.segment_num() > get_min_segment_num(); --bin.segment_num()) { + if (delta > get_min_ring_difference(bin.segment_num()) - .5) + break; } + } } // now find nearest axial position { - const float m = (lor_coords.z2()+lor_coords.z1())/2; -#if 0 + const float m = (lor_coords.z2() + lor_coords.z1()) / 2; +# if 0 // this uses private member of ProjDataInfoCylindrical // enable when moved initialise_ring_diff_arrays_if_not_done_yet(); -#ifndef NDEBUG +# ifndef NDEBUG bin.axial_pos_num()=0; assert(get_m(bin)==- m_offset[bin.segment_num()]); -#endif +# endif bin.axial_pos_num() = round((m + m_offset[bin.segment_num()])/ get_axial_sampling(bin.segment_num())); -#else - bin.axial_pos_num()=0; - bin.axial_pos_num() = - round((m - get_m(bin))/ - get_axial_sampling(bin.segment_num())); -#endif +# else + bin.axial_pos_num() = 0; + bin.axial_pos_num() = round((m - get_m(bin)) / get_axial_sampling(bin.segment_num())); +# endif if (bin.axial_pos_num() < get_min_axial_pos_num(bin.segment_num()) || - bin.axial_pos_num() > get_max_axial_pos_num(bin.segment_num())) - { - bin.set_bin_value(-1); - return bin; - } + bin.axial_pos_num() > get_max_axial_pos_num(bin.segment_num())) { + bin.set_bin_value(-1); + return bin; + } } -#endif +# endif bin.set_bin_value(1); return bin; #endif } - END_NAMESPACE_STIR - diff --git a/src/buildblock/ProjDataInterfile.cxx b/src/buildblock/ProjDataInterfile.cxx index 058ab9a1b1..d853f455a6 100644 --- a/src/buildblock/ProjDataInterfile.cxx +++ b/src/buildblock/ProjDataInterfile.cxx @@ -24,7 +24,7 @@ See STIR/LICENSE.txt for details */ -#include "stir/ProjDataInterfile.h" +#include "stir/ProjDataInterfile.h" #include "stir/utilities.h" #include "stir/IO/interfile.h" @@ -42,42 +42,36 @@ using std::ios; START_NAMESPACE_STIR - void -ProjDataInterfile :: -create_stream(const string& filename, const ios::openmode open_mode) -{ +ProjDataInterfile ::create_stream(const string& filename, const ios::openmode open_mode) { #if 1 - string data_name=filename; + string data_name = filename; { - string::size_type pos=find_pos_of_extension(filename); - if (pos!=string::npos && filename.substr(pos)==".hs") + string::size_type pos = find_pos_of_extension(filename); + if (pos != string::npos && filename.substr(pos) == ".hs") replace_extension(data_name, ".s"); else add_extension(data_name, ".s"); } - string header_name=filename; + string header_name = filename; #else - char * data_name = new char[filename.size() + 5]; + char* data_name = new char[filename.size() + 5]; { strcpy(data_name, filename.c_str()); - const char * const extension = strchr(find_filename(data_name),'.'); - if (extension!=NULL && strcmp(extension, ".hs")==0) + const char* const extension = strchr(find_filename(data_name), '.'); + if (extension != NULL && strcmp(extension, ".hs") == 0) replace_extension(data_name, ".s"); else add_extension(data_name, ".s"); } - char * header_name = new char[filename.size() + 5]; + char* header_name = new char[filename.size() + 5]; strcpy(header_name, data_name); #endif replace_extension(header_name, ".hs"); - write_basic_interfile_PDFS_header(header_name, data_name, - *this); + write_basic_interfile_PDFS_header(header_name, data_name, *this); - sino_stream.reset( - new fstream (data_name.c_str(), open_mode|ios::binary)); - if (!sino_stream->good()) - { + sino_stream.reset(new fstream(data_name.c_str(), open_mode | ios::binary)); + if (!sino_stream->good()) { error("ProjDataInterfile: error opening output file %s\n", data_name.c_str()); } #if 0 @@ -86,35 +80,21 @@ create_stream(const string& filename, const ios::openmode open_mode) #endif } -ProjDataInterfile :: -ProjDataInterfile (shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, - const string& filename, const ios::openmode open_mode, - const vector& segment_sequence_in_stream, - StorageOrder o, - NumericType data_type, - ByteOrder byte_order, - float scale_factor) - : ProjDataFromStream(exam_info_sptr, proj_data_info_ptr, shared_ptr(), 0, - segment_sequence_in_stream, o, data_type, byte_order, scale_factor) -{ +ProjDataInterfile ::ProjDataInterfile(shared_ptr const& exam_info_sptr, + shared_ptr const& proj_data_info_ptr, const string& filename, + const ios::openmode open_mode, const vector& segment_sequence_in_stream, + StorageOrder o, NumericType data_type, ByteOrder byte_order, float scale_factor) + : ProjDataFromStream(exam_info_sptr, proj_data_info_ptr, shared_ptr(), 0, segment_sequence_in_stream, o, data_type, + byte_order, scale_factor) { create_stream(filename, open_mode); } -ProjDataInterfile :: -ProjDataInterfile (shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, - const string& filename, const ios::openmode open_mode, - StorageOrder o, - NumericType data_type, - ByteOrder byte_order, - float scale_factor ) - : ProjDataFromStream(exam_info_sptr, proj_data_info_ptr, shared_ptr(), 0, - o, data_type, byte_order, scale_factor) -{ +ProjDataInterfile ::ProjDataInterfile(shared_ptr const& exam_info_sptr, + shared_ptr const& proj_data_info_ptr, const string& filename, + const ios::openmode open_mode, StorageOrder o, NumericType data_type, ByteOrder byte_order, + float scale_factor) + : ProjDataFromStream(exam_info_sptr, proj_data_info_ptr, shared_ptr(), 0, o, data_type, byte_order, scale_factor) { create_stream(filename, open_mode); } - - END_NAMESPACE_STIR diff --git a/src/buildblock/RegisteredObject.cxx b/src/buildblock/RegisteredObject.cxx index 147cd44177..f0130edf33 100644 --- a/src/buildblock/RegisteredObject.cxx +++ b/src/buildblock/RegisteredObject.cxx @@ -33,23 +33,22 @@ #include "stir/RegisteredObject.h" #ifdef __STIR_REGISTRY_NOT_INLINE -#pragma message("instantiating RegisteredObject > >") -#include "stir/DataProcessor.h" -#include "stir/DiscretisedDensity.h" +# pragma message("instantiating RegisteredObject > >") +# include "stir/DataProcessor.h" +# include "stir/DiscretisedDensity.h" // add here all roots of hierarchies based on RegisteredObject START_NAMESPACE_STIR template -RegisteredObject::RegistryType& -RegisteredObject::registry () -{ +RegisteredObject::RegistryType& +RegisteredObject::registry() { static RegistryType the_registry("None", 0); return the_registry; } -template RegisteredObject > >; +template RegisteredObject>>; // add here all roots of hierarchies based on RegisteredObject END_NAMESPACE_STIR diff --git a/src/buildblock/RelatedViewgrams.cxx b/src/buildblock/RelatedViewgrams.cxx index 70f4bdb774..15658fb573 100644 --- a/src/buildblock/RelatedViewgrams.cxx +++ b/src/buildblock/RelatedViewgrams.cxx @@ -35,7 +35,7 @@ #ifdef _MSC_VER // disable warning that constructor with PMessage is not implemented -#pragma warning(disable: 4661) +# pragma warning(disable : 4661) #endif // _MSC_VER using std::string; @@ -43,11 +43,10 @@ using std::vector; START_NAMESPACE_STIR - // a function which is called internally to see if the object is valid template -void RelatedViewgrams::debug_check_state() const -{ +void +RelatedViewgrams::debug_check_state() const { // KT 09/03/99 can't use any methods of RelatedViewgrams here, as // this causes an infinite recursion with check_state if (viewgrams.size() == 0) @@ -55,138 +54,99 @@ void RelatedViewgrams::debug_check_state() const vector pairs; symmetries_used->get_related_view_segment_numbers( - pairs, - ViewSegmentNumbers( - viewgrams[0].get_view_num(), - viewgrams[0].get_segment_num() - ) ); + pairs, ViewSegmentNumbers(viewgrams[0].get_view_num(), viewgrams[0].get_segment_num())); assert(pairs.size() == viewgrams.size()); - for (unsigned int i=0; i -RelatedViewgrams RelatedViewgrams::get_empty_copy() const -{ +RelatedViewgrams +RelatedViewgrams::get_empty_copy() const { check_state(); - vector > empty_viewgrams; + vector> empty_viewgrams; empty_viewgrams.reserve(viewgrams.size()); // TODO optimise to get shared proj_data_info_ptr - for (unsigned int i=0; i(empty_viewgrams, - symmetries_used); + return RelatedViewgrams(empty_viewgrams, symmetries_used); } -template +template bool -RelatedViewgrams:: -has_same_characteristics(self_type const& other, - string& explanation) const -{ +RelatedViewgrams::has_same_characteristics(self_type const& other, string& explanation) const { using boost::format; using boost::str; - if (*this->get_proj_data_info_sptr() != - *other.get_proj_data_info_sptr()) - { - explanation = - str(format("Differing projection data info:\n%1%\n-------- vs-------\n %2%") - % this->get_proj_data_info_sptr()->parameter_info() - % other.get_proj_data_info_sptr()->parameter_info() - ); - return false; - } - if (*this->get_symmetries_ptr() != - *other.get_symmetries_ptr()) - { - explanation = - str(format("Differing symmetries") - ); - return false; - } - if (this->get_basic_view_num() != - other.get_basic_view_num()) - { - explanation = - str(format("Differing basic view number: %1% vs %2%") - % this->get_basic_view_num() - % other.get_basic_view_num() - ); - return false; - } - if (this->get_basic_segment_num() != - other.get_basic_segment_num()) - { - explanation = - str(format("Differing basic segment number: %1% vs %2%") - % this->get_basic_segment_num() - % other.get_basic_segment_num() - ); - return false; - } + if (*this->get_proj_data_info_sptr() != *other.get_proj_data_info_sptr()) { + explanation = str(format("Differing projection data info:\n%1%\n-------- vs-------\n %2%") % + this->get_proj_data_info_sptr()->parameter_info() % other.get_proj_data_info_sptr()->parameter_info()); + return false; + } + if (*this->get_symmetries_ptr() != *other.get_symmetries_ptr()) { + explanation = str(format("Differing symmetries")); + return false; + } + if (this->get_basic_view_num() != other.get_basic_view_num()) { + explanation = + str(format("Differing basic view number: %1% vs %2%") % this->get_basic_view_num() % other.get_basic_view_num()); + return false; + } + if (this->get_basic_segment_num() != other.get_basic_segment_num()) { + explanation = + str(format("Differing basic segment number: %1% vs %2%") % this->get_basic_segment_num() % other.get_basic_segment_num()); + return false; + } + if (this->get_basic_timing_pos_num() != other.get_basic_timing_pos_num()) { + explanation = str(format("Differing basic timing position index: %1% vs %2%") % this->get_basic_timing_pos_num() % + other.get_basic_timing_pos_num()); + return false; + } return true; } -template +template bool -RelatedViewgrams:: -has_same_characteristics(self_type const& other) const -{ +RelatedViewgrams::has_same_characteristics(self_type const& other) const { std::string explanation; return this->has_same_characteristics(other, explanation); } -template -bool -RelatedViewgrams:: -operator ==(const self_type& that) const -{ - return - this->has_same_characteristics(that) && - std::equal(this->begin(), this->end(), that.begin()); +template +bool +RelatedViewgrams::operator==(const self_type& that) const { + return this->has_same_characteristics(that) && std::equal(this->begin(), this->end(), that.begin()); } - -template -bool -RelatedViewgrams:: -operator !=(const self_type& that) const -{ + +template +bool +RelatedViewgrams::operator!=(const self_type& that) const { return !((*this) == that); } /*! \warning: this uses multiplication according to elemT (careful for overflow for integer types!) */ template -RelatedViewgrams& -RelatedViewgrams:: -operator*= (const elemT f) -{ +RelatedViewgrams& +RelatedViewgrams::operator*=(const elemT f) { for (iterator iter = begin(); iter != end(); ++iter) *iter *= f; return *this; } /*! \warning: this uses division according to elemT (i.e. no rounding or so) */ -template +template RelatedViewgrams& -RelatedViewgrams:: -operator/= (const elemT f) -{ - assert(f!=0); +RelatedViewgrams::operator/=(const elemT f) { + assert(f != 0); for (iterator iter = begin(); iter != end(); ++iter) *iter /= f; @@ -195,10 +155,8 @@ operator/= (const elemT f) /*! \warning: this uses addition according to elemT (careful with overflow with integer types!) */ template -RelatedViewgrams& -RelatedViewgrams:: -operator+= (const elemT f) -{ +RelatedViewgrams& +RelatedViewgrams::operator+=(const elemT f) { for (iterator iter = begin(); iter != end(); ++iter) *iter += f; return *this; @@ -206,148 +164,124 @@ operator+= (const elemT f) /*! \warning: this uses subtraction according to elemT (careful with unsigned types!) */ template -RelatedViewgrams& -RelatedViewgrams:: -operator-= (const elemT f) -{ +RelatedViewgrams& +RelatedViewgrams::operator-=(const elemT f) { for (iterator iter = begin(); iter != end(); ++iter) *iter -= f; return *this; } - /*! \warning: this uses multiplication according to elemT (careful for overflow for integer types!) */ -template +template RelatedViewgrams& -RelatedViewgrams:: -operator*= (const RelatedViewgrams& arg) -{ +RelatedViewgrams::operator*=(const RelatedViewgrams& arg) { assert(get_num_viewgrams() == arg.get_num_viewgrams()); - iterator iter = begin(); + iterator iter = begin(); const_iterator arg_iter = arg.begin(); - for ( ; iter != end(); ++iter, ++arg_iter) + for (; iter != end(); ++iter, ++arg_iter) *iter *= *arg_iter; return *this; } /*! \warning: this uses division according to elemT (i.e. no rounding or so) */ -template +template RelatedViewgrams& -RelatedViewgrams:: -operator/= (const RelatedViewgrams& arg) -{ +RelatedViewgrams::operator/=(const RelatedViewgrams& arg) { assert(get_num_viewgrams() == arg.get_num_viewgrams()); - iterator iter = begin(); + iterator iter = begin(); const_iterator arg_iter = arg.begin(); - for ( ; iter != end(); ++iter, ++arg_iter) + for (; iter != end(); ++iter, ++arg_iter) *iter /= *arg_iter; return *this; } - /*! \warning: this uses addition according to elemT (careful with overflow with integer types!) */ -template +template RelatedViewgrams& -RelatedViewgrams:: -operator+= (const RelatedViewgrams& arg) -{ +RelatedViewgrams::operator+=(const RelatedViewgrams& arg) { assert(get_num_viewgrams() == arg.get_num_viewgrams()); - iterator iter = begin(); + iterator iter = begin(); const_iterator arg_iter = arg.begin(); - for ( ; iter != end(); ++iter, ++arg_iter) + for (; iter != end(); ++iter, ++arg_iter) *iter += *arg_iter; return *this; } /*! \warning: this uses subtraction according to elemT (careful with unsigned types!) */ -template +template RelatedViewgrams& -RelatedViewgrams:: -operator-= (const RelatedViewgrams& arg) -{ +RelatedViewgrams::operator-=(const RelatedViewgrams& arg) { assert(get_num_viewgrams() == arg.get_num_viewgrams()); - iterator iter = begin(); + iterator iter = begin(); const_iterator arg_iter = arg.begin(); - for ( ; iter != end(); ++iter, ++arg_iter) + for (; iter != end(); ++iter, ++arg_iter) *iter -= *arg_iter; return *this; } - - template -elemT -RelatedViewgrams:: -find_max() const -{ - Array<1,elemT> max_per_viewgram(get_num_viewgrams()); - typename Array<1,elemT>::iterator max_iter = max_per_viewgram.begin(); - const_iterator iter = begin(); - while (iter != end()) - { +elemT +RelatedViewgrams::find_max() const { + Array<1, elemT> max_per_viewgram(get_num_viewgrams()); + typename Array<1, elemT>::iterator max_iter = max_per_viewgram.begin(); + const_iterator iter = begin(); + while (iter != end()) { *max_iter = iter->find_max(); - ++iter; ++ max_iter; + ++iter; + ++max_iter; } return max_per_viewgram.find_max(); } template -elemT -RelatedViewgrams:: -find_min() const -{ - Array<1,elemT> min_per_viewgram(get_num_viewgrams()); - typename Array<1,elemT>::iterator min_iter = min_per_viewgram.begin(); - const_iterator iter = begin(); - while (iter != end()) - { +elemT +RelatedViewgrams::find_min() const { + Array<1, elemT> min_per_viewgram(get_num_viewgrams()); + typename Array<1, elemT>::iterator min_iter = min_per_viewgram.begin(); + const_iterator iter = begin(); + while (iter != end()) { *min_iter = iter->find_min(); - ++iter; ++ min_iter; + ++iter; + ++min_iter; } return min_per_viewgram.find_min(); } - template -void -RelatedViewgrams::fill(const elemT &n) -{ - for (iterator iter = begin(); iter != end(); ++iter) +void +RelatedViewgrams::fill(const elemT& n) { + for (iterator iter = begin(); iter != end(); ++iter) iter->fill(n); } -/*! +/*! This function is necessary because it modifies the size of - each viewgram sequentially. This is not allowed by an external + each viewgram sequentially. This is not allowed by an external function, and leads to different proj_data_info_ptrs anyway. So, it would be caught by an assert at some point. */ template -void RelatedViewgrams:: -grow(const IndexRange<2>& range) -{ +void +RelatedViewgrams::grow(const IndexRange<2>& range) { check_state(); - if (begin()==end()) + if (begin() == end()) return; if (range == begin()->get_index_range()) return; - assert(range.is_regular()==true); + assert(range.is_regular() == true); // first construct a new appropriate ProjDataInfo object const int ax_min = range.get_min_index(); const int ax_max = range.get_max_index(); - + shared_ptr pdi_ptr(get_proj_data_info_sptr()->clone()); // set axial_pos range for all segments - for (const_iterator iter= begin(); - iter != end(); - ++iter) - { + for (const_iterator iter = begin(); iter != end(); ++iter) { pdi_ptr->set_min_axial_pos_num(ax_min, iter->get_segment_num()); pdi_ptr->set_max_axial_pos_num(ax_max, iter->get_segment_num()); } @@ -355,21 +289,17 @@ grow(const IndexRange<2>& range) pdi_ptr->set_max_tangential_pos_num(range[ax_min].get_max_index()); shared_ptr pdi_shared_ptr = pdi_ptr; - // now resize each viewgram + // now resize each viewgram // this will not set their respective proj_data_info_ptr correctly though, // so, we have to construct new viewgrams for this - for (iterator iter= begin(); - iter != end(); - ++iter) - { + for (iterator iter = begin(); iter != end(); ++iter) { iter->grow(range); - *iter = Viewgram(*iter, pdi_shared_ptr, - iter->get_view_num(), iter->get_segment_num()); + *iter = Viewgram(*iter, pdi_shared_ptr, iter->get_view_num(), iter->get_segment_num(), iter->get_timing_pos_num()); } check_state(); } -/* +/* TODO #include "stir/zoom.h" @@ -389,13 +319,13 @@ void RelatedViewgrams::zoom(const float zoom, const float Xoffp, const fl */ /* template -void RelatedViewgrams::grow_num_bins(const int new_min_bin_num, - const int new_max_bin_num) +void RelatedViewgrams::grow_num_bins(const int new_min_bin_num, + const int new_max_bin_num) { for (vector::iterator iter= viewgrams.begin(); iter != viewgrams.end(); iter++) - (*iter).grow_width(new_min_bin_num, new_max_bin_num); + (*iter).grow_width(new_min_bin_num, new_max_bin_num); } */ diff --git a/src/buildblock/SSRB.cxx b/src/buildblock/SSRB.cxx index 2db55baa52..1c1447a7a1 100644 --- a/src/buildblock/SSRB.cxx +++ b/src/buildblock/SSRB.cxx @@ -46,285 +46,198 @@ START_NAMESPACE_STIR // TODO this function needs work to reliable handle segments with unequal 'num_segments_to_combine' (as GE Advance) // parts with 'num_segments_to_combine' should be revised, all the rest is fine -ProjDataInfo * -SSRB(const ProjDataInfo& in_proj_data_info, - const int num_segments_to_combine, - const int num_views_to_combine, - const int num_tang_poss_to_trim, - const int max_in_segment_num_to_process_argument, - const int num_tof_bins_to_combine - ) -{ - if (num_tof_bins_to_combine!=1) - error("SSRB: num_tof_bins_to_combine (%d) currently needs to be 1", - num_tof_bins_to_combine); - if (num_segments_to_combine%2==0) - error("SSRB: num_segments_to_combine (%d) needs to be odd\n", - num_segments_to_combine); - const int max_in_segment_num_to_process = - max_in_segment_num_to_process_argument >= 0 - ? max_in_segment_num_to_process_argument - : in_proj_data_info.get_max_segment_num(); +ProjDataInfo* +SSRB(const ProjDataInfo& in_proj_data_info, const int num_segments_to_combine, const int num_views_to_combine, + const int num_tang_poss_to_trim, const int max_in_segment_num_to_process_argument, const int num_tof_bins_to_combine) { + if (num_tof_bins_to_combine != 1) + error("SSRB: num_tof_bins_to_combine (%d) currently needs to be 1", num_tof_bins_to_combine); + if (num_segments_to_combine % 2 == 0) + error("SSRB: num_segments_to_combine (%d) needs to be odd\n", num_segments_to_combine); + const int max_in_segment_num_to_process = max_in_segment_num_to_process_argument >= 0 ? max_in_segment_num_to_process_argument + : in_proj_data_info.get_max_segment_num(); if (in_proj_data_info.get_max_segment_num() < max_in_segment_num_to_process) error("SSRB: max_in_segment_num_to_process (%d) is too large\n" - "Input data has maximum segment number %d.", - max_in_segment_num_to_process, - in_proj_data_info.get_max_segment_num()); - if (in_proj_data_info.get_num_tangential_poss() <= - num_tang_poss_to_trim) - error("SSRB: too large number of tangential positions to trim (%d)\n", - num_tang_poss_to_trim); - const ProjDataInfoCylindrical * const in_proj_data_info_sptr = - dynamic_cast - (&in_proj_data_info); - if (in_proj_data_info_sptr== NULL) - { - error("SSRB works only on segments with proj_data_info of " - "type ProjDataInfoCylindrical\n"); - } - ProjDataInfoCylindrical * out_proj_data_info_sptr = - dynamic_cast - (in_proj_data_info_sptr->clone()); - - out_proj_data_info_sptr-> - set_num_views( - in_proj_data_info.get_num_views()/ - num_views_to_combine); - out_proj_data_info_sptr-> - set_num_tangential_poss(in_proj_data_info.get_num_tangential_poss() - - num_tang_poss_to_trim); + "Input data has maximum segment number %d.", + max_in_segment_num_to_process, in_proj_data_info.get_max_segment_num()); + if (in_proj_data_info.get_num_tangential_poss() <= num_tang_poss_to_trim) + error("SSRB: too large number of tangential positions to trim (%d)\n", num_tang_poss_to_trim); + const ProjDataInfoCylindrical* const in_proj_data_info_sptr = dynamic_cast(&in_proj_data_info); + if (in_proj_data_info_sptr == NULL) { + error("SSRB works only on segments with proj_data_info of " + "type ProjDataInfoCylindrical\n"); + } + ProjDataInfoCylindrical* out_proj_data_info_sptr = dynamic_cast(in_proj_data_info_sptr->clone()); + + out_proj_data_info_sptr->set_num_views(in_proj_data_info.get_num_views() / num_views_to_combine); + out_proj_data_info_sptr->set_num_tangential_poss(in_proj_data_info.get_num_tangential_poss() - num_tang_poss_to_trim); // Find new maximum segment_num - // To understand this formula, check how the out_segment_num is related to + // To understand this formula, check how the out_segment_num is related to // the in_segment_num below - const int out_max_segment_num = - ((max_in_segment_num_to_process == -1 - ? in_proj_data_info.get_max_segment_num() - : max_in_segment_num_to_process - )-(num_segments_to_combine/2))/num_segments_to_combine; - if (out_max_segment_num <0) - error("SSRB: max_in_segment_num_to_process %d is too small. No output segments\n", - max_in_segment_num_to_process); + const int out_max_segment_num = + ((max_in_segment_num_to_process == -1 ? in_proj_data_info.get_max_segment_num() : max_in_segment_num_to_process) - + (num_segments_to_combine / 2)) / + num_segments_to_combine; + if (out_max_segment_num < 0) + error("SSRB: max_in_segment_num_to_process %d is too small. No output segments\n", max_in_segment_num_to_process); const int in_axial_compression = - in_proj_data_info_sptr->get_max_ring_difference(0) - - in_proj_data_info_sptr->get_min_ring_difference(0) - + 1; - - out_proj_data_info_sptr->reduce_segment_range(-out_max_segment_num,out_max_segment_num); - for (int out_segment_num = -out_max_segment_num; - out_segment_num <= out_max_segment_num; - ++out_segment_num) + in_proj_data_info_sptr->get_max_ring_difference(0) - in_proj_data_info_sptr->get_min_ring_difference(0) + 1; + + out_proj_data_info_sptr->reduce_segment_range(-out_max_segment_num, out_max_segment_num); + for (int out_segment_num = -out_max_segment_num; out_segment_num <= out_max_segment_num; ++out_segment_num) { + const int in_min_segment_num = out_segment_num * num_segments_to_combine - num_segments_to_combine / 2; + const int in_max_segment_num = out_segment_num * num_segments_to_combine + num_segments_to_combine / 2; + out_proj_data_info_sptr->set_min_ring_difference(in_proj_data_info_sptr->get_min_ring_difference(in_min_segment_num), + out_segment_num); + out_proj_data_info_sptr->set_max_ring_difference(in_proj_data_info_sptr->get_max_ring_difference(in_max_segment_num), + out_segment_num); + + out_proj_data_info_sptr->set_min_axial_pos_num(0, out_segment_num); + + // find number of axial_poss in out_segment + // get_m could be replaced by get_t { - const int in_min_segment_num = out_segment_num*num_segments_to_combine - num_segments_to_combine/2; - const int in_max_segment_num = out_segment_num*num_segments_to_combine + num_segments_to_combine/2; - out_proj_data_info_sptr-> - set_min_ring_difference(in_proj_data_info_sptr->get_min_ring_difference(in_min_segment_num), - out_segment_num); - out_proj_data_info_sptr-> - set_max_ring_difference(in_proj_data_info_sptr->get_max_ring_difference(in_max_segment_num), - out_segment_num); - - out_proj_data_info_sptr-> - set_min_axial_pos_num(0,out_segment_num); - - // find number of axial_poss in out_segment - // get_m could be replaced by get_t - { - float min_m =1.E37F; - float max_m =-1.E37F; - for (int in_segment_num = in_min_segment_num; - in_segment_num <= in_max_segment_num; - ++in_segment_num) - { - if (in_axial_compression != - (in_proj_data_info_sptr->get_max_ring_difference(in_segment_num) - - in_proj_data_info_sptr->get_min_ring_difference(in_segment_num) + - 1)) - warning("SSRB: in_proj_data_info with non-identical axial compression for all segments.\n" - "That's ok, but results might not be what you expect.\n"); - - min_m = - min(min_m, - in_proj_data_info_sptr-> - get_m(Bin(in_segment_num,0,in_proj_data_info_sptr->get_min_axial_pos_num(in_segment_num), 0))); - max_m = - max(max_m, - in_proj_data_info_sptr-> - get_m(Bin(in_segment_num,0,in_proj_data_info_sptr->get_max_axial_pos_num(in_segment_num), 0))); - } - const float number_of_ms = - (max_m - min_m)/out_proj_data_info_sptr->get_axial_sampling(out_segment_num)+1; - if (fabs(round(number_of_ms)-number_of_ms) > 1.E-3) - error("SSRB: number of axial positions to be found in out_segment %d is non-integer %g\n", - out_segment_num, number_of_ms); - out_proj_data_info_sptr-> - set_max_axial_pos_num(round(number_of_ms) - 1, - out_segment_num); + float min_m = 1.E37F; + float max_m = -1.E37F; + for (int in_segment_num = in_min_segment_num; in_segment_num <= in_max_segment_num; ++in_segment_num) { + if (in_axial_compression != (in_proj_data_info_sptr->get_max_ring_difference(in_segment_num) - + in_proj_data_info_sptr->get_min_ring_difference(in_segment_num) + 1)) + warning("SSRB: in_proj_data_info with non-identical axial compression for all segments.\n" + "That's ok, but results might not be what you expect.\n"); + + min_m = min(min_m, in_proj_data_info_sptr->get_m( + Bin(in_segment_num, 0, in_proj_data_info_sptr->get_min_axial_pos_num(in_segment_num), 0))); + max_m = max(max_m, in_proj_data_info_sptr->get_m( + Bin(in_segment_num, 0, in_proj_data_info_sptr->get_max_axial_pos_num(in_segment_num), 0))); } + const float number_of_ms = (max_m - min_m) / out_proj_data_info_sptr->get_axial_sampling(out_segment_num) + 1; + if (fabs(round(number_of_ms) - number_of_ms) > 1.E-3) + error("SSRB: number of axial positions to be found in out_segment %d is non-integer %g\n", out_segment_num, number_of_ms); + out_proj_data_info_sptr->set_max_axial_pos_num(round(number_of_ms) - 1, out_segment_num); } + } + + if (num_tof_bins_to_combine != 1) { + if (num_tof_bins_to_combine < 1) + error("SSRB: num_tof_bins_to_combine needs to be at least 1"); + const int new_tof_mash_factor = in_proj_data_info_sptr->get_tof_mash_factor() * num_tof_bins_to_combine; + out_proj_data_info_sptr->set_tof_mash_factor(new_tof_mash_factor); + } return out_proj_data_info_sptr; } -void -SSRB(const string& output_filename, - const ProjData& in_proj_data, - const int num_segments_to_combine, - const int num_views_to_combine, - const int num_tang_poss_to_trim, - const bool do_norm, - const int max_in_segment_num_to_process, - const int num_tof_bins_to_combine - ) -{ - shared_ptr out_proj_data_info_sptr( - SSRB(*in_proj_data.get_proj_data_info_sptr(), - num_segments_to_combine, - num_views_to_combine, - num_tang_poss_to_trim, - max_in_segment_num_to_process, - num_tof_bins_to_combine - )); - ProjDataInterfile out_proj_data(in_proj_data.get_exam_info_sptr(), - out_proj_data_info_sptr, output_filename, std::ios::out); +void +SSRB(const string& output_filename, const ProjData& in_proj_data, const int num_segments_to_combine, + const int num_views_to_combine, const int num_tang_poss_to_trim, const bool do_norm, const int max_in_segment_num_to_process, + const int num_tof_bins_to_combine) { + shared_ptr out_proj_data_info_sptr(SSRB(*in_proj_data.get_proj_data_info_sptr(), num_segments_to_combine, + num_views_to_combine, num_tang_poss_to_trim, + max_in_segment_num_to_process, num_tof_bins_to_combine)); + ProjDataInterfile out_proj_data(in_proj_data.get_exam_info_sptr(), out_proj_data_info_sptr, output_filename, std::ios::out); SSRB(out_proj_data, in_proj_data, do_norm); } -void -SSRB(ProjData& out_proj_data, - const ProjData& in_proj_data, - const bool do_norm - ) -{ +void +SSRB(ProjData& out_proj_data, const ProjData& in_proj_data, const bool do_norm) { + if (in_proj_data.get_proj_data_info_sptr()->is_tof_data()) + error("SSRB for TOF data is not currently implemented.\n"); + const shared_ptr in_proj_data_info_sptr = - dynamic_pointer_cast - (in_proj_data.get_proj_data_info_sptr()); - if (is_null_ptr(in_proj_data_info_sptr)) - { + dynamic_pointer_cast(in_proj_data.get_proj_data_info_sptr()); + if (is_null_ptr(in_proj_data_info_sptr)) { error("SSRB works only on segments with proj_data_info of " - "type ProjDataInfoCylindrical\n"); + "type ProjDataInfoCylindrical\n"); } const shared_ptr out_proj_data_info_sptr = - dynamic_pointer_cast - (out_proj_data.get_proj_data_info_sptr()); - if (is_null_ptr(out_proj_data_info_sptr)) - { + dynamic_pointer_cast(out_proj_data.get_proj_data_info_sptr()); + if (is_null_ptr(out_proj_data_info_sptr)) { error("SSRB works only on segments with proj_data_info of " - "type ProjDataInfoCylindrical\n"); + "type ProjDataInfoCylindrical\n"); } - const int num_views_to_combine = - in_proj_data.get_num_views()/ out_proj_data.get_num_views(); - + const int num_views_to_combine = in_proj_data.get_num_views() / out_proj_data.get_num_views(); - if (in_proj_data.get_min_view_num()!=0 || out_proj_data.get_min_view_num()!=0) - error ("SSRB can only mash views when min_view_num==0\n"); + if (in_proj_data.get_min_view_num() != 0 || out_proj_data.get_min_view_num() != 0) + error("SSRB can only mash views when min_view_num==0\n"); if (in_proj_data.get_num_views() % out_proj_data.get_num_views()) - error ("SSRB can only mash views when out_num_views divides in_num_views\n"); - - for (int out_segment_num = out_proj_data.get_min_segment_num(); - out_segment_num <= out_proj_data.get_max_segment_num(); - ++out_segment_num) + error("SSRB can only mash views when out_num_views divides in_num_views\n"); + + for (int out_segment_num = out_proj_data.get_min_segment_num(); out_segment_num <= out_proj_data.get_max_segment_num(); + ++out_segment_num) { + // find range of input segments that fit in the current output segment + int in_min_segment_num = in_proj_data.get_max_segment_num(); + int in_max_segment_num = in_proj_data.get_min_segment_num(); { - // find range of input segments that fit in the current output segment - int in_min_segment_num = in_proj_data.get_max_segment_num(); - int in_max_segment_num = in_proj_data.get_min_segment_num(); - { - // this the only place where we need ProjDataInfoCylindrical - // Presumably for other types, there'd be something equivalent (say range of theta) - const int out_min_ring_diff = - out_proj_data_info_sptr->get_min_ring_difference(out_segment_num); - const int out_max_ring_diff = - out_proj_data_info_sptr->get_max_ring_difference(out_segment_num); - for (int in_segment_num = in_proj_data.get_min_segment_num(); - in_segment_num <= in_proj_data.get_max_segment_num(); - ++in_segment_num) - { - const int in_min_ring_diff = - in_proj_data_info_sptr->get_min_ring_difference(in_segment_num); - const int in_max_ring_diff = - in_proj_data_info_sptr->get_max_ring_difference(in_segment_num); - if (in_min_ring_diff >= out_min_ring_diff && - in_max_ring_diff <= out_max_ring_diff) - { - // it's a in_segment that should be rebinned in the out_segment - if (in_min_segment_num > in_segment_num) - in_min_segment_num = in_segment_num; - if (in_max_segment_num < in_segment_num) - in_max_segment_num = in_segment_num; - } - else if (in_min_ring_diff > out_max_ring_diff || - in_max_ring_diff < out_min_ring_diff) - { - // this one is outside the range of the out_segment - } - else - { - error("SSRB called with in and out ring difference ranges that overlap:\n" - "in_segment %d has ring diffs (%d,%d)\n" - "out_segment %d has ring diffs (%d,%d)\n", - in_segment_num, in_min_ring_diff, in_max_ring_diff, - in_segment_num, out_min_ring_diff, out_max_ring_diff); - } - } - - // keep sinograms out of the loop to avoid reallocations - // initialise to something because there's no default constructor - Sinogram out_sino = - out_proj_data.get_empty_sinogram(out_proj_data.get_min_axial_pos_num(out_segment_num),out_segment_num); - Sinogram in_sino = - in_proj_data.get_empty_sinogram(in_proj_data.get_min_axial_pos_num(out_segment_num),out_segment_num); - - for (int out_ax_pos_num = out_proj_data.get_min_axial_pos_num(out_segment_num); - out_ax_pos_num <= out_proj_data.get_max_axial_pos_num(out_segment_num); - ++out_ax_pos_num ) - { - out_sino= out_proj_data.get_empty_sinogram(out_ax_pos_num, out_segment_num); - // get_m could be replaced by get_t - const float out_m = out_proj_data_info_sptr->get_m(Bin(out_segment_num,0, out_ax_pos_num, 0)); - - unsigned int num_in_ax_pos = 0; - - for (int in_segment_num = in_min_segment_num; - in_segment_num <= in_max_segment_num; - ++in_segment_num) - for (int in_ax_pos_num = in_proj_data.get_min_axial_pos_num(in_segment_num); - in_ax_pos_num <= in_proj_data.get_max_axial_pos_num(in_segment_num); - ++in_ax_pos_num ) - { - const float in_m = in_proj_data_info_sptr->get_m(Bin(in_segment_num,0, in_ax_pos_num, 0)); - if (fabs(out_m - in_m) < 1E-4) - { - ++num_in_ax_pos; - - in_sino = in_proj_data.get_sinogram(in_ax_pos_num, in_segment_num); - for (int in_view_num=in_proj_data.get_min_view_num(); - in_view_num <= in_proj_data.get_max_view_num(); - ++in_view_num) - for (int tangential_pos_num= - max(in_proj_data.get_min_tangential_pos_num(), - out_proj_data.get_min_tangential_pos_num()); - tangential_pos_num <= - min(in_proj_data.get_max_tangential_pos_num(), - out_proj_data.get_max_tangential_pos_num()); - ++tangential_pos_num) - out_sino[in_view_num/num_views_to_combine][tangential_pos_num] += - in_sino[in_view_num][tangential_pos_num]; - - break; // out of loop over ax_pos as we found where to put it - } - } - if (do_norm && num_in_ax_pos!=0) - out_sino /= static_cast(num_in_ax_pos*num_views_to_combine); - if (num_in_ax_pos==0) - warning("SSRB: no sinograms contributing to output segment %d, ax_pos %d\n", - out_segment_num, out_ax_pos_num); - - out_proj_data.set_sinogram(out_sino); - } + // this the only place where we need ProjDataInfoCylindrical + // Presumably for other types, there'd be something equivalent (say range of theta) + const int out_min_ring_diff = out_proj_data_info_sptr->get_min_ring_difference(out_segment_num); + const int out_max_ring_diff = out_proj_data_info_sptr->get_max_ring_difference(out_segment_num); + for (int in_segment_num = in_proj_data.get_min_segment_num(); in_segment_num <= in_proj_data.get_max_segment_num(); + ++in_segment_num) { + const int in_min_ring_diff = in_proj_data_info_sptr->get_min_ring_difference(in_segment_num); + const int in_max_ring_diff = in_proj_data_info_sptr->get_max_ring_difference(in_segment_num); + if (in_min_ring_diff >= out_min_ring_diff && in_max_ring_diff <= out_max_ring_diff) { + // it's a in_segment that should be rebinned in the out_segment + if (in_min_segment_num > in_segment_num) + in_min_segment_num = in_segment_num; + if (in_max_segment_num < in_segment_num) + in_max_segment_num = in_segment_num; + } else if (in_min_ring_diff > out_max_ring_diff || in_max_ring_diff < out_min_ring_diff) { + // this one is outside the range of the out_segment + } else { + error("SSRB called with in and out ring difference ranges that overlap:\n" + "in_segment %d has ring diffs (%d,%d)\n" + "out_segment %d has ring diffs (%d,%d)\n", + in_segment_num, in_min_ring_diff, in_max_ring_diff, in_segment_num, out_min_ring_diff, out_max_ring_diff); + } + } + + // keep sinograms out of the loop to avoid reallocations + // initialise to something because there's no default constructor + Sinogram out_sino = + out_proj_data.get_empty_sinogram(out_proj_data.get_min_axial_pos_num(out_segment_num), out_segment_num); + Sinogram in_sino = + in_proj_data.get_empty_sinogram(in_proj_data.get_min_axial_pos_num(out_segment_num), out_segment_num); + + for (int out_ax_pos_num = out_proj_data.get_min_axial_pos_num(out_segment_num); + out_ax_pos_num <= out_proj_data.get_max_axial_pos_num(out_segment_num); ++out_ax_pos_num) { + out_sino = out_proj_data.get_empty_sinogram(out_ax_pos_num, out_segment_num); + // get_m could be replaced by get_t + const float out_m = out_proj_data_info_sptr->get_m(Bin(out_segment_num, 0, out_ax_pos_num, 0)); + + unsigned int num_in_ax_pos = 0; + + for (int in_segment_num = in_min_segment_num; in_segment_num <= in_max_segment_num; ++in_segment_num) + for (int in_ax_pos_num = in_proj_data.get_min_axial_pos_num(in_segment_num); + in_ax_pos_num <= in_proj_data.get_max_axial_pos_num(in_segment_num); ++in_ax_pos_num) { + const float in_m = in_proj_data_info_sptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num, 0)); + if (fabs(out_m - in_m) < 1E-4) { + ++num_in_ax_pos; + + in_sino = in_proj_data.get_sinogram(in_ax_pos_num, in_segment_num); + for (int in_view_num = in_proj_data.get_min_view_num(); in_view_num <= in_proj_data.get_max_view_num(); + ++in_view_num) + for (int tangential_pos_num = + max(in_proj_data.get_min_tangential_pos_num(), out_proj_data.get_min_tangential_pos_num()); + tangential_pos_num <= + min(in_proj_data.get_max_tangential_pos_num(), out_proj_data.get_max_tangential_pos_num()); + ++tangential_pos_num) + out_sino[in_view_num / num_views_to_combine][tangential_pos_num] += in_sino[in_view_num][tangential_pos_num]; + + break; // out of loop over ax_pos as we found where to put it + } + } + if (do_norm && num_in_ax_pos != 0) + out_sino /= static_cast(num_in_ax_pos * num_views_to_combine); + if (num_in_ax_pos == 0) + warning("SSRB: no sinograms contributing to output segment %d, ax_pos %d\n", out_segment_num, out_ax_pos_num); + + out_proj_data.set_sinogram(out_sino); } } + } } END_NAMESPACE_STIR diff --git a/src/buildblock/Scanner.cxx b/src/buildblock/Scanner.cxx index 51a7a1301d..9cdd51b7c4 100644 --- a/src/buildblock/Scanner.cxx +++ b/src/buildblock/Scanner.cxx @@ -3,6 +3,7 @@ Copyright (C) 2000 - 2010-07-21, Hammersmith Imanet Ltd Copyright (C) 2011, Kris Thielemans Copyright (C) 2010-2013, King's College London + Copyright (C) 2016, University of Hull Copyright (C) 2013-2016,2019,2020 University College London Copyright (C) 2017-2018, University of Leeds This file is part of STIR. @@ -44,12 +45,11 @@ #include #include #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif - #ifndef STIR_NO_NAMESPACES using std::cerr; using std::cout; @@ -62,865 +62,722 @@ using std::list; START_NAMESPACE_STIR // local convenience functions to make a list of strings -static list - string_list(const string&); -static list - string_list(const string&, const string&); -static list - string_list(const string&, const string&, const string&); -static list - string_list(const string&, const string&, const string&, const string&); -static list - string_list(const string&, const string&, const string&, const string&, const string&); - +static list string_list(const string&); +static list string_list(const string&, const string&); +static list string_list(const string&, const string&, const string&); +static list string_list(const string&, const string&, const string&, const string&); +static list string_list(const string&, const string&, const string&, const string&, const string&); - -Scanner::Scanner(Type scanner_type) -{ +Scanner::Scanner(Type scanner_type) { // set_params parameters: // // Type type_v, // const list& list_of_names_v, // - // int num_rings_v, - // int max_num_non_arccorrected_bins_v, - // (optional) int default_num_arccorrected_bins_v, + // int num_rings_v, + // int max_num_non_arccorrected_bins_v, + // (optional) int default_num_arccorrected_bins_v, // int num_detectors_per_ring_v, // // float inner_ring_radius_v, // float average_depth_of_interaction_v, // float ring_spacing_v, - // float bin_size_v, + // float bin_size_v, // float intrinsic_tilt_v, // - // int num_axial_blocks_per_bucket_v, - // int num_transaxial_blocks_per_bucket_v, - // int num_axial_crystals_per_block_v, + // int num_axial_blocks_per_bucket_v, + // int num_transaxial_blocks_per_bucket_v, + // int num_axial_crystals_per_block_v, // int num_transaxial_crystals_per_block_v, // int num_axial_crystals_per_singles_unit_v, // int num_transaxial_crystals_per_singles_unit_v, // int num_detector_layers_v // - /* for CTI scanners (at least upto 966): - before arc-correction, central_bin_size ~= ring_radius* pi/num_detectors - num_transaxial_crystals_per_singles_unit= + before arc-correction, central_bin_size ~= ring_radius* pi/num_detectors + num_transaxial_crystals_per_singles_unit= transaxial_blocks_per_bucket*transaxial_crystals_per_block - num_axial_crystals_per_singles_unit= + num_axial_crystals_per_singles_unit= axial_crystals_per_block * x where x=1 except for the 966 where x=2 */ - - switch ( scanner_type ) { + switch (scanner_type) { case E931: // KT 25/01/2002 corrected ring_spacing - set_params(E931, string_list("ECAT 931"), - 8, 192, 2 * 256, - 510.0F, 7.0F, 13.5F, 3.129F, 0.0F, - 2, 4, 4, 8, 4, 8 * 4, 1, - 0.37f, 511.f); + set_params(E931, string_list("ECAT 931"), 8, 192, 192, 2 * 256, 510.0F, 7.0F, 13.5F, 3.129F, 0.0F, 2, 4, 4, 8, 4, 8 * 4, 1, + 0.37F, 511.F, 0, 0.F, 0.F); // 16 BUCKETS per ring in TWO rings - i.e. 32 buckets in total break; case E951: - set_params(E951, string_list("ECAT 951"), - 16, 192, 2 * 256, - 510.0F, 7.0F, 6.75F, 3.12932F, 0.0F, - 1, 4, 8, 8, 8, 8 * 4, 1); + set_params(E951, string_list("ECAT 951"), 16, 192, 192, 2 * 256, 510.0F, 7.0F, 6.75F, 3.12932F, 0.0F, 1, 4, 8, 8, 8, 8 * 4, 1, + 0.0F, 511.F, 0, 0.F, 0.F); break; case E953: - set_params(E953, string_list("ECAT 953"), - 16, 160, 2 * 192, - 382.5F, 7.0F, 6.75F, 3.12932F, static_cast(15.*_PI/180), - 1, 4, 8, 8, 8, 8 * 4, 1); + set_params(E953, string_list("ECAT 953"), 16, 160, 160, 2 * 192, 382.5F, 7.0F, 6.75F, 3.12932F, + static_cast(15. * _PI / 180), 1, 4, 8, 8, 8, 8 * 4, 1, 0.0F, 511.F, 0, 0.F, 0.F); break; case E921: - set_params(E921, string_list("ECAT 921", "ECAT EXACT", "EXACT"), - 24, 192, 2* 192, - 412.5F, 7.0F, 6.75F, 3.375F, static_cast(15.*_PI/180), - 1, 4, 8, 8, 8, 8 * 4, 1); + set_params(E921, string_list("ECAT 921", "ECAT EXACT", "EXACT"), 24, 192, 192, 2 * 192, 412.5F, 7.0F, 6.75F, 3.375F, + static_cast(15. * _PI / 180), 1, 4, 8, 8, 8, 8 * 4, 1, 0.0F, 511.F, 0, 0.F, 0.F); break; case E925: - - set_params(E925, string_list("ECAT 925", "ECAT ART"), - 24, 192, 2* 192, - 412.5F, 7.0F, 6.75F, 3.375F, static_cast(15.*_PI/180), - 3, 4, 8, 8, 8, 8 * 4, 1); + + set_params(E925, string_list("ECAT 925", "ECAT ART"), 24, 192, 192, 2 * 192, 412.5F, 7.0F, 6.75F, 3.375F, + static_cast(15. * _PI / 180), 3, 4, 8, 8, 8, 8 * 4, 1, 0.0F, 511.F, 0, 0.F, 0.F); break; - case E961: - set_params(E961,string_list("ECAT 961", "ECAT HR"), - 24, 336, 2* 392, - 412.0F, 7.0F, 6.25F, 1.650F, static_cast(13.*_PI/180), - 1, 8, 8, 7, 8, 7 * 8, 1); - break; + set_params(E961, string_list("ECAT 961", "ECAT HR"), 24, 336, 336, 2 * 392, 412.0F, 7.0F, 6.25F, 1.650F, + static_cast(13. * _PI / 180), 1, 8, 8, 7, 8, 7 * 8, 1, 0.0F, 511.F, 0, 0.F, 0.F); + break; case E962: - set_params(E962,string_list("ECAT 962","ECAT HR+"), - 32, 288, 2* 288, - 412.0F, 7.0F, 4.85F, 2.25F, 0.0F, - 4, 3, 8, 8, 8, 8 * 3, 1); + set_params(E962, string_list("ECAT 962", "ECAT HR+"), 32, 288, 288, 2 * 288, 412.0F, 7.0F, 4.85F, 2.25F, 0.0F, 4, 3, 8, 8, 8, + 8 * 3, 1, 0.0F, 511.F, 0, 0.F, 0.F); break; case E966: - set_params(E966, string_list("ECAT EXACT 3D", "EXACT 3D", "ECAT HR++","ECAT 966"), - 48, 288, 2* 288, - 412.0F, 7.0F, 4.850F, 2.250F, 0.0, - 6, 2, 8, 8, 2 * 8, 8 * 2, 1); - break; + set_params(E966, string_list("ECAT EXACT 3D", "EXACT 3D", "ECAT HR++", "ECAT 966"), 48, 288, 288, 2 * 288, 412.0F, 7.0F, + 4.850F, 2.250F, 0.0, 6, 2, 8, 8, 2 * 8, 8 * 2, 1, 0.0F, 511.F, 0, 0.F, 0.F); + break; case E1080: // data added by Robert Barnett, Westmead Hospital, Sydney - set_params(E1080, string_list("ECAT 1080", "Biograph 16", "1080"), - 41, 336, 2* 336, - 412.0F, 7.0F, 4.0F, 2.000F, 0.0F, - 1, 2, 13+1, 13+1, 0, 0, 1);// TODO bucket/singles info? - // Transaxial blocks have 13 physical crystals and a gap at the + set_params(E1080, string_list("ECAT 1080", "Biograph 16", "1080"), 41, 336, 336, 2 * 336, 412.0F, 7.0F, 4.0F, 2.000F, 0.0F, 1, + 2, 13 + 1, 13 + 1, 0, 0, 1, 0.0F, 511.F, 0, 0.F, 0.F); + // Transaxial blocks have 13 physical crystals and a gap at the // 14th crystal where the counts are zero. - // There are 39 rings with 13 axial crystals per block. Two virtual - // rings are added, but contain counts after applying axial compression. + // There are 39 rings with 13 axial crystals per block. break; case Siemens_mMR: // 8x8 blocks, 1 virtual "crystal", 56 blocks along the ring, 8 blocks in axial direction - // Transaxial blocks have 8 physical crystals and a gap at the + // Transaxial blocks have 8 physical crystals and a gap at the // 9th crystal where the counts are zero. - set_params(Siemens_mMR, string_list("Siemens mMR", "mMR", "2008"), - 64, 344, 2* 252, - 328.0F, 7.0F, 4.0625F, 2.08626F, 0.0F, - 2, 1, 8, 9, 16, 9, 1, - 0.145f, 511.f); // TODO bucket/singles info incorrect? 224 buckets in total, but not sure how distributed + set_params(Siemens_mMR, string_list("Siemens mMR", "mMR", "2008"), 64, 344, 344, 2 * 252, 328.0F, 7.0F, 4.0625F, 2.08626F, + 0.0F, 2, 1, 8, 9, 16, 9, 1, 0.145F, 511.F, 0, 0.F, + 0.F); // TODO bucket/singles info incorrect? 224 buckets in total, but not sure how distributed + break; + + case test_scanner: + // This is a relatively small scanner for test purposes. + set_params(test_scanner, string_list("test_scanner"), 4, 344, 344, 2 * 252, 328.0F, 7.0F, 4.0625F, 2.08626F, 0.0F, 1, 1, 4, 1, + 4, 1, 1, 0.0F, 511.F, (short int)(410), (float)(10.0F), (float)(400.0F)); break; case Siemens_mCT: - // 13x13 blocks, 1 virtual "crystal" along axial and transaxial direction, 48 blocks along the ring, 4 blocks in axial direction - set_params(Siemens_mCT, string_list("Siemens mCT", "mCT", "2011", "1104" /* used in norm files */, "1094" /* used in attenuation files */), - 55, 400, (13+1)*48, - 421.0F, 7.0F, 4.054F, 2.005F, 0.0F, - 4, 1, 13+1, 13+1, 0,0, 1 ); // TODO singles info incorrect + // 13x13 blocks, 1 virtual "crystal" along axial and transaxial direction, 48 blocks along the ring, 4 blocks in axial + // direction + set_params(Siemens_mCT, + string_list("Siemens mCT", "mCT", "2011", "1104" /* used in norm files */, "1094" /* used in attenuation files */), + 55, 400, 336, (13 + 1) * 48, 421.0F, 7.0F, 4.054F, 2.005F, 0.0F, 4, 1, 13 + 1, 13 + 1, 0, 0, 1, + // energy + 0.F, 511.F, + // TOF TODO: timing res + 13, 4.0625 * 1000 / 13, -1.F); // TODO singles info incorrect // energy: 435-650 - // 13 TOF bins break; +// case PETMR_Signa: +// set_params(PETMR_Signa, string_list("GE Signa PET/MR", "PET/MR Signa", "Signa PET/MR"), +// 45, +// 357, +// 331, // TODO +// 2 * 224, +// 311.8F, +// 8.5F, +// 5.56F, +// 2.01565F, // TO CHECK +// static_cast(-5.23*_PI/180),//sign? TODO value +// 5, +// 4, +// 9, 4, 1, 1, 1, +// 0.105F, // energy resolution from Levin et al. TMI 2016 +// 511.F, +// (short int)(351), +// (float)(89.0F/13.0F), //TODO +// (float)(390.0F) ); +// break; + + case Vision_600: + set_params( + Vision_600, // type + string_list("Siemens Vision", "Vision", "1208"), // names + 80, // rings + 520, // max n non-arc-corr bins + 520, // default n arc-corr bins + 21*38, // num detector per ring + 420.0F, // inner ring radius (mm) + 7.0F, // unsure on this // avg DoI (mm) + 3.29114F, // ring spacing (mm) + 1.6F, // bin size (mm) + 0.0F, // intrinsic tilt + // 8 axial block, 38 transaxial blocks total, no buckets? + 1, 1, // n axial/trans blocks per bucket + 10, 21, // n axial/trans xtals per block + 10, 21, // n axial/trans xtals per singles unit + 1, // n detector layers + // energy + 0.F, 511.F, + 33, // max n timing position + 143.231, // timing position bin size + -1.F // ?? // timing resolution + ); + break; + + case RPT: - - set_params(RPT, string_list("PRT-1", "RPT"), - 16, 128, 2 * 192, - 380.0F - 7.0F, 7.0F, 6.75F, 3.1088F, 0.0F, - 1, 4, 8, 8, 8, 32, 1); + + set_params(RPT, string_list("PRT-1", "RPT"), 16, 128, 128, 2 * 192, 380.0F - 7.0F, 7.0F, 6.75F, 3.1088F, 0.0F, 1, 4, 8, 8, 8, + 32, 1, 0.0F, 511.F, 0, 0.F, 0.F); // Default 7.0mm average interaction depth. // This 7mm taken off the inner ring radius so that the effective radius remains 380mm - break; + break; case RATPET: - - set_params(RATPET, string_list("RATPET"), - 8, 56, 2 * 56, - 115 / 2.F, 7.0F, 6.25F, 1.65F, 0.0F, - 1, 16, 8, 7, 8, 0, 1); // HR block, 4 buckets per ring - + + set_params(RATPET, string_list("RATPET"), 8, 56, 56, 2 * 56, 115 / 2.F, 7.0F, 6.25F, 1.65F, 0.0F, 1, 16, 8, 7, 8, 0, 1, 0.0F, + 511.F, 0, 0.F, 0.F); // HR block, 4 buckets per ring + // Default 7.0mm average interaction depth. - // 8 x 0 crystals per singles unit because not known + // 8 x 0 crystals per singles unit because not known // although likely transaxial_blocks_per_bucket*transaxial_crystals_per_block break; case PANDA: - - set_params(PANDA, string_list("PANDA"), - 1 /*NumRings*/, 512 /*MaxBinsNonArcCor*/, 512 /*MaxBinsArcCor*/, 2048 /*NumDetPerRing*/, - /*MeanInnerRadius*/ 75.5/2.F, /*AverageDoI*/ 10.F, /*Ring Spacing*/ 3.F, /*BinSize*/ 0.1F, /*IntrinsicTilt*/ 0.F, - 1, 1, 1, 1, 0, 0, 1); + + set_params(PANDA, string_list("PANDA"), 1 /*NumRings*/, 512 /*MaxBinsNonArcCor*/, 512 /*MaxBinsArcCor*/, + 2048 /*NumDetPerRing*/, + /*MeanInnerRadius*/ 75.5 / 2.F, /*AverageDoI*/ 10.F, /*Ring Spacing*/ 3.F, /*BinSize*/ 0.1F, /*IntrinsicTilt*/ 0.F, + 1, 1, 1, 1, 0, 0, 1, 0.0F, 511.F, 0, 0.F, 0.F); break; - + case nanoPET: - - set_params(nanoPET, string_list("nanoPET"), /*Modelling the gap with one fake crystal */ - 81, 39*3, /* We could also model gaps in the future as one detector so 39->39+1, while 1 (point source), 3 (mouse) or 5 (rats) */ - 39*3, /* Just put the same with NonArcCor for now*/ - 12 * 39, 174.F, 5.0F, 1.17F, 1.17F, /* Actual size is 1.12 and 0.05 is the thickness of the optical reflector */ 0.0F, /* not sure for this */ - 0,0,0,0,0,0, 1); - break; + + set_params(nanoPET, string_list("nanoPET"), /*Modelling the gap with one fake crystal */ + 81, 39 * 3, /* We could also model gaps in the future as one detector so 39->39+1, while 1 (point source), 3 + (mouse) or 5 (rats) */ + 39 * 3, /* Just put the same with NonArcCor for now*/ + 12 * 39, 174.F, 5.0F, 1.17F, 1.17F, + /* Actual size is 1.12 and 0.05 is the thickness of the optical reflector */ 0.0F, /* not sure for this */ + 0, 0, 0, 0, 0, 0, 1, 0.0F, 511.F, 0, 0.F, 0.F); + break; case HYPERimage: - - set_params(HYPERimage, string_list("HYPERimage"), /*Modelling the gap with one fake crystal */ - 22, 239, 245, - 490, 103.97F, 3.0F, 1.4F, 1.4F, /* Actual size is 1.3667 and assume 0.0333 is the thickness of the optical reflector */ 0.F, - 0,0,0,0,0,0,1); - break; - - + + set_params(HYPERimage, string_list("HYPERimage"), /*Modelling the gap with one fake crystal */ + 22, 239, 245, 490, 103.97F, 3.0F, 1.4F, 1.4F, + /* Actual size is 1.3667 and assume 0.0333 is the thickness of the optical reflector */ 0.F, 0, 0, 0, 0, 0, 0, 1, + 0.0F, 511.F, 0, 0.F, 0.F); + break; + case Advance: - - // 283 bins (non-uniform sampling) + + // 283 bins (non-uniform sampling) // 281 bins (uniform sampling) /* crystal size 4x8x30*/ - set_params(Advance, string_list("GE Advance", "Advance"), - 18, 283, 281, 2 * 336, - 471.875F - 8.4F, 8.4F, 8.5F, 1.970177F, 0.0F, //TODO view offset shouldn't be zero - 3, 2, 6, 6, 1, 1, 1); - break; + set_params(Advance, string_list("GE Advance", "Advance"), 18, 283, 281, 2 * 336, 471.875F - 8.4F, 8.4F, 8.5F, 1.970177F, + 0.0F, // TODO view offset shouldn't be zero + 3, 2, 6, 6, 1, 1, 1, 0.0F, 511.F, 0, 0.F, 0.F); + break; case DiscoveryLS: // identical to Advance - set_params(DiscoveryLS, string_list("GE Discovery LS", "Discovery LS"), - 18, 283, 281, 2 * 336, - 471.875F - 8.4F, 8.4F, 8.5F, 1.970177F, 0.0F, //TODO view offset shouldn't be zero - 3, 2, 6, 6, 1, 1, 1); + set_params(DiscoveryLS, string_list("GE Discovery LS", "Discovery LS"), 18, 283, 281, 2 * 336, 471.875F - 8.4F, 8.4F, 8.5F, + 1.970177F, 0.0F, // TODO view offset shouldn't be zero + 3, 2, 6, 6, 1, 1, 1, 0.0F, 511.F, 0, 0.F, 0.F); break; - case DiscoveryST: + case DiscoveryST: - // 249 bins (non-uniform sampling) + // 249 bins (non-uniform sampling) // 221 bins (uniform sampling) /* crystal size: 6.3 x 6.3 x 30 mm*/ - set_params(DiscoveryST, string_list("GE Discovery ST", "Discovery ST"), - 24, 249, 221, 2 * 210, - 886.2F/2.F, 8.4F, 6.54F, 3.195F, - static_cast(-4.54224*_PI/180),//sign? - 4, 2, 6, 6, 1, 1, 1);// TODO not sure about sign of view_offset + set_params(DiscoveryST, string_list("GE Discovery ST", "Discovery ST"), 24, 249, 221, 2 * 210, 886.2F / 2.F, 8.4F, 6.54F, + 3.195F, + static_cast(-4.54224 * _PI / 180), // sign? + 4, 2, 6, 6, 1, 1, 1, 0.0F, 511.F, 0, 0.F, 0.F); // TODO not sure about sign of view_offset + break; + + case DiscoverySTE: + + set_params(DiscoverySTE, string_list("GE Discovery STE", "Discovery STE"), 24, 329, 293, 2 * 280, 886.2F / 2.F, 8.4F, 6.54F, + 2.397F, + static_cast(-4.5490 * _PI / 180), // sign? + 4, 2, 6, 8, 1, 1, 1, 0.0F, 511.F, (short int)(410), (float)(10.0F), + (float)(400.0F)); // TODO not sure about sign of view_offset + break; + + case DiscoverySTE_nonTOF: + + set_params(DiscoverySTE_nonTOF, string_list("GE Discovery STE nonTOF", "Discovery STE nonTOF"), 24, 329, 293, 2 * 280, + 886.2F / 2.F, 8.4F, 6.54F, 2.397F, + static_cast(-4.5490 * _PI / 180), // sign? + 4, 2, 6, 8, 1, 1, 1, 0.0F, 511.F, (short int)(0.F), (float)(0.F), + (float)(0.F)); // TODO not sure about sign of view_offset + break; + + case ntest_TOF_50: // dummy + // 8x8 blocks, 1 virtual "crystal", 56 blocks along the ring, 8 blocks in axial direction + // Transaxial blocks have 8 physical crystals and a gap at the + // 9th crystal where the counts are zero. + set_params(ntest_TOF_50, string_list("ntest_TOF_50"), 24, 320, 320, 666, 424.5F, 7.0F, 4.16F, 2.0F, 0.0F, 1, 1, 24, 1, 24, 1, + 1, 0.0f, 511.f, (short int)(2999), (float)(1.0F), + (float)(81.2)); // TODO bucket/singles info incorrect? 224 buckets in total, but not sure how di$ break; - case DiscoverySTE: + case DiscoveryRX: - set_params(DiscoverySTE, string_list("GE Discovery STE", "Discovery STE"), - 24, 329, 293, 2 * 280, - 886.2F/2.F, 8.4F, 6.54F, 2.397F, - static_cast(-4.5490*_PI/180),//sign? - 4, 2, 6, 8, 1, 1, 1);// TODO not sure about sign of view_offset + set_params(DiscoveryRX, string_list("GE Discovery RX", "Discovery RX"), 24, 367, 331, 2 * 315, 886.2F / 2.F, 9.4F, 6.54F, + 2.13F, + static_cast(-4.5950 * _PI / 180), // sign? + 4, 2, 6, 9, 1, 1, 1, 0.0F, 511.F, 1, 1.F, 1.F); // TODO not sure about sign of view_offset break; - case DiscoveryRX: - - set_params(DiscoveryRX, string_list("GE Discovery RX", "Discovery RX"), - 24, - 367, - 331, - 2 * 315, - 886.2F/2.F, - 9.4F, - 6.54F, 2.13F, - static_cast(-4.5950*_PI/180),//sign? - 4, - 2, - 6, 9, 1, 1, 1);// TODO not sure about sign of view_offset + case Discovery600: + + set_params(Discovery600, string_list("GE Discovery 600", "Discovery 600"), 24, 339, + 293, // TODO + 2 * 256, 826.70F / 2.F - 8.4F, 8.4F, 6.54F, 2.3974F, + static_cast(-4.5490 * _PI / 180), // sign? TODO value + 4, 2, 6, 8, 1, 1, 1, 0.0F, 511.F, 1, 1.F, 1.F); break; - case Discovery600: - - set_params(Discovery600, string_list("GE Discovery 600", "Discovery 600"), - 24, - 339, - 293, // TODO - 2 * 256, - 826.70F/2.F - 8.4F, - 8.4F, - 6.54F, - 2.3974F, - static_cast(-4.5490*_PI/180),//sign? TODO value - 4, - 2, - 6, 8, 1, 1, 1); + case PETMR_Signa: + set_params(PETMR_Signa, string_list("GE Signa PET/MR", "PET/MR Signa", "Signa PET/MR"), 45, 357, + 331, // TODO + 2 * 224, 311.8F, 8.5F, 5.56F, + 2.01565F, // TO CHECK + static_cast(-5.23 * _PI / 180), // sign? TODO value + 5, 4, 9, 4, 1, 1, 1, + 0.105F, // energy resolution from Levin et al. TMI 2016 + 511.F, (short int)(351), + (float)(89.0F / 13.0F), // TODO + (float)(390.0F)); break; + case PETMR_Signa_nonTOF: -case PETMR_Signa: - - set_params(PETMR_Signa, string_list("GE Signa PET/MR", "PET/MR Signa", "Signa PET/MR"), - 45, - 357, - 331, // TODO - 2 * 224, - 311.8F, - 8.5F, - 5.56F, - 2.01565F, // TO CHECK - static_cast(-5.23*_PI/180),//sign? TODO value - 5, - 4, - 9, 4, 1, 1, 1, - 0.105F, // energy resolution from Levin et al. TMI 2016 - 511.F); -break; + set_params(PETMR_Signa_nonTOF, string_list("GE PET/MR Signa nonTOF", "GE PET/MR Signa nonTOF"), 45, 357, + 331, // TODO + 2 * 224, 317.0F, 9.4F, 5.55F, + 2.1306F, // TO CHECK + static_cast(-5.23 * _PI / 180), // sign? TODO value + 5, 4, 9, 4, 1, 1, 1, + 0.105F, // energy resolution from Levin et al. TMI 2016 + 511.F, (short int)(0), + (float)(0), // TODO + (float)(0)); + break; case Discovery690: // same as 710 - set_params(Discovery690, string_list("GE Discovery 690", "Discovery 690", - "GE Discovery 710", "Discovery 710"), - 24, - 381, + set_params(Discovery690, string_list("GE Discovery 690", "Discovery 690", "GE Discovery 710", "Discovery 710"), 24, 381, 331, // TODO - 2 * 288, - 405.1F, - 9.4F, - 6.54F, - 2.1306F, - static_cast(-5.021*_PI/180),//sign? TODO value - 4, - 2, - 6, 9, 1, 1, 1 -#ifdef STIR_TOF - , - (short int)(55), - (float)(89.0F), - (float)(550.0F) -#endif -); - + 2 * 288, 405.1F, 9.4F, 6.54F, 2.1306F, + static_cast(-5.021 * _PI / 180), // sign? TODO value + 4, 2, 6, 9, 1, 1, 1, 0.0F, 511.F, (short int)(55), (float)(89.0F), (float)(550.0F)); break; - case DiscoveryMI3ring: // This is the 3-ring DMI // Hsu et al. 2017 JNM // crystal size 3.95 x 5.3 x 25 - set_params(DiscoveryMI3ring, string_list("GE Discovery MI 3 rings", "Discovery MI3", "Discovery MI"), // needs to include last value as used by GE in RDF files - 27, - 415, - 401, // TODO should compute num_arccorrected_bins from effective_FOV/default_bin_size - 2 * 272, - 380.5F - 9.4F,//TODO inner_ring_radius and DOI, currently set such that effective ring-radius is correct - 9.4F,//TODO DOI - 5.52296F, // ring-spacing - 2.206F,//TODO currently using the central bin size default bin size. GE might be using something else - static_cast(-4.399*_PI/180), //TODO check sign - 3, 4, - 9, 4, - 1, 1, - 1, + set_params(DiscoveryMI3ring, + string_list("GE Discovery MI 3 rings", "Discovery MI3", + "Discovery MI"), // needs to include last value as used by GE in RDF files + 27, 415, + 401, // TODO should compute num_arccorrected_bins from effective_FOV/default_bin_size + 2 * 272, + 380.5F - 9.4F, // TODO inner_ring_radius and DOI, currently set such that effective ring-radius is correct + 9.4F, // TODO DOI + 5.52296F, // ring-spacing + 2.206F, // TODO currently using the central bin size default bin size. GE might be using something else + static_cast(-4.399 * _PI / 180), // TODO check sign + 3, 4, 9, 4, 1, 1, 1, 0.0944F, // energy resolution from Hsu et al. 2017 - 511.F); + 511.F, (short int)(0), + (float)(0), // TODO + (float)(0)); break; case DiscoveryMI4ring: // This is the 4-ring DMI // as above, but one extra block // Hsu et al. 2017 JNM // crystal size 3.95 x 5.3 x 25 - set_params(DiscoveryMI4ring, string_list("GE Discovery MI 4 rings", "Discovery MI4", "Discovery MI"), // needs to include last value as used by GE in RDF files - 36, - 415, - 401, // TODO should compute num_arccorrected_bins from effective_FOV/default_bin_size - 2 * 272, - 380.5F - 9.4F,//TODO inner_ring_radius and DOI, currently set such that effective ring-radius is correct - 9.4F,//TODO DOI - 5.52296F, // ring-spacing - 2.206F,//TODO currently using the central bin size default bin size. GE might be using something else - static_cast(-4.399*_PI/180), //TODO check sign - 4, 4, - 9, 4, - 1, 1, - 1, + set_params(DiscoveryMI4ring, + string_list("GE Discovery MI 4 rings", "Discovery MI4", + "Discovery MI"), // needs to include last value as used by GE in RDF files + 36, 415, + 401, // TODO should compute num_arccorrected_bins from effective_FOV/default_bin_size + 2 * 272, + 380.5F - 9.4F, // TODO inner_ring_radius and DOI, currently set such that effective ring-radius is correct + 9.4F, // TODO DOI + 5.52296F, // ring-spacing + 2.206F, // TODO currently using the central bin size default bin size. GE might be using something else + static_cast(-4.399 * _PI / 180), // TODO check sign + 4, 4, 9, 4, 1, 1, 1, 0.0944F, // energy resolution from Hsu et al. 2017 - 511.F); + 511.F, (short int)(0), + (float)(0), // TODO + (float)(0)); break; case HZLR: - set_params(HZLR, string_list("Positron HZL/R"), - 32, 256, 2 * 192, - 780.0F, 7.0F, 5.1875F, 2.F, 0.0F, - 0, 0, 0, 0, 0,0, 1); + set_params(HZLR, string_list("Positron HZL/R"), 32, 256, 2 * 192, 2 * 192, 780.0F, 7.0F, 5.1875F, 2.F, 0.0F, 0, 0, 0, 0, 0, 0, + 1, 0.0F, 511.F, 0, 0.F, 0.F); // Default 7.0mm average interaction depth. // crystals per singles unit etc unknown break; case HRRT: - set_params(HRRT, string_list("HRRT"), - 104, 288, 2 * 288, - 234.765F, 7.0F, 2.4375F, 1.21875F, 0.0F, - 0, 0, 0, 0, 0, 0, 2); // added by Dylan Togane + set_params(HRRT, string_list("HRRT"), 104, 288, 2 * 288, 2 * 288, 234.765F, 7.0F, 2.4375F, 1.21875F, 0.0F, 0, 0, 0, 0, 0, 0, + 2, 0.0F, 511.F, 0, 0.F, 0.F); // added by Dylan Togane // warning: used 7.0mm average interaction depth. // crystals per singles unit etc unknown break; case Allegro: - /* + /* The following info is partially from - + Journal of Nuclear Medicine Vol. 45 No. 6 1040-1049 - Imaging Characteristics of a 3-Dimensional GSO Whole-Body PET Camera - Suleman Surti, PhD and Joel S. Karp, PhD + Imaging Characteristics of a 3-Dimensional GSO Whole-Body PET Camera + Suleman Surti, PhD and Joel S. Karp, PhD http://jnm.snmjournals.org/cgi/content/full/45/6/1040 Other info is from Ralph Brinks (Philips Research Lab, Aachen). - + The Allegro scanner is comprised of 28 flat modules of a 22 x 29 array of 4 x 6 x 20 mm3 GSO crystals. The output sinograms however consist - of 23 x 29 logical crystals per module. + of 23 x 29 logical crystals per module. This creates problems for the current version of STIR as the current - Scanner object does not support does. At present, KT put the + Scanner object does not support does. At present, KT put the transaxial info on crystals to 0. For 662keV photons the mean positron range in GSO is about 14 mm, so we put in 12mm for 511 keV, but we don't really know. Ralph Brinks things there is only one singles rate for the whole scanner. */ - set_params(Allegro,string_list("Allegro", "Philips Allegro"), - 29, 295, 28*23, - 430.05F, 12.F, - 6.3F, 4.3F, 0.0F, - 1, 0, - 29, 0 /* 23* or 22*/, - 29, 0 /* all detectors in a ring? */, - 1); + set_params(Allegro, string_list("Allegro", "Philips Allegro"), 29, 295, 28 * 23, 28 * 23, 430.05F, 12.F, 6.3F, 4.3F, 0.0F, 1, + 0, 29, 0 /* 23* or 22*/, 29, 0 /* all detectors in a ring? */, 1, 0.0F, 511.F, 0, 0.F, 0.F); break; case GeminiTF: - set_params(GeminiTF,string_list("GeminiTF", "Philips GeminiTF"), - 44, 322, 287, // Based on GATE output - Normally it is 644 detectors at each of the 44 rings - 322*2, // Actual number of crystals is 644 + set_params(GeminiTF, string_list("GeminiTF", "Philips GeminiTF"), 44, 322, + 287, // Based on GATE output - Normally it is 644 detectors at each of the 44 rings + 322 * 2, // Actual number of crystals is 644 450.17F, 8.F, // DOI is from XXX et al 2008 MIC - 4.F, 4.F, 0.F, - 0, 0, - 0, 0, // Not considering any gap, but this is per module 28 flat modules in total, while 420 PMTs - 0, 0 /* Not sure about these, but shouldn't be important */, - 1); + 4.F, 4.F, 0.F, 0, 0, 0, + 0, // Not considering any gap, but this is per module 28 flat modules in total, while 420 PMTs + 0, 0 /* Not sure about these, but shouldn't be important */, 1, 0.0F, 511.F, 0, 0.F, 0.F); break; case HiDAC: // all of these don't make any sense for the HiDAC - set_params(HiDAC, string_list("HiDAC"), - 0, 0, 0, - 0.F, 0.F, 0.F, 0.F, 0.F, - 0, 0, 0, 0, 0, 0, 0); - + set_params(HiDAC, string_list("HiDAC"), 0, 0, 0, 0, 0.F, 0.F, 0.F, 0.F, 0.F, 0, 0, 0, 0, 0, 0, 0, 0.0F, 511.F, 0, 0.F, 0.F); + break; - + case User_defined_scanner: // zlong, 08-04-2004, Userdefined support - set_params(User_defined_scanner, string_list("Userdefined"), - 0, 0, 0, - 0.F, 0.F, 0.F, 0.F, 0.F, - 0, 0, 0, 0, 0, 0, 0); - + set_params(User_defined_scanner, string_list("Userdefined"), 0, 0, 0, 0, 0.F, 0.F, 0.F, 0.F, 0.F, 0, 0, 0, 0, 0, 0, 0, 0.0F, + 511.F, 0, 0.F, 0.F); + break; default: - // warning("Unknown scanner type used for initialisation of Scanner\n"); - set_params(Unknown_scanner, string_list("Unknown"), - 0, 0, 0, - 0.F, 0.F, 0.F, 0.F, 0.F, - 0, 0, 0, 0, 0, 0, 0); - + // warning("Unknown scanner type used for initialisation of Scanner\n"); + set_params(Unknown_scanner, string_list("Unknown"), 0, 0, 0, 0, 0.F, 0.F, 0.F, 0.F, 0.F, 0, 0, 0, 0, 0, 0, 0, 0.0F, 511.F, 0, + 0.F, 0.F); + break; - } - } - -Scanner::Scanner(Type type_v, const list& list_of_names_v, - int num_detectors_per_ring_v, int num_rings_v, - int max_num_non_arccorrected_bins_v, - int default_num_arccorrected_bins_v, - float inner_ring_radius_v, float average_depth_of_interaction_v, - float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, - int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, - int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, - int num_axial_crystals_per_singles_unit_v, - int num_transaxial_crystals_per_singles_unit_v, - int num_detector_layers_v, - float energy_resolution_v, - float reference_energy_v) -{ - set_params(type_v, list_of_names_v, num_rings_v, - max_num_non_arccorrected_bins_v, - default_num_arccorrected_bins_v, - num_detectors_per_ring_v, - inner_ring_radius_v, - average_depth_of_interaction_v, - ring_spacing_v, bin_size_v, intrinsic_tilt_v, - num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, - num_axial_crystals_per_block_v, num_transaxial_crystals_per_block_v, - num_axial_crystals_per_singles_unit_v, - num_transaxial_crystals_per_singles_unit_v, - num_detector_layers_v, - energy_resolution_v, - reference_energy_v); +Scanner::Scanner(Type type_v, const list& list_of_names_v, int num_detectors_per_ring_v, int num_rings_v, + int max_num_non_arccorrected_bins_v, int default_num_arccorrected_bins_v, float inner_ring_radius_v, + float average_depth_of_interaction_v, float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, + int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, + int num_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, + int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, float energy_resolution_v, + float reference_energy_v, short int max_num_of_timing_poss_v, float size_timing_pos_v, + float timing_resolution_v) { + set_params(type_v, list_of_names_v, num_rings_v, max_num_non_arccorrected_bins_v, default_num_arccorrected_bins_v, + num_detectors_per_ring_v, inner_ring_radius_v, average_depth_of_interaction_v, ring_spacing_v, bin_size_v, + intrinsic_tilt_v, num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, num_axial_crystals_per_block_v, + num_transaxial_crystals_per_block_v, num_axial_crystals_per_singles_unit_v, + num_transaxial_crystals_per_singles_unit_v, num_detector_layers_v, energy_resolution_v, reference_energy_v, + max_num_of_timing_poss_v, size_timing_pos_v, timing_resolution_v); } - - -Scanner::Scanner(Type type_v, const string& name, - int num_detectors_per_ring_v, int num_rings_v, - int max_num_non_arccorrected_bins_v, - int default_num_arccorrected_bins_v, - float inner_ring_radius_v, float average_depth_of_interaction_v, - float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, - int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, - int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, - int num_axial_crystals_per_singles_unit_v, - int num_transaxial_crystals_per_singles_unit_v, - int num_detector_layers_v, - float energy_resolution_v, - float reference_energy_v) -{ - set_params(type_v, string_list(name), num_rings_v, - max_num_non_arccorrected_bins_v, - default_num_arccorrected_bins_v, - num_detectors_per_ring_v, - inner_ring_radius_v, - average_depth_of_interaction_v, - ring_spacing_v, bin_size_v, intrinsic_tilt_v, - num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, - num_axial_crystals_per_block_v, num_transaxial_crystals_per_block_v, - num_axial_crystals_per_singles_unit_v, - num_transaxial_crystals_per_singles_unit_v, - num_detector_layers_v, - energy_resolution_v, - reference_energy_v); +Scanner::Scanner(Type type_v, const string& name, int num_detectors_per_ring_v, int num_rings_v, + int max_num_non_arccorrected_bins_v, int default_num_arccorrected_bins_v, float inner_ring_radius_v, + float average_depth_of_interaction_v, float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, + int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, + int num_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, + int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, float energy_resolution_v, + float reference_energy_v, short int max_num_of_timing_poss_v, float size_timing_pos_v, + float timing_resolution_v) { + set_params(type_v, string_list(name), num_rings_v, max_num_non_arccorrected_bins_v, default_num_arccorrected_bins_v, + num_detectors_per_ring_v, inner_ring_radius_v, average_depth_of_interaction_v, ring_spacing_v, bin_size_v, + intrinsic_tilt_v, num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, num_axial_crystals_per_block_v, + num_transaxial_crystals_per_block_v, num_axial_crystals_per_singles_unit_v, + num_transaxial_crystals_per_singles_unit_v, num_detector_layers_v, energy_resolution_v, reference_energy_v, + max_num_of_timing_poss_v, size_timing_pos_v, timing_resolution_v); } - - - - - - -void -Scanner:: -set_params(Type type_v,const list& list_of_names_v, - int num_rings_v, - int max_num_non_arccorrected_bins_v, - int num_detectors_per_ring_v, - float inner_ring_radius_v, - float average_depth_of_interaction_v, - float ring_spacing_v, - float bin_size_v, float intrinsic_tilt_v, - int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, - int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, - int num_axial_crystals_per_singles_unit_v, - int num_transaxial_crystals_per_singles_unit_v, - int num_detector_layers_v, - float energy_resolution_v, - float reference_energy_v) -{ - set_params(type_v, list_of_names_v, num_rings_v, - max_num_non_arccorrected_bins_v, - max_num_non_arccorrected_bins_v, - num_detectors_per_ring_v, - inner_ring_radius_v, - average_depth_of_interaction_v, - ring_spacing_v, bin_size_v, intrinsic_tilt_v, - num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, - num_axial_crystals_per_block_v, num_transaxial_crystals_per_block_v, - num_axial_crystals_per_singles_unit_v, - num_transaxial_crystals_per_singles_unit_v, - num_detector_layers_v, - energy_resolution_v, - reference_energy_v); -} - - void -Scanner:: -set_params(Type type_v,const list& list_of_names_v, - int num_rings_v, - int max_num_non_arccorrected_bins_v, - int default_num_arccorrected_bins_v, - int num_detectors_per_ring_v, - float inner_ring_radius_v, - float average_depth_of_interaction_v, - float ring_spacing_v, - float bin_size_v, float intrinsic_tilt_v, - int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, - int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, - int num_axial_crystals_per_singles_unit_v, - int num_transaxial_crystals_per_singles_unit_v, - int num_detector_layers_v, - float energy_resolution_v, - float reference_energy_v) -{ +Scanner::set_params(Type type_v, const std::list& list_of_names_v, int num_rings_v, + int max_num_non_arccorrected_bins_v, int default_num_arccorrected_bins_v, int num_detectors_per_ring_v, + float inner_ring_radius_v, float average_depth_of_interaction_v, float ring_spacing_v, float bin_size_v, + float intrinsic_tilt_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, + int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, + int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, + int num_detector_layers_v, float energy_resolution_v, float reference_energy_v, + short int max_num_of_timing_poss_v, float size_timing_pos_v, float timing_resolution_v) { type = type_v; - list_of_names = list_of_names_v; - num_rings = num_rings_v; + list_of_names = list_of_names_v; + num_rings = num_rings_v; max_num_non_arccorrected_bins = max_num_non_arccorrected_bins_v; default_num_arccorrected_bins = default_num_arccorrected_bins_v; - num_detectors_per_ring = num_detectors_per_ring_v; - inner_ring_radius = inner_ring_radius_v; + num_detectors_per_ring = num_detectors_per_ring_v; + inner_ring_radius = inner_ring_radius_v; average_depth_of_interaction = average_depth_of_interaction_v; ring_spacing = ring_spacing_v; bin_size = bin_size_v; - intrinsic_tilt = intrinsic_tilt_v; + intrinsic_tilt = intrinsic_tilt_v; num_transaxial_blocks_per_bucket = num_transaxial_blocks_per_bucket_v; num_axial_blocks_per_bucket = num_axial_blocks_per_bucket_v; - num_axial_crystals_per_block= num_axial_crystals_per_block_v; - num_transaxial_crystals_per_block= num_transaxial_crystals_per_block_v; + num_axial_crystals_per_block = num_axial_crystals_per_block_v; + num_transaxial_crystals_per_block = num_transaxial_crystals_per_block_v; num_axial_crystals_per_singles_unit = num_axial_crystals_per_singles_unit_v; num_transaxial_crystals_per_singles_unit = num_transaxial_crystals_per_singles_unit_v; num_detector_layers = num_detector_layers_v; energy_resolution = energy_resolution_v; if (reference_energy_v <= 0) - reference_energy = 511.f; + reference_energy = 511.f; else - reference_energy = reference_energy_v; - + reference_energy = reference_energy_v; + max_num_of_timing_poss = max_num_of_timing_poss_v; + size_timing_pos = size_timing_pos_v; + timing_resolution = timing_resolution_v; } /*! \todo The current list is bound to be incomplete. would be better to stick it in set_params(). */ int -Scanner:: -get_num_virtual_axial_crystals_per_block() const -{ - switch(get_type()) - { - case E1080: - case Siemens_mCT: - return 1; - default: - return 0; - } +Scanner::get_num_virtual_axial_crystals_per_block() const { + switch (get_type()) { + case E1080: + case Siemens_mCT: + return 1; + default: + return 0; + } } /*! \todo The current list is bound to be incomplete. would be better to stick it in set_params(). */ int -Scanner:: -get_num_virtual_transaxial_crystals_per_block() const -{ - switch(get_type()) - { - case E1080: - case Siemens_mCT: - case Siemens_mMR: - return 1; - default: - return 0; - } +Scanner::get_num_virtual_transaxial_crystals_per_block() const { + switch (get_type()) { + case E1080: + case Siemens_mCT: + case Siemens_mMR: + return 1; + default: + return 0; + } } /*! \todo Can currently only set to hard-wired values. Otherwise calls error() */ void -Scanner:: -set_num_virtual_axial_crystals_per_block(int val) -{ - //num_virtual_axial_crystals_per_block = val; +Scanner::set_num_virtual_axial_crystals_per_block(int val) { + // num_virtual_axial_crystals_per_block = val; if (this->get_num_virtual_axial_crystals_per_block() != val) error("Scanner::set_num_virtual_axial_crystals_per_block not really implemented yet"); } /*! \todo Can currently only set to hard-wired values. Otherwise calls error() */ void -Scanner:: -set_num_virtual_transaxial_crystals_per_block(int val) -{ - //num_virtual_transaxial_crystals_per_block = val; +Scanner::set_num_virtual_transaxial_crystals_per_block(int val) { + // num_virtual_transaxial_crystals_per_block = val; if (this->get_num_virtual_transaxial_crystals_per_block() != val) error("Scanner::set_num_virtual_transaxial_crystals_per_block not really implemented yet"); } - -Succeeded -Scanner:: -check_consistency() const -{ - if (intrinsic_tilt<-_PI || intrinsic_tilt>_PI) +Succeeded +Scanner::check_consistency() const { + if (intrinsic_tilt < -_PI || intrinsic_tilt > _PI) warning("Scanner %s: intrinsic_tilt is very large. maybe it's in degrees (but should be in radians)", - this->get_name().c_str()); + this->get_name().c_str()); { - if (get_num_transaxial_crystals_per_block() <= 0 || - get_num_transaxial_blocks() <= 0) - warning("Scanner %s: transaxial block info is not set (probably irrelevant unless you use a projector or normalisation that needs this block info)", - this->get_name().c_str()); - else - { - const int dets_per_ring = - get_num_transaxial_blocks() * - get_num_transaxial_crystals_per_block(); - if ( dets_per_ring != get_num_detectors_per_ring()) - { - warning("Scanner %s: inconsistent transaxial block info", - this->get_name().c_str()); - return Succeeded::no; - } + if (get_num_transaxial_crystals_per_block() <= 0 || get_num_transaxial_blocks() <= 0) + warning("Scanner %s: transaxial block info is not set (probably irrelevant unless you use a projector or normalisation " + "that needs this block info)", + this->get_name().c_str()); + else { + const int dets_per_ring = get_num_transaxial_blocks() * get_num_transaxial_crystals_per_block(); + if (dets_per_ring != get_num_detectors_per_ring()) { + warning("Scanner %s: inconsistent transaxial block info", this->get_name().c_str()); + return Succeeded::no; } + } } { - if (get_num_transaxial_blocks_per_bucket() <= 0 || - get_num_transaxial_buckets() <=0) - warning("Scanner %s: transaxial bucket info is not set (probably irrelevant unless you use dead-time correction that needs this info)", - this->get_name().c_str()); - else - { - const int blocks_per_ring = - get_num_transaxial_buckets() * - get_num_transaxial_blocks_per_bucket(); - if ( blocks_per_ring != get_num_transaxial_blocks()) - { - warning("Scanner %s: inconsistent transaxial block/bucket info", - this->get_name().c_str()); - return Succeeded::no; - } + if (get_num_transaxial_blocks_per_bucket() <= 0 || get_num_transaxial_buckets() <= 0) + warning("Scanner %s: transaxial bucket info is not set (probably irrelevant unless you use dead-time correction that needs " + "this info)", + this->get_name().c_str()); + else { + const int blocks_per_ring = get_num_transaxial_buckets() * get_num_transaxial_blocks_per_bucket(); + if (blocks_per_ring != get_num_transaxial_blocks()) { + warning("Scanner %s: inconsistent transaxial block/bucket info", this->get_name().c_str()); + return Succeeded::no; } + } } { - if (get_num_axial_crystals_per_block() <= 0 || - get_num_axial_blocks() <=0) - warning("Scanner %s: axial block info is not set (probably irrelevant unless you use a projector or normalisation that needs this block info)", - this->get_name().c_str()); - else - { - const int dets_axial = - get_num_axial_blocks() * - get_num_axial_crystals_per_block(); - if ( dets_axial != (get_num_rings() + get_num_virtual_axial_crystals_per_block())) - { - warning("Scanner %s: inconsistent axial block info: %d vs %d", - this->get_name().c_str(), - dets_axial, get_num_rings() + get_num_virtual_axial_crystals_per_block()); - return Succeeded::no; - } + if (get_num_axial_crystals_per_block() <= 0 || get_num_axial_blocks() <= 0) + warning("Scanner %s: axial block info is not set (probably irrelevant unless you use a projector or normalisation that " + "needs this block info)", + this->get_name().c_str()); + else { + const int dets_axial = get_num_axial_blocks() * get_num_axial_crystals_per_block(); + if (dets_axial != (get_num_rings() + get_num_virtual_axial_crystals_per_block())) { + warning("Scanner %s: inconsistent axial block info: %d vs %d", this->get_name().c_str(), dets_axial, + get_num_rings() + get_num_virtual_axial_crystals_per_block()); + return Succeeded::no; } + } } { - if (get_num_axial_blocks_per_bucket() <= 0 || - get_num_axial_buckets() <=0) - warning("Scanner %s: axial bucket info is not set (probably irrelevant unless you use dead-time correction that needs this info)", - this->get_name().c_str()); - else - { - const int blocks_axial = - get_num_axial_buckets() * - get_num_axial_blocks_per_bucket(); - if ( blocks_axial != get_num_axial_blocks()) - { - warning("Scanner %s: inconsistent axial block/bucket info", - this->get_name().c_str()); - return Succeeded::no; - } + if (get_num_axial_blocks_per_bucket() <= 0 || get_num_axial_buckets() <= 0) + warning("Scanner %s: axial bucket info is not set (probably irrelevant unless you use dead-time correction that needs this " + "info)", + this->get_name().c_str()); + else { + const int blocks_axial = get_num_axial_buckets() * get_num_axial_blocks_per_bucket(); + if (blocks_axial != get_num_axial_blocks()) { + warning("Scanner %s: inconsistent axial block/bucket info", this->get_name().c_str()); + return Succeeded::no; } + } } // checks on singles units { if (get_num_transaxial_crystals_per_singles_unit() <= 0) - warning("Scanner %s: transaxial singles_unit info is not set (probably irrelevant unless you use dead-time correction that needs this info)", - this->get_name().c_str()); - else - { - if ( get_num_detectors_per_ring() % get_num_transaxial_crystals_per_singles_unit() != 0) - { - warning("Scanner %s: inconsistent transaxial singles unit info:\n" - "\tnum_detectors_per_ring %d should be a multiple of num_transaxial_crystals_per_singles_unit %d", - this->get_name().c_str(), - get_num_detectors_per_ring(), get_num_transaxial_crystals_per_singles_unit()); - return Succeeded::no; - } - if ( get_num_transaxial_crystals_per_bucket() % get_num_transaxial_crystals_per_singles_unit() != 0) - { - warning("Scanner %s: inconsistent transaxial singles unit info:\n" - "\tnum_transaxial_crystals_per_bucket %d should be a multiple of num_transaxial_crystals_per_singles_unit %d", - this->get_name().c_str(), - get_num_transaxial_crystals_per_bucket(), get_num_transaxial_crystals_per_singles_unit()); - return Succeeded::no; - } + warning("Scanner %s: transaxial singles_unit info is not set (probably irrelevant unless you use dead-time correction that " + "needs this info)", + this->get_name().c_str()); + else { + if (get_num_detectors_per_ring() % get_num_transaxial_crystals_per_singles_unit() != 0) { + warning("Scanner %s: inconsistent transaxial singles unit info:\n" + "\tnum_detectors_per_ring %d should be a multiple of num_transaxial_crystals_per_singles_unit %d", + this->get_name().c_str(), get_num_detectors_per_ring(), get_num_transaxial_crystals_per_singles_unit()); + return Succeeded::no; } + if (get_num_transaxial_crystals_per_bucket() % get_num_transaxial_crystals_per_singles_unit() != 0) { + warning("Scanner %s: inconsistent transaxial singles unit info:\n" + "\tnum_transaxial_crystals_per_bucket %d should be a multiple of num_transaxial_crystals_per_singles_unit %d", + this->get_name().c_str(), get_num_transaxial_crystals_per_bucket(), + get_num_transaxial_crystals_per_singles_unit()); + return Succeeded::no; + } + } } { if (get_num_axial_crystals_per_singles_unit() <= 0) - warning("Scanner %s: axial singles_unit info is not set (probably irrelevant unless you use dead-time correction that needs this info)", - this->get_name().c_str()); - else - { - if ( get_num_rings() % get_num_axial_crystals_per_singles_unit() != 0) - { - warning("Scanner %s: inconsistent axial singles unit info:\n" - "\tnum_rings %d should be a multiple of num_axial_crystals_per_singles_unit %d", - this->get_name().c_str(), - get_num_rings(), get_num_axial_crystals_per_singles_unit()); - return Succeeded::no; - } - if ( get_num_axial_crystals_per_bucket() % get_num_axial_crystals_per_singles_unit() != 0) - { - warning("Scanner %s: inconsistent axial singles unit info:\n" - "\tnum_axial_crystals_per_bucket %d should be a multiple of num_axial_crystals_per_singles_unit %d", - this->get_name().c_str(), - get_num_axial_crystals_per_bucket(), get_num_axial_crystals_per_singles_unit()); - return Succeeded::no; - } + warning("Scanner %s: axial singles_unit info is not set (probably irrelevant unless you use dead-time correction that " + "needs this info)", + this->get_name().c_str()); + else { + if (get_num_rings() % get_num_axial_crystals_per_singles_unit() != 0) { + warning("Scanner %s: inconsistent axial singles unit info:\n" + "\tnum_rings %d should be a multiple of num_axial_crystals_per_singles_unit %d", + this->get_name().c_str(), get_num_rings(), get_num_axial_crystals_per_singles_unit()); + return Succeeded::no; } + if (get_num_axial_crystals_per_bucket() % get_num_axial_crystals_per_singles_unit() != 0) { + warning("Scanner %s: inconsistent axial singles unit info:\n" + "\tnum_axial_crystals_per_bucket %d should be a multiple of num_axial_crystals_per_singles_unit %d", + this->get_name().c_str(), get_num_axial_crystals_per_bucket(), get_num_axial_crystals_per_singles_unit()); + return Succeeded::no; + } + } } return Succeeded::yes; } - - - - - - // TODO replace by using boost::floating_point_comparison -bool static close_enough(const double a, const double b) -{ - return fabs(a-b) <= std::min(fabs(a), fabs(b)) * 10E-4; -} +bool static close_enough(const double a, const double b) { return fabs(a - b) <= std::min(fabs(a), fabs(b)) * 10E-4; } -bool -Scanner::operator ==(const Scanner& scanner) const -{ -if (!close_enough(energy_resolution, scanner.energy_resolution) && - !close_enough(reference_energy, scanner.reference_energy)) +bool +Scanner::operator==(const Scanner& scanner) const { + if (!close_enough(energy_resolution, scanner.energy_resolution) && !close_enough(reference_energy, scanner.reference_energy)) warning("The energy resolution of the two scanners is different. \n" " %f opposed to %f" - "This only affects scatter simulation. \n", energy_resolution, scanner.energy_resolution); - - return - (num_rings == scanner.num_rings) && - (max_num_non_arccorrected_bins == scanner.max_num_non_arccorrected_bins) && - (default_num_arccorrected_bins == scanner.default_num_arccorrected_bins) && - (num_detectors_per_ring == scanner.num_detectors_per_ring) && - close_enough(inner_ring_radius, scanner.inner_ring_radius) && - close_enough(average_depth_of_interaction, scanner.average_depth_of_interaction) && - close_enough(ring_spacing, scanner.ring_spacing) && - close_enough(bin_size,scanner.bin_size) && - close_enough(intrinsic_tilt,scanner.intrinsic_tilt) && - (num_transaxial_blocks_per_bucket == scanner.num_transaxial_blocks_per_bucket) && - (num_axial_blocks_per_bucket == scanner.num_axial_blocks_per_bucket) && - (num_axial_crystals_per_block == scanner.num_axial_crystals_per_block) && - (num_transaxial_crystals_per_block == scanner.num_transaxial_crystals_per_block) && - (num_detector_layers == scanner.num_detector_layers) && - (num_axial_crystals_per_singles_unit == scanner.num_axial_crystals_per_singles_unit) && - (num_transaxial_crystals_per_singles_unit == scanner.num_transaxial_crystals_per_singles_unit); + "This only affects scatter simulation. \n", + energy_resolution, scanner.energy_resolution); + + bool ok = (num_rings == scanner.num_rings) && (max_num_non_arccorrected_bins == scanner.max_num_non_arccorrected_bins) && + (default_num_arccorrected_bins == scanner.default_num_arccorrected_bins) && + (num_detectors_per_ring == scanner.num_detectors_per_ring) && + close_enough(inner_ring_radius, scanner.inner_ring_radius) && + close_enough(average_depth_of_interaction, scanner.average_depth_of_interaction) && + close_enough(ring_spacing, scanner.ring_spacing) && close_enough(bin_size, scanner.bin_size) && + close_enough(intrinsic_tilt, scanner.intrinsic_tilt) && + (num_transaxial_blocks_per_bucket == scanner.num_transaxial_blocks_per_bucket) && + (num_axial_blocks_per_bucket == scanner.num_axial_blocks_per_bucket) && + (num_axial_crystals_per_block == scanner.num_axial_crystals_per_block) && + (num_transaxial_crystals_per_block == scanner.num_transaxial_crystals_per_block) && + (num_detector_layers == scanner.num_detector_layers) && + (num_axial_crystals_per_singles_unit == scanner.num_axial_crystals_per_singles_unit) && + (num_transaxial_crystals_per_singles_unit == scanner.num_transaxial_crystals_per_singles_unit); + + if (this->is_tof_ready() && scanner.is_tof_ready()) { + ok = (max_num_of_timing_poss == scanner.max_num_of_timing_poss) && close_enough(size_timing_pos, scanner.size_timing_pos) && + close_enough(timing_resolution, scanner.timing_resolution); + } + return ok; } - -const list& -Scanner::get_all_names() const -{return list_of_names;} - +const list& +Scanner::get_all_names() const { + return list_of_names; +} const string& -Scanner::get_name() const -{ - - return *(list_of_names.begin()); - +Scanner::get_name() const { + + return *(list_of_names.begin()); } string -Scanner::parameter_info() const -{ +Scanner::parameter_info() const { // warning: these should match the parsing keywords in InterfilePDFSHeader #ifdef BOOST_NO_STRINGSTREAM // dangerous for out-of-range, but 'old-style' ostrstream seems to need this @@ -929,51 +786,48 @@ Scanner::parameter_info() const #else std::ostringstream s; #endif - s << "Scanner parameters:= "<<'\n'; + s << "Scanner parameters:= " << '\n'; - s << "Scanner type := " << get_name() <<'\n'; + s << "Scanner type := " << get_name() << '\n'; s << "Number of rings := " << num_rings << '\n'; s << "Number of detectors per ring := " << get_num_detectors_per_ring() << '\n'; - s << "Inner ring diameter (cm) := " << get_inner_ring_radius()*2./10 << '\n' + s << "Inner ring diameter (cm) := " << get_inner_ring_radius() * 2. / 10 << '\n' << "Average depth of interaction (cm) := " << get_average_depth_of_interaction() / 10 << '\n' - << "Distance between rings (cm) := " << get_ring_spacing()/10 << '\n' - << "Default bin size (cm) := " << get_default_bin_size()/10. << '\n' - << "View offset (degrees) := " << get_default_intrinsic_tilt()*180/_PI << '\n'; - s << "Maximum number of non-arc-corrected bins := " - << get_max_num_non_arccorrected_bins() << '\n' - << "Default number of arc-corrected bins := " - << get_default_num_arccorrected_bins() << '\n'; - if (get_energy_resolution() >= 0 && get_reference_energy() >= 0) - { + << "Distance between rings (cm) := " << get_ring_spacing() / 10 << '\n' + << "Default bin size (cm) := " << get_default_bin_size() / 10. << '\n' + << "View offset (degrees) := " << get_default_intrinsic_tilt() * 180 / _PI << '\n'; + s << "Maximum number of non-arc-corrected bins := " << get_max_num_non_arccorrected_bins() << '\n' + << "Default number of arc-corrected bins := " << get_default_num_arccorrected_bins() << '\n'; + if (get_energy_resolution() >= 0 && get_reference_energy() >= 0) { s << "Energy resolution := " << get_energy_resolution() << '\n'; s << "Reference energy (in keV) := " << get_reference_energy() << '\n'; } + if (is_tof_ready()) { + s << "Number of TOF time bins :=" << get_max_num_timing_poss() << "\n"; + s << "Size of timing bin (ps) :=" << get_size_of_timing_pos() << "\n"; + s << "Timing resolution (ps) :=" << get_timing_resolution() << "\n"; + } + // block/bucket description - s << "Number of blocks per bucket in transaxial direction := " - << get_num_transaxial_blocks_per_bucket() << '\n' - << "Number of blocks per bucket in axial direction := " - << get_num_axial_blocks_per_bucket() << '\n' - << "Number of crystals per block in axial direction := " - << get_num_axial_crystals_per_block() << '\n' - << "Number of crystals per block in transaxial direction := " - << get_num_transaxial_crystals_per_block() << '\n' - << "Number of detector layers := " - << get_num_detector_layers() << '\n' - << "Number of crystals per singles unit in axial direction := " - << get_num_axial_crystals_per_singles_unit() << '\n' - << "Number of crystals per singles unit in transaxial direction := " - << get_num_transaxial_crystals_per_singles_unit() << '\n'; - + s << "Number of blocks per bucket in transaxial direction := " << get_num_transaxial_blocks_per_bucket() << '\n' + << "Number of blocks per bucket in axial direction := " << get_num_axial_blocks_per_bucket() << '\n' + << "Number of crystals per block in axial direction := " << get_num_axial_crystals_per_block() << '\n' + << "Number of crystals per block in transaxial direction := " << get_num_transaxial_crystals_per_block() << '\n' + << "Number of detector layers := " << get_num_detector_layers() << '\n' + << "Number of crystals per singles unit in axial direction := " << get_num_axial_crystals_per_singles_unit() << '\n' + << "Number of crystals per singles unit in transaxial direction := " << get_num_transaxial_crystals_per_singles_unit() + << '\n'; + s << "end scanner parameters:=\n"; return s.str(); } -string Scanner::list_names() const -{ +string +Scanner::list_names() const { #ifdef BOOST_NO_STRINGSTREAM // dangerous for out-of-range, but 'old-style' ostrstream seems to need this char str[3000]; @@ -986,12 +840,11 @@ string Scanner::list_names() const // work-around VC bug std:: #endif - list::const_iterator iterator = list_of_names.begin(); + list::const_iterator iterator = list_of_names.begin(); s << *iterator; ++iterator; - while(iterator!=list_of_names.end()) - { - s << " , " << *iterator ; + while (iterator != list_of_names.end()) { + s << " , " << *iterator; ++iterator; } @@ -1001,138 +854,95 @@ string Scanner::list_names() const /************************************************ static members *************************************************/ -Scanner* Scanner::ask_parameters() -{ +Scanner* +Scanner::ask_parameters() { cerr << list_all_names(); - const string name=ask_string("Enter the name of the scanner"); + const string name = ask_string("Enter the name of the scanner"); - //get the type from the name itself - Scanner* scanner_ptr = - get_scanner_from_name(name); + // get the type from the name itself + Scanner* scanner_ptr = get_scanner_from_name(name); // N.E: New optional parameters have been added, namely // energy resolution and timing resolution, // lets give users the chance to set these parameters on // old scanners. This should stay here as a transitional step. - if (scanner_ptr->type != Unknown_scanner && scanner_ptr->type != User_defined_scanner) - { - info("Two new options are available: (a) Energy Resolution and (b) Reference energy (in keV)." - "They are used in Scatter Simulation. In case, you need them, please set them" - "manually in your file."); + if (scanner_ptr->type != Unknown_scanner && scanner_ptr->type != User_defined_scanner) { + info("Two new options are available: (a) Energy Resolution and (b) Reference energy (in keV)." + "They are used in Scatter Simulation. In case, you need them, please set them " + "manually in your file. More over, the creation of a Time-Of-Flight scanner with energy" + "information is not supported. You have to do it manually."); - return scanner_ptr; - } + return scanner_ptr; + } if (scanner_ptr->type == Unknown_scanner) cerr << "I didn't recognise the scanner you entered."; cerr << "I'll ask lots of questions\n"; - - while (true) - { - int num_detectors_per_ring = - ask_num("Enter number of detectors per ring:",0,2000,128); - - int NoRings = - ask_num("Enter number of rings :",0,1000,16); - - int NoBins = - ask_num("Enter default number of tangential positions for this scanner: ",0,3000,128); - - float InnerRingRadius= - ask_num("Enter inner ring radius (in mm): ",0.F,600.F,256.F); - - float AverageDepthOfInteraction = - ask_num("Enter average depth of interaction (in mm): ", 0.F, 100.F, 0.F); - - float RingSpacing= - ask_num("Enter ring spacing (in mm): ",0.F,30.F,6.75F); - - float BinSize= - ask_num("Enter default (tangential) bin size after arc-correction (in mm):",0.F,60.F,3.75F); - float intrTilt= - ask_num("Enter intrinsic_tilt (in degrees):",-180.F,360.F,0.F); - int TransBlocksPerBucket = - ask_num("Enter number of transaxial blocks per bucket: ",0,10,2); - int AxialBlocksPerBucket = - ask_num("Enter number of axial blocks per bucket: ",0,10,6); - int AxialCrystalsPerBlock = - ask_num("Enter number of axial crystals per block: ",0,12,8); - int TransaxialCrystalsPerBlock = - ask_num("Enter number of transaxial crystals per block: ",0,12,8); - int AxialCrstalsPerSinglesUnit = - ask_num("Enter number of axial crystals per singles unit: ", 0, NoRings, 1); - int TransaxialCrystalsPerSinglesUnit = + + while (true) { + int num_detectors_per_ring = ask_num("Enter number of detectors per ring:", 0, 2000, 128); + + int NoRings = ask_num("Enter number of rings :", 0, 1000, 16); + + int NoBins = ask_num("Enter default number of tangential positions for this scanner: ", 0, 3000, 128); + + float InnerRingRadius = ask_num("Enter inner ring radius (in mm): ", 0.F, 600.F, 256.F); + + float AverageDepthOfInteraction = ask_num("Enter average depth of interaction (in mm): ", 0.F, 100.F, 0.F); + + float RingSpacing = ask_num("Enter ring spacing (in mm): ", 0.F, 30.F, 6.75F); + + float BinSize = ask_num("Enter default (tangential) bin size after arc-correction (in mm):", 0.F, 60.F, 3.75F); + float intrTilt = ask_num("Enter intrinsic_tilt (in degrees):", -180.F, 360.F, 0.F); + int TransBlocksPerBucket = ask_num("Enter number of transaxial blocks per bucket: ", 0, 10, 2); + int AxialBlocksPerBucket = ask_num("Enter number of axial blocks per bucket: ", 0, 10, 6); + int AxialCrystalsPerBlock = ask_num("Enter number of axial crystals per block: ", 0, 12, 8); + int TransaxialCrystalsPerBlock = ask_num("Enter number of transaxial crystals per block: ", 0, 12, 8); + int AxialCrstalsPerSinglesUnit = ask_num("Enter number of axial crystals per singles unit: ", 0, NoRings, 1); + int TransaxialCrystalsPerSinglesUnit = ask_num("Enter number of transaxial crystals per singles unit: ", 0, num_detectors_per_ring, 1); - - float EnergyResolution = - ask_num("Enter the energy resolution of the scanner : ", 0.0f, 1000.0f, -1.0f); - - float ReferenceEnergy = - ask_num("Enter the reference energy for the energy resolution (in keV):", 0.0f, 1000.0f, -1.0f); - - int num_detector_layers = - ask_num("Enter number of detector layers per block: ",1,100,1); - Type type = User_defined_scanner; - - if (EnergyResolution > -1 && ReferenceEnergy > -1) - scanner_ptr = - new Scanner(type, string_list(name), - num_detectors_per_ring, NoRings, - NoBins, NoBins, - InnerRingRadius, AverageDepthOfInteraction, - RingSpacing, BinSize,intrTilt*float(_PI)/180, - AxialBlocksPerBucket,TransBlocksPerBucket, - AxialCrystalsPerBlock,TransaxialCrystalsPerBlock, - AxialCrstalsPerSinglesUnit, TransaxialCrystalsPerSinglesUnit, - num_detector_layers, - EnergyResolution, - ReferenceEnergy ); - else - scanner_ptr = - new Scanner(type, string_list(name), - num_detectors_per_ring, NoRings, - NoBins, NoBins, - InnerRingRadius, AverageDepthOfInteraction, - RingSpacing, BinSize,intrTilt*float(_PI)/180, - AxialBlocksPerBucket,TransBlocksPerBucket, - AxialCrystalsPerBlock,TransaxialCrystalsPerBlock, - AxialCrstalsPerSinglesUnit, TransaxialCrystalsPerSinglesUnit, - num_detector_layers); - - if (scanner_ptr->check_consistency()==Succeeded::yes || - !ask("Ask questions again?",true)) - return scanner_ptr; - - delete scanner_ptr; - } // infinite loop -} + short int Num_TOF_bins = ask_num("Number of TOF time bins :", 0, 800, 0); + float Size_TOF_bin = ask_num("Size of timing bin (ps) :", 0.0f, 100.0f, 0.0f); + float TOF_resolution = ask_num("Timing resolution (ps) :", 0.0f, 1000.0f, 0.0f); + float EnergyResolution = ask_num("Enter the energy resolution of the scanner : ", 0.0f, 1000.0f, -1.0f); -Scanner * -Scanner::get_scanner_from_name(const string& name) -{ - Scanner * scanner_ptr; + float ReferenceEnergy = ask_num("Enter the reference energy for the energy resolution (in keV):", 0.0f, 1000.0f, -1.0f); - const string matching_name = - standardise_interfile_keyword(name); - Type type= E931; - while (type != Unknown_scanner) - { + int num_detector_layers = ask_num("Enter number of detector layers per block: ", 1, 100, 1); + Type type = User_defined_scanner; + + scanner_ptr = new Scanner(type, string_list(name), num_detectors_per_ring, NoRings, NoBins, NoBins, InnerRingRadius, + AverageDepthOfInteraction, RingSpacing, BinSize, intrTilt * float(_PI) / 180, AxialBlocksPerBucket, + TransBlocksPerBucket, AxialCrystalsPerBlock, TransaxialCrystalsPerBlock, AxialCrstalsPerSinglesUnit, + TransaxialCrystalsPerSinglesUnit, num_detector_layers, EnergyResolution, ReferenceEnergy, + Num_TOF_bins, Size_TOF_bin, TOF_resolution); + + if (scanner_ptr->check_consistency() == Succeeded::yes || !ask("Ask questions again?", true)) + return scanner_ptr; + + delete scanner_ptr; + } // infinite loop +} + +Scanner* +Scanner::get_scanner_from_name(const string& name) { + Scanner* scanner_ptr; + + const string matching_name = standardise_interfile_keyword(name); + Type type = E931; + while (type != Unknown_scanner) { scanner_ptr = new Scanner(type); const list& list_of_names = scanner_ptr->get_all_names(); - for (std::list::const_iterator iter =list_of_names.begin(); - iter!=list_of_names.end(); - ++iter) - { - const string matching_scanner_name = - standardise_interfile_keyword(*iter); - if (matching_scanner_name==matching_name) - return scanner_ptr; - } - + for (std::list::const_iterator iter = list_of_names.begin(); iter != list_of_names.end(); ++iter) { + const string matching_scanner_name = standardise_interfile_keyword(*iter); + if (matching_scanner_name == matching_name) + return scanner_ptr; + } + // we didn't find it yet delete scanner_ptr; // tricky business to find next type @@ -1144,10 +954,9 @@ Scanner::get_scanner_from_name(const string& name) return new Scanner(Unknown_scanner); } - -string Scanner:: list_all_names() -{ - Scanner * scanner_ptr; +string +Scanner::list_all_names() { + Scanner* scanner_ptr; #ifdef BOOST_NO_STRINGSTREAM // dangerous for out-of-range, but 'old-style' ostrstream seems to need this char str[30000]; @@ -1156,43 +965,38 @@ string Scanner:: list_all_names() std::ostringstream s; #endif - Type type= E931; - while (type != Unknown_scanner) - { + Type type = E931; + while (type != Unknown_scanner) { scanner_ptr = new Scanner(type); s << scanner_ptr->list_names() << '\n'; - + delete scanner_ptr; // tricky business to find next type int int_type = type; ++int_type; type = static_cast(int_type); } - + return s.str(); } - -static list -string_list(const string& s) -{ +static list +string_list(const string& s) { list l; l.push_back(s); return l; } -static list -string_list(const string& s1, const string& s2) -{ +static list +string_list(const string& s1, const string& s2) { list l; l.push_back(s1); l.push_back(s2); return l; } -static list -string_list(const string& s1, const string& s2, const string& s3) -{ +static list +string_list(const string& s1, const string& s2, const string& s3) { list l; l.push_back(s1); l.push_back(s2); @@ -1200,9 +1004,8 @@ string_list(const string& s1, const string& s2, const string& s3) return l; } -static list -string_list(const string& s1, const string& s2, const string& s3, const string& s4) -{ +static list +string_list(const string& s1, const string& s2, const string& s3, const string& s4) { list l; l.push_back(s1); l.push_back(s2); @@ -1212,8 +1015,7 @@ string_list(const string& s1, const string& s2, const string& s3, const string& } static list -string_list(const string& s1, const string& s2, const string& s3, const string& s4, const string& s5) -{ +string_list(const string& s1, const string& s2, const string& s3, const string& s4, const string& s5) { list l; l.push_back(s1); l.push_back(s2); diff --git a/src/buildblock/Segment.cxx b/src/buildblock/Segment.cxx index fa02b03397..f8935a540a 100644 --- a/src/buildblock/Segment.cxx +++ b/src/buildblock/Segment.cxx @@ -38,62 +38,43 @@ using std::string; START_NAMESPACE_STIR - -template +template bool -Segment:: -has_same_characteristics(self_type const& other, - string& explanation) const -{ +Segment::has_same_characteristics(self_type const& other, string& explanation) const { using boost::format; using boost::str; - if (typeid(*this) != typeid(other)) - { - explanation = - str(format("Differing data types:%1% vs %2%") - % typeid(*this).name() - % typeid(other).name() - ); - return false; - } - if (*this->get_proj_data_info_sptr() != - *other.get_proj_data_info_sptr()) - { - explanation = - str(format("Differing projection data info:\n%1%\n-------- vs-------\n %2%") - % this->get_proj_data_info_sptr()->parameter_info() - % other.get_proj_data_info_sptr()->parameter_info() - ); - return false; - } - if (this->get_segment_num() != - other.get_segment_num()) - { - explanation = - str(format("Differing segment number: %1% vs %2%") - % this->get_segment_num() - % other.get_segment_num() - ); - return false; - } + if (typeid(*this) != typeid(other)) { + explanation = str(format("Differing data types:%1% vs %2%") % typeid(*this).name() % typeid(other).name()); + return false; + } + if (*this->get_proj_data_info_sptr() != *other.get_proj_data_info_sptr()) { + explanation = str(format("Differing projection data info:\n%1%\n-------- vs-------\n %2%") % + this->get_proj_data_info_sptr()->parameter_info() % other.get_proj_data_info_sptr()->parameter_info()); + return false; + } + if (this->get_segment_num() != other.get_segment_num()) { + explanation = str(format("Differing segment number: %1% vs %2%") % this->get_segment_num() % other.get_segment_num()); + return false; + } + if (this->get_timing_pos_num() != other.get_timing_pos_num()) { + explanation = + str(format("Differing timing position index: %1% vs %2%") % this->get_timing_pos_num() % other.get_timing_pos_num()); + return false; + } return true; } -template +template bool -Segment:: -has_same_characteristics(self_type const& other) const -{ +Segment::has_same_characteristics(self_type const& other) const { std::string explanation; return this->has_same_characteristics(other, explanation); } -template -bool -Segment:: -operator !=(const self_type& that) const -{ +template +bool +Segment::operator!=(const self_type& that) const { return !((*this) == that); } diff --git a/src/buildblock/SegmentBySinogram.cxx b/src/buildblock/SegmentBySinogram.cxx index 5924178cde..ebf049ca14 100644 --- a/src/buildblock/SegmentBySinogram.cxx +++ b/src/buildblock/SegmentBySinogram.cxx @@ -37,102 +37,75 @@ START_NAMESPACE_STIR - - template -SegmentBySinogram :: -SegmentBySinogram(const Array<3,elemT>& v, - const shared_ptr& pdi_ptr, - const int segment_num) - : - Segment(pdi_ptr, segment_num), - Array<3,elemT>(v) -{ - assert( get_min_view_num() == pdi_ptr->get_min_view_num()); - assert( get_max_view_num() == pdi_ptr->get_max_view_num()); - assert( get_min_axial_pos_num() == pdi_ptr->get_min_axial_pos_num(segment_num)); - assert( get_max_axial_pos_num() == pdi_ptr->get_max_axial_pos_num(segment_num)); - assert( get_min_tangential_pos_num() == pdi_ptr->get_min_tangential_pos_num()); - assert( get_max_tangential_pos_num() == pdi_ptr->get_max_tangential_pos_num()); +SegmentBySinogram::SegmentBySinogram(const Array<3, elemT>& v, const shared_ptr& pdi_ptr, + const int segment_num, const int timing_pos_num) + : Segment(pdi_ptr, segment_num, timing_pos_num), Array<3, elemT>(v) { + assert(get_min_view_num() == pdi_ptr->get_min_view_num()); + assert(get_max_view_num() == pdi_ptr->get_max_view_num()); + assert(get_min_axial_pos_num() == pdi_ptr->get_min_axial_pos_num(segment_num)); + assert(get_max_axial_pos_num() == pdi_ptr->get_max_axial_pos_num(segment_num)); + assert(get_min_tangential_pos_num() == pdi_ptr->get_min_tangential_pos_num()); + assert(get_max_tangential_pos_num() == pdi_ptr->get_max_tangential_pos_num()); } -template -SegmentBySinogram :: -SegmentBySinogram(const shared_ptr& pdi_ptr, - const int segment_num) - : - Segment(pdi_ptr, segment_num), - Array<3,elemT>(IndexRange3D(pdi_ptr->get_min_axial_pos_num(segment_num), - pdi_ptr->get_max_axial_pos_num(segment_num), - pdi_ptr->get_min_view_num(), - pdi_ptr->get_max_view_num(), - pdi_ptr->get_min_tangential_pos_num(), - pdi_ptr->get_max_tangential_pos_num())) -{} +template +SegmentBySinogram::SegmentBySinogram(const shared_ptr& pdi_ptr, const int segment_num, + const int timing_pos_num) + : Segment(pdi_ptr, segment_num, timing_pos_num), + Array<3, elemT>(IndexRange3D(pdi_ptr->get_min_axial_pos_num(segment_num), pdi_ptr->get_max_axial_pos_num(segment_num), + pdi_ptr->get_min_view_num(), pdi_ptr->get_max_view_num(), + pdi_ptr->get_min_tangential_pos_num(), pdi_ptr->get_max_tangential_pos_num())) {} template -SegmentBySinogram:: -SegmentBySinogram(const SegmentByView& s_v ) - : Segment(s_v.get_proj_data_info_sptr()->create_shared_clone(), - s_v.get_segment_num()), - Array<3,elemT> (IndexRange3D (s_v.get_min_axial_pos_num(), s_v.get_max_axial_pos_num(), - s_v.get_min_view_num(), s_v.get_max_view_num(), - s_v.get_min_tangential_pos_num(), s_v.get_max_tangential_pos_num())) -{ - - for (int r=get_min_axial_pos_num(); r<= get_max_axial_pos_num(); r++) +SegmentBySinogram::SegmentBySinogram(const SegmentByView& s_v) + + : Segment(s_v.get_proj_data_info_sptr()->create_shared_clone(), s_v.get_segment_num(), s_v.get_timing_pos_num()), + Array<3, elemT>(IndexRange3D(s_v.get_min_axial_pos_num(), s_v.get_max_axial_pos_num(), s_v.get_min_view_num(), + s_v.get_max_view_num(), s_v.get_min_tangential_pos_num(), s_v.get_max_tangential_pos_num())) { + + for (int r = get_min_axial_pos_num(); r <= get_max_axial_pos_num(); r++) set_sinogram(s_v.get_sinogram(r)); } -template -bool -SegmentBySinogram:: -operator ==(const Segment& that) const -{ - return - this->has_same_characteristics(that) && - Array<3,elemT>::operator==(static_cast(that)); +template +bool +SegmentBySinogram::operator==(const Segment& that) const { + return this->has_same_characteristics(that) && Array<3, elemT>::operator==(static_cast(that)); } - template -Viewgram -SegmentBySinogram::get_viewgram(int view_num) const -{ +Viewgram +SegmentBySinogram::get_viewgram(int view_num) const { // gcc 2.95.2 needs a this-> in front of get_min_ring for unclear reasons - Array<2,elemT> pre_view(IndexRange2D(this->get_min_axial_pos_num(), get_max_axial_pos_num(), - get_min_tangential_pos_num(),get_max_tangential_pos_num())); - for (int r=get_min_axial_pos_num(); r<= get_max_axial_pos_num(); r++) - pre_view[r] = Array<3,elemT>::operator[](r)[view_num]; - //KT 9/12 constructed a PETSinogram before... + Array<2, elemT> pre_view(IndexRange2D(this->get_min_axial_pos_num(), get_max_axial_pos_num(), get_min_tangential_pos_num(), + get_max_tangential_pos_num())); + for (int r = get_min_axial_pos_num(); r <= get_max_axial_pos_num(); r++) + pre_view[r] = Array<3, elemT>::operator[](r)[view_num]; + // KT 9/12 constructed a PETSinogram before... // CL&KT 15/12 added ring_difference stuff - return Viewgram(pre_view, this->proj_data_info_sptr->create_shared_clone(), view_num, - this->get_segment_num()); + return Viewgram(pre_view, this->proj_data_info_sptr->create_shared_clone(), view_num, this->get_segment_num(), + this->get_timing_pos_num()); } template void -SegmentBySinogram::set_viewgram(const Viewgram& viewgram) -{ - for (int r=get_min_axial_pos_num(); r<= get_max_axial_pos_num(); r++) - Array<3,elemT>::operator[](r)[viewgram.get_view_num()] = viewgram[r]; +SegmentBySinogram::set_viewgram(const Viewgram& viewgram) { + for (int r = get_min_axial_pos_num(); r <= get_max_axial_pos_num(); r++) + Array<3, elemT>::operator[](r)[viewgram.get_view_num()] = viewgram[r]; } - - /*! This makes sure that the new Array dimensions are the same as those in the ProjDataInfo member. */ template -void -SegmentBySinogram:: -resize(const IndexRange<3>& range) -{ +void +SegmentBySinogram::resize(const IndexRange<3>& range) { if (range == this->get_index_range()) return; - assert(range.is_regular()==true); + assert(range.is_regular() == true); const int ax_min = range.get_min_index(); const int ax_max = range.get_max_index(); @@ -142,30 +115,26 @@ resize(const IndexRange<3>& range) assert(range[ax_min].get_min_index() == 0); shared_ptr pdi_sptr = this->proj_data_info_sptr->create_shared_clone(); - + pdi_sptr->set_min_axial_pos_num(ax_min, this->get_segment_num()); pdi_sptr->set_max_axial_pos_num(ax_max, this->get_segment_num()); - + pdi_sptr->set_num_views(range[ax_min].get_max_index() + 1); pdi_sptr->set_min_tangential_pos_num(range[ax_min][0].get_min_index()); pdi_sptr->set_max_tangential_pos_num(range[ax_min][0].get_max_index()); this->proj_data_info_sptr = pdi_sptr; - Array<3,elemT>::resize(range); - + Array<3, elemT>::resize(range); } - /*! This makes sure that the new Array dimensions are the same as those in the ProjDataInfo member. */ template -void -SegmentBySinogram:: -grow(const IndexRange<3>& range) -{ +void +SegmentBySinogram::grow(const IndexRange<3>& range) { resize(range); } diff --git a/src/buildblock/SegmentByView.cxx b/src/buildblock/SegmentByView.cxx index 6dee073a3a..478b2d4216 100644 --- a/src/buildblock/SegmentByView.cxx +++ b/src/buildblock/SegmentByView.cxx @@ -36,102 +36,74 @@ START_NAMESPACE_STIR - template -SegmentByView:: -SegmentByView(const Array<3,elemT>& v, - const shared_ptr& pdi_ptr, - const int segment_num) - : - Segment(pdi_ptr, segment_num), - Array<3,elemT>(v) -{ - assert( get_min_view_num() == pdi_ptr->get_min_view_num()); - assert( get_max_view_num() == pdi_ptr->get_max_view_num()); - assert( get_min_axial_pos_num() == pdi_ptr->get_min_axial_pos_num(segment_num)); - assert( get_max_axial_pos_num() == pdi_ptr->get_max_axial_pos_num(segment_num)); - assert( get_min_tangential_pos_num() == pdi_ptr->get_min_tangential_pos_num()); - assert( get_max_tangential_pos_num() == pdi_ptr->get_max_tangential_pos_num()); - +SegmentByView::SegmentByView(const Array<3, elemT>& v, const shared_ptr& pdi_ptr, + const int segment_num, const int timing_pos_num) + : Segment(pdi_ptr, segment_num, timing_pos_num), Array<3, elemT>(v) { + assert(get_min_view_num() == pdi_ptr->get_min_view_num()); + assert(get_max_view_num() == pdi_ptr->get_max_view_num()); + assert(get_min_axial_pos_num() == pdi_ptr->get_min_axial_pos_num(segment_num)); + assert(get_max_axial_pos_num() == pdi_ptr->get_max_axial_pos_num(segment_num)); + assert(get_min_tangential_pos_num() == pdi_ptr->get_min_tangential_pos_num()); + assert(get_max_tangential_pos_num() == pdi_ptr->get_max_tangential_pos_num()); } template -SegmentByView:: -SegmentByView(const shared_ptr& pdi_ptr, - const int segment_num) - : - Segment(pdi_ptr, segment_num), - Array<3,elemT>(IndexRange3D(pdi_ptr->get_min_view_num(), - pdi_ptr->get_max_view_num(), - pdi_ptr->get_min_axial_pos_num(segment_num), - pdi_ptr->get_max_axial_pos_num(segment_num), - pdi_ptr->get_min_tangential_pos_num(), - pdi_ptr->get_max_tangential_pos_num())) -{} +SegmentByView::SegmentByView(const shared_ptr& pdi_ptr, const int segment_num, + const int timing_pos_num) + : Segment(pdi_ptr, segment_num, timing_pos_num), + Array<3, elemT>(IndexRange3D(pdi_ptr->get_min_view_num(), pdi_ptr->get_max_view_num(), + pdi_ptr->get_min_axial_pos_num(segment_num), pdi_ptr->get_max_axial_pos_num(segment_num), + pdi_ptr->get_min_tangential_pos_num(), pdi_ptr->get_max_tangential_pos_num())) {} template SegmentByView::SegmentByView(const SegmentBySinogram& s_s) - : Segment(s_s.get_proj_data_info_sptr()->create_shared_clone(), - s_s.get_segment_num()), - - Array<3,elemT> (IndexRange3D(s_s.get_min_view_num(),s_s.get_max_view_num(), - s_s.get_min_axial_pos_num(),s_s.get_max_axial_pos_num(), - s_s.get_min_tangential_pos_num(), s_s.get_max_tangential_pos_num())) -{ - - for (int v=get_min_view_num(); v<= get_max_view_num(); v++) + : Segment(s_s.get_proj_data_info_sptr()->create_shared_clone(), s_s.get_segment_num(), s_s.get_timing_pos_num()), + + Array<3, elemT>(IndexRange3D(s_s.get_min_view_num(), s_s.get_max_view_num(), s_s.get_min_axial_pos_num(), + s_s.get_max_axial_pos_num(), s_s.get_min_tangential_pos_num(), + s_s.get_max_tangential_pos_num())) { + + for (int v = get_min_view_num(); v <= get_max_view_num(); v++) set_viewgram(s_s.get_viewgram(v)); } - -template -bool -SegmentByView:: -operator ==(const Segment& that) const -{ - return - this->has_same_characteristics(that) && - Array<3,elemT>::operator==(static_cast(that)); +template +bool +SegmentByView::operator==(const Segment& that) const { + return this->has_same_characteristics(that) && Array<3, elemT>::operator==(static_cast(that)); } template -Sinogram -SegmentByView::get_sinogram(int axial_pos_num) const -{ +Sinogram +SegmentByView::get_sinogram(int axial_pos_num) const { // gcc 2.95.2 needs a this-> in front of get_min_voew_num for unclear reasons - Array<2,elemT> pre_sino(IndexRange2D(this->get_min_view_num(), get_max_view_num(), - get_min_tangential_pos_num(),get_max_tangential_pos_num())); - for (int v=get_min_view_num(); v<= get_max_view_num(); v++) - pre_sino[v] = Array<3,elemT>::operator[](v)[axial_pos_num]; - - return Sinogram(pre_sino, this->proj_data_info_sptr, axial_pos_num, - this->get_segment_num()); + Array<2, elemT> pre_sino( + IndexRange2D(this->get_min_view_num(), get_max_view_num(), get_min_tangential_pos_num(), get_max_tangential_pos_num())); + for (int v = get_min_view_num(); v <= get_max_view_num(); v++) + pre_sino[v] = Array<3, elemT>::operator[](v)[axial_pos_num]; + + return Sinogram(pre_sino, this->proj_data_info_sptr, axial_pos_num, this->get_segment_num(), this->get_timing_pos_num()); } template void -SegmentByView::set_sinogram(const Sinogram& sino, int axial_pos_num) -{ - for (int v=get_min_view_num(); v<= get_max_view_num(); v++) - Array<3,elemT>::operator[](v)[axial_pos_num] = sino[v]; +SegmentByView::set_sinogram(const Sinogram& sino, int axial_pos_num) { + for (int v = get_min_view_num(); v <= get_max_view_num(); v++) + Array<3, elemT>::operator[](v)[axial_pos_num] = sino[v]; } - - - /*! This makes sure that the new Array dimensions are the same as those in the ProjDataInfo member. */ template -void -SegmentByView:: -resize(const IndexRange<3>& range) -{ +void +SegmentByView::resize(const IndexRange<3>& range) { if (range == this->get_index_range()) return; - assert(range.is_regular()==true); + assert(range.is_regular() == true); // can only handle min_view==0 at the moment // TODO @@ -141,18 +113,17 @@ resize(const IndexRange<3>& range) const int ax_min = range[0].get_min_index(); const int ax_max = range[0].get_max_index(); - + pdi_ptr->set_min_axial_pos_num(ax_min, this->get_segment_num()); pdi_ptr->set_max_axial_pos_num(ax_max, this->get_segment_num()); - + pdi_ptr->set_num_views(range.get_max_index() + 1); pdi_ptr->set_min_tangential_pos_num(range[0][ax_min].get_min_index()); pdi_ptr->set_max_tangential_pos_num(range[0][ax_min].get_max_index()); this->proj_data_info_sptr.reset(pdi_ptr); - Array<3,elemT>::resize(range); - + Array<3, elemT>::resize(range); } /*! @@ -160,10 +131,8 @@ resize(const IndexRange<3>& range) ProjDataInfo member. */ template -void -SegmentByView:: -grow(const IndexRange<3>& range) -{ +void +SegmentByView::grow(const IndexRange<3>& range) { resize(range); } @@ -173,5 +142,4 @@ grow(const IndexRange<3>& range) template class SegmentByView; - END_NAMESPACE_STIR diff --git a/src/buildblock/SeparableArrayFunctionObject.cxx b/src/buildblock/SeparableArrayFunctionObject.cxx index 051ccc79f2..86f8cef91b 100644 --- a/src/buildblock/SeparableArrayFunctionObject.cxx +++ b/src/buildblock/SeparableArrayFunctionObject.cxx @@ -34,40 +34,29 @@ START_NAMESPACE_STIR template -SeparableArrayFunctionObject:: -SeparableArrayFunctionObject() -: all_1d_array_filters(VectorWithOffset< shared_ptr > >(num_dim)) -{} +SeparableArrayFunctionObject::SeparableArrayFunctionObject() + : all_1d_array_filters(VectorWithOffset>>(num_dim)) {} template -SeparableArrayFunctionObject:: -SeparableArrayFunctionObject(const VectorWithOffset< shared_ptr > >& array_filters) -: all_1d_array_filters(array_filters) -{ +SeparableArrayFunctionObject::SeparableArrayFunctionObject( + const VectorWithOffset>>& array_filters) + : all_1d_array_filters(array_filters) { assert(all_1d_array_filters.get_length() == num_dim); } - template -void -SeparableArrayFunctionObject:: -do_it(Array& array) const -{ - if (!is_trivial()) - { +void +SeparableArrayFunctionObject::do_it(Array& array) const { + if (!is_trivial()) { #ifndef NDEBUG - // currently in_place_apply_array_functions_on_each_index doesn't handle 0 - // pointers gracefully, so we check here that there aren't any - for (typename VectorWithOffset< shared_ptr > >::const_iterator - iter=all_1d_array_filters.begin(); - iter!=all_1d_array_filters.end(); - ++iter) - assert(!is_null_ptr(*iter)); + // currently in_place_apply_array_functions_on_each_index doesn't handle 0 + // pointers gracefully, so we check here that there aren't any + for (typename VectorWithOffset>>::const_iterator iter = all_1d_array_filters.begin(); + iter != all_1d_array_filters.end(); ++iter) + assert(!is_null_ptr(*iter)); #endif - in_place_apply_array_functions_on_each_index(array, - all_1d_array_filters.begin(), - all_1d_array_filters.end()); - } + in_place_apply_array_functions_on_each_index(array, all_1d_array_filters.begin(), all_1d_array_filters.end()); + } } #if 0 @@ -80,7 +69,7 @@ do_it(Array& out_array, const Array& //if (!is_trivial()) { -#ifndef NDEBUG +# ifndef NDEBUG // currently apply_array_functions_on_each_index doesn't handle 0 // pointers gracefully, so we check here that there aren't any for ( VectorWithOffset< shared_ptr > >::const_iterator @@ -88,7 +77,7 @@ do_it(Array& out_array, const Array& iter!=all_1d_array_filters.end(); ++iter) assert(!is_null_ptr(*iter)); -#endif +# endif apply_array_functions_on_each_index(out_array, in_array, all_1d_array_filters.begin(), all_1d_array_filters.end()); @@ -100,26 +89,17 @@ do_it(Array& out_array, const Array& #endif template -bool -SeparableArrayFunctionObject:: -is_trivial() const -{ - for (typename VectorWithOffset< shared_ptr > >::const_iterator - iter=all_1d_array_filters.begin(); - iter!=all_1d_array_filters.end(); - ++iter) - { - if (!is_null_ptr(*iter) && !(*iter)->is_trivial()) - return false; - } - return true; +bool +SeparableArrayFunctionObject::is_trivial() const { + for (typename VectorWithOffset>>::const_iterator iter = all_1d_array_filters.begin(); + iter != all_1d_array_filters.end(); ++iter) { + if (!is_null_ptr(*iter) && !(*iter)->is_trivial()) + return false; + } + return true; } - // instantiation template class SeparableArrayFunctionObject<3, float>; END_NAMESPACE_STIR - - - diff --git a/src/buildblock/SeparableCartesianMetzImageFilter.cxx b/src/buildblock/SeparableCartesianMetzImageFilter.cxx index 3240aa9bde..9694e6e042 100644 --- a/src/buildblock/SeparableCartesianMetzImageFilter.cxx +++ b/src/buildblock/SeparableCartesianMetzImageFilter.cxx @@ -29,52 +29,39 @@ #include "stir/SeparableCartesianMetzImageFilter.h" #include "stir/VoxelsOnCartesianGrid.h" - START_NAMESPACE_STIR - template Succeeded -SeparableCartesianMetzImageFilter:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) +SeparableCartesianMetzImageFilter::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { -/* if (consistency_check(density) == Succeeded::no) - return Succeeded::no; - */ - const VoxelsOnCartesianGrid& image = - dynamic_cast&>(density); + /* if (consistency_check(density) == Succeeded::no) + return Succeeded::no; + */ + const VoxelsOnCartesianGrid& image = dynamic_cast&>(density); + + metz_filter = + SeparableMetzArrayFilter<3, elemT>(get_metz_fwhms(), get_metz_powers(), image.get_voxel_size(), get_max_kernel_sizes()); - metz_filter = - SeparableMetzArrayFilter<3,elemT>(get_metz_fwhms(), - get_metz_powers(), - image.get_voxel_size(), - get_max_kernel_sizes()); - return Succeeded::yes; - } - template void -SeparableCartesianMetzImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const +SeparableCartesianMetzImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& density) const -{ - //assert(consistency_check(density) == Succeeded::yes); - metz_filter(density); +{ + // assert(consistency_check(density) == Succeeded::yes); + metz_filter(density); } - template void -SeparableCartesianMetzImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, - const DiscretisedDensity<3,elemT>& in_density) const -{ - //assert(consistency_check(in_density) == Succeeded::yes); - metz_filter(out_density,in_density); +SeparableCartesianMetzImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { + // assert(consistency_check(in_density) == Succeeded::yes); + metz_filter(out_density, in_density); } #if 0 @@ -104,50 +91,42 @@ consistency_check( const DiscretisedDensity<3, elemT>& image) const #endif template -SeparableCartesianMetzImageFilter:: -SeparableCartesianMetzImageFilter() -: fwhms(VectorWithOffset(1,3)), - metz_powers(VectorWithOffset(1,3)), - max_kernel_sizes(VectorWithOffset(1,3)) -{ +SeparableCartesianMetzImageFilter::SeparableCartesianMetzImageFilter() + : fwhms(VectorWithOffset(1, 3)), metz_powers(VectorWithOffset(1, 3)), + max_kernel_sizes(VectorWithOffset(1, 3)) { set_defaults(); } template VectorWithOffset -SeparableCartesianMetzImageFilter:: -get_metz_fwhms() const -{ return fwhms;} +SeparableCartesianMetzImageFilter::get_metz_fwhms() const { + return fwhms; +} template -VectorWithOffset -SeparableCartesianMetzImageFilter:: -get_metz_powers() const -{ return metz_powers;} - +VectorWithOffset +SeparableCartesianMetzImageFilter::get_metz_powers() const { + return metz_powers; +} template -VectorWithOffset -SeparableCartesianMetzImageFilter:: -get_max_kernel_sizes() const -{ return max_kernel_sizes;} +VectorWithOffset +SeparableCartesianMetzImageFilter::get_max_kernel_sizes() const { + return max_kernel_sizes; +} template void -SeparableCartesianMetzImageFilter:: -set_defaults() -{ +SeparableCartesianMetzImageFilter::set_defaults() { base_type::set_defaults(); fwhms.fill(0); - metz_powers.fill(0); + metz_powers.fill(0); max_kernel_sizes.fill(-1); } template -void -SeparableCartesianMetzImageFilter:: -initialise_keymap() -{ +void +SeparableCartesianMetzImageFilter::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Separable Cartesian Metz Filter Parameters"); this->parser.add_key("x-dir filter FWHM (in mm)", &fwhms[3]); @@ -155,25 +134,21 @@ initialise_keymap() this->parser.add_key("z-dir filter FWHM (in mm)", &fwhms[1]); this->parser.add_key("x-dir filter Metz power", &metz_powers[3]); this->parser.add_key("y-dir filter Metz power", &metz_powers[2]); - this->parser.add_key("z-dir filter Metz power", &metz_powers[1]); + this->parser.add_key("z-dir filter Metz power", &metz_powers[1]); this->parser.add_key("x-dir maximum kernel size", &max_kernel_sizes[3]); this->parser.add_key("y-dir maximum kernel size", &max_kernel_sizes[2]); this->parser.add_key("z-dir maximum kernel size", &max_kernel_sizes[1]); this->parser.add_stop_key("END Separable Cartesian Metz Filter Parameters"); } - template <> -const char * const -SeparableCartesianMetzImageFilter::registered_name = - "Separable Cartesian Metz"; - +const char* const SeparableCartesianMetzImageFilter::registered_name = "Separable Cartesian Metz"; -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif // Register this class in the ImageProcessor registry // static SeparableCartesianMetzImageFilter::RegisterIt dummy; @@ -182,6 +157,3 @@ SeparableCartesianMetzImageFilter::registered_name = template class SeparableCartesianMetzImageFilter; END_NAMESPACE_STIR - - - diff --git a/src/buildblock/SeparableConvolutionImageFilter.cxx b/src/buildblock/SeparableConvolutionImageFilter.cxx index 7023ddd387..5d143ede49 100644 --- a/src/buildblock/SeparableConvolutionImageFilter.cxx +++ b/src/buildblock/SeparableConvolutionImageFilter.cxx @@ -1,8 +1,8 @@ /*! \file - \ingroup ImageProcessor + \ingroup ImageProcessor \brief Implementation of class stir::SeparableConvolutionImageFilter - + \author Kris Thielemans \author Sanida Mustafovic */ @@ -35,125 +35,88 @@ using std::max; START_NAMESPACE_STIR -template<> -const char * const -SeparableConvolutionImageFilter::registered_name = - "Separable Convolution"; - +template <> +const char* const SeparableConvolutionImageFilter::registered_name = "Separable Convolution"; template -void -SeparableConvolutionImageFilter:: -initialise_keymap() -{ +void +SeparableConvolutionImageFilter::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Separable Convolution Filter Parameters"); - this->parser.add_key("x-dir filter coefficients", &(*(filter_coefficients_for_parsing.begin()+2))); - this->parser.add_key("y-dir filter coefficients", &(*(filter_coefficients_for_parsing.begin()+1))); + this->parser.add_key("x-dir filter coefficients", &(*(filter_coefficients_for_parsing.begin() + 2))); + this->parser.add_key("y-dir filter coefficients", &(*(filter_coefficients_for_parsing.begin() + 1))); this->parser.add_key("z-dir filter coefficients", &(*filter_coefficients_for_parsing.begin())); this->parser.add_stop_key("END Separable Convolution Filter Parameters"); - } template -bool -SeparableConvolutionImageFilter:: -post_processing() -{ +bool +SeparableConvolutionImageFilter::post_processing() { if (base_type::post_processing() != false) return true; - // copy filter_coefficients_for_parsing to filter_coefficients + // copy filter_coefficients_for_parsing to filter_coefficients // todo drop any 0s at the start or end - typename VectorWithOffset< VectorWithOffset >::iterator - coefficients_iter = filter_coefficients.begin(); + typename VectorWithOffset>::iterator coefficients_iter = filter_coefficients.begin(); #ifndef STIR_NO_NAMESPACES - std:: + std:: #endif - vector< vector >::const_iterator - parsing_iter = filter_coefficients_for_parsing.begin(); - for (; - parsing_iter != filter_coefficients_for_parsing.end(); - ++parsing_iter, ++coefficients_iter) - { - const unsigned int size = static_cast(parsing_iter->size()); - const int min_index = -static_cast((size/2)); - if (size%2==0) - warning("Parsing SeparableConvolutionImageFilter\n" - "Even number of filter coefficients for the %d-th dimension." - "I'll (effectively) append a 0 at the end.\n", - coefficients_iter - filter_coefficients.begin() + 1); - - *coefficients_iter = VectorWithOffset(min_index, min_index + size - 1); - - // can't use std::copy because of cast. sigh. - typename VectorWithOffset::iterator - coefficients_elem_iter = coefficients_iter->begin(); + vector>::const_iterator parsing_iter = filter_coefficients_for_parsing.begin(); + for (; parsing_iter != filter_coefficients_for_parsing.end(); ++parsing_iter, ++coefficients_iter) { + const unsigned int size = static_cast(parsing_iter->size()); + const int min_index = -static_cast((size / 2)); + if (size % 2 == 0) + warning("Parsing SeparableConvolutionImageFilter\n" + "Even number of filter coefficients for the %d-th dimension." + "I'll (effectively) append a 0 at the end.\n", + coefficients_iter - filter_coefficients.begin() + 1); + + *coefficients_iter = VectorWithOffset(min_index, min_index + size - 1); + + // can't use std::copy because of cast. sigh. + typename VectorWithOffset::iterator coefficients_elem_iter = coefficients_iter->begin(); #ifndef STIR_NO_NAMESPACES - std:: + std:: #endif - vector::const_iterator - parsing_elem_iter = parsing_iter->begin(); - for (; - parsing_elem_iter != parsing_iter->end(); - ++parsing_elem_iter, ++coefficients_elem_iter) - *coefficients_elem_iter = static_cast(*parsing_elem_iter); - } + vector::const_iterator parsing_elem_iter = parsing_iter->begin(); + for (; parsing_elem_iter != parsing_iter->end(); ++parsing_elem_iter, ++coefficients_elem_iter) + *coefficients_elem_iter = static_cast(*parsing_elem_iter); + } return false; } template -SeparableConvolutionImageFilter:: -SeparableConvolutionImageFilter() -: filter_coefficients_for_parsing(3) -{ - set_defaults(); +SeparableConvolutionImageFilter::SeparableConvolutionImageFilter() : filter_coefficients_for_parsing(3) { + set_defaults(); } - template -SeparableConvolutionImageFilter:: -SeparableConvolutionImageFilter( - const VectorWithOffset< VectorWithOffset >& - filter_coefficients) - : - filter_coefficients_for_parsing(filter_coefficients.get_length()), - filter_coefficients(filter_coefficients) -{ - assert(filter_coefficients.get_length()==3);// num_dimensions +SeparableConvolutionImageFilter::SeparableConvolutionImageFilter( + const VectorWithOffset>& filter_coefficients) + : filter_coefficients_for_parsing(filter_coefficients.get_length()), filter_coefficients(filter_coefficients) { + assert(filter_coefficients.get_length() == 3); // num_dimensions - // copy filter_coefficients to filter_coefficients_for_parsing such + // copy filter_coefficients to filter_coefficients_for_parsing such // that get_parameters() works properly - typename VectorWithOffset< VectorWithOffset >::const_iterator - coefficients_iter = filter_coefficients.begin(); + typename VectorWithOffset>::const_iterator coefficients_iter = filter_coefficients.begin(); #ifndef STIR_NO_NAMESPACES - std:: + std:: #endif - vector< vector >::iterator - parsing_iter = filter_coefficients_for_parsing.begin(); - for (; - parsing_iter != filter_coefficients_for_parsing.end(); - ++parsing_iter, ++coefficients_iter) - { - // make sure that there are 0s appended such that parsing will read it back - // in correct place - const unsigned parsing_size = - 2*(max(coefficients_iter->get_max_index(), - -coefficients_iter->get_min_index())) + 1; - // make it long enough, and initialise with 0 - *parsing_iter = vector(coefficients_iter->get_length(), 0); - - for (int i = coefficients_iter->get_min_index(); - i <= coefficients_iter->get_max_index(); - ++i) - (*parsing_iter)[static_cast((parsing_size/2) + i)] = - (*coefficients_iter)[i]; - } - + vector>::iterator parsing_iter = filter_coefficients_for_parsing.begin(); + for (; parsing_iter != filter_coefficients_for_parsing.end(); ++parsing_iter, ++coefficients_iter) { + // make sure that there are 0s appended such that parsing will read it back + // in correct place + const unsigned parsing_size = 2 * (max(coefficients_iter->get_max_index(), -coefficients_iter->get_min_index())) + 1; + // make it long enough, and initialise with 0 + *parsing_iter = vector(coefficients_iter->get_length(), 0); + + for (int i = coefficients_iter->get_min_index(); i <= coefficients_iter->get_max_index(); ++i) + (*parsing_iter)[static_cast((parsing_size / 2) + i)] = (*coefficients_iter)[i]; + } } #if 0 @@ -168,68 +131,48 @@ get_filter_coefficients() template Succeeded -SeparableConvolutionImageFilter:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) -{ - VectorWithOffset< shared_ptr > > - all_1d_filters(filter_coefficients.get_min_index(), - filter_coefficients.get_max_index()); - - typename VectorWithOffset< VectorWithOffset >::const_iterator - coefficients_iter = filter_coefficients.begin(); - typename VectorWithOffset< shared_ptr > >::iterator - filter_iter = all_1d_filters.begin(); - for (; - coefficients_iter != filter_coefficients.end(); - ++filter_iter, ++coefficients_iter) - { - - filter_iter->reset(new ArrayFilter1DUsingConvolution(*coefficients_iter)); - } - filter = SeparableArrayFunctionObject<3,elemT>(all_1d_filters); +SeparableConvolutionImageFilter::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { + VectorWithOffset>> all_1d_filters(filter_coefficients.get_min_index(), + filter_coefficients.get_max_index()); + + typename VectorWithOffset>::const_iterator coefficients_iter = filter_coefficients.begin(); + typename VectorWithOffset>>::iterator filter_iter = all_1d_filters.begin(); + for (; coefficients_iter != filter_coefficients.end(); ++filter_iter, ++coefficients_iter) { + + filter_iter->reset(new ArrayFilter1DUsingConvolution(*coefficients_iter)); + } + filter = SeparableArrayFunctionObject<3, elemT>(all_1d_filters); return Succeeded::yes; - } - template void -SeparableConvolutionImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const - -{ - filter(density); +SeparableConvolutionImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& density) const +{ + filter(density); } - template void -SeparableConvolutionImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, - const DiscretisedDensity<3,elemT>& in_density) const -{ - filter(out_density,in_density); +SeparableConvolutionImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { + filter(out_density, in_density); } - template void -SeparableConvolutionImageFilter:: -set_defaults() -{ +SeparableConvolutionImageFilter::set_defaults() { base_type::set_defaults(); - filter_coefficients = - VectorWithOffset< VectorWithOffset >(3); + filter_coefficients = VectorWithOffset>(3); } - -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif template class SeparableConvolutionImageFilter; diff --git a/src/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx index 5518cf2557..781d15a8af 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -53,130 +53,105 @@ using std::cerr; using std::endl; #endif - START_NAMESPACE_STIR template -SeparableGaussianArrayFilter:: -SeparableGaussianArrayFilter() -:fwhms(0),max_kernel_sizes(0) -{ - for (int i=1;i<=num_dimensions;i++) +SeparableGaussianArrayFilter::SeparableGaussianArrayFilter() : fwhms(0), max_kernel_sizes(0) { + for (int i = 1; i <= num_dimensions; i++) { - this->all_1d_array_filters[i-1]. - reset(new ArrayFilter1DUsingConvolution()); + this->all_1d_array_filters[i - 1].reset(new ArrayFilter1DUsingConvolution()); } } template -SeparableGaussianArrayFilter:: -SeparableGaussianArrayFilter(const float fwhms_v,const float max_kernel_sizes_v, bool normalise) -:fwhms(fwhms_v),max_kernel_sizes(max_kernel_sizes_v) - { - - //normalisation to 1 is optinal - construct_filter(normalise); - } +SeparableGaussianArrayFilter::SeparableGaussianArrayFilter(const float fwhms_v, + const float max_kernel_sizes_v, bool normalise) + : fwhms(fwhms_v), max_kernel_sizes(max_kernel_sizes_v) { + // normalisation to 1 is optinal + construct_filter(normalise); +} -template -SeparableGaussianArrayFilter:: -SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& fwhms_v, - const BasicCoordinate< num_dimensions,int>& max_kernel_sizes_v, bool normalise) +template +SeparableGaussianArrayFilter::SeparableGaussianArrayFilter( + const BasicCoordinate& fwhms_v, const BasicCoordinate& max_kernel_sizes_v, + bool normalise) -:fwhms(fwhms_v),max_kernel_sizes(max_kernel_sizes_v) -{ - construct_filter(normalise); + : fwhms(fwhms_v), max_kernel_sizes(max_kernel_sizes_v) { + construct_filter(normalise); } - template void -SeparableGaussianArrayFilter:: -construct_filter(bool normalise) -{ - for (int i = 1; i<=num_dimensions;i++) - { +SeparableGaussianArrayFilter::construct_filter(bool normalise) { + for (int i = 1; i <= num_dimensions; i++) { VectorWithOffset filter_coefficients; - calculate_coefficients(filter_coefficients, max_kernel_sizes[i], - fwhms[i],normalise); + calculate_coefficients(filter_coefficients, max_kernel_sizes[i], fwhms[i], normalise); { - std::stringstream ss; - ss << "Gaussian filter dim[" << i << "] =" << filter_coefficients; - info(ss.str(), 2); + std::stringstream ss; + ss << "Gaussian filter dim[" << i << "] =" << filter_coefficients; + info(ss.str(), 2); } - this->all_1d_array_filters[i-1]. - reset(new ArrayFilter1DUsingConvolution(filter_coefficients)); - - } + this->all_1d_array_filters[i - 1].reset(new ArrayFilter1DUsingConvolution(filter_coefficients)); + } } -template +template void -SeparableGaussianArrayFilter:: -calculate_coefficients(VectorWithOffset& filter_coefficients, const int max_kernel_sizes, - const float fwhms, bool normalise) +SeparableGaussianArrayFilter::calculate_coefficients(VectorWithOffset& filter_coefficients, + const int max_kernel_sizes, const float fwhms, + bool normalise) { - if (max_kernel_sizes==0) + if (max_kernel_sizes == 0) error("SeparableGaussianArrayFilter called with max_kernel_size==0 (use -1 for auto-length)"); - const double standard_deviation = sqrt(fwhms*fwhms/(8*log(2.))); + const double standard_deviation = sqrt(fwhms * fwhms / (8 * log(2.))); - if (standard_deviation==0) - { - filter_coefficients.recycle(); - return; + if (standard_deviation == 0) { + filter_coefficients.recycle(); + return; } - int kernel_length = max_kernel_sizes/2; - if (max_kernel_sizes<0) - { - const double ZERO_TOL= 0.000001; // consistent with other files - // find the value x where a normal distribution is ZERO_TOL/sqrt(2 pi) - const double normal_max_x = sqrt(-2*log(ZERO_TOL)); - // rescale to actual - const double max_x = normal_max_x * standard_deviation; - kernel_length = static_cast(ceil(max_x)); - } - filter_coefficients.grow(-kernel_length,kernel_length); - - filter_coefficients[0] = static_cast(1/sqrt(2*_PI)/standard_deviation); - - for (int i = 1; i<=kernel_length;i++) - { - filter_coefficients[i] = - filter_coefficients[-i]= static_cast( - exp(-square(i)/(2.*square(standard_deviation)))/ - sqrt(2*square(standard_deviation)*_PI)); + int kernel_length = max_kernel_sizes / 2; + if (max_kernel_sizes < 0) { + const double ZERO_TOL = 0.000001; // consistent with other files + // find the value x where a normal distribution is ZERO_TOL/sqrt(2 pi) + const double normal_max_x = sqrt(-2 * log(ZERO_TOL)); + // rescale to actual + const double max_x = normal_max_x * standard_deviation; + kernel_length = static_cast(ceil(max_x)); } + filter_coefficients.grow(-kernel_length, kernel_length); -// normalisation: rescaled to dc =1 + filter_coefficients[0] = static_cast(1 / sqrt(2 * _PI) / standard_deviation); -if (normalise) + for (int i = 1; i <= kernel_length; i++) { + filter_coefficients[i] = filter_coefficients[-i] = + static_cast(exp(-square(i) / (2. * square(standard_deviation))) / sqrt(2 * square(standard_deviation) * _PI)); + } - { + // normalisation: rescaled to dc =1 - double sum = 0.; - for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) - { - sum +=double (filter_coefficients[i]); - } + if (normalise) - for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) - { - filter_coefficients[i] /= sum; - } + { + double sum = 0.; + for (int i = filter_coefficients.get_min_index(); i <= filter_coefficients.get_max_index(); i++) { + sum += double(filter_coefficients[i]); } + for (int i = filter_coefficients.get_min_index(); i <= filter_coefficients.get_max_index(); i++) { + filter_coefficients[i] /= sum; + } + } } - -template class SeparableGaussianArrayFilter<3,float>; +template class SeparableGaussianArrayFilter<3, float>; END_NAMESPACE_STIR diff --git a/src/buildblock/SeparableGaussianImageFilter.cxx b/src/buildblock/SeparableGaussianImageFilter.cxx index fe98226c19..8a85325351 100644 --- a/src/buildblock/SeparableGaussianImageFilter.cxx +++ b/src/buildblock/SeparableGaussianImageFilter.cxx @@ -35,154 +35,116 @@ START_NAMESPACE_STIR -//TODO remove define +// TODO remove define #define num_dimensions 3 - template Succeeded -SeparableGaussianImageFilter:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) -{ - +SeparableGaussianImageFilter::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { - if(dynamic_cast*>(&density)== 0) + if (dynamic_cast*>(&density) == 0) - { - warning("SeparableGaussianImageFilter can only handle images of type VoxelsOnCartesianGrid"); - return Succeeded::no; - } + { + warning("SeparableGaussianImageFilter can only handle images of type VoxelsOnCartesianGrid"); + return Succeeded::no; + } - - const BasicCoordinate< num_dimensions,float> rescale = dynamic_cast*>(&density)->get_grid_spacing(); - gaussian_filter = SeparableGaussianArrayFilter(fwhms/rescale,max_kernel_sizes,normalise); + const BasicCoordinate rescale = + dynamic_cast*>(&density)->get_grid_spacing(); + gaussian_filter = SeparableGaussianArrayFilter(fwhms / rescale, max_kernel_sizes, normalise); return Succeeded::yes; - } - template void -SeparableGaussianImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const +SeparableGaussianImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& density) const { - gaussian_filter(density); - + gaussian_filter(density); } - template void -SeparableGaussianImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, - const DiscretisedDensity<3,elemT>& in_density) const -{ +SeparableGaussianImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { - gaussian_filter(out_density,in_density); + gaussian_filter(out_density, in_density); } - template -SeparableGaussianImageFilter:: -SeparableGaussianImageFilter() -: fwhms(0),max_kernel_sizes(0) -{ +SeparableGaussianImageFilter::SeparableGaussianImageFilter() : fwhms(0), max_kernel_sizes(0) { set_defaults(); } template -BasicCoordinate< num_dimensions,float> -SeparableGaussianImageFilter:: -get_fwhms() -{ +BasicCoordinate +SeparableGaussianImageFilter::get_fwhms() { return fwhms; } template bool -SeparableGaussianImageFilter:: -get_normalised_filter() -{ - return normalise; +SeparableGaussianImageFilter::get_normalised_filter() { + return normalise; } - template -BasicCoordinate< num_dimensions,int> -SeparableGaussianImageFilter:: -get_max_kernel_sizes() -{ +BasicCoordinate +SeparableGaussianImageFilter::get_max_kernel_sizes() { return max_kernel_sizes; } - template void -SeparableGaussianImageFilter:: -set_defaults() -{ - base_type::set_defaults(); - fwhms.fill(0); - max_kernel_sizes.fill(-1); - normalise = true; - +SeparableGaussianImageFilter::set_defaults() { + base_type::set_defaults(); + fwhms.fill(0); + max_kernel_sizes.fill(-1); + normalise = true; } template void -SeparableGaussianImageFilter:: -initialise_keymap() -{ - base_type::initialise_keymap(); - this->parser.add_start_key("Separable Gaussian Filter Parameters"); - this->parser.add_key("x-dir filter FWHM (in mm)", &fwhms[3]); - this->parser.add_key("y-dir filter FWHM (in mm)", &fwhms[2]); - this->parser.add_key("z-dir filter FWHM (in mm)", &fwhms[1]); - this->parser.add_key("x-dir maximum kernel size", &max_kernel_sizes[3]); - this->parser.add_key("y-dir maximum kernel size", &max_kernel_sizes[2]); - this->parser.add_key("z-dir maximum kernel size", &max_kernel_sizes[1]); - this->parser.add_key("Normalise filter to 1", &normalise); - this->parser.add_stop_key("END Separable Gaussian Filter Parameters"); +SeparableGaussianImageFilter::initialise_keymap() { + base_type::initialise_keymap(); + this->parser.add_start_key("Separable Gaussian Filter Parameters"); + this->parser.add_key("x-dir filter FWHM (in mm)", &fwhms[3]); + this->parser.add_key("y-dir filter FWHM (in mm)", &fwhms[2]); + this->parser.add_key("z-dir filter FWHM (in mm)", &fwhms[1]); + this->parser.add_key("x-dir maximum kernel size", &max_kernel_sizes[3]); + this->parser.add_key("y-dir maximum kernel size", &max_kernel_sizes[2]); + this->parser.add_key("z-dir maximum kernel size", &max_kernel_sizes[1]); + this->parser.add_key("Normalise filter to 1", &normalise); + this->parser.add_stop_key("END Separable Gaussian Filter Parameters"); } template void -SeparableGaussianImageFilter:: -set_fwhms(const BasicCoordinate< num_dimensions,float>& arg) -{ - fwhms = BasicCoordinate(arg); +SeparableGaussianImageFilter::set_fwhms(const BasicCoordinate& arg) { + fwhms = BasicCoordinate(arg); } template void -SeparableGaussianImageFilter:: -set_max_kernel_sizes(const BasicCoordinate< num_dimensions,int>& arg) -{ - max_kernel_sizes = BasicCoordinate(arg); +SeparableGaussianImageFilter::set_max_kernel_sizes(const BasicCoordinate& arg) { + max_kernel_sizes = BasicCoordinate(arg); } template void -SeparableGaussianImageFilter:: -set_normalise(const bool arg) -{ +SeparableGaussianImageFilter::set_normalise(const bool arg) { normalise = arg; } +template <> +const char* const SeparableGaussianImageFilter::registered_name = "Separable Gaussian"; -template<> -const char * const -SeparableGaussianImageFilter::registered_name = - "Separable Gaussian"; - - -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif // Register this class in the ImageProcessor registry // static SeparableGaussianImageFilter::RegisterIt dummy; diff --git a/src/buildblock/SeparableMetzArrayFilter.cxx b/src/buildblock/SeparableMetzArrayFilter.cxx index 2e9c659e5d..6c3cc23dc2 100644 --- a/src/buildblock/SeparableMetzArrayFilter.cxx +++ b/src/buildblock/SeparableMetzArrayFilter.cxx @@ -47,201 +47,172 @@ using std::endl; START_NAMESPACE_STIR +const float ZERO_TOL = 0.000001F; // MJ 12/05/98 Made consistent with other files +const double TPI = 6.28318530717958647692; -const float ZERO_TOL= 0.000001F; //MJ 12/05/98 Made consistent with other files -const double TPI=6.28318530717958647692; - -// build Gaussian kernel according to the full width half maximum +// build Gaussian kernel according to the full width half maximum template -static void build_gauss(VectorWithOffset&kernel, - int res,float s2, float sampling_interval); +static void build_gauss(VectorWithOffset& kernel, int res, float s2, float sampling_interval); template -static void build_metz(VectorWithOffset&kernel, - float N,float fwhm, float MmPerVoxel, int max_kernel_size); - - +static void build_metz(VectorWithOffset& kernel, float N, float fwhm, float MmPerVoxel, int max_kernel_size); template -SeparableMetzArrayFilter:: -SeparableMetzArrayFilter - (const VectorWithOffset& fwhms_v, - const VectorWithOffset& metz_powers_v, - const BasicCoordinate& sampling_distances_v, - const VectorWithOffset& max_kernel_sizes_v) - : fwhms(fwhms_v), - metz_powers(metz_powers_v), - sampling_distances(sampling_distances_v), - max_kernel_sizes(max_kernel_sizes_v) -{ +SeparableMetzArrayFilter::SeparableMetzArrayFilter( + const VectorWithOffset& fwhms_v, const VectorWithOffset& metz_powers_v, + const BasicCoordinate& sampling_distances_v, const VectorWithOffset& max_kernel_sizes_v) + : fwhms(fwhms_v), metz_powers(metz_powers_v), sampling_distances(sampling_distances_v), max_kernel_sizes(max_kernel_sizes_v) { assert(metz_powers.get_length() == num_dimensions); assert(fwhms.get_length() == num_dimensions); assert(metz_powers.get_min_index() == 1); assert(fwhms.get_min_index() == 1); assert(max_kernel_sizes.get_length() == num_dimensions); assert(max_kernel_sizes.get_min_index() == 1); - - for (int i=1; i<=num_dimensions; ++i) - { + + for (int i = 1; i <= num_dimensions; ++i) { VectorWithOffset kernel; - build_metz(kernel, metz_powers[i],fwhms[i],sampling_distances[i],max_kernel_sizes[i]); - - for (int j=0;j0.0) printf ("%d-dir Metz[%d]=%f\n",i,j,kernel[j]); - else printf ("%d-dir Gauss[%d]=%f\n",i,j,kernel[j]); - - - this->all_1d_array_filters[i-1].reset(new ArrayFilter1DUsingConvolutionSymmetricKernel(kernel)); - + build_metz(kernel, metz_powers[i], fwhms[i], sampling_distances[i], max_kernel_sizes[i]); + + for (int j = 0; j < kernel.get_length(); j++) + if (metz_powers[i] > 0.0) + printf("%d-dir Metz[%d]=%f\n", i, j, kernel[j]); + else + printf("%d-dir Gauss[%d]=%f\n", i, j, kernel[j]); + + this->all_1d_array_filters[i - 1].reset(new ArrayFilter1DUsingConvolutionSymmetricKernel(kernel)); } } template -void build_gauss(VectorWithOffset&kernel, int res,float s2, float sampling_interval) -{ - - +void +build_gauss(VectorWithOffset& kernel, int res, float s2, float sampling_interval) { + elemT sum; - int cutoff=0; - int j,hres; - - - - hres = res/2; - kernel[hres-1] = static_cast(1/sqrt(s2*TPI)); - sum = kernel[hres-1]; - kernel[res-1] = 0; - for (j=1;(j(kernel[hres-1]* exp(-0.5*(j*sampling_interval)*(j*sampling_interval)/s2)); - kernel[hres+j-1] = kernel [hres-j-1]; - sum += 2.0F * kernel[hres-j-1]; - if (kernel[hres-j-1] (1 / sqrt(s2 * TPI)); + sum = kernel[hres - 1]; + kernel[res - 1] = 0; + for (j = 1; (j < hres && !cutoff); j++) { + kernel[hres - j - 1] = + static_cast(kernel[hres - 1] * exp(-0.5 * (j * sampling_interval) * (j * sampling_interval) / s2)); + kernel[hres + j - 1] = kernel[hres - j - 1]; + sum += 2.0F * kernel[hres - j - 1]; + if (kernel[hres - j - 1] < kernel[hres - 1] * ZERO_TOL) + cutoff = 1; + } + /* Normalize the filter to 1 */ - for (j=0;j +void +build_metz(VectorWithOffset& kernel, float N, float fwhm, float MmPerVox, int max_kernel_size) { + int kernel_length = 0; + if (fwhm > 0.0F) { + // MJ 12/05/98 compute parameters relevant to DFT/IDFT + elemT s2 = fwhm * fwhm / (8 * log(2.F)); // variance in Mm + const int n = 7; // determines cut-off in both space and frequency domains + const elemT sinc_length = 10000.0F; + int samples_per_voxel = (int)(MmPerVox * 2 * sqrt(2 * log(10.F) * n / s2) / TPI + 1); + const elemT sampling_interval = MmPerVox / samples_per_voxel; + elemT stretch = (samples_per_voxel > 1) ? sinc_length : 0.0F; + + int Res = (int)(log((sqrt(8 * n * log(10.) * s2) + stretch) / sampling_interval) / log(2.) + 1); + Res = (int)pow(2.0, (double)Res); // MJ 12/05/98 made adaptive -//MJ 19/04/99 Used KT's solution to the shifted index problem. Also build_metz now allocates the kernel. -template -void build_metz(VectorWithOffset& kernel, - float N,float fwhm, float MmPerVox, int max_kernel_size) -{ - - int kernel_length = 0; - - if(fwhm>0.0F){ - - //MJ 12/05/98 compute parameters relevant to DFT/IDFT - - elemT s2 = fwhm*fwhm/(8*log(2.F)); //variance in Mm - - const int n=7; //determines cut-off in both space and frequency domains - const elemT sinc_length=10000.0F; - int samples_per_voxel=(int)(MmPerVox*2*sqrt(2*log(10.F)*n/s2)/TPI +1); - const elemT sampling_interval=MmPerVox/samples_per_voxel; - elemT stretch= (samples_per_voxel>1)?sinc_length:0.0F; - - int Res=(int)(log((sqrt(8*n*log(10.)*s2)+stretch)/sampling_interval)/log(2.)+1); - Res=(int) pow(2.0,(double) Res); //MJ 12/05/98 made adaptive - info(boost::format("Filter parameters:\n" - "Variance: %1%\n" - "Voxel dimension (in mm): %2%\n" - "Samples per voxel: %3%\n" - "Sampling interval (in mm): %4%\n" - "FFT vector length: %5%") - % s2 % MmPerVox % samples_per_voxel % sampling_interval % Res); - + "Variance: %1%\n" + "Voxel dimension (in mm): %2%\n" + "Samples per voxel: %3%\n" + "Sampling interval (in mm): %4%\n" + "FFT vector length: %5%") % + s2 % MmPerVox % samples_per_voxel % sampling_interval % Res); + /* allocate memory to metz arrays */ VectorWithOffset filter(Res); filter.fill(0.0); - //The former technique was illegal. - Array<1,std::complex > fftdata(0,Res-1); - fftdata.fill(0.0); - + // The former technique was illegal. + Array<1, std::complex> fftdata(0, Res - 1); + fftdata.fill(0.0); + /* build gaussian */ - build_gauss(filter,Res,s2,sampling_interval); + build_gauss(filter, Res, s2, sampling_interval); /* Build the fft array*/ - for (int i=0;i<=Res-(Res/2);i++) { - fftdata[i].real(filter[Res/2-1+i]); + for (int i = 0; i <= Res - (Res / 2); i++) { + fftdata[i].real(filter[Res / 2 - 1 + i]); } - - for (int i=1;i<(Res/2);i++) { - fftdata[Res-(Res/2)+i].real(filter[i-1]); + + for (int i = 1; i < (Res / 2); i++) { + fftdata[Res - (Res / 2) + i].real(filter[i - 1]); } /* FFT to frequency space */ fourier(fftdata); - /* Build Metz */ + /* Build Metz */ N++; - - int cutoff=(int) (sampling_interval*Res/(2*MmPerVox)); - //cerr<0.0){ - // cerr<cutoff && Res-i>cutoff) zabs2=0; - - } - - if (zabs2>1) zabs2=static_cast (1-ZERO_TOL); - if (zabs2>0) { - // if (zabs2>=1) cerr< 0.0) { + // cerr< cutoff && Res - i > cutoff) + zabs2 = 0; + } + + if (zabs2 > 1) + zabs2 = static_cast(1 - ZERO_TOL); + if (zabs2 > 0) { + // if (zabs2>=1) cerr<=0;i--){ - if (fabs((double) filter[i])>=(0.0001)*filter[0]) break; - else (kernel_length)--; - + kernel_length = Res; + + for (int i = Res - 1; i >= 0; i--) { + if (fabs((double)filter[i]) >= (0.0001) * filter[0]) + break; + else + (kernel_length)--; } - - + #if 0 // SM&KT 04/04/2001 removed this truncation of the kernel as we don't have the relevant parameter anymore if ((kernel_length)>length_of_row_to_filter/2){ @@ -249,36 +220,31 @@ void build_metz(VectorWithOffset& kernel, } #endif - if (max_kernel_size>0 && (kernel_length)>max_kernel_size/2){ - kernel_length=max_kernel_size/2; + if (max_kernel_size > 0 && (kernel_length) > max_kernel_size / 2) { + kernel_length = max_kernel_size / 2; } - - //VectorWithOffset kernel(kernel_length);//=new elemT[(kernel_length)]; - kernel.grow(0,kernel_length-1); - - for (int i=0;i<(kernel_length);i++) kernel[i]=filter[i]; - - //return kernel; + + // VectorWithOffset kernel(kernel_length);//=new elemT[(kernel_length)]; + kernel.grow(0, kernel_length - 1); + + for (int i = 0; i < (kernel_length); i++) + kernel[i] = filter[i]; + + // return kernel; } - - else{ - //VectorWithOffset kernel(1);//=new elemT[1]; - kernel.grow(0,0); + + else { + // VectorWithOffset kernel(1);//=new elemT[1]; + kernel.grow(0, 0); //*kernel=1.0F; - //kernel_length=1L; + // kernel_length=1L; kernel[0] = 1.F; - kernel_length=1; - - //return kernel; - } + kernel_length = 1; + // return kernel; + } } - - template class SeparableMetzArrayFilter<3, float>; END_NAMESPACE_STIR - - - diff --git a/src/buildblock/Sinogram.cxx b/src/buildblock/Sinogram.cxx index a56ccd7d4f..5b2dd1cb33 100644 --- a/src/buildblock/Sinogram.cxx +++ b/src/buildblock/Sinogram.cxx @@ -35,92 +35,67 @@ #ifdef _MSC_VER // disable warning that not all functions have been implemented when instantiating -#pragma warning(disable: 4661) +# pragma warning(disable : 4661) #endif // _MSC_VER using std::string; START_NAMESPACE_STIR -template +template bool -Sinogram:: -has_same_characteristics(self_type const& other, - string& explanation) const -{ +Sinogram::has_same_characteristics(self_type const& other, string& explanation) const { using boost::format; using boost::str; - if (*this->get_proj_data_info_sptr() != - *other.get_proj_data_info_sptr()) - { - explanation = - str(format("Differing projection data info:\n%1%\n-------- vs-------\n %2%") - % this->get_proj_data_info_sptr()->parameter_info() - % other.get_proj_data_info_sptr()->parameter_info() - ); - return false; - } - if (this->get_axial_pos_num() != - other.get_axial_pos_num()) - { - explanation = - str(format("Differing axial position number: %1% vs %2%") - % this->get_axial_pos_num() - % other.get_axial_pos_num() - ); - return false; - } - if (this->get_segment_num() != - other.get_segment_num()) - { - explanation = - str(format("Differing segment number: %1% vs %2%") - % this->get_segment_num() - % other.get_segment_num() - ); - return false; - } + if (*this->get_proj_data_info_sptr() != *other.get_proj_data_info_sptr()) { + explanation = str(format("Differing projection data info:\n%1%\n-------- vs-------\n %2%") % + this->get_proj_data_info_sptr()->parameter_info() % other.get_proj_data_info_sptr()->parameter_info()); + return false; + } + if (this->get_axial_pos_num() != other.get_axial_pos_num()) { + explanation = + str(format("Differing axial position number: %1% vs %2%") % this->get_axial_pos_num() % other.get_axial_pos_num()); + return false; + } + if (this->get_segment_num() != other.get_segment_num()) { + explanation = str(format("Differing segment number: %1% vs %2%") % this->get_segment_num() % other.get_segment_num()); + return false; + } + if (this->get_timing_pos_num() != other.get_timing_pos_num()) { + explanation = + str(format("Differing timing position index: %1% vs %2%") % this->get_timing_pos_num() % other.get_timing_pos_num()); + return false; + } return true; } -template +template bool -Sinogram:: -has_same_characteristics(self_type const& other) const -{ +Sinogram::has_same_characteristics(self_type const& other) const { std::string explanation; return this->has_same_characteristics(other, explanation); } -template -bool -Sinogram:: -operator ==(const self_type& that) const -{ - return - this->has_same_characteristics(that) && - base_type::operator==(that); +template +bool +Sinogram::operator==(const self_type& that) const { + return this->has_same_characteristics(that) && base_type::operator==(that); } - -template -bool -Sinogram:: -operator !=(const self_type& that) const -{ + +template +bool +Sinogram::operator!=(const self_type& that) const { return !((*this) == that); } - /*! This makes sure that the new Array dimensions are the same as those in the ProjDataInfo member. */ template -void -Sinogram:: -resize(const IndexRange<2>& range) -{ +void +Sinogram::resize(const IndexRange<2>& range) { if (range == this->get_index_range()) return; @@ -128,17 +103,16 @@ resize(const IndexRange<2>& range) // TODO assert(range.get_min_index() == 0); - - shared_ptr pdi_ptr (proj_data_info_ptr->clone()); - + + shared_ptr pdi_ptr(proj_data_info_ptr->clone()); + pdi_ptr->set_num_views(range.get_max_index() + 1); pdi_ptr->set_min_tangential_pos_num(range[0].get_min_index()); pdi_ptr->set_max_tangential_pos_num(range[0].get_max_index()); proj_data_info_ptr = pdi_ptr; - Array<2,elemT>::resize(range); - + Array<2, elemT>::resize(range); } /*! @@ -146,10 +120,8 @@ resize(const IndexRange<2>& range) ProjDataInfo member. */ template -void -Sinogram:: -grow(const IndexRange<2>& range) -{ +void +Sinogram::grow(const IndexRange<2>& range) { resize(range); } diff --git a/src/buildblock/TextWriter.cxx b/src/buildblock/TextWriter.cxx index db41f3e387..a18402d6c3 100644 --- a/src/buildblock/TextWriter.cxx +++ b/src/buildblock/TextWriter.cxx @@ -6,18 +6,19 @@ aTextWriter* TextWriterHandle::information_channel_; aTextWriter* TextWriterHandle::warning_channel_; aTextWriter* TextWriterHandle::error_channel_; -void writeText(const char* text, OUTPUT_CHANNEL channel) { - TextWriterHandle h; - switch (channel) { - case INFORMATION_CHANNEL: - h.print_information(text); - break; - case WARNING_CHANNEL: - h.print_warning(text); - break; - case ERROR_CHANNEL: - h.print_error(text); - } +void +writeText(const char* text, OUTPUT_CHANNEL channel) { + TextWriterHandle h; + switch (channel) { + case INFORMATION_CHANNEL: + h.print_information(text); + break; + case WARNING_CHANNEL: + h.print_warning(text); + break; + case ERROR_CHANNEL: + h.print_error(text); + } } END_NAMESPACE_STIR diff --git a/src/buildblock/ThresholdMinToSmallPositiveValueDataProcessor.cxx b/src/buildblock/ThresholdMinToSmallPositiveValueDataProcessor.cxx index e64e034f7a..23e4e32267 100644 --- a/src/buildblock/ThresholdMinToSmallPositiveValueDataProcessor.cxx +++ b/src/buildblock/ThresholdMinToSmallPositiveValueDataProcessor.cxx @@ -28,94 +28,70 @@ #include "stir/ThresholdMinToSmallPositiveValueDataProcessor.h" #include "stir/thresholding.h" #include "stir/DiscretisedDensity.h" -#include "stir/modelling/ParametricDiscretisedDensity.h" -#include "stir/modelling/KineticParameters.h" +#include "stir/modelling/ParametricDiscretisedDensity.h" +#include "stir/modelling/KineticParameters.h" START_NAMESPACE_STIR - template Succeeded -ThresholdMinToSmallPositiveValueDataProcessor:: -virtual_set_up(const DataT& density) +ThresholdMinToSmallPositiveValueDataProcessor::virtual_set_up(const DataT& density) { - return Succeeded::yes; + return Succeeded::yes; } - template void -ThresholdMinToSmallPositiveValueDataProcessor:: -virtual_apply(DataT& data) const +ThresholdMinToSmallPositiveValueDataProcessor::virtual_apply(DataT& data) const -{ +{ threshold_min_to_small_positive_value(data.begin_all(), data.end_all(), 0.000001F); - //threshold_min_to_small_positive_value_and_truncate_rim(data, 0); + // threshold_min_to_small_positive_value_and_truncate_rim(data, 0); } - template void -ThresholdMinToSmallPositiveValueDataProcessor:: -virtual_apply(DataT& out_data, - const DataT& in_data) const -{ +ThresholdMinToSmallPositiveValueDataProcessor::virtual_apply(DataT& out_data, const DataT& in_data) const { out_data = in_data; threshold_min_to_small_positive_value(out_data.begin_all(), out_data.end_all(), 0.000001F); } template -ThresholdMinToSmallPositiveValueDataProcessor:: -ThresholdMinToSmallPositiveValueDataProcessor() -{ +ThresholdMinToSmallPositiveValueDataProcessor::ThresholdMinToSmallPositiveValueDataProcessor() { set_defaults(); } template void -ThresholdMinToSmallPositiveValueDataProcessor:: -set_defaults() -{ +ThresholdMinToSmallPositiveValueDataProcessor::set_defaults() { base_type::set_defaults(); } template -void -ThresholdMinToSmallPositiveValueDataProcessor:: -initialise_keymap() -{ +void +ThresholdMinToSmallPositiveValueDataProcessor::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Threshold Min To Small Positive Value Parameters"); this->parser.add_stop_key("END Threshold Min To Small Positive Value Parameters"); } +template +const char* const ThresholdMinToSmallPositiveValueDataProcessor::registered_name = "Threshold Min To Small Positive Value"; - -template -const char * const -ThresholdMinToSmallPositiveValueDataProcessor:: - registered_name = - "Threshold Min To Small Positive Value"; - - -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif // Register this class in the DataProcessor registry // static ThresholdMinToSmallPositiveValueDataProcessor::RegisterIt dummy; // have the above variable in a separate file, which you need to pass at link time -template class ThresholdMinToSmallPositiveValueDataProcessor >; -template class ThresholdMinToSmallPositiveValueDataProcessor< ParametricVoxelsOnCartesianGrid >; -//template class ThresholdMinToSmallPositiveValueDataProcessor< VoxelsOnCartesianGrid > >; -//template class ThresholdMinToSmallPositiveValueDataProcessor< VoxelsOnCartesianGrid > >; -//template class ThresholdMinToSmallPositiveValueDataProcessor< VoxelsOnCartesianGrid > >; +template class ThresholdMinToSmallPositiveValueDataProcessor>; +template class ThresholdMinToSmallPositiveValueDataProcessor; +// template class ThresholdMinToSmallPositiveValueDataProcessor< VoxelsOnCartesianGrid > >; +// template class ThresholdMinToSmallPositiveValueDataProcessor< VoxelsOnCartesianGrid > >; +// template class ThresholdMinToSmallPositiveValueDataProcessor< VoxelsOnCartesianGrid > >; END_NAMESPACE_STIR - - - - diff --git a/src/buildblock/TimeFrameDefinitions.cxx b/src/buildblock/TimeFrameDefinitions.cxx index 5bf60661b4..3c06dd662f 100644 --- a/src/buildblock/TimeFrameDefinitions.cxx +++ b/src/buildblock/TimeFrameDefinitions.cxx @@ -17,11 +17,11 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup buildblock \brief Implementation of class stir::TimeFrameDefinitions - + \author Kris Thielemans */ @@ -29,8 +29,8 @@ #include "stir/ExamInfo.h" #include "stir/IO/FileSignature.h" #ifdef HAVE_LLN_MATRIX -#include "stir/IO/stir_ecat6.h" -#include "stir/IO/stir_ecat7.h" +# include "stir/IO/stir_ecat6.h" +# include "stir/IO/stir_ecat7.h" #endif #include "stir/IO/InterfileHeader.h" #include "stir/IO/interfile.h" @@ -54,108 +54,80 @@ using std::ifstream; START_NAMESPACE_STIR - double -TimeFrameDefinitions:: -get_start_time(unsigned int frame_num) const -{ - return frame_times.at(frame_num-1).first; +TimeFrameDefinitions::get_start_time(unsigned int frame_num) const { + return frame_times.at(frame_num - 1).first; } double -TimeFrameDefinitions:: -get_end_time(unsigned int frame_num) const -{ - return frame_times.at(frame_num-1).second; +TimeFrameDefinitions::get_end_time(unsigned int frame_num) const { + return frame_times.at(frame_num - 1).second; } double -TimeFrameDefinitions:: -get_duration(unsigned int frame_num) const -{ +TimeFrameDefinitions::get_duration(unsigned int frame_num) const { return get_end_time(frame_num) - get_start_time(frame_num); } double -TimeFrameDefinitions:: -get_start_time() const -{ +TimeFrameDefinitions::get_start_time() const { return get_start_time(1); } double -TimeFrameDefinitions:: -get_end_time() const -{ +TimeFrameDefinitions::get_end_time() const { return get_end_time(get_num_frames()); } unsigned int -TimeFrameDefinitions:: -get_num_frames() const -{ +TimeFrameDefinitions::get_num_frames() const { return static_cast(frame_times.size()); } unsigned int -TimeFrameDefinitions:: -get_num_time_frames() const -{ +TimeFrameDefinitions::get_num_time_frames() const { return static_cast(frame_times.size()); } -TimeFrameDefinitions:: -TimeFrameDefinitions() -{} +TimeFrameDefinitions::TimeFrameDefinitions() {} -unsigned int -TimeFrameDefinitions:: -get_time_frame_num(const double start_time, const double end_time) const -{ - assert(end_time >=start_time); - for (unsigned int i = 1; i <=this->get_num_frames(); i++) - { - const double start = this->get_start_time(i); - const double end = this->get_end_time(i); - if (std::fabs(start-start_time)<.01 && std::fabs(end-end_time)<.01) - { - return i; - } +unsigned int +TimeFrameDefinitions::get_time_frame_num(const double start_time, const double end_time) const { + assert(end_time >= start_time); + for (unsigned int i = 1; i <= this->get_num_frames(); i++) { + const double start = this->get_start_time(i); + const double end = this->get_end_time(i); + if (std::fabs(start - start_time) < .01 && std::fabs(end - end_time) < .01) { + return i; } + } // not found return 0; } -TimeFrameDefinitions:: -TimeFrameDefinitions(const string& filename) -{ +TimeFrameDefinitions::TimeFrameDefinitions(const string& filename) { const FileSignature file_signature(filename); - const char * signature = file_signature.get_signature(); + const char* signature = file_signature.get_signature(); #ifdef HAVE_LLN_MATRIX - if (ecat::ecat6::is_ECAT6_file(filename) || - ecat::ecat7::is_ECAT7_file(filename)) - { - shared_ptr exam_info_sptr(ecat::ecat7::read_ECAT7_exam_info(filename)); - *this = exam_info_sptr->time_frame_definitions; - } - else + if (ecat::ecat6::is_ECAT6_file(filename) || ecat::ecat7::is_ECAT7_file(filename)) { + shared_ptr exam_info_sptr(ecat::ecat7::read_ECAT7_exam_info(filename)); + *this = exam_info_sptr->time_frame_definitions; + } else #endif - // Interfile - if (is_interfile_signature(signature)) - { + // Interfile + if (is_interfile_signature(signature)) { #ifndef NDEBUG info(boost::format("TimeFrameDefinitions: trying to read '%s' as Interfile") % filename); #endif - InterfileHeader hdr; + InterfileHeader hdr; if (!hdr.parse(filename.c_str(), false)) // silent parsing - { - error(boost::format("Parsing of Interfile header failed for file '%s'") % filename); - } + { + error(boost::format("Parsing of Interfile header failed for file '%s'") % filename); + } *this = hdr.get_exam_info().time_frame_definitions; - } - else + } else read_fdef_file(filename); #if 0 @@ -171,119 +143,98 @@ TimeFrameDefinitions(const string& filename) cerr << '}' << endl; #endif } - + void -TimeFrameDefinitions:: -read_fdef_file(const string& fdef_filename) -{ +TimeFrameDefinitions::read_fdef_file(const string& fdef_filename) { ifstream in(fdef_filename.c_str()); if (!in) error("TimeFrameDefinitions: Error reading \"%s\"\n", fdef_filename.c_str()); - double previous_end_time = 0; - while (true) - { + while (true) { int num; double duration; in >> num >> duration; if (!in) break; // check if input is ok - // note: allow negative 'duration' if num==0 to be able to skip in negative direction + // note: allow negative 'duration' if num==0 to be able to skip in negative direction // (useful for starting the first frame at negative time) - if (num<0 || (num>0 && duration<=0)) - error("TimeFrameDefinitions: Reading frame_def file \"%s\":\n" - "encountered negative numbers (%d, %g)\n", - fdef_filename.c_str(), num, duration); - - if (num==0) - { - // special case to allow us to skip a time period without storing it - previous_end_time+=duration; - } - while (num--) - { - frame_times.push_back(make_pair(previous_end_time, previous_end_time+duration)); - previous_end_time+=duration; + if (num < 0 || (num > 0 && duration <= 0)) + error("TimeFrameDefinitions: Reading frame_def file \"%s\":\n" + "encountered negative numbers (%d, %g)\n", + fdef_filename.c_str(), num, duration); + + if (num == 0) { + // special case to allow us to skip a time period without storing it + previous_end_time += duration; + } + while (num--) { + frame_times.push_back(make_pair(previous_end_time, previous_end_time + duration)); + previous_end_time += duration; } } - if (this->get_num_frames()==0) + if (this->get_num_frames() == 0) error("TimeFrameDefinitions: Reading frame definitions file \"%s\":\n" - "I didn't discover any frames. Wrong file format?\n" - "Should be an ECAT6, ECAT7 file or a text file with something like\n\n" - "3 50.5\n1 10\n0 3\n1 9\n\n" - "for 3 frames of 50.5 secs, 1 frame of 10 secs, a gap of 3 secs, 1 frame of 9 secs.", - fdef_filename.c_str()); + "I didn't discover any frames. Wrong file format?\n" + "Should be an ECAT6, ECAT7 file or a text file with something like\n\n" + "3 50.5\n1 10\n0 3\n1 9\n\n" + "for 3 frames of 50.5 secs, 1 frame of 10 secs, a gap of 3 secs, 1 frame of 9 secs.", + fdef_filename.c_str()); } -TimeFrameDefinitions:: -TimeFrameDefinitions(const vector >& frame_times) - : frame_times(frame_times) -{ - if (get_num_frames()==0) +TimeFrameDefinitions::TimeFrameDefinitions(const vector>& frame_times) : frame_times(frame_times) { + if (get_num_frames() == 0) return; // check times are in sequence double current_time = get_start_time(1); - for (unsigned int current_frame = 1; current_frame <= get_num_frames(); ++ current_frame) - { - if (current_time > get_start_time(current_frame) + .001) // add .001 to avoid numerical errors - error("TimeFrameDefinitions: frame number %d start_time (%g) is smaller than " - "previous end_time (%g)\n", - current_frame, get_start_time(current_frame), current_time); - if (get_start_time(current_frame) > get_end_time(current_frame) + .01) // add .01 to avoid numerical errors - error("TimeFrameDefinitions: frame number %d start_time (%g) is larger than " - "end_time (%g)\n", - current_frame, get_start_time(current_frame), get_end_time(current_frame)); - current_time = get_end_time(current_frame); - } + for (unsigned int current_frame = 1; current_frame <= get_num_frames(); ++current_frame) { + if (current_time > get_start_time(current_frame) + .001) // add .001 to avoid numerical errors + error("TimeFrameDefinitions: frame number %d start_time (%g) is smaller than " + "previous end_time (%g)\n", + current_frame, get_start_time(current_frame), current_time); + if (get_start_time(current_frame) > get_end_time(current_frame) + .01) // add .01 to avoid numerical errors + error("TimeFrameDefinitions: frame number %d start_time (%g) is larger than " + "end_time (%g)\n", + current_frame, get_start_time(current_frame), get_end_time(current_frame)); + current_time = get_end_time(current_frame); + } } -TimeFrameDefinitions:: -TimeFrameDefinitions(const vector& start_times, - const vector& durations) -{ +TimeFrameDefinitions::TimeFrameDefinitions(const vector& start_times, const vector& durations) { if (start_times.size() != durations.size()) error("TimeFrameDefinitions: constructed with start_times " - "and durations of different length"); + "and durations of different length"); this->frame_times.resize(start_times.size()); - for (unsigned int current_frame = 1; - current_frame <= this->get_num_frames(); - ++ current_frame) - { - frame_times[current_frame-1].first = - start_times[current_frame-1]; - frame_times[current_frame-1].second = - start_times[current_frame-1] + durations[current_frame-1]; - } + for (unsigned int current_frame = 1; current_frame <= this->get_num_frames(); ++current_frame) { + frame_times[current_frame - 1].first = start_times[current_frame - 1]; + frame_times[current_frame - 1].second = start_times[current_frame - 1] + durations[current_frame - 1]; + } } -TimeFrameDefinitions:: -TimeFrameDefinitions(const TimeFrameDefinitions& org_frame_defs, unsigned int frame_num) -{ +TimeFrameDefinitions::TimeFrameDefinitions(const TimeFrameDefinitions& org_frame_defs, unsigned int frame_num) { this->frame_times.push_back(make_pair(org_frame_defs.get_start_time(frame_num), org_frame_defs.get_end_time(frame_num))); } void -TimeFrameDefinitions:: -set_time_frame(const int frame_num, const double start, const double end) -{ - frame_times.at(frame_num-1).first = start; - frame_times.at(frame_num-1).second = end; +TimeFrameDefinitions::set_time_frame(const int frame_num, const double start, const double end) { + frame_times.at(frame_num - 1).first = start; + frame_times.at(frame_num - 1).second = end; } -bool TimeFrameDefinitions::operator == (const TimeFrameDefinitions &t) const { - for (int frame=0;frame_gate_sequence[num-1].second; +TimeGateDefinitions::get_gate_duration(unsigned int num) const { + return this->_gate_sequence[num - 1].second; } unsigned int -TimeGateDefinitions:: -get_gate_num(unsigned int num) const -{ - return this->_gate_sequence[num-1].first; +TimeGateDefinitions::get_gate_num(unsigned int num) const { + return this->_gate_sequence[num - 1].first; } unsigned int -TimeGateDefinitions:: -get_num_gates() const -{ +TimeGateDefinitions::get_num_gates() const { return static_cast(this->_gate_sequence.size()); } unsigned int -TimeGateDefinitions:: -get_num_time_gates() const -{ +TimeGateDefinitions::get_num_time_gates() const { return static_cast(this->_gate_sequence.size()); } -TimeGateDefinitions:: -TimeGateDefinitions() -{} +TimeGateDefinitions::TimeGateDefinitions() {} -TimeGateDefinitions:: -TimeGateDefinitions(const string& gdef_filename) -{ - TimeGateDefinitions::read_gdef_file(gdef_filename); -} +TimeGateDefinitions::TimeGateDefinitions(const string& gdef_filename) { TimeGateDefinitions::read_gdef_file(gdef_filename); } - void -TimeGateDefinitions:: -read_gdef_file(const string& gdef_filename) -{ +TimeGateDefinitions::read_gdef_file(const string& gdef_filename) { ifstream in(gdef_filename.c_str()); - if (!in) - { - const string gdef_newfilename=gdef_filename+".gdef"; - warning("TimeGateDefinitions: Warning failed reading \"%s\"\n Trying with .gdef extension...", gdef_filename.c_str()); - ifstream innew(gdef_filename.c_str()); - if (!innew) - error("TimeGateDefinitions: Error reading \"%s\"\n", gdef_newfilename.c_str()); - } - while (true) - { - int gate_num; - double duration; - in >> gate_num >> duration; - if (!in) - break; - if (gate_num<0 || (gate_num>0 && duration<0)) - error("TimeGateDefinitions: Reading gate_def file \"%s\":\n" - "encountered negative numbers (%d, %g)\n", - gdef_filename.c_str(), gate_num, duration); - this->_gate_sequence.push_back(make_pair(gate_num, duration)); - } - if (this->get_num_gates()==0) + if (!in) { + const string gdef_newfilename = gdef_filename + ".gdef"; + warning("TimeGateDefinitions: Warning failed reading \"%s\"\n Trying with .gdef extension...", gdef_filename.c_str()); + ifstream innew(gdef_filename.c_str()); + if (!innew) + error("TimeGateDefinitions: Error reading \"%s\"\n", gdef_newfilename.c_str()); + } + while (true) { + int gate_num; + double duration; + in >> gate_num >> duration; + if (!in) + break; + if (gate_num < 0 || (gate_num > 0 && duration < 0)) + error("TimeGateDefinitions: Reading gate_def file \"%s\":\n" + "encountered negative numbers (%d, %g)\n", + gdef_filename.c_str(), gate_num, duration); + this->_gate_sequence.push_back(make_pair(gate_num, duration)); + } + if (this->get_num_gates() == 0) error("TimeGateDefinitions: Reading gate definitions file \"%s\":\n" - "I didn't discover any gates. Wrong file format?\n" - "A text file with something like\n\n" - "3 50.5\n1 10\n10 7\n\n" - "for 3rd gate of 50.5 secs, 1st gate of 10 secs, 10th gate of 7 secs.", - gdef_filename.c_str()); + "I didn't discover any gates. Wrong file format?\n" + "A text file with something like\n\n" + "3 50.5\n1 10\n10 7\n\n" + "for 3rd gate of 50.5 secs, 1st gate of 10 secs, 10th gate of 7 secs.", + gdef_filename.c_str()); } -TimeGateDefinitions:: -TimeGateDefinitions(const vector >& gate_sequence) - : _gate_sequence(gate_sequence) -{ +TimeGateDefinitions::TimeGateDefinitions(const vector>& gate_sequence) + : _gate_sequence(gate_sequence) { if (gate_sequence.size() == 0) error("TimeGateDefinitions: constructed with gate_sequence of no gates"); return; - + this->_gate_sequence.resize(gate_sequence.size()); - for (unsigned int current_gate = 1; - current_gate <= this->_gate_sequence.size(); - ++current_gate) - { - this->_gate_sequence[current_gate-1].first = - gate_sequence[current_gate-1].first; - this->_gate_sequence[current_gate-1].second = - gate_sequence[current_gate-1].second; - } + for (unsigned int current_gate = 1; current_gate <= this->_gate_sequence.size(); ++current_gate) { + this->_gate_sequence[current_gate - 1].first = gate_sequence[current_gate - 1].first; + this->_gate_sequence[current_gate - 1].second = gate_sequence[current_gate - 1].second; + } } -TimeGateDefinitions:: -TimeGateDefinitions(const vector& gate_num_vector, - const vector& duration_vector) -{ +TimeGateDefinitions::TimeGateDefinitions(const vector& gate_num_vector, const vector& duration_vector) { if (gate_num_vector.size() != duration_vector.size()) error("TimeGateDefinitions: constructed with gate_sequence " "and durations of different length"); this->_gate_sequence.resize(gate_num_vector.size()); - for (unsigned int current_gate = 1; - current_gate <= gate_num_vector.size(); - ++current_gate) - { - this->_gate_sequence[current_gate-1].first = - gate_num_vector[current_gate-1]; - this->_gate_sequence[current_gate-1].second = - duration_vector[current_gate-1]; - } + for (unsigned int current_gate = 1; current_gate <= gate_num_vector.size(); ++current_gate) { + this->_gate_sequence[current_gate - 1].first = gate_num_vector[current_gate - 1]; + this->_gate_sequence[current_gate - 1].second = duration_vector[current_gate - 1]; + } } END_NAMESPACE_STIR diff --git a/src/buildblock/TruncateToCylindricalFOVImageProcessor.cxx b/src/buildblock/TruncateToCylindricalFOVImageProcessor.cxx index fa6f5bd16b..c596a2e54f 100644 --- a/src/buildblock/TruncateToCylindricalFOVImageProcessor.cxx +++ b/src/buildblock/TruncateToCylindricalFOVImageProcessor.cxx @@ -31,84 +31,61 @@ START_NAMESPACE_STIR template <> -const char * const -TruncateToCylindricalFOVImageProcessor::registered_name = - "Truncate To Cylindrical FOV"; - +const char* const TruncateToCylindricalFOVImageProcessor::registered_name = "Truncate To Cylindrical FOV"; template -void -TruncateToCylindricalFOVImageProcessor:: -initialise_keymap() -{ +void +TruncateToCylindricalFOVImageProcessor::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Truncate To Cylindrical FOV Parameters"); this->parser.add_key("strictly_less_than_radius", &_strictly_less_than_radius); this->parser.add_stop_key("END Truncate To Cylindrical FOV Parameters"); } - template -void -TruncateToCylindricalFOVImageProcessor:: -set_defaults() -{ +void +TruncateToCylindricalFOVImageProcessor::set_defaults() { base_type::set_defaults(); this->_strictly_less_than_radius = true; } - - template Succeeded -TruncateToCylindricalFOVImageProcessor:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) +TruncateToCylindricalFOVImageProcessor::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { - if (dynamic_cast *>(&density) == 0) + if (dynamic_cast*>(&density) == 0) return Succeeded::no; else return Succeeded::yes; - } - template void -TruncateToCylindricalFOVImageProcessor:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const +TruncateToCylindricalFOVImageProcessor::virtual_apply(DiscretisedDensity<3, elemT>& density) const -{ - truncate_rim(density, 0, this->_strictly_less_than_radius); +{ + truncate_rim(density, 0, this->_strictly_less_than_radius); } - template void -TruncateToCylindricalFOVImageProcessor:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, - const DiscretisedDensity<3,elemT>& in_density) const -{ +TruncateToCylindricalFOVImageProcessor::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { out_density = in_density; this->virtual_apply(out_density); } - template -TruncateToCylindricalFOVImageProcessor:: -TruncateToCylindricalFOVImageProcessor() -{ +TruncateToCylindricalFOVImageProcessor::TruncateToCylindricalFOVImageProcessor() { this->set_defaults(); } - - - -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif // Register this class in the ImageProcessor registry // static TruncateToCylindricalFOVImageProcessor::RegisterIt dummy; @@ -117,6 +94,3 @@ TruncateToCylindricalFOVImageProcessor() template class TruncateToCylindricalFOVImageProcessor; END_NAMESPACE_STIR - - - diff --git a/src/buildblock/Verbosity.cxx b/src/buildblock/Verbosity.cxx index 5bb42a716d..1bb4dd2e42 100644 --- a/src/buildblock/Verbosity.cxx +++ b/src/buildblock/Verbosity.cxx @@ -31,23 +31,21 @@ START_NAMESPACE_STIR // Global static pointer used to ensure a single instance of the class. -Verbosity* Verbosity::_instance = NULL; +Verbosity* Verbosity::_instance = NULL; -Verbosity::Verbosity(){ - _verbosity_level = 2; -}; +Verbosity::Verbosity() { _verbosity_level = 2; }; -int Verbosity::get() -{ - if (!_instance) // Only allow one instance of class to be generated. +int +Verbosity::get() { + if (!_instance) // Only allow one instance of class to be generated. _instance = new Verbosity; return _instance->_verbosity_level; } -void Verbosity::set(int level) -{ - if (!_instance) // Only allow one instance of class to be generated. +void +Verbosity::set(int level) { + if (!_instance) // Only allow one instance of class to be generated. _instance = new Verbosity; _instance->_verbosity_level = level; diff --git a/src/buildblock/Viewgram.cxx b/src/buildblock/Viewgram.cxx index 630420ad31..16fc4f4597 100644 --- a/src/buildblock/Viewgram.cxx +++ b/src/buildblock/Viewgram.cxx @@ -35,79 +35,56 @@ #ifdef _MSC_VER // disable warning that not all functions have been implemented when instantiating -#pragma warning(disable: 4661) +# pragma warning(disable : 4661) #endif // _MSC_VER using std::string; START_NAMESPACE_STIR -template +template bool -Viewgram:: -has_same_characteristics(self_type const& other, - string& explanation) const -{ +Viewgram::has_same_characteristics(self_type const& other, string& explanation) const { using boost::format; using boost::str; - if (*this->get_proj_data_info_sptr() != - *other.get_proj_data_info_sptr()) - { - explanation = - str(format("Differing projection data info:\n%1%\n-------- vs-------\n %2%") - % this->get_proj_data_info_sptr()->parameter_info() - % other.get_proj_data_info_sptr()->parameter_info() - ); - return false; - } - if (this->get_view_num() != - other.get_view_num()) - { - explanation = - str(format("Differing view number: %1% vs %2%") - % this->get_view_num() - % other.get_view_num() - ); - return false; - } - if (this->get_segment_num() != - other.get_segment_num()) - { - explanation = - str(format("Differing segment number: %1% vs %2%") - % this->get_segment_num() - % other.get_segment_num() - ); - return false; - } + if (*this->get_proj_data_info_sptr() != *other.get_proj_data_info_sptr()) { + explanation = str(format("Differing projection data info:\n%1%\n-------- vs-------\n %2%") % + this->get_proj_data_info_sptr()->parameter_info() % other.get_proj_data_info_sptr()->parameter_info()); + return false; + } + if (this->get_view_num() != other.get_view_num()) { + explanation = str(format("Differing view number: %1% vs %2%") % this->get_view_num() % other.get_view_num()); + return false; + } + if (this->get_segment_num() != other.get_segment_num()) { + explanation = str(format("Differing segment number: %1% vs %2%") % this->get_segment_num() % other.get_segment_num()); + return false; + } + if (this->get_timing_pos_num() != other.get_timing_pos_num()) { + explanation = + str(format("Differing timing position index: %1% vs %2%") % this->get_timing_pos_num() % other.get_timing_pos_num()); + return false; + } return true; } -template +template bool -Viewgram:: -has_same_characteristics(self_type const& other) const -{ +Viewgram::has_same_characteristics(self_type const& other) const { std::string explanation; return this->has_same_characteristics(other, explanation); } -template -bool -Viewgram:: -operator ==(const self_type& that) const -{ - return - this->has_same_characteristics(that) && - base_type::operator==(that); +template +bool +Viewgram::operator==(const self_type& that) const { + return this->has_same_characteristics(that) && base_type::operator==(that); } - -template -bool -Viewgram:: -operator !=(const self_type& that) const -{ + +template +bool +Viewgram::operator!=(const self_type& that) const { return !((*this) == that); } @@ -116,18 +93,16 @@ operator !=(const self_type& that) const ProjDataInfo member. */ template -void -Viewgram:: -resize(const IndexRange<2>& range) -{ +void +Viewgram::resize(const IndexRange<2>& range) { if (range == this->get_index_range()) return; - assert(range.is_regular()==true); + assert(range.is_regular() == true); const int ax_min = range.get_min_index(); const int ax_max = range.get_max_index(); - + shared_ptr pdi_sptr(proj_data_info_sptr->clone()); pdi_sptr->set_min_axial_pos_num(ax_min, get_segment_num()); @@ -137,24 +112,19 @@ resize(const IndexRange<2>& range) proj_data_info_sptr = pdi_sptr; - Array<2,elemT>::resize(range); - + Array<2, elemT>::resize(range); } - /*! This makes sure that the new Array dimensions are the same as those in the ProjDataInfo member. */ template -void -Viewgram:: -grow(const IndexRange<2>& range) -{ +void +Viewgram::grow(const IndexRange<2>& range) { resize(range); } - /****************************** instantiations ****************************/ diff --git a/src/buildblock/VoxelsOnCartesianGrid.cxx b/src/buildblock/VoxelsOnCartesianGrid.cxx index fce96131b0..5b3d692575 100644 --- a/src/buildblock/VoxelsOnCartesianGrid.cxx +++ b/src/buildblock/VoxelsOnCartesianGrid.cxx @@ -18,11 +18,11 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup densitydata - \brief Implementations of stir::VoxelsOnCartesianGrid + \file + \ingroup densitydata + \brief Implementations of stir::VoxelsOnCartesianGrid - \author Sanida Mustafovic + \author Sanida Mustafovic \author Kris Thielemans (with help from Alexey Zverovich) \author PARAPET project @@ -55,24 +55,18 @@ START_NAMESPACE_STIR // a local help function to find appropriate sizes etc. -static void find_sampling_and_z_size( - float& z_sampling, - float& s_sampling, - int& z_size, - const ProjDataInfo* proj_data_info_ptr) -{ +static void +find_sampling_and_z_size(float& z_sampling, float& s_sampling, int& z_size, const ProjDataInfo* proj_data_info_ptr) { // first z- things - if (const ProjDataInfoCylindrical* - proj_data_info_cyl_ptr = - dynamic_cast(proj_data_info_ptr)) + if (const ProjDataInfoCylindrical* proj_data_info_cyl_ptr = dynamic_cast(proj_data_info_ptr)) - { + { // the case of cylindrical data - z_sampling = proj_data_info_cyl_ptr->get_ring_spacing()/2; - + z_sampling = proj_data_info_cyl_ptr->get_ring_spacing() / 2; + // for 'span>1' case, we take z_size = number of sinograms in segment 0 // for 'span==1' case, we take 2*num_rings-1 @@ -80,152 +74,104 @@ static void find_sampling_and_z_size( assert(proj_data_info_cyl_ptr->get_min_segment_num() <= 0); assert(proj_data_info_cyl_ptr->get_max_segment_num() >= 0); - if (z_size<0) - z_size = - proj_data_info_cyl_ptr->get_max_ring_difference(0) > - proj_data_info_cyl_ptr->get_min_ring_difference(0) - ? proj_data_info_cyl_ptr->get_num_axial_poss(0) - : 2*proj_data_info_cyl_ptr->get_num_axial_poss(0) - 1; - } - else - { + if (z_size < 0) + z_size = proj_data_info_cyl_ptr->get_max_ring_difference(0) > proj_data_info_cyl_ptr->get_min_ring_difference(0) + ? proj_data_info_cyl_ptr->get_num_axial_poss(0) + : 2 * proj_data_info_cyl_ptr->get_num_axial_poss(0) - 1; + } else { // this is any other weird projection data. We just check sampling of segment 0 - + // first check if we have segment 0 assert(proj_data_info_cyl_ptr->get_min_segment_num() <= 0); assert(proj_data_info_cyl_ptr->get_max_segment_num() >= 0); // TODO make this independent on segment etc. - z_sampling = - proj_data_info_ptr->get_sampling_in_t(Bin(0,0,1,0)); + z_sampling = proj_data_info_ptr->get_sampling_in_t(Bin(0, 0, 1, 0)); - if (z_size<0) + if (z_size < 0) z_size = proj_data_info_ptr->get_num_axial_poss(0); } // now do s_sampling { - s_sampling = - proj_data_info_ptr->get_scanner_ptr()->get_default_bin_size(); - if (s_sampling <= 0) - { - s_sampling = - proj_data_info_ptr->get_sampling_in_s(Bin(0,0,0,0)); - info(boost::format("Determining voxel size from default_bin_size failed as it is not set.\n" - "Using sampling_in_s for central bin %1%.") % - s_sampling); - } - else - { - info(boost::format("Determined voxel size by dividing default_bin_size (%1%) by zoom") % - s_sampling); - } - + s_sampling = proj_data_info_ptr->get_scanner_ptr()->get_default_bin_size(); + if (s_sampling <= 0) { + s_sampling = proj_data_info_ptr->get_sampling_in_s(Bin(0, 0, 0, 0)); + info(boost::format("Determining voxel size from default_bin_size failed as it is not set.\n" + "Using sampling_in_s for central bin %1%.") % + s_sampling); + } else { + info(boost::format("Determined voxel size by dividing default_bin_size (%1%) by zoom") % s_sampling); + } } - } +template +VoxelsOnCartesianGrid::VoxelsOnCartesianGrid() : DiscretisedDensityOnCartesianGrid<3, elemT>() {} -template -VoxelsOnCartesianGrid ::VoxelsOnCartesianGrid() - : DiscretisedDensityOnCartesianGrid<3,elemT>() -{} - -template -VoxelsOnCartesianGrid::VoxelsOnCartesianGrid - (const Array<3,elemT>& v, - const CartesianCoordinate3D& origin, - const BasicCoordinate<3,float>& grid_spacing) - :DiscretisedDensityOnCartesianGrid<3,elemT> - (v.get_index_range(),origin,grid_spacing) -{ - Array<3,elemT>::operator=(v); +template +VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const Array<3, elemT>& v, const CartesianCoordinate3D& origin, + const BasicCoordinate<3, float>& grid_spacing) + : DiscretisedDensityOnCartesianGrid<3, elemT>(v.get_index_range(), origin, grid_spacing) { + Array<3, elemT>::operator=(v); } +template +VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const IndexRange<3>& range, const CartesianCoordinate3D& origin, + const BasicCoordinate<3, float>& grid_spacing) + : DiscretisedDensityOnCartesianGrid<3, elemT>(range, origin, grid_spacing) {} -template -VoxelsOnCartesianGrid::VoxelsOnCartesianGrid - (const IndexRange<3>& range, - const CartesianCoordinate3D& origin, - const BasicCoordinate<3,float>& grid_spacing) - :DiscretisedDensityOnCartesianGrid<3,elemT> - (range,origin,grid_spacing) -{} - -template -VoxelsOnCartesianGrid::VoxelsOnCartesianGrid - (const shared_ptr < const ExamInfo > & exam_info_sptr, - const Array<3,elemT>& v, - const CartesianCoordinate3D& origin, - const BasicCoordinate<3,float>& grid_spacing) - :DiscretisedDensityOnCartesianGrid<3,elemT> - (exam_info_sptr,v.get_index_range(),origin,grid_spacing) -{ - Array<3,elemT>::operator=(v); +template +VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const shared_ptr& exam_info_sptr, const Array<3, elemT>& v, + const CartesianCoordinate3D& origin, + const BasicCoordinate<3, float>& grid_spacing) + : DiscretisedDensityOnCartesianGrid<3, elemT>(exam_info_sptr, v.get_index_range(), origin, grid_spacing) { + Array<3, elemT>::operator=(v); } - -template -VoxelsOnCartesianGrid::VoxelsOnCartesianGrid - (const shared_ptr < const ExamInfo > & exam_info_sptr, - const IndexRange<3>& range, - const CartesianCoordinate3D& origin, - const BasicCoordinate<3,float>& grid_spacing) - :DiscretisedDensityOnCartesianGrid<3,elemT> - (exam_info_sptr,range,origin,grid_spacing) -{} +template +VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const shared_ptr& exam_info_sptr, const IndexRange<3>& range, + const CartesianCoordinate3D& origin, + const BasicCoordinate<3, float>& grid_spacing) + : DiscretisedDensityOnCartesianGrid<3, elemT>(exam_info_sptr, range, origin, grid_spacing) {} // KT 10/12/2001 use new format of args for the constructor, and remove the make_xy_size_odd constructor -template -VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const ProjDataInfo& proj_data_info, - const float zoom, +template +VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const ProjDataInfo& proj_data_info, const float zoom, const CartesianCoordinate3D& origin, const CartesianCoordinate3D& sizes) - + { shared_ptr exam_info_sptr_v(new ExamInfo); - this->construct_from_projdata_info(exam_info_sptr_v,proj_data_info, - CartesianCoordinate3D(1.F, zoom, zoom), - origin, + this->construct_from_projdata_info(exam_info_sptr_v, proj_data_info, CartesianCoordinate3D(1.F, zoom, zoom), origin, sizes); } -template -VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const shared_ptr < const ExamInfo > & exam_info_sptr_v, - const ProjDataInfo& proj_data_info, - const float zoom, +template +VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const shared_ptr& exam_info_sptr_v, + const ProjDataInfo& proj_data_info, const float zoom, const CartesianCoordinate3D& origin, - const CartesianCoordinate3D& sizes) -{ - this->construct_from_projdata_info(exam_info_sptr_v,proj_data_info, - CartesianCoordinate3D(1.F, zoom, zoom), - origin, + const CartesianCoordinate3D& sizes) { + this->construct_from_projdata_info(exam_info_sptr_v, proj_data_info, CartesianCoordinate3D(1.F, zoom, zoom), origin, sizes); } -template -VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const shared_ptr < const ExamInfo > & exam_info_sptr_v, - const ProjDataInfo& proj_data_info, - const CartesianCoordinate3D& zooms, +template +VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const shared_ptr& exam_info_sptr_v, + const ProjDataInfo& proj_data_info, const CartesianCoordinate3D& zooms, const CartesianCoordinate3D& origin, - const CartesianCoordinate3D& sizes) -{ - this->construct_from_projdata_info(exam_info_sptr_v,proj_data_info, - zooms, - origin, - sizes); + const CartesianCoordinate3D& sizes) { + this->construct_from_projdata_info(exam_info_sptr_v, proj_data_info, zooms, origin, sizes); } -template +template void -VoxelsOnCartesianGrid:: -construct_from_projdata_info(const shared_ptr < const ExamInfo > & exam_info_sptr_v, - const ProjDataInfo& proj_data_info, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& origin, - const CartesianCoordinate3D& sizes) -{ +VoxelsOnCartesianGrid::construct_from_projdata_info(const shared_ptr& exam_info_sptr_v, + const ProjDataInfo& proj_data_info, + const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& origin, + const CartesianCoordinate3D& sizes) { this->exam_info_sptr = exam_info_sptr_v; // sadly, this code is a complete copy of the above // probably avoidable in C++11 @@ -233,112 +179,93 @@ construct_from_projdata_info(const shared_ptr < const ExamInfo > & exam_info_spt int z_size = sizes.z(); // initialise to 0 to prevent compiler warnings - //int z_size = 0; + // int z_size = 0; float z_sampling = 0; float s_sampling = 0; find_sampling_and_z_size(z_sampling, s_sampling, z_size, &proj_data_info); - - this->set_grid_spacing( - CartesianCoordinate3D(z_sampling, s_sampling, s_sampling) / zooms - ); + + this->set_grid_spacing(CartesianCoordinate3D(z_sampling, s_sampling, s_sampling) / zooms); int x_size_used = sizes.x(); int y_size_used = sizes.y(); - if (sizes.x()==-1 || sizes.y()==-1) - { - // default it to cover full FOV by taking image_size>=2*FOVradius_in_pixs+1 - const float FOVradius_in_mm = - max(proj_data_info.get_s(Bin(0,0,0,proj_data_info.get_max_tangential_pos_num())), - -proj_data_info.get_s(Bin(0,0,0,proj_data_info.get_min_tangential_pos_num()))); - if (sizes.x()==-1) - x_size_used = 2*static_cast(ceil(FOVradius_in_mm / get_voxel_size().x())) + 1; - if (sizes.y()==-1) - y_size_used = 2*static_cast(ceil(FOVradius_in_mm / get_voxel_size().y())) + 1; - } - if (x_size_used<0) - error("VoxelsOnCartesianGrid: attempt to construct image with negative x_size %d\n", - x_size_used); - if (x_size_used==0) + if (sizes.x() == -1 || sizes.y() == -1) { + // default it to cover full FOV by taking image_size>=2*FOVradius_in_pixs+1 + const float FOVradius_in_mm = max(proj_data_info.get_s(Bin(0, 0, 0, proj_data_info.get_max_tangential_pos_num())), + -proj_data_info.get_s(Bin(0, 0, 0, proj_data_info.get_min_tangential_pos_num()))); + if (sizes.x() == -1) + x_size_used = 2 * static_cast(ceil(FOVradius_in_mm / get_voxel_size().x())) + 1; + if (sizes.y() == -1) + y_size_used = 2 * static_cast(ceil(FOVradius_in_mm / get_voxel_size().y())) + 1; + } + if (x_size_used < 0) + error("VoxelsOnCartesianGrid: attempt to construct image with negative x_size %d\n", x_size_used); + if (x_size_used == 0) warning("VoxelsOnCartesianGrid: constructed image with x_size 0\n"); - if (y_size_used<0) - error("VoxelsOnCartesianGrid: attempt to construct image with negative y_size %d\n", - y_size_used); - if (y_size_used==0) + if (y_size_used < 0) + error("VoxelsOnCartesianGrid: attempt to construct image with negative y_size %d\n", y_size_used); + if (y_size_used == 0) warning("VoxelsOnCartesianGrid: constructed image with y_size 0\n"); - IndexRange3D range (0, z_size-1, - -(y_size_used/2), -(y_size_used/2) + y_size_used-1, - -(x_size_used/2), -(x_size_used/2) + x_size_used-1); - + IndexRange3D range(0, z_size - 1, -(y_size_used / 2), -(y_size_used / 2) + y_size_used - 1, -(x_size_used / 2), + -(x_size_used / 2) + x_size_used - 1); this->grow(range); } /*! This member function will be unnecessary when all compilers can handle - 'covariant' return types. + 'covariant' return types. It is a non-virtual counterpart of get_empty_voxels_on_cartesian_grid. */ -template +template VoxelsOnCartesianGrid* VoxelsOnCartesianGrid::get_empty_voxels_on_cartesian_grid() const { - return new VoxelsOnCartesianGrid(this->get_exam_info().create_shared_clone(), - this->get_index_range(), - this->get_origin(), + return new VoxelsOnCartesianGrid(this->get_exam_info().create_shared_clone(), this->get_index_range(), this->get_origin(), this->get_grid_spacing()); } - -template +template #ifdef STIR_NO_COVARIANT_RETURN_TYPES -DiscretisedDensity<3,elemT>* +DiscretisedDensity<3, elemT>* #else VoxelsOnCartesianGrid* #endif -VoxelsOnCartesianGrid::get_empty_copy() const -{ +VoxelsOnCartesianGrid::get_empty_copy() const { return get_empty_voxels_on_cartesian_grid(); } -template +template #ifdef STIR_NO_COVARIANT_RETURN_TYPES -DiscretisedDensity<3,elemT>* +DiscretisedDensity<3, elemT>* #else VoxelsOnCartesianGrid* #endif -VoxelsOnCartesianGrid::clone() const -{ - VoxelsOnCartesianGrid *temp = new VoxelsOnCartesianGrid(*this); +VoxelsOnCartesianGrid::clone() const { + VoxelsOnCartesianGrid* temp = new VoxelsOnCartesianGrid(*this); temp->set_exam_info(temp->get_exam_info()); return temp; } -template -void -VoxelsOnCartesianGrid::set_voxel_size(const BasicCoordinate<3,float>& c) -{ +template +void +VoxelsOnCartesianGrid::set_voxel_size(const BasicCoordinate<3, float>& c) { this->set_grid_spacing(c); } -template -PixelsOnCartesianGrid -VoxelsOnCartesianGrid::get_plane(const int z) const -{ - PixelsOnCartesianGrid - plane(this->operator[](z), - this->get_origin(), - Coordinate2D(get_voxel_size().y(), get_voxel_size().x()) - ); +template +PixelsOnCartesianGrid +VoxelsOnCartesianGrid::get_plane(const int z) const { + PixelsOnCartesianGrid plane(this->operator[](z), this->get_origin(), + Coordinate2D(get_voxel_size().y(), get_voxel_size().x())); return plane; } /*! This function requires that the dimensions, origin and grid_spacings match. */ -template -void -VoxelsOnCartesianGrid::set_plane(const PixelsOnCartesianGrid& plane, const int z) -{ +template +void +VoxelsOnCartesianGrid::set_plane(const PixelsOnCartesianGrid& plane, const int z) { assert(this->get_min_x() == plane.get_min_x()); assert(this->get_max_x() == plane.get_max_x()); assert(this->get_min_y() == plane.get_min_y()); @@ -346,18 +273,17 @@ VoxelsOnCartesianGrid::set_plane(const PixelsOnCartesianGrid& plan assert(this->get_origin() == plane.get_origin()); assert(this->get_voxel_size().x() == plane.get_pixel_size().x()); assert(this->get_voxel_size().y() == plane.get_pixel_size().y()); - - this->operator[](z) = plane; + + this->operator[](z) = plane; } -template -void -VoxelsOnCartesianGrid::grow_z_range(const int min_z, const int max_z) -{ +template +void +VoxelsOnCartesianGrid::grow_z_range(const int min_z, const int max_z) { /* This is somewhat complicated as Array is not very good with regular ranges. - It works by - - getting the regular range, - - 'grow' this by hand, + It works by + - getting the regular range, + - 'grow' this by hand, - make a general IndexRange from this - call Array::grow with the general range */ @@ -372,30 +298,24 @@ VoxelsOnCartesianGrid::grow_z_range(const int min_z, const int max_z) this->grow(IndexRange<3>(min_indices, max_indices)); } -template -BasicCoordinate<3,int> -VoxelsOnCartesianGrid:: -get_lengths() const -{ +template +BasicCoordinate<3, int> +VoxelsOnCartesianGrid::get_lengths() const { return make_coordinate(this->get_z_size(), this->get_y_size(), this->get_x_size()); } -template -BasicCoordinate<3,int> -VoxelsOnCartesianGrid:: -get_min_indices() const -{ +template +BasicCoordinate<3, int> +VoxelsOnCartesianGrid::get_min_indices() const { CartesianCoordinate3D min_indices; CartesianCoordinate3D max_indices; this->get_regular_range(min_indices, max_indices); return min_indices; } -template -BasicCoordinate<3,int> -VoxelsOnCartesianGrid:: -get_max_indices() const -{ +template +BasicCoordinate<3, int> +VoxelsOnCartesianGrid::get_max_indices() const { CartesianCoordinate3D min_indices; CartesianCoordinate3D max_indices; this->get_regular_range(min_indices, max_indices); @@ -493,13 +413,13 @@ VoxelsOnCartesianGrid VoxelsOnCartesianGrid::ask_parameters() instantiations **********************************************/ template class VoxelsOnCartesianGrid; -template class VoxelsOnCartesianGrid >; +template class VoxelsOnCartesianGrid>; END_NAMESPACE_STIR #include "stir/modelling/KineticParameters.h" namespace stir { - template class VoxelsOnCartesianGrid >; - template class VoxelsOnCartesianGrid >; - template class VoxelsOnCartesianGrid >; -} +template class VoxelsOnCartesianGrid>; +template class VoxelsOnCartesianGrid>; +template class VoxelsOnCartesianGrid>; +} // namespace stir diff --git a/src/buildblock/buildblock_registries.cxx b/src/buildblock/buildblock_registries.cxx index c4e66fd977..13261f4311 100644 --- a/src/buildblock/buildblock_registries.cxx +++ b/src/buildblock/buildblock_registries.cxx @@ -25,7 +25,7 @@ \brief File that registers all stir::RegisterObject children in buildblock \author Kris Thielemans - + */ #include "stir/SeparableCartesianMetzImageFilter.h" @@ -38,7 +38,7 @@ #include "stir/NonseparableConvolutionUsingRealDFTImageFilter.h" #include "stir/TruncateToCylindricalFOVImageProcessor.h" #ifdef HAVE_JSON -#include "stir/HUToMuImageProcessor.h" +# include "stir/HUToMuImageProcessor.h" #endif START_NAMESPACE_STIR @@ -48,9 +48,9 @@ static SeparableCartesianMetzImageFilter::RegisterIt dummy2; static SeparableGaussianImageFilter::RegisterIt dummySGF; static SeparableConvolutionImageFilter::RegisterIt dummy5; static NonseparableConvolutionUsingRealDFTImageFilter::RegisterIt dummy7; -static TruncateToCylindricalFOVImageProcessor ::RegisterIt dummy6; -static ChainedDataProcessor >::RegisterIt dummy3; -static ThresholdMinToSmallPositiveValueDataProcessor >::RegisterIt dummy4; +static TruncateToCylindricalFOVImageProcessor::RegisterIt dummy6; +static ChainedDataProcessor>::RegisterIt dummy3; +static ThresholdMinToSmallPositiveValueDataProcessor>::RegisterIt dummy4; #ifdef HAVE_JSON static HUToMuImageProcessor>::RegisterIt dummyHUToMu; diff --git a/src/buildblock/centre_of_gravity.cxx b/src/buildblock/centre_of_gravity.cxx index 112bd76c56..a0c5c74913 100644 --- a/src/buildblock/centre_of_gravity.cxx +++ b/src/buildblock/centre_of_gravity.cxx @@ -17,15 +17,14 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup Array - - \brief Implementations of centre_of_gravity.h - \warning Only 1, 2 and 3 dimensional versions with floats are instantiated. + + \brief Implementations of centre_of_gravity.h + \warning Only 1, 2 and 3 dimensional versions with floats are instantiated. \author Kris Thielemans */ - #include "stir/VoxelsOnCartesianGrid.h" #include "stir/CartesianCoordinate3D.h" #include "stir/centre_of_gravity.h" @@ -37,106 +36,86 @@ using std::min; using std::max; #endif - START_NAMESPACE_STIR template T -find_unweighted_centre_of_gravity_1d(const VectorWithOffset& row) -{ +find_unweighted_centre_of_gravity_1d(const VectorWithOffset& row) { T CoG; assign(CoG, 0); - for (int x=row.get_min_index(); x<=row.get_max_index(); x++) - CoG += row[x]*x; + for (int x = row.get_min_index(); x <= row.get_max_index(); x++) + CoG += row[x] * x; return CoG; } #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -#define T float +# define T float #else template #endif T -find_unweighted_centre_of_gravity(const Array<1,T>& row) -{ +find_unweighted_centre_of_gravity(const Array<1, T>& row) { return find_unweighted_centre_of_gravity_1d(row); } template -BasicCoordinate -find_unweighted_centre_of_gravity(const Array& array) -{ +BasicCoordinate +find_unweighted_centre_of_gravity(const Array& array) { if (array.size() == 0) - return BasicCoordinate(0); + return BasicCoordinate(0); /* Use recursion to lower dimensional case, based on the following sum_ijk {i,j,k} a_ijk - = sum_i {i,0,0} sum_jk a_ijk + + = sum_i {i,0,0} sum_jk a_ijk + sum_i sum_jk {0,j,k} a_ijk The first term can be computed as a 1D CoG calculation, the last term is a sum of num_dimensions-1 CoG's. */ // last term - BasicCoordinate lower_dimension_CoG(0); - for (int i=array.get_min_index(); i<=array.get_max_index(); ++i) - { - lower_dimension_CoG += find_unweighted_centre_of_gravity(array[i]); - } + BasicCoordinate lower_dimension_CoG(0); + for (int i = array.get_min_index(); i <= array.get_max_index(); ++i) { + lower_dimension_CoG += find_unweighted_centre_of_gravity(array[i]); + } // first term - Array<1,T> - first_dim_sums(array.get_min_index(), array.get_max_index()); - for (int i=array.get_min_index(); i<=array.get_max_index(); ++i) - { - first_dim_sums[i] = array[i].sum(); - } - const T first_dim_CoG = - find_unweighted_centre_of_gravity(first_dim_sums); + Array<1, T> first_dim_sums(array.get_min_index(), array.get_max_index()); + for (int i = array.get_min_index(); i <= array.get_max_index(); ++i) { + first_dim_sums[i] = array[i].sum(); + } + const T first_dim_CoG = find_unweighted_centre_of_gravity(first_dim_sums); // put them into 1 coordinate and return return join(first_dim_CoG, lower_dimension_CoG); } - template -BasicCoordinate -find_centre_of_gravity(const Array& array) -{ +BasicCoordinate +find_centre_of_gravity(const Array& array) { const T sum = array.sum(); if (sum == 0) error("Warning: find_centre_of_gravity cannot properly normalise, as data sum to 0\n"); - return - find_unweighted_centre_of_gravity(array) / sum; + return find_unweighted_centre_of_gravity(array) / sum; } - template void -find_centre_of_gravity_in_mm_per_plane( VectorWithOffset< CartesianCoordinate3D >& allCoG, - VectorWithOffset& weights, - const VoxelsOnCartesianGrid& image) -{ - - allCoG = - VectorWithOffset< CartesianCoordinate3D > - (image.get_min_index(), image.get_max_index()); - weights = - VectorWithOffset - (image.get_min_index(), image.get_max_index()); - - for (int z=image.get_min_index(); z<=image.get_max_index(); z++) - { +find_centre_of_gravity_in_mm_per_plane(VectorWithOffset>& allCoG, VectorWithOffset& weights, + const VoxelsOnCartesianGrid& image) { + + allCoG = VectorWithOffset>(image.get_min_index(), image.get_max_index()); + weights = VectorWithOffset(image.get_min_index(), image.get_max_index()); + + for (int z = image.get_min_index(); z <= image.get_max_index(); z++) { weights[z] = max(image[z].sum(), 0.F); - if (weights[z]==0) - allCoG[z] = CartesianCoordinate3D(0.F,0.F,0.F); - else - { - const BasicCoordinate<2,T> CoG = find_centre_of_gravity(image[z]); - allCoG[z].y() = CoG[1]; - allCoG[z].x() = CoG[2]; - } + if (weights[z] == 0) + allCoG[z] = CartesianCoordinate3D(0.F, 0.F, 0.F); + else { + const BasicCoordinate<2, T> CoG = find_centre_of_gravity(image[z]); + allCoG[z].y() = CoG[1]; + allCoG[z].x() = CoG[2]; + } allCoG[z].z() = static_cast(z); allCoG[z] = image.get_physical_coordinates_for_indices(allCoG[z]); } @@ -144,22 +123,16 @@ find_centre_of_gravity_in_mm_per_plane( VectorWithOffset< CartesianCoordinate3D template CartesianCoordinate3D -find_centre_of_gravity_in_mm(const VoxelsOnCartesianGrid& image) -{ - const BasicCoordinate<3,T> CoG = find_centre_of_gravity(image); - return image.get_physical_coordinates_for_indices(CoG); +find_centre_of_gravity_in_mm(const VoxelsOnCartesianGrid& image) { + const BasicCoordinate<3, T> CoG = find_centre_of_gravity(image); + return image.get_physical_coordinates_for_indices(CoG); } - - //******* INSTANTIATIONS // next instantiations already does 1 and 2 dimensional versions of the other functions -template -void -find_centre_of_gravity_in_mm_per_plane( VectorWithOffset< CartesianCoordinate3D >& allCoG, - VectorWithOffset& weights, - const VoxelsOnCartesianGrid& image); +template void find_centre_of_gravity_in_mm_per_plane(VectorWithOffset>& allCoG, + VectorWithOffset& weights, const VoxelsOnCartesianGrid& image); /* template @@ -167,8 +140,6 @@ BasicCoordinate<3,float> find_centre_of_gravity(const Array<3,float>&); */ // this instantiates 3D versions -template -CartesianCoordinate3D -find_centre_of_gravity_in_mm(const VoxelsOnCartesianGrid& image); +template CartesianCoordinate3D find_centre_of_gravity_in_mm(const VoxelsOnCartesianGrid& image); END_NAMESPACE_STIR diff --git a/src/buildblock/date_time_functions.cxx b/src/buildblock/date_time_functions.cxx index 2b43f8fd9b..73422e66ff 100644 --- a/src/buildblock/date_time_functions.cxx +++ b/src/buildblock/date_time_functions.cxx @@ -16,9 +16,9 @@ */ /*! - \file + \file \ingroup date_time - + \brief Functions for date-time conversions \author Kris Thielemans @@ -34,33 +34,32 @@ START_NAMESPACE_STIR -int time_zone_offset_in_secs() -{ +int +time_zone_offset_in_secs() { static bool first_run = true; static int tz_offset; - if (first_run) - { - first_run = false; - - time_t current_time = time(0); - //struct tm * local_time = localtime(¤t_time); - //std::cerr << "Local: " << local_time->tm_hour << ',' << local_time->tm_isdst; - struct tm * gmt = gmtime(¤t_time); - //std::cerr << ", GMT: " << gmt->tm_hour << ',' << gmt->tm_isdst << "\n"; - time_t gm_time = mktime(gmt); - // std::cerr << " diff Local-GMT: " << difftime(current_time, gm_time)/3600. << "\n"; - tz_offset =round(difftime(current_time, gm_time)); - } + if (first_run) { + first_run = false; + + time_t current_time = time(0); + // struct tm * local_time = localtime(¤t_time); + // std::cerr << "Local: " << local_time->tm_hour << ',' << local_time->tm_isdst; + struct tm* gmt = gmtime(¤t_time); + // std::cerr << ", GMT: " << gmt->tm_hour << ',' << gmt->tm_isdst << "\n"; + time_t gm_time = mktime(gmt); + // std::cerr << " diff Local-GMT: " << difftime(current_time, gm_time)/3600. << "\n"; + tz_offset = round(difftime(current_time, gm_time)); + } return tz_offset; } -int current_time_zone_and_DST_offset_in_secs() -{ +int +current_time_zone_and_DST_offset_in_secs() { time_t current_time = time(0); - struct tm * local_time = localtime(¤t_time); + struct tm* local_time = localtime(¤t_time); const int isdst = local_time->tm_isdst; - return time_zone_offset_in_secs() + isdst*3600; + return time_zone_offset_in_secs() + isdst * 3600; } /* internal function to find the time_t for the Unix epoch @@ -70,75 +69,64 @@ int current_time_zone_and_DST_offset_in_secs() in the GB/Portugal time_zone. This is of course weird. However, as long as we handle this internally consistently, it shouldn't matter. */ -static -time_t unix_epoch_time_t() -{ +static time_t +unix_epoch_time_t() { static bool first_run = true; static time_t epoch_offset; - if (first_run) - { - first_run = false; - struct tm time_info_start; // 1 JAN 1970 00:00 in local time (without DST) - time_info_start.tm_year = 1970 - 1900; - time_info_start.tm_mon = 0; - time_info_start.tm_mday = 1; - time_info_start.tm_sec = 0; - time_info_start.tm_min = 0; - time_info_start.tm_hour = 0; - time_info_start.tm_isdst = 0; - time_t loc_time_start = mktime(&time_info_start); - epoch_offset = loc_time_start + time_zone_offset_in_secs(); - if (epoch_offset != 0) - info(boost::format("Using Unix epoch (1Jan1970) offset of %1%") % epoch_offset, 3); - } + if (first_run) { + first_run = false; + struct tm time_info_start; // 1 JAN 1970 00:00 in local time (without DST) + time_info_start.tm_year = 1970 - 1900; + time_info_start.tm_mon = 0; + time_info_start.tm_mday = 1; + time_info_start.tm_sec = 0; + time_info_start.tm_min = 0; + time_info_start.tm_hour = 0; + time_info_start.tm_isdst = 0; + time_t loc_time_start = mktime(&time_info_start); + epoch_offset = loc_time_start + time_zone_offset_in_secs(); + if (epoch_offset != 0) + info(boost::format("Using Unix epoch (1Jan1970) offset of %1%") % epoch_offset, 3); + } return epoch_offset; } -std::string DICOM_date_time_to_DT(const std::string& date_org, const std::string& time_org, const std::string& TZ_org) -{ +std::string +DICOM_date_time_to_DT(const std::string& date_org, const std::string& time_org, const std::string& TZ_org) { // get rid of white spaces, just in case const std::string date = standardise_interfile_keyword(date_org); const std::string time = standardise_interfile_keyword(time_org); const std::string TZ = standardise_interfile_keyword(TZ_org); - if ((date.size()!=8) || (time.size()<6 || (time.size()>6 && time[6]!='.')) - || (!TZ.empty() && TZ.size()!=5)) + if ((date.size() != 8) || (time.size() < 6 || (time.size() > 6 && time[6] != '.')) || (!TZ.empty() && TZ.size() != 5)) error(boost::format("DICOM_date_time_to_DT: ill-formed input: date=%s, time=%s, TZ info=%s") % date % time % TZ); - return date+time+TZ; + return date + time + TZ; } static double -parse_DICOM_TZ(const std::string& tz, const bool silent) -{ +parse_DICOM_TZ(const std::string& tz, const bool silent) { double tz_offset; - if (tz.empty()) + if (tz.empty()) { { - { - tz_offset = time_zone_offset_in_secs(); - if (!silent) - warning(boost::format("No Time_Zone info in DICOM DT. Using local time-zone without DST (%+.0f secs)") % tz_offset); - } + tz_offset = time_zone_offset_in_secs(); + if (!silent) + warning(boost::format("No Time_Zone info in DICOM DT. Using local time-zone without DST (%+.0f secs)") % tz_offset); } - else - { - if (tz.size() != 5) - error("Time_Zone info '" + tz + "' does not fit DICOM standard"); - else - { - tz_offset = - (boost::lexical_cast(tz.substr(0,3))*60 + - boost::lexical_cast(tz.substr(3)))*60; - //info(boost::format("Found time zone difference in DICOM DT '%s' of %g secs") - // % str % tz_offset, 2); - } + } else { + if (tz.size() != 5) + error("Time_Zone info '" + tz + "' does not fit DICOM standard"); + else { + tz_offset = (boost::lexical_cast(tz.substr(0, 3)) * 60 + boost::lexical_cast(tz.substr(3))) * 60; + // info(boost::format("Found time zone difference in DICOM DT '%s' of %g secs") + // % str % tz_offset, 2); } + } return tz_offset; } static void -parse_DICOM_fraction_and_TZ(std::string& fraction, std::string& tz_string, const std::string& str) -{ +parse_DICOM_fraction_and_TZ(std::string& fraction, std::string& tz_string, const std::string& str) { const std::string rest = str.substr(14); std::size_t tz_pos = rest.find('+'); @@ -152,21 +140,23 @@ parse_DICOM_fraction_and_TZ(std::string& fraction, std::string& tz_string, const fraction = rest; } -double DICOM_datetime_to_secs_since_Unix_epoch(const std::string& str_org, bool silent) -{ +double +DICOM_datetime_to_secs_since_Unix_epoch(const std::string& str_org, bool silent) { // get rid of white spaces, just in case const std::string str = standardise_interfile_keyword(str_org); - if (str.size()<14) + if (str.size() < 14) error("DICOM DT '" + str + "' is ill-formed"); struct tm time_info; - time_info.tm_year = boost::lexical_cast(str.substr(0,4)) - 1900; - time_info.tm_mon = boost::lexical_cast(str.substr(4,2)) - 1; - time_info.tm_mday = boost::lexical_cast(str.substr(6,2)); - time_info.tm_hour = boost::lexical_cast(str.substr(8,2));; - time_info.tm_min = boost::lexical_cast(str.substr(10,2));; - time_info.tm_sec = boost::lexical_cast(str.substr(12,2)); + time_info.tm_year = boost::lexical_cast(str.substr(0, 4)) - 1900; + time_info.tm_mon = boost::lexical_cast(str.substr(4, 2)) - 1; + time_info.tm_mday = boost::lexical_cast(str.substr(6, 2)); + time_info.tm_hour = boost::lexical_cast(str.substr(8, 2)); + ; + time_info.tm_min = boost::lexical_cast(str.substr(10, 2)); + ; + time_info.tm_sec = boost::lexical_cast(str.substr(12, 2)); time_info.tm_isdst = 0; // no DST // find the time as if the above is specified in the local time_zone double time_diff = difftime(mktime(&time_info), unix_epoch_time_t()); @@ -182,91 +172,72 @@ double DICOM_datetime_to_secs_since_Unix_epoch(const std::string& str_org, bool time_diff -= tz_offset - time_zone_offset_in_secs(); // handle fraction of seconds - if (fraction.size()>0) - { - if (fraction[0] != '.') - error("DICOM DT '" + str + "' is ill-formed for the fractional seconds"); - try - { - const double frac_secs = boost::lexical_cast(fraction); - time_diff += frac_secs; - } - catch (...) - { - error("DICOM DT '" + str + "' is ill-formed for the fractional seconds"); - } + if (fraction.size() > 0) { + if (fraction[0] != '.') + error("DICOM DT '" + str + "' is ill-formed for the fractional seconds"); + try { + const double frac_secs = boost::lexical_cast(fraction); + time_diff += frac_secs; + } catch (...) { + error("DICOM DT '" + str + "' is ill-formed for the fractional seconds"); } + } } - info(boost::format("DICOM DT '%s' = %.2fs since unix epoch (1970)")% str % time_diff, 3); + info(boost::format("DICOM DT '%s' = %.2fs since unix epoch (1970)") % str % time_diff, 3); return time_diff; } -std::string secs_since_Unix_epoch_to_DICOM_datetime(double secs, int time_zone_offset_in_secs) -{ - const int tz_in_mins = time_zone_offset_in_secs/60; +std::string +secs_since_Unix_epoch_to_DICOM_datetime(double secs, int time_zone_offset_in_secs) { + const int tz_in_mins = time_zone_offset_in_secs / 60; // check it's in minutes (as expected, but also imposed by DICOM) { - if (round(tz_in_mins*60 - secs)>1) - error(boost::format("secs_since_Unix_epoch_to_DICOM_datetime: can only handle time_zone offsets that are a multiple of 60, argument was %d") % time_zone_offset_in_secs); + if (round(tz_in_mins * 60 - secs) > 1) + error(boost::format("secs_since_Unix_epoch_to_DICOM_datetime: can only handle time_zone offsets that are a multiple of 60, " + "argument was %d") % + time_zone_offset_in_secs); } time_t time = round(floor(secs) + unix_epoch_time_t() + time_zone_offset_in_secs); - struct tm * time_info = gmtime(&time); - return (boost::format("%04d%02d%02d%02d%02d%02d.%02d%+03d%02d") % - (time_info->tm_year + 1900)% - (time_info->tm_mon+1) % - time_info->tm_mday % - time_info->tm_hour % - time_info->tm_min % - time_info->tm_sec % - round((secs - floor(secs))*100) % - (tz_in_mins/60) % - (tz_in_mins%60)).str(); + struct tm* time_info = gmtime(&time); + return (boost::format("%04d%02d%02d%02d%02d%02d.%02d%+03d%02d") % (time_info->tm_year + 1900) % (time_info->tm_mon + 1) % + time_info->tm_mday % time_info->tm_hour % time_info->tm_min % time_info->tm_sec % round((secs - floor(secs)) * 100) % + (tz_in_mins / 60) % (tz_in_mins % 60)) + .str(); } - DateTimeStrings -DICOM_datetime_to_Interfile(const std::string& str) -{ +DICOM_datetime_to_Interfile(const std::string& str) { // just do a conversion to check on format (will throw if there's an error) DICOM_datetime_to_secs_since_Unix_epoch(str); DateTimeStrings dt; - dt.date = str.substr(0,4) + ':' + str.substr(4,2) + ':' + str.substr(6,2); - dt.time = str.substr(8,2) + ':' + str.substr(10,2) + ':' + str.substr(12); + dt.date = str.substr(0, 4) + ':' + str.substr(4, 2) + ':' + str.substr(6, 2); + dt.time = str.substr(8, 2) + ':' + str.substr(10, 2) + ':' + str.substr(12); return dt; } std::string -Interfile_datetime_to_DICOM(const DateTimeStrings& dt) -{ +Interfile_datetime_to_DICOM(const DateTimeStrings& dt) { // get rid of white spaces, just in case const std::string date = standardise_interfile_keyword(dt.date); const std::string time = standardise_interfile_keyword(dt.time); - if ((date.size()!=10) || - (date[4] != ':') || - (date[7] != ':')) + if ((date.size() != 10) || (date[4] != ':') || (date[7] != ':')) error("Interfile_datetime_to_DICOM: ill-formed date: " + date); - if ((time.size()<8) || - (time[2] != ':') || - (time[5] != ':')) + if ((time.size() < 8) || (time[2] != ':') || (time[5] != ':')) error("Interfile_datetime_to_DICOM: ill-formed time: " + time); - return - date.substr(0,4) + date.substr(5,2) + date.substr(8,2) + - time.substr(0,2) + time.substr(3,2) + time.substr(6); + return date.substr(0, 4) + date.substr(5, 2) + date.substr(8, 2) + time.substr(0, 2) + time.substr(3, 2) + time.substr(6); } -double Interfile_datetime_to_secs_since_Unix_epoch(const DateTimeStrings& intf, bool silent) -{ - return - DICOM_datetime_to_secs_since_Unix_epoch(Interfile_datetime_to_DICOM(intf), silent); +double +Interfile_datetime_to_secs_since_Unix_epoch(const DateTimeStrings& intf, bool silent) { + return DICOM_datetime_to_secs_since_Unix_epoch(Interfile_datetime_to_DICOM(intf), silent); } -DateTimeStrings secs_since_Unix_epoch_to_Interfile_datetime(double secs, int time_zone_offset_in_secs) -{ - return - DICOM_datetime_to_Interfile(secs_since_Unix_epoch_to_DICOM_datetime(secs, time_zone_offset_in_secs)); +DateTimeStrings +secs_since_Unix_epoch_to_Interfile_datetime(double secs, int time_zone_offset_in_secs) { + return DICOM_datetime_to_Interfile(secs_since_Unix_epoch_to_DICOM_datetime(secs, time_zone_offset_in_secs)); } END_NAMESPACE_STIR diff --git a/src/buildblock/error.cxx b/src/buildblock/error.cxx index e693e79702..faff01b7e3 100644 --- a/src/buildblock/error.cxx +++ b/src/buildblock/error.cxx @@ -1,8 +1,8 @@ // // /*! - \file - + \file + \brief defines the stir::error() function \author Kris Thielemans @@ -40,29 +40,27 @@ Visual Studio can be accomodated with the following work-around */ #ifdef BOOST_MSVC -#define vsnprintf _vsnprintf +# define vsnprintf _vsnprintf #endif START_NAMESPACE_STIR -void error(const char *const s, ...) -{ +void +error(const char* const s, ...) { va_list ap; va_start(ap, s); - const unsigned size=10000; + const unsigned size = 10000; char tmp[size]; - const int returned_size= vsnprintf(tmp,size, s, ap); + const int returned_size = vsnprintf(tmp, size, s, ap); std::stringstream ss; va_end(ap); - if (returned_size<0) - ss << "\nERROR: but error formatting error message" << std::endl; - else - { - ss << "\nERROR: " << tmp << std::endl; - if (static_cast(returned_size)>=size) - ss << "\nWARNING: previous error message truncated as it exceeds " - << size << "bytes" << std::endl; + if (returned_size < 0) + ss << "\nERROR: but error formatting error message" << std::endl; + else { + ss << "\nERROR: " << tmp << std::endl; + if (static_cast(returned_size) >= size) + ss << "\nWARNING: previous error message truncated as it exceeds " << size << "bytes" << std::endl; } writeText(ss.str().c_str(), ERROR_CHANNEL); std::string msg = tmp; diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index 455b993594..04b8a1be38 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -8,22 +8,22 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! -\file +\file \ingroup projdata \brief Implementation of functions to extension of direct sinograms in view direction \author Kris Thielemans \author Charalampos Tsoumpas - + */ #include "stir/Array.h" #include "stir/SegmentBySinogram.h" @@ -35,136 +35,105 @@ START_NAMESPACE_STIR -namespace detail -{ - /* This function takes symmetries in the sinogram space into account - to find data in the negative segment if necessary. - However, it needs testing if it would work for non-direct sinograms. - */ - inline static - Array<2,float> - extend_sinogram_in_views(const Array<2,float>& sino_positive_segment, - const Array<2,float>& sino_negative_segment, - const ProjDataInfo& proj_data_info, - const int min_view_extension, const int max_view_extension) - { - //* Check if projdata are from 0 to pi-phi - bool min_is_extended=false; - bool max_is_extended=false; - BasicCoordinate<2,int> min_in, max_in; - if (!sino_positive_segment.get_regular_range(min_in, max_in)) - { - warning("input segment 0 should have a regular range"); - } - - const int org_min_view_num=min_in[1]; - const int org_max_view_num=max_in[1]; - - const float min_phi = proj_data_info.get_phi(Bin(0,0,0,0)); - const float max_phi = proj_data_info.get_phi(Bin(0,max_in[1],0,0)); - - const float sampling_phi = - proj_data_info.get_phi(Bin(0,1,0,0)) - min_phi; - const int num_views_for_180 = round(_PI/sampling_phi); - - if (fabs(min_phi)< .01) - { - min_in[1]-=min_view_extension; - min_is_extended=true; - } - if (fabs(max_phi-(_PI-sampling_phi))<.01) - { - max_in[1]+=max_view_extension; - max_is_extended=true; - } - - - IndexRange<2> extended_range(min_in, max_in); - Array<2,float> input_extended_view(extended_range); - - if (!min_is_extended) - warning("Minimum view of the original projdata is not 0"); - if (!max_is_extended) - warning("Maximum view of the original projdata is not 180-sampling_phi"); - - for (int view_num=min_in[1]; view_num<=max_in[1]; ++view_num) - { - bool use_extension=false; - int symmetric_view_num=0; - if (view_numorg_max_view_num && max_is_extended==true) - { - use_extension=true; - symmetric_view_num = view_num - num_views_for_180; - } - - if (!use_extension) - input_extended_view[view_num]= - sino_positive_segment[view_num]; - else - { - const int symmetric_min = std::max(min_in[2], -max_in[2]); - const int symmetric_max = std::min(-min_in[2], max_in[2]); - for (int tang_num=symmetric_min; tang_num<=symmetric_max; ++tang_num) - input_extended_view[view_num][tang_num]= - sino_negative_segment[symmetric_view_num][-tang_num]; - // now do extrapolation where we don't have data - for (int tang_num=min_in[2]; tang_num +extend_sinogram_in_views(const Array<2, float>& sino_positive_segment, const Array<2, float>& sino_negative_segment, + const ProjDataInfo& proj_data_info, const int min_view_extension, const int max_view_extension) { + //* Check if projdata are from 0 to pi-phi + bool min_is_extended = false; + bool max_is_extended = false; + BasicCoordinate<2, int> min_in, max_in; + if (!sino_positive_segment.get_regular_range(min_in, max_in)) { + warning("input segment 0 should have a regular range"); + } + + const int org_min_view_num = min_in[1]; + const int org_max_view_num = max_in[1]; + + const float min_phi = proj_data_info.get_phi(Bin(0, 0, 0, 0)); + const float max_phi = proj_data_info.get_phi(Bin(0, max_in[1], 0, 0)); + + const float sampling_phi = proj_data_info.get_phi(Bin(0, 1, 0, 0)) - min_phi; + const int num_views_for_180 = round(_PI / sampling_phi); + + if (fabs(min_phi) < .01) { + min_in[1] -= min_view_extension; + min_is_extended = true; } + if (fabs(max_phi - (_PI - sampling_phi)) < .01) { + max_in[1] += max_view_extension; + max_is_extended = true; + } + + IndexRange<2> extended_range(min_in, max_in); + Array<2, float> input_extended_view(extended_range); + + if (!min_is_extended) + warning("Minimum view of the original projdata is not 0"); + if (!max_is_extended) + warning("Maximum view of the original projdata is not 180-sampling_phi"); + + for (int view_num = min_in[1]; view_num <= max_in[1]; ++view_num) { + bool use_extension = false; + int symmetric_view_num = 0; + if (view_num < org_min_view_num && min_is_extended == true) { + use_extension = true; + symmetric_view_num = view_num + num_views_for_180; + } else if (view_num > org_max_view_num && max_is_extended == true) { + use_extension = true; + symmetric_view_num = view_num - num_views_for_180; + } + + if (!use_extension) + input_extended_view[view_num] = sino_positive_segment[view_num]; + else { + const int symmetric_min = std::max(min_in[2], -max_in[2]); + const int symmetric_max = std::min(-min_in[2], max_in[2]); + for (int tang_num = symmetric_min; tang_num <= symmetric_max; ++tang_num) + input_extended_view[view_num][tang_num] = sino_negative_segment[symmetric_view_num][-tang_num]; + // now do extrapolation where we don't have data + for (int tang_num = min_in[2]; tang_num < symmetric_min; ++tang_num) + input_extended_view[view_num][tang_num] = input_extended_view[view_num][symmetric_min]; + for (int tang_num = symmetric_max + 1; tang_num <= max_in[2]; ++tang_num) + input_extended_view[view_num][tang_num] = input_extended_view[view_num][symmetric_max]; + } + } // loop over views + return input_extended_view; +} } // end of namespace detail -Array<3,float> -extend_segment_in_views(const SegmentBySinogram& sino, - const int min_view_extension, const int max_view_extension) -{ - if (sino.get_segment_num()!=0) +Array<3, float> +extend_segment_in_views(const SegmentBySinogram& sino, const int min_view_extension, const int max_view_extension) { + if (sino.get_segment_num() != 0) error("extend_segment with single segment works only for segment 0"); - BasicCoordinate<3,int> min, max; - - min[1]=sino.get_min_axial_pos_num(); - max[1]=sino.get_max_axial_pos_num(); - min[2]=sino.get_min_view_num(); - max[2]=sino.get_max_view_num(); - min[3]=sino.get_min_tangential_pos_num(); - max[3]=sino.get_max_tangential_pos_num(); - const IndexRange<3> out_range(min,max); - Array<3,float> out(out_range); - for (int ax_pos_num=min[1]; ax_pos_num <=max[1] ; ++ax_pos_num) - { - out[ax_pos_num] = - detail:: - extend_sinogram_in_views(sino[ax_pos_num],sino[ax_pos_num], - *(sino.get_proj_data_info_sptr()), - min_view_extension, max_view_extension); - } + BasicCoordinate<3, int> min, max; + + min[1] = sino.get_min_axial_pos_num(); + max[1] = sino.get_max_axial_pos_num(); + min[2] = sino.get_min_view_num(); + max[2] = sino.get_max_view_num(); + min[3] = sino.get_min_tangential_pos_num(); + max[3] = sino.get_max_tangential_pos_num(); + const IndexRange<3> out_range(min, max); + Array<3, float> out(out_range); + for (int ax_pos_num = min[1]; ax_pos_num <= max[1]; ++ax_pos_num) { + out[ax_pos_num] = detail::extend_sinogram_in_views(sino[ax_pos_num], sino[ax_pos_num], *(sino.get_proj_data_info_sptr()), + min_view_extension, max_view_extension); + } return out; } -Array<2,float> -extend_sinogram_in_views(const Sinogram& sino, - const int min_view_extension, const int max_view_extension) -{ - if (sino.get_segment_num()!=0) +Array<2, float> +extend_sinogram_in_views(const Sinogram& sino, const int min_view_extension, const int max_view_extension) { + if (sino.get_segment_num() != 0) error("extend_segment with single segment works only for segment 0"); - return - detail:: - extend_sinogram_in_views(sino, sino, - *(sino.get_proj_data_info_sptr()), - min_view_extension, max_view_extension); + return detail::extend_sinogram_in_views(sino, sino, *(sino.get_proj_data_info_sptr()), min_view_extension, max_view_extension); } END_NAMESPACE_STIR diff --git a/src/buildblock/find_fwhm_in_image.cxx b/src/buildblock/find_fwhm_in_image.cxx index ba1ce904a4..fa77d2af3c 100644 --- a/src/buildblock/find_fwhm_in_image.cxx +++ b/src/buildblock/find_fwhm_in_image.cxx @@ -29,7 +29,7 @@ #include "stir/round.h" #include "stir/assign_to_subregion.h" #include "stir/extract_line.h" -#include +#include #include using namespace std; @@ -39,274 +39,241 @@ START_NAMESPACE_STIR /* 2 functions that calculate the maximum point (x0,y0) of a parabola that passes through 3 points. - As input it takes the Begin and End Iterators of a sequence of numbers (e.g. vector). - The three points are the maximum (x2,y2) of this sequence and the two neighbour points - (x1,y1) and (x3,y3). + As input it takes the Begin and End Iterators of a sequence of numbers (e.g. vector). + The three points are the maximum (x2,y2) of this sequence and the two neighbour points + (x1,y1) and (x3,y3). The first function returns the maximum point value y0, the secodn returns x0 -*/ +*/ template -static float parabolic_3points_fit(const RandomAccessIterType& begin_iter, - const RandomAccessIterType& end_iter); +static float parabolic_3points_fit(const RandomAccessIterType& begin_iter, const RandomAccessIterType& end_iter); template -static float parabolic_3points_fit_x0(const RandomAccessIterType& begin_iter, - const RandomAccessIterType& end_iter) ; - +static float parabolic_3points_fit_x0(const RandomAccessIterType& begin_iter, const RandomAccessIterType& end_iter); + template -static float find_NEMA_level(const Array<1,elemT>& column, const float level) -{ - const float real_maximum_value = - parabolic_3points_fit(column.begin(),column.end()); - return find_level_width(column.begin(),column.end(),real_maximum_value/level) ; +static float +find_NEMA_level(const Array<1, elemT>& column, const float level) { + const float real_maximum_value = parabolic_3points_fit(column.begin(), column.end()); + return find_level_width(column.begin(), column.end(), real_maximum_value / level); } template -std::list > -find_fwhm_in_image(DiscretisedDensity<3,elemT> & input_image, - const unsigned int num_maxima, - const float level, - const int dimension, - const bool nema) -{ - ResolutionIndex<3,float> res_index; - std::list > list_res_index; - - const DiscretisedDensityOnCartesianGrid <3,float>* input_image_cartesian_ptr = - dynamic_cast< DiscretisedDensityOnCartesianGrid<3,float>*> (&input_image); - if (input_image_cartesian_ptr == 0) - { - error("find_fwhm_in_image currently only works with DiscretisedDensityOnCartesianGrid images"); - } - BasicCoordinate<3,int> min_index, max_index; +std::list> +find_fwhm_in_image(DiscretisedDensity<3, elemT>& input_image, const unsigned int num_maxima, const float level, + const int dimension, const bool nema) { + ResolutionIndex<3, float> res_index; + std::list> list_res_index; + + const DiscretisedDensityOnCartesianGrid<3, float>* input_image_cartesian_ptr = + dynamic_cast*>(&input_image); + if (input_image_cartesian_ptr == 0) { + error("find_fwhm_in_image currently only works with DiscretisedDensityOnCartesianGrid images"); + } + BasicCoordinate<3, int> min_index, max_index; if (!input_image.get_regular_range(min_index, max_index)) error("find_fwhm_in_image works only on regular ranges\n"); - - CartesianCoordinate3D - grid_spacing=input_image_cartesian_ptr->get_grid_spacing(); - - for (unsigned int maximum_num=0; maximum_num!=num_maxima; ++ maximum_num) - { - float current_maximum ; - BasicCoordinate<3,int> max_location ; - Coordinate3D do_direction(true,true,true); - if(dimension!=0)//Divide into [maximum_num] slices and returns a max per slice - { - const float step=float( max_index[dimension]- min_index[dimension])/float(num_maxima-1); - const int slice= round(min_index[dimension] + maximum_num*step); - max_location = maximum_location_per_slice(input_image,slice,dimension); - current_maximum = input_image[max_location]; - do_direction[dimension]=false; - } - else // Searches through out the image to find the point sources - { - max_location = indices_at_maximum(input_image); - current_maximum = input_image[max_location]; - } - res_index.voxel_location = max_location; - res_index.voxel_value = current_maximum ; - for(int i=1;i<=3;++i) - res_index.resolution[i] = grid_spacing[i]* - (do_direction[i] ? (nema?find_NEMA_level(extract_line(input_image,max_location, - i), level) : - find_NEMA_level(interpolate_line(input_image,max_location, - do_direction, - i), level)): 0); - list_res_index.push_back(res_index); - if (maximum_num+1!= num_maxima && dimension==0) - assign_to_subregion(input_image,max_location,round(res_index.resolution/grid_spacing/level*2), input_image.find_min()); + + CartesianCoordinate3D grid_spacing = input_image_cartesian_ptr->get_grid_spacing(); + + for (unsigned int maximum_num = 0; maximum_num != num_maxima; ++maximum_num) { + float current_maximum; + BasicCoordinate<3, int> max_location; + Coordinate3D do_direction(true, true, true); + if (dimension != 0) // Divide into [maximum_num] slices and returns a max per slice + { + const float step = float(max_index[dimension] - min_index[dimension]) / float(num_maxima - 1); + const int slice = round(min_index[dimension] + maximum_num * step); + max_location = maximum_location_per_slice(input_image, slice, dimension); + current_maximum = input_image[max_location]; + do_direction[dimension] = false; + } else // Searches through out the image to find the point sources + { + max_location = indices_at_maximum(input_image); + current_maximum = input_image[max_location]; } - return list_res_index ; -} + res_index.voxel_location = max_location; + res_index.voxel_value = current_maximum; + for (int i = 1; i <= 3; ++i) + res_index.resolution[i] = + grid_spacing[i] * (do_direction[i] + ? (nema ? find_NEMA_level(extract_line(input_image, max_location, i), level) + : find_NEMA_level(interpolate_line(input_image, max_location, do_direction, i), level)) + : 0); + list_res_index.push_back(res_index); + if (maximum_num + 1 != num_maxima && dimension == 0) + assign_to_subregion(input_image, max_location, round(res_index.resolution / grid_spacing / level * 2), + input_image.find_min()); + } + return list_res_index; +} -template -BasicCoordinate<3,int> -maximum_location_per_slice(const Array<3,elemT>& input_array, - const int slice, const int dimension) -{ - BasicCoordinate<3,int> min_index, max_index; +template +BasicCoordinate<3, int> +maximum_location_per_slice(const Array<3, elemT>& input_array, const int slice, const int dimension) { + BasicCoordinate<3, int> min_index, max_index; if (!input_array.get_regular_range(min_index, max_index)) error("maximum_location_per_slice works only on regular ranges\n"); - BasicCoordinate<3,int> min_slice_index=min_index, - max_slice_index=max_index; - min_slice_index[dimension] = slice ; - max_slice_index[dimension] = slice ; - const IndexRange<3> slice_range(min_slice_index,max_slice_index); - Array<3,elemT> slice_array(slice_range); - BasicCoordinate<3,int> counter; - for (counter[1]=min_slice_index[1]; counter[1]<= max_slice_index[1] ; ++counter[1]) - for (counter[2]=min_slice_index[2]; counter[2]<= max_slice_index[2] ; ++counter[2]) - for (counter[3]=min_slice_index[3]; counter[3]<= max_slice_index[3] ; ++counter[3]) - slice_array[counter] = input_array[counter]; - return indices_at_maximum(slice_array); -} - + BasicCoordinate<3, int> min_slice_index = min_index, max_slice_index = max_index; + min_slice_index[dimension] = slice; + max_slice_index[dimension] = slice; + const IndexRange<3> slice_range(min_slice_index, max_slice_index); + Array<3, elemT> slice_array(slice_range); + BasicCoordinate<3, int> counter; + for (counter[1] = min_slice_index[1]; counter[1] <= max_slice_index[1]; ++counter[1]) + for (counter[2] = min_slice_index[2]; counter[2] <= max_slice_index[2]; ++counter[2]) + for (counter[3] = min_slice_index[3]; counter[3] <= max_slice_index[3]; ++counter[3]) + slice_array[counter] = input_array[counter]; + return indices_at_maximum(slice_array); +} + template -Array<1,elemT> -interpolate_line(const Array<3,elemT>& input_array, - const BasicCoordinate<3,int>& max_location, - const BasicCoordinate<3,bool>& do_direction, - const int dimension) +Array<1, elemT> +interpolate_line(const Array<3, elemT>& input_array, const BasicCoordinate<3, int>& max_location, + const BasicCoordinate<3, bool>& do_direction, const int dimension) /* - This function interpolates a column from the given array, that includes the particular voxel and returns + This function interpolates a column from the given array, that includes the particular voxel and returns a column in Array<1,elemT> type, at the wanted dimension (z=1, y=2, x=3). //Assume same index at each direction // -*/ +*/ { - BasicCoordinate<3,int> min_index, max_index; + BasicCoordinate<3, int> min_index, max_index; if (!input_array.get_regular_range(min_index, max_index)) error("interpolate_line works only on regular ranges\n"); - Array<1,elemT> line(min_index[dimension],max_index[dimension]); + Array<1, elemT> line(min_index[dimension], max_index[dimension]); { - Array<1,elemT> line_z(min_index[1],max_index[1]), - line_y(min_index[2],max_index[2]), - line_x(min_index[3],max_index[3]), - line_000(min_index[dimension],max_index[dimension]), - line_001(min_index[dimension],max_index[dimension]), - line_010(min_index[dimension],max_index[dimension]), - line_100(min_index[dimension],max_index[dimension]), - line_011(min_index[dimension],max_index[dimension]), - line_101(min_index[dimension],max_index[dimension]), - line_110(min_index[dimension],max_index[dimension]), - line_111(min_index[dimension],max_index[dimension]); - line_z = extract_line(input_array,max_location,1); - line_y = extract_line(input_array,max_location,2); - line_x = extract_line(input_array,max_location,3); - float z0=do_direction[1] ? parabolic_3points_fit_x0(line_z.begin(),line_z.end()) : 0; - float y0=do_direction[2] ? parabolic_3points_fit_x0(line_y.begin(),line_y.end()) : 0; - float x0=do_direction[3] ? parabolic_3points_fit_x0(line_x.begin(),line_x.end()) : 0; - - BasicCoordinate<3,int> location_000,location_001,location_010,location_100, - location_011,location_101,location_110,location_111; - location_000 = max_location; - - location_001[1] = max_location[1]; - location_001[2] = max_location[2]; - location_001[3] = x0>0 ? max_location[3]+1 : (x0<0 ? max_location[3]-1 : max_location[3]) ; - - location_010[1] = max_location[1]; - location_010[2] = y0>0 ? max_location[2]+1 : (y0<0 ? max_location[2]-1 : max_location[2]) ; + Array<1, elemT> line_z(min_index[1], max_index[1]), line_y(min_index[2], max_index[2]), line_x(min_index[3], max_index[3]), + line_000(min_index[dimension], max_index[dimension]), line_001(min_index[dimension], max_index[dimension]), + line_010(min_index[dimension], max_index[dimension]), line_100(min_index[dimension], max_index[dimension]), + line_011(min_index[dimension], max_index[dimension]), line_101(min_index[dimension], max_index[dimension]), + line_110(min_index[dimension], max_index[dimension]), line_111(min_index[dimension], max_index[dimension]); + line_z = extract_line(input_array, max_location, 1); + line_y = extract_line(input_array, max_location, 2); + line_x = extract_line(input_array, max_location, 3); + float z0 = do_direction[1] ? parabolic_3points_fit_x0(line_z.begin(), line_z.end()) : 0; + float y0 = do_direction[2] ? parabolic_3points_fit_x0(line_y.begin(), line_y.end()) : 0; + float x0 = do_direction[3] ? parabolic_3points_fit_x0(line_x.begin(), line_x.end()) : 0; + + BasicCoordinate<3, int> location_000, location_001, location_010, location_100, location_011, location_101, location_110, + location_111; + location_000 = max_location; + + location_001[1] = max_location[1]; + location_001[2] = max_location[2]; + location_001[3] = x0 > 0 ? max_location[3] + 1 : (x0 < 0 ? max_location[3] - 1 : max_location[3]); + + location_010[1] = max_location[1]; + location_010[2] = y0 > 0 ? max_location[2] + 1 : (y0 < 0 ? max_location[2] - 1 : max_location[2]); location_010[3] = max_location[3]; - - location_100[1] = z0>0 ? max_location[1]+1 : (z0<0 ? max_location[1]-1 : max_location[1]) ; - location_100[2] = max_location[2]; + location_100[1] = z0 > 0 ? max_location[1] + 1 : (z0 < 0 ? max_location[1] - 1 : max_location[1]); + location_100[2] = max_location[2]; location_100[3] = max_location[3]; - - - location_011[1] = max_location[1]; - location_011[2] = y0>0 ? max_location[2]+1 : (y0<0 ? max_location[2]-1 : max_location[2]) ; - location_011[3] = x0>0 ? max_location[3]+1 : (x0<0 ? max_location[3]-1 : max_location[3]) ; - - location_101[1] = z0>0 ? max_location[1]+1 : (z0<0 ? max_location[1]-1 : max_location[1]) ; - location_101[2] = max_location[2]; - location_101[3] = x0>0 ? max_location[3]+1 : (x0<0 ? max_location[3]-1 : max_location[3]) ; - - location_110[1] = z0>0 ? max_location[1]+1 : (z0<0 ? max_location[1]-1 : max_location[1]) ; - location_110[2] = y0>0 ? max_location[2]+1 : (y0<0 ? max_location[2]-1 : max_location[2]) ; - location_110[3] = max_location[3] ; - - location_111[1] = z0>0 ? max_location[1]+1 : (z0<0 ? max_location[1]-1 : max_location[1]) ; - location_111[2] = y0>0 ? max_location[2]+1 : (y0<0 ? max_location[2]-1 : max_location[2]) ; - location_111[3] = x0>0 ? max_location[3]+1 : (x0<0 ? max_location[3]-1 : max_location[3]) ; - - line_000 = extract_line(input_array,location_000,dimension); - line_001 = extract_line(input_array,location_001,dimension); - line_010 = extract_line(input_array,location_010,dimension); - line_100 = extract_line(input_array,location_100,dimension); - line_011 = extract_line(input_array,location_011,dimension); - line_101 = extract_line(input_array,location_101,dimension); - - line_110 = extract_line(input_array,location_110,dimension); - line_111 = extract_line(input_array,location_111,dimension); - line = line_000*(1-abs(z0))*(1-abs(y0))*(1-abs(x0)) ; - line+= line_001*(1-abs(z0))*(1-abs(y0))*abs(x0) ; - line+= line_010*(1-abs(z0))*abs(y0)*(1-abs(x0)) ; - line+= line_100*abs(z0)*(1-abs(y0))*(1-abs(x0)) ; - line+= line_011*(1-abs(z0))*abs(y0)*abs(x0) ; - line+= line_101*abs(z0)*(1-abs(y0))*abs(x0) ; - line+= line_110*abs(z0)*abs(y0)*(1-abs(x0)) ; - line+= line_111*abs(z0)*abs(y0)*abs(x0) ; + + location_011[1] = max_location[1]; + location_011[2] = y0 > 0 ? max_location[2] + 1 : (y0 < 0 ? max_location[2] - 1 : max_location[2]); + location_011[3] = x0 > 0 ? max_location[3] + 1 : (x0 < 0 ? max_location[3] - 1 : max_location[3]); + + location_101[1] = z0 > 0 ? max_location[1] + 1 : (z0 < 0 ? max_location[1] - 1 : max_location[1]); + location_101[2] = max_location[2]; + location_101[3] = x0 > 0 ? max_location[3] + 1 : (x0 < 0 ? max_location[3] - 1 : max_location[3]); + + location_110[1] = z0 > 0 ? max_location[1] + 1 : (z0 < 0 ? max_location[1] - 1 : max_location[1]); + location_110[2] = y0 > 0 ? max_location[2] + 1 : (y0 < 0 ? max_location[2] - 1 : max_location[2]); + location_110[3] = max_location[3]; + + location_111[1] = z0 > 0 ? max_location[1] + 1 : (z0 < 0 ? max_location[1] - 1 : max_location[1]); + location_111[2] = y0 > 0 ? max_location[2] + 1 : (y0 < 0 ? max_location[2] - 1 : max_location[2]); + location_111[3] = x0 > 0 ? max_location[3] + 1 : (x0 < 0 ? max_location[3] - 1 : max_location[3]); + + line_000 = extract_line(input_array, location_000, dimension); + line_001 = extract_line(input_array, location_001, dimension); + line_010 = extract_line(input_array, location_010, dimension); + line_100 = extract_line(input_array, location_100, dimension); + line_011 = extract_line(input_array, location_011, dimension); + line_101 = extract_line(input_array, location_101, dimension); + + line_110 = extract_line(input_array, location_110, dimension); + line_111 = extract_line(input_array, location_111, dimension); + line = line_000 * (1 - abs(z0)) * (1 - abs(y0)) * (1 - abs(x0)); + line += line_001 * (1 - abs(z0)) * (1 - abs(y0)) * abs(x0); + line += line_010 * (1 - abs(z0)) * abs(y0) * (1 - abs(x0)); + line += line_100 * abs(z0) * (1 - abs(y0)) * (1 - abs(x0)); + line += line_011 * (1 - abs(z0)) * abs(y0) * abs(x0); + line += line_101 * abs(z0) * (1 - abs(y0)) * abs(x0); + line += line_110 * abs(z0) * abs(y0) * (1 - abs(x0)); + line += line_111 * abs(z0) * abs(y0) * abs(x0); } - return line ; -} + return line; +} template -float parabolic_3points_fit(const RandomAccessIterType& begin_iter, - const RandomAccessIterType& end_iter) -{ - float real_max_value; - const RandomAccessIterType max_iter = std::max_element(begin_iter,end_iter); - if (max_iter==end_iter-1 || max_iter==begin_iter) - return *max_iter; // In case maximum is at the borders of the image - { - const float y1 = *(max_iter-1); - const float y2 = *max_iter; - const float y3 = *(max_iter+1); +float +parabolic_3points_fit(const RandomAccessIterType& begin_iter, const RandomAccessIterType& end_iter) { + float real_max_value; + const RandomAccessIterType max_iter = std::max_element(begin_iter, end_iter); + if (max_iter == end_iter - 1 || max_iter == begin_iter) + return *max_iter; // In case maximum is at the borders of the image + { + const float y1 = *(max_iter - 1); + const float y2 = *max_iter; + const float y3 = *(max_iter + 1); const float x1 = -1.; - const float x2 = 0.; // Giving the axis zero point at x2. - const float x3 = 1.; - const float a1 = (x1-x2)*(x1-x3); - const float a2 = (x2-x1)*(x2-x3); - const float a3 = (x3-x2)*(x3-x1); - /* + const float x2 = 0.; // Giving the axis zero point at x2. + const float x3 = 1.; + const float a1 = (x1 - x2) * (x1 - x3); + const float a2 = (x2 - x1) * (x2 - x3); + const float a3 = (x3 - x2) * (x3 - x1); + /* Now find parameters for parabola that fits these 3 points. Using Langrange's classical formula, equation will be: y(x)=((x - x2)*(x - x3)*y1/a1)+ ((x - x1)*(x - x3)*y2/a2) + ((x - x1)*(x - x2)*y3/a3) - y'(x0) = 0 => x0 = 0.5*(x1*a1*(y2*a3+y3*a2)+x2*a2*(y1*a3+y3*a1)+x3*a3*(y1*a2+y2*a1))/(y1*a2*a3+y2*a1*a3+y3*a1*a2) - */ - const float x0 = 0.5F*(x1*a1*(y2*a3+y3*a2)+x2*a2*(y1*a3+y3*a1)+x3*a3*(y1*a2+y2*a1)) - /(y1*a2*a3+y2*a1*a3+y3*a1*a2) ; - real_max_value = ((x0 - x2)*(x0 - x3)*y1/a1) + - ((x0 - x1)*(x0 - x3)*y2/a2) + - ((x0 - x1)*(x0 - x2)*y3/a3) ; - - } - return real_max_value ; -} + y'(x0) = 0 => x0 = 0.5*(x1*a1*(y2*a3+y3*a2)+x2*a2*(y1*a3+y3*a1)+x3*a3*(y1*a2+y2*a1))/(y1*a2*a3+y2*a1*a3+y3*a1*a2) + */ + const float x0 = 0.5F * (x1 * a1 * (y2 * a3 + y3 * a2) + x2 * a2 * (y1 * a3 + y3 * a1) + x3 * a3 * (y1 * a2 + y2 * a1)) / + (y1 * a2 * a3 + y2 * a1 * a3 + y3 * a1 * a2); + real_max_value = ((x0 - x2) * (x0 - x3) * y1 / a1) + ((x0 - x1) * (x0 - x3) * y2 / a2) + ((x0 - x1) * (x0 - x2) * y3 / a3); + } + return real_max_value; +} template -float parabolic_3points_fit_x0(const RandomAccessIterType& begin_iter, - const RandomAccessIterType& end_iter) -{ - // float real_max_value; - const RandomAccessIterType max_iter = std::max_element(begin_iter,end_iter); - if (max_iter==end_iter-1) return 0; // In case maximum is at the borders of the image - if (max_iter==begin_iter) return 0; - //else - - const float y1 = *(max_iter-1); - const float y2 = *max_iter; - const float y3 = *(max_iter+1); +float +parabolic_3points_fit_x0(const RandomAccessIterType& begin_iter, const RandomAccessIterType& end_iter) { + // float real_max_value; + const RandomAccessIterType max_iter = std::max_element(begin_iter, end_iter); + if (max_iter == end_iter - 1) + return 0; // In case maximum is at the borders of the image + if (max_iter == begin_iter) + return 0; + // else + + const float y1 = *(max_iter - 1); + const float y2 = *max_iter; + const float y3 = *(max_iter + 1); const float x1 = -1.; - const float x2 = 0.; // Giving the axis zero point at x2. - const float x3 = 1.; - const float a1 = (x1-x2)*(x1-x3); - const float a2 = (x2-x1)*(x2-x3); - const float a3 = (x3-x2)*(x3-x1); - /* + const float x2 = 0.; // Giving the axis zero point at x2. + const float x3 = 1.; + const float a1 = (x1 - x2) * (x1 - x3); + const float a2 = (x2 - x1) * (x2 - x3); + const float a3 = (x3 - x2) * (x3 - x1); + /* Now find parameters for parabola that fits these 3 points. Using Langrange's classical formula, equation will be: y(x)=((x - x2)*(x - x3)*y1/a1)+ ((x - x1)*(x - x3)*y2/a2) + ((x - x1)*(x - x2)*y3/a3) - y'(x0) = 0 => x0 = 0.5*(x1*a1*(y2*a3+y3*a2)+x2*a2*(y1*a3+y3*a1)+x3*a3*(y1*a2+y2*a1))/(y1*a2*a3+y2*a1*a3+y3*a1*a2) - */ - const float x0 = 0.5F*(x1*a1*(y2*a3+y3*a2)+x2*a2*(y1*a3+y3*a1)+x3*a3*(y1*a2+y2*a1)) - /(y1*a2*a3+y2*a1*a3+y3*a1*a2) ; - return x0 ; -} - + y'(x0) = 0 => x0 = 0.5*(x1*a1*(y2*a3+y3*a2)+x2*a2*(y1*a3+y3*a1)+x3*a3*(y1*a2+y2*a1))/(y1*a2*a3+y2*a1*a3+y3*a1*a2) + */ + const float x0 = 0.5F * (x1 * a1 * (y2 * a3 + y3 * a2) + x2 * a2 * (y1 * a3 + y3 * a1) + x3 * a3 * (y1 * a2 + y2 * a1)) / + (y1 * a2 * a3 + y2 * a1 * a3 + y3 * a1 * a2); + return x0; +} /*************************************************** instantiations ***************************************************/ -template -std::list > -find_fwhm_in_image<>(DiscretisedDensity<3,float> & input_image, - const unsigned int num_maxima, - const float level, - const int dimension, - const bool nema); - - +template std::list> find_fwhm_in_image<>(DiscretisedDensity<3, float>& input_image, + const unsigned int num_maxima, const float level, + const int dimension, const bool nema); + END_NAMESPACE_STIR diff --git a/src/buildblock/getopt.c b/src/buildblock/getopt.c index fff1f5164c..6b5bd344e7 100644 --- a/src/buildblock/getopt.c +++ b/src/buildblock/getopt.c @@ -25,21 +25,19 @@ Ditto for AIX 3.2 and . */ #ifndef HAVE_SYSTEM_GETOPT +# ifndef _NO_PROTO +# define _NO_PROTO +# endif -#ifndef _NO_PROTO -# define _NO_PROTO -#endif - - -#if !defined __STDC__ || !__STDC__ +# if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ -# ifndef const -# define const -# endif -#endif +# ifndef const +# define const +# endif +# endif -#include +# include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C @@ -49,47 +47,46 @@ program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ -#define GETOPT_INTERFACE_VERSION 2 -#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 -# include -# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -# define ELIDE_CODE -# endif -#endif - -#ifndef ELIDE_CODE +# define GETOPT_INTERFACE_VERSION 2 +# if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +# endif +# ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ +# ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ -# include -# include -#endif /* GNU C library. */ - -#ifdef VMS -# include -# if HAVE_STRING_H - 0 -# include -# endif -#endif - -#ifndef _ +# include +# include +# endif /* GNU C library. */ + +# ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +# endif + +# ifndef _ /* This is for other GNU distributions with internationalized messages. */ -# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC -# include -# ifndef _ -# define _(msgid) gettext (msgid) -# endif -# else -# define _(msgid) (msgid) -# endif -# if defined _LIBC && defined USE_IN_LIBIO -# include -# endif -#endif +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# ifndef _ +# define _(msgid) gettext(msgid) +# endif +# else +# define _(msgid) (msgid) +# endif +# if defined _LIBC && defined USE_IN_LIBIO +# include +# endif +# endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user @@ -105,7 +102,7 @@ GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ -#include "stir/getopt.h" +# include "stir/getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, @@ -113,7 +110,7 @@ Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ -char *optarg; +char* optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller @@ -143,7 +140,7 @@ int __getopt_initialized; If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ -static char *nextchar; +static char* nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ @@ -185,63 +182,57 @@ int optopt = '?'; of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; +static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; +static char* posixly_correct; -#ifdef __GNU_LIBRARY__ +# ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ -# include -# define my_index strchr -#else +# include +# define my_index strchr +# else -# if HAVE_STRING_H || WIN32 /* Pete Wilson mod 7/28/02 */ -# include -# else -# include -# endif +# if HAVE_STRING_H || WIN32 /* Pete Wilson mod 7/28/02 */ +# include +# else +# include +# endif /* Avoid depending on library functions or files whose names are inconsistent. */ -#ifndef getenv -extern char *getenv (); -#endif +# ifndef getenv +extern char* getenv(); +# endif -static char * -my_index (str, chr) - const char *str; - int chr; +static char* my_index(str, chr) const char* str; +int chr; { - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } + while (*str) { + if (*str == chr) + return (char*)str; + str++; + } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ -#ifdef __GNUC__ +# ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ -# if (!defined __STDC__ || !__STDC__) && !defined strlen +# if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); -# endif /* not __STDC__ */ -#endif /* __GNUC__ */ +extern int strlen(const char*); +# endif /* not __STDC__ */ +# endif /* __GNUC__ */ -#endif /* not __GNU_LIBRARY__ */ +# endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ @@ -252,38 +243,37 @@ extern int strlen (const char *); static int first_nonopt; static int last_nonopt; -#ifdef _LIBC +# ifdef _LIBC /* Stored original parameters. XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ extern int __libc_argc; -extern char **__libc_argv; +extern char** __libc_argv; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ -# ifdef USE_NONOPTION_FLAGS +# ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ -extern char *__getopt_nonoption_flags; +extern char* __getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; -# endif - -# ifdef USE_NONOPTION_FLAGS -# define SWAP_FLAGS(ch1, ch2) \ - if (nonoption_flags_len > 0) \ - { \ - char __tmp = __getopt_nonoption_flags[ch1]; \ - __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ - __getopt_nonoption_flags[ch2] = __tmp; \ - } -# else -# define SWAP_FLAGS(ch1, ch2) -# endif -#else /* !_LIBC */ -# define SWAP_FLAGS(ch1, ch2) -#endif /* _LIBC */ +# endif + +# ifdef USE_NONOPTION_FLAGS +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +# else +# define SWAP_FLAGS(ch1, ch2) +# endif +# else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +# endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) @@ -294,83 +284,71 @@ static int nonoption_flags_len; `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ -#if defined __STDC__ && __STDC__ -static void exchange (char **); -#endif +# if defined __STDC__ && __STDC__ +static void exchange(char**); +# endif -static void -exchange (argv) - char **argv; +static void exchange(argv) char** argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; - char *tem; + char* tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ -#if defined _LIBC && defined USE_NONOPTION_FLAGS +# if defined _LIBC && defined USE_NONOPTION_FLAGS /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ - if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) - { - /* We must extend the array. The user plays games with us and - presents new arguments. */ - char *new_str = malloc (top + 1); - if (new_str == NULL) - nonoption_flags_len = nonoption_flags_max_len = 0; - else - { - memset (__mempcpy (new_str, __getopt_nonoption_flags, - nonoption_flags_max_len), - '\0', top + 1 - nonoption_flags_max_len); - nonoption_flags_max_len = top + 1; - __getopt_nonoption_flags = new_str; - } + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char* new_str = malloc(top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else { + memset(__mempcpy(new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; } -#endif - - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - SWAP_FLAGS (bottom + i, middle + i); - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } + } +# endif + + while (top > middle && middle > bottom) { + if (top - middle > middle - bottom) { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS(bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } else { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS(bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; } + } /* Update records for the slots the non-options now occupy. */ @@ -380,14 +358,12 @@ exchange (argv) /* Initialize the internal data when the first call is made. */ -#if defined __STDC__ && __STDC__ -static const char *_getopt_initialize (int, char *const *, const char *); -#endif -static const char * -_getopt_initialize (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; +# if defined __STDC__ && __STDC__ +static const char* _getopt_initialize(int, char* const*, const char*); +# endif +static const char* _getopt_initialize(argc, argv, optstring) int argc; +char* const* argv; +const char* optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped @@ -397,54 +373,42 @@ _getopt_initialize (argc, argv, optstring) nextchar = NULL; - posixly_correct = getenv ("POSIXLY_CORRECT"); + posixly_correct = getenv("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) + if (optstring[0] == '-') { + ordering = RETURN_IN_ORDER; + ++optstring; + } else if (optstring[0] == '+') { + ordering = REQUIRE_ORDER; + ++optstring; + } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; -#if defined _LIBC && defined USE_NONOPTION_FLAGS - if (posixly_correct == NULL - && argc == __libc_argc && argv == __libc_argv) - { - if (nonoption_flags_max_len == 0) - { - if (__getopt_nonoption_flags == NULL - || __getopt_nonoption_flags[0] == '\0') - nonoption_flags_max_len = -1; - else - { - const char *orig_str = __getopt_nonoption_flags; - int len = nonoption_flags_max_len = strlen (orig_str); - if (nonoption_flags_max_len < argc) - nonoption_flags_max_len = argc; - __getopt_nonoption_flags = - (char *) malloc (nonoption_flags_max_len); - if (__getopt_nonoption_flags == NULL) - nonoption_flags_max_len = -1; - else - memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), - '\0', nonoption_flags_max_len - len); - } - } - nonoption_flags_len = nonoption_flags_max_len; +# if defined _LIBC && defined USE_NONOPTION_FLAGS + if (posixly_correct == NULL && argc == __libc_argc && argv == __libc_argv) { + if (nonoption_flags_max_len == 0) { + if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else { + const char* orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen(orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = (char*)malloc(nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset(__mempcpy(__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); + } } - else + nonoption_flags_len = nonoption_flags_max_len; + } else nonoption_flags_len = 0; -#endif +# endif return optstring; } @@ -505,14 +469,12 @@ _getopt_initialize (argc, argv, optstring) If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ -int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; +int _getopt_internal(argc, argv, optstring, longopts, longind, long_only) int argc; +char* const* argv; +const char* optstring; +const struct option* longopts; +int* longind; +int long_only; { int print_errors = opterr; if (optstring[0] == ':') @@ -523,102 +485,95 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) optarg = NULL; - if (optind == 0 || !__getopt_initialized) - { - if (optind == 0) - optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = _getopt_initialize (argc, argv, optstring); - __getopt_initialized = 1; - } + if (optind == 0 || !__getopt_initialized) { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize(argc, argv, optstring); + __getopt_initialized = 1; + } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ -#if defined _LIBC && defined USE_NONOPTION_FLAGS -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ - || (optind < nonoption_flags_len \ - && __getopt_nonoption_flags[optind] == '1')) -#else -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') -#endif - - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ - - /* Give FIRST_NONOPT and LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > optind) - last_nonopt = optind; - if (first_nonopt > optind) +# if defined _LIBC && defined USE_NONOPTION_FLAGS +# define NONOPTION_P \ + (argv[optind][0] != '-' || argv[optind][1] == '\0' || \ + (optind < nonoption_flags_len && __getopt_nonoption_flags[optind] == '1')) +# else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +# endif + + if (nextchar == NULL || *nextchar == '\0') { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT and LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange((char**)argv); + else if (last_nonopt != optind) first_nonopt = optind; - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc && NONOPTION_P) - optind++; - last_nonopt = optind; - } + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; + if (optind != argc && !strcmp(argv[optind], "--")) { + optind++; - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange((char**)argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; - optind = argc; - } + optind = argc; + } - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return -1; - } + if (optind == argc) { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ - if (NONOPTION_P) - { - if (ordering == REQUIRE_ORDER) - return -1; - optarg = argv[optind++]; - return 1; - } + if (NONOPTION_P) { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } + nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); + } /* Decode the current option-ARGV-element. */ @@ -635,626 +590,520 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) This distinction seems to be the most useful approach. */ - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else if (long_only - || pfound->has_arg != p->has_arg - || pfound->flag != p->flag - || pfound->val != p->val) - /* Second or later nonexact match found. */ - ambig = 1; - } + if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1]))))) { + char* nameend; + const struct option* p; + const struct option* pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, nextchar, nameend - nextchar)) { + if ((unsigned int)(nameend - nextchar) == (unsigned int)strlen(p->name)) { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if (pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } - if (ambig && !exact) - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; + if (ambig && !exact) { + if (print_errors) { +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; - __asprintf (&buf, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); + __asprintf(&buf, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); - free (buf); -#else - fprintf (stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); -#endif - } - nextchar += strlen (nextchar); - optind++; - optopt = 0; - return '?'; - } + free(buf); +# else + fprintf(stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); +# endif + } + nextchar += strlen(nextchar); + optind++; + optopt = 0; + return '?'; + } - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; -#endif - - if (argv[optind - 1][1] == '-') - { - /* --option */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("\ + if (pfound != NULL) { + option_index = indfound; + optind++; + if (*nameend) { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else { + if (print_errors) { +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; +# endif + + if (argv[optind - 1][1] == '-') { + /* --option */ +# if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("\ %s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); -#else - fprintf (stderr, _("\ + argv[0], pfound->name); +# else + fprintf(stderr, _("\ %s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); -#endif - } - else - { - /* +option or -option */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("\ + argv[0], pfound->name); +# endif + } else { + /* +option or -option */ +# if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("\ %s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], - pfound->name); -#else - fprintf (stderr, _("\ + argv[0], argv[optind - 1][0], pfound->name); +# else + fprintf(stderr, _("\ %s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], pfound->name); -#endif - } + argv[0], argv[optind - 1][0], pfound->name); +# endif + } -#if defined _LIBC && defined USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); +# if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); - free (buf); -#endif - } + free(buf); +# endif + } - nextchar += strlen (nextchar); + nextchar += strlen(nextchar); - optopt = pfound->val; - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); -#endif - } - nextchar += strlen (nextchar); - optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; + optopt = pfound->val; + return '?'; } + } else if (pfound->has_arg == 1) { + if (optind < argc) + optarg = argv[optind++]; + else { + if (print_errors) { +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; -#endif - - if (argv[optind][1] == '-') - { - /* --option */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); -#else - fprintf (stderr, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); -#endif - } - else - { - /* +option or -option */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); -#else - fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); -#endif - } - -#if defined _LIBC && defined USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __asprintf(&buf, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); - free (buf); -#endif - } - nextchar = (char *) ""; - optind++; - optopt = 0; - return '?'; + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +# else + fprintf(stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); +# endif + } + nextchar += strlen(nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; } + } + nextchar += strlen(nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; } + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' || my_index(optstring, *nextchar) == NULL) { + if (print_errors) { +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; +# endif + + if (argv[optind][1] == '-') { + /* --option */ +# if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); +# else + fprintf(stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); +# endif + } else { + /* +option or -option */ +# if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); +# else + fprintf(stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); +# endif + } + +# if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +# endif + } + nextchar = (char*)""; + optind++; + optopt = 0; + return '?'; + } + } + /* Look at and handle the next short option-character. */ { char c = *nextchar++; - char *temp = my_index (optstring, c); + char* temp = my_index(optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; - if (temp == NULL || c == ':') - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; -#endif - - if (posixly_correct) - { - /* 1003.2 specifies the format of this message. */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("%s: illegal option -- %c\n"), - argv[0], c); -#else - fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); -#endif - } - else - { -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("%s: invalid option -- %c\n"), - argv[0], c); -#else - fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); -#endif - } - -#if defined _LIBC && defined USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + if (temp == NULL || c == ':') { + if (print_errors) { +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; +# endif + + if (posixly_correct) { + /* 1003.2 specifies the format of this message. */ +# if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: illegal option -- %c\n"), argv[0], c); +# else + fprintf(stderr, _("%s: illegal option -- %c\n"), argv[0], c); +# endif + } else { +# if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: invalid option -- %c\n"), argv[0], c); +# else + fprintf(stderr, _("%s: invalid option -- %c\n"), argv[0], c); +# endif + } - free (buf); -#endif - } - optopt = c; - return '?'; +# if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +# endif } + optopt = c; + return '?'; + } /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; + if (temp[0] == 'W' && temp[1] == ';') { + char* nameend; + const struct option* p; + const struct option* pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (print_errors) - { - /* 1003.2 specifies the format of this message. */ -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, _("%s: option requires an argument -- %c\n"), - argv[0], c); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); -#endif - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } + /* This is an option that requires an argument. */ + if (*nextchar != '\0') { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } else if (optind == argc) { + if (print_errors) { + /* 1003.2 specifies the format of this message. */ +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; + + __asprintf(&buf, _("%s: option requires an argument -- %c\n"), argv[0], c); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +# else + fprintf(stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); +# endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; + c = '?'; + return c; + } else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, nextchar, nameend - nextchar)) { + if ((unsigned int)(nameend - nextchar) == strlen(p->name)) { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if (pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) { + if (print_errors) { +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; + + __asprintf(&buf, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +# else + fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); +# endif + } + nextchar += strlen(nextchar); + optind++; + return '?'; + } + if (pfound != NULL) { + option_index = indfound; + if (*nameend) { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else { + if (print_errors) { +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; + + __asprintf(&buf, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); - /* optarg is now the argument, see if it's in the - table of longopts. */ - - for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); else - /* Second or later nonexact match found. */ - ambig = 1; + fputs(buf, stderr); + + free(buf); +# else + fprintf(stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); +# endif } - if (ambig && !exact) - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); -#endif - } - nextchar += strlen (nextchar); - optind++; + + nextchar += strlen(nextchar); return '?'; } - if (pfound != NULL) - { - option_index = indfound; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); + } else if (pfound->has_arg == 1) { + if (optind < argc) + optarg = argv[optind++]; + else { + if (print_errors) { +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; + + __asprintf(&buf, _("\ +%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); - free (buf); -#else - fprintf (stderr, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); -#endif - } - - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, _("\ -%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); -#endif - } - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; + free(buf); +# else + fprintf(stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); +# endif + } + nextchar += strlen(nextchar); + return optstring[0] == ':' ? ':' : '?'; } - nextchar = NULL; - return 'W'; /* Let the application handle it. */ + } + nextchar += strlen(nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (print_errors) - { - /* 1003.2 specifies the format of this message. */ -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, - _("%s: option requires an argument -- %c\n"), - argv[0], c); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, - _("%s: option requires an argument -- %c\n"), - argv[0], c); -#endif - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') { + if (temp[2] == ':') { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') { + optarg = nextchar; + optind++; + } else + optarg = NULL; + nextchar = NULL; + } else { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } else if (optind == argc) { + if (print_errors) { + /* 1003.2 specifies the format of this message. */ +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; + + __asprintf(&buf, _("%s: option requires an argument -- %c\n"), argv[0], c); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; + fputs(buf, stderr); + + free(buf); +# else + fprintf(stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); +# endif } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; } + } return c; } } -int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -#endif /* Not ELIDE_CODE. */ +int getopt(argc, argv, optstring) int argc; +char* const* argv; +const char* optstring; +{ return _getopt_internal(argc, argv, optstring, (const struct option*)0, (int*)0, 0); } +# endif /* Not ELIDE_CODE. */ /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ -/* #define TEST */ /* Pete Wilson mod 7/28/02 */ -#ifdef TEST +/* #define TEST */ /* Pete Wilson mod 7/28/02 */ +# ifdef TEST -#ifndef exit /* Pete Wilson mod 7/28/02 */ - int exit(int); /* Pete Wilson mod 7/28/02 */ -#endif /* Pete Wilson mod 7/28/02 */ +# ifndef exit /* Pete Wilson mod 7/28/02 */ +int exit(int); /* Pete Wilson mod 7/28/02 */ +# endif /* Pete Wilson mod 7/28/02 */ -int -main (argc, argv) - int argc; - char **argv; +int main(argc, argv) int argc; +char** argv; { int c; int digit_optind = 0; - while (1) - { - int this_option_optind = optind ? optind : 1; - - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == -1) - break; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } + while (1) { + int this_option_optind = optind ? optind : 1; + + c = getopt(argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf("option %c\n", c); + break; + + case 'a': + printf("option a\n"); + break; + + case 'b': + printf("option b\n"); + break; + + case 'c': + printf("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf("?? getopt returned character code 0%o ??\n", c); } + } - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } + if (optind < argc) { + printf("non-option ARGV-elements: "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\n"); + } - exit (0); + exit(0); } -#endif /* TEST */ +# endif /* TEST */ #endif /* HAVE_SYSTEM_GETOPT */ diff --git a/src/buildblock/interfile_keyword_functions.cxx b/src/buildblock/interfile_keyword_functions.cxx index 0bd6d48354..e74cc3ac1e 100644 --- a/src/buildblock/interfile_keyword_functions.cxx +++ b/src/buildblock/interfile_keyword_functions.cxx @@ -32,38 +32,32 @@ using namespace std; START_NAMESPACE_STIR -string -standardise_interfile_keyword(const string& keyword) -{ - string::size_type cp =0; //current index - char const * const white_space = " \t_!"; - +string +standardise_interfile_keyword(const string& keyword) { + string::size_type cp = 0; // current index + char const* const white_space = " \t_!"; + // skip white space - cp=keyword.find_first_not_of(white_space,0); - - if(cp==string::npos) + cp = keyword.find_first_not_of(white_space, 0); + + if (cp == string::npos) return string(); - + // remove trailing white spaces - const string::size_type eok=keyword.find_last_not_of(white_space); - + const string::size_type eok = keyword.find_last_not_of(white_space); + string kw; - kw.reserve(eok-cp+1); + kw.reserve(eok - cp + 1); bool previous_was_white_space = false; - while (cp <= eok) - { - if (isspace(static_cast(keyword[cp])) || keyword[cp]=='_' || keyword[cp]=='!') - { - if (!previous_was_white_space) - { - kw.append(1,' '); + while (cp <= eok) { + if (isspace(static_cast(keyword[cp])) || keyword[cp] == '_' || keyword[cp] == '!') { + if (!previous_was_white_space) { + kw.append(1, ' '); previous_was_white_space = true; } // else: skip this white space character - } - else - { - kw.append(1,static_cast(tolower(static_cast(keyword[cp])))); + } else { + kw.append(1, static_cast(tolower(static_cast(keyword[cp])))); previous_was_white_space = false; } ++cp; @@ -71,5 +65,4 @@ standardise_interfile_keyword(const string& keyword) return kw; } - END_NAMESPACE_STIR diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 34508e057e..1ab7966934 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -9,12 +9,12 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! @@ -24,7 +24,7 @@ \author Charalampos Tsoumpas \author Kris Thielemans - + */ #include "stir/ProjData.h" //#include "stir/display.h" @@ -44,87 +44,69 @@ START_NAMESPACE_STIR -namespace detail_interpolate_projdata -{ - /* Collection of functions to remove interleaving in non-arccorrected data. +namespace detail_interpolate_projdata { +/* Collection of functions to remove interleaving in non-arccorrected data. - It does this by doubling the number of views, and filling in the new - tangential positions by averaging the 4 neighbouring bins. +It does this by doubling the number of views, and filling in the new +tangential positions by averaging the 4 neighbouring bins. - WARNING: most of STIR will get confused by the resulting sinograms, - so only use them here for the interpolate_projdata implementation. - */ - - static shared_ptr - make_non_interleaved_proj_data_info(const ProjDataInfo& proj_data_info) - { +WARNING: most of STIR will get confused by the resulting sinograms, +so only use them here for the interpolate_projdata implementation. +*/ - if (dynamic_cast(&proj_data_info) == NULL) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); +static shared_ptr +make_non_interleaved_proj_data_info(const ProjDataInfo& proj_data_info) { - shared_ptr new_proj_data_info_sptr( - proj_data_info.clone()); - new_proj_data_info_sptr-> - set_num_views(proj_data_info.get_num_views()*2); - return new_proj_data_info_sptr; - } + if (dynamic_cast(&proj_data_info) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - // access Sinogram element with wrap-around and boundary conditions - static float sino_element(const Sinogram& sinogram, const int view_num, const int tangential_pos_num) - { - assert(sinogram.get_min_view_num() == 0); - const int num_views = sinogram.get_num_views(); - const int tang_pos_num = (view_num>=num_views? -1: 1)*tangential_pos_num; - if (tang_pos_num < sinogram.get_min_tangential_pos_num() || - tang_pos_num > sinogram.get_max_tangential_pos_num()) - return 0.F; - else - return sinogram[view_num%num_views][tang_pos_num]; - } + shared_ptr new_proj_data_info_sptr(proj_data_info.clone()); + new_proj_data_info_sptr->set_num_views(proj_data_info.get_num_views() * 2); + return new_proj_data_info_sptr; +} - static void - make_non_interleaved_sinogram(Sinogram& out_sinogram, - const Sinogram& in_sinogram) - { - if (is_null_ptr(dynamic_pointer_cast(in_sinogram.get_proj_data_info_sptr()))) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - assert(out_sinogram.get_min_view_num() == 0); - assert(in_sinogram.get_min_view_num() == 0); - assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()*2); - assert(in_sinogram.get_segment_num() == 0); - assert(out_sinogram.get_segment_num() == 0); - - for (int view_num = out_sinogram.get_min_view_num(); - view_num <= out_sinogram.get_max_view_num(); - ++view_num) - { - for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; - tangential_pos_num <= out_sinogram.get_max_tangential_pos_num()-1; - ++tangential_pos_num) - { - if ((view_num+tangential_pos_num)%2 == 0) - { - const int in_view_num = - view_num%2==0 ? view_num/2 : (view_num+1)/2; - out_sinogram[view_num][tangential_pos_num] = - sino_element(in_sinogram, in_view_num, tangential_pos_num); - } - else - { - const int next_in_view = view_num/2+1; - const int other_in_view = (view_num+1)/2; - - out_sinogram[view_num][tangential_pos_num] = - (sino_element(in_sinogram, view_num/2, tangential_pos_num) + - sino_element(in_sinogram, next_in_view, tangential_pos_num) + - sino_element(in_sinogram, other_in_view, tangential_pos_num-1) + - sino_element(in_sinogram, other_in_view, tangential_pos_num+1) - )/4; - } - } +// access Sinogram element with wrap-around and boundary conditions +static float +sino_element(const Sinogram& sinogram, const int view_num, const int tangential_pos_num) { + assert(sinogram.get_min_view_num() == 0); + const int num_views = sinogram.get_num_views(); + const int tang_pos_num = (view_num >= num_views ? -1 : 1) * tangential_pos_num; + if (tang_pos_num < sinogram.get_min_tangential_pos_num() || tang_pos_num > sinogram.get_max_tangential_pos_num()) + return 0.F; + else + return sinogram[view_num % num_views][tang_pos_num]; +} + +static void +make_non_interleaved_sinogram(Sinogram& out_sinogram, const Sinogram& in_sinogram) { + if (is_null_ptr(dynamic_pointer_cast(in_sinogram.get_proj_data_info_sptr()))) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + assert(out_sinogram.get_min_view_num() == 0); + assert(in_sinogram.get_min_view_num() == 0); + assert(out_sinogram.get_num_views() == in_sinogram.get_num_views() * 2); + assert(in_sinogram.get_segment_num() == 0); + assert(out_sinogram.get_segment_num() == 0); + + for (int view_num = out_sinogram.get_min_view_num(); view_num <= out_sinogram.get_max_view_num(); ++view_num) { + for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num() + 1; + tangential_pos_num <= out_sinogram.get_max_tangential_pos_num() - 1; ++tangential_pos_num) { + if ((view_num + tangential_pos_num) % 2 == 0) { + const int in_view_num = view_num % 2 == 0 ? view_num / 2 : (view_num + 1) / 2; + out_sinogram[view_num][tangential_pos_num] = sino_element(in_sinogram, in_view_num, tangential_pos_num); + } else { + const int next_in_view = view_num / 2 + 1; + const int other_in_view = (view_num + 1) / 2; + + out_sinogram[view_num][tangential_pos_num] = (sino_element(in_sinogram, view_num / 2, tangential_pos_num) + + sino_element(in_sinogram, next_in_view, tangential_pos_num) + + sino_element(in_sinogram, other_in_view, tangential_pos_num - 1) + + sino_element(in_sinogram, other_in_view, tangential_pos_num + 1)) / + 4; } + } } +} #if 0 // not needed for now @@ -138,179 +120,134 @@ namespace detail_interpolate_projdata make_non_interleaved_sinogram(out_sinogram, in_sinogram); return out_sinogram; - } + } #endif - static void - make_non_interleaved_segment(SegmentBySinogram& out_segment, - const SegmentBySinogram& in_segment) - { - if (is_null_ptr(dynamic_pointer_cast(in_segment.get_proj_data_info_sptr()))) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - for (int axial_pos_num = out_segment.get_min_axial_pos_num(); - axial_pos_num <= out_segment.get_max_axial_pos_num(); - ++axial_pos_num) - { - Sinogram out_sinogram = out_segment.get_sinogram(axial_pos_num); - make_non_interleaved_sinogram(out_sinogram, - in_segment.get_sinogram(axial_pos_num)); - out_segment.set_sinogram(out_sinogram); - } +static void +make_non_interleaved_segment(SegmentBySinogram& out_segment, const SegmentBySinogram& in_segment) { + if (is_null_ptr(dynamic_pointer_cast(in_segment.get_proj_data_info_sptr()))) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + for (int axial_pos_num = out_segment.get_min_axial_pos_num(); axial_pos_num <= out_segment.get_max_axial_pos_num(); + ++axial_pos_num) { + Sinogram out_sinogram = out_segment.get_sinogram(axial_pos_num); + make_non_interleaved_sinogram(out_sinogram, in_segment.get_sinogram(axial_pos_num)); + out_segment.set_sinogram(out_sinogram); } +} - static SegmentBySinogram - make_non_interleaved_segment(const ProjDataInfo& non_interleaved_proj_data_info, - const SegmentBySinogram& in_segment) - { - SegmentBySinogram out_segment = - non_interleaved_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num()); +static SegmentBySinogram +make_non_interleaved_segment(const ProjDataInfo& non_interleaved_proj_data_info, const SegmentBySinogram& in_segment) { + SegmentBySinogram out_segment = + non_interleaved_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num(), in_segment.get_timing_pos_num()); - make_non_interleaved_segment(out_segment, in_segment); - return out_segment; - } + make_non_interleaved_segment(out_segment, in_segment); + return out_segment; +} } // end namespace detail_interpolate_projdata - using namespace detail_interpolate_projdata; - -Succeeded -interpolate_projdata(ProjData& proj_data_out, - const ProjData& proj_data_in, const BSpline::BSplineType these_types, - const bool remove_interleaving, - const bool use_view_offset) -{ - BasicCoordinate<3, BSpline::BSplineType> these_types_3; - these_types_3[1]=these_types_3[2]=these_types_3[3]=these_types; - interpolate_projdata(proj_data_out,proj_data_in,these_types_3, remove_interleaving, use_view_offset); + +Succeeded +interpolate_projdata(ProjData& proj_data_out, const ProjData& proj_data_in, const BSpline::BSplineType these_types, + const bool remove_interleaving, const bool use_view_offset) { + BasicCoordinate<3, BSpline::BSplineType> these_types_3; + these_types_3[1] = these_types_3[2] = these_types_3[3] = these_types; + interpolate_projdata(proj_data_out, proj_data_in, these_types_3, remove_interleaving, use_view_offset); return Succeeded::yes; } -Succeeded -interpolate_projdata(ProjData& proj_data_out, - const ProjData& proj_data_in, - const BasicCoordinate<3, BSpline::BSplineType> & these_types, - const bool remove_interleaving, - const bool use_view_offset) -{ +Succeeded +interpolate_projdata(ProjData& proj_data_out, const ProjData& proj_data_in, + const BasicCoordinate<3, BSpline::BSplineType>& these_types, const bool remove_interleaving, + const bool use_view_offset) { if (use_view_offset) warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); - const ProjDataInfo & proj_data_in_info = - *proj_data_in.get_proj_data_info_sptr(); - const ProjDataInfo & proj_data_out_info = - *proj_data_out.get_proj_data_info_sptr(); + const ProjDataInfo& proj_data_in_info = *proj_data_in.get_proj_data_info_sptr(); + const ProjDataInfo& proj_data_out_info = *proj_data_out.get_proj_data_info_sptr(); - if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) - { - error("interpolate_projdata needs both projection data to be of the same type\n" - "(e.g. both arc-corrected or both not arc-corrected)"); - } + if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) { + error("interpolate_projdata needs both projection data to be of the same type\n" + "(e.g. both arc-corrected or both not arc-corrected)"); + } // check for the same ring radius // This is strictly speaking only necessary for non-arccorrected data, but // we leave it in for all cases. if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - - proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) - { - error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); - } - - + proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) { + error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); + } BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); - BasicCoordinate<3, double> offset, step ; - + BasicCoordinate<3, double> offset, step; + // find relation between out_index and in_index such that they correspond to the same physical position // out_index * m_zoom + m_offset = in_index - const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); - const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); + const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0, 0, 0, 0)); + const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0, 0, 0, 0)); // offset in 'in' index units - offset[1] = - (proj_data_in_info.get_m(Bin(0,0,0,0)) - - proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; - step[1]= - out_sampling_m/in_sampling_m; - - const float in_sampling_phi = - (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / - (remove_interleaving ? 2 : 1); - - const float out_sampling_phi = - proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); - - const float out_view_offset = - use_view_offset - ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - const float in_view_offset = - use_view_offset - ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - offset[2] = - (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; - step[2] = - out_sampling_phi/in_sampling_phi; - - const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); - const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); - offset[3] = - (proj_data_out_info.get_s(Bin(0,0,0,0)) - - proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; - step[3]= - out_sampling_s/in_sampling_s; - + offset[1] = (proj_data_in_info.get_m(Bin(0, 0, 0, 0)) - proj_data_out_info.get_m(Bin(0, 0, 0, 0))) / in_sampling_m; + step[1] = out_sampling_m / in_sampling_m; + + const float in_sampling_phi = + (proj_data_in_info.get_phi(Bin(0, 1, 0, 0)) - proj_data_in_info.get_phi(Bin(0, 0, 0, 0))) / (remove_interleaving ? 2 : 1); + + const float out_sampling_phi = proj_data_out_info.get_phi(Bin(0, 1, 0, 0)) - proj_data_out_info.get_phi(Bin(0, 0, 0, 0)); + + const float out_view_offset = use_view_offset ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() : 0.F; + const float in_view_offset = use_view_offset ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() : 0.F; + offset[2] = (proj_data_in_info.get_phi(Bin(0, 0, 0, 0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0, 0, 0, 0)) - + out_view_offset) / + in_sampling_phi; + step[2] = out_sampling_phi / in_sampling_phi; + + const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0, 0, 0, 0)); + const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0, 0, 0, 0)); + offset[3] = (proj_data_out_info.get_s(Bin(0, 0, 0, 0)) - proj_data_in_info.get_s(Bin(0, 0, 0, 0))) / in_sampling_s; + step[3] = out_sampling_s / in_sampling_s; + // initialise interpolator - if (remove_interleaving) - { - shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_in_info); + if (remove_interleaving) { + shared_ptr non_interleaved_proj_data_info_sptr = make_non_interleaved_proj_data_info(proj_data_in_info); const SegmentBySinogram non_interleaved_segment = - make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_in.get_segment_by_sinogram(0)); + make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_in.get_segment_by_sinogram(0)); // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); - Array<3,float> extended = - extend_segment_in_views(non_interleaved_segment, 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } + Array<3, float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); + for (int z = extended.get_min_index(); z <= extended.get_max_index(); ++z) { + for (int y = extended[z].get_min_index(); y <= extended[z].get_max_index(); ++y) { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min - 1, old_max + 1); + extended[z][y][old_min - 1] = extended[z][y][old_min]; + extended[z][y][old_max + 1] = extended[z][y][old_max]; } + } proj_data_interpolator.set_coef(extended); - } - else - { - Array<3,float> extended = - extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } + } else { + Array<3, float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); + for (int z = extended.get_min_index(); z <= extended.get_max_index(); ++z) { + for (int y = extended[z].get_min_index(); y <= extended[z].get_max_index(); ++y) { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min - 1, old_max + 1); + extended[z][y][old_min - 1] = extended[z][y][old_min]; + extended[z][y][old_max + 1] = extended[z][y][old_max]; } + } proj_data_interpolator.set_coef(extended); } - - // now do interpolation - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + + // now do interpolation + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0); sample_function_on_regular_grid(sino_3D_out, proj_data_interpolator, offset, step); proj_data_out.set_segment(sino_3D_out); if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; + return Succeeded::no; return Succeeded::yes; } diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index da06c31a63..c3f59cdffe 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -8,12 +8,12 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! @@ -23,7 +23,7 @@ \author Charalampos Tsoumpas \author Kris Thielemans - + */ #include "stir/ProjData.h" #include "stir/ProjDataInfo.h" @@ -34,91 +34,66 @@ START_NAMESPACE_STIR -Succeeded -inverse_SSRB(ProjData& proj_data_4D, - const ProjData& proj_data_3D) -{ - const shared_ptr proj_data_3D_info_sptr = - dynamic_pointer_cast - (proj_data_3D.get_proj_data_info_sptr()); - const shared_ptr proj_data_4D_info_sptr = - dynamic_pointer_cast - (proj_data_4D.get_proj_data_info_sptr()); - if ((proj_data_3D_info_sptr->get_min_view_num() != - proj_data_4D_info_sptr->get_min_view_num()) || - (proj_data_3D_info_sptr->get_min_view_num() != - proj_data_4D_info_sptr->get_min_view_num())) - { - warning("inverse_SSRB: incompatible view-information"); - return Succeeded::no; - } - if ((proj_data_3D_info_sptr->get_min_tangential_pos_num() != - proj_data_4D_info_sptr->get_min_tangential_pos_num()) || - (proj_data_3D_info_sptr->get_min_tangential_pos_num() != - proj_data_4D_info_sptr->get_min_tangential_pos_num())) - { - warning("inverse_SSRB: incompatible tangential_pos-information"); - return Succeeded::no; - } +Succeeded +inverse_SSRB(ProjData& proj_data_4D, const ProjData& proj_data_3D) { + const shared_ptr proj_data_3D_info_sptr = + dynamic_pointer_cast(proj_data_3D.get_proj_data_info_sptr()); + const shared_ptr proj_data_4D_info_sptr = + dynamic_pointer_cast(proj_data_4D.get_proj_data_info_sptr()); + if ((proj_data_3D_info_sptr->get_min_view_num() != proj_data_4D_info_sptr->get_min_view_num()) || + (proj_data_3D_info_sptr->get_min_view_num() != proj_data_4D_info_sptr->get_min_view_num())) { + warning("inverse_SSRB: incompatible view-information"); + return Succeeded::no; + } + if ((proj_data_3D_info_sptr->get_min_tangential_pos_num() != proj_data_4D_info_sptr->get_min_tangential_pos_num()) || + (proj_data_3D_info_sptr->get_min_tangential_pos_num() != proj_data_4D_info_sptr->get_min_tangential_pos_num())) { + warning("inverse_SSRB: incompatible tangential_pos-information"); + return Succeeded::no; + } + + // keep sinograms out of the loop to avoid reallocations + // initialise to something because there's no default constructor + Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0), 0); + Sinogram sino_3D = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0), 0); + + for (int out_segment_num = proj_data_4D.get_min_segment_num(); out_segment_num <= proj_data_4D.get_max_segment_num(); + ++out_segment_num) { + for (int out_ax_pos_num = proj_data_4D.get_min_axial_pos_num(out_segment_num); + out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(out_segment_num); ++out_ax_pos_num) { + sino_4D = proj_data_4D.get_empty_sinogram(out_ax_pos_num, out_segment_num); + const float out_m = proj_data_4D_info_sptr->get_m(Bin(out_segment_num, 0, out_ax_pos_num, 0)); + int num_contributing_sinos = 0; - // keep sinograms out of the loop to avoid reallocations - // initialise to something because there's no default constructor - Sinogram sino_4D = - proj_data_4D. - get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); - Sinogram sino_3D = - proj_data_3D. - get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); - - for (int out_segment_num = proj_data_4D.get_min_segment_num(); - out_segment_num <= proj_data_4D.get_max_segment_num(); - ++out_segment_num) - { - for (int out_ax_pos_num = proj_data_4D.get_min_axial_pos_num(out_segment_num); - out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(out_segment_num); - ++out_ax_pos_num ) - { - sino_4D = proj_data_4D.get_empty_sinogram(out_ax_pos_num, out_segment_num); - const float out_m = - proj_data_4D_info_sptr-> - get_m(Bin(out_segment_num, 0, out_ax_pos_num, 0)); - int num_contributing_sinos = 0; - - for (int in_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); - in_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); - ++in_ax_pos_num ) - { - sino_3D = proj_data_3D.get_sinogram(in_ax_pos_num,0); - const float in_m = - proj_data_3D_info_sptr->get_m(Bin(0, 0, in_ax_pos_num, 0)); + for (int in_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); in_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); + ++in_ax_pos_num) { + sino_3D = proj_data_3D.get_sinogram(in_ax_pos_num, 0); + const float in_m = proj_data_3D_info_sptr->get_m(Bin(0, 0, in_ax_pos_num, 0)); - if (fabs(out_m - in_m) < 1E-2) - { - ++num_contributing_sinos; - sino_4D += sino_3D; - if (proj_data_4D.set_sinogram(sino_4D) == Succeeded::no) - return Succeeded::no; - break; - } - const float in_m_next = in_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? - -1000000.F : proj_data_3D_info_sptr->get_m(Bin(0, 0, in_ax_pos_num+1, 0)); + if (fabs(out_m - in_m) < 1E-2) { + ++num_contributing_sinos; + sino_4D += sino_3D; + if (proj_data_4D.set_sinogram(sino_4D) == Succeeded::no) + return Succeeded::no; + break; + } + const float in_m_next = in_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) + ? -1000000.F + : proj_data_3D_info_sptr->get_m(Bin(0, 0, in_ax_pos_num + 1, 0)); - if (fabs(out_m - .5F*(in_m + in_m_next)) < 1E-2) - { - ++num_contributing_sinos; - sino_4D += sino_3D; - sino_4D += proj_data_3D.get_sinogram(in_ax_pos_num+1,0); - sino_4D *= .5F; - if (proj_data_4D.set_sinogram(sino_4D) == Succeeded::no) - return Succeeded::no; - break; - } - } - if (num_contributing_sinos == 0) - warning("inverse_SSRB: no sinogram contributes to segment %d, axial_pos_num %d", - out_segment_num, out_ax_pos_num); - } - } - return Succeeded::yes; + if (fabs(out_m - .5F * (in_m + in_m_next)) < 1E-2) { + ++num_contributing_sinos; + sino_4D += sino_3D; + sino_4D += proj_data_3D.get_sinogram(in_ax_pos_num + 1, 0); + sino_4D *= .5F; + if (proj_data_4D.set_sinogram(sino_4D) == Succeeded::no) + return Succeeded::no; + break; + } + } + if (num_contributing_sinos == 0) + warning("inverse_SSRB: no sinogram contributes to segment %d, axial_pos_num %d", out_segment_num, out_ax_pos_num); + } + } + return Succeeded::yes; } END_NAMESPACE_STIR diff --git a/src/buildblock/line.cxx b/src/buildblock/line.cxx index 337fbb6bd9..28d6c7ceed 100644 --- a/src/buildblock/line.cxx +++ b/src/buildblock/line.cxx @@ -31,230 +31,204 @@ */ #include "stir/line.h" - START_NAMESPACE_STIR -const int LINE_ERROR =-1; -const int LINE_OK = 0; +const int LINE_ERROR = -1; +const int LINE_OK = 0; -string Line::get_keyword() -{ - // keyword stops at either := or an index [] +string +Line::get_keyword() { + // keyword stops at either := or an index [] // TODO should check that = follows : to allow keywords with colons in there - const size_type eok =find_first_of(":[",0); - return substr(0,eok); + const size_type eok = find_first_of(":[", 0); + return substr(0, eok); } -int Line::get_index() -{ - size_type cp,sok,eok; - // we take 0 as a default value for the index - int in=0; - string sin; - // make sure that the index is part of the key (i.e. before :=) - cp=find_first_of(":[",0); - if(cp!=string::npos && operator[](cp) == '[') - { - sok=cp+1; - eok=find_first_of(']',cp); - // check if closing bracket really there - if (eok == string::npos) - { - // TODO do something more graceful - warning("Interfile warning: invalid vectored key in line \n'%s'.\n%s", - this->c_str(), - "Assuming this is not a vectored key."); - return 0; - } - sin=substr(sok,eok-sok); - in=atoi(sin.c_str()); - } - return in; +int +Line::get_index() { + size_type cp, sok, eok; + // we take 0 as a default value for the index + int in = 0; + string sin; + // make sure that the index is part of the key (i.e. before :=) + cp = find_first_of(":[", 0); + if (cp != string::npos && operator[](cp) == '[') { + sok = cp + 1; + eok = find_first_of(']', cp); + // check if closing bracket really there + if (eok == string::npos) { + // TODO do something more graceful + warning("Interfile warning: invalid vectored key in line \n'%s'.\n%s", this->c_str(), + "Assuming this is not a vectored key."); + return 0; + } + sin = substr(sok, eok - sok); + in = atoi(sin.c_str()); + } + return in; } -int Line::get_param(string& s) -{ - size_type sok,eok; //start & end pos. of keyword - size_type cp =0; //current index - - cp=find('=',0); - - if(cp!=string::npos) - { - cp++; - sok=find_first_not_of(' ',cp); - if(sok!=string::npos) - { - cp=length(); - // strip trailing white space - eok=find_last_not_of(" \t",cp); - s=substr(sok,eok-sok+1); - return LINE_OK; - } - } - return LINE_ERROR; +int +Line::get_param(string& s) { + size_type sok, eok; // start & end pos. of keyword + size_type cp = 0; // current index + + cp = find('=', 0); + + if (cp != string::npos) { + cp++; + sok = find_first_not_of(' ', cp); + if (sok != string::npos) { + cp = length(); + // strip trailing white space + eok = find_last_not_of(" \t", cp); + s = substr(sok, eok - sok + 1); + return LINE_OK; + } + } + return LINE_ERROR; } -int Line::get_param(int& i) -{ - string s; - int r; - - r=get_param(s); - if(r==LINE_OK) - i=atoi(s.c_str()); - - return r; -} +int +Line::get_param(int& i) { + string s; + int r; + r = get_param(s); + if (r == LINE_OK) + i = atoi(s.c_str()); -int Line::get_param(unsigned long& i) -{ - string s; - int r; - - r=get_param(s); - if(r==LINE_OK) - // TODO not unsigned now - i=atol(s.c_str()); - - return r; + return r; } +int +Line::get_param(unsigned long& i) { + string s; + int r; -int Line::get_param(double& i) -{ - string s; - int r; + r = get_param(s); + if (r == LINE_OK) + // TODO not unsigned now + i = atol(s.c_str()); - r=get_param(s); - if(r==LINE_OK) - i=atof(s.c_str()); - - return r; + return r; } +int +Line::get_param(double& i) { + string s; + int r; + r = get_param(s); + if (r == LINE_OK) + i = atof(s.c_str()); -int Line::get_param(vector& v) -{ - string s; - size_type cp; - size_type eop; - bool end=false; - - cp=find_first_of('=',0)+1; - // skip white space - cp=find_first_not_of(" \t",cp); - // TODO? this does not check if brackets are balanced - while (!end) - { - cp=find_first_not_of("{},",cp); - - if(cp==string::npos) - { - end=true; - } - else - { - eop=find_first_of(",}",cp); - if(eop==string::npos) - { - end=true; - eop=length(); - } - s=substr(cp,eop-cp); - // TODO use strstream, would allow templates - v.push_back(atoi(s.c_str())); - cp=eop+1; - } - } - return LINE_OK; + return r; } +int +Line::get_param(vector& v) { + string s; + size_type cp; + size_type eop; + bool end = false; + + cp = find_first_of('=', 0) + 1; + // skip white space + cp = find_first_not_of(" \t", cp); + // TODO? this does not check if brackets are balanced + while (!end) { + cp = find_first_not_of("{},", cp); + + if (cp == string::npos) { + end = true; + } else { + eop = find_first_of(",}", cp); + if (eop == string::npos) { + end = true; + eop = length(); + } + s = substr(cp, eop - cp); + // TODO use strstream, would allow templates + v.push_back(atoi(s.c_str())); + cp = eop + 1; + } + } + return LINE_OK; +} -int Line::get_param(vector& v) -{ - string s; - // KT 02/11/98 don't use temporary variable anymore - //int r=LINE_OK; - size_type cp; - size_type eop; - bool end=false; - - cp=find_first_of('=',0)+1; - // skip white space - cp=find_first_not_of(" \t",cp); - // TODO? this does not check if brackets are balanced - while (!end) - { - cp=find_first_not_of("{},",cp); - - if(cp==string::npos) - { - end=true; - } - else - { - eop=find_first_of(",}",cp); - if(eop==string::npos) - { - end=true; - eop=length(); - } - s=substr(cp,eop-cp); - // TODO use strstream, would allow templates - v.push_back(atof(s.c_str())); - cp=eop+1; - } - } - return LINE_OK; +int +Line::get_param(vector& v) { + string s; + // KT 02/11/98 don't use temporary variable anymore + // int r=LINE_OK; + size_type cp; + size_type eop; + bool end = false; + + cp = find_first_of('=', 0) + 1; + // skip white space + cp = find_first_not_of(" \t", cp); + // TODO? this does not check if brackets are balanced + while (!end) { + cp = find_first_not_of("{},", cp); + + if (cp == string::npos) { + end = true; + } else { + eop = find_first_of(",}", cp); + if (eop == string::npos) { + end = true; + eop = length(); + } + s = substr(cp, eop - cp); + // TODO use strstream, would allow templates + v.push_back(atof(s.c_str())); + cp = eop + 1; + } + } + return LINE_OK; } -int Line::get_param(vector& v) -{ - string s; - - size_type cp; - size_type eop; - bool end=false; - - cp=find_first_of('=',0)+1; - // skip white space - cp=find_first_not_of(" \t",cp); - // TODO? this does not check if brackets are balanced - while (!end) - { - cp=find_first_not_of("{},",cp); - cp=find_first_not_of(" \t",cp); - - if(cp==string::npos) - { - end=true; - } - else - { - eop=find_first_of(",}",cp); - if(eop==string::npos) - { - end=true; - eop=length(); - } - // trim ending white space - size_type eop2 = find_last_not_of(" \t",eop); - s=substr(cp,eop2-cp); - - v.push_back(s); - cp=eop+1; - } - } - return LINE_OK; +int +Line::get_param(vector& v) { + string s; + + size_type cp; + size_type eop; + bool end = false; + + cp = find_first_of('=', 0) + 1; + // skip white space + cp = find_first_not_of(" \t", cp); + // TODO? this does not check if brackets are balanced + while (!end) { + cp = find_first_not_of("{},", cp); + cp = find_first_not_of(" \t", cp); + + if (cp == string::npos) { + end = true; + } else { + eop = find_first_of(",}", cp); + if (eop == string::npos) { + end = true; + eop = length(); + } + // trim ending white space + size_type eop2 = find_last_not_of(" \t", eop); + s = substr(cp, eop2 - cp); + + v.push_back(s); + cp = eop + 1; + } + } + return LINE_OK; } -Line& Line::operator=(const char* ch) -{ - string::operator=(ch); - return *this; +Line& +Line::operator=(const char* ch) { + string::operator=(ch); + return *this; } END_NAMESPACE_STIR diff --git a/src/buildblock/linear_regression.cxx b/src/buildblock/linear_regression.cxx index aefebfc8e0..4f9d994192 100644 --- a/src/buildblock/linear_regression.cxx +++ b/src/buildblock/linear_regression.cxx @@ -7,10 +7,10 @@ \brief Implementation for stir::linear_regression() function - \author Kris Thielemans + \author Kris Thielemans \author PARAPET project -*/ +*/ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2011, Hammersmith Imanet Ltd @@ -35,34 +35,21 @@ START_NAMESPACE_STIR namespace detail { - // see linear_regression.inl for more info - +// see linear_regression.inl for more info template -void linear_regression_compute_fit_from_S(Value& constant, Value& scale, - Value& chi_square, - Value& variance_of_constant, - Value& variance_of_scale, - Value& covariance_of_constant_with_scale, - const double S, - const double Sx, - const double Sy, - const double Syy, - const double Stt, - const double Sty, - const std::size_t data_size, - const bool use_estimated_variance - ) -{ - - - +void +linear_regression_compute_fit_from_S(Value& constant, Value& scale, Value& chi_square, Value& variance_of_constant, + Value& variance_of_scale, Value& covariance_of_constant_with_scale, const double S, + const double Sx, const double Sy, const double Syy, const double Stt, const double Sty, + const std::size_t data_size, const bool use_estimated_variance) { + scale = static_cast(Sty / Stt); constant = static_cast((Sy - Sx * scale) / S); - variance_of_scale = static_cast(1/ Stt); - variance_of_constant = static_cast((1 + square(Sx)/(S*Stt))/S); - covariance_of_constant_with_scale = static_cast(- Sx / (S*Stt)); - + variance_of_scale = static_cast(1 / Stt); + variance_of_constant = static_cast((1 + square(Sx) / (S * Stt)) / S); + covariance_of_constant_with_scale = static_cast(-Sx / (S * Stt)); + // Compute chi_square, i.e. // sum_i weights[i]*(measured_data[i] - (constant+scale*coordinates[i]))^2 // It turns out this can be done using previously calculated constants, @@ -70,59 +57,36 @@ void linear_regression_compute_fit_from_S(Value& constant, Value& scale, // Proving the next identity is a tough algebraic calculation // (performed by KT in Mathematica) - chi_square = static_cast(Syy - square(scale)*Stt - square(Sy)/S); - - if (chi_square<0) - { - warning("linear_regression found negative chi_square %g.\n" - "This is probably just because of rounding errors and indicates " - "a small error compared to the data. I will set it to 0 to avoid " - "problems with sqrt(chi_square).", - chi_square); - chi_square=0; - } - if (use_estimated_variance==true) - { - const Value estimated_variance = - static_cast(chi_square/(data_size - 2)); - variance_of_scale *=estimated_variance; - variance_of_constant *=estimated_variance; - covariance_of_constant_with_scale *=estimated_variance; + chi_square = static_cast(Syy - square(scale) * Stt - square(Sy) / S); + + if (chi_square < 0) { + warning("linear_regression found negative chi_square %g.\n" + "This is probably just because of rounding errors and indicates " + "a small error compared to the data. I will set it to 0 to avoid " + "problems with sqrt(chi_square).", + chi_square); + chi_square = 0; + } + if (use_estimated_variance == true) { + const Value estimated_variance = static_cast(chi_square / (data_size - 2)); + variance_of_scale *= estimated_variance; + variance_of_constant *= estimated_variance; + covariance_of_constant_with_scale *= estimated_variance; } } // instantiations -template void -linear_regression_compute_fit_from_S<>(float& constant, float& scale, - float& chi_square, - float& variance_of_constant, - float& variance_of_scale, - float& covariance_of_constant_with_scale, - const double S, - const double Sx, - const double Sy, - const double Syy, - const double Stt, - const double Sty, - const std::size_t data_size, - const bool use_estimated_variance - ); - -template void -linear_regression_compute_fit_from_S<>(double& constant, double& scale, - double& chi_square, - double& variance_of_constant, - double& variance_of_scale, - double& covariance_of_constant_with_scale, - const double S, - const double Sx, - const double Sy, - const double Syy, - const double Stt, - const double Sty, - const std::size_t data_size, - const bool use_estimated_variance - ); +template void linear_regression_compute_fit_from_S<>(float& constant, float& scale, float& chi_square, + float& variance_of_constant, float& variance_of_scale, + float& covariance_of_constant_with_scale, const double S, const double Sx, + const double Sy, const double Syy, const double Stt, const double Sty, + const std::size_t data_size, const bool use_estimated_variance); + +template void linear_regression_compute_fit_from_S<>(double& constant, double& scale, double& chi_square, + double& variance_of_constant, double& variance_of_scale, + double& covariance_of_constant_with_scale, const double S, const double Sx, + const double Sy, const double Syy, const double Stt, const double Sty, + const std::size_t data_size, const bool use_estimated_variance); } // end namespace detail diff --git a/src/buildblock/num_threads.cxx b/src/buildblock/num_threads.cxx index 12bc2d0dab..e7762512e0 100644 --- a/src/buildblock/num_threads.cxx +++ b/src/buildblock/num_threads.cxx @@ -21,7 +21,7 @@ \brief Implementation of functions related to setting/getting the number of threads - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/num_threads.h" @@ -32,13 +32,13 @@ #include #ifdef STIR_OPENMP -#include +# include #endif START_NAMESPACE_STIR -int get_max_num_threads() -{ +int +get_max_num_threads() { #ifdef STIR_OPENMP return omp_get_max_threads(); #else @@ -46,53 +46,47 @@ int get_max_num_threads() #endif } -void set_num_threads(const int num_threads) -{ +void +set_num_threads(const int num_threads) { static bool already_set_once = false; - if (num_threads==0) - { - if (!already_set_once) - { - set_default_num_threads(); - } + if (num_threads == 0) { + if (!already_set_once) { + set_default_num_threads(); } - else - { + } else { #ifdef STIR_OPENMP - omp_set_num_threads(num_threads); + omp_set_num_threads(num_threads); - if (omp_get_max_threads()==1) - warning("Using OpenMP with number of threads=1 produces parallel overhead. You should compile without OPENMP support"); + if (omp_get_max_threads() == 1) + warning("Using OpenMP with number of threads=1 produces parallel overhead. You should compile without OPENMP support"); #else - if (num_threads!=1) - warning("You have asked for more than 1 thread but this is ignored as STIR was not compiled with OpenMP support."); + if (num_threads != 1) + warning("You have asked for more than 1 thread but this is ignored as STIR was not compiled with OpenMP support."); #endif - } + } already_set_once = true; } -int get_default_num_threads() -{ +int +get_default_num_threads() { #ifdef STIR_OPENMP - int default_num_threads = std::max((int)floor(omp_get_num_procs()*.9), 2); - if (omp_get_num_procs()==1) - default_num_threads=1; + int default_num_threads = std::max((int)floor(omp_get_num_procs() * .9), 2); + if (omp_get_num_procs() == 1) + default_num_threads = 1; - if (getenv("OMP_NUM_THREADS")!=NULL) - { - default_num_threads=atoi(getenv("OMP_NUM_THREADS")); - } + if (getenv("OMP_NUM_THREADS") != NULL) { + default_num_threads = atoi(getenv("OMP_NUM_THREADS")); + } return default_num_threads; #else return 1; #endif } -void set_default_num_threads() -{ +void +set_default_num_threads() { set_num_threads(get_default_num_threads()); } - END_NAMESPACE_STIR diff --git a/src/buildblock/overlap_interpolate.cxx b/src/buildblock/overlap_interpolate.cxx index 349d4ae139..0c7d95d0b1 100644 --- a/src/buildblock/overlap_interpolate.cxx +++ b/src/buildblock/overlap_interpolate.cxx @@ -32,9 +32,9 @@ #include "stir/VectorWithOffset.h" START_NAMESPACE_STIR -/*! +/*! - This is an implementation of 'overlap' interpolation on + This is an implementation of 'overlap' interpolation on arbitrary data types (using templates). This type of interpolation considers the data as the samples of @@ -52,7 +52,7 @@ START_NAMESPACE_STIR range of indices). Note that a similar (but less general) effect to using 'offset' can be achieved by adjusting the min and max indices of the out_data. - + \param assign_rest_with_zeroes If \c false does not set values in \c out_data which do not overlap with \c in_data. @@ -64,7 +64,7 @@ START_NAMESPACE_STIR (The convention is used that the 'bins' are centered around the coordinate value.) - \warning when T involves integral types, there is no rounding + \warning when T involves integral types, there is no rounding but truncation. \par Examples: @@ -85,16 +85,16 @@ START_NAMESPACE_STIR offset = 0 out_data = {a/2, a/2+b+c/2, c/2} indices from -1 to 1 \endverbatim - + \par Implementation details: Because this implementation works for arbitrary (numeric) types T, it is slightly more complicated than would be necessary for (say) floats. - In particular,
+ In particular,
- we do our best to avoid creating temporary objects of type T
- we zero values by using multiplication with 0
(actually we use T::operator*=(0)). This is to allow the case where - T::operator=(int) does not exist (in particular, in our higher + T::operator=(int) does not exist (in particular, in our higher dimensional arrays). @@ -107,136 +107,114 @@ START_NAMESPACE_STIR template void -overlap_interpolate(VectorWithOffset& out_data, - const VectorWithOffset& in_data, - const float zoom, - const float offset, - const bool assign_rest_with_zeroes) -{ - assert(zoom>0); - +overlap_interpolate(VectorWithOffset& out_data, const VectorWithOffset& in_data, const float zoom, const float offset, + const bool assign_rest_with_zeroes) { + assert(zoom > 0); + // First check trivial case - if (zoom==1.F && offset==0.F && - in_data.get_min_index()==out_data.get_min_index() && - in_data.get_max_index()==out_data.get_max_index()) - { + if (zoom == 1.F && offset == 0.F && in_data.get_min_index() == out_data.get_min_index() && + in_data.get_max_index() == out_data.get_max_index()) { out_data = in_data; return; } - - if(zoom>=1) - { - // Shrinking to a smaller bin size - + + if (zoom >= 1) { + // Shrinking to a smaller bin size + // start at the first 'in' bin that overlaps the 'out' data. // compute by checking by comparing its position with // the position of the left edge of the first 'out' bin: // left_edge = (out_data.get_min_index() - .5)/zoom + offset // x1 -.5 <= left_edge < x1+.5 int x2 = out_data.get_min_index(); - int x1 = (int)floor((x2 - .5)/zoom + offset + .5); - + int x1 = (int)floor((x2 - .5) / zoom + offset + .5); + // the next variable holds the difference between the coordinates // of the right edges of the 'in' bin and the 'out' bin, computed // in a coordinate system where the 'out' voxels are unit distance apart - double diff_between_right_edges = - zoom*(x1-offset+.5) - (x2 + .5); - - for(; - x2 <= out_data.get_max_index(); - x2++, diff_between_right_edges--) - { - - if(x1> in_data.get_max_index()) - { - // just fill out_data with 0, - // no need to check/update diff_between_right_edges - if (assign_rest_with_zeroes) - out_data[x2] *= 0; - - continue; + double diff_between_right_edges = zoom * (x1 - offset + .5) - (x2 + .5); + + for (; x2 <= out_data.get_max_index(); x2++, diff_between_right_edges--) { + + if (x1 > in_data.get_max_index()) { + // just fill out_data with 0, + // no need to check/update diff_between_right_edges + if (assign_rest_with_zeroes) + out_data[x2] *= 0; + + continue; } - - assert(diff_between_right_edges<= zoom/*+epsilon*/); - assert(diff_between_right_edges>= -1/*epsilon*/); - - if (diff_between_right_edges >= 0) - { - if(x1 >= in_data.get_min_index()) - { - out_data[x2] = in_data[x1]; + + assert(diff_between_right_edges <= zoom /*+epsilon*/); + assert(diff_between_right_edges >= -1 /*epsilon*/); + + if (diff_between_right_edges >= 0) { + if (x1 >= in_data.get_min_index()) { + out_data[x2] = in_data[x1]; #ifndef STIR_OVERLAP_NORMALISATION - out_data[x2] /= zoom; + out_data[x2] /= zoom; #endif - } - else - { - if (assign_rest_with_zeroes) - out_data[x2] *= 0; - } - } - else - { - /* + } else { + if (assign_rest_with_zeroes) + out_data[x2] *= 0; + } + } else { + /* Set out_data[x2] according to - + T V1; // bin value at x1 - T V2; // bin value at x1+1 + T V2; // bin value at x1+1 out_data[x2] = (V1+diff_between_right_edges*(V1-V2))/zoom; - + The lines below are more complicated because - - testing if x1, x1+1 are inside the range of in_data - - everything is done without creating temporary objects of type T + - testing if x1, x1+1 are inside the range of in_data + - everything is done without creating temporary objects of type T */ - if(x1 >= in_data.get_min_index()) - { - out_data[x2] = in_data[x1]; - out_data[x2] *= static_cast(1/diff_between_right_edges + 1); // note conversion to float to avoid compiler warnings in case that T is float (or a float array) - } - else - { - if (assign_rest_with_zeroes) - out_data[x2] *= 0; - } - if(x1+1 <= in_data.get_max_index() && x1+1>=in_data.get_min_index()) - { - out_data[x2] -= in_data[x1+1]; - } - + if (x1 >= in_data.get_min_index()) { + out_data[x2] = in_data[x1]; + out_data[x2] *= static_cast( + 1 / diff_between_right_edges + + 1); // note conversion to float to avoid compiler warnings in case that T is float (or a float array) + } else { + if (assign_rest_with_zeroes) + out_data[x2] *= 0; + } + if (x1 + 1 <= in_data.get_max_index() && x1 + 1 >= in_data.get_min_index()) { + out_data[x2] -= in_data[x1 + 1]; + } + #ifndef STIR_OVERLAP_NORMALISATION - out_data[x2] *= static_cast(diff_between_right_edges/zoom); + out_data[x2] *= static_cast(diff_between_right_edges / zoom); #else - out_data[x2] *= static_cast(diff_between_right_edges); + out_data[x2] *= static_cast(diff_between_right_edges); #endif - - // advance 'in' bin - x1++; - diff_between_right_edges += zoom; + + // advance 'in' bin + x1++; + diff_between_right_edges += zoom; } - }// End of for x2 - - } - else - { - // case zoom <1 : stretching the bin size + } // End of for x2 + + } else { + // case zoom <1 : stretching the bin size // start 1 before the first 'in' bin that overlaps the 'out' data. // compute by comparing its position with // the position of the left edge of the first 'out' bin: // left_edge = (out_data.get_min_index() - .5)/zoom + offset // x1-.5 <= left_edge < x1+.5 - - const float inverse_zoom = 1/zoom; - + + const float inverse_zoom = 1 / zoom; + // current coordinate in out_data int x2 = out_data.get_min_index(); // current coordinate in in_data - int x1 = (int)floor((x2 - .5)*inverse_zoom + offset + .5); - + int x1 = (int)floor((x2 - .5) * inverse_zoom + offset + .5); + // the next variable holds the difference between the coordinates // of the right edges of the 'in' bin and the 'out' bin, computed // in a coordinate system where the 'in' bins are unit distance apart - double diff_between_right_edges = (x1-offset+.5) - (x2 + .5)*inverse_zoom; - + double diff_between_right_edges = (x1 - offset + .5) - (x2 + .5) * inverse_zoom; + // we will loop over x1 to update out_data[x2] from in_data[x1] // however, we first check if the left edge of the first in_data is // to the left of the left edge of the first out_data. @@ -244,161 +222,102 @@ overlap_interpolate(VectorWithOffset& out_data, // lies outside the 'out' bin. In the loop later, this part of the // 'in' bin will be added again. { - const double diff_between_left_edges = - diff_between_right_edges-1+inverse_zoom; - if (diff_between_left_edges < 0 && - x1 >= in_data.get_min_index() && x1 <= in_data.get_max_index() ) - { - out_data[x2] = in_data[x1]; - out_data[x2] *= static_cast(diff_between_left_edges); - } - else - { - if (assign_rest_with_zeroes) - out_data[x2] *= 0; + const double diff_between_left_edges = diff_between_right_edges - 1 + inverse_zoom; + if (diff_between_left_edges < 0 && x1 >= in_data.get_min_index() && x1 <= in_data.get_max_index()) { + out_data[x2] = in_data[x1]; + out_data[x2] *= static_cast(diff_between_left_edges); + } else { + if (assign_rest_with_zeroes) + out_data[x2] *= 0; } } - for (; - x1 <= in_data.get_max_index(); - x1++, diff_between_right_edges++) - { - assert(diff_between_right_edges<= 1/*+epsilon*/); - assert(diff_between_right_edges>= -inverse_zoom/*-epsilon*/); - - if (diff_between_right_edges <= 0) - { - // 'in' bin fits entirely in the 'out' bin - if (x1 >= in_data.get_min_index()) - out_data[x2] += in_data[x1]; + for (; x1 <= in_data.get_max_index(); x1++, diff_between_right_edges++) { + assert(diff_between_right_edges <= 1 /*+epsilon*/); + assert(diff_between_right_edges >= -inverse_zoom /*-epsilon*/); + + if (diff_between_right_edges <= 0) { + // 'in' bin fits entirely in the 'out' bin + if (x1 >= in_data.get_min_index()) + out_data[x2] += in_data[x1]; + } else { + // dx = fraction of 'in' bin that lies within 'out' bin + const double dx = 1 - diff_between_right_edges; + // update current 'out' bin + if (x1 >= in_data.get_min_index()) { + // out_data[x2] += in_data[x1]*dx; + if (fabs(dx) > 1e-5) { + out_data[x2] /= static_cast(dx); + out_data[x2] += in_data[x1]; + out_data[x2] *= static_cast(dx); + } + } + // next bin + x2++; + diff_between_right_edges -= inverse_zoom; + // update this one with the rest + if (x2 <= out_data.get_max_index()) { + if (x1 >= in_data.get_min_index()) { + // out_data[x2] = in_data[x1]*(1-dx); + out_data[x2] = in_data[x1]; + out_data[x2] *= static_cast((1 - dx)); + } else if (assign_rest_with_zeroes) { + out_data[x2] *= 0; + } + } else { + // x2 goes out of range, so we can just as well stop + break; + } } - else - { - // dx = fraction of 'in' bin that lies within 'out' bin - const double dx= 1- diff_between_right_edges; - // update current 'out' bin - if (x1 >= in_data.get_min_index()) - { - // out_data[x2] += in_data[x1]*dx; - if (fabs(dx) > 1e-5) - { - out_data[x2] /= static_cast(dx); - out_data[x2] += in_data[x1]; - out_data[x2] *= static_cast(dx); - } - } - // next bin - x2++; - diff_between_right_edges -= inverse_zoom; - // update this one with the rest - if (x2<= out_data.get_max_index()) - { - if (x1 >= in_data.get_min_index()) - { - // out_data[x2] = in_data[x1]*(1-dx); - out_data[x2] = in_data[x1]; - out_data[x2] *= static_cast((1-dx)); - } - else if (assign_rest_with_zeroes) - { - out_data[x2] *= 0; - } - } - else - { - // x2 goes out of range, so we can just as well stop - break; - } - } - - }// End of for x1 - - if (assign_rest_with_zeroes) - { + + } // End of for x1 + + if (assign_rest_with_zeroes) { // set rest of out_data to 0 - for (x2++; - x2 <= out_data.get_max_index(); - x2++) - out_data[x2] *= 0; + for (x2++; x2 <= out_data.get_max_index(); x2++) + out_data[x2] *= 0; } #ifdef STIR_OVERLAP_NORMALISATION - for (x2 = out_data.get_min_index(); - x2 <= out_data.get_max_index(); - x2++) - out_data[x2] *= static_cast(zoom); + for (x2 = out_data.get_min_index(); x2 <= out_data.get_max_index(); x2++) + out_data[x2] *= static_cast(zoom); #endif - - - }// End of if(zoom>1) - -} - + } // End of if(zoom>1) +} /************************************************ Instantiations ************************************************/ -template -void -overlap_interpolate<>(VectorWithOffset& out_data, - const VectorWithOffset& in_data, - const float zoom, - const float offset, - const bool assign_rest_with_zeroes); - -template -void -overlap_interpolate<>(VectorWithOffset& out_data, - const VectorWithOffset& in_data, - const float zoom, - const float offset, - const bool assign_rest_with_zeroes); +template void overlap_interpolate<>(VectorWithOffset& out_data, const VectorWithOffset& in_data, const float zoom, + const float offset, const bool assign_rest_with_zeroes); + +template void overlap_interpolate<>(VectorWithOffset& out_data, const VectorWithOffset& in_data, const float zoom, + const float offset, const bool assign_rest_with_zeroes); END_NAMESPACE_STIR - // TODO remove +// TODO remove #if defined(OLDDESIGN) -#include "stir/Tensor2D.h" - -template -void -overlap_interpolate<>(VectorWithOffset >& out_data, - const VectorWithOffset >& in_data, - const float zoom, - const float offset, - const bool assign_rest_with_zeroes); +# include "stir/Tensor2D.h" -template -void -overlap_interpolate<>(VectorWithOffset >& out_data, - const VectorWithOffset >& in_data, - const float zoom, - const float offset, - const bool assign_rest_with_zeroes); +template void overlap_interpolate<>(VectorWithOffset>& out_data, const VectorWithOffset>& in_data, + const float zoom, const float offset, const bool assign_rest_with_zeroes); +template void overlap_interpolate<>(VectorWithOffset>& out_data, const VectorWithOffset>& in_data, + const float zoom, const float offset, const bool assign_rest_with_zeroes); -#else +#else -#include "stir/Array.h" +# include "stir/Array.h" START_NAMESPACE_STIR -template -void -overlap_interpolate<>(VectorWithOffset >& out_data, - const VectorWithOffset >& in_data, - const float zoom, - const float offset, - const bool assign_rest_with_zeroes); - -template -void -overlap_interpolate<>(VectorWithOffset >& out_data, - const VectorWithOffset >& in_data, - const float zoom, - const float offset, - const bool assign_rest_with_zeroes); +template void overlap_interpolate<>(VectorWithOffset>& out_data, const VectorWithOffset>& in_data, + const float zoom, const float offset, const bool assign_rest_with_zeroes); + +template void overlap_interpolate<>(VectorWithOffset>& out_data, const VectorWithOffset>& in_data, + const float zoom, const float offset, const bool assign_rest_with_zeroes); #endif END_NAMESPACE_STIR diff --git a/src/buildblock/recon_array_functions.cxx b/src/buildblock/recon_array_functions.cxx index a966fe795a..51d7eb41c9 100644 --- a/src/buildblock/recon_array_functions.cxx +++ b/src/buildblock/recon_array_functions.cxx @@ -3,18 +3,18 @@ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2011, Hammersmith Imanet Ltd - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! @@ -25,11 +25,11 @@ \author Matthew Jacobson \author Kris Thielemans \author PARAPET project - + */ -//some miscellaneous operators for sinograms and images +// some miscellaneous operators for sinograms and images #include "stir/recon_array_functions.h" #include "stir/min_positive_element.h" @@ -52,156 +52,135 @@ START_NAMESPACE_STIR const float SMALL_NUM = 0.000001F; - // AZ 07/10/99: added -void truncate_rim(Viewgram& viewgram, const int rim_truncation_sino) -{ - const int rs=viewgram.get_min_axial_pos_num(); - const int re=viewgram.get_max_axial_pos_num(); - const int bs=viewgram.get_min_tangential_pos_num(); - const int be=viewgram.get_max_tangential_pos_num(); - - //MJ 12/04/2000 to remove the necessity for grow in things like sum_over_projections() - int upper_truncation_offset=rim_truncation_sino; - if(viewgram.get_num_tangential_poss()%2!=0) upper_truncation_offset--; - - - for(int r=rs;r<=re;r++) - { - for(int b=bs;b& viewgram, const int rim_truncation_sino) { + const int rs = viewgram.get_min_axial_pos_num(); + const int re = viewgram.get_max_axial_pos_num(); + const int bs = viewgram.get_min_tangential_pos_num(); + const int be = viewgram.get_max_tangential_pos_num(); + + // MJ 12/04/2000 to remove the necessity for grow in things like sum_over_projections() + int upper_truncation_offset = rim_truncation_sino; + if (viewgram.get_num_tangential_poss() % 2 != 0) + upper_truncation_offset--; + + for (int r = rs; r <= re; r++) { + for (int b = bs; b < bs + rim_truncation_sino; b++) + viewgram[r][b] = 0; + for (int b = be - upper_truncation_offset; b <= be; b++) + viewgram[r][b] = 0; + } } -void truncate_rim(SegmentByView& seg, const int rim_truncation_sino) -{ - - const int vs=seg.get_min_view_num(); - const int ve=seg.get_max_view_num(); - const int rs=seg.get_min_axial_pos_num(); - const int re=seg.get_max_axial_pos_num(); - const int bs=seg.get_min_tangential_pos_num(); - const int be=seg.get_max_tangential_pos_num(); - - //MJ 25/03/2000 to remove the necessity for grow in things like sum_over_projections() - int upper_truncation_offset=rim_truncation_sino; - if(seg.get_num_tangential_poss()%2!=0) upper_truncation_offset--; - - for(int v=vs;v<=ve;v++) - for(int r=rs;r<=re;r++) - { - for(int b=bs;b& seg, const int rim_truncation_sino) { + + const int vs = seg.get_min_view_num(); + const int ve = seg.get_max_view_num(); + const int rs = seg.get_min_axial_pos_num(); + const int re = seg.get_max_axial_pos_num(); + const int bs = seg.get_min_tangential_pos_num(); + const int be = seg.get_max_tangential_pos_num(); + + // MJ 25/03/2000 to remove the necessity for grow in things like sum_over_projections() + int upper_truncation_offset = rim_truncation_sino; + if (seg.get_num_tangential_poss() % 2 != 0) + upper_truncation_offset--; + + for (int v = vs; v <= ve; v++) + for (int r = rs; r <= re; r++) { + for (int b = bs; b < bs + rim_truncation_sino; b++) + seg[v][r][b] = 0; + for (int b = be - upper_truncation_offset; b <= be; b++) + seg[v][r][b] = 0; } - } - -void truncate_rim(SegmentBySinogram& seg, const int rim_truncation_sino) -{ - - const int vs=seg.get_min_view_num(); - const int ve=seg.get_max_view_num(); - const int rs=seg.get_min_axial_pos_num(); - const int re=seg.get_max_axial_pos_num(); - const int bs=seg.get_min_tangential_pos_num(); - const int be=seg.get_max_tangential_pos_num(); - - //MJ 25/03/2000 to remove the necessity for grow in things like sum_over_projections() - int upper_truncation_offset=rim_truncation_sino; - if(seg.get_num_tangential_poss()%2!=0) upper_truncation_offset--; - - - for(int r=rs;r<=re;r++) - for(int v=vs;v<=ve;v++) - { - for(int b=bs;b& seg, const int rim_truncation_sino) { + + const int vs = seg.get_min_view_num(); + const int ve = seg.get_max_view_num(); + const int rs = seg.get_min_axial_pos_num(); + const int re = seg.get_max_axial_pos_num(); + const int bs = seg.get_min_tangential_pos_num(); + const int be = seg.get_max_tangential_pos_num(); + + // MJ 25/03/2000 to remove the necessity for grow in things like sum_over_projections() + int upper_truncation_offset = rim_truncation_sino; + if (seg.get_num_tangential_poss() % 2 != 0) + upper_truncation_offset--; + + for (int r = rs; r <= re; r++) + for (int v = vs; v <= ve; v++) { + for (int b = bs; b < bs + rim_truncation_sino; b++) + seg[r][v][b] = 0; + for (int b = be - upper_truncation_offset; b <= be; b++) + seg[r][v][b] = 0; } } -//MJ 18/9/98 new -void truncate_rim(DiscretisedDensity<3,float>& input_image, - const int rim_truncation_image, - const bool strictly_less_than_radius) -{ +// MJ 18/9/98 new +void +truncate_rim(DiscretisedDensity<3, float>& input_image, const int rim_truncation_image, const bool strictly_less_than_radius) { // TODO the 'rim_truncate' part of this function does not make a lot of sense in general - DiscretisedDensityOnCartesianGrid<3,float>& input_image_cartesian = - dynamic_cast&>(input_image); + DiscretisedDensityOnCartesianGrid<3, float>& input_image_cartesian = + dynamic_cast&>(input_image); if (!input_image_cartesian.is_regular()) error("truncate_rim called for non-regular grid. Not implemented"); - const int zs=input_image_cartesian.get_min_index(); - const int ys=input_image_cartesian[zs].get_min_index(); - const int xs=input_image_cartesian[zs][ys].get_min_index(); - - const int ze=input_image_cartesian.get_max_index(); - const int ye=input_image_cartesian[zs].get_max_index(); - const int xe=input_image_cartesian[zs][ys].get_max_index(); - + const int zs = input_image_cartesian.get_min_index(); + const int ys = input_image_cartesian[zs].get_min_index(); + const int xs = input_image_cartesian[zs][ys].get_min_index(); + + const int ze = input_image_cartesian.get_max_index(); + const int ye = input_image_cartesian[zs].get_max_index(); + const int xe = input_image_cartesian[zs][ys].get_max_index(); + // TODO check what happens with even-sized images (i.e. where is the centre?) - - //const int zm=(zs+ze)/2; - const int ym=(ys+ye)/2; - const int xm=(xs+xe)/2; - - const float truncated_radius = - static_cast((xe-xs)/2 - rim_truncation_image); - - - if (strictly_less_than_radius) - { - for (int z=zs; z<=ze; z++) - for (int y=ys; y <= ye; y++) - for (int x=xs; x<= xe; x++) - { - if(square(xm-x)+square(ym-y)>=square(truncated_radius)) - input_image[z][y][x]=0; - } - } - else - { - for (int z=zs; z<=ze; z++) - for (int y=ys; y <= ye; y++) - for (int x=xs; x<= xe; x++) - { - if(square(xm-x)+square(ym-y)>square(truncated_radius)) - input_image[z][y][x]=0; - } - } + + // const int zm=(zs+ze)/2; + const int ym = (ys + ye) / 2; + const int xm = (xs + xe) / 2; + + const float truncated_radius = static_cast((xe - xs) / 2 - rim_truncation_image); + + if (strictly_less_than_radius) { + for (int z = zs; z <= ze; z++) + for (int y = ys; y <= ye; y++) + for (int x = xs; x <= xe; x++) { + if (square(xm - x) + square(ym - y) >= square(truncated_radius)) + input_image[z][y][x] = 0; + } + } else { + for (int z = zs; z <= ze; z++) + for (int y = ys; y <= ye; y++) + for (int x = xs; x <= xe; x++) { + if (square(xm - x) + square(ym - y) > square(truncated_radius)) + input_image[z][y][x] = 0; + } + } } +// AZ&KT 04/10/99: added rim_truncation_sino +void +divide_and_truncate(Viewgram& numerator, const Viewgram& denominator, const int rim_truncation_sino, int& count, + int& count2, double* log_likelihood_ptr /* = NULL */) { + + const int rs = numerator.get_min_axial_pos_num(); + const int re = numerator.get_max_axial_pos_num(); + const int bs = numerator.get_min_tangential_pos_num(); + const int be = numerator.get_max_tangential_pos_num(); + const float small_value = max(numerator.find_max() * SMALL_NUM, 0.F); + + double result = 0; // use this for total result for this viewgram, reducing numerical error + for (int r = rs; r <= re; r++) { + double sub_result = 0; // use this for total result for this r, reducing numerical error + for (int b = bs; b <= be; b++) { -// AZ&KT 04/10/99: added rim_truncation_sino -void divide_and_truncate(Viewgram& numerator, - const Viewgram& denominator, - const int rim_truncation_sino, - int& count, int& count2, double* log_likelihood_ptr /* = NULL */) -{ - - const int rs=numerator.get_min_axial_pos_num(); - const int re=numerator.get_max_axial_pos_num(); - const int bs=numerator.get_min_tangential_pos_num(); - const int be=numerator.get_max_tangential_pos_num(); - - - const float small_value= - max(numerator.find_max()*SMALL_NUM, 0.F); - - double result=0; // use this for total result for this viewgram, reducing numerical error - for(int r=rs;r<=re;r++) - { - double sub_result=0; // use this for total result for this r, reducing numerical error - for(int b=bs;b<=be;b++){ - // KT&SM&MJ 21/05/2001 changed truncation strategy // before singularities (non-zero divided by zero) were set to 0 // now they are set to max_quotient @@ -224,138 +203,112 @@ void divide_and_truncate(Viewgram& numerator, }; #else - if(bbe-rim_truncation_sino ) - { - numerator[r][b] = 0; - } - else - { - float& num = numerator[r][b]; - if (num<=small_value) // KT Feb2011 was "num max_quotient*denom) - { - // cancel singularity - count++; - if (log_likelihood_ptr != NULL) - sub_result -= double(num*log(num/max_quotient)); - num = max_quotient; - } - else - { - if (log_likelihood_ptr != NULL) - sub_result -= double(num*log(denom)); - num = num/denom; - } - } - } + if (b < bs + rim_truncation_sino || b > be - rim_truncation_sino) { + numerator[r][b] = 0; + } else { + float& num = numerator[r][b]; + if (num <= small_value) // KT Feb2011 was "num max_quotient * denom) { + // cancel singularity + count++; + if (log_likelihood_ptr != NULL) + sub_result -= double(num * log(num / max_quotient)); + num = max_quotient; + } else { + if (log_likelihood_ptr != NULL) + sub_result -= double(num * log(denom)); + num = num / denom; + } + } + } #endif } - if (log_likelihood_ptr != NULL) + if (log_likelihood_ptr != NULL) result += sub_result; } - if (log_likelihood_ptr != NULL) + if (log_likelihood_ptr != NULL) *log_likelihood_ptr += result; - } - - -void divide_and_truncate(RelatedViewgrams& numerator, const RelatedViewgrams& denominator, - const int rim_truncation_sino, - int& count, int& count2, double* log_likelihood_ptr ) -{ +void +divide_and_truncate(RelatedViewgrams& numerator, const RelatedViewgrams& denominator, const int rim_truncation_sino, + int& count, int& count2, double* log_likelihood_ptr) { assert(numerator.get_num_viewgrams() == denominator.get_num_viewgrams()); assert(*(numerator.get_proj_data_info_sptr()) == (*denominator.get_proj_data_info_sptr())); RelatedViewgrams::iterator numerator_iter = numerator.begin(); RelatedViewgrams::const_iterator denominator_iter = denominator.begin(); - while(numerator_iter!=numerator.end()) - { - divide_and_truncate(*numerator_iter, - *denominator_iter, - rim_truncation_sino, - count, count2, log_likelihood_ptr); - ++numerator_iter; - ++denominator_iter; + while (numerator_iter != numerator.end()) { + divide_and_truncate(*numerator_iter, *denominator_iter, rim_truncation_sino, count, count2, log_likelihood_ptr); + ++numerator_iter; + ++denominator_iter; } } +void +divide_array(SegmentByView& numerator, const SegmentByView& denominator) { + + const int vs = numerator.get_min_view_num(); + const int ve = numerator.get_max_view_num(); + const int rs = numerator.get_min_axial_pos_num(); + const int re = numerator.get_max_axial_pos_num(); + const int bs = numerator.get_min_tangential_pos_num(); + const int be = numerator.get_max_tangential_pos_num(); -void divide_array(SegmentByView& numerator,const SegmentByView& denominator) -{ - - const int vs=numerator.get_min_view_num(); - const int ve=numerator.get_max_view_num(); - const int rs=numerator.get_min_axial_pos_num(); - const int re=numerator.get_max_axial_pos_num(); - const int bs=numerator.get_min_tangential_pos_num(); - const int be=numerator.get_max_tangential_pos_num(); - - for(int v=vs;v<=ve;v++) - for(int r=rs;r<=re;r++) - for(int b=bs;b<=be;b++) - { - - if (denominator[v][r][b] != 0.0) - numerator[v][r][b]=numerator[v][r][b]/denominator[v][r][b]; - else - numerator[v][r][b]=0.0; - - } - + for (int v = vs; v <= ve; v++) + for (int r = rs; r <= re; r++) + for (int b = bs; b <= be; b++) { + + if (denominator[v][r][b] != 0.0) + numerator[v][r][b] = numerator[v][r][b] / denominator[v][r][b]; + else + numerator[v][r][b] = 0.0; + } } -void divide_array(DiscretisedDensity<3,float>& numerator, const DiscretisedDensity<3,float>& denominator) -{ +void +divide_array(DiscretisedDensity<3, float>& numerator, const DiscretisedDensity<3, float>& denominator) { assert(numerator.get_index_range() == denominator.get_index_range()); - float small_value= numerator.find_max()*SMALL_NUM; - small_value=(small_value>0.0F)?small_value:0.0F; + float small_value = numerator.find_max() * SMALL_NUM; + small_value = (small_value > 0.0F) ? small_value : 0.0F; // TODO rewrite in terms of 'full' iterator - - for (int z=numerator.get_min_index(); z<=numerator.get_max_index(); z++) - for (int y=numerator[z].get_min_index(); y<=numerator[z].get_max_index(); y++) - for (int x=numerator[z][y].get_min_index(); x<=numerator[z][y].get_max_index(); x++) - { - - if(fabs(denominator[z][y][x])<=small_value && fabs(numerator[z][y][x])<=small_value) - { - numerator[z][y][x]=0; - } - else - numerator[z][y][x]/=denominator[z][y][x]; + + for (int z = numerator.get_min_index(); z <= numerator.get_max_index(); z++) + for (int y = numerator[z].get_min_index(); y <= numerator[z].get_max_index(); y++) + for (int x = numerator[z][y].get_min_index(); x <= numerator[z][y].get_max_index(); x++) { + + if (fabs(denominator[z][y][x]) <= small_value && fabs(numerator[z][y][x]) <= small_value) { + numerator[z][y][x] = 0; + } else + numerator[z][y][x] /= denominator[z][y][x]; } - } // MJ 03/01/2000 for loglikelihood computation // KT 21/05/2001 make sure it returns same result as divide_and_truncate above -void accumulate_loglikelihood(Viewgram& projection_data, - const Viewgram& estimated_projections, - const int rim_truncation_sino, - double* accum) -{ - - const int rs=projection_data.get_min_axial_pos_num(); - const int re=projection_data.get_max_axial_pos_num(); - const int bs=projection_data.get_min_tangential_pos_num(); - const int be=projection_data.get_max_tangential_pos_num(); +void +accumulate_loglikelihood(Viewgram& projection_data, const Viewgram& estimated_projections, + const int rim_truncation_sino, double* accum) { + + const int rs = projection_data.get_min_axial_pos_num(); + const int re = projection_data.get_max_axial_pos_num(); + const int bs = projection_data.get_min_tangential_pos_num(); + const int be = projection_data.get_max_tangential_pos_num(); /* note for implementation: First compute result for this viewgram in a local variable, @@ -366,85 +319,66 @@ void accumulate_loglikelihood(Viewgram& projection_data, accum would be no longer change because of the finite precision. */ double result = 0; - const float small_value= - max(projection_data.find_max()*SMALL_NUM, 0.F); + const float small_value = max(projection_data.find_max() * SMALL_NUM, 0.F); const float max_quotient = 10000.F; - for(int r=rs;r<=re;r++) - { - double sub_result=0; // use this for total result for this r, reducing numerical error - for(int b=bs;b<=be;b++) - if(!( - bbe-rim_truncation_sino )) - { - // if (estimated_projections[r][b] == 0) - // std::cerr << "Zero at " << r << ", " << b <<'\n'; - const float new_estimate = - max(estimated_projections[r][b], - projection_data[r][b]/max_quotient); - if (projection_data[r][b]<=small_value) - sub_result += - double(new_estimate); - else - sub_result += projection_data[r][b]*log(double(new_estimate)) - double(new_estimate); - } + for (int r = rs; r <= re; r++) { + double sub_result = 0; // use this for total result for this r, reducing numerical error + for (int b = bs; b <= be; b++) + if (!(b < bs + rim_truncation_sino || b > be - rim_truncation_sino)) { + // if (estimated_projections[r][b] == 0) + // std::cerr << "Zero at " << r << ", " << b <<'\n'; + const float new_estimate = max(estimated_projections[r][b], projection_data[r][b] / max_quotient); + if (projection_data[r][b] <= small_value) + sub_result += -double(new_estimate); + else + sub_result += projection_data[r][b] * log(double(new_estimate)) - double(new_estimate); + } result += sub_result; } *accum += result; } - - -void multiply_and_add(DiscretisedDensity<3,float> &image_res, const DiscretisedDensity<3,float> &image_scaled, float scalar) -{ +void +multiply_and_add(DiscretisedDensity<3, float>& image_res, const DiscretisedDensity<3, float>& image_scaled, float scalar) { assert(image_res.get_index_range() == image_scaled.get_index_range()); // TODO rewrite in terms of 'full' iterator - - for (int z=image_res.get_min_index(); z<=image_res.get_max_index(); z++) - for (int y=image_res[z].get_min_index(); y<=image_res[z].get_max_index(); y++) - for (int x=image_res[z][y].get_min_index(); x<=image_res[z][y].get_max_index(); x++) - { - image_res[z][y][x] += image_scaled[z][y][x] *scalar; - } + for (int z = image_res.get_min_index(); z <= image_res.get_max_index(); z++) + for (int y = image_res[z].get_min_index(); y <= image_res[z].get_max_index(); y++) + for (int x = image_res[z][y].get_min_index(); x <= image_res[z][y].get_max_index(); x++) { + image_res[z][y][x] += image_scaled[z][y][x] * scalar; + } } +// to be used with in_place_function +float +neg_trunc(float x) { - -//to be used with in_place_function -float neg_trunc(float x) -{ - - return (x<0.0F)?0.0F:x; - + return (x < 0.0F) ? 0.0F : x; } - - -void truncate_end_planes(DiscretisedDensity<3,float> &input_image, int input_num_planes) -{ +void +truncate_end_planes(DiscretisedDensity<3, float>& input_image, int input_num_planes) { // TODO this function does not make a lot of sense in general #ifndef NDEBUG // this will throw an exception when the cast is invalid - dynamic_cast&>(input_image); + dynamic_cast&>(input_image); #endif - const int zs=input_image.get_min_index(); - const int ze=input_image.get_max_index(); - - int upper_limit=(input_image.get_length() % 2 == 1)?input_image.get_length()/2+1:input_image.get_length()/2; + const int zs = input_image.get_min_index(); + const int ze = input_image.get_max_index(); - int num_planes=input_num_planes<=upper_limit?input_num_planes:upper_limit; - - for (int j=0;j scale_factors) -{ - const ProjDataInfo &proj_data_info = - dynamic_cast - (*scaled_scatter_proj_data.get_proj_data_info_sptr()); +Succeeded +scale_sinograms(ProjData& scaled_scatter_proj_data, const ProjData& scatter_proj_data, const Array<2, float> scale_factors) { + const ProjDataInfo& proj_data_info = dynamic_cast(*scaled_scatter_proj_data.get_proj_data_info_sptr()); Bin bin; - - for (bin.segment_num()=proj_data_info.get_min_segment_num(); - bin.segment_num()<=proj_data_info.get_max_segment_num(); - ++bin.segment_num()) - for (bin.axial_pos_num()= - proj_data_info.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num()<=proj_data_info.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - { - Sinogram scatter_sinogram = scatter_proj_data.get_sinogram( - bin.axial_pos_num(),bin.segment_num(),0); - Sinogram scaled_sinogram = - scatter_sinogram; - scaled_sinogram*=scale_factors[bin.segment_num()][bin.axial_pos_num()]; - - if (scaled_scatter_proj_data.set_sinogram(scaled_sinogram) == Succeeded::no) - return Succeeded::no; - } + + for (bin.segment_num() = proj_data_info.get_min_segment_num(); bin.segment_num() <= proj_data_info.get_max_segment_num(); + ++bin.segment_num()) + for (bin.axial_pos_num() = proj_data_info.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= proj_data_info.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) { + Sinogram scatter_sinogram = scatter_proj_data.get_sinogram(bin.axial_pos_num(), bin.segment_num(), 0); + Sinogram scaled_sinogram = scatter_sinogram; + scaled_sinogram *= scale_factors[bin.segment_num()][bin.axial_pos_num()]; + + if (scaled_scatter_proj_data.set_sinogram(scaled_sinogram) == Succeeded::no) + return Succeeded::no; + } return Succeeded::yes; } +Array<2, float> +get_scale_factors_per_sinogram(const ProjData& numerator_proj_data, const ProjData& denominator_proj_data, + const ProjData& weights_proj_data) { -Array<2,float> -get_scale_factors_per_sinogram(const ProjData& numerator_proj_data, - const ProjData& denominator_proj_data, - const ProjData& weights_proj_data) -{ - - const ProjDataInfo &proj_data_info = - dynamic_cast - (*weights_proj_data.get_proj_data_info_sptr()); + const ProjDataInfo& proj_data_info = dynamic_cast(*weights_proj_data.get_proj_data_info_sptr()); Bin bin; // scale factor to use when the denominator is zero const float default_scale = 1.F; - IndexRange2D sinogram_range(proj_data_info.get_min_segment_num(),proj_data_info.get_max_segment_num(),0,0); - for (int segment_num=proj_data_info.get_min_segment_num(); - segment_num<=proj_data_info.get_max_segment_num(); - ++segment_num) - { - sinogram_range[segment_num].resize( - proj_data_info.get_min_axial_pos_num(segment_num), - proj_data_info.get_max_axial_pos_num(segment_num) ); - } - Array<2,float> total_in_denominator(sinogram_range), - total_in_numerator(sinogram_range); - Array<2,float> scale_factors(sinogram_range); - for (bin.segment_num()=proj_data_info.get_min_segment_num(); - bin.segment_num()<=proj_data_info.get_max_segment_num(); - ++bin.segment_num()) - for (bin.axial_pos_num()= - proj_data_info.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num()<=proj_data_info.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - { - const Sinogram weights = - weights_proj_data.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - const Sinogram denominator_sinogram = - denominator_proj_data.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - const Array<2,float> weighted_denominator_sinogram = denominator_sinogram * weights; - const Array<2,float> weighted_numerator_sinogram = - numerator_proj_data.get_sinogram(bin.axial_pos_num(),bin.segment_num()) * weights; - total_in_denominator[bin.segment_num()][bin.axial_pos_num()] = weighted_denominator_sinogram.sum(); - total_in_numerator[bin.segment_num()][bin.axial_pos_num()] = weighted_numerator_sinogram.sum(); - - if (denominator_sinogram.sum()==0.f) - { - scale_factors[bin.segment_num()][bin.axial_pos_num()] = default_scale; - } - else - { - if (total_in_denominator[bin.segment_num()][bin.axial_pos_num()]<= - denominator_sinogram.sum()/ - (proj_data_info.get_num_views() * proj_data_info.get_num_tangential_poss()) * .001f - ) - { - warning("Problem at segment %d, axial pos %d in finding sinogram scaling factor.\n" - "Weighted data in denominator %g is very small compared to total in sinogram %g.\n" - "Adjust weights?.\n" - "I will use scale factor %g", - bin.segment_num(),bin.axial_pos_num(), - total_in_denominator[bin.segment_num()][bin.axial_pos_num()], - denominator_sinogram.sum(), - default_scale - ); - scale_factors[bin.segment_num()][bin.axial_pos_num()] = default_scale; - } - else - { - scale_factors[bin.segment_num()][bin.axial_pos_num()] = - total_in_numerator[bin.segment_num()][bin.axial_pos_num()]/ - total_in_denominator[bin.segment_num()][bin.axial_pos_num()]; - } - } + IndexRange2D sinogram_range(proj_data_info.get_min_segment_num(), proj_data_info.get_max_segment_num(), 0, 0); + for (int segment_num = proj_data_info.get_min_segment_num(); segment_num <= proj_data_info.get_max_segment_num(); + ++segment_num) { + sinogram_range[segment_num].resize(proj_data_info.get_min_axial_pos_num(segment_num), + proj_data_info.get_max_axial_pos_num(segment_num)); + } + Array<2, float> total_in_denominator(sinogram_range), total_in_numerator(sinogram_range); + Array<2, float> scale_factors(sinogram_range); + for (bin.segment_num() = proj_data_info.get_min_segment_num(); bin.segment_num() <= proj_data_info.get_max_segment_num(); + ++bin.segment_num()) + for (bin.axial_pos_num() = proj_data_info.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= proj_data_info.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) { + const Sinogram weights = weights_proj_data.get_sinogram(bin.axial_pos_num(), bin.segment_num()); + const Sinogram denominator_sinogram = denominator_proj_data.get_sinogram(bin.axial_pos_num(), bin.segment_num()); + const Array<2, float> weighted_denominator_sinogram = denominator_sinogram * weights; + const Array<2, float> weighted_numerator_sinogram = + numerator_proj_data.get_sinogram(bin.axial_pos_num(), bin.segment_num()) * weights; + total_in_denominator[bin.segment_num()][bin.axial_pos_num()] = weighted_denominator_sinogram.sum(); + total_in_numerator[bin.segment_num()][bin.axial_pos_num()] = weighted_numerator_sinogram.sum(); + + if (denominator_sinogram.sum() == 0.f) { + scale_factors[bin.segment_num()][bin.axial_pos_num()] = default_scale; + } else { + if (total_in_denominator[bin.segment_num()][bin.axial_pos_num()] <= + denominator_sinogram.sum() / (proj_data_info.get_num_views() * proj_data_info.get_num_tangential_poss()) * .001f) { + warning("Problem at segment %d, axial pos %d in finding sinogram scaling factor.\n" + "Weighted data in denominator %g is very small compared to total in sinogram %g.\n" + "Adjust weights?.\n" + "I will use scale factor %g", + bin.segment_num(), bin.axial_pos_num(), total_in_denominator[bin.segment_num()][bin.axial_pos_num()], + denominator_sinogram.sum(), default_scale); + scale_factors[bin.segment_num()][bin.axial_pos_num()] = default_scale; + } else { + scale_factors[bin.segment_num()][bin.axial_pos_num()] = total_in_numerator[bin.segment_num()][bin.axial_pos_num()] / + total_in_denominator[bin.segment_num()][bin.axial_pos_num()]; + } } - - return scale_factors; + } + + return scale_factors; } END_NAMESPACE_STIR - diff --git a/src/buildblock/utilities.cxx b/src/buildblock/utilities.cxx index 20420eb830..99fe921554 100644 --- a/src/buildblock/utilities.cxx +++ b/src/buildblock/utilities.cxx @@ -1,6 +1,6 @@ /*! - \file - + \file + \brief non-inline implementations for utility.h \author Kris Thielemans @@ -46,163 +46,140 @@ using std::string; START_NAMESPACE_STIR -bool -ask (const string& str, bool default_value) -{ +bool +ask(const string& str, bool default_value) { string input; - - while (true) - { - cerr << "\n" << str - << " [Y/N D:" - << (default_value ? 'Y' : 'N') - << "]: "; - std::getline(std::cin, input); - if (input.size()==0) - return default_value; - const char answer = input[0]; - switch (answer) - { - case 'N': - case 'n': - return false; - case 'Y': - case 'y': - return true; - default: - cerr << "\nPlease answer Y or N\n"; - } + + while (true) { + cerr << "\n" << str << " [Y/N D:" << (default_value ? 'Y' : 'N') << "]: "; + std::getline(std::cin, input); + if (input.size() == 0) + return default_value; + const char answer = input[0]; + switch (answer) { + case 'N': + case 'n': + return false; + case 'Y': + case 'y': + return true; + default: + cerr << "\nPlease answer Y or N\n"; + } } } - -string ask_string (const string& str, const string& default_value) -{ +string +ask_string(const string& str, const string& default_value) { string input; - - cerr << "\n" << str - << "\n[default_value : \"" - << default_value - << "\"]: \n"; + + cerr << "\n" << str << "\n[default_value : \"" << default_value << "\"]: \n"; std::getline(std::cin, input); - if (input.size()==0) + if (input.size() == 0) return default_value; else return input; } -FILE*& open_read_binary(FILE*& fptr, - const string& name) -{ - fptr = fopen(name.c_str(), "rb"); - if (ferror(fptr)) - { error("Error opening file %s\n", name.c_str()); } +FILE*& +open_read_binary(FILE*& fptr, const string& name) { + fptr = fopen(name.c_str(), "rb"); + if (ferror(fptr)) { + error("Error opening file %s\n", name.c_str()); + } return fptr; } -FILE*& open_write_binary(FILE*& fptr, - const string& name) -{ - fptr = fopen(name.c_str(), "wb"); - if (ferror(fptr)) - { error("Error opening file %s\n", name.c_str()); } +FILE*& +open_write_binary(FILE*& fptr, const string& name) { + fptr = fopen(name.c_str(), "wb"); + if (ferror(fptr)) { + error("Error opening file %s\n", name.c_str()); + } return fptr; } -void close_file(FILE*& fptr) -{ +void +close_file(FILE*& fptr) { fclose(fptr); - fptr=0; + fptr = 0; } -const char * -find_filename(const char * const filename_with_directory) -{ - const char * name; +const char* +find_filename(const char* const filename_with_directory) { + const char* name; #if defined(__OS_VAX__) - name = strrchr(filename_with_directory,']'); - if (name==NULL) - name = strrchr(filename_with_directory,':'); + name = strrchr(filename_with_directory, ']'); + if (name == NULL) + name = strrchr(filename_with_directory, ':'); #elif defined(__OS_WIN__) - name = strrchr(filename_with_directory,'\\'); - if (name==NULL) - name = strrchr(filename_with_directory,'/'); - if (name==NULL) - name = strrchr(filename_with_directory,':'); + name = strrchr(filename_with_directory, '\\'); + if (name == NULL) + name = strrchr(filename_with_directory, '/'); + if (name == NULL) + name = strrchr(filename_with_directory, ':'); #elif defined(__OS_MAC__) - name = strrchr(filename_with_directory,':'); + name = strrchr(filename_with_directory, ':'); #else // defined(__OS_UNIX__) - name = strrchr(filename_with_directory,'/'); -#endif - if (name!=NULL) - // KT 10/01/2000 name++ changed to name+1 - return name+1; - else - return filename_with_directory; + name = strrchr(filename_with_directory, '/'); +#endif + if (name != NULL) + // KT 10/01/2000 name++ changed to name+1 + return name + 1; + else + return filename_with_directory; } string::size_type -find_pos_of_filename(const string& filename_with_directory) -{ +find_pos_of_filename(const string& filename_with_directory) { string::size_type pos; #if defined(__OS_VAX__) - pos = filename_with_directory.find_last_of( ']'); - if (pos==string::npos) - pos = filename_with_directory.find_last_of( ':'); + pos = filename_with_directory.find_last_of(']'); + if (pos == string::npos) + pos = filename_with_directory.find_last_of(':'); #elif defined(__OS_WIN__) - pos = filename_with_directory.find_last_of( '\\'); - if (pos==string::npos) - pos = filename_with_directory.find_last_of( '/'); - if (pos==string::npos) - pos = filename_with_directory.find_last_of( ':'); + pos = filename_with_directory.find_last_of('\\'); + if (pos == string::npos) + pos = filename_with_directory.find_last_of('/'); + if (pos == string::npos) + pos = filename_with_directory.find_last_of(':'); #elif defined(__OS_MAC__) - pos = filename_with_directory.find_last_of( ':'); + pos = filename_with_directory.find_last_of(':'); #else // defined(__OS_UNIX__) - pos = filename_with_directory.find_last_of( '/'); -#endif + pos = filename_with_directory.find_last_of('/'); +#endif if (pos != string::npos) - return pos+1; + return pos + 1; else return 0; } - string -get_filename(const string& filename_with_directory) -{ - return - filename_with_directory.substr(find_pos_of_filename(filename_with_directory)); +get_filename(const string& filename_with_directory) { + return filename_with_directory.substr(find_pos_of_filename(filename_with_directory)); } -char * -get_directory_name(char *directory_name, - const char * const filename_with_directory) -{ - size_t num_chars_in_directory_name = - find_filename(filename_with_directory) - filename_with_directory; +char* +get_directory_name(char* directory_name, const char* const filename_with_directory) { + size_t num_chars_in_directory_name = find_filename(filename_with_directory) - filename_with_directory; strncpy(directory_name, filename_with_directory, num_chars_in_directory_name); directory_name[num_chars_in_directory_name] = '\0'; return directory_name; } string -get_directory_name(const string& filename_with_directory) -{ - string dir_name = - filename_with_directory.substr(0, find_pos_of_filename(filename_with_directory)); +get_directory_name(const string& filename_with_directory) { + string dir_name = filename_with_directory.substr(0, find_pos_of_filename(filename_with_directory)); if (dir_name.empty()) dir_name = "."; return dir_name; } string::size_type -find_pos_of_extension(const string& file_in_directory_name) -{ - string::size_type pos_of_dot = - file_in_directory_name.find_last_of('.'); - string::size_type pos_of_filename = - find_pos_of_filename(file_in_directory_name); +find_pos_of_extension(const string& file_in_directory_name) { + string::size_type pos_of_dot = file_in_directory_name.find_last_of('.'); + string::size_type pos_of_filename = find_pos_of_filename(file_in_directory_name); if (pos_of_dot >= pos_of_filename) return pos_of_dot; else @@ -222,19 +199,14 @@ char *add_extension(char *file_in_directory_name, } #endif -string& -add_extension(string& file_in_directory_name, - const string& extension) -{ - string::size_type pos = - find_pos_of_extension(file_in_directory_name); +string& +add_extension(string& file_in_directory_name, const string& extension) { + string::size_type pos = find_pos_of_extension(file_in_directory_name); if (pos == string::npos) file_in_directory_name += extension; return file_in_directory_name; } - - #if 0 // terribly dangerous for memory overrun. // will only work if new extension is shorter than old @@ -253,43 +225,35 @@ char *replace_extension(char *file_in_directory_name, } #endif -string& -replace_extension(string& file_in_directory_name, - const string& extension) -{ - string::size_type pos = - find_pos_of_extension(file_in_directory_name); +string& +replace_extension(string& file_in_directory_name, const string& extension) { + string::size_type pos = find_pos_of_extension(file_in_directory_name); if (pos != string::npos) file_in_directory_name.erase(pos); file_in_directory_name += extension; - + return file_in_directory_name; } bool -is_absolute_pathname(const char * const filename_with_directory) -{ +is_absolute_pathname(const char* const filename_with_directory) { #if defined(__OS_VAX__) // relative names either contain no '[', or have '[.' - const char * const ptr = strchr(filename_with_directory,'['); - if (ptr==NULL) + const char* const ptr = strchr(filename_with_directory, '['); + if (ptr == NULL) return false; else - return *(ptr+1) != '.'; + return *(ptr + 1) != '.'; #elif defined(__OS_WIN__) // relative names do not start with '\' or '?:\' - if (filename_with_directory[0] == '\\' || - filename_with_directory[0] == '/') + if (filename_with_directory[0] == '\\' || filename_with_directory[0] == '/') return true; else - return (strlen(filename_with_directory)>3 && - filename_with_directory[1] == ':' && - (filename_with_directory[2] == '\\' || - filename_with_directory[2] == '/') - ); + return (strlen(filename_with_directory) > 3 && filename_with_directory[1] == ':' && + (filename_with_directory[2] == '\\' || filename_with_directory[2] == '/')); #elif defined(__OS_MAC__) // relative names either have no ':' or do not start with ':' - const char * const ptr = strchr(filename_with_directory,':'); + const char* const ptr = strchr(filename_with_directory, ':'); if (ptr == NULL) return false; else @@ -297,48 +261,37 @@ is_absolute_pathname(const char * const filename_with_directory) #else // defined(__OS_UNIX__) // absolute names start with '/' return filename_with_directory[0] == '/'; -#endif +#endif } bool -is_absolute_pathname(const string& filename_with_directory) -{ - return - is_absolute_pathname(filename_with_directory.c_str()); +is_absolute_pathname(const string& filename_with_directory) { + return is_absolute_pathname(filename_with_directory.c_str()); } -// Warning: this function assumes that filename_with_directory +// Warning: this function assumes that filename_with_directory // points to sufficient allocated space to contain the new string -char * -prepend_directory_name(char * filename_with_directory, - const char * const directory_name) -{ - if (is_absolute_pathname(filename_with_directory) || - directory_name == 0 || - strlen(directory_name) == 0) +char* +prepend_directory_name(char* filename_with_directory, const char* const directory_name) { + if (is_absolute_pathname(filename_with_directory) || directory_name == 0 || strlen(directory_name) == 0) return filename_with_directory; - char * new_name = - new char[strlen(filename_with_directory) + strlen(directory_name) + 4]; + char* new_name = new char[strlen(filename_with_directory) + strlen(directory_name) + 4]; strcpy(new_name, directory_name); - char * end_of_new_name = new_name + strlen(directory_name)-1; - + char* end_of_new_name = new_name + strlen(directory_name) - 1; #if defined(__OS_VAX__) // relative names either contain no '[', or have '[.' - if (filename_with_directory[0] != '[' || - *end_of_new_name != ']') + if (filename_with_directory[0] != '[' || *end_of_new_name != ']') strcat(new_name, filename_with_directory); - else - { + else { // peel of the ][ pair *end_of_new_name = '\0'; - strcat(new_name, filename_with_directory+1); + strcat(new_name, filename_with_directory + 1); } #elif defined(__OS_WIN__) // append \ if necessary - if (*end_of_new_name != ':' && *end_of_new_name != '\\' && - *end_of_new_name != '/') + if (*end_of_new_name != ':' && *end_of_new_name != '\\' && *end_of_new_name != '/') strcat(new_name, "\\"); strcat(new_name, filename_with_directory); #elif defined(__OS_MAC__) @@ -348,7 +301,7 @@ prepend_directory_name(char * filename_with_directory, strcat(new_name, ":"); // do not copy starting ':' of filename if (filename_with_directory[0] == ':') - strcat(new_name, filename_with_directory+1); + strcat(new_name, filename_with_directory + 1); else strcat(new_name, filename_with_directory); #else // defined(__OS_UNIX__) @@ -356,7 +309,7 @@ prepend_directory_name(char * filename_with_directory, if (*end_of_new_name != '/') strcat(new_name, "/"); strcat(new_name, filename_with_directory); -#endif +#endif strcpy(filename_with_directory, new_name); delete[] new_name; @@ -364,122 +317,91 @@ prepend_directory_name(char * filename_with_directory, } string -ask_filename_with_extension( - const string& prompt, - const string& default_extension) -{ +ask_filename_with_extension(const string& prompt, const string& default_extension) { string file_in_directory_name; - while (file_in_directory_name.size()==0) - { + while (file_in_directory_name.size() == 0) { cerr << prompt; - if (default_extension.size()!=0) - { - cerr << "(default extension '" - << default_extension - << "'):"; - } + if (default_extension.size() != 0) { + cerr << "(default extension '" << default_extension << "'):"; + } std::getline(std::cin, file_in_directory_name); } - add_extension(file_in_directory_name,default_extension); - return(file_in_directory_name); + add_extension(file_in_directory_name, default_extension); + return (file_in_directory_name); } -char * -ask_filename_with_extension(char *file_in_directory_name, - const string& prompt, - const string& default_extension) -{ - const string answer = - ask_filename_with_extension(prompt, default_extension); +char* +ask_filename_with_extension(char* file_in_directory_name, const string& prompt, const string& default_extension) { + const string answer = ask_filename_with_extension(prompt, default_extension); strcpy(file_in_directory_name, answer.c_str()); - return(file_in_directory_name); + return (file_in_directory_name); } template void -ask_filename_and_open(FSTREAM& s, - const string& prompt, - const string& default_extension, - ios::openmode mode, - bool abort_if_failed) -{ - string filename = - ask_filename_with_extension(prompt, default_extension); - s.open( - filename.c_str(), - mode); - if (abort_if_failed && !s) - { error("Error opening file %s\n", filename.c_str()); } +ask_filename_and_open(FSTREAM& s, const string& prompt, const string& default_extension, ios::openmode mode, + bool abort_if_failed) { + string filename = ask_filename_with_extension(prompt, default_extension); + s.open(filename.c_str(), mode); + if (abort_if_failed && !s) { + error("Error opening file %s\n", filename.c_str()); + } } // instantiations -template -void -ask_filename_and_open(ifstream& s, - const string& prompt, - const string& default_extension, - ios::openmode mode, - bool abort_if_failed); -template -void -ask_filename_and_open(ofstream& s, - const string& prompt, - const string& default_extension, - ios::openmode mode, - bool abort_if_failed); -template -void -ask_filename_and_open(fstream& s, - const string& prompt, - const string& default_extension, - ios::openmode mode, - bool abort_if_failed); +template void ask_filename_and_open(ifstream& s, const string& prompt, const string& default_extension, ios::openmode mode, + bool abort_if_failed); +template void ask_filename_and_open(ofstream& s, const string& prompt, const string& default_extension, ios::openmode mode, + bool abort_if_failed); +template void ask_filename_and_open(fstream& s, const string& prompt, const string& default_extension, ios::openmode mode, + bool abort_if_failed); // find number of remaining characters -streamsize find_remaining_size (istream& input) -{ - streampos file_current_pos = input.tellg(); - input.seekg(0L, ios::end); - streampos file_end = input.tellg(); - input.clear(); // necessary because seek past EOF ? - input.seekg(file_current_pos); - return file_end - file_current_pos; +streamsize +find_remaining_size(istream& input) { + streampos file_current_pos = input.tellg(); + input.seekg(0L, ios::end); + streampos file_end = input.tellg(); + input.clear(); // necessary because seek past EOF ? + input.seekg(file_current_pos); + return file_end - file_current_pos; } -void * read_stream_in_memory(istream& input, streamsize& file_size) -{ +void* +read_stream_in_memory(istream& input, streamsize& file_size) { if (file_size == 0) file_size = find_remaining_size(input); - - cerr << "Reading " << file_size << " bytes from file." <(file_size)]; - if (memory == 0) - { error("Not enough memory\n"); } + char* memory = new char[static_cast(file_size)]; + if (memory == 0) { + error("Not enough memory\n"); + } { - const streamsize chunk_size = 1024*64; + const streamsize chunk_size = 1024 * 64; streamsize to_read = file_size; - char *current_location = memory; + char* current_location = memory; - while( to_read != 0) - { - const streamsize this_read_size = + while (to_read != 0) { + const streamsize this_read_size = #ifndef STIR_NO_NAMESPACES - std::min(to_read, chunk_size); + std::min(to_read, chunk_size); #else - min(to_read, chunk_size); + min(to_read, chunk_size); #endif - input.read(current_location, this_read_size); - if (!input) - { error("Error after reading from stream"); } - - to_read -= this_read_size; - current_location += this_read_size; + input.read(current_location, this_read_size); + if (!input) { + error("Error after reading from stream"); } + + to_read -= this_read_size; + current_location += this_read_size; + } } return memory; } diff --git a/src/buildblock/warning.cxx b/src/buildblock/warning.cxx index 162fcfc3ae..ce85eea18d 100644 --- a/src/buildblock/warning.cxx +++ b/src/buildblock/warning.cxx @@ -1,8 +1,8 @@ // // /*! - \file - + \file + \brief defines the stir::warning() function \author Kris Thielemans @@ -40,28 +40,26 @@ Visual Studio can be accomodated with the following work-around */ #ifdef BOOST_MSVC -#define vsnprintf _vsnprintf +# define vsnprintf _vsnprintf #endif START_NAMESPACE_STIR -void warning(const char *const s, ...) -{ +void +warning(const char* const s, ...) { va_list ap; va_start(ap, s); - const unsigned size=10000; + const unsigned size = 10000; char tmp[size]; - const int returned_size= vsnprintf(tmp,size, s, ap); + const int returned_size = vsnprintf(tmp, size, s, ap); std::stringstream ss; va_end(ap); if (returned_size < 0) - ss << "\nWARNING: error formatting warning message" << std::endl; - else - { - ss << "\nWARNING: " << tmp << std::endl; - if (static_cast(returned_size)>=size) - ss << "\nWARNING: previous warning message truncated as it exceeds " - << size << "bytes" << std::endl; + ss << "\nWARNING: error formatting warning message" << std::endl; + else { + ss << "\nWARNING: " << tmp << std::endl; + if (static_cast(returned_size) >= size) + ss << "\nWARNING: previous warning message truncated as it exceeds " << size << "bytes" << std::endl; } writeText(ss.str().c_str(), WARNING_CHANNEL); } diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index 2b20acbace..fa90665cff 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -17,7 +17,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup buildblock \brief Implementations of the stir::zoom functions @@ -36,13 +36,13 @@ - KT introduced 3D zooming for images. - KT converted to new design */ - + #include "stir/interpolate.h" #include "stir/zoom.h" #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" -#include "stir/VoxelsOnCartesianGrid.h" -#include "stir/PixelsOnCartesianGrid.h" +#include "stir/VoxelsOnCartesianGrid.h" +#include "stir/PixelsOnCartesianGrid.h" #include "stir/Viewgram.h" #include "stir/RelatedViewgrams.h" #include "stir/ProjDataInfoCylindricalArcCorr.h" @@ -99,195 +99,150 @@ void zoom_segment (SegmentByView& segment, segment = out_segment; } - #endif void -zoom_viewgrams (RelatedViewgrams& in_viewgrams, - const float zoom, - const int min_tang_pos_num, const int max_tang_pos_num, - const float x_offset_in_mm, const float y_offset_in_mm) -{ +zoom_viewgrams(RelatedViewgrams& in_viewgrams, const float zoom, const int min_tang_pos_num, const int max_tang_pos_num, + const float x_offset_in_mm, const float y_offset_in_mm) { if (min_tang_pos_num == in_viewgrams.get_min_tangential_pos_num() && - max_tang_pos_num == in_viewgrams.get_max_tangential_pos_num() && - zoom == 1.0 && x_offset_in_mm == 0.0 && y_offset_in_mm == 0.0) + max_tang_pos_num == in_viewgrams.get_max_tangential_pos_num() && zoom == 1.0 && x_offset_in_mm == 0.0 && + y_offset_in_mm == 0.0) return; - - shared_ptr - new_proj_data_info_sptr(in_viewgrams.get_proj_data_info_sptr()->clone()); + + shared_ptr new_proj_data_info_sptr(in_viewgrams.get_proj_data_info_sptr()->clone()); ProjDataInfoCylindricalArcCorr* new_proj_data_info_arccorr_sptr = - dynamic_cast(new_proj_data_info_sptr.get()); + dynamic_cast(new_proj_data_info_sptr.get()); - if ( new_proj_data_info_arccorr_sptr==0) + if (new_proj_data_info_arccorr_sptr == 0) error("zoom_viewgram does not support non-arccorrected data. Sorry\n"); - + new_proj_data_info_arccorr_sptr->set_min_tangential_pos_num(min_tang_pos_num); new_proj_data_info_arccorr_sptr->set_max_tangential_pos_num(max_tang_pos_num); - - new_proj_data_info_arccorr_sptr-> - set_tangential_sampling(new_proj_data_info_arccorr_sptr-> - get_tangential_sampling() / zoom); - shared_ptr - symmetries_sptr(in_viewgrams.get_symmetries_ptr()->clone()); + new_proj_data_info_arccorr_sptr->set_tangential_sampling(new_proj_data_info_arccorr_sptr->get_tangential_sampling() / zoom); - RelatedViewgrams - out_viewgrams = - new_proj_data_info_arccorr_sptr-> - get_empty_related_viewgrams(in_viewgrams.get_basic_view_segment_num(), - symmetries_sptr); + shared_ptr symmetries_sptr(in_viewgrams.get_symmetries_ptr()->clone()); + + RelatedViewgrams out_viewgrams = new_proj_data_info_arccorr_sptr->get_empty_related_viewgrams( + in_viewgrams.get_basic_view_segment_num(), symmetries_sptr, false, in_viewgrams.get_basic_timing_pos_num()); { RelatedViewgrams::iterator out_iter = out_viewgrams.begin(); RelatedViewgrams::const_iterator in_iter = in_viewgrams.begin(); for (; out_iter != out_viewgrams.end(); ++out_iter, ++in_iter) - zoom_viewgram(*out_iter, *in_iter, - x_offset_in_mm, y_offset_in_mm); + zoom_viewgram(*out_iter, *in_iter, x_offset_in_mm, y_offset_in_mm); } in_viewgrams = out_viewgrams; } void -zoom_viewgram (Viewgram& in_view, - const float zoom, - const int min_tang_pos_num, const int max_tang_pos_num, - const float x_offset_in_mm, const float y_offset_in_mm) -{ - if (min_tang_pos_num == in_view.get_min_tangential_pos_num() && - max_tang_pos_num == in_view.get_max_tangential_pos_num() && - zoom == 1.0 && x_offset_in_mm == 0.0 && y_offset_in_mm == 0.0) +zoom_viewgram(Viewgram& in_view, const float zoom, const int min_tang_pos_num, const int max_tang_pos_num, + const float x_offset_in_mm, const float y_offset_in_mm) { + if (min_tang_pos_num == in_view.get_min_tangential_pos_num() && max_tang_pos_num == in_view.get_max_tangential_pos_num() && + zoom == 1.0 && x_offset_in_mm == 0.0 && y_offset_in_mm == 0.0) return; - - shared_ptr - new_proj_data_info_sptr(in_view.get_proj_data_info_sptr()->clone()); + + shared_ptr new_proj_data_info_sptr(in_view.get_proj_data_info_sptr()->clone()); ProjDataInfoCylindricalArcCorr* new_proj_data_info_arccorr_sptr = - dynamic_cast(new_proj_data_info_sptr.get()); + dynamic_cast(new_proj_data_info_sptr.get()); - if ( new_proj_data_info_arccorr_sptr==0) + if (new_proj_data_info_arccorr_sptr == 0) error("zoom_viewgram does not support non-arccorrected data. Sorry\n"); - + new_proj_data_info_arccorr_sptr->set_min_tangential_pos_num(min_tang_pos_num); new_proj_data_info_arccorr_sptr->set_max_tangential_pos_num(max_tang_pos_num); - - new_proj_data_info_arccorr_sptr-> - set_tangential_sampling(new_proj_data_info_arccorr_sptr-> - get_tangential_sampling() / zoom); - Viewgram - out_view = new_proj_data_info_arccorr_sptr-> - get_empty_viewgram( - in_view.get_view_num(), - in_view.get_segment_num()); + new_proj_data_info_arccorr_sptr->set_tangential_sampling(new_proj_data_info_arccorr_sptr->get_tangential_sampling() / zoom); + + Viewgram out_view = new_proj_data_info_arccorr_sptr->get_empty_viewgram( + in_view.get_view_num(), in_view.get_segment_num(), false, in_view.get_timing_pos_num()); - zoom_viewgram(out_view, in_view, - x_offset_in_mm, y_offset_in_mm); + zoom_viewgram(out_view, in_view, x_offset_in_mm, y_offset_in_mm); in_view = out_view; } void -zoom_viewgram (Viewgram& out_view, - const Viewgram& in_view, - const float x_offset_in_mm, const float y_offset_in_mm) -{ +zoom_viewgram(Viewgram& out_view, const Viewgram& in_view, const float x_offset_in_mm, const float y_offset_in_mm) { // minimal checks on compatibility - assert(in_view.get_proj_data_info_sptr()->get_num_views() == - out_view.get_proj_data_info_sptr()->get_num_views()); + assert(in_view.get_proj_data_info_sptr()->get_num_views() == out_view.get_proj_data_info_sptr()->get_num_views()); assert(in_view.get_view_num() == out_view.get_view_num()); - assert(in_view.get_proj_data_info_sptr()->get_num_segments() == - out_view.get_proj_data_info_sptr()->get_num_segments()); + assert(in_view.get_proj_data_info_sptr()->get_num_segments() == out_view.get_proj_data_info_sptr()->get_num_segments()); assert(in_view.get_segment_num() == out_view.get_segment_num()); + assert(in_view.get_proj_data_info_sptr()->get_num_tof_poss() == out_view.get_proj_data_info_sptr()->get_num_tof_poss()); + assert(in_view.get_timing_pos_num() == out_view.get_timing_pos_num()); assert(in_view.get_min_axial_pos_num() == out_view.get_min_axial_pos_num()); assert(in_view.get_max_axial_pos_num() == out_view.get_max_axial_pos_num()); // get the pointers to the arc-corrected ProjDataInfo const shared_ptr in_proj_data_info_arccorr_sptr = - dynamic_pointer_cast(in_view.get_proj_data_info_sptr()); + dynamic_pointer_cast(in_view.get_proj_data_info_sptr()); const shared_ptr out_proj_data_info_arccorr_sptr = - dynamic_pointer_cast(out_view.get_proj_data_info_sptr()); + dynamic_pointer_cast(out_view.get_proj_data_info_sptr()); - if (is_null_ptr(in_proj_data_info_arccorr_sptr) || - is_null_ptr(out_proj_data_info_arccorr_sptr)) + if (is_null_ptr(in_proj_data_info_arccorr_sptr) || is_null_ptr(out_proj_data_info_arccorr_sptr)) error("zoom_viewgram does not support non-arccorrected data. Sorry\n"); - - const float in_bin_size = - in_proj_data_info_arccorr_sptr->get_tangential_sampling(); - const float out_bin_size = - out_proj_data_info_arccorr_sptr->get_tangential_sampling(); + const float in_bin_size = in_proj_data_info_arccorr_sptr->get_tangential_sampling(); + const float out_bin_size = out_proj_data_info_arccorr_sptr->get_tangential_sampling(); const float zoom = in_bin_size / out_bin_size; if (out_view.get_min_tangential_pos_num() == in_view.get_min_tangential_pos_num() && - out_view.get_max_tangential_pos_num() == in_view.get_max_tangential_pos_num() && - zoom == 1.0F && x_offset_in_mm == 0.0F && y_offset_in_mm == 0.0F) + out_view.get_max_tangential_pos_num() == in_view.get_max_tangential_pos_num() && zoom == 1.0F && x_offset_in_mm == 0.0F && + y_offset_in_mm == 0.0F) return; - - const float phi = - in_proj_data_info_arccorr_sptr-> - get_phi(Bin(in_view.get_segment_num(), in_view.get_view_num(), 0,0)); + + const float phi = in_proj_data_info_arccorr_sptr->get_phi(Bin(in_view.get_segment_num(), in_view.get_view_num(), 0, 0)); // compute offset in tangential_sampling_in units - const float offset = - (x_offset_in_mm*cos(phi) +y_offset_in_mm*sin(phi))/ in_bin_size; + const float offset = (x_offset_in_mm * cos(phi) + y_offset_in_mm * sin(phi)) / in_bin_size; - for (int axial_pos_num= out_view.get_min_axial_pos_num(); axial_pos_num <= out_view.get_max_axial_pos_num(); ++axial_pos_num) - { - overlap_interpolate(out_view[axial_pos_num], in_view[axial_pos_num], zoom, offset); - } + for (int axial_pos_num = out_view.get_min_axial_pos_num(); axial_pos_num <= out_view.get_max_axial_pos_num(); ++axial_pos_num) { + overlap_interpolate(out_view[axial_pos_num], in_view[axial_pos_num], zoom, offset); + } } - - - -static -VoxelsOnCartesianGrid -construct_new_image_from_zoom_parameters(const VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& offsets_in_mm, - const BasicCoordinate<3,int>& new_sizes_arg) -{ +static VoxelsOnCartesianGrid +construct_new_image_from_zoom_parameters(const VoxelsOnCartesianGrid& image, const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& offsets_in_mm, + const BasicCoordinate<3, int>& new_sizes_arg) { CartesianCoordinate3D new_sizes = new_sizes_arg; - assert(new_sizes.x()>=0); - assert(new_sizes.y()>=0); - assert(new_sizes.z()>=0); - CartesianCoordinate3D - voxel_size = image.get_grid_spacing() / zooms; + assert(new_sizes.x() >= 0); + assert(new_sizes.y() >= 0); + assert(new_sizes.z() >= 0); + CartesianCoordinate3D voxel_size = image.get_grid_spacing() / zooms; // first set origin to 0 - CartesianCoordinate3D - origin(0.F,0.F,0.F); - - VoxelsOnCartesianGrid - new_image(image.get_exam_info_sptr(), - IndexRange3D(0, new_sizes.z()-1, - -new_sizes.y()/2, -new_sizes.y()/2+new_sizes.y()-1, - -new_sizes.x()/2, -new_sizes.x()/2+new_sizes.x()-1), - origin, - voxel_size); + CartesianCoordinate3D origin(0.F, 0.F, 0.F); + + VoxelsOnCartesianGrid new_image(image.get_exam_info_sptr(), + IndexRange3D(0, new_sizes.z() - 1, -new_sizes.y() / 2, + -new_sizes.y() / 2 + new_sizes.y() - 1, -new_sizes.x() / 2, + -new_sizes.x() / 2 + new_sizes.x() - 1), + origin, voxel_size); // find coordinates of middle of images - BasicCoordinate<3,int> min_indices, max_indices; + BasicCoordinate<3, int> min_indices, max_indices; if (!image.get_regular_range(min_indices, max_indices)) error("zoom_image: Non-regular range of coordinates in input image. That's strange."); - BasicCoordinate<3,int> new_min_indices, new_max_indices; + BasicCoordinate<3, int> new_min_indices, new_max_indices; if (!new_image.get_regular_range(new_min_indices, new_max_indices)) error("zoom_image: Non-regular range of coordinates in output image. That's a bug."); - const BasicCoordinate<3,float> middle = - (image.get_physical_coordinates_for_indices(min_indices) + - image.get_physical_coordinates_for_indices(max_indices))/2; - const BasicCoordinate<3,float> new_middle = - (new_image.get_physical_coordinates_for_indices(new_min_indices) + - new_image.get_physical_coordinates_for_indices(new_max_indices))/2; + const BasicCoordinate<3, float> middle = + (image.get_physical_coordinates_for_indices(min_indices) + image.get_physical_coordinates_for_indices(max_indices)) / 2; + const BasicCoordinate<3, float> new_middle = (new_image.get_physical_coordinates_for_indices(new_min_indices) + + new_image.get_physical_coordinates_for_indices(new_max_indices)) / + 2; // now make sure that these are shifted as required new_image.set_origin(offsets_in_mm + middle - new_middle); // check { - const BasicCoordinate<3,float> final_middle = - (new_image.get_physical_coordinates_for_indices(new_min_indices) + - new_image.get_physical_coordinates_for_indices(new_max_indices))/2; + const BasicCoordinate<3, float> final_middle = (new_image.get_physical_coordinates_for_indices(new_min_indices) + + new_image.get_physical_coordinates_for_indices(new_max_indices)) / + 2; if (norm(final_middle - middle - offsets_in_mm) > 1) error("zoom_image bug in finding new origin"); } @@ -295,155 +250,109 @@ construct_new_image_from_zoom_parameters(const VoxelsOnCartesianGrid &ima return new_image; } void -zoom_image_in_place(VoxelsOnCartesianGrid &image, - const float zoom, - const float x_offset_in_mm, const float y_offset_in_mm, - const int new_size, - const ZoomOptions zoom_options) -{ - VoxelsOnCartesianGrid new_image = - zoom_image(image, zoom, x_offset_in_mm, y_offset_in_mm, new_size, zoom_options); +zoom_image_in_place(VoxelsOnCartesianGrid& image, const float zoom, const float x_offset_in_mm, const float y_offset_in_mm, + const int new_size, const ZoomOptions zoom_options) { + VoxelsOnCartesianGrid new_image = zoom_image(image, zoom, x_offset_in_mm, y_offset_in_mm, new_size, zoom_options); image = new_image; } VoxelsOnCartesianGrid -zoom_image(const VoxelsOnCartesianGrid &image, - const float zoom, - const float x_offset_in_mm, const float y_offset_in_mm, - const int new_size, - const ZoomOptions zoom_options) -{ - assert(new_size>=0); - if(zoom==1 && x_offset_in_mm==0 && y_offset_in_mm==0 && new_size== image.get_x_size()) +zoom_image(const VoxelsOnCartesianGrid& image, const float zoom, const float x_offset_in_mm, const float y_offset_in_mm, + const int new_size, const ZoomOptions zoom_options) { + assert(new_size >= 0); + if (zoom == 1 && x_offset_in_mm == 0 && y_offset_in_mm == 0 && new_size == image.get_x_size()) return image; - - const CartesianCoordinate3D zooms(1,zoom,zoom); + + const CartesianCoordinate3D zooms(1, zoom, zoom); const CartesianCoordinate3D offsets_in_mm(0.F, y_offset_in_mm, x_offset_in_mm); - const BasicCoordinate<3,int> new_sizes = - make_coordinate(image.get_length(), new_size, new_size); - - VoxelsOnCartesianGrid new_image = - construct_new_image_from_zoom_parameters(image, - zooms, - offsets_in_mm, - new_sizes); - - PixelsOnCartesianGrid - new_image2D = new_image.get_plane(new_image.get_min_z()); - for (int plane = image.get_min_z(); plane <= image.get_max_z(); plane++) - { - zoom_image(new_image2D, image.get_plane(plane), zoom_options); - new_image.set_plane(new_image2D, plane); - } - - assert(norm(new_image.get_voxel_size() - image.get_voxel_size()/zooms)<1); + const BasicCoordinate<3, int> new_sizes = make_coordinate(image.get_length(), new_size, new_size); + + VoxelsOnCartesianGrid new_image = construct_new_image_from_zoom_parameters(image, zooms, offsets_in_mm, new_sizes); + + PixelsOnCartesianGrid new_image2D = new_image.get_plane(new_image.get_min_z()); + for (int plane = image.get_min_z(); plane <= image.get_max_z(); plane++) { + zoom_image(new_image2D, image.get_plane(plane), zoom_options); + new_image.set_plane(new_image2D, plane); + } + + assert(norm(new_image.get_voxel_size() - image.get_voxel_size() / zooms) < 1); return new_image; } void -zoom_image_in_place(VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& offsets_in_mm, - const BasicCoordinate<3,int>& new_sizes, - const ZoomOptions zoom_options) -{ - const VoxelsOnCartesianGrid new_image = - zoom_image(image, zooms, offsets_in_mm, new_sizes, zoom_options); +zoom_image_in_place(VoxelsOnCartesianGrid& image, const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& offsets_in_mm, const BasicCoordinate<3, int>& new_sizes, + const ZoomOptions zoom_options) { + const VoxelsOnCartesianGrid new_image = zoom_image(image, zooms, offsets_in_mm, new_sizes, zoom_options); image = new_image; } VoxelsOnCartesianGrid -zoom_image(const VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& offsets_in_mm, - const BasicCoordinate<3,int>& new_sizes, - const ZoomOptions zoom_options) -{ +zoom_image(const VoxelsOnCartesianGrid& image, const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& offsets_in_mm, const BasicCoordinate<3, int>& new_sizes, + const ZoomOptions zoom_options) { - VoxelsOnCartesianGrid new_image = - construct_new_image_from_zoom_parameters(image, - zooms, - offsets_in_mm, - new_sizes); + VoxelsOnCartesianGrid new_image = construct_new_image_from_zoom_parameters(image, zooms, offsets_in_mm, new_sizes); zoom_image(new_image, image, zoom_options); return new_image; } -void -zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, - const ZoomOptions zoom_options) -{ +void +zoom_image(VoxelsOnCartesianGrid& image_out, const VoxelsOnCartesianGrid& image_in, + const ZoomOptions zoom_options) { image_out.set_exam_info(image_in.get_exam_info()); -/* - interpolation routine uses the following relation: - x_in_index = x_out_index/zoom + offset - - compare to 'physical' coordinates - x_phys = (x_index) * voxel_size.x + origin.x - - as x_in_phys == x_out_phys, we find - (x_in_index)* voxel_size_in.x + origin_in.x == - (x_out_index )* voxel_size_out.x + origin_out.x - <=> - x_in_index = (x_out_index * voxel_size_out.x - + origin_out.x - origin_in.x) - / voxel_size_in.x - - so, zoom= voxel_size_in.x/ voxel_size_out.x - offset = (origin_out.x - origin_in.x)/ voxel_size_in.x + /* + interpolation routine uses the following relation: + x_in_index = x_out_index/zoom + offset - */ + compare to 'physical' coordinates + x_phys = (x_index) * voxel_size.x + origin.x + + as x_in_phys == x_out_phys, we find + (x_in_index)* voxel_size_in.x + origin_in.x == + (x_out_index )* voxel_size_out.x + origin_out.x + <=> + x_in_index = (x_out_index * voxel_size_out.x + + origin_out.x - origin_in.x) + / voxel_size_in.x + + so, zoom= voxel_size_in.x/ voxel_size_out.x + offset = (origin_out.x - origin_in.x)/ voxel_size_in.x + + */ // check relation between indices and physical coordinates { - const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); - if (norm(image_in.get_physical_coordinates_for_indices(indices) - - (image_in.get_voxel_size() * BasicCoordinate<3,float>(indices) + image_in.get_origin()) - ) > 2.F) + const BasicCoordinate<3, int> indices = make_coordinate(1, 2, 3); + if (norm(image_in.get_physical_coordinates_for_indices(indices) - + (image_in.get_voxel_size() * BasicCoordinate<3, float>(indices) + image_in.get_origin())) > 2.F) error("zoom_image is confused about the relation between indices and physical coordinates"); } - const float zoom_x = - image_in.get_voxel_size().x() / image_out.get_voxel_size().x(); - const float zoom_y = - image_in.get_voxel_size().y() / image_out.get_voxel_size().y(); - const float zoom_z = - image_in.get_voxel_size().z() / image_out.get_voxel_size().z(); - const float x_offset = - (image_out.get_origin().x() - image_in.get_origin().x()) - / image_in.get_voxel_size().x(); - const float y_offset = - (image_out.get_origin().y() - image_in.get_origin().y()) - / image_in.get_voxel_size().y(); - const float z_offset = - (image_out.get_origin().z() - image_in.get_origin().z()) - / image_in.get_voxel_size().z(); - - - if(zoom_x==1.0F && zoom_y==1.0F && zoom_z==1.0F && - x_offset == 0.F && y_offset == 0.F && z_offset == 0.F && - image_in.get_index_range() == image_out.get_index_range() - ) - { - image_out = image_in; - return; - } + const float zoom_x = image_in.get_voxel_size().x() / image_out.get_voxel_size().x(); + const float zoom_y = image_in.get_voxel_size().y() / image_out.get_voxel_size().y(); + const float zoom_z = image_in.get_voxel_size().z() / image_out.get_voxel_size().z(); + const float x_offset = (image_out.get_origin().x() - image_in.get_origin().x()) / image_in.get_voxel_size().x(); + const float y_offset = (image_out.get_origin().y() - image_in.get_origin().y()) / image_in.get_voxel_size().y(); + const float z_offset = (image_out.get_origin().z() - image_in.get_origin().z()) / image_in.get_voxel_size().z(); + + if (zoom_x == 1.0F && zoom_y == 1.0F && zoom_z == 1.0F && x_offset == 0.F && y_offset == 0.F && z_offset == 0.F && + image_in.get_index_range() == image_out.get_index_range()) { + image_out = image_in; + return; + } // TODO creating a lot of new images here... - Array<3,float> - temp(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), - image_in.get_min_y(), image_in.get_max_y(), - image_out.get_min_x(), image_out.get_max_x())); + Array<3, float> temp(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), image_in.get_min_y(), image_in.get_max_y(), + image_out.get_min_x(), image_out.get_max_x())); - for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) - for (int y=image_in.get_min_y(); y<=image_in.get_max_y(); y++) + for (int z = image_in.get_min_z(); z <= image_in.get_max_z(); z++) + for (int y = image_in.get_min_y(); y <= image_in.get_max_y(); y++) overlap_interpolate(temp[z][y], image_in[z][y], zoom_x, x_offset); - Array<3,float> temp2(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), - image_out.get_min_y(), image_out.get_max_y(), - image_out.get_min_x(), image_out.get_max_x())); + Array<3, float> temp2(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), image_out.get_min_y(), image_out.get_max_y(), + image_out.get_min_x(), image_out.get_max_x())); - for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) + for (int z = image_in.get_min_z(); z <= image_in.get_max_z(); z++) overlap_interpolate(temp2[z], temp[z], zoom_y, y_offset); temp.recycle(); @@ -452,101 +361,77 @@ zoom_image(VoxelsOnCartesianGrid &image_out, float scale_image = 1.F; - switch (zoom_options.get_scaling_option()) - { - case ZoomOptions::preserve_values: - { - scale_image = zoom_x*zoom_y*zoom_z; - break; - } - - case ZoomOptions::preserve_projections: + switch (zoom_options.get_scaling_option()) { + case ZoomOptions::preserve_values: { + scale_image = zoom_x * zoom_y * zoom_z; + break; + } - { - scale_image = zoom_y*zoom_z; - break; - } + case ZoomOptions::preserve_projections: - case ZoomOptions::preserve_sum: - { - return; // no need to scale - } + { + scale_image = zoom_y * zoom_z; + break; + } - } + case ZoomOptions::preserve_sum: { + return; // no need to scale + } + } if (scale_image != 1.F) - image_out*= scale_image; - + image_out *= scale_image; } void -zoom_image(PixelsOnCartesianGrid &image2D_out, - const PixelsOnCartesianGrid &image2D_in, - const ZoomOptions zoom_options) -{ +zoom_image(PixelsOnCartesianGrid& image2D_out, const PixelsOnCartesianGrid& image2D_in, + const ZoomOptions zoom_options) { image2D_out.set_exam_info(image2D_in.get_exam_info()); /* see above for how to find zoom and offsets */ - const float zoom_x = - image2D_in.get_pixel_size().x() / image2D_out.get_pixel_size().x(); - const float zoom_y = - image2D_in.get_pixel_size().y() / image2D_out.get_pixel_size().y(); - const float x_offset = - ((image2D_out.get_origin().x() - image2D_in.get_origin().x()) - / image2D_in.get_pixel_size().x() - ); - const float y_offset = - ((image2D_out.get_origin().y() - image2D_in.get_origin().y()) - / image2D_in.get_pixel_size().y() - ); - - if(zoom_x==1.0F && zoom_y==1.0F && - x_offset == 0.F && y_offset == 0.F && - image2D_in.get_index_range() == image2D_out.get_index_range() - ) - { + const float zoom_x = image2D_in.get_pixel_size().x() / image2D_out.get_pixel_size().x(); + const float zoom_y = image2D_in.get_pixel_size().y() / image2D_out.get_pixel_size().y(); + const float x_offset = ((image2D_out.get_origin().x() - image2D_in.get_origin().x()) / image2D_in.get_pixel_size().x()); + const float y_offset = ((image2D_out.get_origin().y() - image2D_in.get_origin().y()) / image2D_in.get_pixel_size().y()); + + if (zoom_x == 1.0F && zoom_y == 1.0F && x_offset == 0.F && y_offset == 0.F && + image2D_in.get_index_range() == image2D_out.get_index_range()) { image2D_out = image2D_in; return; } - Array<2,float> - temp(IndexRange2D(image2D_in.get_min_y(), image2D_in.get_max_y(), - image2D_out.get_min_x(), image2D_out.get_max_x())); + Array<2, float> temp( + IndexRange2D(image2D_in.get_min_y(), image2D_in.get_max_y(), image2D_out.get_min_x(), image2D_out.get_max_x())); - for (int y=image2D_in.get_min_y(); y<=image2D_in.get_max_y(); y++) + for (int y = image2D_in.get_min_y(); y <= image2D_in.get_max_y(); y++) overlap_interpolate(temp[y], image2D_in[y], zoom_x, x_offset); - overlap_interpolate(image2D_out, temp, zoom_y, y_offset); + overlap_interpolate(image2D_out, temp, zoom_y, y_offset); float scale_image = 1.F; - switch (zoom_options.get_scaling_option()) - { - case ZoomOptions::preserve_values: - { - scale_image = zoom_x*zoom_y; - break; - } - - case ZoomOptions::preserve_projections: + switch (zoom_options.get_scaling_option()) { + case ZoomOptions::preserve_values: { + scale_image = zoom_x * zoom_y; + break; + } - { - scale_image = zoom_y; - break; - } + case ZoomOptions::preserve_projections: - case ZoomOptions::preserve_sum: - { - return; // no need to scale - } + { + scale_image = zoom_y; + break; + } - } + case ZoomOptions::preserve_sum: { + return; // no need to scale + } + } if (scale_image != 1.F) - image2D_out*= scale_image; - + image2D_out *= scale_image; } END_NAMESPACE_STIR diff --git a/src/data_buildblock/RegisteredObject.cxx b/src/data_buildblock/RegisteredObject.cxx index b39fd5bd86..b8b7f2b304 100644 --- a/src/data_buildblock/RegisteredObject.cxx +++ b/src/data_buildblock/RegisteredObject.cxx @@ -32,29 +32,26 @@ #include "stir/RegisteredObject.h" #ifdef __STIR_REGISTRY_NOT_INLINE -#pragma message("instantiating RegisteredObject") -#include "stir/data/SinglesRates.h" - +# pragma message("instantiating RegisteredObject") +# include "stir/data/SinglesRates.h" // and others START_NAMESPACE_STIR template -RegisteredObject::RegistryType& -RegisteredObject::registry () -{ +RegisteredObject::RegistryType& +RegisteredObject::registry() { static RegistryType the_registry("None", 0); return the_registry; } # ifdef _MSC_VER -// prevent warning message on reinstantiation, +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) +# pragma warning(disable : 4660) # endif - -template RegisteredObject; +template RegisteredObject; END_NAMESPACE_STIR diff --git a/src/data_buildblock/SinglesRates.cxx b/src/data_buildblock/SinglesRates.cxx index b7afcdfe93..5a2312b90f 100644 --- a/src/data_buildblock/SinglesRates.cxx +++ b/src/data_buildblock/SinglesRates.cxx @@ -31,70 +31,41 @@ using std::vector; START_NAMESPACE_STIR - /* *! FrameSinglesRates constructor. */ -FrameSinglesRates:: -FrameSinglesRates(vector& avg_singles_rates, - double start_time, - double end_time, - shared_ptr scanner_sptr) : - _start_time(start_time), - _end_time(end_time), - _singles(avg_singles_rates), - _scanner_sptr(scanner_sptr) -{ +FrameSinglesRates::FrameSinglesRates(vector& avg_singles_rates, double start_time, double end_time, + shared_ptr scanner_sptr) + : _start_time(start_time), _end_time(end_time), _singles(avg_singles_rates), _scanner_sptr(scanner_sptr) { assert(avg_singles_rates.size() == static_cast(scanner_sptr->get_num_singles_units())); } - - -float -FrameSinglesRates:: -get_singles_rate(int singles_bin_index) const { - return(_singles[singles_bin_index]); +float +FrameSinglesRates::get_singles_rate(int singles_bin_index) const { + return (_singles[singles_bin_index]); } - - -float -FrameSinglesRates:: -get_singles_rate(const DetectionPosition<>& det_pos) const { +float +FrameSinglesRates::get_singles_rate(const DetectionPosition<>& det_pos) const { int singles_bin_index = _scanner_sptr->get_singles_bin_index(det_pos); - return(get_singles_rate(singles_bin_index)); + return (get_singles_rate(singles_bin_index)); } - - - double -FrameSinglesRates:: -get_start_time() const { - return(_start_time); +FrameSinglesRates::get_start_time() const { + return (_start_time); } - + double -FrameSinglesRates:: -get_end_time() const { - return(_end_time); +FrameSinglesRates::get_end_time() const { + return (_end_time); } - - // Get the average singles rate for a particular bin. float -SinglesRates:: -get_singles_rate(const DetectionPosition<>& det_pos, - const double start_time, const double end_time) const -{ +SinglesRates::get_singles_rate(const DetectionPosition<>& det_pos, const double start_time, const double end_time) const { const int singles_bin_index = scanner_sptr->get_singles_bin_index(det_pos); - return(get_singles_rate(singles_bin_index, start_time, end_time)); + return (get_singles_rate(singles_bin_index, start_time, end_time)); } - - END_NAMESPACE_STIR - - - diff --git a/src/data_buildblock/SinglesRatesForTimeFrames.cxx b/src/data_buildblock/SinglesRatesForTimeFrames.cxx index 47825f7dc5..5316cbaa60 100644 --- a/src/data_buildblock/SinglesRatesForTimeFrames.cxx +++ b/src/data_buildblock/SinglesRatesForTimeFrames.cxx @@ -30,57 +30,39 @@ START_NAMESPACE_STIR -SinglesRatesForTimeFrames:: -SinglesRatesForTimeFrames() -{} - +SinglesRatesForTimeFrames::SinglesRatesForTimeFrames() {} -float -SinglesRatesForTimeFrames:: -get_singles_rate(const int singles_bin_index, - const unsigned int time_frame_num) const -{ - return(this->_singles[time_frame_num][singles_bin_index]); +float +SinglesRatesForTimeFrames::get_singles_rate(const int singles_bin_index, const unsigned int time_frame_num) const { + return (this->_singles[time_frame_num][singles_bin_index]); } -void -SinglesRatesForTimeFrames:: -set_singles_rate(const int singles_bin_index, - const unsigned time_frame_num, - const float new_rate) +void +SinglesRatesForTimeFrames::set_singles_rate(const int singles_bin_index, const unsigned time_frame_num, const float new_rate) { this->_singles[time_frame_num][singles_bin_index] = new_rate; } - float -SinglesRatesForTimeFrames:: -get_singles_rate(const int singles_bin_index, - const double start_time, - const double end_time) const -{ - const unsigned frame_number = - this->_time_frame_defs.get_time_frame_num(start_time, end_time); +SinglesRatesForTimeFrames::get_singles_rate(const int singles_bin_index, const double start_time, const double end_time) const { + const unsigned frame_number = this->_time_frame_defs.get_time_frame_num(start_time, end_time); if (frame_number == 0) return -1.F; else - return(get_singles_rate(singles_bin_index, frame_number)); + return (get_singles_rate(singles_bin_index, frame_number)); } -unsigned int +unsigned int SinglesRatesForTimeFrames::get_num_frames() const { - return(this->_time_frame_defs.get_num_frames()); + return (this->_time_frame_defs.get_num_frames()); } const TimeFrameDefinitions& -SinglesRatesForTimeFrames:: -get_time_frame_definitions() const -{ +SinglesRatesForTimeFrames::get_time_frame_definitions() const { return this->_time_frame_defs; } - #if 0 double SinglesRatesForTimeFrames:: @@ -106,5 +88,3 @@ get_frame_end(unsigned int frame_number) const { #endif END_NAMESPACE_STIR - - diff --git a/src/data_buildblock/SinglesRatesFromECAT7.cxx b/src/data_buildblock/SinglesRatesFromECAT7.cxx index d6ccf21feb..a7884fe79e 100644 --- a/src/data_buildblock/SinglesRatesFromECAT7.cxx +++ b/src/data_buildblock/SinglesRatesFromECAT7.cxx @@ -30,7 +30,7 @@ #include "stir/IO/stir_ecat7.h" #include "stir/IndexRange2D.h" #ifdef HAVE_LLN_MATRIX -#include "ecat_model.h" +# include "ecat_model.h" #endif #include @@ -44,20 +44,15 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 -const char * const -SinglesRatesFromECAT7::registered_name = "Singles From ECAT7"; - -SinglesRatesFromECAT7:: -SinglesRatesFromECAT7() -{} +const char* const SinglesRatesFromECAT7::registered_name = "Singles From ECAT7"; +SinglesRatesFromECAT7::SinglesRatesFromECAT7() {} int -SinglesRatesFromECAT7::read_singles_from_file(const std::string& ECAT7_filename, - const std::ios::openmode open_mode) +SinglesRatesFromECAT7::read_singles_from_file(const std::string& ECAT7_filename, const std::ios::openmode open_mode) { - + int num_frames = 0; #ifndef HAVE_LLN_MATRIX @@ -68,112 +63,78 @@ SinglesRatesFromECAT7::read_singles_from_file(const std::string& ECAT7_filename, MatrixFile* mptr = matrix_open(ECAT7_filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); - if (mptr==0) { + if (mptr == 0) { error("Error opening '%s' as ECAT7\n", ECAT7_filename.c_str()); } - if (!(mptr->mhptr->file_type == Byte3dSinogram || - mptr->mhptr->file_type == Short3dSinogram || + if (!(mptr->mhptr->file_type == Byte3dSinogram || mptr->mhptr->file_type == Short3dSinogram || mptr->mhptr->file_type == Float3dSinogram)) { - error("SinglesRatesFromECAT7: filename %s should be an ECAT7 emission file\n", - ECAT7_filename.c_str()); + error("SinglesRatesFromECAT7: filename %s should be an ECAT7 emission file\n", ECAT7_filename.c_str()); } - - scanner_sptr.reset(find_scanner_from_ECAT_system_type(mptr->mhptr->system_type)); + scanner_sptr.reset(find_scanner_from_ECAT_system_type(mptr->mhptr->system_type)); if (scanner_sptr->get_type() != Scanner::E966) { warning("check SinglesRatesFromECAT7 for non-966\n"); } - - Main_header* main_header = reinterpret_cast( mptr->mhptr ) ; + Main_header* main_header = reinterpret_cast(mptr->mhptr); num_frames = main_header->num_frames; // Get total number of bins for this type of scanner. const int total_singles_units = scanner_sptr->get_num_singles_units(); - if ( total_singles_units > 0 ) { + if (total_singles_units > 0) { // Create the main array of data. - this->_singles = Array<2,float>(IndexRange2D(1, main_header->num_frames, - 0, total_singles_units - 1)); + this->_singles = Array<2, float>(IndexRange2D(1, main_header->num_frames, 0, total_singles_units - 1)); } - MatrixData* matrix; - std::vector > time_frames(main_header->num_frames); + std::vector> time_frames(main_header->num_frames); + for (int mat_frame = 1; mat_frame <= num_frames; mat_frame++) { + // cerr << "Reading frame " << mat_frame <(matrix->shptr); - time_frames[mat_frame-1].first=scan_subheader_ptr->frame_start_time/1000.; - time_frames[mat_frame-1].second= - time_frames[mat_frame-1].first + - scan_subheader_ptr->frame_duration/1000.; + Scan3D_subheader* scan_subheader_ptr = reinterpret_cast(matrix->shptr); + time_frames[mat_frame - 1].first = scan_subheader_ptr->frame_start_time / 1000.; + time_frames[mat_frame - 1].second = time_frames[mat_frame - 1].first + scan_subheader_ptr->frame_duration / 1000.; - float const* singles_ptr = reinterpret_cast(scan_subheader_ptr->uncor_singles);//matrix->data_ptr); + float const* singles_ptr = reinterpret_cast(scan_subheader_ptr->uncor_singles); // matrix->data_ptr); // The order of the singles units in the sub header is the same as required // by the main singles array. This may not be the case for other file formats. - for (int singles_bin = 0 ; singles_bin < total_singles_units ; ++singles_bin) { + for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { this->_singles[mat_frame][singles_bin] = *(singles_ptr + singles_bin); } - } this->_time_frame_defs = TimeFrameDefinitions(time_frames); #endif - return(num_frames); - + return (num_frames); } - - - - - - - - -void -SinglesRatesFromECAT7:: -initialise_keymap() -{ +void +SinglesRatesFromECAT7::initialise_keymap() { parser.add_start_key("Singles Rates From ECAT7"); parser.add_key("ECAT7_filename", &ECAT7_filename); parser.add_stop_key("End Singles Rates From ECAT7"); } -bool -SinglesRatesFromECAT7:: -post_processing() -{ +bool +SinglesRatesFromECAT7::post_processing() { read_singles_from_file(ECAT7_filename); return false; } - -void -SinglesRatesFromECAT7::set_defaults() -{ +void +SinglesRatesFromECAT7::set_defaults() { ECAT7_filename = ""; } - - - - - END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT END_NAMESPACE_STIR - - diff --git a/src/data_buildblock/SinglesRatesFromGEHDF5.cxx b/src/data_buildblock/SinglesRatesFromGEHDF5.cxx old mode 100755 new mode 100644 index 394a45189e..96ab6f4aaf --- a/src/data_buildblock/SinglesRatesFromGEHDF5.cxx +++ b/src/data_buildblock/SinglesRatesFromGEHDF5.cxx @@ -45,48 +45,39 @@ using std::streampos; using std::ios; #endif - - START_NAMESPACE_STIR namespace GE { namespace RDF_HDF5 { -const char * const -SinglesRatesFromGEHDF5::registered_name = "Singles From GE HDF5 listmode File"; +const char* const SinglesRatesFromGEHDF5::registered_name = "Singles From GE HDF5 listmode File"; const double MAX_INTERVAL_DIFFERENCE = 0.05; // 5% max difference. -//PW Will not change this bit of code. +// PW Will not change this bit of code. // Constructor -SinglesRatesFromGEHDF5:: -SinglesRatesFromGEHDF5() -{} - +SinglesRatesFromGEHDF5::SinglesRatesFromGEHDF5() {} // Generate a FramesSinglesRate - containing the average rates // for a frame begining at start_time and ending at end_time. FrameSinglesRates -SinglesRatesFromGEHDF5:: -get_rates_for_frame(double start_time, - double end_time) const { +SinglesRatesFromGEHDF5::get_rates_for_frame(double start_time, double end_time) const { int num_singles_units = SinglesRates::scanner_sptr->get_num_singles_units(); // Create a temporary vector std::vector average_singles_rates(num_singles_units); - // Loop over all bins. - for(int singles_bin = 0 ; singles_bin < num_singles_units ; ++singles_bin) { + for (int singles_bin = 0; singles_bin < num_singles_units; ++singles_bin) { average_singles_rates[singles_bin] = get_singles_rate(singles_bin, start_time, end_time); } - + // Determine that start and end slice indices. int start_slice = get_start_time_slice_index(start_time); int end_slice = get_end_time_slice_index(end_time); - + double frame_start_time; - if ( start_slice == 0 ) { + if (start_slice == 0) { frame_start_time = _times[0] - _singles_time_interval; } else { frame_start_time = _times[start_slice - 1]; @@ -95,290 +86,223 @@ get_rates_for_frame(double start_time, double frame_end_time = _times[end_slice]; // Create temp FrameSinglesRate object - FrameSinglesRates frame_rates(average_singles_rates, - frame_start_time, - frame_end_time, - SinglesRates::scanner_sptr); - - return(frame_rates); - -} - - - + FrameSinglesRates frame_rates(average_singles_rates, frame_start_time, frame_end_time, SinglesRates::scanner_sptr); + return (frame_rates); +} // Get time slice index. // Returns the index of the slice that contains the specified time. int -SinglesRatesFromGEHDF5:: -get_end_time_slice_index(double t) const { +SinglesRatesFromGEHDF5::get_end_time_slice_index(double t) const { unsigned int slice_index = 0; // Start with an initial estimate. - if ( _singles_time_interval != 0 ) { + if (_singles_time_interval != 0) { slice_index = static_cast(floor(t / _singles_time_interval)); } - if ( slice_index >= m_num_time_slices ) { + if (slice_index >= m_num_time_slices) { slice_index = m_num_time_slices - 1; - } - + } // Check estimate and determine whether to look further or backwards. // Note that we could just move fowards first and then backwards but this // method is more intuitive. - if ( _times[slice_index] < t ) { - + if (_times[slice_index] < t) { + // Check forwards. - while( slice_index < m_num_time_slices - 1 && - _times[slice_index] < t ) { + while (slice_index < m_num_time_slices - 1 && _times[slice_index] < t) { slice_index++; } } else { // Check backwards. - while( slice_index > 0 && _times[slice_index - 1] >= t ) { + while (slice_index > 0 && _times[slice_index - 1] >= t) { slice_index--; } - } - - return(slice_index); -} - - + return (slice_index); +} // Get time slice index. // Returns first slice ending _after_ t. int -SinglesRatesFromGEHDF5:: -get_start_time_slice_index(double t) const { +SinglesRatesFromGEHDF5::get_start_time_slice_index(double t) const { unsigned int slice_index = 0; // Start with an initial estimate. - if ( _singles_time_interval != 0 ) { + if (_singles_time_interval != 0) { slice_index = static_cast(floor(t / _singles_time_interval)); } - if ( slice_index >= m_num_time_slices ) { + if (slice_index >= m_num_time_slices) { slice_index = m_num_time_slices - 1; - } - + } // Check estimate and determine whether to look further or backwards. // Note that we could just move fowards first and then backwards but this // method is more intuitive. - if ( _times[slice_index] < t ) { - + if (_times[slice_index] < t) { + // Check forwards. - while( slice_index < m_num_time_slices - 1 && - _times[slice_index] <= t ) { + while (slice_index < m_num_time_slices - 1 && _times[slice_index] <= t) { slice_index++; } } else { // Check backwards. - while( slice_index > 0 && _times[slice_index - 1] > t ) { + while (slice_index > 0 && _times[slice_index - 1] > t) { slice_index--; } - } - - return(slice_index); -} - - - - + return (slice_index); +} // Get rates using time slice and singles bin indices. -int -SinglesRatesFromGEHDF5:: -get_singles_rate(int singles_bin_index,int time_slice) const { - +int +SinglesRatesFromGEHDF5::get_singles_rate(int singles_bin_index, int time_slice) const { + // Check ranges. unsigned int total_singles_units = SinglesRates::scanner_sptr->get_num_singles_units(); - - if ( singles_bin_index < 0 || singles_bin_index >= total_singles_units || - time_slice < 0 || time_slice >= m_num_time_slices ) { - return(0); + + if (singles_bin_index < 0 || singles_bin_index >= total_singles_units || time_slice < 0 || time_slice >= m_num_time_slices) { + return (0); } else { return (*m_singles_sptr)[time_slice][singles_bin_index]; } - } - - // Set a singles rate by bin index and time slice. -void -SinglesRatesFromGEHDF5:: -set_singles_rate(int singles_bin_index, int time_slice, int new_rate) { - +void +SinglesRatesFromGEHDF5::set_singles_rate(int singles_bin_index, int time_slice, int new_rate) { + unsigned int total_singles_units = SinglesRates::scanner_sptr->get_num_singles_units(); - - if ( singles_bin_index >= 0 && singles_bin_index < total_singles_units && - time_slice >= 0 && time_slice < m_num_time_slices ) { + + if (singles_bin_index >= 0 && singles_bin_index < total_singles_units && time_slice >= 0 && time_slice < m_num_time_slices) { (*m_singles_sptr)[time_slice][singles_bin_index] = new_rate; } } - - - -unsigned int SinglesRatesFromGEHDF5::rebin(std::vector& new_end_times) { +unsigned int +SinglesRatesFromGEHDF5::rebin(std::vector& new_end_times) { const int num_new_slices = new_end_times.size(); const int total_singles_units = SinglesRates::scanner_sptr->get_num_singles_units(); - + // Create the new array of singles data. - Array<2, unsigned int> new_singles = Array<2, unsigned int>(IndexRange2D(0, num_new_slices - 1, - 0, total_singles_units - 1)); - - + Array<2, unsigned int> new_singles = Array<2, unsigned int>(IndexRange2D(0, num_new_slices - 1, 0, total_singles_units - 1)); + // Sort the set of new time slices. std::sort(new_end_times.begin(), new_end_times.end()); // Start with initial time of 0.0 seconds. double start_time = 0; - // Loop over new time slices. - for(unsigned int new_slice = 0 ; new_slice < new_end_times.size(); ++new_slice) { + for (unsigned int new_slice = 0; new_slice < new_end_times.size(); ++new_slice) { // End time for the new time slice. double end_time = new_end_times[new_slice]; // If start time is beyond last end time in original data, then use zeros. - if ( start_time > _times[m_num_time_slices - 1] ) { - for(int singles_bin = 0 ; singles_bin < total_singles_units ; ++singles_bin) { + if (start_time > _times[m_num_time_slices - 1]) { + for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { new_singles[new_slice][singles_bin] = 0; } } else { // Get the singles rate average between start and end times for all bins. - for(int singles_bin = 0 ; singles_bin < total_singles_units ; ++singles_bin ) { - new_singles[new_slice][singles_bin] = - round(get_singles_rate(singles_bin, start_time, end_time)); + for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { + new_singles[new_slice][singles_bin] = round(get_singles_rate(singles_bin, start_time, end_time)); } - } - + // Next new time slice starts at the end of this slice. start_time = end_time; - } - - + // Set the singles and times using the new sets. m_singles_sptr.reset(new Array<2, unsigned int>(new_singles)); _times = new_end_times; m_num_time_slices = _times.size(); - - return(m_num_time_slices); -} + return (m_num_time_slices); +} - -std::vector -SinglesRatesFromGEHDF5::get_times() const -{ +std::vector +SinglesRatesFromGEHDF5::get_times() const { return _times; } - - - unsigned int -SinglesRatesFromGEHDF5:: -get_num_time_slices() const { - return(m_num_time_slices); +SinglesRatesFromGEHDF5::get_num_time_slices() const { + return (m_num_time_slices); } - - double -SinglesRatesFromGEHDF5:: -get_singles_time_interval() const { - return(_singles_time_interval); +SinglesRatesFromGEHDF5::get_singles_time_interval() const { + return (_singles_time_interval); } - - - - unsigned int -SinglesRatesFromGEHDF5:: -read_singles_from_listmode_file(const std::string& _listmode_filename) -{ - - unsigned int slice = 0; - - //PW Open the list mode file here. - m_input_sptr.reset(new GEHDF5Wrapper(_listmode_filename)); +SinglesRatesFromGEHDF5::read_singles_from_listmode_file(const std::string& _listmode_filename) { + unsigned int slice = 0; - SinglesRates::scanner_sptr = m_input_sptr->get_scanner_sptr(); - // Get total number of bins for this type of scanner. - const int total_singles_units = SinglesRates::scanner_sptr->get_num_singles_units(); + // PW Open the list mode file here. + m_input_sptr.reset(new GEHDF5Wrapper(_listmode_filename)); - m_input_sptr->initialise_singles_data(); + SinglesRates::scanner_sptr = m_input_sptr->get_scanner_sptr(); + // Get total number of bins for this type of scanner. + const int total_singles_units = SinglesRates::scanner_sptr->get_num_singles_units(); - // Allocate the main array. - m_num_time_slices = m_input_sptr->get_num_singles_samples(); - m_singles_sptr.reset(new Array<2, unsigned int>(IndexRange2D(0, m_num_time_slices - 1, 0, total_singles_units - 1))); - - while ( slice < m_num_time_slices) - { - m_input_sptr->read_singles((*m_singles_sptr)[slice],slice+1); - ++slice; - } - - //PW Modify this bit of code too. - if (slice != m_num_time_slices) - { - error("\nSinglesRatesFromGEHDF5: Couldn't read all records in the file. Read %d of %d. Exiting\n", - slice, m_num_time_slices); - //TODO resize singles to return array with new sizes - } - // AB TODO: if listmode or/and m_num_time_slices>! - _times = std::vector(m_num_time_slices); - if (m_num_time_slices>1) // this is the same as checking if the input file is a listmode file - { - for(unsigned int slice = 0;slice < m_num_time_slices;++slice) - _times[slice] = slice+1.0; - - assert(_times.size()!=0); - _singles_time_interval = _times[1] - _times[0]; - } - else // Then it must be a sinogram, and therefore only has 1 time and 1 interval. - { - TimeFrameDefinitions tf = m_input_sptr->get_exam_info_sptr()->get_time_frame_definitions(); - _times[0]= tf.get_duration(1); - _singles_time_interval = tf.get_duration(1); - } - - - // Return number of time slices read. - return slice; - -} + m_input_sptr->initialise_singles_data(); + // Allocate the main array. + m_num_time_slices = m_input_sptr->get_num_singles_samples(); + m_singles_sptr.reset(new Array<2, unsigned int>(IndexRange2D(0, m_num_time_slices - 1, 0, total_singles_units - 1))); + while (slice < m_num_time_slices) { + m_input_sptr->read_singles((*m_singles_sptr)[slice], slice + 1); + ++slice; + } + // PW Modify this bit of code too. + if (slice != m_num_time_slices) { + error("\nSinglesRatesFromGEHDF5: Couldn't read all records in the file. Read %d of %d. Exiting\n", slice, m_num_time_slices); + // TODO resize singles to return array with new sizes + } + // AB TODO: if listmode or/and m_num_time_slices>! + _times = std::vector(m_num_time_slices); + if (m_num_time_slices > 1) // this is the same as checking if the input file is a listmode file + { + for (unsigned int slice = 0; slice < m_num_time_slices; ++slice) + _times[slice] = slice + 1.0; + + assert(_times.size() != 0); + _singles_time_interval = _times[1] - _times[0]; + } else // Then it must be a sinogram, and therefore only has 1 time and 1 interval. + { + TimeFrameDefinitions tf = m_input_sptr->get_exam_info_sptr()->get_time_frame_definitions(); + _times[0] = tf.get_duration(1); + _singles_time_interval = tf.get_duration(1); + } + // Return number of time slices read. + return slice; +} // Write SinglesRatesFromGEHDF5 to a singles file. -std::ostream& +std::ostream& SinglesRatesFromGEHDF5::write(std::ostream& output) { output << (*m_singles_sptr) << std::endl; @@ -386,98 +310,81 @@ SinglesRatesFromGEHDF5::write(std::ostream& output) { return output; } -//PW Figure this out!Does it need any change? +// PW Figure this out!Does it need any change? float -SinglesRatesFromGEHDF5:: -get_singles_rate(const int singles_bin_index, - const double start_time, const double end_time) const { +SinglesRatesFromGEHDF5::get_singles_rate(const int singles_bin_index, const double start_time, const double end_time) const { - // First Calculate an inclusive range. start_time_slice is the + // First Calculate an inclusive range. start_time_slice is the // the first slice with an ending time greater than start_time. // end_time_slice is the first time slice that ends at, or after, // end_time. int start_slice = this->get_start_time_slice_index(start_time); int end_slice = this->get_end_time_slice_index(end_time); - - + // Total contribution from all slices. double total_singles; - - if ( start_slice == end_slice ) { + if (start_slice == end_slice) { // If the start and end slices are the same then just use that time slice. total_singles = static_cast((*m_singles_sptr)[start_slice][singles_bin_index]); } else { - + // Start and end times for starting and ending slices. double slice_start_time; double slice_end_time; - double included_duration; + double included_duration; double old_duration; double fraction; - - + // Total slices included (including fractional amounts) in the average. float total_slices; - - // Calculate the fraction of the start_slice to include. slice_start_time = get_slice_start(start_slice); slice_end_time = _times[start_slice]; - + old_duration = slice_end_time - slice_start_time; included_duration = slice_end_time - start_time; - + fraction = included_duration / old_duration; - - + // Set the total number of contributing bins to this fraction. total_slices = fraction; - + // Set the total singles so far to be the fraction of the bin. total_singles = fraction * (*m_singles_sptr)[start_slice][singles_bin_index]; - - - + // Calculate the fraction of the end_slice to include. slice_start_time = get_slice_start(end_slice); slice_end_time = _times[end_slice]; - + old_duration = slice_end_time - slice_start_time; included_duration = end_time - slice_start_time; - + fraction = included_duration / old_duration; - + // Add this fraction to the total of the number of bins contributing. total_slices += fraction; - + // Add the fraction of the bin to the running total. total_singles += fraction * (*m_singles_sptr)[end_slice][singles_bin_index]; - - + // Add all intervening slices. - for(int slice = start_slice + 1; slice < end_slice ; ++slice, total_slices += 1.0) { + for (int slice = start_slice + 1; slice < end_slice; ++slice, total_slices += 1.0) { total_singles += (*m_singles_sptr)[slice][singles_bin_index]; } - - + // Divide by total amount of contributing slices. total_singles = total_singles / total_slices; - } - return( static_cast(total_singles) ); - + return (static_cast(total_singles)); } float -SinglesRatesFromGEHDF5:: -get_singles_rate(const DetectionPosition<>& det_pos, - const double start_time, - const double end_time) const -{ - return SinglesRates::get_singles_rate(det_pos, start_time, end_time); +SinglesRatesFromGEHDF5::get_singles_rate(const DetectionPosition<>& det_pos, const double start_time, + const double end_time) const { + return SinglesRates::get_singles_rate(det_pos, start_time, end_time); } /* @@ -486,94 +393,72 @@ get_singles_rate(const DetectionPosition<>& det_pos, * */ +void +SinglesRatesFromGEHDF5::set_time_interval() { - - - -void -SinglesRatesFromGEHDF5:: -set_time_interval() { - - // Run through the _times vector and calculate an average difference + // Run through the _times vector and calculate an average difference // between the starts of consecutive time slices. - + // Min and max differences (slice durations). double min_diff = 0; double max_diff = 0; double total = 0; - for(std::vector::const_iterator t = _times.begin(); t < _times.end() - 1; ++t) { + for (std::vector::const_iterator t = _times.begin(); t < _times.end() - 1; ++t) { double diff = *(t + 1) - *t; total += diff; - if ( min_diff == 0 || diff < min_diff ) { + if (min_diff == 0 || diff < min_diff) { min_diff = diff; } - if ( diff > max_diff ) { + if (diff > max_diff) { max_diff = diff; } } _singles_time_interval = total / (_times.size() - 1); - if ( (max_diff - min_diff) / (_singles_time_interval) > MAX_INTERVAL_DIFFERENCE ) { + if ((max_diff - min_diff) / (_singles_time_interval) > MAX_INTERVAL_DIFFERENCE) { // Slice durations are not consistent enough to be considered the same. _singles_time_interval = 0; } - } - // get slice start time. -double -SinglesRatesFromGEHDF5:: -get_slice_start(int slice_index) const { +double +SinglesRatesFromGEHDF5::get_slice_start(int slice_index) const { - if ( slice_index >= m_num_time_slices ) { + if (slice_index >= m_num_time_slices) { slice_index = m_num_time_slices - 1; } - - if ( slice_index == 0 ) { - return(0); + + if (slice_index == 0) { + return (0); } else { - return(_times[slice_index - 1]); + return (_times[slice_index - 1]); } } - - - - - -void -SinglesRatesFromGEHDF5:: -initialise_keymap() -{ -//PW Modify this to change sgl to listmode +void +SinglesRatesFromGEHDF5::initialise_keymap() { + // PW Modify this to change sgl to listmode parser.add_start_key("Singles Rates From GE HDF5 listmode File"); parser.add_key("listmode_filename", &_listmode_filename); parser.add_stop_key("End Singles Rates From GE HDF5 listmode File"); } -bool -SinglesRatesFromGEHDF5:: -post_processing() -{ +bool +SinglesRatesFromGEHDF5::post_processing() { read_singles_from_listmode_file(_listmode_filename); return false; } - -void -SinglesRatesFromGEHDF5::set_defaults() -{ +void +SinglesRatesFromGEHDF5::set_defaults() { _listmode_filename = ""; } -} // namespace -} +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR - - - diff --git a/src/data_buildblock/SinglesRatesFromSglFile.cxx b/src/data_buildblock/SinglesRatesFromSglFile.cxx index d839231809..15051ac6c9 100644 --- a/src/data_buildblock/SinglesRatesFromSglFile.cxx +++ b/src/data_buildblock/SinglesRatesFromSglFile.cxx @@ -32,8 +32,8 @@ #include #ifdef HAVE_LLN_MATRIX -#include "ecat_model.h" -#include "stir/IO/stir_ecat7.h" +# include "ecat_model.h" +# include "stir/IO/stir_ecat7.h" #endif #include #include @@ -44,39 +44,27 @@ using std::streampos; using std::ios; #endif - - START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 -const unsigned -SinglesRatesFromSglFile::SIZE_OF_SINGLES_RECORD = 4*128; - -const char * const -SinglesRatesFromSglFile::registered_name = "Singles From Sgl File"; +const unsigned SinglesRatesFromSglFile::SIZE_OF_SINGLES_RECORD = 4 * 128; +const char* const SinglesRatesFromSglFile::registered_name = "Singles From Sgl File"; const double MAX_INTERVAL_DIFFERENCE = 0.05; // 5% max difference. - -static inline -unsigned long int -convert_4_bytes(unsigned char * buffer) -{ +static inline unsigned long int +convert_4_bytes(unsigned char* buffer) { // The order from the file is always big endian. The native order doesn't matter // when converting by multiplying and adding the individual bytes. - //if (ByteOrder::get_native_order() == ByteOrder::big_endian) + // if (ByteOrder::get_native_order() == ByteOrder::big_endian) // return buffer[0] + 256UL*(buffer[1] + 256UL*(buffer[2] + 256UL*buffer[3])); - //else - return buffer[3] + 256UL*(buffer[2] + 256UL*(buffer[1] + 256UL*buffer[0])); - + // else + return buffer[3] + 256UL * (buffer[2] + 256UL * (buffer[1] + 256UL * buffer[0])); } - - -static inline -void -convert_int_to_4_bytes(unsigned long int val, unsigned char *buffer) { +static inline void +convert_int_to_4_bytes(unsigned long int val, unsigned char* buffer) { // Big endian buffer[0] = (val & 0xff000000) >> 24; buffer[1] = (val & 0x00ff0000) >> 16; @@ -84,40 +72,30 @@ convert_int_to_4_bytes(unsigned long int val, unsigned char *buffer) { buffer[3] = (val & 0x000000ff); } - - - - // Constructor -SinglesRatesFromSglFile:: -SinglesRatesFromSglFile() -{} - +SinglesRatesFromSglFile::SinglesRatesFromSglFile() {} // Generate a FramesSinglesRate - containing the average rates // for a frame begining at start_time and ending at end_time. FrameSinglesRates -SinglesRatesFromSglFile:: -get_rates_for_frame(double start_time, - double end_time) const { +SinglesRatesFromSglFile::get_rates_for_frame(double start_time, double end_time) const { int num_singles_units = scanner_sptr->get_num_singles_units(); // Create a temporary vector std::vector average_singles_rates(num_singles_units); - // Loop over all bins. - for(int singles_bin = 0 ; singles_bin < num_singles_units ; ++singles_bin) { + for (int singles_bin = 0; singles_bin < num_singles_units; ++singles_bin) { average_singles_rates[singles_bin] = get_singles_rate(singles_bin, start_time, end_time); } - + // Determine that start and end slice indices. int start_slice = get_start_time_slice_index(start_time); int end_slice = get_end_time_slice_index(end_time); - + double frame_start_time; - if ( start_slice == 0 ) { + if (start_slice == 0) { frame_start_time = _times[0] - _singles_time_interval; } else { frame_start_time = _times[start_slice - 1]; @@ -126,233 +104,175 @@ get_rates_for_frame(double start_time, double frame_end_time = _times[end_slice]; // Create temp FrameSinglesRate object - FrameSinglesRates frame_rates(average_singles_rates, - frame_start_time, - frame_end_time, - scanner_sptr); - - return(frame_rates); - -} - - - + FrameSinglesRates frame_rates(average_singles_rates, frame_start_time, frame_end_time, scanner_sptr); + return (frame_rates); +} // Get time slice index. // Returns the index of the slice that contains the specified time. int -SinglesRatesFromSglFile:: -get_end_time_slice_index(double t) const { +SinglesRatesFromSglFile::get_end_time_slice_index(double t) const { int slice_index = 0; // Start with an initial estimate. - if ( _singles_time_interval != 0 ) { + if (_singles_time_interval != 0) { slice_index = static_cast(floor(t / _singles_time_interval)); } - if ( slice_index >= _num_time_slices ) { + if (slice_index >= _num_time_slices) { slice_index = _num_time_slices - 1; - } - + } // Check estimate and determine whether to look further or backwards. // Note that we could just move fowards first and then backwards but this // method is more intuitive. - if ( _times[slice_index] < t ) { - + if (_times[slice_index] < t) { + // Check forwards. - while( slice_index < _num_time_slices - 1 && - _times[slice_index] < t ) { + while (slice_index < _num_time_slices - 1 && _times[slice_index] < t) { slice_index++; } } else { // Check backwards. - while( slice_index > 0 && _times[slice_index - 1] >= t ) { + while (slice_index > 0 && _times[slice_index - 1] >= t) { slice_index--; } - } - - return(slice_index); -} - - + return (slice_index); +} // Get time slice index. // Returns first slice ending _after_ t. int -SinglesRatesFromSglFile:: -get_start_time_slice_index(double t) const { +SinglesRatesFromSglFile::get_start_time_slice_index(double t) const { int slice_index = 0; // Start with an initial estimate. - if ( _singles_time_interval != 0 ) { + if (_singles_time_interval != 0) { slice_index = static_cast(floor(t / _singles_time_interval)); } - if ( slice_index >= _num_time_slices ) { + if (slice_index >= _num_time_slices) { slice_index = _num_time_slices - 1; - } - + } // Check estimate and determine whether to look further or backwards. // Note that we could just move fowards first and then backwards but this // method is more intuitive. - if ( _times[slice_index] < t ) { - + if (_times[slice_index] < t) { + // Check forwards. - while( slice_index < _num_time_slices - 1 && - _times[slice_index] <= t ) { + while (slice_index < _num_time_slices - 1 && _times[slice_index] <= t) { slice_index++; } } else { // Check backwards. - while( slice_index > 0 && _times[slice_index - 1] > t ) { + while (slice_index > 0 && _times[slice_index - 1] > t) { slice_index--; } - } - - return(slice_index); -} - - - - + return (slice_index); +} // Get rates using time slice and singles bin indices. -int -SinglesRatesFromSglFile:: -get_singles_rate(int singles_bin_index, int time_slice) const { - +int +SinglesRatesFromSglFile::get_singles_rate(int singles_bin_index, int time_slice) const { + // Check ranges. int total_singles_units = scanner_sptr->get_num_singles_units(); - - if ( singles_bin_index < 0 || singles_bin_index >= total_singles_units || - time_slice < 0 || time_slice >= _num_time_slices ) { - return(0); + + if (singles_bin_index < 0 || singles_bin_index >= total_singles_units || time_slice < 0 || time_slice >= _num_time_slices) { + return (0); } else { return _singles[time_slice][singles_bin_index]; } - } - - // Set a singles rate by bin index and time slice. -void -SinglesRatesFromSglFile:: -set_singles_rate(int singles_bin_index, int time_slice, int new_rate) { - +void +SinglesRatesFromSglFile::set_singles_rate(int singles_bin_index, int time_slice, int new_rate) { + int total_singles_units = scanner_sptr->get_num_singles_units(); - - if ( singles_bin_index >= 0 && singles_bin_index < total_singles_units && - time_slice >= 0 && time_slice < _num_time_slices ) { + + if (singles_bin_index >= 0 && singles_bin_index < total_singles_units && time_slice >= 0 && time_slice < _num_time_slices) { _singles[time_slice][singles_bin_index] = new_rate; } } - - - -int -SinglesRatesFromSglFile:: -rebin(std::vector& new_end_times) { +int +SinglesRatesFromSglFile::rebin(std::vector& new_end_times) { const int num_new_slices = new_end_times.size(); const int total_singles_units = scanner_sptr->get_num_singles_units(); - + // Create the new array of singles data. - Array<2, int> new_singles = Array<2, int>(IndexRange2D(0, num_new_slices - 1, - 0, total_singles_units - 1)); - - + Array<2, int> new_singles = Array<2, int>(IndexRange2D(0, num_new_slices - 1, 0, total_singles_units - 1)); + // Sort the set of new time slices. std::sort(new_end_times.begin(), new_end_times.end()); // Start with initial time of 0.0 seconds. double start_time = 0; - // Loop over new time slices. - for(unsigned int new_slice = 0 ; new_slice < new_end_times.size(); ++new_slice) { + for (unsigned int new_slice = 0; new_slice < new_end_times.size(); ++new_slice) { // End time for the new time slice. double end_time = new_end_times[new_slice]; // If start time is beyond last end time in original data, then use zeros. - if ( start_time > _times[_num_time_slices - 1] ) { - for(int singles_bin = 0 ; singles_bin < total_singles_units ; ++singles_bin) { + if (start_time > _times[_num_time_slices - 1]) { + for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { new_singles[new_slice][singles_bin] = 0; } } else { // Get the singles rate average between start and end times for all bins. - for(int singles_bin = 0 ; singles_bin < total_singles_units ; ++singles_bin ) { - new_singles[new_slice][singles_bin] = - round(get_singles_rate(singles_bin, start_time, end_time)); + for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { + new_singles[new_slice][singles_bin] = round(get_singles_rate(singles_bin, start_time, end_time)); } - } - + // Next new time slice starts at the end of this slice. start_time = end_time; - } - - + // Set the singles and times using the new sets. _singles = new_singles; _times = new_end_times; _num_time_slices = _times.size(); - - return(_num_time_slices); -} + return (_num_time_slices); +} - -std::vector -SinglesRatesFromSglFile::get_times() const -{ +std::vector +SinglesRatesFromSglFile::get_times() const { return _times; } - - - int -SinglesRatesFromSglFile:: -get_num_time_slices() const { - return(_num_time_slices); +SinglesRatesFromSglFile::get_num_time_slices() const { + return (_num_time_slices); } - - double -SinglesRatesFromSglFile:: -get_singles_time_interval() const { - return(_singles_time_interval); +SinglesRatesFromSglFile::get_singles_time_interval() const { + return (_singles_time_interval); } - - - - int -SinglesRatesFromSglFile:: -read_singles_from_sgl_file(const std::string& sgl_filename) -{ +SinglesRatesFromSglFile::read_singles_from_sgl_file(const std::string& sgl_filename) { int slice = 0; @@ -367,95 +287,78 @@ read_singles_from_sgl_file(const std::string& sgl_filename) error("\nSinglesRatesFromSglFile: Couldn't open \"%s\".\n", sgl_filename.c_str()); } - - //first find out the size of the file + // first find out the size of the file singles_file.seekg(0, ios::end); const streampos end_stream_position = singles_file.tellg(); if (!singles_file) { - error("\nSinglesRatesFromSglFile: Couldn't seek to end of file %s.",sgl_filename.c_str()); + error("\nSinglesRatesFromSglFile: Couldn't seek to end of file %s.", sgl_filename.c_str()); } - // go to the beginning and read the singles header singles_file.seekg(0, ios::beg); - + if (!singles_file) { - error("\nSinglesRatesFromSglFile: Couldn't seek to start of file %s.",sgl_filename.c_str()); + error("\nSinglesRatesFromSglFile: Couldn't seek to start of file %s.", sgl_filename.c_str()); } - { char buffer[sizeof(Main_header)]; - singles_file.read(buffer,sizeof(_singles_main_header)); - if (!singles_file) - { - error("\nSinglesRatesFromSglFile: Couldn't read main_header from %s.",sgl_filename.c_str()); - } - else - { + singles_file.read(buffer, sizeof(_singles_main_header)); + if (!singles_file) { + error("\nSinglesRatesFromSglFile: Couldn't read main_header from %s.", sgl_filename.c_str()); + } else { unmap_main_header(buffer, &_singles_main_header); ecat::ecat7::find_scanner(scanner_sptr, _singles_main_header); } } - if (scanner_sptr->get_type() != Scanner::E966) { warning("check SinglesRatesFromSglFile for non-966\n"); } - // Get total number of bins for this type of scanner. const int total_singles_units = scanner_sptr->get_num_singles_units(); // Calculate number of time slices from the length of the data (file size minus header). - _num_time_slices = - static_cast((end_stream_position - static_cast(512)) / - SIZE_OF_SINGLES_RECORD); + _num_time_slices = static_cast((end_stream_position - static_cast(512)) / SIZE_OF_SINGLES_RECORD); - // Allocate the main array. + // Allocate the main array. _singles = Array<2, int>(IndexRange2D(0, _num_time_slices - 1, 0, total_singles_units - 1)); - singles_file.seekg(512, ios::beg); - + while (singles_file && slice < _num_time_slices) { - + // Temporary space to store file data. sgl_str singles_str; - { unsigned char buffer[SIZE_OF_SINGLES_RECORD]; - - singles_file.read(reinterpret_cast(buffer), SIZE_OF_SINGLES_RECORD); + + singles_file.read(reinterpret_cast(buffer), SIZE_OF_SINGLES_RECORD); if (!singles_file) { - + if (!singles_file.eof()) { - warning("Error reading singles file record %d. Stopped reading from this point.", - slice); + warning("Error reading singles file record %d. Stopped reading from this point.", slice); } break; } singles_str.time = convert_4_bytes(buffer); - singles_str.num_sgl = convert_4_bytes(buffer+4); - - for (unsigned int i = 0; i < ( SIZE_OF_SINGLES_RECORD - 8)/4; ++i) { - singles_str.sgl[i] = convert_4_bytes(buffer+8+4*i); + singles_str.num_sgl = convert_4_bytes(buffer + 4); + + for (unsigned int i = 0; i < (SIZE_OF_SINGLES_RECORD - 8) / 4; ++i) { + singles_str.sgl[i] = convert_4_bytes(buffer + 8 + 4 * i); } } - if (singles_str.num_sgl != total_singles_units) { - error("Number of singles units should be %d, but is %d in singles file", - total_singles_units, singles_str.num_sgl); + error("Number of singles units should be %d, but is %d in singles file", total_singles_units, singles_str.num_sgl); } - - // Copy the singles values to the main array. - + // Note. The singles values are arranged num_axial sets of num_transaxial // values. // @@ -468,43 +371,35 @@ read_singles_from_sgl_file(const std::string& sgl_filename) for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { _singles[slice][singles_bin] = static_cast(singles_str.sgl[singles_bin]); } - - + // singles in the sgl file given in msec.multiply with 0.001 to convert into sec. - _times.push_back(singles_str.time*0.001); + _times.push_back(singles_str.time * 0.001); // Add the last two words - total prompts and total randoms. _total_prompts.push_back(singles_str.sgl[total_singles_units]); _total_randoms.push_back(singles_str.sgl[total_singles_units + 1]); - + // Increment the slice index. ++slice; - } - - assert(_times.size()!=0); + + assert(_times.size() != 0); _singles_time_interval = _times[1] - _times[0]; - - if (slice != _num_time_slices) - { + + if (slice != _num_time_slices) { error("\nSinglesRatesFromSglFile: Couldn't read all records in the .sgl file %s. Read %d of %d. Exiting\n", - sgl_filename.c_str(), slice, _num_time_slices); - //TODO resize singles to return array with new sizes + sgl_filename.c_str(), slice, _num_time_slices); + // TODO resize singles to return array with new sizes } #endif // Return number of time slices read. - return slice; - + return slice; } - - - - // Write SinglesRatesFromSglFile to a singles file. -std::ostream& +std::ostream& SinglesRatesFromSglFile::write(std::ostream& output) { #ifndef HAVE_LLN_MATRIX @@ -512,36 +407,35 @@ SinglesRatesFromSglFile::write(std::ostream& output) { error("Compiled without ECAT7 support\n"); #else - + char header_buffer[SIZE_OF_SINGLES_RECORD]; unsigned char buffer[SIZE_OF_SINGLES_RECORD]; - + memset(header_buffer, 0, SIZE_OF_SINGLES_RECORD); // Write header to buffer. map_main_header(header_buffer, &(this->_singles_main_header)); - + // Write buffer to output. output.write(header_buffer, SIZE_OF_SINGLES_RECORD); if (!output) { error("\nSinglesRatesFromSglFile: Failed to write to output."); - return(output); + return (output); } - - + // Empty buffer. memset(buffer, 0, SIZE_OF_SINGLES_RECORD); - + int total_singles_units = scanner_sptr->get_num_singles_units(); unsigned long millisecs; - + // Write 512 byte blocks. One for each time slice recorded. - for(int slice = 0 ; slice < _num_time_slices ; ++slice) { - + for (int slice = 0; slice < _num_time_slices; ++slice) { + // Write data to buffer. millisecs = static_cast(floor(_times[slice] * 1000.0)); - + // Time and number of singles units convert_int_to_4_bytes(millisecs, buffer); convert_int_to_4_bytes(total_singles_units, buffer + 4); @@ -549,219 +443,169 @@ SinglesRatesFromSglFile::write(std::ostream& output) { // Singles units // Note that the order of values in _singles is the same as that of the file. // This may not be the case for other file formats. - for(int singles_bin = 0 ; singles_bin < total_singles_units ; ++singles_bin) { + for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { convert_int_to_4_bytes(_singles[slice][singles_bin], buffer + ((2 + singles_bin) * 4)); } - + // Total prompts and total trues convert_int_to_4_bytes(_total_prompts[slice], buffer + ((2 + total_singles_units) * 4)); convert_int_to_4_bytes(_total_randoms[slice], buffer + ((2 + total_singles_units + 1) * 4)); - - + // Write buffer to output. - output.write(reinterpret_cast(buffer), SIZE_OF_SINGLES_RECORD); - + output.write(reinterpret_cast(buffer), SIZE_OF_SINGLES_RECORD); + if (!output) { error("\nSinglesRatesFromSglFile: Failed to write to output."); break; } - } - #endif return output; } - - float -SinglesRatesFromSglFile:: -get_singles_rate(const int singles_bin_index, - const double start_time, const double end_time) const { +SinglesRatesFromSglFile::get_singles_rate(const int singles_bin_index, const double start_time, const double end_time) const { - // First Calculate an inclusive range. start_time_slice is the + // First Calculate an inclusive range. start_time_slice is the // the first slice with an ending time greater than start_time. // end_time_slice is the first time slice that ends at, or after, // end_time. int start_slice = this->get_start_time_slice_index(start_time); int end_slice = this->get_end_time_slice_index(end_time); - - + // Total contribution from all slices. double total_singles; - - if ( start_slice == end_slice ) { + if (start_slice == end_slice) { // If the start and end slices are the same then just use that time slice. total_singles = static_cast(_singles[start_slice][singles_bin_index]); } else { - + // Start and end times for starting and ending slices. double slice_start_time; double slice_end_time; - double included_duration; + double included_duration; double old_duration; double fraction; - - + // Total slices included (including fractional amounts) in the average. float total_slices; - - // Calculate the fraction of the start_slice to include. slice_start_time = get_slice_start(start_slice); slice_end_time = _times[start_slice]; - + old_duration = slice_end_time - slice_start_time; included_duration = slice_end_time - start_time; - + fraction = included_duration / old_duration; - - + // Set the total number of contributing bins to this fraction. total_slices = fraction; - + // Set the total singles so far to be the fraction of the bin. total_singles = fraction * _singles[start_slice][singles_bin_index]; - - - + // Calculate the fraction of the end_slice to include. slice_start_time = get_slice_start(end_slice); slice_end_time = _times[end_slice]; - + old_duration = slice_end_time - slice_start_time; included_duration = end_time - slice_start_time; - + fraction = included_duration / old_duration; - + // Add this fraction to the total of the number of bins contributing. total_slices += fraction; - + // Add the fraction of the bin to the running total. total_singles += fraction * _singles[end_slice][singles_bin_index]; - - + // Add all intervening slices. - for(int slice = start_slice + 1; slice < end_slice ; ++slice, total_slices += 1.0) { + for (int slice = start_slice + 1; slice < end_slice; ++slice, total_slices += 1.0) { total_singles += _singles[slice][singles_bin_index]; } - - + // Divide by total amount of contributing slices. total_singles = total_singles / total_slices; - } - return( static_cast(total_singles) ); - + return (static_cast(total_singles)); } - - /* * * Private methods. * */ +void +SinglesRatesFromSglFile::set_time_interval() { - - - -void -SinglesRatesFromSglFile:: -set_time_interval() { - - // Run through the _times vector and calculate an average difference + // Run through the _times vector and calculate an average difference // between the starts of consecutive time slices. - + // Min and max differences (slice durations). double min_diff = 0; double max_diff = 0; double total = 0; - for(std::vector::const_iterator t = _times.begin(); t < _times.end() - 1; ++t) { - double diff = *(t + 1) - *t; + for (std::vector::const_iterator t = _times.begin(); t < _times.end() - 1; ++t) { + double diff = *(t + 1) - *t; total += diff; - if ( min_diff == 0 || diff < min_diff ) { + if (min_diff == 0 || diff < min_diff) { min_diff = diff; } - if ( diff > max_diff ) { + if (diff > max_diff) { max_diff = diff; } } - + _singles_time_interval = total / (_times.size() - 1); - - if ( (max_diff - min_diff) / (_singles_time_interval) > MAX_INTERVAL_DIFFERENCE ) { + + if ((max_diff - min_diff) / (_singles_time_interval) > MAX_INTERVAL_DIFFERENCE) { // Slice durations are not consistent enough to be considered the same. _singles_time_interval = 0; } - } - // get slice start time. -double -SinglesRatesFromSglFile:: -get_slice_start(int slice_index) const { +double +SinglesRatesFromSglFile::get_slice_start(int slice_index) const { - if ( slice_index >= _num_time_slices ) { + if (slice_index >= _num_time_slices) { slice_index = _num_time_slices - 1; } - - if ( slice_index == 0 ) { - return(0); + + if (slice_index == 0) { + return (0); } else { - return(_times[slice_index - 1]); + return (_times[slice_index - 1]); } } - - - - - -void -SinglesRatesFromSglFile:: -initialise_keymap() -{ +void +SinglesRatesFromSglFile::initialise_keymap() { parser.add_start_key("Singles Rates From Sgl File"); parser.add_key("sgl_filename", &_sgl_filename); parser.add_stop_key("End Singles Rates From Sgl File"); } -bool -SinglesRatesFromSglFile:: -post_processing() -{ +bool +SinglesRatesFromSglFile::post_processing() { read_singles_from_sgl_file(_sgl_filename); return false; } - -void -SinglesRatesFromSglFile::set_defaults() -{ +void +SinglesRatesFromSglFile::set_defaults() { _sgl_filename = ""; } - - - - - - - END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT END_NAMESPACE_STIR - - - diff --git a/src/data_buildblock/data_buildblock_registries.cxx b/src/data_buildblock/data_buildblock_registries.cxx index b021e683ff..13b9589346 100644 --- a/src/data_buildblock/data_buildblock_registries.cxx +++ b/src/data_buildblock/data_buildblock_registries.cxx @@ -23,15 +23,15 @@ \brief File that registers all stir::RegisterObject children in data_buildblock \author Kris Thielemans - + */ #include "stir/common.h" #ifdef HAVE_LLN_MATRIX -#include "stir/data/SinglesRatesFromECAT7.h" -#include "stir/data/SinglesRatesFromSglFile.h" +# include "stir/data/SinglesRatesFromECAT7.h" +# include "stir/data/SinglesRatesFromSglFile.h" #endif #ifdef HAVE_HDF5 -#include "stir/data/SinglesRatesFromGEHDF5.h" +# include "stir/data/SinglesRatesFromGEHDF5.h" #endif START_NAMESPACE_STIR #ifdef HAVE_LLN_MATRIX @@ -47,4 +47,3 @@ static GE::RDF_HDF5::SinglesRatesFromGEHDF5::RegisterIt dummy300; #endif END_NAMESPACE_STIR - diff --git a/src/display/display_array.cxx b/src/display/display_array.cxx index cc75e6019e..c39461077b 100644 --- a/src/display/display_array.cxx +++ b/src/display/display_array.cxx @@ -16,15 +16,15 @@ */ /*! - \file + \file \ingroup display - + \brief Functions to display stir::Array objects (2d and 3d) and stir::RelatedViewgrams - + \author Kris Thielemans \author PARAPET project - - + + \see display.h for some comments on the interface. @@ -33,9 +33,9 @@
  • STIR_SIMPLE_BITMAPS is based on some functions KT wrote in 1991, - which work in XWindows, DOS (upto SVGA resolution, or using a PGA) and + which work in XWindows, DOS (upto SVGA resolution, or using a PGA) and a VAX using a Matrox card (very much similar to PGA). - It's fairly simplistic. No menus. + It's fairly simplistic. No menus.
  • STIR_MATHLINK puts the imageinfo over a MathLink connection to Mathematica, where it can be displayed anyway you like. @@ -46,17 +46,17 @@ if both STIR_SIMPLE_BITMAPS and STIR_MATHLINK are defined, stir::display asks which version you want to use - + */ // further doxygen comments. Only enabled when running doxygen #ifdef DOXYGEN_SKIP // we need to define these to get doxygen to process their comments -#define STIR_SIMPLE_BITMAPS -#define STIR_MATHLINK -#define STIR_PGM +# define STIR_SIMPLE_BITMAPS +# define STIR_MATHLINK +# define STIR_PGM #endif /*! \def STIR_SIMPLE_BITMAPS - \brief Preprocessor symbol that needs to be defined to enable X-windows + \brief Preprocessor symbol that needs to be defined to enable X-windows functionality for stir::display. \see display_array.cxx for some info @@ -68,7 +68,7 @@ \see display_array.cxx for some info */ /*! \def STIR_SIMPLE_BITMAPS - \brief Preprocessor symbol that needs to be defined to enable PGM + \brief Preprocessor symbol that needs to be defined to enable PGM functionality for stir::display. \see display_array.cxx for some info @@ -83,48 +83,41 @@ #include #include - -// First we define the different implementations. +// First we define the different implementations. // See end of file for display() itself. #ifdef STIR_SIMPLE_BITMAPS // #include "gen.h" // gen.h defined Min (which is used in screen.h) -#define Min std::min -#include "screen.h" -#include +# define Min std::min +# include "screen.h" +# include START_NAMESPACE_STIR // local helper routine, defined after display() template -static void Array2DtoSCImg ( - image_t image[], - const Array<2,elemT>& plane, - int scale, double maxi); +static void Array2DtoSCImg(image_t image[], const Array<2, elemT>& plane, int scale, double maxi); /* KT Warning: g++ 2.7.2.2 compiler bug: - when using VectorWithOffset for the scale_factors (and not the template + when using VectorWithOffset for the scale_factors (and not the template SCALE), g++ complains about a null character. Removing any of the other - parameters, or using int or double as the type, makes this g++ bug + parameters, or using int or double as the type, makes this g++ bug disappear. Or indeed, using a template... */ template -void display_bitmap(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, const char * const title, int scale) -{ +void +display_bitmap(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi, const char* const title, int scale) { if (plane_stack.get_length() == 0) return; Coordinate3D min_indices; Coordinate3D max_indices; - if (!plane_stack.get_regular_range(min_indices, max_indices)) - { + if (!plane_stack.get_regular_range(min_indices, max_indices)) { warning("display_bitmap: can only display 'regular' arrays. Returning.\n"); return; } @@ -133,7 +126,7 @@ void display_bitmap(const Array<3,elemT>& plane_stack, const int length_x = max_indices[3] - min_indices[3] + 1; // KT 30/05/2002 open a window here first, such that SC_X_MAX is set to actual window size - SC_START_BIG(); // KT 30/05/2002 select bigger window size + SC_START_BIG(); // KT 30/05/2002 select bigger window size // window dimensions const int min_x = 0; const int min_y = 0; @@ -143,67 +136,56 @@ void display_bitmap(const Array<3,elemT>& plane_stack, // first try to get all images in one window int num_in_window = plane_stack.get_length(); - screen_image_t *sc_image = new screen_image_t[num_in_window]; - num_in_window = center_sc_images(&scale,min_x,max_x,min_y,max_y, - length_x, - length_y, - sc_image,num_in_window); - if (num_in_window == 0) - { + screen_image_t* sc_image = new screen_image_t[num_in_window]; + num_in_window = center_sc_images(&scale, min_x, max_x, min_y, max_y, length_x, length_y, sc_image, num_in_window); + if (num_in_window == 0) { SC_STOP(); return; } - int nr=plane_stack.get_min_index(); + int nr = plane_stack.get_min_index(); int i; - while (nr<=plane_stack.get_max_index()) - { - if (nr!=plane_stack.get_min_index()) - SC_START_BIG(); // KT 30/05/2002 select bigger window size + while (nr <= plane_stack.get_max_index()) { + if (nr != plane_stack.get_min_index()) + SC_START_BIG(); // KT 30/05/2002 select bigger window size SC_MASK(SC_M_ALL); - SC_CLEAR_BLOCK((SC_C_BACKGROUND+ SC_C_MAX)/3,0,(int)SC_X_MAX ,0,(int)SC_Y_MAX ); - SC_SCALE(SC_X_MAX-30,30, 20, SC_Y_MAX - 60); + SC_CLEAR_BLOCK((SC_C_BACKGROUND + SC_C_MAX) / 3, 0, (int)SC_X_MAX, 0, (int)SC_Y_MAX); + SC_SCALE(SC_X_MAX - 30, 30, 20, SC_Y_MAX - 60); // output title, making some attempt to centre it - if (title != 0) - put_textstr(SC_X_MAX/2 - strlen(title)*4, 35, title); + if (title != 0) + put_textstr(SC_X_MAX / 2 - strlen(title) * 4, 35, title); - const long image_sizeX = scale*(length_x-1)+1; - const long image_sizeY = scale*(length_y-1)+1; + const long image_sizeX = scale * (length_x - 1) + 1; + const long image_sizeY = scale * (length_y - 1) + 1; - for(i=0; i& plane_stack, strcpy(sc_image[i].text, (text[nr] == 0) ? "" : text[nr]); } - draw_sc_images(image_sizeX, - image_sizeY, - sc_image,i); + draw_sc_images(image_sizeX, image_sizeY, sc_image, i); SC_STOP(); - for ( i--; i>=0; i--) - { - //delete[] (sc_image[i].image); now deleted by XDestroyImage - delete[] (sc_image[i].text); + for (i--; i >= 0; i--) { + // delete[] (sc_image[i].image); now deleted by XDestroyImage + delete[](sc_image[i].text); } - if (plane_stack.get_max_index()>nr) - if( !ask("Continue display?",true) ) - break; /* out of while */ + if (plane_stack.get_max_index() > nr) + if (!ask("Continue display?", true)) + break; /* out of while */ } delete[] sc_image; } - // local functions template -static void Array2DtoSCImg ( - image_t image[], - const Array<2,elemT>& plane, - int scale, double maxi) -{ - image_t *pimage; - register image_t *pix; - register int y_count,x_count,i; +static void +Array2DtoSCImg(image_t image[], const Array<2, elemT>& plane, int scale, double maxi) { + image_t* pimage; + register image_t* pix; + register int y_count, x_count, i; // length x,y of original image const int org_length_y = plane.get_length(); const int org_length_x = plane[plane.get_min_index()].get_length(); // length_x,y sizes of constructed image - const int length_x = scale*(org_length_x-1)+1; + const int length_x = scale * (org_length_x - 1) + 1; // const int length_y = scale*(org_length_y-1)+1; /* pix : address in image of current pixel */ - pimage = image; - for (y_count=plane.get_min_index(); y_count<=plane.get_max_index(); y_count++, pimage+=length_x*scale) - for (x_count=plane[y_count].get_min_index(), pix=pimage; x_count<=plane[y_count].get_max_index(); x_count++, pix+=scale) - { + pimage = image; + for (y_count = plane.get_min_index(); y_count <= plane.get_max_index(); y_count++, pimage += length_x * scale) + for (x_count = plane[y_count].get_min_index(), pix = pimage; x_count <= plane[y_count].get_max_index(); + x_count++, pix += scale) { const elemT current = plane[y_count][x_count]; - if (current<=0) + if (current <= 0) *pix = (SC_pixel_t)SC_C_BACKGROUND; - else if ((double)current>=maxi) + else if ((double)current >= maxi) *pix = (SC_pixel_t)SC_C_MAX; else - *pix = (SC_pixel_t)(SC_C_BACKGROUND + - (current * long(SC_C_MAX-SC_C_BACKGROUND)) / maxi); + *pix = (SC_pixel_t)(SC_C_BACKGROUND + (current * long(SC_C_MAX - SC_C_BACKGROUND)) / maxi); } - if (scale==1) return; + if (scale == 1) + return; /* interpolate horizontal lines */ pimage = image; - for (y_count=org_length_y; y_count>0; y_count--, pimage+=length_x*scale) - for (x_count=org_length_x-1,pix=pimage; x_count>0; x_count--,pix+=scale) - { -/* Original, slow but good and easy - float tmp; - - tmp=((float)*(pix+scale) - *pix)/scale ; - for (i=1; i the rounding factor .5 becomes 0x80) - Note: the (int) conversion in the tmp=.... line shouldn't be necessary, - but MsC 5.1 wrongly assumes unsigned long's - when SC_pixel_t is unsigned. -*/ + for (y_count = org_length_y; y_count > 0; y_count--, pimage += length_x * scale) + for (x_count = org_length_x - 1, pix = pimage; x_count > 0; x_count--, pix += scale) { + /* Original, slow but good and easy + float tmp; + + tmp=((float)*(pix+scale) - *pix)/scale ; + for (i=1; i the rounding factor .5 becomes 0x80) + Note: the (int) conversion in the tmp=.... line shouldn't be necessary, + but MsC 5.1 wrongly assumes unsigned long's + when SC_pixel_t is unsigned. + */ long tmp, init; - tmp = (((long)*(pix+scale) - (int)*pix) * 0x100) / scale ; - for (i=1, init=*pix * 0x100L + 0x80; i0; y_count--, pimage += length_x*scale) - for (x_count=length_x, pix=pimage; x_count>0; x_count--,pix++) - { -/* Original - float tmp; - - tmp=((float)*(pix + length_x*scale) - *pix)/scale ; - for (i=1; i 0; y_count--, pimage += length_x * scale) + for (x_count = length_x, pix = pimage; x_count > 0; x_count--, pix++) { + /* Original + float tmp; + + tmp=((float)*(pix + length_x*scale) - *pix)/scale ; + for (i=1; i -void display_mathlink(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, const char * const title, int scale) -{ +void +display_mathlink(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi, const char* const title, int scale) { if (plane_stack.get_length() == 0) return; - init_and_connectlink( "PARAPET"); - fprintf( stderr, "Writing data to MathLink\n"); - MLPutFunction( lp, "List", plane_stack.get_length()); - if( MLError( lp)) - fprintf( stderr, "Error detected by MathLink: %s.\n", - MLErrorMessage(lp)); + init_and_connectlink("PARAPET"); + fprintf(stderr, "Writing data to MathLink\n"); + MLPutFunction(lp, "List", plane_stack.get_length()); + if (MLError(lp)) + fprintf(stderr, "Error detected by MathLink: %s.\n", MLErrorMessage(lp)); int z = scale_factors.get_min_index(); - for (Array<3,elemT>::const_iterator iter1=plane_stack.begin(); - iter1!=plane_stack.end(); - iter1++, z++) - { - MLPutFunction( lp, "List", iter1->get_length()); - for (Array<2,elemT>::const_iterator iter2=iter1->begin(); iter2!=iter1->end(); iter2++) - { - double *tmp = new double[iter2->get_length()]; - int i = 0; - for (Array<1,elemT>::const_iterator iter3=iter2->begin(); iter3!=iter2->end(); iter3++) - tmp[i++] = static_cast(*iter3)*scale_factors[z]; - MLPutRealList(lp,tmp, static_cast(iter2->get_length())); - delete [] tmp; - } + for (Array<3, elemT>::const_iterator iter1 = plane_stack.begin(); iter1 != plane_stack.end(); iter1++, z++) { + MLPutFunction(lp, "List", iter1->get_length()); + for (Array<2, elemT>::const_iterator iter2 = iter1->begin(); iter2 != iter1->end(); iter2++) { + double* tmp = new double[iter2->get_length()]; + int i = 0; + for (Array<1, elemT>::const_iterator iter3 = iter2->begin(); iter3 != iter2->end(); iter3++) + tmp[i++] = static_cast(*iter3) * scale_factors[z]; + MLPutRealList(lp, tmp, static_cast(iter2->get_length())); + delete[] tmp; } - - if( MLError( lp)) - fprintf( stderr, "Error detected by MathLink: %s.\n", - MLErrorMessage(lp)); - MLEndPacket( lp); - MLFlush( lp); - if( MLError( lp)) - fprintf( stderr, "Error detected by MathLink: %s.\n", - MLErrorMessage(lp)); + } + + if (MLError(lp)) + fprintf(stderr, "Error detected by MathLink: %s.\n", MLErrorMessage(lp)); + MLEndPacket(lp); + MLFlush(lp); + if (MLError(lp)) + fprintf(stderr, "Error detected by MathLink: %s.\n", MLErrorMessage(lp)); /*MLPutFunction( lp, "Exit", 0);*/ } - + END_NAMESPACE_STIR #endif // STIR_MATHLINK #ifdef STIR_PGM -#include +# include START_NAMESPACE_STIR - /* TODO, this ignores all arguments for the moment, except plane_stack and scale_factors */ template -void -display_pgm (const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, const char * const title, int scale) -{ +void +display_pgm(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, const VectorWithOffset& text, + double maxi, const char* const title, int scale) { if (plane_stack.get_length() == 0) return; - + Coordinate3D min_indices; Coordinate3D max_indices; - if (!plane_stack.get_regular_range(min_indices, max_indices)) - { + if (!plane_stack.get_regular_range(min_indices, max_indices)) { warning("display_pgm: can only display 'regular' arrays. Returning.\n"); return; } char name[max_filename_length]; ask_filename_with_extension(name, "Name for PGM file", ".pgm"); - - FILE *pgm = fopen ( name , "wb"); - if (pgm == NULL) - { - warning("Error opening file %s for output to PGM.",name); + + FILE* pgm = fopen(name, "wb"); + if (pgm == NULL) { + warning("Error opening file %s for output to PGM.", name); return; } - + { - int X = max_indices[3] - min_indices[3] + 1; + int X = max_indices[3] - min_indices[3] + 1; // for Y take into account we add 1 white line below every image - int Y = (max_indices[2] - min_indices[2] + 2)*plane_stack.get_length(); - fprintf ( pgm, "P5\n#created by PARAPET display \n%d %d\n255\n", X , Y); + int Y = (max_indices[2] - min_indices[2] + 2) * plane_stack.get_length(); + fprintf(pgm, "P5\n#created by PARAPET display \n%d %d\n255\n", X, Y); } - + double scaled_max; - { + { int z = min_indices[1]; - scaled_max = - static_cast(plane_stack[z].find_max() * scale_factors[z]); - for ( z++; z <= max_indices[1]; z++) - { - const double scaled_plane_max = - static_cast(plane_stack[z].find_max() * scale_factors[z]); + scaled_max = static_cast(plane_stack[z].find_max() * scale_factors[z]); + for (z++; z <= max_indices[1]; z++) { + const double scaled_plane_max = static_cast(plane_stack[z].find_max() * scale_factors[z]); if (scaled_max < scaled_plane_max) - scaled_max = scaled_plane_max; + scaled_max = scaled_plane_max; } } - + info(boost::format("Scaled maximum in image = %1%") % scaled_max); - for ( int z = min_indices[1]; z <= max_indices[1]; z++) - { - for ( int y = min_indices[2]; y <= max_indices[2]; y++) - { - for ( int x = min_indices[3]; x <= max_indices[3]; x++) - { - double val = plane_stack[z][y][x]* scale_factors[z]*254. /scaled_max; - int u = static_cast(val+.5); - fprintf ( pgm, "%c", u<0 ? 0 : u ); - } + for (int z = min_indices[1]; z <= max_indices[1]; z++) { + for (int y = min_indices[2]; y <= max_indices[2]; y++) { + for (int x = min_indices[3]; x <= max_indices[3]; x++) { + double val = plane_stack[z][y][x] * scale_factors[z] * 254. / scaled_max; + int u = static_cast(val + .5); + fprintf(pgm, "%c", u < 0 ? 0 : u); + } } // now draw white line below this image - for ( int x = min_indices[3]; x <= max_indices[3]; x++) - { - fprintf ( pgm, "%c", 255 ); - } + for (int x = min_indices[3]; x <= max_indices[3]; x++) { + fprintf(pgm, "%c", 255); + } } - fclose ( pgm); + fclose(pgm); info(boost::format("Wrote PGM plane_stack to file %1%") % name); } @@ -457,17 +408,12 @@ END_NAMESPACE_STIR #endif // STIR_PGM - START_NAMESPACE_STIR template -void display(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, - const char * const title, - int scale) -{ +void +display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, const VectorWithOffset& text, + double maxi, const char* const title, int scale) { if (plane_stack.get_length() == 0) return; @@ -476,141 +422,99 @@ void display(const Array<3,elemT>& plane_stack, assert(plane_stack.get_min_index() == text.get_min_index()); assert(plane_stack.get_max_index() == text.get_max_index()); - info(boost::format("Displaying %1%") % (title==0 ? "" : title)); + info(boost::format("Displaying %1%") % (title == 0 ? "" : title)); #if defined(STIR_PGM) - display_pgm(plane_stack, scale_factors, - text, maxi, title, scale); + display_pgm(plane_stack, scale_factors, text, maxi, title, scale); #endif #if defined(STIR_SIMPLE_BITMAPS) && defined(STIR_MATHLINK) - if (ask_num("Display as bitmap (0) or via MathLink (1)",0,1,0) == 0) - display_bitmap(plane_stack, scale_factors, - text, maxi, title, scale); + if (ask_num("Display as bitmap (0) or via MathLink (1)", 0, 1, 0) == 0) + display_bitmap(plane_stack, scale_factors, text, maxi, title, scale); else - display_mathlink(plane_stack, scale_factors, - text, maxi, title, scale); + display_mathlink(plane_stack, scale_factors, text, maxi, title, scale); #endif #if defined(STIR_SIMPLE_BITMAPS) && !defined(STIR_MATHLINK) - display_bitmap(plane_stack, scale_factors, - text, maxi, title, scale); + display_bitmap(plane_stack, scale_factors, text, maxi, title, scale); #endif #if !defined(STIR_SIMPLE_BITMAPS) && defined(STIR_MATHLINK) - display_mathlink(plane_stack, scale_factors, - text, maxi, title, scale); + display_mathlink(plane_stack, scale_factors, text, maxi, title, scale); #endif } template -void display(const RelatedViewgrams& vs, - double maxi, - const char * const title, - int zoom) -{ - Array<3,float> - all_of_them(IndexRange3D(0,vs.get_num_viewgrams()-1, - vs.get_min_axial_pos_num(),vs.get_max_axial_pos_num(), - vs.get_min_tangential_pos_num(),vs.get_max_tangential_pos_num())); - std::copy(vs.begin(), vs.end(), all_of_them.begin()); - - VectorWithOffset text(all_of_them.get_min_index(), - all_of_them.get_max_index()); - - VectorWithOffset::iterator text_iter = text.begin(); +void +display(const RelatedViewgrams& vs, double maxi, const char* const title, int zoom) { + Array<3, float> all_of_them(IndexRange3D(0, vs.get_num_viewgrams() - 1, vs.get_min_axial_pos_num(), vs.get_max_axial_pos_num(), + vs.get_min_tangential_pos_num(), vs.get_max_tangential_pos_num())); + std::copy(vs.begin(), vs.end(), all_of_them.begin()); + + VectorWithOffset text(all_of_them.get_min_index(), all_of_them.get_max_index()); + + VectorWithOffset::iterator text_iter = text.begin(); typename RelatedViewgrams::const_iterator vs_iter = vs.begin(); - while(vs_iter != vs.end()) - { - *text_iter=new char[100]; - sprintf(*text_iter,"v %d, s %d", vs_iter->get_view_num(), vs_iter->get_segment_num()); + while (vs_iter != vs.end()) { + *text_iter = new char[100]; + sprintf(*text_iter, "v %d, s %d", vs_iter->get_view_num(), vs_iter->get_segment_num()); ++text_iter; ++vs_iter; } - VectorWithOffset scale_factors(all_of_them.get_min_index(), - all_of_them.get_max_index()); + VectorWithOffset scale_factors(all_of_them.get_min_index(), all_of_them.get_max_index()); scale_factors.fill(1.); - - display(all_of_them, scale_factors, text,maxi, title, zoom); + + display(all_of_them, scale_factors, text, maxi, title, zoom); text_iter = text.begin(); - while(text_iter != text.end()) - { - delete[] *text_iter; + while (text_iter != text.end()) { + delete[] * text_iter; ++text_iter; } } - -void display(const DetPairData& det_pair_data, const char * const title) -{ +void +display(const DetPairData& det_pair_data, const char* const title) { const int num_detectors = det_pair_data.get_num_detectors(); - Array<2,float> full_data(IndexRange2D(num_detectors,num_detectors)); + Array<2, float> full_data(IndexRange2D(num_detectors, num_detectors)); for (int a = det_pair_data.get_min_index(); a <= det_pair_data.get_max_index(); ++a) for (int b = det_pair_data.get_min_index(a); b <= det_pair_data.get_max_index(a); ++b) - full_data[a%num_detectors][b%num_detectors] = - det_pair_data(a,b); - display(full_data,title); + full_data[a % num_detectors][b % num_detectors] = det_pair_data(a, b); + display(full_data, title); } -void display(const FanProjData& fan_data, const char * const title) -{ +void +display(const FanProjData& fan_data, const char* const title) { const int num_rings = fan_data.get_num_rings(); const int num_detectors_per_ring = fan_data.get_num_detectors_per_ring(); - Array<3,float> full_data(IndexRange3D(num_rings,num_detectors_per_ring,num_detectors_per_ring)); - for (int ra=fan_data.get_min_ra(); ra <= fan_data.get_max_ra(); ++ra) - { + Array<3, float> full_data(IndexRange3D(num_rings, num_detectors_per_ring, num_detectors_per_ring)); + for (int ra = fan_data.get_min_ra(); ra <= fan_data.get_max_ra(); ++ra) { full_data.fill(0); - for (int a = 0; a(const Array<3,short>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, const char * const title, int scale); -template -void display<>(const Array<3,short>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, const char * const title, int scale); -template -void display<>(const Array<3,float>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, const char * const title, int scale); - -template -void display<>(const Array<3,short>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, const char * const title, int scale); -template -void display<>(const Array<3,short>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, const char * const title, int scale); -template -void display<>(const Array<3,float>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, const char * const title, int scale); - - -template -void display(const RelatedViewgrams& vs, - double maxi, - const char * const title, - int zoom); +template void display<>(const Array<3, short>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi, const char* const title, int scale); +template void display<>(const Array<3, short>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi, const char* const title, int scale); +template void display<>(const Array<3, float>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi, const char* const title, int scale); + +template void display<>(const Array<3, short>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi, const char* const title, int scale); +template void display<>(const Array<3, short>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi, const char* const title, int scale); +template void display<>(const Array<3, float>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi, const char* const title, int scale); + +template void display(const RelatedViewgrams& vs, double maxi, const char* const title, int zoom); END_NAMESPACE_STIR diff --git a/src/display/gen.c b/src/display/gen.c index 12c48730b7..7ed94d7097 100644 --- a/src/display/gen.c +++ b/src/display/gen.c @@ -1,118 +1,119 @@ /* -*/ + */ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2011, Hammersmith Imanet Ltd See STIR/LICENSE.txt for details */ /*! -\file - +\file + \brief Utility functions used by the screen* files (internal use only) - + \author Kris Thielemans \author PARAPET project - - - \see gen.h + + + \see gen.h \internal */ #include "gen.h" #include - #ifdef VAX -#include ssdef -#include descrip -#include iodef -#include dcdef +# include ssdef +# include descrip +# include iodef +# include dcdef -static $DESCRIPTOR(TTdevice,"TT"); +static $DESCRIPTOR(TTdevice, "TT"); static int TTchannel; -char getch() -{ char chr; +char +getch() { + char chr; unsigned int iosb[2]; - if (TTchannel==0) - error_check(sys$assign(&TTdevice,&TTchannel,0,0)); - error_check(sys$qiow(0,TTchannel,IO$_READVBLK|IO$M_ESCAPE|IO$M_NOECHO, - &iosb,0,0,&chr,sizeof(chr),0,0,0,0)); + if (TTchannel == 0) + error_check(sys$assign(&TTdevice, &TTchannel, 0, 0)); + error_check(sys$qiow(0, TTchannel, IO$_READVBLK | IO$M_ESCAPE | IO$M_NOECHO, &iosb, 0, 0, &chr, sizeof(chr), 0, 0, 0, 0)); return (chr); } #endif +int +asknr(char str[], int minv, int maxv, int def) { + char ptr[10]; + int nnn, ret; -int asknr (char str[],int minv,int maxv,int def) -{ char ptr[10]; - int nnn,ret; - - while(1) - { printf ("\n%s [%d:%d D:%d]: ",str,minv,maxv,def); - if (fgets(ptr,10,stdin) == NULL) + while (1) { + printf("\n%s [%d:%d D:%d]: ", str, minv, maxv, def); + if (fgets(ptr, 10, stdin) == NULL) return def; /* nothing read, so return default */ - ret=sscanf(ptr,"%d",&nnn); - if (ret==0 || ret==EOF) + ret = sscanf(ptr, "%d", &nnn); + if (ret == 0 || ret == EOF) return def; - if ((nnn>=minv) && (nnn<=maxv)) + if ((nnn >= minv) && (nnn <= maxv)) return nnn; puts("\nOut of bounds"); } } -size_t fread_check(char *str, void *buffer, size_t size, FILE *infile) -{ size_t ret; +size_t +fread_check(char* str, void* buffer, size_t size, FILE* infile) { + size_t ret; char tmp[200]; - ret = fread(buffer,sizeof(char),size,infile); - if (ferror(infile)) - { sprintf(tmp,"\n%s: error reading for %lu bytes, %lu read\nreason", - str,(unsigned long)size,(unsigned long)ret); + ret = fread(buffer, sizeof(char), size, infile); + if (ferror(infile)) { + sprintf(tmp, "\n%s: error reading for %lu bytes, %lu read\nreason", str, (unsigned long)size, (unsigned long)ret); perror(tmp); error(""); } - return(ret); + return (ret); } -size_t fwrite_check(char *str, void *buffer, size_t size, FILE *outfile) -{ size_t ret; +size_t +fwrite_check(char* str, void* buffer, size_t size, FILE* outfile) { + size_t ret; char tmp[200]; - ret = fwrite(buffer,1,size,outfile); - if (ret < size || ferror(outfile)) - { sprintf(tmp,"\n%s: error writing for %lu bytes, %lu written\nreason", - str,(unsigned long)size,(unsigned long)ret); + ret = fwrite(buffer, 1, size, outfile); + if (ret < size || ferror(outfile)) { + sprintf(tmp, "\n%s: error writing for %lu bytes, %lu written\nreason", str, (unsigned long)size, (unsigned long)ret); if (ferror(outfile)) perror(tmp); error(""); } - return(ret); + return (ret); } -void fseek_check(char *str, FILE *file, long int offset, int pos) -{ if (fseek(file,offset,pos)) - error("%s: error seeking in file to position %lu",str,offset); +void +fseek_check(char* str, FILE* file, long int offset, int pos) { + if (fseek(file, offset, pos)) + error("%s: error seeking in file to position %lu", str, offset); } +void +message(char* fmt, ...) { + va_list ptr; -void message(char *fmt, ...) -{ va_list ptr; - - va_start(ptr,fmt); - fprintf(stderr,"\n"); - vfprintf(stderr,fmt, ptr); + va_start(ptr, fmt); + fprintf(stderr, "\n"); + vfprintf(stderr, fmt, ptr); va_end(ptr); } -void error(char *fmt, ...) -{ va_list ptr; +void +error(char* fmt, ...) { + va_list ptr; - va_start(ptr,fmt); - fprintf(stderr,"\n"); - vfprintf(stderr,fmt, ptr); - fprintf(stderr,"\n"); + va_start(ptr, fmt); + fprintf(stderr, "\n"); + vfprintf(stderr, fmt, ptr); + fprintf(stderr, "\n"); va_end(ptr); exit(EXIT_FAILURE); } diff --git a/src/display/gen.h b/src/display/gen.h index 563f72485e..993d95cd26 100644 --- a/src/display/gen.h +++ b/src/display/gen.h @@ -1,23 +1,23 @@ -/* -*/ +/* + */ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2001, IRSL See STIR/LICENSE.txt for details */ /*! - \file - + \file + \brief Declares some utility functions used by the screen* files - + \author Kris Thielemans \author PARAPET project - - + + This is part of a library by Kris Thielemans, mainly written in 1991. - + \internal Standard include file where some incompatibilities between various @@ -25,8 +25,8 @@ Currently this supports: VAX VMS - #ifdef VAX - ultrix on MIPS + #ifdef VAX + ultrix on MIPS Solaris on Sparc OSF/1 on Alpha AIX on PowerPC @@ -58,7 +58,7 @@ extern "C" { carriage return. You can use it for detecting arrowkeys in combination with the KB_... macro's. */ -extern char getch(void); +extern char getch(void); /* Macro's for using the arrowkeys. Use in the following way: char ch; ch = getch(); @@ -73,100 +73,94 @@ extern char getch(void); // ch is not changed, or the second character in the escape code Note: The following are ANSI escape sequences */ -#define KB_DIRECTION(c) (c==0x1b && getch()==0x5b && \ - (c=getch())>=0x41 && c<=0x44) -#define KB_UPARROW 0x41 -#define KB_DNARROW 0x42 -#define KB_RTARROW 0x43 -#define KB_LTARROW 0x44 +# define KB_DIRECTION(c) (c == 0x1b && getch() == 0x5b && (c = getch()) >= 0x41 && c <= 0x44) +# define KB_UPARROW 0x41 +# define KB_DNARROW 0x42 +# define KB_RTARROW 0x43 +# define KB_LTARROW 0x44 #endif /* VAX */ #if (defined(_WIN32) || defined(WIN32)) && !defined(MSDOS) -#define MSDOS +# define MSDOS #endif #ifdef MSDOS - /* Change 05/02/98 */ -#ifdef __GNUC__ - /* TODO */ -#define getch() getchar() -#else -#include /* for getch */ -#define getch _getch -#endif +/* Change 05/02/98 */ +# ifdef __GNUC__ +/* TODO */ +# define getch() getchar() +# else +# include /* for getch */ +# define getch _getch +# endif /* Macro's for using the arrowkeys. For explanation see above. Replace "escape code" with "extended charcode" */ -#define KB_DIRECTION(c) (c=='\0' && \ - ((c=(char)getch())==0x48 || c==0x4b ||c==0x4d || \ - c==0x50)) -#define KB_UPARROW 0x48 -#define KB_DNARROW 0x50 -#define KB_RTARROW 0x4d -#define KB_LTARROW 0x4b +# define KB_DIRECTION(c) (c == '\0' && ((c = (char)getch()) == 0x48 || c == 0x4b || c == 0x4d || c == 0x50)) +# define KB_UPARROW 0x48 +# define KB_DNARROW 0x50 +# define KB_RTARROW 0x4d +# define KB_LTARROW 0x4b #endif /* MSDOS */ #if !defined(VAX) && !defined(MSDOS) && !defined(__MSL__) -#include /* for getch */ - /* Change November 1997: added 7 lines - work-around a 'bug'. screen.h includes curses.h which #defines some - symbols which conflict in other C++ includes - */ - -#ifdef clear -#undef clear -#endif -#ifdef erase -#undef erase -#endif +# include /* for getch */ +/* Change November 1997: added 7 lines + work-around a 'bug'. screen.h includes curses.h which #defines some + symbols which conflict in other C++ includes +*/ + +# ifdef clear +# undef clear +# endif +# ifdef erase +# undef erase +# endif /* Macro's for using the arrowkeys. For explanation see above. -*/ -#define KB_DIRECTION(c) (c==0x1b && getch()==0x5b && \ - (c=getch())>=0x41 && c<=0x44) -#define KB_UPARROW 0x41 -#define KB_DNARROW 0x42 -#define KB_RTARROW 0x43 -#define KB_LTARROW 0x44 + */ +# define KB_DIRECTION(c) (c == 0x1b && getch() == 0x5b && (c = getch()) >= 0x41 && c <= 0x44) +# define KB_UPARROW 0x41 +# define KB_DNARROW 0x42 +# define KB_RTARROW 0x43 +# define KB_LTARROW 0x44 #endif /*ultrix*/ #ifdef SC_XWINDOWS -#undef KB_DIRECTION -#undef KB_UPARROW -#undef KB_DNARROW -#undef KB_RTARROW -#undef KB_LTARROW +# undef KB_DIRECTION +# undef KB_UPARROW +# undef KB_DNARROW +# undef KB_RTARROW +# undef KB_LTARROW /* the next one is probably wrong */ -#define KB_DIRECTION(c) (c==0x1b && getch()==0x5b && \ - (c=getch())>=0x41 && c<=0x44) -#define KB_UPARROW XK_Up -#define KB_DNARROW XK_Down -#define KB_RTARROW XK_Right -#define KB_LTARROW XK_Left +# define KB_DIRECTION(c) (c == 0x1b && getch() == 0x5b && (c = getch()) >= 0x41 && c <= 0x44) +# define KB_UPARROW XK_Up +# define KB_DNARROW XK_Down +# define KB_RTARROW XK_Right +# define KB_LTARROW XK_Left #endif #include #ifndef Min -#define Min(x,y) ((x)<(y) ? (x) : (y)) +# define Min(x, y) ((x) < (y) ? (x) : (y)) #endif #ifndef Max -#define Max(x,y) ((x)>(y) ? (x) : (y)) +# define Max(x, y) ((x) > (y) ? (x) : (y)) #endif /************************************************************************** ***************************************************************************/ -extern size_t fread_check (char str[],void * buffer,size_t size,FILE *infile); -extern size_t fwrite_check (char str[],void * buffer,size_t size,FILE *outfile); -extern void fseek_check (char str[],FILE *file, long offset, int pos); - -extern int asknr (char str[],int minv,int maxv,int def); +extern size_t fread_check(char str[], void* buffer, size_t size, FILE* infile); +extern size_t fwrite_check(char str[], void* buffer, size_t size, FILE* outfile); +extern void fseek_check(char str[], FILE* file, long offset, int pos); -extern void message(char *fmt, ...); -extern void error (char *fmt, ...); +extern int asknr(char str[], int minv, int maxv, int def); +extern void message(char* fmt, ...); +extern void error(char* fmt, ...); /* Change November 1997: added next 3 lines (end of extern "C") */ #ifdef __cplusplus diff --git a/src/display/mathlinkhelp.c b/src/display/mathlinkhelp.c index 5dcdefa4ef..1e8e37659a 100644 --- a/src/display/mathlinkhelp.c +++ b/src/display/mathlinkhelp.c @@ -1,5 +1,5 @@ /* -*/ + */ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2001, IRSL @@ -7,120 +7,115 @@ */ /*! -\file - +\file + \brief Functions to write data to MathLink - + \author Kris Thielemans \author PARAPET project - - + + \internal */ #ifdef STIR_MATHLINK -#include "mathlink.h" -#include -#include +# include "mathlink.h" +# include +# include -int asknr (char str[], int minv, int maxv,int def) -{ +int +asknr(char str[], int minv, int maxv, int def) { char ptr[10]; - int nnn,ret; + int nnn, ret; - while(1) - { printf ("\n%s [%d:%d D:%d]: ",str,minv,maxv,def); - fgets(ptr,10,stdin); - ret=sscanf(ptr,"%d",&nnn); - if (ret==0 || ret==EOF) + while (1) { + printf("\n%s [%d:%d D:%d]: ", str, minv, maxv, def); + fgets(ptr, 10, stdin); + ret = sscanf(ptr, "%d", &nnn); + if (ret == 0 || ret == EOF) return def; - if ((nnn>=minv) && (nnn<=maxv)) + if ((nnn >= minv) && (nnn <= maxv)) return nnn; puts("\nOut of bounds"); } } +# if MACINTOSH_MATHLINK +extern int mlmactty_init(char*** argvp); +# endif -#if MACINTOSH_MATHLINK -extern int mlmactty_init( char*** argvp); -#endif - -void init_and_connectlink( char* linkname); -static void mlerror( MLINK lp); - +void init_and_connectlink(char* linkname); +static void mlerror(MLINK lp); MLENV ep = (MLENV)0; MLINK lp = (MLINK)0; - - -static void mlerror( MLINK lp) -{ - if( MLError( lp)){ - fprintf( stderr, "Error detected by MathLink: %s.\n", - MLErrorMessage(lp)); - }else{ - fprintf( stderr, "Error detected by this program.\n"); - } - exit(3); +static void +mlerror(MLINK lp) { + if (MLError(lp)) { + fprintf(stderr, "Error detected by MathLink: %s.\n", MLErrorMessage(lp)); + } else { + fprintf(stderr, "Error detected by this program.\n"); + } + exit(3); } - -static void deinit( void) -{ - if( ep) MLDeinitialize( ep); +static void +deinit(void) { + if (ep) + MLDeinitialize(ep); } - -static void closelink( void) -{ - if( lp) MLClose( lp); +static void +closelink(void) { + if (lp) + MLClose(lp); } - -void init_and_connectlink( char* linkname) -{ - long err; - char arguments[200]; - int num = 0; - - /* test if link is already open */ - if (lp != (MLINK)0) - return; - - num = asknr("Number to add to the linkname",0,500,0); - sprintf(arguments, "-linkconnect -linkname \"%s%d\"", linkname, num); - -/* TCP connection, slow... - num = asknr("TCP IP port to connect to",0,4000,1000); - sprintf(arguments, "-linkconnect -linkprotocol \"TCP\" -linkname \"%d@petnt1\"", num); -*/ - -#if MACINTOSH_MATHLINK - MLYieldFunctionObject yielder; - argc = mlmactty_init( &argv); -#endif - - ep = MLInitialize( (MLParametersPointer)0); - if( ep == (MLENV)0) exit(1); - atexit( deinit); - -#if MACINTOSH_MATHLINK - yielder = MLCreateYieldFunction( ep, NewMLYielderProc( MLDefaultYielder), 0); -#endif - - lp = MLOpenString( ep, arguments, &err); - if(lp == (MLINK)0) exit(2); - atexit( closelink); - -#if MACINTOSH_MATHLINK - MLSetYieldFunction( lp, yielder); -#endif - if( MLError( lp) && MLError(lp) != MLECONNECT) - mlerror(lp); +void +init_and_connectlink(char* linkname) { + long err; + char arguments[200]; + int num = 0; + + /* test if link is already open */ + if (lp != (MLINK)0) + return; + + num = asknr("Number to add to the linkname", 0, 500, 0); + sprintf(arguments, "-linkconnect -linkname \"%s%d\"", linkname, num); + + /* TCP connection, slow... + num = asknr("TCP IP port to connect to",0,4000,1000); + sprintf(arguments, "-linkconnect -linkprotocol \"TCP\" -linkname \"%d@petnt1\"", num); + */ + +# if MACINTOSH_MATHLINK + MLYieldFunctionObject yielder; + argc = mlmactty_init(&argv); +# endif + + ep = MLInitialize((MLParametersPointer)0); + if (ep == (MLENV)0) + exit(1); + atexit(deinit); + +# if MACINTOSH_MATHLINK + yielder = MLCreateYieldFunction(ep, NewMLYielderProc(MLDefaultYielder), 0); +# endif + + lp = MLOpenString(ep, arguments, &err); + if (lp == (MLINK)0) + exit(2); + atexit(closelink); + +# if MACINTOSH_MATHLINK + MLSetYieldFunction(lp, yielder); +# endif + if (MLError(lp) && MLError(lp) != MLECONNECT) + mlerror(lp); } - #endif /*STIR_MATHLINK */ diff --git a/src/display/screen.c b/src/display/screen.c index 3e20819ac0..6e46c78f44 100644 --- a/src/display/screen.c +++ b/src/display/screen.c @@ -1,5 +1,5 @@ -/* -*/ +/* + */ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2012, IRSL @@ -19,18 +19,18 @@ */ /*! \file - + \brief very basic display routines for bitmaps (internal use only) - + \author Kris Thielemans \author PARAPET project - - + + \see screen.h for a few details - + \internal - + */ #include "gen.h" @@ -39,8 +39,8 @@ #include "screen.h" #ifdef SC_XWINDOWS - -Display * SCX_display = NULL; + +Display* SCX_display = NULL; Window SCX_window; GC SCX_gc; XVisualInfo SCX_visual_info; @@ -49,7 +49,7 @@ XVisualInfo SCX_visual_info; For Pseudocolor this is an identity mapping, but not for TrueColor (or any of the other visual classes presumably). */ -unsigned long SCX_color_translation[SC_C_FULL+1]; +unsigned long SCX_color_translation[SC_C_FULL + 1]; static XPixmapFormatValues SCX_pixmap_format; @@ -60,87 +60,79 @@ int SC__curPointX, SC__curPointY, SC__filled; unsigned long SC__color; /* Predefined Color scales */ -#define NUMBER_SCALES 5 +# define NUMBER_SCALES 5 /* this gives RGB values, and the number of entries will be used for linear interpolation between this and the next entry. All .F values should add up to 128. Last entry is used for the annotation color. */ -struct color_info { SC_pixel_t R,G,B,F;}; +struct color_info { + SC_pixel_t R, G, B, F; +}; /* last entry is annotation color */ -struct color_info sm4[6]={{0,0,0,32},{0,64,94,32},{0,127,0,32}, - {127,0,0,32},{127,127,127,0},{127,127,0,0}}; +struct color_info sm4[6] = {{0, 0, 0, 32}, {0, 64, 94, 32}, {0, 127, 0, 32}, + {127, 0, 0, 32}, {127, 127, 127, 0}, {127, 127, 0, 0}}; -struct color_info sm4test[6]={{0,0,0,32},{0,0,127,32},{0,127,0,32}, - {127,0,0,32},{127,127,127,0},{127,127,0,0}}; +struct color_info sm4test[6] = {{0, 0, 0, 32}, {0, 0, 127, 32}, {0, 127, 0, 32}, + {127, 0, 0, 32}, {127, 127, 127, 0}, {127, 127, 0, 0}}; /* change November 1997 .F values added only up to 126, added 2 to the second entry */ -struct color_info sm4green[6]={{0,0,0,32},{0,0,127,64},{0,127,0,31}, - {127,0,0,1},{127,127,127,0},{127,127,0,0}}; +struct color_info sm4green[6] = {{0, 0, 0, 32}, {0, 0, 127, 64}, {0, 127, 0, 31}, + {127, 0, 0, 1}, {127, 127, 127, 0}, {127, 127, 0, 0}}; /* KT 28/11/2002 adjusted first .F value to 128 */ -struct color_info bw[4]={{0,0,0,128},{127,127,127,0},{127,127,0,0}}; +struct color_info bw[4] = {{0, 0, 0, 128}, {127, 127, 127, 0}, {127, 127, 0, 0}}; /* KT 29/01/98 added inverse greyscale */ -struct color_info inverse_bw[4]={{127,127,127,128},{0,0,0,0},{127,127,0,0}}; +struct color_info inverse_bw[4] = {{127, 127, 127, 128}, {0, 0, 0, 0}, {127, 127, 0, 0}}; /* KT 17/07/2000 added braces for inverse_bw */ -struct -{ char name[10]; +struct { + char name[10]; int size; - struct color_info *p; -} all_color_scales[NUMBER_SCALES]={{"sm4",5,sm4},{"sm4test",5,sm4test}, - {"sm4green",5,sm4green},{"bw",2,bw}, - {"inverse_bw",2,inverse_bw}}; - + struct color_info* p; +} all_color_scales[NUMBER_SCALES] = { + {"sm4", 5, sm4}, {"sm4test", 5, sm4test}, {"sm4green", 5, sm4green}, {"bw", 2, bw}, {"inverse_bw", 2, inverse_bw}}; /* KT 28/11/2002 heavily modified to account for TrueColor */ -int CreateColormap(Display *mydisplay, XVisualInfo my_visual_info, struct color_info *x, int size) -{ +int +CreateColormap(Display* mydisplay, XVisualInfo my_visual_info, struct color_info* x, int size) { XColor cc; - int i,j,k; - float tmp_r,tmp_g,tmp_b; -/* XWindows defines RGB values as unsigned 16-bit ints, the color scales above - assume values between 0-127, we have to convert these -*/ + int i, j, k; + float tmp_r, tmp_g, tmp_b; + /* XWindows defines RGB values as unsigned 16-bit ints, the color scales above + assume values between 0-127, we have to convert these + */ const float SCX_Color_conv = 60535. / 127; if (my_visual_info.visual == NULL) return 1; - SCX_Colormap = XCreateColormap(mydisplay,DefaultRootWindow (SCX_display), - my_visual_info.visual, - AllocNone - ); - cc.flags = DoRed | DoGreen |DoBlue; + SCX_Colormap = XCreateColormap(mydisplay, DefaultRootWindow(SCX_display), my_visual_info.visual, AllocNone); + cc.flags = DoRed | DoGreen | DoBlue; - for (i=0,k=0;ix, SCX_hint->y, - (unsigned)SCX_hint->width, (unsigned)SCX_hint->height, 5, - SCX_visual_info.depth, InputOutput, - SCX_visual_info.visual, - CWBackingStore|CWColormap|CWBorderPixel|CWBackingPixel, - &attrib); - - XSetStandardProperties (SCX_display, SCX_window, - "Display", "Display", None, 0, 0, SCX_hint); + SCX_window = XCreateWindow(SCX_display, DefaultRootWindow(SCX_display), SCX_hint->x, SCX_hint->y, (unsigned)SCX_hint->width, + (unsigned)SCX_hint->height, 5, SCX_visual_info.depth, InputOutput, SCX_visual_info.visual, + CWBackingStore | CWColormap | CWBorderPixel | CWBackingPixel, &attrib); + + XSetStandardProperties(SCX_display, SCX_window, "Display", "Display", None, 0, 0, SCX_hint); } - SCX_gc = XCreateGC (SCX_display, SCX_window, 0, 0); + SCX_gc = XCreateGC(SCX_display, SCX_window, 0, 0); - XMapWindow (SCX_display, SCX_window); + XMapWindow(SCX_display, SCX_window); XSync(SCX_display, False); /* first set mask to everything, in case we're not in PseudoColor */ @@ -337,11 +308,11 @@ static void SCX_init(XSizeHints* SCX_hint) SC_MASK(SC_M_ANNOTATE); } -#define SCX_hintX 800 -#define SCX_hintY 600 +# define SCX_hintX 800 +# define SCX_hintY 600 -void SCX_START() -{ +void +SCX_START() { XSizeHints SCX_hint; SCX_hint.x = 50; @@ -353,293 +324,254 @@ void SCX_START() SCX_init(&SCX_hint); } -void SCX_START_BIG() -{ +void +SCX_START_BIG() { XSizeHints SCX_hint; - SCX_hint.x = (unsigned int) SCREEN_X_MAX/100; - SCX_hint.y = (unsigned int) SCREEN_Y_MAX/100; - SCX_hint.width = (unsigned int) SCREEN_X_MAX*9/10; - SCX_hint.height = (unsigned int) SCREEN_Y_MAX*9/10; + SCX_hint.x = (unsigned int)SCREEN_X_MAX / 100; + SCX_hint.y = (unsigned int)SCREEN_Y_MAX / 100; + SCX_hint.width = (unsigned int)SCREEN_X_MAX * 9 / 10; + SCX_hint.height = (unsigned int)SCREEN_Y_MAX * 9 / 10; SCX_hint.flags = PPosition | PSize; SCX_init(&SCX_hint); } -/* Change April 1997: +/* Change April 1997: changed two occurences of XLookupString(&report,...) to XLookupString(&report.xkey,...) It worked previously because report is a union including the correct type. */ -int SCX_WRITE(int *Xpos_x,int *Xpos_y,char *text) -{ /* when deleting characters, pieces of the image could disappear ?? */ +int +SCX_WRITE(int* Xpos_x, int* Xpos_y, char* text) { /* when deleting characters, pieces of the image could disappear ?? */ SC_MASK(SC_M_ANNOTATE); - XSelectInput (SCX_display, SCX_window, - ButtonPressMask | KeyPressMask); - while (1) - { XEvent report; + XSelectInput(SCX_display, SCX_window, ButtonPressMask | KeyPressMask); + while (1) { + XEvent report; char chr[2]; - XNextEvent (SCX_display, &report); - switch (report.type) - { case ButtonPress: - if (report.xbutton.button == Button3) - { int x,y; - int stop = 0; - int nr_chr = 0; - x = *Xpos_x = report.xbutton.x ; - y = *Xpos_y = report.xbutton.y ; - while (!stop) - { XNextEvent (SCX_display, &report); - if (report.type == KeyPress) - { - XLookupString(&report.xkey, &chr[0], 1, NULL, NULL); - chr[1] = '\0'; - switch (chr[0]) - { case 13: /* CR */ - text[nr_chr+1] = '\0'; - stop = 1; - break; - case '\177': /* BS ???? change it */ - if (nr_chr ) - { chr[0] = text[--nr_chr]; - x -= SC_CHAR_SPACING; - SC_MOVE(x,y); - SC_COLOR(SC_C_BACKGROUND); - SC_TEXT(chr); - SC_COLOR(SC_C_ANNOTATE); - } - break; - case 27: /* ESC */ - while(nr_chr) - { chr[0] = text[--nr_chr]; - x -= SC_CHAR_SPACING; - SC_MOVE(x,y); - SC_COLOR(SC_C_BACKGROUND); - SC_TEXT(chr); - SC_COLOR(SC_C_ANNOTATE); - } - break; - default : - SC_MOVE(x,y); - SC_TEXT(chr); - x += SC_CHAR_SPACING; - text[nr_chr++] = chr[0]; - break; + XNextEvent(SCX_display, &report); + switch (report.type) { + case ButtonPress: + if (report.xbutton.button == Button3) { + int x, y; + int stop = 0; + int nr_chr = 0; + x = *Xpos_x = report.xbutton.x; + y = *Xpos_y = report.xbutton.y; + while (!stop) { + XNextEvent(SCX_display, &report); + if (report.type == KeyPress) { + XLookupString(&report.xkey, &chr[0], 1, NULL, NULL); + chr[1] = '\0'; + switch (chr[0]) { + case 13: /* CR */ + text[nr_chr + 1] = '\0'; + stop = 1; + break; + case '\177': /* BS ???? change it */ + if (nr_chr) { + chr[0] = text[--nr_chr]; + x -= SC_CHAR_SPACING; + SC_MOVE(x, y); + SC_COLOR(SC_C_BACKGROUND); + SC_TEXT(chr); + SC_COLOR(SC_C_ANNOTATE); + } + break; + case 27: /* ESC */ + while (nr_chr) { + chr[0] = text[--nr_chr]; + x -= SC_CHAR_SPACING; + SC_MOVE(x, y); + SC_COLOR(SC_C_BACKGROUND); + SC_TEXT(chr); + SC_COLOR(SC_C_ANNOTATE); } + break; + default: + SC_MOVE(x, y); + SC_TEXT(chr); + x += SC_CHAR_SPACING; + text[nr_chr++] = chr[0]; + break; } } } - break; - case KeyPress: - XLookupString(&report.xkey, &chr[0], 1, NULL, NULL); - if (chr[0] == 'q' || chr[0] == 'Q') - { SC_MASK(SC_M_ANNOTATE); - return (0); - } - else return(1); - break; + } + break; + case KeyPress: + XLookupString(&report.xkey, &chr[0], 1, NULL, NULL); + if (chr[0] == 'q' || chr[0] == 'Q') { + SC_MASK(SC_M_ANNOTATE); + return (0); + } else + return (1); + break; } } } -void SCX_STOP(stop) -int stop; -{ XEvent report; - -/* KT 28/11/2002 do this only for PseudoColor visuals. For the others, it is a noop */ - if (SCX_get_class(SCX_visual_info)==PseudoColor) - { - message("To change the colormap, press mouse button 2 and\n" - "to stop the display, press a key.\n" - "Both only work while the display window is selected.\n"); - XSelectInput (SCX_display, SCX_window, KeyPressMask | ButtonPressMask); - } - else - XSelectInput (SCX_display, SCX_window, KeyPressMask); - - while (!stop) - { - XNextEvent (SCX_display, &report); - switch (report.type) - { - case KeyPress: - stop = 1; +void SCX_STOP(stop) int stop; +{ + XEvent report; + + /* KT 28/11/2002 do this only for PseudoColor visuals. For the others, it is a noop */ + if (SCX_get_class(SCX_visual_info) == PseudoColor) { + message("To change the colormap, press mouse button 2 and\n" + "to stop the display, press a key.\n" + "Both only work while the display window is selected.\n"); + XSelectInput(SCX_display, SCX_window, KeyPressMask | ButtonPressMask); + } else + XSelectInput(SCX_display, SCX_window, KeyPressMask); + + while (!stop) { + XNextEvent(SCX_display, &report); + switch (report.type) { + case KeyPress: + stop = 1; + break; + case ButtonPress: + if (report.xbutton.button != Button2) break; - case ButtonPress: - if (report.xbutton.button != Button2) break; - CurrentColormap = (CurrentColormap+1) % NUMBER_SCALES; - - SetColormap(SCX_display, SCX_window, SCX_visual_info, - all_color_scales[CurrentColormap].p, - all_color_scales[CurrentColormap].size); - break; - + CurrentColormap = (CurrentColormap + 1) % NUMBER_SCALES; + + SetColormap(SCX_display, SCX_window, SCX_visual_info, all_color_scales[CurrentColormap].p, + all_color_scales[CurrentColormap].size); + break; } } - XUnmapWindow (SCX_display, SCX_window); - XFreeGC (SCX_display, SCX_gc); - XFreeColormap (SCX_display, SCX_Colormap); - XDestroyWindow (SCX_display, SCX_window); - XCloseDisplay (SCX_display); + XUnmapWindow(SCX_display, SCX_window); + XFreeGC(SCX_display, SCX_gc); + XFreeColormap(SCX_display, SCX_Colormap); + XDestroyWindow(SCX_display, SCX_window); + XCloseDisplay(SCX_display); SCX_display = NULL; } -unsigned SCX_X_MAX() -{ Window wdummy; -/*KT 13/10/98 use different variables to prevent conflicts*/ - int x,y; +unsigned +SCX_X_MAX() { + Window wdummy; + /*KT 13/10/98 use different variables to prevent conflicts*/ + int x, y; unsigned width, height, bw, dep; - if (SCX_display) - XGetGeometry(SCX_display, SCX_window, &wdummy, - &x, &y, &width, &height, &bw, &dep); + if (SCX_display) + XGetGeometry(SCX_display, SCX_window, &wdummy, &x, &y, &width, &height, &bw, &dep); else width = SCX_hintX; return (width); } -unsigned SCX_Y_MAX() -{ Window wdummy; -/*KT 13/10/98 use different variables to prevent conflicts*/ - int x,y; +unsigned +SCX_Y_MAX() { + Window wdummy; + /*KT 13/10/98 use different variables to prevent conflicts*/ + int x, y; unsigned width, height, bw, dep; if (SCX_display) - XGetGeometry(SCX_display, SCX_window, &wdummy, - &x, &y, &width, &height, &bw, &dep); + XGetGeometry(SCX_display, SCX_window, &wdummy, &x, &y, &width, &height, &bw, &dep); else height = SCX_hintY; return (height); } -#undef SCX_hintX -#undef SCX_hintY +# undef SCX_hintX +# undef SCX_hintY /* KT 28/11/2002 heavily modified to account for TrueColor */ -void SCX_PutImg (image,x_begin,y_begin,lengthX,lengthY) -image_t *image; -int x_begin,y_begin, lengthX,lengthY; +void SCX_PutImg(image, x_begin, y_begin, lengthX, lengthY) image_t* image; +int x_begin, y_begin, lengthX, lengthY; { - XImage * myimage; - unsigned char * local_image; + XImage* myimage; + unsigned char* local_image; int bytes_per_line; if (SCX_pixmap_format.depth == 0) return; - bytes_per_line = - ((lengthX*SCX_pixmap_format.bits_per_pixel + - SCX_pixmap_format.scanline_pad-1 - )/SCX_pixmap_format.scanline_pad - ) * (SCX_pixmap_format.scanline_pad/8); + bytes_per_line = + ((lengthX * SCX_pixmap_format.bits_per_pixel + SCX_pixmap_format.scanline_pad - 1) / SCX_pixmap_format.scanline_pad) * + (SCX_pixmap_format.scanline_pad / 8); - if (SCX_get_class(SCX_visual_info)!=PseudoColor || bytes_per_line != lengthX ) - { - /* we'll need to copy the image somewhere else, so reserve space for it*/ - local_image =malloc(bytes_per_line*lengthY); - if (local_image==NULL) - { - message("SCX_PutImg: cannot allocate enough memory. I cannot display this bitmap\n"); - return; - } - } - else - { - local_image = (unsigned char*)image; + if (SCX_get_class(SCX_visual_info) != PseudoColor || bytes_per_line != lengthX) { + /* we'll need to copy the image somewhere else, so reserve space for it*/ + local_image = malloc(bytes_per_line * lengthY); + if (local_image == NULL) { + message("SCX_PutImg: cannot allocate enough memory. I cannot display this bitmap\n"); + return; } - + } else { + local_image = (unsigned char*)image; + } - if (SCX_get_class(SCX_visual_info)!=PseudoColor || bytes_per_line != lengthX ) - { + if (SCX_get_class(SCX_visual_info) != PseudoColor || bytes_per_line != lengthX) { int i; - for (i=0; i< lengthX*lengthY; ++i) - { + for (i = 0; i < lengthX * lengthY; ++i) { unsigned long color; - unsigned char * current_position = - local_image + (i/lengthX)*bytes_per_line + - (i%lengthX)*(SCX_pixmap_format.bits_per_pixel/8); - assert(SCX_pixmap_format.bits_per_pixel%8 == 0 ); - assert(image[i]>=SC_C_BACKGROUND); - assert(image[i]<=SC_C_MAX); + unsigned char* current_position = + local_image + (i / lengthX) * bytes_per_line + (i % lengthX) * (SCX_pixmap_format.bits_per_pixel / 8); + assert(SCX_pixmap_format.bits_per_pixel % 8 == 0); + assert(image[i] >= SC_C_BACKGROUND); + assert(image[i] <= SC_C_MAX); color = SCX_color_translation[image[i]]; /* Now store the color in the pixmap, taking care of bits_per_pixel and byte_order. - Code adapted by KT from a very helpful example by Kip Rugger. + Code adapted by KT from a very helpful example by Kip Rugger. */ - if (SCX_pixmap_format.bits_per_pixel == 8) + if (SCX_pixmap_format.bits_per_pixel == 8) ((unsigned char*)current_position)[0] = (unsigned char)color; - else if (SCX_pixmap_format.bits_per_pixel == 16) - { - if (ImageByteOrder(SCX_display)!=MSBFirst) - { - current_position[0] = color; - current_position[1] = color>>8; - } - else - { - current_position[1] = color; - current_position[0] = color>>8; - } - assert(color>>16==0); - } - else if (SCX_pixmap_format.bits_per_pixel == 24) - { - if (ImageByteOrder(SCX_display)!=MSBFirst) - { - current_position[0] = color; - current_position[1] = color>>8; - current_position[2] = color>>16; - } - else - { - current_position[2] = color; - current_position[1] = color>>8; - current_position[0] = color>>16; - } - assert(color>>24 == 0); - } - else if (SCX_pixmap_format.bits_per_pixel == 32) - { - if (ImageByteOrder(SCX_display)!=MSBFirst) - { - current_position[0] = color; - current_position[1] = color>>8; - current_position[2] = color>>16; - current_position[3] = color>>24; - } - else - { - current_position[3] = color; - current_position[2] = color>>8; - current_position[1] = color>>16; - current_position[0] = color>>24; - } - } - else - { - message("SCX_PutImg: bits_per_pixel (%d) does not match 8,16,24 nor 32\n" - "I cannot display the bitmap. Sorry\n", - SCX_pixmap_format.bits_per_pixel); - return; - } + else if (SCX_pixmap_format.bits_per_pixel == 16) { + if (ImageByteOrder(SCX_display) != MSBFirst) { + current_position[0] = color; + current_position[1] = color >> 8; + } else { + current_position[1] = color; + current_position[0] = color >> 8; + } + assert(color >> 16 == 0); + } else if (SCX_pixmap_format.bits_per_pixel == 24) { + if (ImageByteOrder(SCX_display) != MSBFirst) { + current_position[0] = color; + current_position[1] = color >> 8; + current_position[2] = color >> 16; + } else { + current_position[2] = color; + current_position[1] = color >> 8; + current_position[0] = color >> 16; + } + assert(color >> 24 == 0); + } else if (SCX_pixmap_format.bits_per_pixel == 32) { + if (ImageByteOrder(SCX_display) != MSBFirst) { + current_position[0] = color; + current_position[1] = color >> 8; + current_position[2] = color >> 16; + current_position[3] = color >> 24; + } else { + current_position[3] = color; + current_position[2] = color >> 8; + current_position[1] = color >> 16; + current_position[0] = color >> 24; + } + } else { + message("SCX_PutImg: bits_per_pixel (%d) does not match 8,16,24 nor 32\n" + "I cannot display the bitmap. Sorry\n", + SCX_pixmap_format.bits_per_pixel); + return; + } } free(image); - + } /* !PseudoColor */ - myimage = XCreateImage (SCX_display, - SCX_visual_info.visual, - SCX_pixmap_format.depth, - ZPixmap, /*offset */ 0, (char *)local_image, - (unsigned)lengthX, (unsigned)lengthY, - SCX_pixmap_format.scanline_pad, bytes_per_line); - if (myimage == NULL) - { - message("XcreateImage returned 0. No bitmap displayed.\n"); - return; - } + myimage = XCreateImage(SCX_display, SCX_visual_info.visual, SCX_pixmap_format.depth, ZPixmap, /*offset */ 0, (char*)local_image, + (unsigned)lengthX, (unsigned)lengthY, SCX_pixmap_format.scanline_pad, bytes_per_line); + if (myimage == NULL) { + message("XcreateImage returned 0. No bitmap displayed.\n"); + return; + } assert(myimage->byte_order == ImageByteOrder(SCX_display)); -#if 0 +# if 0 message("XImage props.:\nwidth %d\nheight %d\\n xoffset %d\nbitmap_unit %d\nbitmap_pad %d\ndepth %d\n" "bytes_per_line %d\nbits_per_pixel %d\n" " byte_order: %s\n", @@ -647,68 +579,62 @@ int x_begin,y_begin, lengthX,lengthY; myimage->bitmap_unit, myimage->bitmap_pad, myimage->depth, myimage->bytes_per_line, myimage->bits_per_pixel, myimage->byte_order==MSBFirst ? "MSBFirst" : "LSBFirst"); -#endif - +# endif + SC_MASK(SC_M_ALL); - XPutImage (SCX_display, SCX_window, SCX_gc, myimage, - 0, 0, x_begin, y_begin, (unsigned)lengthX, (unsigned)lengthY); + XPutImage(SCX_display, SCX_window, SCX_gc, myimage, 0, 0, x_begin, y_begin, (unsigned)lengthX, (unsigned)lengthY); SC_MASK(SC_C_ANNOTATE); - XDestroyImage(myimage); /* Note: this deallocates local_image as well */ + XDestroyImage(myimage); /* Note: this deallocates local_image as well */ } -void SCX_SAVE_TO_FILE -(int x_begin,int y_begin,int width,int height,FILE *outfile) -{ XImage * myimage; - char *proc = "SCX_SAVE_TO_FILE"; -/* - char *dat; - - myimage = XCreateImage (SCX_display, - XDefaultVisual (SCX_display, DefaultScreen (SCX_display)), - DefaultDepthOfScreen(DefaultScreenOfDisplay(SCX_display)), - ZPixmap, 0, dat, (int) width, (int)height, 8, 0); -*/ - - myimage = XGetImage(SCX_display, SCX_window,x_begin,y_begin, - width,height, AllPlanes,ZPixmap); - fwrite_check(proc,(void *)myimage->data, - (unsigned long)sizeof(SC_pixel_t)*width*height,outfile); +void +SCX_SAVE_TO_FILE(int x_begin, int y_begin, int width, int height, FILE* outfile) { + XImage* myimage; + char* proc = "SCX_SAVE_TO_FILE"; + /* + char *dat; + + myimage = XCreateImage (SCX_display, + XDefaultVisual (SCX_display, DefaultScreen (SCX_display)), + DefaultDepthOfScreen(DefaultScreenOfDisplay(SCX_display)), + ZPixmap, 0, dat, (int) width, (int)height, 8, 0); + */ + + myimage = XGetImage(SCX_display, SCX_window, x_begin, y_begin, width, height, AllPlanes, ZPixmap); + fwrite_check(proc, (void*)myimage->data, (unsigned long)sizeof(SC_pixel_t) * width * height, outfile); } #endif /* SC_XWINDOWS */ /* change November 1997: added this function (was SCX_SCALE before) */ -/* 30/01/98 put high intensities on top of scale +/* 30/01/98 put high intensities on top of scale 25/11/2002 try this again*/ -void SC_SCALE(pos_x,pos_y,size_x,size_y) -int pos_x, pos_y, size_x, size_y; +void SC_SCALE(pos_x, pos_y, size_x, size_y) int pos_x, pos_y, size_x, size_y; { unsigned char par; - float pos_inc; + float pos_inc; float pos_offset; - assert(pos_y+size_y<=SC_Y_MAX); - assert(pos_x+size_x<=SC_X_MAX); + assert(pos_y + size_y <= SC_Y_MAX); + assert(pos_x + size_x <= SC_X_MAX); SC_MASK(SC_M_ALL); SC_PRMFIL(1); - SC_MOVE(pos_x,pos_y); + SC_MOVE(pos_x, pos_y); /* KT 17/06/2000 condition now uses && instead of a ,*/ /* find pos_offset and pos_inc such that y = pos_offset+par*pos_inc varies between pos_y+size_y and pos_y for par between SC_C_BACKGROUND and SC_C_MAX */ - pos_inc = -((float)size_y) / (SC_C_MAX-SC_C_BACKGROUND+1); - pos_offset = pos_y+size_y - pos_inc*SC_C_BACKGROUND; - for(par=SC_C_BACKGROUND; - par<=SC_C_MAX; - par++) - { SC_COLOR(par); - SC_RECT(pos_x+size_x,(int)(pos_offset+pos_inc*par+.5)); - } + pos_inc = -((float)size_y) / (SC_C_MAX - SC_C_BACKGROUND + 1); + pos_offset = pos_y + size_y - pos_inc * SC_C_BACKGROUND; + for (par = SC_C_BACKGROUND; par <= SC_C_MAX; par++) { + SC_COLOR(par); + SC_RECT(pos_x + size_x, (int)(pos_offset + pos_inc * par + .5)); + } SC_PRMFIL(0); SC_MASK(SC_C_ANNOTATE); /* change November 1997: added rectangle around the color scale */ SC_COLOR(SC_C_ANNOTATE); SC_MOVE(pos_x, pos_y); - SC_RECT(pos_x+size_x, pos_y+size_y); + SC_RECT(pos_x + size_x, pos_y + size_y); } diff --git a/src/display/screen.h b/src/display/screen.h index 2791ca7e84..1e9c50efab 100644 --- a/src/display/screen.h +++ b/src/display/screen.h @@ -1,20 +1,20 @@ /*! \file - + \brief very basic display routines for bitmaps (internal use only) - + \author Kris Thielemans \author PARAPET project - + This is part of a library by Kris Thielemans, mainly written in 1991. It provides macros (and a few functions) for displaying stuff on a screen. The files only contain the macros for XWindows. It's fairly simplistic. No menus. Just simple display of bitmaps, lines, points, text strings. - + \internal - + */ /* Copyright (C) 2000 PARAPET partners @@ -34,180 +34,151 @@ See STIR/LICENSE.txt for details */ - /* Change November 1997: added next 3 lines */ #ifdef __cplusplus extern "C" { #endif #ifdef __STDC__ -#define ANSI +# define ANSI #endif - #ifndef SC_pixel_t -#define SC_pixel_t unsigned char +# define SC_pixel_t unsigned char /* Change 13/02/98 */ -#ifndef MSDOS16BIT +# ifndef MSDOS16BIT typedef SC_pixel_t image_t; -#else +# else typedef SC_pixel_t huge image_t; -#endif +# endif #endif /* SC_pixel_t */ - #ifdef SC_XWINDOWS -#include -#include -#include +# include +# include +# include -#define SC_C_BACKGROUND 12 -#define SC_C_MAX 127 /* maximum color to be used */ -#define SC_C_FULL 255 /* maximum color available */ +# define SC_C_BACKGROUND 12 +# define SC_C_MAX 127 /* maximum color to be used */ +# define SC_C_FULL 255 /* maximum color available */ -extern Display * SCX_display; +extern Display* SCX_display; extern Window SCX_window; extern GC SCX_gc; - /* KT 28/11/2002 added for TrueColor support */ +/* KT 28/11/2002 added for TrueColor support */ extern XVisualInfo SCX_visual_info; -extern unsigned long SCX_color_translation[SC_C_FULL+1]; +extern unsigned long SCX_color_translation[SC_C_FULL + 1]; extern int SC__curPointX, SC__curPointY, SC__filled; extern unsigned long SC__color; extern unsigned SCX_X_MAX(void), SCX_Y_MAX(void); -/* define macro to access XVisualInfo.class. +/* define macro to access XVisualInfo.class. This is renamed by X to c_class when compiling C++ programs. */ -#if defined(__cplusplus) || defined(c_plusplus) -#define SCX_get_class(vinfo) vinfo.c_class -#else -#define SCX_get_class(vinfo) vinfo.class -#endif +# if defined(__cplusplus) || defined(c_plusplus) +# define SCX_get_class(vinfo) vinfo.c_class +# else +# define SCX_get_class(vinfo) vinfo.class +# endif extern void SCX_START(void); /* KT 01/03/2000 added next declaration */ extern void SCX_START_BIG(void); extern void SCX_STOP(int stop); -extern int SCX_WRITE(int *x,int *y,char *text); -extern void SCX_PutImg (image_t *, int x_begin, int y_begin, - int lengthX, int lengthY); - -#define SCREEN_X_MAX 1024 /* VR299 max ??*/ -#define SCREEN_Y_MAX 864 /* VR299 max */ -#define SC_START() SCX_START() -#define SC_START_BIG() SCX_START_BIG() -#define SC_STOP() SCX_STOP(0) -#define SC_STOP_CLEAR() SCX_STOP(1) -#define SC_FLUSH() XSync(SCX_display, False) -#define SC_X_MAX SCX_X_MAX() -#define SC_Y_MAX SCX_Y_MAX() -#define SC_CHAR_WIDTH 10 -#define SC_CHAR_HEIGHT 10 -#define SC_CHAR_SPACING 7 -#define SC_PutImg(image,x,y,lx,ly) \ - SCX_PutImg(image,x,y,lx,ly) -#define SC_TJUST(hor,ver) -#define SC_TSTYLE(par) -#define SC_PRMFIL(par) SC__filled = par -#define SC_COLOR(par) XSetForeground(SCX_display, SCX_gc,\ - SC__color = (unsigned long)SCX_color_translation[par]) -#define SC_TSIZE(par) -#define SC_POINT() XDrawPoint(SCX_display,SCX_window,SCX_gc,\ - SC__curPointX, SC__curPointY) -#define SC_MOVE(x,y) { SC__curPointX = (int)(x); SC__curPointY = (int)(y);} -#define SC_DRAW(x,y) { XDrawLine(SCX_display,SCX_window,SCX_gc,\ - SC__curPointX, SC__curPointY, (int)(x),(int)(y));\ - SC_MOVE(x,y);\ - } -#define SC_LINE(x1,y1,x2,y2)\ - { XDrawLine(SCX_display,SCX_window,SCX_gc,\ - (int)(x1), (int)(y1),\ - SC__curPointX=(int)(x2),\ - SC__curPointY=(int)(y2));\ - } -#define SC_RECT(x,y) ( SC__filled ? \ - XFillRectangle(SCX_display, SCX_window, SCX_gc,\ - (int)Min(x,SC__curPointX), (int)Min(y,SC__curPointY),\ - (unsigned int)abs(x-SC__curPointX), (unsigned int)abs(y-SC__curPointY))\ - : XDrawRectangle(SCX_display, SCX_window, SCX_gc,\ - (int)Min(x,SC__curPointX), (int)Min(y,SC__curPointY),\ - (unsigned int)abs(x-SC__curPointX), (unsigned int)abs(y-SC__curPointY))\ - ) -#define SC_RECTR(x,y) ( SC__filled ? \ - XFillRectangle(SCX_display, SCX_window, SCX_gc,\ - (x<0 ? SC__curPointX + x : SC__curPointX),\ - (y<0 ? SC__curPointY + y : SC__curPointY),\ - abs(x), abs(y))\ - : XDrawRectangle(SCX_display, SCX_window, SCX_gc,\ - (x<0 ? SC__curPointX + x : SC__curPointX),\ - (y<0 ? SC__curPointY + y : SC__curPointY),\ - abs(x), abs(y))\ - ) -#define SC_ELLIPSE(x,y) ( SC__filled ? \ - XFillArc(SCX_display, SCX_window,SCX_gc, \ - SC__curPointX-x,SC__curPointY-y,\ - 2*x, 2*y, 0, 360*64)\ - : XDrawArc(SCX_display, SCX_window,SCX_gc, \ - SC__curPointX-x,SC__curPointY-y,\ - 2*x, 2*y, 0, 360*64)\ - ) -#define SC_CIRCLE(x) SC_ELLIPSE(x,x) -#define SC_TEXT(str) XDrawString(SCX_display, SCX_window,SCX_gc, \ - SC__curPointX, SC__curPointY, \ - str, (int)strlen(str)) - /* KT 28/11/2002 only enable mask when the visual is PseudoColor */ -#define SC_MASK(par) if (SCX_get_class(SCX_visual_info)==PseudoColor) \ - XSetPlaneMask(SCX_display, SCX_gc, \ - (unsigned long)par) -#define SC_LINFUN(par) XSetFunction(SCX_display, SCX_gc, par) -#define SC_LUTX(par,R,G,B) -#define SC_CLEARS(par) -#define SC_LUTINT(par) -#define SC_CLEAR_BLOCK(color,x_b,x_e,y_b,y_e) \ - XSetForeground(SCX_display, SCX_gc,\ - (unsigned long)SCX_color_translation[color]); \ - XFillRectangle(SCX_display, SCX_window, SCX_gc, \ - Min((x_b),(x_e)), Min((y_b),(y_e)),\ - abs((x_b)-(x_e)), abs((y_b)-(y_e))); \ - XSetForeground(SCX_display, SCX_gc,\ - (unsigned long)SC__color); -#define SC_LF_REPLACE GXcopy -#define SC_LF_XOR GXxor -#define SC_DEPTH SCX_visual_info.depth -#define SC_C_ANNOTATE (SC_C_MAX+1) +extern int SCX_WRITE(int* x, int* y, char* text); +extern void SCX_PutImg(image_t*, int x_begin, int y_begin, int lengthX, int lengthY); + +# define SCREEN_X_MAX 1024 /* VR299 max ??*/ +# define SCREEN_Y_MAX 864 /* VR299 max */ +# define SC_START() SCX_START() +# define SC_START_BIG() SCX_START_BIG() +# define SC_STOP() SCX_STOP(0) +# define SC_STOP_CLEAR() SCX_STOP(1) +# define SC_FLUSH() XSync(SCX_display, False) +# define SC_X_MAX SCX_X_MAX() +# define SC_Y_MAX SCX_Y_MAX() +# define SC_CHAR_WIDTH 10 +# define SC_CHAR_HEIGHT 10 +# define SC_CHAR_SPACING 7 +# define SC_PutImg(image, x, y, lx, ly) SCX_PutImg(image, x, y, lx, ly) +# define SC_TJUST(hor, ver) +# define SC_TSTYLE(par) +# define SC_PRMFIL(par) SC__filled = par +# define SC_COLOR(par) XSetForeground(SCX_display, SCX_gc, SC__color = (unsigned long)SCX_color_translation[par]) +# define SC_TSIZE(par) +# define SC_POINT() XDrawPoint(SCX_display, SCX_window, SCX_gc, SC__curPointX, SC__curPointY) +# define SC_MOVE(x, y) \ + { \ + SC__curPointX = (int)(x); \ + SC__curPointY = (int)(y); \ + } +# define SC_DRAW(x, y) \ + { \ + XDrawLine(SCX_display, SCX_window, SCX_gc, SC__curPointX, SC__curPointY, (int)(x), (int)(y)); \ + SC_MOVE(x, y); \ + } +# define SC_LINE(x1, y1, x2, y2) \ + { XDrawLine(SCX_display, SCX_window, SCX_gc, (int)(x1), (int)(y1), SC__curPointX = (int)(x2), SC__curPointY = (int)(y2)); } +# define SC_RECT(x, y) \ + (SC__filled ? XFillRectangle(SCX_display, SCX_window, SCX_gc, (int)Min(x, SC__curPointX), (int)Min(y, SC__curPointY), \ + (unsigned int)abs(x - SC__curPointX), (unsigned int)abs(y - SC__curPointY)) \ + : XDrawRectangle(SCX_display, SCX_window, SCX_gc, (int)Min(x, SC__curPointX), (int)Min(y, SC__curPointY), \ + (unsigned int)abs(x - SC__curPointX), (unsigned int)abs(y - SC__curPointY))) +# define SC_RECTR(x, y) \ + (SC__filled ? XFillRectangle(SCX_display, SCX_window, SCX_gc, (x < 0 ? SC__curPointX + x : SC__curPointX), \ + (y < 0 ? SC__curPointY + y : SC__curPointY), abs(x), abs(y)) \ + : XDrawRectangle(SCX_display, SCX_window, SCX_gc, (x < 0 ? SC__curPointX + x : SC__curPointX), \ + (y < 0 ? SC__curPointY + y : SC__curPointY), abs(x), abs(y))) +# define SC_ELLIPSE(x, y) \ + (SC__filled ? XFillArc(SCX_display, SCX_window, SCX_gc, SC__curPointX - x, SC__curPointY - y, 2 * x, 2 * y, 0, 360 * 64) \ + : XDrawArc(SCX_display, SCX_window, SCX_gc, SC__curPointX - x, SC__curPointY - y, 2 * x, 2 * y, 0, 360 * 64)) +# define SC_CIRCLE(x) SC_ELLIPSE(x, x) +# define SC_TEXT(str) XDrawString(SCX_display, SCX_window, SCX_gc, SC__curPointX, SC__curPointY, str, (int)strlen(str)) +/* KT 28/11/2002 only enable mask when the visual is PseudoColor */ +# define SC_MASK(par) \ + if (SCX_get_class(SCX_visual_info) == PseudoColor) \ + XSetPlaneMask(SCX_display, SCX_gc, (unsigned long)par) +# define SC_LINFUN(par) XSetFunction(SCX_display, SCX_gc, par) +# define SC_LUTX(par, R, G, B) +# define SC_CLEARS(par) +# define SC_LUTINT(par) +# define SC_CLEAR_BLOCK(color, x_b, x_e, y_b, y_e) \ + XSetForeground(SCX_display, SCX_gc, (unsigned long)SCX_color_translation[color]); \ + XFillRectangle(SCX_display, SCX_window, SCX_gc, Min((x_b), (x_e)), Min((y_b), (y_e)), abs((x_b) - (x_e)), \ + abs((y_b) - (y_e))); \ + XSetForeground(SCX_display, SCX_gc, (unsigned long)SC__color); +# define SC_LF_REPLACE GXcopy +# define SC_LF_XOR GXxor +# define SC_DEPTH SCX_visual_info.depth +# define SC_C_ANNOTATE (SC_C_MAX + 1) /* two definitions for masking availability */ /* Note: On X-windows, masking works only properly for a PseudoColor visual (i.e. 8-bit color with adjustable colormap) -*/ - /* KT 28/11/2002 changed value for TrueColor support */ -#define SC_M_ALL ((unsigned long)-1L) -#define SC_M_ANNOTATE (SC_C_MAX+1) +*/ +/* KT 28/11/2002 changed value for TrueColor support */ +# define SC_M_ALL ((unsigned long)-1L) +# define SC_M_ANNOTATE (SC_C_MAX + 1) #endif /* SC_XWINDOWS */ - /* change November 1997: added this function (was SCX_SCALE before) */ -extern void SC_SCALE(int pos_x, int pos_y, int size_x,int size_y); +extern void SC_SCALE(int pos_x, int pos_y, int size_x, int size_y); -typedef struct screen_image - { image_t *image; - int sx,sy; - char *text; - } screen_image_t; +typedef struct screen_image { + image_t* image; + int sx, sy; + char* text; +} screen_image_t; /***************************************************************************** - routines found in screengen.c + routines found in screengen.c *****************************************************************************/ /* KT 01/03/2000 added const */ -extern void put_textstr (int x, int y, const char * str); -extern int center_sc_images(int *Pscale, - int min_x,int max_x,int min_y,int max_y, - int SIZE_X,int SIZE_Y, - screen_image_t sc_image[], int nr_sc); -extern void draw_sc_images(int size_x, int size_y, - screen_image_t sc_image[], int no); - +extern void put_textstr(int x, int y, const char* str); +extern int center_sc_images(int* Pscale, int min_x, int max_x, int min_y, int max_y, int SIZE_X, int SIZE_Y, + screen_image_t sc_image[], int nr_sc); +extern void draw_sc_images(int size_x, int size_y, screen_image_t sc_image[], int no); /* Change November 1997: added next 3 lines: end of extern "C" */ #ifdef __cplusplus diff --git a/src/display/screengen.c b/src/display/screengen.c index 489bb9645a..0609e6ea19 100644 --- a/src/display/screengen.c +++ b/src/display/screengen.c @@ -1,19 +1,19 @@ /*! - \file - + \file + \brief very basic display routines - + \author Kris Thielemans (with help from Claire Labbe) \author PARAPET project - - + + Implementations common to all SC_x types - + \see screen.h \internal - + */ /* Copyright (C) 2000 PARAPET partners @@ -25,107 +25,99 @@ #define SCreen_compiling #include "screen.h" - -void put_textstr (int x, int y, const char str[]) -{ - int xx,yy; +void +put_textstr(int x, int y, const char str[]) { + int xx, yy; SC_MASK(SC_M_ANNOTATE); SC_COLOR(SC_C_ANNOTATE); - SC_TJUST(2,1); + SC_TJUST(2, 1); xx = x; yy = y - 15; - SC_MOVE(xx,yy); + SC_MOVE(xx, yy); SC_TEXT(str); - SC_TJUST(1,1); + SC_TJUST(1, 1); SC_MASK(SC_M_ALL); } /* TODO (?) scale should be obeyed if possible, now the smallest scale is used */ -int center_sc_images(int *Pscale, - int min_x,int max_x,int min_y,int max_y, - int SIZE_X,int SIZE_Y, - screen_image_t sc_image[], int nr_sc) -{ int inc_x,inc_y,start_x,start_y; - int nr_x,nr_y,LENGTH_X,LENGTH_Y; - int nr,i,j,x,y,scale; +int +center_sc_images(int* Pscale, int min_x, int max_x, int min_y, int max_y, int SIZE_X, int SIZE_Y, screen_image_t sc_image[], + int nr_sc) { + int inc_x, inc_y, start_x, start_y; + int nr_x, nr_y, LENGTH_X, LENGTH_Y; + int nr, i, j, x, y, scale; /* how many times can we enlarge the images ? */ - LENGTH_X = max_x-min_x; /* size in pixels of the region */ - LENGTH_Y = max_y-min_y; + LENGTH_X = max_x - min_x; /* size in pixels of the region */ + LENGTH_Y = max_y - min_y; /* KT&CL 3/12/97 changed the test if 1 image fits in the window */ - if (LENGTH_X < SIZE_X || LENGTH_Y < SIZE_Y+15) - { message("\nEven one image of this size doesn't fit in the window"); - return(0); + if (LENGTH_X < SIZE_X || LENGTH_Y < SIZE_Y + 15) { + message("\nEven one image of this size doesn't fit in the window"); + return (0); } /* Now we find the maximum scale of the images */ scale = 1; - do - { + do { /* we compute the number of images of this scale that fit in the allowed region. Place for text under the images is reserved */ scale++; - nr_x = LENGTH_X / (scale*(SIZE_X-1) + 1); - nr_y = LENGTH_Y / (scale*(SIZE_Y-1) + 1+15); - } while (nr_x*nr_y >= nr_sc); - scale--; /* one too far */ + nr_x = LENGTH_X / (scale * (SIZE_X - 1) + 1); + nr_y = LENGTH_Y / (scale * (SIZE_Y - 1) + 1 + 15); + } while (nr_x * nr_y >= nr_sc); + scale--; /* one too far */ - nr_x = LENGTH_X / (scale*(SIZE_X-1) + 1); - nr_y = LENGTH_Y / (scale*(SIZE_Y-1) + 1+15); + nr_x = LENGTH_X / (scale * (SIZE_X - 1) + 1); + nr_y = LENGTH_Y / (scale * (SIZE_Y - 1) + 1 + 15); /* we want to center the images in the region eg: we have now computed that a maximum of 4x3 images fits but we have only 7 images ... */ /* KT 11/12/97 added first if to check if all images fit or not, and the else case to change nr_sc */ - if (nr_x*nr_y > nr_sc) - { - if (nr_y==1) nr_x=nr_sc; - else - { - nr_y = nr_sc / nr_x; - if (nr_x*nr_y < nr_sc) nr_y++; - } - } - else - { - nr_sc = nr_x*nr_y; + if (nr_x * nr_y > nr_sc) { + if (nr_y == 1) + nr_x = nr_sc; + else { + nr_y = nr_sc / nr_x; + if (nr_x * nr_y < nr_sc) + nr_y++; } + } else { + nr_sc = nr_x * nr_y; + } - if (*Pscale!=0 && scale>*Pscale) - scale = *Pscale; + if (*Pscale != 0 && scale > *Pscale) + scale = *Pscale; *Pscale = scale; - LENGTH_X = scale*(SIZE_X-1)+1; - LENGTH_Y = scale*(SIZE_Y-1)+1; - start_x = (min_x + max_x - nr_x*LENGTH_X)/2; - start_y = (min_y + max_y - nr_y*(LENGTH_Y+15))/2; - if (start_y<15) + LENGTH_X = scale * (SIZE_X - 1) + 1; + LENGTH_Y = scale * (SIZE_Y - 1) + 1; + start_x = (min_x + max_x - nr_x * LENGTH_X) / 2; + start_y = (min_y + max_y - nr_y * (LENGTH_Y + 15)) / 2; + if (start_y < 15) start_y = 15; - inc_x = (max_x-start_x) / nr_x; - inc_y = (max_y-start_y) / nr_y; - start_y += inc_y*(nr_y-1); /* begin on top of screen */ + inc_x = (max_x - start_x) / nr_x; + inc_y = (max_y - start_y) / nr_y; + start_y += inc_y * (nr_y - 1); /* begin on top of screen */ - for(nr=0, i=0, y=start_y; i #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif - #ifndef STIR_NO_NAMESPACES using std::endl; using std::ends; @@ -45,8 +44,8 @@ using std::ends; START_NAMESPACE_STIR -void ROIValues::init() -{ +void +ROIValues::init() { NumericInfo float_limits; @@ -61,29 +60,26 @@ void ROIValues::init() std_value = 0; } -void ROIValues::update() -{ - if(roi_volume==0) - { +void +ROIValues::update() { + if (roi_volume == 0) { // ill_defined case... mean_value = 0; variance_value = 0; std_value = 0; - } - else - { - mean_value = integral/roi_volume; + } else { + mean_value = integral / roi_volume; const float square_mean = square(mean_value); - variance_value = (integral_of_square/roi_volume - square_mean); + variance_value = (integral_of_square / roi_volume - square_mean); if (fabs(variance_value) < 10E-5 * square_mean) variance_value = 0; std_value = sqrt(variance_value); } } -std::string ROIValues::report() const -{ +std::string +ROIValues::report() const { #ifdef BOOST_NO_STRINGSTREAM // dangerous for out-of-range, but 'old-style' ostrstream seems to need this char str[3000]; @@ -127,8 +123,7 @@ stream << val.std_value< #include // but also for old compilers - START_NAMESPACE_STIR void -compute_ROI_values_per_plane(VectorWithOffset& values, - const DiscretisedDensity<3,float>& density, - const Shape3D& shape, - const CartesianCoordinate3D& num_samples) -{ - const VoxelsOnCartesianGrid& image = - dynamic_cast&>(density); +compute_ROI_values_per_plane(VectorWithOffset& values, const DiscretisedDensity<3, float>& density, + const Shape3D& shape, const CartesianCoordinate3D& num_samples) { + const VoxelsOnCartesianGrid& image = dynamic_cast&>(density); const int min_z = image.get_min_index(); const int max_z = image.get_max_index(); @@ -54,14 +49,11 @@ compute_ROI_values_per_plane(VectorWithOffset& values, // initialise correct size values = VectorWithOffset(min_z, max_z); - shared_ptr > - discretised_shape_ptr(image.get_empty_voxels_on_cartesian_grid()); - + shared_ptr> discretised_shape_ptr(image.get_empty_voxels_on_cartesian_grid()); shape.construct_volume(*discretised_shape_ptr, num_samples); - for (int z=min_z; z<=max_z; z++) - { + for (int z = min_z; z <= max_z; z++) { #if 0 const float volume = (*discretised_shape_ptr)[z].sum() * voxel_volume; (*discretised_shape_ptr)[z] *= image[z]; @@ -78,103 +70,82 @@ compute_ROI_values_per_plane(VectorWithOffset& values, float integral_square = 0; float volume = 0; { - Array<2,float>::const_full_iterator - discr_shape_iter = (*discretised_shape_ptr)[z].begin_all_const(); - const Array<2,float>::const_full_iterator - discr_shape_end = (*discretised_shape_ptr)[z].end_all_const(); - Array<2,float>::const_full_iterator - image_iter = image[z].begin_all_const(); - for (; discr_shape_iter != discr_shape_end; ++discr_shape_iter, ++image_iter) - { - const float weight = *discr_shape_iter; - if (weight ==0) - continue; - volume += weight; - const float org_value = (*image_iter); - if (org_valueROI_max) ROI_max=org_value; - if (org_value==0) - continue; - const float value = weight * (*image_iter); - integral += value; - integral_square += value * (*image_iter); - } + Array<2, float>::const_full_iterator discr_shape_iter = (*discretised_shape_ptr)[z].begin_all_const(); + const Array<2, float>::const_full_iterator discr_shape_end = (*discretised_shape_ptr)[z].end_all_const(); + Array<2, float>::const_full_iterator image_iter = image[z].begin_all_const(); + for (; discr_shape_iter != discr_shape_end; ++discr_shape_iter, ++image_iter) { + const float weight = *discr_shape_iter; + if (weight == 0) + continue; + volume += weight; + const float org_value = (*image_iter); + if (org_value < ROI_min) + ROI_min = org_value; + if (org_value > ROI_max) + ROI_max = org_value; + if (org_value == 0) + continue; + const float value = weight * (*image_iter); + integral += value; + integral_square += value * (*image_iter); + } integral *= voxel_volume; integral_square *= voxel_volume; volume *= voxel_volume; } #endif - values[z] = - ROIValues(volume, integral, integral_square, - ROI_min, ROI_max); + values[z] = ROIValues(volume, integral, integral_square, ROI_min, ROI_max); } - } ROIValues -compute_total_ROI_values(const VectorWithOffset& values) -{ +compute_total_ROI_values(const VectorWithOffset& values) { // can't use std::accumulate, or we have to define ROIValues::operator+ ROIValues tmp; - for(VectorWithOffset::const_iterator iter = values.begin(); - iter != values.end(); - iter++) + for (VectorWithOffset::const_iterator iter = values.begin(); iter != values.end(); iter++) tmp += *iter; return tmp; } ROIValues -compute_total_ROI_values(const DiscretisedDensity<3,float>& image, - const Shape3D& shape, - const CartesianCoordinate3D& num_samples - ) -{ +compute_total_ROI_values(const DiscretisedDensity<3, float>& image, const Shape3D& shape, + const CartesianCoordinate3D& num_samples) { VectorWithOffset values; compute_ROI_values_per_plane(values, image, shape, num_samples); - return - compute_total_ROI_values(values); + return compute_total_ROI_values(values); } - - - // Function that calculate the totals over a certain plane-range - -/* TODO this function isn't used at present, but it's almost the same as + +/* TODO this function isn't used at present, but it's almost the same as compare_ROI_values_per_plane(), so rewrite the latter in terms of this one (after updating it) */ void -compute_plane_range_ROI_values_per_plane(VectorWithOffset& values, - const DiscretisedDensity<3,float>& density, - const CartesianCoordinate2D& plane_range, - const Shape3D& shape, - const CartesianCoordinate3D& num_samples) -{ - const VoxelsOnCartesianGrid& image = - dynamic_cast&>(density); +compute_plane_range_ROI_values_per_plane(VectorWithOffset& values, const DiscretisedDensity<3, float>& density, + const CartesianCoordinate2D& plane_range, const Shape3D& shape, + const CartesianCoordinate3D& num_samples) { + const VoxelsOnCartesianGrid& image = dynamic_cast&>(density); const int min_z = image.get_min_index(); const int max_z = image.get_max_index(); // new range as entered, e.g end planes ignored - int min_z_new = plane_range.x() - min_z; - int max_z_new = max_z - plane_range.y(); - + int min_z_new = plane_range.x() - min_z; + int max_z_new = max_z - plane_range.y(); + const CartesianCoordinate3D voxel_size = image.get_voxel_size(); const float voxel_volume = voxel_size.x() * voxel_size.y() * voxel_size.z(); // initialise correct size values = VectorWithOffset(min_z_new, max_z_new); - VoxelsOnCartesianGrid discretised_shape = - (*image.get_empty_voxels_on_cartesian_grid()); + VoxelsOnCartesianGrid discretised_shape = (*image.get_empty_voxels_on_cartesian_grid()); shape.construct_volume(discretised_shape, num_samples); - for (int z=min_z_new; z<=max_z_new; z++) - { + for (int z = min_z_new; z <= max_z_new; z++) { const float volume = discretised_shape.sum() * voxel_volume; discretised_shape[z] *= image[z]; const float ROI_min = discretised_shape.find_min(); @@ -182,78 +153,66 @@ compute_plane_range_ROI_values_per_plane(VectorWithOffset& values, const float integral = discretised_shape.sum() * voxel_volume; discretised_shape[z] *= image[z]; const float integral_square = discretised_shape.sum() * voxel_volume; - values[z] = - ROIValues(volume, integral, integral_square, - ROI_min, ROI_max); + values[z] = ROIValues(volume, integral, integral_square, ROI_min, ROI_max); } } - float compute_CR_hot(ROIValues& val1, ROIValues& val2) { - return 1 - val1.get_mean()/val2.get_mean(); + return 1 - val1.get_mean() / val2.get_mean(); } float -compute_CR_cold(ROIValues& val1, ROIValues& val2) -{ - return val1.get_mean()/val2.get_mean()- 1; +compute_CR_cold(ROIValues& val1, ROIValues& val2) { + return val1.get_mean() / val2.get_mean() - 1; } - float -compute_uniformity(ROIValues& val) -{ - return val.get_stddev()/val.get_mean(); +compute_uniformity(ROIValues& val) { + return val.get_stddev() / val.get_mean(); } VectorWithOffset -compute_CR_hot_per_plane(VectorWithOffset& val1,VectorWithOffset& val2) -{ +compute_CR_hot_per_plane(VectorWithOffset& val1, VectorWithOffset& val2) { - assert(val1.get_min_index()==val2.get_min_index()); - assert(val1.get_max_index()==val2.get_max_index()); + assert(val1.get_min_index() == val2.get_min_index()); + assert(val1.get_max_index() == val2.get_max_index()); { - VectorWithOffset temp(val1.get_min_index(), val1.get_max_index()); - for (int i =val1.get_min_index();i<=val1.get_max_index();i++) + VectorWithOffset temp(val1.get_min_index(), val1.get_max_index()); + for (int i = val1.get_min_index(); i <= val1.get_max_index(); i++) { - temp[i]= compute_CR_hot(val1[i],val2[i]); + temp[i] = compute_CR_hot(val1[i], val2[i]); } return temp; } } VectorWithOffset -compute_CR_cold_per_plane(VectorWithOffset& val1,VectorWithOffset& val2) -{ +compute_CR_cold_per_plane(VectorWithOffset& val1, VectorWithOffset& val2) { - assert(val1.get_min_index()==val2.get_min_index()); - assert(val1.get_max_index()==val2.get_max_index()); + assert(val1.get_min_index() == val2.get_min_index()); + assert(val1.get_max_index() == val2.get_max_index()); { VectorWithOffset temp(val1.get_min_index(), val1.get_max_index()); - for (int i =val1.get_min_index();i<=val1.get_max_index();i++) + for (int i = val1.get_min_index(); i <= val1.get_max_index(); i++) { - temp[i] = compute_CR_cold(val1[i],val2[i]); + temp[i] = compute_CR_cold(val1[i], val2[i]); } return temp; } - } VectorWithOffset -compute_uniformity_per_plane(VectorWithOffset& val) -{ +compute_uniformity_per_plane(VectorWithOffset& val) { - VectorWithOffset temp(val.get_min_index(), val.get_max_index()); - for (int i =val.get_min_index();i<=val.get_max_index();i++) - { + VectorWithOffset temp(val.get_min_index(), val.get_max_index()); + for (int i = val.get_min_index(); i <= val.get_max_index(); i++) { temp[i] = compute_uniformity(val[i]); } return temp; } - END_NAMESPACE_STIR diff --git a/src/experimental/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx b/src/experimental/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx index 9d7f303327..764d585810 100644 --- a/src/experimental/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx +++ b/src/experimental/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx @@ -36,32 +36,25 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 -const char * const -ECAT7DynamicDiscretisedDensityOutputFileFormat::registered_name = "ECAT7"; +const char* const ECAT7DynamicDiscretisedDensityOutputFileFormat::registered_name = "ECAT7"; -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -ECAT7DynamicDiscretisedDensityOutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) -{ +ECAT7DynamicDiscretisedDensityOutputFileFormat::ECAT7DynamicDiscretisedDensityOutputFileFormat(const NumericType& type, + const ByteOrder& byte_order) { this->set_defaults(); this->set_type_of_numbers(type); this->set_byte_order(byte_order); } -void -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -initialise_keymap() -{ +void +ECAT7DynamicDiscretisedDensityOutputFileFormat::initialise_keymap() { this->parser.add_start_key("ECAT7 Output File Format Parameters"); this->parser.add_stop_key("End ECAT7 Output File Format Parameters"); this->parser.add_key("default scanner name", &default_scanner_name); base_type::initialise_keymap(); } -void -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_defaults() -{ +void +ECAT7DynamicDiscretisedDensityOutputFileFormat::set_defaults() { this->default_scanner_name = "ECAT 962"; base_type::set_defaults(); this->file_byte_order = ByteOrder::big_endian; @@ -71,69 +64,53 @@ set_defaults() } bool -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -post_processing() -{ +ECAT7DynamicDiscretisedDensityOutputFileFormat::post_processing() { if (base_type::post_processing()) return true; - shared_ptr scanner_ptr = - Scanner::get_scanner_from_name(this->default_scanner_name); + shared_ptr scanner_ptr = Scanner::get_scanner_from_name(this->default_scanner_name); - if (find_ECAT_system_type(*scanner_ptr)==0) - { - warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: default_scanner_name %s is not supported\n", - this->default_scanner_name.c_str()); - return true; - } + if (find_ECAT_system_type(*scanner_ptr) == 0) { + warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: default_scanner_name %s is not supported\n", + this->default_scanner_name.c_str()); + return true; + } return false; } -NumericType -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_type_of_numbers(const NumericType& new_type, const bool warn) -{ - const NumericType supported_type_of_numbers = - NumericType("signed integer", 2); - if (new_type != supported_type_of_numbers) - { +NumericType +ECAT7DynamicDiscretisedDensityOutputFileFormat::set_type_of_numbers(const NumericType& new_type, const bool warn) { + const NumericType supported_type_of_numbers = NumericType("signed integer", 2); + if (new_type != supported_type_of_numbers) { if (warn) - warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: output type of numbers is currently fixed to short (2 byte signed integers)\n"); + warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: output type of numbers is currently fixed to short (2 byte signed " + "integers)\n"); this->type_of_numbers = supported_type_of_numbers; - } - else + } else this->type_of_numbers = new_type; return this->type_of_numbers; } -ByteOrder -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) -{ - if (new_byte_order != ByteOrder::big_endian) - { +ByteOrder +ECAT7DynamicDiscretisedDensityOutputFileFormat::set_byte_order(const ByteOrder& new_byte_order, const bool warn) { + if (new_byte_order != ByteOrder::big_endian) { if (warn) warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: byte_order is currently fixed to big-endian\n"); this->file_byte_order = ByteOrder::big_endian; - } - else + } else this->file_byte_order = new_byte_order; return this->file_byte_order; } -Succeeded -ECAT7DynamicDiscretisedDensityOutputFileFormat:: - actual_write_to_file(string& filename, - const DynamicDiscretisedDensity& dynamic_density) const -{ +Succeeded +ECAT7DynamicDiscretisedDensityOutputFileFormat::actual_write_to_file(string& filename, + const DynamicDiscretisedDensity& dynamic_density) const { add_extension(filename, ".img"); - return - dynamic_density.write_to_ecat7(filename); + return dynamic_density.write_to_ecat7(filename); } - -//template class ECAT7DynamicDiscretisedDensityOutputFileFormat; +// template class ECAT7DynamicDiscretisedDensityOutputFileFormat; END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT diff --git a/src/experimental/IO/OutputFileFormat_default.cxx b/src/experimental/IO/OutputFileFormat_default.cxx index 4fd088d172..a4c6e25a6f 100644 --- a/src/experimental/IO/OutputFileFormat_default.cxx +++ b/src/experimental/IO/OutputFileFormat_default.cxx @@ -20,11 +20,9 @@ \ingroup IO \brief initialisation of the stir::OutputFileFormat::_default_sptr member \author Kris Thielemans - -*/ +*/ START_NAMESPACE_STIR END_NAMESPACE_STIR - diff --git a/src/experimental/IO/local_InputFileFormatRegistry.cxx b/src/experimental/IO/local_InputFileFormatRegistry.cxx index 40b290622f..a67757a78a 100644 --- a/src/experimental/IO/local_InputFileFormatRegistry.cxx +++ b/src/experimental/IO/local_InputFileFormatRegistry.cxx @@ -28,5 +28,4 @@ START_NAMESPACE_STIR - END_NAMESPACE_STIR diff --git a/src/experimental/IO/local_OutputFileFormat_default.cxx b/src/experimental/IO/local_OutputFileFormat_default.cxx index 4fd088d172..a4c6e25a6f 100644 --- a/src/experimental/IO/local_OutputFileFormat_default.cxx +++ b/src/experimental/IO/local_OutputFileFormat_default.cxx @@ -20,11 +20,9 @@ \ingroup IO \brief initialisation of the stir::OutputFileFormat::_default_sptr member \author Kris Thielemans - -*/ +*/ START_NAMESPACE_STIR END_NAMESPACE_STIR - diff --git a/src/experimental/buildblock/AbsTimeIntervalFromDynamicData.cxx b/src/experimental/buildblock/AbsTimeIntervalFromDynamicData.cxx index 1ba1346d03..7cd69f1014 100644 --- a/src/experimental/buildblock/AbsTimeIntervalFromDynamicData.cxx +++ b/src/experimental/buildblock/AbsTimeIntervalFromDynamicData.cxx @@ -24,96 +24,68 @@ START_NAMESPACE_STIR -const char * const -AbsTimeIntervalFromDynamicData::registered_name = "from Dynamic Data"; +const char* const AbsTimeIntervalFromDynamicData::registered_name = "from Dynamic Data"; -AbsTimeIntervalFromDynamicData:: -AbsTimeIntervalFromDynamicData() -{ - set_defaults(); -} +AbsTimeIntervalFromDynamicData::AbsTimeIntervalFromDynamicData() { set_defaults(); } -AbsTimeIntervalFromDynamicData:: -AbsTimeIntervalFromDynamicData(const std::string& filename, - const unsigned int start_time_frame_num, - const unsigned int end_time_frame_num) - : - _filename(filename), - _start_time_frame_num(start_time_frame_num), - _end_time_frame_num(end_time_frame_num) -{ +AbsTimeIntervalFromDynamicData::AbsTimeIntervalFromDynamicData(const std::string& filename, + const unsigned int start_time_frame_num, + const unsigned int end_time_frame_num) + : _filename(filename), _start_time_frame_num(start_time_frame_num), _end_time_frame_num(end_time_frame_num) { if (this->set_times() == Succeeded::no) error("Exiting"); // TODO should throw exception } -Succeeded -AbsTimeIntervalFromDynamicData:: -set_times() -{ - if (this->_start_time_frame_num==0) - { - warning("AbsTimeIntervalFromDynamicData: need to set start_time_frame_num"); - return Succeeded::no; - } - if (this->_end_time_frame_num==0) - { - warning("AbsTimeIntervalFromDynamicData: need to set end_time_frame_num"); - return Succeeded::no; - } +Succeeded +AbsTimeIntervalFromDynamicData::set_times() { + if (this->_start_time_frame_num == 0) { + warning("AbsTimeIntervalFromDynamicData: need to set start_time_frame_num"); + return Succeeded::no; + } + if (this->_end_time_frame_num == 0) { + warning("AbsTimeIntervalFromDynamicData: need to set end_time_frame_num"); + return Succeeded::no; + } TimeFrameDefinitions time_frame_defs; shared_ptr data_sptr(DynamicProjData::read_from_file(this->_filename)); - - if (!is_null_ptr(data_sptr)) - { - this->_scan_start_time_in_secs_since_1970 = - data_sptr->get_start_time_in_secs_since_1970(); - time_frame_defs = data_sptr->get_time_frame_definitions(); - } - else - { - info("Trying to read data as an image now."); - - shared_ptr - data_sptr(read_from_file(this->_filename)); - - if (is_null_ptr(data_sptr)) - { - return Succeeded::no; - } - - this->_scan_start_time_in_secs_since_1970 = - data_sptr->get_start_time_in_secs_since_1970(); - time_frame_defs = data_sptr->get_time_frame_definitions(); + + if (!is_null_ptr(data_sptr)) { + this->_scan_start_time_in_secs_since_1970 = data_sptr->get_start_time_in_secs_since_1970(); + time_frame_defs = data_sptr->get_time_frame_definitions(); + } else { + info("Trying to read data as an image now."); + + shared_ptr data_sptr(read_from_file(this->_filename)); + + if (is_null_ptr(data_sptr)) { + return Succeeded::no; } - this->_start_time_in_secs_since_1970 = - this->_scan_start_time_in_secs_since_1970 + - time_frame_defs.get_start_time(this->_start_time_frame_num); + this->_scan_start_time_in_secs_since_1970 = data_sptr->get_start_time_in_secs_since_1970(); + time_frame_defs = data_sptr->get_time_frame_definitions(); + } - this->_end_time_in_secs_since_1970 = - this->_scan_start_time_in_secs_since_1970 + - time_frame_defs.get_end_time(this->_end_time_frame_num); + this->_start_time_in_secs_since_1970 = + this->_scan_start_time_in_secs_since_1970 + time_frame_defs.get_start_time(this->_start_time_frame_num); + + this->_end_time_in_secs_since_1970 = + this->_scan_start_time_in_secs_since_1970 + time_frame_defs.get_end_time(this->_end_time_frame_num); return Succeeded::yes; } - -void -AbsTimeIntervalFromDynamicData:: -set_defaults() -{ - this->_filename =""; +void +AbsTimeIntervalFromDynamicData::set_defaults() { + this->_filename = ""; this->_start_time_in_secs_since_1970 = -1.; this->_start_time_frame_num = 0; this->_end_time_frame_num = 0; } -void -AbsTimeIntervalFromDynamicData:: -initialise_keymap() -{ +void +AbsTimeIntervalFromDynamicData::initialise_keymap() { parser.add_start_key("Absolute Time Interval From Dynamic Data"); parser.add_stop_key("end Absolute Time Interval From Dynamic Data"); @@ -123,14 +95,11 @@ initialise_keymap() } bool -AbsTimeIntervalFromDynamicData:: -post_processing() -{ - if (set_times() == Succeeded::no) - { - warning("AbsTimeIntervalFromDynamicData: not set properly"); - return true; - } +AbsTimeIntervalFromDynamicData::post_processing() { + if (set_times() == Succeeded::no) { + warning("AbsTimeIntervalFromDynamicData: not set properly"); + return true; + } return false; } diff --git a/src/experimental/buildblock/AbsTimeIntervalFromECAT7ACF.cxx b/src/experimental/buildblock/AbsTimeIntervalFromECAT7ACF.cxx index 9fbba20d48..ab47bdeb36 100644 --- a/src/experimental/buildblock/AbsTimeIntervalFromECAT7ACF.cxx +++ b/src/experimental/buildblock/AbsTimeIntervalFromECAT7ACF.cxx @@ -20,70 +20,49 @@ START_NAMESPACE_STIR -const char * const -AbsTimeIntervalFromECAT7ACF::registered_name = "from ECAT7 ACF"; +const char* const AbsTimeIntervalFromECAT7ACF::registered_name = "from ECAT7 ACF"; -AbsTimeIntervalFromECAT7ACF:: -AbsTimeIntervalFromECAT7ACF() -{ - set_defaults(); -} +AbsTimeIntervalFromECAT7ACF::AbsTimeIntervalFromECAT7ACF() { set_defaults(); } -AbsTimeIntervalFromECAT7ACF:: -AbsTimeIntervalFromECAT7ACF(const std::string& filename, double duration_in_secs) - : - _attenuation_filename(filename), - _transmission_duration(duration_in_secs) -{ +AbsTimeIntervalFromECAT7ACF::AbsTimeIntervalFromECAT7ACF(const std::string& filename, double duration_in_secs) + : _attenuation_filename(filename), _transmission_duration(duration_in_secs) { if (set_times() == Succeeded::no) error("Exiting"); // TODO should throw exception } -Succeeded -AbsTimeIntervalFromECAT7ACF:: -set_times() -{ +Succeeded +AbsTimeIntervalFromECAT7ACF::set_times() { #ifdef HAVE_LLN_MATRIX - if (_transmission_duration<=0) - { - warning("AbsTimeIntervalFromECAT7ACF: duration should be > 0 but is %g%.", - _transmission_duration); - return Succeeded::no; - } - MatrixFile* attn_file = matrix_open(_attenuation_filename.c_str(), MAT_READ_ONLY, AttenCor ); - if (attn_file==NULL) - { - warning("Error opening attenuation file '%s'", _attenuation_filename.c_str()); - return Succeeded::no; - } + if (_transmission_duration <= 0) { + warning("AbsTimeIntervalFromECAT7ACF: duration should be > 0 but is %g%.", _transmission_duration); + return Succeeded::no; + } + MatrixFile* attn_file = matrix_open(_attenuation_filename.c_str(), MAT_READ_ONLY, AttenCor); + if (attn_file == NULL) { + warning("Error opening attenuation file '%s'", _attenuation_filename.c_str()); + return Succeeded::no; + } _start_time_in_secs_since_1970 = attn_file->mhptr->scan_start_time; - _end_time_in_secs_since_1970 = - _start_time_in_secs_since_1970 + _transmission_duration; + _end_time_in_secs_since_1970 = _start_time_in_secs_since_1970 + _transmission_duration; matrix_close(attn_file); return Succeeded::yes; #else - warning("Error opening attenuation file %s: compiled without ECAT7 support.", - _attenuation_filename.c_str()); - return Succeeded::no; + warning("Error opening attenuation file %s: compiled without ECAT7 support.", _attenuation_filename.c_str()); + return Succeeded::no; #endif } - -void -AbsTimeIntervalFromECAT7ACF:: -set_defaults() -{ +void +AbsTimeIntervalFromECAT7ACF::set_defaults() { _transmission_duration = -1; - _attenuation_filename =""; + _attenuation_filename = ""; } -void -AbsTimeIntervalFromECAT7ACF:: -initialise_keymap() -{ +void +AbsTimeIntervalFromECAT7ACF::initialise_keymap() { parser.add_start_key("Absolute Time Interval From ECAT7 ACF"); parser.add_stop_key("end Absolute Time Interval From ECAT7 ACF"); @@ -92,14 +71,11 @@ initialise_keymap() } bool -AbsTimeIntervalFromECAT7ACF:: -post_processing() -{ - if (set_times() == Succeeded::no) - { - warning("AbsTimeIntervalFromECAT7ACF: not set properly"); - return true; - } +AbsTimeIntervalFromECAT7ACF::post_processing() { + if (set_times() == Succeeded::no) { + warning("AbsTimeIntervalFromECAT7ACF: not set properly"); + return true; + } return false; } diff --git a/src/experimental/buildblock/AbsTimeIntervalWithParsing.cxx b/src/experimental/buildblock/AbsTimeIntervalWithParsing.cxx index 19e668174e..cc175e6ef3 100644 --- a/src/experimental/buildblock/AbsTimeIntervalWithParsing.cxx +++ b/src/experimental/buildblock/AbsTimeIntervalWithParsing.cxx @@ -19,30 +19,20 @@ START_NAMESPACE_STIR -const char * const -AbsTimeIntervalWithParsing::registered_name = "secs since 1970"; +const char* const AbsTimeIntervalWithParsing::registered_name = "secs since 1970"; -static const double time_not_yet_determined=-4321; - -AbsTimeIntervalWithParsing:: -AbsTimeIntervalWithParsing() -{ - set_defaults(); -} +static const double time_not_yet_determined = -4321; +AbsTimeIntervalWithParsing::AbsTimeIntervalWithParsing() { set_defaults(); } -void -AbsTimeIntervalWithParsing:: -set_defaults() -{ - _start_time_in_secs_since_1970=time_not_yet_determined; - _end_time_in_secs_since_1970=time_not_yet_determined; +void +AbsTimeIntervalWithParsing::set_defaults() { + _start_time_in_secs_since_1970 = time_not_yet_determined; + _end_time_in_secs_since_1970 = time_not_yet_determined; } -void -AbsTimeIntervalWithParsing:: -initialise_keymap() -{ +void +AbsTimeIntervalWithParsing::initialise_keymap() { parser.add_start_key("Absolute Time Interval"); parser.add_stop_key("end Absolute Time Interval"); @@ -51,21 +41,15 @@ initialise_keymap() } bool -AbsTimeIntervalWithParsing:: -post_processing() -{ - if (this->get_start_time_in_secs_since_1970() < 10000.) - { - warning("AbsTimeInterval: start time (%g) too small", - this->get_start_time_in_secs_since_1970()); - return true; - } - if (this->get_duration_in_secs() <= 0.) - { - warning("AbsTimeInterval: duration (%g) should be > 0", - this->get_duration_in_secs()); - return true; - } +AbsTimeIntervalWithParsing::post_processing() { + if (this->get_start_time_in_secs_since_1970() < 10000.) { + warning("AbsTimeInterval: start time (%g) too small", this->get_start_time_in_secs_since_1970()); + return true; + } + if (this->get_duration_in_secs() <= 0.) { + warning("AbsTimeInterval: duration (%g) should be > 0", this->get_duration_in_secs()); + return true; + } return false; } diff --git a/src/experimental/buildblock/DAVArrayFilter3D.cxx b/src/experimental/buildblock/DAVArrayFilter3D.cxx index fd7ae3ca83..3eb52b5e13 100644 --- a/src/experimental/buildblock/DAVArrayFilter3D.cxx +++ b/src/experimental/buildblock/DAVArrayFilter3D.cxx @@ -4,11 +4,11 @@ \file \ingroup buildblock - \brief + \brief \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2001, IRSL @@ -18,7 +18,7 @@ #include "stir_experimental/DAVArrayFilter3D.h" #include "stir/Coordinate3D.h" #include "stir/Array.h" -// remove +// remove #include #include #include @@ -34,131 +34,110 @@ using std::sort; using std::min_element; #endif - START_NAMESPACE_STIR - template -DAVArrayFilter3D::DAVArrayFilter3D(const Coordinate3D& mask_radius) -{ +DAVArrayFilter3D::DAVArrayFilter3D(const Coordinate3D& mask_radius) { mask_radius_x = mask_radius[3]; mask_radius_y = mask_radius[2]; mask_radius_z = mask_radius[1]; - /* assert(mask_radius_x>0); - assert(mask_radius_x%2 == 1); - assert(mask_radius_y>0); - assert(mask_radius_y%2 == 1); - assert(mask_radius_z>0); - assert(mask_radius_z%2 == 1);*/ + /* assert(mask_radius_x>0); + assert(mask_radius_x%2 == 1); + assert(mask_radius_y>0); + assert(mask_radius_y%2 == 1); + assert(mask_radius_z>0); + assert(mask_radius_z%2 == 1);*/ } - - template void -DAVArrayFilter3D:: -do_it(Array<3,elemT>& out_array, const Array<3,elemT>& in_array) const -{ +DAVArrayFilter3D::do_it(Array<3, elemT>& out_array, const Array<3, elemT>& in_array) const { assert(out_array.get_index_range() == in_array.get_index_range()); // initialize out_elem to prevent warning elemT out_elem = 0; - for (int z=in_array.get_min_index()+mask_radius_z;z<= in_array.get_max_index()-mask_radius_z;z++) - for (int y=in_array[z].get_min_index()+mask_radius_y;y <= in_array[z].get_max_index()-mask_radius_y;y++) - for (int x=in_array[z][y].get_min_index()+mask_radius_x;x <= in_array[z][y].get_max_index()-mask_radius_x;x++) - { - extract_neighbours_and_average(out_elem,in_array,Coordinate3D(z,y,x)); - out_array[z][y][x] = out_elem; - } + for (int z = in_array.get_min_index() + mask_radius_z; z <= in_array.get_max_index() - mask_radius_z; z++) + for (int y = in_array[z].get_min_index() + mask_radius_y; y <= in_array[z].get_max_index() - mask_radius_y; y++) + for (int x = in_array[z][y].get_min_index() + mask_radius_x; x <= in_array[z][y].get_max_index() - mask_radius_x; x++) { + extract_neighbours_and_average(out_elem, in_array, Coordinate3D(z, y, x)); + out_array[z][y][x] = out_elem; + } } template void -DAVArrayFilter3D:: -extract_neighbours_and_average(elemT& out_elem, const Array<3,elemT>& in_array,const Coordinate3D& c_pixel) const -{ - - Array<1,float> averaged_arrays3D (0,8); - Array<1,float> averaged_arrays_subtracted3D (0,8); - - averaged_arrays3D.fill(0); - averaged_arrays_subtracted3D.fill(0); - - // TODO - different sizes for different directions - int denom = (2*mask_radius_x+1); - - for(int index=-mask_radius_x;index<=mask_radius_x;index++) - { +DAVArrayFilter3D::extract_neighbours_and_average(elemT& out_elem, const Array<3, elemT>& in_array, + const Coordinate3D& c_pixel) const { + + Array<1, float> averaged_arrays3D(0, 8); + Array<1, float> averaged_arrays_subtracted3D(0, 8); + + averaged_arrays3D.fill(0); + averaged_arrays_subtracted3D.fill(0); + + // TODO - different sizes for different directions + int denom = (2 * mask_radius_x + 1); + + for (int index = -mask_radius_x; index <= mask_radius_x; index++) { // for each z-plane - averaged_arrays3D[0] += in_array[c_pixel[1]][c_pixel[2]+index][c_pixel[3]]; - averaged_arrays3D[1] += in_array[c_pixel[1]][c_pixel[2]-index][c_pixel[3]+index]; - averaged_arrays3D[2] += in_array[c_pixel[1]][c_pixel[2]][c_pixel[3]+index]; - averaged_arrays3D[3] += in_array[c_pixel[1]][c_pixel[2]+index][c_pixel[3]+index]; + averaged_arrays3D[0] += in_array[c_pixel[1]][c_pixel[2] + index][c_pixel[3]]; + averaged_arrays3D[1] += in_array[c_pixel[1]][c_pixel[2] - index][c_pixel[3] + index]; + averaged_arrays3D[2] += in_array[c_pixel[1]][c_pixel[2]][c_pixel[3] + index]; + averaged_arrays3D[3] += in_array[c_pixel[1]][c_pixel[2] + index][c_pixel[3] + index]; // for axial direction - if (mask_radius_z !=0) - { - averaged_arrays3D[4] += in_array[c_pixel[1]+index][c_pixel[2]][c_pixel[3]]; - averaged_arrays3D[5] += in_array[c_pixel[1]-index][c_pixel[2]+index][c_pixel[3]]; - averaged_arrays3D[6] += in_array[c_pixel[1]+index][c_pixel[2]+index][c_pixel[3]]; + if (mask_radius_z != 0) { + averaged_arrays3D[4] += in_array[c_pixel[1] + index][c_pixel[2]][c_pixel[3]]; + averaged_arrays3D[5] += in_array[c_pixel[1] - index][c_pixel[2] + index][c_pixel[3]]; + averaged_arrays3D[6] += in_array[c_pixel[1] + index][c_pixel[2] + index][c_pixel[3]]; // extra two diagonals - averaged_arrays3D[7] += in_array[c_pixel[1]+index][c_pixel[2]+index][c_pixel[3]+index]; - averaged_arrays3D[8] += in_array[c_pixel[1]+index][c_pixel[2]-index][c_pixel[3]+index]; - } - else - { - for (int i = 4;i<=8; i++) - averaged_arrays3D[i] = 0; + averaged_arrays3D[7] += in_array[c_pixel[1] + index][c_pixel[2] + index][c_pixel[3] + index]; + averaged_arrays3D[8] += in_array[c_pixel[1] + index][c_pixel[2] - index][c_pixel[3] + index]; + } else { + for (int i = 4; i <= 8; i++) + averaged_arrays3D[i] = 0; } - } - - for (int i = 0;i<=8;i++) + + for (int i = 0; i <= 8; i++) averaged_arrays3D[i] /= denom; - - averaged_arrays_subtracted3D = averaged_arrays3D - in_array[c_pixel[1]][c_pixel[2]][c_pixel[3]]; - - for (int i = 0;i<=8;i++) - averaged_arrays_subtracted3D[i] = fabs(averaged_arrays_subtracted3D[i]); -/* - int counter = 0; - int ind = 0; - float min_smooth_3D = averaged_arrays_subtracted3D[0]; - - while ( counter <=8) - { - if (min_smooth_3D >averaged_arrays_subtracted3D[counter]) + + averaged_arrays_subtracted3D = averaged_arrays3D - in_array[c_pixel[1]][c_pixel[2]][c_pixel[3]]; + + for (int i = 0; i <= 8; i++) + averaged_arrays_subtracted3D[i] = fabs(averaged_arrays_subtracted3D[i]); + /* + int counter = 0; + int ind = 0; + float min_smooth_3D = averaged_arrays_subtracted3D[0]; + + while ( counter <=8) { - min_smooth_3D = averaged_arrays_subtracted3D[counter]; - ind = counter; + if (min_smooth_3D >averaged_arrays_subtracted3D[counter]) + { + min_smooth_3D = averaged_arrays_subtracted3D[counter]; + ind = counter; + } + counter++; } - counter++; - } -*/ - Array<1,float>::difference_type min_abs_diff_idx = - min_element(averaged_arrays_subtracted3D.begin(), - averaged_arrays_subtracted3D.end()) - - averaged_arrays_subtracted3D.begin(); + */ + Array<1, float>::difference_type min_abs_diff_idx = + min_element(averaged_arrays_subtracted3D.begin(), averaged_arrays_subtracted3D.end()) - + averaged_arrays_subtracted3D.begin(); - out_elem = *(averaged_arrays3D.begin() + min_abs_diff_idx); + out_elem = *(averaged_arrays3D.begin() + min_abs_diff_idx); } - template bool -DAVArrayFilter3D:: -is_trivial() const -{ - if (mask_radius_x!=1 &&mask_radius_y !=1 &&mask_radius_z!=1) +DAVArrayFilter3D::is_trivial() const { + if (mask_radius_x != 1 && mask_radius_y != 1 && mask_radius_z != 1) return true; else return false; - } - // instantiation template DAVArrayFilter3D; END_NAMESPACE_STIR - diff --git a/src/experimental/buildblock/DAVImageFilter3D.cxx b/src/experimental/buildblock/DAVImageFilter3D.cxx index a26b40b6a3..d5848fd944 100644 --- a/src/experimental/buildblock/DAVImageFilter3D.cxx +++ b/src/experimental/buildblock/DAVImageFilter3D.cxx @@ -4,11 +4,11 @@ \file - \brief + \brief \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2001, IRSL @@ -31,69 +31,58 @@ using std::cerr; using std::endl; #endif - START_NAMESPACE_STIR template -DAVImageFilter3D:: DAVImageFilter3D(const CartesianCoordinate3D& mask_radius) -{ +DAVImageFilter3D::DAVImageFilter3D(const CartesianCoordinate3D& mask_radius) { mask_radius_x = mask_radius.x(); mask_radius_y = mask_radius.y(); mask_radius_z = mask_radius.z(); } template -DAVImageFilter3D:: DAVImageFilter3D() -{ +DAVImageFilter3D::DAVImageFilter3D() { set_defaults(); } template Succeeded -DAVImageFilter3D::virtual_set_up (const DiscretisedDensity<3,elemT>& density) -{ +DAVImageFilter3D::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { - //if (consistency_check(density) == Succeeded::no) + // if (consistency_check(density) == Succeeded::no) // return Succeeded::no; - dav_filter = - DAVArrayFilter3D(Coordinate3D - (mask_radius_z, mask_radius_y, mask_radius_x)); + dav_filter = DAVArrayFilter3D(Coordinate3D(mask_radius_z, mask_radius_y, mask_radius_x)); - return Succeeded::yes; + return Succeeded::yes; } template void -DAVImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const -{ - //assert(consistency_check(density) == Succeeded::yes); +DAVImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const { + // assert(consistency_check(density) == Succeeded::yes); dav_filter(density); - } template void -DAVImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& out_density, const DiscretisedDensity<3, elemT>& in_density) const -{ - //assert(consistency_check(in_density) == Succeeded::yes); - // cerr << mask_radius_x << " " << mask_radius_y << endl; - dav_filter(out_density,in_density); - +DAVImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { + // assert(consistency_check(in_density) == Succeeded::yes); + // cerr << mask_radius_x << " " << mask_radius_y << endl; + dav_filter(out_density, in_density); } template void -DAVImageFilter3D::set_defaults() -{ +DAVImageFilter3D::set_defaults() { mask_radius_x = 0; mask_radius_y = 0; mask_radius_z = 0; } template -void -DAVImageFilter3D::initialise_keymap() -{ +void +DAVImageFilter3D::initialise_keymap() { parser.add_start_key("DAV Filter Parameters"); parser.add_key("mask radius x", &mask_radius_x); parser.add_key("mask radius y", &mask_radius_y); @@ -101,16 +90,13 @@ DAVImageFilter3D::initialise_keymap() parser.add_stop_key("END DAV Filter Parameters"); } +const char* const DAVImageFilter3D::registered_name = "DAV"; -const char * const -DAVImageFilter3D::registered_name = - "DAV"; - -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif #if 0 // registration business moved to local_buildblock_registries.cxx @@ -122,6 +108,4 @@ static DAVImageFilter3D::RegisterIt dummy; template DAVImageFilter3D; - END_NAMESPACE_STIR - diff --git a/src/experimental/buildblock/ModifiedInverseAveragingImageFilterAll.cxx b/src/experimental/buildblock/ModifiedInverseAveragingImageFilterAll.cxx index 9049f2a01e..5d75e73749 100644 --- a/src/experimental/buildblock/ModifiedInverseAveragingImageFilterAll.cxx +++ b/src/experimental/buildblock/ModifiedInverseAveragingImageFilterAll.cxx @@ -4,10 +4,10 @@ \file \ingroup buildblock \brief Implementations for class ModifiedInverseAveragingImageFilterAll - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2003, IRSL @@ -43,855 +43,766 @@ using std::endl; #include "stir_experimental/local_helping_functions.h" #include "stir_experimental/fwd_and_bck_manipulation_for_SAF.h" +START_NAMESPACE_STIR +void construct_scaled_filter_coefficients_3D( + VectorWithOffset>>& new_filter_coefficients_3D_array, + VectorWithOffset kernel_1d, const float kapa0_over_kapa1); -START_NAMESPACE_STIR - +void construct_scaled_filter_coefficients_2D(Array<2, float>& new_filter_coefficients_2D_array, VectorWithOffset kernel_1d, + const float kapa0_over_kapa1); -void -construct_scaled_filter_coefficients_3D(VectorWithOffset < VectorWithOffset < VectorWithOffset < float> > > &new_filter_coefficients_3D_array, - VectorWithOffset kernel_1d, - const float kapa0_over_kapa1); +//// IMPLEMENTATION ///// +/**********************************************************************************************/ void -construct_scaled_filter_coefficients_2D(Array<2,float> &new_filter_coefficients_2D_array, - VectorWithOffset kernel_1d, - const float kapa0_over_kapa1); - - //// IMPLEMENTATION ///// -/**********************************************************************************************/ +construct_scaled_filter_coefficients_3D(Array<3, float>& new_filter_coefficients_3D_array, VectorWithOffset kernel_1d, + const float kapa0_over_kapa1) +{ + // in the case where sq_kappas=1 --- scaled_filter == original template filter + Array<3, float> filter_coefficients(IndexRange3D(kernel_1d.get_min_index(), kernel_1d.get_max_index(), + kernel_1d.get_min_index(), kernel_1d.get_max_index(), + kernel_1d.get_min_index(), kernel_1d.get_max_index())); + + create_kernel_3d(filter_coefficients, kernel_1d); -void -construct_scaled_filter_coefficients_3D(Array<3,float> &new_filter_coefficients_3D_array, - VectorWithOffset kernel_1d, - const float kapa0_over_kapa1) - -{ - - // in the case where sq_kappas=1 --- scaled_filter == original template filter - Array<3,float> filter_coefficients(IndexRange3D(kernel_1d.get_min_index(), kernel_1d.get_max_index(), - kernel_1d.get_min_index(), kernel_1d.get_max_index(), - kernel_1d.get_min_index(), kernel_1d.get_max_index())); - - create_kernel_3d (filter_coefficients, kernel_1d); - - #if 1 - // STUFF FOR THE FFT SIZE + // STUFF FOR THE FFT SIZE /****************** *********************************************************************/ - + const int length_of_size_array = 16; - const float kapa0_over_kapa1_interval_size=10.F; + const float kapa0_over_kapa1_interval_size = 10.F; static VectorWithOffset size_for_kapa0_over_kapa1; - if (size_for_kapa0_over_kapa1.get_length()==0) - { - size_for_kapa0_over_kapa1.grow(0,length_of_size_array-1); + if (size_for_kapa0_over_kapa1.get_length() == 0) { + size_for_kapa0_over_kapa1.grow(0, length_of_size_array - 1); size_for_kapa0_over_kapa1.fill(64); } - - const int kapa0_over_kapa1_interval = - min(static_cast(floor(kapa0_over_kapa1/kapa0_over_kapa1_interval_size)), - length_of_size_array-1); - - float sq_kapas = kapa0_over_kapa1; + + const int kapa0_over_kapa1_interval = + min(static_cast(floor(kapa0_over_kapa1 / kapa0_over_kapa1_interval_size)), length_of_size_array - 1); + + float sq_kapas = kapa0_over_kapa1; /******************************************************************************************/ - - if ( sq_kapas > 10000) - { - new_filter_coefficients_3D_array.grow(IndexRange3D(0,0,0,0,0,0)); - } - else if (sq_kapas!=1.F) - { - - while(true) - { + + if (sq_kapas > 10000) { + new_filter_coefficients_3D_array.grow(IndexRange3D(0, 0, 0, 0, 0, 0)); + } else if (sq_kapas != 1.F) { + + while (true) { const int size = size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]; - - int filter_length = static_cast(floor(kernel_1d.get_length()/2)); - - //cerr << "Now doing size " << size << std::endl; - - // FIRST PADD 1D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC + + int filter_length = static_cast(floor(kernel_1d.get_length() / 2)); + + // cerr << "Now doing size " << size << std::endl; + + // FIRST PADD 1D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC // ( DO NOT TAKE IMAGINARY PART INTO ACCOUNT YET) /**********************************************************************************/ - - Array<1,float> filter_coefficients_padded_1D_array(1,size); - - filter_coefficients_padded_1D_array[1] = kernel_1d[0]; - for ( int i = 1;i<=filter_length;i++) - { - filter_coefficients_padded_1D_array[i+1] = kernel_1d[i]; - filter_coefficients_padded_1D_array[size-(i-1)] = kernel_1d[i]; - + + Array<1, float> filter_coefficients_padded_1D_array(1, size); + + filter_coefficients_padded_1D_array[1] = kernel_1d[0]; + for (int i = 1; i <= filter_length; i++) { + filter_coefficients_padded_1D_array[i + 1] = kernel_1d[i]; + filter_coefficients_padded_1D_array[size - (i - 1)] = kernel_1d[i]; } - + /*************************************************************************************/ - - VectorWithOffset < float> kernel_1d_vector; - kernel_1d_vector.grow(1,size); - for ( int i = 1; i<= size ;i++) - kernel_1d_vector[i] = filter_coefficients_padded_1D_array[i]; - - Array<3,float> filter_coefficients_padded(IndexRange3D(1,size,1,size,1,size)); - - create_kernel_3d (filter_coefficients_padded, kernel_1d_vector); - - + + VectorWithOffset kernel_1d_vector; + kernel_1d_vector.grow(1, size); + for (int i = 1; i <= size; i++) + kernel_1d_vector[i] = filter_coefficients_padded_1D_array[i]; + + Array<3, float> filter_coefficients_padded(IndexRange3D(1, size, 1, size, 1, size)); + + create_kernel_3d(filter_coefficients_padded, kernel_1d_vector); + // rescale to DC=1 filter_coefficients_padded /= filter_coefficients_padded.sum(); - - Array<3,float>& fft_filter = filter_coefficients_padded; - + + Array<3, float>& fft_filter = filter_coefficients_padded; + float inverse_sq_kapas; - if (fabs((double)sq_kapas ) >0.000000000001) - inverse_sq_kapas = 1/sq_kapas; - else - inverse_sq_kapas = 0; - - - // Array<1,float> fft_1_1D_array (1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); - Array<1,float> fft_filter_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); - - static shared_ptr > fft_filter_1D_array_64 = - new Array<1,float>(1,2*64*64*64); - static shared_ptr > fft_filter_1D_array_128 = - new Array<1,float> (1,2*128*128*128); - static shared_ptr > fft_filter_1D_array_256 = - new Array<1,float> (1,2*256*256*256); - - - convert_array_3D_into_1D_array(fft_filter_1D_array,fft_filter); - // fft_1_1D_array[1]=1; - - Array<1, int> array_lengths(1,3); + if (fabs((double)sq_kapas) > 0.000000000001) + inverse_sq_kapas = 1 / sq_kapas; + else + inverse_sq_kapas = 0; + + // Array<1,float> fft_1_1D_array (1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() + // *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); + Array<1, float> fft_filter_1D_array(1, 2 * fft_filter.get_length() * fft_filter[fft_filter.get_min_index()].get_length() * + fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); + + static shared_ptr> fft_filter_1D_array_64 = new Array<1, float>(1, 2 * 64 * 64 * 64); + static shared_ptr> fft_filter_1D_array_128 = new Array<1, float>(1, 2 * 128 * 128 * 128); + static shared_ptr> fft_filter_1D_array_256 = new Array<1, float>(1, 2 * 256 * 256 * 256); + + convert_array_3D_into_1D_array(fft_filter_1D_array, fft_filter); + // fft_1_1D_array[1]=1; + + Array<1, int> array_lengths(1, 3); array_lengths[1] = fft_filter.get_length(); array_lengths[2] = fft_filter[fft_filter.get_min_index()].get_length(); array_lengths[3] = fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length(); - Array<3,float> new_filter_coefficients_3D_array_tmp (IndexRange3D(1,filter_coefficients_padded.get_length(),1,filter_coefficients_padded.get_length(),1,filter_coefficients_padded.get_length())); - - // initialise to 0 to prevent from warnings - float fft_1_1D_array = 0; - //fourn(fft_1_1D_array, array_lengths, 3,1); - - if (size == 64) - { - if ( (*fft_filter_1D_array_64)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 3,1); - fft_filter_1D_array /= sqrt(static_cast(size *size*size)); - *fft_filter_1D_array_64 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_64; + Array<3, float> new_filter_coefficients_3D_array_tmp(IndexRange3D(1, filter_coefficients_padded.get_length(), 1, + filter_coefficients_padded.get_length(), 1, + filter_coefficients_padded.get_length())); - } + // initialise to 0 to prevent from warnings + float fft_1_1D_array = 0; + // fourn(fft_1_1D_array, array_lengths, 3,1); + + if (size == 64) { + if ((*fft_filter_1D_array_64)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 3, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size * size)); + *fft_filter_1D_array_64 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_64; + } + } else if (size == 128) { + if ((*fft_filter_1D_array_128)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 3, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size * size)); + *fft_filter_1D_array_128 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_128; + } + } else if (size == 256) { + if ((*fft_filter_1D_array_256)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 3, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size * size)); + *fft_filter_1D_array_256 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_256; + } + } else { + warning("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n"); } - else if (size ==128) - { - if ( (*fft_filter_1D_array_128)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 3,1); - fft_filter_1D_array /= sqrt(static_cast(size *size*size)); - *fft_filter_1D_array_128 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_128; - } - } - else if ( size == 256) - { - if ( (*fft_filter_1D_array_256)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 3,1); - fft_filter_1D_array /= sqrt(static_cast(size *size*size)); - *fft_filter_1D_array_256 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_256; + // fourn(fft_filter_1D_array, array_lengths, 3,1); - } - } - else - { - warning("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n"); - - } - - // fourn(fft_filter_1D_array, array_lengths, 3,1); - // WARNING -- this only works for the FFT where the convention is that the final result // obtained from the FFT is divided with sqrt(N*N*N) - switch (size) - { + switch (size) { case 64: - fft_1_1D_array = static_cast(1/sqrt(static_cast(64*64*64))); - break; + fft_1_1D_array = static_cast(1 / sqrt(static_cast(64 * 64 * 64))); + break; case 128: - fft_1_1D_array = static_cast(1/sqrt(static_cast(128*128*128))); - break; + fft_1_1D_array = static_cast(1 / sqrt(static_cast(128 * 128 * 128))); + break; case 256: - fft_1_1D_array = static_cast(1/sqrt(static_cast(256*256*256))); - break; - + fft_1_1D_array = static_cast(1 / sqrt(static_cast(256 * 256 * 256))); + break; + default: - warning("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n");; - break; + warning("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n"); + ; + break; } - + // to check the outputs make the fft consistant with mathematica // divide 1/sqrt(size) - //fft_1_1D_array /= sqrt(static_cast (size *size*size)); - // fft_filter_1D_array /= sqrt(static_cast(size *size*size)); - - { - Array<1,float> fft_filter_num_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); - //Array<1,float> div_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); - - //mulitply_complex_arrays(fft_filter_num_1D_array,fft_filter_1D_array,fft_1_1D_array); - - fft_filter_num_1D_array = fft_filter_1D_array* fft_1_1D_array; - for ( int k = fft_filter_1D_array.get_min_index(); k<=fft_filter_1D_array.get_max_index();k++) - { - fft_filter_1D_array[k] *= (sq_kapas-1); - fft_filter_1D_array[k] += fft_1_1D_array; - fft_filter_1D_array[k] /= sq_kapas; - - } - - //divide_complex_arrays(div_1D_array,fft_filter_num_1D_array,fft_filter_1D_array); - - divide_complex_arrays(fft_filter_num_1D_array,fft_filter_1D_array); - fourn(fft_filter_num_1D_array, array_lengths,3,-1); - - // make it consistent with mathemematica -- the output of the - fft_filter_num_1D_array /= sqrt(static_cast(size *size*size)); - - -#if 0 + // fft_1_1D_array /= sqrt(static_cast (size *size*size)); + // fft_filter_1D_array /= sqrt(static_cast(size *size*size)); + + { + Array<1, float> fft_filter_num_1D_array( + 1, 2 * fft_filter.get_length() * fft_filter[fft_filter.get_min_index()].get_length() * + fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); + // Array<1,float> div_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() + // *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); + + // mulitply_complex_arrays(fft_filter_num_1D_array,fft_filter_1D_array,fft_1_1D_array); + + fft_filter_num_1D_array = fft_filter_1D_array * fft_1_1D_array; + for (int k = fft_filter_1D_array.get_min_index(); k <= fft_filter_1D_array.get_max_index(); k++) { + fft_filter_1D_array[k] *= (sq_kapas - 1); + fft_filter_1D_array[k] += fft_1_1D_array; + fft_filter_1D_array[k] /= sq_kapas; + } + + // divide_complex_arrays(div_1D_array,fft_filter_num_1D_array,fft_filter_1D_array); + + divide_complex_arrays(fft_filter_num_1D_array, fft_filter_1D_array); + fourn(fft_filter_num_1D_array, array_lengths, 3, -1); + + // make it consistent with mathemematica -- the output of the + fft_filter_num_1D_array /= sqrt(static_cast(size * size * size)); + +# if 0 cerr << "for kappa_0_over_kappa_1 " << kapa0_over_kapa1 ; for (int i =1;i<=size*size*size;i++) { cerr << fft_filter_num_1D_array[i] << " "; - } -#endif - - // take the real part only - /*********************************************************************************/ - { - Array<1,float> real_div_1D_array(1,fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); - - for (int i=0;i<=(size*size*size)-1;i++) - real_div_1D_array[i+1] = fft_filter_num_1D_array[2*i+1]; - - /*********************************************************************************/ - - - convert_array_1D_into_3D_array(new_filter_coefficients_3D_array_tmp,real_div_1D_array); } - } - int kernel_length_x=0; - int kernel_length_y=0; - int kernel_length_z=0; - - // to prevent form aliasing limit the new range for the coefficients to - // filter_coefficients_padded.get_length()/4 - - - // do the x -direction first -- fix y and z to the min and look for the max index in x - int kx = new_filter_coefficients_3D_array_tmp.get_min_index(); - int jx = new_filter_coefficients_3D_array_tmp[kx].get_min_index(); - for (int i=new_filter_coefficients_3D_array_tmp[kx][jx].get_min_index();i<=filter_coefficients_padded[kx][jx].get_max_index()/4;i++) - { - if (fabs((double)new_filter_coefficients_3D_array_tmp[kx][jx][i]) - <= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()].get_min_index()]*1/1000000) break; - else (kernel_length_x)++; - } - - /******************************* Y DIRECTION ************************************/ - - - int ky = new_filter_coefficients_3D_array_tmp.get_min_index(); - int iy = new_filter_coefficients_3D_array_tmp[ky][new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index(); - for (int j=new_filter_coefficients_3D_array_tmp[ky].get_min_index();j<=filter_coefficients_padded[ky].get_max_index()/4;j++) - { - if (fabs((double)new_filter_coefficients_3D_array_tmp[ky][j][iy]) - //= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) break; - <= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()].get_min_index()]*1/1000000) break; - else (kernel_length_y)++; - } - - /********************************************************************************/ - - /******************************* z DIRECTION ************************************/ - - - int jz = new_filter_coefficients_3D_array_tmp.get_min_index(); - int iz = new_filter_coefficients_3D_array_tmp[jz][new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index(); - for (int k=new_filter_coefficients_3D_array_tmp.get_min_index();k<=filter_coefficients_padded.get_max_index()/4;k++) - { - if (fabs((double)new_filter_coefficients_3D_array_tmp[k][jz][iz]) - //<= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) break; - <= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()].get_min_index()]*1/1000000) break; - else (kernel_length_z)++; - } - - /********************************************************************************/ - - if (kernel_length_x == filter_coefficients_padded.get_length()/4) - { - warning("ModifiedInverseAverigingArrayFilter3D: kernel_length_x reached maximum length %d. " - "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" - "Increasing length of FFT array to resolve this problem\n", - kernel_length_x, new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()], new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][kernel_length_x], - kapa0_over_kapa1); - size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]*=2; - for (int i=kapa0_over_kapa1_interval+1; i real_div_1D_array(1, + fft_filter.get_length() * fft_filter[fft_filter.get_min_index()].get_length() * + fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); -void -construct_scaled_filter_coefficients_2D(Array<2,float> &new_filter_coefficients_2D_array, - VectorWithOffset kernel_1d, - const float kapa0_over_kapa1) - -{ + for (int i = 0; i <= (size * size * size) - 1; i++) + real_div_1D_array[i + 1] = fft_filter_num_1D_array[2 * i + 1]; - - if (kapa0_over_kapa1!=0) - { + /*********************************************************************************/ - //kapa0_over_kapa1 - - // in the case where sq_kappas=1 --- scaled_filter == original template filter - Array<2,float> filter_coefficients(IndexRange2D(kernel_1d.get_min_index(), kernel_1d.get_max_index(), - kernel_1d.get_min_index(), kernel_1d.get_max_index())); - - create_kernel_2d (filter_coefficients, kernel_1d); - - -#if 1 - // STUFF FOR THE FFT SIZE - /****************** *********************************************************************/ - - const int length_of_size_array = 16; - const float kapa0_over_kapa1_interval_size=10.F; - static VectorWithOffset size_for_kapa0_over_kapa1; - if (size_for_kapa0_over_kapa1.get_length()==0) - { - size_for_kapa0_over_kapa1.grow(0,length_of_size_array-1); - size_for_kapa0_over_kapa1.fill(64); - } - - const int kapa0_over_kapa1_interval = - min(static_cast(floor(kapa0_over_kapa1/kapa0_over_kapa1_interval_size)), - length_of_size_array-1); - - float sq_kapas = kapa0_over_kapa1; - /******************************************************************************************/ - - if ( sq_kapas > 10000) - { - new_filter_coefficients_2D_array.grow(IndexRange2D(0,0,0,0)); - } - else if (sq_kapas!=1.F) - { - - while(true) - { - const int size = size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]; - - int filter_length = static_cast(floor(kernel_1d.get_length()/2)); - - //cerr << "Now doing size " << size << std::endl; - - // FIRST PADD 1D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC - // ( DO NOT TAKE IMAGINARY PART INTO ACCOUNT YET) - /**********************************************************************************/ - - Array<1,float> filter_coefficients_padded_1D_array(1,size); - - filter_coefficients_padded_1D_array[1] = kernel_1d[0]; - for ( int i = 1;i<=filter_length;i++) - { - filter_coefficients_padded_1D_array[i+1] = kernel_1d[i]; - filter_coefficients_padded_1D_array[size-(i-1)] = kernel_1d[i]; - + convert_array_1D_into_3D_array(new_filter_coefficients_3D_array_tmp, real_div_1D_array); + } } - - - - /*************************************************************************************/ - - VectorWithOffset < float> kernel_1d_vector; - kernel_1d_vector.grow(1,size); - for ( int i = 1; i<= size ;i++) - kernel_1d_vector[i] = filter_coefficients_padded_1D_array[i]; - - Array<2,float> filter_coefficients_padded(IndexRange2D(1,size,1,size)); - - create_kernel_2d (filter_coefficients_padded, kernel_1d_vector); - - - - // rescale to DC=1 - filter_coefficients_padded /= filter_coefficients_padded.sum(); - - Array<2,float>& fft_filter = filter_coefficients_padded; - - float inverse_sq_kapas; - if (fabs((double)sq_kapas ) >0.000000000001) - inverse_sq_kapas = 1/sq_kapas; - else - inverse_sq_kapas = 0; - - - // Array<1,float> fft_1_1D_array (1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); - Array<1,float> fft_filter_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() ); - - static shared_ptr > fft_filter_1D_array_64 = - new Array<1,float>(1,2*64*64); - static shared_ptr > fft_filter_1D_array_128 = - new Array<1,float> (1,2*128*128); - static shared_ptr > fft_filter_1D_array_256 = - new Array<1,float> (1,2*256*256); - static shared_ptr > fft_filter_1D_array_512 = - new Array<1,float> (1,2*512*512); - static shared_ptr > fft_filter_1D_array_1024 = - new Array<1,float> (1,2*1024*1024); - static shared_ptr > fft_filter_1D_array_2048= - new Array<1,float> (1,2*2048*2048); - - - convert_array_2D_into_1D_array(fft_filter_1D_array,fft_filter); - // fft_1_1D_array[1]=1; - - Array<1, int> array_lengths(1,2); - array_lengths[1] = fft_filter.get_length(); - array_lengths[2] = fft_filter[fft_filter.get_min_index()].get_length(); - //array_lengths[3] = fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length(); - - // initialise to 0 to prevent from warnings - float fft_1_1D_array = 0; - - if (size == 64) - { - if ( (*fft_filter_1D_array_64)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_64 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_64; - - } + int kernel_length_x = 0; + int kernel_length_y = 0; + int kernel_length_z = 0; + + // to prevent form aliasing limit the new range for the coefficients to + // filter_coefficients_padded.get_length()/4 + + // do the x -direction first -- fix y and z to the min and look for the max index in x + int kx = new_filter_coefficients_3D_array_tmp.get_min_index(); + int jx = new_filter_coefficients_3D_array_tmp[kx].get_min_index(); + for (int i = new_filter_coefficients_3D_array_tmp[kx][jx].get_min_index(); + i <= filter_coefficients_padded[kx][jx].get_max_index() / 4; i++) { + if (fabs((double)new_filter_coefficients_3D_array_tmp[kx][jx][i]) <= + new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()] + [new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + .get_min_index()] + .get_min_index()] * + 1 / 1000000) + break; + else + (kernel_length_x)++; } - else if (size ==128) - { - if ( (*fft_filter_1D_array_128)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_128 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_128; - } + /******************************* Y DIRECTION ************************************/ + + int ky = new_filter_coefficients_3D_array_tmp.get_min_index(); + int iy = new_filter_coefficients_3D_array_tmp[ky][new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index(); + for (int j = new_filter_coefficients_3D_array_tmp[ky].get_min_index(); + j <= filter_coefficients_padded[ky].get_max_index() / 4; j++) { + if (fabs((double)new_filter_coefficients_3D_array_tmp[ky][j][iy]) + //= + // new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) + // break; + <= + new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()] + [new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + .get_min_index()] + .get_min_index()] * + 1 / 1000000) + break; + else + (kernel_length_y)++; } - else if ( size == 256) - { - if ( (*fft_filter_1D_array_256)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_256 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_256; - } + /********************************************************************************/ + + /******************************* z DIRECTION ************************************/ + + int jz = new_filter_coefficients_3D_array_tmp.get_min_index(); + int iz = new_filter_coefficients_3D_array_tmp[jz][new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index(); + for (int k = new_filter_coefficients_3D_array_tmp.get_min_index(); k <= filter_coefficients_padded.get_max_index() / 4; + k++) { + if (fabs((double)new_filter_coefficients_3D_array_tmp[k][jz][iz]) + //<= + // new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) + // break; + <= + new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()] + [new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + .get_min_index()] + .get_min_index()] * + 1 / 1000000) + break; + else + (kernel_length_z)++; } - else if ( size == 512) - { - if ( (*fft_filter_1D_array_512)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_512 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_512; - } - } - else if ( size == 1024) - { - if ( (*fft_filter_1D_array_1024)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_1024 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_1024; + /********************************************************************************/ + + if (kernel_length_x == filter_coefficients_padded.get_length() / 4) { + warning("ModifiedInverseAverigingArrayFilter3D: kernel_length_x reached maximum length %d. " + "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" + "Increasing length of FFT array to resolve this problem\n", + kernel_length_x, + new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()], + new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()][kernel_length_x], + kapa0_over_kapa1); + size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval] *= 2; + for (int i = kapa0_over_kapa1_interval + 1; i < size_for_kapa0_over_kapa1.get_length(); ++i) + size_for_kapa0_over_kapa1[i] = max(size_for_kapa0_over_kapa1[i], size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]); + } else if (kernel_length_y == filter_coefficients_padded.get_length() / 4) { + warning("ModifiedInverseAverigingArrayFilter3D: kernel_length_y reached maximum length %d. " + "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" + "Increasing length of FFT array to resolve this problem\n", + kernel_length_y, + new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()], + new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][kernel_length_y] + [new_filter_coefficients_3D_array_tmp.get_min_index()], + kapa0_over_kapa1); + size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval] *= 2; + for (int i = kapa0_over_kapa1_interval + 1; i < size_for_kapa0_over_kapa1.get_length(); ++i) + size_for_kapa0_over_kapa1[i] = max(size_for_kapa0_over_kapa1[i], size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]); + } else if (kernel_length_z == filter_coefficients_padded.get_length() / 4) { + warning("ModifiedInverseAverigingArrayFilter3D: kernel_length_z reached maximum length %d. " + "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" + "Increasing length of FFT array to resolve this problem\n", + kernel_length_z, + new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()], + new_filter_coefficients_3D_array_tmp[kernel_length_z][new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()], + kapa0_over_kapa1); + size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval] *= 2; + for (int i = kapa0_over_kapa1_interval + 1; i < size_for_kapa0_over_kapa1.get_length(); ++i) + size_for_kapa0_over_kapa1[i] = max(size_for_kapa0_over_kapa1[i], size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]); + } else { + new_filter_coefficients_3D_array.grow(IndexRange3D(-(kernel_length_z - 1), kernel_length_z, -(kernel_length_y - 1), + kernel_length_y, -(kernel_length_x - 1), kernel_length_x)); + + new_filter_coefficients_3D_array[0][0][0] = new_filter_coefficients_3D_array_tmp[1][1][1]; + new_filter_coefficients_3D_array[kernel_length_z][kernel_length_y][kernel_length_x] = + new_filter_coefficients_3D_array_tmp[kernel_length_z][kernel_length_y][kernel_length_x]; + + for (int k = 1; k <= kernel_length_z - 1; k++) + for (int j = 1; j <= kernel_length_y - 1; j++) + for (int i = 1; i <= kernel_length_x - 1; i++) + + { + new_filter_coefficients_3D_array[k][j][i] = new_filter_coefficients_3D_array_tmp[k + 1][j + 1][i + 1]; + new_filter_coefficients_3D_array[-k][-j][-i] = new_filter_coefficients_3D_array_tmp[k + 1][j + 1][i + 1]; + } + + break; // out of while(true) + } + } // this bracket is for the while loop + } else // sq_kappas == 1 + { + new_filter_coefficients_3D_array = filter_coefficients; + } - } - } - else if ( size == 2048) - { - if ( (*fft_filter_1D_array_2048)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_2048 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_2048; +#endif - } - } - else - { - warning("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n"); - - } - - // fourn(fft_filter_1D_array, array_lengths, 3,1); - - // WARNING -- this only works for the FFT where the convention is that the final result - // obtained from the FFT is divided with sqrt(N*N*N) - switch (size) - { - case 64: - fft_1_1D_array = static_cast(1/sqrt(static_cast(64*64))); - break; - case 128: - fft_1_1D_array = static_cast(1/sqrt(static_cast(128*128))); - break; - case 256: - fft_1_1D_array = static_cast(1/sqrt(static_cast(256*256))); - break; - case 512: - fft_1_1D_array = static_cast(1/sqrt(static_cast(512*512))); - break; - case 1024: - fft_1_1D_array = static_cast(1/sqrt(static_cast(1024*1024))); - break; - case 2048: - fft_1_1D_array = static_cast(1/sqrt(static_cast(2048*2048))); - break; - - default: - warning("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n");; - break; - } - - // to check the outputs make the fft consistant with mathematica - // divide 1/sqrt(size) - //fft_1_1D_array /= sqrt(static_cast (size *size*size)); - // fft_filter_1D_array /= sqrt(static_cast(size *size*size)); - Array<2,float> new_filter_coefficients_2D_array_tmp (IndexRange2D(1,filter_coefficients_padded.get_length(),1,filter_coefficients_padded.get_length())); - - - - { - Array<1,float> fft_filter_num_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length()); - //Array<1,float> div_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length()); - - //mulitply_complex_arrays(fft_filter_num_1D_array,fft_filter_1D_array,fft_1_1D_array); - - fft_filter_num_1D_array = fft_filter_1D_array* fft_1_1D_array; + // rescale to DC=1 + float sum_new_coefficients = 0; + for (int k = new_filter_coefficients_3D_array.get_min_index(); k <= new_filter_coefficients_3D_array.get_max_index(); k++) + for (int j = new_filter_coefficients_3D_array[k].get_min_index(); j <= new_filter_coefficients_3D_array[k].get_max_index(); + j++) + for (int i = new_filter_coefficients_3D_array[k][j].get_min_index(); + i <= new_filter_coefficients_3D_array[k][j].get_max_index(); i++) + sum_new_coefficients += new_filter_coefficients_3D_array[k][j][i]; + + for (int k = new_filter_coefficients_3D_array.get_min_index(); k <= new_filter_coefficients_3D_array.get_max_index(); k++) + for (int j = new_filter_coefficients_3D_array[k].get_min_index(); j <= new_filter_coefficients_3D_array[k].get_max_index(); + j++) + for (int i = new_filter_coefficients_3D_array[k][j].get_min_index(); + i <= new_filter_coefficients_3D_array[k][j].get_max_index(); i++) + new_filter_coefficients_3D_array[k][j][i] /= sum_new_coefficients; +} - fft_filter_1D_array *= (sq_kapas-1); - // this is necesssery since the imagainary part is stored in the odd indices - for ( int i = fft_filter_1D_array.get_min_index(); i<=fft_filter_1D_array.get_max_index(); i+=2) - { - fft_filter_1D_array[i] += fft_1_1D_array; - } - fft_filter_1D_array /= sq_kapas; +void +construct_scaled_filter_coefficients_2D(Array<2, float>& new_filter_coefficients_2D_array, VectorWithOffset kernel_1d, + const float kapa0_over_kapa1) - divide_complex_arrays(fft_filter_num_1D_array,fft_filter_1D_array); +{ + if (kapa0_over_kapa1 != 0) { - - fourn(fft_filter_num_1D_array, array_lengths,2,-1); - - // make it consistent with mathemematica -- the output of the - fft_filter_num_1D_array /= sqrt(static_cast(size *size)); - + // kapa0_over_kapa1 - - // take the real part only - /*********************************************************************************/ - { - Array<1,float> real_div_1D_array(1,fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length()); - - for (int i=0;i<=(size*size)-1;i++) - real_div_1D_array[i+1] = fft_filter_num_1D_array[2*i+1]; - - /*********************************************************************************/ - - convert_array_1D_into_2D_array(new_filter_coefficients_2D_array_tmp,real_div_1D_array); - - } - } + // in the case where sq_kappas=1 --- scaled_filter == original template filter + Array<2, float> filter_coefficients( + IndexRange2D(kernel_1d.get_min_index(), kernel_1d.get_max_index(), kernel_1d.get_min_index(), kernel_1d.get_max_index())); + create_kernel_2d(filter_coefficients, kernel_1d); - int kernel_length_x=0; - int kernel_length_y=0; - - // to prevent form aliasing limit the new range for the coefficients to - // filter_coefficients_padded.get_length()/4 - - //cerr << " X DIERCTION NOW" << endl; - // do the x -direction first -- fix y and z to the min and look for the max index in x - int jy = new_filter_coefficients_2D_array_tmp.get_min_index(); - for (int i=new_filter_coefficients_2D_array_tmp[jy].get_min_index();i<=filter_coefficients_padded[jy].get_max_index()/2;i++) - { - if (fabs((double)new_filter_coefficients_2D_array_tmp[jy][i]) - <= new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()][new_filter_coefficients_2D_array_tmp.get_min_index()]*1/1000000) break; - else (kernel_length_x)++; - } - - /******************************* Y DIRECTION ************************************/ - - - int ix = new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()].get_min_index(); - for (int j=new_filter_coefficients_2D_array_tmp.get_min_index();j<=filter_coefficients_padded.get_max_index()/2;j++) - { - if (fabs((double)new_filter_coefficients_2D_array_tmp[j][ix]) - //= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) break; - <= new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()][new_filter_coefficients_2D_array_tmp.get_min_index()]*1/1000000) break; - else (kernel_length_y)++; - } - - - /********************************************************************************/ - - - /********************************************************************************/ - - if (kernel_length_x == filter_coefficients_padded.get_length()/4) - { - warning("ModifiedInverseAverigingArrayFilter3D: kernel_length_x reached maximum length %d. " - "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" - "Increasing length of FFT array to resolve this problem\n", - kernel_length_x, new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()][new_filter_coefficients_2D_array_tmp.get_min_index()], - new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()][kernel_length_x], - kapa0_over_kapa1); - size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]*=2; - for (int i=kapa0_over_kapa1_interval+1; i size_for_kapa0_over_kapa1; + if (size_for_kapa0_over_kapa1.get_length() == 0) { + size_for_kapa0_over_kapa1.grow(0, length_of_size_array - 1); + size_for_kapa0_over_kapa1.fill(64); } - else //sq_kappas == 1 + + const int kapa0_over_kapa1_interval = + min(static_cast(floor(kapa0_over_kapa1 / kapa0_over_kapa1_interval_size)), length_of_size_array - 1); + + float sq_kapas = kapa0_over_kapa1; + /******************************************************************************************/ + + if (sq_kapas > 10000) { + new_filter_coefficients_2D_array.grow(IndexRange2D(0, 0, 0, 0)); + } else if (sq_kapas != 1.F) { + + while (true) { + const int size = size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]; + + int filter_length = static_cast(floor(kernel_1d.get_length() / 2)); + + // cerr << "Now doing size " << size << std::endl; + + // FIRST PADD 1D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC + // ( DO NOT TAKE IMAGINARY PART INTO ACCOUNT YET) + /**********************************************************************************/ + + Array<1, float> filter_coefficients_padded_1D_array(1, size); + + filter_coefficients_padded_1D_array[1] = kernel_1d[0]; + for (int i = 1; i <= filter_length; i++) { + filter_coefficients_padded_1D_array[i + 1] = kernel_1d[i]; + filter_coefficients_padded_1D_array[size - (i - 1)] = kernel_1d[i]; + } + + /*************************************************************************************/ + + VectorWithOffset kernel_1d_vector; + kernel_1d_vector.grow(1, size); + for (int i = 1; i <= size; i++) + kernel_1d_vector[i] = filter_coefficients_padded_1D_array[i]; + + Array<2, float> filter_coefficients_padded(IndexRange2D(1, size, 1, size)); + + create_kernel_2d(filter_coefficients_padded, kernel_1d_vector); + + // rescale to DC=1 + filter_coefficients_padded /= filter_coefficients_padded.sum(); + + Array<2, float>& fft_filter = filter_coefficients_padded; + + float inverse_sq_kapas; + if (fabs((double)sq_kapas) > 0.000000000001) + inverse_sq_kapas = 1 / sq_kapas; + else + inverse_sq_kapas = 0; + + // Array<1,float> fft_1_1D_array (1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() + // *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); + Array<1, float> fft_filter_1D_array(1, 2 * fft_filter.get_length() * fft_filter[fft_filter.get_min_index()].get_length()); + + static shared_ptr> fft_filter_1D_array_64 = new Array<1, float>(1, 2 * 64 * 64); + static shared_ptr> fft_filter_1D_array_128 = new Array<1, float>(1, 2 * 128 * 128); + static shared_ptr> fft_filter_1D_array_256 = new Array<1, float>(1, 2 * 256 * 256); + static shared_ptr> fft_filter_1D_array_512 = new Array<1, float>(1, 2 * 512 * 512); + static shared_ptr> fft_filter_1D_array_1024 = new Array<1, float>(1, 2 * 1024 * 1024); + static shared_ptr> fft_filter_1D_array_2048 = new Array<1, float>(1, 2 * 2048 * 2048); + + convert_array_2D_into_1D_array(fft_filter_1D_array, fft_filter); + // fft_1_1D_array[1]=1; + + Array<1, int> array_lengths(1, 2); + array_lengths[1] = fft_filter.get_length(); + array_lengths[2] = fft_filter[fft_filter.get_min_index()].get_length(); + // array_lengths[3] = fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length(); + + // initialise to 0 to prevent from warnings + float fft_1_1D_array = 0; + + if (size == 64) { + if ((*fft_filter_1D_array_64)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_64 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_64; + } + } else if (size == 128) { + if ((*fft_filter_1D_array_128)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_128 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_128; + } + } else if (size == 256) { + if ((*fft_filter_1D_array_256)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_256 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_256; + } + } else if (size == 512) { + if ((*fft_filter_1D_array_512)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_512 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_512; + } + } else if (size == 1024) { + if ((*fft_filter_1D_array_1024)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_1024 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_1024; + } + } else if (size == 2048) { + if ((*fft_filter_1D_array_2048)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_2048 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_2048; + } + } else { + warning("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n"); + } + + // fourn(fft_filter_1D_array, array_lengths, 3,1); + + // WARNING -- this only works for the FFT where the convention is that the final result + // obtained from the FFT is divided with sqrt(N*N*N) + switch (size) { + case 64: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(64 * 64))); + break; + case 128: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(128 * 128))); + break; + case 256: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(256 * 256))); + break; + case 512: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(512 * 512))); + break; + case 1024: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(1024 * 1024))); + break; + case 2048: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(2048 * 2048))); + break; + + default: + warning("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n"); + ; + break; + } + + // to check the outputs make the fft consistant with mathematica + // divide 1/sqrt(size) + // fft_1_1D_array /= sqrt(static_cast (size *size*size)); + // fft_filter_1D_array /= sqrt(static_cast(size *size*size)); + Array<2, float> new_filter_coefficients_2D_array_tmp( + IndexRange2D(1, filter_coefficients_padded.get_length(), 1, filter_coefficients_padded.get_length())); + + { + Array<1, float> fft_filter_num_1D_array(1, 2 * fft_filter.get_length() * + fft_filter[fft_filter.get_min_index()].get_length()); + // Array<1,float> div_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length()); + + // mulitply_complex_arrays(fft_filter_num_1D_array,fft_filter_1D_array,fft_1_1D_array); + + fft_filter_num_1D_array = fft_filter_1D_array * fft_1_1D_array; + + fft_filter_1D_array *= (sq_kapas - 1); + // this is necesssery since the imagainary part is stored in the odd indices + for (int i = fft_filter_1D_array.get_min_index(); i <= fft_filter_1D_array.get_max_index(); i += 2) { + fft_filter_1D_array[i] += fft_1_1D_array; + } + fft_filter_1D_array /= sq_kapas; + + divide_complex_arrays(fft_filter_num_1D_array, fft_filter_1D_array); + + fourn(fft_filter_num_1D_array, array_lengths, 2, -1); + + // make it consistent with mathemematica -- the output of the + fft_filter_num_1D_array /= sqrt(static_cast(size * size)); + + // take the real part only + /*********************************************************************************/ + { + Array<1, float> real_div_1D_array(1, fft_filter.get_length() * fft_filter[fft_filter.get_min_index()].get_length()); + + for (int i = 0; i <= (size * size) - 1; i++) + real_div_1D_array[i + 1] = fft_filter_num_1D_array[2 * i + 1]; + + /*********************************************************************************/ + + convert_array_1D_into_2D_array(new_filter_coefficients_2D_array_tmp, real_div_1D_array); + } + } + + int kernel_length_x = 0; + int kernel_length_y = 0; + + // to prevent form aliasing limit the new range for the coefficients to + // filter_coefficients_padded.get_length()/4 + + // cerr << " X DIERCTION NOW" << endl; + // do the x -direction first -- fix y and z to the min and look for the max index in x + int jy = new_filter_coefficients_2D_array_tmp.get_min_index(); + for (int i = new_filter_coefficients_2D_array_tmp[jy].get_min_index(); + i <= filter_coefficients_padded[jy].get_max_index() / 2; i++) { + if (fabs((double)new_filter_coefficients_2D_array_tmp[jy][i]) <= + new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()] + [new_filter_coefficients_2D_array_tmp.get_min_index()] * + 1 / 1000000) + break; + else + (kernel_length_x)++; + } + + /******************************* Y DIRECTION ************************************/ + + int ix = new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()].get_min_index(); + for (int j = new_filter_coefficients_2D_array_tmp.get_min_index(); j <= filter_coefficients_padded.get_max_index() / 2; + j++) { + if (fabs((double)new_filter_coefficients_2D_array_tmp[j][ix]) + //= + // new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) + // break; + <= new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()] + [new_filter_coefficients_2D_array_tmp.get_min_index()] * + 1 / 1000000) + break; + else + (kernel_length_y)++; + } + + /********************************************************************************/ + + /********************************************************************************/ + + if (kernel_length_x == filter_coefficients_padded.get_length() / 4) { + warning("ModifiedInverseAverigingArrayFilter3D: kernel_length_x reached maximum length %d. " + "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" + "Increasing length of FFT array to resolve this problem\n", + kernel_length_x, + new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()] + [new_filter_coefficients_2D_array_tmp.get_min_index()], + new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()][kernel_length_x], + kapa0_over_kapa1); + size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval] *= 2; + for (int i = kapa0_over_kapa1_interval + 1; i < size_for_kapa0_over_kapa1.get_length(); ++i) + size_for_kapa0_over_kapa1[i] = + max(size_for_kapa0_over_kapa1[i], size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]); + } else if (kernel_length_y == filter_coefficients_padded.get_length() / 4) { + warning("ModifiedInverseAverigingArrayFilter3D: kernel_length_y reached maximum length %d. " + "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" + "Increasing length of FFT array to resolve this problem\n", + kernel_length_y, + new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()] + [new_filter_coefficients_2D_array_tmp.get_min_index()], + new_filter_coefficients_2D_array_tmp[kernel_length_y][new_filter_coefficients_2D_array_tmp.get_min_index()], + kapa0_over_kapa1); + size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval] *= 2; + for (int i = kapa0_over_kapa1_interval + 1; i < size_for_kapa0_over_kapa1.get_length(); ++i) + size_for_kapa0_over_kapa1[i] = + max(size_for_kapa0_over_kapa1[i], size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]); + } else { + + /* cerr << " calulcated coefficients " << endl; + for (int j=1;j<=4;j++) + for (int i=1;i<=4;i++) + { + cerr << new_filter_coefficients_2D_array_tmp[j][i] << " " ; + + } cerr << endl;*/ + + new_filter_coefficients_2D_array.grow( + IndexRange2D(-(kernel_length_y - 1), kernel_length_y - 1, -(kernel_length_x - 1), kernel_length_x - 1)); + + new_filter_coefficients_2D_array[0][0] = new_filter_coefficients_2D_array_tmp[1][1]; + + // new_filter_coefficients_2D_array[kernel_length_y-1][kernel_length_x-1] = + // new_filter_coefficients_2D_array_tmp[kernel_length_y][kernel_length_x]; + + for (int j = 0; j <= kernel_length_y - 1; j++) + for (int i = 0; i <= kernel_length_x - 1; i++) { + new_filter_coefficients_2D_array[j][i] = new_filter_coefficients_2D_array_tmp[j + 1][i + 1]; + new_filter_coefficients_2D_array[-j][-i] = new_filter_coefficients_2D_array_tmp[j + 1][i + 1]; + + new_filter_coefficients_2D_array[-j][i] = new_filter_coefficients_2D_array_tmp[j + 1][i + 1]; + new_filter_coefficients_2D_array[j][-i] = new_filter_coefficients_2D_array_tmp[j + 1][i + 1]; + } + + break; // out of while(true) + } + } // this bracket is for the while loop + } else // sq_kappas == 1 { new_filter_coefficients_2D_array = filter_coefficients; } - - -#endif - - + +#endif + // rescale to DC=1 - float sum_new_coefficients =0; - for (int j=new_filter_coefficients_2D_array.get_min_index();j<=new_filter_coefficients_2D_array.get_max_index();j++) - for (int i=new_filter_coefficients_2D_array[j].get_min_index();i<=new_filter_coefficients_2D_array[j].get_max_index();i++) - sum_new_coefficients += new_filter_coefficients_2D_array[j][i]; - - for (int j=new_filter_coefficients_2D_array.get_min_index();j<=new_filter_coefficients_2D_array.get_max_index();j++) - for (int i=new_filter_coefficients_2D_array[j].get_min_index();i<=new_filter_coefficients_2D_array[j].get_max_index();i++) - new_filter_coefficients_2D_array[j][i] /=sum_new_coefficients; + float sum_new_coefficients = 0; + for (int j = new_filter_coefficients_2D_array.get_min_index(); j <= new_filter_coefficients_2D_array.get_max_index(); j++) + for (int i = new_filter_coefficients_2D_array[j].get_min_index(); i <= new_filter_coefficients_2D_array[j].get_max_index(); + i++) + sum_new_coefficients += new_filter_coefficients_2D_array[j][i]; + + for (int j = new_filter_coefficients_2D_array.get_min_index(); j <= new_filter_coefficients_2D_array.get_max_index(); j++) + for (int i = new_filter_coefficients_2D_array[j].get_min_index(); i <= new_filter_coefficients_2D_array[j].get_max_index(); + i++) + new_filter_coefficients_2D_array[j][i] /= sum_new_coefficients; /* cerr << " now assigned symmetric coeff " << endl; - for (int j = new_filter_coefficients_2D_array.get_min_index();j<= new_filter_coefficients_2D_array.get_max_index();j++) - for (int i = new_filter_coefficients_2D_array[j].get_min_index();i<=new_filter_coefficients_2D_array[j].get_max_index();i++) - { - cerr << new_filter_coefficients_2D_array[j][i] << " " ; + for (int j = new_filter_coefficients_2D_array.get_min_index();j<= + new_filter_coefficients_2D_array.get_max_index();j++) for (int i = + new_filter_coefficients_2D_array[j].get_min_index();i<=new_filter_coefficients_2D_array[j].get_max_index();i++) + { + cerr << new_filter_coefficients_2D_array[j][i] << " " ; - }*/ - - -} -else -{ - new_filter_coefficients_2D_array.grow(IndexRange2D(0,0,0,0)); - new_filter_coefficients_2D_array[0][0] =0; + }*/ + + } else { + new_filter_coefficients_2D_array.grow(IndexRange2D(0, 0, 0, 0)); + new_filter_coefficients_2D_array[0][0] = 0; } - } - - #if 1 - template -ModifiedInverseAveragingImageFilterAll:: -ModifiedInverseAveragingImageFilterAll() -{ +ModifiedInverseAveragingImageFilterAll::ModifiedInverseAveragingImageFilterAll() { set_defaults(); } - template -ModifiedInverseAveragingImageFilterAll:: -ModifiedInverseAveragingImageFilterAll(string proj_data_filename_v, - string attenuation_proj_data_filename_v, - const VectorWithOffset& filter_coefficients_v, - shared_ptr proj_data_ptr_v, - shared_ptr attenuation_proj_data_ptr_v, - DiscretisedDensity<3,float>* initial_image_v, - DiscretisedDensity<3,float>* sensitivity_image_v, - DiscretisedDensity<3,float>* precomputed_coefficients_image_v, - DiscretisedDensity<3,float>* normalised_bck_image_v, - int mask_size_v, int num_dim_v) - - +ModifiedInverseAveragingImageFilterAll::ModifiedInverseAveragingImageFilterAll( + string proj_data_filename_v, string attenuation_proj_data_filename_v, const VectorWithOffset& filter_coefficients_v, + shared_ptr proj_data_ptr_v, shared_ptr attenuation_proj_data_ptr_v, + DiscretisedDensity<3, float>* initial_image_v, DiscretisedDensity<3, float>* sensitivity_image_v, + DiscretisedDensity<3, float>* precomputed_coefficients_image_v, DiscretisedDensity<3, float>* normalised_bck_image_v, + int mask_size_v, int num_dim_v) + { - assert(filter_coefficients.get_length() == 0 || - filter_coefficients.begin()==0); - - for (int i = filter_coefficients_v.get_min_index();i<=filter_coefficients_v.get_max_index();i++) + assert(filter_coefficients.get_length() == 0 || filter_coefficients.begin() == 0); + + for (int i = filter_coefficients_v.get_min_index(); i <= filter_coefficients_v.get_max_index(); i++) filter_coefficients[i] = filter_coefficients_v[i]; - proj_data_filename = proj_data_filename_v; + proj_data_filename = proj_data_filename_v; attenuation_proj_data_filename = attenuation_proj_data_filename_v; proj_data_ptr = proj_data_ptr_v; attenuation_proj_data_ptr = attenuation_proj_data_ptr_v; @@ -899,1509 +810,1209 @@ ModifiedInverseAveragingImageFilterAll(string proj_data_filename_v, sensitivity_image = sensitivity_image_v; precomputed_coefficients_image = precomputed_coefficients_image_v; normalised_bck_image = normalised_bck_image_v; - mask_size= mask_size_v; + mask_size = mask_size_v; num_dim = num_dim_v; } - template -Succeeded -ModifiedInverseAveragingImageFilterAll:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) -{ - proj_data_ptr = - ProjData::read_from_file( proj_data_filename); - - if (attenuation_proj_data_filename !="1") - attenuation_proj_data_ptr = - ProjData::read_from_file(attenuation_proj_data_filename); - else +Succeeded +ModifiedInverseAveragingImageFilterAll::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { + proj_data_ptr = ProjData::read_from_file(proj_data_filename); + + if (attenuation_proj_data_filename != "1") + attenuation_proj_data_ptr = ProjData::read_from_file(attenuation_proj_data_filename); + else attenuation_proj_data_ptr = NULL; - if (initial_image_filename !="1") - initial_image = - DiscretisedDensity<3,float>::read_from_file(initial_image_filename); - else - initial_image = NULL; + if (initial_image_filename != "1") + initial_image = DiscretisedDensity<3, float>::read_from_file(initial_image_filename); + else + initial_image = NULL; - if (sensitivity_image_filename !="1") - sensitivity_image = - DiscretisedDensity<3,float>::read_from_file(sensitivity_image_filename); - else + if (sensitivity_image_filename != "1") + sensitivity_image = DiscretisedDensity<3, float>::read_from_file(sensitivity_image_filename); + else sensitivity_image = NULL; - if (precomputed_coefficients_filename !="1") - precomputed_coefficients_image = - DiscretisedDensity<3,float>::read_from_file(precomputed_coefficients_filename); - else - precomputed_coefficients_image =NULL; + if (precomputed_coefficients_filename != "1") + precomputed_coefficients_image = DiscretisedDensity<3, float>::read_from_file(precomputed_coefficients_filename); + else + precomputed_coefficients_image = NULL; - if (normalised_bck_filename !="1") - normalised_bck_image = - DiscretisedDensity<3,float>::read_from_file(normalised_bck_filename); - else - normalised_bck_image =NULL; + if (normalised_bck_filename != "1") + normalised_bck_image = DiscretisedDensity<3, float>::read_from_file(normalised_bck_filename); + else + normalised_bck_image = NULL; + return Succeeded::yes; +} +template +void +ModifiedInverseAveragingImageFilterAll::precalculate_filter_coefficients( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const { - return Succeeded::yes; - -} + VectorWithOffset>> filter_lookup; + filter_lookup.grow(1, 500); + const int k_min = 1; + const float k_interval = 0.01F; // 0.01F; + shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); + VoxelsOnCartesianGrid* in_density_cast = dynamic_cast*>(in_density); -template -void -ModifiedInverseAveragingImageFilterAll::precalculate_filter_coefficients (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const -{ + VoxelsOnCartesianGrid* vox_image_ptr_1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); - - VectorWithOffset < shared_ptr > > filter_lookup; - filter_lookup.grow(1,500); - const int k_min =1; - const float k_interval = 0.01F; //0.01F; - - - shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); - VoxelsOnCartesianGrid* in_density_cast = - dynamic_cast< VoxelsOnCartesianGrid* >(in_density); - - - VoxelsOnCartesianGrid * vox_image_ptr_1 = - new VoxelsOnCartesianGrid (IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - int start_segment_num = proj_data_ptr->get_min_segment_num(); int end_segment_num = proj_data_ptr->get_max_segment_num(); - - VectorWithOffset *> all_segments(start_segment_num, end_segment_num); - VectorWithOffset *> all_segments_for_kappa0(start_segment_num, end_segment_num); - VectorWithOffset *> all_attenuation_segments(start_segment_num, end_segment_num); - - + + VectorWithOffset*> all_segments(start_segment_num, end_segment_num); + VectorWithOffset*> all_segments_for_kappa0(start_segment_num, end_segment_num); + VectorWithOffset*> all_attenuation_segments(start_segment_num, end_segment_num); + // first initialise to false bool do_attenuation = false; - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { all_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); all_segments_for_kappa0[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - - if (attenuation_proj_data_filename!="1") - { + + if (attenuation_proj_data_filename != "1") { do_attenuation = true; - all_attenuation_segments[segment_num] = - new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); - } - else - { + all_attenuation_segments[segment_num] = + new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); + } else { do_attenuation = false; - all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); (*all_attenuation_segments[segment_num]).fill(1); } - } - - vox_image_ptr_1->set_origin(Coordinate3D(0,0,0)); - - shared_ptr > image_sptr = vox_image_ptr_1; - - shared_ptr proj_matrix_ptr = - new ProjMatrixByDenselUsingRayTracing; - - proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), - image_sptr); + + vox_image_ptr_1->set_origin(Coordinate3D(0, 0, 0)); + + shared_ptr> image_sptr = vox_image_ptr_1; + + shared_ptr proj_matrix_ptr = new ProjMatrixByDenselUsingRayTracing; + + proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), image_sptr); info(proj_matrix_ptr->parameter_info()); - fwd_densels_all(all_segments,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - in_density_cast->get_min_y(), in_density_cast->get_max_y(), - in_density_cast->get_min_x(), in_density_cast->get_max_x(), - *in_density); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa0 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa1 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * kappa_coefficients = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - - shared_ptr > kappa0_ptr_bck = vox_image_ptr_kappa0; - shared_ptr > kappa1_ptr_bck = vox_image_ptr_kappa1; - + fwd_densels_all(all_segments, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), in_density_cast->get_max_z(), + in_density_cast->get_min_y(), in_density_cast->get_max_y(), in_density_cast->get_min_x(), + in_density_cast->get_max_x(), *in_density); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa0 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* kappa_coefficients = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + shared_ptr> kappa0_ptr_bck = vox_image_ptr_kappa0; + shared_ptr> kappa1_ptr_bck = vox_image_ptr_kappa1; + // WARNING - find a way of finding max in the sinogram // TODO - include other segments as well - float max_in_viewgram =0.F; - - for (int segment_num = start_segment_num; segment_num<= end_segment_num; segment_num++) - { - SegmentByView segment_by_view = - proj_data_ptr->get_segment_by_view(segment_num); + float max_in_viewgram = 0.F; + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; segment_num++) { + SegmentByView segment_by_view = proj_data_ptr->get_segment_by_view(segment_num); const float current_max_in_viewgram = segment_by_view.find_max(); - if ( current_max_in_viewgram >= max_in_viewgram) - max_in_viewgram = current_max_in_viewgram ; + if (current_max_in_viewgram >= max_in_viewgram) + max_in_viewgram = current_max_in_viewgram; else continue; } - const float threshold = 0.0001F*max_in_viewgram; - + const float threshold = 0.0001F * max_in_viewgram; + info(boost::format(" THRESHOLD IS %1%") % threshold); - - find_inverse_and_bck_densels(*kappa1_ptr_bck,all_segments, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - vox_image_ptr_kappa1->get_min_y(),vox_image_ptr_kappa1->get_max_y(), - vox_image_ptr_kappa1->get_min_x(),vox_image_ptr_kappa1->get_max_x(), - *proj_matrix_ptr, do_attenuation,threshold, false); //true); - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + + find_inverse_and_bck_densels(*kappa1_ptr_bck, all_segments, all_attenuation_segments, vox_image_ptr_kappa1->get_min_z(), + vox_image_ptr_kappa1->get_max_z(), vox_image_ptr_kappa1->get_min_y(), + vox_image_ptr_kappa1->get_max_y(), vox_image_ptr_kappa1->get_min_x(), + vox_image_ptr_kappa1->get_max_x(), *proj_matrix_ptr, do_attenuation, threshold, false); // true); + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { delete all_segments[segment_num]; delete all_attenuation_segments[segment_num]; - } - + } + info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); - - for (int k=in_density_cast->get_min_z();k<=in_density_cast->get_max_z();k++) - for (int j =in_density_cast->get_min_y();j<=in_density_cast->get_max_y();j++) - for (int i =in_density_cast->get_min_x();i<=in_density_cast->get_max_x();i++) - { - - // WARNING - only works for segment zero at the moment - // do the calculation of kappa0 here - kappa0_ptr_bck->fill(0); - for (int segment_num = start_segment_num; - segment_num <= end_segment_num; ++segment_num) - { - (*all_segments_for_kappa0[segment_num]).fill(0); - } - if (true) //attenuation_proj_data_filename !="1") - { - shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid - (IndexRange3D(-mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), - mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - /*shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid(IndexRange3D(k,k, - //-mask_size+k,mask_size+k, - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); */ - CPUTimer timer; - timer.start(); - - // SM 23/05/2002 mask now 3D - const int min_k = max(in_density_cast->get_min_z(),k-mask_size); - const int max_k = min(in_density_cast->get_max_z(),k+mask_size); - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - // the mask size is in 2D only - // SM mask now 3D - for (int k_in =min_k;k_in<=max_k;k_in++) - for (int j_in =min_j;j_in<=max_j;j_in++) - for (int i_in =min_i;i_in<=max_i;i_in++) - { - (*in_density_cast_tmp)[k_in-k+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2)][j_in-j +6][i_in-i+6] = (*in_density_cast)[k_in][j_in][i_in]; - //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; - } - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast_tmp->get_min_z(), in_density_cast_tmp->get_max_z(), - in_density_cast_tmp->get_min_y(),in_density_cast_tmp->get_max_y(), - in_density_cast_tmp->get_min_x(),in_density_cast_tmp->get_max_x(), - *in_density_cast_tmp); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - //k,k, - (ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2,ceil((vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z())/2), - //0,0,0,0, - 6,6,6,6, - *proj_matrix_ptr,false,threshold, false) ;//true); - (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2][6][6]; - //(*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; - - timer.stop(); - //cerr << "kappa0 time "<< timer.value() << endl; - } - else - { - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - min_j,max_j, - min_i,max_i, - //j-2,j+2, - //i-2,i+2, - *in_density_cast); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - j,j,i,i, - *proj_matrix_ptr,false,threshold, true); - - } - float sq_kapas; -// float multiply_with_sensitivity; - if ( fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && - fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001 ) - { - sq_kapas =((*kappa0_ptr_bck)[k][j][i]*(*kappa0_ptr_bck)[k][j][i])/((*kappa1_ptr_bck)[k][j][i]*(*kappa1_ptr_bck)[k][j][i]); - // cerr << "sq_kapas " << sq_kapas << endl; - - //float tmp = (*sensitivity_image)[k][j][i]; - //float tmp_1 = (*sensitivity_image)[ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2][6][6]; - //cerr << (*sensitivity_image)[k][j][i] << " " << (*sensitivity_image)[ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2][6][6]; - - /* multiply_with_sensitivity = (*sensitivity_image)[ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2][6][6]; - if ((*sensitivity_image)[k][j][i] >0.0000001 || (*sensitivity_image)[k][j][i] <-0.0000001) - { - multiply_with_sensitivity /= (*sensitivity_image)[k][j][i]; - } - else - { - multiply_with_sensitivity /= 0.000001F; - }*/ - - // sq_kapas *= multiply_with_sensitivity; - (*kappa_coefficients)[k][j][i] = sq_kapas; - - //sq_kapas = 10.0F; - //cerr << sq_kapas << " " ; - - int k_index ; - //int k_index = min(round(((float)sq_kapas- k_min)/k_interval), 1000); - // if (sq_kapas > 1000) - //{ - //k_index = 1000; - //} - //else - //{ - k_index = round(((float)sq_kapas- k_min)/k_interval); - //} - if (k_index < 1) - {k_index = 1;} - - if ( k_index > 500) - { k_index = 500;} - - - if ( filter_lookup[k_index]==NULL ) - { - Array <3,float> new_coeffs; - info(boost::format("computing new filter for sq_kappas %1% at index %2%") % sq_kapas % k_index); - construct_scaled_filter_coefficients_3D(new_coeffs, filter_coefficients,sq_kapas); - filter_lookup[k_index] = new ArrayFilter3DUsingConvolution(new_coeffs); - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - //new ArrayFilter3DUsingConvolution(new_coeffs); - - } - else - { - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - - } - - - // all_filter_coefficients[k][j][i] = - // new ModifiedInverseAverigingArrayFilter<3,float>(inverse_filter); - - } - else - { - sq_kapas = 0; - // inverse_filter = - // ModifiedInverseAverigingArrayFilter<3,float>(); - all_filter_coefficients[k][j][i] = - new ArrayFilter3DUsingConvolution(); - - } - - } - - write_basic_interfile("kappa_coefficients_2D_SENS",*kappa_coefficients); - delete kappa_coefficients ; + for (int k = in_density_cast->get_min_z(); k <= in_density_cast->get_max_z(); k++) + for (int j = in_density_cast->get_min_y(); j <= in_density_cast->get_max_y(); j++) + for (int i = in_density_cast->get_min_x(); i <= in_density_cast->get_max_x(); i++) { + + // WARNING - only works for segment zero at the moment + // do the calculation of kappa0 here + kappa0_ptr_bck->fill(0); + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + (*all_segments_for_kappa0[segment_num]).fill(0); + } + if (true) // attenuation_proj_data_filename !="1") + { + shared_ptr> in_density_cast_tmp = new VoxelsOnCartesianGrid( + IndexRange3D(-mask_size + (ceil(in_density_cast->get_max_z() - in_density_cast->get_min_z()) / 2), + mask_size + (ceil(in_density_cast->get_max_z() - in_density_cast->get_min_z()) / 2), -mask_size + 6, + mask_size + 6, -mask_size + 6, mask_size + 6), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + /*shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = + new VoxelsOnCartesianGrid(IndexRange3D(k,k, + //-mask_size+k,mask_size+k, + -mask_size+6,mask_size+6, + -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); */ + CPUTimer timer; + timer.start(); + + // SM 23/05/2002 mask now 3D + const int min_k = max(in_density_cast->get_min_z(), k - mask_size); + const int max_k = min(in_density_cast->get_max_z(), k + mask_size); + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + // the mask size is in 2D only + // SM mask now 3D + for (int k_in = min_k; k_in <= max_k; k_in++) + for (int j_in = min_j; j_in <= max_j; j_in++) + for (int i_in = min_i; i_in <= max_i; i_in++) { + (*in_density_cast_tmp)[k_in - k + (ceil(in_density_cast->get_max_z() - in_density_cast->get_min_z()) / 2)] + [j_in - j + 6][i_in - i + 6] = (*in_density_cast)[k_in][j_in][i_in]; + //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; + } + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast_tmp->get_min_z(), + in_density_cast_tmp->get_max_z(), in_density_cast_tmp->get_min_y(), in_density_cast_tmp->get_max_y(), + in_density_cast_tmp->get_min_x(), in_density_cast_tmp->get_max_x(), *in_density_cast_tmp); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + // k,k, + (ceil(vox_image_ptr_kappa1->get_max_z() - vox_image_ptr_kappa1->get_min_z())) / 2, + ceil((vox_image_ptr_kappa1->get_max_z() - vox_image_ptr_kappa1->get_min_z()) / 2), + // 0,0,0,0, + 6, 6, 6, 6, *proj_matrix_ptr, false, threshold, false); // true); + (*kappa0_ptr_bck)[k][j][i] = + (*kappa0_ptr_bck)[(ceil(vox_image_ptr_kappa1->get_max_z() - vox_image_ptr_kappa1->get_min_z())) / 2][6][6]; + //(*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; + + timer.stop(); + // cerr << "kappa0 time "<< timer.value() << endl; + } else { + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), + in_density_cast->get_max_z(), min_j, max_j, min_i, max_i, + // j-2,j+2, + // i-2,i+2, + *in_density_cast); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + vox_image_ptr_kappa1->get_min_z(), vox_image_ptr_kappa1->get_max_z(), j, j, i, i, + *proj_matrix_ptr, false, threshold, true); + } + float sq_kapas; + // float multiply_with_sensitivity; + if (fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && + fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001) { + sq_kapas = ((*kappa0_ptr_bck)[k][j][i] * (*kappa0_ptr_bck)[k][j][i]) / + ((*kappa1_ptr_bck)[k][j][i] * (*kappa1_ptr_bck)[k][j][i]); + // cerr << "sq_kapas " << sq_kapas << endl; + + // float tmp = (*sensitivity_image)[k][j][i]; + // float tmp_1 = (*sensitivity_image)[ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2][6][6]; + // cerr << (*sensitivity_image)[k][j][i] << " " << + // (*sensitivity_image)[ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2][6][6]; + + /* multiply_with_sensitivity = + (*sensitivity_image)[ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2][6][6]; if + ((*sensitivity_image)[k][j][i] >0.0000001 || (*sensitivity_image)[k][j][i] <-0.0000001) + { + multiply_with_sensitivity /= (*sensitivity_image)[k][j][i]; + } + else + { + multiply_with_sensitivity /= 0.000001F; + }*/ + + // sq_kapas *= multiply_with_sensitivity; + (*kappa_coefficients)[k][j][i] = sq_kapas; + + // sq_kapas = 10.0F; + // cerr << sq_kapas << " " ; + + int k_index; + // int k_index = min(round(((float)sq_kapas- k_min)/k_interval), 1000); + // if (sq_kapas > 1000) + //{ + // k_index = 1000; + //} + // else + //{ + k_index = round(((float)sq_kapas - k_min) / k_interval); + //} + if (k_index < 1) { + k_index = 1; + } + + if (k_index > 500) { + k_index = 500; + } + + if (filter_lookup[k_index] == NULL) { + Array<3, float> new_coeffs; + info(boost::format("computing new filter for sq_kappas %1% at index %2%") % sq_kapas % k_index); + construct_scaled_filter_coefficients_3D(new_coeffs, filter_coefficients, sq_kapas); + filter_lookup[k_index] = new ArrayFilter3DUsingConvolution(new_coeffs); + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + // new ArrayFilter3DUsingConvolution(new_coeffs); + + } else { + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + } + + // all_filter_coefficients[k][j][i] = + // new ModifiedInverseAverigingArrayFilter<3,float>(inverse_filter); + + } else { + sq_kapas = 0; + // inverse_filter = + // ModifiedInverseAverigingArrayFilter<3,float>(); + all_filter_coefficients[k][j][i] = new ArrayFilter3DUsingConvolution(); + } + } - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - delete all_segments_for_kappa0[segment_num]; + write_basic_interfile("kappa_coefficients_2D_SENS", *kappa_coefficients); + delete kappa_coefficients; + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + delete all_segments_for_kappa0[segment_num]; } - - - } - template -void -ModifiedInverseAveragingImageFilterAll::precalculate_filter_coefficients_2D (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const -{ - - VectorWithOffset < shared_ptr > > filter_lookup; +void +ModifiedInverseAveragingImageFilterAll::precalculate_filter_coefficients_2D( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const { + + VectorWithOffset>> filter_lookup; const int num_elements_in_interval = 500; - filter_lookup.grow(1,num_elements_in_interval); - const int k_min =1; - const float k_interval = 0.01F; //0.01F; - - - shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); - VoxelsOnCartesianGrid* in_density_cast = - dynamic_cast< VoxelsOnCartesianGrid* >(in_density); - - - VoxelsOnCartesianGrid * vox_image_ptr_1 = - new VoxelsOnCartesianGrid (IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - + filter_lookup.grow(1, num_elements_in_interval); + const int k_min = 1; + const float k_interval = 0.01F; // 0.01F; + + shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); + VoxelsOnCartesianGrid* in_density_cast = dynamic_cast*>(in_density); + + VoxelsOnCartesianGrid* vox_image_ptr_1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + int start_segment_num = proj_data_ptr->get_min_segment_num(); int end_segment_num = proj_data_ptr->get_max_segment_num(); - - VectorWithOffset *> all_segments(start_segment_num, end_segment_num); - VectorWithOffset *> all_segments_for_kappa0(start_segment_num, end_segment_num); - VectorWithOffset *> all_attenuation_segments(start_segment_num, end_segment_num); - - + + VectorWithOffset*> all_segments(start_segment_num, end_segment_num); + VectorWithOffset*> all_segments_for_kappa0(start_segment_num, end_segment_num); + VectorWithOffset*> all_attenuation_segments(start_segment_num, end_segment_num); + // first initialise to false bool do_attenuation = false; - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { all_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); all_segments_for_kappa0[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - - if (attenuation_proj_data_filename!="1") - { + + if (attenuation_proj_data_filename != "1") { do_attenuation = true; - all_attenuation_segments[segment_num] = - new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); - } - else - { + all_attenuation_segments[segment_num] = + new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); + } else { do_attenuation = false; - all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); (*all_attenuation_segments[segment_num]).fill(1); } - } - - vox_image_ptr_1->set_origin(Coordinate3D(0,0,0)); - - shared_ptr > image_sptr = vox_image_ptr_1; - - shared_ptr proj_matrix_ptr = - new ProjMatrixByDenselUsingRayTracing; - - proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), - image_sptr); + + vox_image_ptr_1->set_origin(Coordinate3D(0, 0, 0)); + + shared_ptr> image_sptr = vox_image_ptr_1; + + shared_ptr proj_matrix_ptr = new ProjMatrixByDenselUsingRayTracing; + + proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), image_sptr); info(boost::format("%1%") % proj_matrix_ptr->parameter_info()); - - fwd_densels_all(all_segments,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - in_density_cast->get_min_y(), in_density_cast->get_max_y(), - in_density_cast->get_min_x(), in_density_cast->get_max_x(), - *in_density); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa0 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa1 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * kappa_coefficients = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - - shared_ptr > kappa0_ptr_bck = vox_image_ptr_kappa0; - shared_ptr > kappa1_ptr_bck = vox_image_ptr_kappa1; - + + fwd_densels_all(all_segments, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), in_density_cast->get_max_z(), + in_density_cast->get_min_y(), in_density_cast->get_max_y(), in_density_cast->get_min_x(), + in_density_cast->get_max_x(), *in_density); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa0 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* kappa_coefficients = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + shared_ptr> kappa0_ptr_bck = vox_image_ptr_kappa0; + shared_ptr> kappa1_ptr_bck = vox_image_ptr_kappa1; + // WARNING - find a way of finding max in the sinogram // TODO - include other segments as well - float max_in_viewgram =0.F; - - for (int segment_num = start_segment_num; segment_num<= end_segment_num; segment_num++) - { - SegmentByView segment_by_view = - proj_data_ptr->get_segment_by_view(segment_num); + float max_in_viewgram = 0.F; + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; segment_num++) { + SegmentByView segment_by_view = proj_data_ptr->get_segment_by_view(segment_num); const float current_max_in_viewgram = segment_by_view.find_max(); - if ( current_max_in_viewgram >= max_in_viewgram) - max_in_viewgram = current_max_in_viewgram ; + if (current_max_in_viewgram >= max_in_viewgram) + max_in_viewgram = current_max_in_viewgram; else continue; } - const float threshold = 0.0001F*max_in_viewgram; - + const float threshold = 0.0001F * max_in_viewgram; + info(boost::format(" THRESHOLD IS %1%") % threshold); - - find_inverse_and_bck_densels(*kappa1_ptr_bck,all_segments, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - vox_image_ptr_kappa1->get_min_y(),vox_image_ptr_kappa1->get_max_y(), - vox_image_ptr_kappa1->get_min_x(),vox_image_ptr_kappa1->get_max_x(), - *proj_matrix_ptr, do_attenuation,threshold, false); //true); - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + + find_inverse_and_bck_densels(*kappa1_ptr_bck, all_segments, all_attenuation_segments, vox_image_ptr_kappa1->get_min_z(), + vox_image_ptr_kappa1->get_max_z(), vox_image_ptr_kappa1->get_min_y(), + vox_image_ptr_kappa1->get_max_y(), vox_image_ptr_kappa1->get_min_x(), + vox_image_ptr_kappa1->get_max_x(), *proj_matrix_ptr, do_attenuation, threshold, false); // true); + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { delete all_segments[segment_num]; delete all_attenuation_segments[segment_num]; - } - + } + info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); - - for (int k=in_density_cast->get_min_z();k<=in_density_cast->get_max_z();k++) - for (int j =in_density_cast->get_min_y();j<=in_density_cast->get_max_y();j++) - for (int i =in_density_cast->get_min_x();i<=in_density_cast->get_max_x();i++) - { - - // WARNING - only works for segment zero at the moment - // do the calculation of kappa0 here - kappa0_ptr_bck->fill(0); - for (int segment_num = start_segment_num; - segment_num <= end_segment_num; ++segment_num) - { - (*all_segments_for_kappa0[segment_num]).fill(0); - } - if (true) //attenuation_proj_data_filename !="1") - { -#if 1 - shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid - (IndexRange3D(k,k, - //-mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), - // mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - /*shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid(IndexRange3D(k,k, - //-mask_size+k,mask_size+k, - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); */ - CPUTimer timer; - timer.start(); - - // SM 23/05/2002 mask now 3D - //const int min_k = in_density_cast->get_min_z(); //max(in_density_cast->get_min_z(),k-mask_size); - //const int max_k = in_density_cast->get_max_z(); // min(in_density_cast->get_max_z(),k+mask_size); - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - // the mask size is in 2D only - // SM mask now 3D - //for (int k_in =min_k;k_in<=max_k;k_in++) - for (int j_in =min_j;j_in<=max_j;j_in++) - for (int i_in =min_i;i_in<=max_i;i_in++) - { - (*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; - //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; - } - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast_tmp->get_min_z(), in_density_cast_tmp->get_max_z(), - in_density_cast_tmp->get_min_y(),in_density_cast_tmp->get_max_y(), - in_density_cast_tmp->get_min_x(),in_density_cast_tmp->get_max_x(), - *in_density_cast_tmp); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - k,k, - //(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2,ceil((vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z())/2), - //0,0,0,0, - 6,6,6,6, - *proj_matrix_ptr,false,threshold, false) ;//true); - //(*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2][6][6]; - (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; - - timer.stop(); - //cerr << "kappa0 time "<< timer.value() << endl; - } - else - { - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - min_j,max_j, - min_i,max_i, - //j-2,j+2, - //i-2,i+2, - *in_density_cast); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - j,j,i,i, - *proj_matrix_ptr,false,threshold, true); - - } - float sq_kapas; -// float multiply_with_sensitivity; - if ( fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && - fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001 ) - { - sq_kapas =((*kappa0_ptr_bck)[k][j][i]*(*kappa0_ptr_bck)[k][j][i])/((*kappa1_ptr_bck)[k][j][i]*(*kappa1_ptr_bck)[k][j][i]); - - //cerr << " kappa0 " << (*kappa0_ptr_bck)[k][j][i] << endl; - //cerr << " kappa1 " << (*kappa1_ptr_bck)[k][j][i] << endl; - - - - /* multiply_with_sensitivity = (*sensitivity_image)[ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2][6][6]; - if ((*sensitivity_image)[k][j][i] >0.0000001 || (*sensitivity_image)[k][j][i] <-0.0000001) - { - multiply_with_sensitivity /= (*sensitivity_image)[k][j][i]; - } - else - { - multiply_with_sensitivity /= 0.000001F; - } - - sq_kapas *= multiply_with_sensitivity; */ -#else - float sq_kapas = 1.0F; -#endif - (*kappa_coefficients)[k][j][i] = sq_kapas; - //sq_kapas = 2; - - - - //cerr << " now printing sq_kappas value:" << " " << sq_kapas << endl; - int k_index ; - k_index = round(((float)sq_kapas- k_min)/k_interval); - if (k_index < 1) - {k_index = 1;} - - if ( k_index > num_elements_in_interval) - { k_index = num_elements_in_interval;} - - - if ( filter_lookup[k_index]==NULL ) - { - Array <2,float> new_coeffs; - info(boost::format("computing new filter for sq_kappas %1% at index %2%") % sq_kapas % k_index); - construct_scaled_filter_coefficients_2D(new_coeffs, filter_coefficients,sq_kapas); - filter_lookup[k_index] = new ArrayFilter2DUsingConvolution(new_coeffs); - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - //new ArrayFilter3DUsingConvolution(new_coeffs); - - } - else - { - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - - } - - } - else - { + for (int k = in_density_cast->get_min_z(); k <= in_density_cast->get_max_z(); k++) + for (int j = in_density_cast->get_min_y(); j <= in_density_cast->get_max_y(); j++) + for (int i = in_density_cast->get_min_x(); i <= in_density_cast->get_max_x(); i++) { + + // WARNING - only works for segment zero at the moment + // do the calculation of kappa0 here + kappa0_ptr_bck->fill(0); + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + (*all_segments_for_kappa0[segment_num]).fill(0); + } + if (true) // attenuation_proj_data_filename !="1") + { + +# if 1 + shared_ptr> in_density_cast_tmp = new VoxelsOnCartesianGrid( + IndexRange3D(k, k, + //-mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), + // mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), + -mask_size + 6, mask_size + 6, -mask_size + 6, mask_size + 6), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + /*shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = + new VoxelsOnCartesianGrid(IndexRange3D(k,k, + //-mask_size+k,mask_size+k, + -mask_size+6,mask_size+6, + -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); */ + CPUTimer timer; + timer.start(); + + // SM 23/05/2002 mask now 3D + // const int min_k = in_density_cast->get_min_z(); //max(in_density_cast->get_min_z(),k-mask_size); + // const int max_k = in_density_cast->get_max_z(); // min(in_density_cast->get_max_z(),k+mask_size); + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + // the mask size is in 2D only + // SM mask now 3D + // for (int k_in =min_k;k_in<=max_k;k_in++) + for (int j_in = min_j; j_in <= max_j; j_in++) + for (int i_in = min_i; i_in <= max_i; i_in++) { + (*in_density_cast_tmp)[k][j_in - j + 6][i_in - i + 6] = (*in_density_cast)[k][j_in][i_in]; + //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; + } + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast_tmp->get_min_z(), + in_density_cast_tmp->get_max_z(), in_density_cast_tmp->get_min_y(), in_density_cast_tmp->get_max_y(), + in_density_cast_tmp->get_min_x(), in_density_cast_tmp->get_max_x(), *in_density_cast_tmp); + + find_inverse_and_bck_densels( + *kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, k, k, + //(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2,ceil((vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z())/2), + // 0,0,0,0, + 6, 6, 6, 6, *proj_matrix_ptr, false, threshold, false); // true); + //(*kappa0_ptr_bck)[k][j][i] = + //(*kappa0_ptr_bck)[(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2][6][6]; + (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; + + timer.stop(); + // cerr << "kappa0 time "<< timer.value() << endl; + } else { + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), + in_density_cast->get_max_z(), min_j, max_j, min_i, max_i, + // j-2,j+2, + // i-2,i+2, + *in_density_cast); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + vox_image_ptr_kappa1->get_min_z(), vox_image_ptr_kappa1->get_max_z(), j, j, i, i, + *proj_matrix_ptr, false, threshold, true); + } + float sq_kapas; + // float multiply_with_sensitivity; + if (fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && + fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001) { + sq_kapas = ((*kappa0_ptr_bck)[k][j][i] * (*kappa0_ptr_bck)[k][j][i]) / + ((*kappa1_ptr_bck)[k][j][i] * (*kappa1_ptr_bck)[k][j][i]); + + // cerr << " kappa0 " << (*kappa0_ptr_bck)[k][j][i] << endl; + // cerr << " kappa1 " << (*kappa1_ptr_bck)[k][j][i] << endl; + + /* multiply_with_sensitivity = + (*sensitivity_image)[ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2][6][6]; if + ((*sensitivity_image)[k][j][i] >0.0000001 || (*sensitivity_image)[k][j][i] <-0.0000001) + { + multiply_with_sensitivity /= (*sensitivity_image)[k][j][i]; + } + else + { + multiply_with_sensitivity /= 0.000001F; + } + + sq_kapas *= multiply_with_sensitivity; */ +# else + float sq_kapas = 1.0F; +# endif + (*kappa_coefficients)[k][j][i] = sq_kapas; + // sq_kapas = 2; + + // cerr << " now printing sq_kappas value:" << " " << sq_kapas << endl; + int k_index; + k_index = round(((float)sq_kapas - k_min) / k_interval); + if (k_index < 1) { + k_index = 1; + } + + if (k_index > num_elements_in_interval) { + k_index = num_elements_in_interval; + } + + if (filter_lookup[k_index] == NULL) { + Array<2, float> new_coeffs; + info(boost::format("computing new filter for sq_kappas %1% at index %2%") % sq_kapas % k_index); + construct_scaled_filter_coefficients_2D(new_coeffs, filter_coefficients, sq_kapas); + filter_lookup[k_index] = new ArrayFilter2DUsingConvolution(new_coeffs); + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + // new ArrayFilter3DUsingConvolution(new_coeffs); + } else { + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + } - all_filter_coefficients[k][j][i] = - new ArrayFilter2DUsingConvolution(); - - } - - } + } else { + + all_filter_coefficients[k][j][i] = new ArrayFilter2DUsingConvolution(); + } + } - - //write_basic_interfile("kappa_coefficients_2D_SENS",*kappa_coefficients); - delete kappa_coefficients ; + // write_basic_interfile("kappa_coefficients_2D_SENS",*kappa_coefficients); + delete kappa_coefficients; - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - delete all_segments_for_kappa0[segment_num]; + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + delete all_segments_for_kappa0[segment_num]; } - - - } - - template -void -ModifiedInverseAveragingImageFilterAll::precalculate_filter_coefficients_separable(VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const -{ - - VectorWithOffset < shared_ptr > > filter_lookup; +void +ModifiedInverseAveragingImageFilterAll::precalculate_filter_coefficients_separable( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const { + + VectorWithOffset>> filter_lookup; const int num_elements_in_interval = 500; - filter_lookup.grow(1,num_elements_in_interval); - const int k_min =1; - const float k_interval = 0.01F; //0.01F; - - - shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); - VoxelsOnCartesianGrid* in_density_cast = - dynamic_cast< VoxelsOnCartesianGrid* >(in_density); - - - VoxelsOnCartesianGrid * vox_image_ptr_1 = - new VoxelsOnCartesianGrid (IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - + filter_lookup.grow(1, num_elements_in_interval); + const int k_min = 1; + const float k_interval = 0.01F; // 0.01F; + + shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); + VoxelsOnCartesianGrid* in_density_cast = dynamic_cast*>(in_density); + + VoxelsOnCartesianGrid* vox_image_ptr_1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + int start_segment_num = proj_data_ptr->get_min_segment_num(); int end_segment_num = proj_data_ptr->get_max_segment_num(); - - VectorWithOffset *> all_segments(start_segment_num, end_segment_num); - VectorWithOffset *> all_segments_for_kappa0(start_segment_num, end_segment_num); - VectorWithOffset *> all_attenuation_segments(start_segment_num, end_segment_num); - - + + VectorWithOffset*> all_segments(start_segment_num, end_segment_num); + VectorWithOffset*> all_segments_for_kappa0(start_segment_num, end_segment_num); + VectorWithOffset*> all_attenuation_segments(start_segment_num, end_segment_num); + // first initialise to false bool do_attenuation = false; - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { all_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); all_segments_for_kappa0[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - - if (attenuation_proj_data_filename!="1") - { + + if (attenuation_proj_data_filename != "1") { do_attenuation = true; - all_attenuation_segments[segment_num] = - new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); - } - else - { + all_attenuation_segments[segment_num] = + new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); + } else { do_attenuation = false; - all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); (*all_attenuation_segments[segment_num]).fill(1); } - } - - vox_image_ptr_1->set_origin(Coordinate3D(0,0,0)); - - shared_ptr > image_sptr = vox_image_ptr_1; - - shared_ptr proj_matrix_ptr = - new ProjMatrixByDenselUsingRayTracing; - - proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), - image_sptr); + + vox_image_ptr_1->set_origin(Coordinate3D(0, 0, 0)); + + shared_ptr> image_sptr = vox_image_ptr_1; + + shared_ptr proj_matrix_ptr = new ProjMatrixByDenselUsingRayTracing; + + proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), image_sptr); info(proj_matrix_ptr->parameter_info()); - - fwd_densels_all(all_segments,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - in_density_cast->get_min_y(), in_density_cast->get_max_y(), - in_density_cast->get_min_x(), in_density_cast->get_max_x(), - *in_density); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa0 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa1 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * kappa_coefficients = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - - shared_ptr > kappa0_ptr_bck = vox_image_ptr_kappa0; - shared_ptr > kappa1_ptr_bck = vox_image_ptr_kappa1; - + + fwd_densels_all(all_segments, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), in_density_cast->get_max_z(), + in_density_cast->get_min_y(), in_density_cast->get_max_y(), in_density_cast->get_min_x(), + in_density_cast->get_max_x(), *in_density); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa0 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* kappa_coefficients = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + shared_ptr> kappa0_ptr_bck = vox_image_ptr_kappa0; + shared_ptr> kappa1_ptr_bck = vox_image_ptr_kappa1; + // WARNING - find a way of finding max in the sinogram // TODO - include other segments as well - float max_in_viewgram =0.F; - - for (int segment_num = start_segment_num; segment_num<= end_segment_num; segment_num++) - { - SegmentByView segment_by_view = - proj_data_ptr->get_segment_by_view(segment_num); + float max_in_viewgram = 0.F; + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; segment_num++) { + SegmentByView segment_by_view = proj_data_ptr->get_segment_by_view(segment_num); const float current_max_in_viewgram = segment_by_view.find_max(); - if ( current_max_in_viewgram >= max_in_viewgram) - max_in_viewgram = current_max_in_viewgram ; + if (current_max_in_viewgram >= max_in_viewgram) + max_in_viewgram = current_max_in_viewgram; else continue; } - const float threshold = 0.0001F*max_in_viewgram; - + const float threshold = 0.0001F * max_in_viewgram; + info(boost::format(" THRESHOLD IS %1%") % threshold); - - find_inverse_and_bck_densels(*kappa1_ptr_bck,all_segments, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - vox_image_ptr_kappa1->get_min_y(),vox_image_ptr_kappa1->get_max_y(), - vox_image_ptr_kappa1->get_min_x(),vox_image_ptr_kappa1->get_max_x(), - *proj_matrix_ptr, do_attenuation,threshold, false); //true); - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + + find_inverse_and_bck_densels(*kappa1_ptr_bck, all_segments, all_attenuation_segments, vox_image_ptr_kappa1->get_min_z(), + vox_image_ptr_kappa1->get_max_z(), vox_image_ptr_kappa1->get_min_y(), + vox_image_ptr_kappa1->get_max_y(), vox_image_ptr_kappa1->get_min_x(), + vox_image_ptr_kappa1->get_max_x(), *proj_matrix_ptr, do_attenuation, threshold, false); // true); + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { delete all_segments[segment_num]; delete all_attenuation_segments[segment_num]; - } - + } + info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); - - for (int k=in_density_cast->get_min_z();k<=in_density_cast->get_max_z();k++) - for (int j =in_density_cast->get_min_y();j<=in_density_cast->get_max_y();j++) - for (int i =in_density_cast->get_min_x();i<=in_density_cast->get_max_x();i++) - { - - // WARNING - only works for segment zero at the moment - // do the calculation of kappa0 here - kappa0_ptr_bck->fill(0); - for (int segment_num = start_segment_num; - segment_num <= end_segment_num; ++segment_num) - { - (*all_segments_for_kappa0[segment_num]).fill(0); - } - if (true) //attenuation_proj_data_filename !="1") - { -#if 1 - shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid - (IndexRange3D(k,k, - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - - - // SM 23/05/2002 mask now 3D - const int min_k = in_density_cast->get_min_z(); //max(in_density_cast->get_min_z(),k-mask_size); - const int max_k = in_density_cast->get_max_z(); // min(in_density_cast->get_max_z(),k+mask_size); - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - // the mask size is in 2D only - // SM mask now 3D - //for (int k_in =min_k;k_in<=max_k;k_in++) - for (int j_in =min_j;j_in<=max_j;j_in++) - for (int i_in =min_i;i_in<=max_i;i_in++) - { - (*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; - //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; - } - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast_tmp->get_min_z(), in_density_cast_tmp->get_max_z(), - in_density_cast_tmp->get_min_y(),in_density_cast_tmp->get_max_y(), - in_density_cast_tmp->get_min_x(),in_density_cast_tmp->get_max_x(), - *in_density_cast_tmp); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - k,k, - //(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2,ceil((vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z())/2), - //0,0,0,0, - 6,6,6,6, - *proj_matrix_ptr,false,threshold, false) ;//true); - //(*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2][6][6]; - (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; - - } - else - { - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - min_j,max_j, - min_i,max_i, - *in_density_cast); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - j,j,i,i, - *proj_matrix_ptr,false,threshold, true); - - } - float sq_kapas; - if ( fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && - fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001 ) - { - // cerr << "kapa0" << (*kappa0_ptr_bck)[k][j][i] << endl; - //cerr << "kapa1" << (*kappa1_ptr_bck)[k][j][i] << endl; - - sq_kapas =((*kappa0_ptr_bck)[k][j][i]*(*kappa0_ptr_bck)[k][j][i])/((*kappa1_ptr_bck)[k][j][i]*(*kappa1_ptr_bck)[k][j][i]); - -#else - float sq_kapas = 10.0F; -#endif - (*kappa_coefficients)[k][j][i] = sq_kapas; - - int k_index ; - k_index = round(((float)sq_kapas- k_min)/k_interval); - if (k_index < 1) - {k_index = 1;} - - if ( k_index > num_elements_in_interval) - { k_index = num_elements_in_interval;} - - - if ( filter_lookup[k_index]==NULL ) - { - // Array <1,float> new_coeffs; + + for (int k = in_density_cast->get_min_z(); k <= in_density_cast->get_max_z(); k++) + for (int j = in_density_cast->get_min_y(); j <= in_density_cast->get_max_y(); j++) + for (int i = in_density_cast->get_min_x(); i <= in_density_cast->get_max_x(); i++) { + + // WARNING - only works for segment zero at the moment + // do the calculation of kappa0 here + kappa0_ptr_bck->fill(0); + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + (*all_segments_for_kappa0[segment_num]).fill(0); + } + if (true) // attenuation_proj_data_filename !="1") + { +# if 1 + shared_ptr> in_density_cast_tmp = + new VoxelsOnCartesianGrid(IndexRange3D(k, k, -mask_size + 6, mask_size + 6, -mask_size + 6, mask_size + 6), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + // SM 23/05/2002 mask now 3D + const int min_k = in_density_cast->get_min_z(); // max(in_density_cast->get_min_z(),k-mask_size); + const int max_k = in_density_cast->get_max_z(); // min(in_density_cast->get_max_z(),k+mask_size); + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + // the mask size is in 2D only + // SM mask now 3D + // for (int k_in =min_k;k_in<=max_k;k_in++) + for (int j_in = min_j; j_in <= max_j; j_in++) + for (int i_in = min_i; i_in <= max_i; i_in++) { + (*in_density_cast_tmp)[k][j_in - j + 6][i_in - i + 6] = (*in_density_cast)[k][j_in][i_in]; + //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; + } + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast_tmp->get_min_z(), + in_density_cast_tmp->get_max_z(), in_density_cast_tmp->get_min_y(), in_density_cast_tmp->get_max_y(), + in_density_cast_tmp->get_min_x(), in_density_cast_tmp->get_max_x(), *in_density_cast_tmp); + + find_inverse_and_bck_densels( + *kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, k, k, + //(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2,ceil((vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z())/2), + // 0,0,0,0, + 6, 6, 6, 6, *proj_matrix_ptr, false, threshold, false); // true); + //(*kappa0_ptr_bck)[k][j][i] = + //(*kappa0_ptr_bck)[(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2][6][6]; + (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; + + } else { + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), + in_density_cast->get_max_z(), min_j, max_j, min_i, max_i, *in_density_cast); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + vox_image_ptr_kappa1->get_min_z(), vox_image_ptr_kappa1->get_max_z(), j, j, i, i, + *proj_matrix_ptr, false, threshold, true); + } + float sq_kapas; + if (fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && + fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001) { + // cerr << "kapa0" << (*kappa0_ptr_bck)[k][j][i] << endl; + // cerr << "kapa1" << (*kappa1_ptr_bck)[k][j][i] << endl; + + sq_kapas = ((*kappa0_ptr_bck)[k][j][i] * (*kappa0_ptr_bck)[k][j][i]) / + ((*kappa1_ptr_bck)[k][j][i] * (*kappa1_ptr_bck)[k][j][i]); + +# else + float sq_kapas = 10.0F; +# endif + (*kappa_coefficients)[k][j][i] = sq_kapas; + + int k_index; + k_index = round(((float)sq_kapas - k_min) / k_interval); + if (k_index < 1) { + k_index = 1; + } + + if (k_index > num_elements_in_interval) { + k_index = num_elements_in_interval; + } + + if (filter_lookup[k_index] == NULL) { + // Array <1,float> new_coeffs; info(boost::format("computing new filter for sq_kappas %1% at index %2%") % sq_kapas % k_index); - // construct_scaled_filter_coefficients_1D(new_coeffs, filter_coefficients,sq_kapas); - filter_lookup[k_index] = - new ModifiedInverseAverigingArrayFilter <3, float>(filter_coefficients,sq_kapas); - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - //new ArrayFilter3DUsingConvolution(new_coeffs); - - } - else - { - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - - } - - } - else - { + // construct_scaled_filter_coefficients_1D(new_coeffs, filter_coefficients,sq_kapas); + filter_lookup[k_index] = new ModifiedInverseAverigingArrayFilter<3, float>(filter_coefficients, sq_kapas); + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + // new ArrayFilter3DUsingConvolution(new_coeffs); + } else { + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + } - all_filter_coefficients[k][j][i] = - new ModifiedInverseAverigingArrayFilter <3, float>(); //ArrayFilter2DUsingConvolution(); - - } - - } + } else { - - delete kappa_coefficients ; + all_filter_coefficients[k][j][i] = + new ModifiedInverseAverigingArrayFilter<3, float>(); // ArrayFilter2DUsingConvolution(); + } + } - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - delete all_segments_for_kappa0[segment_num]; + delete kappa_coefficients; + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + delete all_segments_for_kappa0[segment_num]; } - - - } - // densel stuff - > apply -#if 1 +# if 1 template void -ModifiedInverseAveragingImageFilterAll:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, const DiscretisedDensity<3,elemT>& in_density) const -{ - //the first time virtual_apply is called for this object, counter is set to 0 - static int count=0; +ModifiedInverseAveragingImageFilterAll::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { + // the first time virtual_apply is called for this object, counter is set to 0 + static int count = 0; // every time it's called, counter is incremented count++; info(boost::format(" checking the counter %1%") % count); - - const VoxelsOnCartesianGrid& in_density_cast_0 = - dynamic_cast< const VoxelsOnCartesianGrid& >(in_density); - - // the first set is defined for 2d separable case and the second for 3d case -- - // depending weather it is 2d or 3d corresponding coefficints are used. - static VectorWithOffset < VectorWithOffset < VectorWithOffset > > > > all_filter_coefficients; - static VectorWithOffset < VectorWithOffset < VectorWithOffset > > > > all_filter_coefficients_nonseparable_2D; - static VectorWithOffset < VectorWithOffset < VectorWithOffset > > > > all_filter_coefficients_separable; - - if (initial_image_filename!="1") - { - if (count ==1) - { - if ( num_dim == 3) - { - all_filter_coefficients.grow(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z()); - for (int k = in_density_cast_0.get_min_z(); k<=in_density_cast_0.get_max_z();k++) - { - all_filter_coefficients[k].grow(in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y()); - for (int j = in_density_cast_0.get_min_y(); j<=in_density_cast_0.get_max_y();j++) - { - (all_filter_coefficients[k])[j].grow(in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()); - } - } - precalculate_filter_coefficients(all_filter_coefficients,initial_image); - } - else if ( num_dim ==2) - { - all_filter_coefficients_nonseparable_2D.grow(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z()); - for (int k = in_density_cast_0.get_min_z(); k<=in_density_cast_0.get_max_z();k++) - { - all_filter_coefficients_nonseparable_2D[k].grow(in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y()); - for (int j = in_density_cast_0.get_min_y(); j<=in_density_cast_0.get_max_y();j++) - { - (all_filter_coefficients_nonseparable_2D[k])[j].grow(in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()); - } - } - if ( precomputed_coefficients_filename!="1") - { - VoxelsOnCartesianGrid* precomputed_coefficients_image_cast = - dynamic_cast< VoxelsOnCartesianGrid* >(precomputed_coefficients_image); - info(" In here nonseparable"); - for ( int k = precomputed_coefficients_image_cast->get_min_z(); k<=precomputed_coefficients_image_cast->get_max_z();k++) - for ( int j = precomputed_coefficients_image_cast->get_min_y(); j<=precomputed_coefficients_image_cast->get_max_y();j++) - for ( int i = precomputed_coefficients_image_cast->get_min_x(); i<=precomputed_coefficients_image_cast->get_max_x();i++) - { - Array <2,float> new_coeffs; - //cerr << (*precomputed_coefficients_image)[k][j][i] << " " << endl; - if((*precomputed_coefficients_image)[k][j][i] >0.00001 ) - { - construct_scaled_filter_coefficients_2D(new_coeffs,filter_coefficients,1/(*precomputed_coefficients_image)[k][j][i]); - all_filter_coefficients_nonseparable_2D[k][j][i] = - new ArrayFilter2DUsingConvolution(new_coeffs); - } - else - { - all_filter_coefficients_nonseparable_2D[k][j][i] = - new ArrayFilter2DUsingConvolution(); - - } - - - } - } - else - precalculate_filter_coefficients_2D(all_filter_coefficients_nonseparable_2D,initial_image); - - } - else - { - all_filter_coefficients_separable.grow(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z()); - for (int k = in_density_cast_0.get_min_z(); k<=in_density_cast_0.get_max_z();k++) - { - all_filter_coefficients_separable[k].grow(in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y()); - for (int j = in_density_cast_0.get_min_y(); j<=in_density_cast_0.get_max_y();j++) - { - (all_filter_coefficients_separable[k])[j].grow(in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()); - } - } - if ( precomputed_coefficients_filename!="1") - { - info(" In here"); - for ( int k = 0; k<=1;k++) - for ( int j = -26; j<=26;j++) - for ( int i = -26; i<=26;i++) - { - // cerr << k <<" "<< j <<" "<< i <<" "<< endl; - info(boost::format("%1% ") % (*precomputed_coefficients_image)[k][j][i]); - if((*precomputed_coefficients_image)[k][j][i] >0.00001 ) - { - all_filter_coefficients_separable[k][j][i]= - new ModifiedInverseAverigingArrayFilter <3, float>(filter_coefficients,1/(*precomputed_coefficients_image)[k][j][i]); - } - else - { - all_filter_coefficients_separable[k][j][i]= - new ModifiedInverseAverigingArrayFilter <3, float>(); - - } - //construct_scaled_filter_coefficients_2D(new_coeffs,filter_coefficients,(*precomputed_coefficients_image)[k][j][i]); - //all_filter_coefficients_separable[k][j][i] = new ArrayFilter2DUsingConvolution(new_coeffs); - } + const VoxelsOnCartesianGrid& in_density_cast_0 = dynamic_cast&>(in_density); + + // the first set is defined for 2d separable case and the second for 3d case -- + // depending weather it is 2d or 3d corresponding coefficints are used. + static VectorWithOffset>>>> + all_filter_coefficients; + static VectorWithOffset>>>> + all_filter_coefficients_nonseparable_2D; + static VectorWithOffset>>>> + all_filter_coefficients_separable; + + if (initial_image_filename != "1") { + if (count == 1) { + if (num_dim == 3) { + all_filter_coefficients.grow(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z()); + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) { + all_filter_coefficients[k].grow(in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y()); + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) { + (all_filter_coefficients[k])[j].grow(in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()); + } + } + precalculate_filter_coefficients(all_filter_coefficients, initial_image); + } else if (num_dim == 2) { + all_filter_coefficients_nonseparable_2D.grow(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z()); + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) { + all_filter_coefficients_nonseparable_2D[k].grow(in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y()); + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) { + (all_filter_coefficients_nonseparable_2D[k])[j].grow(in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()); + } + } + + if (precomputed_coefficients_filename != "1") { + VoxelsOnCartesianGrid* precomputed_coefficients_image_cast = + dynamic_cast*>(precomputed_coefficients_image); + info(" In here nonseparable"); + for (int k = precomputed_coefficients_image_cast->get_min_z(); k <= precomputed_coefficients_image_cast->get_max_z(); + k++) + for (int j = precomputed_coefficients_image_cast->get_min_y(); j <= precomputed_coefficients_image_cast->get_max_y(); + j++) + for (int i = precomputed_coefficients_image_cast->get_min_x(); + i <= precomputed_coefficients_image_cast->get_max_x(); i++) { + Array<2, float> new_coeffs; + // cerr << (*precomputed_coefficients_image)[k][j][i] << " " << endl; + if ((*precomputed_coefficients_image)[k][j][i] > 0.00001) { + construct_scaled_filter_coefficients_2D(new_coeffs, filter_coefficients, + 1 / (*precomputed_coefficients_image)[k][j][i]); + all_filter_coefficients_nonseparable_2D[k][j][i] = new ArrayFilter2DUsingConvolution(new_coeffs); + } else { + all_filter_coefficients_nonseparable_2D[k][j][i] = new ArrayFilter2DUsingConvolution(); + } + } + } else + precalculate_filter_coefficients_2D(all_filter_coefficients_nonseparable_2D, initial_image); + + } else { + all_filter_coefficients_separable.grow(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z()); + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) { + all_filter_coefficients_separable[k].grow(in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y()); + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) { + (all_filter_coefficients_separable[k])[j].grow(in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()); + } + } + if (precomputed_coefficients_filename != "1") { + info(" In here"); + for (int k = 0; k <= 1; k++) + for (int j = -26; j <= 26; j++) + for (int i = -26; i <= 26; i++) { + // cerr << k <<" "<< j <<" "<< i <<" "<< endl; + info(boost::format("%1% ") % (*precomputed_coefficients_image)[k][j][i]); + if ((*precomputed_coefficients_image)[k][j][i] > 0.00001) { + all_filter_coefficients_separable[k][j][i] = new ModifiedInverseAverigingArrayFilter<3, float>( + filter_coefficients, 1 / (*precomputed_coefficients_image)[k][j][i]); + } else { + all_filter_coefficients_separable[k][j][i] = new ModifiedInverseAverigingArrayFilter<3, float>(); + } + // construct_scaled_filter_coefficients_2D(new_coeffs,filter_coefficients,(*precomputed_coefficients_image)[k][j][i]); + // all_filter_coefficients_separable[k][j][i] = new ArrayFilter2DUsingConvolution(new_coeffs); + } + + } else + + precalculate_filter_coefficients_separable(all_filter_coefficients_separable, initial_image); + } + } + // else + // { + // } + } else // for initial image + { + if (count == 1) { + all_filter_coefficients_separable.grow(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z()); - } - else + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) { + all_filter_coefficients_separable[k].grow(in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y()); + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) { + (all_filter_coefficients_separable[k])[j].grow(in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()); - precalculate_filter_coefficients_separable(all_filter_coefficients_separable,initial_image); - + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + all_filter_coefficients_separable[k][j][i] = new ModifiedInverseAverigingArrayFilter<3, elemT>; + } + } } } - // else - // { - // } - } - else // for initial image - { - if (count==1) - { - all_filter_coefficients_separable.grow(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z()); - - for (int k = in_density_cast_0.get_min_z(); k<=in_density_cast_0.get_max_z();k++) - { - all_filter_coefficients_separable[k].grow(in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y()); - for (int j = in_density_cast_0.get_min_y(); j<=in_density_cast_0.get_max_y();j++) - { - (all_filter_coefficients_separable[k])[j].grow(in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()); - - for (int i = in_density_cast_0.get_min_x(); i<=in_density_cast_0.get_max_x();i++) - { - - all_filter_coefficients_separable[k][j][i] = - new ModifiedInverseAverigingArrayFilter<3,elemT>; - - } - } - } - + + if ((count % 20) == 0 /*|| count == 1 */) { + + shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); + + int limit_segments = 0; + new_data_info_ptr->reduce_segment_range(-limit_segments, limit_segments); + + VoxelsOnCartesianGrid* vox_image_ptr_1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), in_density_cast_0.get_min_y(), + in_density_cast_0.get_max_y(), in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()), + in_density.get_origin(), in_density_cast_0.get_voxel_size()); + + int start_segment_num = proj_data_ptr->get_min_segment_num(); + int end_segment_num = proj_data_ptr->get_max_segment_num(); + + VectorWithOffset*> all_segments(start_segment_num, end_segment_num); + VectorWithOffset*> all_attenuation_segments(start_segment_num, end_segment_num); + + // first initialise to false + bool do_attenuation = false; + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + all_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + + if (attenuation_proj_data_filename != "1") { + do_attenuation = true; + all_attenuation_segments[segment_num] = + new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); + } else { + do_attenuation = false; + all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + (*all_attenuation_segments[segment_num]).fill(1); + } } - - - if ( (count % 20) ==0 /*|| count == 1 */) - { - - shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); - - int limit_segments= 0; - new_data_info_ptr->reduce_segment_range(-limit_segments, limit_segments); - - - VoxelsOnCartesianGrid * vox_image_ptr_1 = - new VoxelsOnCartesianGrid (IndexRange3D(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z(), - in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y(), - in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()), - in_density.get_origin(),in_density_cast_0.get_voxel_size()); - - int start_segment_num = proj_data_ptr->get_min_segment_num(); - int end_segment_num = proj_data_ptr->get_max_segment_num(); - - VectorWithOffset *> all_segments(start_segment_num, end_segment_num); - VectorWithOffset *> all_attenuation_segments(start_segment_num, end_segment_num); - - // first initialise to false - bool do_attenuation = false; - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - all_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - - if (attenuation_proj_data_filename !="1") - { - do_attenuation = true; - all_attenuation_segments[segment_num] = - new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); - } - else - { - do_attenuation = false; - all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - (*all_attenuation_segments[segment_num]).fill(1); - } - - } - - VectorWithOffset *> all_segments_for_kappa0(start_segment_num, end_segment_num); - - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - all_segments_for_kappa0[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - - - vox_image_ptr_1->set_origin(Coordinate3D(0,0,0)); - - shared_ptr > image_sptr = vox_image_ptr_1; - - shared_ptr proj_matrix_ptr = - new ProjMatrixByDenselUsingRayTracing; - - proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), - image_sptr); - info(proj_matrix_ptr->parameter_info()); - - fwd_densels_all(all_segments,proj_matrix_ptr, proj_data_ptr, - in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), - in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y(), - in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x(), - in_density_cast_0); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa0 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z(), - in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y(), - in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()), - in_density.get_origin(),in_density_cast_0.get_voxel_size()); - - - shared_ptr > kappa0_ptr_bck = vox_image_ptr_kappa0; - - VoxelsOnCartesianGrid * vox_image_ptr_kappa1 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z(), - in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y(), - in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()), - in_density.get_origin(),in_density_cast_0.get_voxel_size()); - - shared_ptr > kappa1_ptr_bck = vox_image_ptr_kappa1; - - // WARNING - find a way of finding max in the sinogram - // TODO - include other segments as well - float max_in_viewgram =0.F; - - for (int segment_num = 0; segment_num<= 0; - segment_num++) - { - SegmentByView segment_by_view = - proj_data_ptr->get_segment_by_view(segment_num); - const float current_max_in_viewgram = segment_by_view.find_max(); - if ( current_max_in_viewgram >= max_in_viewgram) - max_in_viewgram = current_max_in_viewgram ; - else - continue; - } - const float threshold = 0.0001F*max_in_viewgram; - - info(boost::format(" THRESHOLD IS %1%") % threshold); - - find_inverse_and_bck_densels(*kappa1_ptr_bck,all_segments, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - vox_image_ptr_kappa1->get_min_y(),vox_image_ptr_kappa1->get_max_y(), - vox_image_ptr_kappa1->get_min_x(),vox_image_ptr_kappa1->get_max_x(), - *proj_matrix_ptr, do_attenuation,threshold,true); - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - delete all_segments[segment_num]; - } - - info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); - - char* file1 = "kappa1"; - //cerr <<" - Saving " << file1 << endl; - write_basic_interfile(file1, *kappa1_ptr_bck); - - - const string filename ="kapa0_div_kapa1_pf"; - shared_ptr output = - new fstream (filename.c_str(), ios::trunc|ios::in|ios::out|ios::binary); - - const string filename1 ="values_of_kapa0_and_kapa1_pf"; - shared_ptr output1 = - new fstream (filename1.c_str(), ios::trunc|ios::in|ios::out|ios::binary); - - - if (!*output1) - error("Error opening output file %s\n",filename1.c_str()); - - if (!*output) - error("Error opening output file %s\n",filename.c_str()); - - - *output << "kapa0_div_kapa1" << endl; - *output << endl; - *output << endl; - *output << "Plane number " << endl; - - int size = filter_coefficients.get_length(); - - //todo - remove - const string testing_kappas_att="kappa_att"; - shared_ptr output_att = - new fstream (testing_kappas_att.c_str(),ios::trunc|ios::out|ios::binary); - - const string testing_kappas_noatt="kappa_noatt"; - shared_ptr output_noatt = - new fstream (testing_kappas_noatt.c_str(),ios::trunc|ios::out|ios::binary); - - if (!*output_att) - error("Error opening output file %s\n",testing_kappas_att.c_str()); - - if (!*output_noatt) - error("Error opening output file %s\n",testing_kappas_noatt.c_str()); - - - for (int k=in_density_cast_0.get_min_z();k<=in_density_cast_0.get_max_z();k++) - for (int j =in_density_cast_0.get_min_y();j<=in_density_cast_0.get_max_y();j++) - for (int i =in_density_cast_0.get_min_x();i<=in_density_cast_0.get_max_x();i++) - { - - // WARNING - only works for segment zero at the moment - // do the calculation of kappa0 here - kappa0_ptr_bck->fill(0); - (*all_segments_for_kappa0[all_segments.get_min_index()]).fill(0); - if (true) //attenuation_proj_data_filename !="1") - { - - shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid - (IndexRange3D(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z(), - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density.get_origin(),in_density_cast_0.get_voxel_size()); - - const int min_j = max(in_density_cast_0.get_min_y(),j-mask_size); - const int max_j = min(in_density_cast_0.get_max_y(),j+mask_size); - const int min_i = max(in_density_cast_0.get_min_x(),i-mask_size); - const int max_i = min(in_density_cast_0.get_max_x(),i+mask_size); - - // the mask size is in 2D only - - for (int j_in =min_j;j_in<=max_j;j_in++) - for (int i_in =min_i;i_in<=max_i;i_in++) - - (*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = in_density_cast_0[k][j_in][i_in]; - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), - in_density_cast_tmp->get_min_y(),in_density_cast_tmp->get_max_y(), - in_density_cast_tmp->get_min_x(),in_density_cast_tmp->get_max_x(), - *in_density_cast_tmp); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - //0,0,0,0, - 6,6,6,6, - *proj_matrix_ptr,false,threshold, true); - (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; - - - *output_att << k <<" " << j << " "<< i << " "<< (*kappa0_ptr_bck)[k][j][i] << endl; - - - } - else - { - const int min_j = max(in_density_cast_0.get_min_y(),j-mask_size); - const int max_j = min(in_density_cast_0.get_max_y(),j+mask_size); - const int min_i = max(in_density_cast_0.get_min_x(),i-mask_size); - const int max_i = min(in_density_cast_0.get_max_x(),i+mask_size); - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), - min_j,max_j, - min_i,max_i, - //j-2,j+2, - //i-2,i+2, - in_density_cast_0); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - j,j,i,i, - *proj_matrix_ptr,false,threshold, true); - - - *output_noatt << k <<" " << j << " "<< i << " "<< (*kappa0_ptr_bck)[k][j][i] << endl; - - } - // cerr << "min and max in image - kappa0 " <find_min() - // << ", " << kappa0_ptr_bck->find_max() << endl; - - char* file0 = "kappa0"; - write_basic_interfile(file0, *kappa0_ptr_bck); - - float sq_kapas; - - if ( fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && - fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001 ) - { - sq_kapas =((*kappa0_ptr_bck)[k][j][i]*(*kappa0_ptr_bck)[k][j][i])/((*kappa1_ptr_bck)[k][j][i]*(*kappa1_ptr_bck)[k][j][i]); - - *output1 << " Values of kapa0 and kapa1" << endl; - *output1<< "for k "<< k; - *output1 <<":"; - *output1 << j; - *output1 <<","; - *output1 <(filter_coefficients,sq_kapas); - // construct_scaled_filter_coefficients(new_coeffs, filter_coefficients,sq_kapas); - // all_filter_coefficients[k][j][i] = - // new ArrayFilter3DUsingConvolution(new_coeffs); - all_filter_coefficients_separable[k][j][i] = - new ModifiedInverseAverigingArrayFilter<3,elemT>(inverse_filter); - - } - else - { - sq_kapas = 0; - inverse_filter = - ModifiedInverseAverigingArrayFilter<3,elemT>(); - all_filter_coefficients_separable[k][j][i] = - new ModifiedInverseAverigingArrayFilter<3,elemT>(inverse_filter); - - } - - } - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - delete all_segments_for_kappa0[segment_num]; - delete all_attenuation_segments[segment_num]; - } - } - } - if ( initial_image_filename =="1" || num_dim ==1) - { - for (int k=in_density_cast_0.get_min_z();k<=in_density_cast_0.get_max_z();k++) - for (int j =in_density_cast_0.get_min_y();j<=in_density_cast_0.get_max_y();j++) - for (int i =in_density_cast_0.get_min_x();i<=in_density_cast_0.get_max_x();i++) - { - Array<3,elemT> tmp_out(IndexRange3D(k,k,j,j,i,i)); - - (*all_filter_coefficients_separable[k][j][i])(tmp_out,in_density); - out_density[k][j][i] = tmp_out[k][j][i]; - - } - } - else - { - - for (int k=in_density_cast_0.get_min_z();k<=in_density_cast_0.get_max_z();k++) - for (int j =in_density_cast_0.get_min_y();j<=in_density_cast_0.get_max_y();j++) - for (int i =in_density_cast_0.get_min_x();i<=in_density_cast_0.get_max_x();i++) - { - Array<3,elemT> tmp_out(IndexRange3D(k,k,j,j,i,i)); - if ( num_dim == 3) - { - (*all_filter_coefficients[k][j][i])(tmp_out,in_density); - out_density[k][j][i] = tmp_out[k][j][i]; - - } - else - { - Array<2,elemT> single_pixel(IndexRange2D(j,j,i,i)); - if ( k==in_density_cast_0.get_min_z() && j==in_density_cast_0.get_min_y() - && i==in_density_cast_0.get_min_x() && count == 300) - { - info(boost::format(" IN the LOOP %1% %2% %3% ") % k % j % i); - for (int k=in_density_cast_0.get_min_z();k<=in_density_cast_0.get_max_z();k++) - for (int j =in_density_cast_0.get_min_y();j<=in_density_cast_0.get_max_y();j++) - for (int i =in_density_cast_0.get_min_x();i<=in_density_cast_0.get_max_x();i++) - { - Array <2,float> new_coeffs; - if(in_density_cast_0[k][j][i] >0.00001 ) - { - VoxelsOnCartesianGrid * newly_computed_coeff = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z(), - in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y(), - in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()), - in_density.get_origin(),in_density_cast_0.get_voxel_size()); - - VoxelsOnCartesianGrid * normalised_bck_image_cast = - dynamic_cast< VoxelsOnCartesianGrid * > (normalised_bck_image); - VoxelsOnCartesianGrid * sensitivity_image_cast = - dynamic_cast< VoxelsOnCartesianGrid * > (sensitivity_image); - - - precompute_filter_coefficients_for_second_apporach(*newly_computed_coeff, - in_density_cast_0, - *sensitivity_image_cast, - *normalised_bck_image_cast); - construct_scaled_filter_coefficients_2D(new_coeffs,filter_coefficients,1/(*newly_computed_coeff)[k][j][i]); - all_filter_coefficients_nonseparable_2D[k][j][i] = - new ArrayFilter2DUsingConvolution(new_coeffs); - delete newly_computed_coeff; - } - - } - } - (*all_filter_coefficients_nonseparable_2D[k][j][i])(single_pixel,in_density[k]); - out_density[k][j][i] = single_pixel[j][i]; - } - - - } - - } - } + VectorWithOffset*> all_segments_for_kappa0(start_segment_num, end_segment_num); -#endif + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) + all_segments_for_kappa0[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + + vox_image_ptr_1->set_origin(Coordinate3D(0, 0, 0)); + + shared_ptr> image_sptr = vox_image_ptr_1; + + shared_ptr proj_matrix_ptr = new ProjMatrixByDenselUsingRayTracing; + + proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), image_sptr); + info(proj_matrix_ptr->parameter_info()); + + fwd_densels_all(all_segments, proj_matrix_ptr, proj_data_ptr, in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), + in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y(), in_density_cast_0.get_min_x(), + in_density_cast_0.get_max_x(), in_density_cast_0); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa0 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), in_density_cast_0.get_min_y(), + in_density_cast_0.get_max_y(), in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()), + in_density.get_origin(), in_density_cast_0.get_voxel_size()); + + shared_ptr> kappa0_ptr_bck = vox_image_ptr_kappa0; + + VoxelsOnCartesianGrid* vox_image_ptr_kappa1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), in_density_cast_0.get_min_y(), + in_density_cast_0.get_max_y(), in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()), + in_density.get_origin(), in_density_cast_0.get_voxel_size()); + + shared_ptr> kappa1_ptr_bck = vox_image_ptr_kappa1; + + // WARNING - find a way of finding max in the sinogram + // TODO - include other segments as well + float max_in_viewgram = 0.F; + + for (int segment_num = 0; segment_num <= 0; segment_num++) { + SegmentByView segment_by_view = proj_data_ptr->get_segment_by_view(segment_num); + const float current_max_in_viewgram = segment_by_view.find_max(); + if (current_max_in_viewgram >= max_in_viewgram) + max_in_viewgram = current_max_in_viewgram; + else + continue; + } + const float threshold = 0.0001F * max_in_viewgram; + + info(boost::format(" THRESHOLD IS %1%") % threshold); + find_inverse_and_bck_densels(*kappa1_ptr_bck, all_segments, all_attenuation_segments, vox_image_ptr_kappa1->get_min_z(), + vox_image_ptr_kappa1->get_max_z(), vox_image_ptr_kappa1->get_min_y(), + vox_image_ptr_kappa1->get_max_y(), vox_image_ptr_kappa1->get_min_x(), + vox_image_ptr_kappa1->get_max_x(), *proj_matrix_ptr, do_attenuation, threshold, true); + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + delete all_segments[segment_num]; + } + + info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); + + char* file1 = "kappa1"; + // cerr <<" - Saving " << file1 << endl; + write_basic_interfile(file1, *kappa1_ptr_bck); + + const string filename = "kapa0_div_kapa1_pf"; + shared_ptr output = new fstream(filename.c_str(), ios::trunc | ios::in | ios::out | ios::binary); + + const string filename1 = "values_of_kapa0_and_kapa1_pf"; + shared_ptr output1 = new fstream(filename1.c_str(), ios::trunc | ios::in | ios::out | ios::binary); + + if (!*output1) + error("Error opening output file %s\n", filename1.c_str()); + + if (!*output) + error("Error opening output file %s\n", filename.c_str()); + + *output << "kapa0_div_kapa1" << endl; + *output << endl; + *output << endl; + *output << "Plane number " << endl; + + int size = filter_coefficients.get_length(); + + // todo - remove + const string testing_kappas_att = "kappa_att"; + shared_ptr output_att = new fstream(testing_kappas_att.c_str(), ios::trunc | ios::out | ios::binary); + + const string testing_kappas_noatt = "kappa_noatt"; + shared_ptr output_noatt = new fstream(testing_kappas_noatt.c_str(), ios::trunc | ios::out | ios::binary); + + if (!*output_att) + error("Error opening output file %s\n", testing_kappas_att.c_str()); + + if (!*output_noatt) + error("Error opening output file %s\n", testing_kappas_noatt.c_str()); + + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + + // WARNING - only works for segment zero at the moment + // do the calculation of kappa0 here + kappa0_ptr_bck->fill(0); + (*all_segments_for_kappa0[all_segments.get_min_index()]).fill(0); + if (true) // attenuation_proj_data_filename !="1") + { + + shared_ptr> in_density_cast_tmp = + new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), + -mask_size + 6, mask_size + 6, -mask_size + 6, mask_size + 6), + in_density.get_origin(), in_density_cast_0.get_voxel_size()); + + const int min_j = max(in_density_cast_0.get_min_y(), j - mask_size); + const int max_j = min(in_density_cast_0.get_max_y(), j + mask_size); + const int min_i = max(in_density_cast_0.get_min_x(), i - mask_size); + const int max_i = min(in_density_cast_0.get_max_x(), i + mask_size); + + // the mask size is in 2D only + + for (int j_in = min_j; j_in <= max_j; j_in++) + for (int i_in = min_i; i_in <= max_i; i_in++) + + (*in_density_cast_tmp)[k][j_in - j + 6][i_in - i + 6] = in_density_cast_0[k][j_in][i_in]; + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast_0.get_min_z(), + in_density_cast_0.get_max_z(), in_density_cast_tmp->get_min_y(), in_density_cast_tmp->get_max_y(), + in_density_cast_tmp->get_min_x(), in_density_cast_tmp->get_max_x(), *in_density_cast_tmp); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + vox_image_ptr_kappa1->get_min_z(), vox_image_ptr_kappa1->get_max_z(), + // 0,0,0,0, + 6, 6, 6, 6, *proj_matrix_ptr, false, threshold, true); + (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; + + *output_att << k << " " << j << " " << i << " " << (*kappa0_ptr_bck)[k][j][i] << endl; + + } else { + const int min_j = max(in_density_cast_0.get_min_y(), j - mask_size); + const int max_j = min(in_density_cast_0.get_max_y(), j + mask_size); + const int min_i = max(in_density_cast_0.get_min_x(), i - mask_size); + const int max_i = min(in_density_cast_0.get_max_x(), i + mask_size); + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast_0.get_min_z(), + in_density_cast_0.get_max_z(), min_j, max_j, min_i, max_i, + // j-2,j+2, + // i-2,i+2, + in_density_cast_0); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + vox_image_ptr_kappa1->get_min_z(), vox_image_ptr_kappa1->get_max_z(), j, j, i, i, + *proj_matrix_ptr, false, threshold, true); + + *output_noatt << k << " " << j << " " << i << " " << (*kappa0_ptr_bck)[k][j][i] << endl; + } + // cerr << "min and max in image - kappa0 " <find_min() + // << ", " << kappa0_ptr_bck->find_max() << endl; + + char* file0 = "kappa0"; + write_basic_interfile(file0, *kappa0_ptr_bck); + + float sq_kapas; + + if (fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && + fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001) { + sq_kapas = ((*kappa0_ptr_bck)[k][j][i] * (*kappa0_ptr_bck)[k][j][i]) / + ((*kappa1_ptr_bck)[k][j][i] * (*kappa1_ptr_bck)[k][j][i]); + + *output1 << " Values of kapa0 and kapa1" << endl; + *output1 << "for k " << k; + *output1 << ":"; + *output1 << j; + *output1 << ","; + *output1 << i; + *output1 << " "; + //*output1 <<(*image_sptr_0)[k][j][i]; + *output1 << (*kappa0_ptr_bck)[k][j][i]; + *output1 << " "; + *output1 << (*kappa1_ptr_bck)[k][j][i]; + *output1 << endl; + *output << "for k " << k; + *output << ":"; + *output << j; + *output << ","; + *output << i; + *output << " "; + *output << sq_kapas; + *output << endl; + + // sq_kapas = 10; + inverse_filter = ModifiedInverseAverigingArrayFilter<3, elemT>(filter_coefficients, sq_kapas); + // construct_scaled_filter_coefficients(new_coeffs, filter_coefficients,sq_kapas); + // all_filter_coefficients[k][j][i] = + // new ArrayFilter3DUsingConvolution(new_coeffs); + all_filter_coefficients_separable[k][j][i] = new ModifiedInverseAverigingArrayFilter<3, elemT>(inverse_filter); + + } else { + sq_kapas = 0; + inverse_filter = ModifiedInverseAverigingArrayFilter<3, elemT>(); + all_filter_coefficients_separable[k][j][i] = new ModifiedInverseAverigingArrayFilter<3, elemT>(inverse_filter); + } + } + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + delete all_segments_for_kappa0[segment_num]; + delete all_attenuation_segments[segment_num]; + } + } + } + if (initial_image_filename == "1" || num_dim == 1) { + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + Array<3, elemT> tmp_out(IndexRange3D(k, k, j, j, i, i)); + + (*all_filter_coefficients_separable[k][j][i])(tmp_out, in_density); + out_density[k][j][i] = tmp_out[k][j][i]; + } + } else { + + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + Array<3, elemT> tmp_out(IndexRange3D(k, k, j, j, i, i)); + if (num_dim == 3) { + (*all_filter_coefficients[k][j][i])(tmp_out, in_density); + out_density[k][j][i] = tmp_out[k][j][i]; + + } else { + Array<2, elemT> single_pixel(IndexRange2D(j, j, i, i)); + if (k == in_density_cast_0.get_min_z() && j == in_density_cast_0.get_min_y() && i == in_density_cast_0.get_min_x() && + count == 300) { + info(boost::format(" IN the LOOP %1% %2% %3% ") % k % j % i); + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + Array<2, float> new_coeffs; + if (in_density_cast_0[k][j][i] > 0.00001) { + VoxelsOnCartesianGrid* newly_computed_coeff = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), + in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y(), + in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()), + in_density.get_origin(), in_density_cast_0.get_voxel_size()); + + VoxelsOnCartesianGrid* normalised_bck_image_cast = + dynamic_cast*>(normalised_bck_image); + VoxelsOnCartesianGrid* sensitivity_image_cast = + dynamic_cast*>(sensitivity_image); + + precompute_filter_coefficients_for_second_apporach(*newly_computed_coeff, in_density_cast_0, + *sensitivity_image_cast, *normalised_bck_image_cast); + construct_scaled_filter_coefficients_2D(new_coeffs, filter_coefficients, + 1 / (*newly_computed_coeff)[k][j][i]); + all_filter_coefficients_nonseparable_2D[k][j][i] = new ArrayFilter2DUsingConvolution(new_coeffs); + delete newly_computed_coeff; + } + } + } + (*all_filter_coefficients_nonseparable_2D[k][j][i])(single_pixel, in_density[k]); + out_density[k][j][i] = single_pixel[j][i]; + } + } + } +} + +# endif template void -ModifiedInverseAveragingImageFilterAll:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const -{ - DiscretisedDensity<3,elemT>* tmp_density = - density.clone(); +ModifiedInverseAveragingImageFilterAll::virtual_apply(DiscretisedDensity<3, elemT>& density) const { + DiscretisedDensity<3, elemT>* tmp_density = density.clone(); virtual_apply(density, *tmp_density); delete tmp_density; } - template void -ModifiedInverseAveragingImageFilterAll::set_defaults() -{ +ModifiedInverseAveragingImageFilterAll::set_defaults() { filter_coefficients.fill(0); - proj_data_filename ="1"; + proj_data_filename = "1"; proj_data_ptr = NULL; - attenuation_proj_data_filename ="1"; - initial_image_filename ="1"; - sensitivity_image_filename ='1'; + attenuation_proj_data_filename = "1"; + initial_image_filename = "1"; + sensitivity_image_filename = '1'; sensitivity_image = NULL; - precomputed_coefficients_filename ='1'; - normalised_bck_filename ='1'; - normalised_bck_image =NULL; - precomputed_coefficients_image =NULL; + precomputed_coefficients_filename = '1'; + normalised_bck_filename = '1'; + normalised_bck_image = NULL; + precomputed_coefficients_image = NULL; attenuation_proj_data_ptr = NULL; mask_size = 0; num_dim = 1; - } template void -ModifiedInverseAveragingImageFilterAll:: initialise_keymap() -{ +ModifiedInverseAveragingImageFilterAll::initialise_keymap() { parser.add_start_key("Modified Inverse Image Filter All Parameters"); parser.add_key("filter_coefficients", &filter_coefficients_for_parsing); parser.add_key("proj_data_filename", &proj_data_filename); @@ -2409,36 +2020,29 @@ ModifiedInverseAveragingImageFilterAll:: initialise_keymap() parser.add_key("initial_image_filename", &initial_image_filename); parser.add_key("sensitivity_image_filename", &sensitivity_image_filename); parser.add_key("mask_size", &mask_size); - parser.add_key("num_dim", & num_dim); - parser.add_key ("precomputed_coefficients_filename", &precomputed_coefficients_filename); - parser.add_key ("normalised_bck_filename", &normalised_bck_filename); + parser.add_key("num_dim", &num_dim); + parser.add_key("precomputed_coefficients_filename", &precomputed_coefficients_filename); + parser.add_key("normalised_bck_filename", &normalised_bck_filename); parser.add_stop_key("END Modified Inverse Image Filter All Parameters"); } template -bool -ModifiedInverseAveragingImageFilterAll:: -post_processing() -{ +bool +ModifiedInverseAveragingImageFilterAll::post_processing() { const unsigned int size = filter_coefficients_for_parsing.size(); - const int min_index = -(size/2); + const int min_index = -(size / 2); filter_coefficients.grow(min_index, min_index + size - 1); - for (int i = min_index; i<= filter_coefficients.get_max_index(); ++i) - filter_coefficients[i] = - static_cast(filter_coefficients_for_parsing[i-min_index]); + for (int i = min_index; i <= filter_coefficients.get_max_index(); ++i) + filter_coefficients[i] = static_cast(filter_coefficients_for_parsing[i - min_index]); return false; } - -const char * const -ModifiedInverseAveragingImageFilterAll::registered_name = - "Modified Inverse Image Filter All"; - +const char* const ModifiedInverseAveragingImageFilterAll::registered_name = "Modified Inverse Image Filter All"; # ifdef _MSC_VER -// prevent warning message on reinstantiation, +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) +# pragma warning(disable : 4660) # endif // Register this class in the ImageProcessor registry @@ -2447,14 +2051,6 @@ ModifiedInverseAveragingImageFilterAll::registered_name = template ModifiedInverseAveragingImageFilterAll; - - END_NAMESPACE_STIR #endif - - - - - - diff --git a/src/experimental/buildblock/ModifiedInverseAverigingArrayFilter.cxx b/src/experimental/buildblock/ModifiedInverseAverigingArrayFilter.cxx index 6038504eed..b1a9abfcfd 100644 --- a/src/experimental/buildblock/ModifiedInverseAverigingArrayFilter.cxx +++ b/src/experimental/buildblock/ModifiedInverseAverigingArrayFilter.cxx @@ -20,290 +20,238 @@ using std::cerr; using std::endl; #endif - - START_NAMESPACE_STIR - - -void -FFT_routines::find_fft_filter(Array<1,float>& filter_coefficients) -{ - four1(filter_coefficients,filter_coefficients.get_length()/2,1); -} - void -FFT_routines::find_fft_unity(Array<1,float>& unity) -{ - four1(filter_coefficients,filter_coefficients.get_length()/2,1); +FFT_routines::find_fft_filter(Array<1, float>& filter_coefficients) { + four1(filter_coefficients, filter_coefficients.get_length() / 2, 1); } +void +FFT_routines::find_fft_unity(Array<1, float>& unity) { + four1(filter_coefficients, filter_coefficients.get_length() / 2, 1); +} template -ModifiedInverseAverigingArrayFilter:: -ModifiedInverseAverigingArrayFilter() - : filter_coefficients(0), kapa0_over_kapa1(0) -{ +ModifiedInverseAverigingArrayFilter::ModifiedInverseAverigingArrayFilter() + : filter_coefficients(0), kapa0_over_kapa1(0) { /*filter_coefficients.grow(0,2); - filter_coefficients[0] =0; - filter_coefficients[1] =1; + filter_coefficients[0] =0; + filter_coefficients[1] =1; filter_coefficients[2] =0; */ - + // because there is no filtering at all, we might as well ignore 3rd direction - for (int i=2;i<=num_dimensions;i++) - { - - all_1d_array_filters[i-1] = - new ArrayFilter1DUsingConvolution();//filter_coefficients); - } + for (int i = 2; i <= num_dimensions; i++) { + all_1d_array_filters[i - 1] = new ArrayFilter1DUsingConvolution(); // filter_coefficients); + } } - //// LOOK UP TABLE VERSION #if 1 template -ModifiedInverseAverigingArrayFilter:: -ModifiedInverseAverigingArrayFilter(const VectorWithOffset& kernel_1d, - const float kapa0_over_kapa1_v) - : -filter_coefficients(kernel_1d), -kapa0_over_kapa1(kapa0_over_kapa1_v) -{ - - // STUFF FOR THE FFT SIZE +ModifiedInverseAverigingArrayFilter::ModifiedInverseAverigingArrayFilter( + const VectorWithOffset& kernel_1d, const float kapa0_over_kapa1_v) + : filter_coefficients(kernel_1d), kapa0_over_kapa1(kapa0_over_kapa1_v) { + + // STUFF FOR THE FFT SIZE /****************** *********************************************************************/ - + const int length_of_size_array = 16; - const float kapa0_over_kapa1_interval_size=10.F; + const float kapa0_over_kapa1_interval_size = 10.F; static VectorWithOffset size_for_kapa0_over_kapa1; - if (size_for_kapa0_over_kapa1.get_length()==0) - { - size_for_kapa0_over_kapa1.grow(0,length_of_size_array-1); + if (size_for_kapa0_over_kapa1.get_length() == 0) { + size_for_kapa0_over_kapa1.grow(0, length_of_size_array - 1); size_for_kapa0_over_kapa1.fill(64); } - - - float sq_kapas = kapa0_over_kapa1; + + float sq_kapas = kapa0_over_kapa1; VectorWithOffset new_filter_coefficients; /******************************************************************************************/ - - if ( sq_kapas > 10000) - { - new_filter_coefficients.grow(0,0); - } - else if (sq_kapas!=1.F) - { - const int kapa0_over_kapa1_interval = - min(static_cast(floor(kapa0_over_kapa1/kapa0_over_kapa1_interval_size)), - length_of_size_array-1); - - while(true) - { + + if (sq_kapas > 10000) { + new_filter_coefficients.grow(0, 0); + } else if (sq_kapas != 1.F) { + const int kapa0_over_kapa1_interval = + min(static_cast(floor(kapa0_over_kapa1 / kapa0_over_kapa1_interval_size)), length_of_size_array - 1); + + while (true) { const int size = size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]; - int filter_length = static_cast(floor(kernel_1d.get_length()/2)); - - //cerr << "Now doing size " << size << std::endl; - + int filter_length = static_cast(floor(kernel_1d.get_length() / 2)); + + // cerr << "Now doing size " << size << std::endl; + float inverse_sq_kapas; - if (fabs((double)sq_kapas ) >0.000000000001) - inverse_sq_kapas = 1/sq_kapas; - else - inverse_sq_kapas = 0; - - static Array<1,float> fft_filter_1D_array_64(1,64); - static Array<1,float> fft_filter_1D_array_128(1,128); - static Array<1,float> fft_filter_1D_array_256(1,256); - static Array<1,float> fft_filter_1D_array_512(1,512); - static Array<1,float> fft_filter_1D_array_1024(1,1024); - static Array<1,float> fft_filter_1D_array_2048(1,2048); - static Array<1,float> fft_filter_1D_array_4096(1,4096); - static Array<1,float> fft_filter_1D_array_8192(1,8192); - - Array<1,float>* fft_filter_1D_array_ptr = 0; - switch (size) - { + if (fabs((double)sq_kapas) > 0.000000000001) + inverse_sq_kapas = 1 / sq_kapas; + else + inverse_sq_kapas = 0; + + static Array<1, float> fft_filter_1D_array_64(1, 64); + static Array<1, float> fft_filter_1D_array_128(1, 128); + static Array<1, float> fft_filter_1D_array_256(1, 256); + static Array<1, float> fft_filter_1D_array_512(1, 512); + static Array<1, float> fft_filter_1D_array_1024(1, 1024); + static Array<1, float> fft_filter_1D_array_2048(1, 2048); + static Array<1, float> fft_filter_1D_array_4096(1, 4096); + static Array<1, float> fft_filter_1D_array_8192(1, 8192); + + Array<1, float>* fft_filter_1D_array_ptr = 0; + switch (size) { case 64: - fft_filter_1D_array_ptr = &fft_filter_1D_array_64; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_64; + break; case 128: - fft_filter_1D_array_ptr = &fft_filter_1D_array_128; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_128; + break; case 256: - fft_filter_1D_array_ptr = &fft_filter_1D_array_256; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_256; + break; case 512: - fft_filter_1D_array_ptr = &fft_filter_1D_array_512; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_512; + break; case 1024: - fft_filter_1D_array_ptr = &fft_filter_1D_array_1024; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_1024; + break; case 2048: - fft_filter_1D_array_ptr = &fft_filter_1D_array_2048; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_2048; + break; case 4096: - fft_filter_1D_array_ptr = &fft_filter_1D_array_4096; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_4096; + break; case 8192: - fft_filter_1D_array_ptr = &fft_filter_1D_array_8192; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_8192; + break; default: - error("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n"); - break; + error("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n"); + break; } - Array<1,float>& fft_filter_1D_array = *fft_filter_1D_array_ptr; - - - if ( fft_filter_1D_array[1] == 0.F) - { - // we have to compute it - // FIRST PADD 1D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC - // ( TAKE IMAGINARY PART INTO ACCOUNT YET) - /**********************************************************************************/ - - Array<1,float> filter_coefficients_padded_1D_array(1,size); - filter_coefficients_padded_1D_array[1] = kernel_1d[0]; - for ( int i = 1;i<=filter_length;i++) - { - filter_coefficients_padded_1D_array[2*i+1] = filter_coefficients[i]; - filter_coefficients_padded_1D_array[size-(2*(i-1)+1)] = filter_coefficients[i]; - - } + Array<1, float>& fft_filter_1D_array = *fft_filter_1D_array_ptr; - /*************************************************************************************/ - //Array<1,float> filter_coefficients_padded(1,size); //1,size_y,1,size_x)); - //filter_coefficients_padded /= filter_coefficients_padded.sum(); - fft_filter_1D_array = filter_coefficients_padded_1D_array; - - four1(fft_filter_1D_array,fft_filter_1D_array.get_length()/2,1); - - fft_filter_1D_array /= sqrt(static_cast(size/2)); + if (fft_filter_1D_array[1] == 0.F) { + // we have to compute it + // FIRST PADD 1D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC + // ( TAKE IMAGINARY PART INTO ACCOUNT YET) + /**********************************************************************************/ + + Array<1, float> filter_coefficients_padded_1D_array(1, size); + filter_coefficients_padded_1D_array[1] = kernel_1d[0]; + for (int i = 1; i <= filter_length; i++) { + filter_coefficients_padded_1D_array[2 * i + 1] = filter_coefficients[i]; + filter_coefficients_padded_1D_array[size - (2 * (i - 1) + 1)] = filter_coefficients[i]; + } + + /*************************************************************************************/ + // Array<1,float> filter_coefficients_padded(1,size); //1,size_y,1,size_x)); + // filter_coefficients_padded /= filter_coefficients_padded.sum(); + fft_filter_1D_array = filter_coefficients_padded_1D_array; + + four1(fft_filter_1D_array, fft_filter_1D_array.get_length() / 2, 1); + + fft_filter_1D_array /= sqrt(static_cast(size / 2)); } - // WARNING -- this only works for the FFT where the convention is that the final result - // obtained from the FFT is divided with sqrt(N*N*N) - // initialise to 0 to prevent from warnings - //fourn(fft_1_1D_array, array_lengths, 3,1); - float fft_1_1D_array = 1/sqrt(static_cast(size/2)); + // WARNING -- this only works for the FFT where the convention is that the final result + // obtained from the FFT is divided with sqrt(N*N*N) + // initialise to 0 to prevent from warnings + // fourn(fft_1_1D_array, array_lengths, 3,1); + float fft_1_1D_array = 1 / sqrt(static_cast(size / 2)); - //cerr << " THE unity stuff " << endl; - //cerr << fft_1_1D_array << " "; + // cerr << " THE unity stuff " << endl; + // cerr << fft_1_1D_array << " "; - Array<1,float> real_div_1D_array(1,size); - - { - - Array<1,float> fft_filter_num_1D_array(1,fft_filter_1D_array.get_length()); //= fft_filter_1D_array; - fft_filter_num_1D_array = fft_filter_1D_array* fft_1_1D_array; - - // TODO we make a copy for the denominator here, which isn't necessary - Array<1,float> fft_filter_denom_1D_array(1,fft_filter_1D_array.get_length()); //= fft_filter_1D_array; - fft_filter_denom_1D_array =fft_filter_1D_array*(sq_kapas-1); - // add fft of 1 (but that's a real constant) - for ( int i = fft_filter_1D_array.get_min_index(); i<=fft_filter_1D_array.get_max_index(); i+=2) - { - fft_filter_denom_1D_array[i] += fft_1_1D_array; - } - fft_filter_denom_1D_array /= sq_kapas; - - divide_complex_arrays(fft_filter_num_1D_array,fft_filter_denom_1D_array); - four1(fft_filter_num_1D_array,fft_filter_num_1D_array.get_length()/2,-1); + Array<1, float> real_div_1D_array(1, size); - - - // make it consistent with mathemematica -- the output of the - fft_filter_num_1D_array /= sqrt(static_cast(size/2)); - + { - // take the real part only - /*********************************************************************************/ - { - - for (int i=0;i<=(size)/2-1;i++) - real_div_1D_array[i+1] = fft_filter_num_1D_array[2*i+1]; - - /*********************************************************************************/ - // cerr << " num " << endl; - //for ( int i = real_div_1D_array.get_min_index(); i<=real_div_1D_array.get_max_index();i++) - //cerr << real_div_1D_array[i] << " "; - - } - } - - int kernel_length=0; - - // to prevent form aliasing limit the new range for the coefficients to - // filter_coefficients_padded.get_length()/4 - - - // do the x -direction first -- fix y and z to the min and look for the max index in x - for (int i=real_div_1D_array.get_min_index(); i<=real_div_1D_array.get_max_index()/4;i++) - { - if (fabs((double)real_div_1D_array[i]) - <= real_div_1D_array[real_div_1D_array.get_min_index()]*1/1000000) break; - else (kernel_length)++; - } - - - if (kernel_length == size/4) - { - warning("ModifiedInverseAverigingArrayFilter3D: kernel_length_x reached maximum length %d. " - "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" - "Increasing length of FFT array to resolve this problem\n", - kernel_length, real_div_1D_array[real_div_1D_array.get_min_index()], real_div_1D_array[kernel_length], - kapa0_over_kapa1); - size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]*=2; - for (int i=kapa0_over_kapa1_interval+1; i fft_filter_num_1D_array(1, fft_filter_1D_array.get_length()); //= fft_filter_1D_array; + fft_filter_num_1D_array = fft_filter_1D_array * fft_1_1D_array; - - - break; // out of while(true) - } - //} - } // this bracket is for the while loop - } - else //sq_kappas == 1 - { - new_filter_coefficients = kernel_1d; - } - - - - float sum_new_coefficients =0.F; - for (int i=new_filter_coefficients.get_min_index();i<=new_filter_coefficients.get_max_index();i++) - sum_new_coefficients += new_filter_coefficients[i]; - - for (int i=new_filter_coefficients.get_min_index();i<=new_filter_coefficients.get_max_index();i++) - new_filter_coefficients[i] /=sum_new_coefficients; - - // to do only filtering in 2d -> - // z-direction is for 0 index - - for (int i=2;i<=num_dimensions;i++) - { - all_1d_array_filters[i-1] = - new ArrayFilter1DUsingConvolution(new_filter_coefficients); - } - + // TODO we make a copy for the denominator here, which isn't necessary + Array<1, float> fft_filter_denom_1D_array(1, fft_filter_1D_array.get_length()); //= fft_filter_1D_array; + fft_filter_denom_1D_array = fft_filter_1D_array * (sq_kapas - 1); + // add fft of 1 (but that's a real constant) + for (int i = fft_filter_1D_array.get_min_index(); i <= fft_filter_1D_array.get_max_index(); i += 2) { + fft_filter_denom_1D_array[i] += fft_1_1D_array; + } + fft_filter_denom_1D_array /= sq_kapas; + + divide_complex_arrays(fft_filter_num_1D_array, fft_filter_denom_1D_array); + four1(fft_filter_num_1D_array, fft_filter_num_1D_array.get_length() / 2, -1); + + // make it consistent with mathemematica -- the output of the + fft_filter_num_1D_array /= sqrt(static_cast(size / 2)); + + // take the real part only + /*********************************************************************************/ + { + + for (int i = 0; i <= (size) / 2 - 1; i++) + real_div_1D_array[i + 1] = fft_filter_num_1D_array[2 * i + 1]; + + /*********************************************************************************/ + // cerr << " num " << endl; + // for ( int i = real_div_1D_array.get_min_index(); i<=real_div_1D_array.get_max_index();i++) + // cerr << real_div_1D_array[i] << " "; + } } - -#endif - + int kernel_length = 0; + + // to prevent form aliasing limit the new range for the coefficients to + // filter_coefficients_padded.get_length()/4 + + // do the x -direction first -- fix y and z to the min and look for the max index in x + for (int i = real_div_1D_array.get_min_index(); i <= real_div_1D_array.get_max_index() / 4; i++) { + if (fabs((double)real_div_1D_array[i]) <= real_div_1D_array[real_div_1D_array.get_min_index()] * 1 / 1000000) + break; + else + (kernel_length)++; + } + + if (kernel_length == size / 4) { + warning("ModifiedInverseAverigingArrayFilter3D: kernel_length_x reached maximum length %d. " + "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" + "Increasing length of FFT array to resolve this problem\n", + kernel_length, real_div_1D_array[real_div_1D_array.get_min_index()], real_div_1D_array[kernel_length], + kapa0_over_kapa1); + size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval] *= 2; + for (int i = kapa0_over_kapa1_interval + 1; i < size_for_kapa0_over_kapa1.get_length(); ++i) + size_for_kapa0_over_kapa1[i] = max(size_for_kapa0_over_kapa1[i], size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]); + } else { + new_filter_coefficients.grow(-(kernel_length - 1), kernel_length - 1); + new_filter_coefficients[0] = real_div_1D_array[1]; + + for (int i = 1; i <= kernel_length - 1; i++) { + new_filter_coefficients[i] = real_div_1D_array[i + 1]; + new_filter_coefficients[-i] = real_div_1D_array[i + 1]; + } + + break; // out of while(true) + } + //} + } // this bracket is for the while loop + } else // sq_kappas == 1 + { + new_filter_coefficients = kernel_1d; + } + + float sum_new_coefficients = 0.F; + for (int i = new_filter_coefficients.get_min_index(); i <= new_filter_coefficients.get_max_index(); i++) + sum_new_coefficients += new_filter_coefficients[i]; + + for (int i = new_filter_coefficients.get_min_index(); i <= new_filter_coefficients.get_max_index(); i++) + new_filter_coefficients[i] /= sum_new_coefficients; + + // to do only filtering in 2d -> + // z-direction is for 0 index + + for (int i = 2; i <= num_dimensions; i++) { + all_1d_array_filters[i - 1] = new ArrayFilter1DUsingConvolution(new_filter_coefficients); + } +} + +#endif // SM new 17/09/2001 #if 0 @@ -326,7 +274,7 @@ ModifiedInverseAverigingArrayFilter(const VectorWithOffset& filter_coeffi *coeff_output<< endl; //cerr < size_for_kapa0_over_kapa1; @@ -519,9 +467,8 @@ ModifiedInverseAverigingArrayFilter(const VectorWithOffset& filter_coeffi { new_filter_coefficients = filter_coefficients; } - - -#endif + +# endif //cerr << " COEFF PRINT NOW" << endl; //for (int i=new_filter_coefficients.get_min_index();i<=new_filter_coefficients.get_max_index();i++) //cerr << new_filter_coefficients[i] << " "; @@ -569,38 +516,13 @@ ModifiedInverseAverigingArrayFilter(const VectorWithOffset& filter_coeffi } - #endif - template ModifiedInverseAverigingArrayFilter<3, float>; END_NAMESPACE_STIR - - - - - - - - - - - - - - - - - - - - - - - -//old +// old #if 0 @@ -688,7 +610,6 @@ ModifiedInverseAverigingArrayFilter(VectorWithOffset & kapa0_over_kapa1) } #endif - #if 0 template ModifiedInverseAverigingArrayFilter:: diff --git a/src/experimental/buildblock/ModifiedInverseAverigingImageFilter.cxx b/src/experimental/buildblock/ModifiedInverseAverigingImageFilter.cxx index 098b079c40..7e880bb08f 100644 --- a/src/experimental/buildblock/ModifiedInverseAverigingImageFilter.cxx +++ b/src/experimental/buildblock/ModifiedInverseAverigingImageFilter.cxx @@ -4,10 +4,10 @@ \file \ingroup buildblock \brief Implementations for class ModifiedInverseAverigingImageFilter - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2011, IRSL @@ -32,7 +32,6 @@ #include "stir_experimental/ArrayFilter2DUsingConvolution.h" #include "stir/info.h" - #include "stir/CPUTimer.h" #include "stir_experimental/fwd_and_bck_manipulation_for_SAF.h" @@ -57,216 +56,185 @@ using std::endl; START_NAMESPACE_STIR +static void construct_scaled_filter_coefficients(Array<3, float>& new_filter_coefficients_3D_array, + const VectorWithOffset& kernel_1d, const bool z_direction_trivial, + const float kapa0_over_kapa1); -static void -construct_scaled_filter_coefficients(Array<3,float> &new_filter_coefficients_3D_array, - const VectorWithOffset& kernel_1d, - const bool z_direction_trivial, - const float kapa0_over_kapa1); - - //// IMPLEMENTATION ///// +//// IMPLEMENTATION ///// /**********************************************************************************************/ - - static void -construct_scaled_filter_coefficients(Array<3,float> &new_filter_coefficients_3D_array, - const VectorWithOffset& kernel_1d, - const bool z_direction_trivial, - const float kapa0_over_kapa1) - +construct_scaled_filter_coefficients(Array<3, float>& new_filter_coefficients_3D_array, const VectorWithOffset& kernel_1d, + const bool z_direction_trivial, const float kapa0_over_kapa1) + { - - // STUFF FOR THE FFT SIZE + + // STUFF FOR THE FFT SIZE /****************** *********************************************************************/ - + const int length_of_size_array = 16; - const float kapa0_over_kapa1_interval_size=10.F; + const float kapa0_over_kapa1_interval_size = 10.F; static VectorWithOffset size_for_kapa0_over_kapa1; - if (size_for_kapa0_over_kapa1.get_length()==0) - { - size_for_kapa0_over_kapa1.grow(0,length_of_size_array-1); + if (size_for_kapa0_over_kapa1.get_length() == 0) { + size_for_kapa0_over_kapa1.grow(0, length_of_size_array - 1); size_for_kapa0_over_kapa1.fill(64); } - - - float sq_kapas = kapa0_over_kapa1; + + float sq_kapas = kapa0_over_kapa1; /******************************************************************************************/ - - if ( sq_kapas > 10000) - { - new_filter_coefficients_3D_array.grow(IndexRange3D(0,0,0,0,0,0)); - } - else if (sq_kapas!=1.F) - { - const int kapa0_over_kapa1_interval = - min(static_cast(floor(kapa0_over_kapa1/kapa0_over_kapa1_interval_size)), - length_of_size_array-1); - while(true) - { + if (sq_kapas > 10000) { + new_filter_coefficients_3D_array.grow(IndexRange3D(0, 0, 0, 0, 0, 0)); + } else if (sq_kapas != 1.F) { + const int kapa0_over_kapa1_interval = + min(static_cast(floor(kapa0_over_kapa1 / kapa0_over_kapa1_interval_size)), length_of_size_array - 1); + + while (true) { const int size = size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]; const int size_z = z_direction_trivial ? 1 : size; - const int size_y = size; + const int size_y = size; const int size_x = size; - int filter_length = static_cast(floor(kernel_1d.get_length()/2)); - + int filter_length = static_cast(floor(kernel_1d.get_length() / 2)); + info(boost::format("Now doing size %1%") % size); - - + float inverse_sq_kapas; - if (fabs((double)sq_kapas ) >0.000000000001) - inverse_sq_kapas = 1/sq_kapas; - else - inverse_sq_kapas = 0; - - // static Array<1,float> fft_filter_1D_array_16(1,2*(size_z==1?1:16)*16*16); - //static Array<1,float> fft_filter_1D_array_32(1,2*(size_z==1?1:32)*32*32); - static Array<1,float> fft_filter_1D_array_64(1,2*(size_z==1?1:64)*64*64); - static Array<1,float> fft_filter_1D_array_128(1,2*(size_z==1?1:128)*128*128); - static Array<1,float> fft_filter_1D_array_256(1,2*(size_z==1?1:256)*256*256); - - Array<1,float>* fft_filter_1D_array_ptr = 0; - switch (size) - { + if (fabs((double)sq_kapas) > 0.000000000001) + inverse_sq_kapas = 1 / sq_kapas; + else + inverse_sq_kapas = 0; + + // static Array<1,float> fft_filter_1D_array_16(1,2*(size_z==1?1:16)*16*16); + // static Array<1,float> fft_filter_1D_array_32(1,2*(size_z==1?1:32)*32*32); + static Array<1, float> fft_filter_1D_array_64(1, 2 * (size_z == 1 ? 1 : 64) * 64 * 64); + static Array<1, float> fft_filter_1D_array_128(1, 2 * (size_z == 1 ? 1 : 128) * 128 * 128); + static Array<1, float> fft_filter_1D_array_256(1, 2 * (size_z == 1 ? 1 : 256) * 256 * 256); + + Array<1, float>* fft_filter_1D_array_ptr = 0; + switch (size) { case 64: - fft_filter_1D_array_ptr = &fft_filter_1D_array_64; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_64; + break; case 128: - fft_filter_1D_array_ptr = &fft_filter_1D_array_128; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_128; + break; case 256: - fft_filter_1D_array_ptr = &fft_filter_1D_array_256; - break; + fft_filter_1D_array_ptr = &fft_filter_1D_array_256; + break; default: - error("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n"); - break; + error("\nModifiedInverseAveragingImageFilter: Cannot do this at the moment -- size is too big'.\n"); + break; } - Array<1,float>& fft_filter_1D_array = *fft_filter_1D_array_ptr; - - Array<1, int> array_lengths(1,3); + Array<1, float>& fft_filter_1D_array = *fft_filter_1D_array_ptr; + + Array<1, int> array_lengths(1, 3); array_lengths[1] = size_z; array_lengths[2] = size_y; array_lengths[3] = size_x; - - if ( fft_filter_1D_array[1] == 0.F) - { - // we have to compute it - // FIRST PADD 1D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC - // ( DO NOT TAKE IMAGINARY PART INTO ACCOUNT YET) - /**********************************************************************************/ - - Array<1,float> filter_coefficients_padded_1D_array(1,size); - - filter_coefficients_padded_1D_array[1] = kernel_1d[0]; - for ( int i = 1;i<=filter_length;i++) - { - filter_coefficients_padded_1D_array[i+1] = kernel_1d[i]; - filter_coefficients_padded_1D_array[size-(i-1)] = kernel_1d[i]; - - } - - /*************************************************************************************/ - - - Array<3,float> filter_coefficients_padded(IndexRange3D(1,size_z,1,size_y,1,size_x)); - - - create_kernel_3d (filter_coefficients_padded, filter_coefficients_padded_1D_array); - - // rescale to DC=1 - filter_coefficients_padded /= filter_coefficients_padded.sum(); - - convert_array_3D_into_1D_array(fft_filter_1D_array,filter_coefficients_padded); - - // TODO remove probably - if (size_z==1) - { - Array<1,int> array_lengths_2d(1,2); - array_lengths_2d[1]=array_lengths[2]; - array_lengths_2d[2]=array_lengths[3]; - fourn(fft_filter_1D_array, array_lengths_2d, 2,1); - } - else - fourn(fft_filter_1D_array, array_lengths, 3,1); - fft_filter_1D_array /= sqrt(static_cast(size_z *size_y*size_x)); - } + + if (fft_filter_1D_array[1] == 0.F) { + // we have to compute it + // FIRST PADD 1D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC + // ( DO NOT TAKE IMAGINARY PART INTO ACCOUNT YET) + /**********************************************************************************/ + + Array<1, float> filter_coefficients_padded_1D_array(1, size); + + filter_coefficients_padded_1D_array[1] = kernel_1d[0]; + for (int i = 1; i <= filter_length; i++) { + filter_coefficients_padded_1D_array[i + 1] = kernel_1d[i]; + filter_coefficients_padded_1D_array[size - (i - 1)] = kernel_1d[i]; + } + + /*************************************************************************************/ + + Array<3, float> filter_coefficients_padded(IndexRange3D(1, size_z, 1, size_y, 1, size_x)); + + create_kernel_3d(filter_coefficients_padded, filter_coefficients_padded_1D_array); + + // rescale to DC=1 + filter_coefficients_padded /= filter_coefficients_padded.sum(); + + convert_array_3D_into_1D_array(fft_filter_1D_array, filter_coefficients_padded); + + // TODO remove probably + if (size_z == 1) { + Array<1, int> array_lengths_2d(1, 2); + array_lengths_2d[1] = array_lengths[2]; + array_lengths_2d[2] = array_lengths[3]; + fourn(fft_filter_1D_array, array_lengths_2d, 2, 1); + } else + fourn(fft_filter_1D_array, array_lengths, 3, 1); + fft_filter_1D_array /= sqrt(static_cast(size_z * size_y * size_x)); + } /* else fft_filter_1D_array[1] != 0 and we have it computed previously */ -/* - cerr << " filter coeff after fft" << endl; - for ( int i = fft_filter_1D_array.get_min_index(); i<= fft_filter_1D_array.get_max_index();i++) - cerr << fft_filter_1D_array[i] << " "; */ + /* + cerr << " filter coeff after fft" << endl; + for ( int i = fft_filter_1D_array.get_min_index(); i<= fft_filter_1D_array.get_max_index();i++) + cerr << fft_filter_1D_array[i] << " "; */ + + Array<3, float> new_filter_coefficients_3D_array_tmp(IndexRange3D(1, size_z, 1, size_y, 1, size_x)); - - Array<3,float> new_filter_coefficients_3D_array_tmp (IndexRange3D(1,size_z,1,size_y,1,size_x)); - // WARNING -- this only works for the FFT where the convention is that the final result - // obtained from the FFT is divided with sqrt(N*N*N) + // obtained from the FFT is divided with sqrt(N*N*N) // initialise to 0 to prevent from warnings - //fourn(fft_1_1D_array, array_lengths, 3,1); - float fft_1_1D_array = 1/sqrt(static_cast(size_z*size_y*size_x)); - - - { - Array<1,float> fft_filter_num_1D_array = fft_filter_1D_array; - fft_filter_num_1D_array *= fft_1_1D_array; - // TODO we make a copy for the denominator here, which isn't necessary - Array<1,float> fft_filter_denom_1D_array = fft_filter_1D_array; - fft_filter_denom_1D_array*= (sq_kapas-1); - // add fft of 1 (but that's a real constant) - for ( int i = fft_filter_1D_array.get_min_index(); i<=fft_filter_1D_array.get_max_index(); i+=2) - { - fft_filter_denom_1D_array[i] += fft_1_1D_array; - } - fft_filter_denom_1D_array /= sq_kapas; + // fourn(fft_1_1D_array, array_lengths, 3,1); + float fft_1_1D_array = 1 / sqrt(static_cast(size_z * size_y * size_x)); + + { + Array<1, float> fft_filter_num_1D_array = fft_filter_1D_array; + fft_filter_num_1D_array *= fft_1_1D_array; + // TODO we make a copy for the denominator here, which isn't necessary + Array<1, float> fft_filter_denom_1D_array = fft_filter_1D_array; + fft_filter_denom_1D_array *= (sq_kapas - 1); + // add fft of 1 (but that's a real constant) + for (int i = fft_filter_1D_array.get_min_index(); i <= fft_filter_1D_array.get_max_index(); i += 2) { + fft_filter_denom_1D_array[i] += fft_1_1D_array; + } + fft_filter_denom_1D_array /= sq_kapas; + + /* cerr << " filter denominator " << endl; + for (int i =1;i<=size_z *size_y*size_x;i++) + { + cerr << fft_filter_denom_1D_array[i] << " "; + } + cerr << endl;*/ + + divide_complex_arrays(fft_filter_num_1D_array, fft_filter_denom_1D_array); + // TODO remove probably + if (size_z == 1) { + Array<1, int> array_lengths_2d(1, 2); + array_lengths_2d[1] = array_lengths[2]; + array_lengths_2d[2] = array_lengths[3]; + fourn(fft_filter_num_1D_array, array_lengths_2d, 2, -1); + } else + fourn(fft_filter_num_1D_array, array_lengths, 3, -1); + + // make it consistent with mathemematica -- the output of the + fft_filter_num_1D_array /= sqrt(static_cast(size_z * size_y * size_x)); -/* cerr << " filter denominator " << endl; - for (int i =1;i<=size_z *size_y*size_x;i++) - { - cerr << fft_filter_denom_1D_array[i] << " "; - } - cerr << endl;*/ - - - divide_complex_arrays(fft_filter_num_1D_array,fft_filter_denom_1D_array); - // TODO remove probably - if (size_z==1) - { - Array<1,int> array_lengths_2d(1,2); - array_lengths_2d[1]=array_lengths[2]; - array_lengths_2d[2]=array_lengths[3]; - fourn(fft_filter_num_1D_array, array_lengths_2d, 2,-1); - } - else - fourn(fft_filter_num_1D_array, array_lengths, 3,-1); - - - // make it consistent with mathemematica -- the output of the - fft_filter_num_1D_array /= sqrt(static_cast(size_z *size_y*size_x)); - #if 0 // cerr << "for kappa_0_over_kappa_1 " << kapa0_over_kapa1 ; cerr << endl; for (int i =1;i<=size_z *size_y*size_x;i++) { cerr << fft_filter_num_1D_array[i] << " "; - } + } #endif - - // take the real part only - /*********************************************************************************/ - { - Array<1,float> real_div_1D_array(1,size_z *size_y*size_x); - - for (int i=0;i<=(size_z *size_y*size_x)-1;i++) - real_div_1D_array[i+1] = fft_filter_num_1D_array[2*i+1]; - - /*********************************************************************************/ - - - convert_array_1D_into_3D_array(new_filter_coefficients_3D_array_tmp,real_div_1D_array); + + // take the real part only + /*********************************************************************************/ + { + Array<1, float> real_div_1D_array(1, size_z * size_y * size_x); + + for (int i = 0; i <= (size_z * size_y * size_x) - 1; i++) + real_div_1D_array[i + 1] = fft_filter_num_1D_array[2 * i + 1]; + + /*********************************************************************************/ + + convert_array_1D_into_3D_array(new_filter_coefficients_3D_array_tmp, real_div_1D_array); #if 0 for (int k = 1;k<= size_z;k++) @@ -277,940 +245,799 @@ construct_scaled_filter_coefficients(Array<3,float> &new_filter_coefficients_3D_ } #endif - } + } } - - int kernel_length_x=0; - int kernel_length_y=0; - int kernel_length_z=0; - - // to prevent form aliasing limit the new range for the coefficients to - // filter_coefficients_padded.get_length()/4 - - - // do the x -direction first -- fix y and z to the min and look for the max index in x - int kx = new_filter_coefficients_3D_array_tmp.get_min_index(); - int jx = new_filter_coefficients_3D_array_tmp[kx].get_min_index(); - for (int i=new_filter_coefficients_3D_array_tmp[kx][jx].get_min_index(); - i<=new_filter_coefficients_3D_array_tmp[kx][jx].get_max_index()/4;i++) - { - if (fabs((double)new_filter_coefficients_3D_array_tmp[kx][jx][i]) - <= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()].get_min_index()]*1/1000000) break; - else (kernel_length_x)++; - } - - /******************************* Y DIRECTION ************************************/ - - - int ky = new_filter_coefficients_3D_array_tmp.get_min_index(); - int iy = new_filter_coefficients_3D_array_tmp[ky][new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index(); - for (int j=new_filter_coefficients_3D_array_tmp[ky].get_min_index();j<=new_filter_coefficients_3D_array_tmp[ky].get_max_index()/4;j++) - { - if (fabs((double)new_filter_coefficients_3D_array_tmp[ky][j][iy]) - //= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) break; - <= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()].get_min_index()]*1/1000000) break; - else (kernel_length_y)++; - } - - /********************************************************************************/ - - /******************************* z DIRECTION ************************************/ - - if (!z_direction_trivial) - { - int jz = new_filter_coefficients_3D_array_tmp.get_min_index(); - int iz = new_filter_coefficients_3D_array_tmp[jz][new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index(); - for (int k=new_filter_coefficients_3D_array_tmp.get_min_index();k<=new_filter_coefficients_3D_array_tmp.get_max_index()/4;k++) - { - if (fabs((double)new_filter_coefficients_3D_array_tmp[k][jz][iz]) - //<= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) break; - <= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()].get_min_index()]*1/1000000) break; - else (kernel_length_z)++; - } - } - else - kernel_length_z = 1; - - /********************************************************************************/ - - if (kernel_length_x == size_x/4) - { - warning("ModifiedInverseAverigingArrayFilter3D: kernel_length_x reached maximum length %d. " - "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" - "Increasing length of FFT array to resolve this problem\n", - kernel_length_x, new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()], new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][kernel_length_x], - kapa0_over_kapa1); - size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]*=2; - for (int i=kapa0_over_kapa1_interval+1; i( + IndexRange3D(z_direction_trivial ? 0 : kernel_1d.get_min_index(), z_direction_trivial ? 0 : kernel_1d.get_max_index(), + kernel_1d.get_min_index(), kernel_1d.get_max_index(), kernel_1d.get_min_index(), kernel_1d.get_max_index())); + create_kernel_3d(new_filter_coefficients_3D_array, kernel_1d); + } - break; // out of while(true) - } - } // this bracket is for the while loop - } - else //sq_kappas == 1 - { - // in the case where sq_kappas=1 --- scaled_filter == original template filter - new_filter_coefficients_3D_array = - Array<3,float>(IndexRange3D(z_direction_trivial? 0 : kernel_1d.get_min_index(), z_direction_trivial? 0 : kernel_1d.get_max_index(), - kernel_1d.get_min_index(), kernel_1d.get_max_index(), - kernel_1d.get_min_index(), kernel_1d.get_max_index())); - - create_kernel_3d (new_filter_coefficients_3D_array, kernel_1d); - } + /*cerr << " Input kernel" << endl; + for ( int i = kernel_1d.get_min_index(); i<=kernel_1d.get_max_index(); i++) + cerr << kernel_1d[i] << " "; - /*cerr << " Input kernel" << endl; - for ( int i = kernel_1d.get_min_index(); i<=kernel_1d.get_max_index(); i++) - cerr << kernel_1d[i] << " "; + for ( int k = 0; k<= new_filter_coefficients_3D_array.get_max_index(); k++) + for ( int j = 0; j<= new_filter_coefficients_3D_array.get_max_index(); j++) + for ( int i = 0; i<= new_filter_coefficients_3D_array.get_max_index(); i++) + { + cerr << new_filter_coefficients_3D_array[k][j][i] << " "; - for ( int k = 0; k<= new_filter_coefficients_3D_array.get_max_index(); k++) - for ( int j = 0; j<= new_filter_coefficients_3D_array.get_max_index(); j++) - for ( int i = 0; i<= new_filter_coefficients_3D_array.get_max_index(); i++) - { - cerr << new_filter_coefficients_3D_array[k][j][i] << " "; - - }*/ - - - - // rescale to DC=1 - new_filter_coefficients_3D_array /= new_filter_coefficients_3D_array.sum(); - /*for (int k = new_filter_coefficients_3D_array.get_min_index();k<=new_filter_coefficients_3D_array.get_max_index() ;k++) - for (int j = new_filter_coefficients_3D_array[k].get_min_index();j<= new_filter_coefficients_3D_array[k].get_max_index();j++) - for (int i = new_filter_coefficients_3D_array[k][j].get_min_index();i<=new_filter_coefficients_3D_array[k][j].get_max_index();i++) - { - cerr << new_filter_coefficients_3D_array[k][j][i] << " "; + }*/ - }*/ - -} + // rescale to DC=1 + new_filter_coefficients_3D_array /= new_filter_coefficients_3D_array.sum(); + /*for (int k = new_filter_coefficients_3D_array.get_min_index();k<=new_filter_coefficients_3D_array.get_max_index() ;k++) + for (int j = new_filter_coefficients_3D_array[k].get_min_index();j<= + new_filter_coefficients_3D_array[k].get_max_index();j++) for (int i = + new_filter_coefficients_3D_array[k][j].get_min_index();i<=new_filter_coefficients_3D_array[k][j].get_max_index();i++) + { + cerr << new_filter_coefficients_3D_array[k][j][i] << " "; + }*/ +} template -ModifiedInverseAverigingImageFilter:: -ModifiedInverseAverigingImageFilter() -{ +ModifiedInverseAverigingImageFilter::ModifiedInverseAverigingImageFilter() { set_defaults(); } - template -ModifiedInverseAverigingImageFilter:: -ModifiedInverseAverigingImageFilter(string proj_data_filename_v, - string attenuation_proj_data_filename_v, - const VectorWithOffset& filter_coefficients_v, - shared_ptr proj_data_ptr_v, - shared_ptr attenuation_proj_data_ptr_v, - DiscretisedDensity<3,float>* initial_image_v, - DiscretisedDensity<3,float>* sensitivity_image_v, - int mask_size_v,bool z_direction_trivial_v) - - +ModifiedInverseAverigingImageFilter::ModifiedInverseAverigingImageFilter( + string proj_data_filename_v, string attenuation_proj_data_filename_v, const VectorWithOffset& filter_coefficients_v, + shared_ptr proj_data_ptr_v, shared_ptr attenuation_proj_data_ptr_v, + DiscretisedDensity<3, float>* initial_image_v, DiscretisedDensity<3, float>* sensitivity_image_v, int mask_size_v, + bool z_direction_trivial_v) + { - assert(filter_coefficients.get_length() == 0 || - filter_coefficients.begin()==0); - - for (int i = filter_coefficients_v.get_min_index();i<=filter_coefficients_v.get_max_index();i++) + assert(filter_coefficients.get_length() == 0 || filter_coefficients.begin() == 0); + + for (int i = filter_coefficients_v.get_min_index(); i <= filter_coefficients_v.get_max_index(); i++) filter_coefficients[i] = filter_coefficients_v[i]; - proj_data_filename = proj_data_filename_v; + proj_data_filename = proj_data_filename_v; attenuation_proj_data_filename = attenuation_proj_data_filename_v; proj_data_ptr = proj_data_ptr_v; attenuation_proj_data_ptr = attenuation_proj_data_ptr_v; initial_image = initial_image_v; sensitivity_image = sensitivity_image_v; - mask_size= mask_size_v; + mask_size = mask_size_v; z_direction_trivial = z_direction_trivial_v; } - template -Succeeded -ModifiedInverseAverigingImageFilter:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) -{ - proj_data_ptr = - ProjData::read_from_file( proj_data_filename); - - if (attenuation_proj_data_filename !="1") - attenuation_proj_data_ptr = - ProjData::read_from_file(attenuation_proj_data_filename); - else +Succeeded +ModifiedInverseAverigingImageFilter::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { + proj_data_ptr = ProjData::read_from_file(proj_data_filename); + + if (attenuation_proj_data_filename != "1") + attenuation_proj_data_ptr = ProjData::read_from_file(attenuation_proj_data_filename); + else attenuation_proj_data_ptr = NULL; - if (initial_image_filename !="1") - initial_image = - DiscretisedDensity<3,float>::read_from_file(initial_image_filename); - else - initial_image = NULL; + if (initial_image_filename != "1") + initial_image = DiscretisedDensity<3, float>::read_from_file(initial_image_filename); + else + initial_image = NULL; - if (sensitivity_image_filename !="1") - sensitivity_image = - DiscretisedDensity<3,float>::read_from_file(sensitivity_image_filename); - else + if (sensitivity_image_filename != "1") + sensitivity_image = DiscretisedDensity<3, float>::read_from_file(sensitivity_image_filename); + else sensitivity_image = NULL; - return Succeeded::yes; - + return Succeeded::yes; } - template -void -ModifiedInverseAverigingImageFilter::precalculate_filter_coefficients (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const -{ +void +ModifiedInverseAverigingImageFilter::precalculate_filter_coefficients( + VectorWithOffset>>>>& all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const { - - VectorWithOffset < shared_ptr > > filter_lookup; + VectorWithOffset>> filter_lookup; const int num_of_elements_in_interval = 500; - filter_lookup.grow(1,num_of_elements_in_interval); - const int k_min =1; - const float k_interval = 0.01F; //0.01F; - - - shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); - VoxelsOnCartesianGrid* in_density_cast = - dynamic_cast< VoxelsOnCartesianGrid* >(in_density); - - - VoxelsOnCartesianGrid * vox_image_ptr_1 = - new VoxelsOnCartesianGrid (IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - + filter_lookup.grow(1, num_of_elements_in_interval); + const int k_min = 1; + const float k_interval = 0.01F; // 0.01F; + + shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); + VoxelsOnCartesianGrid* in_density_cast = dynamic_cast*>(in_density); + + VoxelsOnCartesianGrid* vox_image_ptr_1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + int start_segment_num = proj_data_ptr->get_min_segment_num(); int end_segment_num = proj_data_ptr->get_max_segment_num(); - - - - VectorWithOffset *> all_segments(start_segment_num, end_segment_num); - VectorWithOffset *> all_segments_for_kappa0(start_segment_num, end_segment_num); - VectorWithOffset *> all_attenuation_segments(start_segment_num, end_segment_num); - - + + VectorWithOffset*> all_segments(start_segment_num, end_segment_num); + VectorWithOffset*> all_segments_for_kappa0(start_segment_num, end_segment_num); + VectorWithOffset*> all_attenuation_segments(start_segment_num, end_segment_num); + // first initialise to false bool do_attenuation = false; - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { all_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); all_segments_for_kappa0[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - - if (attenuation_proj_data_filename!="1") - { + + if (attenuation_proj_data_filename != "1") { do_attenuation = true; - all_attenuation_segments[segment_num] = - new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); - } - else - { + all_attenuation_segments[segment_num] = + new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); + } else { do_attenuation = false; - all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); (*all_attenuation_segments[segment_num]).fill(1); } - } - - vox_image_ptr_1->set_origin(Coordinate3D(0,0,0)); - - shared_ptr > image_sptr = vox_image_ptr_1; - - shared_ptr proj_matrix_ptr = - new ProjMatrixByDenselUsingRayTracing; - - proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), - image_sptr); + + vox_image_ptr_1->set_origin(Coordinate3D(0, 0, 0)); + + shared_ptr> image_sptr = vox_image_ptr_1; + + shared_ptr proj_matrix_ptr = new ProjMatrixByDenselUsingRayTracing; + + proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), image_sptr); info(proj_matrix_ptr->parameter_info()); - - //fwd_densels_all(all_segments,proj_matrix_ptr, proj_data_ptr, - //in_density_cast->get_min_z(), in_density_cast->get_max_z(), - //in_density_cast->get_min_y(), in_density_cast->get_max_y(), - //in_density_cast->get_min_x(), in_density_cast->get_max_x(), - //*in_density); - - do_segments_densels_fwd(*in_density_cast,*proj_data_ptr,all_segments, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - in_density_cast->get_min_y(), in_density_cast->get_max_y(), - in_density_cast->get_min_x(), in_density_cast->get_max_x(), - *proj_matrix_ptr); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa0 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa1 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * kappa_coefficients = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - - shared_ptr > kappa0_ptr_bck = vox_image_ptr_kappa0; - shared_ptr > kappa1_ptr_bck = vox_image_ptr_kappa1; - + + // fwd_densels_all(all_segments,proj_matrix_ptr, proj_data_ptr, + // in_density_cast->get_min_z(), in_density_cast->get_max_z(), + // in_density_cast->get_min_y(), in_density_cast->get_max_y(), + // in_density_cast->get_min_x(), in_density_cast->get_max_x(), + //*in_density); + + do_segments_densels_fwd(*in_density_cast, *proj_data_ptr, all_segments, in_density_cast->get_min_z(), + in_density_cast->get_max_z(), in_density_cast->get_min_y(), in_density_cast->get_max_y(), + in_density_cast->get_min_x(), in_density_cast->get_max_x(), *proj_matrix_ptr); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa0 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* kappa_coefficients = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + shared_ptr> kappa0_ptr_bck = vox_image_ptr_kappa0; + shared_ptr> kappa1_ptr_bck = vox_image_ptr_kappa1; + // WARNING - find a way of finding max in the sinogram // TODO - include other segments as well - float max_in_viewgram =0.F; - - for (int segment_num = start_segment_num; segment_num<= end_segment_num; segment_num++) - { - SegmentByView segment_by_view = - proj_data_ptr->get_segment_by_view(segment_num); + float max_in_viewgram = 0.F; + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; segment_num++) { + SegmentByView segment_by_view = proj_data_ptr->get_segment_by_view(segment_num); const float current_max_in_viewgram = segment_by_view.find_max(); - if ( current_max_in_viewgram >= max_in_viewgram) - max_in_viewgram = current_max_in_viewgram ; + if (current_max_in_viewgram >= max_in_viewgram) + max_in_viewgram = current_max_in_viewgram; else continue; } - const float threshold = 0.0001F*max_in_viewgram; - + const float threshold = 0.0001F * max_in_viewgram; + info(boost::format(" THRESHOLD IS %1%") % threshold); - - find_inverse_and_bck_densels(*kappa1_ptr_bck,all_segments, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - vox_image_ptr_kappa1->get_min_y(),vox_image_ptr_kappa1->get_max_y(), - vox_image_ptr_kappa1->get_min_x(),vox_image_ptr_kappa1->get_max_x(), - *proj_matrix_ptr, do_attenuation,threshold, false); //true); - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + + find_inverse_and_bck_densels(*kappa1_ptr_bck, all_segments, all_attenuation_segments, vox_image_ptr_kappa1->get_min_z(), + vox_image_ptr_kappa1->get_max_z(), vox_image_ptr_kappa1->get_min_y(), + vox_image_ptr_kappa1->get_max_y(), vox_image_ptr_kappa1->get_min_x(), + vox_image_ptr_kappa1->get_max_x(), *proj_matrix_ptr, do_attenuation, threshold, false); // true); + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { delete all_segments[segment_num]; delete all_attenuation_segments[segment_num]; - } - + } + info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); - - for (int k=in_density_cast->get_min_z();k<=in_density_cast->get_max_z();k++) - for (int j =in_density_cast->get_min_y();j<=in_density_cast->get_max_y();j++) - for (int i =in_density_cast->get_min_x();i<=in_density_cast->get_max_x();i++) - { - // WARNING - only works for segment zero at the moment - // do the calculation of kappa0 here - kappa0_ptr_bck->fill(0); - for (int segment_num = start_segment_num; - segment_num <= end_segment_num; ++segment_num) - { - (*all_segments_for_kappa0[segment_num]).fill(0); - } - if (true) //attenuation_proj_data_filename !="1") - { -#if 1 - const int new_k_ctr = - z_direction_trivial==1?0:(round((in_density_cast->get_max_z()-in_density_cast->get_min_z())/2.)); - const int mask_size_z = - z_direction_trivial==1?0:mask_size; - - shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid - (IndexRange3D(-mask_size_z+new_k_ctr,mask_size_z+new_k_ctr, - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - CPUTimer timer; - timer.start(); - - // SM 23/05/2002 mask now 3D - - const int min_k = max(in_density_cast->get_min_z(),k-mask_size_z); - const int max_k = min(in_density_cast->get_max_z(),k+mask_size_z); - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - // the mask size is in 2D only - // SM mask now 3D - for (int k_in =min_k;k_in<=max_k;k_in++) - for (int j_in =min_j;j_in<=max_j;j_in++) - for (int i_in =min_i;i_in<=max_i;i_in++) - { - (*in_density_cast_tmp)[k_in-k+new_k_ctr][j_in-j +6][i_in-i+6] = (*in_density_cast)[k_in][j_in][i_in]; - //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; - } - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast_tmp->get_min_z(), in_density_cast_tmp->get_max_z(), - in_density_cast_tmp->get_min_y(),in_density_cast_tmp->get_max_y(), - in_density_cast_tmp->get_min_x(),in_density_cast_tmp->get_max_x(), - *in_density_cast_tmp); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - new_k_ctr,new_k_ctr, - 6,6,6,6, - *proj_matrix_ptr,false,threshold, false) ;//true); - (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[new_k_ctr][6][6]; - //(*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; - - timer.stop(); - //cerr << "kappa0 time "<< timer.value() << endl; - } - else - { - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - min_j,max_j, - min_i,max_i, - //j-2,j+2, - //i-2,i+2, - *in_density_cast); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - j,j,i,i, - *proj_matrix_ptr,false,threshold, true); - - } - float sq_kapas; -// float multiply_with_sensitivity; - if ( fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && - fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001 ) - { - //float tmp = (*kappa0_ptr_bck)[k][j][i]; - //float tmp1 = (*kappa1_ptr_bck)[k][j][i]; - //cerr << "kappa_0 " << (*kappa0_ptr_bck)[k][j][i] << endl; - //cerr << "kappa_1 " << (*kappa1_ptr_bck)[k][j][i] << endl; - - - sq_kapas =((*kappa0_ptr_bck)[k][j][i]*(*kappa0_ptr_bck)[k][j][i])/((*kappa1_ptr_bck)[k][j][i]*(*kappa1_ptr_bck)[k][j][i]); - + + for (int k = in_density_cast->get_min_z(); k <= in_density_cast->get_max_z(); k++) + for (int j = in_density_cast->get_min_y(); j <= in_density_cast->get_max_y(); j++) + for (int i = in_density_cast->get_min_x(); i <= in_density_cast->get_max_x(); i++) { + // WARNING - only works for segment zero at the moment + // do the calculation of kappa0 here + kappa0_ptr_bck->fill(0); + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + (*all_segments_for_kappa0[segment_num]).fill(0); + } + if (true) // attenuation_proj_data_filename !="1") + { +#if 1 + const int new_k_ctr = + z_direction_trivial == 1 ? 0 : (round((in_density_cast->get_max_z() - in_density_cast->get_min_z()) / 2.)); + const int mask_size_z = z_direction_trivial == 1 ? 0 : mask_size; + + shared_ptr> in_density_cast_tmp = + new VoxelsOnCartesianGrid(IndexRange3D(-mask_size_z + new_k_ctr, mask_size_z + new_k_ctr, -mask_size + 6, + mask_size + 6, -mask_size + 6, mask_size + 6), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + CPUTimer timer; + timer.start(); + + // SM 23/05/2002 mask now 3D + + const int min_k = max(in_density_cast->get_min_z(), k - mask_size_z); + const int max_k = min(in_density_cast->get_max_z(), k + mask_size_z); + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + // the mask size is in 2D only + // SM mask now 3D + for (int k_in = min_k; k_in <= max_k; k_in++) + for (int j_in = min_j; j_in <= max_j; j_in++) + for (int i_in = min_i; i_in <= max_i; i_in++) { + (*in_density_cast_tmp)[k_in - k + new_k_ctr][j_in - j + 6][i_in - i + 6] = (*in_density_cast)[k_in][j_in][i_in]; + //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; + } + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast_tmp->get_min_z(), + in_density_cast_tmp->get_max_z(), in_density_cast_tmp->get_min_y(), in_density_cast_tmp->get_max_y(), + in_density_cast_tmp->get_min_x(), in_density_cast_tmp->get_max_x(), *in_density_cast_tmp); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, new_k_ctr, new_k_ctr, + 6, 6, 6, 6, *proj_matrix_ptr, false, threshold, false); // true); + (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[new_k_ctr][6][6]; + //(*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; + + timer.stop(); + // cerr << "kappa0 time "<< timer.value() << endl; + } else { + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), + in_density_cast->get_max_z(), min_j, max_j, min_i, max_i, + // j-2,j+2, + // i-2,i+2, + *in_density_cast); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + vox_image_ptr_kappa1->get_min_z(), vox_image_ptr_kappa1->get_max_z(), j, j, i, i, + *proj_matrix_ptr, false, threshold, true); + } + float sq_kapas; + // float multiply_with_sensitivity; + if (fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && + fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001) { + // float tmp = (*kappa0_ptr_bck)[k][j][i]; + // float tmp1 = (*kappa1_ptr_bck)[k][j][i]; + // cerr << "kappa_0 " << (*kappa0_ptr_bck)[k][j][i] << endl; + // cerr << "kappa_1 " << (*kappa1_ptr_bck)[k][j][i] << endl; + + sq_kapas = ((*kappa0_ptr_bck)[k][j][i] * (*kappa0_ptr_bck)[k][j][i]) / + ((*kappa1_ptr_bck)[k][j][i] * (*kappa1_ptr_bck)[k][j][i]); + #else - float sq_kapas = 10.0F; + float sq_kapas = 10.0F; #endif - (*kappa_coefficients)[k][j][i] = sq_kapas; - - - - // cerr << " now printing sq_kappas value:" << " " << sq_kapas << endl; - int k_index ; - k_index = round(((float)sq_kapas- k_min)/k_interval); - if (k_index < 1) - {k_index = 1;} - - if ( k_index > num_of_elements_in_interval) - { k_index = num_of_elements_in_interval;} - - - if ( filter_lookup[k_index]==NULL ) - { // first compute the filter and store in filter_loopup - //const bool z_direction_trivial= false;//TODO parse - - Array <3,float> new_coeffs; - info(boost::format("computing new filter for sq_kappas %1% at index %2%") % sq_kapas % k_index); - construct_scaled_filter_coefficients(new_coeffs, filter_coefficients,z_direction_trivial,sq_kapas); - filter_lookup[k_index] = new ArrayFilter3DUsingConvolution(new_coeffs); - - } - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - - } - else - { - all_filter_coefficients[k][j][i] = - new ArrayFilter3DUsingConvolution(); - } - - } + (*kappa_coefficients)[k][j][i] = sq_kapas; + + // cerr << " now printing sq_kappas value:" << " " << sq_kapas << endl; + int k_index; + k_index = round(((float)sq_kapas - k_min) / k_interval); + if (k_index < 1) { + k_index = 1; + } + + if (k_index > num_of_elements_in_interval) { + k_index = num_of_elements_in_interval; + } + + if (filter_lookup[k_index] == NULL) { // first compute the filter and store in filter_loopup + // const bool z_direction_trivial= false;//TODO parse + + Array<3, float> new_coeffs; + info(boost::format("computing new filter for sq_kappas %1% at index %2%") % sq_kapas % k_index); + construct_scaled_filter_coefficients(new_coeffs, filter_coefficients, z_direction_trivial, sq_kapas); + filter_lookup[k_index] = new ArrayFilter3DUsingConvolution(new_coeffs); + } + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + + } else { + all_filter_coefficients[k][j][i] = new ArrayFilter3DUsingConvolution(); + } + } - - // write_basic_interfile("kappa_coefficients_2D_SENS",*kappa_coefficients); - delete kappa_coefficients ; + // write_basic_interfile("kappa_coefficients_2D_SENS",*kappa_coefficients); + delete kappa_coefficients; - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - delete all_segments_for_kappa0[segment_num]; + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + delete all_segments_for_kappa0[segment_num]; } - - - } // densel stuff - > apply template void -ModifiedInverseAverigingImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, const DiscretisedDensity<3,elemT>& in_density) const -{ - //the first time virtual_apply is called for this object, counter is set to 0 - static int count=0; +ModifiedInverseAverigingImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { + // the first time virtual_apply is called for this object, counter is set to 0 + static int count = 0; // every time it's called, counter is incremented count++; info(boost::format("checking the counter %1%") % count); - - const VoxelsOnCartesianGrid& in_density_cast_0 = - dynamic_cast< const VoxelsOnCartesianGrid& >(in_density); - - static VectorWithOffset < VectorWithOffset < VectorWithOffset > > > > all_filter_coefficients; - - - if (initial_image_filename!="1") - { - if (count ==1) - { - all_filter_coefficients.grow(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z()); - for (int k = in_density_cast_0.get_min_z(); k<=in_density_cast_0.get_max_z();k++) - { - all_filter_coefficients[k].grow(in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y()); - for (int j = in_density_cast_0.get_min_y(); j<=in_density_cast_0.get_max_y();j++) - { - (all_filter_coefficients[k])[j].grow(in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()); - + const VoxelsOnCartesianGrid& in_density_cast_0 = dynamic_cast&>(in_density); + + static VectorWithOffset>>>> all_filter_coefficients; + + if (initial_image_filename != "1") { + if (count == 1) { + all_filter_coefficients.grow(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z()); + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) { + all_filter_coefficients[k].grow(in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y()); + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) + + { + (all_filter_coefficients[k])[j].grow(in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()); + } } + precalculate_filter_coefficients(all_filter_coefficients, initial_image); + } + // else + // { + // } + } else // for initial image + { + if (count == 1) { + all_filter_coefficients.grow(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z()); + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) { + all_filter_coefficients[k].grow(in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y()); + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) { + (all_filter_coefficients[k])[j].grow(in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()); + + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + + all_filter_coefficients[k][j][i] = new ModifiedInverseAverigingArrayFilter<3, elemT>; + } + } + } } - precalculate_filter_coefficients(all_filter_coefficients,initial_image); + + if ((count % 20) == 0 /*|| count == 1 */) { + + shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); + + int limit_segments = 0; + new_data_info_ptr->reduce_segment_range(-limit_segments, limit_segments); + + VoxelsOnCartesianGrid* vox_image_ptr_1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), in_density_cast_0.get_min_y(), + in_density_cast_0.get_max_y(), in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()), + in_density.get_origin(), in_density_cast_0.get_voxel_size()); + + int start_segment_num = proj_data_ptr->get_min_segment_num(); + int end_segment_num = proj_data_ptr->get_max_segment_num(); + + VectorWithOffset*> all_segments(start_segment_num, end_segment_num); + VectorWithOffset*> all_attenuation_segments(start_segment_num, end_segment_num); + + // first initialise to false + bool do_attenuation = false; + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + all_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + + if (attenuation_proj_data_filename != "1") { + do_attenuation = true; + all_attenuation_segments[segment_num] = + new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); + } else { + do_attenuation = false; + all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + (*all_attenuation_segments[segment_num]).fill(1); + } + } + + VectorWithOffset*> all_segments_for_kappa0(start_segment_num, end_segment_num); + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) + all_segments_for_kappa0[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + + vox_image_ptr_1->set_origin(Coordinate3D(0, 0, 0)); + + shared_ptr> image_sptr = vox_image_ptr_1; + + shared_ptr proj_matrix_ptr = new ProjMatrixByDenselUsingRayTracing; + + proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), image_sptr); + info(proj_matrix_ptr->parameter_info()); + + fwd_densels_all(all_segments, proj_matrix_ptr, proj_data_ptr, in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), + in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y(), in_density_cast_0.get_min_x(), + in_density_cast_0.get_max_x(), in_density_cast_0); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa0 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), in_density_cast_0.get_min_y(), + in_density_cast_0.get_max_y(), in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()), + in_density.get_origin(), in_density_cast_0.get_voxel_size()); + + shared_ptr> kappa0_ptr_bck = vox_image_ptr_kappa0; + + VoxelsOnCartesianGrid* vox_image_ptr_kappa1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), in_density_cast_0.get_min_y(), + in_density_cast_0.get_max_y(), in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()), + in_density.get_origin(), in_density_cast_0.get_voxel_size()); + + shared_ptr> kappa1_ptr_bck = vox_image_ptr_kappa1; + + // WARNING - find a way of finding max in the sinogram + // TODO - include other segments as well + float max_in_viewgram = 0.F; + + for (int segment_num = 0; segment_num <= 0; segment_num++) { + SegmentByView segment_by_view = proj_data_ptr->get_segment_by_view(segment_num); + const float current_max_in_viewgram = segment_by_view.find_max(); + if (current_max_in_viewgram >= max_in_viewgram) + max_in_viewgram = current_max_in_viewgram; + else + continue; + } + const float threshold = 0.0001F * max_in_viewgram; + + info(boost::format(" THRESHOLD IS %1%") % threshold); + + find_inverse_and_bck_densels(*kappa1_ptr_bck, all_segments, all_attenuation_segments, vox_image_ptr_kappa1->get_min_z(), + vox_image_ptr_kappa1->get_max_z(), vox_image_ptr_kappa1->get_min_y(), + vox_image_ptr_kappa1->get_max_y(), vox_image_ptr_kappa1->get_min_x(), + vox_image_ptr_kappa1->get_max_x(), *proj_matrix_ptr, do_attenuation, threshold, true); + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + delete all_segments[segment_num]; + } + + info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); + + char* file1 = "kappa1"; + // cerr <<" - Saving " << file1 << endl; + write_basic_interfile(file1, *kappa1_ptr_bck); + + const string filename = "kapa0_div_kapa1_pf"; + shared_ptr output = new fstream(filename.c_str(), ios::trunc | ios::in | ios::out | ios::binary); + + const string filename1 = "values_of_kapa0_and_kapa1_pf"; + shared_ptr output1 = new fstream(filename1.c_str(), ios::trunc | ios::in | ios::out | ios::binary); + + if (!*output1) + error("Error opening output file %s\n", filename1.c_str()); + + if (!*output) + error("Error opening output file %s\n", filename.c_str()); + + *output << "kapa0_div_kapa1" << endl; + *output << endl; + *output << endl; + *output << "Plane number " << endl; + + // int size = filter_coefficients.get_length(); + + // todo - remove + const string testing_kappas_att = "kappa_att"; + shared_ptr output_att = new fstream(testing_kappas_att.c_str(), ios::trunc | ios::out | ios::binary); + + const string testing_kappas_noatt = "kappa_noatt"; + shared_ptr output_noatt = new fstream(testing_kappas_noatt.c_str(), ios::trunc | ios::out | ios::binary); + + if (!*output_att) + error("Error opening output file %s\n", testing_kappas_att.c_str()); + + if (!*output_noatt) + error("Error opening output file %s\n", testing_kappas_noatt.c_str()); + + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + + // WARNING - only works for segment zero at the moment + // do the calculation of kappa0 here + kappa0_ptr_bck->fill(0); + (*all_segments_for_kappa0[all_segments.get_min_index()]).fill(0); + if (true) // attenuation_proj_data_filename !="1") + { + + shared_ptr> in_density_cast_tmp = + new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), + -mask_size + 6, mask_size + 6, -mask_size + 6, mask_size + 6), + in_density.get_origin(), in_density_cast_0.get_voxel_size()); + + const int min_j = max(in_density_cast_0.get_min_y(), j - mask_size); + const int max_j = min(in_density_cast_0.get_max_y(), j + mask_size); + const int min_i = max(in_density_cast_0.get_min_x(), i - mask_size); + const int max_i = min(in_density_cast_0.get_max_x(), i + mask_size); + + // the mask size is in 2D only + + for (int j_in = min_j; j_in <= max_j; j_in++) + for (int i_in = min_i; i_in <= max_i; i_in++) + + (*in_density_cast_tmp)[k][j_in - j + 6][i_in - i + 6] = in_density_cast_0[k][j_in][i_in]; + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast_0.get_min_z(), + in_density_cast_0.get_max_z(), in_density_cast_tmp->get_min_y(), in_density_cast_tmp->get_max_y(), + in_density_cast_tmp->get_min_x(), in_density_cast_tmp->get_max_x(), *in_density_cast_tmp); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + vox_image_ptr_kappa1->get_min_z(), vox_image_ptr_kappa1->get_max_z(), + // 0,0,0,0, + 6, 6, 6, 6, *proj_matrix_ptr, false, threshold, true); + (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; + + *output_att << k << " " << j << " " << i << " " << (*kappa0_ptr_bck)[k][j][i] << endl; + + } else { + const int min_j = max(in_density_cast_0.get_min_y(), j - mask_size); + const int max_j = min(in_density_cast_0.get_max_y(), j + mask_size); + const int min_i = max(in_density_cast_0.get_min_x(), i - mask_size); + const int max_i = min(in_density_cast_0.get_max_x(), i + mask_size); + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast_0.get_min_z(), + in_density_cast_0.get_max_z(), min_j, max_j, min_i, max_i, + // j-2,j+2, + // i-2,i+2, + in_density_cast_0); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + vox_image_ptr_kappa1->get_min_z(), vox_image_ptr_kappa1->get_max_z(), j, j, i, i, + *proj_matrix_ptr, false, threshold, true); + + *output_noatt << k << " " << j << " " << i << " " << (*kappa0_ptr_bck)[k][j][i] << endl; + } + // cerr << "min and max in image - kappa0 " <find_min() + // << ", " << kappa0_ptr_bck->find_max() << endl; + + char* file0 = "kappa0"; + write_basic_interfile(file0, *kappa0_ptr_bck); + + float sq_kapas; + + if (fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && + fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001) { + sq_kapas = ((*kappa0_ptr_bck)[k][j][i] * (*kappa0_ptr_bck)[k][j][i]) / + ((*kappa1_ptr_bck)[k][j][i] * (*kappa1_ptr_bck)[k][j][i]); + + *output1 << " Values of kapa0 and kapa1" << endl; + *output1 << "for k " << k; + *output1 << ":"; + *output1 << j; + *output1 << ","; + *output1 << i; + *output1 << " "; + //*output1 <<(*image_sptr_0)[k][j][i]; + *output1 << (*kappa0_ptr_bck)[k][j][i]; + *output1 << " "; + *output1 << (*kappa1_ptr_bck)[k][j][i]; + *output1 << endl; + *output << "for k " << k; + *output << ":"; + *output << j; + *output << ","; + *output << i; + *output << " "; + *output << sq_kapas; + *output << endl; + + // sq_kapas = 10; + all_filter_coefficients[k][j][i] = new ModifiedInverseAverigingArrayFilter<3, elemT>(filter_coefficients, sq_kapas); + + } else { + all_filter_coefficients[k][j][i] = new ModifiedInverseAverigingArrayFilter<3, elemT>(); + } + } + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + delete all_segments_for_kappa0[segment_num]; + delete all_attenuation_segments[segment_num]; + } } - // else - // { - // } } - else // for initial image - { - if (count==1) - { - all_filter_coefficients.grow(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z()); - - for (int k = in_density_cast_0.get_min_z(); k<=in_density_cast_0.get_max_z();k++) - { - all_filter_coefficients[k].grow(in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y()); - for (int j = in_density_cast_0.get_min_y(); j<=in_density_cast_0.get_max_y();j++) - { - (all_filter_coefficients[k])[j].grow(in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()); - - for (int i = in_density_cast_0.get_min_x(); i<=in_density_cast_0.get_max_x();i++) - { - - all_filter_coefficients[k][j][i] = - new ModifiedInverseAverigingArrayFilter<3,elemT>; - - } - } - } - + + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + Array<3, elemT> tmp_out(IndexRange3D(k, k, j, j, i, i)); + + (*all_filter_coefficients[k][j][i])(tmp_out, in_density); + out_density[k][j][i] = tmp_out[k][j][i]; } - - - if ( (count % 20) ==0 /*|| count == 1 */) - { - - shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); - - int limit_segments= 0; - new_data_info_ptr->reduce_segment_range(-limit_segments, limit_segments); - - - VoxelsOnCartesianGrid * vox_image_ptr_1 = - new VoxelsOnCartesianGrid (IndexRange3D(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z(), - in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y(), - in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()), - in_density.get_origin(),in_density_cast_0.get_voxel_size()); - - int start_segment_num = proj_data_ptr->get_min_segment_num(); - int end_segment_num = proj_data_ptr->get_max_segment_num(); - - VectorWithOffset *> all_segments(start_segment_num, end_segment_num); - VectorWithOffset *> all_attenuation_segments(start_segment_num, end_segment_num); - - // first initialise to false - bool do_attenuation = false; - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - all_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - - if (attenuation_proj_data_filename !="1") - { - do_attenuation = true; - all_attenuation_segments[segment_num] = - new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); - } - else - { - do_attenuation = false; - all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - (*all_attenuation_segments[segment_num]).fill(1); - } - - } - - VectorWithOffset *> all_segments_for_kappa0(start_segment_num, end_segment_num); - - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - all_segments_for_kappa0[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - - - vox_image_ptr_1->set_origin(Coordinate3D(0,0,0)); - - shared_ptr > image_sptr = vox_image_ptr_1; - - shared_ptr proj_matrix_ptr = - new ProjMatrixByDenselUsingRayTracing; - - proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), - image_sptr); - info(proj_matrix_ptr->parameter_info()); - - fwd_densels_all(all_segments,proj_matrix_ptr, proj_data_ptr, - in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), - in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y(), - in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x(), - in_density_cast_0); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa0 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z(), - in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y(), - in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()), - in_density.get_origin(),in_density_cast_0.get_voxel_size()); - - - shared_ptr > kappa0_ptr_bck = vox_image_ptr_kappa0; - - VoxelsOnCartesianGrid * vox_image_ptr_kappa1 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z(), - in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y(), - in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()), - in_density.get_origin(),in_density_cast_0.get_voxel_size()); - - shared_ptr > kappa1_ptr_bck = vox_image_ptr_kappa1; - - // WARNING - find a way of finding max in the sinogram - // TODO - include other segments as well - float max_in_viewgram =0.F; - - for (int segment_num = 0; segment_num<= 0; - segment_num++) - { - SegmentByView segment_by_view = - proj_data_ptr->get_segment_by_view(segment_num); - const float current_max_in_viewgram = segment_by_view.find_max(); - if ( current_max_in_viewgram >= max_in_viewgram) - max_in_viewgram = current_max_in_viewgram ; - else - continue; - } - const float threshold = 0.0001F*max_in_viewgram; - - info(boost::format(" THRESHOLD IS %1%") % threshold); - - find_inverse_and_bck_densels(*kappa1_ptr_bck,all_segments, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - vox_image_ptr_kappa1->get_min_y(),vox_image_ptr_kappa1->get_max_y(), - vox_image_ptr_kappa1->get_min_x(),vox_image_ptr_kappa1->get_max_x(), - *proj_matrix_ptr, do_attenuation,threshold,true); - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - delete all_segments[segment_num]; - } - - info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); - - char* file1 = "kappa1"; - //cerr <<" - Saving " << file1 << endl; - write_basic_interfile(file1, *kappa1_ptr_bck); - - - const string filename ="kapa0_div_kapa1_pf"; - shared_ptr output = - new fstream (filename.c_str(), ios::trunc|ios::in|ios::out|ios::binary); - - const string filename1 ="values_of_kapa0_and_kapa1_pf"; - shared_ptr output1 = - new fstream (filename1.c_str(), ios::trunc|ios::in|ios::out|ios::binary); - - - if (!*output1) - error("Error opening output file %s\n",filename1.c_str()); - - if (!*output) - error("Error opening output file %s\n",filename.c_str()); - - - *output << "kapa0_div_kapa1" << endl; - *output << endl; - *output << endl; - *output << "Plane number " << endl; - - // int size = filter_coefficients.get_length(); - - //todo - remove - const string testing_kappas_att="kappa_att"; - shared_ptr output_att = - new fstream (testing_kappas_att.c_str(),ios::trunc|ios::out|ios::binary); - - const string testing_kappas_noatt="kappa_noatt"; - shared_ptr output_noatt = - new fstream (testing_kappas_noatt.c_str(),ios::trunc|ios::out|ios::binary); - - if (!*output_att) - error("Error opening output file %s\n",testing_kappas_att.c_str()); - - if (!*output_noatt) - error("Error opening output file %s\n",testing_kappas_noatt.c_str()); - - - for (int k=in_density_cast_0.get_min_z();k<=in_density_cast_0.get_max_z();k++) - for (int j =in_density_cast_0.get_min_y();j<=in_density_cast_0.get_max_y();j++) - for (int i =in_density_cast_0.get_min_x();i<=in_density_cast_0.get_max_x();i++) - { - - // WARNING - only works for segment zero at the moment - // do the calculation of kappa0 here - kappa0_ptr_bck->fill(0); - (*all_segments_for_kappa0[all_segments.get_min_index()]).fill(0); - if (true) //attenuation_proj_data_filename !="1") - { - - shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid - (IndexRange3D(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z(), - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density.get_origin(),in_density_cast_0.get_voxel_size()); - - const int min_j = max(in_density_cast_0.get_min_y(),j-mask_size); - const int max_j = min(in_density_cast_0.get_max_y(),j+mask_size); - const int min_i = max(in_density_cast_0.get_min_x(),i-mask_size); - const int max_i = min(in_density_cast_0.get_max_x(),i+mask_size); - - // the mask size is in 2D only - - for (int j_in =min_j;j_in<=max_j;j_in++) - for (int i_in =min_i;i_in<=max_i;i_in++) - - (*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = in_density_cast_0[k][j_in][i_in]; - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), - in_density_cast_tmp->get_min_y(),in_density_cast_tmp->get_max_y(), - in_density_cast_tmp->get_min_x(),in_density_cast_tmp->get_max_x(), - *in_density_cast_tmp); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - //0,0,0,0, - 6,6,6,6, - *proj_matrix_ptr,false,threshold, true); - (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; - - - *output_att << k <<" " << j << " "<< i << " "<< (*kappa0_ptr_bck)[k][j][i] << endl; - - - } - else - { - const int min_j = max(in_density_cast_0.get_min_y(),j-mask_size); - const int max_j = min(in_density_cast_0.get_max_y(),j+mask_size); - const int min_i = max(in_density_cast_0.get_min_x(),i-mask_size); - const int max_i = min(in_density_cast_0.get_max_x(),i+mask_size); - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), - min_j,max_j, - min_i,max_i, - //j-2,j+2, - //i-2,i+2, - in_density_cast_0); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - j,j,i,i, - *proj_matrix_ptr,false,threshold, true); - - - *output_noatt << k <<" " << j << " "<< i << " "<< (*kappa0_ptr_bck)[k][j][i] << endl; - - } - // cerr << "min and max in image - kappa0 " <find_min() - // << ", " << kappa0_ptr_bck->find_max() << endl; - - char* file0 = "kappa0"; - write_basic_interfile(file0, *kappa0_ptr_bck); - - float sq_kapas; - - if ( fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && - fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001 ) - { - sq_kapas =((*kappa0_ptr_bck)[k][j][i]*(*kappa0_ptr_bck)[k][j][i])/((*kappa1_ptr_bck)[k][j][i]*(*kappa1_ptr_bck)[k][j][i]); - - *output1 << " Values of kapa0 and kapa1" << endl; - *output1<< "for k "<< k; - *output1 <<":"; - *output1 << j; - *output1 <<","; - *output1 <(filter_coefficients,sq_kapas); - - } - else - { - all_filter_coefficients[k][j][i] = - new ModifiedInverseAverigingArrayFilter<3,elemT>(); - - } - - } - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - delete all_segments_for_kappa0[segment_num]; - delete all_attenuation_segments[segment_num]; - } - } - } - - for (int k=in_density_cast_0.get_min_z();k<=in_density_cast_0.get_max_z();k++) - for (int j =in_density_cast_0.get_min_y();j<=in_density_cast_0.get_max_y();j++) - for (int i =in_density_cast_0.get_min_x();i<=in_density_cast_0.get_max_x();i++) - { - Array<3,elemT> tmp_out(IndexRange3D(k,k,j,j,i,i)); - - (*all_filter_coefficients[k][j][i])(tmp_out,in_density); - out_density[k][j][i] = tmp_out[k][j][i]; - - } - } +} template void -ModifiedInverseAverigingImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const -{ - DiscretisedDensity<3,elemT>* tmp_density = - density.clone(); +ModifiedInverseAverigingImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& density) const { + DiscretisedDensity<3, elemT>* tmp_density = density.clone(); virtual_apply(density, *tmp_density); delete tmp_density; } - template void -ModifiedInverseAverigingImageFilter::set_defaults() -{ +ModifiedInverseAverigingImageFilter::set_defaults() { filter_coefficients.fill(0); - proj_data_filename ="1"; + proj_data_filename = "1"; proj_data_ptr = NULL; - attenuation_proj_data_filename ="1"; - initial_image_filename ="1"; - sensitivity_image_filename ='1'; + attenuation_proj_data_filename = "1"; + initial_image_filename = "1"; + sensitivity_image_filename = '1'; sensitivity_image = NULL; attenuation_proj_data_ptr = NULL; mask_size = 0; z_direction_trivial = true; - } template void -ModifiedInverseAverigingImageFilter:: initialise_keymap() -{ +ModifiedInverseAverigingImageFilter::initialise_keymap() { parser.add_start_key("Modified Inverse Image Filter Parameters"); parser.add_key("filter_coefficients", &filter_coefficients_for_parsing); parser.add_key("proj_data_filename", &proj_data_filename); @@ -1223,32 +1050,23 @@ ModifiedInverseAverigingImageFilter:: initialise_keymap() } template -bool -ModifiedInverseAverigingImageFilter:: -post_processing() -{ +bool +ModifiedInverseAverigingImageFilter::post_processing() { const unsigned int size = filter_coefficients_for_parsing.size(); - const int min_index = -(size/2); + const int min_index = -(size / 2); filter_coefficients.grow(min_index, min_index + size - 1); - for (int i = min_index; i<= filter_coefficients.get_max_index(); ++i) - filter_coefficients[i] = - static_cast(filter_coefficients_for_parsing[i-min_index]); + for (int i = min_index; i <= filter_coefficients.get_max_index(); ++i) + filter_coefficients[i] = static_cast(filter_coefficients_for_parsing[i - min_index]); return false; } +const char* const ModifiedInverseAverigingImageFilter::registered_name = "Modified Inverse Image Filter"; - - -const char * const -ModifiedInverseAverigingImageFilter::registered_name = - "Modified Inverse Image Filter"; - - -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif // Register this class in the ImageProcessor registry // static SeparableCartesianMetzImageFilter::RegisterIt dummy; @@ -1256,14 +1074,6 @@ ModifiedInverseAverigingImageFilter::registered_name = template ModifiedInverseAverigingImageFilter; - - END_NAMESPACE_STIR - /************************************************************************************************/ - - - - - diff --git a/src/experimental/buildblock/NonseparableSpatiallyVaryingFilters.cxx b/src/experimental/buildblock/NonseparableSpatiallyVaryingFilters.cxx index 586d1489e7..b6c70c4bb2 100644 --- a/src/experimental/buildblock/NonseparableSpatiallyVaryingFilters.cxx +++ b/src/experimental/buildblock/NonseparableSpatiallyVaryingFilters.cxx @@ -4,10 +4,10 @@ \file \ingroup buildblock \brief Implementations for class NonseparableSpatiallyVaryingFilters - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2003, IRSL @@ -43,552 +43,463 @@ using std::endl; #include "stir_experimental/local_helping_functions.h" #include "stir_experimental/fwd_and_bck_manipulation_for_SAF.h" - - START_NAMESPACE_STIR -void -construct_scaled_filter_coefficients_2D(Array<2,float> &new_filter_coefficients_2D_array, - Array<2,float>& kernel_2d,const float kapa0_over_kapa1, - int number_of_coefficients_before_padding); - - +void construct_scaled_filter_coefficients_2D(Array<2, float>& new_filter_coefficients_2D_array, Array<2, float>& kernel_2d, + const float kapa0_over_kapa1, int number_of_coefficients_before_padding); /**********************************************************************************************/ - - - - void -construct_scaled_filter_coefficients_2D(Array<2,float> &new_filter_coefficients_2D_array, - Array<2,float>& kernel_2d,const float kapa0_over_kapa1, - int number_of_coefficients_before_padding) - +construct_scaled_filter_coefficients_2D(Array<2, float>& new_filter_coefficients_2D_array, Array<2, float>& kernel_2d, + const float kapa0_over_kapa1, int number_of_coefficients_before_padding) + { #if 1 - if (kapa0_over_kapa1!=0) - { - - // in the case where sq_kappas=1 --- scaled_filter == original template filter - Array<2,float> filter_coefficients(IndexRange2D(kernel_2d.get_min_index(), kernel_2d.get_max_index(), - kernel_2d[0].get_min_index(), kernel_2d[0].get_max_index())); + if (kapa0_over_kapa1 != 0) { + + // in the case where sq_kappas=1 --- scaled_filter == original template filter + Array<2, float> filter_coefficients(IndexRange2D(kernel_2d.get_min_index(), kernel_2d.get_max_index(), + kernel_2d[0].get_min_index(), kernel_2d[0].get_max_index())); filter_coefficients = kernel_2d; - + // create_kernel_2d (filter_coefficients, kernel_1d); - - -#if 1 - // STUFF FOR THE FFT SIZE + +# if 1 + // STUFF FOR THE FFT SIZE /****************** *********************************************************************/ - + const int length_of_size_array = 16; - const float kapa0_over_kapa1_interval_size=10.F; + const float kapa0_over_kapa1_interval_size = 10.F; static VectorWithOffset size_for_kapa0_over_kapa1; - if (size_for_kapa0_over_kapa1.get_length()==0) - { - size_for_kapa0_over_kapa1.grow(0,length_of_size_array-1); + if (size_for_kapa0_over_kapa1.get_length() == 0) { + size_for_kapa0_over_kapa1.grow(0, length_of_size_array - 1); size_for_kapa0_over_kapa1.fill(64); } - - const int kapa0_over_kapa1_interval = - min(static_cast(floor(kapa0_over_kapa1/kapa0_over_kapa1_interval_size)), - length_of_size_array-1); - - float sq_kapas = kapa0_over_kapa1; - /******************************************************************************************/ - - if ( sq_kapas > 10000) - { - new_filter_coefficients_2D_array.grow(IndexRange2D(0,0,0,0)); - } - else if (sq_kapas!=1.F) - { - - while(true) - { - const int size = size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]; - - int filter_length_y = static_cast(floor(kernel_2d.get_length()/2)); - int filter_length_x = static_cast(floor(kernel_2d[0].get_length()/2)); - - //cerr << "Now doing size " << size << std::endl; - - // FIRST PADD 2D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC - // ( DO NOT TAKE IMAGINARY PART INTO ACCOUNT YET) - /**********************************************************************************/ - - Array<2,float> filter_coefficients_padded_2D_array(IndexRange2D(1,size,1,size)); - //int number_of_coefficients_before_padding = 15; - - - int min_kernel_2d_y = kernel_2d.get_min_index(); - int min_kernel_2d_x = kernel_2d[1].get_min_index(); - int tmp_y = min_kernel_2d_y; - int tmp_x = min_kernel_2d_x; - - for ( int j = 0;j<=number_of_coefficients_before_padding-1;j++) - for ( int i = 0;i<=number_of_coefficients_before_padding-1;i++) - { - filter_coefficients_padded_2D_array[j+1][i+1] = kernel_2d[j+min_kernel_2d_y][i+min_kernel_2d_x]; - if ( i != (number_of_coefficients_before_padding-1)) - { - filter_coefficients_padded_2D_array[j+1][size-(i)] = kernel_2d[j+min_kernel_2d_y][i+min_kernel_2d_x+1]; - } - - } - - int j_n = 1; - for ( int j = size-(number_of_coefficients_before_padding-1);j<=size-1;j++) - { - for ( int i = 0;i<=number_of_coefficients_before_padding-1;i++) - { - filter_coefficients_padded_2D_array[j+1][i+1] = kernel_2d[j_n][i+min_kernel_2d_x]; - if ( i!=number_of_coefficients_before_padding-1) - { - filter_coefficients_padded_2D_array[j+1][size-(i)] = kernel_2d[j_n][i+min_kernel_2d_x+1]; - } - } - j_n ++; - } + const int kapa0_over_kapa1_interval = + min(static_cast(floor(kapa0_over_kapa1 / kapa0_over_kapa1_interval_size)), length_of_size_array - 1); + float sq_kapas = kapa0_over_kapa1; + /******************************************************************************************/ - /* for ( int j = 1;j<=64;j++) - { - for ( int i = 1;i<=64;i++) - { - cerr << filter_coefficients_padded_2D_array[j][i] << " " ; - } - cerr << endl; - } -*/ - /*************************************************************************************/ - - - // this is not needed any longer 2D kernel already created -/* VectorWithOffset < float> kernel_1d_vector; - kernel_1d_vector.grow(1,size); - for ( int i = 1; i<= size ;i++) - kernel_1d_vector[i] = filter_coefficients_padded_1D_array[i]; - - Array<2,float> filter_coefficients_padded(IndexRange2D(1,size,1,size)); - - create_kernel_2d (filter_coefficients_padded, kernel_1d_vector);*/ - Array<2,float> filter_coefficients_padded(IndexRange2D(1,size,1,size)); - filter_coefficients_padded = filter_coefficients_padded_2D_array; - - - // rescale to DC=1 - float tmp = filter_coefficients_padded.sum(); - filter_coefficients_padded /= filter_coefficients_padded.sum(); - /* for ( int j = filter_coefficients_padded.get_min_index(); j<=filter_coefficients_padded.get_max_index();j++) - for ( int i = filter_coefficients_padded.get_min_index(); i<= filter_coefficients_padded.get_max_index();i++) - cerr << filter_coefficients_padded[j][i] << " ";*/ - - Array<2,float>& fft_filter = filter_coefficients_padded; - float inverse_sq_kapas; - if (fabs((double)sq_kapas ) >0.000000000001) - inverse_sq_kapas = 1/sq_kapas; - else - inverse_sq_kapas = 0; - - - // Array<1,float> fft_1_1D_array (1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); - Array<1,float> fft_filter_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() ); - - static shared_ptr > fft_filter_1D_array_64 = - new Array<1,float>(1,2*64*64); - static shared_ptr > fft_filter_1D_array_128 = - new Array<1,float> (1,2*128*128); - static shared_ptr > fft_filter_1D_array_256 = - new Array<1,float> (1,2*256*256); - static shared_ptr > fft_filter_1D_array_512 = - new Array<1,float> (1,2*512*512); - static shared_ptr > fft_filter_1D_array_1024 = - new Array<1,float> (1,2*1024*1024); - static shared_ptr > fft_filter_1D_array_2048= - new Array<1,float> (1,2*2048*2048); - - - convert_array_2D_into_1D_array(fft_filter_1D_array,fft_filter); - - Array<1, int> array_lengths(1,2); - array_lengths[1] = fft_filter.get_length(); - array_lengths[2] = fft_filter[fft_filter.get_min_index()].get_length(); - //array_lengths[3] = fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length(); - - // initialise to 0 to prevent from warnings - float fft_1_1D_array = 0; - - if (size == 64) - { - if ( (*fft_filter_1D_array_64)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_64 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_64; - - } - } - else if (size ==128) - { - if ( (*fft_filter_1D_array_128)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_128 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_128; - - } - } - else if ( size == 256) - { - if ( (*fft_filter_1D_array_256)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_256 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_256; - - } - } - else if ( size == 512) - { - if ( (*fft_filter_1D_array_512)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_512 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_512; - - } - } - else if ( size == 1024) - { - if ( (*fft_filter_1D_array_1024)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_1024 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_1024; - - } - } - else if ( size == 2048) - { - if ( (*fft_filter_1D_array_2048)[1] == 0.F) - { - fourn(fft_filter_1D_array, array_lengths, 2,1); - fft_filter_1D_array /= sqrt(static_cast(size *size)); - *fft_filter_1D_array_2048 = fft_filter_1D_array; - } - else - { - fft_filter_1D_array = *fft_filter_1D_array_2048; - - } - } - else - { - warning("\nNonseparableSpatiallyVaryingFilters: Cannot do this at the moment -- size is too big'.\n"); - - } - - // fourn(fft_filter_1D_array, array_lengths, 3,1); - - // WARNING -- this only works for the FFT where the convention is that the final result - // obtained from the FFT is divided with sqrt(N*N*N) - switch (size) - { - case 64: - fft_1_1D_array = static_cast(1/sqrt(static_cast(64*64))); - break; - case 128: - fft_1_1D_array = static_cast(1/sqrt(static_cast(128*128))); - break; - case 256: - fft_1_1D_array = static_cast(1/sqrt(static_cast(256*256))); - break; - case 512: - fft_1_1D_array = static_cast(1/sqrt(static_cast(512*512))); - break; - case 1024: - fft_1_1D_array = static_cast(1/sqrt(static_cast(1024*1024))); - break; - case 2048: - fft_1_1D_array = static_cast(1/sqrt(static_cast(2048*2048))); - break; - - default: - warning("\nNonseparableSpatiallyVaryingFilters: Cannot do this at the moment -- size is too big'.\n");; - break; - } - - // to check the outputs make the fft consistant with mathematica - // divide 1/sqrt(size) - //fft_1_1D_array /= sqrt(static_cast (size *size*size)); - // fft_filter_1D_array /= sqrt(static_cast(size *size*size)); - Array<2,float> new_filter_coefficients_2D_array_tmp (IndexRange2D(1,filter_coefficients_padded.get_length(),1,filter_coefficients_padded.get_length())); - - { - Array<1,float> fft_filter_num_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length()); - //Array<1,float> div_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length()); - - //mulitply_complex_arrays(fft_filter_num_1D_array,fft_filter_1D_array,fft_1_1D_array); - - - fft_filter_num_1D_array = fft_filter_1D_array* fft_1_1D_array; -#if 0 + if (sq_kapas > 10000) { + new_filter_coefficients_2D_array.grow(IndexRange2D(0, 0, 0, 0)); + } else if (sq_kapas != 1.F) { + + while (true) { + const int size = size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]; + + int filter_length_y = static_cast(floor(kernel_2d.get_length() / 2)); + int filter_length_x = static_cast(floor(kernel_2d[0].get_length() / 2)); + + // cerr << "Now doing size " << size << std::endl; + + // FIRST PADD 2D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC + // ( DO NOT TAKE IMAGINARY PART INTO ACCOUNT YET) + /**********************************************************************************/ + + Array<2, float> filter_coefficients_padded_2D_array(IndexRange2D(1, size, 1, size)); + // int number_of_coefficients_before_padding = 15; + + int min_kernel_2d_y = kernel_2d.get_min_index(); + int min_kernel_2d_x = kernel_2d[1].get_min_index(); + int tmp_y = min_kernel_2d_y; + int tmp_x = min_kernel_2d_x; + + for (int j = 0; j <= number_of_coefficients_before_padding - 1; j++) + for (int i = 0; i <= number_of_coefficients_before_padding - 1; i++) { + filter_coefficients_padded_2D_array[j + 1][i + 1] = kernel_2d[j + min_kernel_2d_y][i + min_kernel_2d_x]; + if (i != (number_of_coefficients_before_padding - 1)) { + filter_coefficients_padded_2D_array[j + 1][size - (i)] = kernel_2d[j + min_kernel_2d_y][i + min_kernel_2d_x + 1]; + } + } + + int j_n = 1; + for (int j = size - (number_of_coefficients_before_padding - 1); j <= size - 1; j++) { + for (int i = 0; i <= number_of_coefficients_before_padding - 1; i++) { + filter_coefficients_padded_2D_array[j + 1][i + 1] = kernel_2d[j_n][i + min_kernel_2d_x]; + if (i != number_of_coefficients_before_padding - 1) { + filter_coefficients_padded_2D_array[j + 1][size - (i)] = kernel_2d[j_n][i + min_kernel_2d_x + 1]; + } + } + j_n++; + } + + /* for ( int j = 1;j<=64;j++) + { + for ( int i = 1;i<=64;i++) + { + cerr << filter_coefficients_padded_2D_array[j][i] << " " ; + } + cerr << endl; + } + */ + /*************************************************************************************/ + + // this is not needed any longer 2D kernel already created + /* VectorWithOffset < float> kernel_1d_vector; + kernel_1d_vector.grow(1,size); + for ( int i = 1; i<= size ;i++) + kernel_1d_vector[i] = filter_coefficients_padded_1D_array[i]; + + Array<2,float> filter_coefficients_padded(IndexRange2D(1,size,1,size)); + + create_kernel_2d (filter_coefficients_padded, kernel_1d_vector);*/ + Array<2, float> filter_coefficients_padded(IndexRange2D(1, size, 1, size)); + filter_coefficients_padded = filter_coefficients_padded_2D_array; + + // rescale to DC=1 + float tmp = filter_coefficients_padded.sum(); + filter_coefficients_padded /= filter_coefficients_padded.sum(); + /* for ( int j = filter_coefficients_padded.get_min_index(); j<=filter_coefficients_padded.get_max_index();j++) + for ( int i = filter_coefficients_padded.get_min_index(); i<= filter_coefficients_padded.get_max_index();i++) + cerr << filter_coefficients_padded[j][i] << " ";*/ + + Array<2, float>& fft_filter = filter_coefficients_padded; + float inverse_sq_kapas; + if (fabs((double)sq_kapas) > 0.000000000001) + inverse_sq_kapas = 1 / sq_kapas; + else + inverse_sq_kapas = 0; + + // Array<1,float> fft_1_1D_array (1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length() + // *fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length()); + Array<1, float> fft_filter_1D_array(1, 2 * fft_filter.get_length() * fft_filter[fft_filter.get_min_index()].get_length()); + + static shared_ptr> fft_filter_1D_array_64 = new Array<1, float>(1, 2 * 64 * 64); + static shared_ptr> fft_filter_1D_array_128 = new Array<1, float>(1, 2 * 128 * 128); + static shared_ptr> fft_filter_1D_array_256 = new Array<1, float>(1, 2 * 256 * 256); + static shared_ptr> fft_filter_1D_array_512 = new Array<1, float>(1, 2 * 512 * 512); + static shared_ptr> fft_filter_1D_array_1024 = new Array<1, float>(1, 2 * 1024 * 1024); + static shared_ptr> fft_filter_1D_array_2048 = new Array<1, float>(1, 2 * 2048 * 2048); + + convert_array_2D_into_1D_array(fft_filter_1D_array, fft_filter); + + Array<1, int> array_lengths(1, 2); + array_lengths[1] = fft_filter.get_length(); + array_lengths[2] = fft_filter[fft_filter.get_min_index()].get_length(); + // array_lengths[3] = fft_filter[fft_filter.get_min_index()][fft_filter.get_min_index()].get_length(); + + // initialise to 0 to prevent from warnings + float fft_1_1D_array = 0; + + if (size == 64) { + if ((*fft_filter_1D_array_64)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_64 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_64; + } + } else if (size == 128) { + if ((*fft_filter_1D_array_128)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_128 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_128; + } + } else if (size == 256) { + if ((*fft_filter_1D_array_256)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_256 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_256; + } + } else if (size == 512) { + if ((*fft_filter_1D_array_512)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_512 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_512; + } + } else if (size == 1024) { + if ((*fft_filter_1D_array_1024)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_1024 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_1024; + } + } else if (size == 2048) { + if ((*fft_filter_1D_array_2048)[1] == 0.F) { + fourn(fft_filter_1D_array, array_lengths, 2, 1); + fft_filter_1D_array /= sqrt(static_cast(size * size)); + *fft_filter_1D_array_2048 = fft_filter_1D_array; + } else { + fft_filter_1D_array = *fft_filter_1D_array_2048; + } + } else { + warning("\nNonseparableSpatiallyVaryingFilters: Cannot do this at the moment -- size is too big'.\n"); + } + + // fourn(fft_filter_1D_array, array_lengths, 3,1); + + // WARNING -- this only works for the FFT where the convention is that the final result + // obtained from the FFT is divided with sqrt(N*N*N) + switch (size) { + case 64: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(64 * 64))); + break; + case 128: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(128 * 128))); + break; + case 256: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(256 * 256))); + break; + case 512: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(512 * 512))); + break; + case 1024: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(1024 * 1024))); + break; + case 2048: + fft_1_1D_array = static_cast(1 / sqrt(static_cast(2048 * 2048))); + break; + + default: + warning("\nNonseparableSpatiallyVaryingFilters: Cannot do this at the moment -- size is too big'.\n"); + ; + break; + } + + // to check the outputs make the fft consistant with mathematica + // divide 1/sqrt(size) + // fft_1_1D_array /= sqrt(static_cast (size *size*size)); + // fft_filter_1D_array /= sqrt(static_cast(size *size*size)); + Array<2, float> new_filter_coefficients_2D_array_tmp( + IndexRange2D(1, filter_coefficients_padded.get_length(), 1, filter_coefficients_padded.get_length())); + + { + Array<1, float> fft_filter_num_1D_array(1, 2 * fft_filter.get_length() * + fft_filter[fft_filter.get_min_index()].get_length()); + // Array<1,float> div_1D_array(1, 2*fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length()); + + // mulitply_complex_arrays(fft_filter_num_1D_array,fft_filter_1D_array,fft_1_1D_array); + + fft_filter_num_1D_array = fft_filter_1D_array * fft_1_1D_array; +# if 0 for ( int i = fft_filter_num_1D_array.get_min_index(); i<=fft_filter_num_1D_array.get_max_index();i++) cerr << fft_filter_num_1D_array[i] << i << " "; -#endif - fft_filter_1D_array *= (sq_kapas-1); - // this is necesssery since the imagainary part is stored in the odd indices - for ( int i = fft_filter_1D_array.get_min_index(); i<=fft_filter_1D_array.get_max_index(); i+=2) - { - fft_filter_1D_array[i] += fft_1_1D_array; - } - fft_filter_1D_array /= sq_kapas; - - divide_complex_arrays(fft_filter_num_1D_array,fft_filter_1D_array); - - fourn(fft_filter_num_1D_array, array_lengths,2,-1); - - // make it consistent with mathemematica -- the output of the - fft_filter_num_1D_array /= sqrt(static_cast(size *size)); - - // take the real part only - /*********************************************************************************/ - { - Array<1,float> real_div_1D_array(1,fft_filter.get_length()*fft_filter[fft_filter.get_min_index()].get_length()); - - for (int i=0;i<=(size*size)-1;i++) - real_div_1D_array[i+1] = fft_filter_num_1D_array[2*i+1]; - - /*********************************************************************************/ - - convert_array_1D_into_2D_array(new_filter_coefficients_2D_array_tmp,real_div_1D_array); - - } - } - -#if 0 +# endif + fft_filter_1D_array *= (sq_kapas - 1); + // this is necesssery since the imagainary part is stored in the odd indices + for (int i = fft_filter_1D_array.get_min_index(); i <= fft_filter_1D_array.get_max_index(); i += 2) { + fft_filter_1D_array[i] += fft_1_1D_array; + } + fft_filter_1D_array /= sq_kapas; + + divide_complex_arrays(fft_filter_num_1D_array, fft_filter_1D_array); + + fourn(fft_filter_num_1D_array, array_lengths, 2, -1); + + // make it consistent with mathemematica -- the output of the + fft_filter_num_1D_array /= sqrt(static_cast(size * size)); + + // take the real part only + /*********************************************************************************/ + { + Array<1, float> real_div_1D_array(1, fft_filter.get_length() * fft_filter[fft_filter.get_min_index()].get_length()); + + for (int i = 0; i <= (size * size) - 1; i++) + real_div_1D_array[i + 1] = fft_filter_num_1D_array[2 * i + 1]; + + /*********************************************************************************/ + + convert_array_1D_into_2D_array(new_filter_coefficients_2D_array_tmp, real_div_1D_array); + } + } + +# if 0 for ( int j = new_filter_coefficients_2D_array_tmp.get_min_index(); j<=new_filter_coefficients_2D_array_tmp.get_max_index();j++) for ( int i = new_filter_coefficients_2D_array_tmp[1].get_min_index(); i<=new_filter_coefficients_2D_array_tmp[1].get_max_index();i++) { cerr << new_filter_coefficients_2D_array_tmp[j][i] << i << " "; } - -#endif - - int kernel_length_x=0; - int kernel_length_y=0; - - // to prevent form aliasing limit the new range for the coefficients to - // filter_coefficients_padded.get_length()/2 - - //cerr << " X DIERCTION NOW" << endl; - // do the x -direction first -- fix y and z to the min and look for the max index in x - int jy = new_filter_coefficients_2D_array_tmp.get_min_index(); - for (int i=new_filter_coefficients_2D_array_tmp[jy].get_min_index();i<=filter_coefficients_padded[jy].get_max_index()/2;i++) - { - if (fabs((double)new_filter_coefficients_2D_array_tmp[jy][i]) - <= new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()][new_filter_coefficients_2D_array_tmp.get_min_index()]*1/1000000) break; - else (kernel_length_x)++; - } - - /******************************* Y DIRECTION ************************************/ - - - int ix = new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()].get_min_index(); - for (int j=new_filter_coefficients_2D_array_tmp.get_min_index();j<=filter_coefficients_padded.get_max_index()/2;j++) - { - if (fabs((double)new_filter_coefficients_2D_array_tmp[j][ix]) - //= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) break; - <= new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()][new_filter_coefficients_2D_array_tmp.get_min_index()]*1/1000000) break; - else (kernel_length_y)++; - } - - - /********************************************************************************/ - - - /********************************************************************************/ - - if (kernel_length_x == filter_coefficients_padded.get_length()/2) - { - warning("NonseparableSpatiallyVaryingFilters: kernel_length_x reached maximum length %d. " - "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" - "Increasing length of FFT array to resolve this problem\n", - kernel_length_x, new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()][new_filter_coefficients_2D_array_tmp.get_min_index()], - new_filter_coefficients_2D_array_tmp[new_filter_coefficients_2D_array_tmp.get_min_index()][kernel_length_x], - kapa0_over_kapa1); - size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]*=2; - for (int i=kapa0_over_kapa1_interval+1; i -NonseparableSpatiallyVaryingFilters:: -NonseparableSpatiallyVaryingFilters() -{ +NonseparableSpatiallyVaryingFilters::NonseparableSpatiallyVaryingFilters() { set_defaults(); } - template -NonseparableSpatiallyVaryingFilters:: -NonseparableSpatiallyVaryingFilters(string proj_data_filename_v, - string attenuation_proj_data_filename_v, - const Array<2,float>& filter_coefficients_v, - shared_ptr proj_data_ptr_v, - shared_ptr attenuation_proj_data_ptr_v, - DiscretisedDensity<3,float>* initial_image_v, - DiscretisedDensity<3,float>* sensitivity_image_v, - DiscretisedDensity<3,float>* precomputed_coefficients_image_v, - DiscretisedDensity<3,float>* normalised_bck_image_v, - int mask_size_v, int num_dim_v) - - +NonseparableSpatiallyVaryingFilters::NonseparableSpatiallyVaryingFilters( + string proj_data_filename_v, string attenuation_proj_data_filename_v, const Array<2, float>& filter_coefficients_v, + shared_ptr proj_data_ptr_v, shared_ptr attenuation_proj_data_ptr_v, + DiscretisedDensity<3, float>* initial_image_v, DiscretisedDensity<3, float>* sensitivity_image_v, + DiscretisedDensity<3, float>* precomputed_coefficients_image_v, DiscretisedDensity<3, float>* normalised_bck_image_v, + int mask_size_v, int num_dim_v) + { - assert(filter_coefficients.get_length() == 0 || - filter_coefficients.begin()==0); - - for (int i = filter_coefficients_v.get_min_index();i<=filter_coefficients_v.get_max_index();i++) + assert(filter_coefficients.get_length() == 0 || filter_coefficients.begin() == 0); + + for (int i = filter_coefficients_v.get_min_index(); i <= filter_coefficients_v.get_max_index(); i++) filter_coefficients[i] = filter_coefficients_v[i]; - proj_data_filename = proj_data_filename_v; + proj_data_filename = proj_data_filename_v; attenuation_proj_data_filename = attenuation_proj_data_filename_v; proj_data_ptr = proj_data_ptr_v; attenuation_proj_data_ptr = attenuation_proj_data_ptr_v; @@ -596,556 +507,446 @@ NonseparableSpatiallyVaryingFilters(string proj_data_filename_v, sensitivity_image = sensitivity_image_v; precomputed_coefficients_image = precomputed_coefficients_image_v; normalised_bck_image = normalised_bck_image_v; - mask_size= mask_size_v; + mask_size = mask_size_v; num_dim = num_dim_v; } - template -Succeeded -NonseparableSpatiallyVaryingFilters:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) -{ - proj_data_ptr = - ProjData::read_from_file( proj_data_filename); - - if (attenuation_proj_data_filename !="1") - attenuation_proj_data_ptr = - ProjData::read_from_file(attenuation_proj_data_filename); - else +Succeeded +NonseparableSpatiallyVaryingFilters::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { + proj_data_ptr = ProjData::read_from_file(proj_data_filename); + + if (attenuation_proj_data_filename != "1") + attenuation_proj_data_ptr = ProjData::read_from_file(attenuation_proj_data_filename); + else attenuation_proj_data_ptr = NULL; - - if (initial_image_filename !="1") - initial_image = - DiscretisedDensity<3,float>::read_from_file(initial_image_filename); - else - initial_image = NULL; - - if (sensitivity_image_filename !="1") - sensitivity_image = - DiscretisedDensity<3,float>::read_from_file(sensitivity_image_filename); - else + + if (initial_image_filename != "1") + initial_image = DiscretisedDensity<3, float>::read_from_file(initial_image_filename); + else + initial_image = NULL; + + if (sensitivity_image_filename != "1") + sensitivity_image = DiscretisedDensity<3, float>::read_from_file(sensitivity_image_filename); + else sensitivity_image = NULL; - - if (precomputed_coefficients_filename !="1") - precomputed_coefficients_image = - DiscretisedDensity<3,float>::read_from_file(precomputed_coefficients_filename); + + if (precomputed_coefficients_filename != "1") + precomputed_coefficients_image = DiscretisedDensity<3, float>::read_from_file(precomputed_coefficients_filename); else - precomputed_coefficients_image =NULL; - - if (normalised_bck_filename !="1") - normalised_bck_image = - DiscretisedDensity<3,float>::read_from_file(normalised_bck_filename); + precomputed_coefficients_image = NULL; + + if (normalised_bck_filename != "1") + normalised_bck_image = DiscretisedDensity<3, float>::read_from_file(normalised_bck_filename); else - normalised_bck_image =NULL; - - - + normalised_bck_image = NULL; + return Succeeded::yes; - } +template +void +NonseparableSpatiallyVaryingFilters::precalculate_filter_coefficients_2D( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const { + VectorWithOffset>> filter_lookup; + const int num_elements_in_interval = 500; + filter_lookup.grow(1, num_elements_in_interval); + const int k_min = 1; + const float k_interval = 0.01F; // 0.01F; + shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); + VoxelsOnCartesianGrid* in_density_cast = dynamic_cast*>(in_density); + + VoxelsOnCartesianGrid* vox_image_ptr_1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); -template -void -NonseparableSpatiallyVaryingFilters::precalculate_filter_coefficients_2D (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const -{ - - VectorWithOffset < shared_ptr > > filter_lookup; - const int num_elements_in_interval = 500; - filter_lookup.grow(1,num_elements_in_interval); - const int k_min =1; - const float k_interval = 0.01F; //0.01F; - - - shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); - VoxelsOnCartesianGrid* in_density_cast = - dynamic_cast< VoxelsOnCartesianGrid* >(in_density); - - - VoxelsOnCartesianGrid * vox_image_ptr_1 = - new VoxelsOnCartesianGrid (IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - int start_segment_num = proj_data_ptr->get_min_segment_num(); int end_segment_num = proj_data_ptr->get_max_segment_num(); - - VectorWithOffset *> all_segments(start_segment_num, end_segment_num); - VectorWithOffset *> all_segments_for_kappa0(start_segment_num, end_segment_num); - VectorWithOffset *> all_attenuation_segments(start_segment_num, end_segment_num); - - + + VectorWithOffset*> all_segments(start_segment_num, end_segment_num); + VectorWithOffset*> all_segments_for_kappa0(start_segment_num, end_segment_num); + VectorWithOffset*> all_attenuation_segments(start_segment_num, end_segment_num); + // first initialise to false bool do_attenuation = false; - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { all_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); all_segments_for_kappa0[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - - if (attenuation_proj_data_filename!="1") - { + + if (attenuation_proj_data_filename != "1") { do_attenuation = true; - all_attenuation_segments[segment_num] = - new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); - } - else - { + all_attenuation_segments[segment_num] = + new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); + } else { do_attenuation = false; - all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); (*all_attenuation_segments[segment_num]).fill(1); } - } - - vox_image_ptr_1->set_origin(Coordinate3D(0,0,0)); - - shared_ptr > image_sptr = vox_image_ptr_1; - - shared_ptr proj_matrix_ptr = - new ProjMatrixByDenselUsingRayTracing; - - proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), - image_sptr); + + vox_image_ptr_1->set_origin(Coordinate3D(0, 0, 0)); + + shared_ptr> image_sptr = vox_image_ptr_1; + + shared_ptr proj_matrix_ptr = new ProjMatrixByDenselUsingRayTracing; + + proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), image_sptr); info(proj_matrix_ptr->parameter_info()); - - fwd_densels_all(all_segments,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - in_density_cast->get_min_y(), in_density_cast->get_max_y(), - in_density_cast->get_min_x(), in_density_cast->get_max_x(), - *in_density); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa0 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa1 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * kappa_coefficients = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - - shared_ptr > kappa0_ptr_bck = vox_image_ptr_kappa0; - shared_ptr > kappa1_ptr_bck = vox_image_ptr_kappa1; - + + fwd_densels_all(all_segments, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), in_density_cast->get_max_z(), + in_density_cast->get_min_y(), in_density_cast->get_max_y(), in_density_cast->get_min_x(), + in_density_cast->get_max_x(), *in_density); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa0 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* kappa_coefficients = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + shared_ptr> kappa0_ptr_bck = vox_image_ptr_kappa0; + shared_ptr> kappa1_ptr_bck = vox_image_ptr_kappa1; + // WARNING - find a way of finding max in the sinogram // TODO - include other segments as well - float max_in_viewgram =0.F; - - for (int segment_num = start_segment_num; segment_num<= end_segment_num; segment_num++) - { - SegmentByView segment_by_view = - proj_data_ptr->get_segment_by_view(segment_num); + float max_in_viewgram = 0.F; + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; segment_num++) { + SegmentByView segment_by_view = proj_data_ptr->get_segment_by_view(segment_num); const float current_max_in_viewgram = segment_by_view.find_max(); - if ( current_max_in_viewgram >= max_in_viewgram) - max_in_viewgram = current_max_in_viewgram ; + if (current_max_in_viewgram >= max_in_viewgram) + max_in_viewgram = current_max_in_viewgram; else continue; } - const float threshold = 0.0001F*max_in_viewgram; - + const float threshold = 0.0001F * max_in_viewgram; + info(boost::format(" THRESHOLD IS %1%") % threshold); - - find_inverse_and_bck_densels(*kappa1_ptr_bck,all_segments, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - vox_image_ptr_kappa1->get_min_y(),vox_image_ptr_kappa1->get_max_y(), - vox_image_ptr_kappa1->get_min_x(),vox_image_ptr_kappa1->get_max_x(), - *proj_matrix_ptr, do_attenuation,threshold, false); //true); - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + + find_inverse_and_bck_densels(*kappa1_ptr_bck, all_segments, all_attenuation_segments, vox_image_ptr_kappa1->get_min_z(), + vox_image_ptr_kappa1->get_max_z(), vox_image_ptr_kappa1->get_min_y(), + vox_image_ptr_kappa1->get_max_y(), vox_image_ptr_kappa1->get_min_x(), + vox_image_ptr_kappa1->get_max_x(), *proj_matrix_ptr, do_attenuation, threshold, false); // true); + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { delete all_segments[segment_num]; delete all_attenuation_segments[segment_num]; - } - + } + info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); - - for (int k=in_density_cast->get_min_z();k<=in_density_cast->get_max_z();k++) - for (int j =in_density_cast->get_min_y();j<=in_density_cast->get_max_y();j++) - for (int i =in_density_cast->get_min_x();i<=in_density_cast->get_max_x();i++) - { - - // WARNING - only works for segment zero at the moment - // do the calculation of kappa0 here - kappa0_ptr_bck->fill(0); - for (int segment_num = start_segment_num; - segment_num <= end_segment_num; ++segment_num) - { - (*all_segments_for_kappa0[segment_num]).fill(0); - } - if (true) //attenuation_proj_data_filename !="1") - { - -#if 1 - shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid - (IndexRange3D(k,k, - //-mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), - // mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - /*shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid(IndexRange3D(k,k, - //-mask_size+k,mask_size+k, - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); */ - CPUTimer timer; - timer.start(); - - // SM 23/05/2002 mask now 3D - //const int min_k = in_density_cast->get_min_z(); //max(in_density_cast->get_min_z(),k-mask_size); - //const int max_k = in_density_cast->get_max_z(); // min(in_density_cast->get_max_z(),k+mask_size); - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - // the mask size is in 2D only - // SM mask now 3D - //for (int k_in =min_k;k_in<=max_k;k_in++) - for (int j_in =min_j;j_in<=max_j;j_in++) - for (int i_in =min_i;i_in<=max_i;i_in++) - { - (*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; - //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; - } - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast_tmp->get_min_z(), in_density_cast_tmp->get_max_z(), - in_density_cast_tmp->get_min_y(),in_density_cast_tmp->get_max_y(), - in_density_cast_tmp->get_min_x(),in_density_cast_tmp->get_max_x(), - *in_density_cast_tmp); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - k,k, - //(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2,ceil((vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z())/2), - //0,0,0,0, - 6,6,6,6, - *proj_matrix_ptr,false,threshold, false) ;//true); - //(*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2][6][6]; - (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; - - timer.stop(); - //cerr << "kappa0 time "<< timer.value() << endl; - } - else - { - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - min_j,max_j, - min_i,max_i, - //j-2,j+2, - //i-2,i+2, - *in_density_cast); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - j,j,i,i, - *proj_matrix_ptr,false,threshold, true); - - } - float sq_kapas; - // float multiply_with_sensitivity; - if ( fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && - fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001 ) - { - sq_kapas =((*kappa0_ptr_bck)[k][j][i]*(*kappa0_ptr_bck)[k][j][i])/((*kappa1_ptr_bck)[k][j][i]*(*kappa1_ptr_bck)[k][j][i]); - -#else - float sq_kapas = 1.0F; -#endif - (*kappa_coefficients)[k][j][i] = sq_kapas; - - //cerr << " now printing sq_kappas value:" << " " << sq_kapas << endl; - int k_index ; - k_index = round(((float)sq_kapas- k_min)/k_interval); - if (k_index < 1) - {k_index = 1;} - - if ( k_index > num_elements_in_interval) - { k_index = num_elements_in_interval;} - - - if ( filter_lookup[k_index]==NULL ) - { - Array <2,float> new_coeffs; + + for (int k = in_density_cast->get_min_z(); k <= in_density_cast->get_max_z(); k++) + for (int j = in_density_cast->get_min_y(); j <= in_density_cast->get_max_y(); j++) + for (int i = in_density_cast->get_min_x(); i <= in_density_cast->get_max_x(); i++) { + + // WARNING - only works for segment zero at the moment + // do the calculation of kappa0 here + kappa0_ptr_bck->fill(0); + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + (*all_segments_for_kappa0[segment_num]).fill(0); + } + if (true) // attenuation_proj_data_filename !="1") + { + +# if 1 + shared_ptr> in_density_cast_tmp = new VoxelsOnCartesianGrid( + IndexRange3D(k, k, + //-mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), + // mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), + -mask_size + 6, mask_size + 6, -mask_size + 6, mask_size + 6), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + /*shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = + new VoxelsOnCartesianGrid(IndexRange3D(k,k, + //-mask_size+k,mask_size+k, + -mask_size+6,mask_size+6, + -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); */ + CPUTimer timer; + timer.start(); + + // SM 23/05/2002 mask now 3D + // const int min_k = in_density_cast->get_min_z(); //max(in_density_cast->get_min_z(),k-mask_size); + // const int max_k = in_density_cast->get_max_z(); // min(in_density_cast->get_max_z(),k+mask_size); + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + // the mask size is in 2D only + // SM mask now 3D + // for (int k_in =min_k;k_in<=max_k;k_in++) + for (int j_in = min_j; j_in <= max_j; j_in++) + for (int i_in = min_i; i_in <= max_i; i_in++) { + (*in_density_cast_tmp)[k][j_in - j + 6][i_in - i + 6] = (*in_density_cast)[k][j_in][i_in]; + //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; + } + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast_tmp->get_min_z(), + in_density_cast_tmp->get_max_z(), in_density_cast_tmp->get_min_y(), in_density_cast_tmp->get_max_y(), + in_density_cast_tmp->get_min_x(), in_density_cast_tmp->get_max_x(), *in_density_cast_tmp); + + find_inverse_and_bck_densels( + *kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, k, k, + //(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2,ceil((vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z())/2), + // 0,0,0,0, + 6, 6, 6, 6, *proj_matrix_ptr, false, threshold, false); // true); + //(*kappa0_ptr_bck)[k][j][i] = + //(*kappa0_ptr_bck)[(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2][6][6]; + (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; + + timer.stop(); + // cerr << "kappa0 time "<< timer.value() << endl; + } else { + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), + in_density_cast->get_max_z(), min_j, max_j, min_i, max_i, + // j-2,j+2, + // i-2,i+2, + *in_density_cast); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + vox_image_ptr_kappa1->get_min_z(), vox_image_ptr_kappa1->get_max_z(), j, j, i, i, + *proj_matrix_ptr, false, threshold, true); + } + float sq_kapas; + // float multiply_with_sensitivity; + if (fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && + fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001) { + sq_kapas = ((*kappa0_ptr_bck)[k][j][i] * (*kappa0_ptr_bck)[k][j][i]) / + ((*kappa1_ptr_bck)[k][j][i] * (*kappa1_ptr_bck)[k][j][i]); + +# else + float sq_kapas = 1.0F; +# endif + (*kappa_coefficients)[k][j][i] = sq_kapas; + + // cerr << " now printing sq_kappas value:" << " " << sq_kapas << endl; + int k_index; + k_index = round(((float)sq_kapas - k_min) / k_interval); + if (k_index < 1) { + k_index = 1; + } + + if (k_index > num_elements_in_interval) { + k_index = num_elements_in_interval; + } + + if (filter_lookup[k_index] == NULL) { + Array<2, float> new_coeffs; info(boost::format("computing new filter for sq_kappas %1% at index %2%") % sq_kapas % k_index); - construct_scaled_filter_coefficients_2D(new_coeffs, filter_coefficients,sq_kapas, number_of_coefficients_before_padding); - filter_lookup[k_index] = new ArrayFilter2DUsingConvolution(new_coeffs); - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - - } - else - { - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - - } - - } - else - { - - - all_filter_coefficients[k][j][i] = - new ArrayFilter2DUsingConvolution(); - - } - - } - delete kappa_coefficients ; - - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - delete all_segments_for_kappa0[segment_num]; + construct_scaled_filter_coefficients_2D(new_coeffs, filter_coefficients, sq_kapas, + number_of_coefficients_before_padding); + filter_lookup[k_index] = new ArrayFilter2DUsingConvolution(new_coeffs); + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + + } else { + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + } + + } else { + + all_filter_coefficients[k][j][i] = new ArrayFilter2DUsingConvolution(); + } } - - - -} + delete kappa_coefficients; + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + delete all_segments_for_kappa0[segment_num]; + } +} // densel stuff - > apply -#if 1 +# if 1 template void -NonseparableSpatiallyVaryingFilters:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, const DiscretisedDensity<3,elemT>& in_density) const -{ +NonseparableSpatiallyVaryingFilters::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { - //the first time virtual_apply is called for this object, counter is set to 0 - static int count=0; + // the first time virtual_apply is called for this object, counter is set to 0 + static int count = 0; // every time it's called, counter is incremented count++; info(boost::format(" checking the counter %1%") % count); - - const VoxelsOnCartesianGrid& in_density_cast_0 = - dynamic_cast< const VoxelsOnCartesianGrid& >(in_density); - - // the first set is defined for 2d separable case and the second for 3d case -- - // depending weather it is 2d or 3d corresponding coefficints are used. - static VectorWithOffset < VectorWithOffset < VectorWithOffset > > > > all_filter_coefficients_nonseparable_2D; - - if (initial_image_filename!="1") - { - if (count ==1) - { - all_filter_coefficients_nonseparable_2D.grow(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z()); - for (int k = in_density_cast_0.get_min_z(); k<=in_density_cast_0.get_max_z();k++) - { - all_filter_coefficients_nonseparable_2D[k].grow(in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y()); - for (int j = in_density_cast_0.get_min_y(); j<=in_density_cast_0.get_max_y();j++) - { - (all_filter_coefficients_nonseparable_2D[k])[j].grow(in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()); - } - } - - if ( precomputed_coefficients_filename!="1") - { - VoxelsOnCartesianGrid* precomputed_coefficients_image_cast = - dynamic_cast< VoxelsOnCartesianGrid* >(precomputed_coefficients_image); - info(" In here nonseparable"); - for ( int k = precomputed_coefficients_image_cast->get_min_z(); k<=precomputed_coefficients_image_cast->get_max_z();k++) - for ( int j = precomputed_coefficients_image_cast->get_min_y(); j<=precomputed_coefficients_image_cast->get_max_y();j++) - for ( int i = precomputed_coefficients_image_cast->get_min_x(); i<=precomputed_coefficients_image_cast->get_max_x();i++) - { - Array <2,float> new_coeffs; - if((*precomputed_coefficients_image)[k][j][i] >0.00001 ) - { - construct_scaled_filter_coefficients_2D(new_coeffs,filter_coefficients,1/(*precomputed_coefficients_image)[k][j][i], number_of_coefficients_before_padding); - all_filter_coefficients_nonseparable_2D[k][j][i] = - new ArrayFilter2DUsingConvolution(new_coeffs); - } - else - { - all_filter_coefficients_nonseparable_2D[k][j][i] = - new ArrayFilter2DUsingConvolution(); - - } - - - } + + const VoxelsOnCartesianGrid& in_density_cast_0 = dynamic_cast&>(in_density); + + // the first set is defined for 2d separable case and the second for 3d case -- + // depending weather it is 2d or 3d corresponding coefficints are used. + static VectorWithOffset>>>> + all_filter_coefficients_nonseparable_2D; + + if (initial_image_filename != "1") { + if (count == 1) { + all_filter_coefficients_nonseparable_2D.grow(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z()); + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) { + all_filter_coefficients_nonseparable_2D[k].grow(in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y()); + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) { + (all_filter_coefficients_nonseparable_2D[k])[j].grow(in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()); + } } - else - precalculate_filter_coefficients_2D(all_filter_coefficients_nonseparable_2D,initial_image); - - + + if (precomputed_coefficients_filename != "1") { + VoxelsOnCartesianGrid* precomputed_coefficients_image_cast = + dynamic_cast*>(precomputed_coefficients_image); + info(" In here nonseparable"); + for (int k = precomputed_coefficients_image_cast->get_min_z(); k <= precomputed_coefficients_image_cast->get_max_z(); k++) + for (int j = precomputed_coefficients_image_cast->get_min_y(); j <= precomputed_coefficients_image_cast->get_max_y(); + j++) + for (int i = precomputed_coefficients_image_cast->get_min_x(); i <= precomputed_coefficients_image_cast->get_max_x(); + i++) { + Array<2, float> new_coeffs; + if ((*precomputed_coefficients_image)[k][j][i] > 0.00001) { + construct_scaled_filter_coefficients_2D(new_coeffs, filter_coefficients, + 1 / (*precomputed_coefficients_image)[k][j][i], + number_of_coefficients_before_padding); + all_filter_coefficients_nonseparable_2D[k][j][i] = new ArrayFilter2DUsingConvolution(new_coeffs); + } else { + all_filter_coefficients_nonseparable_2D[k][j][i] = new ArrayFilter2DUsingConvolution(); + } + } + } else + precalculate_filter_coefficients_2D(all_filter_coefficients_nonseparable_2D, initial_image); } - + + } else // for initial image + { } - else // for initial image - {} - - for (int k=in_density_cast_0.get_min_z();k<=in_density_cast_0.get_max_z();k++) - for (int j =in_density_cast_0.get_min_y();j<=in_density_cast_0.get_max_y();j++) - for (int i =in_density_cast_0.get_min_x();i<=in_density_cast_0.get_max_x();i++) - { - Array<3,elemT> tmp_out(IndexRange3D(k,k,j,j,i,i)); - Array<2,elemT> single_pixel(IndexRange2D(j,j,i,i)); - if ( k==in_density_cast_0.get_min_z() && j==in_density_cast_0.get_min_y() - && i==in_density_cast_0.get_min_x() && count == 300 && precomputed_coefficients_filename!="1" - && normalised_bck_filename !="1") - - { - info(boost::format(" IN the LOOP %1% %2% %3% ") % k % j % i); - for (int k=in_density_cast_0.get_min_z();k<=in_density_cast_0.get_max_z();k++) - for (int j =in_density_cast_0.get_min_y();j<=in_density_cast_0.get_max_y();j++) - for (int i =in_density_cast_0.get_min_x();i<=in_density_cast_0.get_max_x();i++) - { - Array <2,float> new_coeffs; - if(in_density_cast_0[k][j][i] >0.00001 ) - { - VoxelsOnCartesianGrid * newly_computed_coeff = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z(), - in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y(), - in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()), - in_density.get_origin(),in_density_cast_0.get_voxel_size()); - - VoxelsOnCartesianGrid * normalised_bck_image_cast = - dynamic_cast< VoxelsOnCartesianGrid * > (normalised_bck_image); - VoxelsOnCartesianGrid * sensitivity_image_cast = - dynamic_cast< VoxelsOnCartesianGrid * > (sensitivity_image); - - - precompute_filter_coefficients_for_second_apporach(*newly_computed_coeff, - in_density_cast_0, - *sensitivity_image_cast, - *normalised_bck_image_cast); - construct_scaled_filter_coefficients_2D(new_coeffs,filter_coefficients,1/(*newly_computed_coeff)[k][j][i], number_of_coefficients_before_padding); - all_filter_coefficients_nonseparable_2D[k][j][i] = - new ArrayFilter2DUsingConvolution(new_coeffs); - delete newly_computed_coeff; - } - - } - } - (*all_filter_coefficients_nonseparable_2D[k][j][i])(single_pixel,in_density[k]); - out_density[k][j][i] = single_pixel[j][i]; - } - - } -#endif - - - - template - void - NonseparableSpatiallyVaryingFilters:: - virtual_apply(DiscretisedDensity<3,elemT>& density) const - { - DiscretisedDensity<3,elemT>* tmp_density = - density.clone(); - virtual_apply(density, *tmp_density); - delete tmp_density; - } - - - template - void - NonseparableSpatiallyVaryingFilters::set_defaults() - { - filter_coefficients.fill(0); - proj_data_filename ="1"; - proj_data_ptr = NULL; - attenuation_proj_data_filename ="1"; - initial_image_filename ="1"; - initial_image =NULL; - sensitivity_image_filename ='1'; - sensitivity_image = NULL; - precomputed_coefficients_filename ='1'; - normalised_bck_filename ='1'; - normalised_bck_image =NULL; - precomputed_coefficients_image =NULL; - attenuation_proj_data_ptr = NULL; - mask_size = 0; - num_dim = 1; - number_of_coefficients_before_padding =0; - - } - - template - void - NonseparableSpatiallyVaryingFilters:: initialise_keymap() - { - parser.add_start_key("Nonseparable Spatially Varying Filters"); - parser.add_key("filter_coefficients", &filter_coefficients_for_parsing); - parser.add_key("proj_data_filename", &proj_data_filename); - parser.add_key("attenuation_proj_data_filename", &attenuation_proj_data_filename); - parser.add_key("initial_image_filename", &initial_image_filename); - parser.add_key("sensitivity_image_filename", &sensitivity_image_filename); - parser.add_key("mask_size", &mask_size); - parser.add_key("num_dim", & num_dim); - parser.add_key ("precomputed_coefficients_filename", &precomputed_coefficients_filename); - parser.add_key ("normalised_bck_filename", &normalised_bck_filename); - parser.add_key("number of coefficients before padding", &number_of_coefficients_before_padding); - parser.add_stop_key("END Nonseparable Spatially Varying Filters"); - } - + + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + Array<3, elemT> tmp_out(IndexRange3D(k, k, j, j, i, i)); + Array<2, elemT> single_pixel(IndexRange2D(j, j, i, i)); + if (k == in_density_cast_0.get_min_z() && j == in_density_cast_0.get_min_y() && i == in_density_cast_0.get_min_x() && + count == 300 && precomputed_coefficients_filename != "1" && normalised_bck_filename != "1") + + { + info(boost::format(" IN the LOOP %1% %2% %3% ") % k % j % i); + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + Array<2, float> new_coeffs; + if (in_density_cast_0[k][j][i] > 0.00001) { + VoxelsOnCartesianGrid* newly_computed_coeff = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z(), in_density_cast_0.get_min_y(), + in_density_cast_0.get_max_y(), in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()), + in_density.get_origin(), in_density_cast_0.get_voxel_size()); + + VoxelsOnCartesianGrid* normalised_bck_image_cast = + dynamic_cast*>(normalised_bck_image); + VoxelsOnCartesianGrid* sensitivity_image_cast = + dynamic_cast*>(sensitivity_image); + + precompute_filter_coefficients_for_second_apporach(*newly_computed_coeff, in_density_cast_0, + *sensitivity_image_cast, *normalised_bck_image_cast); + construct_scaled_filter_coefficients_2D(new_coeffs, filter_coefficients, 1 / (*newly_computed_coeff)[k][j][i], + number_of_coefficients_before_padding); + all_filter_coefficients_nonseparable_2D[k][j][i] = new ArrayFilter2DUsingConvolution(new_coeffs); + delete newly_computed_coeff; + } + } + } + (*all_filter_coefficients_nonseparable_2D[k][j][i])(single_pixel, in_density[k]); + out_density[k][j][i] = single_pixel[j][i]; + } +} +# endif + template -bool -NonseparableSpatiallyVaryingFilters:: -post_processing() -{ - const unsigned int size_x = filter_coefficients_for_parsing[1].get_length(); - const unsigned int size_y = filter_coefficients_for_parsing.get_length(); +void +NonseparableSpatiallyVaryingFilters::virtual_apply(DiscretisedDensity<3, elemT>& density) const { + DiscretisedDensity<3, elemT>* tmp_density = density.clone(); + virtual_apply(density, *tmp_density); + delete tmp_density; +} - const int min_index_y = -(size_y/2); - const int min_index_x = -(size_x/2); - filter_coefficients.grow(IndexRange2D(min_index_y, min_index_y + size_y - 1, - min_index_x, min_index_x + size_x - 1 )); +template +void +NonseparableSpatiallyVaryingFilters::set_defaults() { + filter_coefficients.fill(0); + proj_data_filename = "1"; + proj_data_ptr = NULL; + attenuation_proj_data_filename = "1"; + initial_image_filename = "1"; + initial_image = NULL; + sensitivity_image_filename = '1'; + sensitivity_image = NULL; + precomputed_coefficients_filename = '1'; + normalised_bck_filename = '1'; + normalised_bck_image = NULL; + precomputed_coefficients_image = NULL; + attenuation_proj_data_ptr = NULL; + mask_size = 0; + num_dim = 1; + number_of_coefficients_before_padding = 0; +} - for (int j = min_index_y; j<=filter_coefficients.get_max_index(); ++j) - for (int i = min_index_x; i<= filter_coefficients[j].get_max_index(); ++i) - { - filter_coefficients[j][i] = - static_cast(filter_coefficients_for_parsing[j-min_index_y][i-min_index_x]); +template +void +NonseparableSpatiallyVaryingFilters::initialise_keymap() { + parser.add_start_key("Nonseparable Spatially Varying Filters"); + parser.add_key("filter_coefficients", &filter_coefficients_for_parsing); + parser.add_key("proj_data_filename", &proj_data_filename); + parser.add_key("attenuation_proj_data_filename", &attenuation_proj_data_filename); + parser.add_key("initial_image_filename", &initial_image_filename); + parser.add_key("sensitivity_image_filename", &sensitivity_image_filename); + parser.add_key("mask_size", &mask_size); + parser.add_key("num_dim", &num_dim); + parser.add_key("precomputed_coefficients_filename", &precomputed_coefficients_filename); + parser.add_key("normalised_bck_filename", &normalised_bck_filename); + parser.add_key("number of coefficients before padding", &number_of_coefficients_before_padding); + parser.add_stop_key("END Nonseparable Spatially Varying Filters"); +} + +template +bool +NonseparableSpatiallyVaryingFilters::post_processing() { + const unsigned int size_x = filter_coefficients_for_parsing[1].get_length(); + const unsigned int size_y = filter_coefficients_for_parsing.get_length(); + + const int min_index_y = -(size_y / 2); + const int min_index_x = -(size_x / 2); + filter_coefficients.grow(IndexRange2D(min_index_y, min_index_y + size_y - 1, min_index_x, min_index_x + size_x - 1)); + + for (int j = min_index_y; j <= filter_coefficients.get_max_index(); ++j) + for (int i = min_index_x; i <= filter_coefficients[j].get_max_index(); ++i) { + filter_coefficients[j][i] = static_cast(filter_coefficients_for_parsing[j - min_index_y][i - min_index_x]); } -return false; + return false; } - - -const char * const -NonseparableSpatiallyVaryingFilters::registered_name = -"Nonseparable Spatially Varying Filters"; - - + +const char* const NonseparableSpatiallyVaryingFilters::registered_name = "Nonseparable Spatially Varying Filters"; + # ifdef _MSC_VER - // prevent warning message on reinstantiation, - // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) +// prevent warning message on reinstantiation, +// note that we get a linking error if we don't have the explicit instantiation below +# pragma warning(disable : 4660) # endif - - // Register this class in the ImageProcessor registry - // static SeparableCartesianMetzImageFilter::RegisterIt dummy; - // have the above variable in a separate file, which you need t - - template NonseparableSpatiallyVaryingFilters; - - - - END_NAMESPACE_STIR - + +// Register this class in the ImageProcessor registry +// static SeparableCartesianMetzImageFilter::RegisterIt dummy; +// have the above variable in a separate file, which you need t + +template NonseparableSpatiallyVaryingFilters; + +END_NAMESPACE_STIR + #endif diff --git a/src/experimental/buildblock/NonseparableSpatiallyVaryingFilters3D.cxx b/src/experimental/buildblock/NonseparableSpatiallyVaryingFilters3D.cxx index bb5395e662..c7571101ac 100644 --- a/src/experimental/buildblock/NonseparableSpatiallyVaryingFilters3D.cxx +++ b/src/experimental/buildblock/NonseparableSpatiallyVaryingFilters3D.cxx @@ -4,10 +4,10 @@ \file \ingroup buildblock \brief Implementations for class NonseparableSpatiallyVaryingFilters3D - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2003, IRSL @@ -45,136 +45,119 @@ using std::map; #include "stir_experimental/local_helping_functions.h" #include "stir_experimental/fwd_and_bck_manipulation_for_SAF.h" - - START_NAMESPACE_STIR -void -construct_scaled_filter_coefficients_3D(Array<3,float> &new_filter_coefficients_2D_array, - Array<3,float>& kernel_3d,const float kapa0_over_kapa1); - +void construct_scaled_filter_coefficients_3D(Array<3, float>& new_filter_coefficients_2D_array, Array<3, float>& kernel_3d, + const float kapa0_over_kapa1); //// IMPLEMENTATION ///// /**********************************************************************************************/ void -construct_scaled_filter_coefficients_3D(Array<3,float> &new_filter_coefficients_3D_array, - Array<3,float>& kernel_3d,const float kapa0_over_kapa1) -{ +construct_scaled_filter_coefficients_3D(Array<3, float>& new_filter_coefficients_3D_array, Array<3, float>& kernel_3d, + const float kapa0_over_kapa1) { /**************************************************************************************/ - if (kapa0_over_kapa1!=0) - { - // in the case where sq_kappas=1 --- scaled_filter == original template filter - Array<3,float> filter_coefficients(IndexRange3D(kernel_3d.get_min_index(), kernel_3d.get_max_index(), - kernel_3d[0].get_min_index(), kernel_3d[0].get_max_index(), - kernel_3d[0][0].get_min_index(), kernel_3d[0][0].get_max_index())); - + if (kapa0_over_kapa1 != 0) { + // in the case where sq_kappas=1 --- scaled_filter == original template filter + Array<3, float> filter_coefficients(IndexRange3D(kernel_3d.get_min_index(), kernel_3d.get_max_index(), + kernel_3d[0].get_min_index(), kernel_3d[0].get_max_index(), + kernel_3d[0][0].get_min_index(), kernel_3d[0][0].get_max_index())); + filter_coefficients = kernel_3d; - const int length_of_size_array = 16; - const float kapa0_over_kapa1_interval_size=10.F; - static VectorWithOffset size_for_kapa0_over_kapa1; - if (size_for_kapa0_over_kapa1.get_length()==0) - { - size_for_kapa0_over_kapa1.grow(0,length_of_size_array-1); - size_for_kapa0_over_kapa1.fill(64); - } - - - float sq_kapas = kapa0_over_kapa1; - /******************************************************************************************/ - - if ( sq_kapas > 10000) - { - new_filter_coefficients_3D_array.grow(IndexRange3D(0,0,0,0,0,0)); - new_filter_coefficients_3D_array.fill(1); - } - else if (sq_kapas!=1.F) - { - const int kapa0_over_kapa1_interval = - min(static_cast(floor(kapa0_over_kapa1/kapa0_over_kapa1_interval_size)), - length_of_size_array-1); + const int length_of_size_array = 16; + const float kapa0_over_kapa1_interval_size = 10.F; + static VectorWithOffset size_for_kapa0_over_kapa1; + if (size_for_kapa0_over_kapa1.get_length() == 0) { + size_for_kapa0_over_kapa1.grow(0, length_of_size_array - 1); + size_for_kapa0_over_kapa1.fill(64); + } - while(true) - { - const int size = size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]; - const int size_z = kernel_3d.get_length()==1 ? 1 : size; - const int size_y = size; - const int size_x = size; - - info(boost::format("Now doing size %1%") % size); - - float inverse_sq_kapas; - if (fabs((double)sq_kapas ) >0.000000000001) - inverse_sq_kapas = 1/sq_kapas; - else - inverse_sq_kapas = 0; - - static Array<1,float> fft_filter_1D_array_64(1,2*(size_z==1?1:64)*64*64); - static Array<1,float> fft_filter_1D_array_128(1,2*(size_z==1?1:128)*128*128); - static Array<1,float> fft_filter_1D_array_256(1,2*(size_z==1?1:256)*256*256); - //static Array<1,float> fft_filter_1D_array_512(1,2*(size_z==1?1:512)*512*512); - - Array<1,float>* fft_filter_1D_array_ptr = 0; - switch (size) - { - case 64: - fft_filter_1D_array_ptr = &fft_filter_1D_array_64; - break; - case 128: - fft_filter_1D_array_ptr = &fft_filter_1D_array_128; - break; - case 256: - fft_filter_1D_array_ptr = &fft_filter_1D_array_256; - break; - //case 512: - //fft_filter_1D_array_ptr = &fft_filter_1D_array_512; - //break; - default: - error("\nNonseparableSpatiallyVaryingFilters3D: Cannot do this at the moment -- size is too big'.\n"); - break; - } - Array<1,float>& fft_filter_1D_array = *fft_filter_1D_array_ptr; - - Array<1, int> array_lengths(1,3); - array_lengths[1] = size_z; - array_lengths[2] = size_y; - array_lengths[3] = size_x; - - if ( fft_filter_1D_array[1] == 0.F) - { - // we have to compute it - // FIRST PADD 1D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC - // ( DO NOT TAKE IMAGINARY PART INTO ACCOUNT YET) - /**********************************************************************************/ - - Array<3,float> filter_coefficients_padded_3D_array(IndexRange3D(1,size_z,1,size_y,1,size_x)); - - // here do the padding - const int min_kernel_3d_z = kernel_3d.get_min_index(); - const int min_kernel_3d_y = kernel_3d[min_kernel_3d_z].get_min_index(); - const int min_kernel_3d_x = kernel_3d[min_kernel_3d_z][min_kernel_3d_y].get_min_index(); - const int oldsize_z = kernel_3d.get_length(); - const int oldsize_y = kernel_3d[min_kernel_3d_z].get_length(); - const int oldsize_x = kernel_3d[min_kernel_3d_z][min_kernel_3d_y].get_length(); - - const int max_kernel_3d_z= kernel_3d.get_max_index()-min_kernel_3d_z; - const int max_kernel_3d_y= kernel_3d[min_kernel_3d_z].get_max_index()-min_kernel_3d_y; - const int max_kernel_3d_x= kernel_3d[min_kernel_3d_z][min_kernel_3d_y].get_max_index()-min_kernel_3d_x; - for ( int k = -(oldsize_z/2);k<=-(oldsize_z/2)+oldsize_z-1;k++) - for ( int j = -(oldsize_y/2);j<=-(oldsize_y/2)+oldsize_y-1;j++) - for ( int i = -(oldsize_x/2);i<=-(oldsize_x/2)+oldsize_x-1;i++) - { - const int newk= k>=0 ? k : size_z+k; - const int newj= j>=0 ? j : size_y+j; - const int newi= i>=0 ? i : size_x+i; - const int oldk= k>=0 ? k : oldsize_z+k; - const int oldj= j>=0 ? j : oldsize_y+j; - const int oldi= i>=0 ? i : oldsize_x+i; - filter_coefficients_padded_3D_array[newk+1][newj+1][newi+1] = - kernel_3d[oldk+min_kernel_3d_z][oldj+min_kernel_3d_y][oldi+min_kernel_3d_x]; - - } + float sq_kapas = kapa0_over_kapa1; + /******************************************************************************************/ + + if (sq_kapas > 10000) { + new_filter_coefficients_3D_array.grow(IndexRange3D(0, 0, 0, 0, 0, 0)); + new_filter_coefficients_3D_array.fill(1); + } else if (sq_kapas != 1.F) { + const int kapa0_over_kapa1_interval = + min(static_cast(floor(kapa0_over_kapa1 / kapa0_over_kapa1_interval_size)), length_of_size_array - 1); + + while (true) { + const int size = size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]; + const int size_z = kernel_3d.get_length() == 1 ? 1 : size; + const int size_y = size; + const int size_x = size; + + info(boost::format("Now doing size %1%") % size); + + float inverse_sq_kapas; + if (fabs((double)sq_kapas) > 0.000000000001) + inverse_sq_kapas = 1 / sq_kapas; + else + inverse_sq_kapas = 0; + + static Array<1, float> fft_filter_1D_array_64(1, 2 * (size_z == 1 ? 1 : 64) * 64 * 64); + static Array<1, float> fft_filter_1D_array_128(1, 2 * (size_z == 1 ? 1 : 128) * 128 * 128); + static Array<1, float> fft_filter_1D_array_256(1, 2 * (size_z == 1 ? 1 : 256) * 256 * 256); + // static Array<1,float> fft_filter_1D_array_512(1,2*(size_z==1?1:512)*512*512); + + Array<1, float>* fft_filter_1D_array_ptr = 0; + switch (size) { + case 64: + fft_filter_1D_array_ptr = &fft_filter_1D_array_64; + break; + case 128: + fft_filter_1D_array_ptr = &fft_filter_1D_array_128; + break; + case 256: + fft_filter_1D_array_ptr = &fft_filter_1D_array_256; + break; + // case 512: + // fft_filter_1D_array_ptr = &fft_filter_1D_array_512; + // break; + default: + error("\nNonseparableSpatiallyVaryingFilters3D: Cannot do this at the moment -- size is too big'.\n"); + break; + } + Array<1, float>& fft_filter_1D_array = *fft_filter_1D_array_ptr; + + Array<1, int> array_lengths(1, 3); + array_lengths[1] = size_z; + array_lengths[2] = size_y; + array_lengths[3] = size_x; + + if (fft_filter_1D_array[1] == 0.F) { + // we have to compute it + // FIRST PADD 1D FILTER COEFFICIENTS AND MAKE THEM SYMMETRIC + // ( DO NOT TAKE IMAGINARY PART INTO ACCOUNT YET) + /**********************************************************************************/ + + Array<3, float> filter_coefficients_padded_3D_array(IndexRange3D(1, size_z, 1, size_y, 1, size_x)); + + // here do the padding + const int min_kernel_3d_z = kernel_3d.get_min_index(); + const int min_kernel_3d_y = kernel_3d[min_kernel_3d_z].get_min_index(); + const int min_kernel_3d_x = kernel_3d[min_kernel_3d_z][min_kernel_3d_y].get_min_index(); + const int oldsize_z = kernel_3d.get_length(); + const int oldsize_y = kernel_3d[min_kernel_3d_z].get_length(); + const int oldsize_x = kernel_3d[min_kernel_3d_z][min_kernel_3d_y].get_length(); + + const int max_kernel_3d_z = kernel_3d.get_max_index() - min_kernel_3d_z; + const int max_kernel_3d_y = kernel_3d[min_kernel_3d_z].get_max_index() - min_kernel_3d_y; + const int max_kernel_3d_x = kernel_3d[min_kernel_3d_z][min_kernel_3d_y].get_max_index() - min_kernel_3d_x; + for (int k = -(oldsize_z / 2); k <= -(oldsize_z / 2) + oldsize_z - 1; k++) + for (int j = -(oldsize_y / 2); j <= -(oldsize_y / 2) + oldsize_y - 1; j++) + for (int i = -(oldsize_x / 2); i <= -(oldsize_x / 2) + oldsize_x - 1; i++) { + const int newk = k >= 0 ? k : size_z + k; + const int newj = j >= 0 ? j : size_y + j; + const int newi = i >= 0 ? i : size_x + i; + const int oldk = k >= 0 ? k : oldsize_z + k; + const int oldj = j >= 0 ? j : oldsize_y + j; + const int oldi = i >= 0 ? i : oldsize_x + i; + filter_coefficients_padded_3D_array[newk + 1][newj + 1][newi + 1] = + kernel_3d[oldk + min_kernel_3d_z][oldj + min_kernel_3d_y][oldi + min_kernel_3d_x]; + } #if 0 for ( int k = 1; k<=size_z;k++) { @@ -189,226 +172,239 @@ construct_scaled_filter_coefficients_3D(Array<3,float> &new_filter_coefficients_ cerr << endl; } cerr << endl; - } + } -#endif - - // rescale to DC=1 -// filter_coefficients_padded_3D_array /= filter_coefficients_padded_3D_array.sum(); - - convert_array_3D_into_1D_array(fft_filter_1D_array,filter_coefficients_padded_3D_array); - //cerr << fft_filter_1D_array[fft_filter_1D_array.get_min_index()]<< " " << fft_filter_1D_array[fft_filter_1D_array.get_min_index()+1]<<" "; - - fourn(fft_filter_1D_array, array_lengths, 3,1); - fft_filter_1D_array /= sqrt(static_cast(size_z *size_y*size_x)); - } - - //for ( int i = fft_filter_1D_array.get_min_index(); i<=fft_filter_1D_array.get_max_index();i++) - //cerr << fft_filter_1D_array[i]<< " "; - - - Array<3,float> new_filter_coefficients_3D_array_tmp (IndexRange3D(1,size_z,1,size_y,1,size_x)); - - // WARNING -- this only works for the FFT where the convention is that the final result - // obtained from the FFT is divided with sqrt(N*N*N) - // initialise to 0 to prevent from warnings - //fourn(fft_1_1D_array, array_lengths, 3,1); - float fft_1_1D_array = 1/sqrt(static_cast(size_z*size_y*size_x)); - { - Array<1,float> fft_filter_num_1D_array = fft_filter_1D_array; - fft_filter_num_1D_array *= fft_1_1D_array; - // TODO we make a copy for the denominator here, which isn't necessary - Array<1,float> fft_filter_denom_1D_array = fft_filter_1D_array; - fft_filter_denom_1D_array*= (sq_kapas-1); - // add fft of 1 (but that's a real constant) - for ( int i = fft_filter_1D_array.get_min_index(); i<=fft_filter_1D_array.get_max_index(); i+=2) - { - fft_filter_denom_1D_array[i] += fft_1_1D_array; - } - fft_filter_denom_1D_array /= sq_kapas; - - - divide_complex_arrays(fft_filter_num_1D_array,fft_filter_denom_1D_array); - fourn(fft_filter_num_1D_array, array_lengths, 3,-1); - - - // make it consistent with mathemematica -- the output of the - fft_filter_num_1D_array /= sqrt(static_cast(size_z *size_y*size_x)); +#endif - - - // take the real part only - /*********************************************************************************/ - { - Array<1,float> real_div_1D_array(1,size_z *size_y*size_x); - - for (int i=0;i<=(size_z *size_y*size_x)-1;i++) - real_div_1D_array[i+1] = fft_filter_num_1D_array[2*i+1]; - - /*********************************************************************************/ - - - convert_array_1D_into_3D_array(new_filter_coefficients_3D_array_tmp,real_div_1D_array); - - - - } - } - - int kernel_length_x=0; - int kernel_length_y=0; - int kernel_length_z=0; - - // to prevent form aliasing limit the new range for the coefficients to - // filter_coefficients_padded.get_length()/4 - - int threshold = 10000000; - // do the x -direction first -- fix y and z to the min and look for the max index in x - int kx = new_filter_coefficients_3D_array_tmp.get_min_index(); - int jx = new_filter_coefficients_3D_array_tmp[kx].get_min_index(); - for (int i=new_filter_coefficients_3D_array_tmp[kx][jx].get_min_index(); - i<=new_filter_coefficients_3D_array_tmp[kx][jx].get_max_index()/2;i++) - { - if (fabs((double)new_filter_coefficients_3D_array_tmp[kx][jx][i]) - <= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()].get_min_index()]*1/threshold) break; - else (kernel_length_x)++; - } - - /******************************* Y DIRECTION ************************************/ - - - int ky = new_filter_coefficients_3D_array_tmp.get_min_index(); - int iy = new_filter_coefficients_3D_array_tmp[ky][new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index(); - for (int j=new_filter_coefficients_3D_array_tmp[ky].get_min_index();j<=new_filter_coefficients_3D_array_tmp[ky].get_max_index()/2;j++) - { - if (fabs((double)new_filter_coefficients_3D_array_tmp[ky][j][iy]) - //= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) break; - <= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()].get_min_index()]*1/threshold) break; - else (kernel_length_y)++; - } - - /********************************************************************************/ - - /******************************* z DIRECTION ************************************/ - - if (size_z==1) - kernel_length_z=1; - else - { - int jz = new_filter_coefficients_3D_array_tmp.get_min_index(); - int iz = new_filter_coefficients_3D_array_tmp[jz][new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index(); - for (int k=new_filter_coefficients_3D_array_tmp.get_min_index();k<=new_filter_coefficients_3D_array_tmp.get_max_index()/2;k++) - { - if (fabs((double)new_filter_coefficients_3D_array_tmp[k][jz][iz]) - //<= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) break; - <= new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()].get_min_index()]*1/threshold) break; - else (kernel_length_z)++; - } - } - /********************************************************************************/ - - if (kernel_length_x == size_x/2) - { - warning("NonseparableSpatiallyVaryingFilters3D: kernel_length_x reached maximum length %d. " - "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" - "Increasing length of FFT array to resolve this problem\n", - kernel_length_x, new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()], new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][kernel_length_x], - kapa0_over_kapa1); - size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]*=2; - for (int i=kapa0_over_kapa1_interval+1; i(size_z * size_y * size_x)); + } + + // for ( int i = fft_filter_1D_array.get_min_index(); i<=fft_filter_1D_array.get_max_index();i++) + // cerr << fft_filter_1D_array[i]<< " "; + + Array<3, float> new_filter_coefficients_3D_array_tmp(IndexRange3D(1, size_z, 1, size_y, 1, size_x)); + + // WARNING -- this only works for the FFT where the convention is that the final result + // obtained from the FFT is divided with sqrt(N*N*N) + // initialise to 0 to prevent from warnings + // fourn(fft_1_1D_array, array_lengths, 3,1); + float fft_1_1D_array = 1 / sqrt(static_cast(size_z * size_y * size_x)); + { + Array<1, float> fft_filter_num_1D_array = fft_filter_1D_array; + fft_filter_num_1D_array *= fft_1_1D_array; + // TODO we make a copy for the denominator here, which isn't necessary + Array<1, float> fft_filter_denom_1D_array = fft_filter_1D_array; + fft_filter_denom_1D_array *= (sq_kapas - 1); + // add fft of 1 (but that's a real constant) + for (int i = fft_filter_1D_array.get_min_index(); i <= fft_filter_1D_array.get_max_index(); i += 2) { + fft_filter_denom_1D_array[i] += fft_1_1D_array; + } + fft_filter_denom_1D_array /= sq_kapas; + + divide_complex_arrays(fft_filter_num_1D_array, fft_filter_denom_1D_array); + fourn(fft_filter_num_1D_array, array_lengths, 3, -1); + + // make it consistent with mathemematica -- the output of the + fft_filter_num_1D_array /= sqrt(static_cast(size_z * size_y * size_x)); + + // take the real part only + /*********************************************************************************/ + { + Array<1, float> real_div_1D_array(1, size_z * size_y * size_x); + + for (int i = 0; i <= (size_z * size_y * size_x) - 1; i++) + real_div_1D_array[i + 1] = fft_filter_num_1D_array[2 * i + 1]; + + /*********************************************************************************/ + + convert_array_1D_into_3D_array(new_filter_coefficients_3D_array_tmp, real_div_1D_array); + } + } + + int kernel_length_x = 0; + int kernel_length_y = 0; + int kernel_length_z = 0; + + // to prevent form aliasing limit the new range for the coefficients to + // filter_coefficients_padded.get_length()/4 + + int threshold = 10000000; + // do the x -direction first -- fix y and z to the min and look for the max index in x + int kx = new_filter_coefficients_3D_array_tmp.get_min_index(); + int jx = new_filter_coefficients_3D_array_tmp[kx].get_min_index(); + for (int i = new_filter_coefficients_3D_array_tmp[kx][jx].get_min_index(); + i <= new_filter_coefficients_3D_array_tmp[kx][jx].get_max_index() / 2; i++) { + if (fabs((double)new_filter_coefficients_3D_array_tmp[kx][jx][i]) <= + new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()] + [new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + .get_min_index()] + .get_min_index()] * + 1 / threshold) + break; + else + (kernel_length_x)++; + } + + /******************************* Y DIRECTION ************************************/ + + int ky = new_filter_coefficients_3D_array_tmp.get_min_index(); + int iy = new_filter_coefficients_3D_array_tmp[ky][new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index(); + for (int j = new_filter_coefficients_3D_array_tmp[ky].get_min_index(); + j <= new_filter_coefficients_3D_array_tmp[ky].get_max_index() / 2; j++) { + if (fabs((double)new_filter_coefficients_3D_array_tmp[ky][j][iy]) + //= + // new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) + // break; + <= + new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index()] + [new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + .get_min_index()] + .get_min_index()] * + 1 / threshold) + break; + else + (kernel_length_y)++; + } + + /********************************************************************************/ + + /******************************* z DIRECTION ************************************/ + + if (size_z == 1) + kernel_length_z = 1; + else { + int jz = new_filter_coefficients_3D_array_tmp.get_min_index(); + int iz = new_filter_coefficients_3D_array_tmp[jz][new_filter_coefficients_3D_array_tmp.get_min_index()].get_min_index(); + for (int k = new_filter_coefficients_3D_array_tmp.get_min_index(); + k <= new_filter_coefficients_3D_array_tmp.get_max_index() / 2; k++) { + if (fabs((double)new_filter_coefficients_3D_array_tmp[k][jz][iz]) + //<= + // new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()][new_filter_coefficients_3D_array_tmp.get_min_index()]*1/100000000) + // break; + <= new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + .get_min_index()] + [new_filter_coefficients_3D_array_tmp + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + .get_min_index()] + .get_min_index()] * + 1 / threshold) + break; + else + (kernel_length_z)++; + } + } + /********************************************************************************/ + + if (kernel_length_x == size_x / 2) { + warning("NonseparableSpatiallyVaryingFilters3D: kernel_length_x reached maximum length %d. " + "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" + "Increasing length of FFT array to resolve this problem\n", + kernel_length_x, + new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()], + new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()][kernel_length_x], + kapa0_over_kapa1); + size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval] *= 2; + for (int i = kapa0_over_kapa1_interval + 1; i < size_for_kapa0_over_kapa1.get_length(); ++i) + size_for_kapa0_over_kapa1[i] = + max(size_for_kapa0_over_kapa1[i], size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]); + } else if (kernel_length_y == size_y / 2) { + warning("NonseparableSpatiallyVaryingFilters3D: kernel_length_y reached maximum length %d. " + "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" + "Increasing length of FFT array to resolve this problem\n", + kernel_length_y, + new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()], + new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()][kernel_length_y] + [new_filter_coefficients_3D_array_tmp.get_min_index()], + kapa0_over_kapa1); + size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval] *= 2; + for (int i = kapa0_over_kapa1_interval + 1; i < size_for_kapa0_over_kapa1.get_length(); ++i) + size_for_kapa0_over_kapa1[i] = + max(size_for_kapa0_over_kapa1[i], size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]); + } else if (kernel_length_z == size_z / 2) { + warning("NonseparableSpatiallyVaryingFilters3D: kernel_length_z reached maximum length %d. " + "First filter coefficient %g, last %g, kappa0_over_kappa1 was %g\n" + "Increasing length of FFT array to resolve this problem\n", + kernel_length_z, + new_filter_coefficients_3D_array_tmp[new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()], + new_filter_coefficients_3D_array_tmp[kernel_length_z][new_filter_coefficients_3D_array_tmp.get_min_index()] + [new_filter_coefficients_3D_array_tmp.get_min_index()], + kapa0_over_kapa1); + size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval] *= 2; + for (int i = kapa0_over_kapa1_interval + 1; i < size_for_kapa0_over_kapa1.get_length(); ++i) + size_for_kapa0_over_kapa1[i] = + max(size_for_kapa0_over_kapa1[i], size_for_kapa0_over_kapa1[kapa0_over_kapa1_interval]); + } else { + info(boost::format("kernel lengths found: (z,y,x): (%1%,%2%,%3%)") % kernel_length_z % kernel_length_y % + kernel_length_x); + new_filter_coefficients_3D_array.grow(IndexRange3D(-(kernel_length_z - 1), kernel_length_z - 1, -(kernel_length_y - 1), + kernel_length_y - 1, -(kernel_length_x - 1), kernel_length_x - 1)); + + for (int k = 0; k <= kernel_length_z - 1; k++) + for (int j = 0; j <= kernel_length_y - 1; j++) + for (int i = 0; i <= kernel_length_x - 1; i++) { + new_filter_coefficients_3D_array[k][j][i] = new_filter_coefficients_3D_array[k][j][-i] = + new_filter_coefficients_3D_array[k][-j][-i] = new_filter_coefficients_3D_array[k][-j][i] = + new_filter_coefficients_3D_array[-k][j][i] = new_filter_coefficients_3D_array[-k][-j][i] = + new_filter_coefficients_3D_array[-k][j][-i] = new_filter_coefficients_3D_array[-k][-j][-i] = + new_filter_coefficients_3D_array_tmp[k + 1][j + 1][i + 1]; + } + + break; // out of while(true) + } + } // this bracket is for the while loop + } else // sq_kappas == 1 { - const unsigned int size_x = filter_coefficients[0][0].get_length(); - const unsigned int size_y = filter_coefficients[0].get_length(); - const unsigned int size_z = filter_coefficients.get_length(); - - const int min_index_z = -(size_z/2); - const int min_index_y = -(size_y/2); - const int min_index_x = -(size_x/2); - - new_filter_coefficients_3D_array.grow(IndexRange3D(min_index_z, min_index_z + size_z - 1, - min_index_y, min_index_y + size_y - 1, - min_index_x, min_index_x + size_x - 1 )); - - for (int k = 0;k<= new_filter_coefficients_3D_array.get_max_index();k++) - { - const int oldk = filter_coefficients.get_min_index()+k; - for (int j = 0;j<= new_filter_coefficients_3D_array[oldk].get_max_index();j++) - { - const int oldj = filter_coefficients[oldk].get_min_index()+j; - for (int i = 0;i<= new_filter_coefficients_3D_array[oldk][oldj].get_max_index();i++) - { - const int oldi = filter_coefficients[oldk][oldj].get_min_index()+i; - const float tmp = filter_coefficients[oldk][oldj][oldi]; - new_filter_coefficients_3D_array[k][j][i]= - new_filter_coefficients_3D_array[k][j][-i]= - new_filter_coefficients_3D_array[k][-j][i]= - new_filter_coefficients_3D_array[k][-j][-i]= - new_filter_coefficients_3D_array[-k][j][i]= - new_filter_coefficients_3D_array[-k][-j][i]= - new_filter_coefficients_3D_array[-k][j][-i]= - new_filter_coefficients_3D_array[-k][-j][-i]= - tmp; - } - } + const unsigned int size_x = filter_coefficients[0][0].get_length(); + const unsigned int size_y = filter_coefficients[0].get_length(); + const unsigned int size_z = filter_coefficients.get_length(); + + const int min_index_z = -(size_z / 2); + const int min_index_y = -(size_y / 2); + const int min_index_x = -(size_x / 2); + + new_filter_coefficients_3D_array.grow(IndexRange3D(min_index_z, min_index_z + size_z - 1, min_index_y, + min_index_y + size_y - 1, min_index_x, min_index_x + size_x - 1)); + + for (int k = 0; k <= new_filter_coefficients_3D_array.get_max_index(); k++) { + const int oldk = filter_coefficients.get_min_index() + k; + for (int j = 0; j <= new_filter_coefficients_3D_array[oldk].get_max_index(); j++) { + const int oldj = filter_coefficients[oldk].get_min_index() + j; + for (int i = 0; i <= new_filter_coefficients_3D_array[oldk][oldj].get_max_index(); i++) { + const int oldi = filter_coefficients[oldk][oldj].get_min_index() + i; + const float tmp = filter_coefficients[oldk][oldj][oldi]; + new_filter_coefficients_3D_array[k][j][i] = new_filter_coefficients_3D_array[k][j][-i] = + new_filter_coefficients_3D_array[k][-j][i] = new_filter_coefficients_3D_array[k][-j][-i] = + new_filter_coefficients_3D_array[-k][j][i] = new_filter_coefficients_3D_array[-k][-j][i] = + new_filter_coefficients_3D_array[-k][j][-i] = new_filter_coefficients_3D_array[-k][-j][-i] = tmp; + } + } } - - } #if 0 @@ -419,48 +415,33 @@ construct_scaled_filter_coefficients_3D(Array<3,float> &new_filter_coefficients_ cerr << new_filter_coefficients_3D_array[k][j][i] << " " ; } - #endif // rescale to DC=1 - new_filter_coefficients_3D_array /= new_filter_coefficients_3D_array.sum(); - -} + new_filter_coefficients_3D_array /= new_filter_coefficients_3D_array.sum(); + } } - - #if 1 - template -NonseparableSpatiallyVaryingFilters3D:: -NonseparableSpatiallyVaryingFilters3D() -{ +NonseparableSpatiallyVaryingFilters3D::NonseparableSpatiallyVaryingFilters3D() { set_defaults(); } - template -NonseparableSpatiallyVaryingFilters3D:: -NonseparableSpatiallyVaryingFilters3D(string proj_data_filename_v, - string attenuation_proj_data_filename_v, - const Array<3,float>& filter_coefficients_v, - shared_ptr proj_data_ptr_v, - shared_ptr attenuation_proj_data_ptr_v, - DiscretisedDensity<3,float>* initial_image_v, - DiscretisedDensity<3,float>* sensitivity_image_v, - DiscretisedDensity<3,float>* precomputed_coefficients_image_v, - DiscretisedDensity<3,float>* normalised_bck_image_v, - int mask_size_v, float rescaling_coefficient_v) - - +NonseparableSpatiallyVaryingFilters3D::NonseparableSpatiallyVaryingFilters3D( + string proj_data_filename_v, string attenuation_proj_data_filename_v, const Array<3, float>& filter_coefficients_v, + shared_ptr proj_data_ptr_v, shared_ptr attenuation_proj_data_ptr_v, + DiscretisedDensity<3, float>* initial_image_v, DiscretisedDensity<3, float>* sensitivity_image_v, + DiscretisedDensity<3, float>* precomputed_coefficients_image_v, DiscretisedDensity<3, float>* normalised_bck_image_v, + int mask_size_v, float rescaling_coefficient_v) + { - assert(filter_coefficients.get_length() == 0 || - filter_coefficients.begin()==0); - - for (int i = filter_coefficients_v.get_min_index();i<=filter_coefficients_v.get_max_index();i++) + assert(filter_coefficients.get_length() == 0 || filter_coefficients.begin() == 0); + + for (int i = filter_coefficients_v.get_min_index(); i <= filter_coefficients_v.get_max_index(); i++) filter_coefficients[i] = filter_coefficients_v[i]; - proj_data_filename = proj_data_filename_v; + proj_data_filename = proj_data_filename_v; attenuation_proj_data_filename = attenuation_proj_data_filename_v; proj_data_ptr = proj_data_ptr_v; attenuation_proj_data_ptr = attenuation_proj_data_ptr_v; @@ -468,601 +449,493 @@ NonseparableSpatiallyVaryingFilters3D(string proj_data_filename_v, sensitivity_image = sensitivity_image_v; precomputed_coefficients_image = precomputed_coefficients_image_v; normalised_bck_image = normalised_bck_image_v; - mask_size= mask_size_v; - //num_dim = num_dim_v; - rescaling_coefficient=rescaling_coefficient_v; + mask_size = mask_size_v; + // num_dim = num_dim_v; + rescaling_coefficient = rescaling_coefficient_v; } - template -Succeeded -NonseparableSpatiallyVaryingFilters3D:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) -{ - proj_data_ptr = - ProjData::read_from_file( proj_data_filename); - - if (attenuation_proj_data_filename !="1") - attenuation_proj_data_ptr = - ProjData::read_from_file(attenuation_proj_data_filename); - else +Succeeded +NonseparableSpatiallyVaryingFilters3D::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { + proj_data_ptr = ProjData::read_from_file(proj_data_filename); + + if (attenuation_proj_data_filename != "1") + attenuation_proj_data_ptr = ProjData::read_from_file(attenuation_proj_data_filename); + else attenuation_proj_data_ptr = NULL; - - if (initial_image_filename !="1") - initial_image = - DiscretisedDensity<3,float>::read_from_file(initial_image_filename); - else - initial_image = NULL; - - if (sensitivity_image_filename !="1") - sensitivity_image = - DiscretisedDensity<3,float>::read_from_file(sensitivity_image_filename); - else + + if (initial_image_filename != "1") + initial_image = DiscretisedDensity<3, float>::read_from_file(initial_image_filename); + else + initial_image = NULL; + + if (sensitivity_image_filename != "1") + sensitivity_image = DiscretisedDensity<3, float>::read_from_file(sensitivity_image_filename); + else sensitivity_image = NULL; - - if (precomputed_coefficients_filename !="1") - precomputed_coefficients_image = - DiscretisedDensity<3,float>::read_from_file(precomputed_coefficients_filename); + + if (precomputed_coefficients_filename != "1") + precomputed_coefficients_image = DiscretisedDensity<3, float>::read_from_file(precomputed_coefficients_filename); else - precomputed_coefficients_image =NULL; - - if (normalised_bck_filename !="1") - normalised_bck_image = - DiscretisedDensity<3,float>::read_from_file(normalised_bck_filename); + precomputed_coefficients_image = NULL; + + if (normalised_bck_filename != "1") + normalised_bck_image = DiscretisedDensity<3, float>::read_from_file(normalised_bck_filename); else - normalised_bck_image =NULL; - - - + normalised_bck_image = NULL; + return Succeeded::yes; - } +template +void +NonseparableSpatiallyVaryingFilters3D::precalculate_filter_coefficients_3D( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const { + VectorWithOffset>> filter_lookup; + filter_lookup.grow(1, 500); + const int k_min = 1; + const float k_interval = 0.01F; // 0.01F; + shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); + VoxelsOnCartesianGrid* in_density_cast = dynamic_cast*>(in_density); -template -void -NonseparableSpatiallyVaryingFilters3D::precalculate_filter_coefficients_3D (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const -{ + VoxelsOnCartesianGrid* vox_image_ptr_1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); - - VectorWithOffset < shared_ptr > > filter_lookup; - filter_lookup.grow(1,500); - const int k_min =1; - const float k_interval = 0.01F; //0.01F; - - - shared_ptr new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); - VoxelsOnCartesianGrid* in_density_cast = - dynamic_cast< VoxelsOnCartesianGrid* >(in_density); - - - VoxelsOnCartesianGrid * vox_image_ptr_1 = - new VoxelsOnCartesianGrid (IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - int start_segment_num = proj_data_ptr->get_min_segment_num(); int end_segment_num = proj_data_ptr->get_max_segment_num(); - - VectorWithOffset *> all_segments(start_segment_num, end_segment_num); - VectorWithOffset *> all_segments_for_kappa0(start_segment_num, end_segment_num); - VectorWithOffset *> all_attenuation_segments(start_segment_num, end_segment_num); - - + + VectorWithOffset*> all_segments(start_segment_num, end_segment_num); + VectorWithOffset*> all_segments_for_kappa0(start_segment_num, end_segment_num); + VectorWithOffset*> all_attenuation_segments(start_segment_num, end_segment_num); + // first initialise to false bool do_attenuation = false; - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { all_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); all_segments_for_kappa0[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); - - if (attenuation_proj_data_filename!="1") - { + + if (attenuation_proj_data_filename != "1") { do_attenuation = true; - all_attenuation_segments[segment_num] = - new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); - } - else - { + all_attenuation_segments[segment_num] = + new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(segment_num)); + } else { do_attenuation = false; - all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); + all_attenuation_segments[segment_num] = new SegmentByView(proj_data_ptr->get_empty_segment_by_view(segment_num)); (*all_attenuation_segments[segment_num]).fill(1); } - } - - vox_image_ptr_1->set_origin(Coordinate3D(0,0,0)); - - shared_ptr > image_sptr = vox_image_ptr_1; - - shared_ptr proj_matrix_ptr = - new ProjMatrixByDenselUsingRayTracing; - - proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), - image_sptr); + + vox_image_ptr_1->set_origin(Coordinate3D(0, 0, 0)); + + shared_ptr> image_sptr = vox_image_ptr_1; + + shared_ptr proj_matrix_ptr = new ProjMatrixByDenselUsingRayTracing; + + proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), image_sptr); info(boost::format("%1%") % proj_matrix_ptr->parameter_info()); - - fwd_densels_all(all_segments,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - in_density_cast->get_min_y(), in_density_cast->get_max_y(), - in_density_cast->get_min_x(), in_density_cast->get_max_x(), - *in_density); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa0 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * vox_image_ptr_kappa1 = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - VoxelsOnCartesianGrid * kappa_coefficients = - new VoxelsOnCartesianGrid(IndexRange3D(in_density_cast->get_min_z(),in_density_cast->get_max_z(), - in_density_cast->get_min_y(),in_density_cast->get_max_y(), - in_density_cast->get_min_x(),in_density_cast->get_max_x()), - in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - - - shared_ptr > kappa0_ptr_bck = vox_image_ptr_kappa0; - shared_ptr > kappa1_ptr_bck = vox_image_ptr_kappa1; - + + fwd_densels_all(all_segments, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), in_density_cast->get_max_z(), + in_density_cast->get_min_y(), in_density_cast->get_max_y(), in_density_cast->get_min_x(), + in_density_cast->get_max_x(), *in_density); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa0 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* vox_image_ptr_kappa1 = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + VoxelsOnCartesianGrid* kappa_coefficients = new VoxelsOnCartesianGrid( + IndexRange3D(in_density_cast->get_min_z(), in_density_cast->get_max_z(), in_density_cast->get_min_y(), + in_density_cast->get_max_y(), in_density_cast->get_min_x(), in_density_cast->get_max_x()), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + + shared_ptr> kappa0_ptr_bck = vox_image_ptr_kappa0; + shared_ptr> kappa1_ptr_bck = vox_image_ptr_kappa1; + // WARNING - find a way of finding max in the sinogram // TODO - include other segments as well - float max_in_viewgram =0.F; - - for (int segment_num = start_segment_num; segment_num<= end_segment_num; segment_num++) - { - SegmentByView segment_by_view = - proj_data_ptr->get_segment_by_view(segment_num); + float max_in_viewgram = 0.F; + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; segment_num++) { + SegmentByView segment_by_view = proj_data_ptr->get_segment_by_view(segment_num); const float current_max_in_viewgram = segment_by_view.find_max(); - if ( current_max_in_viewgram >= max_in_viewgram) - max_in_viewgram = current_max_in_viewgram ; + if (current_max_in_viewgram >= max_in_viewgram) + max_in_viewgram = current_max_in_viewgram; else continue; } - const float threshold = 0.0001F*max_in_viewgram; - + const float threshold = 0.0001F * max_in_viewgram; + info(boost::format(" THRESHOLD IS %1%") % threshold); - - find_inverse_and_bck_densels(*kappa1_ptr_bck,all_segments, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - vox_image_ptr_kappa1->get_min_y(),vox_image_ptr_kappa1->get_max_y(), - vox_image_ptr_kappa1->get_min_x(),vox_image_ptr_kappa1->get_max_x(), - *proj_matrix_ptr, do_attenuation,threshold, false); //true); - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + + find_inverse_and_bck_densels(*kappa1_ptr_bck, all_segments, all_attenuation_segments, vox_image_ptr_kappa1->get_min_z(), + vox_image_ptr_kappa1->get_max_z(), vox_image_ptr_kappa1->get_min_y(), + vox_image_ptr_kappa1->get_max_y(), vox_image_ptr_kappa1->get_min_x(), + vox_image_ptr_kappa1->get_max_x(), *proj_matrix_ptr, do_attenuation, threshold, false); // true); + + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { delete all_segments[segment_num]; delete all_attenuation_segments[segment_num]; - } - + } + info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); - - for (int k=in_density_cast->get_min_z();k<=in_density_cast->get_max_z();k++) - for (int j =in_density_cast->get_min_y();j<=in_density_cast->get_max_y();j++) - for (int i =in_density_cast->get_min_x();i<=in_density_cast->get_max_x();i++) - { - - // WARNING - only works for segment zero at the moment - // do the calculation of kappa0 here - kappa0_ptr_bck->fill(0); - for (int segment_num = start_segment_num; - segment_num <= end_segment_num; ++segment_num) - { - (*all_segments_for_kappa0[segment_num]).fill(0); - } - if (true) //attenuation_proj_data_filename !="1") - { - shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid - (IndexRange3D(-mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), - mask_size+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2), - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); - /*shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = - new VoxelsOnCartesianGrid(IndexRange3D(k,k, - //-mask_size+k,mask_size+k, - -mask_size+6,mask_size+6, - -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); */ - CPUTimer timer; - timer.start(); - - // SM 23/05/2002 mask now 3D - const int min_k = max(in_density_cast->get_min_z(),k-mask_size); - const int max_k = min(in_density_cast->get_max_z(),k+mask_size); - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - // the mask size is in 2D only - // SM mask now 3D - for (int k_in =min_k;k_in<=max_k;k_in++) - for (int j_in =min_j;j_in<=max_j;j_in++) - for (int i_in =min_i;i_in<=max_i;i_in++) - { - (*in_density_cast_tmp)[k_in-k+(ceil(in_density_cast->get_max_z()-in_density_cast->get_min_z())/2)][j_in-j +6][i_in-i+6] = (*in_density_cast)[k_in][j_in][i_in]; - //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; - } - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast_tmp->get_min_z(), in_density_cast_tmp->get_max_z(), - in_density_cast_tmp->get_min_y(),in_density_cast_tmp->get_max_y(), - in_density_cast_tmp->get_min_x(),in_density_cast_tmp->get_max_x(), - *in_density_cast_tmp); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - //k,k, - (ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2,ceil((vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z())/2), - //0,0,0,0, - 6,6,6,6, - *proj_matrix_ptr,false,threshold, false) ;//true); - (*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[(ceil(vox_image_ptr_kappa1->get_max_z()-vox_image_ptr_kappa1->get_min_z()))/2][6][6]; - //(*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; - - timer.stop(); - //cerr << "kappa0 time "<< timer.value() << endl; - } - else - { - const int min_j = max(in_density_cast->get_min_y(),j-mask_size); - const int max_j = min(in_density_cast->get_max_y(),j+mask_size); - const int min_i = max(in_density_cast->get_min_x(),i-mask_size); - const int max_i = min(in_density_cast->get_max_x(),i+mask_size); - - fwd_densels_all(all_segments_for_kappa0,proj_matrix_ptr, proj_data_ptr, - in_density_cast->get_min_z(), in_density_cast->get_max_z(), - min_j,max_j, - min_i,max_i, - //j-2,j+2, - //i-2,i+2, - *in_density_cast); - - find_inverse_and_bck_densels(*kappa0_ptr_bck,all_segments_for_kappa0, - all_attenuation_segments, - vox_image_ptr_kappa1->get_min_z(),vox_image_ptr_kappa1->get_max_z(), - j,j,i,i, - *proj_matrix_ptr,false,threshold, true); - - } - float sq_kapas; -// float multiply_with_sensitivity; - if ( fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && - fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001 ) - { - sq_kapas =((*kappa0_ptr_bck)[k][j][i]*(*kappa0_ptr_bck)[k][j][i])/((*kappa1_ptr_bck)[k][j][i]*(*kappa1_ptr_bck)[k][j][i]); - // cerr << "sq_kapas " << sq_kapas << endl; - - (*kappa_coefficients)[k][j][i] = sq_kapas; - - int k_index ; - k_index = round(((float)sq_kapas- k_min)/k_interval); - if (k_index < 1) - {k_index = 1;} - - if ( k_index > 500) - { k_index = 500;} - - - if ( filter_lookup[k_index]==NULL ) - { - Array <3,float> new_coeffs; - info(boost::format("computing new filter for sq_kappas %1% at index %2%") % sq_kapas % k_index); - construct_scaled_filter_coefficients_3D(new_coeffs, filter_coefficients,sq_kapas); - filter_lookup[k_index] = new ArrayFilter3DUsingConvolution(new_coeffs); - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - //new ArrayFilter3DUsingConvolution(new_coeffs); - - } - else - { - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; - - } - - - // all_filter_coefficients[k][j][i] = - // new ModifiedInverseAverigingArrayFilter<3,float>(inverse_filter); - - } - else - { - sq_kapas = 0; - // inverse_filter = - // ModifiedInverseAverigingArrayFilter<3,float>(); - all_filter_coefficients[k][j][i] = - new ArrayFilter3DUsingConvolution(); - - } - - } - - // write_basic_interfile("kappa_coefficients_2D_SENS",*kappa_coefficients); - delete kappa_coefficients ; + for (int k = in_density_cast->get_min_z(); k <= in_density_cast->get_max_z(); k++) + for (int j = in_density_cast->get_min_y(); j <= in_density_cast->get_max_y(); j++) + for (int i = in_density_cast->get_min_x(); i <= in_density_cast->get_max_x(); i++) { + + // WARNING - only works for segment zero at the moment + // do the calculation of kappa0 here + kappa0_ptr_bck->fill(0); + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + (*all_segments_for_kappa0[segment_num]).fill(0); + } + if (true) // attenuation_proj_data_filename !="1") + { + shared_ptr> in_density_cast_tmp = new VoxelsOnCartesianGrid( + IndexRange3D(-mask_size + (ceil(in_density_cast->get_max_z() - in_density_cast->get_min_z()) / 2), + mask_size + (ceil(in_density_cast->get_max_z() - in_density_cast->get_min_z()) / 2), -mask_size + 6, + mask_size + 6, -mask_size + 6, mask_size + 6), + in_density_cast->get_origin(), in_density_cast->get_voxel_size()); + /*shared_ptr< VoxelsOnCartesianGrid > in_density_cast_tmp = + new VoxelsOnCartesianGrid(IndexRange3D(k,k, + //-mask_size+k,mask_size+k, + -mask_size+6,mask_size+6, + -mask_size+6,mask_size+6),in_density_cast->get_origin(),in_density_cast->get_voxel_size()); */ + CPUTimer timer; + timer.start(); + + // SM 23/05/2002 mask now 3D + const int min_k = max(in_density_cast->get_min_z(), k - mask_size); + const int max_k = min(in_density_cast->get_max_z(), k + mask_size); + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + // the mask size is in 2D only + // SM mask now 3D + for (int k_in = min_k; k_in <= max_k; k_in++) + for (int j_in = min_j; j_in <= max_j; j_in++) + for (int i_in = min_i; i_in <= max_i; i_in++) { + (*in_density_cast_tmp)[k_in - k + (ceil(in_density_cast->get_max_z() - in_density_cast->get_min_z()) / 2)] + [j_in - j + 6][i_in - i + 6] = (*in_density_cast)[k_in][j_in][i_in]; + //(*in_density_cast_tmp)[k][j_in-j +6][i_in-i+6] = (*in_density_cast)[k][j_in][i_in]; + } + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast_tmp->get_min_z(), + in_density_cast_tmp->get_max_z(), in_density_cast_tmp->get_min_y(), in_density_cast_tmp->get_max_y(), + in_density_cast_tmp->get_min_x(), in_density_cast_tmp->get_max_x(), *in_density_cast_tmp); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + // k,k, + (ceil(vox_image_ptr_kappa1->get_max_z() - vox_image_ptr_kappa1->get_min_z())) / 2, + ceil((vox_image_ptr_kappa1->get_max_z() - vox_image_ptr_kappa1->get_min_z()) / 2), + // 0,0,0,0, + 6, 6, 6, 6, *proj_matrix_ptr, false, threshold, false); // true); + (*kappa0_ptr_bck)[k][j][i] = + (*kappa0_ptr_bck)[(ceil(vox_image_ptr_kappa1->get_max_z() - vox_image_ptr_kappa1->get_min_z())) / 2][6][6]; + //(*kappa0_ptr_bck)[k][j][i] = (*kappa0_ptr_bck)[k][6][6]; + + timer.stop(); + // cerr << "kappa0 time "<< timer.value() << endl; + } else { + const int min_j = max(in_density_cast->get_min_y(), j - mask_size); + const int max_j = min(in_density_cast->get_max_y(), j + mask_size); + const int min_i = max(in_density_cast->get_min_x(), i - mask_size); + const int max_i = min(in_density_cast->get_max_x(), i + mask_size); + + fwd_densels_all(all_segments_for_kappa0, proj_matrix_ptr, proj_data_ptr, in_density_cast->get_min_z(), + in_density_cast->get_max_z(), min_j, max_j, min_i, max_i, + // j-2,j+2, + // i-2,i+2, + *in_density_cast); + + find_inverse_and_bck_densels(*kappa0_ptr_bck, all_segments_for_kappa0, all_attenuation_segments, + vox_image_ptr_kappa1->get_min_z(), vox_image_ptr_kappa1->get_max_z(), j, j, i, i, + *proj_matrix_ptr, false, threshold, true); + } + float sq_kapas; + // float multiply_with_sensitivity; + if (fabs((double)(*kappa1_ptr_bck)[k][j][i]) > 0.00000000000001 && + fabs((double)(*kappa0_ptr_bck)[k][j][i]) > 0.00000000000001) { + sq_kapas = ((*kappa0_ptr_bck)[k][j][i] * (*kappa0_ptr_bck)[k][j][i]) / + ((*kappa1_ptr_bck)[k][j][i] * (*kappa1_ptr_bck)[k][j][i]); + // cerr << "sq_kapas " << sq_kapas << endl; + + (*kappa_coefficients)[k][j][i] = sq_kapas; + + int k_index; + k_index = round(((float)sq_kapas - k_min) / k_interval); + if (k_index < 1) { + k_index = 1; + } + + if (k_index > 500) { + k_index = 500; + } + + if (filter_lookup[k_index] == NULL) { + Array<3, float> new_coeffs; + info(boost::format("computing new filter for sq_kappas %1% at index %2%") % sq_kapas % k_index); + construct_scaled_filter_coefficients_3D(new_coeffs, filter_coefficients, sq_kapas); + filter_lookup[k_index] = new ArrayFilter3DUsingConvolution(new_coeffs); + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + // new ArrayFilter3DUsingConvolution(new_coeffs); + + } else { + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; + } + + // all_filter_coefficients[k][j][i] = + // new ModifiedInverseAverigingArrayFilter<3,float>(inverse_filter); + + } else { + sq_kapas = 0; + // inverse_filter = + // ModifiedInverseAverigingArrayFilter<3,float>(); + all_filter_coefficients[k][j][i] = new ArrayFilter3DUsingConvolution(); + } + } + + // write_basic_interfile("kappa_coefficients_2D_SENS",*kappa_coefficients); + delete kappa_coefficients; - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { - delete all_segments_for_kappa0[segment_num]; + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { + delete all_segments_for_kappa0[segment_num]; } - - - } // densel stuff - > apply -#if 1 +# if 1 template void -NonseparableSpatiallyVaryingFilters3D:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, const DiscretisedDensity<3,elemT>& in_density) const -{ +NonseparableSpatiallyVaryingFilters3D::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { - static map > > filter_lookup; + static map>> filter_lookup; - - //the first time virtual_apply is called for this object, counter is set to 0 - static int count=0; + // the first time virtual_apply is called for this object, counter is set to 0 + static int count = 0; // every time it's called, counter is incremented count++; info(boost::format("checking the counter %1%") % count); - - const VoxelsOnCartesianGrid& in_density_cast_0 = - dynamic_cast< const VoxelsOnCartesianGrid& >(in_density); - - // the first set is defined for 2d separable case and the second for 3d case -- - // depending wether it is 2d or 3d corresponding coefficints are used. - static VectorWithOffset < VectorWithOffset < VectorWithOffset > > > > all_filter_coefficients; + + const VoxelsOnCartesianGrid& in_density_cast_0 = dynamic_cast&>(in_density); + + // the first set is defined for 2d separable case and the second for 3d case -- + // depending wether it is 2d or 3d corresponding coefficints are used. + static VectorWithOffset>>>> + all_filter_coefficients; bool recompute_filters = false; - //if (initial_image_filename!="1") - //{ - if (count ==1) - { - recompute_filters = true; - all_filter_coefficients.grow(in_density_cast_0.get_min_z(),in_density_cast_0.get_max_z()); - for (int k = in_density_cast_0.get_min_z(); k<=in_density_cast_0.get_max_z();k++) - { - all_filter_coefficients[k].grow(in_density_cast_0.get_min_y(),in_density_cast_0.get_max_y()); - for (int j = in_density_cast_0.get_min_y(); j<=in_density_cast_0.get_max_y();j++) - { - (all_filter_coefficients[k])[j].grow(in_density_cast_0.get_min_x(),in_density_cast_0.get_max_x()); - } - } - - if ( precomputed_coefficients_filename=="1" ) - { - info("Initialisation precomputed coefficients to 1"); - precomputed_coefficients_image = in_density_cast_0.get_empty_discretised_density(); - precomputed_coefficients_image->fill(1); + // if (initial_image_filename!="1") + //{ + if (count == 1) { + recompute_filters = true; + all_filter_coefficients.grow(in_density_cast_0.get_min_z(), in_density_cast_0.get_max_z()); + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) { + all_filter_coefficients[k].grow(in_density_cast_0.get_min_y(), in_density_cast_0.get_max_y()); + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) { + (all_filter_coefficients[k])[j].grow(in_density_cast_0.get_min_x(), in_density_cast_0.get_max_x()); } } - VoxelsOnCartesianGrid* precomputed_coefficients_image_cast = - dynamic_cast< VoxelsOnCartesianGrid* >(precomputed_coefficients_image); - if (recompute_every_num_subiterations>0 && - count>recompute_from_subiteration_num && - count %recompute_every_num_subiterations == 0) - { - recompute_filters = true; - info("recompute coefficients now\n WARNING this is specific to approach 2!"); - - VoxelsOnCartesianGrid * normalised_bck_image_cast = - dynamic_cast< VoxelsOnCartesianGrid * > (normalised_bck_image); - VoxelsOnCartesianGrid * sensitivity_image_cast = - dynamic_cast< VoxelsOnCartesianGrid * > (sensitivity_image); - - // WARNING this is specific to approach 2! - precompute_filter_coefficients_for_second_apporach(*precomputed_coefficients_image_cast, - in_density_cast_0, - *sensitivity_image_cast, - *normalised_bck_image_cast); + + if (precomputed_coefficients_filename == "1") { + info("Initialisation precomputed coefficients to 1"); + precomputed_coefficients_image = in_density_cast_0.get_empty_discretised_density(); + precomputed_coefficients_image->fill(1); } + } + VoxelsOnCartesianGrid* precomputed_coefficients_image_cast = + dynamic_cast*>(precomputed_coefficients_image); + if (recompute_every_num_subiterations > 0 && count > recompute_from_subiteration_num && + count % recompute_every_num_subiterations == 0) { + recompute_filters = true; + info("recompute coefficients now\n WARNING this is specific to approach 2!"); + + VoxelsOnCartesianGrid* normalised_bck_image_cast = dynamic_cast*>(normalised_bck_image); + VoxelsOnCartesianGrid* sensitivity_image_cast = dynamic_cast*>(sensitivity_image); + + // WARNING this is specific to approach 2! + precompute_filter_coefficients_for_second_apporach(*precomputed_coefficients_image_cast, in_density_cast_0, + *sensitivity_image_cast, *normalised_bck_image_cast); + } - if (recompute_filters) - { - info(boost::format("Min,max in coefficients: %1%, %2%") % precomputed_coefficients_image->find_min()*rescaling_coefficient % precomputed_coefficients_image->find_max()*rescaling_coefficient); - info("In here nonseparable"); - float max = precomputed_coefficients_image->find_max()*rescaling_coefficient; - -#if 0 + if (recompute_filters) { + info(boost::format("Min,max in coefficients: %1%, %2%") % precomputed_coefficients_image->find_min() * rescaling_coefficient % + precomputed_coefficients_image->find_max() * rescaling_coefficient); + info("In here nonseparable"); + float max = precomputed_coefficients_image->find_max() * rescaling_coefficient; + +# if 0 if (count==1) k_interval = max*.01F; -#endif - info(boost::format(" New k_interval is %1% ") % k_interval); - - for ( int k = precomputed_coefficients_image_cast->get_min_z(); k<=precomputed_coefficients_image_cast->get_max_z();k++) - for ( int j = precomputed_coefficients_image_cast->get_min_y(); j<=precomputed_coefficients_image_cast->get_max_y();j++) - for ( int i = precomputed_coefficients_image_cast->get_min_x(); i<=precomputed_coefficients_image_cast->get_max_x();i++) - - { - - // rescaling coefficients should be < 1 for narrowing the kernel and >1 for broadening the kernel - const float tmp = float((*precomputed_coefficients_image)[k][j][i]* rescaling_coefficient); - //const int k_index = round(((float)1/(max(.000000001F,tmp)))/k_interval); - const int k_index = round((tmp)/k_interval); -#if 1 - if (filter_lookup.find(k_index)==filter_lookup.end()) - - { - - info(boost::format("Now doing index %1% i.e. value %2% for tmp %3%") % k_index % k_index*k_interval % tmp); - if (tmp >0.0000001) - { - Array <3,float> new_coeffs; - construct_scaled_filter_coefficients_3D(new_coeffs,filter_coefficients,1/tmp); - filter_lookup[k_index] = new ArrayFilter3DUsingConvolution(new_coeffs); -#if 0 +# endif + info(boost::format(" New k_interval is %1% ") % k_interval); + + for (int k = precomputed_coefficients_image_cast->get_min_z(); k <= precomputed_coefficients_image_cast->get_max_z(); k++) + for (int j = precomputed_coefficients_image_cast->get_min_y(); j <= precomputed_coefficients_image_cast->get_max_y(); j++) + for (int i = precomputed_coefficients_image_cast->get_min_x(); i <= precomputed_coefficients_image_cast->get_max_x(); i++) + + { + + // rescaling coefficients should be < 1 for narrowing the kernel and >1 for broadening the kernel + const float tmp = float((*precomputed_coefficients_image)[k][j][i] * rescaling_coefficient); + // const int k_index = round(((float)1/(max(.000000001F,tmp)))/k_interval); + const int k_index = round((tmp) / k_interval); +# if 1 + if (filter_lookup.find(k_index) == filter_lookup.end()) + + { + + info(boost::format("Now doing index %1% i.e. value %2% for tmp %3%") % k_index % k_index * k_interval % tmp); + if (tmp > 0.0000001) { + Array<3, float> new_coeffs; + construct_scaled_filter_coefficients_3D(new_coeffs, filter_coefficients, 1 / tmp); + filter_lookup[k_index] = new ArrayFilter3DUsingConvolution(new_coeffs); +# if 0 { char filename[1000]; sprintf(filename, "filter%g.hv",tmp); filename[7]='_'; write_basic_interfile(filename, new_coeffs); } -#endif - } - else - { - filter_lookup[k_index] = new ArrayFilter3DUsingConvolution(); - } - - } - all_filter_coefficients[k][j][i] = filter_lookup[k_index]; -#else - - info(boost::format("Now doing tmp %1%") % tmp); - if (tmp >0.0000001) - { - Array <3,float> new_coeffs; - construct_scaled_filter_coefficients_3D(new_coeffs,filter_coefficients,1/tmp); - all_filter_coefficients[k][j][i] = new ArrayFilter3DUsingConvolution(new_coeffs); - } - else - { - all_filter_coefficients[k][j][i] = new ArrayFilter3DUsingConvolution(); - } -#endif - } - - } // end recompute_filters +# endif + } else { + filter_lookup[k_index] = new ArrayFilter3DUsingConvolution(); + } + } + all_filter_coefficients[k][j][i] = filter_lookup[k_index]; +# else + + info(boost::format("Now doing tmp %1%") % tmp); + if (tmp > 0.0000001) { + Array<3, float> new_coeffs; + construct_scaled_filter_coefficients_3D(new_coeffs, filter_coefficients, 1 / tmp); + all_filter_coefficients[k][j][i] = new ArrayFilter3DUsingConvolution(new_coeffs); + } else { + all_filter_coefficients[k][j][i] = new ArrayFilter3DUsingConvolution(); + } +# endif + } + + } // end recompute_filters - info("now filtering"); - - for (int k=in_density_cast_0.get_min_z();k<=in_density_cast_0.get_max_z();k++) - for (int j =in_density_cast_0.get_min_y();j<=in_density_cast_0.get_max_y();j++) - for (int i =in_density_cast_0.get_min_x();i<=in_density_cast_0.get_max_x();i++) - { - Array<3,elemT> single_pixel(IndexRange3D(k,k,j,j,i,i)); - - //cerr << "in here" << endl; - (*all_filter_coefficients[k][j][i])(single_pixel,in_density); - out_density[k][j][i] = single_pixel[k][j][i]; + + for (int k = in_density_cast_0.get_min_z(); k <= in_density_cast_0.get_max_z(); k++) + for (int j = in_density_cast_0.get_min_y(); j <= in_density_cast_0.get_max_y(); j++) + for (int i = in_density_cast_0.get_min_x(); i <= in_density_cast_0.get_max_x(); i++) { + Array<3, elemT> single_pixel(IndexRange3D(k, k, j, j, i, i)); + + // cerr << "in here" << endl; + (*all_filter_coefficients[k][j][i])(single_pixel, in_density); + out_density[k][j][i] = single_pixel[k][j][i]; } - } -#endif - - +# endif template void -NonseparableSpatiallyVaryingFilters3D:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const -{ - DiscretisedDensity<3,elemT>* tmp_density = - density.clone(); +NonseparableSpatiallyVaryingFilters3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const { + DiscretisedDensity<3, elemT>* tmp_density = density.clone(); virtual_apply(density, *tmp_density); delete tmp_density; } - template void -NonseparableSpatiallyVaryingFilters3D::set_defaults() -{ - filter_coefficients.fill(0); - proj_data_filename ="1"; - proj_data_ptr = NULL; - attenuation_proj_data_filename ="1"; - initial_image_filename ="1"; - initial_image =NULL; - sensitivity_image_filename ='1'; - sensitivity_image = NULL; - precomputed_coefficients_filename ='1'; - normalised_bck_filename ='1'; - normalised_bck_image =NULL; - precomputed_coefficients_image =NULL; - attenuation_proj_data_ptr = NULL; - mask_size = 0; - //num_dim = 1; - k_interval =0; - rescaling_coefficient =0; - - recompute_from_subiteration_num = 1; - recompute_every_num_subiterations = 0; - - } - - template - void - NonseparableSpatiallyVaryingFilters3D:: initialise_keymap() - { - parser.add_start_key("Nonseparable Spatially Varying Filters 3D"); - parser.add_key("filter_coefficients", &filter_coefficients_for_parsing); - parser.add_key("proj_data_filename", &proj_data_filename); - parser.add_key("attenuation_proj_data_filename", &attenuation_proj_data_filename); - parser.add_key("initial_image_filename", &initial_image_filename); - parser.add_key("sensitivity_image_filename", &sensitivity_image_filename); - parser.add_key("mask_size", &mask_size); - parser.add_key("k_interval", &k_interval); - parser.add_key("rescaling coefficient", & rescaling_coefficient); - parser.add_key ("precomputed_coefficients_filename", &precomputed_coefficients_filename); - parser.add_key ("normalised_bck_filename", &normalised_bck_filename); - parser.add_key ("recompute_from_subiteration_num", & recompute_from_subiteration_num); - parser.add_key ("recompute_every_num_subiterations", & recompute_every_num_subiterations); - parser.add_stop_key("END Nonseparable Spatially Varying Filters 3D"); - } - +NonseparableSpatiallyVaryingFilters3D::set_defaults() { + filter_coefficients.fill(0); + proj_data_filename = "1"; + proj_data_ptr = NULL; + attenuation_proj_data_filename = "1"; + initial_image_filename = "1"; + initial_image = NULL; + sensitivity_image_filename = '1'; + sensitivity_image = NULL; + precomputed_coefficients_filename = '1'; + normalised_bck_filename = '1'; + normalised_bck_image = NULL; + precomputed_coefficients_image = NULL; + attenuation_proj_data_ptr = NULL; + mask_size = 0; + // num_dim = 1; + k_interval = 0; + rescaling_coefficient = 0; + + recompute_from_subiteration_num = 1; + recompute_every_num_subiterations = 0; +} + template -bool -NonseparableSpatiallyVaryingFilters3D:: -post_processing() -{ - const unsigned int size_x = filter_coefficients_for_parsing[0][0].get_length(); - const unsigned int size_y = filter_coefficients_for_parsing[0].get_length(); - const unsigned int size_z = filter_coefficients_for_parsing.get_length(); +void +NonseparableSpatiallyVaryingFilters3D::initialise_keymap() { + parser.add_start_key("Nonseparable Spatially Varying Filters 3D"); + parser.add_key("filter_coefficients", &filter_coefficients_for_parsing); + parser.add_key("proj_data_filename", &proj_data_filename); + parser.add_key("attenuation_proj_data_filename", &attenuation_proj_data_filename); + parser.add_key("initial_image_filename", &initial_image_filename); + parser.add_key("sensitivity_image_filename", &sensitivity_image_filename); + parser.add_key("mask_size", &mask_size); + parser.add_key("k_interval", &k_interval); + parser.add_key("rescaling coefficient", &rescaling_coefficient); + parser.add_key("precomputed_coefficients_filename", &precomputed_coefficients_filename); + parser.add_key("normalised_bck_filename", &normalised_bck_filename); + parser.add_key("recompute_from_subiteration_num", &recompute_from_subiteration_num); + parser.add_key("recompute_every_num_subiterations", &recompute_every_num_subiterations); + parser.add_stop_key("END Nonseparable Spatially Varying Filters 3D"); +} - const int min_index_z = -(size_z/2); - const int min_index_y = -(size_y/2); - const int min_index_x = -(size_x/2); +template +bool +NonseparableSpatiallyVaryingFilters3D::post_processing() { + const unsigned int size_x = filter_coefficients_for_parsing[0][0].get_length(); + const unsigned int size_y = filter_coefficients_for_parsing[0].get_length(); + const unsigned int size_z = filter_coefficients_for_parsing.get_length(); + + const int min_index_z = -(size_z / 2); + const int min_index_y = -(size_y / 2); + const int min_index_x = -(size_x / 2); + + filter_coefficients.grow(IndexRange3D(min_index_z, min_index_z + size_z - 1, min_index_y, min_index_y + size_y - 1, min_index_x, + min_index_x + size_x - 1)); + + for (int k = min_index_z; k <= filter_coefficients.get_max_index(); ++k) + for (int j = min_index_y; j <= filter_coefficients[k].get_max_index(); ++j) + for (int i = min_index_x; i <= filter_coefficients[k][j].get_max_index(); ++i) { + filter_coefficients[k][j][i] = + static_cast(filter_coefficients_for_parsing[k - min_index_z][j - min_index_y][i - min_index_x]); + } + return false; +} - filter_coefficients.grow(IndexRange3D(min_index_z, min_index_z + size_z - 1, - min_index_y, min_index_y + size_y - 1, - min_index_x, min_index_x + size_x - 1 )); +const char* const NonseparableSpatiallyVaryingFilters3D::registered_name = "Nonseparable Spatially Varying Filters 3D"; - for (int k = min_index_z; k<=filter_coefficients.get_max_index(); ++k) - for (int j = min_index_y; j<=filter_coefficients[k].get_max_index(); ++j) - for (int i = min_index_x; i<= filter_coefficients[k][j].get_max_index(); ++i) - { - filter_coefficients[k][j][i] = - static_cast(filter_coefficients_for_parsing[k-min_index_z][j-min_index_y][i-min_index_x]); - } -return false; -} - - -const char * const -NonseparableSpatiallyVaryingFilters3D::registered_name = -"Nonseparable Spatially Varying Filters 3D"; - - # ifdef _MSC_VER - // prevent warning message on reinstantiation, - // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) +// prevent warning message on reinstantiation, +// note that we get a linking error if we don't have the explicit instantiation below +# pragma warning(disable : 4660) # endif - - // Register this class in the ImageProcessor registry - // static SeparableCartesianMetzImageFilter::RegisterIt dummy; - // have the above variable in a separate file, which you need t - + +// Register this class in the ImageProcessor registry +// static SeparableCartesianMetzImageFilter::RegisterIt dummy; +// have the above variable in a separate file, which you need t + template NonseparableSpatiallyVaryingFilters3D; - - - + END_NAMESPACE_STIR - -#endif +#endif diff --git a/src/experimental/buildblock/Quaternion.cxx b/src/experimental/buildblock/Quaternion.cxx index a3afd76d1d..f80d65a7d4 100644 --- a/src/experimental/buildblock/Quaternion.cxx +++ b/src/experimental/buildblock/Quaternion.cxx @@ -15,24 +15,15 @@ See STIR/LICENSE.txt for details */ - #include "stir_experimental/Quaternion.h" - START_NAMESPACE_STIR template -Quaternion::Quaternion() - : base_type() -{} +Quaternion::Quaternion() : base_type() {} template -Quaternion::Quaternion(const coordT& c1, - const coordT& c2, - const coordT& c3, - const coordT& c4) - : base_type() -{ +Quaternion::Quaternion(const coordT& c1, const coordT& c2, const coordT& c3, const coordT& c4) : base_type() { (*this)[1] = c1; (*this)[2] = c2; (*this)[3] = c3; @@ -40,9 +31,7 @@ Quaternion::Quaternion(const coordT& c1, } template -Quaternion::Quaternion(const base_type& c) - : base_type(c) -{} +Quaternion::Quaternion(const base_type& c) : base_type(c) {} #if 0 template @@ -74,7 +63,6 @@ Quaternion:: component_4() const } #endif - template class Quaternion; END_NAMESPACE_STIR diff --git a/src/experimental/buildblock/RegisteredObject.cxx b/src/experimental/buildblock/RegisteredObject.cxx index b442156b4b..5a90a61324 100644 --- a/src/experimental/buildblock/RegisteredObject.cxx +++ b/src/experimental/buildblock/RegisteredObject.cxx @@ -39,20 +39,18 @@ START_NAMESPACE_STIR template -RegisteredObject::RegistryType& -RegisteredObject::registry () -{ +RegisteredObject::RegistryType& +RegisteredObject::registry() { static RegistryType the_registry("None", 0); return the_registry; } # ifdef _MSC_VER -// prevent warning message on reinstantiation, +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) +# pragma warning(disable : 4660) # endif - // template RegisteredObject< >; END_NAMESPACE_STIR diff --git a/src/experimental/buildblock/SeparableLowPassArrayFilter.cxx b/src/experimental/buildblock/SeparableLowPassArrayFilter.cxx index 313ab92f23..b3174cce0b 100644 --- a/src/experimental/buildblock/SeparableLowPassArrayFilter.cxx +++ b/src/experimental/buildblock/SeparableLowPassArrayFilter.cxx @@ -2,7 +2,6 @@ #include "stir_experimental/SeparableLowPassArrayFilter.h" #include "stir/ArrayFilter1DUsingConvolution.h" - #include #include @@ -18,57 +17,40 @@ using std::endl; See STIR/LICENSE.txt for details */ - START_NAMESPACE_STIR template -SeparableLowPassArrayFilter:: -SeparableLowPassArrayFilter() -{ - for (int i=1;i<=num_dimensions;i++) - { - all_1d_array_filters[i-1] = - new ArrayFilter1DUsingConvolution(); +SeparableLowPassArrayFilter::SeparableLowPassArrayFilter() { + for (int i = 1; i <= num_dimensions; i++) { + all_1d_array_filters[i - 1] = new ArrayFilter1DUsingConvolution(); } } - -template -SeparableLowPassArrayFilter:: -SeparableLowPassArrayFilter(const VectorWithOffset& filter_coefficients_v, int z_trivial) -:filter_coefficients(filter_coefficients_v) -{ +template +SeparableLowPassArrayFilter::SeparableLowPassArrayFilter( + const VectorWithOffset& filter_coefficients_v, int z_trivial) + : filter_coefficients(filter_coefficients_v) { info("Printing filter coefficients"); - for (int i =filter_coefficients_v.get_min_index();i<=filter_coefficients_v.get_max_index();i++) + for (int i = filter_coefficients_v.get_min_index(); i <= filter_coefficients_v.get_max_index(); i++) info(boost::format("%1% %2% ") % i % filter_coefficients_v[i]); - //err << " Z_TRIVIAL " << z_trivial << endl; - - if (!z_trivial) - { - for (int i=1;i<=num_dimensions;i++) - { - //cerr << "in the right loop" << endl; - all_1d_array_filters[i-1] = - new ArrayFilter1DUsingConvolution(filter_coefficients_v); - } - } - else - { - for (int i=2;i<=num_dimensions;i++) - { - //cerr << "in the wrong loop" << endl; - all_1d_array_filters[i-1] = - new ArrayFilter1DUsingConvolution(filter_coefficients_v); - //new ArrayFilter1DUsingConvolutionSymmetricKernel(filter_coefficients_v); + // err << " Z_TRIVIAL " << z_trivial << endl; + + if (!z_trivial) { + for (int i = 1; i <= num_dimensions; i++) { + // cerr << "in the right loop" << endl; + all_1d_array_filters[i - 1] = new ArrayFilter1DUsingConvolution(filter_coefficients_v); + } + } else { + for (int i = 2; i <= num_dimensions; i++) { + // cerr << "in the wrong loop" << endl; + all_1d_array_filters[i - 1] = new ArrayFilter1DUsingConvolution(filter_coefficients_v); + // new ArrayFilter1DUsingConvolutionSymmetricKernel(filter_coefficients_v); + } + all_1d_array_filters[0] = new ArrayFilter1DUsingConvolution(); } - all_1d_array_filters[0] = - new ArrayFilter1DUsingConvolution(); - - } - } -template SeparableLowPassArrayFilter<3,float>; +template SeparableLowPassArrayFilter<3, float>; END_NAMESPACE_STIR diff --git a/src/experimental/buildblock/SeparableLowPassImageFilter.cxx b/src/experimental/buildblock/SeparableLowPassImageFilter.cxx index d496e43d1a..fcaf729d72 100644 --- a/src/experimental/buildblock/SeparableLowPassImageFilter.cxx +++ b/src/experimental/buildblock/SeparableLowPassImageFilter.cxx @@ -9,134 +9,99 @@ START_NAMESPACE_STIR template -SeparableLowPassImageFilter:: -SeparableLowPassImageFilter() -:filter_coefficients(VectorWithOffset(-1,1)) -{ - set_defaults(); +SeparableLowPassImageFilter::SeparableLowPassImageFilter() : filter_coefficients(VectorWithOffset(-1, 1)) { + set_defaults(); } template VectorWithOffset -SeparableLowPassImageFilter:: -get_filter_coefficients() -{ +SeparableLowPassImageFilter::get_filter_coefficients() { return filter_coefficients; } - + template Succeeded -SeparableLowPassImageFilter:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) -{ - - /* VectorWithOffset filter_coeff(filter_coefficients.size()); +SeparableLowPassImageFilter::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { + + /* VectorWithOffset filter_coeff(filter_coefficients.size()); - for ( int i =1; i <=filter_coefficients.size(); i++) - { - filter_coeff[i] = static_cast(filter_coefficients[i]); - }*/ + for ( int i =1; i <=filter_coefficients.size(); i++) + { + filter_coeff[i] = static_cast(filter_coefficients[i]); + }*/ + const VoxelsOnCartesianGrid& image = dynamic_cast&>(density); - const VoxelsOnCartesianGrid& image = - dynamic_cast&>(density); + lowpass_filter = SeparableLowPassArrayFilter<3, elemT>(filter_coefficients, z_trivial); - lowpass_filter = - SeparableLowPassArrayFilter<3,elemT>(filter_coefficients, z_trivial); - return Succeeded::yes; - } - template void -SeparableLowPassImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const +SeparableLowPassImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& density) const -{ - //assert(consistency_check(density) == Succeeded::yes); - lowpass_filter(density); +{ + // assert(consistency_check(density) == Succeeded::yes); + lowpass_filter(density); /*cerr <<"Line profile out " << endl; for (int i = -26;i<=26;i++) - cerr << density[10][1][i] << " "; - + cerr << density[10][1][i] << " "; + cerr << endl;*/ } - template void -SeparableLowPassImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, - const DiscretisedDensity<3,elemT>& in_density) const -{ - //assert(consistency_check(in_density) == Succeeded::yes); - lowpass_filter(out_density,in_density); +SeparableLowPassImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { + // assert(consistency_check(in_density) == Succeeded::yes); + lowpass_filter(out_density, in_density); /* cerr <<"Line profile " << endl; for (int i = -26;i<=26;i++) - cerr << out_density[10][0][i] << " "; - - cerr << endl;*/ - - + cerr << out_density[10][0][i] << " "; + cerr << endl;*/ } - template void -SeparableLowPassImageFilter:: -set_defaults() -{ - //for ( int i = 0;i<=filter_coefficients.get_length();i++) - filter_coefficients.fill(0); - z_trivial =1; - - +SeparableLowPassImageFilter::set_defaults() { + // for ( int i = 0;i<=filter_coefficients.get_length();i++) + filter_coefficients.fill(0); + z_trivial = 1; } template -void -SeparableLowPassImageFilter:: -initialise_keymap() -{ +void +SeparableLowPassImageFilter::initialise_keymap() { parser.add_start_key("Separable Lowpass Filter Parameters"); parser.add_key("filter_coefficients", &filter_coefficients_for_parsing); parser.add_key("z_trivial", &z_trivial); parser.add_stop_key("END Separable Lowpass Filter Parameters"); - } template -bool -SeparableLowPassImageFilter:: -post_processing() -{ +bool +SeparableLowPassImageFilter::post_processing() { const unsigned int size = filter_coefficients_for_parsing.size(); - const int min_index = -static_cast(size/2); + const int min_index = -static_cast(size / 2); filter_coefficients.grow(min_index, min_index + size - 1); - for (int i = min_index; i<= filter_coefficients.get_max_index(); ++i) - filter_coefficients[i] = - static_cast(filter_coefficients_for_parsing[i-min_index]); + for (int i = min_index; i <= filter_coefficients.get_max_index(); ++i) + filter_coefficients[i] = static_cast(filter_coefficients_for_parsing[i - min_index]); return false; } +const char* const SeparableLowPassImageFilter::registered_name = "Separable Lowpass Filter"; - -const char * const -SeparableLowPassImageFilter::registered_name = - "Separable Lowpass Filter"; - - -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif // Register this class in the ImageProcessor registry // static SeparableLowPassImageFilter::RegisterIt dummy; diff --git a/src/experimental/buildblock/fwd_and_bck_manipulation_for_SAF.cxx b/src/experimental/buildblock/fwd_and_bck_manipulation_for_SAF.cxx index d0df849e50..a3719d0db8 100644 --- a/src/experimental/buildblock/fwd_and_bck_manipulation_for_SAF.cxx +++ b/src/experimental/buildblock/fwd_and_bck_manipulation_for_SAF.cxx @@ -1,141 +1,97 @@ #include "stir_experimental/fwd_and_bck_manipulation_for_SAF.h" - - START_NAMESPACE_STIR void -find_inverse_and_bck_densels(DiscretisedDensity<3,float>& image, - VectorWithOffset *>& all_segments, - VectorWithOffset *>& attenuation_segmnets, - const int min_z, const int max_z, - const int min_y, const int max_y, - const int min_x, const int max_x, - ProjMatrixByDensel& proj_matrix, bool do_attenuation, - const float threshold,bool normalize_result) -{ - /* VectorWithOffset *> all_ones(0); - all_ones[0] = - new SegmentByView(all_segments[0]->get_empty_segment_by_view(segment_num)); - (*all_ones[0]).fill(1);*/ - +find_inverse_and_bck_densels(DiscretisedDensity<3, float>& image, VectorWithOffset*>& all_segments, + VectorWithOffset*>& attenuation_segmnets, const int min_z, const int max_z, + const int min_y, const int max_y, const int min_x, const int max_x, ProjMatrixByDensel& proj_matrix, + bool do_attenuation, const float threshold, bool normalize_result) { + /* VectorWithOffset *> all_ones(0); + all_ones[0] = + new SegmentByView(all_segments[0]->get_empty_segment_by_view(segment_num)); + (*all_ones[0]).fill(1);*/ + ProjMatrixElemsForOneDensel probs; - for (int z = min_z; z<= max_z; ++z) - { - for (int y = min_y; y<= max_y; ++y) - { - for (int x = min_x; x<= max_x; ++x) - { - Densel densel(z,y,x); - proj_matrix.get_proj_matrix_elems_for_one_densel(probs, densel); - - float denominator = 0; - float sensitivity= 0; - for (ProjMatrixElemsForOneDensel::const_iterator element_ptr = probs.begin(); - element_ptr != probs.end();++element_ptr) - { - //cerr << element_ptr->segment_num() << endl; - const float val=element_ptr->get_value(); - - if (element_ptr->axial_pos_num()<= all_segments[element_ptr->segment_num()]->get_max_axial_pos_num() && - element_ptr->axial_pos_num()>= all_segments[element_ptr->segment_num()]->get_min_axial_pos_num()) - { - const float bin= - max(threshold,(*all_segments[element_ptr->segment_num()])[element_ptr->view_num()][element_ptr->axial_pos_num()][element_ptr->tangential_pos_num()]); - denominator+= square(val); + for (int z = min_z; z <= max_z; ++z) { + for (int y = min_y; y <= max_y; ++y) { + for (int x = min_x; x <= max_x; ++x) { + Densel densel(z, y, x); + proj_matrix.get_proj_matrix_elems_for_one_densel(probs, densel); + + float denominator = 0; + float sensitivity = 0; + for (ProjMatrixElemsForOneDensel::const_iterator element_ptr = probs.begin(); element_ptr != probs.end(); ++element_ptr) { + // cerr << element_ptr->segment_num() << endl; + const float val = element_ptr->get_value(); - if (do_attenuation) - { - float bin_attenuation= - (*attenuation_segmnets[element_ptr->segment_num()])[element_ptr->view_num()][element_ptr->axial_pos_num()][element_ptr->tangential_pos_num()]; - image[z][y][x] += (bin_attenuation/bin) * square(val); - sensitivity+=bin_attenuation*val; - } - else - { - image[z][y][x] += (1.F/bin) * square(val); - sensitivity+=val; - } - } - } - image[z][y][x]/= square(sensitivity); - if (normalize_result) - image[z][y][x]/= denominator; + if (element_ptr->axial_pos_num() <= all_segments[element_ptr->segment_num()]->get_max_axial_pos_num() && + element_ptr->axial_pos_num() >= all_segments[element_ptr->segment_num()]->get_min_axial_pos_num()) { + const float bin = + max(threshold, (*all_segments[element_ptr->segment_num()])[element_ptr->view_num()][element_ptr->axial_pos_num()] + [element_ptr->tangential_pos_num()]); + denominator += square(val); + if (do_attenuation) { + float bin_attenuation = + (*attenuation_segmnets[element_ptr->segment_num()])[element_ptr->view_num()][element_ptr->axial_pos_num()] + [element_ptr->tangential_pos_num()]; + image[z][y][x] += (bin_attenuation / bin) * square(val); + sensitivity += bin_attenuation * val; + } else { + image[z][y][x] += (1.F / bin) * square(val); + sensitivity += val; + } + } + } + image[z][y][x] /= square(sensitivity); + if (normalize_result) + image[z][y][x] /= denominator; } - } } - - - for (DiscretisedDensity<3,float>::full_iterator iter = image.begin_all(); - iter !=image.end_all(); - ++iter) + for (DiscretisedDensity<3, float>::full_iterator iter = image.begin_all(); iter != image.end_all(); ++iter) *iter = sqrt(*iter); } - void -do_segments_densels_fwd(const VoxelsOnCartesianGrid& image, - ProjData& proj_data, - VectorWithOffset *>& all_segments, - const int min_z, const int max_z, - const int min_y, const int max_y, - const int min_x, const int max_x, - ProjMatrixByDensel& proj_matrix) -{ - +do_segments_densels_fwd(const VoxelsOnCartesianGrid& image, ProjData& proj_data, + VectorWithOffset*>& all_segments, const int min_z, const int max_z, const int min_y, + const int max_y, const int min_x, const int max_x, ProjMatrixByDensel& proj_matrix) { + ProjMatrixElemsForOneDensel probs; - for (int z = min_z; z<= max_z; ++z) - { - for (int y = min_y; y<= max_y; ++y) - { - for (int x = min_x; x<= max_x; ++x) - { + for (int z = min_z; z <= max_z; ++z) { + for (int y = min_y; y <= max_y; ++y) { + for (int x = min_x; x <= max_x; ++x) { if (image[z][y][x] == 0) continue; - Densel densel(z,y,x); + Densel densel(z, y, x); proj_matrix.get_proj_matrix_elems_for_one_densel(probs, densel); - for (ProjMatrixElemsForOneDensel::const_iterator element_ptr = probs.begin(); - element_ptr != probs.end(); - ++element_ptr) - { - if (element_ptr->axial_pos_num()<= proj_data.get_max_axial_pos_num(element_ptr->segment_num()) && - element_ptr->axial_pos_num()>= proj_data.get_min_axial_pos_num(element_ptr->segment_num())) - (*all_segments[element_ptr->segment_num()])[element_ptr->view_num()][element_ptr->axial_pos_num()][element_ptr->tangential_pos_num()] += - image[z][y][x] * element_ptr->get_value(); + for (ProjMatrixElemsForOneDensel::const_iterator element_ptr = probs.begin(); element_ptr != probs.end(); ++element_ptr) { + if (element_ptr->axial_pos_num() <= proj_data.get_max_axial_pos_num(element_ptr->segment_num()) && + element_ptr->axial_pos_num() >= proj_data.get_min_axial_pos_num(element_ptr->segment_num())) + (*all_segments[element_ptr->segment_num()])[element_ptr->view_num()][element_ptr->axial_pos_num()] + [element_ptr->tangential_pos_num()] += + image[z][y][x] * element_ptr->get_value(); } } } } - } void -fwd_densels_all(VectorWithOffset *>& all_segments, - shared_ptr proj_matrix_ptr, - shared_ptr proj_data_ptr, - const int min_z, const int max_z, - const int min_y, const int max_y, - const int min_x, const int max_x, - const DiscretisedDensity<3,float>& in_density) - +fwd_densels_all(VectorWithOffset*>& all_segments, shared_ptr proj_matrix_ptr, + shared_ptr proj_data_ptr, const int min_z, const int max_z, const int min_y, const int max_y, + const int min_x, const int max_x, const DiscretisedDensity<3, float>& in_density) + { - - const VoxelsOnCartesianGrid& in_density_cast_0 = - dynamic_cast< const VoxelsOnCartesianGrid& >(in_density); - - - do_segments_densels_fwd(in_density_cast_0, - *proj_data_ptr, - all_segments, - min_z, max_z, - min_y, max_y, - min_x, max_x, - *proj_matrix_ptr); - + + const VoxelsOnCartesianGrid& in_density_cast_0 = dynamic_cast&>(in_density); + + do_segments_densels_fwd(in_density_cast_0, *proj_data_ptr, all_segments, min_z, max_z, min_y, max_y, min_x, max_x, + *proj_matrix_ptr); } END_NAMESPACE_STIR \ No newline at end of file diff --git a/src/experimental/buildblock/local_buildblock_registries.cxx b/src/experimental/buildblock/local_buildblock_registries.cxx index bd02a654b7..97d64d714d 100644 --- a/src/experimental/buildblock/local_buildblock_registries.cxx +++ b/src/experimental/buildblock/local_buildblock_registries.cxx @@ -5,20 +5,20 @@ */ #include "stir_experimental/SeparableGaussianImageFilter.h" #ifdef SANIDA -#include "stir_experimental/DAVImageFilter3D.h" -#include "stir_experimental/ModifiedInverseAverigingImageFilter.h" -#include "stir_experimental/ModifiedInverseAveragingImageFilterAll.h" -#include "stir_experimental/NonseparableSpatiallyVaryingFilters.h" -#include "stir_experimental/NonseparableSpatiallyVaryingFilters3D.h" -#include "stir_experimental/multiply_plane_scale_factorsImageProcessor.h" +# include "stir_experimental/DAVImageFilter3D.h" +# include "stir_experimental/ModifiedInverseAverigingImageFilter.h" +# include "stir_experimental/ModifiedInverseAveragingImageFilterAll.h" +# include "stir_experimental/NonseparableSpatiallyVaryingFilters.h" +# include "stir_experimental/NonseparableSpatiallyVaryingFilters3D.h" +# include "stir_experimental/multiply_plane_scale_factorsImageProcessor.h" #endif #if 0 -#include "stir_experimental/AbsTimeIntervalWithParsing.h" -#ifdef HAVE_LLN_MATRIX -#include "stir_experimental/AbsTimeIntervalFromECAT7ACF.h" -#endif -#include "stir_experimental/AbsTimeIntervalFromDynamicData.h" +# include "stir_experimental/AbsTimeIntervalWithParsing.h" +# ifdef HAVE_LLN_MATRIX +# include "stir_experimental/AbsTimeIntervalFromECAT7ACF.h" +# endif +# include "stir_experimental/AbsTimeIntervalFromDynamicData.h" #endif START_NAMESPACE_STIR @@ -27,10 +27,10 @@ static SeparableGaussianImageFilter::RegisterIt dummy4; static ModifiedInverseAverigingImageFilter::RegisterIt dummy2; static DAVImageFilter3D::RegisterIt dummy1; -//static InverseSeparableCartesianMetzImageFilter ::RegisterIt dummy3; +// static InverseSeparableCartesianMetzImageFilter ::RegisterIt dummy3; static SeparableLowPassImageFilter::RegisterIt dummy4; -//static ModifiedInverseAveragingImageFilterAll::RegisterIt dummy6; -static NonseparableSpatiallyVaryingFilters:: RegisterIt dummy7; +// static ModifiedInverseAveragingImageFilterAll::RegisterIt dummy6; +static NonseparableSpatiallyVaryingFilters::RegisterIt dummy7; static NonseparableSpatiallyVaryingFilters3D::RegisterIt dummy8; #endif @@ -38,11 +38,10 @@ static NonseparableSpatiallyVaryingFilters3D::RegisterIt dummy8; static multiply_plane_scale_factorsImageProcessor::RegisterIt dummy101; static AbsTimeIntervalWithParsing::RegisterIt dummy200; -#ifdef HAVE_LLN_MATRIX +# ifdef HAVE_LLN_MATRIX static AbsTimeIntervalFromECAT7ACF::RegisterIt dummy201; -#endif +# endif static AbsTimeIntervalFromDynamicData::RegisterIt dummy202; #endif END_NAMESPACE_STIR - diff --git a/src/experimental/buildblock/local_helping_functions.cxx b/src/experimental/buildblock/local_helping_functions.cxx index 9ce261c2be..1fc8dc8cf3 100644 --- a/src/experimental/buildblock/local_helping_functions.cxx +++ b/src/experimental/buildblock/local_helping_functions.cxx @@ -16,155 +16,127 @@ using std::cerr; using std::endl; #endif - - START_NAMESPACE_STIR // divide complex arrays where elements are stored as follows: // A = array[ a(1), a(2), a(3), a(4), a(5), a(6), a(7), a(8), a(9),a(10)] // Re[A] = even coeff -// Im[A] = odd coeff +// Im[A] = odd coeff - -void divide_complex_arrays(Array<1,float>& out_array, const Array<1,float>& array_nom, - const Array<1,float>& array_denom) -{ - assert(array_nom.get_length()== array_denom.get_length()); - assert(out_array.get_length()== array_denom.get_length()); +void +divide_complex_arrays(Array<1, float>& out_array, const Array<1, float>& array_nom, const Array<1, float>& array_denom) { + assert(array_nom.get_length() == array_denom.get_length()); + assert(out_array.get_length() == array_denom.get_length()); out_array.fill(0); - + int i = 1; int j = 2; - while (j <=array_nom.get_max_index()) - { - float tmp = (array_denom[i]*array_denom[i])+(array_denom[j]*array_denom[j]); - out_array[i] = (array_nom[i]*array_denom[i] + array_nom[j]*array_denom[j])/tmp; - out_array[j] =(array_nom[j]*array_denom[i]-array_nom[i]*array_denom[j])/tmp; - i=i+2; - j=j+2; - + while (j <= array_nom.get_max_index()) { + float tmp = (array_denom[i] * array_denom[i]) + (array_denom[j] * array_denom[j]); + out_array[i] = (array_nom[i] * array_denom[i] + array_nom[j] * array_denom[j]) / tmp; + out_array[j] = (array_nom[j] * array_denom[i] - array_nom[i] * array_denom[j]) / tmp; + i = i + 2; + j = j + 2; } } -void mulitply_complex_arrays(Array<1,float>& out_array, const Array<1,float>& array_nom, - const Array<1,float>& array_denom) -{ - assert(array_nom.get_length()== array_denom.get_length()); - assert(out_array.get_length()== array_denom.get_length()); +void +mulitply_complex_arrays(Array<1, float>& out_array, const Array<1, float>& array_nom, const Array<1, float>& array_denom) { + assert(array_nom.get_length() == array_denom.get_length()); + assert(out_array.get_length() == array_denom.get_length()); out_array.fill(0); - + int i = 1; int j = 2; - while (j <=array_nom.get_max_index()) - { - out_array[i] = (array_nom[i]*array_denom[i] - array_nom[j]*array_denom[j]); - out_array[j] =(array_nom[j]*array_denom[i]+ array_nom[i]*array_denom[j]); - i=i+2; - j=j+2; - + while (j <= array_nom.get_max_index()) { + out_array[i] = (array_nom[i] * array_denom[i] - array_nom[j] * array_denom[j]); + out_array[j] = (array_nom[j] * array_denom[i] + array_nom[i] * array_denom[j]); + i = i + 2; + j = j + 2; } } // two argument implementation +void +mulitply_complex_arrays(Array<1, float>& array_nom, const Array<1, float>& array_denom) { -void mulitply_complex_arrays(Array<1,float>& array_nom, - const Array<1,float>& array_denom) -{ - - int i = 1; int j = 2; - while (j <=array_nom.get_max_index()) - { - float tmp1 =(array_nom[i]*array_denom[i] - array_nom[j]*array_denom[j]); - float tmp2 =(array_nom[j]*array_denom[i]+ array_nom[i]*array_denom[j]); - - array_nom[i] =tmp1 ; - array_nom[j] =tmp2 ; - i=i+2; - j=j+2; - + while (j <= array_nom.get_max_index()) { + float tmp1 = (array_nom[i] * array_denom[i] - array_nom[j] * array_denom[j]); + float tmp2 = (array_nom[j] * array_denom[i] + array_nom[i] * array_denom[j]); + + array_nom[i] = tmp1; + array_nom[j] = tmp2; + i = i + 2; + j = j + 2; } } +void +divide_complex_arrays(Array<1, float>& array_nom, const Array<1, float>& array_denom) { + // assert(array_nom.get_length()== array_denom.get_length()); + // assert(out_array.get_length()== array_denom.get_length()); + // out_array.fill(0); - -void divide_complex_arrays( Array<1,float>& array_nom, - const Array<1,float>& array_denom) -{ - //assert(array_nom.get_length()== array_denom.get_length()); - //assert(out_array.get_length()== array_denom.get_length()); - //out_array.fill(0); - int i = 1; int j = 2; - while (j <=array_nom.get_max_index()) - { - float denom = (array_denom[i]*array_denom[i])+(array_denom[j]*array_denom[j]); - float out1 = (array_nom[i]*array_denom[i] + array_nom[j]*array_denom[j])/denom; - float out2 = (array_nom[j]*array_denom[i]-array_nom[i]*array_denom[j])/denom; + while (j <= array_nom.get_max_index()) { + float denom = (array_denom[i] * array_denom[i]) + (array_denom[j] * array_denom[j]); + float out1 = (array_nom[i] * array_denom[i] + array_nom[j] * array_denom[j]) / denom; + float out2 = (array_nom[j] * array_denom[i] - array_nom[i] * array_denom[j]) / denom; - array_nom[i] = out1; + array_nom[i] = out1; array_nom[j] = out2; - i=i+2; - j=j+2; - + i = i + 2; + j = j + 2; } } - +void +create_kernel_3d(Array<3, float>& kernel_3d, const VectorWithOffset& kernel_1d) { -void create_kernel_3d ( Array<3,float>& kernel_3d, const VectorWithOffset < float>& kernel_1d) -{ + if (kernel_3d.get_min_index() == kernel_3d.get_max_index()) { + info("In the right loop"); + Array<2, float> kernel_2d( + IndexRange2D(kernel_1d.get_min_index(), kernel_1d.get_max_index(), kernel_1d.get_min_index(), kernel_1d.get_max_index())); - if (kernel_3d.get_min_index() ==kernel_3d.get_max_index()) - { - info("In the right loop"); - Array<2,float> kernel_2d(IndexRange2D(kernel_1d.get_min_index(), kernel_1d.get_max_index(), - kernel_1d.get_min_index(), kernel_1d.get_max_index())); - - for ( int j = kernel_3d[kernel_3d.get_min_index()].get_min_index(); j<=kernel_3d[kernel_3d.get_min_index()].get_max_index();j++) - for ( int i = kernel_3d[kernel_3d.get_min_index()][j].get_min_index(); i<=kernel_3d[kernel_3d.get_min_index()][j].get_max_index();i++) - { - kernel_2d[j][i] = kernel_1d[j]*kernel_1d[i]; + for (int j = kernel_3d[kernel_3d.get_min_index()].get_min_index(); j <= kernel_3d[kernel_3d.get_min_index()].get_max_index(); + j++) + for (int i = kernel_3d[kernel_3d.get_min_index()][j].get_min_index(); + i <= kernel_3d[kernel_3d.get_min_index()][j].get_max_index(); i++) { + kernel_2d[j][i] = kernel_1d[j] * kernel_1d[i]; } - for ( int k = kernel_3d.get_min_index(); k<=kernel_3d.get_max_index();k++) - for ( int j = kernel_3d[k].get_min_index(); j<=kernel_3d[k].get_max_index();j++) - for ( int i = kernel_3d[k][j].get_min_index(); i<=kernel_3d[k][j].get_max_index();i++) - { - kernel_3d[k][j][i] = kernel_2d[j][i]; - } + for (int k = kernel_3d.get_min_index(); k <= kernel_3d.get_max_index(); k++) + for (int j = kernel_3d[k].get_min_index(); j <= kernel_3d[k].get_max_index(); j++) + for (int i = kernel_3d[k][j].get_min_index(); i <= kernel_3d[k][j].get_max_index(); i++) { + kernel_3d[k][j][i] = kernel_2d[j][i]; } - else - { - for ( int k = kernel_3d.get_min_index(); k<=kernel_3d.get_max_index();k++) - for ( int j = kernel_3d[k].get_min_index(); j<=kernel_3d[k].get_max_index();j++) - for ( int i = kernel_3d[k][j].get_min_index(); i<=kernel_3d[k][j].get_max_index();i++) - { - kernel_3d[k][j][i] = kernel_1d[k]*kernel_1d[j]*kernel_1d[i]; - } - } - - + } else { + for (int k = kernel_3d.get_min_index(); k <= kernel_3d.get_max_index(); k++) + for (int j = kernel_3d[k].get_min_index(); j <= kernel_3d[k].get_max_index(); j++) + for (int i = kernel_3d[k][j].get_min_index(); i <= kernel_3d[k][j].get_max_index(); i++) { + kernel_3d[k][j][i] = kernel_1d[k] * kernel_1d[j] * kernel_1d[i]; + } + } } -void create_kernel_2d ( Array<2, float> & kernel_2d, const VectorWithOffset < float>& kernel_1d) -{ - - for ( int j = kernel_2d.get_min_index(); j<=kernel_2d.get_max_index();j++) - for ( int i = kernel_2d[j].get_min_index(); i<=kernel_2d[j].get_max_index();i++) - { - kernel_2d[j][i] = kernel_1d[j]*kernel_1d[i]; - } - +void +create_kernel_2d(Array<2, float>& kernel_2d, const VectorWithOffset& kernel_1d) { + for (int j = kernel_2d.get_min_index(); j <= kernel_2d.get_max_index(); j++) + for (int i = kernel_2d[j].get_min_index(); i <= kernel_2d[j].get_max_index(); i++) { + kernel_2d[j][i] = kernel_1d[j] * kernel_1d[i]; + } } // this function padds 3d filter kernel with zeros and also makes it symmetric -void padd_filter_coefficients_3D_and_make_them_symmetric(VectorWithOffset < VectorWithOffset < VectorWithOffset < float> > > &padded_filter_coefficients_3D, - VectorWithOffset < VectorWithOffset < VectorWithOffset < float> > > &filter_coefficients) - +void +padd_filter_coefficients_3D_and_make_them_symmetric( + VectorWithOffset>>& padded_filter_coefficients_3D, + VectorWithOffset>>& filter_coefficients) + { int min_z = padded_filter_coefficients_3D.get_min_index(); int max_z = padded_filter_coefficients_3D.get_max_index(); @@ -173,192 +145,164 @@ void padd_filter_coefficients_3D_and_make_them_symmetric(VectorWithOffset < Vect int min_x = padded_filter_coefficients_3D[min_z][min_y].get_min_index(); int max_x = padded_filter_coefficients_3D[min_z][min_y].get_max_index(); - int start_z = (filter_coefficients.get_max_index() -filter_coefficients.get_min_index())/2 -1; - int start_y = (filter_coefficients[start_z].get_max_index() -filter_coefficients[start_z].get_min_index())/2 -1; - int start_x = (filter_coefficients[start_z][start_y].get_max_index() -filter_coefficients[start_z][start_y].get_min_index())/2 -1; + int start_z = (filter_coefficients.get_max_index() - filter_coefficients.get_min_index()) / 2 - 1; + int start_y = (filter_coefficients[start_z].get_max_index() - filter_coefficients[start_z].get_min_index()) / 2 - 1; + int start_x = + (filter_coefficients[start_z][start_y].get_max_index() - filter_coefficients[start_z][start_y].get_min_index()) / 2 - 1; int end_z = filter_coefficients.get_max_index(); int end_y = filter_coefficients[end_z].get_max_index(); int end_x = filter_coefficients[end_z][end_y].get_max_index(); - + int size = padded_filter_coefficients_3D.get_length(); - - for ( int k=start_z; k <= end_z;k++) - { - for ( int j=start_y; j <= end_y;j++) - { - for ( int i=start_x; i <= end_x;i++) - { - float tmp = filter_coefficients[k][j][i]; - padded_filter_coefficients_3D[k+min_z][j+min_y][i+min_x] = filter_coefficients[k][j][i]; - info(boost::format("%1% ") % padded_filter_coefficients_3D[k+min_z][j+min_y][i+min_x]); - float tmp_1 = padded_filter_coefficients_3D[k+min_z][j+min_y][i+min_x]; - //padded_filter_coefficients_3D[size-pad_k][size-pad_j][size-pad_i] = filter_coefficients[k][j][i]; - } + + for (int k = start_z; k <= end_z; k++) { + for (int j = start_y; j <= end_y; j++) { + for (int i = start_x; i <= end_x; i++) { + float tmp = filter_coefficients[k][j][i]; + padded_filter_coefficients_3D[k + min_z][j + min_y][i + min_x] = filter_coefficients[k][j][i]; + info(boost::format("%1% ") % padded_filter_coefficients_3D[k + min_z][j + min_y][i + min_x]); + float tmp_1 = padded_filter_coefficients_3D[k + min_z][j + min_y][i + min_x]; + // padded_filter_coefficients_3D[size-pad_k][size-pad_j][size-pad_i] = filter_coefficients[k][j][i]; + } } } info(" Padded filter coefficients "); - for ( int k = -4;k<=4;k++) - for ( int j = -4;j<=4;j++) - for ( int i = -4;i<=4;i++) - { - info(boost::format("%1% ") % padded_filter_coefficients_3D[k][j][i]); + for (int k = -4; k <= 4; k++) + for (int j = -4; j <= 4; j++) + for (int i = -4; i <= 4; i++) { + info(boost::format("%1% ") % padded_filter_coefficients_3D[k][j][i]); } - - } - // convert 3d array into 1d where the output size is (x_size*y_size*z_size)*2. the faactor 2 // is used for the imaginary part in FT. -void convert_array_3D_into_1D_array( Array<1,float>& out_array,const Array<3,float>& in_array) -{ +void +convert_array_3D_into_1D_array(Array<1, float>& out_array, const Array<3, float>& in_array) { // check the sizes -- the outsput array should be twice the size of the input array because - // the data is stored as multidimesional complex array with real nad imaginary part - assert ( out_array.get_length() == (2 *in_array.get_length()*in_array[in_array.get_min_index()].get_length()* in_array[in_array.get_min_index()][in_array.get_min_index()].get_length())); - + // the data is stored as multidimesional complex array with real nad imaginary part + assert(out_array.get_length() == (2 * in_array.get_length() * in_array[in_array.get_min_index()].get_length() * + in_array[in_array.get_min_index()][in_array.get_min_index()].get_length())); + #if 1 - assert(out_array.get_min_index()==1); - assert(in_array.get_min_index()==1); - assert(in_array[1].get_min_index()==1); - assert(in_array[1][1].get_min_index()==1); - - Array<1,float> tmp_out_array(out_array.get_min_index(), out_array.get_max_index()); + assert(out_array.get_min_index() == 1); + assert(in_array.get_min_index() == 1); + assert(in_array[1].get_min_index() == 1); + assert(in_array[1][1].get_min_index() == 1); + + Array<1, float> tmp_out_array(out_array.get_min_index(), out_array.get_max_index()); int y_size = in_array[in_array.get_min_index()].get_length(); int x_size = in_array[in_array.get_min_index()][in_array.get_min_index()].get_length(); - for ( int k = in_array.get_min_index(); k<=in_array.get_max_index(); k++) - for ( int j = in_array[k].get_min_index(); j<=in_array[k].get_max_index(); j++) - for ( int i = in_array[k][j].get_min_index(); i<=in_array[k][j].get_max_index(); i++) - { - float tmp = in_array[k][j][i]; - float tmp_1 = ((j-1)*y_size+i)+(k-1)*(y_size*x_size); - tmp_out_array[((j-1)*y_size+i)+(k-1)*(y_size*x_size)] = in_array[k][j][i]; - + for (int k = in_array.get_min_index(); k <= in_array.get_max_index(); k++) + for (int j = in_array[k].get_min_index(); j <= in_array[k].get_max_index(); j++) + for (int i = in_array[k][j].get_min_index(); i <= in_array[k][j].get_max_index(); i++) { + float tmp = in_array[k][j][i]; + float tmp_1 = ((j - 1) * y_size + i) + (k - 1) * (y_size * x_size); + tmp_out_array[((j - 1) * y_size + i) + (k - 1) * (y_size * x_size)] = in_array[k][j][i]; } - - out_array[1] = tmp_out_array[1]; - + + out_array[1] = tmp_out_array[1]; + int r = 3; - for ( int k = tmp_out_array.get_min_index()+1; k<=tmp_out_array.get_max_index()/2; k++) - { - out_array[r] = tmp_out_array[k]; - r +=2; - } + for (int k = tmp_out_array.get_min_index() + 1; k <= tmp_out_array.get_max_index() / 2; k++) { + out_array[r] = tmp_out_array[k]; + r += 2; + } #else - Array<1,float>::iterator iter_1d = out_array.begin(); - Array<3,float>::const_full_iterator iter_3d = in_array.begin_all(); - while(iter_1d != out_array.end()) - { + Array<1, float>::iterator iter_1d = out_array.begin(); + Array<3, float>::const_full_iterator iter_3d = in_array.begin_all(); + while (iter_1d != out_array.end()) { *iter_1d++ = *iter_3d++; // real part - *iter_1d++ = 0; // imaginary part + *iter_1d++ = 0; // imaginary part } #endif } // real part only -> into 3D ( complex parta already separated) -void convert_array_1D_into_3D_array( Array<3,float>& out_array,const Array<1,float>& in_array) -{ +void +convert_array_1D_into_3D_array(Array<3, float>& out_array, const Array<1, float>& in_array) { #if 1 - assert(in_array.get_min_index()==1); - assert(out_array.get_min_index()==1); - assert(out_array[1].get_min_index()==1); - assert(out_array[1][1].get_min_index()==1); - - int z_size = out_array.get_length(); - int y_size = out_array[out_array.get_min_index()].get_length(); - int x_size = out_array[out_array.get_min_index()][out_array.get_min_index()].get_length(); - - - for ( int k = out_array.get_min_index(); k<=out_array.get_max_index(); k++) - for ( int j = out_array[k].get_min_index(); j<=out_array[k].get_max_index(); j++) - for ( int i = out_array[k][j].get_min_index(); i<=out_array[k][j].get_max_index(); i++) - { - out_array[k][j][i] = in_array[((j-1)*y_size+i)+(k-1)*(y_size*x_size)]; + assert(in_array.get_min_index() == 1); + assert(out_array.get_min_index() == 1); + assert(out_array[1].get_min_index() == 1); + assert(out_array[1][1].get_min_index() == 1); + + int z_size = out_array.get_length(); + int y_size = out_array[out_array.get_min_index()].get_length(); + int x_size = out_array[out_array.get_min_index()][out_array.get_min_index()].get_length(); + + for (int k = out_array.get_min_index(); k <= out_array.get_max_index(); k++) + for (int j = out_array[k].get_min_index(); j <= out_array[k].get_max_index(); j++) + for (int i = out_array[k][j].get_min_index(); i <= out_array[k][j].get_max_index(); i++) { + out_array[k][j][i] = in_array[((j - 1) * y_size + i) + (k - 1) * (y_size * x_size)]; } #else - Array<3,float>::full_iterator iter_3d = out_array.begin_all(); - Array<1,float>::const_iterator iter_1d = in_array.begin(); - while(iter_1d != in_array.end()) - { + Array<3, float>::full_iterator iter_3d = out_array.begin_all(); + Array<1, float>::const_iterator iter_1d = in_array.begin(); + while (iter_1d != in_array.end()) { *iter_3d++ = *iter_1d++; // real part - iter_1d++; // skip imaginary part + iter_1d++; // skip imaginary part } #endif - } - - - // convert 2d array into 1d where the output size is (x_size*y_size)*2. the faactor 2 // is used for the imaginary part in FT. -void convert_array_2D_into_1D_array( Array<1,float>& out_array,Array<2,float>& in_array) -{ - - Array<1,float> tmp_out_array(out_array.get_min_index(), out_array.get_max_index()); +void +convert_array_2D_into_1D_array(Array<1, float>& out_array, Array<2, float>& in_array) { + + Array<1, float> tmp_out_array(out_array.get_min_index(), out_array.get_max_index()); int y_size = in_array.get_length(); int x_size = in_array[in_array.get_min_index()].get_length(); // check the sizes -- the outsput array should be twice the size of the input array because - // the data is stored as multidimesional complex array with real nad imaginary part -// assert ( out_array.get_length() == (2 *in_array.get_length()*in_array[in_array_get_min_index()].get_length()* in_array[in_array_get_min_index()][in_array_get_min_index()].get_length())); - - for ( int j = in_array.get_min_index(); j<=in_array.get_max_index(); j++) - for ( int i = in_array[j].get_min_index(); i<=in_array[j].get_max_index(); i++) - { - float tmp = in_array[j][i]; - float tmp_1 = ((j-1)*y_size+i); - tmp_out_array[((j-1)*y_size+i)] = in_array[j][i]; - - } - - out_array[1] = tmp_out_array[1]; - - int r = 3; - for ( int k = tmp_out_array.get_min_index()+1; k<=tmp_out_array.get_max_index()/2; k++) - { - out_array[r] = tmp_out_array[k]; - r +=2; - } + // the data is stored as multidimesional complex array with real nad imaginary part + // assert ( out_array.get_length() == (2 *in_array.get_length()*in_array[in_array_get_min_index()].get_length()* + // in_array[in_array_get_min_index()][in_array_get_min_index()].get_length())); + + for (int j = in_array.get_min_index(); j <= in_array.get_max_index(); j++) + for (int i = in_array[j].get_min_index(); i <= in_array[j].get_max_index(); i++) { + float tmp = in_array[j][i]; + float tmp_1 = ((j - 1) * y_size + i); + tmp_out_array[((j - 1) * y_size + i)] = in_array[j][i]; + } + out_array[1] = tmp_out_array[1]; + + int r = 3; + for (int k = tmp_out_array.get_min_index() + 1; k <= tmp_out_array.get_max_index() / 2; k++) { + out_array[r] = tmp_out_array[k]; + r += 2; + } } // real part only -> into 3D ( complex parta already separated) -void convert_array_1D_into_2D_array( Array<2,float>& out_array,Array<1,float>& in_array) -{ +void +convert_array_1D_into_2D_array(Array<2, float>& out_array, Array<1, float>& in_array) { - int y_size = out_array.get_length(); - int x_size = out_array[out_array.get_min_index()].get_length(); + int y_size = out_array.get_length(); + int x_size = out_array[out_array.get_min_index()].get_length(); - - for ( int j = out_array.get_min_index(); j<=out_array.get_max_index(); j++) - for ( int i = out_array[j].get_min_index(); i<=out_array[j].get_max_index(); i++) - { - out_array[j][i] = in_array[((j-1)*y_size+i)]; - } + for (int j = out_array.get_min_index(); j <= out_array.get_max_index(); j++) + for (int i = out_array[j].get_min_index(); i <= out_array[j].get_max_index(); i++) { + out_array[j][i] = in_array[((j - 1) * y_size + i)]; + } } - -void precompute_filter_coefficients_for_second_apporach(VoxelsOnCartesianGrid& precomputed_coefficients, - const VoxelsOnCartesianGrid& input_image, - VoxelsOnCartesianGrid& sensitivity_image, - VoxelsOnCartesianGrid& normalised_bck) -{ - - for (int k=input_image.get_min_z();k<=input_image.get_max_z();k++) - for (int j =input_image.get_min_y();j<=input_image.get_max_y();j++) - for (int i =input_image.get_min_x();i<=input_image.get_max_x();i++) - { - if ( sensitivity_image[k][j][i]> 0.00001 ||sensitivity_image[k][j][i] < -0.00001) - precomputed_coefficients[k][j][i] = input_image[k][j][i] /sensitivity_image[k][j][i]; - precomputed_coefficients[k][j][i] = precomputed_coefficients[k][j][i] *normalised_bck[k][j][i]; +void +precompute_filter_coefficients_for_second_apporach(VoxelsOnCartesianGrid& precomputed_coefficients, + const VoxelsOnCartesianGrid& input_image, + VoxelsOnCartesianGrid& sensitivity_image, + VoxelsOnCartesianGrid& normalised_bck) { + + for (int k = input_image.get_min_z(); k <= input_image.get_max_z(); k++) + for (int j = input_image.get_min_y(); j <= input_image.get_max_y(); j++) + for (int i = input_image.get_min_x(); i <= input_image.get_max_x(); i++) { + if (sensitivity_image[k][j][i] > 0.00001 || sensitivity_image[k][j][i] < -0.00001) + precomputed_coefficients[k][j][i] = input_image[k][j][i] / sensitivity_image[k][j][i]; + precomputed_coefficients[k][j][i] = precomputed_coefficients[k][j][i] * normalised_bck[k][j][i]; } - - - - } - - + END_NAMESPACE_STIR diff --git a/src/experimental/buildblock/multiply_plane_scale_factorsImageProcessor.cxx b/src/experimental/buildblock/multiply_plane_scale_factorsImageProcessor.cxx index e3578d37e5..48463dd24a 100644 --- a/src/experimental/buildblock/multiply_plane_scale_factorsImageProcessor.cxx +++ b/src/experimental/buildblock/multiply_plane_scale_factorsImageProcessor.cxx @@ -26,113 +26,81 @@ using std::copy; START_NAMESPACE_STIR template <> -const char * const -multiply_plane_scale_factorsImageProcessor::registered_name = - "multiply_plane_scale_factors"; - +const char* const multiply_plane_scale_factorsImageProcessor::registered_name = "multiply_plane_scale_factors"; template void -multiply_plane_scale_factorsImageProcessor:: -set_defaults() -{ +multiply_plane_scale_factorsImageProcessor::set_defaults() { base_type::set_defaults(); plane_scale_factors.resize(0); } template -void -multiply_plane_scale_factorsImageProcessor:: -initialise_keymap() -{ +void +multiply_plane_scale_factorsImageProcessor::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("multiply_plane_scale_factors Parameters"); - this->parser.add_key("plane_scale_factors",&plane_scale_factors); + this->parser.add_key("plane_scale_factors", &plane_scale_factors); this->parser.add_stop_key("END multiply_plane_scale_factors Parameters"); } template -multiply_plane_scale_factorsImageProcessor:: -multiply_plane_scale_factorsImageProcessor() -{ +multiply_plane_scale_factorsImageProcessor::multiply_plane_scale_factorsImageProcessor() { set_defaults(); } template -multiply_plane_scale_factorsImageProcessor:: -multiply_plane_scale_factorsImageProcessor(const vector& plane_scale_factors) - : plane_scale_factors(plane_scale_factors) -{ -} +multiply_plane_scale_factorsImageProcessor::multiply_plane_scale_factorsImageProcessor( + const vector& plane_scale_factors) + : plane_scale_factors(plane_scale_factors) {} template -multiply_plane_scale_factorsImageProcessor:: -multiply_plane_scale_factorsImageProcessor(const VectorWithOffset& plane_scale_factors_v) -{ +multiply_plane_scale_factorsImageProcessor::multiply_plane_scale_factorsImageProcessor( + const VectorWithOffset& plane_scale_factors_v) { plane_scale_factors.resize(plane_scale_factors_v.get_length()); copy(plane_scale_factors_v.begin(), plane_scale_factors_v.end(), plane_scale_factors.begin()); } - + template Succeeded -multiply_plane_scale_factorsImageProcessor:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) +multiply_plane_scale_factorsImageProcessor::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { - if (density.get_length()!=static_cast(plane_scale_factors.size())) - { + if (density.get_length() != static_cast(plane_scale_factors.size())) { warning("multiply_plane_scale_factors: number of planes (%d) should be equal to number of scale factors (%d).\n", - density.get_length(),plane_scale_factors.size()); + density.get_length(), plane_scale_factors.size()); return Succeeded::no; - } - else - return Succeeded::yes; + } else + return Succeeded::yes; } - template void -multiply_plane_scale_factorsImageProcessor:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const - -{ - if (density.get_length()!=static_cast(plane_scale_factors.size())) - { - error("Exiting\n"); - } - for (int z=density.get_min_index(); - z<=density.get_max_index(); - ++z) - density[z] *= - static_cast - ( - plane_scale_factors[static_cast::size_type> - (z-density.get_min_index())] - ); -} +multiply_plane_scale_factorsImageProcessor::virtual_apply(DiscretisedDensity<3, elemT>& density) const +{ + if (density.get_length() != static_cast(plane_scale_factors.size())) { + error("Exiting\n"); + } + for (int z = density.get_min_index(); z <= density.get_max_index(); ++z) + density[z] *= + static_cast(plane_scale_factors[static_cast::size_type>(z - density.get_min_index())]); +} template void -multiply_plane_scale_factorsImageProcessor:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, - const DiscretisedDensity<3,elemT>& in_density) const -{ +multiply_plane_scale_factorsImageProcessor::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { out_density = in_density; virtual_apply(out_density); } - - -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif template class multiply_plane_scale_factorsImageProcessor; END_NAMESPACE_STIR - - - diff --git a/src/experimental/iterative/OSSPS/line_search.cxx b/src/experimental/iterative/OSSPS/line_search.cxx index c544df940b..f92ee6c416 100644 --- a/src/experimental/iterative/OSSPS/line_search.cxx +++ b/src/experimental/iterative/OSSPS/line_search.cxx @@ -22,32 +22,28 @@ \brief disabled implementation of doing a simple line search (from the stir::OSSPSReconstruction class) \author Kris Thielemans - + */ #error this code does not compile right now // only used in (disabled) line_search below -static -void accumulate_loglikelihood(RelatedViewgrams& projection_data, - const RelatedViewgrams& estimated_projections, - float* accum) -{ +static void +accumulate_loglikelihood(RelatedViewgrams& projection_data, const RelatedViewgrams& estimated_projections, + float* accum) { RelatedViewgrams::iterator p_iter = projection_data.begin(); RelatedViewgrams::iterator p_end = projection_data.end(); RelatedViewgrams::const_iterator e_iter = estimated_projections.begin(); - while (p_iter!= p_end) - { - accumulate_loglikelihood(*p_iter, *e_iter, /* rim_truncation_sino*/0, accum); - ++p_iter; ++e_iter; - } + while (p_iter != p_end) { + accumulate_loglikelihood(*p_iter, *e_iter, /* rim_truncation_sino*/ 0, accum); + ++p_iter; + ++e_iter; + } } - + template -float -OSSPSReconstruction:: -line_search(const TargetT& current_estimate, const TargetT& additive_update) -{ +float +OSSPSReconstruction::line_search(const TargetT& current_estimate, const TargetT& additive_update) { if (!this->do_line_search) return 1; @@ -57,157 +53,130 @@ line_search(const TargetT& current_estimate, const TargetT& additive_update) return 0; #else float result; - + CPUTimer timer; timer.reset(); timer.start(); - PoissonLogLikelihoodWithLinearModelForMeanAndProjData& - objective_function = - static_cast&> - (*this->objective_function_sptr); + PoissonLogLikelihoodWithLinearModelForMeanAndProjData& objective_function = + static_cast&>(*this->objective_function_sptr); shared_ptr symmetries_sptr = - objective_function.get_projector_pair().get_symmetries_used()->clone(); + objective_function.get_projector_pair().get_symmetries_used()->clone(); const double start_time = - objective_function.get_time_frame_definitions().get_start_time(objective_function.get_time_frame_num()); - const double end_time = - objective_function.get_time_frame_definitions().get_end_time(objective_function.get_time_frame_num()); + objective_function.get_time_frame_definitions().get_start_time(objective_function.get_time_frame_num()); + const double end_time = objective_function.get_time_frame_definitions().get_end_time(objective_function.get_time_frame_num()); - //for (int segment_num = -objective_function.get_max_segment_num_to_process(); + // for (int segment_num = -objective_function.get_max_segment_num_to_process(); // segment_num<= objective_function.get_max_segment_num_to_process(); - // ++segment_num) - // { - // for (int view = objective_function.get_proj_data().get_min_view_num(); - // view <= objective_function.get_proj_data().get_max_view_num(); + // ++segment_num) + // { + // for (int view = objective_function.get_proj_data().get_min_view_num(); + // view <= objective_function.get_proj_data().get_max_view_num(); // ++view) - const int segment_num=0; - const int view_num=0; + const int segment_num = 0; + const int view_num = 0; { const ViewSegmentNumbers view_segment_num(view_num, segment_num); - + if (!symmetries_sptr->is_basic(view_segment_num)) error("line search:seg 0, view 0 is not basic"); RelatedViewgrams measured_viewgrams = - objective_function.get_proj_data().get_related_viewgrams(view_segment_num, symmetries_sptr); - RelatedViewgrams forward_model_viewgrams = - measured_viewgrams.get_empty_copy(); + objective_function.get_proj_data().get_related_viewgrams(view_segment_num, symmetries_sptr); + RelatedViewgrams forward_model_viewgrams = measured_viewgrams.get_empty_copy(); { - objective_function.get_projector_pair().get_forward_projector_sptr()-> - forward_project(forward_model_viewgrams, current_estimate); - + objective_function.get_projector_pair().get_forward_projector_sptr()->forward_project(forward_model_viewgrams, + current_estimate); + objective_function.get_normalisation().undo(forward_model_viewgrams, start_time, end_time); - - const ProjData * const additive_ptr = - objective_function.get_additive_proj_data_sptr().get(); + + const ProjData* const additive_ptr = objective_function.get_additive_proj_data_sptr().get(); if (!is_null_ptr(additive_ptr)) - forward_model_viewgrams += - additive_ptr->get_related_viewgrams(view_segment_num, symmetries_sptr); + forward_model_viewgrams += additive_ptr->get_related_viewgrams(view_segment_num, symmetries_sptr); } - RelatedViewgrams forward_model_update_viewgrams = - measured_viewgrams.get_empty_copy(); + RelatedViewgrams forward_model_update_viewgrams = measured_viewgrams.get_empty_copy(); { - objective_function.get_projector_pair().get_forward_projector_sptr()-> - forward_project(forward_model_update_viewgrams, additive_update); + objective_function.get_projector_pair().get_forward_projector_sptr()->forward_project(forward_model_update_viewgrams, + additive_update); } - RelatedViewgrams tmp_viewgrams = - measured_viewgrams.get_empty_copy(); - -#define FUNC(value, alpha) \ - {\ - value = 0; \ - tmp_viewgrams = forward_model_update_viewgrams; \ - tmp_viewgrams *= alpha; \ - tmp_viewgrams += forward_model_viewgrams; \ - accumulate_loglikelihood(measured_viewgrams,\ - tmp_viewgrams, \ - &value);\ + RelatedViewgrams tmp_viewgrams = measured_viewgrams.get_empty_copy(); + +# define FUNC(value, alpha) \ + { \ + value = 0; \ + tmp_viewgrams = forward_model_update_viewgrams; \ + tmp_viewgrams *= alpha; \ + tmp_viewgrams += forward_model_viewgrams; \ + accumulate_loglikelihood(measured_viewgrams, tmp_viewgrams, &value); \ } // simple bisection - float min_alpha=.2;// used to be .1 - float max_alpha=10;// used to be 1000 - int iter_num=0; + float min_alpha = .2; // used to be .1 + float max_alpha = 10; // used to be 1000 + int iter_num = 0; float current = 1; - float previous=-1; // set somewhere crazy such that we do at least 1 iteration + float previous = -1; // set somewhere crazy such that we do at least 1 iteration float value_at_min; float value_at_max; float value_at_current; FUNC(value_at_min, min_alpha); FUNC(value_at_max, max_alpha); - while (iter_num++ != 100 && fabs(previous/current -1)>.02) - { - previous = current; - FUNC(value_at_current, current); - info(boost::format("line search at %1% value %2%") % current % value_at_current); - if (value_at_current <= value_at_min && - value_at_max <= value_at_current) - { - min_alpha = current; - value_at_min = value_at_current; - current = (current + max_alpha)/2; - } - else if (value_at_current <= value_at_max && value_at_min <= value_at_current) - { - max_alpha = current; - value_at_max = value_at_current; - current = (current + min_alpha)/2; - } - else - { - if (value_at_current > value_at_max || - value_at_current > value_at_min) - { - const float scale=(value_at_min+value_at_max)/2; - if (std::fabs((value_at_current - value_at_max)/scale) < .01 || - std::fabs((value_at_current - value_at_min)/scale) < .01) - { - // it's probably just rounding error, so we have converged - break; // out of while - } - warning("line search error. Function non-convex?\n" - "min %g (%g), curr %g (delta %g), max %g (delta %g)", - min_alpha, value_at_min, - current, value_at_current-value_at_min, - max_alpha, value_at_max-value_at_min - ); - const float list_from = std::max(0.F,min_alpha-1); - const float list_to = std::min(100.F,max_alpha+1); - const float increment = (list_to - list_from)/100; - for (current=list_from; current<=list_to; current += increment) - { - FUNC(value_at_current, current); - info(boost::format("%1% d %2%") % current % value_at_current-value_at_min); - } - exit(EXIT_FAILURE); - } - // need to decide if we go left or right - float half_way_left = (current + min_alpha)/2; - float value_at_half_way_left; - FUNC(value_at_half_way_left, half_way_left); - if (value_at_half_way_left > value_at_current) - { - // it has to be at the right - min_alpha = current; - value_at_min = value_at_current; - current = (current + max_alpha)/2; - } - else - { - // it's at the left. - // TODO we'll be recomputing the value here - max_alpha = current; - value_at_max = value_at_current; - current = (current + min_alpha)/2; - } - } - } // end of while + while (iter_num++ != 100 && fabs(previous / current - 1) > .02) { + previous = current; + FUNC(value_at_current, current); + info(boost::format("line search at %1% value %2%") % current % value_at_current); + if (value_at_current <= value_at_min && value_at_max <= value_at_current) { + min_alpha = current; + value_at_min = value_at_current; + current = (current + max_alpha) / 2; + } else if (value_at_current <= value_at_max && value_at_min <= value_at_current) { + max_alpha = current; + value_at_max = value_at_current; + current = (current + min_alpha) / 2; + } else { + if (value_at_current > value_at_max || value_at_current > value_at_min) { + const float scale = (value_at_min + value_at_max) / 2; + if (std::fabs((value_at_current - value_at_max) / scale) < .01 || + std::fabs((value_at_current - value_at_min) / scale) < .01) { + // it's probably just rounding error, so we have converged + break; // out of while + } + warning("line search error. Function non-convex?\n" + "min %g (%g), curr %g (delta %g), max %g (delta %g)", + min_alpha, value_at_min, current, value_at_current - value_at_min, max_alpha, value_at_max - value_at_min); + const float list_from = std::max(0.F, min_alpha - 1); + const float list_to = std::min(100.F, max_alpha + 1); + const float increment = (list_to - list_from) / 100; + for (current = list_from; current <= list_to; current += increment) { + FUNC(value_at_current, current); + info(boost::format("%1% d %2%") % current % value_at_current - value_at_min); + } + exit(EXIT_FAILURE); + } + // need to decide if we go left or right + float half_way_left = (current + min_alpha) / 2; + float value_at_half_way_left; + FUNC(value_at_half_way_left, half_way_left); + if (value_at_half_way_left > value_at_current) { + // it has to be at the right + min_alpha = current; + value_at_min = value_at_current; + current = (current + max_alpha) / 2; + } else { + // it's at the left. + // TODO we'll be recomputing the value here + max_alpha = current; + value_at_max = value_at_current; + current = (current + min_alpha) / 2; + } + } + } // end of while result = current; } timer.stop(); @@ -215,9 +184,9 @@ line_search(const TargetT& current_estimate, const TargetT& additive_update) info(boost::format("value for alpha %1%") % result); /* this->output_file_format_ptr-> - write_to_file("curr_est", current_estimate); + write_to_file("curr_est", current_estimate); this->output_file_format_ptr-> - write_to_file("upd", additive_update); + write_to_file("upd", additive_update); exit(0); */ diff --git a/src/experimental/listmode/CListModeDataLMF.cxx b/src/experimental/listmode/CListModeDataLMF.cxx index e7a929e78f..ad1e980756 100644 --- a/src/experimental/listmode/CListModeDataLMF.cxx +++ b/src/experimental/listmode/CListModeDataLMF.cxx @@ -7,19 +7,18 @@ \author Monica Vieira Martins \author Christian Morel \author Kris Thielemans - + */ /* Crystal Clear Collaboration Copyright (C) 2003 IPHE/UNIL, CH-1015 Lausanne Copyright (C) 2003- 2011, Hammersmith Imanet Ltd - This software is distributed under the terms + This software is distributed under the terms of the GNU Lesser General Public Licence (LGPL) See STIR/LICENSE.txt for details */ - #include "stir_experimental/listmode/CListModeDataLMF.h" #include "stir_experimental/listmode/CListRecordLMF.h" #include "stir/Succeeded.h" @@ -34,68 +33,57 @@ using std::streampos; START_NAMESPACE_STIR -CListModeDataLMF:: -CListModeDataLMF(const string& listmode_filename) - : listmode_filename(listmode_filename) -{ - //opening and reading file.cch, filling in structure LMF_cch +CListModeDataLMF::CListModeDataLMF(const string& listmode_filename) : listmode_filename(listmode_filename) { + // opening and reading file.cch, filling in structure LMF_cch // string::c_str() returns a "const char *", but LMFcchReader takes a "char*" // (which is a bad idea, unless you really want to modify the string) // at the moment, I gamble that LMFcchReader does not modify the string // TODO check (and ideally change argument types of LMFcchReader) - if(LMFcchReader(const_cast(listmode_filename.c_str()))) + if (LMFcchReader(const_cast(listmode_filename.c_str()))) exit(EXIT_FAILURE); - - //opening file.ccs - pfCCS = open_CCS_file2(listmode_filename.c_str()); /* open the LMF binary file */ - if(pfCCS==NULL) - error("Cannot open list mode file %s",listmode_filename.c_str()); - - fseek(pfCCS,0L,0); /* find the begin of file */ - //allocate and fill in the encoding header structure + + // opening file.ccs + pfCCS = open_CCS_file2(listmode_filename.c_str()); /* open the LMF binary file */ + if (pfCCS == NULL) + error("Cannot open list mode file %s", listmode_filename.c_str()); + + fseek(pfCCS, 0L, 0); /* find the begin of file */ + // allocate and fill in the encoding header structure pEncoH = readHead(pfCCS); // TODO set scanner_ptr somehow - //fill scanner check list + // fill scanner check list // scanCheckList = fill_ScannerCheckList(scanCheckList, pEncoH); } -CListModeDataLMF:: -~CListModeDataLMF() -{ - if(pfCCS) { +CListModeDataLMF::~CListModeDataLMF() { + if (pfCCS) { fclose(pfCCS); } LMFcchReaderDestructor(); - destroyReadHead();//ccsReadHeadDestructor + destroyReadHead(); // ccsReadHeadDestructor destroy_findXYZinLMFfile(pEncoH); } -shared_ptr -CListModeDataLMF:: -get_empty_record_sptr() const -{ +shared_ptr +CListModeDataLMF::get_empty_record_sptr() const { return new CListRecordLMF; } Succeeded -CListModeDataLMF:: -get_next_record(CListRecord& record) const -{ +CListModeDataLMF::get_next_record(CListRecord& record) const { if (is_null_ptr(pfCCS)) return Succeeded::no; // check type - assert(dynamic_cast(&record) != 0); + assert(dynamic_cast(&record) != 0); - // TODO ignores time + // TODO ignores time double x1, y1, z1, x2, y2, z2; - if (!findXYZinLMFfile(pfCCS, - &x1, &y1, &z1, &x2, &y2, &z2, - pEncoH)) - return Succeeded::no; + if (!findXYZinLMFfile(pfCCS, &x1, &y1, &z1, &x2, &y2, &z2, pEncoH)) + return Succeeded::no; CListEventDataLMF event_data; event_data.pos1().x() = static_cast(x1); @@ -112,13 +100,11 @@ get_next_record(CListRecord& record) const } Succeeded -CListModeDataLMF:: -reset() -{ +CListModeDataLMF::reset() { if (is_null_ptr(pfCCS)) return Succeeded::no; - if (!fseek(pfCCS,0L,0)) /* find the begin of file */ + if (!fseek(pfCCS, 0L, 0)) /* find the begin of file */ return Succeeded::no; else return Succeeded::yes; @@ -127,20 +113,16 @@ reset() // TODO do ftell and fseek really tell/change about the current listmode event // or is there another LMF function? CListModeData::SavedPosition -CListModeDataLMF:: -save_get_position() -{ +CListModeDataLMF::save_get_position() { assert(!is_null_ptr(pfCCS)); // TODO should somehow check if ftell() worked and return an error if it didn't const unsigned long pos = ftell(pfCCS); saved_get_positions.push_back(pos); - return saved_get_positions.size()-1; -} + return saved_get_positions.size() - 1; +} Succeeded -CListModeDataLMF:: -set_get_position(const CListModeDataLMF::SavedPosition& pos) -{ +CListModeDataLMF::set_get_position(const CListModeDataLMF::SavedPosition& pos) { if (is_null_ptr(pfCCS)) return Succeeded::no; diff --git a/src/experimental/listmode/LmToProjDataWithMC.cxx b/src/experimental/listmode/LmToProjDataWithMC.cxx index 626ea28731..53eb76d845 100644 --- a/src/experimental/listmode/LmToProjDataWithMC.cxx +++ b/src/experimental/listmode/LmToProjDataWithMC.cxx @@ -21,76 +21,60 @@ START_NAMESPACE_STIR -void -LmToProjDataWithMC::set_defaults() -{ +void +LmToProjDataWithMC::set_defaults() { LmToProjData::set_defaults(); reference_position_is_average_position_in_frame = false; _reference_abs_time_sptr.reset(); - ro3d_ptr.reset(); + ro3d_ptr.reset(); } -void -LmToProjDataWithMC::initialise_keymap() -{ +void +LmToProjDataWithMC::initialise_keymap() { LmToProjData::initialise_keymap(); parser.add_start_key("LmToProjDataWithMC Parameters"); - parser.add_key("reference_position_is_average_position_in_frame", - &reference_position_is_average_position_in_frame); - parser.add_parsing_key("time interval for reference position type", - &_reference_abs_time_sptr); - parser.add_parsing_key("Rigid Object 3D Motion Type", &ro3d_ptr); + parser.add_key("reference_position_is_average_position_in_frame", &reference_position_is_average_position_in_frame); + parser.add_parsing_key("time interval for reference position type", &_reference_abs_time_sptr); + parser.add_parsing_key("Rigid Object 3D Motion Type", &ro3d_ptr); } -LmToProjDataWithMC:: -LmToProjDataWithMC(const char * const par_filename) -{ +LmToProjDataWithMC::LmToProjDataWithMC(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - parse(par_filename) ; + if (par_filename != 0) + parse(par_filename); else ask_parameters(); - } bool -LmToProjDataWithMC:: -post_processing() -{ +LmToProjDataWithMC::post_processing() { if (LmToProjData::post_processing()) return true; - - if (is_null_ptr(ro3d_ptr)) - { + + if (is_null_ptr(ro3d_ptr)) { warning("Invalid Rigid Object 3D Motion object\n"); return true; } - if (reference_position_is_average_position_in_frame) - { - if (!is_null_ptr(_reference_abs_time_sptr)) - { - warning("time interval for reference position is set, but you asked for average over each frame"); - return true; - } + if (reference_position_is_average_position_in_frame) { + if (!is_null_ptr(_reference_abs_time_sptr)) { + warning("time interval for reference position is set, but you asked for average over each frame"); + return true; + } + } else { + // set transformation_to_reference_position + if (is_null_ptr(_reference_abs_time_sptr)) { + warning("time interval for reference position is not set"); + return true; } - else { - // set transformation_to_reference_position - if (is_null_ptr(_reference_abs_time_sptr)) - { - warning("time interval for reference position is not set"); - return true; - } - { - const RigidObject3DTransformation av_motion = - this->ro3d_ptr-> - compute_average_motion_in_scanner_coords(*_reference_abs_time_sptr); - cerr << "Reference quaternion: " << av_motion.get_quaternion()<ro3d_ptr->compute_average_motion_in_scanner_coords(*_reference_abs_time_sptr); + cerr << "Reference quaternion: " << av_motion.get_quaternion() << endl; + cerr << "Reference translation: " << av_motion.get_translation() << endl; + _transformation_to_reference_position = av_motion.inverse(); } + } #ifdef FRAME_BASED_DT_CORR cerr << "LmToProjDataWithMC Using FRAME_BASED_DT_CORR\n"; @@ -106,78 +90,61 @@ post_processing() } void -LmToProjDataWithMC:: -start_new_time_frame(const unsigned int current_frame_num) -{ +LmToProjDataWithMC::start_new_time_frame(const unsigned int current_frame_num) { LmToProjData::start_new_time_frame(current_frame_num); - if (reference_position_is_average_position_in_frame) - { - const double start_time = frame_defs.get_start_time(current_frame_num); - const double end_time = frame_defs.get_end_time(current_frame_num); - const RigidObject3DTransformation av_motion = - this->ro3d_ptr-> - compute_average_motion_in_scanner_coords_rel_time(start_time, end_time); - cerr << "Reference quaternion: " << av_motion.get_quaternion()<ro3d_ptr->compute_average_motion_in_scanner_coords_rel_time(start_time, end_time); + cerr << "Reference quaternion: " << av_motion.get_quaternion() << endl; + cerr << "Reference translation: " << av_motion.get_translation() << endl; + _transformation_to_reference_position = av_motion.inverse(); + } } void -LmToProjDataWithMC:: -process_new_time_event(const CListTime& time_event) -{ - assert(fabs(current_time - time_event.get_time_in_secs())<.0001); - this->ro3dtrans = - compose(this->_transformation_to_reference_position, - this->ro3d_ptr->get_motion_in_scanner_coords_rel_time(current_time)); - +LmToProjDataWithMC::process_new_time_event(const CListTime& time_event) { + assert(fabs(current_time - time_event.get_time_in_secs()) < .0001); + this->ro3dtrans = + compose(this->_transformation_to_reference_position, this->ro3d_ptr->get_motion_in_scanner_coords_rel_time(current_time)); } -void -LmToProjDataWithMC::get_bin_from_event(Bin& bin, const CListEvent& event) const -{ +void +LmToProjDataWithMC::get_bin_from_event(Bin& bin, const CListEvent& event) const { const ProjDataInfoCylindricalNoArcCorr& proj_data_info = - static_cast(*template_proj_data_info_ptr); + static_cast(*template_proj_data_info_ptr); #ifndef FRAME_BASED_DT_CORR const double start_time = current_time; const double end_time = current_time; #else const double start_time = frame_defs.get_start_time(current_frame_num); - const double end_time =frame_defs.get_end_time(current_frame_num); + const double end_time = frame_defs.get_end_time(current_frame_num); #endif event.get_bin(bin, *this->proj_data_info_cyl_uncompressed_ptr); - if (bin.get_bin_value()<=0) + if (bin.get_bin_value() <= 0) return; // rejected for some strange reason - const float bin_efficiency = normalisation_ptr->get_bin_efficiency(bin,start_time,end_time); - - //Do the motion correction - this->ro3dtrans.transform_bin(bin, - proj_data_info, - *this->proj_data_info_cyl_uncompressed_ptr); - - if (bin.get_bin_value() > 0) - { - if (do_pre_normalisation) - { - // now normalise event taking into account the - // normalisation factor before motion correction - // Note: this normalisation is not really correct - // we need to take the number of uncompressed bins that - // contribute to this bin into account (will be done in - // do_post_normalisation). - // In addition, there is time-based normalisation. - // See Thielemans et al, Proc. MIC 2003 - bin.set_bin_value(1/bin_efficiency); - } - else - { - bin.set_bin_value(1); - } + const float bin_efficiency = normalisation_ptr->get_bin_efficiency(bin, start_time, end_time); + + // Do the motion correction + this->ro3dtrans.transform_bin(bin, proj_data_info, *this->proj_data_info_cyl_uncompressed_ptr); + + if (bin.get_bin_value() > 0) { + if (do_pre_normalisation) { + // now normalise event taking into account the + // normalisation factor before motion correction + // Note: this normalisation is not really correct + // we need to take the number of uncompressed bins that + // contribute to this bin into account (will be done in + // do_post_normalisation). + // In addition, there is time-based normalisation. + // See Thielemans et al, Proc. MIC 2003 + bin.set_bin_value(1 / bin_efficiency); + } else { + bin.set_bin_value(1); } - + } } - END_NAMESPACE_STIR diff --git a/src/experimental/listmode_utilities/change_lm_time_tags.cxx b/src/experimental/listmode_utilities/change_lm_time_tags.cxx index 334d1c9ef3..4de89265e6 100644 --- a/src/experimental/listmode_utilities/change_lm_time_tags.cxx +++ b/src/experimental/listmode_utilities/change_lm_time_tags.cxx @@ -5,27 +5,26 @@ For internal use only. */ /*! - \file + \file \ingroup listmode_utilities \brief Program to change time-tags of listmode data - + \author Kris Thielemans - + $Revision $ */ #include "stir/shared_ptr.h" #include "stir/ByteOrder.h" #include "stir/listmode/CListRecord.h" -#include "stir/listmode/CListRecordECAT966.h"// TODO get rid of this +#include "stir/listmode/CListRecordECAT966.h" // TODO get rid of this #include "stir/listmode/CListModeData.h" #include #include -static -void open_next(std::fstream& s, const std::string& filename_prefix, int& num) -{ +static void +open_next(std::fstream& s, const std::string& filename_prefix, int& num) { if (s.is_open()) s.close(); @@ -40,25 +39,18 @@ void open_next(std::fstream& s, const std::string& filename_prefix, int& num) ++num; } - - USING_NAMESPACE_STIR - - - - /************************ main ************************/ +int +main(int argc, char* argv[]) { -int main(int argc, char * argv[]) -{ - - if (argc!=4 && argc!=5) { + if (argc != 4 && argc != 5) { std::cerr << "Usage: " << argv[0] - << " \\\n\t output_filename_prefix input_filename_prefix\\\n" + << " \\\n\t output_filename_prefix input_filename_prefix\\\n" "\t time_offset_in_millisecs [output_file_number]\n" - "\noutput_file_number defaults to 1\n" + "\noutput_file_number defaults to 1\n" "Example arguments:\n" "\t fixed_H666_lm1 H666_lm1 30000 2\n"; exit(EXIT_FAILURE); @@ -66,12 +58,9 @@ int main(int argc, char * argv[]) const std::string output_filename_prefix = argv[1]; const std::string input_filename = argv[2]; const unsigned long time_offset_in_millisecs = atol(argv[3]); - int out_filename_counter = argc==5 ? atoi(argv[4]) : 1; - - shared_ptr - lm_data_ptr = - CListModeData::read_from_file(input_filename); + int out_filename_counter = argc == 5 ? atoi(argv[4]) : 1; + shared_ptr lm_data_ptr = CListModeData::read_from_file(input_filename); // go to the beginning of the binary data lm_data_ptr->reset(); @@ -79,56 +68,41 @@ int main(int argc, char * argv[]) unsigned long size_written = 0; std::fstream out_file; open_next(out_file, output_filename_prefix, out_filename_counter); - { + { // loop over all events in the listmode file - shared_ptr record_sptr = - lm_data_ptr->get_empty_record_sptr(); + shared_ptr record_sptr = lm_data_ptr->get_empty_record_sptr(); CListRecord& record = *record_sptr; - if (dynamic_cast(&record) == 0) + if (dynamic_cast(&record) == 0) error("Currently only works on 966 data. Code needs fixing."); - const unsigned record_size = - sizeof(static_cast(record).raw); - const bool do_byte_swap = - record_size>1 && - ByteOrder::big_endian != ByteOrder::get_native_order(); - - while (true) - { - if (lm_data_ptr->get_next_record(record) == Succeeded::no) - { - // no more events in file for some reason - break; //get out of while loop + const unsigned record_size = sizeof(static_cast(record).raw); + const bool do_byte_swap = record_size > 1 && ByteOrder::big_endian != ByteOrder::get_native_order(); + + while (true) { + if (lm_data_ptr->get_next_record(record) == Succeeded::no) { + // no more events in file for some reason + break; // get out of while loop + } + if (record.is_time()) { + const unsigned long new_time = record.time().get_time_in_millisecs() + time_offset_in_millisecs; + if (record.time().set_time_in_millisecs(new_time) == Succeeded::no) { + warning("Did not succeed in changing time. Stopping"); + break; } - if (record.is_time()) - { - const unsigned long new_time = - record.time().get_time_in_millisecs() + time_offset_in_millisecs; - if (record.time().set_time_in_millisecs(new_time) == Succeeded::no) - { - warning("Did not succeed in changing time. Stopping"); - break; - } - } - // WARNING: modifies record - if (do_byte_swap) - ByteOrder::swap_order(static_cast(record).raw); - out_file.write(reinterpret_cast(&static_cast(record).raw), - record_size); - if (!out_file) - error("Error writing to file"); - size_written += record_size; - - if (size_written >= 1912602624UL) - open_next(out_file, output_filename_prefix, out_filename_counter); - - } // end of while loop over all events - + } + // WARNING: modifies record + if (do_byte_swap) + ByteOrder::swap_order(static_cast(record).raw); + out_file.write(reinterpret_cast(&static_cast(record).raw), record_size); + if (!out_file) + error("Error writing to file"); + size_written += record_size; + + if (size_written >= 1912602624UL) + open_next(out_file, output_filename_prefix, out_filename_counter); + + } // end of while loop over all events } - return EXIT_SUCCESS; } - - - diff --git a/src/experimental/listmode_utilities/get_singles_info.cxx b/src/experimental/listmode_utilities/get_singles_info.cxx index d1f4d46537..4a2c04b79b 100644 --- a/src/experimental/listmode_utilities/get_singles_info.cxx +++ b/src/experimental/listmode_utilities/get_singles_info.cxx @@ -15,7 +15,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/TimeFrameDefinitions.h" #include "stir/data/SinglesRatesFromSglFile.h" @@ -30,31 +29,24 @@ using std::string; USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) { - - -int -main (int argc, char* argv[]) -{ - - if (argc!=5) - { - cerr << "Usage: " << argv[0] << " output_filename sgl_filename fdef_filename frame_num\n"; - exit(EXIT_FAILURE); - } + if (argc != 5) { + cerr << "Usage: " << argv[0] << " output_filename sgl_filename fdef_filename frame_num\n"; + exit(EXIT_FAILURE); + } const string output_filename = argv[1]; const string sgl_filename = argv[2]; const string frame_defs_filename = argv[3]; const unsigned frame_num = atoi(argv[4]); - // SinglesRatesFromSglFile object. ecat::ecat7::SinglesRatesFromSglFile singles_from_sgl; - + // Read in the singles file. singles_from_sgl.read_singles_from_sgl_file(sgl_filename); - // read time frame definitions const TimeFrameDefinitions frame_defs(frame_defs_filename); @@ -72,21 +64,18 @@ main (int argc, char* argv[]) // Retrieve start and end times for this frame. double start_time = frame_defs.get_start_time(frame_num); double end_time = frame_defs.get_end_time(frame_num); - + // Create a new FrameSinglesRates object for the frame. - FrameSinglesRates frame_singles_rates = - singles_from_sgl.get_rates_for_frame(start_time, end_time); + FrameSinglesRates frame_singles_rates = singles_from_sgl.get_rates_for_frame(start_time, end_time); - // Get scanner details and, from these, the number of singles units. - const Scanner *scanner = frame_singles_rates.get_scanner_ptr(); + const Scanner* scanner = frame_singles_rates.get_scanner_ptr(); int total_singles_units = scanner->get_num_singles_units(); - + // Now write to file - for(int singles_bin = 0 ; singles_bin < total_singles_units ; ++singles_bin) { - output << singles_bin << " " - << frame_singles_rates.get_singles_rate(singles_bin) << '\n'; + for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { + output << singles_bin << " " << frame_singles_rates.get_singles_rate(singles_bin) << '\n'; } - + return EXIT_SUCCESS; } diff --git a/src/experimental/listmode_utilities/lm_to_projdata_with_MC.cxx b/src/experimental/listmode_utilities/lm_to_projdata_with_MC.cxx index caf68bebac..30af40d5f4 100644 --- a/src/experimental/listmode_utilities/lm_to_projdata_with_MC.cxx +++ b/src/experimental/listmode_utilities/lm_to_projdata_with_MC.cxx @@ -1,14 +1,14 @@ // // /*! - \file + \file \ingroup listmode \brief main for LmToProjDataWithMC - + \author Kris Thielemans \author Sanida Mustafovic - + */ /* Copyright (C) 2003- 2003, Hammersmith Imanet @@ -27,11 +27,11 @@ using std::endl; /* Here's a sample .par file \verbatim -LmToProjDataWithMC Parameters := +LmToProjDataWithMC Parameters := input file := listmode data output filename := precorrected_MC_data.s - + Bin Normalisation type:= From ECAT7 Bin Normalisation From ECAT7:= normalisation_ECAT7_filename:= norm_filename.n @@ -39,31 +39,27 @@ End Bin Normalisation From ECAT7:= store_prompts:= delayed_increment:= - do_time_frame := + do_time_frame := start_time:= end_time:= num_segments_in_memory: - -*/ - +*/ USING_NAMESPACE_STIR - - USING_NAMESPACE_STIR -int main(int argc, char * argv[]) -{ - - if (argc!=1 && argc!=2) { +int +main(int argc, char* argv[]) { + + if (argc != 1 && argc != 2) { cerr << "Usage: " << argv[0] << " [par_file]\n"; exit(EXIT_FAILURE); } - LmToProjDataWithMC application(argc==2 ? argv[1] : 0); + LmToProjDataWithMC application(argc == 2 ? argv[1] : 0); application.process_data(); return EXIT_SUCCESS; diff --git a/src/experimental/motion/MatchTrackerAndScanner.cxx b/src/experimental/motion/MatchTrackerAndScanner.cxx index d7c634e654..e348e4eb10 100644 --- a/src/experimental/motion/MatchTrackerAndScanner.cxx +++ b/src/experimental/motion/MatchTrackerAndScanner.cxx @@ -10,7 +10,7 @@ \brief Implementation of class stir::MatchTrackerAndScanner. \author Kris Thielemans - + */ #include "stir_experimental/motion/MatchTrackerAndScanner.h" #include "stir/stream.h" @@ -27,142 +27,113 @@ #include #include #include -# ifdef BOOST_NO_STDC_NAMESPACE -namespace std { using ::sqrt; } -# endif +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::sqrt; +} +#endif START_NAMESPACE_STIR - -void -MatchTrackerAndScanner::set_defaults() -{ +void +MatchTrackerAndScanner::set_defaults() { this->_ro3d_sptr.reset(); - this->scan_start_time_secs_since_1970_UTC=-1; + this->scan_start_time_secs_since_1970_UTC = -1; this->relative_threshold = .1F; } -void -MatchTrackerAndScanner::initialise_keymap() -{ +void +MatchTrackerAndScanner::initialise_keymap() { parser.add_start_key("Match Tracker and Scanner Parameters"); - parser.add_key("scan_start_time_secs_since_1970_UTC", - &this->scan_start_time_secs_since_1970_UTC); - parser.add_key("time frame definition filename",&this->frame_definition_filename); - parser.add_parsing_key("Rigid Object 3D Motion Type", &this->_ro3d_sptr); + parser.add_key("scan_start_time_secs_since_1970_UTC", &this->scan_start_time_secs_since_1970_UTC); + parser.add_key("time frame definition filename", &this->frame_definition_filename); + parser.add_parsing_key("Rigid Object 3D Motion Type", &this->_ro3d_sptr); parser.add_key("image_filename_prefix", &this->_image_filename_prefix); parser.add_key("relative_threshold", &this->relative_threshold); parser.add_stop_key("END"); } -MatchTrackerAndScanner:: -MatchTrackerAndScanner(const char * const par_filename) -{ +MatchTrackerAndScanner::MatchTrackerAndScanner(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - { - if (parse(par_filename)==false) - exit(EXIT_FAILURE); - } - else + if (par_filename != 0) { + if (parse(par_filename) == false) + exit(EXIT_FAILURE); + } else ask_parameters(); - } bool -MatchTrackerAndScanner:: -post_processing() -{ - - if (scan_start_time_secs_since_1970_UTC==-1) - { - warning("scan_start_time_secs_since_1970_UTC not set.\n" - "Will use relative time (to RigidObjectMotion object, which for Polaris means relative to the start of the scan data you use for synchronisation)."); - scan_start_time = 0; +MatchTrackerAndScanner::post_processing() { + + if (scan_start_time_secs_since_1970_UTC == -1) { + warning("scan_start_time_secs_since_1970_UTC not set.\n" + "Will use relative time (to RigidObjectMotion object, which for Polaris means relative to the start of the scan data " + "you use for synchronisation)."); + scan_start_time = 0; + } else { + if (scan_start_time_secs_since_1970_UTC < 1000) { + warning("scan_start_time_secs_since_1970_UTC too small"); + return true; } - else { - if (scan_start_time_secs_since_1970_UTC<1000) - { - warning("scan_start_time_secs_since_1970_UTC too small"); - return true; - } - { - // convert to time_in_secs since midnight - time_t sec_time = scan_start_time_secs_since_1970_UTC; - - scan_start_time = - _ro3d_sptr->secs_since_1970_to_rel_time(sec_time); - } + // convert to time_in_secs since midnight + time_t sec_time = scan_start_time_secs_since_1970_UTC; + + scan_start_time = _ro3d_sptr->secs_since_1970_to_rel_time(sec_time); } - + } + // handle time frame definitions etc - if (frame_definition_filename.size()==0) - { - warning("Have to specify 'time frame_definition_filename'"); - return true; - } + if (frame_definition_filename.size() == 0) { + warning("Have to specify 'time frame_definition_filename'"); + return true; + } frame_defs = TimeFrameDefinitions(frame_definition_filename); - if (is_null_ptr(_ro3d_sptr)) - { + if (is_null_ptr(_ro3d_sptr)) { warning("Invalid Rigid Object 3D Motion object"); return true; } - - if (_image_filename_prefix.size()==0) - { + if (_image_filename_prefix.size() == 0) { warning("have to specify 'image_filename_prefix'"); return true; } - if (this->relative_threshold<0.F || this->relative_threshold>1.F) - { + if (this->relative_threshold < 0.F || this->relative_threshold > 1.F) { warning("this->relative_threshold has to be between 0 and 1"); return true; } return false; - } const TimeFrameDefinitions& -MatchTrackerAndScanner:: -get_time_frame_defs() const -{ +MatchTrackerAndScanner::get_time_frame_defs() const { return frame_defs; } - Succeeded -MatchTrackerAndScanner:: -run() -{ - std::vector > polaris_points; - std::vector > positions_in_scanner; +MatchTrackerAndScanner::run() { + std::vector> polaris_points; + std::vector> positions_in_scanner; std::cout << "\nI will now read the images and tracker data for each time frame.\n" - << "I will report intra-frame movement as the stddev w.r.t. mean position\n" - << "of the marker according to the tracker data. This is a value in mm.\n"; + << "I will report intra-frame movement as the stddev w.r.t. mean position\n" + << "of the marker according to the tracker data. This is a value in mm.\n"; - for (unsigned current_frame_num=1U; - current_frame_num<=this->get_time_frame_defs().get_num_frames(); - ++current_frame_num) + for (unsigned current_frame_num = 1U; current_frame_num <= this->get_time_frame_defs().get_num_frames(); ++current_frame_num) { + // read image and find maximum + CartesianCoordinate3D location_of_image_max_in_mm; { - // read image and find maximum - CartesianCoordinate3D location_of_image_max_in_mm; - { - char rest[50]; - sprintf(rest, "_f%ug1d0b0.hv", current_frame_num); - const string input_filename = this->get_image_filename_prefix() + rest; - - shared_ptr< DiscretisedDensity<3,float> > - input_image_sptr(read_from_file >(input_filename)); + char rest[50]; + sprintf(rest, "_f%ug1d0b0.hv", current_frame_num); + const string input_filename = this->get_image_filename_prefix() + rest; + shared_ptr> input_image_sptr(read_from_file>(input_filename)); #if 0 // old code that used the location of the maximum @@ -183,116 +154,86 @@ run() location_of_image_max_in_mm = grid_spacing * BasicCoordinate<3,float>(max_index); #else - // new code that uses centre of gravity - const VoxelsOnCartesianGrid * input_image_cartesian_ptr = - dynamic_cast< VoxelsOnCartesianGrid* > (input_image_sptr.get()); + // new code that uses centre of gravity + const VoxelsOnCartesianGrid* input_image_cartesian_ptr = + dynamic_cast*>(input_image_sptr.get()); - if (input_image_cartesian_ptr== 0) - { - error("Image '%s' should be voxels on a cartesian grid", - input_filename.c_str()); - } - const float threshold = - input_image_sptr->find_max() * this->relative_threshold; - threshold_lower(input_image_sptr->begin_all(), input_image_sptr->end_all(), - threshold); - (*input_image_sptr) -= threshold; - location_of_image_max_in_mm = - find_centre_of_gravity_in_mm(*input_image_cartesian_ptr); -#endif + if (input_image_cartesian_ptr == 0) { + error("Image '%s' should be voxels on a cartesian grid", input_filename.c_str()); } + const float threshold = input_image_sptr->find_max() * this->relative_threshold; + threshold_lower(input_image_sptr->begin_all(), input_image_sptr->end_all(), threshold); + (*input_image_sptr) -= threshold; + location_of_image_max_in_mm = find_centre_of_gravity_in_mm(*input_image_cartesian_ptr); +#endif + } - // now go through tracker data for this frame - { - const double start_time = - this->get_frame_start_time(current_frame_num); - const double end_time = - this->get_frame_end_time(current_frame_num); - - cerr << "\nDoing frame " << current_frame_num - << ": from " << start_time << " to " << end_time << endl; - - const std::vector sample_times = - this->get_motion(). - get_rel_time_of_samples(start_time, end_time); - - if (sample_times.size() == 0) - error("No tracker samples between %g and %g (relative to scan start)", - start_time, end_time); - - // some variables that will be used to compute the stddev over the frame - // to check intra-frame movement - CartesianCoordinate3D sum_location_in_tracker_coords(0,0,0); - CartesianCoordinate3D sum_square_location_in_tracker_coords(0,0,0); - CartesianCoordinate3D first_location_in_tracker_coords = - this->get_motion(). - get_motion_in_tracker_coords_rel_time(sample_times[0]).inverse(). - transform_point(CartesianCoordinate3D(0,0,0)); - - for (std::vector::const_iterator iter=sample_times.begin(); - iter != sample_times.end(); - ++iter) - { - CartesianCoordinate3D location_in_tracker_coords = - this->get_motion(). - get_motion_in_tracker_coords_rel_time(*iter).inverse(). - transform_point(CartesianCoordinate3D(0,0,0)); - polaris_points.push_back(location_in_tracker_coords); - positions_in_scanner.push_back(location_of_image_max_in_mm); - - sum_location_in_tracker_coords += - location_in_tracker_coords - first_location_in_tracker_coords; - sum_square_location_in_tracker_coords += - square(location_in_tracker_coords - first_location_in_tracker_coords); - } - // check if frame is uniform - const unsigned num_samples = sample_times.size(); - const CartesianCoordinate3D variance = - (sum_square_location_in_tracker_coords - - square(sum_location_in_tracker_coords)/num_samples)/ - (num_samples-1); - //std::cerr << sum_location_in_tracker_coords/num_samples - // << sum_square_location_in_tracker_coords/num_samples - // << variance; - // note: threshold with 0 before sqrt to avoid problems with rounding errors - const double stddev = - std::sqrt(std::max(0.F,(variance[1]+variance[2]+variance[3])/3)); - - if (stddev>2) - warning("Intra-frame motion for frame %d is too large: %g", - current_frame_num, stddev); - else - std::cerr << "Intra-frame motion for frame " << current_frame_num - << " : " << stddev; + // now go through tracker data for this frame + { + const double start_time = this->get_frame_start_time(current_frame_num); + const double end_time = this->get_frame_end_time(current_frame_num); + + cerr << "\nDoing frame " << current_frame_num << ": from " << start_time << " to " << end_time << endl; + + const std::vector sample_times = this->get_motion().get_rel_time_of_samples(start_time, end_time); + + if (sample_times.size() == 0) + error("No tracker samples between %g and %g (relative to scan start)", start_time, end_time); + + // some variables that will be used to compute the stddev over the frame + // to check intra-frame movement + CartesianCoordinate3D sum_location_in_tracker_coords(0, 0, 0); + CartesianCoordinate3D sum_square_location_in_tracker_coords(0, 0, 0); + CartesianCoordinate3D first_location_in_tracker_coords = this->get_motion() + .get_motion_in_tracker_coords_rel_time(sample_times[0]) + .inverse() + .transform_point(CartesianCoordinate3D(0, 0, 0)); + + for (std::vector::const_iterator iter = sample_times.begin(); iter != sample_times.end(); ++iter) { + CartesianCoordinate3D location_in_tracker_coords = + this->get_motion().get_motion_in_tracker_coords_rel_time(*iter).inverse().transform_point( + CartesianCoordinate3D(0, 0, 0)); + polaris_points.push_back(location_in_tracker_coords); + positions_in_scanner.push_back(location_of_image_max_in_mm); + + sum_location_in_tracker_coords += location_in_tracker_coords - first_location_in_tracker_coords; + sum_square_location_in_tracker_coords += square(location_in_tracker_coords - first_location_in_tracker_coords); } - } // end of loop over frames + // check if frame is uniform + const unsigned num_samples = sample_times.size(); + const CartesianCoordinate3D variance = + (sum_square_location_in_tracker_coords - square(sum_location_in_tracker_coords) / num_samples) / (num_samples - 1); + // std::cerr << sum_location_in_tracker_coords/num_samples + // << sum_square_location_in_tracker_coords/num_samples + // << variance; + // note: threshold with 0 before sqrt to avoid problems with rounding errors + const double stddev = std::sqrt(std::max(0.F, (variance[1] + variance[2] + variance[3]) / 3)); + + if (stddev > 2) + warning("Intra-frame motion for frame %d is too large: %g", current_frame_num, stddev); + else + std::cerr << "Intra-frame motion for frame " << current_frame_num << " : " << stddev; + } + } // end of loop over frames - //std::cout << positions_in_scanner; - //std::cout << polaris_points; + // std::cout << positions_in_scanner; + // std::cout << polaris_points; // now find match RigidObject3DTransformation transformation; - if (RigidObject3DTransformation:: - find_closest_transformation(this->_transformation_from_scanner_coords, - positions_in_scanner.begin(), positions_in_scanner.end(), - polaris_points.begin(), - Quaternion(1,0,0,0)) == - Succeeded::no) - { - warning("Could not find match"); // note: find_closest_transformation writes some more info - return Succeeded::no; - } - - const double RMSE = - RigidObject3DTransformation::RMSE(this->_transformation_from_scanner_coords, - positions_in_scanner.begin(), positions_in_scanner.end(), - polaris_points.begin()); - - std::cout << "\n\nResult for transformation from scanner to tracker:\n\t" - << this->_transformation_from_scanner_coords; - std::cout << "\nRMSE (in mm) = " << RMSE - << '\n'; - if (RMSE>4) + if (RigidObject3DTransformation::find_closest_transformation( + this->_transformation_from_scanner_coords, positions_in_scanner.begin(), positions_in_scanner.end(), + polaris_points.begin(), Quaternion(1, 0, 0, 0)) == Succeeded::no) { + warning("Could not find match"); // note: find_closest_transformation writes some more info + return Succeeded::no; + } + + const double RMSE = RigidObject3DTransformation::RMSE(this->_transformation_from_scanner_coords, positions_in_scanner.begin(), + positions_in_scanner.end(), polaris_points.begin()); + + std::cout << "\n\nResult for transformation from scanner to tracker:\n\t" << this->_transformation_from_scanner_coords; + std::cout << "\nRMSE (in mm) = " << RMSE << '\n'; + if (RMSE > 4) warning("RMSE is rather large. I'm expecting a value around 1.5 mm"); std::cout << "If this is ok, edit your file specifying the transformation.\n"; diff --git a/src/experimental/motion/NonRigidObjectTransformationUsingBSplines.cxx b/src/experimental/motion/NonRigidObjectTransformationUsingBSplines.cxx index f7e6d28874..3ca61422dc 100644 --- a/src/experimental/motion/NonRigidObjectTransformationUsingBSplines.cxx +++ b/src/experimental/motion/NonRigidObjectTransformationUsingBSplines.cxx @@ -14,7 +14,7 @@ */ #include "stir_experimental/motion/NonRigidObjectTransformationUsingBSplines.h" -#include "stir/stream.h"//xxx +#include "stir/stream.h" //xxx #include "stir/IO/read_from_file.h" #include "stir/numerics/determinant.h" #include "stir/IndexRange2D.h" @@ -36,105 +36,73 @@ START_NAMESPACE_STIR template <> -const char * const -NonRigidObjectTransformationUsingBSplines<3,float>::registered_name = "BSplines transformation"; - +const char* const NonRigidObjectTransformationUsingBSplines<3, float>::registered_name = "BSplines transformation"; //////////// functions for reading NCAT transformations /////////////////////// // (shouldn't be in this file) -static -Succeeded -parse_line(const std::string& deformation_field_from_NCAT_file, - std::istream& ncat_file, - CartesianCoordinate3D& current_voxel, - CartesianCoordinate3D& current_displacement) -{ +static Succeeded +parse_line(const std::string& deformation_field_from_NCAT_file, std::istream& ncat_file, + CartesianCoordinate3D& current_voxel, CartesianCoordinate3D& current_displacement) { std::string line; std::getline(ncat_file, line); - if (!ncat_file) - { - warning("Error reading line in NCAT file %s", deformation_field_from_NCAT_file.c_str()); - return Succeeded::no; - } - const std::string::size_type position = - line.find("FRAME"); + if (!ncat_file) { + warning("Error reading line in NCAT file %s", deformation_field_from_NCAT_file.c_str()); + return Succeeded::no; + } + const std::string::size_type position = line.find("FRAME"); CartesianCoordinate3D new_voxel_coords; CartesianCoordinate3D current_voxel_coords; int frame_num1, frame_num2; #if 1 - if ( - std::sscanf(line.c_str() + position, - "FRAME%d %f %f %f FRAME%d %f %f %f", - &frame_num1, - ¤t_voxel_coords.x(), ¤t_voxel_coords.y(), ¤t_voxel_coords.z(), - &frame_num2, - &new_voxel_coords.x(), &new_voxel_coords.y(), &new_voxel_coords.z()) - != 8) - { - warning("Error parsing line in NCAT file %s:\n\"%s\"\nstart position %d\ntext to parse:\n%s", - deformation_field_from_NCAT_file.c_str(), - line.c_str(), - position, - line.c_str() + position); - return Succeeded::no; - } + if (std::sscanf(line.c_str() + position, "FRAME%d %f %f %f FRAME%d %f %f %f", &frame_num1, ¤t_voxel_coords.x(), + ¤t_voxel_coords.y(), ¤t_voxel_coords.z(), &frame_num2, &new_voxel_coords.x(), &new_voxel_coords.y(), + &new_voxel_coords.z()) != 8) { + warning("Error parsing line in NCAT file %s:\n\"%s\"\nstart position %d\ntext to parse:\n%s", + deformation_field_from_NCAT_file.c_str(), line.c_str(), position, line.c_str() + position); + return Succeeded::no; + } current_displacement = new_voxel_coords - current_voxel_coords; #else // old version of NCAT output is slightly different - if ( - std::sscanf(line.c_str() + position, - "FRAME%d %f %f %f FRAME%d %f %f %f VECTOR %f %f %f", - &frame_num1, - ¤t_voxel_coords.x(), ¤t_voxel_coords.y(), ¤t_voxel_coords.z(), - &frame_num2, - &new_voxel_coords.x(), &new_voxel_coords.y(), &new_voxel_coords.z(), - ¤t_displacement.x(), ¤t_displacement.y(), ¤t_displacement.z()) - != 11) - { - warning("Error parsing line in NCAT file %s:\n\"%s\"\nstart position %d\ntext to parse:\n%s", - deformation_field_from_NCAT_file.c_str(), - line.c_str(), - position, - line.c_str() + position); - return Succeeded::no; - } - if (norm(new_voxel_coords - current_voxel_coords - current_displacement) > .1) - { - warning("Error in line in NCAT file %s: inconsistent coordinates\n\"%s\"", - deformation_field_from_NCAT_file.c_str(), - line.c_str()); - info(boost::format("%1% %2% %3% %4%") % new_voxel_coords % current_voxel_coords % current_displacement % new_voxel_coords - current_voxel_coords - current_displacement); - return Succeeded::no; - } + if (std::sscanf(line.c_str() + position, "FRAME%d %f %f %f FRAME%d %f %f %f VECTOR %f %f %f", &frame_num1, + ¤t_voxel_coords.x(), ¤t_voxel_coords.y(), ¤t_voxel_coords.z(), &frame_num2, + &new_voxel_coords.x(), &new_voxel_coords.y(), &new_voxel_coords.z(), ¤t_displacement.x(), + ¤t_displacement.y(), ¤t_displacement.z()) != 11) { + warning("Error parsing line in NCAT file %s:\n\"%s\"\nstart position %d\ntext to parse:\n%s", + deformation_field_from_NCAT_file.c_str(), line.c_str(), position, line.c_str() + position); + return Succeeded::no; + } + if (norm(new_voxel_coords - current_voxel_coords - current_displacement) > .1) { + warning("Error in line in NCAT file %s: inconsistent coordinates\n\"%s\"", deformation_field_from_NCAT_file.c_str(), + line.c_str()); + info(boost::format("%1% %2% %3% %4%") % new_voxel_coords % current_voxel_coords % current_displacement % new_voxel_coords - + current_voxel_coords - current_displacement); + return Succeeded::no; + } #endif - current_voxel = round(current_voxel_coords); - if (norm(BasicCoordinate<3,float>(current_voxel) - current_voxel_coords) > .01) - { - warning("Error in line in NCAT file %s: ORIG voxel coordinates are expected to be on the grid\n\"%s\"", - deformation_field_from_NCAT_file.c_str(), - line.c_str()); - return Succeeded::no; - } - return Succeeded::yes; + current_voxel = round(current_voxel_coords); + if (norm(BasicCoordinate<3, float>(current_voxel) - current_voxel_coords) > .01) { + warning("Error in line in NCAT file %s: ORIG voxel coordinates are expected to be on the grid\n\"%s\"", + deformation_field_from_NCAT_file.c_str(), line.c_str()); + return Succeeded::no; + } + return Succeeded::yes; } -static -Succeeded -set_deformation_field_from_NCAT_file(DeformationFieldOnCartesianGrid<3,float>& deformation_field, - const std::string& deformation_field_from_NCAT_file, - const CartesianCoordinate3D& image_size, - const CartesianCoordinate3D& grid_spacing, - const CartesianCoordinate3D& origin) -{ +static Succeeded +set_deformation_field_from_NCAT_file(DeformationFieldOnCartesianGrid<3, float>& deformation_field, + const std::string& deformation_field_from_NCAT_file, + const CartesianCoordinate3D& image_size, + const CartesianCoordinate3D& grid_spacing, + const CartesianCoordinate3D& origin) { std::ifstream ncat_file(deformation_field_from_NCAT_file.c_str()); - if (!ncat_file) - { - warning("Error opening NCAT file %s", deformation_field_from_NCAT_file.c_str()); - return Succeeded::no; - } + if (!ncat_file) { + warning("Error opening NCAT file %s", deformation_field_from_NCAT_file.c_str()); + return Succeeded::no; + } // skip first line { std::string line; @@ -149,136 +117,108 @@ set_deformation_field_from_NCAT_file(DeformationFieldOnCartesianGrid<3,float>& d info("start parsing NCAT"); CartesianCoordinate3D current_voxel; CartesianCoordinate3D current_displacement; - while (ncat_file) - { - if (parse_line(deformation_field_from_NCAT_file, - ncat_file, - current_voxel, - current_displacement) - != Succeeded::yes) - return Succeeded::no; - const CartesianCoordinate3D current_displacement_in_mm = - current_displacement * grid_spacing; - if (current_voxel[1] < deformation_field[1].get_min_index() || - current_voxel[1] > deformation_field[1].get_max_index() || - current_voxel[2] < deformation_field[1][current_voxel[1]].get_min_index() || - current_voxel[2] > deformation_field[1][current_voxel[1]].get_max_index() || - current_voxel[3] < deformation_field[1][current_voxel[1]][current_voxel[2]].get_min_index() || - current_voxel[3] > deformation_field[1][current_voxel[1]][current_voxel[2]].get_max_index()) - { - info(boost::format("Coordinates out of range : %1% %2%") % current_voxel % current_displacement); - return Succeeded::no; - } - deformation_field[1][current_voxel] = current_displacement_in_mm.z(); - deformation_field[2][current_voxel] = current_displacement_in_mm.y(); - deformation_field[3][current_voxel] = current_displacement_in_mm.x(); - if (ncat_file.eof()) - break; + while (ncat_file) { + if (parse_line(deformation_field_from_NCAT_file, ncat_file, current_voxel, current_displacement) != Succeeded::yes) + return Succeeded::no; + const CartesianCoordinate3D current_displacement_in_mm = current_displacement * grid_spacing; + if (current_voxel[1] < deformation_field[1].get_min_index() || current_voxel[1] > deformation_field[1].get_max_index() || + current_voxel[2] < deformation_field[1][current_voxel[1]].get_min_index() || + current_voxel[2] > deformation_field[1][current_voxel[1]].get_max_index() || + current_voxel[3] < deformation_field[1][current_voxel[1]][current_voxel[2]].get_min_index() || + current_voxel[3] > deformation_field[1][current_voxel[1]][current_voxel[2]].get_max_index()) { + info(boost::format("Coordinates out of range : %1% %2%") % current_voxel % current_displacement); + return Succeeded::no; } + deformation_field[1][current_voxel] = current_displacement_in_mm.z(); + deformation_field[2][current_voxel] = current_displacement_in_mm.y(); + deformation_field[3][current_voxel] = current_displacement_in_mm.x(); + if (ncat_file.eof()) + break; + } info("end parsing NCAT"); return Succeeded::yes; } /////////////// end of NCAT parsing stuff ////////////// - /////////////// binary ///////////////////////////////// -static -Succeeded -set_deformation_field_from_file(DeformationFieldOnCartesianGrid<3,float>& deformation_field, - CartesianCoordinate3D& grid_spacing, - CartesianCoordinate3D& origin, - const std::string& deformation_field_from_file_x, - const std::string& deformation_field_from_file_y, - const std::string& deformation_field_from_file_z) -{ - shared_ptr > - image_sptr(read_from_file >(deformation_field_from_file_z)); - if (is_null_ptr(image_sptr)) - { - error(boost::format("Error reading %1%") % deformation_field_from_file_z); - return Succeeded::no; - } - VoxelsOnCartesianGrid const * voxels_ptr = - dynamic_cast const *>(image_sptr.get()); - if (is_null_ptr(voxels_ptr)) - { - error(boost::format("Error reading %1%: should be of type VoxelsOnCartesianGrid") % deformation_field_from_file_z); - return Succeeded::no; - } +static Succeeded +set_deformation_field_from_file(DeformationFieldOnCartesianGrid<3, float>& deformation_field, + CartesianCoordinate3D& grid_spacing, CartesianCoordinate3D& origin, + const std::string& deformation_field_from_file_x, + const std::string& deformation_field_from_file_y, + const std::string& deformation_field_from_file_z) { + shared_ptr> image_sptr( + read_from_file>(deformation_field_from_file_z)); + if (is_null_ptr(image_sptr)) { + error(boost::format("Error reading %1%") % deformation_field_from_file_z); + return Succeeded::no; + } + VoxelsOnCartesianGrid const* voxels_ptr = dynamic_cast const*>(image_sptr.get()); + if (is_null_ptr(voxels_ptr)) { + error(boost::format("Error reading %1%: should be of type VoxelsOnCartesianGrid") % deformation_field_from_file_z); + return Succeeded::no; + } deformation_field[1] = *image_sptr; origin = image_sptr->get_origin(); grid_spacing = voxels_ptr->get_grid_spacing(); - image_sptr = - read_from_file >(deformation_field_from_file_y); - if (is_null_ptr(image_sptr)) - { - error(boost::format("Error reading %1%") % deformation_field_from_file_y.c_str()); - return Succeeded::no; - } + image_sptr = read_from_file>(deformation_field_from_file_y); + if (is_null_ptr(image_sptr)) { + error(boost::format("Error reading %1%") % deformation_field_from_file_y.c_str()); + return Succeeded::no; + } deformation_field[2] = *image_sptr; - image_sptr = - read_from_file >(deformation_field_from_file_x); - if (is_null_ptr(image_sptr)) - { - error(boost::format("Error reading %1%") % deformation_field_from_file_x.c_str()); - return Succeeded::no; - } + image_sptr = read_from_file>(deformation_field_from_file_x); + if (is_null_ptr(image_sptr)) { + error(boost::format("Error reading %1%") % deformation_field_from_file_x.c_str()); + return Succeeded::no; + } deformation_field[3] = *image_sptr; return Succeeded::yes; } -static -Succeeded -set_deformation_field_from_file(DeformationFieldOnCartesianGrid<3,float>& deformation_field, - CartesianCoordinate3D& grid_spacing, - CartesianCoordinate3D& origin, - const std::string& deformation_field_multicomponent_filename) -{ - // Read the multicomponent image - unique_ptr > > uptr = - read_from_file > >( - deformation_field_multicomponent_filename); - - const VoxelsOnCartesianGrid > &voxel_coords(*uptr); - - deformation_field[1] = Array<3,float>(voxel_coords.get_index_range()); - deformation_field[2] = Array<3,float>(voxel_coords.get_index_range()); - deformation_field[3] = Array<3,float>(voxel_coords.get_index_range()); - - // Loop over z, y and x - for (int k=voxel_coords.get_min_z(); k<=voxel_coords.get_max_z(); k++) - for (int j=voxel_coords.get_min_y(); j<=voxel_coords.get_max_y(); j++) - for (int i=voxel_coords.get_min_x(); i<=voxel_coords.get_max_x(); i++) - // Loop over the 3 dimensions - // (as there are different x, y and z images) - for (int a=1; a<=3; a++) - deformation_field[a][k][j][i] = voxel_coords[k][j][i][a]; - - grid_spacing = voxel_coords.get_grid_spacing(); - origin = voxel_coords.get_origin(); +static Succeeded +set_deformation_field_from_file(DeformationFieldOnCartesianGrid<3, float>& deformation_field, + CartesianCoordinate3D& grid_spacing, CartesianCoordinate3D& origin, + const std::string& deformation_field_multicomponent_filename) { + // Read the multicomponent image + unique_ptr>> uptr = + read_from_file>>(deformation_field_multicomponent_filename); + + const VoxelsOnCartesianGrid>& voxel_coords(*uptr); + + deformation_field[1] = Array<3, float>(voxel_coords.get_index_range()); + deformation_field[2] = Array<3, float>(voxel_coords.get_index_range()); + deformation_field[3] = Array<3, float>(voxel_coords.get_index_range()); + + // Loop over z, y and x + for (int k = voxel_coords.get_min_z(); k <= voxel_coords.get_max_z(); k++) + for (int j = voxel_coords.get_min_y(); j <= voxel_coords.get_max_y(); j++) + for (int i = voxel_coords.get_min_x(); i <= voxel_coords.get_max_x(); i++) + // Loop over the 3 dimensions + // (as there are different x, y and z images) + for (int a = 1; a <= 3; a++) + deformation_field[a][k][j][i] = voxel_coords[k][j][i][a]; + + grid_spacing = voxel_coords.get_grid_spacing(); + origin = voxel_coords.get_origin(); return Succeeded::yes; } template void -NonRigidObjectTransformationUsingBSplines:: -set_defaults() -{ - this->deformation_field_sptr.reset(new DeformationFieldOnCartesianGrid); +NonRigidObjectTransformationUsingBSplines::set_defaults() { + this->deformation_field_sptr.reset(new DeformationFieldOnCartesianGrid); this->_bspline_type = BSpline::cubic; - this->_origin = make_coordinate(0.F,0.F,0.F); + this->_origin = make_coordinate(0.F, 0.F, 0.F); } - template -void -NonRigidObjectTransformationUsingBSplines:: -initialise_keymap() -{ +void +NonRigidObjectTransformationUsingBSplines::initialise_keymap() { this->parser.add_key("grid spacing", &this->_grid_spacing); this->parser.add_key("origin", &this->_origin); this->parser.add_key("deformation field", this->deformation_field_sptr.get()); @@ -297,80 +237,56 @@ initialise_keymap() } template -void -NonRigidObjectTransformationUsingBSplines:: -set_key_values() -{ +void +NonRigidObjectTransformationUsingBSplines::set_key_values() { // TODO following is only correct if bspline coefficients are equal to samples - /* + /* for (int i=1; i<=num_dimensions; ++i) (*this->deformation_field_sptr)[i] = this->interpolator[i].get_coefficients(); */ this->_bspline_order = static_cast(this->_bspline_type); } - + template -bool -NonRigidObjectTransformationUsingBSplines:: -post_processing() -{ +bool +NonRigidObjectTransformationUsingBSplines::post_processing() { this->_bspline_type = static_cast(this->_bspline_order); - if ((*this->deformation_field_sptr)[1].size()==0) - { - if (this->_deformation_field_from_NCAT_file.size() == 0) - { - if (this->_deformation_field_from_file_z.size() == 0) - { - if (this->_deformation_field_multicomponent_filename.size() == 0) - { - warning("NonRigidObjectTransformationUsingBSplines:\n" + if ((*this->deformation_field_sptr)[1].size() == 0) { + if (this->_deformation_field_from_NCAT_file.size() == 0) { + if (this->_deformation_field_from_file_z.size() == 0) { + if (this->_deformation_field_multicomponent_filename.size() == 0) { + warning("NonRigidObjectTransformationUsingBSplines:\n" "you need to set either deformation_field, " "deformation_field_from_NCAT_file or deformation multicomponent filename"); - return true; - } - else - { - if (set_deformation_field_from_file(*(this->deformation_field_sptr), - this->_grid_spacing, - this->_origin, - this->_deformation_field_multicomponent_filename) - == Succeeded::no) - return true; - } - } - else - { - if (set_deformation_field_from_file(*(this->deformation_field_sptr), - this->_grid_spacing, - this->_origin, - this->_deformation_field_from_file_x, - this->_deformation_field_from_file_y, - this->_deformation_field_from_file_z) - == Succeeded::no) - return true; - } - - } - else - { - if (set_deformation_field_from_NCAT_file(*(this->deformation_field_sptr), - this->_deformation_field_from_NCAT_file, - this->_deformation_field_from_NCAT_size, - this->_grid_spacing, - this->_origin) - == Succeeded::no) - return true; - } + return true; + } else { + if (set_deformation_field_from_file(*(this->deformation_field_sptr), this->_grid_spacing, this->_origin, + this->_deformation_field_multicomponent_filename) == Succeeded::no) + return true; + } + } else { + if (set_deformation_field_from_file(*(this->deformation_field_sptr), this->_grid_spacing, this->_origin, + this->_deformation_field_from_file_x, this->_deformation_field_from_file_y, + this->_deformation_field_from_file_z) == Succeeded::no) + return true; + } + + } else { + if (set_deformation_field_from_NCAT_file(*(this->deformation_field_sptr), this->_deformation_field_from_NCAT_file, + this->_deformation_field_from_NCAT_size, this->_grid_spacing, + this->_origin) == Succeeded::no) + return true; } + } #ifndef NDEBUG info("Starting to compute interpolators"); #endif - for (int i=1; i<=num_dimensions; ++i) - this->interpolator[i] = - BSpline::BSplinesRegularGrid((*this->deformation_field_sptr)[i],this->_bspline_type); + for (int i = 1; i <= num_dimensions; ++i) + this->interpolator[i] = + BSpline::BSplinesRegularGrid((*this->deformation_field_sptr)[i], this->_bspline_type); #ifndef NDEBUG info("Done computing interpolators"); #endif @@ -378,99 +294,88 @@ post_processing() // at present, have to do this by assigning an object as opposed to 0 // in case we want to parse twice // WARNING: do not reassign a new pointer, as the keymap stores a pointer to the deformation_field object - *(this->deformation_field_sptr) = DeformationFieldOnCartesianGrid(); + *(this->deformation_field_sptr) = DeformationFieldOnCartesianGrid(); return false; } - template -NonRigidObjectTransformationUsingBSplines:: -NonRigidObjectTransformationUsingBSplines() -{ +NonRigidObjectTransformationUsingBSplines::NonRigidObjectTransformationUsingBSplines() { this->set_defaults(); } template -NonRigidObjectTransformationUsingBSplines:: -NonRigidObjectTransformationUsingBSplines(const std::string &filename_x, const std::string &filename_y, const std::string &filename_z, const int bspline_order) -{ - this->set_defaults(); +NonRigidObjectTransformationUsingBSplines::NonRigidObjectTransformationUsingBSplines( + const std::string& filename_x, const std::string& filename_y, const std::string& filename_z, const int bspline_order) { + this->set_defaults(); - // Get the origin and spacing from the x and assume it's the same for y and z - shared_ptr > image_sptr(read_from_file >(filename_x)); + // Get the origin and spacing from the x and assume it's the same for y and z + shared_ptr> image_sptr(read_from_file>(filename_x)); - if (is_null_ptr(image_sptr)) - error("Error reading %s", filename_x.c_str()); + if (is_null_ptr(image_sptr)) + error("Error reading %s", filename_x.c_str()); - VoxelsOnCartesianGrid const * voxels_ptr = dynamic_cast const *>(image_sptr.get()); + VoxelsOnCartesianGrid const* voxels_ptr = dynamic_cast const*>(image_sptr.get()); - if (is_null_ptr(voxels_ptr)) - error(boost::format("Error reading %1%: should be of type VoxelsOnCartesianGrid") % filename_x); + if (is_null_ptr(voxels_ptr)) + error(boost::format("Error reading %1%: should be of type VoxelsOnCartesianGrid") % filename_x); - this->_origin = image_sptr->get_origin(); - this->_grid_spacing = voxels_ptr->get_grid_spacing(); + this->_origin = image_sptr->get_origin(); + this->_grid_spacing = voxels_ptr->get_grid_spacing(); - this->_deformation_field_from_file_x = filename_x; - this->_deformation_field_from_file_y = filename_y; - this->_deformation_field_from_file_z = filename_z; - this->_deformation_field_multicomponent_filename = ""; + this->_deformation_field_from_file_x = filename_x; + this->_deformation_field_from_file_y = filename_y; + this->_deformation_field_from_file_z = filename_z; + this->_deformation_field_multicomponent_filename = ""; - this->_bspline_order = bspline_order; + this->_bspline_order = bspline_order; - this->post_processing(); + this->post_processing(); } template -NonRigidObjectTransformationUsingBSplines:: -NonRigidObjectTransformationUsingBSplines(const std::string &filename, const int bspline_order) -{ - this->set_defaults(); - - this->_deformation_field_multicomponent_filename = filename; - this->_deformation_field_from_file_x = ""; - this->_deformation_field_from_file_y = ""; - this->_deformation_field_from_file_z = ""; - this->_bspline_order = bspline_order; - - this->post_processing(); +NonRigidObjectTransformationUsingBSplines::NonRigidObjectTransformationUsingBSplines( + const std::string& filename, const int bspline_order) { + this->set_defaults(); + + this->_deformation_field_multicomponent_filename = filename; + this->_deformation_field_from_file_x = ""; + this->_deformation_field_from_file_y = ""; + this->_deformation_field_from_file_z = ""; + this->_bspline_order = bspline_order; + + this->post_processing(); } template -BasicCoordinate -NonRigidObjectTransformationUsingBSplines:: -transform_point(const BasicCoordinate& point) const -{ +BasicCoordinate +NonRigidObjectTransformationUsingBSplines::transform_point( + const BasicCoordinate& point) const { // note: current Bspline needs double here - const BasicCoordinate point_in_grid_coords = - BasicCoordinate((point - this->_origin)/this->_grid_spacing); - BasicCoordinate result; - for (int i=1; i<=num_dimensions; ++i) - result[i]= this->interpolator[i](point_in_grid_coords); + const BasicCoordinate point_in_grid_coords = + BasicCoordinate((point - this->_origin) / this->_grid_spacing); + BasicCoordinate result; + for (int i = 1; i <= num_dimensions; ++i) + result[i] = this->interpolator[i](point_in_grid_coords); return result + point; } template float -NonRigidObjectTransformationUsingBSplines:: -jacobian(const BasicCoordinate& point) const -{ +NonRigidObjectTransformationUsingBSplines::jacobian( + const BasicCoordinate& point) const { // note: current Bspline needs double here - const BasicCoordinate point_in_grid_coords = - BasicCoordinate((point - this->_origin)/this->_grid_spacing); - Array<2,float> jacobian_matrix(IndexRange2D(1,num_dimensions,1,num_dimensions)); - for (int i=1; i<=num_dimensions; ++i) - { - BasicCoordinate gradient = - this->interpolator[i].gradient(point_in_grid_coords)/ - this->_grid_spacing; - gradient[i] += 1; // take into account that we're only modelling deformation. - std::copy(gradient.begin(), gradient.end(), jacobian_matrix[i].begin()); - } - return - std::fabs(determinant(jacobian_matrix)); + const BasicCoordinate point_in_grid_coords = + BasicCoordinate((point - this->_origin) / this->_grid_spacing); + Array<2, float> jacobian_matrix(IndexRange2D(1, num_dimensions, 1, num_dimensions)); + for (int i = 1; i <= num_dimensions; ++i) { + BasicCoordinate gradient = this->interpolator[i].gradient(point_in_grid_coords) / this->_grid_spacing; + gradient[i] += 1; // take into account that we're only modelling deformation. + std::copy(gradient.begin(), gradient.end(), jacobian_matrix[i].begin()); + } + return std::fabs(determinant(jacobian_matrix)); } ////////////////////// instantiations -template class NonRigidObjectTransformationUsingBSplines<3,float>; +template class NonRigidObjectTransformationUsingBSplines<3, float>; END_NAMESPACE_STIR diff --git a/src/experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.cxx b/src/experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.cxx index 691f6bf768..c777bd9734 100644 --- a/src/experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.cxx +++ b/src/experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.cxx @@ -13,7 +13,6 @@ */ - #include "stir/recon_buildblock/DataSymmetriesForBins.h" #include "stir_experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h" #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" @@ -34,93 +33,79 @@ #include "stir/DataSymmetriesForViewSegmentNumbers.h" // include the following to set defaults #ifndef USE_PMRT -#include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" -#include "stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" +# include "stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h" #else -#include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" -#include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" -#include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" +# include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" +# include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" #endif #include "stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h" #include "stir/IO/OutputFileFormat.h" -#include +#include #include #include START_NAMESPACE_STIR -template -const char * const -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -registered_name = -"PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion"; +template +const char* const PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::registered_name = + "PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion"; -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_defaults() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_defaults() { base_type::set_defaults(); this->_input_filename = ""; - this->max_segment_num_to_process=-1; + this->max_segment_num_to_process = -1; // KT 20/06/2001 disabled - //num_views_to_add=1; + // num_views_to_add=1; this->_gated_proj_data_sptr.reset(); this->zero_seg0_end_planes = 0; this->_additive_projection_data_filename = "0"; this->_gated_additive_proj_data_sptr.reset(); - // set default for projector_pair_ptr #ifndef USE_PMRT - shared_ptr forward_projector_ptr - (new ForwardProjectorByBinUsingRayTracing()); - shared_ptr back_projector_ptr - (new BackProjectorByBinUsingInterpolation()); + shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingRayTracing()); + shared_ptr back_projector_ptr(new BackProjectorByBinUsingInterpolation()); #else - shared_ptr PM - (new ProjMatrixByBinUsingRayTracing()); - shared_ptr forward_projector_ptr - (new ForwardProjectorByBinUsingProjMatrixByBin(PM)); - shared_ptr back_projector_ptr - (new BackProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr back_projector_ptr(new BackProjectorByBinUsingProjMatrixByBin(PM)); #endif - this->projector_pair_ptr - .reset(new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); + this->projector_pair_ptr.reset(new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); // TODO at present we used a fixed size vector - this->_normalisation_sptrs.resize(1,20); - for (int gate_num=1; gate_num<=20; ++gate_num) + this->_normalisation_sptrs.resize(1, 20); + for (int gate_num = 1; gate_num <= 20; ++gate_num) this->_normalisation_sptrs[gate_num].reset(new TrivialBinNormalisation); this->frame_num = 1; this->frame_definition_filename = ""; - this->_forward_transformations.resize(1,20); + this->_forward_transformations.resize(1, 20); // image stuff - this->output_image_size_xy=-1; - this->output_image_size_z=-1; - this->zoom=1.F; - this->Xoffset=0.F; - this->Yoffset=0.F; + this->output_image_size_xy = -1; + this->output_image_size_z = -1; + this->zoom = 1.F; + this->Xoffset = 0.F; + this->Yoffset = 0.F; // KT 20/06/2001 new - this->Zoffset=0.F; - + this->Zoffset = 0.F; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -initialise_keymap() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion Parameters"); this->parser.add_stop_key("End PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion Parameters"); - this->parser.add_key("input filename",&this->_input_filename); + this->parser.add_key("input filename", &this->_input_filename); this->parser.add_key("maximum absolute segment number to process", &this->max_segment_num_to_process); this->parser.add_key("zero end planes of segment 0", &this->zero_seg0_end_planes); @@ -128,18 +113,18 @@ initialise_keymap() // image stuff this->parser.add_key("zoom", &this->zoom); - this->parser.add_key("XY output image size (in pixels)",&this->output_image_size_xy); - this->parser.add_key("Z output image size (in pixels)",&this->output_image_size_z); - //parser.add_key("X offset (in mm)", &this->Xoffset); // KT 10122001 added spaces - //parser.add_key("Y offset (in mm)", &this->Yoffset); - + this->parser.add_key("XY output image size (in pixels)", &this->output_image_size_xy); + this->parser.add_key("Z output image size (in pixels)", &this->output_image_size_z); + // parser.add_key("X offset (in mm)", &this->Xoffset); // KT 10122001 added spaces + // parser.add_key("Y offset (in mm)", &this->Yoffset); + this->parser.add_key("Z offset (in mm)", &this->Zoffset); this->parser.add_parsing_key("Projector pair type", &this->projector_pair_ptr); // TODO - this->parser.add_key("additive sinograms",&this->_additive_projection_data_filename); + this->parser.add_key("additive sinograms", &this->_additive_projection_data_filename); // normalisation (and attenuation correction) - this->parser.add_key("time frame definition filename", &this->frame_definition_filename); + this->parser.add_key("time frame definition filename", &this->frame_definition_filename); this->parser.add_key("time frame number", &this->frame_num); this->parser.add_parsing_key("Bin Normalisation type for gate 1", &this->_normalisation_sptrs[1]); this->parser.add_parsing_key("Bin Normalisation type for gate 2", &this->_normalisation_sptrs[2]); @@ -162,218 +147,171 @@ initialise_keymap() this->parser.add_parsing_key("Bin Normalisation type for gate 19", &this->_normalisation_sptrs[19]); this->parser.add_parsing_key("Bin Normalisation type for gate 20", &this->_normalisation_sptrs[20]); - - - this->parser.add_parsing_key("transformation type for gate 1", - &this->_forward_transformations[1]); - this->parser.add_parsing_key("transformation type for gate 2", - &this->_forward_transformations[2]); - this->parser.add_parsing_key("transformation type for gate 3", - &this->_forward_transformations[3]); - this->parser.add_parsing_key("transformation type for gate 4", - &this->_forward_transformations[4]); - this->parser.add_parsing_key("transformation type for gate 5", - &this->_forward_transformations[5]); - this->parser.add_parsing_key("transformation type for gate 6", - &this->_forward_transformations[6]); - this->parser.add_parsing_key("transformation type for gate 7", - &this->_forward_transformations[7]); - this->parser.add_parsing_key("transformation type for gate 8", - &this->_forward_transformations[8]); - this->parser.add_parsing_key("transformation type for gate 9", - &this->_forward_transformations[9]); - this->parser.add_parsing_key("transformation type for gate 10", - &this->_forward_transformations[10]); - this->parser.add_parsing_key("transformation type for gate 11", - &this->_forward_transformations[11]); - this->parser.add_parsing_key("transformation type for gate 12", - &this->_forward_transformations[12]); - this->parser.add_parsing_key("transformation type for gate 13", - &this->_forward_transformations[13]); - this->parser.add_parsing_key("transformation type for gate 14", - &this->_forward_transformations[14]); - this->parser.add_parsing_key("transformation type for gate 15", - &this->_forward_transformations[15]); - this->parser.add_parsing_key("transformation type for gate 16", - &this->_forward_transformations[16]); - this->parser.add_parsing_key("transformation type for gate 17", - &this->_forward_transformations[17]); - this->parser.add_parsing_key("transformation type for gate 18", - &this->_forward_transformations[18]); - this->parser.add_parsing_key("transformation type for gate 19", - &this->_forward_transformations[19]); - this->parser.add_parsing_key("transformation type for gate 20", - &this->_forward_transformations[20]); - - + this->parser.add_parsing_key("transformation type for gate 1", &this->_forward_transformations[1]); + this->parser.add_parsing_key("transformation type for gate 2", &this->_forward_transformations[2]); + this->parser.add_parsing_key("transformation type for gate 3", &this->_forward_transformations[3]); + this->parser.add_parsing_key("transformation type for gate 4", &this->_forward_transformations[4]); + this->parser.add_parsing_key("transformation type for gate 5", &this->_forward_transformations[5]); + this->parser.add_parsing_key("transformation type for gate 6", &this->_forward_transformations[6]); + this->parser.add_parsing_key("transformation type for gate 7", &this->_forward_transformations[7]); + this->parser.add_parsing_key("transformation type for gate 8", &this->_forward_transformations[8]); + this->parser.add_parsing_key("transformation type for gate 9", &this->_forward_transformations[9]); + this->parser.add_parsing_key("transformation type for gate 10", &this->_forward_transformations[10]); + this->parser.add_parsing_key("transformation type for gate 11", &this->_forward_transformations[11]); + this->parser.add_parsing_key("transformation type for gate 12", &this->_forward_transformations[12]); + this->parser.add_parsing_key("transformation type for gate 13", &this->_forward_transformations[13]); + this->parser.add_parsing_key("transformation type for gate 14", &this->_forward_transformations[14]); + this->parser.add_parsing_key("transformation type for gate 15", &this->_forward_transformations[15]); + this->parser.add_parsing_key("transformation type for gate 16", &this->_forward_transformations[16]); + this->parser.add_parsing_key("transformation type for gate 17", &this->_forward_transformations[17]); + this->parser.add_parsing_key("transformation type for gate 18", &this->_forward_transformations[18]); + this->parser.add_parsing_key("transformation type for gate 19", &this->_forward_transformations[19]); + this->parser.add_parsing_key("transformation type for gate 20", &this->_forward_transformations[20]); } -template +template bool -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -post_processing() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::post_processing() { if (base_type::post_processing() == true) return true; - if (this->_input_filename.length() == 0) - { warning("You need to specify an input file"); return true; } - - this->_gated_proj_data_sptr = GatedProjData::read_from_file(this->_input_filename); + if (this->_input_filename.length() == 0) { + warning("You need to specify an input file"); + return true; + } - // image stuff - if (this->zoom <= 0) - { warning("zoom should be positive"); return true; } - - if (this->output_image_size_xy!=-1 && this->output_image_size_xy<1) // KT 10122001 appended_xy - { warning("output image size xy must be positive (or -1 as default)"); return true; } - if (this->output_image_size_z!=-1 && this->output_image_size_z<1) // KT 10122001 new - { warning("output image size z must be positive (or -1 as default)"); return true; } + this->_gated_proj_data_sptr = GatedProjData::read_from_file(this->_input_filename); + // image stuff + if (this->zoom <= 0) { + warning("zoom should be positive"); + return true; + } - if (this->_additive_projection_data_filename != "0") + if (this->output_image_size_xy != -1 && this->output_image_size_xy < 1) // KT 10122001 appended_xy { - this->_gated_additive_proj_data_sptr = - GatedProjData::read_from_file(this->_additive_projection_data_filename); + warning("output image size xy must be positive (or -1 as default)"); + return true; + } + if (this->output_image_size_z != -1 && this->output_image_size_z < 1) // KT 10122001 new + { + warning("output image size z must be positive (or -1 as default)"); + return true; + } + + if (this->_additive_projection_data_filename != "0") { + this->_gated_additive_proj_data_sptr = GatedProjData::read_from_file(this->_additive_projection_data_filename); }; - // read time frame def - if (this->frame_definition_filename.size()!=0) + // read time frame def + if (this->frame_definition_filename.size() != 0) this->frame_defs = TimeFrameDefinitions(this->frame_definition_filename); - else - { - // make a single frame starting from 0 to 1. - std::vector > frame_times(1, std::pair(0,1)); - this->frame_defs = TimeFrameDefinitions(frame_times); - } + else { + // make a single frame starting from 0 to 1. + std::vector> frame_times(1, std::pair(0, 1)); + this->frame_defs = TimeFrameDefinitions(frame_times); + } return false; } template -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion< + TargetT>::PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion() { this->set_defaults(); } template -TargetT * -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -construct_target_ptr() const -{ - return - new VoxelsOnCartesianGrid (*this->_gated_proj_data_sptr->get_proj_data_info_sptr(), - static_cast(this->zoom), - CartesianCoordinate3D(static_cast(this->Zoffset), - static_cast(this->Yoffset), - static_cast(this->Xoffset)), - CartesianCoordinate3D(this->output_image_size_z, - this->output_image_size_xy, - this->output_image_size_xy) - ); +TargetT* +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::construct_target_ptr() const { + return new VoxelsOnCartesianGrid( + *this->_gated_proj_data_sptr->get_proj_data_info_sptr(), static_cast(this->zoom), + CartesianCoordinate3D(static_cast(this->Zoffset), static_cast(this->Yoffset), + static_cast(this->Xoffset)), + CartesianCoordinate3D(this->output_image_size_z, this->output_image_size_xy, this->output_image_size_xy)); } /*************************************************************** set_ functions ***************************************************************/ -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_proj_data_sptr(const shared_ptr& arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_proj_data_sptr( + const shared_ptr& arg) { this->_gated_proj_data_sptr = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_max_segment_num_to_process(const int arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_max_segment_num_to_process(const int arg) { this->max_segment_num_to_process = arg; - } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_zero_seg0_end_planes(const bool arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_zero_seg0_end_planes(const bool arg) { this->zero_seg0_end_planes = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_additive_proj_data_sptr(const shared_ptr& arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_additive_proj_data_sptr( + const shared_ptr& arg) { this->_gated_additive_proj_data_sptr = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_projector_pair_sptr(const shared_ptr& arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_projector_pair_sptr( + const shared_ptr& arg) { this->projector_pair_ptr = arg; - } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_frame_num(const int arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_frame_num(const int arg) { this->frame_num = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_frame_definitions(const TimeFrameDefinitions& arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_frame_definitions( + const TimeFrameDefinitions& arg) { this->frame_defs = arg; } /*************************************************************** set_up() ***************************************************************/ -template -Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_up_before_sensitivity(shared_ptr const& target_sptr) -{ - shared_ptr - proj_data_info_sptr(this->_gated_proj_data_sptr->get_proj_data_info_sptr()->clone()); - - if (this->max_segment_num_to_process==-1) - this->max_segment_num_to_process = - proj_data_info_sptr->get_max_segment_num(); - - if (this->max_segment_num_to_process > proj_data_info_sptr->get_max_segment_num()) - { - warning("max_segment_num_to_process (%d) is too large", - this->max_segment_num_to_process); - return Succeeded::no; - } +template +Succeeded +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_up_before_sensitivity( + shared_ptr const& target_sptr) { + shared_ptr proj_data_info_sptr(this->_gated_proj_data_sptr->get_proj_data_info_sptr()->clone()); + + if (this->max_segment_num_to_process == -1) + this->max_segment_num_to_process = proj_data_info_sptr->get_max_segment_num(); - proj_data_info_sptr-> - reduce_segment_range(-this->max_segment_num_to_process, - +this->max_segment_num_to_process); - - if (is_null_ptr(this->projector_pair_ptr)) - { warning("You need to specify a projector pair"); return Succeeded::no; } + if (this->max_segment_num_to_process > proj_data_info_sptr->get_max_segment_num()) { + warning("max_segment_num_to_process (%d) is too large", this->max_segment_num_to_process); + return Succeeded::no; + } + + proj_data_info_sptr->reduce_segment_range(-this->max_segment_num_to_process, +this->max_segment_num_to_process); + + if (is_null_ptr(this->projector_pair_ptr)) { + warning("You need to specify a projector pair"); + return Succeeded::no; + } // set projectors to be used for the calculations - this->projector_pair_ptr->set_up(proj_data_info_sptr, - target_sptr); + this->projector_pair_ptr->set_up(proj_data_info_sptr, target_sptr); // TODO check compatibility between symmetries for forward and backprojector - this->symmetries_sptr.reset( - this->projector_pair_ptr->get_back_projector_sptr()->get_symmetries_used()->clone()); + this->symmetries_sptr.reset(this->projector_pair_ptr->get_back_projector_sptr()->get_symmetries_used()->clone()); // initialise the objective functions for each gate { @@ -381,88 +319,53 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) shared_ptr empty_target_sptr(target_sptr->get_empty_copy()); this->_functions.resize(this->_gated_proj_data_sptr->get_num_gates()); - for (unsigned int gate_num=1; - gate_num<=this->_gated_proj_data_sptr->get_num_gates(); - ++gate_num) + for (unsigned int gate_num = 1; gate_num <= this->_gated_proj_data_sptr->get_num_gates(); ++gate_num) { + + PoissonLogLikelihoodWithLinearModelForMeanAndProjData objective_function; + + objective_function.set_proj_data_sptr(this->_gated_proj_data_sptr->get_proj_data_sptr(gate_num)); + objective_function.set_max_segment_num_to_process(this->max_segment_num_to_process); + objective_function.set_zero_seg0_end_planes(this->zero_seg0_end_planes); + { - - PoissonLogLikelihoodWithLinearModelForMeanAndProjData - objective_function; - - objective_function. - set_proj_data_sptr(this->_gated_proj_data_sptr->get_proj_data_sptr(gate_num)); - objective_function. - set_max_segment_num_to_process(this->max_segment_num_to_process); - objective_function. - set_zero_seg0_end_planes(this->zero_seg0_end_planes); - - { - shared_ptr projector_pair_sptr_this_gate; - - if (is_null_ptr(this->_forward_transformations[gate_num])) - { - projector_pair_sptr_this_gate = - this->projector_pair_ptr; - } - else - { - Transform3DObjectImageProcessor const * forward_transformer_ptr = - dynamic_cast const *> - (this->_forward_transformations[gate_num].get()); - if (forward_transformer_ptr==0) - { - warning("transformation type has to be Transform3DObjectImageProcessor"); - return Succeeded::no; - } - shared_ptr forward_projector_sptr_this_gate - ( - new PresmoothingForwardProjectorByBin(this->projector_pair_ptr-> - get_forward_projector_sptr(), - this->_forward_transformations[gate_num]) - ); - - shared_ptr > transpose_transformer_sptr - ( - //forward_transformer_ptr->clone() - new Transform3DObjectImageProcessor(*forward_transformer_ptr) - ); - // TODO get rid if dynamic cast when using boost::shared_ptr - Transform3DObjectImageProcessor & transpose_transformer = - dynamic_cast &>(*transpose_transformer_sptr); - transpose_transformer. - set_do_transpose(!forward_transformer_ptr->get_do_transpose()); - shared_ptr back_projector_sptr_this_gate - (new PostsmoothingBackProjectorByBin(this->projector_pair_ptr-> - get_back_projector_sptr(), - transpose_transformer_sptr) - ); - projector_pair_sptr_this_gate. - reset(new ProjectorByBinPairUsingSeparateProjectors - (forward_projector_sptr_this_gate, - back_projector_sptr_this_gate)); - } - objective_function. - set_projector_pair_sptr(projector_pair_sptr_this_gate); - } - if (is_null_ptr(this->_gated_additive_proj_data_sptr)) - { - shared_ptr nullsptr; - objective_function. - set_additive_proj_data_sptr(nullsptr); - } - else - { - objective_function. - set_additive_proj_data_sptr(this->_gated_additive_proj_data_sptr->get_proj_data_sptr(gate_num)); + shared_ptr projector_pair_sptr_this_gate; + + if (is_null_ptr(this->_forward_transformations[gate_num])) { + projector_pair_sptr_this_gate = this->projector_pair_ptr; + } else { + Transform3DObjectImageProcessor const* forward_transformer_ptr = + dynamic_cast const*>(this->_forward_transformations[gate_num].get()); + if (forward_transformer_ptr == 0) { + warning("transformation type has to be Transform3DObjectImageProcessor"); + return Succeeded::no; } - objective_function. - set_frame_num(this->frame_num); - objective_function. - set_frame_definitions(this->frame_defs); - objective_function. - set_normalisation_sptr(this->_normalisation_sptrs[gate_num]); - objective_function. - set_num_subsets(this->num_subsets); + shared_ptr forward_projector_sptr_this_gate(new PresmoothingForwardProjectorByBin( + this->projector_pair_ptr->get_forward_projector_sptr(), this->_forward_transformations[gate_num])); + + shared_ptr> transpose_transformer_sptr( + // forward_transformer_ptr->clone() + new Transform3DObjectImageProcessor(*forward_transformer_ptr)); + // TODO get rid if dynamic cast when using boost::shared_ptr + Transform3DObjectImageProcessor& transpose_transformer = + dynamic_cast&>(*transpose_transformer_sptr); + transpose_transformer.set_do_transpose(!forward_transformer_ptr->get_do_transpose()); + shared_ptr back_projector_sptr_this_gate(new PostsmoothingBackProjectorByBin( + this->projector_pair_ptr->get_back_projector_sptr(), transpose_transformer_sptr)); + projector_pair_sptr_this_gate.reset( + new ProjectorByBinPairUsingSeparateProjectors(forward_projector_sptr_this_gate, back_projector_sptr_this_gate)); + } + objective_function.set_projector_pair_sptr(projector_pair_sptr_this_gate); + } + if (is_null_ptr(this->_gated_additive_proj_data_sptr)) { + shared_ptr nullsptr; + objective_function.set_additive_proj_data_sptr(nullsptr); + } else { + objective_function.set_additive_proj_data_sptr(this->_gated_additive_proj_data_sptr->get_proj_data_sptr(gate_num)); + } + objective_function.set_frame_num(this->frame_num); + objective_function.set_frame_definitions(this->frame_defs); + objective_function.set_normalisation_sptr(this->_normalisation_sptrs[gate_num]); + objective_function.set_num_subsets(this->num_subsets); #if 0 // we need to prevent computation of the subsensitivities at present @@ -477,13 +380,12 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) set_sensitivity_sptr(empty_target_sptr, 0); } #endif - if (objective_function.set_up(empty_target_sptr) != Succeeded::yes) - error("Single gate objective functions is not set-up correctly!"); - - // TODO dangerous for -1 - this->_functions[gate_num-1] = objective_function; + if (objective_function.set_up(empty_target_sptr) != Succeeded::yes) + error("Single gate objective functions is not set-up correctly!"); - } + // TODO dangerous for -1 + this->_functions[gate_num - 1] = objective_function; + } } #if 0 if (base_type::set_up(target_sptr) != Succeeded::yes) @@ -497,21 +399,16 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) functions that compute the value/gradient of the objective function etc ***************************************************************/ -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion< + TargetT>::compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, const TargetT& current_estimate, + const int subset_num) { typename base_type::_functions_iterator_type iter = this->_functions.begin(); typename base_type::_functions_iterator_type end_iter = this->_functions.end(); - if (iter != end_iter) - { - iter->compute_sub_gradient_without_penalty_plus_sensitivity(gradient, - current_estimate, - subset_num); - } + if (iter != end_iter) { + iter->compute_sub_gradient_without_penalty_plus_sensitivity(gradient, current_estimate, subset_num); + } ++iter; if (iter == end_iter) return; @@ -519,53 +416,37 @@ compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, // TODO!!!!!!!! shared_ptr gradient_this_function_sptr(gradient.get_empty_copy()); - while (iter != end_iter) - { - iter->compute_sub_gradient_without_penalty_plus_sensitivity(*gradient_this_function_sptr, - current_estimate, - subset_num); - // now add it to the total gradient - typename TargetT::full_iterator gradient_iter = - gradient.begin_all(); - typename TargetT::full_iterator gradient_end = - gradient.end_all(); - typename TargetT::const_full_iterator gradient_this_function_iter = - gradient_this_function_sptr ->begin_all_const(); - while (gradient_iter != gradient_end) - { - *gradient_iter++ += *gradient_this_function_iter++; - } - ++iter; + while (iter != end_iter) { + iter->compute_sub_gradient_without_penalty_plus_sensitivity(*gradient_this_function_sptr, current_estimate, subset_num); + // now add it to the total gradient + typename TargetT::full_iterator gradient_iter = gradient.begin_all(); + typename TargetT::full_iterator gradient_end = gradient.end_all(); + typename TargetT::const_full_iterator gradient_this_function_iter = gradient_this_function_sptr->begin_all_const(); + while (gradient_iter != gradient_end) { + *gradient_iter++ += *gradient_this_function_iter++; } - - + ++iter; + } } - -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::add_subset_sensitivity( + TargetT& sensitivity, const int subset_num) const { typename base_type::_functions_const_iterator_type iter = this->_functions.begin(); typename base_type::_functions_const_iterator_type end_iter = this->_functions.end(); - while (iter != end_iter) - { - iter->add_subset_sensitivity(sensitivity, - subset_num); - - ++iter; - } + while (iter != end_iter) { + iter->add_subset_sensitivity(sensitivity, subset_num); + ++iter; + } } +#ifdef _MSC_VER +// prevent warning message on instantiation of abstract class +# pragma warning(disable : 4661) +#endif -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif - -template class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion >; +template class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion>; END_NAMESPACE_STIR - diff --git a/src/experimental/motion/Polaris_MT_File.cxx b/src/experimental/motion/Polaris_MT_File.cxx index 24e8b49607..93e567111e 100644 --- a/src/experimental/motion/Polaris_MT_File.cxx +++ b/src/experimental/motion/Polaris_MT_File.cxx @@ -1,14 +1,14 @@ // // /*! - \file + \file \ingroup motion \brief Implementation of class stir::Polaris_MT_File - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2003- 2010, Hammersmith Imanet Ltd @@ -22,232 +22,171 @@ using std::ifstream; #endif +START_NAMESPACE_STIR -START_NAMESPACE_STIR - -Polaris_MT_File::Polaris_MT_File(const std::string& mt_filename) -{ +Polaris_MT_File::Polaris_MT_File(const std::string& mt_filename) { ifstream mt_stream(mt_filename.c_str()); - if (!mt_stream) - { - error( "Polaris_MT_File: error opening file %s - Does it Exist?", mt_filename.c_str()) ; + if (!mt_stream) { + error("Polaris_MT_File: error opening file %s - Does it Exist?", mt_filename.c_str()); } - - const unsigned int MAX_STRING_LENGTH=512; + + const unsigned int MAX_STRING_LENGTH = 512; char DataStr[MAX_STRING_LENGTH]; /* Read opening line */ - if ( !mt_stream.getline( DataStr, MAX_STRING_LENGTH) ) - { - error("Polaris_MT_File: error reading Line 1 of file %s", - mt_filename.c_str()); - } + if (!mt_stream.getline(DataStr, MAX_STRING_LENGTH)) { + error("Polaris_MT_File: error reading Line 1 of file %s", mt_filename.c_str()); + } // find out which file format this file was written in - if (strncmp(DataStr, "Collection Data", 14)==0) - { - // Output of NDI Toolviewer - // format of first line - // Collection Data : Port 0B ( ICL S/N: 3608C803 Type: 01000000 Rev: 000 ) - read_NDI_Toolviewer_mt_file(mt_filename, mt_stream, DataStr); - } - else - { - // it's of the following format - //23/5/2003 18:18:32 - 11 1 966_IRSL_II - read_Peter_Bloomfield_mt_file(mt_filename, mt_stream, DataStr); - } + if (strncmp(DataStr, "Collection Data", 14) == 0) { + // Output of NDI Toolviewer + // format of first line + // Collection Data : Port 0B ( ICL S/N: 3608C803 Type: 01000000 Rev: 000 ) + read_NDI_Toolviewer_mt_file(mt_filename, mt_stream, DataStr); + } else { + // it's of the following format + // 23/5/2003 18:18:32 - 11 1 966_IRSL_II + read_Peter_Bloomfield_mt_file(mt_filename, mt_stream, DataStr); + } mt_stream.close(); -} +} void -Polaris_MT_File:: -read_Peter_Bloomfield_mt_file(const std::string& mt_filename, std::istream& mt_stream, const char * const first_line) -{ - const unsigned int MAX_STRING_LENGTH=512; +Polaris_MT_File::read_Peter_Bloomfield_mt_file(const std::string& mt_filename, std::istream& mt_stream, + const char* const first_line) { + const unsigned int MAX_STRING_LENGTH = 512; // parse first line { int v1, v2; char toolkit[MAX_STRING_LENGTH]; std::tm start_time_tm; - if (sscanf(first_line, "%d/%d/%d %d:%d:%d - %d %d %511s", - &start_time_tm.tm_mday, - &start_time_tm.tm_mon, - &start_time_tm.tm_year, - &start_time_tm.tm_hour, - &start_time_tm.tm_min, - &start_time_tm.tm_sec, - &v1, - &v2, - toolkit) != 9) - error("Polaris_MT_File: error parsing first line of file %s", - mt_filename.c_str()); + if (sscanf(first_line, "%d/%d/%d %d:%d:%d - %d %d %511s", &start_time_tm.tm_mday, &start_time_tm.tm_mon, + &start_time_tm.tm_year, &start_time_tm.tm_hour, &start_time_tm.tm_min, &start_time_tm.tm_sec, &v1, &v2, + toolkit) != 9) + error("Polaris_MT_File: error parsing first line of file %s", mt_filename.c_str()); start_time_tm.tm_mon -= 1; start_time_tm.tm_year -= 1900; start_time_tm.tm_isdst = -1; - start_time_in_secs_since_1970 = - mktime(&start_time_tm); + start_time_in_secs_since_1970 = mktime(&start_time_tm); if (start_time_in_secs_since_1970 == std::time_t(-1)) - error("Polaris_MT_File: error interpreting data/time in first line of mt file %s", - mt_filename.c_str()); + error("Polaris_MT_File: error interpreting data/time in first line of mt file %s", mt_filename.c_str()); std::cout << "\nPolaris .mt file info:" - << "\n\tDate: " << asctime(&start_time_tm) - << "\t\twhich is " << start_time_in_secs_since_1970 << " secs since 1970 UTC" - << "\n\tToolkit: " << toolkit - << "\n\tVersion info (?): " << v1 << ' ' << v2 << std::endl; - + << "\n\tDate: " << asctime(&start_time_tm) << "\t\twhich is " << start_time_in_secs_since_1970 + << " secs since 1970 UTC" + << "\n\tToolkit: " << toolkit << "\n\tVersion info (?): " << v1 << ' ' << v2 << std::endl; } - Record record; + Record record; char DataStr[MAX_STRING_LENGTH]; - while (!mt_stream.eof() && - mt_stream.getline( DataStr, MAX_STRING_LENGTH)) - { - /* Extract elements from string */ - if (sscanf( DataStr, "%lf %u %c %f %f %f %f %f %f %f %f", - &record.sample_time, &record.rand_num, &record.total_num, - &record.quat[1], &record.quat[2], &record.quat[3], &record.quat[4], - &record.trans.x(), &record.trans.y(), &record.trans.z(), - &record.rms ) ==11) - { - // Peter's code only recorded inside FOV events - record.out_of_FOV = 0; - // Petere's code did not record the frame - record.frame_num = 0; // TODO might want to use the 60Hz convention to convert sample_time to frame - - // normalise the quaternion. It is only approximately - // normalised in the mt file (probably just due to - // truncation of the floats etc.) - record.quat.normalise(); - vector_of_records.push_back(record); - vector_of_tags.push_back(record); - } - else if (sscanf( DataStr, "%lf %u %c : ---- Missing ----", - &record.sample_time, &record.rand_num, &record.total_num - ) ==3) - { - vector_of_tags.push_back(record); - } - else - { - warning("\nPolaris_MT_File: skipping (as I cannot decode) the following line:\n" - "'%s'\n", - DataStr); - } + while (!mt_stream.eof() && mt_stream.getline(DataStr, MAX_STRING_LENGTH)) { + /* Extract elements from string */ + if (sscanf(DataStr, "%lf %u %c %f %f %f %f %f %f %f %f", &record.sample_time, &record.rand_num, &record.total_num, + &record.quat[1], &record.quat[2], &record.quat[3], &record.quat[4], &record.trans.x(), &record.trans.y(), + &record.trans.z(), &record.rms) == 11) { + // Peter's code only recorded inside FOV events + record.out_of_FOV = 0; + // Petere's code did not record the frame + record.frame_num = 0; // TODO might want to use the 60Hz convention to convert sample_time to frame + + // normalise the quaternion. It is only approximately + // normalised in the mt file (probably just due to + // truncation of the floats etc.) + record.quat.normalise(); + vector_of_records.push_back(record); + vector_of_tags.push_back(record); + } else if (sscanf(DataStr, "%lf %u %c : ---- Missing ----", &record.sample_time, &record.rand_num, &record.total_num) == 3) { + vector_of_tags.push_back(record); + } else { + warning("\nPolaris_MT_File: skipping (as I cannot decode) the following line:\n" + "'%s'\n", + DataStr); } - - + } } - - void -Polaris_MT_File:: -read_NDI_Toolviewer_mt_file(const std::string& mt_filename, std::istream& mt_stream, const char * const first_line) -{ - const unsigned int MAX_STRING_LENGTH=512; +Polaris_MT_File::read_NDI_Toolviewer_mt_file(const std::string& mt_filename, std::istream& mt_stream, + const char* const first_line) { + const unsigned int MAX_STRING_LENGTH = 512; char DataStr[MAX_STRING_LENGTH]; // parse second line with the data // format: // [June 25, 2010 04:00PM] - mt_stream.getline( DataStr, MAX_STRING_LENGTH); + mt_stream.getline(DataStr, MAX_STRING_LENGTH); { std::tm start_time_tm; start_time_tm.tm_sec = 0; - if (strptime(DataStr, "[%b %d,%Y%I:%M%p]", - &start_time_tm) == NULL) - error("Polaris_MT_File: error parsing date line of file %s", - mt_filename.c_str()); + if (strptime(DataStr, "[%b %d,%Y%I:%M%p]", &start_time_tm) == NULL) + error("Polaris_MT_File: error parsing date line of file %s", mt_filename.c_str()); - //start_time_tm.tm_mon -= 1; - //start_time_tm.tm_year -= 1900; + // start_time_tm.tm_mon -= 1; + // start_time_tm.tm_year -= 1900; start_time_tm.tm_isdst = -1; - start_time_in_secs_since_1970 = - mktime(&start_time_tm); + start_time_in_secs_since_1970 = mktime(&start_time_tm); if (start_time_in_secs_since_1970 == std::time_t(-1)) - error("Polaris_MT_File: error interpreting data/time in 3rd line of mt file %s", - mt_filename.c_str()); + error("Polaris_MT_File: error interpreting data/time in 3rd line of mt file %s", mt_filename.c_str()); std::cout << "\nPolaris .mt file info:" - << "\n\tDate: " << asctime(&start_time_tm) - << "\t\twhich is " << start_time_in_secs_since_1970 << " secs since 1970 UTC" << std::endl; - + << "\n\tDate: " << asctime(&start_time_tm) << "\t\twhich is " << start_time_in_secs_since_1970 + << " secs since 1970 UTC" << std::endl; } // skip empty line - mt_stream.getline( DataStr, MAX_STRING_LENGTH); + mt_stream.getline(DataStr, MAX_STRING_LENGTH); // skip line containing "frame, Q0, ... - mt_stream.getline( DataStr, MAX_STRING_LENGTH); - - - Record record; - while (!mt_stream.eof() && - mt_stream.getline( DataStr, MAX_STRING_LENGTH)) - { - /* Extract elements from string */ - // Frame, Q0, Qx, Qy, Qz, x, y, z, Error, OOV - if (sscanf( DataStr, "%u,%f,%f,%f,%f,%f,%f,%f,%f,%u", - &record.frame_num, - &record.quat[1], &record.quat[2], &record.quat[3], &record.quat[4], - &record.trans.x(), &record.trans.y(), &record.trans.z(), - &record.rms, - &record.out_of_FOV ) ==10) - { - // convert Polaris frame to time - // frame runs at a 60Hz clock - // set time of first sample to 0 - if (vector_of_records.size()==0) - record.sample_time = 0; - else - record.sample_time = double(record.frame_num - vector_of_records[0].frame_num)/60; - - // Toolviewer does not store random numbers sent to listmode - record.rand_num = 0; - // normalise the quaternion. It is only approximately - // normalised in the mt file (probably just due to - // truncation of the floats etc.) - record.quat.normalise(); - vector_of_records.push_back(record); - vector_of_tags.push_back(record); - } - else if (sscanf( DataStr, "%u, MISSING", - &record.frame_num - ) ==1) - { - vector_of_tags.push_back(record); - } + mt_stream.getline(DataStr, MAX_STRING_LENGTH); + + Record record; + while (!mt_stream.eof() && mt_stream.getline(DataStr, MAX_STRING_LENGTH)) { + /* Extract elements from string */ + // Frame, Q0, Qx, Qy, Qz, x, y, z, Error, OOV + if (sscanf(DataStr, "%u,%f,%f,%f,%f,%f,%f,%f,%f,%u", &record.frame_num, &record.quat[1], &record.quat[2], &record.quat[3], + &record.quat[4], &record.trans.x(), &record.trans.y(), &record.trans.z(), &record.rms, &record.out_of_FOV) == 10) { + // convert Polaris frame to time + // frame runs at a 60Hz clock + // set time of first sample to 0 + if (vector_of_records.size() == 0) + record.sample_time = 0; else - { - warning("\nPolaris_MT_File: skipping (as I cannot decode) the following line:\n" - "'%s'\n", - DataStr); - } + record.sample_time = double(record.frame_num - vector_of_records[0].frame_num) / 60; + + // Toolviewer does not store random numbers sent to listmode + record.rand_num = 0; + // normalise the quaternion. It is only approximately + // normalised in the mt file (probably just due to + // truncation of the floats etc.) + record.quat.normalise(); + vector_of_records.push_back(record); + vector_of_tags.push_back(record); + } else if (sscanf(DataStr, "%u, MISSING", &record.frame_num) == 1) { + vector_of_tags.push_back(record); + } else { + warning("\nPolaris_MT_File: skipping (as I cannot decode) the following line:\n" + "'%s'\n", + DataStr); } + } warning("NDI Toolviewer output file does not seem to specify the seconds of the acquisition time"); } std::time_t -Polaris_MT_File:: -get_start_time_in_secs_since_1970() -{ - return start_time_in_secs_since_1970; +Polaris_MT_File::get_start_time_in_secs_since_1970() { + return start_time_in_secs_since_1970; } -Polaris_MT_File::Record -Polaris_MT_File::operator[](unsigned int in) const -{ - assert(in>=0); - assert(in= 0); + assert(in < vector_of_records.size()); return vector_of_records[in]; } - -END_NAMESPACE_STIR - +END_NAMESPACE_STIR diff --git a/src/experimental/motion/RegisteredObject.cxx b/src/experimental/motion/RegisteredObject.cxx index c79654facc..d6ed29dce8 100644 --- a/src/experimental/motion/RegisteredObject.cxx +++ b/src/experimental/motion/RegisteredObject.cxx @@ -21,31 +21,27 @@ #ifdef __STIR_REGISTRY_NOT_INLINE -#pragma message("instantiating RegisteredObject") -#include "stir_experimental/SinglesRates.h" +# pragma message("instantiating RegisteredObject") +# include "stir_experimental/SinglesRates.h" // add here all roots of hierarchies based on RegisteredObject -#pragma message("instantiating RegisteredObject") -#include "stir_experimental/motion/RigidObject3DMotion.h" - +# pragma message("instantiating RegisteredObject") +# include "stir_experimental/motion/RigidObject3DMotion.h" START_NAMESPACE_STIR template -RegisteredObject::RegistryType& -RegisteredObject::registry () -{ +RegisteredObject::RegistryType& +RegisteredObject::registry() { static RegistryType the_registry("None", 0); return the_registry; } - -//template RegisteredObject; +// template RegisteredObject; template RegisteredObject; // add here all roots of hierarchies based on RegisteredObject - END_NAMESPACE_STIR #endif diff --git a/src/experimental/motion/RigidObject3DMotion.cxx b/src/experimental/motion/RigidObject3DMotion.cxx index 4765b08c4c..b3b330696c 100644 --- a/src/experimental/motion/RigidObject3DMotion.cxx +++ b/src/experimental/motion/RigidObject3DMotion.cxx @@ -23,17 +23,13 @@ START_NAMESPACE_STIR - - -void -RigidObject3DMotion::set_defaults() -{ - //time_offset=time_not_yet_determined; +void +RigidObject3DMotion::set_defaults() { + // time_offset=time_not_yet_determined; } -void -RigidObject3DMotion::initialise_keymap() -{ +void +RigidObject3DMotion::initialise_keymap() { #if 0 parser.add_key("reference_quaternion", &reference_quaternion); parser.add_key("reference_translation", &reference_translation); @@ -41,15 +37,12 @@ RigidObject3DMotion::initialise_keymap() } bool -RigidObject3DMotion:: -post_processing() -{ +RigidObject3DMotion::post_processing() { - if (!is_synchronised()) - { - warning("RigidObject3DMotion object not synchronised."); - return true; - } + if (!is_synchronised()) { + warning("RigidObject3DMotion object not synchronised."); + return true; + } #if 0 else { @@ -85,40 +78,26 @@ compute_average_motion_rel_time(const double start_time, const double end_time) #endif RigidObject3DTransformation -RigidObject3DMotion:: -compute_average_motion_in_tracker_coords(const AbsTimeInterval& interval) const -{ - return - this->compute_average_motion_in_tracker_coords_rel_time - (this->secs_since_1970_to_rel_time(interval.get_start_time_in_secs_since_1970()), - this->secs_since_1970_to_rel_time(interval.get_end_time_in_secs_since_1970())); +RigidObject3DMotion::compute_average_motion_in_tracker_coords(const AbsTimeInterval& interval) const { + return this->compute_average_motion_in_tracker_coords_rel_time( + this->secs_since_1970_to_rel_time(interval.get_start_time_in_secs_since_1970()), + this->secs_since_1970_to_rel_time(interval.get_end_time_in_secs_since_1970())); } RigidObject3DTransformation -RigidObject3DMotion:: -compute_average_motion_in_scanner_coords(const AbsTimeInterval& interval) const -{ - return - compose(this->compute_average_motion_in_tracker_coords(interval), - this->get_transformation_from_scanner_coords()); +RigidObject3DMotion::compute_average_motion_in_scanner_coords(const AbsTimeInterval& interval) const { + return compose(this->compute_average_motion_in_tracker_coords(interval), this->get_transformation_from_scanner_coords()); } RigidObject3DTransformation -RigidObject3DMotion:: -compute_average_motion_in_scanner_coords_rel_time(const double start_time, const double end_time) const -{ - return - compose(this->compute_average_motion_in_tracker_coords_rel_time(start_time, end_time), - this->get_transformation_from_scanner_coords()); +RigidObject3DMotion::compute_average_motion_in_scanner_coords_rel_time(const double start_time, const double end_time) const { + return compose(this->compute_average_motion_in_tracker_coords_rel_time(start_time, end_time), + this->get_transformation_from_scanner_coords()); } -RigidObject3DTransformation -RigidObject3DMotion:: -get_motion_in_scanner_coords_rel_time(const double time) const -{ - return - compose(this->get_motion_in_tracker_coords_rel_time(time), - this->get_transformation_from_scanner_coords()); +RigidObject3DTransformation +RigidObject3DMotion::get_motion_in_scanner_coords_rel_time(const double time) const { + return compose(this->get_motion_in_tracker_coords_rel_time(time), this->get_transformation_from_scanner_coords()); } #if 0 @@ -141,7 +120,7 @@ RigidObject3DMotion:: is_synchronised() const { return time_offset!=time_not_yet_determined; -} +} #endif END_NAMESPACE_STIR diff --git a/src/experimental/motion/RigidObject3DMotionFromPolaris.cxx b/src/experimental/motion/RigidObject3DMotionFromPolaris.cxx index 4578aa409f..d343b1884a 100644 --- a/src/experimental/motion/RigidObject3DMotionFromPolaris.cxx +++ b/src/experimental/motion/RigidObject3DMotionFromPolaris.cxx @@ -5,14 +5,14 @@ For internal GE use only. */ /*! - \file + \file \ingroup motion \brief Implementation of class stir::RigidObject3DMotionFromPolaris - + \author Sanida Mustafovic \author Kris Thielemans - + */ #include "stir_experimental/motion/RigidObject3DMotionFromPolaris.h" @@ -31,38 +31,39 @@ #include #ifndef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif -# ifdef BOOST_NO_STDC_NAMESPACE -namespace std { using ::time_t; using ::tm; using ::localtime; } +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::time_t; +using ::tm; +using ::localtime; +} // namespace std #endif START_NAMESPACE_STIR template -static inline -void -push_back(VectorWithOffset& v, const T& elem) -{ - if (v.capacity()==v.size()) - v.reserve(v.capacity()*2); - - v.resize(v.size()+1); - v[v.size()-1] = elem; -} +static inline void +push_back(VectorWithOffset& v, const T& elem) { + if (v.capacity() == v.size()) + v.reserve(v.capacity() * 2); + v.resize(v.size() + 1); + v[v.size() - 1] = elem; +} -static const double time_not_yet_determined=-1234567.8; -static const CartesianCoordinate3D invalid_translation(1.E9F,2.E9F,3.E9F); +static const double time_not_yet_determined = -1234567.8; +static const CartesianCoordinate3D invalid_translation(1.E9F, 2.E9F, 3.E9F); /*! Convert from Polaris transformation to STIR conventions The Polaris records info as q0 qx qy qz tx ty tz, where the coordinate system is right-handed (see the Polaris manual). The STIR coordinate system is left-handed. We do take - a coordinate transformation into account when applying + a coordinate transformation into account when applying Polaris transformations to scanner coordinates. However, that coordinate transformation uses RigidObject3DTransformation, and hence cannot swap right-handed to left-handed. @@ -82,12 +83,12 @@ static const CartesianCoordinate3D invalid_translation(1.E9F,2.E9F,3.E9F) \code qx=qY,qy=qX,qz=qZ. \endcode - This not so obvious as it sounds as there is a potential sign here. - For instance, the Polaris convention uses a quaternion + This not so obvious as it sounds as there is a potential sign here. + For instance, the Polaris convention uses a quaternion (0,x,y,z) for a point, - while RigidObject3DTransformation uses (0,z,y,x) + while RigidObject3DTransformation uses (0,z,y,x) (see the point2quat function in RigidObject3DTransformation.cxx ). - So, effectively there are 2 coordinate swaps between Polaris conventions and + So, effectively there are 2 coordinate swaps between Polaris conventions and RigidObject3DTransformation: \code Quaternion(q0,qZ,qY,qX) = Quaternion(q0,qz,qx,qy) @@ -95,9 +96,7 @@ static const CartesianCoordinate3D invalid_translation(1.E9F,2.E9F,3.E9F) and qz,qx,qy is an even permutation of qx,qy,qz */ RigidObject3DTransformation -RigidObject3DMotionFromPolaris:: -make_transformation_from_polaris_data(Polaris_MT_File::Record const& record) -{ +RigidObject3DMotionFromPolaris::make_transformation_from_polaris_data(Polaris_MT_File::Record const& record) { /* WARNING: This depends conventions in RigidObject3DTransformation. @@ -109,119 +108,90 @@ make_transformation_from_polaris_data(Polaris_MT_File::Record const& record) return RigidObject3DTransformation(record.quat, record.trans); point2quat(z,y,x)->(0,z,y,x) and no DO_XY_SWAP - return + return RigidObject3DTransformation(Quaternion(record.quat[1], - -record.quat[3], - -record.quat[2], - -record.quat[4]), - CartesianCoordinate3D(record.trans.z(), - record.trans.x(), - record.trans.y())); - */ - return - RigidObject3DTransformation(Quaternion(record.quat[1], - record.quat[4], - record.quat[2], - record.quat[3]), - CartesianCoordinate3D(record.trans.z(), - record.trans.x(), - record.trans.y())); + -record.quat[3], + -record.quat[2], + -record.quat[4]), + CartesianCoordinate3D(record.trans.z(), + record.trans.x(), + record.trans.y())); + */ + return RigidObject3DTransformation(Quaternion(record.quat[1], record.quat[4], record.quat[2], record.quat[3]), + CartesianCoordinate3D(record.trans.z(), record.trans.x(), record.trans.y())); } -// Find and store gating values in a vector from lm_file -static void -find_and_store_gate_tag_values_from_lm(VectorWithOffset& lm_times_in_millisecs, - VectorWithOffset& lm_random_number, - CListModeData& listmode_data, - const unsigned int mask_for_tags); +// Find and store gating values in a vector from lm_file +static void find_and_store_gate_tag_values_from_lm(VectorWithOffset& lm_times_in_millisecs, + VectorWithOffset& lm_random_number, CListModeData& listmode_data, + const unsigned int mask_for_tags); -const char * const -RigidObject3DMotionFromPolaris::registered_name = "Motion From Polaris"; +const char* const RigidObject3DMotionFromPolaris::registered_name = "Motion From Polaris"; -RigidObject3DMotionFromPolaris::RigidObject3DMotionFromPolaris() -{ - set_defaults(); +RigidObject3DMotionFromPolaris::RigidObject3DMotionFromPolaris() { set_defaults(); } +const RigidObject3DTransformation& +RigidObject3DMotionFromPolaris::get_transformation_to_scanner_coords() const { + return move_to_scanner_coords; } -const RigidObject3DTransformation& -RigidObject3DMotionFromPolaris:: -get_transformation_to_scanner_coords() const -{ return move_to_scanner_coords; } - - -const RigidObject3DTransformation& -RigidObject3DMotionFromPolaris:: -get_transformation_from_scanner_coords() const -{ return move_from_scanner_coords; } +const RigidObject3DTransformation& +RigidObject3DMotionFromPolaris::get_transformation_from_scanner_coords() const { + return move_from_scanner_coords; +} -void -RigidObject3DMotionFromPolaris:: -set_transformation_from_scanner_coords(const RigidObject3DTransformation& new_move_from_scanner_coords) -{ +void +RigidObject3DMotionFromPolaris::set_transformation_from_scanner_coords( + const RigidObject3DTransformation& new_move_from_scanner_coords) { this->move_from_scanner_coords = new_move_from_scanner_coords; this->move_to_scanner_coords = this->move_from_scanner_coords.inverse(); } - -double -RigidObject3DMotionFromPolaris:: -rel_time_to_polaris_time(const double time) const -{ - return time*time_drift + time_offset; +double +RigidObject3DMotionFromPolaris::rel_time_to_polaris_time(const double time) const { + return time * time_drift + time_offset; } -double -RigidObject3DMotionFromPolaris:: -polaris_time_to_rel_time(const double time) const -{ - return (time - time_offset)/time_drift; +double +RigidObject3DMotionFromPolaris::polaris_time_to_rel_time(const double time) const { + return (time - time_offset) / time_drift; } std::vector -RigidObject3DMotionFromPolaris:: -get_rel_time_of_samples(const double start_time, const double end_time) const -{ +RigidObject3DMotionFromPolaris::get_rel_time_of_samples(const double start_time, const double end_time) const { const double polaris_start_time = this->rel_time_to_polaris_time(start_time); const double polaris_end_time = this->rel_time_to_polaris_time(end_time); std::vector result; - Polaris_MT_File::const_iterator iter=this->mt_file_ptr->begin(); + Polaris_MT_File::const_iterator iter = this->mt_file_ptr->begin(); - while (iter!= this->mt_file_ptr->end() && iter->sample_time< polaris_start_time) + while (iter != this->mt_file_ptr->end() && iter->sample_time < polaris_start_time) ++iter; - while (iter!= this->mt_file_ptr->end() && iter->sample_time<= polaris_end_time) - { + while (iter != this->mt_file_ptr->end() && iter->sample_time <= polaris_end_time) { result.push_back(this->polaris_time_to_rel_time(iter->sample_time)); ++iter; } return result; } - RigidObject3DTransformation -RigidObject3DMotionFromPolaris:: -compute_average_motion_polaris_time(const double start_time, const double end_time) const -{ +RigidObject3DMotionFromPolaris::compute_average_motion_polaris_time(const double start_time, const double end_time) const { // CartesianCoordinate3D euler_angles; - int samples = 0 ; - CartesianCoordinate3D total_t(0,0,0); - Quaternion total_q(0,0,0,0); - - Polaris_MT_File::const_iterator iter=mt_file_ptr->begin(); + int samples = 0; + CartesianCoordinate3D total_t(0, 0, 0); + Quaternion total_q(0, 0, 0, 0); - while (iter!= mt_file_ptr->end()) - { + Polaris_MT_File::const_iterator iter = mt_file_ptr->begin(); + + while (iter != mt_file_ptr->end()) { /* Accept motions recorded during time interval */ - if ((iter->sample_time >= start_time ) && ( iter->sample_time<= end_time)) - { - RigidObject3DTransformation transf = - make_transformation_from_polaris_data(*iter); - Quaternion quater = transf.get_quaternion(); - const CartesianCoordinate3D trans= transf.get_translation(); + if ((iter->sample_time >= start_time) && (iter->sample_time <= end_time)) { + RigidObject3DTransformation transf = make_transformation_from_polaris_data(*iter); + Quaternion quater = transf.get_quaternion(); + const CartesianCoordinate3D trans = transf.get_translation(); // make sure that all quaternions use a fixed sign choice, otherwise adding them up does not make a lot of sense - if (quater[1]<0) - quater *= -1; + if (quater[1] < 0) + quater *= -1; /* Maintain running total quaternions and translations */ total_t += trans; total_q += quater; @@ -230,101 +200,83 @@ compute_average_motion_polaris_time(const double start_time, const double end_ti ++iter; } /* Average quat and translation */ - - if (samples==0) - { - error("RigidObject3DMotionFromPolaris::compute_average_motion_polaris_time:\n" - "\t Start-end range (%g-%g) does not seem to overlap with MT info.", - start_time, end_time); - } - - total_q /=static_cast(samples); - if (norm(total_q)<.9) + + if (samples == 0) { + error("RigidObject3DMotionFromPolaris::compute_average_motion_polaris_time:\n" + "\t Start-end range (%g-%g) does not seem to overlap with MT info.", + start_time, end_time); + } + + total_q /= static_cast(samples); + if (norm(total_q) < .9) warning("RigidObject3DMotionFromPolaris::compute_average_motion_polaris_time:\n" - "\taveraged quaternion has norm %g which is very different from 1.\n" - "\tThis indicates large movement in the range (%g-%g).", - norm(total_q), start_time, end_time); + "\taveraged quaternion has norm %g which is very different from 1.\n" + "\tThis indicates large movement in the range (%g-%g).", + norm(total_q), start_time, end_time); total_q.normalise(); - total_t /= samples; - + total_t /= samples; + return RigidObject3DTransformation(total_q, total_t); } -RigidObject3DTransformation -RigidObject3DMotionFromPolaris:: -compute_average_motion_in_tracker_coords_rel_time(const double start_time, const double end_time) const -{ - return compute_average_motion_polaris_time(rel_time_to_polaris_time(start_time), - rel_time_to_polaris_time(end_time)); +RigidObject3DTransformation +RigidObject3DMotionFromPolaris::compute_average_motion_in_tracker_coords_rel_time(const double start_time, + const double end_time) const { + return compute_average_motion_polaris_time(rel_time_to_polaris_time(start_time), rel_time_to_polaris_time(end_time)); } -RigidObject3DTransformation -RigidObject3DMotionFromPolaris:: -get_motion_in_tracker_coords_rel_time(const double time) const -{ - const double polaris_time = - rel_time_to_polaris_time(time); +RigidObject3DTransformation +RigidObject3DMotionFromPolaris::get_motion_in_tracker_coords_rel_time(const double time) const { + const double polaris_time = rel_time_to_polaris_time(time); - Polaris_MT_File::const_iterator iterator_for_record_just_after_this_time = - mt_file_ptr->begin(); + Polaris_MT_File::const_iterator iterator_for_record_just_after_this_time = mt_file_ptr->begin(); - while (iterator_for_record_just_after_this_time!= mt_file_ptr->end() && + while (iterator_for_record_just_after_this_time != mt_file_ptr->end() && iterator_for_record_just_after_this_time->sample_time < polaris_time) ++iterator_for_record_just_after_this_time; - if (iterator_for_record_just_after_this_time == mt_file_ptr->end()) - { + if (iterator_for_record_just_after_this_time == mt_file_ptr->end()) { error("RigidObject3DMotionFromPolaris: motion asked for time %g which is " - "beyond the range of data (time in Polaris units: %g)\n", - time, polaris_time); + "beyond the range of data (time in Polaris units: %g)\n", + time, polaris_time); // statement to avoid compiler warning return RigidObject3DTransformation(); + } else { + return make_transformation_from_polaris_data(*iterator_for_record_just_after_this_time); } - else - { - return - make_transformation_from_polaris_data(*iterator_for_record_just_after_this_time); - } - } - -void -RigidObject3DMotionFromPolaris:: -do_synchronisation(CListModeData& listmode_data) -{ +void +RigidObject3DMotionFromPolaris::do_synchronisation(CListModeData& listmode_data) { VectorWithOffset lm_times_in_millisecs; VectorWithOffset lm_random_numbers; - find_and_store_gate_tag_values_from_lm(lm_times_in_millisecs,lm_random_numbers,listmode_data, this->_mask_for_tags); + find_and_store_gate_tag_values_from_lm(lm_times_in_millisecs, lm_random_numbers, listmode_data, this->_mask_for_tags); cout << "done find and store gate tag values" << endl; - const VectorWithOffset::size_type num_lm_tags = lm_random_numbers.size() ; - if (num_lm_tags==0) + const VectorWithOffset::size_type num_lm_tags = lm_random_numbers.size(); + if (num_lm_tags == 0) error("RigidObject3DMotionFromPolaris: no time data in list mode file"); const unsigned long num_mt_tags = mt_file_ptr->num_tags(); - if (num_mt_tags==0) + if (num_mt_tags == 0) error("RigidObject3DMotionFromPolaris: no data in polaris file"); - - /* Determine location of LM random numbers in Motion Tracking list + /* Determine location of LM random numbers in Motion Tracking list WARNING: assumes that mt is started BEFORE lm */ double start_MT_time_of_matching_sequence = 0; // copy mt times into a vector - Array<1,double> mt_match_times; - Array<1,double> lm_match_times; + Array<1, double> mt_match_times; + Array<1, double> lm_match_times; mt_match_times.reserve(lm_times_in_millisecs.size()); lm_match_times.reserve(lm_times_in_millisecs.size()); - for (long int mt_offset = 0; mt_offset + num_lm_tags <= num_mt_tags; ++mt_offset ) - { + for (long int mt_offset = 0; mt_offset + num_lm_tags <= num_mt_tags; ++mt_offset) { // check if tags match from current position - Polaris_MT_File::const_iterator iterator_for_random_num = - mt_file_ptr->begin_all_tags() + mt_offset; + Polaris_MT_File::const_iterator iterator_for_random_num = mt_file_ptr->begin_all_tags() + mt_offset; // check if first tag matches if ((iterator_for_random_num->rand_num & this->_mask_for_tags) != lm_random_numbers[0]) - continue; + continue; unsigned long int num_matched_tags = 1; start_MT_time_of_matching_sequence = (double)iterator_for_random_num->sample_time; @@ -335,505 +287,399 @@ do_synchronisation(CListModeData& listmode_data) push_back(lm_match_times, (double)lm_times_in_millisecs[0]); ++iterator_for_random_num; unsigned int lm_tag_num = 1; - while (iterator_for_random_num!= mt_file_ptr->end_all_tags() && - lm_tag_num < num_lm_tags) - { - if ((iterator_for_random_num->rand_num & this->_mask_for_tags) != lm_random_numbers[lm_tag_num]) - { - // no match - if (num_matched_tags > 10) - { - warning("Matching sequence of length %d (starting at MT time %g) breaks at MT time %g", - num_matched_tags, start_MT_time_of_matching_sequence, - (double)iterator_for_random_num->sample_time); - } - num_matched_tags = 0; - break; // get out of loop over tags - } - push_back(mt_match_times, (double)iterator_for_random_num->sample_time); - push_back(lm_match_times, (double)lm_times_in_millisecs[lm_tag_num]); - - ++num_matched_tags; - - // The code that finds the list mode tags only stores a new tag when the channels change value, - // assuming that a different random number will be used every time. This assumption is no - // no longer valid when a cable isn't connected. - // We get around this problem by deleting repeated occurences in both data streams. - // In addition, we'll ignore 0 tags (which might occur because we're masking out a channel). - const unsigned int current_rand_num = iterator_for_random_num->rand_num & this->_mask_for_tags; - ++iterator_for_random_num; - while (iterator_for_random_num!= mt_file_ptr->end_all_tags() && - ((iterator_for_random_num->rand_num & this->_mask_for_tags) == current_rand_num || - (iterator_for_random_num->rand_num & this->_mask_for_tags) == 0)) - { - ++iterator_for_random_num; - } - const unsigned int current_lm_rand_num = lm_random_numbers[lm_tag_num] & this->_mask_for_tags; - ++lm_tag_num; - while (lm_tag_num < num_lm_tags && - ((lm_random_numbers[lm_tag_num] & this->_mask_for_tags) == current_lm_rand_num || - (lm_random_numbers[lm_tag_num] & this->_mask_for_tags) == 0)) - { - ++lm_tag_num; - } - } // end of loop that checks current offset - - if (num_matched_tags!=0) - { + while (iterator_for_random_num != mt_file_ptr->end_all_tags() && lm_tag_num < num_lm_tags) { + if ((iterator_for_random_num->rand_num & this->_mask_for_tags) != lm_random_numbers[lm_tag_num]) { + // no match + if (num_matched_tags > 10) { + warning("Matching sequence of length %d (starting at MT time %g) breaks at MT time %g", num_matched_tags, + start_MT_time_of_matching_sequence, (double)iterator_for_random_num->sample_time); + } + num_matched_tags = 0; + break; // get out of loop over tags + } + push_back(mt_match_times, (double)iterator_for_random_num->sample_time); + push_back(lm_match_times, (double)lm_times_in_millisecs[lm_tag_num]); + + ++num_matched_tags; + + // The code that finds the list mode tags only stores a new tag when the channels change value, + // assuming that a different random number will be used every time. This assumption is no + // no longer valid when a cable isn't connected. + // We get around this problem by deleting repeated occurences in both data streams. + // In addition, we'll ignore 0 tags (which might occur because we're masking out a channel). + const unsigned int current_rand_num = iterator_for_random_num->rand_num & this->_mask_for_tags; + ++iterator_for_random_num; + while (iterator_for_random_num != mt_file_ptr->end_all_tags() && + ((iterator_for_random_num->rand_num & this->_mask_for_tags) == current_rand_num || + (iterator_for_random_num->rand_num & this->_mask_for_tags) == 0)) { + ++iterator_for_random_num; + } + const unsigned int current_lm_rand_num = lm_random_numbers[lm_tag_num] & this->_mask_for_tags; + ++lm_tag_num; + while (lm_tag_num < num_lm_tags && ((lm_random_numbers[lm_tag_num] & this->_mask_for_tags) == current_lm_rand_num || + (lm_random_numbers[lm_tag_num] & this->_mask_for_tags) == 0)) { + ++lm_tag_num; + } + } // end of loop that checks current offset + + if (num_matched_tags != 0) { // yes, they match cout << "\n\tFound " << num_matched_tags << " matching tags between mt file and list mode data\n"; - cout << "\tEntry " << mt_offset << " in .mt file (MT time " - << start_MT_time_of_matching_sequence << ") corresponds to start of list mode data \n"; + cout << "\tEntry " << mt_offset << " in .mt file (MT time " << start_MT_time_of_matching_sequence + << ") corresponds to start of list mode data \n"; this->time_offset = start_MT_time_of_matching_sequence; // fit { - // note: initialise to 0 to avoid compiler warnings - double constant = 0; double scale = 0; - // first shift mt times according to our initial estimate - // and scale lm_times to secs. - // This will make the fit a bit more stable. - mt_match_times -= this->time_offset; - lm_match_times /= 1000.; - - VectorWithOffset weights(num_matched_tags); - weights.fill(1.F); - // ignore first data point - // TODO explain why - weights[0]=0; - - // copy mt times into a vector - // note: initialise to 0 to avoid compiler warnings - double chi_square = 0; - double variance_of_constant = 0; - double variance_of_scale = 0; - double covariance_of_constant_with_scale = 0; - linear_regression(constant, scale, - chi_square, - variance_of_constant, - variance_of_scale, - covariance_of_constant_with_scale, - mt_match_times.begin(), mt_match_times.end(), - lm_match_times.begin(), - weights.begin(), - /* use_estimated_variance = */true - ); - - std::cout << "\tscale = " << scale << " +- " << sqrt(variance_of_scale) - << ", cst = " << constant << " +- " << sqrt(variance_of_constant) - << "\n\tchi_square = " << chi_square - << "\n\tcovariance = " << covariance_of_constant_with_scale - << endl; - this->time_offset += constant; - this->time_drift = scale; - - // report max-difference - { - Array<1,double> diff = lm_match_times * scale + constant - mt_match_times; - // ignore first - diff.resize(1,diff.size()-1); - std::cout << "\nDeviation between Polaris and listmode time is between " - << diff.find_min() << " and " << diff.find_max() << '\n'; - } + // note: initialise to 0 to avoid compiler warnings + double constant = 0; + double scale = 0; + // first shift mt times according to our initial estimate + // and scale lm_times to secs. + // This will make the fit a bit more stable. + mt_match_times -= this->time_offset; + lm_match_times /= 1000.; + + VectorWithOffset weights(num_matched_tags); + weights.fill(1.F); + // ignore first data point + // TODO explain why + weights[0] = 0; + + // copy mt times into a vector + // note: initialise to 0 to avoid compiler warnings + double chi_square = 0; + double variance_of_constant = 0; + double variance_of_scale = 0; + double covariance_of_constant_with_scale = 0; + linear_regression(constant, scale, chi_square, variance_of_constant, variance_of_scale, covariance_of_constant_with_scale, + mt_match_times.begin(), mt_match_times.end(), lm_match_times.begin(), weights.begin(), + /* use_estimated_variance = */ true); + + std::cout << "\tscale = " << scale << " +- " << sqrt(variance_of_scale) << ", cst = " << constant << " +- " + << sqrt(variance_of_constant) << "\n\tchi_square = " << chi_square + << "\n\tcovariance = " << covariance_of_constant_with_scale << endl; + this->time_offset += constant; + this->time_drift = scale; + + // report max-difference + { + Array<1, double> diff = lm_match_times * scale + constant - mt_match_times; + // ignore first + diff.resize(1, diff.size() - 1); + std::cout << "\nDeviation between Polaris and listmode time is between " << diff.find_min() << " and " + << diff.find_max() << '\n'; + } } // end of fit - std::cout << "\n\tTime offset " << time_offset << " drift " << time_drift << '\n'; - // do some reporting of time discrepancies + std::cout << "\n\tTime offset " << time_offset << " drift " << time_drift << '\n'; + // do some reporting of time discrepancies { - // Find average period between Polaris samples. - // Used for warning about anomalous differences between sample times. - const double expected_tag_period = - ((mt_file_ptr->end_all_tags()-1)->sample_time - - mt_file_ptr->begin_all_tags()->sample_time)/ - ((mt_file_ptr->end_all_tags()-1) - - mt_file_ptr->begin_all_tags()); - - Polaris_MT_File::const_iterator mt_iter = - mt_file_ptr->begin_all_tags() + mt_offset; - double previous_mt_tag_time = mt_iter->sample_time; - while (mt_iter!= mt_file_ptr->end_all_tags() && - lm_tag_num < num_lm_tags) - { - const float mt_tag_time = mt_iter->sample_time; - ++mt_iter; - const float elapsed_mt_tag_time = - (mt_tag_time - previous_mt_tag_time); - if (elapsed_mt_tag_time > 1.3F * expected_tag_period) - { - warning("MT file contains a time interval (%g) that is larger than expected after time %g", - elapsed_mt_tag_time, previous_mt_tag_time); - } - previous_mt_tag_time = mt_tag_time; - } + // Find average period between Polaris samples. + // Used for warning about anomalous differences between sample times. + const double expected_tag_period = + ((mt_file_ptr->end_all_tags() - 1)->sample_time - mt_file_ptr->begin_all_tags()->sample_time) / + ((mt_file_ptr->end_all_tags() - 1) - mt_file_ptr->begin_all_tags()); + + Polaris_MT_File::const_iterator mt_iter = mt_file_ptr->begin_all_tags() + mt_offset; + double previous_mt_tag_time = mt_iter->sample_time; + while (mt_iter != mt_file_ptr->end_all_tags() && lm_tag_num < num_lm_tags) { + const float mt_tag_time = mt_iter->sample_time; + ++mt_iter; + const float elapsed_mt_tag_time = (mt_tag_time - previous_mt_tag_time); + if (elapsed_mt_tag_time > 1.3F * expected_tag_period) { + warning("MT file contains a time interval (%g) that is larger than expected after time %g", elapsed_mt_tag_time, + previous_mt_tag_time); + } + previous_mt_tag_time = mt_tag_time; + } } return; } } // if we get here, we didn't find a match - warning( "No matching data found" ); + warning("No matching data found"); std::cerr << "Some diagnostics\n"; { - const std::time_t listmode_data_start_time_in_secs = - listmode_data.get_scan_start_time_in_secs_since_1970(); - if (listmode_data_start_time_in_secs!=std::time_t(-1)) - { - std::cerr << "List mode data started at " - << listmode_data_start_time_in_secs - << " secs since 1970\n"; - // Polaris times are currently in localtime since midnight - // This relies on TZ though: bad! (TODO) - struct std::tm* lm_start_time_tm = std::localtime( &listmode_data_start_time_in_secs ) ; - const double lm_start_time = - ( lm_start_time_tm->tm_hour * 3600. ) + - ( lm_start_time_tm->tm_min * 60. ) + - lm_start_time_tm->tm_sec ; - - std::cerr <<"Listmode file says that listmode start time is " - << lm_start_time - << " in secs after midnight local time"<< endl; - } - else - { - std::cerr <<"Listmode file has scan_start_time not filled in\n"; - } - std::cerr << "Polaris tracking started at " - << mt_file_ptr->get_start_time_in_secs_since_1970() - << " secs since 1970\n"; - std::cerr << "Polaris first and last tags are at " - << mt_file_ptr->begin_all_tags()->sample_time << ", " - << (mt_file_ptr->end_all_tags()-1)->sample_time - << " in secs after midnight local time\n"; + const std::time_t listmode_data_start_time_in_secs = listmode_data.get_scan_start_time_in_secs_since_1970(); + if (listmode_data_start_time_in_secs != std::time_t(-1)) { + std::cerr << "List mode data started at " << listmode_data_start_time_in_secs << " secs since 1970\n"; + // Polaris times are currently in localtime since midnight + // This relies on TZ though: bad! (TODO) + struct std::tm* lm_start_time_tm = std::localtime(&listmode_data_start_time_in_secs); + const double lm_start_time = + (lm_start_time_tm->tm_hour * 3600.) + (lm_start_time_tm->tm_min * 60.) + lm_start_time_tm->tm_sec; + + std::cerr << "Listmode file says that listmode start time is " << lm_start_time << " in secs after midnight local time" + << endl; + } else { + std::cerr << "Listmode file has scan_start_time not filled in\n"; + } + std::cerr << "Polaris tracking started at " << mt_file_ptr->get_start_time_in_secs_since_1970() << " secs since 1970\n"; + std::cerr << "Polaris first and last tags are at " << mt_file_ptr->begin_all_tags()->sample_time << ", " + << (mt_file_ptr->end_all_tags() - 1)->sample_time << " in secs after midnight local time\n"; std::cerr << "\nFirst 50 list mode tags:\n"; - for (unsigned int lm_tag_num = 1; lm_tag_num <= std::min(std::size_t(50),num_lm_tags); ++lm_tag_num) - { - std::cerr << lm_random_numbers[lm_tag_num] << ", "; - } + for (unsigned int lm_tag_num = 1; lm_tag_num <= std::min(std::size_t(50), num_lm_tags); ++lm_tag_num) { + std::cerr << lm_random_numbers[lm_tag_num] << ", "; + } std::cerr << "... \n"; - } - error( "\n\t\tNo matching data found" ) ; - + } + error("\n\t\tNo matching data found"); } -void -RigidObject3DMotionFromPolaris:: -set_mask_for_tags(const unsigned int mask_for_tags) -{ +void +RigidObject3DMotionFromPolaris::set_mask_for_tags(const unsigned int mask_for_tags) { this->_mask_for_tags = mask_for_tags; } +Succeeded +RigidObject3DMotionFromPolaris::synchronise() { + if (this->list_mode_filename.size() == 0) { + warning("Could not synchronise as listmode filename missing."); + return Succeeded::no; + } -Succeeded -RigidObject3DMotionFromPolaris::synchronise() -{ - if (this->list_mode_filename.size() == 0) - { - warning("Could not synchronise as listmode filename missing."); - return Succeeded::no; - } - - this->listmode_data_start_time_in_secs=std::time_t(-1); + this->listmode_data_start_time_in_secs = std::time_t(-1); - try - { - shared_ptr lm_data_ptr - (read_from_file(list_mode_filename)); + try { + shared_ptr lm_data_ptr(read_from_file(list_mode_filename)); - this->listmode_data_start_time_in_secs = - lm_data_ptr->get_scan_start_time_in_secs_since_1970(); + this->listmode_data_start_time_in_secs = lm_data_ptr->get_scan_start_time_in_secs_since_1970(); - if (this->listmode_data_start_time_in_secs==std::time_t(-1)) - { - warning("Scan start time could not be found from list mode data"); - } + if (this->listmode_data_start_time_in_secs == std::time_t(-1)) { + warning("Scan start time could not be found from list mode data"); } - catch (...) - { - warning("List mode file \"%s\" not found or in incorrect format", this->list_mode_filename.c_str()); - } - + } catch (...) { + warning("List mode file \"%s\" not found or in incorrect format", this->list_mode_filename.c_str()); + } { // TODO warning->info - warning("Looking for synchronisation file: Assuming that listmode corresponds to \"%s\".", - this->list_mode_filename.c_str()); + warning("Looking for synchronisation file: Assuming that listmode corresponds to \"%s\".", this->list_mode_filename.c_str()); - const string sync_filename = - this->list_mode_filename + "_" + - get_filename(this->mt_filename) + - ".sync"; + const string sync_filename = this->list_mode_filename + "_" + get_filename(this->mt_filename) + ".sync"; // define parser for .sync file format const int current_sync_version = 2; - int sync_version=-1; + int sync_version = -1; KeyParser parser; parser.add_start_key("Polaris vs. list mode synchronisation file"); parser.add_stop_key("end"); parser.add_key("version", &sync_version); parser.add_key("time offset", &this->time_offset); parser.add_key("time drift", &this->time_drift); - - this->time_offset =time_not_yet_determined; + + this->time_offset = time_not_yet_determined; this->time_drift = 1; std::ifstream sync_file(sync_filename.c_str()); - if (sync_file) - { - if (parser.parse(sync_file) == false || - sync_version!=current_sync_version || - this->time_offset == time_not_yet_determined) - { - warning("RigidObject3DMotionFromPolaris: Error while reading synchronisation file \"%s\".\n" - "Remove file and start again.", - sync_filename.c_str()); - if (sync_version!=current_sync_version) - warning("Reason: version should be %d", current_sync_version); - if (this->time_offset == time_not_yet_determined) - warning("Reason: time_offset not set"); - return Succeeded::no; - } + if (sync_file) { + if (parser.parse(sync_file) == false || sync_version != current_sync_version || + this->time_offset == time_not_yet_determined) { + warning("RigidObject3DMotionFromPolaris: Error while reading synchronisation file \"%s\".\n" + "Remove file and start again.", + sync_filename.c_str()); + if (sync_version != current_sync_version) + warning("Reason: version should be %d", current_sync_version); + if (this->time_offset == time_not_yet_determined) + warning("Reason: time_offset not set"); + return Succeeded::no; } - else - { - // TODO warning- - lm_data_ptr(read_from_file(this->list_mode_filename)); - - this->do_synchronisation(*lm_data_ptr); - - // write info to .sync file - std::ofstream out_sync_file(sync_filename.c_str()); - if (!out_sync_file) - { - warning("Could not open synchronisation file %s for writing. Proceeding...\n", - sync_filename.c_str()); - } - else - { - // set variable such that the correct number will be written to file - sync_version=current_sync_version; - out_sync_file << parser.parameter_info(); - warning("Synchronisation written to file %s", sync_filename.c_str()); - } - } - + } else { + // TODO warning- lm_data_ptr(read_from_file(this->list_mode_filename)); + + this->do_synchronisation(*lm_data_ptr); + + // write info to .sync file + std::ofstream out_sync_file(sync_filename.c_str()); + if (!out_sync_file) { + warning("Could not open synchronisation file %s for writing. Proceeding...\n", sync_filename.c_str()); + } else { + // set variable such that the correct number will be written to file + sync_version = current_sync_version; + out_sync_file << parser.parameter_info(); + warning("Synchronisation written to file %s", sync_filename.c_str()); + } + } + // write sync info to cerr std::cerr << parser.parameter_info(); } - if (fabs(time_drift-1) > max_time_drift_deviation) - { - warning("RigidObject3DMotionFromPolaris: time_drift %g is too large.\n" - "You could change the tolerance using the 'maximum time drift deviation' keyword.", - time_drift); + if (fabs(time_drift - 1) > max_time_drift_deviation) { + warning("RigidObject3DMotionFromPolaris: time_drift %g is too large.\n" + "You could change the tolerance using the 'maximum time drift deviation' keyword.", + time_drift); + return Succeeded::no; + } + if (this->listmode_data_start_time_in_secs != std::time_t(-1)) { + // Polaris times are currently in localtime since midnight + // This relies on TZ though: bad! (TODO) + struct std::tm* lm_start_time_tm = std::localtime(&this->listmode_data_start_time_in_secs); + const double lm_start_time = + (lm_start_time_tm->tm_hour * 3600.) + (lm_start_time_tm->tm_min * 60.) + lm_start_time_tm->tm_sec; + + cout << "\nListmode file says that listmode start time is " << lm_start_time << " in secs after midnight local time" << endl; + + if (fabs(time_offset - lm_start_time) > max_time_offset_deviation) { + warning("RigidObject3DMotionFromPolaris: max_time_offset deviation %g is too large.\n" + "You could change the tolerance using the 'maximum time offset deviation' keyword.", + time_offset - lm_start_time); return Succeeded::no; } - if (this->listmode_data_start_time_in_secs!=std::time_t(-1)) - { - // Polaris times are currently in localtime since midnight - // This relies on TZ though: bad! (TODO) - struct std::tm* lm_start_time_tm = std::localtime( &this->listmode_data_start_time_in_secs ) ; - const double lm_start_time = - ( lm_start_time_tm->tm_hour * 3600. ) + - ( lm_start_time_tm->tm_min * 60. ) + - lm_start_time_tm->tm_sec ; - - cout << "\nListmode file says that listmode start time is " - << lm_start_time - << " in secs after midnight local time"<< endl; - - if (fabs(time_offset - lm_start_time) > max_time_offset_deviation) - { - warning("RigidObject3DMotionFromPolaris: max_time_offset deviation %g is too large.\n" - "You could change the tolerance using the 'maximum time offset deviation' keyword.", - time_offset - lm_start_time); - return Succeeded::no; - } - } - else - { - this->listmode_data_start_time_in_secs = - mt_file_ptr->get_start_time_in_secs_since_1970() + - round(time_offset - mt_file_ptr->begin_all_tags()->sample_time); - warning("Used first line of Polaris to get absolute time info of\n" - "start of list mode data (ignoring time-drift):\n" - "estimated at %ld secs since 1970 UTC", - this->listmode_data_start_time_in_secs); - } + } else { + this->listmode_data_start_time_in_secs = + mt_file_ptr->get_start_time_in_secs_since_1970() + round(time_offset - mt_file_ptr->begin_all_tags()->sample_time); + warning("Used first line of Polaris to get absolute time info of\n" + "start of list mode data (ignoring time-drift):\n" + "estimated at %ld secs since 1970 UTC", + this->listmode_data_start_time_in_secs); + } - if (fabs(this->secs_since_1970_to_rel_time(this->listmode_data_start_time_in_secs))>.1) - { - warning("RigidObject3DMotionFromPolaris: internal problem with time_offsets. Sorry"); - return Succeeded::no; - } - if (fabs(rel_time_to_polaris_time(this->secs_since_1970_to_rel_time(mt_file_ptr->get_start_time_in_secs_since_1970())) - - mt_file_ptr->begin_all_tags()->sample_time) > max_time_offset_deviation) - { - warning("Polaris start of data (%g secs since midnight) does not seem to match \n" - "with its first time tag (%g),\n" - "or there's a very large time drift. I'm stopping anyway.\n", - rel_time_to_polaris_time(this->secs_since_1970_to_rel_time(mt_file_ptr->get_start_time_in_secs_since_1970())), - mt_file_ptr->begin_all_tags()->sample_time); - return Succeeded::no; - } - - return Succeeded::yes; + if (fabs(this->secs_since_1970_to_rel_time(this->listmode_data_start_time_in_secs)) > .1) { + warning("RigidObject3DMotionFromPolaris: internal problem with time_offsets. Sorry"); + return Succeeded::no; + } + if (fabs(rel_time_to_polaris_time(this->secs_since_1970_to_rel_time(mt_file_ptr->get_start_time_in_secs_since_1970())) - + mt_file_ptr->begin_all_tags()->sample_time) > max_time_offset_deviation) { + warning("Polaris start of data (%g secs since midnight) does not seem to match \n" + "with its first time tag (%g),\n" + "or there's a very large time drift. I'm stopping anyway.\n", + rel_time_to_polaris_time(this->secs_since_1970_to_rel_time(mt_file_ptr->get_start_time_in_secs_since_1970())), + mt_file_ptr->begin_all_tags()->sample_time); + return Succeeded::no; + } + return Succeeded::yes; } -double -RigidObject3DMotionFromPolaris:: -secs_since_1970_to_rel_time(std::time_t secs) const -{ +double +RigidObject3DMotionFromPolaris::secs_since_1970_to_rel_time(std::time_t secs) const { // TODO WARNING assumes that list mode data starts at rel_time 0 (which is ok for 962 and 966) // somewhat tricky as time_t might be an unsigned type, and potentially longer than 'long' - if (secs>this->listmode_data_start_time_in_secs) - return - static_cast(secs-this->listmode_data_start_time_in_secs); + if (secs > this->listmode_data_start_time_in_secs) + return static_cast(secs - this->listmode_data_start_time_in_secs); else - return - -static_cast(this->listmode_data_start_time_in_secs-secs); + return -static_cast(this->listmode_data_start_time_in_secs - secs); } - + void -find_and_store_gate_tag_values_from_lm(VectorWithOffset& lm_time, - VectorWithOffset& lm_random_number, - CListModeData& listmode_data/*const string& lm_filename*/, - const unsigned int mask_for_tags) -{ - - unsigned LastChannelState=0; - unsigned ChState=0;; - int PulseWidth = 0 ; - unsigned long StartPulseTime=0; - - +find_and_store_gate_tag_values_from_lm(VectorWithOffset& lm_time, VectorWithOffset& lm_random_number, + CListModeData& listmode_data /*const string& lm_filename*/, + const unsigned int mask_for_tags) { + + unsigned LastChannelState = 0; + unsigned ChState = 0; + ; + int PulseWidth = 0; + unsigned long StartPulseTime = 0; + // TODO make sure that enough events are read for synchronisation - unsigned long max_num_events = 1UL << (8*sizeof(unsigned long)-1); - //unsigned long max_num_events = 100000; + unsigned long max_num_events = 1UL << (8 * sizeof(unsigned long) - 1); + // unsigned long max_num_events = 100000; long more_events = max_num_events; - - // reset listmode to the beginning + + // reset listmode to the beginning listmode_data.reset(); - - shared_ptr record_sptr = listmode_data.get_empty_record_sptr(); - CListRecordWithGatingInput& record = dynamic_cast(*record_sptr); - while (more_events) - { - unsigned long CurrentTime=0; - if (listmode_data.get_next_record(record) == Succeeded::no) - { - break; //get out of while loop + shared_ptr record_sptr = listmode_data.get_empty_record_sptr(); + CListRecordWithGatingInput& record = dynamic_cast(*record_sptr); + + while (more_events) { + unsigned long CurrentTime = 0; + if (listmode_data.get_next_record(record) == Succeeded::no) { + break; // get out of while loop } - if (record.is_time()) - { + if (record.is_time()) { CurrentTime = record.time().get_time_in_millisecs(); } - if (record.is_gating_input()) - { - unsigned CurrentChannelState = record.gating_input().get_gating() & mask_for_tags; - - - if ( LastChannelState != CurrentChannelState && CurrentChannelState ) - { - if ( PulseWidth > 5 ) //TODO get rid of number 5 - { - push_back(lm_random_number,ChState); - push_back(lm_time,StartPulseTime); - } - LastChannelState = CurrentChannelState ; - PulseWidth = 0 ; - } - else if ( LastChannelState == CurrentChannelState && CurrentChannelState ) - { - if ( !PulseWidth ) StartPulseTime = CurrentTime ; - ChState = LastChannelState ; - PulseWidth += 1 ; + if (record.is_gating_input()) { + unsigned CurrentChannelState = record.gating_input().get_gating() & mask_for_tags; + + if (LastChannelState != CurrentChannelState && CurrentChannelState) { + if (PulseWidth > 5) // TODO get rid of number 5 + { + push_back(lm_random_number, ChState); + push_back(lm_time, StartPulseTime); + } + LastChannelState = CurrentChannelState; + PulseWidth = 0; + } else if (LastChannelState == CurrentChannelState && CurrentChannelState) { + if (!PulseWidth) + StartPulseTime = CurrentTime; + ChState = LastChannelState; + PulseWidth += 1; } } - more_events-=1; + more_events -= 1; } int s = lm_random_number.size(); - //for ( int i = 1; i<= lm_random_number.size(); i++) - //cerr << lm_random_number[i] << " "; - - if (s <=1) + // for ( int i = 1; i<= lm_random_number.size(); i++) + // cerr << lm_random_number[i] << " "; + + if (s <= 1) error("RigidObject3DMotionFromPolaris: No random numbers stored from lm file \n"); - //cerr << " LM random number" << endl; + // cerr << " LM random number" << endl; - //for ( int i = 0;i<=10;i++) - //cerr << lm_random_number[i] << " " ; + // for ( int i = 0;i<=10;i++) + // cerr << lm_random_number[i] << " " ; - // reset listmode to the beginning + // reset listmode to the beginning listmode_data.reset(); - } +bool +RigidObject3DMotionFromPolaris::is_synchronised() const { + return time_offset != time_not_yet_determined; +} -bool -RigidObject3DMotionFromPolaris:: -is_synchronised() const -{ - return time_offset!=time_not_yet_determined; -} - -void -RigidObject3DMotionFromPolaris::set_defaults() -{ +void +RigidObject3DMotionFromPolaris::set_defaults() { RigidObject3DMotion::set_defaults(); - this->list_mode_filename=""; + this->list_mode_filename = ""; this->mt_filename = ""; this->transformation_from_scanner_coordinates_filename = ""; // set to some invalid transformation such that we can detect this later // note: cannot initialise with an invalid quaternion as the RigidObject3DTransformation constructor has an assert - this->move_from_scanner_coords= - RigidObject3DTransformation(Quaternion(1.F,0.F,0.F,0.F),invalid_translation); + this->move_from_scanner_coords = RigidObject3DTransformation(Quaternion(1.F, 0.F, 0.F, 0.F), invalid_translation); this->time_offset = time_not_yet_determined; this->max_time_drift_deviation = .01; this->max_time_offset_deviation = 3.; - this->_mask_for_tags= 0xffffffff; + this->_mask_for_tags = 0xffffffff; } - -void -RigidObject3DMotionFromPolaris::initialise_keymap() -{ +void +RigidObject3DMotionFromPolaris::initialise_keymap() { RigidObject3DMotion::initialise_keymap(); parser.add_start_key("Rigid Object 3D Motion From Polaris Parameters"); parser.add_key("mt filename", &mt_filename); - parser.add_key("list_mode_filename",&list_mode_filename); - - parser.add_key("transformation_from_scanner_coordinates_filename", - &transformation_from_scanner_coordinates_filename); - parser.add_key("maximum time_drift deviation", - &max_time_drift_deviation); - parser.add_key("maximum time offset deviation", - &max_time_offset_deviation); - parser.add_key("mask for tags", - &this->_mask_for_tags); + parser.add_key("list_mode_filename", &list_mode_filename); + + parser.add_key("transformation_from_scanner_coordinates_filename", &transformation_from_scanner_coordinates_filename); + parser.add_key("maximum time_drift deviation", &max_time_drift_deviation); + parser.add_key("maximum time offset deviation", &max_time_offset_deviation); + parser.add_key("mask for tags", &this->_mask_for_tags); parser.add_stop_key("End Rigid Object 3D Motion From Polaris"); } -bool RigidObject3DMotionFromPolaris::post_processing() -{ - if (set_mt_file(mt_filename) == Succeeded::no) - { - warning("Error initialising mt file \n"); - return true; - } +bool +RigidObject3DMotionFromPolaris::post_processing() { + if (set_mt_file(mt_filename) == Succeeded::no) { + warning("Error initialising mt file \n"); + return true; + } - if (this->transformation_from_scanner_coordinates_filename.size()>0) - { + if (this->transformation_from_scanner_coordinates_filename.size() > 0) { #if 0 std::ifstream move_from_scanner_file(transformation_from_scanner_coordinates_filename.c_str()); if (!move_from_scanner_file.good()) @@ -863,101 +709,84 @@ bool RigidObject3DMotionFromPolaris::post_processing() KeyParser parser; parser.add_start_key("Move from scanner to tracker coordinates"); parser.add_key("conventions", &conventions); - parser.add_key("transformation",&transformation_as_string); - parser.add_stop_key("END"); - if (parser.parse(transformation_from_scanner_coordinates_filename.c_str()) == false) - { - warning("Error reading transformation_from_scanner_coordinates_filename:\n'%s'", - transformation_from_scanner_coordinates_filename.c_str()); - return true; - } - if (conventions != "q0qzqyqx and left-handed") - { - warning("Error reading transformation_from_scanner_coordinates_filename:\n'%s'" - "\nvalue for 'conventions' keyword has to be 'q0qzqyqx and left-handed'", - "\nbut is '%s'", - transformation_from_scanner_coordinates_filename.c_str(), - conventions.c_str()); - return true; - } + parser.add_key("transformation", &transformation_as_string); + parser.add_stop_key("END"); + if (parser.parse(transformation_from_scanner_coordinates_filename.c_str()) == false) { + warning("Error reading transformation_from_scanner_coordinates_filename:\n'%s'", + transformation_from_scanner_coordinates_filename.c_str()); + return true; + } + if (conventions != "q0qzqyqx and left-handed") { + warning("Error reading transformation_from_scanner_coordinates_filename:\n'%s'" + "\nvalue for 'conventions' keyword has to be 'q0qzqyqx and left-handed'", + "\nbut is '%s'", transformation_from_scanner_coordinates_filename.c_str(), conventions.c_str()); + return true; + } std::stringstream transformation_as_stream(transformation_as_string); transformation_as_stream >> move_from_scanner_coords; - if (!transformation_as_stream.good()) - { - warning("Error reading transformation_from_scanner_coordinates_filename:\n'%s'" - "\nvalue for 'transformation' keyword is invalid." - "\nIt should be something like '{{q0,qz,qy,qx},{tz,ty,tx}}'", - transformation_from_scanner_coordinates_filename.c_str()); - return true; - } - if (std::fabs(norm(move_from_scanner_coords.get_quaternion())-1)>.01) - { -#ifdef BOOST_NO_STRINGSTREAM - // dangerous for out-of-range, but 'old-style' ostrstream seems to need this - char str[100000]; - ostrstream s(str, 100000); -#else - std::ostringstream s; -#endif - s << move_from_scanner_coords; - warning("Error reading transformation_from_scanner_coordinates_filename:\n'%s'" - "\nvalue for 'transformation' keyword is invalid:" - "\nquaternion should be normalised to 1." - "\ntransformation read:\n%s", - transformation_from_scanner_coordinates_filename.c_str(), - s.str().c_str()); - return true; - } + if (!transformation_as_stream.good()) { + warning("Error reading transformation_from_scanner_coordinates_filename:\n'%s'" + "\nvalue for 'transformation' keyword is invalid." + "\nIt should be something like '{{q0,qz,qy,qx},{tz,ty,tx}}'", + transformation_from_scanner_coordinates_filename.c_str()); + return true; + } + if (std::fabs(norm(move_from_scanner_coords.get_quaternion()) - 1) > .01) { +# ifdef BOOST_NO_STRINGSTREAM + // dangerous for out-of-range, but 'old-style' ostrstream seems to need this + char str[100000]; + ostrstream s(str, 100000); +# else + std::ostringstream s; +# endif + s << move_from_scanner_coords; + warning("Error reading transformation_from_scanner_coordinates_filename:\n'%s'" + "\nvalue for 'transformation' keyword is invalid:" + "\nquaternion should be normalised to 1." + "\ntransformation read:\n%s", + transformation_from_scanner_coordinates_filename.c_str(), s.str().c_str()); + return true; + } } #endif - cerr << "'Move_from_scanner' quaternion " << move_from_scanner_coords.get_quaternion()<set_transformation_from_scanner_coords(move_from_scanner_coords); } - if (norm(this->move_from_scanner_coords.get_translation() - invalid_translation)<1) - { - warning("transformation from scanner coordinates invalid. \"transformation_from_scanner_coordinates_filename\" keyword not set?"); - return true; - } + if (norm(this->move_from_scanner_coords.get_translation() - invalid_translation) < 1) { + warning( + "transformation from scanner coordinates invalid. \"transformation_from_scanner_coordinates_filename\" keyword not set?"); + return true; + } - if (max_time_drift_deviation<0 || max_time_drift_deviation>.9) - { - warning("Polaris: Invalid max_time_drift_deviation %g", max_time_drift_deviation); - return true; - } - if (max_time_offset_deviation<0 || max_time_offset_deviation>100000) - { - warning("Polaris: Invalid max_time_offset_deviation %g", max_time_offset_deviation); - return true; - } + if (max_time_drift_deviation < 0 || max_time_drift_deviation > .9) { + warning("Polaris: Invalid max_time_drift_deviation %g", max_time_drift_deviation); + return true; + } + if (max_time_offset_deviation < 0 || max_time_offset_deviation > 100000) { + warning("Polaris: Invalid max_time_offset_deviation %g", max_time_offset_deviation); + return true; + } synchronise(); - - if (RigidObject3DMotion::post_processing()==true) + + if (RigidObject3DMotion::post_processing() == true) return true; return false; } -Succeeded -RigidObject3DMotionFromPolaris:: -set_mt_file(const string& mt_filename_v) -{ +Succeeded +RigidObject3DMotionFromPolaris::set_mt_file(const string& mt_filename_v) { mt_filename = mt_filename_v; mt_file_ptr.reset(new Polaris_MT_File(mt_filename)); return is_null_ptr(mt_file_ptr) ? Succeeded::no : Succeeded::yes; } -Succeeded -RigidObject3DMotionFromPolaris:: -set_list_mode_data_file(const string& lm_filename) -{ +Succeeded +RigidObject3DMotionFromPolaris::set_list_mode_data_file(const string& lm_filename) { this->list_mode_filename = lm_filename; return Succeeded::yes; } - - END_NAMESPACE_STIR - - diff --git a/src/experimental/motion/RigidObject3DTransformation.cxx b/src/experimental/motion/RigidObject3DTransformation.cxx index f069604bf5..947314ab47 100644 --- a/src/experimental/motion/RigidObject3DTransformation.cxx +++ b/src/experimental/motion/RigidObject3DTransformation.cxx @@ -5,7 +5,7 @@ For internal GE use only. */ /*! - \file + \file \ingroup motion \brief implementation of class RigidObject3DTransformation \author Sanida Mustafovic @@ -26,7 +26,7 @@ #include #include #ifndef NEW_ROT -#include "stir/ProjDataInfoCylindricalNoArcCorr.h" +# include "stir/ProjDataInfoCylindricalNoArcCorr.h" #endif #ifndef STIR_NO_NAMESPACES @@ -36,55 +36,55 @@ using std::endl; //#define DO_XY_SWAP - -# ifdef BOOST_NO_STDC_NAMESPACE +#ifdef BOOST_NO_STDC_NAMESPACE // avoid some problems with overloaded function -#define usqrt(x)(float)sqrt((double)(x)) -#define uatan2(y, x)(float)atan2((double)(y), (double)(x)) -#define ucos(x) (float)cos((double)(x)) -#define usin(x) (float)sin((double)(x)) -namespace std { using ::fabs; } +# define usqrt(x) (float)sqrt((double)(x)) +# define uatan2(y, x) (float)atan2((double)(y), (double)(x)) +# define ucos(x) (float)cos((double)(x)) +# define usin(x) (float)sin((double)(x)) +namespace std { +using ::fabs; +} #else -#define usqrt(x) std::sqrt(x) -#define uatan2(y,x) std::atan2(y,x) -#define ucos(x) std::cos(x) -#define usin(x) std::sin(x) +# define usqrt(x) std::sqrt(x) +# define uatan2(y, x) std::atan2(y, x) +# define ucos(x) std::cos(x) +# define usin(x) std::sin(x) #endif -/* decide on convention: FIRSTROT defined: rotate first before translation. +/* decide on convention: FIRSTROT defined: rotate first before translation. Note: FIRSTROT code effectively computes inverse transformation of !FIRSTROT WARNING: if FIRSTROT is defined, the Polaris code needs to be modified */ //#define FIRSTROT /* if next not defined, implements transformation using matrices (same result, but slower) - (implementation should be faster if matrices are stored instead of quaternions -*/ -#define WITHQUAT + (implementation should be faster if matrices are stored instead of quaternions +*/ +#define WITHQUAT #if !defined(WITHQUAT) && !defined(FIRSTROT) -#error did not implement FIRSTROT yet with matrices +# error did not implement FIRSTROT yet with matrices #endif #ifndef WITHQUAT -#include "stir/numerics/MatrixFunction.h" +# include "stir/numerics/MatrixFunction.h" #endif START_NAMESPACE_STIR -const char * const -RigidObject3DTransformation::registered_name = "rigid"; +const char* const RigidObject3DTransformation::registered_name = "rigid"; #ifdef DO_XY_SWAP - //! a function to convert a coordinate in a right-handed system to a left-handed system as used by STIR - static inline - CartesianCoordinate3D - right_handed_to_stir(const CartesianCoordinate3D& p) - { return CartesianCoordinate3D(p.z(), p.x(), p.y()); } - //! a function to convert a coordinate in a left-handed system as used by STIR to a right-handed system - static inline - CartesianCoordinate3D - stir_to_right_handed(const CartesianCoordinate3D& p) - { return CartesianCoordinate3D(p.z(), p.x(), p.y()); } +//! a function to convert a coordinate in a right-handed system to a left-handed system as used by STIR +static inline CartesianCoordinate3D +right_handed_to_stir(const CartesianCoordinate3D& p) { + return CartesianCoordinate3D(p.z(), p.x(), p.y()); +} +//! a function to convert a coordinate in a left-handed system as used by STIR to a right-handed system +static inline CartesianCoordinate3D +stir_to_right_handed(const CartesianCoordinate3D& p) { + return CartesianCoordinate3D(p.z(), p.x(), p.y()); +} #endif @@ -93,97 +93,85 @@ RigidObject3DTransformation::registered_name = "rigid"; The rest of the code is written independent of the convention used. */ #if 1 -static inline -Quaternion -point2quat(const CartesianCoordinate3D& p) -{ return Quaternion(0,p.z(),p.y(),p.x());} +static inline Quaternion +point2quat(const CartesianCoordinate3D& p) { + return Quaternion(0, p.z(), p.y(), p.x()); +} -static inline -CartesianCoordinate3D -quat2point(const Quaternion& q) -{ - assert(std::fabs(q[1])<.1); - // return CartesianCoordinate3D(q[4],q[3],q[2]); - return CartesianCoordinate3D(q[2],q[3],q[4]); +static inline CartesianCoordinate3D +quat2point(const Quaternion& q) { + assert(std::fabs(q[1]) < .1); + // return CartesianCoordinate3D(q[4],q[3],q[2]); + return CartesianCoordinate3D(q[2], q[3], q[4]); } #else /* other convention as used in Horn's paper but it's in contrast to the usual STIR convention of specifying coordinates as z,y,x */ -static inline -Quaternion -point2quat(const CartesianCoordinate3D& p) -{ return Quaternion(0,p.x(),p.y(),p.z());} -static inline -CartesianCoordinate3D -quat2point(const Quaternion& q) -{ - assert(std::fabs(q[1])<.1); - return CartesianCoordinate3D(q[4],q[3],q[2]); +static inline Quaternion +point2quat(const CartesianCoordinate3D& p) { + return Quaternion(0, p.x(), p.y(), p.z()); +} +static inline CartesianCoordinate3D +quat2point(const Quaternion& q) { + assert(std::fabs(q[1]) < .1); + return CartesianCoordinate3D(q[4], q[3], q[2]); } #endif -RigidObject3DTransformation:: -RigidObject3DTransformation () -: quat(Quaternion(1,0,0,0)), - translation(CartesianCoordinate3D(0,0,0)) -{} - +RigidObject3DTransformation::RigidObject3DTransformation() + : quat(Quaternion(1, 0, 0, 0)), translation(CartesianCoordinate3D(0, 0, 0)) {} -RigidObject3DTransformation:: -RigidObject3DTransformation (const Quaternion& quat_v, const CartesianCoordinate3D& translation_v) -: quat(quat_v), translation(translation_v) -{ +RigidObject3DTransformation::RigidObject3DTransformation(const Quaternion& quat_v, + const CartesianCoordinate3D& translation_v) + : quat(quat_v), translation(translation_v) { // test if quaternion normalised - assert(fabs(square(quat[1]) + square(quat[2]) + square(quat[3]) +square(quat[4]) - 1)<1E-3); + assert(fabs(square(quat[1]) + square(quat[2]) + square(quat[3]) + square(quat[4]) - 1) < 1E-3); // alternatively we could just normalise it here } -RigidObject3DTransformation -RigidObject3DTransformation::inverse() const -{ +RigidObject3DTransformation +RigidObject3DTransformation::inverse() const { #ifdef FIRSTROT /* Formula for inverse is a bit complicated because of fixed order of first rotation and then translation tr_point= transform(point) = - q*point*conj(q) + trans - invtransform(tr_point) = - invq*(q*point*conj(q)+trans)*conj(invq) - + q*point*conj(q) + trans + invtransform(tr_point) = + invq*(q*point*conj(q)+trans)*conj(invq) - invq*trans*conj(invq) = point - so -invq*trans*conj(invq) + -invtrans==0 + so -invq*trans*conj(invq) + -invtrans==0 */ #else - /* Formula for inverse is a bit complicated because of - fixed order of first translation and then rotation - - tr_point= transform(point) = - conj(q)*(point-trans)*q - invtransform(tr_point) = - conj(invq)*(tr_point - invtrans)*invq - = conj(invq)*(conj(q)*(point-trans)*q - invtrans)*invq - = point - so -conj(q)*(trans)*q + -invtrans==0 - */ + /* Formula for inverse is a bit complicated because of + fixed order of first translation and then rotation + + tr_point= transform(point) = + conj(q)*(point-trans)*q + invtransform(tr_point) = + conj(invq)*(tr_point - invtrans)*invq + = conj(invq)*(conj(q)*(point-trans)*q - invtrans)*invq + = point + so -conj(q)*(trans)*q + -invtrans==0 + */ #endif // note: both FIRSTROT and !FIRSTROT end up with the same formula const Quaternion qtrans = point2quat(translation); const Quaternion qinvtrans = conjugate(quat) * qtrans * quat; const CartesianCoordinate3D invtrans = quat2point(qinvtrans); - return RigidObject3DTransformation(conjugate(quat), invtrans*(-1)); + return RigidObject3DTransformation(conjugate(quat), invtrans * (-1)); } Quaternion -RigidObject3DTransformation::get_quaternion() const -{ +RigidObject3DTransformation::get_quaternion() const { return quat; } -CartesianCoordinate3D -RigidObject3DTransformation::get_translation() const -{ +CartesianCoordinate3D +RigidObject3DTransformation::get_translation() const { return translation; } @@ -200,94 +188,86 @@ RigidObject3DTransformation::get_euler_angles() const Succeeded RigidObject3DTransformation::set_euler_angles() { - #error not implemented +# error not implemented return Succeeded::no; } #endif -//CartesianCoordinate3D -BasicCoordinate<3,float> -RigidObject3DTransformation::transform_point(const //CartesianCoordinate3D& - BasicCoordinate<3,float>& point) const -{ +// CartesianCoordinate3D +BasicCoordinate<3, float> +RigidObject3DTransformation::transform_point(const // CartesianCoordinate3D& + BasicCoordinate<3, float>& point) const { CartesianCoordinate3D swapped_point = #ifndef DO_XY_SWAP - point; + point; #else stir_to_right_handed(point); #endif #ifdef WITHQUAT - //transformation with quaternions - -#ifdef FIRSTROT - const CartesianCoordinate3D transformed_point = - quat2point(quat * point2quat(swapped_point) * conjugate(quat)) + - translation; -#else - const CartesianCoordinate3D transformed_point = - quat2point(conjugate(quat) * point2quat(swapped_point - translation) * quat); -#endif + // transformation with quaternions + +# ifdef FIRSTROT + const CartesianCoordinate3D transformed_point = + quat2point(quat * point2quat(swapped_point) * conjugate(quat)) + translation; +# else + const CartesianCoordinate3D transformed_point = + quat2point(conjugate(quat) * point2quat(swapped_point - translation) * quat); +# endif -#else // for rotational matrix +#else // for rotational matrix // transformation with rotational matrix - Array<2,float> matrix = Array<2,float>(IndexRange2D(0,2,0,2)); + Array<2, float> matrix = Array<2, float>(IndexRange2D(0, 2, 0, 2)); - quaternion2m3(matrix,quat); + quaternion2m3(matrix, quat); - - Array<1,float> tmp(matrix.get_min_index(), matrix.get_max_index()); + Array<1, float> tmp(matrix.get_min_index(), matrix.get_max_index()); - tmp[matrix.get_min_index()]=swapped_point.x(); - tmp[matrix.get_min_index()+1]=swapped_point.y(); - tmp[matrix.get_max_index()]=swapped_point.z(); + tmp[matrix.get_min_index()] = swapped_point.x(); + tmp[matrix.get_min_index() + 1] = swapped_point.y(); + tmp[matrix.get_max_index()] = swapped_point.z(); // rotation - Array<1,float> out = matrix_multiply(matrix,tmp); - //translation + Array<1, float> out = matrix_multiply(matrix, tmp); + // translation out[matrix.get_min_index()] += translation.x(); - out[matrix.get_min_index()+1] += translation.y(); + out[matrix.get_min_index() + 1] += translation.y(); out[matrix.get_max_index()] += translation.z(); - const CartesianCoordinate3D transformed_point(out[out.get_max_index()],out[out.get_min_index()+1],out[out.get_min_index()]); + const CartesianCoordinate3D transformed_point(out[out.get_max_index()], out[out.get_min_index() + 1], + out[out.get_min_index()]); #endif - return + return #ifndef DO_XY_SWAP - transformed_point; + transformed_point; #else - right_handed_to_stir(transformed_point); + right_handed_to_stir(transformed_point); #endif } -void -RigidObject3DTransformation:: -transform_bin(Bin& bin,const ProjDataInfo& out_proj_data_info, - const ProjDataInfo& in_proj_data_info) const -{ +void +RigidObject3DTransformation::transform_bin(Bin& bin, const ProjDataInfo& out_proj_data_info, + const ProjDataInfo& in_proj_data_info) const { const float value = bin.get_bin_value(); #ifndef NEW_ROT CartesianCoordinate3D coord_1; CartesianCoordinate3D coord_2; - dynamic_cast(in_proj_data_info). - find_cartesian_coordinates_of_detection(coord_1,coord_2,bin); - + dynamic_cast(in_proj_data_info) + .find_cartesian_coordinates_of_detection(coord_1, coord_2, bin); + // now do the movement - - const CartesianCoordinate3D - coord_1_transformed = transform_point(coord_1); - - const CartesianCoordinate3D - coord2transformed = transform_point(coord_2); - - dynamic_cast(out_proj_data_info). - find_bin_given_cartesian_coordinates_of_detection(bin, - coord_1_transformed, - coord2transformed); + + const CartesianCoordinate3D coord_1_transformed = transform_point(coord_1); + + const CartesianCoordinate3D coord2transformed = transform_point(coord_2); + + dynamic_cast(out_proj_data_info) + .find_bin_given_cartesian_coordinates_of_detection(bin, coord_1_transformed, coord2transformed); #else LORInAxialAndNoArcCorrSinogramCoordinates lor; in_proj_data_info.get_LOR(lor, bin); @@ -296,46 +276,40 @@ transform_bin(Bin& bin,const ProjDataInfo& out_proj_data_info, // TODO origin // currently, the origin used for proj_data_info is in the centre of the scanner, // while for standard images it is in the centre of the first ring. - // This is pretty horrible though, as the transform_point function has no clue + // This is pretty horrible though, as the transform_point function has no clue // where the origin is - // Note that the present shift will make this version compatible with the + // Note that the present shift will make this version compatible with the // version above, as find_bin_given_cartesian_coordinates_of_detection // also uses an origin in the centre of the first ring - const float z_shift = - (in_proj_data_info.get_scanner_ptr()->get_num_rings()-1)/2.F * - in_proj_data_info.get_scanner_ptr()->get_ring_spacing(); + const float z_shift = + (in_proj_data_info.get_scanner_ptr()->get_num_rings() - 1) / 2.F * in_proj_data_info.get_scanner_ptr()->get_ring_spacing(); lor_as_points.p1().z() += z_shift; lor_as_points.p2().z() += z_shift; - LORAs2Points - transformed_lor_as_points(transform_point(lor_as_points.p1()), - transform_point(lor_as_points.p2())); - assert(*in_proj_data_info.get_scanner_ptr() == - *out_proj_data_info.get_scanner_ptr()); + LORAs2Points transformed_lor_as_points(transform_point(lor_as_points.p1()), transform_point(lor_as_points.p2())); + assert(*in_proj_data_info.get_scanner_ptr() == *out_proj_data_info.get_scanner_ptr()); transformed_lor_as_points.p1().z() -= z_shift; transformed_lor_as_points.p2().z() -= z_shift; bin = out_proj_data_info.get_bin(transformed_lor_as_points); #endif - if (bin.get_bin_value()>0) + if (bin.get_bin_value() > 0) bin.set_bin_value(value); } - void -RigidObject3DTransformation::get_relative_transformation(RigidObject3DTransformation& output, const RigidObject3DTransformation& reference) -{ +RigidObject3DTransformation::get_relative_transformation(RigidObject3DTransformation& output, + const RigidObject3DTransformation& reference) { #if 1 error("RigidObject3DTransformation::get_relative_transformation not implemented\n"); #else // this is very wrong. // correct code needs to transform translation (KT has it in Mathematica) CartesianCoordinate3D trans; - Quaternion quat; - quat = (*this).quat-reference.quat; - trans = (*this).translation-reference.translation; - - output(quat,trans); -#endif + Quaternion quat; + quat = (*this).quat - reference.quat; + trans = (*this).translation - reference.translation; + output(quat, trans); +#endif } #if 0 @@ -446,286 +420,201 @@ RigidObject3DTransformation::euler2quaternion(Quaternion& quat,const Coor } #endif -RigidObject3DTransformation -compose (const RigidObject3DTransformation& apply_last, - const RigidObject3DTransformation& apply_first) -{ +RigidObject3DTransformation +compose(const RigidObject3DTransformation& apply_last, const RigidObject3DTransformation& apply_first) { #ifdef FIRSTROT const Quaternion q2 = apply_last.get_quaternion(); - const CartesianCoordinate3D trans = - quat2point(q2 * - point2quat(apply_first.get_translation())* - conjugate(q2)); + const CartesianCoordinate3D trans = quat2point(q2 * point2quat(apply_first.get_translation()) * conjugate(q2)); - return RigidObject3DTransformation(q2 * apply_first.get_quaternion(), - apply_last.get_translation()+trans); + return RigidObject3DTransformation(q2 * apply_first.get_quaternion(), apply_last.get_translation() + trans); #else const Quaternion q1 = apply_first.get_quaternion(); - const CartesianCoordinate3D trans = - quat2point(q1 * - point2quat(apply_last.get_translation())* - conjugate(q1)); + const CartesianCoordinate3D trans = quat2point(q1 * point2quat(apply_last.get_translation()) * conjugate(q1)); - return RigidObject3DTransformation(q1*apply_last.get_quaternion(), - apply_first.get_translation()+trans); + return RigidObject3DTransformation(q1 * apply_last.get_quaternion(), apply_first.get_translation() + trans); #endif } std::ostream& -operator<<(std::ostream& out, - const RigidObject3DTransformation& rigid_object_transformation) -{ - out << '{' - << rigid_object_transformation.get_quaternion() - << ',' - << rigid_object_transformation.get_translation() - << "}"; +operator<<(std::ostream& out, const RigidObject3DTransformation& rigid_object_transformation) { + out << '{' << rigid_object_transformation.get_quaternion() << ',' << rigid_object_transformation.get_translation() << "}"; return out; } - std::istream& -operator>>(std::istream& in, - RigidObject3DTransformation& rigid_object_transformation) -{ +operator>>(std::istream& in, RigidObject3DTransformation& rigid_object_transformation) { char c; in >> std::ws >> c; - if (!in || c != '{') - { - in.setstate( std::ios::failbit); - return in; - } + if (!in || c != '{') { + in.setstate(std::ios::failbit); + return in; + } Quaternion q; in >> q; in >> std::ws >> c; - if (!in || c != ',') - { - in.setstate( std::ios::failbit); - return in; - } + if (!in || c != ',') { + in.setstate(std::ios::failbit); + return in; + } CartesianCoordinate3D t; in >> t; in >> std::ws >> c; - if (!in || c != '}') - { - in.setstate( std::ios::failbit); - return in; - } - rigid_object_transformation = RigidObject3DTransformation(q,t); + if (!in || c != '}') { + in.setstate(std::ios::failbit); + return in; + } + rigid_object_transformation = RigidObject3DTransformation(q, t); return in; } - /****************** find_closest_transformation **************/ -namespace detail -{ +namespace detail { - template - static - Array<2,float> - construct_Horn_matrix(Iter1T start_orig_points, - Iter1T end_orig_points, - Iter2T start_transformed_points, - const CartesianCoordinate3D& orig_average, - const CartesianCoordinate3D& transf_average) - { - Array<2,float> m(IndexRange2D(4,4)); - Iter1T orig_iter=start_orig_points; - Iter2T transf_iter=start_transformed_points; - while (orig_iter!=end_orig_points) - { +template +static Array<2, float> +construct_Horn_matrix(Iter1T start_orig_points, Iter1T end_orig_points, Iter2T start_transformed_points, + const CartesianCoordinate3D& orig_average, const CartesianCoordinate3D& transf_average) { + Array<2, float> m(IndexRange2D(4, 4)); + Iter1T orig_iter = start_orig_points; + Iter2T transf_iter = start_transformed_points; + while (orig_iter != end_orig_points) { #if 1 - const Quaternion q1 =point2quat(*orig_iter - orig_average); - const Quaternion q2 = point2quat(*transf_iter - transf_average); - m[0][0] += q1[2]*q2[2] + q1[3]*q2[3] + q1[4]*q2[4]; - m[0][1] += q1[4]*q2[3] - q1[3]*q2[4]; - m[0][2] += -q1[4]*q2[2] + q1[2]*q2[4]; - m[0][3] += q1[3]*q2[2] - q1[2]*q2[3]; - m[1][1] += q1[2]*q2[2] - q1[3]*q2[3] - q1[4]*q2[4]; - m[1][2] += q1[3]*q2[2] + q1[2]*q2[3]; - m[1][3] += q1[4]*q2[2] + q1[2]*q2[4]; - m[2][2] += -q1[2]*q2[2] + q1[3]*q2[3] - q1[4]*q2[4]; - m[2][3] += q1[4]*q2[3] + q1[3]*q2[4]; - m[3][3] += -q1[2]*q2[2] - q1[3]*q2[3] + q1[4]*q2[4]; + const Quaternion q1 = point2quat(*orig_iter - orig_average); + const Quaternion q2 = point2quat(*transf_iter - transf_average); + m[0][0] += q1[2] * q2[2] + q1[3] * q2[3] + q1[4] * q2[4]; + m[0][1] += q1[4] * q2[3] - q1[3] * q2[4]; + m[0][2] += -q1[4] * q2[2] + q1[2] * q2[4]; + m[0][3] += q1[3] * q2[2] - q1[2] * q2[3]; + m[1][1] += q1[2] * q2[2] - q1[3] * q2[3] - q1[4] * q2[4]; + m[1][2] += q1[3] * q2[2] + q1[2] * q2[3]; + m[1][3] += q1[4] * q2[2] + q1[2] * q2[4]; + m[2][2] += -q1[2] * q2[2] + q1[3] * q2[3] - q1[4] * q2[4]; + m[2][3] += q1[4] * q2[3] + q1[3] * q2[4]; + m[3][3] += -q1[2] * q2[2] - q1[3] * q2[3] + q1[4] * q2[4]; #else - // This is the original formulatino as given in e.g. R. Fulton's thesis - // However, it is specific to the convention used for point2quat - // while the above is independent of the convention - const CartesianCoordinate3D orig=*orig_iter - orig_average; - const CartesianCoordinate3D transf=*transf_iter - transf_average; - m[0][0] += - -(-orig.x()*transf.x()-orig.y()*transf.y()-orig.z()*transf.z()); - m[0][1] += - -(-transf.y()*orig.z()+orig.y()*transf.z()); - m[0][2] += - -(transf.x()*orig.z()-orig.x()*transf.z()); - m[0][3] += - -(-transf.x()*orig.y()+orig.x()*transf.y()); - - m[1][1] += - -(-orig.x()*transf.x()+orig.y()*transf.y()+orig.z()*transf.z()); - m[1][2] += - -(-transf.x()*orig.y()-orig.x()*transf.y()); - m[1][3] += - -(-transf.x()*orig.z()-orig.x()*transf.z()); - - m[2][2] += - -(orig.x()*transf.x()-orig.y()*transf.y()+orig.z()*transf.z()); - m[2][3] += - -(-transf.y()*orig.z()-orig.y()*transf.z()); - - m[3][3] += - -(orig.x()*transf.x()+orig.y()*transf.y()-orig.z()*transf.z()); + // This is the original formulatino as given in e.g. R. Fulton's thesis + // However, it is specific to the convention used for point2quat + // while the above is independent of the convention + const CartesianCoordinate3D orig = *orig_iter - orig_average; + const CartesianCoordinate3D transf = *transf_iter - transf_average; + m[0][0] += -(-orig.x() * transf.x() - orig.y() * transf.y() - orig.z() * transf.z()); + m[0][1] += -(-transf.y() * orig.z() + orig.y() * transf.z()); + m[0][2] += -(transf.x() * orig.z() - orig.x() * transf.z()); + m[0][3] += -(-transf.x() * orig.y() + orig.x() * transf.y()); + + m[1][1] += -(-orig.x() * transf.x() + orig.y() * transf.y() + orig.z() * transf.z()); + m[1][2] += -(-transf.x() * orig.y() - orig.x() * transf.y()); + m[1][3] += -(-transf.x() * orig.z() - orig.x() * transf.z()); + + m[2][2] += -(orig.x() * transf.x() - orig.y() * transf.y() + orig.z() * transf.z()); + m[2][3] += -(-transf.y() * orig.z() - orig.y() * transf.z()); + + m[3][3] += -(orig.x() * transf.x() + orig.y() * transf.y() - orig.z() * transf.z()); #endif - ++orig_iter; - ++transf_iter; - } - - // now make symmetric - m[1][0] = m[0][1]; - m[2][0] = m[0][2]; - m[3][0] = m[0][3]; - m[2][1] = m[1][2]; - m[3][1] = m[1][3]; - m[3][2] = m[2][3]; - - //std::cerr << "\nHorn: " << m; - return m; + ++orig_iter; + ++transf_iter; } - template - static - Array<2,float> - construct_Horn_matrix(Iter1T start_orig_points, - Iter1T end_orig_points, - Iter2T start_transformed_points) - { - const CartesianCoordinate3D orig_average = - average(start_orig_points, end_orig_points); - const CartesianCoordinate3D transf_average = - average(start_transformed_points, - start_transformed_points + (end_orig_points - start_orig_points)); - - return construct_Horn_matrix(start_orig_points, end_orig_points, - orig_average, transf_average); - } + // now make symmetric + m[1][0] = m[0][1]; + m[2][0] = m[0][2]; + m[3][0] = m[0][3]; + m[2][1] = m[1][2]; + m[3][1] = m[1][3]; + m[3][2] = m[2][3]; + + // std::cerr << "\nHorn: " << m; + return m; +} + +template +static Array<2, float> +construct_Horn_matrix(Iter1T start_orig_points, Iter1T end_orig_points, Iter2T start_transformed_points) { + const CartesianCoordinate3D orig_average = average(start_orig_points, end_orig_points); + const CartesianCoordinate3D transf_average = + average(start_transformed_points, start_transformed_points + (end_orig_points - start_orig_points)); + + return construct_Horn_matrix(start_orig_points, end_orig_points, orig_average, transf_average); +} } // end of namespace detail template double -RigidObject3DTransformation:: -RMSE(const RigidObject3DTransformation& transformation, - Iter1T start_orig_points, - Iter1T end_orig_points, - Iter2T start_transformed_points) -{ +RigidObject3DTransformation::RMSE(const RigidObject3DTransformation& transformation, Iter1T start_orig_points, + Iter1T end_orig_points, Iter2T start_transformed_points) { double result = 0; - Iter1T orig_iter=start_orig_points; - Iter2T transf_iter=start_transformed_points; - while (orig_iter!=end_orig_points) - { - result += norm_squared(transformation.transform_point(*orig_iter) - - *transf_iter); - ++orig_iter; - ++transf_iter; - } - + Iter1T orig_iter = start_orig_points; + Iter2T transf_iter = start_transformed_points; + while (orig_iter != end_orig_points) { + result += norm_squared(transformation.transform_point(*orig_iter) - *transf_iter); + ++orig_iter; + ++transf_iter; + } + return std::sqrt(result / (end_orig_points - start_orig_points)); } template Succeeded -RigidObject3DTransformation:: -find_closest_transformation(RigidObject3DTransformation& result, - Iter1T start_orig_points, - Iter1T end_orig_points, - Iter2T start_transformed_points, - const Quaternion& initial_rotation) -{ +RigidObject3DTransformation::find_closest_transformation(RigidObject3DTransformation& result, Iter1T start_orig_points, + Iter1T end_orig_points, Iter2T start_transformed_points, + const Quaternion& initial_rotation) { #ifdef DO_XY_SWAP error("Currently find_closest_transformation does not work with these conventions"); #endif - const CartesianCoordinate3D orig_average = - average(start_orig_points, end_orig_points); - const CartesianCoordinate3D transf_average = - average(start_transformed_points, - start_transformed_points + (end_orig_points - start_orig_points)); - - const Array<2,float> horn_matrix = - detail::construct_Horn_matrix(start_orig_points, - end_orig_points, - start_transformed_points, - orig_average, transf_average); - + const CartesianCoordinate3D orig_average = average(start_orig_points, end_orig_points); + const CartesianCoordinate3D transf_average = + average(start_transformed_points, start_transformed_points + (end_orig_points - start_orig_points)); + + const Array<2, float> horn_matrix = + detail::construct_Horn_matrix(start_orig_points, end_orig_points, start_transformed_points, orig_average, transf_average); + float max_eigenvalue; - Array<1,float> max_eigenvector; - Array<1,float> start(4); + Array<1, float> max_eigenvector; + Array<1, float> start(4); std::copy(initial_rotation.begin(), initial_rotation.end(), start.begin()); - if (max_eigenvector_using_power_method(max_eigenvalue, - max_eigenvector, - horn_matrix, - start, - /* tolerance*/ .0005, - /*max_num_iterations*/ 10000UL) - == Succeeded::no) - { - warning("find_closest_transformation failed because power method did not converge"); - return Succeeded::no; - } + if (max_eigenvector_using_power_method(max_eigenvalue, max_eigenvector, horn_matrix, start, + /* tolerance*/ .0005, + /*max_num_iterations*/ 10000UL) == Succeeded::no) { + warning("find_closest_transformation failed because power method did not converge"); + return Succeeded::no; + } Quaternion q; std::copy(max_eigenvector.begin(), max_eigenvector.end(), q.begin()); #ifdef FIRSTROT q = conjugate(q); - const RigidObject3DTransformation - centred_transf(q,CartesianCoordinate3D(0,0,0)); - const CartesianCoordinate3D translation = - transf_average - centred_transf.transform_point(orig_average); + const RigidObject3DTransformation centred_transf(q, CartesianCoordinate3D(0, 0, 0)); + const CartesianCoordinate3D translation = transf_average - centred_transf.transform_point(orig_average); #else - const RigidObject3DTransformation - centred_transf(conjugate(q),CartesianCoordinate3D(0,0,0)); + const RigidObject3DTransformation centred_transf(conjugate(q), CartesianCoordinate3D(0, 0, 0)); - const CartesianCoordinate3D translation = - orig_average - centred_transf.transform_point(transf_average); + const CartesianCoordinate3D translation = orig_average - centred_transf.transform_point(transf_average); #endif result = RigidObject3DTransformation(q, translation); return Succeeded::yes; } - -template -Succeeded -RigidObject3DTransformation:: -find_closest_transformation<>(RigidObject3DTransformation& result, - std::vector >::const_iterator start_orig_points, - std::vector >::const_iterator end_orig_points, - std::vector >::const_iterator start_transformed_points, - const Quaternion& initial_rotation); -template -Succeeded -RigidObject3DTransformation:: -find_closest_transformation<>(RigidObject3DTransformation& result, - std::vector >::iterator start_orig_points, - std::vector >::iterator end_orig_points, - std::vector >::iterator start_transformed_points, - const Quaternion& initial_rotation); - - -template -double -RigidObject3DTransformation:: -RMSE<>(const RigidObject3DTransformation&, - std::vector >::const_iterator start_orig_points, - std::vector >::const_iterator end_orig_points, - std::vector >::const_iterator start_transformed_points); - -template -double -RigidObject3DTransformation:: -RMSE<>(const RigidObject3DTransformation&, - std::vector >::iterator start_orig_points, - std::vector >::iterator end_orig_points, - std::vector >::iterator start_transformed_points); +template Succeeded RigidObject3DTransformation::find_closest_transformation<>( + RigidObject3DTransformation& result, std::vector>::const_iterator start_orig_points, + std::vector>::const_iterator end_orig_points, + std::vector>::const_iterator start_transformed_points, + const Quaternion& initial_rotation); +template Succeeded RigidObject3DTransformation::find_closest_transformation<>( + RigidObject3DTransformation& result, std::vector>::iterator start_orig_points, + std::vector>::iterator end_orig_points, + std::vector>::iterator start_transformed_points, const Quaternion& initial_rotation); + +template double +RigidObject3DTransformation::RMSE<>(const RigidObject3DTransformation&, + std::vector>::const_iterator start_orig_points, + std::vector>::const_iterator end_orig_points, + std::vector>::const_iterator start_transformed_points); + +template double RigidObject3DTransformation::RMSE<>(const RigidObject3DTransformation&, + std::vector>::iterator start_orig_points, + std::vector>::iterator end_orig_points, + std::vector>::iterator start_transformed_points); END_NAMESPACE_STIR diff --git a/src/experimental/motion/TimeFrameMotion.cxx b/src/experimental/motion/TimeFrameMotion.cxx index a7d92cd9fc..f3256314ec 100644 --- a/src/experimental/motion/TimeFrameMotion.cxx +++ b/src/experimental/motion/TimeFrameMotion.cxx @@ -17,28 +17,25 @@ START_NAMESPACE_STIR -void -TimeFrameMotion::set_defaults() -{ +void +TimeFrameMotion::set_defaults() { _ro3d_sptr.reset(); _reference_abs_time_sptr.reset(); _frame_num_to_process = -1; _do_move_to_reference = true; - _scan_start_time_secs_since_1970_UTC=-1; - _frame_defs=TimeFrameDefinitions(); + _scan_start_time_secs_since_1970_UTC = -1; + _frame_defs = TimeFrameDefinitions(); } -void -TimeFrameMotion::initialise_keymap() -{ +void +TimeFrameMotion::initialise_keymap() { - parser.add_key("scan_start_time_secs_since_1970_UTC", - &_scan_start_time_secs_since_1970_UTC); - parser.add_key("time frame definition filename",&_frame_definition_filename); + parser.add_key("scan_start_time_secs_since_1970_UTC", &_scan_start_time_secs_since_1970_UTC); + parser.add_key("time frame definition filename", &_frame_definition_filename); parser.add_parsing_key("time interval for reference position type", &_reference_abs_time_sptr); parser.add_key("move_to_reference", &_do_move_to_reference); parser.add_key("frame_num_to_process", &_frame_num_to_process); - parser.add_parsing_key("Rigid Object 3D Motion Type", &_ro3d_sptr); + parser.add_parsing_key("Rigid Object 3D Motion Type", &_ro3d_sptr); } /* @@ -49,7 +46,7 @@ TimeFrameMotion(const char * const par_filename) if (par_filename!=0) { if (parse(par_filename)==false) - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } else ask_parameters(); @@ -57,121 +54,92 @@ TimeFrameMotion(const char * const par_filename) } */ bool -TimeFrameMotion:: -post_processing() -{ - - if (_scan_start_time_secs_since_1970_UTC==-1) - { - warning("scan_start_time_secs_since_1970_UTC not set.\n" - "Frame definitions will be assumed to use the same reference point as the tracker (which for Polaris means the start of the list mode data)."); - _scan_start_time = 0; +TimeFrameMotion::post_processing() { + + if (_scan_start_time_secs_since_1970_UTC == -1) { + warning("scan_start_time_secs_since_1970_UTC not set.\n" + "Frame definitions will be assumed to use the same reference point as the tracker (which for Polaris means the start " + "of the list mode data)."); + _scan_start_time = 0; + } else { + if (_scan_start_time_secs_since_1970_UTC < 1000) { + warning("scan_start_time_secs_since_1970_UTC too small"); + return true; } - else { - if (_scan_start_time_secs_since_1970_UTC<1000) - { - warning("scan_start_time_secs_since_1970_UTC too small"); - return true; - } - { - // save _scan_start_time as rel_time as reported by ro3d - time_t sec_time = _scan_start_time_secs_since_1970_UTC; - - _scan_start_time = - _ro3d_sptr->secs_since_1970_to_rel_time(sec_time); - } + // save _scan_start_time as rel_time as reported by ro3d + time_t sec_time = _scan_start_time_secs_since_1970_UTC; + + _scan_start_time = _ro3d_sptr->secs_since_1970_to_rel_time(sec_time); } - + } + // handle time frame definitions etc - if (_frame_definition_filename.size()==0) - { - warning("Have to specify 'time frame_definition_filename'\n"); - return true; - } + if (_frame_definition_filename.size() == 0) { + warning("Have to specify 'time frame_definition_filename'\n"); + return true; + } _frame_defs = TimeFrameDefinitions(_frame_definition_filename); - if (is_null_ptr(_ro3d_sptr)) - { + if (is_null_ptr(_ro3d_sptr)) { warning("Invalid Rigid Object 3D Motion object\n"); return true; } - if (_frame_num_to_process!=-1 && - (_frame_num_to_process<1 || - static_cast(_frame_num_to_process)>_frame_defs.get_num_frames())) - { - warning("Frame number should be between 1 and %d\n", - _frame_defs.get_num_frames()); - return true; - } + if (_frame_num_to_process != -1 && + (_frame_num_to_process < 1 || static_cast(_frame_num_to_process) > _frame_defs.get_num_frames())) { + warning("Frame number should be between 1 and %d\n", _frame_defs.get_num_frames()); + return true; + } // set transformation_to_reference_position - if (is_null_ptr(_reference_abs_time_sptr)) - { - warning("time interval for reference position is not set"); - return true; - } - { - const RigidObject3DTransformation av_motion = - _ro3d_sptr->compute_average_motion_in_scanner_coords(*_reference_abs_time_sptr); - _transformation_to_reference_position =av_motion.inverse(); - } - - set_frame_num_to_process(_frame_num_to_process); + if (is_null_ptr(_reference_abs_time_sptr)) { + warning("time interval for reference position is not set"); + return true; + } + { + const RigidObject3DTransformation av_motion = _ro3d_sptr->compute_average_motion_in_scanner_coords(*_reference_abs_time_sptr); + _transformation_to_reference_position = av_motion.inverse(); + } - return false; + set_frame_num_to_process(_frame_num_to_process); + return false; } -void -TimeFrameMotion:: -move_to_reference(const bool value) -{ - _do_move_to_reference=value; +void +TimeFrameMotion::move_to_reference(const bool value) { + _do_move_to_reference = value; } int -TimeFrameMotion:: -get_frame_num_to_process() const -{ +TimeFrameMotion::get_frame_num_to_process() const { return _frame_num_to_process; } void -TimeFrameMotion:: -set_frame_num_to_process(const int value) -{ - _frame_num_to_process=value; - if (_frame_num_to_process==-1) +TimeFrameMotion::set_frame_num_to_process(const int value) { + _frame_num_to_process = value; + if (_frame_num_to_process == -1) return; - const double start_time = - this->get_frame_start_time(_frame_num_to_process); - const double end_time = - this->get_frame_end_time(_frame_num_to_process); - - _current_rigid_object_transformation = - compose(_transformation_to_reference_position, - _ro3d_sptr-> - compute_average_motion_in_scanner_coords_rel_time(start_time, end_time)); + const double start_time = this->get_frame_start_time(_frame_num_to_process); + const double end_time = this->get_frame_end_time(_frame_num_to_process); + + _current_rigid_object_transformation = compose( + _transformation_to_reference_position, _ro3d_sptr->compute_average_motion_in_scanner_coords_rel_time(start_time, end_time)); if (!_do_move_to_reference) - _current_rigid_object_transformation = - _current_rigid_object_transformation.inverse(); + _current_rigid_object_transformation = _current_rigid_object_transformation.inverse(); } -const RigidObject3DTransformation& -TimeFrameMotion:: -get_current_rigid_object_transformation() const -{ +const RigidObject3DTransformation& +TimeFrameMotion::get_current_rigid_object_transformation() const { return _current_rigid_object_transformation; } const TimeFrameDefinitions& -TimeFrameMotion:: -get_time_frame_defs() const -{ +TimeFrameMotion::get_time_frame_defs() const { return _frame_defs; } diff --git a/src/experimental/motion/Transform3DObjectImageProcessor.cxx b/src/experimental/motion/Transform3DObjectImageProcessor.cxx index fee4711def..b7a2c6b1a6 100644 --- a/src/experimental/motion/Transform3DObjectImageProcessor.cxx +++ b/src/experimental/motion/Transform3DObjectImageProcessor.cxx @@ -5,9 +5,9 @@ */ /*! \file - \ingroup ImageProcessor + \ingroup ImageProcessor \brief Implementation of class stir::Transform3DObjectImageProcessor - + \author Kris Thielemans */ @@ -22,292 +22,216 @@ #include "stir/info.h" START_NAMESPACE_STIR -template<> -const char * const -Transform3DObjectImageProcessor::registered_name = +template <> +const char* const Transform3DObjectImageProcessor::registered_name = #if XXX -"rigid transformation"; + "rigid transformation"; #else -"transformation"; + "transformation"; #endif - template -void -Transform3DObjectImageProcessor:: -initialise_keymap() -{ +void +Transform3DObjectImageProcessor::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Transformation Parameters"); #if XXX - this->parser.add_key("transformation",&this->transformation_as_string); + this->parser.add_key("transformation", &this->transformation_as_string); #else - this->parser.add_parsing_key("transformation type",&this->transformation_sptr); + this->parser.add_parsing_key("transformation type", &this->transformation_sptr); #endif this->parser.add_key("do jacobian", &this->_do_jacobian); this->parser.add_key("do transpose", &this->_do_transpose); this->parser.add_key("cache_transformed_coords", &this->_cache_transformed_coords); this->parser.add_stop_key("END Transformation Parameters"); - } template -bool -Transform3DObjectImageProcessor:: -post_processing() -{ +bool +Transform3DObjectImageProcessor::post_processing() { if (base_type::post_processing() != false) return true; #if XXX - if (this->transformation_as_string.size()>0) - { - std::stringstream transformation_as_stream(transformation_as_string); - transformation_as_stream >> this->transformation; - if (!transformation_as_stream.good()) - { - warning("value for 'transformation' keyword is invalid." - "\nIt should be something like '{{q0,qz,qy,qx},{tz,ty,tx}}'"); - return true; - } - if (std::fabs(norm(this->transformation.get_quaternion())-1)>.01) - { - warning("Quaternion should have norm 1 but is %g", - norm(this->transformation.get_quaternion())); - return true; - } - } + if (this->transformation_as_string.size() > 0) { + std::stringstream transformation_as_stream(transformation_as_string); + transformation_as_stream >> this->transformation; + if (!transformation_as_stream.good()) { + warning("value for 'transformation' keyword is invalid." + "\nIt should be something like '{{q0,qz,qy,qx},{tz,ty,tx}}'"); + return true; + } + if (std::fabs(norm(this->transformation.get_quaternion()) - 1) > .01) { + warning("Quaternion should have norm 1 but is %g", norm(this->transformation.get_quaternion())); + return true; + } + } info(boost::format("'transformation' quaternion %1%") % this->transformation.get_quaternion()); info(boost::format("'transformation' translation %1%") % this->transformation.get_translation()); #else - if (is_null_ptr(transformation_sptr)) - { - warning("No transformation set"); - return true; - } + if (is_null_ptr(transformation_sptr)) { + warning("No transformation set"); + return true; + } #endif this->_transformed_coords.recycle(); return false; } template -Transform3DObjectImageProcessor:: -Transform3DObjectImageProcessor(const shared_ptr > transf) -{ +Transform3DObjectImageProcessor::Transform3DObjectImageProcessor(const shared_ptr> transf) { set_defaults(); this->transformation_sptr = transf; } template Succeeded -Transform3DObjectImageProcessor:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) -{ - if (this->_cache_transformed_coords) - { - CPUTimer timer; - timer.start(); - if (!this->_do_jacobian ) - { - this->_transformed_coords = - find_grid_coords_of_transformed_centres(density, - density, - *this->transformation_sptr); - } - else - { - this->_transformed_coords_and_jacobian = - find_grid_coords_of_transformed_centres_and_jacobian(density, - density, - *this->transformation_sptr); - } - timer.stop(); - info(boost::format("CPU time for computing centre coords %1% secs") % timer.value()); - } - else - { - this->_transformed_coords.recycle(); - this->_transformed_coords_and_jacobian.recycle(); +Transform3DObjectImageProcessor::virtual_set_up(const DiscretisedDensity<3, elemT>& density) { + if (this->_cache_transformed_coords) { + CPUTimer timer; + timer.start(); + if (!this->_do_jacobian) { + this->_transformed_coords = find_grid_coords_of_transformed_centres(density, density, *this->transformation_sptr); + } else { + this->_transformed_coords_and_jacobian = + find_grid_coords_of_transformed_centres_and_jacobian(density, density, *this->transformation_sptr); } - return Succeeded::yes; + timer.stop(); + info(boost::format("CPU time for computing centre coords %1% secs") % timer.value()); + } else { + this->_transformed_coords.recycle(); + this->_transformed_coords_and_jacobian.recycle(); + } + return Succeeded::yes; } - template void -Transform3DObjectImageProcessor:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const +Transform3DObjectImageProcessor::virtual_apply(DiscretisedDensity<3, elemT>& density) const -{ - shared_ptr > density_copy_sptr(density.clone()); +{ + shared_ptr> density_copy_sptr(density.clone()); density.fill(0); - this->virtual_apply(density, *density_copy_sptr); + this->virtual_apply(density, *density_copy_sptr); } - template void -Transform3DObjectImageProcessor:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, - const DiscretisedDensity<3,elemT>& in_density) const -{ +Transform3DObjectImageProcessor::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { #if XXX if (this->_do_transpose) - transpose_of_transform_3d_object(out_density, - in_density, - this->transformation); + transpose_of_transform_3d_object(out_density, in_density, this->transformation); else - transform_3d_object(out_density, - in_density, - this->transformation); + transform_3d_object(out_density, in_density, this->transformation); #else - if (this->_cache_transformed_coords) - { - if (this->_do_transpose) - { - PushTransposeLinearInterpolator interpolator; - //PushNearestNeighbourInterpolator interpolator; - interpolator.set_output(out_density); - - for (int z= in_density.get_min_index(); z<= in_density.get_max_index(); ++z) - for (int y= in_density[z].get_min_index(); y<= in_density[z].get_max_index(); ++y) - for (int x= in_density[z][y].get_min_index(); x<= in_density[z][y].get_max_index(); ++x) - { - if (this->_do_jacobian ) - { - const float jacobian = - this->_transformed_coords_and_jacobian[z][y][x].second; - if (jacobian<.01) - error("jacobian too small : %g at z=%d,y=%d,x=%d", - jacobian,z,y,x); - interpolator.add_to(this->_transformed_coords_and_jacobian[z][y][x].first, - in_density[z][y][x]*jacobian); - } - else - interpolator.add_to(this->_transformed_coords[z][y][x], in_density[z][y][x]); - } - } - else - { - PullLinearInterpolator interpolator; - //PullNearestNeighbourInterpolator interpolator; - interpolator.set_input(in_density); - for (int z= out_density.get_min_index(); z<= out_density.get_max_index(); ++z) - for (int y= out_density[z].get_min_index(); y<= out_density[z].get_max_index(); ++y) - for (int x= out_density[z][y].get_min_index(); x<= out_density[z][y].get_max_index(); ++x) - { - if (this->_do_jacobian ) - { - const float jacobian = - this->_transformed_coords_and_jacobian[z][y][x].second; - if (jacobian<.01) - error("jacobian too small : %g at z=%d,y=%d,x=%d", - jacobian,z,y,x); - // TODO thnk about divide or multiply jacobian - out_density[z][y][x] = - interpolator(this->_transformed_coords_and_jacobian[z][y][x].first)*jacobian; - } - else - out_density[z][y][x] = - interpolator(this->_transformed_coords[z][y][x]); - } - } - } - else // !_cache_transformed_coords - { - if (this->_do_transpose) - transform_3d_object_push_interpolation(out_density, - in_density, - *this->transformation_sptr, - PushTransposeLinearInterpolator(), - //PushNearestNeighbourInterpolator(), - this->_do_jacobian); - else - transform_3d_object_pull_interpolation(out_density, - in_density, - *this->transformation_sptr, - PullLinearInterpolator(), - //PullNearestNeighbourInterpolator(), - this->_do_jacobian ); + if (this->_cache_transformed_coords) { + if (this->_do_transpose) { + PushTransposeLinearInterpolator interpolator; + // PushNearestNeighbourInterpolator interpolator; + interpolator.set_output(out_density); + + for (int z = in_density.get_min_index(); z <= in_density.get_max_index(); ++z) + for (int y = in_density[z].get_min_index(); y <= in_density[z].get_max_index(); ++y) + for (int x = in_density[z][y].get_min_index(); x <= in_density[z][y].get_max_index(); ++x) { + if (this->_do_jacobian) { + const float jacobian = this->_transformed_coords_and_jacobian[z][y][x].second; + if (jacobian < .01) + error("jacobian too small : %g at z=%d,y=%d,x=%d", jacobian, z, y, x); + interpolator.add_to(this->_transformed_coords_and_jacobian[z][y][x].first, in_density[z][y][x] * jacobian); + } else + interpolator.add_to(this->_transformed_coords[z][y][x], in_density[z][y][x]); + } + } else { + PullLinearInterpolator interpolator; + // PullNearestNeighbourInterpolator interpolator; + interpolator.set_input(in_density); + for (int z = out_density.get_min_index(); z <= out_density.get_max_index(); ++z) + for (int y = out_density[z].get_min_index(); y <= out_density[z].get_max_index(); ++y) + for (int x = out_density[z][y].get_min_index(); x <= out_density[z][y].get_max_index(); ++x) { + if (this->_do_jacobian) { + const float jacobian = this->_transformed_coords_and_jacobian[z][y][x].second; + if (jacobian < .01) + error("jacobian too small : %g at z=%d,y=%d,x=%d", jacobian, z, y, x); + // TODO thnk about divide or multiply jacobian + out_density[z][y][x] = interpolator(this->_transformed_coords_and_jacobian[z][y][x].first) * jacobian; + } else + out_density[z][y][x] = interpolator(this->_transformed_coords[z][y][x]); + } } + } else // !_cache_transformed_coords + { + if (this->_do_transpose) + transform_3d_object_push_interpolation(out_density, in_density, *this->transformation_sptr, + PushTransposeLinearInterpolator(), + // PushNearestNeighbourInterpolator(), + this->_do_jacobian); + else + transform_3d_object_pull_interpolation(out_density, in_density, *this->transformation_sptr, PullLinearInterpolator(), + // PullNearestNeighbourInterpolator(), + this->_do_jacobian); + } #endif } - template void -Transform3DObjectImageProcessor:: -set_defaults() -{ +Transform3DObjectImageProcessor::set_defaults() { base_type::set_defaults(); - this->_do_transpose=false; - this->_do_jacobian=false; - this->_cache_transformed_coords=false; + this->_do_transpose = false; + this->_do_jacobian = false; + this->_cache_transformed_coords = false; #if XXX - this->transformation = RigidObject3DTransformation(Quaternion(1,0,0,0), - CartesianCoordinate3D(0,0,0)); + this->transformation = RigidObject3DTransformation(Quaternion(1, 0, 0, 0), CartesianCoordinate3D(0, 0, 0)); #else this->transformation_sptr.reset(); #endif } - template bool -Transform3DObjectImageProcessor:: -get_do_transpose() const -{ +Transform3DObjectImageProcessor::get_do_transpose() const { return this->_do_transpose; } template void -Transform3DObjectImageProcessor:: -set_do_transpose(const bool value) -{ +Transform3DObjectImageProcessor::set_do_transpose(const bool value) { this->_do_transpose = value; } template bool -Transform3DObjectImageProcessor:: -get_do_jacobian() const -{ +Transform3DObjectImageProcessor::get_do_jacobian() const { return this->_do_jacobian; } template void -Transform3DObjectImageProcessor:: -set_do_jacobian(const bool value) -{ +Transform3DObjectImageProcessor::set_do_jacobian(const bool value) { this->_do_jacobian = value; } template bool -Transform3DObjectImageProcessor:: -get_do_cache() const -{ +Transform3DObjectImageProcessor::get_do_cache() const { return this->_cache_transformed_coords; } template void -Transform3DObjectImageProcessor:: -set_do_cache(const bool value) -{ +Transform3DObjectImageProcessor::set_do_cache(const bool value) { this->_cache_transformed_coords = value; } -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif template class Transform3DObjectImageProcessor; diff --git a/src/experimental/motion/local_motion_registries.cxx b/src/experimental/motion/local_motion_registries.cxx index cb7565824f..c4edc8accc 100644 --- a/src/experimental/motion/local_motion_registries.cxx +++ b/src/experimental/motion/local_motion_registries.cxx @@ -13,7 +13,6 @@ */ - // #include "stir_experimental/motion/RigidObject3DMotionFromPolaris.h" #include "stir_experimental/motion/Transform3DObjectImageProcessor.h" #include "stir_experimental/motion/NonRigidObjectTransformationUsingBSplines.h" @@ -29,9 +28,9 @@ START_NAMESPACE_STIR static Transform3DObjectImageProcessor::RegisterIt dummy1000; -static NonRigidObjectTransformationUsingBSplines<3,float>::RegisterIt dummy2000; -//static RigidObject3DTransformation::RegisterIt dummy2000; +static NonRigidObjectTransformationUsingBSplines<3, float>::RegisterIt dummy2000; +// static RigidObject3DTransformation::RegisterIt dummy2000; -// static PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion >::RegisterIt dummy4000; +// static PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion >::RegisterIt +// dummy4000; END_NAMESPACE_STIR - diff --git a/src/experimental/motion/transform_3d_object.cxx b/src/experimental/motion/transform_3d_object.cxx index 7966e96544..16fe5e0856 100644 --- a/src/experimental/motion/transform_3d_object.cxx +++ b/src/experimental/motion/transform_3d_object.cxx @@ -29,149 +29,108 @@ #include "stir_experimental/motion/RigidObject3DTransformation.h" #include "stir_experimental/numerics/more_interpolators.h" #ifdef ROT_INT -#include "stir_experimental/motion/bin_interpolate.h" +# include "stir_experimental/motion/bin_interpolate.h" #endif START_NAMESPACE_STIR - -Succeeded -transform_3d_object(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const RigidObject3DTransformation& transformation_in_to_out) -{ - return - transform_3d_object_pull_interpolation(out_density, - in_density, - transformation_in_to_out.inverse(), - PullLinearInterpolator(), - /*do_jacobian=*/false ); // jacobian is 1 anyway +Succeeded +transform_3d_object(DiscretisedDensity<3, float>& out_density, const DiscretisedDensity<3, float>& in_density, + const RigidObject3DTransformation& transformation_in_to_out) { + return transform_3d_object_pull_interpolation(out_density, in_density, transformation_in_to_out.inverse(), + PullLinearInterpolator(), + /*do_jacobian=*/false); // jacobian is 1 anyway } Succeeded -transpose_of_transform_3d_object(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const RigidObject3DTransformation& transformation_in_to_out) -{ - return - transform_3d_object_push_interpolation(out_density, - in_density, - transformation_in_to_out.inverse(), - PushTransposeLinearInterpolator(), - /*do_jacobian=*/false ); // jacobian is 1 anyway +transpose_of_transform_3d_object(DiscretisedDensity<3, float>& out_density, const DiscretisedDensity<3, float>& in_density, + const RigidObject3DTransformation& transformation_in_to_out) { + return transform_3d_object_push_interpolation(out_density, in_density, transformation_in_to_out.inverse(), + PushTransposeLinearInterpolator(), + /*do_jacobian=*/false); // jacobian is 1 anyway } //////////////////////////////////////// // ugly functions for storing transformed points. // TODO clean up at some point -Array<3, BasicCoordinate<3,float> > -find_grid_coords_of_transformed_centres(const DiscretisedDensity<3,float>& source_density, - const DiscretisedDensity<3,float>& target_density, - const ObjectTransformation<3,float>& transformation_source_to_target) -{ - Array<3, BasicCoordinate<3,float> > transformed_centre_coords(source_density.get_index_range()); - const VoxelsOnCartesianGrid& target_image = - dynamic_cast const&>(target_density); - const VoxelsOnCartesianGrid& source_image = - dynamic_cast const&>(source_density); - - for (int z= source_image.get_min_index(); z<= source_image.get_max_index(); ++z) - for (int y= source_image[z].get_min_index(); y<= source_image[z].get_max_index(); ++y) - for (int x= source_image[z][y].get_min_index(); x<= source_image[z][y].get_max_index(); ++x) - { +Array<3, BasicCoordinate<3, float>> +find_grid_coords_of_transformed_centres(const DiscretisedDensity<3, float>& source_density, + const DiscretisedDensity<3, float>& target_density, + const ObjectTransformation<3, float>& transformation_source_to_target) { + Array<3, BasicCoordinate<3, float>> transformed_centre_coords(source_density.get_index_range()); + const VoxelsOnCartesianGrid& target_image = dynamic_cast const&>(target_density); + const VoxelsOnCartesianGrid& source_image = dynamic_cast const&>(source_density); + + for (int z = source_image.get_min_index(); z <= source_image.get_max_index(); ++z) + for (int y = source_image[z].get_min_index(); y <= source_image[z].get_max_index(); ++y) + for (int x = source_image[z][y].get_min_index(); x <= source_image[z][y].get_max_index(); ++x) { const CartesianCoordinate3D current_point = - CartesianCoordinate3D(static_cast(z), - static_cast(y), - static_cast(x)) * - source_image.get_voxel_size() + - source_image.get_origin(); - const CartesianCoordinate3D new_point = - transformation_source_to_target.transform_point(current_point); + CartesianCoordinate3D(static_cast(z), static_cast(y), static_cast(x)) * + source_image.get_voxel_size() + + source_image.get_origin(); + const CartesianCoordinate3D new_point = transformation_source_to_target.transform_point(current_point); const CartesianCoordinate3D new_point_target_image_coords = - (new_point - target_image.get_origin()) / target_image.get_voxel_size(); - transformed_centre_coords[z][y][x] = new_point_target_image_coords; - } + (new_point - target_image.get_origin()) / target_image.get_voxel_size(); + transformed_centre_coords[z][y][x] = new_point_target_image_coords; + } return transformed_centre_coords; } -Array<3, std::pair, float> > -find_grid_coords_of_transformed_centres_and_jacobian(const DiscretisedDensity<3,float>& source_density, - const DiscretisedDensity<3,float>& target_density, - const ObjectTransformation<3,float>& transformation_source_to_target) -{ - Array<3, std::pair, float> > transformed_centre_coords(source_density.get_index_range()); - const VoxelsOnCartesianGrid& target_image = - dynamic_cast const&>(target_density); - const VoxelsOnCartesianGrid& source_image = - dynamic_cast const&>(source_density); - - for (int z= source_image.get_min_index(); z<= source_image.get_max_index(); ++z) - for (int y= source_image[z].get_min_index(); y<= source_image[z].get_max_index(); ++y) - for (int x= source_image[z][y].get_min_index(); x<= source_image[z][y].get_max_index(); ++x) - { +Array<3, std::pair, float>> +find_grid_coords_of_transformed_centres_and_jacobian(const DiscretisedDensity<3, float>& source_density, + const DiscretisedDensity<3, float>& target_density, + const ObjectTransformation<3, float>& transformation_source_to_target) { + Array<3, std::pair, float>> transformed_centre_coords(source_density.get_index_range()); + const VoxelsOnCartesianGrid& target_image = dynamic_cast const&>(target_density); + const VoxelsOnCartesianGrid& source_image = dynamic_cast const&>(source_density); + + for (int z = source_image.get_min_index(); z <= source_image.get_max_index(); ++z) + for (int y = source_image[z].get_min_index(); y <= source_image[z].get_max_index(); ++y) + for (int x = source_image[z][y].get_min_index(); x <= source_image[z][y].get_max_index(); ++x) { const CartesianCoordinate3D current_point = - CartesianCoordinate3D(static_cast(z), - static_cast(y), - static_cast(x)) * - source_image.get_voxel_size() + - source_image.get_origin(); - const CartesianCoordinate3D new_point = - transformation_source_to_target.transform_point(current_point); + CartesianCoordinate3D(static_cast(z), static_cast(y), static_cast(x)) * + source_image.get_voxel_size() + + source_image.get_origin(); + const CartesianCoordinate3D new_point = transformation_source_to_target.transform_point(current_point); const CartesianCoordinate3D new_point_target_image_coords = - (new_point - target_image.get_origin()) / target_image.get_voxel_size(); - transformed_centre_coords[z][y][x].first = new_point_target_image_coords; - transformed_centre_coords[z][y][x].second = - transformation_source_to_target.jacobian(current_point); - } + (new_point - target_image.get_origin()) / target_image.get_voxel_size(); + transformed_centre_coords[z][y][x].first = new_point_target_image_coords; + transformed_centre_coords[z][y][x].second = transformation_source_to_target.jacobian(current_point); + } return transformed_centre_coords; } ///////////////////////////////// // transform ProjData Succeeded -transform_3d_object(ProjData& out_proj_data, - const ProjData& in_proj_data, - const RigidObject3DTransformation& rigid_object_transformation) -{ - return transform_3d_object(out_proj_data, - in_proj_data, - rigid_object_transformation, - in_proj_data.get_min_segment_num(), - in_proj_data.get_max_segment_num()); +transform_3d_object(ProjData& out_proj_data, const ProjData& in_proj_data, + const RigidObject3DTransformation& rigid_object_transformation) { + return transform_3d_object(out_proj_data, in_proj_data, rigid_object_transformation, in_proj_data.get_min_segment_num(), + in_proj_data.get_max_segment_num()); } Succeeded -transform_3d_object(ProjData& out_proj_data, - const ProjData& in_proj_data, - const RigidObject3DTransformation& rigid_object_transformation, - const int min_in_segment_num_to_process, - const int max_in_segment_num_to_process) -{ +transform_3d_object(ProjData& out_proj_data, const ProjData& in_proj_data, + const RigidObject3DTransformation& rigid_object_transformation, const int min_in_segment_num_to_process, + const int max_in_segment_num_to_process) { #ifdef NEW_ROT - warning( "Using NEW_ROT"); + warning("Using NEW_ROT"); #else warning("Using original ROT"); #endif #ifndef NEW_ROT - const ProjDataInfoCylindricalNoArcCorr* const - out_proj_data_info_noarccor_ptr = - dynamic_cast(out_proj_data.get_proj_data_info_sptr()); - const ProjDataInfoCylindricalNoArcCorr* const - in_proj_data_info_noarccor_ptr = - dynamic_cast(in_proj_data.get_proj_data_info_sptr()); - if (out_proj_data_info_noarccor_ptr == 0 || - in_proj_data_info_noarccor_ptr == 0) - { - warning("Wrong type of proj_data_info (no-arccorrection)\n"); - return Succeeded::no; - } + const ProjDataInfoCylindricalNoArcCorr* const out_proj_data_info_noarccor_ptr = + dynamic_cast(out_proj_data.get_proj_data_info_sptr()); + const ProjDataInfoCylindricalNoArcCorr* const in_proj_data_info_noarccor_ptr = + dynamic_cast(in_proj_data.get_proj_data_info_sptr()); + if (out_proj_data_info_noarccor_ptr == 0 || in_proj_data_info_noarccor_ptr == 0) { + warning("Wrong type of proj_data_info (no-arccorrection)\n"); + return Succeeded::no; + } #else - const ProjDataInfo& - out_proj_data_info = - *out_proj_data.get_proj_data_info_sptr(); - const ProjDataInfo& - in_proj_data_info = *in_proj_data.get_proj_data_info_sptr(); + const ProjDataInfo& out_proj_data_info = *out_proj_data.get_proj_data_info_sptr(); + const ProjDataInfo& in_proj_data_info = *in_proj_data.get_proj_data_info_sptr(); #endif const int out_min_segment_num = out_proj_data.get_min_segment_num(); const int out_max_segment_num = out_proj_data.get_max_segment_num(); @@ -179,138 +138,97 @@ transform_3d_object(ProjData& out_proj_data, #if 1 warning("Using push interpolation"); -#ifdef ROT_INT +# ifdef ROT_INT warning("with linear interpolation"); -#endif - VectorWithOffset > > out_seg_ptr(out_min_segment_num, out_max_segment_num); - for (int segment_num = out_min_segment_num; - segment_num <= out_max_segment_num; - ++segment_num) - out_seg_ptr[segment_num]. - reset(new SegmentByView(out_proj_data.get_empty_segment_by_view(segment_num))); - for (int segment_num = min_in_segment_num_to_process; - segment_num <= max_in_segment_num_to_process; - ++segment_num) - { - const SegmentByView in_segment = - in_proj_data.get_segment_by_view( segment_num); - info(boost::format("segment_num %1%") % segment_num); - const int in_max_ax_pos_num = in_segment.get_max_axial_pos_num(); - const int in_min_ax_pos_num = in_segment.get_min_axial_pos_num(); - const int in_max_view_num = in_segment.get_max_view_num(); - const int in_min_view_num = in_segment.get_min_view_num(); - const int in_max_tang_pos_num = in_segment.get_max_tangential_pos_num(); - const int in_min_tang_pos_num = in_segment.get_min_tangential_pos_num(); - for (int view_num=in_min_view_num; view_num<=in_max_view_num; ++view_num) - for (int ax_pos_num=in_min_ax_pos_num; ax_pos_num<=in_max_ax_pos_num; ++ax_pos_num) - for (int tang_pos_num=in_min_tang_pos_num; tang_pos_num<=in_max_tang_pos_num; ++tang_pos_num) - { - Bin bin(segment_num, view_num, ax_pos_num, tang_pos_num, - in_segment[view_num][ax_pos_num][tang_pos_num]); - if (bin.get_bin_value()==0) - continue; -#ifndef ROT_INT - rigid_object_transformation.transform_bin(bin, -# ifndef NEW_ROT - *out_proj_data_info_noarccor_ptr, - *in_proj_data_info_noarccor_ptr -# else - out_proj_data_info, - in_proj_data_info -# endif - ); - if (bin.get_bin_value()>0) - (*out_seg_ptr[bin.segment_num()])[bin.view_num()] - [bin.axial_pos_num()] - [bin.tangential_pos_num()] += - bin.get_bin_value(); -#else -# ifndef NEW_ROT -# error ROT_INT defined but NEW_ROT not -# endif - LORInAxialAndNoArcCorrSinogramCoordinates transformed_lor; - if (get_transformed_LOR(transformed_lor, - rigid_object_transformation, - bin, - in_proj_data_info) == Succeeded::yes) - bin_interpolate(out_seg_ptr, transformed_lor, out_proj_data_info, in_proj_data_info, bin.get_bin_value()); -#endif - - } - } +# endif + VectorWithOffset>> out_seg_ptr(out_min_segment_num, out_max_segment_num); + for (int segment_num = out_min_segment_num; segment_num <= out_max_segment_num; ++segment_num) + out_seg_ptr[segment_num].reset(new SegmentByView(out_proj_data.get_empty_segment_by_view(segment_num))); + for (int segment_num = min_in_segment_num_to_process; segment_num <= max_in_segment_num_to_process; ++segment_num) { + const SegmentByView in_segment = in_proj_data.get_segment_by_view(segment_num); + info(boost::format("segment_num %1%") % segment_num); + const int in_max_ax_pos_num = in_segment.get_max_axial_pos_num(); + const int in_min_ax_pos_num = in_segment.get_min_axial_pos_num(); + const int in_max_view_num = in_segment.get_max_view_num(); + const int in_min_view_num = in_segment.get_min_view_num(); + const int in_max_tang_pos_num = in_segment.get_max_tangential_pos_num(); + const int in_min_tang_pos_num = in_segment.get_min_tangential_pos_num(); + for (int view_num = in_min_view_num; view_num <= in_max_view_num; ++view_num) + for (int ax_pos_num = in_min_ax_pos_num; ax_pos_num <= in_max_ax_pos_num; ++ax_pos_num) + for (int tang_pos_num = in_min_tang_pos_num; tang_pos_num <= in_max_tang_pos_num; ++tang_pos_num) { + Bin bin(segment_num, view_num, ax_pos_num, tang_pos_num, in_segment[view_num][ax_pos_num][tang_pos_num]); + if (bin.get_bin_value() == 0) + continue; +# ifndef ROT_INT + rigid_object_transformation.transform_bin(bin, +# ifndef NEW_ROT + *out_proj_data_info_noarccor_ptr, *in_proj_data_info_noarccor_ptr +# else + out_proj_data_info, in_proj_data_info +# endif + ); + if (bin.get_bin_value() > 0) + (*out_seg_ptr[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += + bin.get_bin_value(); +# else +# ifndef NEW_ROT +# error ROT_INT defined but NEW_ROT not +# endif + LORInAxialAndNoArcCorrSinogramCoordinates transformed_lor; + if (get_transformed_LOR(transformed_lor, rigid_object_transformation, bin, in_proj_data_info) == Succeeded::yes) + bin_interpolate(out_seg_ptr, transformed_lor, out_proj_data_info, in_proj_data_info, bin.get_bin_value()); +# endif + } + } Succeeded succes = Succeeded::yes; - for (int segment_num = out_proj_data.get_min_segment_num(); - segment_num <= out_proj_data.get_max_segment_num(); - ++segment_num) - { - if (out_proj_data.set_segment(*out_seg_ptr[segment_num]) == Succeeded::no) - succes = Succeeded::no; - } + for (int segment_num = out_proj_data.get_min_segment_num(); segment_num <= out_proj_data.get_max_segment_num(); ++segment_num) { + if (out_proj_data.set_segment(*out_seg_ptr[segment_num]) == Succeeded::no) + succes = Succeeded::no; + } return succes; - #else warning("Using pull interpolation"); - - const RigidObject3DTransformation - inverse_rigid_object_transformation = - rigid_object_transformation.inverse(); - VectorWithOffset > > - in_seg_ptr(min_in_segment_num_to_process,max_in_segment_num_to_process); - for (int segment_num = min_in_segment_num_to_process; - segment_num <= max_in_segment_num_to_process; - ++segment_num) - in_seg_ptr[segment_num] = - new SegmentByView(in_proj_data.get_segment_by_view(segment_num)); - for (int segment_num = out_min_segment_num; - segment_num <= out_max_segment_num; - ++segment_num) - { - SegmentByView out_segment = - out_proj_data.get_empty_segment_by_view( segment_num); - info(boost::format("segment_num %1%") % segment_num); - const int out_max_ax_pos_num = out_segment.get_max_axial_pos_num(); - const int out_min_ax_pos_num = out_segment.get_min_axial_pos_num(); - const int out_max_view_num = out_segment.get_max_view_num(); - const int out_min_view_num = out_segment.get_min_view_num(); - const int out_max_tang_pos_num = out_segment.get_max_tangential_pos_num(); - const int out_min_tang_pos_num = out_segment.get_min_tangential_pos_num(); - for (int view_num=out_min_view_num; view_num<=out_max_view_num; ++view_num) - for (int ax_pos_num=out_min_ax_pos_num; ax_pos_num<=out_max_ax_pos_num; ++ax_pos_num) - for (int tang_pos_num=out_min_tang_pos_num; tang_pos_num<=out_max_tang_pos_num; ++tang_pos_num) - { - Bin bin(segment_num, view_num, ax_pos_num, tang_pos_num,1); - inverse_rigid_object_transformation. - transform_bin(bin, -#ifndef NEW_ROT - *in_proj_data_info_noarccor_ptr, - *out_proj_data_info_noarccor_ptr -#else - in_proj_data_info, - out_proj_data_info -#endif - ); - if (bin.get_bin_value()>0 && - bin.segment_num()>=min_in_segment_num_to_process && - bin.segment_num()<=max_in_segment_num_to_process) - { - out_segment[view_num][ax_pos_num][tang_pos_num] = - (*in_seg_ptr[bin.segment_num()])[bin.view_num()] - [bin.axial_pos_num()] - [bin.tangential_pos_num()]; - } - } - if (out_proj_data.set_segment(out_segment) == Succeeded::no) - return Succeeded::no; - } + const RigidObject3DTransformation inverse_rigid_object_transformation = rigid_object_transformation.inverse(); + VectorWithOffset>> in_seg_ptr(min_in_segment_num_to_process, max_in_segment_num_to_process); + for (int segment_num = min_in_segment_num_to_process; segment_num <= max_in_segment_num_to_process; ++segment_num) + in_seg_ptr[segment_num] = new SegmentByView(in_proj_data.get_segment_by_view(segment_num)); + for (int segment_num = out_min_segment_num; segment_num <= out_max_segment_num; ++segment_num) { + SegmentByView out_segment = out_proj_data.get_empty_segment_by_view(segment_num); + info(boost::format("segment_num %1%") % segment_num); + const int out_max_ax_pos_num = out_segment.get_max_axial_pos_num(); + const int out_min_ax_pos_num = out_segment.get_min_axial_pos_num(); + const int out_max_view_num = out_segment.get_max_view_num(); + const int out_min_view_num = out_segment.get_min_view_num(); + const int out_max_tang_pos_num = out_segment.get_max_tangential_pos_num(); + const int out_min_tang_pos_num = out_segment.get_min_tangential_pos_num(); + for (int view_num = out_min_view_num; view_num <= out_max_view_num; ++view_num) + for (int ax_pos_num = out_min_ax_pos_num; ax_pos_num <= out_max_ax_pos_num; ++ax_pos_num) + for (int tang_pos_num = out_min_tang_pos_num; tang_pos_num <= out_max_tang_pos_num; ++tang_pos_num) { + Bin bin(segment_num, view_num, ax_pos_num, tang_pos_num, 1); + inverse_rigid_object_transformation.transform_bin(bin, +# ifndef NEW_ROT + *in_proj_data_info_noarccor_ptr, *out_proj_data_info_noarccor_ptr +# else + in_proj_data_info, out_proj_data_info +# endif + ); + + if (bin.get_bin_value() > 0 && bin.segment_num() >= min_in_segment_num_to_process && + bin.segment_num() <= max_in_segment_num_to_process) { + out_segment[view_num][ax_pos_num][tang_pos_num] = + (*in_seg_ptr[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()]; + } + } + if (out_proj_data.set_segment(out_segment) == Succeeded::no) + return Succeeded::no; + } return Succeeded::yes; #endif - - } END_NAMESPACE_STIR diff --git a/src/experimental/motion_test/test_BSpline_transformations.cxx b/src/experimental/motion_test/test_BSpline_transformations.cxx index c1077dd8fc..4428371585 100644 --- a/src/experimental/motion_test/test_BSpline_transformations.cxx +++ b/src/experimental/motion_test/test_BSpline_transformations.cxx @@ -41,7 +41,7 @@ #include "stir/HighResWallClockTimer.h" #include "stir/is_null_ptr.h" #ifdef HAVE_ITK -#include "stir/IO/ITKOutputFileFormat.h" +# include "stir/IO/ITKOutputFileFormat.h" #endif START_NAMESPACE_STIR @@ -53,17 +53,14 @@ using namespace std; \brief Test class for Transformations */ -class TestBSplineTransformation : public RunTests -{ +class TestBSplineTransformation : public RunTests { public: //! Constructor that can take some input data to run the test with - TestBSplineTransformation(const string &to_transform, - const string &ground_truth, - const string &disp_4D); + TestBSplineTransformation(const string& to_transform, const string& ground_truth, const string& disp_4D); void run_tests(); -protected: +protected: int _bspline_order; string _to_transform, _ground_truth, _disp_4D; @@ -71,111 +68,102 @@ class TestBSplineTransformation : public RunTests void run_transformation(); }; -TestBSplineTransformation:: -TestBSplineTransformation(const string &to_transform, - const string &ground_truth, - const string &disp_4D) : - _to_transform(to_transform), - _ground_truth(ground_truth), - _disp_4D(disp_4D) -{ - if (_to_transform.empty()) everything_ok = false; - if (_disp_4D.empty()) everything_ok = false; - _bspline_order = 1; +TestBSplineTransformation::TestBSplineTransformation(const string& to_transform, const string& ground_truth, + const string& disp_4D) + : _to_transform(to_transform), _ground_truth(ground_truth), _disp_4D(disp_4D) { + if (_to_transform.empty()) + everything_ok = false; + if (_disp_4D.empty()) + everything_ok = false; + _bspline_order = 1; } void -TestBSplineTransformation:: -run_transformation() -{ - // Open image - std::cerr << "\nabout to read the image to transform...\n"; - shared_ptr > input( - DiscretisedDensity<3,float>::read_from_file(_to_transform)); - if(is_null_ptr(input)) { - std::cerr << "\nError reading image to transform.\n"; - everything_ok = false; - return; - } - - // Open ground truth - std::cerr << "\nabout to read the ground truth image...\n"; - shared_ptr > ground_truth( - DiscretisedDensity<3,float>::read_from_file(_ground_truth)); - if(is_null_ptr(ground_truth)) { - std::cerr << "\nError reading ground truth image.\n"; - everything_ok = false; - return; - } - - shared_ptr > fwrd_non_rigid( - new NonRigidObjectTransformationUsingBSplines<3,float>(_disp_4D,_bspline_order)); - - // Image processors - shared_ptr > forward_transform( new Transform3DObjectImageProcessor(fwrd_non_rigid)); - shared_ptr > adjoint_transform( new Transform3DObjectImageProcessor(*forward_transform)); - adjoint_transform->set_do_transpose(!forward_transform->get_do_transpose()); - - std::cout << "\n\tDoing forward transformation...\n"; - shared_ptr > forward(input->clone()); - forward_transform->apply(*forward); - - std::cout << "\n\tDoing adjoint transformation...\n"; - shared_ptr > adjoint(forward->clone()); - adjoint_transform->apply(*adjoint); - - // Might be slightly different due to interpolation differences - set_tolerance(1); - check_if_equal(*ground_truth, *forward, "4D forward transformation does not equal ground truth"); - - // Some information is lost by transforming part of the image out of the FOV. - // When we move it back, it's blank, so we can't do following comparison. - //check_if_equal(*input, *back_4D, "4D: fwrd->back should equal original input. doesn't."); - - // Only write if ITK is present (since you want 3d and 4d in same format, but it's hassle to - // check that the format supports both 3d and 4d writing. +TestBSplineTransformation::run_transformation() { + // Open image + std::cerr << "\nabout to read the image to transform...\n"; + shared_ptr> input(DiscretisedDensity<3, float>::read_from_file(_to_transform)); + if (is_null_ptr(input)) { + std::cerr << "\nError reading image to transform.\n"; + everything_ok = false; + return; + } + + // Open ground truth + std::cerr << "\nabout to read the ground truth image...\n"; + shared_ptr> ground_truth(DiscretisedDensity<3, float>::read_from_file(_ground_truth)); + if (is_null_ptr(ground_truth)) { + std::cerr << "\nError reading ground truth image.\n"; + everything_ok = false; + return; + } + + shared_ptr> fwrd_non_rigid( + new NonRigidObjectTransformationUsingBSplines<3, float>(_disp_4D, _bspline_order)); + + // Image processors + shared_ptr> forward_transform( + new Transform3DObjectImageProcessor(fwrd_non_rigid)); + shared_ptr> adjoint_transform( + new Transform3DObjectImageProcessor(*forward_transform)); + adjoint_transform->set_do_transpose(!forward_transform->get_do_transpose()); + + std::cout << "\n\tDoing forward transformation...\n"; + shared_ptr> forward(input->clone()); + forward_transform->apply(*forward); + + std::cout << "\n\tDoing adjoint transformation...\n"; + shared_ptr> adjoint(forward->clone()); + adjoint_transform->apply(*adjoint); + + // Might be slightly different due to interpolation differences + set_tolerance(1); + check_if_equal(*ground_truth, *forward, "4D forward transformation does not equal ground truth"); + + // Some information is lost by transforming part of the image out of the FOV. + // When we move it back, it's blank, so we can't do following comparison. + // check_if_equal(*input, *back_4D, "4D: fwrd->back should equal original input. doesn't."); + + // Only write if ITK is present (since you want 3d and 4d in same format, but it's hassle to + // check that the format supports both 3d and 4d writing. #ifdef HAVE_ITK - ITKOutputFileFormat output_file_format; - output_file_format.default_extension = ".nii"; - output_file_format.write_to_file("STIRtmp_forward", *forward); - output_file_format.write_to_file("STIRtmp_adjoint", *adjoint); + ITKOutputFileFormat output_file_format; + output_file_format.default_extension = ".nii"; + output_file_format.write_to_file("STIRtmp_forward", *forward); + output_file_format.write_to_file("STIRtmp_adjoint", *adjoint); #endif } void -TestBSplineTransformation:: -run_tests() -{ - try { - cerr << "Tests for TransformationTests\n"; - this->run_transformation(); - } - catch(...) { - everything_ok = false; - } +TestBSplineTransformation::run_tests() { + try { + cerr << "Tests for TransformationTests\n"; + this->run_transformation(); + } catch (...) { + everything_ok = false; + } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 4) { - cerr << "\n\tUsage: " << argv[0] << " <1> <2> <3>\n"; - cerr << "\t\t<1>: Image to transform\n"; - cerr << "\t\t<2>: Transformed result (ground truth)\n"; - cerr << "\t\t<3>: Multi-component displacement field image\n"; - return EXIT_FAILURE; - } +int +main(int argc, char** argv) { + if (argc != 4) { + cerr << "\n\tUsage: " << argv[0] << " <1> <2> <3>\n"; + cerr << "\t\t<1>: Image to transform\n"; + cerr << "\t\t<2>: Transformed result (ground truth)\n"; + cerr << "\t\t<3>: Multi-component displacement field image\n"; + return EXIT_FAILURE; + } - set_default_num_threads(); + set_default_num_threads(); - TestBSplineTransformation tests(argv[1], argv[2], argv[3]); + TestBSplineTransformation tests(argv[1], argv[2], argv[3]); - if (tests.is_everything_ok()) - tests.run_tests(); + if (tests.is_everything_ok()) + tests.run_tests(); - return tests.main_return_value(); + return tests.main_return_value(); } diff --git a/src/experimental/motion_utilities/add_planes_to_image.cxx b/src/experimental/motion_utilities/add_planes_to_image.cxx index c973ff457a..f1b3836002 100644 --- a/src/experimental/motion_utilities/add_planes_to_image.cxx +++ b/src/experimental/motion_utilities/add_planes_to_image.cxx @@ -17,38 +17,32 @@ using std::vector; USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) { -int -main(int argc, char * argv[]) -{ - - if (argc !=5) - { - cerr << " Usage: " << argv[0]<< " Output filename, input image, number of planes-min, number of planes-right " << endl; + if (argc != 5) { + cerr << " Usage: " << argv[0] << " Output filename, input image, number of planes-min, number of planes-right " << endl; return EXIT_FAILURE; } const string input_filename = argv[1]; - shared_ptr > input_image_sptr(read_from_file >(argv[2])); + shared_ptr> input_image_sptr(read_from_file>(argv[2])); const int number_of_planes_min = atoi(argv[3]); const int number_of_planes_max = atoi(argv[4]); - VoxelsOnCartesianGrid * input_image_sptr_vox= - dynamic_cast *> (input_image_sptr.get()); - - VoxelsOnCartesianGrid * output_image; - output_image =input_image_sptr_vox->get_empty_voxels_on_cartesian_grid(); - output_image->grow_z_range(output_image->get_min_z()-number_of_planes_min, output_image->get_max_z()+number_of_planes_max); + VoxelsOnCartesianGrid* input_image_sptr_vox = dynamic_cast*>(input_image_sptr.get()); - for (int k=input_image_sptr_vox->get_min_z();k<=input_image_sptr_vox->get_max_z();k++) - for (int j =input_image_sptr_vox->get_min_y();j<=input_image_sptr_vox->get_max_y();j++) - for (int i =input_image_sptr_vox->get_min_x();i<=input_image_sptr_vox->get_max_x();i++) - { - (*output_image)[k][j][i] = (*input_image_sptr_vox)[k][j][i]; + VoxelsOnCartesianGrid* output_image; + output_image = input_image_sptr_vox->get_empty_voxels_on_cartesian_grid(); + output_image->grow_z_range(output_image->get_min_z() - number_of_planes_min, output_image->get_max_z() + number_of_planes_max); + for (int k = input_image_sptr_vox->get_min_z(); k <= input_image_sptr_vox->get_max_z(); k++) + for (int j = input_image_sptr_vox->get_min_y(); j <= input_image_sptr_vox->get_max_y(); j++) + for (int i = input_image_sptr_vox->get_min_x(); i <= input_image_sptr_vox->get_max_x(); i++) { + (*output_image)[k][j][i] = (*input_image_sptr_vox)[k][j][i]; } - - write_basic_interfile(argv[1], *output_image); + + write_basic_interfile(argv[1], *output_image); return EXIT_SUCCESS; } diff --git a/src/experimental/motion_utilities/find_motion_corrected_norm_factors.cxx b/src/experimental/motion_utilities/find_motion_corrected_norm_factors.cxx index 917a040b2e..33068cbd11 100644 --- a/src/experimental/motion_utilities/find_motion_corrected_norm_factors.cxx +++ b/src/experimental/motion_utilities/find_motion_corrected_norm_factors.cxx @@ -33,22 +33,22 @@ #define USE_SegmentByView #ifdef USE_SegmentByView -#include "stir/SegmentByView.h" +# include "stir/SegmentByView.h" #else -#include "stir/Array.h" -#include "stir/IndexRange3D.h" +# include "stir/Array.h" +# include "stir/IndexRange3D.h" #endif #ifdef ROT_INT -#include "stir_experimental/motion/bin_interpolate.h" +# include "stir_experimental/motion/bin_interpolate.h" #endif // set elem_type to what you want to use for the sinogram elements -#if defined(USE_SegmentByView) - typedef float elem_type; +#if defined(USE_SegmentByView) +typedef float elem_type; # define OUTPUTNumericType NumericType::FLOAT #else - typedef short elem_type; +typedef short elem_type; # define OUTPUTNumericType NumericType::SHORT #endif @@ -61,39 +61,29 @@ typedef SegmentByView segment_type; // used for allocating segments. // TODO replace by ProjDataInMemory -typedef VectorWithOffset > all_segments_type; -static void -allocate_segments(all_segments_type& segments, - const int start_segment_index, - const int end_segment_index, - const ProjDataInfo* proj_data_info_ptr); +typedef VectorWithOffset> all_segments_type; +static void allocate_segments(all_segments_type& segments, const int start_segment_index, const int end_segment_index, + const ProjDataInfo* proj_data_info_ptr); /* last parameter only used if USE_SegmentByView first parameter only used when not USE_SegmentByView - */ -static void -save_and_delete_segments(shared_ptr& output, - all_segments_type& segments, - const int start_segment_index, - const int end_segment_index, - ProjData& proj_data); - -// In the next 3 functions, the 'output' parameter needs to be passed + */ +static void save_and_delete_segments(shared_ptr& output, all_segments_type& segments, const int start_segment_index, + const int end_segment_index, ProjData& proj_data); + +// In the next 3 functions, the 'output' parameter needs to be passed // because save_and_delete_segments needs it when we're not using SegmentByView -static -shared_ptr -construct_proj_data(shared_ptr& output, - const string& output_filename, - const shared_ptr& proj_data_info_ptr); +static shared_ptr construct_proj_data(shared_ptr& output, const string& output_filename, + const shared_ptr& proj_data_info_ptr); /*! \ingroup motion \brief Class to compute 'time-efficiency' factors for motino corrected projection data When list mode data is binned into 3d sinograms using motion correction, (or - when a 3d sinograms is motion corrected), the resulting sinogram is not + when a 3d sinograms is motion corrected), the resulting sinogram is not 'consistent' due to some LORs not being measured during the whole frame. This is discussed in some detail in
    - K. Thielemans, S. Mustafovic, L. Schnorr, - Image Reconstruction of Motion Corrected Sinograms, + K. Thielemans, S. Mustafovic, L. Schnorr, + Image Reconstruction of Motion Corrected Sinograms, poster at IEEE Medical Imaging Conf. 2003, available at http://www.hammersmithimanet.com/~kris/papers/. @@ -150,18 +140,15 @@ maximum number of time intervals per frame:=1 END:= \endverbatim */ -class FindMCNormFactors : public ParsingObject -{ +class FindMCNormFactors : public ParsingObject { public: - FindMCNormFactors(const char * const par_filename); + FindMCNormFactors(const char* const par_filename); TimeFrameDefinitions frame_defs; virtual void process_data(); - -protected: - +protected: //! parsing functions virtual void set_defaults(); virtual void initialise_keymap(); @@ -175,53 +162,49 @@ class FindMCNormFactors : public ParsingObject shared_ptr template_proj_data_info_ptr; shared_ptr proj_data_info_uncompressed_ptr; - const ProjDataInfoCylindricalNoArcCorr * proj_data_info_cyl_uncompressed_ptr; + const ProjDataInfoCylindricalNoArcCorr* proj_data_info_cyl_uncompressed_ptr; shared_ptr scanner_ptr; bool do_pre_normalisation; - bool do_time_frame; - private: int frame_num; shared_ptr ro3d_ptr; - shared_ptr _reference_abs_time_sptr; + shared_ptr _reference_abs_time_sptr; RigidObject3DTransformation _transformation_to_reference_position; shared_ptr normalisation_ptr; - + double time_interval; int min_num_time_intervals_per_frame; int max_num_time_intervals_per_frame; }; -void -FindMCNormFactors::set_defaults() -{ +void +FindMCNormFactors::set_defaults() { max_segment_num_to_process = -1; ro3d_ptr.reset(); _reference_abs_time_sptr.reset(); normalisation_ptr.reset(); do_pre_normalisation = true; - time_interval=1; + time_interval = 1; min_num_time_intervals_per_frame = 1; max_num_time_intervals_per_frame = 100; frame_num = -1; } -void -FindMCNormFactors::initialise_keymap() -{ +void +FindMCNormFactors::initialise_keymap() { parser.add_start_key("FindMCNormFactors Parameters"); parser.add_key("template_projdata", &template_proj_data_name); - parser.add_key("maximum absolute segment number to process", &max_segment_num_to_process); - parser.add_key("time frame_definition file",&frame_definition_filename); + parser.add_key("maximum absolute segment number to process", &max_segment_num_to_process); + parser.add_key("time frame_definition file", &frame_definition_filename); parser.add_key("time frame number", &frame_num); - parser.add_key("output filename prefix",&output_filename_prefix); - parser.add_parsing_key("Rigid Object 3D Motion Type", &ro3d_ptr); + parser.add_key("output filename prefix", &output_filename_prefix); + parser.add_parsing_key("Rigid Object 3D Motion Type", &ro3d_ptr); parser.add_parsing_key("time interval for reference position type", &_reference_abs_time_sptr); parser.add_parsing_key("Bin Normalisation type", &normalisation_ptr); parser.add_key("do pre normalisation", &do_pre_normalisation); @@ -231,121 +214,85 @@ FindMCNormFactors::initialise_keymap() parser.add_stop_key("END"); } -FindMCNormFactors:: -FindMCNormFactors(const char * const par_filename) -{ +FindMCNormFactors::FindMCNormFactors(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - { - if (parse(par_filename) == false) - error("Please correct parameter file"); - } - else + if (par_filename != 0) { + if (parse(par_filename) == false) + error("Please correct parameter file"); + } else ask_parameters(); - } bool -FindMCNormFactors:: -post_processing() -{ - - - if (output_filename_prefix.size()==0) - { - warning("You have to specify an output_filename_prefix\n"); - return true; - } +FindMCNormFactors::post_processing() { + if (output_filename_prefix.size() == 0) { + warning("You have to specify an output_filename_prefix\n"); + return true; + } - if (template_proj_data_name.size()==0) - { - warning("You have to specify template_projdata\n"); - return true; - } - shared_ptr template_proj_data_ptr = - ProjData::read_from_file(template_proj_data_name); + if (template_proj_data_name.size() == 0) { + warning("You have to specify template_projdata\n"); + return true; + } + shared_ptr template_proj_data_ptr = ProjData::read_from_file(template_proj_data_name); - template_proj_data_info_ptr = - template_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(); + template_proj_data_info_ptr = template_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(); // initialise segment_num related variables - if (max_segment_num_to_process==-1) - max_segment_num_to_process = - template_proj_data_info_ptr->get_max_segment_num(); - else - { - max_segment_num_to_process = - min(max_segment_num_to_process, - template_proj_data_info_ptr->get_max_segment_num()); - template_proj_data_info_ptr-> - reduce_segment_range(-max_segment_num_to_process, - max_segment_num_to_process); - } - + if (max_segment_num_to_process == -1) + max_segment_num_to_process = template_proj_data_info_ptr->get_max_segment_num(); + else { + max_segment_num_to_process = min(max_segment_num_to_process, template_proj_data_info_ptr->get_max_segment_num()); + template_proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); + } - scanner_ptr. - reset(new Scanner(*template_proj_data_info_ptr->get_scanner_ptr())); + scanner_ptr.reset(new Scanner(*template_proj_data_info_ptr->get_scanner_ptr())); // TODO this won't work for the HiDAC or so - proj_data_info_uncompressed_ptr. - reset(ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - 1, scanner_ptr->get_num_rings()-1, - scanner_ptr->get_num_detectors_per_ring()/2, - scanner_ptr->get_default_num_arccorrected_bins(), - false)); + proj_data_info_uncompressed_ptr.reset(ProjDataInfo::ProjDataInfoCTI(scanner_ptr, 1, scanner_ptr->get_num_rings() - 1, + scanner_ptr->get_num_detectors_per_ring() / 2, + scanner_ptr->get_default_num_arccorrected_bins(), false)); proj_data_info_cyl_uncompressed_ptr = - dynamic_cast - (proj_data_info_uncompressed_ptr.get()); - + dynamic_cast(proj_data_info_uncompressed_ptr.get()); - if (!do_pre_normalisation && is_null_ptr(normalisation_ptr)) - { - //normalisation_ptr = new TrivialBinNormalisation; - warning("Invalid normalisation object\n"); - return true; - } - if (!do_pre_normalisation && - normalisation_ptr->set_up(proj_data_info_uncompressed_ptr) - != Succeeded::yes) - { - warning("set-up of normalisation failed\n"); - return true; - } + if (!do_pre_normalisation && is_null_ptr(normalisation_ptr)) { + // normalisation_ptr = new TrivialBinNormalisation; + warning("Invalid normalisation object\n"); + return true; + } + if (!do_pre_normalisation && normalisation_ptr->set_up(proj_data_info_uncompressed_ptr) != Succeeded::yes) { + warning("set-up of normalisation failed\n"); + return true; + } // handle time frame definitions etc do_time_frame = true; - if (do_time_frame && frame_definition_filename.size()==0) - { - warning("Have to specify either 'time frame_definition_filename' or 'num_events_to_store'\n"); - return true; - } + if (do_time_frame && frame_definition_filename.size() == 0) { + warning("Have to specify either 'time frame_definition_filename' or 'num_events_to_store'\n"); + return true; + } - if (frame_definition_filename.size()!=0) + if (frame_definition_filename.size() != 0) frame_defs = TimeFrameDefinitions(frame_definition_filename); - else - { - // make a single frame starting from 0. End value will be ignored. - vector > frame_times(1, pair(0,1)); - frame_defs = TimeFrameDefinitions(frame_times); - } - if (frame_num != -1 && - (frame_num<1 || unsigned(frame_num)> frame_defs.get_num_frames())) - { - warning("'time frame num (%u) should be either -1 or between 1 and the number of frames (%u)", - frame_num, frame_defs.get_num_frames()); - return true; - } - - if (is_null_ptr(ro3d_ptr)) - { - warning("Invalid Rigid Object 3D Motion object\n"); + else { + // make a single frame starting from 0. End value will be ignored. + vector> frame_times(1, pair(0, 1)); + frame_defs = TimeFrameDefinitions(frame_times); + } + if (frame_num != -1 && (frame_num < 1 || unsigned(frame_num) > frame_defs.get_num_frames())) { + warning("'time frame num (%u) should be either -1 or between 1 and the number of frames (%u)", frame_num, + frame_defs.get_num_frames()); return true; } + if (is_null_ptr(ro3d_ptr)) { + warning("Invalid Rigid Object 3D Motion object\n"); + return true; + } #if 0 if (!ro3d_ptr->is_synchronised()) @@ -356,25 +303,20 @@ post_processing() #endif // set transformation_to_reference_position - if (is_null_ptr(_reference_abs_time_sptr)) - { - warning("time interval for reference position is not set"); - return true; - } - { - RigidObject3DTransformation av_motion = - ro3d_ptr->compute_average_motion_in_scanner_coords(*_reference_abs_time_sptr); - _transformation_to_reference_position =av_motion.inverse(); - } + if (is_null_ptr(_reference_abs_time_sptr)) { + warning("time interval for reference position is not set"); + return true; + } + { + RigidObject3DTransformation av_motion = ro3d_ptr->compute_average_motion_in_scanner_coords(*_reference_abs_time_sptr); + _transformation_to_reference_position = av_motion.inverse(); + } return false; } - - -void -FindMCNormFactors::process_data() -{ +void +FindMCNormFactors::process_data() { #ifdef NEW_ROT cerr << "Using NEW_ROT\n"; #else @@ -384,291 +326,203 @@ FindMCNormFactors::process_data() warning("with linear interpolation"); #endif - all_segments_type - segments (template_proj_data_info_ptr->get_min_segment_num(), - template_proj_data_info_ptr->get_max_segment_num()); + all_segments_type segments(template_proj_data_info_ptr->get_min_segment_num(), + template_proj_data_info_ptr->get_max_segment_num()); + + const unsigned min_frame_num = frame_num == -1 ? 1 : unsigned(frame_num); + const unsigned max_frame_num = frame_num == -1 ? frame_defs.get_num_frames() : unsigned(frame_num); + + for (unsigned int current_frame_num = min_frame_num; current_frame_num <= max_frame_num; ++current_frame_num) { + const double start_time = frame_defs.get_start_time(current_frame_num); + const double end_time = frame_defs.get_end_time(current_frame_num); + const double frame_duration = end_time - start_time; + const int num_time_intervals_this_frame = + max(min(round(frame_duration / time_interval), max_num_time_intervals_per_frame), min_num_time_intervals_per_frame); + const double time_interval_this_frame = frame_duration / num_time_intervals_this_frame; - const unsigned min_frame_num = - frame_num==-1 ? 1 : unsigned(frame_num); - const unsigned max_frame_num = - frame_num==-1 ? frame_defs.get_num_frames() : unsigned(frame_num); + cerr << "\nDoing frame " << current_frame_num << ": from " << start_time << " to " << end_time << " with " + << num_time_intervals_this_frame << " time intervals of length " << time_interval_this_frame << endl; + + //*********** open output file + shared_ptr output; + shared_ptr out_proj_data_ptr; - for (unsigned int current_frame_num = min_frame_num; - current_frame_num<= max_frame_num; - ++current_frame_num) { - const double start_time = frame_defs.get_start_time(current_frame_num); - const double end_time = frame_defs.get_end_time(current_frame_num); - const double frame_duration = end_time - start_time; - const int num_time_intervals_this_frame = - max(min(round(frame_duration/time_interval), - max_num_time_intervals_per_frame), - min_num_time_intervals_per_frame); - const double time_interval_this_frame = - frame_duration / num_time_intervals_this_frame; - - cerr << "\nDoing frame " << current_frame_num - << ": from " << start_time << " to " << end_time - << " with " << num_time_intervals_this_frame - << " time intervals of length " - << time_interval_this_frame - << endl; - - - //*********** open output file - shared_ptr output; - shared_ptr out_proj_data_ptr; - - { - char rest[50]; - sprintf(rest, "_f%ug1d0b0", current_frame_num); - const string output_filename = output_filename_prefix + rest; - - out_proj_data_ptr = - construct_proj_data(output, output_filename, template_proj_data_info_ptr); - } - - allocate_segments(segments, - template_proj_data_info_ptr->get_min_segment_num(), - template_proj_data_info_ptr->get_max_segment_num(), - template_proj_data_info_ptr.get()); - - const int start_segment_index = template_proj_data_info_ptr->get_min_segment_num(); - const int end_segment_index = template_proj_data_info_ptr->get_max_segment_num(); - - - const ProjDataInfoCylindricalNoArcCorr * const out_proj_data_info_ptr = - dynamic_cast - (out_proj_data_ptr->get_proj_data_info_sptr()); - if (out_proj_data_info_ptr== NULL) - { - error("works only on proj_data_info of " - "type ProjDataInfoCylindricalNoArcCorr\n"); - } - - int current_num_time_intervals=0; - cerr << "Doing time intervals: "; - for (double current_time = start_time; - current_time<=end_time; - current_time+=time_interval_this_frame) - { - if (++current_num_time_intervals > num_time_intervals_this_frame) - break; - cerr << '(' << current_time << '-' << current_time+time_interval_this_frame << ") "; - - if (current_time+time_interval_this_frame > end_time + time_interval_this_frame*.01) - error("\ntime interval goes beyond end of frame. Check code!\n"); - const RigidObject3DTransformation ro3dtrans = - compose(_transformation_to_reference_position, - ro3d_ptr-> - compute_average_motion_in_scanner_coords_rel_time(current_time, - current_time+time_interval_this_frame)); - - for (int in_segment_num = proj_data_info_uncompressed_ptr->get_min_segment_num(); - in_segment_num <= proj_data_info_uncompressed_ptr->get_max_segment_num(); - ++in_segment_num) - { - - - for (int in_ax_pos_num = proj_data_info_uncompressed_ptr->get_min_axial_pos_num(in_segment_num); - in_ax_pos_num <= proj_data_info_uncompressed_ptr->get_max_axial_pos_num(in_segment_num); - ++in_ax_pos_num ) - { - - for (int in_view_num=proj_data_info_uncompressed_ptr->get_min_view_num(); - in_view_num <= proj_data_info_uncompressed_ptr->get_max_view_num(); - ++in_view_num) - { - - for (int in_tangential_pos_num=proj_data_info_uncompressed_ptr->get_min_tangential_pos_num(); - in_tangential_pos_num <= proj_data_info_uncompressed_ptr->get_max_tangential_pos_num(); - ++in_tangential_pos_num) - { - const Bin original_bin(in_segment_num,in_view_num,in_ax_pos_num, in_tangential_pos_num, 1); + char rest[50]; + sprintf(rest, "_f%ug1d0b0", current_frame_num); + const string output_filename = output_filename_prefix + rest; + + out_proj_data_ptr = construct_proj_data(output, output_filename, template_proj_data_info_ptr); + } + + allocate_segments(segments, template_proj_data_info_ptr->get_min_segment_num(), + template_proj_data_info_ptr->get_max_segment_num(), template_proj_data_info_ptr.get()); + + const int start_segment_index = template_proj_data_info_ptr->get_min_segment_num(); + const int end_segment_index = template_proj_data_info_ptr->get_max_segment_num(); + + const ProjDataInfoCylindricalNoArcCorr* const out_proj_data_info_ptr = + dynamic_cast(out_proj_data_ptr->get_proj_data_info_sptr()); + if (out_proj_data_info_ptr == NULL) { + error("works only on proj_data_info of " + "type ProjDataInfoCylindricalNoArcCorr\n"); + } + + int current_num_time_intervals = 0; + cerr << "Doing time intervals: "; + for (double current_time = start_time; current_time <= end_time; current_time += time_interval_this_frame) { + if (++current_num_time_intervals > num_time_intervals_this_frame) + break; + cerr << '(' << current_time << '-' << current_time + time_interval_this_frame << ") "; + + if (current_time + time_interval_this_frame > end_time + time_interval_this_frame * .01) + error("\ntime interval goes beyond end of frame. Check code!\n"); + const RigidObject3DTransformation ro3dtrans = compose( + _transformation_to_reference_position, + ro3d_ptr->compute_average_motion_in_scanner_coords_rel_time(current_time, current_time + time_interval_this_frame)); + + for (int in_segment_num = proj_data_info_uncompressed_ptr->get_min_segment_num(); + in_segment_num <= proj_data_info_uncompressed_ptr->get_max_segment_num(); ++in_segment_num) { + + for (int in_ax_pos_num = proj_data_info_uncompressed_ptr->get_min_axial_pos_num(in_segment_num); + in_ax_pos_num <= proj_data_info_uncompressed_ptr->get_max_axial_pos_num(in_segment_num); ++in_ax_pos_num) { + + for (int in_view_num = proj_data_info_uncompressed_ptr->get_min_view_num(); + in_view_num <= proj_data_info_uncompressed_ptr->get_max_view_num(); ++in_view_num) { + + for (int in_tangential_pos_num = proj_data_info_uncompressed_ptr->get_min_tangential_pos_num(); + in_tangential_pos_num <= proj_data_info_uncompressed_ptr->get_max_tangential_pos_num(); + ++in_tangential_pos_num) { + const Bin original_bin(in_segment_num, in_view_num, in_ax_pos_num, in_tangential_pos_num, 1); #ifndef ROT_INT - // find new bin position - Bin bin = original_bin; - - ro3dtrans.transform_bin(bin, - *out_proj_data_info_ptr, - *proj_data_info_cyl_uncompressed_ptr); - if (bin.get_bin_value()>0) - { - // now check if we have its segment in memory - if (bin.segment_num() >= start_segment_index && bin.segment_num()<=end_segment_index) - { - // TODO remove scale factor - // it's there to compensate what we have in LmToProjDataWithMC - if (do_pre_normalisation) - { - (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += - 1.F/ - (out_proj_data_info_ptr-> - get_num_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), - bin.axial_pos_num())* - out_proj_data_info_ptr->get_view_mashing_factor()); - } - else - { - (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += - normalisation_ptr-> - get_bin_efficiency(original_bin,start_time,end_time); - - } - } - } + // find new bin position + Bin bin = original_bin; + + ro3dtrans.transform_bin(bin, *out_proj_data_info_ptr, *proj_data_info_cyl_uncompressed_ptr); + if (bin.get_bin_value() > 0) { + // now check if we have its segment in memory + if (bin.segment_num() >= start_segment_index && bin.segment_num() <= end_segment_index) { + // TODO remove scale factor + // it's there to compensate what we have in LmToProjDataWithMC + if (do_pre_normalisation) { + (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += + 1.F / (out_proj_data_info_ptr->get_num_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), + bin.axial_pos_num()) * + out_proj_data_info_ptr->get_view_mashing_factor()); + } else { + (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += + normalisation_ptr->get_bin_efficiency(original_bin, start_time, end_time); + } + } + } #else - const float value = - do_pre_normalisation - ? 1 - : normalisation_ptr->get_bin_efficiency(original_bin,start_time,end_time); - LORInAxialAndNoArcCorrSinogramCoordinates transformed_lor; - if (get_transformed_LOR(transformed_lor, - ro3dtrans, - original_bin, - *proj_data_info_uncompressed_ptr) - == Succeeded::yes) - bin_interpolate(segments, transformed_lor, - *out_proj_data_info_ptr, - *proj_data_info_uncompressed_ptr, value); + const float value = + do_pre_normalisation ? 1 : normalisation_ptr->get_bin_efficiency(original_bin, start_time, end_time); + LORInAxialAndNoArcCorrSinogramCoordinates transformed_lor; + if (get_transformed_LOR(transformed_lor, ro3dtrans, original_bin, *proj_data_info_uncompressed_ptr) == + Succeeded::yes) + bin_interpolate(segments, transformed_lor, *out_proj_data_info_ptr, *proj_data_info_uncompressed_ptr, value); #endif - } - } - } - } - } - // decrease our counter of the number of time intervals to set it to - // the number we actually had - --current_num_time_intervals; - if (current_num_time_intervals != num_time_intervals_this_frame) - warning("\nUnexpected number of time intervals %d, should be %d", - current_num_time_intervals, num_time_intervals_this_frame); - for (int segment_num=start_segment_index; segment_num<=end_segment_index; ++segment_num) - { - if (current_num_time_intervals>0) - (*(segments[segment_num])) /= current_num_time_intervals; - // add constant to avoid division by 0 later. - (*(segments[segment_num])) +=.00001; - } - save_and_delete_segments(output, segments, - start_segment_index, end_segment_index, - *out_proj_data_ptr); - + } + } + } + } + } + // decrease our counter of the number of time intervals to set it to + // the number we actually had + --current_num_time_intervals; + if (current_num_time_intervals != num_time_intervals_this_frame) + warning("\nUnexpected number of time intervals %d, should be %d", current_num_time_intervals, + num_time_intervals_this_frame); + for (int segment_num = start_segment_index; segment_num <= end_segment_index; ++segment_num) { + if (current_num_time_intervals > 0) + (*(segments[segment_num])) /= current_num_time_intervals; + // add constant to avoid division by 0 later. + (*(segments[segment_num])) += .00001; } - + save_and_delete_segments(output, segments, start_segment_index, end_segment_index, *out_proj_data_ptr); + } } - - /************************* Local helper routines *************************/ +void +allocate_segments(all_segments_type& segments, const int start_segment_index, const int end_segment_index, + const ProjDataInfo* proj_data_info_ptr) { -void -allocate_segments( all_segments_type& segments, - const int start_segment_index, - const int end_segment_index, - const ProjDataInfo* proj_data_info_ptr) -{ - - for (int seg=start_segment_index ; seg<=end_segment_index; seg++) - { + for (int seg = start_segment_index; seg <= end_segment_index; seg++) { #ifdef USE_SegmentByView - segments[seg]. - reset(new SegmentByView( - proj_data_info_ptr->get_empty_segment_by_view (seg))); + segments[seg].reset(new SegmentByView(proj_data_info_ptr->get_empty_segment_by_view(seg))); #else - segments[seg] = - new Array<3,elem_type>(IndexRange3D(0, proj_data_info_ptr->get_num_views()-1, - 0, proj_data_info_ptr->get_num_axial_poss(seg)-1, - -(proj_data_info_ptr->get_num_tangential_poss()/2), - proj_data_info_ptr->get_num_tangential_poss()-(proj_data_info_ptr->get_num_tangential_poss()/2)-1)); + segments[seg] = new Array<3, elem_type>( + IndexRange3D(0, proj_data_info_ptr->get_num_views() - 1, 0, proj_data_info_ptr->get_num_axial_poss(seg) - 1, + -(proj_data_info_ptr->get_num_tangential_poss() / 2), + proj_data_info_ptr->get_num_tangential_poss() - (proj_data_info_ptr->get_num_tangential_poss() / 2) - 1)); #endif } } -void -save_and_delete_segments(shared_ptr& output, - all_segments_type& segments, - const int start_segment_index, - const int end_segment_index, - ProjData& proj_data) -{ - - for (int seg=start_segment_index; seg<=end_segment_index; seg++) - { +void +save_and_delete_segments(shared_ptr& output, all_segments_type& segments, const int start_segment_index, + const int end_segment_index, ProjData& proj_data) { + + for (int seg = start_segment_index; seg <= end_segment_index; seg++) { { #ifdef USE_SegmentByView proj_data.set_segment(*segments[seg]); #else write_data(*output, (*segments[seg])); #endif - //delete segments[seg]; + // delete segments[seg]; segments[seg].reset(); // deallocate for shared_ptr } - } } - - -static -shared_ptr -construct_proj_data(shared_ptr& output, - const string& output_filename, - const shared_ptr& proj_data_info_ptr) -{ +static shared_ptr +construct_proj_data(shared_ptr& output, const string& output_filename, + const shared_ptr& proj_data_info_ptr) { vector segment_sequence_in_stream(proj_data_info_ptr->get_num_segments()); - { + { #ifndef STIR_NO_NAMESPACES std:: // explcitly needed by VC #endif - vector::iterator current_segment_iter = - segment_sequence_in_stream.begin(); - for (int segment_num=proj_data_info_ptr->get_min_segment_num(); - segment_num<=proj_data_info_ptr->get_max_segment_num(); + vector::iterator current_segment_iter = segment_sequence_in_stream.begin(); + for (int segment_num = proj_data_info_ptr->get_min_segment_num(); segment_num <= proj_data_info_ptr->get_max_segment_num(); ++segment_num) *current_segment_iter++ = segment_num; } #ifdef USE_SegmentByView // don't need output stream in this case - shared_ptr retvalue - (new ProjDataInterfile(proj_data_info_ptr, output_filename, ios::out, - segment_sequence_in_stream, - ProjDataFromStream::Segment_View_AxialPos_TangPos, - OUTPUTNumericType)); + shared_ptr retvalue(new ProjDataInterfile(proj_data_info_ptr, output_filename, ios::out, segment_sequence_in_stream, + ProjDataFromStream::Segment_View_AxialPos_TangPos, OUTPUTNumericType)); return retvalue; #else // this code would work for USE_SegmentByView as well, but the above is far simpler... - output = new fstream (output_filename.c_str(), ios::out|ios::binary); + output = new fstream(output_filename.c_str(), ios::out | ios::binary); if (!*output) - error("Error opening output file %s\n",output_filename.c_str()); - shared_ptr proj_data_ptr = - new ProjDataFromStream(proj_data_info_ptr, output, - /*offset=*/0, - segment_sequence_in_stream, - ProjDataFromStream::Segment_View_AxialPos_TangPos, - OUTPUTNumericType); + error("Error opening output file %s\n", output_filename.c_str()); + shared_ptr proj_data_ptr = new ProjDataFromStream( + proj_data_info_ptr, output, + /*offset=*/0, segment_sequence_in_stream, ProjDataFromStream::Segment_View_AxialPos_TangPos, OUTPUTNumericType); write_basic_interfile_PDFS_header(output_filename, *proj_data_ptr); - return proj_data_ptr; + return proj_data_ptr; #endif } - END_NAMESPACE_STIR - - USING_NAMESPACE_STIR -int main(int argc, char * argv[]) -{ - - if (argc!=1 && argc!=2) { +int +main(int argc, char* argv[]) { + + if (argc != 1 && argc != 2) { cerr << "Usage: " << argv[0] << " [par_file]\n"; exit(EXIT_FAILURE); } - FindMCNormFactors application(argc==2 ? argv[1] : 0); + FindMCNormFactors application(argc == 2 ? argv[1] : 0); application.process_data(); return EXIT_SUCCESS; diff --git a/src/experimental/motion_utilities/list_deformation_vectors.cxx b/src/experimental/motion_utilities/list_deformation_vectors.cxx index d73b9f1beb..b6458b863a 100644 --- a/src/experimental/motion_utilities/list_deformation_vectors.cxx +++ b/src/experimental/motion_utilities/list_deformation_vectors.cxx @@ -10,7 +10,7 @@ \brief Utility to move an image according to average motion in the frame. \author Kris Thielemans - + \par Usage \verbatim move_image \\ @@ -19,7 +19,7 @@ [par_file] \endverbatim See class documentation for stir::MoveImage for more info, including the format - of the par_file. + of the par_file. Command line switches override any values in the par_file. @@ -38,9 +38,9 @@ START_NAMESPACE_STIR /*! \ingroup motion \brief A class for moving an image according to average motion in the frame. - \see transform_3d_object(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const RigidObject3DTransformation& rigid_object_transformation) + \see transform_3d_object(DiscretisedDensity<3,float>& out_density, + const DiscretisedDensity<3,float>& in_density, + const RigidObject3DTransformation& rigid_object_transformation) \par Example par file \verbatim @@ -48,17 +48,15 @@ START_NAMESPACE_STIR END := \endverbatim -*/ -class MyApp : public ParsingObject -{ +*/ +class MyApp : public ParsingObject { typedef ParsingObject base_type; + public: - MyApp(const char * const par_filename); + MyApp(const char* const par_filename); virtual Succeeded process_data(); protected: - - //! parsing functions virtual void set_defaults(); virtual void initialise_keymap(); @@ -66,118 +64,92 @@ class MyApp : public ParsingObject //! parsing variables // string input_filename; - //string output_filename_prefix; + // string output_filename_prefix; private: - shared_ptr > transformation_sptr; + shared_ptr> transformation_sptr; }; -void -MyApp::set_defaults() -{ -} +void +MyApp::set_defaults() {} - -void -MyApp::initialise_keymap() -{ +void +MyApp::initialise_keymap() { this->parser.add_start_key("Object Transformation Parameters"); - this->parser.add_parsing_key("transformation type",&this->transformation_sptr); + this->parser.add_parsing_key("transformation type", &this->transformation_sptr); this->parser.add_stop_key("END"); } -MyApp:: -MyApp(const char * const par_filename) -{ +MyApp::MyApp(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - { - if (parse(par_filename)==false) - exit(EXIT_FAILURE); - } - else + if (par_filename != 0) { + if (parse(par_filename) == false) + exit(EXIT_FAILURE); + } else ask_parameters(); - } bool -MyApp:: -post_processing() -{ +MyApp::post_processing() { if (base_type::post_processing() == true) return true; - if (is_null_ptr(this->transformation_sptr)) - { - warning("You have to specify a transformation"); - return true; - } + if (is_null_ptr(this->transformation_sptr)) { + warning("You have to specify a transformation"); + return true; + } return false; } - -Succeeded -MyApp:: -process_data() -{ - BasicCoordinate<3,float> in_coord; - while(true) - { - std::cout << "\nNext:\n"; - std::cin >> in_coord; - std::cout << this->transformation_sptr->transform_point(in_coord) - << this->transformation_sptr->transform_point(in_coord) - in_coord - << " Jacobian " - << this->transformation_sptr->jacobian(in_coord) - << std::endl; - } +Succeeded +MyApp::process_data() { + BasicCoordinate<3, float> in_coord; + while (true) { + std::cout << "\nNext:\n"; + std::cin >> in_coord; + std::cout << this->transformation_sptr->transform_point(in_coord) + << this->transformation_sptr->transform_point(in_coord) - in_coord << " Jacobian " + << this->transformation_sptr->jacobian(in_coord) << std::endl; + } return Succeeded::yes; } - END_NAMESPACE_STIR - - USING_NAMESPACE_STIR -int main(int argc, char * argv[]) -{ - bool move_to_reference=true; - bool set_move_to_reference=false; - bool set_frame_num_to_process=false; - int frame_num_to_process=-1; - while (argc>=2 && argv[1][1]=='-') - { - if (strcmp(argv[1],"--move-to-reference")==0) - { - set_move_to_reference=true; - move_to_reference=atoi(argv[2]); - argc-=2; argv+=2; - } - else if (strcmp(argv[1], "--frame_num_to_process")==0) - { - set_frame_num_to_process=true; - frame_num_to_process=atoi(argv[2]); - argc-=2; argv+=2; - } - else - { - warning("Wrong option\n"); - exit(EXIT_FAILURE); - } +int +main(int argc, char* argv[]) { + bool move_to_reference = true; + bool set_move_to_reference = false; + bool set_frame_num_to_process = false; + int frame_num_to_process = -1; + while (argc >= 2 && argv[1][1] == '-') { + if (strcmp(argv[1], "--move-to-reference") == 0) { + set_move_to_reference = true; + move_to_reference = atoi(argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--frame_num_to_process") == 0) { + set_frame_num_to_process = true; + frame_num_to_process = atoi(argv[2]); + argc -= 2; + argv += 2; + } else { + warning("Wrong option\n"); + exit(EXIT_FAILURE); } + } - if (argc!=1 && argc!=2) { + if (argc != 1 && argc != 2) { cerr << "Usage: " << argv[0] << " \\\n" - << "\t[--move-to-reference 0|1] \\\n" - << "\t[--frame_num_to_process number]\\\n" - << "\t[par_file]\n"; + << "\t[--move-to-reference 0|1] \\\n" + << "\t[--frame_num_to_process number]\\\n" + << "\t[par_file]\n"; exit(EXIT_FAILURE); } - MyApp application(argc==2 ? argv[1] : 0); - Succeeded success = - application.process_data(); + MyApp application(argc == 2 ? argv[1] : 0); + Succeeded success = application.process_data(); return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/motion_utilities/list_polaris_info.cxx b/src/experimental/motion_utilities/list_polaris_info.cxx index 0cbd1a76e4..3b9f9293b7 100644 --- a/src/experimental/motion_utilities/list_polaris_info.cxx +++ b/src/experimental/motion_utilities/list_polaris_info.cxx @@ -21,59 +21,54 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit(const char * const prog_name) -{ - std::cerr << "Usage:\n" << prog_name << "\\\n" - << "\t[--mask-for-tags value ] \\\n" - << "\tpolarisfile.mt \n"; +static void +print_usage_and_exit(const char* const prog_name) { + std::cerr << "Usage:\n" + << prog_name << "\\\n" + << "\t[--mask-for-tags value ] \\\n" + << "\tpolarisfile.mt \n"; exit(EXIT_FAILURE); } -int main(int argc, char * argv[]) -{ - const char * const prog_name = argv[0]; +int +main(int argc, char* argv[]) { + const char* const prog_name = argv[0]; unsigned int mask_for_tags = 0xfffffff; - while (argc>2 && argv[1][0] == '-') - { - if (strcmp(argv[1], "--mask-for-tags")==0) - { - mask_for_tags = atoi(argv[2]); - argc-=2; argv+=2; - } - else - { - print_usage_and_exit(prog_name); - } + while (argc > 2 && argv[1][0] == '-') { + if (strcmp(argv[1], "--mask-for-tags") == 0) { + mask_for_tags = atoi(argv[2]); + argc -= 2; + argv += 2; + } else { + print_usage_and_exit(prog_name); } + } - - if (argc!=2) { + if (argc != 2) { print_usage_and_exit(prog_name); } - const char * const polaris_filename = argv[1]; + const char* const polaris_filename = argv[1]; Polaris_MT_File polaris_data(polaris_filename); std::time_t start_time_secs = polaris_data.get_start_time_in_secs_since_1970(); - char * start_time_str = ctime(&start_time_secs); // use internal pointer provided by ctime (string is ended by newline) + char* start_time_str = ctime(&start_time_secs); // use internal pointer provided by ctime (string is ended by newline) - std::cout << "\nInformation for " << polaris_filename - << "\nPolaris tracking start at " << start_time_secs << " secs since 1970 UTC, " - << "\n which is " << start_time_str - << " in your local time zone" - << "\nNumber of samples: " << polaris_data.num_samples() - << "\nNumber of tags sent to scanner (recorded in the tracking file): " << polaris_data.num_tags(); + std::cout << "\nInformation for " << polaris_filename << "\nPolaris tracking start at " << start_time_secs + << " secs since 1970 UTC, " + << "\n which is " << start_time_str << " in your local time zone" + << "\nNumber of samples: " << polaris_data.num_samples() + << "\nNumber of tags sent to scanner (recorded in the tracking file): " << polaris_data.num_tags(); - if (polaris_data.num_samples()>1) - { - std::cout << "\nFirst sample (in \"polaris\" secs) at: " << polaris_data.begin()->sample_time - << "\nLast sample (in \"polaris\" secs) at : " << (polaris_data.end()-1)->sample_time - << "\nInterval between first and last sample (in secs) : " << (polaris_data.end()-1)->sample_time - polaris_data.begin()->sample_time; - } + if (polaris_data.num_samples() > 1) { + std::cout << "\nFirst sample (in \"polaris\" secs) at: " << polaris_data.begin()->sample_time + << "\nLast sample (in \"polaris\" secs) at : " << (polaris_data.end() - 1)->sample_time + << "\nInterval between first and last sample (in secs) : " + << (polaris_data.end() - 1)->sample_time - polaris_data.begin()->sample_time; + } std::cout << std::endl; - return EXIT_SUCCESS; } diff --git a/src/experimental/motion_utilities/match_tracker_and_scanner.cxx b/src/experimental/motion_utilities/match_tracker_and_scanner.cxx index f806df621a..bd9f29df9f 100644 --- a/src/experimental/motion_utilities/match_tracker_and_scanner.cxx +++ b/src/experimental/motion_utilities/match_tracker_and_scanner.cxx @@ -7,7 +7,7 @@ /*! \file \ingroup motion_utilities - \brief A utility for finding the coordinate transformation between tracker and scanner + \brief A utility for finding the coordinate transformation between tracker and scanner coordinate systems. \par Usage @@ -19,22 +19,20 @@ \author Kris Thielemans - + */ #include "stir/Succeeded.h" #include "stir_experimental/motion/MatchTrackerAndScanner.h" -int main(int argc, char ** argv) -{ +int +main(int argc, char** argv) { - if (argc!=1 && argc!=2) { + if (argc != 1 && argc != 2) { cerr << "Usage: " << argv[0] << " \\\n" - << "\t[par_file]\n"; + << "\t[par_file]\n"; exit(EXIT_FAILURE); } - stir::MatchTrackerAndScanner application(argc==2 ? argv[1] : 0); + stir::MatchTrackerAndScanner application(argc == 2 ? argv[1] : 0); - return - application.run() == stir::Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; + return application.run() == stir::Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/motion_utilities/move_image.cxx b/src/experimental/motion_utilities/move_image.cxx index 7005e436f2..e5aba760f4 100644 --- a/src/experimental/motion_utilities/move_image.cxx +++ b/src/experimental/motion_utilities/move_image.cxx @@ -10,7 +10,7 @@ \brief Utility to move an image according to average motion in the frame. \author Kris Thielemans - + \par Usage \verbatim move_image \\ @@ -19,7 +19,7 @@ [par_file] \endverbatim See class documentation for stir::MoveImage for more info, including the format - of the par_file. + of the par_file. Command line switches override any values in the par_file. @@ -40,9 +40,9 @@ START_NAMESPACE_STIR /*! \ingroup motion \brief A class for moving an image according to average motion in the frame. - \see transform_3d_object(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const RigidObject3DTransformation& rigid_object_transformation) + \see transform_3d_object(DiscretisedDensity<3,float>& out_density, + const DiscretisedDensity<3,float>& in_density, + const RigidObject3DTransformation& rigid_object_transformation) \par Example par file \see TimeFrameMotion for other parameters @@ -61,20 +61,17 @@ START_NAMESPACE_STIR END := \endverbatim -*/ -class MoveImage : public TimeFrameMotion -{ +*/ +class MoveImage : public TimeFrameMotion { private: typedef TimeFrameMotion base_type; -public: - MoveImage(const char * const par_filename); +public: + MoveImage(const char* const par_filename); virtual Succeeded process_data(); protected: - - //! parsing functions virtual void set_defaults(); virtual void initialise_keymap(); @@ -83,165 +80,127 @@ class MoveImage : public TimeFrameMotion //! parsing variables string input_filename; string output_filename_prefix; + private: - shared_ptr > in_density_sptr; - shared_ptr > > - output_file_format_sptr; + shared_ptr> in_density_sptr; + shared_ptr>> output_file_format_sptr; }; -void -MoveImage::set_defaults() -{ +void +MoveImage::set_defaults() { base_type::set_defaults(); - output_file_format_sptr = - OutputFileFormat >::default_sptr(); + output_file_format_sptr = OutputFileFormat>::default_sptr(); } -void -MoveImage::initialise_keymap() -{ +void +MoveImage::initialise_keymap() { parser.add_start_key("MoveImage Parameters"); - parser.add_key("input file",&input_filename); - parser.add_key("output filename prefix",&output_filename_prefix); - parser.add_parsing_key("Output file format",&output_file_format_sptr); + parser.add_key("input file", &input_filename); + parser.add_key("output filename prefix", &output_filename_prefix); + parser.add_parsing_key("Output file format", &output_file_format_sptr); base_type::initialise_keymap(); parser.add_stop_key("END"); } -MoveImage:: -MoveImage(const char * const par_filename) -{ +MoveImage::MoveImage(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - { - if (parse(par_filename)==false) - exit(EXIT_FAILURE); - } - else + if (par_filename != 0) { + if (parse(par_filename) == false) + exit(EXIT_FAILURE); + } else ask_parameters(); - } bool -MoveImage:: -post_processing() -{ +MoveImage::post_processing() { if (base_type::post_processing() == true) return true; - if (output_filename_prefix.size()==0) - { - warning("You have to specify an output_filename_prefix"); - return true; - } - in_density_sptr = - read_from_file >(input_filename); + if (output_filename_prefix.size() == 0) { + warning("You have to specify an output_filename_prefix"); + return true; + } + in_density_sptr = read_from_file>(input_filename); return false; } +Succeeded +MoveImage::process_data() { + shared_ptr> out_density_sptr(in_density_sptr->get_empty_discretised_density()); -Succeeded -MoveImage:: -process_data() -{ - shared_ptr< DiscretisedDensity<3,float> > out_density_sptr - (in_density_sptr->get_empty_discretised_density()); - - const unsigned int min_frame_num = - this->get_frame_num_to_process()==-1 - ? 1 : this->get_frame_num_to_process(); + const unsigned int min_frame_num = this->get_frame_num_to_process() == -1 ? 1 : this->get_frame_num_to_process(); const unsigned int max_frame_num = - this->get_frame_num_to_process()==-1 - ? this->get_time_frame_defs().get_num_frames() - : this->get_frame_num_to_process(); + this->get_frame_num_to_process() == -1 ? this->get_time_frame_defs().get_num_frames() : this->get_frame_num_to_process(); + + for (unsigned int current_frame_num = min_frame_num; current_frame_num <= max_frame_num; ++current_frame_num) { + const double start_time = this->get_time_frame_defs().get_start_time(current_frame_num); + const double end_time = this->get_time_frame_defs().get_end_time(current_frame_num); + info(boost::format("Doing frame %1% (from %2% to %3% secs)") % current_frame_num % start_time % end_time); + set_frame_num_to_process(current_frame_num); + + out_density_sptr->fill(0); + + transform_3d_object(*out_density_sptr, *in_density_sptr, this->get_current_rigid_object_transformation()); + + //*********** open output file - for (unsigned int current_frame_num = min_frame_num; - current_frame_num<=max_frame_num; - ++current_frame_num) { - const double start_time = - this->get_time_frame_defs().get_start_time(current_frame_num); - const double end_time = - this->get_time_frame_defs().get_end_time(current_frame_num); - info(boost::format("Doing frame %1% (from %2% to %3% secs)") % current_frame_num % start_time % end_time); - set_frame_num_to_process(current_frame_num); - - out_density_sptr->fill(0); - - transform_3d_object(*out_density_sptr, *in_density_sptr, - this->get_current_rigid_object_transformation()); - - - //*********** open output file - - { - char rest[50]; - sprintf(rest, "_f%ug1d0b0", current_frame_num); - const string output_filename = output_filename_prefix + rest; - if (output_file_format_sptr->write_to_file(output_filename, *out_density_sptr) - == Succeeded::no) - { - warning("Error writing file %s. Exiting\n", - output_filename.c_str()); - return Succeeded::no; - } - } + char rest[50]; + sprintf(rest, "_f%ug1d0b0", current_frame_num); + const string output_filename = output_filename_prefix + rest; + if (output_file_format_sptr->write_to_file(output_filename, *out_density_sptr) == Succeeded::no) { + warning("Error writing file %s. Exiting\n", output_filename.c_str()); + return Succeeded::no; + } } + } return Succeeded::yes; } - END_NAMESPACE_STIR - - USING_NAMESPACE_STIR -int main(int argc, char * argv[]) -{ - bool move_to_reference=true; - bool set_move_to_reference=false; - bool set_frame_num_to_process=false; - int frame_num_to_process=-1; - while (argc>=2 && argv[1][1]=='-') - { - if (strcmp(argv[1],"--move-to-reference")==0) - { - set_move_to_reference=true; - move_to_reference=atoi(argv[2]); - argc-=2; argv+=2; - } - else if (strcmp(argv[1], "--frame_num_to_process")==0) - { - set_frame_num_to_process=true; - frame_num_to_process=atoi(argv[2]); - argc-=2; argv+=2; - } - else - { - warning("Wrong option\n"); - exit(EXIT_FAILURE); - } +int +main(int argc, char* argv[]) { + bool move_to_reference = true; + bool set_move_to_reference = false; + bool set_frame_num_to_process = false; + int frame_num_to_process = -1; + while (argc >= 2 && argv[1][1] == '-') { + if (strcmp(argv[1], "--move-to-reference") == 0) { + set_move_to_reference = true; + move_to_reference = atoi(argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--frame_num_to_process") == 0) { + set_frame_num_to_process = true; + frame_num_to_process = atoi(argv[2]); + argc -= 2; + argv += 2; + } else { + warning("Wrong option\n"); + exit(EXIT_FAILURE); } + } - if (argc!=1 && argc!=2) { + if (argc != 1 && argc != 2) { cerr << "Usage: " << argv[0] << " \\\n" - << "\t[--move-to-reference 0|1] \\\n" - << "\t[--frame_num_to_process number]\\\n" - << "\t[par_file]\n"; + << "\t[--move-to-reference 0|1] \\\n" + << "\t[--frame_num_to_process number]\\\n" + << "\t[par_file]\n"; exit(EXIT_FAILURE); } - MoveImage application(argc==2 ? argv[1] : 0); + MoveImage application(argc == 2 ? argv[1] : 0); if (set_move_to_reference) application.move_to_reference(move_to_reference); if (set_frame_num_to_process) application.set_frame_num_to_process(frame_num_to_process); - Succeeded success = - application.process_data(); + Succeeded success = application.process_data(); return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/motion_utilities/move_projdata.cxx b/src/experimental/motion_utilities/move_projdata.cxx index 286cf0c9d7..1074d8b0c6 100644 --- a/src/experimental/motion_utilities/move_projdata.cxx +++ b/src/experimental/motion_utilities/move_projdata.cxx @@ -8,7 +8,7 @@ \brief Utility to move projection data according to average motion in the frame. \author Kris Thielemans - + \par Usage \verbatim move_projdata \\ @@ -17,7 +17,7 @@ [par_file] \endverbatim See class documentation for stir::MoveProjData for more info, including the format - of the par_file. + of the par_file. Command line switches override any values in the par_file. @@ -38,9 +38,9 @@ START_NAMESPACE_STIR Output is currently always in interfile format \see transform_3d_object(ProjData& out_proj_data, - const ProjData& in_proj_data, - const RigidObject3DTransformation& rigid_object_transformation) - + const ProjData& in_proj_data, + const RigidObject3DTransformation& rigid_object_transformation) + \par Example par file \see TimeFrameMotion for other parameters \verbatim @@ -57,19 +57,17 @@ START_NAMESPACE_STIR END := \endverbatim -*/ -class MoveProjData : public TimeFrameMotion -{ +*/ +class MoveProjData : public TimeFrameMotion { private: typedef TimeFrameMotion base_type; + public: - MoveProjData(const char * const par_filename); + MoveProjData(const char* const par_filename); virtual Succeeded process_data(); protected: - - //! parsing functions virtual void set_defaults(); virtual void initialise_keymap(); @@ -84,180 +82,141 @@ class MoveProjData : public TimeFrameMotion int max_out_segment_num_to_process; private: - shared_ptr in_proj_data_sptr; + shared_ptr in_proj_data_sptr; shared_ptr proj_data_info_ptr; // template for output - // shared_ptr output_file_format_sptr; + // shared_ptr output_file_format_sptr; }; -void -MoveProjData::set_defaults() -{ +void +MoveProjData::set_defaults() { base_type::set_defaults(); - //output_file_format_sptr = new DefaultOutputFileFormat; + // output_file_format_sptr = new DefaultOutputFileFormat; - max_in_segment_num_to_process=-1; - max_out_segment_num_to_process=-1; + max_in_segment_num_to_process = -1; + max_out_segment_num_to_process = -1; } -void -MoveProjData::initialise_keymap() -{ +void +MoveProjData::initialise_keymap() { parser.add_start_key("MoveProjData Parameters"); - parser.add_key("input file",&input_filename); - parser.add_key("output template filename",&output_template_filename); - parser.add_key("output filename prefix",&output_filename_prefix); + parser.add_key("input file", &input_filename); + parser.add_key("output template filename", &output_template_filename); + parser.add_key("output filename prefix", &output_filename_prefix); parser.add_key("max_out_segment_num_to_process", &max_out_segment_num_to_process); parser.add_key("max_in_segment_num_to_process", &max_in_segment_num_to_process); - //parser.add_parsing_key("Output file format",&output_file_format_sptr); + // parser.add_parsing_key("Output file format",&output_file_format_sptr); base_type::initialise_keymap(); parser.add_stop_key("END"); } -MoveProjData:: -MoveProjData(const char * const par_filename) -{ +MoveProjData::MoveProjData(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - { - if (parse(par_filename)==false) - exit(EXIT_FAILURE); - } - else + if (par_filename != 0) { + if (parse(par_filename) == false) + exit(EXIT_FAILURE); + } else ask_parameters(); - } bool -MoveProjData:: -post_processing() -{ +MoveProjData::post_processing() { if (base_type::post_processing() == true) return true; - if (output_filename_prefix.size()==0) - { - warning("You have to specify an output_filename_prefix\n"); - return true; - } - in_proj_data_sptr = - ProjData::read_from_file(input_filename); - if (max_in_segment_num_to_process<0) + if (output_filename_prefix.size() == 0) { + warning("You have to specify an output_filename_prefix\n"); + return true; + } + in_proj_data_sptr = ProjData::read_from_file(input_filename); + if (max_in_segment_num_to_process < 0) max_in_segment_num_to_process = in_proj_data_sptr->get_max_segment_num(); - if (output_template_filename.size() != 0) - { - shared_ptr template_proj_data_sptr = - ProjData::read_from_file(output_template_filename); - proj_data_info_ptr = - template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); - } - else - { - proj_data_info_ptr = - in_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); - } - if (max_out_segment_num_to_process<0) - max_out_segment_num_to_process = - proj_data_info_ptr->get_max_segment_num(); + if (output_template_filename.size() != 0) { + shared_ptr template_proj_data_sptr = ProjData::read_from_file(output_template_filename); + proj_data_info_ptr = template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); + } else { + proj_data_info_ptr = in_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); + } + if (max_out_segment_num_to_process < 0) + max_out_segment_num_to_process = proj_data_info_ptr->get_max_segment_num(); else - proj_data_info_ptr->reduce_segment_range(-max_out_segment_num_to_process,max_out_segment_num_to_process); - + proj_data_info_ptr->reduce_segment_range(-max_out_segment_num_to_process, max_out_segment_num_to_process); return false; } -Succeeded -MoveProjData:: -process_data() -{ +Succeeded +MoveProjData::process_data() { shared_ptr out_proj_data_sptr; - const unsigned int min_frame_num = - this->get_frame_num_to_process()==-1 - ? 1 : this->get_frame_num_to_process(); + const unsigned int min_frame_num = this->get_frame_num_to_process() == -1 ? 1 : this->get_frame_num_to_process(); const unsigned int max_frame_num = - this->get_frame_num_to_process()==-1 - ? this->get_time_frame_defs().get_num_frames() - : this->get_frame_num_to_process(); + this->get_frame_num_to_process() == -1 ? this->get_time_frame_defs().get_num_frames() : this->get_frame_num_to_process(); - for (unsigned int current_frame_num = min_frame_num; - current_frame_num<=max_frame_num; - ++current_frame_num) + for (unsigned int current_frame_num = min_frame_num; current_frame_num <= max_frame_num; ++current_frame_num) { + set_frame_num_to_process(current_frame_num); { - set_frame_num_to_process(current_frame_num); - { - char rest[50]; - sprintf(rest, "_f%ug1d0b0", current_frame_num); - const string output_filename = output_filename_prefix + rest; - out_proj_data_sptr. - reset(new ProjDataInterfile (in_proj_data_sptr->get_exam_info_sptr(), proj_data_info_ptr, output_filename, ios::out)); - } - - std::cout << "Applying transformation " - << this->get_current_rigid_object_transformation() - << '\n'; - - if (transform_3d_object(*out_proj_data_sptr, *in_proj_data_sptr, - this->get_current_rigid_object_transformation()) - == Succeeded::no) - return Succeeded::no; + char rest[50]; + sprintf(rest, "_f%ug1d0b0", current_frame_num); + const string output_filename = output_filename_prefix + rest; + out_proj_data_sptr.reset( + new ProjDataInterfile(in_proj_data_sptr->get_exam_info_sptr(), proj_data_info_ptr, output_filename, ios::out)); } + + std::cout << "Applying transformation " << this->get_current_rigid_object_transformation() << '\n'; + + if (transform_3d_object(*out_proj_data_sptr, *in_proj_data_sptr, this->get_current_rigid_object_transformation()) == + Succeeded::no) + return Succeeded::no; + } return Succeeded::yes; } - END_NAMESPACE_STIR - - USING_NAMESPACE_STIR -int main(int argc, char * argv[]) -{ - bool move_to_reference=true; - bool set_move_to_reference=false; - bool set_frame_num_to_process=false; - int frame_num_to_process=-1; - while (argc>=2 && argv[1][1]=='-') - { - if (strcmp(argv[1],"--move-to-reference")==0) - { - set_move_to_reference=true; - move_to_reference=atoi(argv[2]); - argc-=2; argv+=2; - } - else if (strcmp(argv[1], "--frame_num_to_process")==0) - { - set_frame_num_to_process=true; - frame_num_to_process=atoi(argv[2]); - argc-=2; argv+=2; - } - else - { - warning("Wrong option\n"); - exit(EXIT_FAILURE); - } +int +main(int argc, char* argv[]) { + bool move_to_reference = true; + bool set_move_to_reference = false; + bool set_frame_num_to_process = false; + int frame_num_to_process = -1; + while (argc >= 2 && argv[1][1] == '-') { + if (strcmp(argv[1], "--move-to-reference") == 0) { + set_move_to_reference = true; + move_to_reference = atoi(argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--frame_num_to_process") == 0) { + set_frame_num_to_process = true; + frame_num_to_process = atoi(argv[2]); + argc -= 2; + argv += 2; + } else { + warning("Wrong option\n"); + exit(EXIT_FAILURE); } + } - if (argc!=1 && argc!=2) { + if (argc != 1 && argc != 2) { cerr << "Usage: " << argv[0] << " \\\n" - << "\t[--move-to-reference 0|1] \\\n" - << "\t[--frame_num_to_process number]\\\n" - << "\t[par_file]\n"; + << "\t[--move-to-reference 0|1] \\\n" + << "\t[--frame_num_to_process number]\\\n" + << "\t[par_file]\n"; exit(EXIT_FAILURE); } - MoveProjData application(argc==2 ? argv[1] : 0); + MoveProjData application(argc == 2 ? argv[1] : 0); if (set_move_to_reference) application.move_to_reference(move_to_reference); if (set_frame_num_to_process) application.set_frame_num_to_process(frame_num_to_process); - Succeeded success = - application.process_data(); + Succeeded success = application.process_data(); return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/motion_utilities/non_rigid_transform.cxx b/src/experimental/motion_utilities/non_rigid_transform.cxx index 58619ed12a..792b2c1d0e 100644 --- a/src/experimental/motion_utilities/non_rigid_transform.cxx +++ b/src/experimental/motion_utilities/non_rigid_transform.cxx @@ -24,10 +24,11 @@ \author Richard Brown \par Usage: - \code + \code non_rigid_transform output_filename input_filename output_file_format_param displacement_field_4D OR - non_rigid_transform output_filename input_filename output_file_format_param displacement_field_x displacement_field_y displacement_field_z + non_rigid_transform output_filename input_filename output_file_format_param displacement_field_x displacement_field_y + displacement_field_z An example of an output parameter file is as follows: OutputFileFormat Parameters:= @@ -50,86 +51,85 @@ #include "stir_experimental/motion/NonRigidObjectTransformationUsingBSplines.h" #include "stir_experimental/motion/Transform3DObjectImageProcessor.h" -int main(int argc, char *argv[]) -{ - USING_NAMESPACE_STIR - - if (argc < 5 || argc > 8) { - std::cerr << "\nUsage:\n"; - std::cerr << "\tnon_rigid_transform output_filename input_filename bspline_order displacement_field_4D [output_file_format_param]\n"; - std::cerr << "\t\tOR\n"; - std::cerr << "\tnon_rigid_transform output_filename input_filename bspline_order displacement_field_x displacement_field_y displacement_field_z [output_file_format_param]\n"; - return EXIT_SUCCESS; +int +main(int argc, char* argv[]) { + USING_NAMESPACE_STIR + + if (argc < 5 || argc > 8) { + std::cerr << "\nUsage:\n"; + std::cerr << "\tnon_rigid_transform output_filename input_filename bspline_order displacement_field_4D " + "[output_file_format_param]\n"; + std::cerr << "\t\tOR\n"; + std::cerr << "\tnon_rigid_transform output_filename input_filename bspline_order displacement_field_x displacement_field_y " + "displacement_field_z [output_file_format_param]\n"; + return EXIT_SUCCESS; + } + + try { + + // Read all the input info + const std::string output_filename = argv[1]; + const std::string input_filename = argv[2]; + const int bspline_order = atoi(argv[3]); + std::string disp_4d = "", disp_x = "", disp_y = "", disp_z = ""; + if (argc <= 6) + disp_4d = argv[4]; + else { + disp_x = argv[4]; + disp_y = argv[5]; + disp_z = argv[6]; + } + std::string output_file_format_param = ""; + if (argc == 6) + output_file_format_param = argv[5]; + else if (argc == 8) + output_file_format_param = argv[7]; + + // Read input image + std::cerr << "\nReading input image...\n"; + shared_ptr> to_transform_sptr(read_from_file>(input_filename)); + if (is_null_ptr(to_transform_sptr)) + throw std::runtime_error("Failed to read input image (" + input_filename + ")."); + + // Create transform + std::cerr << "\nCreating transform...\n"; + shared_ptr> fwrd_non_rigid; + // If 4D + if (!disp_4d.empty()) + fwrd_non_rigid.reset(new NonRigidObjectTransformationUsingBSplines<3, float>(disp_4d, bspline_order)); + else + fwrd_non_rigid.reset(new NonRigidObjectTransformationUsingBSplines<3, float>(disp_x, disp_y, disp_z, bspline_order)); + + // Image processor + std::cerr << "\nDoing transformation...\n"; + Transform3DObjectImageProcessor fwrd_transform(fwrd_non_rigid); + fwrd_transform.apply(*to_transform_sptr); + + // Save + std::cerr << "\nSaving result to file (" << output_filename << ")...\n"; + shared_ptr>> output_file_format = + OutputFileFormat>::default_sptr(); + if (!output_file_format_param.empty()) { + KeyParser parser; + parser.add_start_key("output file format parameters"); + parser.add_parsing_key("output file format type", &output_file_format); + parser.add_stop_key("END"); + if (parser.parse(output_file_format_param.c_str()) == false || is_null_ptr(output_file_format)) { + warning("Error parsing output file format. Using default format."); + output_file_format = OutputFileFormat>::default_sptr(); + } } + if (output_file_format->write_to_file(output_filename, *to_transform_sptr) == Succeeded::no) + throw std::runtime_error("Failed to save to file."); - try { - - // Read all the input info - const std::string output_filename = argv[1]; - const std::string input_filename = argv[2]; - const int bspline_order = atoi(argv[3]); - std::string disp_4d="", disp_x="", disp_y="", disp_z=""; - if (argc <= 6) - disp_4d = argv[4]; - else { - disp_x = argv[4]; - disp_y = argv[5]; - disp_z = argv[6]; - } - std::string output_file_format_param = ""; - if (argc==6) - output_file_format_param = argv[5]; - else if (argc==8) - output_file_format_param = argv[7]; - - // Read input image - std::cerr << "\nReading input image...\n"; - shared_ptr > to_transform_sptr( - read_from_file >(input_filename)); - if (is_null_ptr(to_transform_sptr)) - throw std::runtime_error("Failed to read input image (" + input_filename + ")."); - - // Create transform - std::cerr << "\nCreating transform...\n"; - shared_ptr > fwrd_non_rigid; - // If 4D - if (!disp_4d.empty()) - fwrd_non_rigid.reset(new NonRigidObjectTransformationUsingBSplines<3,float>(disp_4d,bspline_order)); - else - fwrd_non_rigid.reset(new NonRigidObjectTransformationUsingBSplines<3,float>(disp_x,disp_y,disp_z,bspline_order)); - - // Image processor - std::cerr << "\nDoing transformation...\n"; - Transform3DObjectImageProcessor fwrd_transform(fwrd_non_rigid); - fwrd_transform.apply(*to_transform_sptr); - - // Save - std::cerr << "\nSaving result to file (" << output_filename << ")...\n"; - shared_ptr > > output_file_format = - OutputFileFormat >::default_sptr(); - if (!output_file_format_param.empty()) { - KeyParser parser; - parser.add_start_key("output file format parameters"); - parser.add_parsing_key("output file format type", &output_file_format); - parser.add_stop_key("END"); - if (parser.parse(output_file_format_param.c_str()) == false || is_null_ptr(output_file_format)) { - warning("Error parsing output file format. Using default format."); - output_file_format = OutputFileFormat >::default_sptr(); - } - } - if (output_file_format->write_to_file(output_filename,*to_transform_sptr) == Succeeded::no) - throw std::runtime_error("Failed to save to file."); - - // If all is good, exit - return EXIT_SUCCESS; + // If all is good, exit + return EXIT_SUCCESS; // If there was an error - } catch(const std::exception &error) { - std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; - return EXIT_FAILURE; - } catch(...) { - return EXIT_FAILURE; - } + } catch (const std::exception& error) { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + return EXIT_FAILURE; + } catch (...) { + return EXIT_FAILURE; + } } - - diff --git a/src/experimental/motion_utilities/remove_corrupted_sinograms.cxx b/src/experimental/motion_utilities/remove_corrupted_sinograms.cxx index da67e95209..5d8f559808 100644 --- a/src/experimental/motion_utilities/remove_corrupted_sinograms.cxx +++ b/src/experimental/motion_utilities/remove_corrupted_sinograms.cxx @@ -10,17 +10,17 @@ See general MC doc for how the LMC method works. This is a program that takes corrupted sinograms - (normally after motion correction is applied) and cuts away planes that - have too much missing data. The amount that is cut is determined by the user + (normally after motion correction is applied) and cuts away planes that + have too much missing data. The amount that is cut is determined by the user in percentage of a total amount of bins in each efficiency sinogram. Because of restrictions in stir::ProjDataInfoCylindrical, we have to cut the same number of sinograms in each segment. This is because get_m() et al rely - on the centre of the scanner to correspond to the middle sinogram. Unfortunately, this + on the centre of the scanner to correspond to the middle sinogram. Unfortunately, this results in potentially cutting valid data in the oblique segments... - + It would not be too difficult to change ProjDataInfoCylindrical to allow - different offsets, but then we need to write those into the Interfile + different offsets, but then we need to write those into the Interfile headers etc. @@ -28,7 +28,6 @@ \author Kris Thielemans */ - #include "stir/ProjData.h" #include "stir/ProjDataInfo.h" #include "stir/ProjDataInterfile.h" @@ -52,263 +51,201 @@ using std::vector; USING_NAMESPACE_STIR - - - // note: we ignore outer bins as they tend not to contribute to the image anyway static float -get_percentage_corrupted(const Sinogram& sinogram) -{ - int counter=0; - const int total_num_bins_sino = sinogram.get_num_views()*(sinogram.get_num_tangential_poss()-40); - for ( int view_num = sinogram.get_min_view_num(); - view_num <= sinogram.get_max_view_num(); view_num++) - for ( int tang_pos = sinogram.get_min_tangential_pos_num()+20; - tang_pos <= sinogram.get_max_tangential_pos_num()-20; - tang_pos++) - { - const float bin = sinogram[view_num][tang_pos]; - if (fabs(bin/0.1) < 3) - counter ++; - } - return static_cast(counter)/static_cast (total_num_bins_sino)*100; +get_percentage_corrupted(const Sinogram& sinogram) { + int counter = 0; + const int total_num_bins_sino = sinogram.get_num_views() * (sinogram.get_num_tangential_poss() - 40); + for (int view_num = sinogram.get_min_view_num(); view_num <= sinogram.get_max_view_num(); view_num++) + for (int tang_pos = sinogram.get_min_tangential_pos_num() + 20; tang_pos <= sinogram.get_max_tangential_pos_num() - 20; + tang_pos++) { + const float bin = sinogram[view_num][tang_pos]; + if (fabs(bin / 0.1) < 3) + counter++; + } + return static_cast(counter) / static_cast(total_num_bins_sino) * 100; } -void check_for_corrupted_sinograms(int& axial_pos_to_remove_min, - int& axial_pos_to_remove_max, - const ProjData& proj_data, - const int segment_num, - const float tolerance_of_corruption) +void +check_for_corrupted_sinograms(int& axial_pos_to_remove_min, int& axial_pos_to_remove_max, const ProjData& proj_data, + const int segment_num, const float tolerance_of_corruption) { - axial_pos_to_remove_min =0; - axial_pos_to_remove_max =0; - for (int axial_pos_num =proj_data.get_min_axial_pos_num(segment_num); - axial_pos_num <=proj_data.get_max_axial_pos_num(segment_num); - ++axial_pos_num) - { - const float percentage_corrupted= - get_percentage_corrupted(proj_data.get_sinogram(axial_pos_num, segment_num)); - cerr << "Percentage corrupted at plane " << axial_pos_num << " is " << percentage_corrupted << "\n"; - if ( percentage_corrupted >tolerance_of_corruption) - axial_pos_to_remove_min++; - else - break; - } + axial_pos_to_remove_min = 0; + axial_pos_to_remove_max = 0; + for (int axial_pos_num = proj_data.get_min_axial_pos_num(segment_num); + axial_pos_num <= proj_data.get_max_axial_pos_num(segment_num); ++axial_pos_num) { + const float percentage_corrupted = get_percentage_corrupted(proj_data.get_sinogram(axial_pos_num, segment_num)); + cerr << "Percentage corrupted at plane " << axial_pos_num << " is " << percentage_corrupted << "\n"; + if (percentage_corrupted > tolerance_of_corruption) + axial_pos_to_remove_min++; + else + break; + } // now do the max side - for (int axial_pos_num =proj_data.get_max_axial_pos_num(segment_num); - axial_pos_num >proj_data.get_min_axial_pos_num(segment_num)+axial_pos_to_remove_min; - axial_pos_num--) - { - const float percentage_corrupted= - get_percentage_corrupted(proj_data.get_sinogram(axial_pos_num, segment_num)); - cerr << "Percentage corrupted at plane " << axial_pos_num << " is " << percentage_corrupted << "\n"; - if ( percentage_corrupted >tolerance_of_corruption) - axial_pos_to_remove_max++; - else - break; - } + for (int axial_pos_num = proj_data.get_max_axial_pos_num(segment_num); + axial_pos_num > proj_data.get_min_axial_pos_num(segment_num) + axial_pos_to_remove_min; axial_pos_num--) { + const float percentage_corrupted = get_percentage_corrupted(proj_data.get_sinogram(axial_pos_num, segment_num)); + cerr << "Percentage corrupted at plane " << axial_pos_num << " is " << percentage_corrupted << "\n"; + if (percentage_corrupted > tolerance_of_corruption) + axial_pos_to_remove_max++; + else + break; + } // check if any sinograms left - if (axial_pos_to_remove_max+axial_pos_to_remove_min >= - proj_data.get_num_axial_poss(segment_num)) + if (axial_pos_to_remove_max + axial_pos_to_remove_min >= proj_data.get_num_axial_poss(segment_num)) return; - /* Now make sure that we cut an even number of sinograms. Otherwise current + /* Now make sure that we cut an even number of sinograms. Otherwise current ProjDataInfoCylindrical has problems figuring out the offsets for get_m(). */ - if ((axial_pos_to_remove_max+axial_pos_to_remove_min)%2 !=0) - { - const float percentage_corrupted_min = - get_percentage_corrupted(proj_data.get_sinogram(proj_data.get_min_axial_pos_num(segment_num)+axial_pos_to_remove_min, 0)); - const float percentage_corrupted_max = - get_percentage_corrupted(proj_data.get_sinogram(proj_data.get_max_axial_pos_num(segment_num)-axial_pos_to_remove_min, 0)); - if (percentage_corrupted_max>=percentage_corrupted_min) - ++axial_pos_to_remove_max; - else - ++axial_pos_to_remove_min; - } - - + if ((axial_pos_to_remove_max + axial_pos_to_remove_min) % 2 != 0) { + const float percentage_corrupted_min = get_percentage_corrupted( + proj_data.get_sinogram(proj_data.get_min_axial_pos_num(segment_num) + axial_pos_to_remove_min, 0)); + const float percentage_corrupted_max = get_percentage_corrupted( + proj_data.get_sinogram(proj_data.get_max_axial_pos_num(segment_num) - axial_pos_to_remove_min, 0)); + if (percentage_corrupted_max >= percentage_corrupted_min) + ++axial_pos_to_remove_max; + else + ++axial_pos_to_remove_min; + } } int -main(int argc, char* argv[]) -{ - - if ( argc !=6) - { +main(int argc, char* argv[]) { + + if (argc != 6) { cerr << "Usage:" << argv[0] << "Output filename, sinogram to modify and \n" - <<"the corresponding efficieny file, max_number_of_segment_to_process \n," - << "tolerance_of_corruption(in %)" << endl; + << "the corresponding efficieny file, max_number_of_segment_to_process \n," + << "tolerance_of_corruption(in %)" << endl; return EXIT_FAILURE; } #if 1 - const string output_filename = argv[1]; - shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); - shared_ptr eff_projdata_ptr = ProjData::read_from_file(argv[3]); - + const string output_filename = argv[1]; + shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); + shared_ptr eff_projdata_ptr = ProjData::read_from_file(argv[3]); + int max_segment_num_to_process = atoi(argv[4]); - float tolerance_of_corruption =static_cast(atof(argv[5])); - //int num_axial_poss_to_remove_at_min_side = atoi(argv[5]); - //int num_axial_poss_to_remove_at_max_side = atoi(argv[6]); + float tolerance_of_corruption = static_cast(atof(argv[5])); + // int num_axial_poss_to_remove_at_min_side = atoi(argv[5]); + // int num_axial_poss_to_remove_at_max_side = atoi(argv[6]); vector record_of_number_of_planes_to_remove_min; vector record_of_number_of_planes_to_remove_max; - + // construct new proj_data_info_ptr for output data - shared_ptr proj_data_info_ptr = - in_projdata_ptr->get_proj_data_info_sptr()->create_shared_clone(); + shared_ptr proj_data_info_ptr = in_projdata_ptr->get_proj_data_info_sptr()->create_shared_clone(); - if (proj_data_info_ptr->get_max_segment_num()get_max_segment_num() < max_segment_num_to_process) max_segment_num_to_process = proj_data_info_ptr->get_max_segment_num(); { - - proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, - max_segment_num_to_process); + + proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); // now set new number of axial positions - VectorWithOffset - new_num_axial_poss_per_segment(-max_segment_num_to_process, - max_segment_num_to_process); -#if 1 + VectorWithOffset new_num_axial_poss_per_segment(-max_segment_num_to_process, max_segment_num_to_process); +# if 1 int axial_pos_to_remove_min; int axial_pos_to_remove_max; // only do segment zero and use that for all other segments - check_for_corrupted_sinograms(axial_pos_to_remove_min, - axial_pos_to_remove_max, - *eff_projdata_ptr, 0, - tolerance_of_corruption); - - int number_of_axial_pos_to_remove = axial_pos_to_remove_min+axial_pos_to_remove_max; - - record_of_number_of_planes_to_remove_min.push_back(axial_pos_to_remove_min); - record_of_number_of_planes_to_remove_max.push_back(axial_pos_to_remove_max); - - new_num_axial_poss_per_segment[0] = - in_projdata_ptr->get_num_axial_poss(0) - - number_of_axial_pos_to_remove; - if (new_num_axial_poss_per_segment[0]>1) - proj_data_info_ptr->set_num_axial_poss_per_segment(new_num_axial_poss_per_segment); - else - { - warning("%s: there are not enough axial positions even in segment 0\n" - "Too much motion for this procedure to work.\n", - argv[0]); - exit(EXIT_FAILURE); - } - - for (int segment_num=proj_data_info_ptr->get_min_segment_num(); - segment_num<=proj_data_info_ptr->get_max_segment_num(); - ++segment_num) - { - if (segment_num !=0) - { - //num_axial_poss_to_remove_at_min_side+ - //num_axial_poss_to_remove_at_max_side; - new_num_axial_poss_per_segment[segment_num] = - in_projdata_ptr->get_num_axial_poss(segment_num) - - number_of_axial_pos_to_remove; - if (new_num_axial_poss_per_segment[segment_num]>0) - proj_data_info_ptr->set_num_axial_poss_per_segment(new_num_axial_poss_per_segment); - else - { - proj_data_info_ptr->reduce_segment_range(-abs(segment_num)+1,abs(segment_num)-1); - } - } - } -#endif - if (proj_data_info_ptr->get_max_segment_num()get_max_segment_num()+1, - 2*max_segment_num_to_process+1); + check_for_corrupted_sinograms(axial_pos_to_remove_min, axial_pos_to_remove_max, *eff_projdata_ptr, 0, + tolerance_of_corruption); + + int number_of_axial_pos_to_remove = axial_pos_to_remove_min + axial_pos_to_remove_max; + + record_of_number_of_planes_to_remove_min.push_back(axial_pos_to_remove_min); + record_of_number_of_planes_to_remove_max.push_back(axial_pos_to_remove_max); + + new_num_axial_poss_per_segment[0] = in_projdata_ptr->get_num_axial_poss(0) - number_of_axial_pos_to_remove; + if (new_num_axial_poss_per_segment[0] > 1) + proj_data_info_ptr->set_num_axial_poss_per_segment(new_num_axial_poss_per_segment); + else { + warning("%s: there are not enough axial positions even in segment 0\n" + "Too much motion for this procedure to work.\n", + argv[0]); + exit(EXIT_FAILURE); + } + + for (int segment_num = proj_data_info_ptr->get_min_segment_num(); segment_num <= proj_data_info_ptr->get_max_segment_num(); + ++segment_num) { + if (segment_num != 0) { + // num_axial_poss_to_remove_at_min_side+ + // num_axial_poss_to_remove_at_max_side; + new_num_axial_poss_per_segment[segment_num] = + in_projdata_ptr->get_num_axial_poss(segment_num) - number_of_axial_pos_to_remove; + if (new_num_axial_poss_per_segment[segment_num] > 0) + proj_data_info_ptr->set_num_axial_poss_per_segment(new_num_axial_poss_per_segment); + else { + proj_data_info_ptr->reduce_segment_range(-abs(segment_num) + 1, abs(segment_num) - 1); + } + } + } +# endif + if (proj_data_info_ptr->get_max_segment_num() < max_segment_num_to_process) + warning("%s WARNING: highest segments were corrupted too much. \n" + "I am keeping only %d segments instead of %d\n", + argv[0], 2 * proj_data_info_ptr->get_max_segment_num() + 1, 2 * max_segment_num_to_process + 1); } // check if everything was done consistently { - /* We do this by checking if all m-coordinates are shifted with the + /* We do this by checking if all m-coordinates are shifted with the same amount. */ - const ProjDataInfo& in_proj_data_info = - *(in_projdata_ptr->get_proj_data_info_sptr()); + const ProjDataInfo& in_proj_data_info = *(in_projdata_ptr->get_proj_data_info_sptr()); - const float m_difference_segment_0 = - in_proj_data_info.get_m(Bin(0,0,0,0)) - - proj_data_info_ptr->get_m(Bin(0,0,0,0)); + const float m_difference_segment_0 = in_proj_data_info.get_m(Bin(0, 0, 0, 0)) - proj_data_info_ptr->get_m(Bin(0, 0, 0, 0)); // variable used to scale differences in floating point comparison - const float reference_sampling_in_m = - in_proj_data_info.get_sampling_in_m(Bin(0,0,0,0)); - - for (int segment_num=proj_data_info_ptr->get_min_segment_num(); - segment_num<=proj_data_info_ptr->get_max_segment_num(); - ++segment_num) - { - const float m_difference = - in_proj_data_info.get_m(Bin(segment_num,0,0,0)) - - proj_data_info_ptr->get_m(Bin(segment_num,0,0,0)) - - m_difference_segment_0; - if (fabs(m_difference) > .001*reference_sampling_in_m) - { - error("remove_corrupted_sinograms: inconsistent shift in axial direction.\n" - "At segment %d, shift w.r.t segment 0 of %g mm.\n" - "Check code!\n", - segment_num, - m_difference ); - } + const float reference_sampling_in_m = in_proj_data_info.get_sampling_in_m(Bin(0, 0, 0, 0)); + + for (int segment_num = proj_data_info_ptr->get_min_segment_num(); segment_num <= proj_data_info_ptr->get_max_segment_num(); + ++segment_num) { + const float m_difference = in_proj_data_info.get_m(Bin(segment_num, 0, 0, 0)) - + proj_data_info_ptr->get_m(Bin(segment_num, 0, 0, 0)) - m_difference_segment_0; + if (fabs(m_difference) > .001 * reference_sampling_in_m) { + error("remove_corrupted_sinograms: inconsistent shift in axial direction.\n" + "At segment %d, shift w.r.t segment 0 of %g mm.\n" + "Check code!\n", + segment_num, m_difference); } + } } - ProjDataInterfile out_projdata(in_projdata_ptr->get_exam_info_sptr(), proj_data_info_ptr, output_filename); + ProjDataInterfile out_projdata(in_projdata_ptr->get_exam_info_sptr(), proj_data_info_ptr, output_filename); Succeeded succes = Succeeded::yes; - std::vector::iterator iter_record_of_number_of_planes_to_remove_min = - record_of_number_of_planes_to_remove_min.begin(); - std::vector::iterator iter_record_of_number_of_planes_to_remove_max = - record_of_number_of_planes_to_remove_max.begin(); - - for (int segment_num = out_projdata.get_min_segment_num(); - segment_num <= out_projdata.get_max_segment_num(); - ++segment_num) - { - SegmentBySinogram out_segment = - out_projdata.get_empty_segment_by_sinogram(segment_num); - const SegmentBySinogram in_segment = - in_projdata_ptr->get_segment_by_sinogram( segment_num); - - int num_axial_poss_to_remove_at_min_side = *iter_record_of_number_of_planes_to_remove_min; - int num_axial_poss_to_remove_at_max_side = *iter_record_of_number_of_planes_to_remove_max; - - // warning: current reconstruction script relies on the following messages - // appearing in the log file! - - cerr << " Number of planes to remove on the min side is " << num_axial_poss_to_remove_at_min_side << endl; - cerr << " Number of planes to remove on the max side is " << num_axial_poss_to_remove_at_max_side << endl; - - - int ax_pos_num_out = out_segment.get_min_axial_pos_num(); - for (int ax_pos_num=(in_segment.get_min_axial_pos_num()+num_axial_poss_to_remove_at_min_side); - ax_pos_num<=in_segment.get_max_axial_pos_num()-num_axial_poss_to_remove_at_max_side; - ++ax_pos_num, ++ax_pos_num_out) - { - // cerr << ax_pos_num << " "; - // note: the next line is ok even with different proj_data_info's - // for each segment. The reason is that Array::operator[] - // and assignment is used, which ignores proj_data_info - out_segment[ax_pos_num_out] = in_segment[ax_pos_num]; - } - if (out_projdata.set_segment(out_segment) == Succeeded::no) - succes = Succeeded::no; - // cerr << endl; - - - + std::vector::iterator iter_record_of_number_of_planes_to_remove_min = record_of_number_of_planes_to_remove_min.begin(); + std::vector::iterator iter_record_of_number_of_planes_to_remove_max = record_of_number_of_planes_to_remove_max.begin(); + + for (int segment_num = out_projdata.get_min_segment_num(); segment_num <= out_projdata.get_max_segment_num(); ++segment_num) { + SegmentBySinogram out_segment = out_projdata.get_empty_segment_by_sinogram(segment_num); + const SegmentBySinogram in_segment = in_projdata_ptr->get_segment_by_sinogram(segment_num); + + int num_axial_poss_to_remove_at_min_side = *iter_record_of_number_of_planes_to_remove_min; + int num_axial_poss_to_remove_at_max_side = *iter_record_of_number_of_planes_to_remove_max; + + // warning: current reconstruction script relies on the following messages + // appearing in the log file! + + cerr << " Number of planes to remove on the min side is " << num_axial_poss_to_remove_at_min_side << endl; + cerr << " Number of planes to remove on the max side is " << num_axial_poss_to_remove_at_max_side << endl; + + int ax_pos_num_out = out_segment.get_min_axial_pos_num(); + for (int ax_pos_num = (in_segment.get_min_axial_pos_num() + num_axial_poss_to_remove_at_min_side); + ax_pos_num <= in_segment.get_max_axial_pos_num() - num_axial_poss_to_remove_at_max_side; + ++ax_pos_num, ++ax_pos_num_out) { + // cerr << ax_pos_num << " "; + // note: the next line is ok even with different proj_data_info's + // for each segment. The reason is that Array::operator[] + // and assignment is used, which ignores proj_data_info + out_segment[ax_pos_num_out] = in_segment[ax_pos_num]; } + if (out_projdata.set_segment(out_segment) == Succeeded::no) + succes = Succeeded::no; + // cerr << endl; + } - #endif - return succes == Succeeded::no ? EXIT_FAILURE : EXIT_SUCCESS; } - diff --git a/src/experimental/motion_utilities/report_movement.cxx b/src/experimental/motion_utilities/report_movement.cxx index 03e5a901a8..14db9600eb 100644 --- a/src/experimental/motion_utilities/report_movement.cxx +++ b/src/experimental/motion_utilities/report_movement.cxx @@ -10,7 +10,7 @@ \brief Utility to report RMSE w.r.t. reference position and within the frames \author Kris Thielemans - + \par Usage \verbatim report_movement \\ @@ -18,7 +18,7 @@ [par_file] \endverbatim See class documentation for stir::ReportMovement for more info, including the format - of the par_file. + of the par_file. Command line switches override any values in the par_file. @@ -43,46 +43,43 @@ START_NAMESPACE_STIR ; parameters from TimeFrameMotion - reference point 1:={50,0,0} - reference point 2:={100,0,30} - reference point 3:={100,0,-30} + reference point 1:={50,0,0} + reference point 2:={100,0,30} + reference point 3:={100,0,-30} ; next defaults to 'report_movement' output filename prefix := somestring END := \endverbatim -*/ -class ReportMovement : public TimeFrameMotion -{ +*/ +class ReportMovement : public TimeFrameMotion { private: typedef TimeFrameMotion base_type; + public: - ReportMovement(const char * const par_filename); + ReportMovement(const char* const par_filename); virtual Succeeded process_data(); protected: - std::vector > reference_points; + std::vector> reference_points; std::string output_filename_prefix; - + //! parsing functions virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - }; -void -ReportMovement::set_defaults() -{ +void +ReportMovement::set_defaults() { base_type::set_defaults(); - reference_points.resize(3, make_coordinate(0.F,0.F,0.F)); + reference_points.resize(3, make_coordinate(0.F, 0.F, 0.F)); output_filename_prefix = "report_movement"; } -void -ReportMovement::initialise_keymap() -{ +void +ReportMovement::initialise_keymap() { parser.add_start_key("ReportMovement Parameters"); base_type::initialise_keymap(); @@ -93,35 +90,25 @@ ReportMovement::initialise_keymap() parser.add_stop_key("END"); } -ReportMovement:: -ReportMovement(const char * const par_filename) -{ +ReportMovement::ReportMovement(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - { - if (parse(par_filename)==false) - exit(EXIT_FAILURE); - } - else + if (par_filename != 0) { + if (parse(par_filename) == false) + exit(EXIT_FAILURE); + } else ask_parameters(); - } bool -ReportMovement:: -post_processing() -{ +ReportMovement::post_processing() { if (base_type::post_processing() == true) return true; return false; } - -Succeeded -ReportMovement:: -process_data() -{ +Succeeded +ReportMovement::process_data() { std::string filename_all = this->output_filename_prefix + "_all.log"; std::ofstream output_all(filename_all.c_str()); @@ -130,13 +117,9 @@ process_data() std::cout << "\nI will write output in " << filename_all << " and " << filename_summary << '\n'; - const unsigned int min_frame_num = - this->get_frame_num_to_process()==-1 - ? 1 : this->get_frame_num_to_process(); + const unsigned int min_frame_num = this->get_frame_num_to_process() == -1 ? 1 : this->get_frame_num_to_process(); const unsigned int max_frame_num = - this->get_frame_num_to_process()==-1 - ? this->get_time_frame_defs().get_num_frames() - : this->get_frame_num_to_process(); + this->get_frame_num_to_process() == -1 ? this->get_time_frame_defs().get_num_frames() : this->get_frame_num_to_process(); double MSE_within_frame_all_frames = 0; double MSE_from_ref_all_frames = 0; @@ -144,136 +127,107 @@ process_data() double max_RMSE_from_ref = 0; unsigned num_samples_all_frames = 0; - for (unsigned int current_frame_num = min_frame_num; - current_frame_num<=max_frame_num; - ++current_frame_num) + for (unsigned int current_frame_num = min_frame_num; current_frame_num <= max_frame_num; ++current_frame_num) { + double MSE_within_frame_this_frame = 0; + double MSE_from_ref_this_frame = 0; + unsigned num_samples_this_frame = 0; + const double start_time = this->get_frame_start_time(current_frame_num); + const double end_time = this->get_frame_end_time(current_frame_num); + + // cerr << "\nDoing frame " << current_frame_num + // << ": from " << start_time << " to " << end_time << endl; + + // set_frame_num_to_process(current_frame_num); + + const RigidObject3DTransformation frame_transformation_to_reference = + compose(this->get_rigid_object_transformation_to_reference(), + this->get_motion().compute_average_motion_in_scanner_coords_rel_time(start_time, end_time)); + + // now go through tracker data for this frame { - double MSE_within_frame_this_frame = 0; - double MSE_from_ref_this_frame = 0; - unsigned num_samples_this_frame = 0; - const double start_time = - this->get_frame_start_time(current_frame_num); - const double end_time = - this->get_frame_end_time(current_frame_num); - - //cerr << "\nDoing frame " << current_frame_num - // << ": from " << start_time << " to " << end_time << endl; - - //set_frame_num_to_process(current_frame_num); - - const RigidObject3DTransformation frame_transformation_to_reference = - compose(this->get_rigid_object_transformation_to_reference(), - this->get_motion(). - compute_average_motion_in_scanner_coords_rel_time(start_time, end_time)); - - // now go through tracker data for this frame - { - const std::vector sample_times = - this->get_motion(). - get_rel_time_of_samples(start_time, end_time); - - if (sample_times.size() == 0) - error("No tracker samples between %g and %g (relative to scan start)", - start_time, end_time); - - for (std::vector::const_iterator iter=sample_times.begin(); - iter != sample_times.end(); - ++iter) - { - const RigidObject3DTransformation current_transformation_to_reference = - compose(this->get_rigid_object_transformation_to_reference(), - this->get_motion(). - get_motion_in_scanner_coords_rel_time(*iter)); - - const RigidObject3DTransformation current_transformation_to_frame_ref = - compose(frame_transformation_to_reference, - current_transformation_to_reference.inverse()); - - const double RMSE_within_frame = - RigidObject3DTransformation:: - RMSE(current_transformation_to_frame_ref, - this->reference_points.begin(), this->reference_points.end(), - this->reference_points.begin()); - - const double RMSE_from_ref = - RigidObject3DTransformation:: - RMSE(current_transformation_to_reference, - this->reference_points.begin(), this->reference_points.end(), - this->reference_points.begin()); - - output_all << *iter << " " << RMSE_within_frame << " " << RMSE_from_ref << '\n'; - - ++num_samples_this_frame; - MSE_within_frame_this_frame += square(RMSE_within_frame); - MSE_from_ref_this_frame += square(RMSE_from_ref); - - max_RMSE_within_frame = std::max(max_RMSE_within_frame, RMSE_within_frame); - max_RMSE_from_ref = std::max(max_RMSE_from_ref, RMSE_from_ref); - } // end of loop over tracker samples - } - output_summary << "Total RMSE frame " << current_frame_num << " " - << std::sqrt(MSE_within_frame_this_frame/num_samples_this_frame) << " " - << std::sqrt(MSE_from_ref_this_frame/num_samples_this_frame) << '\n'; - MSE_within_frame_all_frames += MSE_within_frame_this_frame; - MSE_from_ref_all_frames += MSE_from_ref_this_frame; - num_samples_all_frames += num_samples_this_frame; - } // end of loop over frames - - output_summary << "\n\nTotal RMSE all frames " - << std::sqrt(MSE_within_frame_all_frames/num_samples_all_frames) << " " - << std::sqrt(MSE_from_ref_all_frames/num_samples_all_frames) << '\n' - << "Maximum RMSE occuring at a certain time " - << max_RMSE_within_frame <<" " - << max_RMSE_from_ref << '\n'; + const std::vector sample_times = this->get_motion().get_rel_time_of_samples(start_time, end_time); + if (sample_times.size() == 0) + error("No tracker samples between %g and %g (relative to scan start)", start_time, end_time); - return Succeeded::yes; -} + for (std::vector::const_iterator iter = sample_times.begin(); iter != sample_times.end(); ++iter) { + const RigidObject3DTransformation current_transformation_to_reference = + compose(this->get_rigid_object_transformation_to_reference(), + this->get_motion().get_motion_in_scanner_coords_rel_time(*iter)); + const RigidObject3DTransformation current_transformation_to_frame_ref = + compose(frame_transformation_to_reference, current_transformation_to_reference.inverse()); -END_NAMESPACE_STIR + const double RMSE_within_frame = + RigidObject3DTransformation::RMSE(current_transformation_to_frame_ref, this->reference_points.begin(), + this->reference_points.end(), this->reference_points.begin()); + + const double RMSE_from_ref = + RigidObject3DTransformation::RMSE(current_transformation_to_reference, this->reference_points.begin(), + this->reference_points.end(), this->reference_points.begin()); + output_all << *iter << " " << RMSE_within_frame << " " << RMSE_from_ref << '\n'; + ++num_samples_this_frame; + MSE_within_frame_this_frame += square(RMSE_within_frame); + MSE_from_ref_this_frame += square(RMSE_from_ref); + + max_RMSE_within_frame = std::max(max_RMSE_within_frame, RMSE_within_frame); + max_RMSE_from_ref = std::max(max_RMSE_from_ref, RMSE_from_ref); + } // end of loop over tracker samples + } + output_summary << "Total RMSE frame " << current_frame_num << " " + << std::sqrt(MSE_within_frame_this_frame / num_samples_this_frame) << " " + << std::sqrt(MSE_from_ref_this_frame / num_samples_this_frame) << '\n'; + MSE_within_frame_all_frames += MSE_within_frame_this_frame; + MSE_from_ref_all_frames += MSE_from_ref_this_frame; + num_samples_all_frames += num_samples_this_frame; + } // end of loop over frames + + output_summary << "\n\nTotal RMSE all frames " << std::sqrt(MSE_within_frame_all_frames / num_samples_all_frames) << " " + << std::sqrt(MSE_from_ref_all_frames / num_samples_all_frames) << '\n' + << "Maximum RMSE occuring at a certain time " << max_RMSE_within_frame << " " << max_RMSE_from_ref << '\n'; + + return Succeeded::yes; +} + +END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char * argv[]) -{ - bool move_to_reference=true; - bool set_move_to_reference=false; - bool set_frame_num_to_process=false; - int frame_num_to_process=-1; - while (argc>=2 && argv[1][1]=='-') - { - if (strcmp(argv[1], "--frame_num_to_process")==0) - { - set_frame_num_to_process=true; - frame_num_to_process=atoi(argv[2]); - argc-=2; argv+=2; - } - else - { - warning("Wrong option\n"); - exit(EXIT_FAILURE); - } +int +main(int argc, char* argv[]) { + bool move_to_reference = true; + bool set_move_to_reference = false; + bool set_frame_num_to_process = false; + int frame_num_to_process = -1; + while (argc >= 2 && argv[1][1] == '-') { + if (strcmp(argv[1], "--frame_num_to_process") == 0) { + set_frame_num_to_process = true; + frame_num_to_process = atoi(argv[2]); + argc -= 2; + argv += 2; + } else { + warning("Wrong option\n"); + exit(EXIT_FAILURE); } + } - if (argc!=2) { + if (argc != 2) { cerr << "Usage: " << argv[0] << " \\\n" - << "\t[--frame_num_to_process number]\\\n" - << "\tpar_file\n\n" - << "file *_all.log will contain RMSE for each sample of the motion tracker.\n" - << "file *_summary.log will contain global RMSE for frame and scan\n" - << "RMSE is reported first within frame, then w.r.t. reference position\n"; + << "\t[--frame_num_to_process number]\\\n" + << "\tpar_file\n\n" + << "file *_all.log will contain RMSE for each sample of the motion tracker.\n" + << "file *_summary.log will contain global RMSE for frame and scan\n" + << "RMSE is reported first within frame, then w.r.t. reference position\n"; exit(EXIT_FAILURE); } - ReportMovement application(argc==2 ? argv[1] : 0); + ReportMovement application(argc == 2 ? argv[1] : 0); if (set_move_to_reference) application.move_to_reference(move_to_reference); if (set_frame_num_to_process) application.set_frame_num_to_process(frame_num_to_process); - Succeeded success = - application.process_data(); + Succeeded success = application.process_data(); return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/motion_utilities/rigid_object_transform_image.cxx b/src/experimental/motion_utilities/rigid_object_transform_image.cxx index 857e1ba3bc..1d3dc9e68d 100644 --- a/src/experimental/motion_utilities/rigid_object_transform_image.cxx +++ b/src/experimental/motion_utilities/rigid_object_transform_image.cxx @@ -15,9 +15,9 @@ namespace stir { // for doxygen specified by 1 quaternion and 1 translation vector. Conventions for these are as for Polaris. - \see transform_3d_object(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const RigidObject3DTransformation& rigid_object_transformation) + \see transform_3d_object(DiscretisedDensity<3,float>& out_density, + const DiscretisedDensity<3,float>& in_density, + const RigidObject3DTransformation& rigid_object_transformation) \par Usage Run to get a usage message @@ -49,7 +49,6 @@ using std::endl; START_NAMESPACE_STIR - #if 0 class TF @@ -81,134 +80,109 @@ class TF END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - const char * const program_name = argv[0]; +int +main(int argc, char** argv) { + const char* const program_name = argv[0]; // skip program name --argc; ++argv; - shared_ptr > > - output_format_sptr = - OutputFileFormat >::default_sptr(); + shared_ptr>> output_format_sptr = + OutputFileFormat>::default_sptr(); int interpolation_order = 1; bool do_origin_shift = true; - while (argc>0 && argv[0][0]=='-') - { - if (strcmp(argv[0], "--output-format")==0) - { - if (argc<2) - { - cerr << "Option '--output-format' expects a (filename) argument\n"; - exit(EXIT_FAILURE); - } - KeyParser parser; - parser.add_start_key("output file format parameters"); - parser.add_parsing_key("output file format type", &output_format_sptr); - parser.add_stop_key("END"); - if (parser.parse(argv[1]) == false || is_null_ptr(output_format_sptr)) - { - cerr << "Error parsing output file format from " << argv[1]< 0 && argv[0][0] == '-') { + if (strcmp(argv[0], "--output-format") == 0) { + if (argc < 2) { + cerr << "Option '--output-format' expects a (filename) argument\n"; + exit(EXIT_FAILURE); + } + KeyParser parser; + parser.add_start_key("output file format parameters"); + parser.add_parsing_key("output file format type", &output_format_sptr); + parser.add_stop_key("END"); + if (parser.parse(argv[1]) == false || is_null_ptr(output_format_sptr)) { + cerr << "Error parsing output file format from " << argv[1] << endl; + exit(EXIT_FAILURE); + } + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--interpolation_order") == 0) { interpolation_order = atoi(argv[1]); - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "--no_origin_shift")==0) - { + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--no_origin_shift") == 0) { do_origin_shift = false; - argc-=1; argv+=1; + argc -= 1; + argv += 1; + } else { + cerr << "Unknown option '" << argv[0] << "'\n"; + exit(EXIT_FAILURE); } - else - { cerr << "Unknown option '" << argv[0] <<"'\n"; exit(EXIT_FAILURE); } } - if (argc != 3) - { - cerr << "Usage:\n" - << program_name - << "\n [--no_origin_shift] [--output-format parameter-filename ] [--interpolation_order 0|1]\\\n" - << "output_filename input_filename \"{{q0, qz, qy, qx},{ tz, ty, tx}}\"\n" - << "interpolation_order defaults to 1\n"; - exit(EXIT_FAILURE); - } - const string output_filename = argv[0]; - const string input_filename = argv[1]; - shared_ptr > in_density_sptr - (read_from_file >(input_filename)); - shared_ptr< DiscretisedDensity<3,float> > out_density_sptr - (in_density_sptr->get_empty_discretised_density()); + if (argc != 3) { + cerr << "Usage:\n" + << program_name << "\n [--no_origin_shift] [--output-format parameter-filename ] [--interpolation_order 0|1]\\\n" + << "output_filename input_filename \"{{q0, qz, qy, qx},{ tz, ty, tx}}\"\n" + << "interpolation_order defaults to 1\n"; + exit(EXIT_FAILURE); + } + const string output_filename = argv[0]; + const string input_filename = argv[1]; + shared_ptr> in_density_sptr(read_from_file>(input_filename)); + shared_ptr> out_density_sptr(in_density_sptr->get_empty_discretised_density()); RigidObject3DTransformation rigid_object_transformation; { std::istringstream s(argv[2]); s >> rigid_object_transformation; if (!s) - error("error parsing transformation"); + error("error parsing transformation"); } - if (do_origin_shift) - { - const float z_shift= - (in_density_sptr->get_min_index()+in_density_sptr->get_max_index())/2.F* - dynamic_cast const&>(*in_density_sptr).get_voxel_size().z(); - - RigidObject3DTransformation from_centre_to_out(Quaternion(1,0,0,0), - CartesianCoordinate3D(-z_shift,0,0)); - RigidObject3DTransformation from_in_to_centre(Quaternion(1,0,0,0), - CartesianCoordinate3D(z_shift,0,0)); - rigid_object_transformation = - compose(from_centre_to_out, - compose(rigid_object_transformation, from_in_to_centre)); - std::cout << "\nTransformation after shift: " << rigid_object_transformation; - } + if (do_origin_shift) { + const float z_shift = (in_density_sptr->get_min_index() + in_density_sptr->get_max_index()) / 2.F * + dynamic_cast const&>(*in_density_sptr).get_voxel_size().z(); + + RigidObject3DTransformation from_centre_to_out(Quaternion(1, 0, 0, 0), CartesianCoordinate3D(-z_shift, 0, 0)); + RigidObject3DTransformation from_in_to_centre(Quaternion(1, 0, 0, 0), CartesianCoordinate3D(z_shift, 0, 0)); + rigid_object_transformation = compose(from_centre_to_out, compose(rigid_object_transformation, from_in_to_centre)); + std::cout << "\nTransformation after shift: " << rigid_object_transformation; + } CPUTimer timer; timer.start(); Succeeded success = Succeeded::yes; - switch (interpolation_order) - { - case 0: - std::cout << "Using nearest neighbour interpolation\n"; - success = - transform_3d_object_pull_interpolation(*out_density_sptr, - *in_density_sptr, - rigid_object_transformation.inverse(), - PullNearestNeighbourInterpolator(), - /*do_jacobian=*/false ); // jacobian is 1 anyway - break; - case 1: - std::cout << "Using linear interpolation\n"; - success = - transform_3d_object_pull_interpolation(*out_density_sptr, - *in_density_sptr, - rigid_object_transformation.inverse(), - PullLinearInterpolator(), - /*do_jacobian=*/false ); // jacobian is 1 anyway - break; - default: - warning("Currently only interpolation_order 0 or 1"); - exit(EXIT_FAILURE); - } - + switch (interpolation_order) { + case 0: + std::cout << "Using nearest neighbour interpolation\n"; + success = transform_3d_object_pull_interpolation(*out_density_sptr, *in_density_sptr, rigid_object_transformation.inverse(), + PullNearestNeighbourInterpolator(), + /*do_jacobian=*/false); // jacobian is 1 anyway + break; + case 1: + std::cout << "Using linear interpolation\n"; + success = transform_3d_object_pull_interpolation(*out_density_sptr, *in_density_sptr, rigid_object_transformation.inverse(), + PullLinearInterpolator(), + /*do_jacobian=*/false); // jacobian is 1 anyway + break; + default: + warning("Currently only interpolation_order 0 or 1"); + exit(EXIT_FAILURE); + } - if (success == Succeeded::no) - { - warning("Error transforming data\n"); - exit(EXIT_FAILURE); - } + if (success == Succeeded::no) { + warning("Error transforming data\n"); + exit(EXIT_FAILURE); + } timer.stop(); cerr << "CPU time " << timer.value() << endl; // write it to file - const Succeeded succes = - output_format_sptr->write_to_file(output_filename, *out_density_sptr); + const Succeeded succes = output_format_sptr->write_to_file(output_filename, *out_density_sptr); return succes == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/motion_utilities/rigid_object_transform_projdata.cxx b/src/experimental/motion_utilities/rigid_object_transform_projdata.cxx index 8953741caf..95964f967b 100644 --- a/src/experimental/motion_utilities/rigid_object_transform_projdata.cxx +++ b/src/experimental/motion_utilities/rigid_object_transform_projdata.cxx @@ -13,8 +13,8 @@ namespace stir { // for doxygen as for Polaris. \see transform_3d_object(ProjData& out_proj_data, - const ProjData& in_proj_data, - const RigidObject3DTransformation& rigid_object_transformation) + const ProjData& in_proj_data, + const RigidObject3DTransformation& rigid_object_transformation) \par Usage Run to get a usage message @@ -22,7 +22,7 @@ namespace stir { // for doxygen \author Kris Thielemans */ -} // END_NAMESPACE_STIR +} // namespace stir #include "stir/ProjDataInterfile.h" #include "stir/Succeeded.h" @@ -35,99 +35,80 @@ namespace stir { // for doxygen USING_NAMESPACE_STIR - -int main(int argc, char **argv) -{ - const char * const program_name = argv[0]; +int +main(int argc, char** argv) { + const char* const program_name = argv[0]; // skip program name --argc; ++argv; bool do_origin_shift = true; - while (argc>0 && argv[0][0]=='-') - { - if (strcmp(argv[0], "--no_origin_shift")==0) - { + while (argc > 0 && argv[0][0] == '-') { + if (strcmp(argv[0], "--no_origin_shift") == 0) { do_origin_shift = false; - argc-=1; argv+=1; + argc -= 1; + argv += 1; + } else { + std::cerr << "Unknown option '" << argv[0] << "'\n"; + exit(EXIT_FAILURE); } - else - { std::cerr << "Unknown option '" << argv[0] <<"'\n"; exit(EXIT_FAILURE); } } - if (argc < 3 || argc > 6) - { - std::cerr << "Usage:\n" - << program_name - << "\n\t [--no_origin_shift]\\" - << "\n\t output_filename input_projdata_name \\" - << "\n\t \"{{q0, qz, qy, qx},{ tz, ty, tx}}\"\\" - <<"\n\t [max_in_segment_num_to_process [template_projdata_name [max_out_segment_num_to_process ]]]\n" - << "max_in_segment_num_to_process defaults to all segments\n" - << "max_out_segment_num_to_process defaults to all segments in template\n"; - exit(EXIT_FAILURE); - } - const std::string output_filename = argv[0]; - shared_ptr in_projdata_sptr = ProjData::read_from_file(argv[1]); - //const float angle_around_x = atof(argv[3]) *_PI/180; + if (argc < 3 || argc > 6) { + std::cerr << "Usage:\n" + << program_name << "\n\t [--no_origin_shift]\\" + << "\n\t output_filename input_projdata_name \\" + << "\n\t \"{{q0, qz, qy, qx},{ tz, ty, tx}}\"\\" + << "\n\t [max_in_segment_num_to_process [template_projdata_name [max_out_segment_num_to_process ]]]\n" + << "max_in_segment_num_to_process defaults to all segments\n" + << "max_out_segment_num_to_process defaults to all segments in template\n"; + exit(EXIT_FAILURE); + } + const std::string output_filename = argv[0]; + shared_ptr in_projdata_sptr = ProjData::read_from_file(argv[1]); + // const float angle_around_x = atof(argv[3]) *_PI/180; RigidObject3DTransformation rigid_object_transformation; { std::istringstream s(argv[2]); s >> rigid_object_transformation; if (!s) - error("error parsing transformation"); + error("error parsing transformation"); } - const int max_in_segment_num_to_process = argc <4 ? in_projdata_sptr->get_max_segment_num() : atoi(argv[3]); + const int max_in_segment_num_to_process = argc < 4 ? in_projdata_sptr->get_max_segment_num() : atoi(argv[3]); shared_ptr proj_data_info_ptr; // template for output - int max_out_segment_num_to_process=-1; - if (argc>=5) - { - shared_ptr template_proj_data_sptr = - ProjData::read_from_file(argv[4]); - proj_data_info_ptr = - template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); - if (argc>=6) - max_out_segment_num_to_process = atoi(argv[5]); - } - else - { - proj_data_info_ptr = - in_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone(); - } - if (max_out_segment_num_to_process<0) - max_out_segment_num_to_process = - proj_data_info_ptr->get_max_segment_num(); + int max_out_segment_num_to_process = -1; + if (argc >= 5) { + shared_ptr template_proj_data_sptr = ProjData::read_from_file(argv[4]); + proj_data_info_ptr = template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); + if (argc >= 6) + max_out_segment_num_to_process = atoi(argv[5]); + } else { + proj_data_info_ptr = in_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone(); + } + if (max_out_segment_num_to_process < 0) + max_out_segment_num_to_process = proj_data_info_ptr->get_max_segment_num(); else - proj_data_info_ptr->reduce_segment_range(-max_out_segment_num_to_process,max_out_segment_num_to_process); - - ProjDataInterfile out_projdata(in_projdata_sptr->get_exam_info_sptr(), proj_data_info_ptr, output_filename, std::ios::out); - - if (do_origin_shift) - { - const float in_z_shift = - -in_projdata_sptr->get_proj_data_info_sptr()->get_m(Bin(0,0,0,0)); - const float out_z_shift = - -proj_data_info_ptr->get_m(Bin(0,0,0,0)); - - RigidObject3DTransformation from_centre_to_out(Quaternion(1,0,0,0), - CartesianCoordinate3D(-out_z_shift,0,0)); - RigidObject3DTransformation from_in_to_centre(Quaternion(1,0,0,0), - CartesianCoordinate3D(in_z_shift,0,0)); - rigid_object_transformation = - compose(from_centre_to_out, - compose(rigid_object_transformation, from_in_to_centre)); - std::cout << "\nTransformation after shift: " << rigid_object_transformation; - } + proj_data_info_ptr->reduce_segment_range(-max_out_segment_num_to_process, max_out_segment_num_to_process); + + ProjDataInterfile out_projdata(in_projdata_sptr->get_exam_info_sptr(), proj_data_info_ptr, output_filename, std::ios::out); + + if (do_origin_shift) { + const float in_z_shift = -in_projdata_sptr->get_proj_data_info_sptr()->get_m(Bin(0, 0, 0, 0)); + const float out_z_shift = -proj_data_info_ptr->get_m(Bin(0, 0, 0, 0)); + + RigidObject3DTransformation from_centre_to_out(Quaternion(1, 0, 0, 0), + CartesianCoordinate3D(-out_z_shift, 0, 0)); + RigidObject3DTransformation from_in_to_centre(Quaternion(1, 0, 0, 0), CartesianCoordinate3D(in_z_shift, 0, 0)); + rigid_object_transformation = compose(from_centre_to_out, compose(rigid_object_transformation, from_in_to_centre)); + std::cout << "\nTransformation after shift: " << rigid_object_transformation; + } CPUTimer timer; timer.start(); - Succeeded succes = - transform_3d_object(out_projdata, *in_projdata_sptr, - rigid_object_transformation, - -max_in_segment_num_to_process, - max_in_segment_num_to_process); + Succeeded succes = transform_3d_object(out_projdata, *in_projdata_sptr, rigid_object_transformation, + -max_in_segment_num_to_process, max_in_segment_num_to_process); timer.stop(); std::cerr << "CPU time " << timer.value() << '\n'; return succes == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; diff --git a/src/experimental/motion_utilities/sync_polaris.cxx b/src/experimental/motion_utilities/sync_polaris.cxx index d9f7938853..dea374ea3c 100644 --- a/src/experimental/motion_utilities/sync_polaris.cxx +++ b/src/experimental/motion_utilities/sync_polaris.cxx @@ -11,13 +11,13 @@ \author Kris Thielemans - \see RigidObject3DMotionFromPolaris + \see RigidObject3DMotionFromPolaris \warning This will change dramatically when using new Polaris acquisition software. \par Usage: \verbatim sync_polaris somefile.mt listmode_filename_prefix \endverbatim - where the list mode data is specified as for \c lm_to_projdata (i.e. without + where the list mode data is specified as for \c lm_to_projdata (i.e. without _1.lm for ECAT list mode data. } */ @@ -30,61 +30,56 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit(const char * const prog_name) -{ - std::cerr << "Usage:\n" << prog_name << "\\\n" - << "\t[--max_time_offset_deviation value ] \\\n" - << "\t[--mask-for-tags value ] \\\n" - << "\tpolarisfile.mt listmode_filename_prefix\n" - << "\twhere the list mode data is specified as for lm_to_projdata\n" - << "\t(i.e. without _1.lm for ECAT list mode data.\n" - << "\tMask defaults to 0xfffffff, i.e. use all channels.\n" - << "\tNote: use decimal specification for mask\n"; +static void +print_usage_and_exit(const char* const prog_name) { + std::cerr << "Usage:\n" + << prog_name << "\\\n" + << "\t[--max_time_offset_deviation value ] \\\n" + << "\t[--mask-for-tags value ] \\\n" + << "\tpolarisfile.mt listmode_filename_prefix\n" + << "\twhere the list mode data is specified as for lm_to_projdata\n" + << "\t(i.e. without _1.lm for ECAT list mode data.\n" + << "\tMask defaults to 0xfffffff, i.e. use all channels.\n" + << "\tNote: use decimal specification for mask\n"; exit(EXIT_FAILURE); } -int main(int argc, char * argv[]) -{ - const char * const prog_name = argv[0]; +int +main(int argc, char* argv[]) { + const char* const prog_name = argv[0]; unsigned int mask_for_tags = 0xfffffff; const double initial_max_time_offset_deviation = -10E37; double max_time_offset_deviation = initial_max_time_offset_deviation; - while (argc>2 && argv[1][0] == '-') - { - if (strcmp(argv[1], "--max_time_offset_deviation")==0) - { - max_time_offset_deviation = atof(argv[2]); - argc-=2; argv+=2; - } - else if (strcmp(argv[1], "--mask-for-tags")==0) - { - mask_for_tags = atoi(argv[2]); - argc-=2; argv+=2; - } - else - { - print_usage_and_exit(prog_name); - } + while (argc > 2 && argv[1][0] == '-') { + if (strcmp(argv[1], "--max_time_offset_deviation") == 0) { + max_time_offset_deviation = atof(argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--mask-for-tags") == 0) { + mask_for_tags = atoi(argv[2]); + argc -= 2; + argv += 2; + } else { + print_usage_and_exit(prog_name); } + } - - if (argc!=3) { + if (argc != 3) { print_usage_and_exit(prog_name); } - const char * const polaris_filename = argv[1]; - const char * const list_mode_filename = argv[2]; + const char* const polaris_filename = argv[1]; + const char* const list_mode_filename = argv[2]; RigidObject3DMotionFromPolaris polaris_motion; if (polaris_motion.set_mt_file(polaris_filename) == Succeeded::no) return EXIT_FAILURE; - if (polaris_motion.set_list_mode_data_file(list_mode_filename) == Succeeded::no) return EXIT_FAILURE; - if (max_time_offset_deviation!=initial_max_time_offset_deviation) + if (max_time_offset_deviation != initial_max_time_offset_deviation) polaris_motion.set_max_time_offset_deviation(max_time_offset_deviation); polaris_motion.set_mask_for_tags(mask_for_tags); diff --git a/src/experimental/recon_buildblock/BinNormalisationFromML2D.cxx b/src/experimental/recon_buildblock/BinNormalisationFromML2D.cxx index fdface0f33..9d27e91845 100644 --- a/src/experimental/recon_buildblock/BinNormalisationFromML2D.cxx +++ b/src/experimental/recon_buildblock/BinNormalisationFromML2D.cxx @@ -24,7 +24,6 @@ \author Kris Thielemans */ - #include "stir_experimental/recon_buildblock/BinNormalisationFromML2D.h" #include "stir/RelatedViewgrams.h" #include "stir/ViewSegmentNumbers.h" @@ -38,25 +37,20 @@ START_NAMESPACE_STIR -const char * const -BinNormalisationFromML2D::registered_name = "From ML2D"; - +const char* const BinNormalisationFromML2D::registered_name = "From ML2D"; -void -BinNormalisationFromML2D::set_defaults() -{ - normalisation_filename_prefix=""; +void +BinNormalisationFromML2D::set_defaults() { + normalisation_filename_prefix = ""; do_block = true; do_geo = true; do_eff = true; - eff_iter_num=0; - iter_num=0; + eff_iter_num = 0; + iter_num = 0; } -void -BinNormalisationFromML2D:: -initialise_keymap() -{ +void +BinNormalisationFromML2D::initialise_keymap() { parser.add_start_key("Bin Normalisation From ML2D"); parser.add_key("normalisation_filename_prefix", &normalisation_filename_prefix); parser.add_key("use block factors", &do_block); @@ -67,139 +61,103 @@ initialise_keymap() parser.add_stop_key("End Bin Normalisation From ML2D"); } -bool -BinNormalisationFromML2D:: -post_processing() -{ +bool +BinNormalisationFromML2D::post_processing() { return false; } -BinNormalisationFromML2D:: -BinNormalisationFromML2D() -{ - set_defaults(); -} +BinNormalisationFromML2D::BinNormalisationFromML2D() { set_defaults(); } -Succeeded -BinNormalisationFromML2D:: -set_up(const shared_ptr& proj_data_info_ptr) -{ - norm_factors_ptr= new ProjDataInMemory(proj_data_info_ptr, false /* i.e. do not initialise */); - const int num_detectors = - proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); - const int num_crystals_per_block = - proj_data_info_ptr->get_scanner_ptr()-> - get_num_transaxial_crystals_per_block(); - const int num_blocks = - proj_data_info_ptr->get_scanner_ptr()-> - get_num_transaxial_blocks(); +Succeeded +BinNormalisationFromML2D::set_up(const shared_ptr& proj_data_info_ptr) { + norm_factors_ptr = new ProjDataInMemory(proj_data_info_ptr, false /* i.e. do not initialise */); + const int num_detectors = proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_crystals_per_block = proj_data_info_ptr->get_scanner_ptr()->get_num_transaxial_crystals_per_block(); + const int num_blocks = proj_data_info_ptr->get_scanner_ptr()->get_num_transaxial_blocks(); const int segment_num = 0; - Array<1,float> efficiencies(num_detectors); - assert(num_crystals_per_block%2 == 0); - GeoData norm_geo_data(IndexRange2D(num_crystals_per_block/2, num_detectors)); + Array<1, float> efficiencies(num_detectors); + assert(num_crystals_per_block % 2 == 0); + GeoData norm_geo_data(IndexRange2D(num_crystals_per_block / 2, num_detectors)); BlockData norm_block_data(IndexRange2D(num_blocks, num_blocks)); DetPairData det_pair_data; for (int ax_pos_num = proj_data_info_ptr->get_min_axial_pos_num(segment_num); - ax_pos_num <= proj_data_info_ptr->get_max_axial_pos_num(segment_num); - ++ax_pos_num) - { + ax_pos_num <= proj_data_info_ptr->get_max_axial_pos_num(segment_num); ++ax_pos_num) { + + // efficiencies + if (do_eff) { + char* normalisation_filename = new char[normalisation_filename_prefix.size() + 30]; + sprintf(normalisation_filename, "%s_%s_%d_%d_%d.out", normalisation_filename_prefix.c_str(), "eff", ax_pos_num, iter_num, + eff_iter_num); + ifstream in(normalisation_filename); + in >> efficiencies; + if (!in) { + warning("BinNormalisationFromML2D: Error reading %s\n", normalisation_filename); + delete[] normalisation_filename; + return Succeeded::no; + } - // efficiencies + delete[] normalisation_filename; + } + // geo norm + if (do_geo) { + { + char* normalisation_filename = new char[normalisation_filename_prefix.size() + 30]; + sprintf(normalisation_filename, "%s_%s_%d_%d.out", normalisation_filename_prefix.c_str(), "geo", ax_pos_num, iter_num); + ifstream in(normalisation_filename); + in >> norm_geo_data; + if (!in) { + warning("BinNormalisationFromML2D: Error reading %s\n", normalisation_filename); + delete[] normalisation_filename; + return Succeeded::no; + } + delete[] normalisation_filename; + } + } + // block norm + if (do_block) { + { + char* normalisation_filename = new char[normalisation_filename_prefix.size() + 30]; + sprintf(normalisation_filename, "%s_%s_%d_%d.out", normalisation_filename_prefix.c_str(), "block", ax_pos_num, iter_num); + ifstream in(normalisation_filename); + in >> norm_block_data; + if (!in) { + warning("BinNormalisationFromML2D: Error reading %s\n", normalisation_filename); + delete[] normalisation_filename; + return Succeeded::no; + } + delete[] normalisation_filename; + } + } + { + make_det_pair_data(det_pair_data, *proj_data_info_ptr, segment_num, ax_pos_num); + det_pair_data.fill(1); if (do_eff) - { - char *normalisation_filename = new char[normalisation_filename_prefix.size() + 30]; - sprintf(normalisation_filename, "%s_%s_%d_%d_%d.out", - normalisation_filename_prefix.c_str(), "eff", ax_pos_num, iter_num, eff_iter_num); - ifstream in(normalisation_filename); - in >> efficiencies; - if (!in) - { - warning("BinNormalisationFromML2D: Error reading %s\n", normalisation_filename); - delete[] normalisation_filename; - return Succeeded::no; - } - - delete[] normalisation_filename; - } - // geo norm + apply_efficiencies(det_pair_data, efficiencies, true /*apply_or_undo*/); if (do_geo) - { - { - char *normalisation_filename = new char[normalisation_filename_prefix.size() + 30]; - sprintf(normalisation_filename, "%s_%s_%d_%d.out", - normalisation_filename_prefix.c_str(), "geo", ax_pos_num, iter_num); - ifstream in(normalisation_filename); - in >> norm_geo_data; - if (!in) - { - warning("BinNormalisationFromML2D: Error reading %s\n", normalisation_filename); - delete[] normalisation_filename; - return Succeeded::no; - } - delete[] normalisation_filename; - } - } - // block norm + apply_geo_norm(det_pair_data, norm_geo_data, true /*apply_or_undo*/); if (do_block) - { - { - char *normalisation_filename = new char[normalisation_filename_prefix.size() + 30]; - sprintf(normalisation_filename, "%s_%s_%d_%d.out", - normalisation_filename_prefix.c_str(), "block", ax_pos_num, iter_num); - ifstream in(normalisation_filename); - in >> norm_block_data; - if (!in) - { - warning("BinNormalisationFromML2D: Error reading %s\n", normalisation_filename); - delete[] normalisation_filename; - return Succeeded::no; - } - delete[] normalisation_filename; - } - } - { - make_det_pair_data(det_pair_data, *proj_data_info_ptr, segment_num, ax_pos_num); - det_pair_data.fill(1); - if (do_eff) - apply_efficiencies(det_pair_data, efficiencies, true/*apply_or_undo*/); - if (do_geo) - apply_geo_norm(det_pair_data, norm_geo_data, true/*apply_or_undo*/); - if (do_block) - apply_block_norm(det_pair_data, norm_block_data, true/*apply_or_undo*/); - set_det_pair_data(*norm_factors_ptr, - det_pair_data, - segment_num, - ax_pos_num); - } + apply_block_norm(det_pair_data, norm_block_data, true /*apply_or_undo*/); + set_det_pair_data(*norm_factors_ptr, det_pair_data, segment_num, ax_pos_num); } - - return Succeeded::yes; -} + } + return Succeeded::yes; +} -void -BinNormalisationFromML2D::apply(RelatedViewgrams& viewgrams) const - { - const ViewSegmentNumbers vs_num=viewgrams.get_basic_view_segment_num(); - const DataSymmetriesForViewSegmentNumbers * symmetries_ptr = - viewgrams.get_symmetries_ptr(); - viewgrams *= - norm_factors_ptr->get_related_viewgrams(vs_num,symmetries_ptr->clone()); - } +void +BinNormalisationFromML2D::apply(RelatedViewgrams& viewgrams) const { + const ViewSegmentNumbers vs_num = viewgrams.get_basic_view_segment_num(); + const DataSymmetriesForViewSegmentNumbers* symmetries_ptr = viewgrams.get_symmetries_ptr(); + viewgrams *= norm_factors_ptr->get_related_viewgrams(vs_num, symmetries_ptr->clone()); +} -void -BinNormalisationFromML2D:: -undo(RelatedViewgrams& viewgrams) const - { - const ViewSegmentNumbers vs_num=viewgrams.get_basic_view_segment_num(); - const DataSymmetriesForViewSegmentNumbers * symmetries_ptr = - viewgrams.get_symmetries_ptr(); - viewgrams /= - norm_factors_ptr->get_related_viewgrams(vs_num,symmetries_ptr->clone()); - } +void +BinNormalisationFromML2D::undo(RelatedViewgrams& viewgrams) const { + const ViewSegmentNumbers vs_num = viewgrams.get_basic_view_segment_num(); + const DataSymmetriesForViewSegmentNumbers* symmetries_ptr = viewgrams.get_symmetries_ptr(); + viewgrams /= norm_factors_ptr->get_related_viewgrams(vs_num, symmetries_ptr->clone()); +} - END_NAMESPACE_STIR - diff --git a/src/experimental/recon_buildblock/BinNormalisationSinogramRescaling.cxx b/src/experimental/recon_buildblock/BinNormalisationSinogramRescaling.cxx index 8b9794d354..0b90119177 100644 --- a/src/experimental/recon_buildblock/BinNormalisationSinogramRescaling.cxx +++ b/src/experimental/recon_buildblock/BinNormalisationSinogramRescaling.cxx @@ -3,7 +3,7 @@ /*! \file \ingroup recon_buildblock - \ingroup + \ingroup \brief Implementation for class BinNormalisationSinogramRescaling @@ -14,7 +14,6 @@ See STIR/LICENSE.txt for details */ - #include "stir_experimental/recon_buildblock/BinNormalisationSinogramRescaling.h" #include "stir/shared_ptr.h" #include "stir/RelatedViewgrams.h" @@ -32,148 +31,110 @@ using std::ifstream; START_NAMESPACE_STIR +const char* const BinNormalisationSinogramRescaling::registered_name = "Sinogram Rescaling"; -const char * const -BinNormalisationSinogramRescaling::registered_name = "Sinogram Rescaling"; - -void -BinNormalisationSinogramRescaling::set_defaults() -{ +void +BinNormalisationSinogramRescaling::set_defaults() { sinogram_rescaling_factors_filename = ""; } -void -BinNormalisationSinogramRescaling:: -initialise_keymap() -{ +void +BinNormalisationSinogramRescaling::initialise_keymap() { parser.add_start_key("Bin Normalisation Sinogram Rescaling"); parser.add_key("sinogram_rescaling_factors_filename", &sinogram_rescaling_factors_filename); parser.add_stop_key("End Bin Normalisation Sinogram Rescaling"); } -bool -BinNormalisationSinogramRescaling:: -post_processing() -{ - if (sinogram_rescaling_factors_filename.size()==0) - { - warning("You have to specify sinogram rescaling filename\n"); - return true; - } +bool +BinNormalisationSinogramRescaling::post_processing() { + if (sinogram_rescaling_factors_filename.size() == 0) { + warning("You have to specify sinogram rescaling filename\n"); + return true; + } return false; } +BinNormalisationSinogramRescaling::BinNormalisationSinogramRescaling() { set_defaults(); } -BinNormalisationSinogramRescaling:: -BinNormalisationSinogramRescaling() -{ - set_defaults(); -} - -BinNormalisationSinogramRescaling:: -BinNormalisationSinogramRescaling(const string& filename) - : sinogram_rescaling_factors_filename(filename) -{ -} +BinNormalisationSinogramRescaling::BinNormalisationSinogramRescaling(const string& filename) + : sinogram_rescaling_factors_filename(filename) {} Succeeded -BinNormalisationSinogramRescaling:: -set_up(const shared_ptr& proj_data_info_sptr_v) -{ - proj_data_info_sptr = proj_data_info_sptr_v; - +BinNormalisationSinogramRescaling::set_up(const shared_ptr& proj_data_info_sptr_v) { + proj_data_info_sptr = proj_data_info_sptr_v; + const int min_segment_num = proj_data_info_sptr->get_min_segment_num(); const int max_segment_num = proj_data_info_sptr->get_max_segment_num(); // empty data. get out quickly! if (max_segment_num < min_segment_num) return Succeeded::yes; - + ifstream input(sinogram_rescaling_factors_filename.c_str()); input >> rescaling_factors; - if (!input) - { - warning("Error reading rescaling factors from %s\n", - sinogram_rescaling_factors_filename.c_str()); - return Succeeded::no; - } + if (!input) { + warning("Error reading rescaling factors from %s\n", sinogram_rescaling_factors_filename.c_str()); + return Succeeded::no; + } rescaling_factors.set_offset(min_segment_num); - bool something_wrong = - rescaling_factors.get_max_index() != max_segment_num; - - for (int segment_num = min_segment_num; !something_wrong && segment_num<=max_segment_num; ++segment_num) - { - const int min_axial_pos_num = - proj_data_info_sptr->get_min_axial_pos_num(segment_num); - const int max_axial_pos_num = - proj_data_info_sptr->get_max_axial_pos_num(segment_num); - rescaling_factors[segment_num].set_offset(min_axial_pos_num); - something_wrong = - something_wrong || - rescaling_factors[segment_num].get_max_index() != max_axial_pos_num; - for (int axial_pos_num = min_axial_pos_num; !something_wrong && axial_pos_num<=max_axial_pos_num; ++axial_pos_num) - { - rescaling_factors[segment_num][axial_pos_num].set_offset(proj_data_info_sptr->get_min_view_num()); - something_wrong = - something_wrong || - rescaling_factors[segment_num][axial_pos_num].get_max_index() != proj_data_info_sptr->get_max_view_num(); - } - } - if (something_wrong) - { - warning("rescaling factors (%s) have wrong sizes for this projdata\n", - sinogram_rescaling_factors_filename.c_str()); - return Succeeded::no; + bool something_wrong = rescaling_factors.get_max_index() != max_segment_num; + + for (int segment_num = min_segment_num; !something_wrong && segment_num <= max_segment_num; ++segment_num) { + const int min_axial_pos_num = proj_data_info_sptr->get_min_axial_pos_num(segment_num); + const int max_axial_pos_num = proj_data_info_sptr->get_max_axial_pos_num(segment_num); + rescaling_factors[segment_num].set_offset(min_axial_pos_num); + something_wrong = something_wrong || rescaling_factors[segment_num].get_max_index() != max_axial_pos_num; + for (int axial_pos_num = min_axial_pos_num; !something_wrong && axial_pos_num <= max_axial_pos_num; ++axial_pos_num) { + rescaling_factors[segment_num][axial_pos_num].set_offset(proj_data_info_sptr->get_min_view_num()); + something_wrong = something_wrong || + rescaling_factors[segment_num][axial_pos_num].get_max_index() != proj_data_info_sptr->get_max_view_num(); } + } + if (something_wrong) { + warning("rescaling factors (%s) have wrong sizes for this projdata\n", sinogram_rescaling_factors_filename.c_str()); + return Succeeded::no; + } return Succeeded::yes; } -float -BinNormalisationSinogramRescaling:: -get_bin_efficiency(const Bin& bin, const double /*start_time*/, const double /*end_time*/) const -{ +float +BinNormalisationSinogramRescaling::get_bin_efficiency(const Bin& bin, const double /*start_time*/, + const double /*end_time*/) const { return rescaling_factors[bin.segment_num()][bin.axial_pos_num()][bin.view_num()]; - } - -void -BinNormalisationSinogramRescaling:: -apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ - for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) - { - - Bin bin(iter->get_segment_num(),iter->get_view_num(), 0, 0); - for (bin.axial_pos_num()= iter->get_min_axial_pos_num(); bin.axial_pos_num()<=iter->get_max_axial_pos_num(); ++bin.axial_pos_num()) - for (bin.tangential_pos_num()= iter->get_min_tangential_pos_num(); bin.tangential_pos_num()<=iter->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] *= - get_bin_efficiency(bin,start_time, end_time); +void +BinNormalisationSinogramRescaling::apply(RelatedViewgrams& viewgrams, const double start_time, + const double end_time) const { + for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + + Bin bin(iter->get_segment_num(), iter->get_view_num(), 0, 0); + for (bin.axial_pos_num() = iter->get_min_axial_pos_num(); bin.axial_pos_num() <= iter->get_max_axial_pos_num(); + ++bin.axial_pos_num()) + for (bin.tangential_pos_num() = iter->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= iter->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] *= get_bin_efficiency(bin, start_time, end_time); } - } -void -BinNormalisationSinogramRescaling:: -undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +void +BinNormalisationSinogramRescaling::undo(RelatedViewgrams& viewgrams, const double start_time, + const double end_time) const { for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { - Bin bin(iter->get_segment_num(),iter->get_view_num(), 0,0); - for (bin.axial_pos_num()= iter->get_min_axial_pos_num(); bin.axial_pos_num()<=iter->get_max_axial_pos_num(); ++bin.axial_pos_num()) - for (bin.tangential_pos_num()= iter->get_min_tangential_pos_num(); bin.tangential_pos_num()<=iter->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] /= - std::max(1.E-20F,get_bin_efficiency(bin, start_time, end_time)); - + Bin bin(iter->get_segment_num(), iter->get_view_num(), 0, 0); + for (bin.axial_pos_num() = iter->get_min_axial_pos_num(); bin.axial_pos_num() <= iter->get_max_axial_pos_num(); + ++bin.axial_pos_num()) + for (bin.tangential_pos_num() = iter->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= iter->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] /= + std::max(1.E-20F, get_bin_efficiency(bin, start_time, end_time)); } - } - END_NAMESPACE_STIR - diff --git a/src/experimental/recon_buildblock/BinNormalisationUsingProfile.cxx b/src/experimental/recon_buildblock/BinNormalisationUsingProfile.cxx index 9d0e64057e..44faec60e9 100644 --- a/src/experimental/recon_buildblock/BinNormalisationUsingProfile.cxx +++ b/src/experimental/recon_buildblock/BinNormalisationUsingProfile.cxx @@ -13,33 +13,28 @@ See STIR/LICENSE.txt for details */ - #include "stir_experimental/recon_buildblock/BinNormalisationUsingProfile.h" #include "stir/RelatedViewgrams.h" #include "stir/stream.h" START_NAMESPACE_STIR -const char * const - BinNormalisationUsingProfile:: - registered_name = "Using Profile"; +const char* const BinNormalisationUsingProfile::registered_name = "Using Profile"; -void BinNormalisationUsingProfile::set_defaults() -{ +void +BinNormalisationUsingProfile::set_defaults() { profile_filename = ""; } -void BinNormalisationUsingProfile::initialise_keymap() -{ +void +BinNormalisationUsingProfile::initialise_keymap() { parser.add_start_key("Bin Normalisation Using Profile"); parser.add_key("normalisation_profile_filename", &profile_filename); parser.add_stop_key("End Bin Normalisation Using Profile"); } -bool -BinNormalisationUsingProfile:: -post_processing() -{ +bool +BinNormalisationUsingProfile::post_processing() { #if 0 profile = Array<1,float>(-114,113); ifstream profile_data(profile_filename.c_str()); @@ -48,59 +43,38 @@ post_processing() #else ifstream profile_data(profile_filename.c_str()); profile_data >> profile; - profile.set_offset(-(profile.get_length()/2)); + profile.set_offset(-(profile.get_length() / 2)); #endif - if (!profile_data) - { - warning("Error reading profile %s\n", profile_filename.c_str()); - return true; - } + if (!profile_data) { + warning("Error reading profile %s\n", profile_filename.c_str()); + return true; + } return false; } +BinNormalisationUsingProfile::BinNormalisationUsingProfile() { set_defaults(); } -BinNormalisationUsingProfile:: -BinNormalisationUsingProfile() -{ - set_defaults(); -} - -BinNormalisationUsingProfile:: -BinNormalisationUsingProfile(const string& filename) - : profile_filename(filename) -{ - if (post_processing()==true) +BinNormalisationUsingProfile::BinNormalisationUsingProfile(const string& filename) : profile_filename(filename) { + if (post_processing() == true) error("Exiting\n"); } -void -BinNormalisationUsingProfile:: -apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ - RelatedViewgrams::iterator viewgrams_iter = - viewgrams.begin(); - for (; - viewgrams_iter != viewgrams.end(); - ++viewgrams_iter) - { - for (int ax_pos_num=viewgrams_iter->get_min_index(); - ax_pos_num<=viewgrams_iter->get_max_index(); - ++ax_pos_num) - { - for (int i=std::max(profile.get_min_index(),viewgrams.get_min_tangential_pos_num()); - i <= std::min(profile.get_max_index(),viewgrams.get_max_tangential_pos_num()); - ++i) - (*viewgrams_iter)[ax_pos_num][i] *= profile[i]; - - // (*viewgrams_iter)[ax_pos_num] *= profile; - } +void +BinNormalisationUsingProfile::apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const { + RelatedViewgrams::iterator viewgrams_iter = viewgrams.begin(); + for (; viewgrams_iter != viewgrams.end(); ++viewgrams_iter) { + for (int ax_pos_num = viewgrams_iter->get_min_index(); ax_pos_num <= viewgrams_iter->get_max_index(); ++ax_pos_num) { + for (int i = std::max(profile.get_min_index(), viewgrams.get_min_tangential_pos_num()); + i <= std::min(profile.get_max_index(), viewgrams.get_max_tangential_pos_num()); ++i) + (*viewgrams_iter)[ax_pos_num][i] *= profile[i]; + + // (*viewgrams_iter)[ax_pos_num] *= profile; } + } } void -BinNormalisationUsingProfile:: -undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +BinNormalisationUsingProfile::undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const { /* const int old_min = profile.get_min_index(); const int old_max = profile.get_max_index(); @@ -115,24 +89,14 @@ undo(RelatedViewgrams& viewgrams,const double start_time, const double en profile[i] = 1.F; */ - RelatedViewgrams::iterator viewgrams_iter = - viewgrams.begin(); - for (; - viewgrams_iter != viewgrams.end(); - ++viewgrams_iter) - { - for (int ax_pos_num=viewgrams_iter->get_min_index(); - ax_pos_num<=viewgrams_iter->get_max_index(); - ++ax_pos_num) - { - for (int i=std::max(profile.get_min_index(),viewgrams.get_min_tangential_pos_num()); - i <= std::min(profile.get_max_index(),viewgrams.get_max_tangential_pos_num()); - ++i) - (*viewgrams_iter)[ax_pos_num][i] /= profile[i]; - } + RelatedViewgrams::iterator viewgrams_iter = viewgrams.begin(); + for (; viewgrams_iter != viewgrams.end(); ++viewgrams_iter) { + for (int ax_pos_num = viewgrams_iter->get_min_index(); ax_pos_num <= viewgrams_iter->get_max_index(); ++ax_pos_num) { + for (int i = std::max(profile.get_min_index(), viewgrams.get_min_tangential_pos_num()); + i <= std::min(profile.get_max_index(), viewgrams.get_max_tangential_pos_num()); ++i) + (*viewgrams_iter)[ax_pos_num][i] /= profile[i]; } + } } - END_NAMESPACE_STIR - diff --git a/src/experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.cxx b/src/experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.cxx index 0bb4af0838..7a7cc0ba33 100644 --- a/src/experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.cxx +++ b/src/experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.cxx @@ -2,25 +2,25 @@ // /* Copyright (C) 2000 PARAPET partners - Copyright (C) 2000- 2007, Hammersmith Imanet Ltd - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + Copyright (C) 2000- 2007, Hammersmith Imanet Ltd + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! \file \ingroup buildblock - \brief non-inline implementations for class + \brief non-inline implementations for class stir::DataSymmetriesForDensels_PET_CartesianGrid \author Kris Thielemans @@ -39,16 +39,15 @@ START_NAMESPACE_STIR //! find correspondence between axial_pos_num and image coordinates /*! z = num_planes_per_axial_pos * axial_pos_num + axial_pos_to_z_offset - compute the offset by matching up the centre of the scanner + compute the offset by matching up the centre of the scanner in the 2 coordinate systems */ -static void -find_relation_between_coordinate_systems(int& num_planes_per_scanner_ring, - VectorWithOffset& num_planes_per_axial_pos, +static void +find_relation_between_coordinate_systems(int& num_planes_per_scanner_ring, VectorWithOffset& num_planes_per_axial_pos, VectorWithOffset& axial_pos_to_z_offset, const ProjDataInfoCylindrical* proj_data_info_cyl_ptr, - const DiscretisedDensityOnCartesianGrid<3,float> * cartesian_grid_info_ptr) - + const DiscretisedDensityOnCartesianGrid<3, float>* cartesian_grid_info_ptr) + { const int min_segment_num = proj_data_info_cyl_ptr->get_min_segment_num(); @@ -57,88 +56,73 @@ find_relation_between_coordinate_systems(int& num_planes_per_scanner_ring, num_planes_per_axial_pos = VectorWithOffset(min_segment_num, max_segment_num); axial_pos_to_z_offset = VectorWithOffset(min_segment_num, max_segment_num); - // TODO and WARNING: get_grid_spacing()[1] is z() + // TODO and WARNING: get_grid_spacing()[1] is z() const float image_plane_spacing = cartesian_grid_info_ptr->get_grid_spacing()[1]; - - { - const float num_planes_per_scanner_ring_float = - proj_data_info_cyl_ptr->get_ring_spacing() / image_plane_spacing; - + + { + const float num_planes_per_scanner_ring_float = proj_data_info_cyl_ptr->get_ring_spacing() / image_plane_spacing; + num_planes_per_scanner_ring = round(num_planes_per_scanner_ring_float); - + if (fabs(num_planes_per_scanner_ring_float - num_planes_per_scanner_ring) > 1.E-5) error("DataSymmetriesForDensels_PET_CartesianGrid can currently only support z-grid spacing " - "equal to the ring spacing of the scanner divided by an integer. Sorry\n"); + "equal to the ring spacing of the scanner divided by an integer. Sorry\n"); } - - if (fabs( cartesian_grid_info_ptr->get_origin().x()) > 1.E-5) + + if (fabs(cartesian_grid_info_ptr->get_origin().x()) > 1.E-5) error("DataSymmetriesForDensels_PET_CartesianGrid can currently only support x-origin = 0 " - "Sorry\n"); - if (fabs( cartesian_grid_info_ptr->get_origin().y()) > 1.E-5) + "Sorry\n"); + if (fabs(cartesian_grid_info_ptr->get_origin().y()) > 1.E-5) error("DataSymmetriesForDensels_PET_CartesianGrid can currently only support y-origin = 0 " - "Sorry\n"); - - - for (int segment_num=min_segment_num; segment_num<=max_segment_num; ++segment_num) - { - { - const float - num_planes_per_axial_pos_float = - proj_data_info_cyl_ptr->get_axial_sampling(segment_num)/image_plane_spacing; - + "Sorry\n"); + + for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) { + { + const float num_planes_per_axial_pos_float = proj_data_info_cyl_ptr->get_axial_sampling(segment_num) / image_plane_spacing; + num_planes_per_axial_pos[segment_num] = round(num_planes_per_axial_pos_float); - + if (fabs(num_planes_per_axial_pos_float - num_planes_per_axial_pos[segment_num]) > 1.E-5) error("DataSymmetriesForDensels_PET_CartesianGrid can currently only support z-grid spacing " - "equal to the axial sampling in the projection data divided by an integer. Sorry\n"); + "equal to the axial sampling in the projection data divided by an integer. Sorry\n"); + } - } - const float delta = proj_data_info_cyl_ptr->get_average_ring_difference(segment_num); - + // KT 20/06/2001 take origin.z() into account - axial_pos_to_z_offset[segment_num] = - (cartesian_grid_info_ptr->get_max_index() + cartesian_grid_info_ptr->get_min_index())/2.F - - cartesian_grid_info_ptr->get_origin().z()/image_plane_spacing - - - (num_planes_per_axial_pos[segment_num] - *(proj_data_info_cyl_ptr->get_max_axial_pos_num(segment_num) - + proj_data_info_cyl_ptr->get_min_axial_pos_num(segment_num)) - + num_planes_per_scanner_ring*delta)/2; + axial_pos_to_z_offset[segment_num] = + (cartesian_grid_info_ptr->get_max_index() + cartesian_grid_info_ptr->get_min_index()) / 2.F - + cartesian_grid_info_ptr->get_origin().z() / image_plane_spacing - + (num_planes_per_axial_pos[segment_num] * (proj_data_info_cyl_ptr->get_max_axial_pos_num(segment_num) + + proj_data_info_cyl_ptr->get_min_axial_pos_num(segment_num)) + + num_planes_per_scanner_ring * delta) / + 2; } } -/*! The DiscretisedDensity pointer has to point to an object of +/*! The DiscretisedDensity pointer has to point to an object of type DiscretisedDensityOnCartesianGrid (or a derived type). - + We really need only the geometrical info from the image. At the moment we have to use the data itself as well. */ -DataSymmetriesForDensels_PET_CartesianGrid:: -DataSymmetriesForDensels_PET_CartesianGrid -( - const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& image_info_ptr -) - : proj_data_info_ptr(proj_data_info_ptr_v) -{ - if(dynamic_cast(proj_data_info_ptr.get()) == NULL) +DataSymmetriesForDensels_PET_CartesianGrid::DataSymmetriesForDensels_PET_CartesianGrid( + const shared_ptr& proj_data_info_ptr_v, const shared_ptr>& image_info_ptr) + : proj_data_info_ptr(proj_data_info_ptr_v) { + if (dynamic_cast(proj_data_info_ptr.get()) == NULL) error("DataSymmetriesForDensels_PET_CartesianGrid constructed with wrong type of ProjDataInfo: %s\n" "(can only handle projection data corresponding to a cylinder)\n", - typeid(*proj_data_info_ptr).name()); + typeid(*proj_data_info_ptr).name()); + + const DiscretisedDensityOnCartesianGrid<3, float>* cartesian_grid_info_ptr = + dynamic_cast*>(image_info_ptr.get()); - const DiscretisedDensityOnCartesianGrid<3,float> * - cartesian_grid_info_ptr = - dynamic_cast *> - (image_info_ptr.get()); - if (cartesian_grid_info_ptr == NULL) error("DataSymmetriesForDensels_PET_CartesianGrid constructed with wrong type of image info: %s\n", - typeid(*image_info_ptr).name()); + typeid(*image_info_ptr).name()); // WARNING get_grid_spacing()[1] == z - const float z_origin_in_planes = - image_info_ptr->get_origin().z()/cartesian_grid_info_ptr->get_grid_spacing()[1]; + const float z_origin_in_planes = image_info_ptr->get_origin().z() / cartesian_grid_info_ptr->get_grid_spacing()[1]; // z_origin_in_planes should be an integer if (fabs(round(z_origin_in_planes) - z_origin_in_planes) > 1.E-4) error("DataSymmetriesForDensels_PET_CartesianGrid: the shift in the " @@ -146,97 +130,75 @@ DataSymmetriesForDensels_PET_CartesianGrid "separation (%g)\n", image_info_ptr->get_origin().z(), cartesian_grid_info_ptr->get_grid_spacing()[1]); + num_views = proj_data_info_ptr->get_num_views(); - - num_views= proj_data_info_ptr->get_num_views(); - - if (num_views%4!=0) + if (num_views % 4 != 0) error("DataSymmetriesForDensels_PET_CartesianGrid can only handle projection data " - "with the number of views a multiple of 4, while it is %d\n", - num_views); + "with the number of views a multiple of 4, while it is %d\n", + num_views); // check on segment symmetry - if (proj_data_info_ptr->get_tantheta(Bin(0,0,0,0)) != 0) + if (proj_data_info_ptr->get_tantheta(Bin(0, 0, 0, 0)) != 0) error("DataSymmetriesForDensels_PET_CartesianGrid can only handle projection data " - "with segment 0 corresponding to direct planes (i.e. theta==0)\n"); - - for (int segment_num=1; - segment_num<= min(proj_data_info_ptr->get_max_segment_num(), - -proj_data_info_ptr->get_min_segment_num()); - ++segment_num) - if (fabs(proj_data_info_ptr->get_tantheta(Bin(segment_num,0,0,0)) + - proj_data_info_ptr->get_tantheta(Bin(-segment_num,0,0,0))) > 1.E-4F) + "with segment 0 corresponding to direct planes (i.e. theta==0)\n"); + + for (int segment_num = 1; + segment_num <= min(proj_data_info_ptr->get_max_segment_num(), -proj_data_info_ptr->get_min_segment_num()); ++segment_num) + if (fabs(proj_data_info_ptr->get_tantheta(Bin(segment_num, 0, 0, 0)) + + proj_data_info_ptr->get_tantheta(Bin(-segment_num, 0, 0, 0))) > 1.E-4F) + error("DataSymmetriesForDensels_PET_CartesianGrid can only handle projection data " + "with negative segment numbers corresponding to -theta of the positive segments. " + "This is not true for segment pair %d.\n", + segment_num); + + // feable check on s-symmetry + if (fabs(proj_data_info_ptr->get_s(Bin(0, 0, 0, 1)) + proj_data_info_ptr->get_s(Bin(0, 0, 0, -1))) > 1.E-4F) error("DataSymmetriesForDensels_PET_CartesianGrid can only handle projection data " - "with negative segment numbers corresponding to -theta of the positive segments. " - "This is not true for segment pair %d.\n", - segment_num); - - //feable check on s-symmetry - if (fabs(proj_data_info_ptr->get_s(Bin(0,0,0,1)) + - proj_data_info_ptr->get_s(Bin(0,0,0,-1))) > 1.E-4F) - error("DataSymmetriesForDensels_PET_CartesianGrid can only handle projection data " - "with tangential_pos_num such that\n" + "with tangential_pos_num such that\n" " get_s(...,tang_pos_num)==-get_s(...,-tang_pos_num)\n"); - - find_relation_between_coordinate_systems(num_planes_per_scanner_ring, - num_planes_per_axial_pos, - axial_pos_to_z_offset, - static_cast(proj_data_info_ptr.get()), - cartesian_grid_info_ptr); + + find_relation_between_coordinate_systems(num_planes_per_scanner_ring, num_planes_per_axial_pos, axial_pos_to_z_offset, + static_cast(proj_data_info_ptr.get()), + cartesian_grid_info_ptr); num_planes = image_info_ptr->get_length(); if (image_info_ptr->get_min_index() != 0) error("DataSymmetriesForDensels_PET_CartesianGrid can currently only support z-min-index == 0"); - num_independent_planes = num_planes_per_axial_pos[0]; - for (int segment_num=proj_data_info_ptr->get_min_segment_num(); - segment_num<= proj_data_info_ptr->get_max_segment_num(); - ++segment_num) - { + num_independent_planes = num_planes_per_axial_pos[0]; + for (int segment_num = proj_data_info_ptr->get_min_segment_num(); segment_num <= proj_data_info_ptr->get_max_segment_num(); + ++segment_num) { if (num_independent_planes != num_planes_per_axial_pos[segment_num]) error("DataSymmetriesForDensels_PET_CartesianGrid can currently only support " "projection data with the same axial spacing in every segment.\n"); } } - #ifndef STIR_NO_COVARIANT_RETURN_TYPES - DataSymmetriesForDensels_PET_CartesianGrid * +DataSymmetriesForDensels_PET_CartesianGrid* #else - DataSymmetriesForDensels * +DataSymmetriesForDensels* #endif -DataSymmetriesForDensels_PET_CartesianGrid:: -clone() const -{ +DataSymmetriesForDensels_PET_CartesianGrid::clone() const { return new DataSymmetriesForDensels_PET_CartesianGrid(*this); } bool -DataSymmetriesForDensels_PET_CartesianGrid:: -operator ==(const DataSymmetriesForDensels_PET_CartesianGrid& that) const -{ +DataSymmetriesForDensels_PET_CartesianGrid::operator==(const DataSymmetriesForDensels_PET_CartesianGrid& that) const { if (!base_type::operator==(that)) return false; - return - *this->proj_data_info_ptr == *that.proj_data_info_ptr && - this->num_planes == that.num_planes && - this->num_independent_planes == that.num_independent_planes && - this->num_views == that.num_views && - this->num_planes_per_scanner_ring == that.num_planes_per_scanner_ring && - this->num_planes_per_axial_pos == that.num_planes_per_axial_pos && - this->axial_pos_to_z_offset == that.axial_pos_to_z_offset; + return *this->proj_data_info_ptr == *that.proj_data_info_ptr && this->num_planes == that.num_planes && + this->num_independent_planes == that.num_independent_planes && this->num_views == that.num_views && + this->num_planes_per_scanner_ring == that.num_planes_per_scanner_ring && + this->num_planes_per_axial_pos == that.num_planes_per_axial_pos && + this->axial_pos_to_z_offset == that.axial_pos_to_z_offset; } - -bool -DataSymmetriesForDensels_PET_CartesianGrid:: -blindly_equals(const root_type * const sym_ptr) const -{ - assert(dynamic_cast(sym_ptr) != 0); - return - this->operator==(static_cast(*sym_ptr)); +bool +DataSymmetriesForDensels_PET_CartesianGrid::blindly_equals(const root_type* const sym_ptr) const { + assert(dynamic_cast(sym_ptr) != 0); + return this->operator==(static_cast(*sym_ptr)); } - END_NAMESPACE_STIR diff --git a/src/experimental/recon_buildblock/ParametricQuadraticPrior.cxx b/src/experimental/recon_buildblock/ParametricQuadraticPrior.cxx index fee9a6b227..5ec88633d9 100644 --- a/src/experimental/recon_buildblock/ParametricQuadraticPrior.cxx +++ b/src/experimental/recon_buildblock/ParametricQuadraticPrior.cxx @@ -19,8 +19,8 @@ /*! \file \ingroup recon_buildblock - \brief implementation of the stir::ParametricQuadraticPrior class - + \brief implementation of the stir::ParametricQuadraticPrior class + \author Kris Thielemans \author Sanida Mustafovic \author Charalampos Tsoumpas @@ -35,12 +35,11 @@ START_NAMESPACE_STIR template -void -ParametricQuadraticPrior::initialise_keymap() -{ +void +ParametricQuadraticPrior::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Quadratic Prior Parameters"); - this->parser.add_key("only 2D", &this->only_2D); + this->parser.add_key("only 2D", &this->only_2D); this->parser.add_key("kappa filename", &this->kappa_filename); this->parser.add_key("weights", &this->weights); this->parser.add_key("gradient filename prefix", &this->gradient_filename_prefix); @@ -48,152 +47,137 @@ ParametricQuadraticPrior::initialise_keymap() } template -bool -ParametricQuadraticPrior::post_processing() -{ - if (base_type::post_processing()==true) +bool +ParametricQuadraticPrior::post_processing() { + if (base_type::post_processing() == true) return true; if (kappa_filename.size() != 0) this->kappa_ptr = read_from_file(kappa_filename); - if (this->weights.size() ==0) - { - // will call compute_weights() to fill it in - } - else - { - for (unsigned int param_num=1; param_num<=TargetT::get_num_params(); ++param_num) - { - this->_single_quadratic_priors[param_num].set_weights(this->get_weights()); // ChT: At the moment weights are treated equally. - //ChT: ToCheck - shared_ptr - kappa_sptr(this->get_kappa_sptr()->construct_single_density(param_num).clone()); - this->_single_quadratic_priors[param_num].set_kappa_sptr(kappa_sptr); - } - // only_2D?? + if (this->weights.size() == 0) { + // will call compute_weights() to fill it in + } else { + for (unsigned int param_num = 1; param_num <= TargetT::get_num_params(); ++param_num) { + this->_single_quadratic_priors[param_num].set_weights( + this->get_weights()); // ChT: At the moment weights are treated equally. + // ChT: ToCheck + shared_ptr kappa_sptr( + this->get_kappa_sptr()->construct_single_density(param_num).clone()); + this->_single_quadratic_priors[param_num].set_kappa_sptr(kappa_sptr); } + // only_2D?? + } return false; } template Succeeded -ParametricQuadraticPrior::set_up (shared_ptr > const& target_sptr) -{ +ParametricQuadraticPrior::set_up(shared_ptr> const& target_sptr) { base_type::set_up(target_sptr); return Succeeded::yes; } template -void ParametricQuadraticPrior::check(DiscretisedDensity<3,TargetT> const& current_image_estimate) const -{ +void +ParametricQuadraticPrior::check(DiscretisedDensity<3, TargetT> const& current_image_estimate) const { // Do base-class check base_type::check(current_image_estimate); } template void -ParametricQuadraticPrior::set_defaults() -{ +ParametricQuadraticPrior::set_defaults() { base_type::set_defaults(); this->only_2D = false; - this->kappa_ptr.reset(); + this->kappa_ptr.reset(); this->weights.recycle(); - // construct _single_quadratic_priors - this->_single_quadratic_priors.resize(1,2); + // construct _single_quadratic_priors + this->_single_quadratic_priors.resize(1, 2); } template <> -const char * const -ParametricQuadraticPrior::registered_name = - "Quadratic"; +const char* const ParametricQuadraticPrior::registered_name = "Quadratic"; template -ParametricQuadraticPrior::ParametricQuadraticPrior() -{ - // construct _single_quadratic_priors - this->_single_quadratic_priors.resize(1,2); +ParametricQuadraticPrior::ParametricQuadraticPrior() { + // construct _single_quadratic_priors + this->_single_quadratic_priors.resize(1, 2); set_defaults(); } template ParametricQuadraticPrior::ParametricQuadraticPrior(const bool only_2D_v, float penalisation_factor_v) - : only_2D(only_2D_v) -{ + : only_2D(only_2D_v) { this->penalisation_factor = penalisation_factor_v; // should be able to ommit it - // construct _single_quadratic_priors - this->_single_quadratic_priors.resize(1,2); - for (unsigned int param_num=1; param_num<=TargetT::get_num_params(); ++param_num) - this->_single_quadratic_priors[param_num].set_penalisation_factor(penalisation_factor_v); - //What to do for the only 2D? + // construct _single_quadratic_priors + this->_single_quadratic_priors.resize(1, 2); + for (unsigned int param_num = 1; param_num <= TargetT::get_num_params(); ++param_num) + this->_single_quadratic_priors[param_num].set_penalisation_factor(penalisation_factor_v); + // What to do for the only 2D? } - //! get penalty weights for the neigbourhood +//! get penalty weights for the neigbourhood template -Array<3,float> -ParametricQuadraticPrior:: -get_weights() const -{ return this->weights; } +Array<3, float> +ParametricQuadraticPrior::get_weights() const { + return this->weights; +} - //! set penalty weights for the neigbourhood +//! set penalty weights for the neigbourhood template -void -ParametricQuadraticPrior:: -set_weights(const Array<3,float>& w) -{ this->weights = w; } +void +ParametricQuadraticPrior::set_weights(const Array<3, float>& w) { + this->weights = w; +} - //! get current kappa image - /*! \warning As this function returns a shared_ptr, this is dangerous. You should not - modify the image by manipulating the image refered to by this pointer. - Unpredictable results will occur. - */ +//! get current kappa image +/*! \warning As this function returns a shared_ptr, this is dangerous. You should not + modify the image by manipulating the image refered to by this pointer. + Unpredictable results will occur. +*/ template -shared_ptr -ParametricQuadraticPrior:: -get_kappa_sptr() const -{ return this->kappa_ptr; } +shared_ptr +ParametricQuadraticPrior::get_kappa_sptr() const { + return this->kappa_ptr; +} - //! set kappa image +//! set kappa image template -void -ParametricQuadraticPrior:: -set_kappa_sptr(const shared_ptr& k) -{ this->kappa_ptr = k; } +void +ParametricQuadraticPrior::set_kappa_sptr(const shared_ptr& k) { + this->kappa_ptr = k; +} template double -ParametricQuadraticPrior:: -compute_value(const TargetT ¤t_image_estimate) -{ +ParametricQuadraticPrior::compute_value(const TargetT& current_image_estimate) { this->check(current_image_estimate); - double sum=0.; // At the moment I will have equal weights... so it is the sum (or the mean???) value of the two methods - for (unsigned int param_num=1; param_num<=TargetT::get_num_params(); ++param_num) - sum+=this->_single_quadratic_priors[param_num].compute_value(current_image_estimate.construct_single_density(param_num)); + double sum = 0.; // At the moment I will have equal weights... so it is the sum (or the mean???) value of the two methods + for (unsigned int param_num = 1; param_num <= TargetT::get_num_params(); ++param_num) + sum += this->_single_quadratic_priors[param_num].compute_value(current_image_estimate.construct_single_density(param_num)); return sum; -} +} template -void -ParametricQuadraticPrior:: -compute_gradient(TargetT& prior_gradient, - const TargetT ¤t_image_estimate) -{ +void +ParametricQuadraticPrior::compute_gradient(TargetT& prior_gradient, const TargetT& current_image_estimate) { this->check(current_image_estimate); - for (unsigned int param_num=1; param_num<=TargetT::get_num_params(); ++param_num) - { - typename TargetT::SingleDiscretisedDensityType single_density = prior_gradient.construct_single_density(param_num); - this->_single_quadratic_priors[param_num].compute_gradient(single_density,current_image_estimate.construct_single_density(param_num)); - prior_gradient.update_parametric_image(single_density,param_num); - } - if (gradient_filename_prefix.size()>0) - { - static int count = 0; - ++count; // Maybe it will be usefult to add here a writing step, intialised by the parameter file, otherwise we will run out of space! - char *filename = new char[gradient_filename_prefix.size()+100]; - sprintf(filename, "%s%d.img", gradient_filename_prefix.c_str(), count); - // This works only for ParametricVoxelsOnCartesianGrid and maybe for other ecat7 format files. - write_to_file(filename, prior_gradient); - delete[] filename; - } + for (unsigned int param_num = 1; param_num <= TargetT::get_num_params(); ++param_num) { + typename TargetT::SingleDiscretisedDensityType single_density = prior_gradient.construct_single_density(param_num); + this->_single_quadratic_priors[param_num].compute_gradient(single_density, + current_image_estimate.construct_single_density(param_num)); + prior_gradient.update_parametric_image(single_density, param_num); + } + if (gradient_filename_prefix.size() > 0) { + static int count = 0; + ++count; // Maybe it will be usefult to add here a writing step, intialised by the parameter file, otherwise we will run out + // of space! + char* filename = new char[gradient_filename_prefix.size() + 100]; + sprintf(filename, "%s%d.img", gradient_filename_prefix.c_str(), count); + // This works only for ParametricVoxelsOnCartesianGrid and maybe for other ecat7 format files. + write_to_file(filename, prior_gradient); + delete[] filename; + } } #if 0 @@ -216,52 +200,45 @@ compute_Hessian(TargetT& prior_Hessian_for_single_densel, else prior_Hessian_for_single_densel.update_parametric_image(single_density.get_empty_copy(),param_num); } -} +} #endif template -void -ParametricQuadraticPrior::parabolic_surrogate_curvature(TargetT& parabolic_surrogate_curvature, - const TargetT ¤t_image_estimate) -{ +void +ParametricQuadraticPrior::parabolic_surrogate_curvature(TargetT& parabolic_surrogate_curvature, + const TargetT& current_image_estimate) { this->check(current_image_estimate); - for (unsigned int param_num=1; param_num<=TargetT::get_num_params(); ++param_num) - { - typename TargetT::SingleDiscretisedDensityType single_density = parabolic_surrogate_curvature.construct_single_density(param_num); - this->_single_quadratic_priors[param_num].parabolic_surrogate_curvature(single_density,current_image_estimate.construct_single_density(param_num)); - parabolic_surrogate_curvature.update_parametric_image(single_density,param_num); - } + for (unsigned int param_num = 1; param_num <= TargetT::get_num_params(); ++param_num) { + typename TargetT::SingleDiscretisedDensityType single_density = + parabolic_surrogate_curvature.construct_single_density(param_num); + this->_single_quadratic_priors[param_num].parabolic_surrogate_curvature( + single_density, current_image_estimate.construct_single_density(param_num)); + parabolic_surrogate_curvature.update_parametric_image(single_density, param_num); + } } template -Succeeded -ParametricQuadraticPrior:: -add_multiplication_with_approximate_Hessian(TargetT& output, - const TargetT& input) const -{ +Succeeded +ParametricQuadraticPrior::add_multiplication_with_approximate_Hessian(TargetT& output, const TargetT& input) const { this->check(input); - for (unsigned int param_num=1; param_num<=TargetT::get_num_params(); ++param_num) - { - typename TargetT::SingleDiscretisedDensityType single_density = output.construct_single_density(param_num); - Succeeded if_success=this->_single_quadratic_priors[param_num].add_multiplication_with_approximate_Hessian(single_density, - input.construct_single_density(param_num)); - if(if_success==Succeeded::no) - return if_success; - else - output.update_parametric_image(single_density,param_num); - } + for (unsigned int param_num = 1; param_num <= TargetT::get_num_params(); ++param_num) { + typename TargetT::SingleDiscretisedDensityType single_density = output.construct_single_density(param_num); + Succeeded if_success = this->_single_quadratic_priors[param_num].add_multiplication_with_approximate_Hessian( + single_density, input.construct_single_density(param_num)); + if (if_success == Succeeded::no) + return if_success; + else + output.update_parametric_image(single_density, param_num); + } return Succeeded::yes; } - -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif -template class ParametricQuadraticPrior; +template class ParametricQuadraticPrior; END_NAMESPACE_STIR - - diff --git a/src/experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.cxx b/src/experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.cxx index df8948fc3f..e0f8d877db 100644 --- a/src/experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.cxx +++ b/src/experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.cxx @@ -36,137 +36,129 @@ #include "stir/DataSymmetriesForViewSegmentNumbers.h" // include the following to set defaults #ifndef USE_PMRT -#include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" -#include "stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" +# include "stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h" #else -#include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" -#include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" -#include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" +# include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" +# include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" #endif #include "stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h" #include "stir/Succeeded.h" //#include "stir/IO/OutputFileFormat.h" //#include -#include +#include #include "stir_experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.h" START_NAMESPACE_STIR -template -const char * const -PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData:: -registered_name = -"PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData"; +template +const char* const PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData::registered_name = + "PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData"; -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData:: -set_defaults() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData::set_defaults() { base_type::set_defaults(); - this->_input_filename=""; - this->_max_segment_num_to_process=0; - //num_views_to_add=1; // KT 20/06/2001 disabled - this->_dyn_proj_data_sptr=NULL; + this->_input_filename = ""; + this->_max_segment_num_to_process = 0; + // num_views_to_add=1; // KT 20/06/2001 disabled + this->_dyn_proj_data_sptr = NULL; this->_zero_seg0_end_planes = 0; this->_additive_dyn_proj_data_filename = "0"; - this->_additive_dyn_proj_data_sptr=NULL; + this->_additive_dyn_proj_data_sptr = NULL; #ifndef USE_PMRT // set default for _projector_pair_ptr - shared_ptr forward_projector_ptr = - new ForwardProjectorByBinUsingRayTracing(); - shared_ptr back_projector_ptr = - new BackProjectorByBinUsingInterpolation(); + shared_ptr forward_projector_ptr = new ForwardProjectorByBinUsingRayTracing(); + shared_ptr back_projector_ptr = new BackProjectorByBinUsingInterpolation(); #else - shared_ptr PM = - new ProjMatrixByBinUsingRayTracing(); - shared_ptr forward_projector_ptr = - new ForwardProjectorByBinUsingProjMatrixByBin(PM); - shared_ptr back_projector_ptr = - new BackProjectorByBinUsingProjMatrixByBin(PM); + shared_ptr PM = new ProjMatrixByBinUsingRayTracing(); + shared_ptr forward_projector_ptr = new ForwardProjectorByBinUsingProjMatrixByBin(PM); + shared_ptr back_projector_ptr = new BackProjectorByBinUsingProjMatrixByBin(PM); #endif - this->_projector_pair_ptr = - new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr); + this->_projector_pair_ptr = new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr); this->_normalisation_sptr = new TrivialBinNormalisation; // image stuff - this->_output_image_size_xy=-1; - this->_output_image_size_z=-1; - this->_zoom=1.F; - this->_Xoffset=0.F; - this->_Yoffset=0.F; - this->_Zoffset=0.F; // KT 20/06/2001 new + this->_output_image_size_xy = -1; + this->_output_image_size_z = -1; + this->_zoom = 1.F; + this->_Xoffset = 0.F; + this->_Yoffset = 0.F; + this->_Zoffset = 0.F; // KT 20/06/2001 new } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData:: -initialise_keymap() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData Parameters"); this->parser.add_stop_key("End PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData Parameters"); - this->parser.add_key("input file",&this->_input_filename); + this->parser.add_key("input file", &this->_input_filename); -// parser.add_key("mash x views", &num_views_to_add); // KT 20/06/2001 disabled + // parser.add_key("mash x views", &num_views_to_add); // KT 20/06/2001 disabled this->parser.add_key("maximum absolute segment number to process", &this->_max_segment_num_to_process); this->parser.add_key("zero end planes of segment 0", &this->_zero_seg0_end_planes); -// image stuff + // image stuff this->parser.add_key("zoom", &this->_zoom); - this->parser.add_key("XY output image size (in pixels)",&this->_output_image_size_xy); - this->parser.add_key("Z output image size (in pixels)",&this->_output_image_size_z); + this->parser.add_key("XY output image size (in pixels)", &this->_output_image_size_xy); + this->parser.add_key("Z output image size (in pixels)", &this->_output_image_size_z); -// parser.add_key("X offset (in mm)", &this->Xoffset); // KT 10122001 added spaces -// parser.add_key("Y offset (in mm)", &this->Yoffset); + // parser.add_key("X offset (in mm)", &this->Xoffset); // KT 10122001 added spaces + // parser.add_key("Y offset (in mm)", &this->Yoffset); this->parser.add_key("Z offset (in mm)", &this->_Zoffset); this->parser.add_parsing_key("Projector pair type", &this->_projector_pair_ptr); -// Scatter correction - this->parser.add_key("additive sinograms",&this->_additive_dyn_proj_data_filename); + // Scatter correction + this->parser.add_key("additive sinograms", &this->_additive_dyn_proj_data_filename); -// normalisation (and attenuation correction) + // normalisation (and attenuation correction) this->parser.add_parsing_key("Bin Normalisation type", &this->_normalisation_sptr); } -template +template bool -PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData:: -post_processing() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData::post_processing() { if (base_type::post_processing() == true) return true; - if (this->_input_filename.length() == 0) - { warning("You need to specify an input file"); return true; } - + if (this->_input_filename.length() == 0) { + warning("You need to specify an input file"); + return true; + } + #if 0 // KT 20/06/2001 disabled as not functional yet if (num_views_to_add!=1 && (num_views_to_add<=0 || num_views_to_add%2 != 0)) { warning("The 'mash x views' key has an invalid value (must be 1 or even number)"); return true; } -#endif - this->_dyn_proj_data_sptr=DynamicProjData::read_from_file(_input_filename); +#endif + this->_dyn_proj_data_sptr = DynamicProjData::read_from_file(_input_filename); - // image stuff - if (this->_zoom <= 0) - { warning("zoom should be positive"); return true; } - - if (this->_output_image_size_xy!=-1 && this->_output_image_size_xy<1) // KT 10122001 appended_xy - { warning("output image size xy must be positive (or -1 as default)"); return true; } - if (this->_output_image_size_z!=-1 && this->_output_image_size_z<1) // KT 10122001 new - { warning("output image size z must be positive (or -1 as default)"); return true; } + // image stuff + if (this->_zoom <= 0) { + warning("zoom should be positive"); + return true; + } - if (this->_additive_dyn_proj_data_filename != "0") + if (this->_output_image_size_xy != -1 && this->_output_image_size_xy < 1) // KT 10122001 appended_xy { - cerr << "\nReading additive projdata data " - << this->_additive_dyn_proj_data_filename - << endl; - this->_additive_dyn_proj_data_sptr = - DynamicProjData::read_from_file(this->_additive_dyn_proj_data_filename); + warning("output image size xy must be positive (or -1 as default)"); + return true; } -return false; + if (this->_output_image_size_z != -1 && this->_output_image_size_z < 1) // KT 10122001 new + { + warning("output image size z must be positive (or -1 as default)"); + return true; + } + + if (this->_additive_dyn_proj_data_filename != "0") { + cerr << "\nReading additive projdata data " << this->_additive_dyn_proj_data_filename << endl; + this->_additive_dyn_proj_data_sptr = DynamicProjData::read_from_file(this->_additive_dyn_proj_data_filename); + } + return false; } #if 0 // ChT::ToDo template @@ -180,8 +172,8 @@ template TargetT * PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData:: construct_target_ptr() const -{ -#if 0 +{ +# if 0 const shared_ptr > density_template_sptr = (*(this->_dyn_proj_data_sptr->get_proj_data_info_sptr()), static_cast(this->_zoom), @@ -196,9 +188,9 @@ construct_target_ptr() const return new DynamicDiscretisedDensity(this->_frame_defs(),scanner_sptr,density_template_sptr); -#else +# else return 0; -#endif +# endif } /*************************************************************** subset balancing @@ -393,11 +385,11 @@ add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const } #endif // ChT::ToDo -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif +#ifdef _MSC_VER +// prevent warning message on instantiation of abstract class +# pragma warning(disable : 4661) +#endif -template class PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData; +template class PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData; END_NAMESPACE_STIR diff --git a/src/experimental/recon_buildblock/PostsmoothingForwardProjectorByBin.cxx b/src/experimental/recon_buildblock/PostsmoothingForwardProjectorByBin.cxx index 2b826970a6..503f12e9b0 100644 --- a/src/experimental/recon_buildblock/PostsmoothingForwardProjectorByBin.cxx +++ b/src/experimental/recon_buildblock/PostsmoothingForwardProjectorByBin.cxx @@ -23,28 +23,21 @@ using std::min; using std::max; START_NAMESPACE_STIR -const char * const -PostsmoothingForwardProjectorByBin::registered_name = - "Post Smoothing"; - +const char* const PostsmoothingForwardProjectorByBin::registered_name = "Post Smoothing"; void -PostsmoothingForwardProjectorByBin:: -set_defaults() -{ +PostsmoothingForwardProjectorByBin::set_defaults() { tang_kernel_double.resize(0); ax_kernel_double.resize(0); original_forward_projector_ptr.reset(); tang_kernel = VectorWithOffset(); ax_kernel = VectorWithOffset(); - smooth_segment_0_axially= false; + smooth_segment_0_axially = false; } void -PostsmoothingForwardProjectorByBin:: -initialise_keymap() -{ +PostsmoothingForwardProjectorByBin::initialise_keymap() { parser.add_start_key("Post Smoothing Forward Projector"); parser.add_stop_key("End Post Smoothing Forward Projector"); parser.add_parsing_key("Original Forward projector type", &original_forward_projector_ptr); @@ -55,169 +48,116 @@ initialise_keymap() } bool -PostsmoothingForwardProjectorByBin:: -post_processing() -{ - if (is_null_ptr(original_forward_projector_ptr)) - { +PostsmoothingForwardProjectorByBin::post_processing() { + if (is_null_ptr(original_forward_projector_ptr)) { warning("Post Smoothing Forward Projector: original forward projector needs to be set"); return true; } - if (tang_kernel_double.size()>0) - { - const int max_kernel_num = tang_kernel_double.size()/2; - const int min_kernel_num = max_kernel_num - tang_kernel_double.size()+1; + if (tang_kernel_double.size() > 0) { + const int max_kernel_num = tang_kernel_double.size() / 2; + const int min_kernel_num = max_kernel_num - tang_kernel_double.size() + 1; tang_kernel.grow(min_kernel_num, max_kernel_num); - int i=min_kernel_num; - int j=0; - while(i<=max_kernel_num) - { - tang_kernel[i++] = - static_cast(tang_kernel_double[j++]); - } + int i = min_kernel_num; + int j = 0; + while (i <= max_kernel_num) { + tang_kernel[i++] = static_cast(tang_kernel_double[j++]); + } } - if (ax_kernel_double.size()>0) - { - const int max_kernel_num = ax_kernel_double.size()/2; - const int min_kernel_num = max_kernel_num - ax_kernel_double.size()+1; + if (ax_kernel_double.size() > 0) { + const int max_kernel_num = ax_kernel_double.size() / 2; + const int min_kernel_num = max_kernel_num - ax_kernel_double.size() + 1; ax_kernel.grow(min_kernel_num, max_kernel_num); - int i=min_kernel_num; - int j=0; - while(i<=max_kernel_num) - { - ax_kernel[i++] = - static_cast(ax_kernel_double[j++]); - } + int i = min_kernel_num; + int j = 0; + while (i <= max_kernel_num) { + ax_kernel[i++] = static_cast(ax_kernel_double[j++]); + } } return false; } -PostsmoothingForwardProjectorByBin:: - PostsmoothingForwardProjectorByBin() -{ - set_defaults(); -} +PostsmoothingForwardProjectorByBin::PostsmoothingForwardProjectorByBin() { set_defaults(); } -PostsmoothingForwardProjectorByBin:: -PostsmoothingForwardProjectorByBin( - const shared_ptr& original_forward_projector_ptr, - const VectorWithOffset& tangential_kernel, - const VectorWithOffset& axial_kernel, - const bool smooth_segment_0_axially) - : original_forward_projector_ptr(original_forward_projector_ptr), - tang_kernel(tangential_kernel), - ax_kernel(axial_kernel), - smooth_segment_0_axially(smooth_segment_0_axially) -{} +PostsmoothingForwardProjectorByBin::PostsmoothingForwardProjectorByBin( + const shared_ptr& original_forward_projector_ptr, const VectorWithOffset& tangential_kernel, + const VectorWithOffset& axial_kernel, const bool smooth_segment_0_axially) + : original_forward_projector_ptr(original_forward_projector_ptr), tang_kernel(tangential_kernel), ax_kernel(axial_kernel), + smooth_segment_0_axially(smooth_segment_0_axially) {} void -PostsmoothingForwardProjectorByBin:: -set_up(const shared_ptr& proj_data_info_ptr, - const shared_ptr >& image_info_ptr) -{ +PostsmoothingForwardProjectorByBin::set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& image_info_ptr) { original_forward_projector_ptr->set_up(proj_data_info_ptr, image_info_ptr); } -const DataSymmetriesForViewSegmentNumbers * -PostsmoothingForwardProjectorByBin:: -get_symmetries_used() const -{ +const DataSymmetriesForViewSegmentNumbers* +PostsmoothingForwardProjectorByBin::get_symmetries_used() const { return original_forward_projector_ptr->get_symmetries_used(); } #ifdef STIR_PROJECTORS_AS_V3 -void -PostsmoothingForwardProjectorByBin:: -actual_forward_project(RelatedViewgrams& viewgrams, - const DiscretisedDensity<3,float>& density, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - original_forward_projector_ptr->forward_project(viewgrams, density, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - for(RelatedViewgrams::iterator iter = viewgrams.begin(); - iter != viewgrams.end(); - ++iter) - { - smooth(*iter, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - } - +void +PostsmoothingForwardProjectorByBin::actual_forward_project(RelatedViewgrams& viewgrams, + const DiscretisedDensity<3, float>& density, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num) { + original_forward_projector_ptr->forward_project(viewgrams, density, min_axial_pos_num, max_axial_pos_num, + min_tangential_pos_num, max_tangential_pos_num); + for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + smooth(*iter, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); + } } #endif void -PostsmoothingForwardProjectorByBin:: -actual_forward_project(RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - // No need to do the data processing since it was already done on set_input() - original_forward_projector_ptr->forward_project(viewgrams, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - - for(RelatedViewgrams::iterator iter = viewgrams.begin(); - iter != viewgrams.end(); - ++iter) - { - smooth(*iter, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - } +PostsmoothingForwardProjectorByBin::actual_forward_project(RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { + // No need to do the data processing since it was already done on set_input() + original_forward_projector_ptr->forward_project(viewgrams, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); + + for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + smooth(*iter, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); + } } -void -PostsmoothingForwardProjectorByBin:: -smooth(Viewgram& v, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ +void +PostsmoothingForwardProjectorByBin::smooth(Viewgram& v, const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num) const { // first do tangentially { VectorWithOffset new_row(min_tangential_pos_num, max_tangential_pos_num); - - for (int ax_pos = min_axial_pos_num; ax_pos<= max_axial_pos_num; ++ax_pos) - { - for (int tang_pos = min_tangential_pos_num; tang_pos<= max_tangential_pos_num; ++tang_pos) - { - new_row[tang_pos] = 0; - for (int i=max(tang_pos - v.get_max_tangential_pos_num(), tang_kernel.get_min_index()); - i<= tang_kernel.get_max_index() && i<= tang_pos - v.get_min_tangential_pos_num(); ++i) - new_row[tang_pos] += tang_kernel[i] * v[ax_pos][tang_pos-i]; - } - // copy new_row to old_row - for (int tang_pos = min_tangential_pos_num; tang_pos<= max_tangential_pos_num; ++tang_pos) - { - v[ax_pos][tang_pos] = new_row[tang_pos]; - } + + for (int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num; ++ax_pos) { + for (int tang_pos = min_tangential_pos_num; tang_pos <= max_tangential_pos_num; ++tang_pos) { + new_row[tang_pos] = 0; + for (int i = max(tang_pos - v.get_max_tangential_pos_num(), tang_kernel.get_min_index()); + i <= tang_kernel.get_max_index() && i <= tang_pos - v.get_min_tangential_pos_num(); ++i) + new_row[tang_pos] += tang_kernel[i] * v[ax_pos][tang_pos - i]; + } + // copy new_row to old_row + for (int tang_pos = min_tangential_pos_num; tang_pos <= max_tangential_pos_num; ++tang_pos) { + v[ax_pos][tang_pos] = new_row[tang_pos]; } + } } // now do axially - if (!v.get_segment_num()==0 || smooth_segment_0_axially) - { + if (!v.get_segment_num() == 0 || smooth_segment_0_axially) { VectorWithOffset new_column(min_axial_pos_num, max_axial_pos_num); - - for (int tang_pos = min_tangential_pos_num; tang_pos<= max_tangential_pos_num; ++tang_pos) - { - for (int ax_pos = min_axial_pos_num; ax_pos<= max_axial_pos_num; ++ax_pos) - { - new_column[ax_pos] = 0; - for (int i=std::max(ax_pos - v.get_max_axial_pos_num(), ax_kernel.get_min_index()); - i<= ax_kernel.get_max_index() && i<= ax_pos - v.get_min_axial_pos_num(); ++i) - new_column[ax_pos] += ax_kernel[i] * v[ax_pos][tang_pos-i]; - } - // copy new_column to old_column - for (int ax_pos = min_axial_pos_num; ax_pos<= max_axial_pos_num; ++ax_pos) - { - v[ax_pos][tang_pos] = new_column[ax_pos]; - } + + for (int tang_pos = min_tangential_pos_num; tang_pos <= max_tangential_pos_num; ++tang_pos) { + for (int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num; ++ax_pos) { + new_column[ax_pos] = 0; + for (int i = std::max(ax_pos - v.get_max_axial_pos_num(), ax_kernel.get_min_index()); + i <= ax_kernel.get_max_index() && i <= ax_pos - v.get_min_axial_pos_num(); ++i) + new_column[ax_pos] += ax_kernel[i] * v[ax_pos][tang_pos - i]; } + // copy new_column to old_column + for (int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num; ++ax_pos) { + v[ax_pos][tang_pos] = new_column[ax_pos]; + } + } } - } - - END_NAMESPACE_STIR diff --git a/src/experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.cxx b/src/experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.cxx index 6131bf2d18..97aa41bcfc 100644 --- a/src/experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.cxx +++ b/src/experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.cxx @@ -15,8 +15,6 @@ See STIR/LICENSE.txt for details */ - - #include "stir_experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.h" #include "stir/recon_buildblock/TrivialDataSymmetriesForBins.h" #include "stir/VoxelsOnCartesianGrid.h" @@ -27,93 +25,64 @@ START_NAMESPACE_STIR +const char* const ProjMatrixByBinSinglePhoton::registered_name = "Single Photon"; -const char * const -ProjMatrixByBinSinglePhoton::registered_name = - "Single Photon"; - -ProjMatrixByBinSinglePhoton:: -ProjMatrixByBinSinglePhoton() -{ - set_defaults(); -} +ProjMatrixByBinSinglePhoton::ProjMatrixByBinSinglePhoton() { set_defaults(); } -void -ProjMatrixByBinSinglePhoton::initialise_keymap() -{ +void +ProjMatrixByBinSinglePhoton::initialise_keymap() { ProjMatrixByBin::initialise_keymap(); parser.add_start_key("Single Photon Matrix Parameters"); parser.add_stop_key("End Single Photon Matrix Parameters"); } - void -ProjMatrixByBinSinglePhoton::set_defaults() -{ +ProjMatrixByBinSinglePhoton::set_defaults() { ProjMatrixByBin::set_defaults(); } - void -ProjMatrixByBinSinglePhoton:: -set_up( - const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr - ) -{ - proj_data_info_ptr= proj_data_info_ptr_v; - if (dynamic_cast(proj_data_info_ptr.get()) == 0) +ProjMatrixByBinSinglePhoton::set_up(const shared_ptr& proj_data_info_ptr_v, + const shared_ptr>& density_info_ptr) { + proj_data_info_ptr = proj_data_info_ptr_v; + if (dynamic_cast(proj_data_info_ptr.get()) == 0) error("Single Photm projection matrix can handle on non-arccorrected data\n"); - const VoxelsOnCartesianGrid * image_info_ptr = - dynamic_cast*> (density_info_ptr.get()); + const VoxelsOnCartesianGrid* image_info_ptr = dynamic_cast*>(density_info_ptr.get()); if (image_info_ptr == NULL) error("ProjMatrixByBinSinglePhoton initialised with a wrong type of DiscretisedDensity\n"); - image_info_ptr->get_regular_range(min_index, max_index); - if (min_index[1]!=0 || max_index[1]!=0) + if (min_index[1] != 0 || max_index[1] != 0) error("Image should have only 1 plane\n"); - if (max_index[2]-min_index[2]+1 != proj_data_info_ptr->get_scanner_ptr()->get_num_rings()) + if (max_index[2] - min_index[2] + 1 != proj_data_info_ptr->get_scanner_ptr()->get_num_rings()) error("Image should have y-dimension equal to the number of rings\n"); - if (max_index[3]-min_index[3]+1 != proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring()) + if (max_index[3] - min_index[3] + 1 != proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring()) error("Image should have x-dimension equal to the number of detectors per ring\n"); - symmetries_ptr - .reset(new TrivialDataSymmetriesForBins(proj_data_info_ptr)); - + symmetries_ptr.reset(new TrivialDataSymmetriesForBins(proj_data_info_ptr)); }; - -void -ProjMatrixByBinSinglePhoton:: -calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +void +ProjMatrixByBinSinglePhoton::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { const Bin bin = lor.get_bin(); assert(lor.size() == 0); - vector > det_pos_pairs; - static_cast(*proj_data_info_ptr). - get_all_det_pos_pairs_for_bin(det_pos_pairs, bin); - for (std::vector >::const_iterator det_pos_pair_iter = det_pos_pairs.begin(); - det_pos_pair_iter != det_pos_pairs.end(); - ++det_pos_pair_iter) - { - lor.push_back(ProjMatrixElemsForOneBin:: - value_type(Coordinate3D(0, - det_pos_pair_iter->pos1().axial_coord() + min_index[2], - det_pos_pair_iter->pos1().tangential_coord() + min_index[3]),1)); - lor.push_back(ProjMatrixElemsForOneBin:: - value_type(Coordinate3D(0, - det_pos_pair_iter->pos2().axial_coord() + min_index[2], - det_pos_pair_iter->pos2().tangential_coord() + min_index[3]),1)); - } + vector> det_pos_pairs; + static_cast(*proj_data_info_ptr).get_all_det_pos_pairs_for_bin(det_pos_pairs, bin); + for (std::vector>::const_iterator det_pos_pair_iter = det_pos_pairs.begin(); + det_pos_pair_iter != det_pos_pairs.end(); ++det_pos_pair_iter) { + lor.push_back( + ProjMatrixElemsForOneBin::value_type(Coordinate3D(0, det_pos_pair_iter->pos1().axial_coord() + min_index[2], + det_pos_pair_iter->pos1().tangential_coord() + min_index[3]), + 1)); + lor.push_back( + ProjMatrixElemsForOneBin::value_type(Coordinate3D(0, det_pos_pair_iter->pos2().axial_coord() + min_index[2], + det_pos_pair_iter->pos2().tangential_coord() + min_index[3]), + 1)); + } } - - END_NAMESPACE_STIR - diff --git a/src/experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.cxx b/src/experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.cxx index 1d5a54637a..45131b7f49 100644 --- a/src/experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.cxx +++ b/src/experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.cxx @@ -18,8 +18,6 @@ */ - - #include "stir_experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.h" #include "stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.h" #include "stir/VoxelsOnCartesianGrid.h" @@ -30,130 +28,94 @@ START_NAMESPACE_STIR +const char* const ProjMatrixByBinUsingSolidAngle::registered_name = "Solid Angle"; -const char * const -ProjMatrixByBinUsingSolidAngle::registered_name = - "Solid Angle"; - -ProjMatrixByBinUsingSolidAngle:: -ProjMatrixByBinUsingSolidAngle() -{ - set_defaults(); -} +ProjMatrixByBinUsingSolidAngle::ProjMatrixByBinUsingSolidAngle() { set_defaults(); } -void -ProjMatrixByBinUsingSolidAngle::initialise_keymap() -{ +void +ProjMatrixByBinUsingSolidAngle::initialise_keymap() { ProjMatrixByBin::initialise_keymap(); parser.add_start_key("Solid Angle Matrix Parameters"); parser.add_stop_key("End Solid Angle Matrix Parameters"); } - void -ProjMatrixByBinUsingSolidAngle::set_defaults() -{ +ProjMatrixByBinUsingSolidAngle::set_defaults() { ProjMatrixByBin::set_defaults(); } - void -ProjMatrixByBinUsingSolidAngle:: -set_up( - const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr - ) -{ - proj_data_info_ptr= proj_data_info_ptr_v; - const VoxelsOnCartesianGrid * image_info_ptr = - dynamic_cast*> (density_info_ptr.get()); +ProjMatrixByBinUsingSolidAngle::set_up(const shared_ptr& proj_data_info_ptr_v, + const shared_ptr>& density_info_ptr) { + proj_data_info_ptr = proj_data_info_ptr_v; + const VoxelsOnCartesianGrid* image_info_ptr = dynamic_cast*>(density_info_ptr.get()); if (image_info_ptr == NULL) error("ProjMatrixByBinUsingSolidAngle initialised with a wrong type of DiscretisedDensity\n"); - voxel_size = image_info_ptr->get_voxel_size(); origin = image_info_ptr->get_origin(); image_info_ptr->get_regular_range(min_index, max_index); - symmetries_ptr - .reset(new DataSymmetriesForBins_PET_CartesianGrid(proj_data_info_ptr, - density_info_ptr)); - + symmetries_ptr.reset(new DataSymmetriesForBins_PET_CartesianGrid(proj_data_info_ptr, density_info_ptr)); }; - ////////////////////////////////////// - -inline int sign(const float x) -{ - return x>0 ? 1 : -1; +inline int +sign(const float x) { + return x > 0 ? 1 : -1; } // integral from centre of trapezoid to s -// height is 1, m2 is half length of plateau, m3 is half total length -inline float trapezoid_integral(const float s, - const float m2, - const float m3) -{ +// height is 1, m2 is half length of plateau, m3 is half total length +inline float +trapezoid_integral(const float s, const float m2, const float m3) { const float abs_s = fabs(s); - const float abs_s_min_m3 = abs_s-m3; - const float maxval = m2+m3; - if(abs_s_min_m3 >= 0) - return sign(s)*maxval/2; - if(abs_s >= m2) - { - const float minval = m3-m2; - return sign(s) *(maxval - square(abs_s_min_m3)/minval)/2; + const float abs_s_min_m3 = abs_s - m3; + const float maxval = m2 + m3; + if (abs_s_min_m3 >= 0) + return sign(s) * maxval / 2; + if (abs_s >= m2) { + const float minval = m3 - m2; + return sign(s) * (maxval - square(abs_s_min_m3) / minval) / 2; } return s; } - - template -inline T cube(const T x) -{ - return x*x*x; +inline T +cube(const T x) { + return x * x * x; } // both of height 1 // 0/0 when m2? == m3? -inline float convolution_2_trapezoids(const float x, - const float m21, - const float m31, - const float m22, - const float m32) -{ - return -(cube(fabs(m21 - m22 - x)) + cube(fabs(m21 + m22 - x)) - - cube(fabs(m22 - m31 - x)) - cube(fabs(m22 + m31 - x)) - - cube(fabs(m21 - m32 - x)) + cube(fabs(m31 - m32 - x)) - - cube(fabs(m21 + m32 - x)) + cube(fabs(m31 + m32 - x)) + - cube(fabs(m21 - m22 + x)) + cube(fabs(m21 + m22 + x)) - - cube(fabs(m22 - m31 + x)) - cube(fabs(m22 + m31 + x)) - - cube(fabs(m21 - m32 + x)) + cube(fabs(m31 - m32 + x)) - - cube(fabs(m21 + m32 + x)) + cube(fabs(m31 + m32 + x)))/ - (12*(m21 - m31)*(m22 - m32)); +inline float +convolution_2_trapezoids(const float x, const float m21, const float m31, const float m22, const float m32) { + return (cube(fabs(m21 - m22 - x)) + cube(fabs(m21 + m22 - x)) - cube(fabs(m22 - m31 - x)) - cube(fabs(m22 + m31 - x)) - + cube(fabs(m21 - m32 - x)) + cube(fabs(m31 - m32 - x)) - cube(fabs(m21 + m32 - x)) + cube(fabs(m31 + m32 - x)) + + cube(fabs(m21 - m22 + x)) + cube(fabs(m21 + m22 + x)) - cube(fabs(m22 - m31 + x)) - cube(fabs(m22 + m31 + x)) - + cube(fabs(m21 - m32 + x)) + cube(fabs(m31 - m32 + x)) - cube(fabs(m21 + m32 + x)) + cube(fabs(m31 + m32 + x))) / + (12 * (m21 - m31) * (m22 - m32)); } /* -inline float VOI_small_voxel(const float s_voxel, - const float half_voxel_size) +inline float VOI_small_voxel(const float s_voxel, + const float half_voxel_size) { - const float res = + const float res = min(.5,s_voxel+half_voxel_size) - max(-.5, s_voxel-half_voxel_size); return res<0 ? 0 : res; } -inline float VOI(const float s_voxel, - const float half_voxel_size, - const float halfcosminsin, - const float halfcosplussin) +inline float VOI(const float s_voxel, + const float half_voxel_size, + const float halfcosminsin, + const float halfcosplussin) { - - return + + return VOI_small_voxel(s_voxel+halfcosminsin, half_voxel_size) + VOI_small_voxel(s_voxel-halfcosminsin, half_voxel_size) + VOI_small_voxel(s_voxel+halfcosplussin, half_voxel_size) + @@ -161,208 +123,164 @@ inline float VOI(const float s_voxel, } */ -inline float VOI(const float s_voxel, - const float half_bin_size, - const float halfcosminsin, - const float halfcosplussin) -{ - return - trapezoid_integral(half_bin_size-s_voxel, halfcosminsin, halfcosplussin) - - trapezoid_integral(-half_bin_size- s_voxel, halfcosminsin, halfcosplussin); +inline float +VOI(const float s_voxel, const float half_bin_size, const float halfcosminsin, const float halfcosplussin) { + return trapezoid_integral(half_bin_size - s_voxel, halfcosminsin, halfcosplussin) - + trapezoid_integral(-half_bin_size - s_voxel, halfcosminsin, halfcosplussin); } -inline float SA_rotated_voxel(const float s_voxel, - const float half_voxel_size, - const float m2, - const float m3) -{ - return - trapezoid_integral(half_voxel_size+s_voxel, m2, m3) - - trapezoid_integral(-half_voxel_size+s_voxel, m2, m3); +inline float +SA_rotated_voxel(const float s_voxel, const float half_voxel_size, const float m2, const float m3) { + return trapezoid_integral(half_voxel_size + s_voxel, m2, m3) - trapezoid_integral(-half_voxel_size + s_voxel, m2, m3); } -inline float SAapprox(const float s_voxel, - const float half_voxel_size, - const float m2, - const float m3, - const float halfcosminsin, - const float halfcosplussin) -{ - - return - /* - SA_rotated_voxel(s_voxel+halfcosminsin/2, half_voxel_size, m2, m3) + - SA_rotated_voxel(s_voxel-halfcosminsin/2, half_voxel_size, m2, m3) + - SA_rotated_voxel(s_voxel+halfcosplussin/2, half_voxel_size, m2, m3) + - SA_rotated_voxel(s_voxel-halfcosplussin/2, half_voxel_size, m2, m3); - */ - SA_rotated_voxel(s_voxel+halfcosminsin/2, .5, m2, m3) + - SA_rotated_voxel(s_voxel-halfcosminsin/2, .5, m2, m3) + - SA_rotated_voxel(s_voxel+halfcosplussin/2, .5, m2, m3) + - SA_rotated_voxel(s_voxel-halfcosplussin/2, .5, m2, m3); - +inline float +SAapprox(const float s_voxel, const float half_voxel_size, const float m2, const float m3, const float halfcosminsin, + const float halfcosplussin) { + + return + /* + SA_rotated_voxel(s_voxel+halfcosminsin/2, half_voxel_size, m2, m3) + + SA_rotated_voxel(s_voxel-halfcosminsin/2, half_voxel_size, m2, m3) + + SA_rotated_voxel(s_voxel+halfcosplussin/2, half_voxel_size, m2, m3) + + SA_rotated_voxel(s_voxel-halfcosplussin/2, half_voxel_size, m2, m3); + */ + SA_rotated_voxel(s_voxel + halfcosminsin / 2, .5, m2, m3) + SA_rotated_voxel(s_voxel - halfcosminsin / 2, .5, m2, m3) + + SA_rotated_voxel(s_voxel + halfcosplussin / 2, .5, m2, m3) + SA_rotated_voxel(s_voxel - halfcosplussin / 2, .5, m2, m3); } -inline float SA(const float s_voxel, - const float half_voxel_size, - const float m2, - const float m3, - const float halfcosminsin, - const float halfcosplussin) -{ - return - halfcosminsin==halfcosplussin ? - SA_rotated_voxel(s_voxel, .5, m2, m3) - : - convolution_2_trapezoids(s_voxel,m2,m3, halfcosminsin, halfcosplussin); +inline float +SA(const float s_voxel, const float half_voxel_size, const float m2, const float m3, const float halfcosminsin, + const float halfcosplussin) { + return halfcosminsin == halfcosplussin ? SA_rotated_voxel(s_voxel, .5, m2, m3) + : convolution_2_trapezoids(s_voxel, m2, m3, halfcosminsin, halfcosplussin); } - -void -ProjMatrixByBinUsingSolidAngle:: -calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +void +ProjMatrixByBinUsingSolidAngle::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { const Bin bin = lor.get_bin(); - //assert(bin.axial_pos_num() == 0); + // assert(bin.axial_pos_num() == 0); assert(bin.tangential_pos_num() >= 0); - assert(bin.segment_num() >= 0 ); - assert(bin.segment_num() <= proj_data_info_ptr->get_max_segment_num()); - assert(bin.view_num() <= proj_data_info_ptr->get_num_views()/4); - assert(bin.view_num()>=0); + assert(bin.segment_num() >= 0); + assert(bin.segment_num() <= proj_data_info_ptr->get_max_segment_num()); + assert(bin.view_num() <= proj_data_info_ptr->get_num_views() / 4); + assert(bin.view_num() >= 0); assert(lor.size() == 0); - + const float tantheta = proj_data_info_ptr->get_tantheta(bin); - const float costheta = 1/sqrt(1+square(tantheta)); + const float costheta = 1 / sqrt(1 + square(tantheta)); const float phi = proj_data_info_ptr->get_phi(bin); const float cphi = cos(phi); const float sphi = sin(phi); const float s_in_mm = proj_data_info_ptr->get_s(bin); const float t_in_mm = proj_data_info_ptr->get_t(bin); - - // use FOV which is circular, and is slightly 'inside' the image to avoid + // use FOV which is circular, and is slightly 'inside' the image to avoid // index out of range - const float fovrad_in_mm = - min((min(max_index.x(), -min_index.x())-1)*voxel_size.x(), - (min(max_index.y(), -min_index.y())-1)*voxel_size.y()); - if (s_in_mm >= fovrad_in_mm) return; - + const float fovrad_in_mm = + min((min(max_index.x(), -min_index.x()) - 1) * voxel_size.x(), (min(max_index.y(), -min_index.y()) - 1) * voxel_size.y()); + if (s_in_mm >= fovrad_in_mm) + return; - const float sampling_distance_of_adjacent_LORs_z = - proj_data_info_ptr->get_sampling_in_t(bin)/costheta; - + const float sampling_distance_of_adjacent_LORs_z = proj_data_info_ptr->get_sampling_in_t(bin) / costheta; // find number of LORs we have to take, such that we don't miss voxels // we have to subtract a tiny amount from the quotient, to avoid having too many LORs // solely due to numerical rounding errors - const int num_lors_per_axial_pos = - static_cast(ceil(sampling_distance_of_adjacent_LORs_z / voxel_size.z() - 1.E-3)); + const int num_lors_per_axial_pos = static_cast(ceil(sampling_distance_of_adjacent_LORs_z / voxel_size.z() - 1.E-3)); - assert(num_lors_per_axial_pos>0); + assert(num_lors_per_axial_pos > 0); // code below is currently restricted to 2 LORs - assert(num_lors_per_axial_pos<=2); + assert(num_lors_per_axial_pos <= 2); // merging code assumes integer multiple - assert(fabs(sampling_distance_of_adjacent_LORs_z - - num_lors_per_axial_pos*voxel_size.z()) <= 1E-4); - + assert(fabs(sampling_distance_of_adjacent_LORs_z - num_lors_per_axial_pos * voxel_size.z()) <= 1E-4); // find offset in z, taking into account if there are 1 or 2 LORs // KT 20/06/2001 take origin.z() into account - const float offset_in_z = - (num_lors_per_axial_pos == 1 || tantheta == 0 ? - 0.F : -sampling_distance_of_adjacent_LORs_z/4) - - origin.z(); - + const float offset_in_z = + (num_lors_per_axial_pos == 1 || tantheta == 0 ? 0.F : -sampling_distance_of_adjacent_LORs_z / 4) - origin.z(); /* Intersection points of LOR and image FOV (assuming infinitely long scanner)*/ /* compute X1f, Y1f,,Z1f et al in voxelcoordinates. */ - + const float TMP2f = sqrt(square(fovrad_in_mm) - square(s_in_mm)); - //const float X2f = (s_in_mm * cphi - sphi * TMP2f)/voxel_size.x(); - const float X1f = (s_in_mm * cphi + sphi * TMP2f)/voxel_size.x(); - //const float Y2f = (s_in_mm * sphi + cphi * TMP2f)/voxel_size.y(); - const float Y1f = (s_in_mm * sphi - cphi * TMP2f)/voxel_size.y(); - - const float Z1f = - (t_in_mm/costheta - TMP2f*tantheta + offset_in_z)/voxel_size.z() - + (max_index.z() + min_index.z())/2.F; - //const float Z2f = + // const float X2f = (s_in_mm * cphi - sphi * TMP2f)/voxel_size.x(); + const float X1f = (s_in_mm * cphi + sphi * TMP2f) / voxel_size.x(); + // const float Y2f = (s_in_mm * sphi + cphi * TMP2f)/voxel_size.y(); + const float Y1f = (s_in_mm * sphi - cphi * TMP2f) / voxel_size.y(); + + const float Z1f = + (t_in_mm / costheta - TMP2f * tantheta + offset_in_z) / voxel_size.z() + (max_index.z() + min_index.z()) / 2.F; + // const float Z2f = // (t_in_mm/costheta + TMP2f*tantheta + offset_in_z)/voxel_size.z() // + (max_index.z() + min_index.z())/2.F; - const CartesianCoordinate3D start_point(Z1f,Y1f,X1f); - //const CartesianCoordinate3D stop_point(Z2f,Y2f,X2f); + const CartesianCoordinate3D start_point(Z1f, Y1f, X1f); + // const CartesianCoordinate3D stop_point(Z2f,Y2f,X2f); - const float tphi = sphi/cphi; + const float tphi = sphi / cphi; // do actual computation for this LOR - const float halfcosplussin = (1+tphi)/2; - const float halfcosminsin = (1-tphi)/2; - const float bin_size = proj_data_info_ptr->get_sampling_in_s(bin)*2;// factor 2 necessary for actual detector size TODO - //? 1/x *2 ? - const float half_bin_size = bin_size/2/voxel_size.x()/cphi; - const float fovrad = fovrad_in_mm/voxel_size.x(); - //const float half_voxel_size = cphi; - const float half_tube_length = - sqrt(square(proj_data_info_ptr->get_scanner_ptr()->get_effective_ring_radius()) - - square(s_in_mm))/voxel_size.x(); - { - // Compute first pixel in a beam (not on a ray ) - const float max_s = halfcosplussin*2 + half_bin_size +0.01F; - const float min_s = -max_s; - - // start guaranteed on the right of the tube - int XonpreviousRow = min(static_cast(ceil(X1f + max_s)), max_index[3]); - int Y = static_cast(ceil(Y1f)); - float s_voxel_onpreviousRow=XonpreviousRow+Y*tphi-s_in_mm/voxel_size.x()/cphi; - // next assert is not true because we pushed X inside the FOV again - // assert(s_voxel_onpreviousRow > max_s); - - int X; - float s_voxel; - do - { - while (s_voxel_onpreviousRow>max_s) - { - /* horizontal*/ - --XonpreviousRow; - --s_voxel_onpreviousRow; - } - X= XonpreviousRow; - s_voxel = s_voxel_onpreviousRow; - - const float depth = fabs(-X* sphi + Y*cphi); - const float rel_depth = depth/half_tube_length; - const float m3 = half_bin_size; - const float m2 = m3 * rel_depth; - const float height_of_trapezoid = 2*m3/(1+rel_depth)/half_tube_length*(cphi); - - // this should have a check on X>=min_index[3] if s<0 was included - while (s_voxel>min_s) - { - const float Pbv = - //VOI(s_voxel, half_bin_size, halfcosminsin,halfcosplussin); - SA(s_voxel, half_bin_size, m2,m3,halfcosminsin,halfcosplussin) * - height_of_trapezoid; - //assert(Pbv>0); - // warning: threshold depends on scale (currently VOI max is 1) - if (Pbv>.0001) - lor.push_back(ProjMatrixElemsForOneBin::value_type(Coordinate3D(0,Y,X),Pbv)); - // this could be made with break - /* horizontal*/ - --X; - --s_voxel; - } - /* vertical */ - ++Y; - s_voxel_onpreviousRow+=tphi; - + const float halfcosplussin = (1 + tphi) / 2; + const float halfcosminsin = (1 - tphi) / 2; + const float bin_size = proj_data_info_ptr->get_sampling_in_s(bin) * 2; // factor 2 necessary for actual detector size TODO + //? 1/x *2 ? + const float half_bin_size = bin_size / 2 / voxel_size.x() / cphi; + const float fovrad = fovrad_in_mm / voxel_size.x(); + // const float half_voxel_size = cphi; + const float half_tube_length = + sqrt(square(proj_data_info_ptr->get_scanner_ptr()->get_effective_ring_radius()) - square(s_in_mm)) / voxel_size.x(); + { + // Compute first pixel in a beam (not on a ray ) + const float max_s = halfcosplussin * 2 + half_bin_size + 0.01F; + const float min_s = -max_s; + + // start guaranteed on the right of the tube + int XonpreviousRow = min(static_cast(ceil(X1f + max_s)), max_index[3]); + int Y = static_cast(ceil(Y1f)); + float s_voxel_onpreviousRow = XonpreviousRow + Y * tphi - s_in_mm / voxel_size.x() / cphi; + // next assert is not true because we pushed X inside the FOV again + // assert(s_voxel_onpreviousRow > max_s); + + int X; + float s_voxel; + do { + while (s_voxel_onpreviousRow > max_s) { + /* horizontal*/ + --XonpreviousRow; + --s_voxel_onpreviousRow; } - while (square(X) + square(Y) < square(fovrad)); - } + X = XonpreviousRow; + s_voxel = s_voxel_onpreviousRow; + + const float depth = fabs(-X * sphi + Y * cphi); + const float rel_depth = depth / half_tube_length; + const float m3 = half_bin_size; + const float m2 = m3 * rel_depth; + const float height_of_trapezoid = 2 * m3 / (1 + rel_depth) / half_tube_length * (cphi); + + // this should have a check on X>=min_index[3] if s<0 was included + while (s_voxel > min_s) { + const float Pbv = + // VOI(s_voxel, half_bin_size, halfcosminsin,halfcosplussin); + SA(s_voxel, half_bin_size, m2, m3, halfcosminsin, halfcosplussin) * height_of_trapezoid; + // assert(Pbv>0); + // warning: threshold depends on scale (currently VOI max is 1) + if (Pbv > .0001) + lor.push_back(ProjMatrixElemsForOneBin::value_type(Coordinate3D(0, Y, X), Pbv)); + // this could be made with break + /* horizontal*/ + --X; + --s_voxel; + } + /* vertical */ + ++Y; + s_voxel_onpreviousRow += tphi; + + } while (square(X) + square(Y) < square(fovrad)); + } #if 0 // now add on other LORs @@ -383,10 +301,6 @@ calculate_proj_matrix_elems_for_one_bin( } // if( num_lors_per_axial_pos>1) #endif - } - - END_NAMESPACE_STIR - diff --git a/src/experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.cxx b/src/experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.cxx index 749e649889..59c9ff04b8 100644 --- a/src/experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.cxx +++ b/src/experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.cxx @@ -18,8 +18,6 @@ See STIR/LICENSE.txt for details */ - - #include "stir_experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.h" #include "stir/VoxelsOnCartesianGrid.h" #include "stir/ProjDataInfo.h" @@ -32,25 +30,16 @@ START_NAMESPACE_STIR +const char* const ProjMatrixByBinWithPositronRange::registered_name = "With Positron Range"; -const char * const -ProjMatrixByBinWithPositronRange::registered_name = - "With Positron Range"; +ProjMatrixByBinWithPositronRange::ProjMatrixByBinWithPositronRange() { set_defaults(); } -ProjMatrixByBinWithPositronRange:: -ProjMatrixByBinWithPositronRange() -{ - set_defaults(); -} - -void -ProjMatrixByBinWithPositronRange::initialise_keymap() -{ +void +ProjMatrixByBinWithPositronRange::initialise_keymap() { ProjMatrixByBin::initialise_keymap(); parser.add_start_key("With Positron Range Matrix Parameters"); - parser.add_parsing_key("matrix type to use after positron range blurring", - &post_projmatrix_ptr); - parser.add_key("C", &positron_range_C); + parser.add_parsing_key("matrix type to use after positron range blurring", &post_projmatrix_ptr); + parser.add_key("C", &positron_range_C); parser.add_key("k1", &positron_range_k1); parser.add_key("k2", &positron_range_k2); parser.add_key("zoom (odd integer)", &positron_range_zoom); @@ -58,105 +47,76 @@ ProjMatrixByBinWithPositronRange::initialise_keymap() parser.add_stop_key("End With Positron Range Matrix Parameters"); } - void -ProjMatrixByBinWithPositronRange::set_defaults() -{ +ProjMatrixByBinWithPositronRange::set_defaults() { ProjMatrixByBin::set_defaults(); - positron_range_C =-1; - positron_range_k1=-1; - positron_range_k2=-1; - post_proj_matrix_ptr=0; - positron_range_zoom=1; - positron_num_samples=1; + positron_range_C = -1; + positron_range_k1 = -1; + positron_range_k2 = -1; + post_proj_matrix_ptr = 0; + positron_range_zoom = 1; + positron_num_samples = 1; } bool -ProjMatrixByBinWithPositronRange::post_processing() -{ +ProjMatrixByBinWithPositronRange::post_processing() { if (ProjMatrixByBin::post_processing() == true) return true; - if (positron_range_C < 0 || positron_range_C>1) - { - warning("C has to be between 0 and 1 but is %g", positron_range_C); - return true; - } - if (positron_range_k1 < 0) - { - warning("k1 has to be larger than 0 but is %g", positron_range_k1); - return true; - } - if (positron_range_k2 < 0) - { - warning("k2 has to be larger than 0 but is %g", positron_range_k2); - return true; - } - if (positron_range_zoom < 1 || positron_range_zoom%2==0) - { - warning("zoom has to be larger than 0 and odd but is %d", positron_range_zoom); - return true; - } - if (positron_range_num_samples < 1 || positron_range_num_samples%2==0) - { - warning("num_samples has to be larger than 0 and odd but is %d", positron_range_num_samples); - return true; - } - if (is_null_ptr(post_projmatrix_ptr)) - { - warning("matrix has to be valid"); - return true; - } + if (positron_range_C < 0 || positron_range_C > 1) { + warning("C has to be between 0 and 1 but is %g", positron_range_C); + return true; + } + if (positron_range_k1 < 0) { + warning("k1 has to be larger than 0 but is %g", positron_range_k1); + return true; + } + if (positron_range_k2 < 0) { + warning("k2 has to be larger than 0 but is %g", positron_range_k2); + return true; + } + if (positron_range_zoom < 1 || positron_range_zoom % 2 == 0) { + warning("zoom has to be larger than 0 and odd but is %d", positron_range_zoom); + return true; + } + if (positron_range_num_samples < 1 || positron_range_num_samples % 2 == 0) { + warning("num_samples has to be larger than 0 and odd but is %d", positron_range_num_samples); + return true; + } + if (is_null_ptr(post_projmatrix_ptr)) { + warning("matrix has to be valid"); + return true; + } return false; } void -ProjMatrixByBinWithPositronRange:: -set_up( - const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr - ) -{ - proj_data_info_ptr= proj_data_info_ptr_v; - const VoxelsOnCartesianGrid * image_info_ptr = - dynamic_cast*> (density_info_ptr.get()); +ProjMatrixByBinWithPositronRange::set_up(const shared_ptr& proj_data_info_ptr_v, + const shared_ptr>& density_info_ptr) { + proj_data_info_ptr = proj_data_info_ptr_v; + const VoxelsOnCartesianGrid* image_info_ptr = dynamic_cast*>(density_info_ptr.get()); if (image_info_ptr == NULL) error("ProjMatrixByBinWithPositronRange initialised with a wrong type of DiscretisedDensity\n"); - voxel_size = image_info_ptr->get_voxel_size(); origin = image_info_ptr->get_origin(); image_info_ptr->get_regular_range(min_index, max_index); - const CartesianCoordinate3D zoomed_voxel_size = - voxel_size/zoom; - const CartesianCoordinate3D zoomed_max_index = - max_index * zoom + (zoom-1)/2 + (positron_range_num_sample-1)/2; - const CartesianCoordinate3Dzoomed_min_index = - min_index * zoom - (zoom-1)/2 - (positron_range_num_sample-1)/2; - - shared_ptr > zoomed_density_info_ptr = - new VoxelsOnCartesianGrid(IndexRange<3>(zoomed_min_index, zoomed_max_index), - origin, - zoomed_voxel_size); + const CartesianCoordinate3D zoomed_voxel_size = voxel_size / zoom; + const CartesianCoordinate3D zoomed_max_index = max_index * zoom + (zoom - 1) / 2 + (positron_range_num_sample - 1) / 2; + const CartesianCoordinate3D zoomed_min_index = min_index * zoom - (zoom - 1) / 2 - (positron_range_num_sample - 1) / 2; + + shared_ptr> zoomed_density_info_ptr = + new VoxelsOnCartesianGrid(IndexRange<3>(zoomed_min_index, zoomed_max_index), origin, zoomed_voxel_size); post_projmatrix_ptr->set_up(proj_data_info_ptr, zoomed_density_info_ptr); // TODO think about this. Should somehow depend on symmetries of underlying projmatrix - symmetries_ptr = - new DataSymmetriesForBins_PET_CartesianGrid(proj_data_info_ptr, - density_info_ptr); - + symmetries_ptr = new DataSymmetriesForBins_PET_CartesianGrid(proj_data_info_ptr, density_info_ptr); }; - ////////////////////////////////////// - - -void -ProjMatrixByBinWithPositronRange:: -calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +void +ProjMatrixByBinWithPositronRange::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { // This code is incomplete, and should not be used without major revision // and thorough testing. The reason for BOOST_STATIC_ASSERT is to enforce // this revision and testing before it gets used. @@ -170,14 +130,9 @@ calculate_proj_matrix_elems_for_one_bin( zoomed_projmatrix_ptr->get_proj_matrix_elems_for_one_bin(zoomed_lor); - for (ProjMatrixElemsForOneBin::const_iterator iter = zoomed_lor.begin(); - iter != zoomed_lor.end(); - ++iter) - { - ProjMatrixElemsForOneBinValue - } + for (ProjMatrixElemsForOneBin::const_iterator iter = zoomed_lor.begin(); iter != zoomed_lor.end(); ++iter) { + ProjMatrixElemsForOneBinValue + } } - END_NAMESPACE_STIR - diff --git a/src/experimental/recon_buildblock/ProjMatrixByDensel.cxx b/src/experimental/recon_buildblock/ProjMatrixByDensel.cxx index 6ac4aff05a..0c5c18f92f 100644 --- a/src/experimental/recon_buildblock/ProjMatrixByDensel.cxx +++ b/src/experimental/recon_buildblock/ProjMatrixByDensel.cxx @@ -4,13 +4,13 @@ \file \ingroup recon_buildblock - - \brief implementation of the ProjMatrixByDensel class - + + \brief implementation of the ProjMatrixByDensel class + \author Mustapha Sadki \author Kris Thielemans \author PARAPET project - + */ /* Copyright (C) 2000 PARAPET partners @@ -18,66 +18,50 @@ See STIR/LICENSE.txt for details */ - #include "stir_experimental/recon_buildblock/ProjMatrixByDensel.h" #include "stir/recon_buildblock/ProjMatrixElemsForOneDensel.h" #include "stir/Succeeded.h" //#include #ifndef STIR_NO_NAMESPACES -//using std::cout; -//using std::endl; +// using std::cout; +// using std::endl; #endif - START_NAMESPACE_STIR -ProjMatrixByDensel::ProjMatrixByDensel() -{ - cache_disabled=false; -} - -Succeeded -ProjMatrixByDensel:: -get_cached_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probabilities) const - - - -{ - if ( cache_disabled ) +ProjMatrixByDensel::ProjMatrixByDensel() { cache_disabled = false; } + +Succeeded +ProjMatrixByDensel::get_cached_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel& probabilities) const + +{ + if (cache_disabled) return Succeeded::no; - + const Densel densel = probabilities.get_densel(); #ifndef NDEBUG // Check that this is a 'basic' coordinate - Densel densel_copy = densel; - assert ( !get_symmetries_ptr()->find_basic_densel(densel_copy)); -#endif - - - const_MapProjMatrixElemsForOneDenselIterator pos = - cache_collection.find(cache_key( densel)); - - if ( pos != cache_collection. end()) - { - //cout << Key << " =========>> entry found in cache " << endl; - probabilities = pos->second; - return Succeeded::yes; - } - - //cout << " This entry is not in the cache :" << Key << endl; - return Succeeded::no; -} - + Densel densel_copy = densel; + assert(!get_symmetries_ptr()->find_basic_densel(densel_copy)); +#endif + const_MapProjMatrixElemsForOneDenselIterator pos = cache_collection.find(cache_key(densel)); -//TODO + if (pos != cache_collection.end()) { + // cout << Key << " =========>> entry found in cache " << endl; + probabilities = pos->second; + return Succeeded::yes; + } + // cout << " This entry is not in the cache :" << Key << endl; + return Succeeded::no; +} +// TODO -////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// #if 0 // KT moved here //! store the projection matrix to the file by rows @@ -128,8 +112,6 @@ void ProjMatrixByDensel::write_to_file_by_densel( cout << "End of write_to_file_by_densel " << endl; } - #endif - END_NAMESPACE_STIR diff --git a/src/experimental/recon_buildblock/ProjMatrixByDenselOnCartesianGridUsingElement.cxx b/src/experimental/recon_buildblock/ProjMatrixByDenselOnCartesianGridUsingElement.cxx index b48a2c75d2..fe8c416b96 100644 --- a/src/experimental/recon_buildblock/ProjMatrixByDenselOnCartesianGridUsingElement.cxx +++ b/src/experimental/recon_buildblock/ProjMatrixByDenselOnCartesianGridUsingElement.cxx @@ -15,7 +15,6 @@ See STIR/LICENSE.txt for details */ - #include "stir_experimental/recon_buildblock/ProjMatrixByDenselOnCartesianGridUsingElement.h" #include "stir/DiscretisedDensityOnCartesianGrid.h" #include "stir/Bin.h" @@ -24,42 +23,33 @@ START_NAMESPACE_STIR void -ProjMatrixByDenselOnCartesianGridUsingElement:: -set_up( +ProjMatrixByDenselOnCartesianGridUsingElement::set_up( const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) -{ + const shared_ptr>& density_info_ptr // TODO should be Info only +) { proj_data_info_ptr = proj_data_info_ptr_v; - const DiscretisedDensityOnCartesianGrid<3,float>* image_info_ptr = - dynamic_cast*> (density_info_ptr.get()); + const DiscretisedDensityOnCartesianGrid<3, float>* image_info_ptr = + dynamic_cast*>(density_info_ptr.get()); if (image_info_ptr == NULL) error("ProjMatrixByDenselOnCartesianGridUsingElement initialised with a wrong type of DiscretisedDensity\n"); - grid_spacing = image_info_ptr->get_grid_spacing(); origin = image_info_ptr->get_origin(); - min_z_index = image_info_ptr->get_min_index(); - max_z_index = image_info_ptr->get_max_index(); - - + min_z_index = image_info_ptr->get_min_index(); + max_z_index = image_info_ptr->get_max_index(); }; ////////////////////////////////////// -void -ProjMatrixByDenselOnCartesianGridUsingElement:: -calculate_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +ProjMatrixByDenselOnCartesianGridUsingElement::calculate_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { const Densel densel = probs.get_densel(); const float xctr = densel[3] * grid_spacing.x() - origin.x(); const float yctr = densel[2] * grid_spacing.y() - origin.y(); - const float zctr = - (densel[1] - (min_z_index + max_z_index)/2.F) * grid_spacing.z() + - origin.z(); + const float zctr = (densel[1] - (min_z_index + max_z_index) / 2.F) * grid_spacing.z() + origin.z(); const CartesianCoordinate3D densel_ctr(zctr, yctr, xctr); @@ -69,229 +59,180 @@ calculate_proj_matrix_elems_for_one_densel( // // The easiest is to just loop over all bins, but that's terribly slow. // First optimisation: - // I exit the loops over axial_pos_num and tangential_pos_num as soon as a 0 + // I exit the loops over axial_pos_num and tangential_pos_num as soon as a 0 // LOI is found after a non-zero one. // This avoids computing lots of zeroes to the right of the non-zero range. // This ASSUMES that the nonzero range of bins is connected. // Second optimisation: - // For the loop over tang_pos_num, I also keep track of which tang_pos_num gave the - // first non-zero result for a view (stored in previous_min_tang_pos). The next - // view will then start the tang_pos_num loop from + // For the loop over tang_pos_num, I also keep track of which tang_pos_num gave the + // first non-zero result for a view (stored in previous_min_tang_pos). The next + // view will then start the tang_pos_num loop from // previous_min_tang_pos+previous_inc_min_tang_pos (where the increment is less than -2). // This avoids computing lots of zeroes to the left of the non-zero range. - // There's a check that the increment was enough to the left, but there's still + // There's a check that the increment was enough to the left, but there's still // some work to do there. See comments below. - for (int seg = proj_data_info_ptr->get_min_segment_num(); seg <= proj_data_info_ptr->get_max_segment_num(); ++seg) - { + for (int seg = proj_data_info_ptr->get_min_segment_num(); seg <= proj_data_info_ptr->get_max_segment_num(); ++seg) { int previous_min_tang_pos = proj_data_info_ptr->get_min_tangential_pos_num(); // The current logic checks if start_tang_pos gives non-zero. If so, decrement it, // otherwise, assume that the non-zero bins lie to the right. This is in some - // case not true: it's even more to the left, i.e. previous_inc_min_tang_pos was + // case not true: it's even more to the left, i.e. previous_inc_min_tang_pos was // not negative enough. // So, currently I set the increment such that start_tang_pos is guaranteed to be // less or equal to proj_data_info_ptr->get_min_tangential_pos_num(). // This guarantees I don't miss anything, but it's slow... - int previous_inc_min_tang_pos = - proj_data_info_ptr->get_min_tangential_pos_num() - proj_data_info_ptr->get_max_tangential_pos_num(); - const float num_planes_per_axial_pos = - proj_data_info_ptr->get_sampling_in_t(Bin(seg,0,0,0))* - sqrt(1+square(proj_data_info_ptr->get_tantheta(Bin(seg,0,0,0))))/ - grid_spacing[1]; - const int min_ax_pos = - proj_data_info_ptr->get_min_axial_pos_num(seg) + - static_cast(floor((densel[1]-max_z_index)/num_planes_per_axial_pos - 1)); - const int max_ax_pos = - proj_data_info_ptr->get_max_axial_pos_num(seg) + - static_cast(ceil((densel[1]-min_z_index)/num_planes_per_axial_pos + 1)); + int previous_inc_min_tang_pos = + proj_data_info_ptr->get_min_tangential_pos_num() - proj_data_info_ptr->get_max_tangential_pos_num(); + const float num_planes_per_axial_pos = proj_data_info_ptr->get_sampling_in_t(Bin(seg, 0, 0, 0)) * + sqrt(1 + square(proj_data_info_ptr->get_tantheta(Bin(seg, 0, 0, 0)))) / + grid_spacing[1]; + const int min_ax_pos = proj_data_info_ptr->get_min_axial_pos_num(seg) + + static_cast(floor((densel[1] - max_z_index) / num_planes_per_axial_pos - 1)); + const int max_ax_pos = proj_data_info_ptr->get_max_axial_pos_num(seg) + + static_cast(ceil((densel[1] - min_z_index) / num_planes_per_axial_pos + 1)); int previous_min_ax_pos = min_ax_pos; int previous_inc_min_ax_pos = -1; - for (int view = proj_data_info_ptr->get_min_view_num(); view <= proj_data_info_ptr->get_max_view_num(); ++view) - { + for (int view = proj_data_info_ptr->get_min_view_num(); view <= proj_data_info_ptr->get_max_view_num(); ++view) { bool found_nonzero_axial = false; int start_ax_pos = previous_min_ax_pos + previous_inc_min_ax_pos; int ax_pos_inc = -1; - for (int ax_pos = start_ax_pos; ax_pos <= max_ax_pos; ax_pos+=ax_pos_inc) - { - if (ax_posget_max_tangential_pos_num(); tang_pos+=tang_pos_inc) - { - if (tang_posget_min_tangential_pos_num()) - { + for (int tang_pos = start_tang_pos; tang_pos <= proj_data_info_ptr->get_max_tangential_pos_num(); + tang_pos += tang_pos_inc) { + if (tang_pos < proj_data_info_ptr->get_min_tangential_pos_num()) { tang_pos_inc = 1; - tang_pos=proj_data_info_ptr->get_min_tangential_pos_num(); + tang_pos = proj_data_info_ptr->get_min_tangential_pos_num(); continue; } // else - + bin.tangential_pos_num() = tang_pos; - const float LOI = - get_element(bin, densel_ctr); - if (LOI > 0) - { - if (tang_pos_inc==-1) - { + const float LOI = get_element(bin, densel_ctr); + if (LOI > 0) { + if (tang_pos_inc == -1) { // it's non-zero, check next bin to the left --previous_inc_min_tang_pos; - } - else - { - if (!found_nonzero_tangential) - { - //std::cerr << "\tfirst tang_pos at " << tang_pos + } else { + if (!found_nonzero_tangential) { + // std::cerr << "\tfirst tang_pos at " << tang_pos // << '(' << seg << ',' << view << ',' << ax_pos << ')'<< std::endl; previous_min_tang_pos = tang_pos; found_nonzero_tangential = true; } - if (ax_pos_inc==+1) - { - bin.set_bin_value(LOI); + if (ax_pos_inc == +1) { + bin.set_bin_value(LOI); probs.push_back(ProjMatrixElemsForOneDensel::value_type(bin)); } } - } - else // the Pbv was zero + } else // the Pbv was zero { - if (tang_pos_inc==-1) - { - tang_pos_inc=1; - } - else - { - if (found_nonzero_tangential) - { + if (tang_pos_inc == -1) { + tang_pos_inc = 1; + } else { + if (found_nonzero_tangential) { // the first tang_pos where the result is zero again. So, all the next ones will be 0 as well. break; } } } } // end loop over tang_pos - if (found_nonzero_tangential) - { - if (ax_pos_inc==-1) - { + if (found_nonzero_tangential) { + if (ax_pos_inc == -1) { // it's non-zero, check next bin to the left --previous_inc_min_ax_pos; - } - else - { - if (!found_nonzero_axial) - { + } else { + if (!found_nonzero_axial) { previous_min_ax_pos = ax_pos; found_nonzero_axial = true; } } - } - else // all bins for this ax_pos were zero + } else // all bins for this ax_pos were zero { - if (ax_pos_inc==-1) - { + if (ax_pos_inc == -1) { ax_pos_inc = 1; - } - else if (found_nonzero_axial) - { + } else if (found_nonzero_axial) { // the first ax_pos where the result is zero again. So, all the next ones will be 0 as well. break; - // TODO potentially, the mechanism of using previous_min_ax_pos caused the + // TODO potentially, the mechanism of using previous_min_ax_pos caused the // ax_pos loop to miss to non-zero bins. See above } } - } - + #else - while(true) - { + while (true) { // if we're at the smallest bin, keep the increment - if (start_tang_pos<=proj_data_info_ptr->get_min_tangential_pos_num()) - { - start_tang_pos=proj_data_info_ptr->get_min_tangential_pos_num(); + if (start_tang_pos <= proj_data_info_ptr->get_min_tangential_pos_num()) { + start_tang_pos = proj_data_info_ptr->get_min_tangential_pos_num(); break; - } - else - { - const float LOI = - get_element(bin, densel_ctr); - if (LOI > 0) - { + } else { + const float LOI = get_element(bin, densel_ctr); + if (LOI > 0) { // it's non-zero, check next bin to the left --previous_inc_min_tang_pos; --start_tang_pos; - } - else + } else break; } } - if (start_tang_pos > proj_data_info_ptr->get_min_tangential_pos_num()) - { + if (start_tang_pos > proj_data_info_ptr->get_min_tangential_pos_num()) { // the current bin was 0, so we don't have to redo it ++start_tang_pos; } - //std::cerr << "Start at tang_pos " << start_tang_pos + // std::cerr << "Start at tang_pos " << start_tang_pos // << " (" << seg << ',' << view << ',' << ax_pos << ')'<< std::endl; - for (int tang_pos = start_tang_pos; tang_pos <= proj_data_info_ptr->get_max_tangential_pos_num(); ++tang_pos) - { - Bin bin(seg, view, ax_pos, tang_pos); - const float LOI = - get_element(bin, densel_ctr); - if (LOI > 0) - { - if (!found_nonzero_tangential) - { - //std::cerr << "\tfirst tang_pos at " << tang_pos + for (int tang_pos = start_tang_pos; tang_pos <= proj_data_info_ptr->get_max_tangential_pos_num(); ++tang_pos) { + Bin bin(seg, view, ax_pos, tang_pos); + const float LOI = get_element(bin, densel_ctr); + if (LOI > 0) { + if (!found_nonzero_tangential) { + // std::cerr << "\tfirst tang_pos at " << tang_pos // << '(' << seg << ',' << view << ',' << ax_pos << ')'<< std::endl; - //XXXprevious_min_tang_pos = tang_pos; + // XXXprevious_min_tang_pos = tang_pos; } found_nonzero_tangential = true; - bin.set_bin_value(LOI); + bin.set_bin_value(LOI); probs.push_back(ProjMatrixElemsForOneDensel::value_type(bin)); - } - else if (found_nonzero_tangential) - { + } else if (found_nonzero_tangential) { // the first tang_pos where the result is zero again. So, all the next ones will be 0 as well. - //XXXbreak; + // XXXbreak; } } // end loop over tang_pos - if (found_nonzero_axial) - { - if (!found_nonzero_tangential) - { + if (found_nonzero_axial) { + if (!found_nonzero_tangential) { // the first ax_pos where the result is zero again. So, all the next ones will be 0 as well. - //XXXbreak; - // TODO potentially, the mechanism of using previous_min_tang_pos caused the + // XXXbreak; + // TODO potentially, the mechanism of using previous_min_tang_pos caused the // tang_pos loop to miss to non-zero bins. This would occur if start_tang_pos was to // the 'right' of the nonzero range. - // The only way I see to check this is to do a + // The only way I see to check this is to do a // loop here to the left of the start_tang_pos; } - } - else - { - //if (found_nonzero_tangential) + } else { + // if (found_nonzero_tangential) // std::cerr << "first ax_pos at " << ax_pos // << '(' << seg << ',' << view << ')' << std::endl; found_nonzero_axial = found_nonzero_tangential; } - } #endif // next assert only possible when every voxel is detected at least once in every seg,view @@ -299,7 +240,6 @@ calculate_proj_matrix_elems_for_one_densel( // assert(found_nonzero_axial); } } - #if 0 @@ -391,4 +331,3 @@ static void merge_zplus1(ProjMatrixElemsForOneDensel& probs) #endif END_NAMESPACE_STIR - diff --git a/src/experimental/recon_buildblock/ProjMatrixByDenselUsingRayTracing.cxx b/src/experimental/recon_buildblock/ProjMatrixByDenselUsingRayTracing.cxx index 94261610aa..b6d7290626 100644 --- a/src/experimental/recon_buildblock/ProjMatrixByDenselUsingRayTracing.cxx +++ b/src/experimental/recon_buildblock/ProjMatrixByDenselUsingRayTracing.cxx @@ -15,8 +15,6 @@ See STIR/LICENSE.txt for details */ - - #include "stir_experimental/recon_buildblock/ProjMatrixByDenselUsingRayTracing.h" #include "stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.h" #include "stir/VoxelsOnCartesianGrid.h" @@ -32,110 +30,84 @@ using std::min; START_NAMESPACE_STIR +const char* const ProjMatrixByDenselUsingRayTracing::registered_name = "Ray Tracing"; -const char * const -ProjMatrixByDenselUsingRayTracing::registered_name = - "Ray Tracing"; - -ProjMatrixByDenselUsingRayTracing:: -ProjMatrixByDenselUsingRayTracing() -{ - set_defaults(); -} +ProjMatrixByDenselUsingRayTracing::ProjMatrixByDenselUsingRayTracing() { set_defaults(); } -void -ProjMatrixByDenselUsingRayTracing::initialise_keymap() -{ +void +ProjMatrixByDenselUsingRayTracing::initialise_keymap() { parser.add_start_key("Ray Tracing Matrix Parameters"); - //parser.add_key("restrict to cylindrical FOV", &restrict_to_cylindrical_FOV); - parser.add_key("number of rays in tangential direction to trace for each bin", - &num_tangential_LORs); + // parser.add_key("restrict to cylindrical FOV", &restrict_to_cylindrical_FOV); + parser.add_key("number of rays in tangential direction to trace for each bin", &num_tangential_LORs); parser.add_key("use actual detector boundaries", &use_actual_detector_boundaries); -parser.add_stop_key("End Ray Tracing Matrix Parameters"); + parser.add_stop_key("End Ray Tracing Matrix Parameters"); } - void -ProjMatrixByDenselUsingRayTracing::set_defaults() -{ - //ProjMatrixByDensel::set_defaults(); - //restrict_to_cylindrical_FOV = true; +ProjMatrixByDenselUsingRayTracing::set_defaults() { + // ProjMatrixByDensel::set_defaults(); + // restrict_to_cylindrical_FOV = true; num_tangential_LORs = 1; use_actual_detector_boundaries = false; } - bool -ProjMatrixByDenselUsingRayTracing::post_processing() -{ - //if (ProjMatrixByDensel::post_processing() == true) +ProjMatrixByDenselUsingRayTracing::post_processing() { + // if (ProjMatrixByDensel::post_processing() == true) // return true; - if (num_tangential_LORs<1) - { - warning("ProjMatrixByDenselUsingRayTracing: num_tangential_LORs should be at least 1, but is %d\n", - num_tangential_LORs); + if (num_tangential_LORs < 1) { + warning("ProjMatrixByDenselUsingRayTracing: num_tangential_LORs should be at least 1, but is %d\n", num_tangential_LORs); return true; } return false; } const DataSymmetriesForDensels* -ProjMatrixByDenselUsingRayTracing:: get_symmetries_ptr() const -{ - return symmetries_ptr.get(); +ProjMatrixByDenselUsingRayTracing::get_symmetries_ptr() const { + return symmetries_ptr.get(); } void -ProjMatrixByDenselUsingRayTracing:: -set_up( +ProjMatrixByDenselUsingRayTracing::set_up( const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) -{ + const shared_ptr>& density_info_ptr // TODO should be Info only +) { base_type::set_up(proj_data_info_ptr_v, density_info_ptr); - const VoxelsOnCartesianGrid * image_info_ptr = - dynamic_cast*> (density_info_ptr.get()); + const VoxelsOnCartesianGrid* image_info_ptr = dynamic_cast*>(density_info_ptr.get()); if (image_info_ptr == NULL) error("ProjMatrixByDenselUsingRayTracing initialised with a wrong type of DiscretisedDensity\n"); - voxel_size = image_info_ptr->get_voxel_size(); origin = image_info_ptr->get_origin(); image_info_ptr->get_regular_range(min_index, max_index); - - for (int segment_num = proj_data_info_ptr->get_min_segment_num(); - segment_num <= proj_data_info_ptr->get_max_segment_num(); - ++segment_num) - { - Bin bin (segment_num,0,0,0); - if (fabs(proj_data_info_ptr->get_sampling_in_m(bin) / voxel_size.z() - 1)> .001) - error("ProjMatrixByDenselUsingRayTracing used for pixel size (in z) which is " - "not equal to the axial sampling (you're probably not using axially compressed data). I can't handle " - "this yet. Sorry.\n"); + for (int segment_num = proj_data_info_ptr->get_min_segment_num(); segment_num <= proj_data_info_ptr->get_max_segment_num(); + ++segment_num) { + Bin bin(segment_num, 0, 0, 0); + if (fabs(proj_data_info_ptr->get_sampling_in_m(bin) / voxel_size.z() - 1) > .001) + error("ProjMatrixByDenselUsingRayTracing used for pixel size (in z) which is " + "not equal to the axial sampling (you're probably not using axially compressed data). I can't handle " + "this yet. Sorry.\n"); } - symmetries_ptr - .reset(new DataSymmetriesForDensels_PET_CartesianGrid(proj_data_info_ptr, - density_info_ptr)); - const float sampling_distance_of_adjacent_LORs_xy = - proj_data_info_ptr->get_sampling_in_s(Bin(0,0,0,0)); - - if(sampling_distance_of_adjacent_LORs_xy > voxel_size.x() + 1.E-3 || - sampling_distance_of_adjacent_LORs_xy > voxel_size.y() + 1.E-3) - warning("WARNING: ProjMatrixByDenselUsingRayTracing used for pixel size (in x,y) " - "that is smaller than the densel size.\n" - "This matrix will completely miss some voxels for some (or all) views.\n"); - if(sampling_distance_of_adjacent_LORs_xy < voxel_size.x() - 1.E-3 || - sampling_distance_of_adjacent_LORs_xy < voxel_size.y() - 1.E-3) - warning("WARNING: ProjMatrixByDenselUsingRayTracing used for pixel size (in x,y) " - "that is larger than the densel size.\n" - "Backprojecting with this matrix will have artefacts at views 0 and 90 degrees.\n"); - - xhalfsize = voxel_size.x()/2; - yhalfsize = voxel_size.y()/2; - zhalfsize = voxel_size.z()/2; + symmetries_ptr.reset(new DataSymmetriesForDensels_PET_CartesianGrid(proj_data_info_ptr, density_info_ptr)); + const float sampling_distance_of_adjacent_LORs_xy = proj_data_info_ptr->get_sampling_in_s(Bin(0, 0, 0, 0)); + + if (sampling_distance_of_adjacent_LORs_xy > voxel_size.x() + 1.E-3 || + sampling_distance_of_adjacent_LORs_xy > voxel_size.y() + 1.E-3) + warning("WARNING: ProjMatrixByDenselUsingRayTracing used for pixel size (in x,y) " + "that is smaller than the densel size.\n" + "This matrix will completely miss some voxels for some (or all) views.\n"); + if (sampling_distance_of_adjacent_LORs_xy < voxel_size.x() - 1.E-3 || + sampling_distance_of_adjacent_LORs_xy < voxel_size.y() - 1.E-3) + warning("WARNING: ProjMatrixByDenselUsingRayTracing used for pixel size (in x,y) " + "that is larger than the densel size.\n" + "Backprojecting with this matrix will have artefacts at views 0 and 90 degrees.\n"); + + xhalfsize = voxel_size.x() / 2; + yhalfsize = voxel_size.y() / 2; + zhalfsize = voxel_size.z() / 2; }; #if 0 @@ -153,87 +125,66 @@ add_adjacent_z(ProjMatrixElemsForOneDensel& probs); */ static void merge_zplus1(ProjMatrixElemsForOneDensel& probs); #endif -static inline int sign(const float x) -{ return x>=0 ? 1 : - 1; } - +static inline int +sign(const float x) { + return x >= 0 ? 1 : -1; +} // for positive halfsizes, this is valid for 0<=phi<=Pi/2 && 0& densel_ctr, - const float xhalfsize, const float yhalfsize, const float zhalfsize, - const float ctheta, const float tantheta, - const float cphi, const float sphi, - const float m, const float s) -{ +static inline float +projection_of_voxel(const CartesianCoordinate3D& densel_ctr, const float xhalfsize, const float yhalfsize, + const float zhalfsize, const float ctheta, const float tantheta, const float cphi, const float sphi, + const float m, const float s) { // if you want to relax the next assertion, replace yhalfsize with sign(sphi)*yhalfsize below - //assert(sphi>0); - return - fabs(tantheta)<1.E-4 ? - projection2D_of_voxel_help(densel_ctr.x(), densel_ctr.y(), densel_ctr.z(), - sign(cphi)*xhalfsize, sign(sphi)*yhalfsize, zhalfsize, - cphi, sphi, - m, s) - : - projection_of_voxel_help(densel_ctr.x(), densel_ctr.y(), densel_ctr.z(), - sign(cphi)*xhalfsize, sign(sphi)*yhalfsize, sign(tantheta)*zhalfsize, - ctheta, tantheta, - cphi, sphi, - m, s); + // assert(sphi>0); + return fabs(tantheta) < 1.E-4 + ? projection2D_of_voxel_help(densel_ctr.x(), densel_ctr.y(), densel_ctr.z(), sign(cphi) * xhalfsize, + sign(sphi) * yhalfsize, zhalfsize, cphi, sphi, m, s) + : projection_of_voxel_help(densel_ctr.x(), densel_ctr.y(), densel_ctr.z(), sign(cphi) * xhalfsize, + sign(sphi) * yhalfsize, sign(tantheta) * zhalfsize, ctheta, tantheta, cphi, sphi, m, s); } #if 0 @@ -244,15 +195,12 @@ static inline float #endif float -ProjMatrixByDenselUsingRayTracing:: -get_element(const Bin& bin, - const CartesianCoordinate3D& densel_ctr) const -{ +ProjMatrixByDenselUsingRayTracing::get_element(const Bin& bin, const CartesianCoordinate3D& densel_ctr) const { const ProjDataInfo& proj_data_info = *proj_data_info_ptr; const float tantheta = proj_data_info.get_tantheta(bin); - const float costheta = 1/sqrt(1+square(tantheta)); - const float m = proj_data_info.get_t(bin)/costheta; + const float costheta = 1 / sqrt(1 + square(tantheta)); + const float m = proj_data_info.get_t(bin) / costheta; float phi; float s_in_mm = proj_data_info_ptr->get_s(bin); @@ -265,92 +213,63 @@ file. on Linux on x86. A bit of a mistery that. */ - if (!use_actual_detector_boundaries) - { + if (!use_actual_detector_boundaries) { phi = proj_data_info_ptr->get_phi(bin); - //s_in_mm = proj_data_info_ptr->get_s(bin); - } - else - { + // s_in_mm = proj_data_info_ptr->get_s(bin); + } else { // can be static_cast later on const ProjDataInfoCylindricalNoArcCorr& proj_data_info_noarccor = - dynamic_cast(*proj_data_info_ptr); + dynamic_cast(*proj_data_info_ptr); // TODO check on 180 degrees for views - const int num_detectors = - proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); - const float ring_radius = - proj_data_info_ptr->get_scanner_ptr()->get_effective_ring_radius(); - - int det_num1=0, det_num2=0; - proj_data_info_noarccor. - get_det_num_pair_for_view_tangential_pos_num(det_num1, - det_num2, - bin.view_num(), - bin.tangential_pos_num()); - phi = (det_num1+det_num2)*_PI/num_detectors-_PI/2; - - s_in_mm = ring_radius*sin((det_num1-det_num2)*_PI/num_detectors+_PI/2); + const int num_detectors = proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); + const float ring_radius = proj_data_info_ptr->get_scanner_ptr()->get_effective_ring_radius(); + + int det_num1 = 0, det_num2 = 0; + proj_data_info_noarccor.get_det_num_pair_for_view_tangential_pos_num(det_num1, det_num2, bin.view_num(), + bin.tangential_pos_num()); + phi = (det_num1 + det_num2) * _PI / num_detectors - _PI / 2; + + s_in_mm = ring_radius * sin((det_num1 - det_num2) * _PI / num_detectors + _PI / 2); } // phi in KT's Mathematica conventions - const float phiKT = phi + _PI/2; + const float phiKT = phi + _PI / 2; const float cphi = cos(phiKT); const float sphi = sin(phiKT); - + // KT TODOCHECK s_in_mm *= -1; float res = 0; - - if (num_tangential_LORs == 1) - { - res = - projection_of_voxel(densel_ctr, - xhalfsize, yhalfsize, zhalfsize, - costheta, tantheta, - cphi, sphi, - m, s_in_mm); - } - else - { + + if (num_tangential_LORs == 1) { + res = projection_of_voxel(densel_ctr, xhalfsize, yhalfsize, zhalfsize, costheta, tantheta, cphi, sphi, m, s_in_mm); + } else { // get_sampling_in_s returns sampling in interleaved case // interleaved case has a sampling which is twice as high const float s_inc = - (!use_actual_detector_boundaries ? 1 : 2) * - proj_data_info_ptr->get_sampling_in_s(bin)/num_tangential_LORs; - float current_s_in_mm = - s_in_mm - s_inc*(num_tangential_LORs-1)/2.F; + (!use_actual_detector_boundaries ? 1 : 2) * proj_data_info_ptr->get_sampling_in_s(bin) / num_tangential_LORs; + float current_s_in_mm = s_in_mm - s_inc * (num_tangential_LORs - 1) / 2.F; bool found_non_zero = false; - for (int s_LOR_num=1; s_LOR_num<=num_tangential_LORs; ++s_LOR_num, current_s_in_mm+=s_inc) - { + for (int s_LOR_num = 1; s_LOR_num <= num_tangential_LORs; ++s_LOR_num, current_s_in_mm += s_inc) { const float current_res = - projection_of_voxel(densel_ctr, - xhalfsize, yhalfsize, zhalfsize, - costheta, tantheta, - cphi, sphi, - m, current_s_in_mm); - if (current_res>0) - { - found_non_zero = true; - res += current_res; - } - else if (found_non_zero) - { + projection_of_voxel(densel_ctr, xhalfsize, yhalfsize, zhalfsize, costheta, tantheta, cphi, sphi, m, current_s_in_mm); + if (current_res > 0) { + found_non_zero = true; + res += current_res; + } else if (found_non_zero) { // we've found non_zeroes, but this is one IS 0, so all the next ones // will be 0 as well. So, we get out. continue; } - } + } } - - return - (res > xhalfsize/1000.) ? - res + + return (res > xhalfsize / 1000.) ? res #ifndef NEWSCALE - /voxel_size.x() // normalise to some kind of 'pixel units' + / voxel_size.x() // normalise to some kind of 'pixel units' #endif - : 0; + : 0; } END_NAMESPACE_STIR - diff --git a/src/experimental/recon_buildblock/local_recon_buildblock_registries.cxx b/src/experimental/recon_buildblock/local_recon_buildblock_registries.cxx index f7edd08182..3872beacfb 100644 --- a/src/experimental/recon_buildblock/local_recon_buildblock_registries.cxx +++ b/src/experimental/recon_buildblock/local_recon_buildblock_registries.cxx @@ -13,10 +13,9 @@ \author Kris Thielemans */ - #if 0 -#include "stir_experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.h" -#include "stir_experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.h" +# include "stir_experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.h" +# include "stir_experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.h" #endif //#include "stir_experimental/recon_buildblock/BackProjectorByBinDistanceDriven.h" @@ -27,13 +26,13 @@ //#include "stir_experimental/recon_buildblock/oldBackProjectorByBinUsingInterpolation.h" #include "stir_experimental/recon_buildblock/PostsmoothingForwardProjectorByBin.h" #if 0 -#include "stir_experimental/recon_buildblock/BinNormalisationUsingProfile.h" -#include "stir_experimental/recon_buildblock/BinNormalisationSinogramRescaling.h" +# include "stir_experimental/recon_buildblock/BinNormalisationUsingProfile.h" +# include "stir_experimental/recon_buildblock/BinNormalisationSinogramRescaling.h" //#include "stir/recon_buildblock/FilterRootPrior.h" -#include "stir_experimental/recon_buildblock/ParametricQuadraticPrior.h" -#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h" -#include "stir/modelling/ParametricDiscretisedDensity.h" -#include "stir/DynamicDiscretisedDensity.h" +# include "stir_experimental/recon_buildblock/ParametricQuadraticPrior.h" +# include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h" +# include "stir/modelling/ParametricDiscretisedDensity.h" +# include "stir/DynamicDiscretisedDensity.h" #endif START_NAMESPACE_STIR @@ -47,15 +46,15 @@ static PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::RegisterIt dummy5; #endif -//static PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData::RegisterIt Dummyyyy; -//static BackProjectorByBinDistanceDriven::RegisterIt dummy1001; -//static ForwardProjectorByBinDistanceDriven::RegisterIt dummy1002; +// static PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData::RegisterIt Dummyyyy; +// static BackProjectorByBinDistanceDriven::RegisterIt dummy1001; +// static ForwardProjectorByBinDistanceDriven::RegisterIt dummy1002; -//static NonquadraticPriorWithNaturalLogarithm::RegisterIt dummy22; +// static NonquadraticPriorWithNaturalLogarithm::RegisterIt dummy22; -//static oldForwardProjectorByBinUsingRayTracing::RegisterIt dummy1; +// static oldForwardProjectorByBinUsingRayTracing::RegisterIt dummy1; static PostsmoothingForwardProjectorByBin::RegisterIt dummy2; -//static oldBackProjectorByBinUsingInterpolation::RegisterIt dummy5; +// static oldBackProjectorByBinUsingInterpolation::RegisterIt dummy5; #if 0 diff --git a/src/experimental/recon_test/fwdtestDensel.cxx b/src/experimental/recon_test/fwdtestDensel.cxx index 240ae0a2c5..af30f065cc 100644 --- a/src/experimental/recon_test/fwdtestDensel.cxx +++ b/src/experimental/recon_test/fwdtestDensel.cxx @@ -12,7 +12,7 @@ This programme allows forward projection of a few segments/views - only, or of the full data set. + only, or of the full data set. Usage: \verbatim @@ -21,7 +21,7 @@ The proj_data_file will be used to get the scanner, mashing etc. details (its data will \e not be used, nor will it be overwritten). If no proj_data_file is given, some questions are asked to use 'standard' - characteristics. + characteristics. */ /* Copyright (C) 2000 PARAPET partners @@ -43,362 +43,255 @@ #include "stir/CPUTimer.h" #include - - USING_NAMESPACE_STIR USING_NAMESPACE_STD - /******************* Declarations local functions *******************/ -static void -do_segments(const VoxelsOnCartesianGrid& image, ProjData& s3d, - const int min_z, const int max_z, - const int min_y, const int max_y, - const int min_x, const int max_x, - ProjMatrixByDensel&, - const bool disp); -static void -fill_cuboid(VoxelsOnCartesianGrid& image); -static void -fill_cylinder(VoxelsOnCartesianGrid& image); - - +static void do_segments(const VoxelsOnCartesianGrid& image, ProjData& s3d, const int min_z, const int max_z, + const int min_y, const int max_y, const int min_x, const int max_x, ProjMatrixByDensel&, const bool disp); +static void fill_cuboid(VoxelsOnCartesianGrid& image); +static void fill_cylinder(VoxelsOnCartesianGrid& image); /*************************** main ***********************************/ -int -main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { - if(argc!=2) - { - cerr<<"Usage: " << argv[0] << " [proj_data-file]\n" - <<"The projdata-file will be used to get the scanner, mashing etc. details" - << endl; + if (argc != 2) { + cerr << "Usage: " << argv[0] << " [proj_data-file]\n" + << "The projdata-file will be used to get the scanner, mashing etc. details" << endl; } - ProjDataInfo* new_data_info_ptr; - if(argc==2) - { - shared_ptr proj_data_ptr = - ProjData::read_from_file(argv[1]); - new_data_info_ptr= proj_data_ptr->get_proj_data_info_sptr()->clone(); + if (argc == 2) { + shared_ptr proj_data_ptr = ProjData::read_from_file(argv[1]); + new_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr()->clone(); + } else { + new_data_info_ptr = ProjDataInfo::ask_parameters(); } - else - { - new_data_info_ptr= ProjDataInfo::ask_parameters(); - } - int limit_segments= - ask_num("Maximum absolute segment number to process: ", 0, - new_data_info_ptr->get_max_segment_num(), - new_data_info_ptr->get_max_segment_num() ); + int limit_segments = ask_num("Maximum absolute segment number to process: ", 0, new_data_info_ptr->get_max_segment_num(), + new_data_info_ptr->get_max_segment_num()); new_data_info_ptr->reduce_segment_range(-limit_segments, limit_segments); const string output_file_name = "fwdtest_out.s"; - shared_ptr sino_stream = new fstream (output_file_name.c_str(), ios::out|ios::binary); - if (!sino_stream->good()) - { - error("fwdtest: error opening file %s\n",output_file_name.c_str()); + shared_ptr sino_stream = new fstream(output_file_name.c_str(), ios::out | ios::binary); + if (!sino_stream->good()) { + error("fwdtest: error opening file %s\n", output_file_name.c_str()); } - shared_ptr proj_data_ptr = - new ProjDataFromStream(new_data_info_ptr,sino_stream); + shared_ptr proj_data_ptr = new ProjDataFromStream(new_data_info_ptr, sino_stream); write_basic_interfile_PDFS_header(output_file_name, *proj_data_ptr); - cerr << "Output will be written to " << output_file_name - << " and its Interfile header\n"; + cerr << "Output will be written to " << output_file_name << " and its Interfile header\n"; - - const int dispstart = - ask_num("Display start image ? no (0), yes (1)", - 0,1,0); + const int dispstart = ask_num("Display start image ? no (0), yes (1)", 0, 1, 0); - const int save = - ask_num("Save start images ? no (0), yes (1)", - 0,1,0); - - shared_ptr > image_sptr = 0; - VoxelsOnCartesianGrid * vox_image_ptr = 0; + const int save = ask_num("Save start images ? no (0), yes (1)", 0, 1, 0); + shared_ptr> image_sptr = 0; + VoxelsOnCartesianGrid* vox_image_ptr = 0; - switch (ask_num("Start image is cuboid (1) or cylinder (2) or on file (3)",1,3,2)) - { - case 1: - { - const float zoom = ask_num("Zoom factor (>1 means smaller voxels)",0.F,10.F,1.F); - int xy_size = static_cast(proj_data_ptr->get_num_tangential_poss()*zoom); - xy_size = ask_num("Number of x,y pixels",3,xy_size*2,xy_size); - int z_size = 2*proj_data_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings()-1; - z_size = ask_num("Number of z pixels",1,1000,z_size); - image_sptr = vox_image_ptr = - new VoxelsOnCartesianGrid(*(proj_data_ptr->get_proj_data_info_sptr()), - zoom, - CartesianCoordinate3D(0,0,0), - Coordinate3D(z_size,xy_size,xy_size)); - - fill_cuboid(*vox_image_ptr); - break; - } - case 2: - { - const float zoom = ask_num("Zoom factor (>1 means smaller voxels)",0.F,10.F,1.F); - int xy_size = static_cast(proj_data_ptr->get_num_tangential_poss()*zoom); - xy_size = ask_num("Number of x,y pixels",3,xy_size*2,xy_size); - int z_size = 2*proj_data_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings()-1; - z_size = ask_num("Number of z pixels",1,1000,z_size); - image_sptr = vox_image_ptr = - new VoxelsOnCartesianGrid(*(proj_data_ptr->get_proj_data_info_sptr()), - zoom, - CartesianCoordinate3D(0,0,0), - Coordinate3D(z_size,xy_size,xy_size)); - fill_cylinder(*vox_image_ptr); - break; - } - case 3: - { - char filename[max_filename_length]; - - ask_filename_with_extension(filename, "Input file name ?", ".hv"); - - image_sptr = - DiscretisedDensity<3,float>::read_from_file(filename); - vox_image_ptr = dynamic_cast *> (image_sptr.get()); - - break; - } + switch (ask_num("Start image is cuboid (1) or cylinder (2) or on file (3)", 1, 3, 2)) { + case 1: { + const float zoom = ask_num("Zoom factor (>1 means smaller voxels)", 0.F, 10.F, 1.F); + int xy_size = static_cast(proj_data_ptr->get_num_tangential_poss() * zoom); + xy_size = ask_num("Number of x,y pixels", 3, xy_size * 2, xy_size); + int z_size = 2 * proj_data_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings() - 1; + z_size = ask_num("Number of z pixels", 1, 1000, z_size); + image_sptr = vox_image_ptr = + new VoxelsOnCartesianGrid(*(proj_data_ptr->get_proj_data_info_sptr()), zoom, CartesianCoordinate3D(0, 0, 0), + Coordinate3D(z_size, xy_size, xy_size)); + + fill_cuboid(*vox_image_ptr); + break; + } + case 2: { + const float zoom = ask_num("Zoom factor (>1 means smaller voxels)", 0.F, 10.F, 1.F); + int xy_size = static_cast(proj_data_ptr->get_num_tangential_poss() * zoom); + xy_size = ask_num("Number of x,y pixels", 3, xy_size * 2, xy_size); + int z_size = 2 * proj_data_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings() - 1; + z_size = ask_num("Number of z pixels", 1, 1000, z_size); + image_sptr = vox_image_ptr = + new VoxelsOnCartesianGrid(*(proj_data_ptr->get_proj_data_info_sptr()), zoom, CartesianCoordinate3D(0, 0, 0), + Coordinate3D(z_size, xy_size, xy_size)); + fill_cylinder(*vox_image_ptr); + break; + } + case 3: { + char filename[max_filename_length]; + + ask_filename_with_extension(filename, "Input file name ?", ".hv"); + + image_sptr = DiscretisedDensity<3, float>::read_from_file(filename); + vox_image_ptr = dynamic_cast*>(image_sptr.get()); + + break; + } } - const float z_origin = - ask_num("Shift z-origin (in pixels)", - -vox_image_ptr->get_length()/2, - vox_image_ptr->get_length()/2, - 0) *vox_image_ptr->get_voxel_size().z(); - - vox_image_ptr->set_origin(Coordinate3D(z_origin,0,0)); + const float z_origin = + ask_num("Shift z-origin (in pixels)", -vox_image_ptr->get_length() / 2, vox_image_ptr->get_length() / 2, 0) * + vox_image_ptr->get_voxel_size().z(); + + vox_image_ptr->set_origin(Coordinate3D(z_origin, 0, 0)); // use shared_ptr such that it cleans up automatically - shared_ptr proj_matrix_ptr = - new ProjMatrixByDenselUsingRayTracing; -/* do - { - proj_matrix_ptr= - ProjMatrixByDensel::ask_type_and_parameters(); - } - while (proj_matrix_ptr.use_count()==0); -*/ - proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), - image_sptr); + shared_ptr proj_matrix_ptr = new ProjMatrixByDenselUsingRayTracing; + /* do + { + proj_matrix_ptr= + ProjMatrixByDensel::ask_type_and_parameters(); + } + while (proj_matrix_ptr.use_count()==0); + */ + proj_matrix_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), image_sptr); cerr << proj_matrix_ptr->parameter_info(); - if (dispstart) - { - cerr << "Displaying start image"; - //display(*image_sptr, image_sptr->find_max()); - } - + if (dispstart) { + cerr << "Displaying start image"; + // display(*image_sptr, image_sptr->find_max()); + } - if (save) - { + if (save) { cerr << "Saving start image to 'test_image'" << endl; write_basic_interfile("test_image", *image_sptr); } - - -// if (ask("Do full forward projection ?", true)) - //do - { + + // if (ask("Do full forward projection ?", true)) + // do + { const int min_z = ask_num("Min z", vox_image_ptr->get_min_z(), vox_image_ptr->get_max_z(), vox_image_ptr->get_min_z()); const int max_z = ask_num("Max z", min_z, vox_image_ptr->get_max_z(), vox_image_ptr->get_max_z()); const int min_y = ask_num("Min y", vox_image_ptr->get_min_y(), vox_image_ptr->get_max_y(), vox_image_ptr->get_min_y()); const int max_y = ask_num("Max y", min_y, vox_image_ptr->get_max_y(), vox_image_ptr->get_max_y()); const int min_x = ask_num("Min x", vox_image_ptr->get_min_x(), vox_image_ptr->get_max_x(), vox_image_ptr->get_min_x()); const int max_x = ask_num("Max x", min_x, vox_image_ptr->get_max_x(), vox_image_ptr->get_max_x()); - + CPUTimer timer; timer.reset(); timer.start(); - - do_segments(*vox_image_ptr, *proj_data_ptr, - min_z, max_z, - min_y, max_y, - min_x, max_x, - *proj_matrix_ptr, - false); - - timer.stop(); - cerr << timer.value() << " s CPU time"<& image, - ProjData& proj_data, - const int min_z, const int max_z, - const int min_y, const int max_y, - const int min_x, const int max_x, - ProjMatrixByDensel& proj_matrix, - const bool disp) -{ +do_segments(const VoxelsOnCartesianGrid& image, ProjData& proj_data, const int min_z, const int max_z, const int min_y, + const int max_y, const int min_x, const int max_x, ProjMatrixByDensel& proj_matrix, const bool disp) { const int start_segment_num = proj_data.get_min_segment_num(); const int end_segment_num = proj_data.get_max_segment_num(); - VectorWithOffset *> all_segments(start_segment_num, end_segment_num); + VectorWithOffset*> all_segments(start_segment_num, end_segment_num); for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) all_segments[segment_num] = new SegmentByView(proj_data.get_empty_segment_by_view(segment_num)); ProjMatrixElemsForOneDensel probs; - for (int z = min_z; z<= max_z; ++z) - { - //std::cerr << "z "<< z<< std::endl; - for (int y = min_y; y<= max_y; ++y) - { - for (int x = min_x; x<= max_x; ++x) - { + for (int z = min_z; z <= max_z; ++z) { + // std::cerr << "z "<< z<< std::endl; + for (int y = min_y; y <= max_y; ++y) { + for (int x = min_x; x <= max_x; ++x) { if (image[z][y][x] == 0) continue; - Densel densel(z,y,x); + Densel densel(z, y, x); proj_matrix.get_proj_matrix_elems_for_one_densel(probs, densel); - for (ProjMatrixElemsForOneDensel::const_iterator element_ptr = probs.begin(); - element_ptr != probs.end(); - ++element_ptr) - { - if (element_ptr->axial_pos_num()<= proj_data.get_max_axial_pos_num(element_ptr->segment_num()) && - element_ptr->axial_pos_num()>= proj_data.get_min_axial_pos_num(element_ptr->segment_num())) - (*all_segments[element_ptr->segment_num()])[element_ptr->view_num()][element_ptr->axial_pos_num()][element_ptr->tangential_pos_num()] += - image[z][y][x] * element_ptr->get_value(); + for (ProjMatrixElemsForOneDensel::const_iterator element_ptr = probs.begin(); element_ptr != probs.end(); ++element_ptr) { + if (element_ptr->axial_pos_num() <= proj_data.get_max_axial_pos_num(element_ptr->segment_num()) && + element_ptr->axial_pos_num() >= proj_data.get_min_axial_pos_num(element_ptr->segment_num())) + (*all_segments[element_ptr->segment_num()])[element_ptr->view_num()][element_ptr->axial_pos_num()] + [element_ptr->tangential_pos_num()] += + image[z][y][x] * element_ptr->get_value(); } } } } - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - { + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) { if (!(proj_data.set_segment(*all_segments[segment_num]) == Succeeded::yes)) - error("Error set_segment\n"); + error("Error set_segment\n"); delete all_segments[segment_num]; - } + } } +void +fill_cuboid(VoxelsOnCartesianGrid& image) { + const float voxel_value = ask_num("Voxel value", -10E10F, 10E10F, 1.F); + const int xs = ask_num("Start X coordinate", image.get_min_x(), image.get_max_x(), (image.get_min_x() + image.get_max_x()) / 2); + const int ys = ask_num("Start Y coordinate", image.get_min_y(), image.get_max_y(), (image.get_min_y() + image.get_max_y()) / 2); + const int zs = ask_num("Start Z coordinate", image.get_min_z(), image.get_max_z(), (image.get_min_z() + image.get_max_z()) / 2); - -void fill_cuboid(VoxelsOnCartesianGrid& image) -{ - const float voxel_value = ask_num("Voxel value",-10E10F, 10E10F,1.F); - const int xs = ask_num("Start X coordinate", - image.get_min_x(), image.get_max_x(), - (image.get_min_x()+ image.get_max_x())/2); - const int ys = ask_num("Start Y coordinate", - image.get_min_y(), image.get_max_y(), - (image.get_min_y()+ image.get_max_y())/2); - const int zs = ask_num("Start Z coordinate", - image.get_min_z(), image.get_max_z(), - (image.get_min_z()+ image.get_max_z())/2); - const int xe = ask_num("End X coordinate", xs, image.get_max_x(), xs); const int ye = ask_num("End Y coordinate", ys, image.get_max_y(), ys); const int ze = ask_num("End Z coordinate", zs, image.get_max_z(), zs); - - - cerr << "Start coordinate: (x,y,z) = (" - << xs << ", " << ys << ", " << zs - << ")" << endl; - cerr << "End coordinate: (x,y,z) = (" - << xe << ", " << ye << ", " << ze - << ")" << endl; - + + cerr << "Start coordinate: (x,y,z) = (" << xs << ", " << ys << ", " << zs << ")" << endl; + cerr << "End coordinate: (x,y,z) = (" << xe << ", " << ye << ", " << ze << ")" << endl; + image.fill(0); - for (int z=zs; z<=ze; z++) - for (int y=ys; y <= ye; y++) - for (int x=xs; x<= xe; x++) - image[z][y][x] = voxel_value; + for (int z = zs; z <= ze; z++) + for (int y = ys; y <= ye; y++) + for (int x = xs; x <= xe; x++) + image[z][y][x] = voxel_value; } -void fill_cylinder(VoxelsOnCartesianGrid& image) -{ - const float voxel_value = ask_num("Voxel value",-10E10F, 10E10F,1.F); - - const double xc = - ask_num("Centre X coordinate", - (double)image.get_min_x(), (double)image.get_max_x(), - (image.get_min_x()+ image.get_max_x())/2.); - - const double yc = - ask_num("Centre Y coordinate", - (double)image.get_min_y(), (double)image.get_max_y(), - (image.get_min_y()+ image.get_max_y())/2.); - - const double zc = - ask_num("Centre Z coordinate", - (double)image.get_min_z(), (double)image.get_max_z(), - (image.get_min_z()+ image.get_max_z())/2.); - - - const double Rcyl = - ask_num("Radius (pixels)", - .5, (image.get_max_x()- image.get_min_x())/2., - (image.get_max_x()- image.get_min_x())/4.); - +void +fill_cylinder(VoxelsOnCartesianGrid& image) { + const float voxel_value = ask_num("Voxel value", -10E10F, 10E10F, 1.F); + + const double xc = ask_num("Centre X coordinate", (double)image.get_min_x(), (double)image.get_max_x(), + (image.get_min_x() + image.get_max_x()) / 2.); + + const double yc = ask_num("Centre Y coordinate", (double)image.get_min_y(), (double)image.get_max_y(), + (image.get_min_y() + image.get_max_y()) / 2.); + + const double zc = ask_num("Centre Z coordinate", (double)image.get_min_z(), (double)image.get_max_z(), + (image.get_min_z() + image.get_max_z()) / 2.); + + const double Rcyl = + ask_num("Radius (pixels)", .5, (image.get_max_x() - image.get_min_x()) / 2., (image.get_max_x() - image.get_min_x()) / 4.); + // Max length is num_planes+1 because of edges of voxels - const double Lcyl = - ask_num("Length (planes)", 1., (image.get_max_z()- image.get_min_z())+1., - (image.get_max_z()- image.get_min_z())+1.); - - - cerr << "Centre coordinate: (x,y,z) = (" - << xc << ", " << yc << ", " << zc - << ")" << endl; - cerr << "Radius = " << Rcyl << ", Length = " << Lcyl << endl; - - const int num_samples = - ask_num("With how many points (in x,y direction) do I sample each voxel ?", - 1,100,5); - - Array<2,float> plane = image[0]; - - for (int y=image.get_min_y(); y<=image.get_max_y(); y++) - for (int x=image.get_min_x(); x<=image.get_max_x(); x++) - { - double value = 0; - - for (double ysmall=-(num_samples-1.)/num_samples/2.; - ysmall < 0.5; - ysmall+= 1./num_samples) - { - const double ytry = y-ysmall-yc; - - for (double xsmall=-(num_samples-1.)/num_samples/2.; - xsmall < 0.5; - xsmall+= 1./num_samples) - { - const double xtry = x-xsmall-xc; - - if (xtry*xtry + ytry*ytry <= Rcyl*Rcyl) - value++; - } - } - // update plane with normalised value (independent of num_samples) - plane[y][x] = voxel_value*value/(num_samples*num_samples); + const double Lcyl = + ask_num("Length (planes)", 1., (image.get_max_z() - image.get_min_z()) + 1., (image.get_max_z() - image.get_min_z()) + 1.); + + cerr << "Centre coordinate: (x,y,z) = (" << xc << ", " << yc << ", " << zc << ")" << endl; + cerr << "Radius = " << Rcyl << ", Length = " << Lcyl << endl; + + const int num_samples = ask_num("With how many points (in x,y direction) do I sample each voxel ?", 1, 100, 5); + + Array<2, float> plane = image[0]; + + for (int y = image.get_min_y(); y <= image.get_max_y(); y++) + for (int x = image.get_min_x(); x <= image.get_max_x(); x++) { + double value = 0; + + for (double ysmall = -(num_samples - 1.) / num_samples / 2.; ysmall < 0.5; ysmall += 1. / num_samples) { + const double ytry = y - ysmall - yc; + + for (double xsmall = -(num_samples - 1.) / num_samples / 2.; xsmall < 0.5; xsmall += 1. / num_samples) { + const double xtry = x - xsmall - xc; + + if (xtry * xtry + ytry * ytry <= Rcyl * Rcyl) + value++; + } } - - for (int z=image.get_min_z(); z<=image.get_max_z(); z++) - { - // use 2. to make both args of min() and max() double - float zfactor = (std::min(z+.5, zc+Lcyl/2.) - std::max(z-.5, zc-Lcyl/2.)); - if (zfactor<0) zfactor = 0; - image[z] = plane; - image[z] *= zfactor; + // update plane with normalised value (independent of num_samples) + plane[y][x] = voxel_value * value / (num_samples * num_samples); } - -} + for (int z = image.get_min_z(); z <= image.get_max_z(); z++) { + // use 2. to make both args of min() and max() double + float zfactor = (std::min(z + .5, zc + Lcyl / 2.) - std::max(z - .5, zc - Lcyl / 2.)); + if (zfactor < 0) + zfactor = 0; + image[z] = plane; + image[z] *= zfactor; + } +} diff --git a/src/experimental/recon_test/test_ProjMatrixByBinUsingInterpolation.cxx b/src/experimental/recon_test/test_ProjMatrixByBinUsingInterpolation.cxx index c7f9d73a58..1cb8e0723a 100644 --- a/src/experimental/recon_test/test_ProjMatrixByBinUsingInterpolation.cxx +++ b/src/experimental/recon_test/test_ProjMatrixByBinUsingInterpolation.cxx @@ -4,11 +4,11 @@ \file \ingroup test - + \brief Test program for ProjMatrixByBinUsingInterpolation - + \author Kris Thielemans - + */ /* Copyright (C) 2003- 2004, Hammersmith Imanet @@ -38,11 +38,9 @@ using std::cerr; START_NAMESPACE_STIR template -bool -coordinates_less(const BasicCoordinate<3,T>& el1, const BasicCoordinate<3,T>& el2) -{ - return el1[1]& el1, const BasicCoordinate<3, T>& el2) { + return el1[1] < el2[1] || (el1[1] == el2[1] && (el1[2] < el2[2] || (el1[2] == el2[2] && el1[3] < el2[3]))); } /*! @@ -50,39 +48,32 @@ coordinates_less(const BasicCoordinate<3,T>& el1, const BasicCoordinate<3,T>& el \brief Test class for ProjMatrixByBinUsingInterpolation */ -class ProjMatrixByBinUsingInterpolationTests : public RunTests -{ +class ProjMatrixByBinUsingInterpolationTests : public RunTests { public: - ProjMatrixByBinUsingInterpolationTests(char const * template_proj_data_filename = 0); + ProjMatrixByBinUsingInterpolationTests(char const* template_proj_data_filename = 0); void run_tests(); + private: - char const * template_proj_data_filename; + char const* template_proj_data_filename; shared_ptr proj_data_info_sptr; - void run_tests_2_proj_matrices_1_bin(const ProjMatrixByBin& proj_matrix_no_symm, - const ProjMatrixByBin& proj_matrix_with_symm, - const Bin& bin); - void run_tests_2_proj_matrices(const ProjMatrixByBin& proj_matrix_no_symm, - const ProjMatrixByBin& proj_matrix_with_symm); + void run_tests_2_proj_matrices_1_bin(const ProjMatrixByBin& proj_matrix_no_symm, const ProjMatrixByBin& proj_matrix_with_symm, + const Bin& bin); + void run_tests_2_proj_matrices(const ProjMatrixByBin& proj_matrix_no_symm, const ProjMatrixByBin& proj_matrix_with_symm); void run_tests_all_symmetries(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_sptr - ); + const shared_ptr>& density_sptr); void run_tests_for_1_projdata(const shared_ptr& proj_data_info_sptr); }; -ProjMatrixByBinUsingInterpolationTests:: -ProjMatrixByBinUsingInterpolationTests(char const * template_proj_data_filename) - : template_proj_data_filename(template_proj_data_filename) -{} +ProjMatrixByBinUsingInterpolationTests::ProjMatrixByBinUsingInterpolationTests(char const* template_proj_data_filename) + : template_proj_data_filename(template_proj_data_filename) {} void -ProjMatrixByBinUsingInterpolationTests:: -run_tests_2_proj_matrices_1_bin(const ProjMatrixByBin& proj_matrix_no_symm, - const ProjMatrixByBin& proj_matrix_with_symm, - const Bin& bin) -{ +ProjMatrixByBinUsingInterpolationTests::run_tests_2_proj_matrices_1_bin(const ProjMatrixByBin& proj_matrix_no_symm, + const ProjMatrixByBin& proj_matrix_with_symm, + const Bin& bin) { #if 0 // SYM // assert(proj_matrix_with_symm.get_symmetries_ptr()->is_basic(bin)); // vector related_bins; @@ -104,538 +95,426 @@ run_tests_2_proj_matrices_1_bin(const ProjMatrixByBin& proj_matrix_no_symm, get_proj_matrix_elems_for_one_bin(elems_no_sym, *bin_iter); #else - ProjMatrixElemsForOneBin elems_no_sym; - ProjMatrixElemsForOneBin elems_with_sym; - { - proj_matrix_with_symm. - get_proj_matrix_elems_for_one_bin(elems_with_sym, bin); - proj_matrix_no_symm. - get_proj_matrix_elems_for_one_bin(elems_no_sym, bin); + ProjMatrixElemsForOneBin elems_no_sym; + ProjMatrixElemsForOneBin elems_with_sym; + { + proj_matrix_with_symm.get_proj_matrix_elems_for_one_bin(elems_with_sym, bin); + proj_matrix_no_symm.get_proj_matrix_elems_for_one_bin(elems_no_sym, bin); #endif - elems_no_sym.sort(); - elems_with_sym.sort(); - if (!check(elems_no_sym == elems_with_sym, "comparing lors")) - { - // SYM const Bin bin=*bin_iter; - cerr << "Current bin: segment = " << bin.segment_num() - << ", axial pos " << bin.axial_pos_num() - << ", view = " << bin.view_num() - << ", tangential_pos_num = " << bin.tangential_pos_num() << "\n"; - cerr << "no sym ("<get_coords()!= with_sym_iter->get_coords() || - fabs(no_sym_iter->get_value()/with_sym_iter->get_value() -1) > .0002) - { - bool inc_no_sym_iter = false; - if (no_sym_iter!=elems_no_sym.end() && - (with_sym_iter==elems_with_sym.end() || - coordinates_less(no_sym_iter->get_coords(),with_sym_iter->get_coords()) || - no_sym_iter->get_coords()==with_sym_iter->get_coords())) - { - cerr << no_sym_iter->get_coords() - << ':' << no_sym_iter->get_value() - << " || "; - inc_no_sym_iter = true; - } - else - cerr << " || "; - if (with_sym_iter!=elems_with_sym.end() && - (no_sym_iter==elems_no_sym.end() || - !coordinates_less(no_sym_iter->get_coords(),with_sym_iter->get_coords()))) - { - cerr << with_sym_iter->get_coords() - << ':' << with_sym_iter->get_value(); - ++with_sym_iter; - } - if (inc_no_sym_iter) - ++no_sym_iter; - cerr << "\n"; - } - else - { - if (no_sym_iter!=elems_no_sym.end()) - ++no_sym_iter; - if (with_sym_iter!=elems_with_sym.end()) - ++with_sym_iter; - } - } - } + elems_no_sym.sort(); + elems_with_sym.sort(); + if (!check(elems_no_sym == elems_with_sym, "comparing lors")) { + // SYM const Bin bin=*bin_iter; + cerr << "Current bin: segment = " << bin.segment_num() << ", axial pos " << bin.axial_pos_num() + << ", view = " << bin.view_num() << ", tangential_pos_num = " << bin.tangential_pos_num() << "\n"; + cerr << "no sym (" << elems_no_sym.size() << ") with sym (" << elems_with_sym.size() << ")\n"; + ProjMatrixElemsForOneBin::const_iterator no_sym_iter = elems_no_sym.begin(); + ProjMatrixElemsForOneBin::const_iterator with_sym_iter = elems_with_sym.begin(); + while (no_sym_iter != elems_no_sym.end() || with_sym_iter != elems_with_sym.end()) { + if (no_sym_iter == elems_no_sym.end() || with_sym_iter == elems_with_sym.end() || + no_sym_iter->get_coords() != with_sym_iter->get_coords() || + fabs(no_sym_iter->get_value() / with_sym_iter->get_value() - 1) > .0002) { + bool inc_no_sym_iter = false; + if (no_sym_iter != elems_no_sym.end() && + (with_sym_iter == elems_with_sym.end() || coordinates_less(no_sym_iter->get_coords(), with_sym_iter->get_coords()) || + no_sym_iter->get_coords() == with_sym_iter->get_coords())) { + cerr << no_sym_iter->get_coords() << ':' << no_sym_iter->get_value() << " || "; + inc_no_sym_iter = true; + } else + cerr << " || "; + if (with_sym_iter != elems_with_sym.end() && + (no_sym_iter == elems_no_sym.end() || !coordinates_less(no_sym_iter->get_coords(), with_sym_iter->get_coords()))) { + cerr << with_sym_iter->get_coords() << ':' << with_sym_iter->get_value(); + ++with_sym_iter; + } + if (inc_no_sym_iter) + ++no_sym_iter; + cerr << "\n"; + } else { + if (no_sym_iter != elems_no_sym.end()) + ++no_sym_iter; + if (with_sym_iter != elems_with_sym.end()) + ++with_sym_iter; + } } + } +} } void -ProjMatrixByBinUsingInterpolationTests:: -run_tests_2_proj_matrices(const ProjMatrixByBin& proj_matrix_no_symm, - const ProjMatrixByBin& proj_matrix_with_symm) -{ +ProjMatrixByBinUsingInterpolationTests::run_tests_2_proj_matrices(const ProjMatrixByBin& proj_matrix_no_symm, + const ProjMatrixByBin& proj_matrix_with_symm) { #if 1 - for (int s=-proj_data_info_sptr->get_max_segment_num(); s<=proj_data_info_sptr->get_max_segment_num(); ++s) - for (int v=proj_data_info_sptr->get_min_view_num(); - v <= proj_data_info_sptr->get_max_view_num(); - ++v) - for (int a=proj_data_info_sptr->get_min_axial_pos_num(s); - a <= proj_data_info_sptr->get_max_axial_pos_num(s); - ++a) - for (int t=-6; t<=6; t+=3) - { - const Bin bin(s,v,a,t); - //SYM if (proj_matrix_with_symm.get_symmetries_ptr()->is_basic(bin)) - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); - } + for (int s = -proj_data_info_sptr->get_max_segment_num(); s <= proj_data_info_sptr->get_max_segment_num(); ++s) + for (int v = proj_data_info_sptr->get_min_view_num(); v <= proj_data_info_sptr->get_max_view_num(); ++v) + for (int a = proj_data_info_sptr->get_min_axial_pos_num(s); a <= proj_data_info_sptr->get_max_axial_pos_num(s); ++a) + for (int t = -6; t <= 6; t += 3) { + const Bin bin(s, v, a, t); + // SYM if (proj_matrix_with_symm.get_symmetries_ptr()->is_basic(bin)) + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); + } #else const int oblique_seg_num = proj_data_info_sptr->get_max_segment_num(); - const int view45 = - proj_data_info_sptr->get_num_views()/4; - assert(fabs(proj_data_info_sptr-> - get_phi(Bin(0,view45,0,0)) - _PI/4)<.001); - + const int view45 = proj_data_info_sptr->get_num_views() / 4; + assert(fabs(proj_data_info_sptr->get_phi(Bin(0, view45, 0, 0)) - _PI / 4) < .001); + { - const Bin bin(oblique_seg_num,1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,1,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 1, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,1,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 1, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,0,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 0, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,0,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 0, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,0,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 0, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,0,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 0, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,0,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 0, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,0,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 0, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,0,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 0, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,view45,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, view45, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,view45,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, view45, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,view45,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, view45, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,view45,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, view45, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,view45,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, view45, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,view45,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, view45, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,view45,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, view45, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,view45,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, view45, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } - { - const Bin bin(oblique_seg_num,2*view45+1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 2 * view45 + 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,2*view45+1,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 2 * view45 + 1, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,2*view45+1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 2 * view45 + 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,2*view45+1,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 2 * view45 + 1, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,2*view45+1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 2 * view45 + 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,2*view45+1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 2 * view45 + 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,2*view45+1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 2 * view45 + 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,2*view45+1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 2 * view45 + 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } #endif } - void -ProjMatrixByBinUsingInterpolationTests:: -run_tests_all_symmetries(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_sptr - ) -{ +ProjMatrixByBinUsingInterpolationTests::run_tests_all_symmetries(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& density_sptr) { - ProjMatrixByBinUsingInterpolation proj_matrix_no_sym; - { - stringstream str; - str << - "Interpolation Matrix Parameters :=\n" - "do symmetry 90degrees min phi := 0\n" - "do symmetry 180degrees min phi := 0\n" - "do_symmetry_swap_segment := 0\n" - "do_symmetry_swap_s := 0\n" - "do_symmetry_shift_z := 0\n" - "End Interpolation Matrix Parameters :=\n"; - if (!check(proj_matrix_no_sym.parse(str), - "parsing projection matrix parameters")) - return; - proj_matrix_no_sym.set_up(proj_data_info_sptr, density_sptr); - } + ProjMatrixByBinUsingInterpolation proj_matrix_no_sym; + { + stringstream str; + str << "Interpolation Matrix Parameters :=\n" + "do symmetry 90degrees min phi := 0\n" + "do symmetry 180degrees min phi := 0\n" + "do_symmetry_swap_segment := 0\n" + "do_symmetry_swap_s := 0\n" + "do_symmetry_shift_z := 0\n" + "End Interpolation Matrix Parameters :=\n"; + if (!check(proj_matrix_no_sym.parse(str), "parsing projection matrix parameters")) + return; + proj_matrix_no_sym.set_up(proj_data_info_sptr, density_sptr); + } - { - cerr << "\t\tTesting with all symmetries\n"; - ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; - - stringstream str; - str << - "Interpolation Matrix Parameters :=\n" - "do symmetry 90degrees min phi := 1\n" - "do symmetry 180degrees min phi := 1\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 1\n" - "do_symmetry_shift_z := 1\n" - "End Interpolation Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + { + cerr << "\t\tTesting with all symmetries\n"; + ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; + + stringstream str; + str << "Interpolation Matrix Parameters :=\n" + "do symmetry 90degrees min phi := 1\n" + "do symmetry 180degrees min phi := 1\n" + "do_symmetry_swap_segment := 1\n" + "do_symmetry_swap_s := 1\n" + "do_symmetry_shift_z := 1\n" + "End Interpolation Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with all symmetries except 90-phi\n"; - ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; - - stringstream str; - str << - "Interpolation Matrix Parameters :=\n" - "do symmetry 90degrees min phi := 0\n" - "do symmetry 180degrees min phi := 1\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 1\n" - "do_symmetry_shift_z := 1\n" - "End Interpolation Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with all symmetries except 90-phi\n"; + ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; + + stringstream str; + str << "Interpolation Matrix Parameters :=\n" + "do symmetry 90degrees min phi := 0\n" + "do symmetry 180degrees min phi := 1\n" + "do_symmetry_swap_segment := 1\n" + "do_symmetry_swap_s := 1\n" + "do_symmetry_shift_z := 1\n" + "End Interpolation Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with all symmetries except phi symms\n"; - ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; - - stringstream str; - str << - "Interpolation Matrix Parameters :=\n" - "do symmetry 90degrees min phi := 0\n" - "do symmetry 180degrees min phi := 0\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 1\n" - "do_symmetry_shift_z := 1\n" - "End Interpolation Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with all symmetries except phi symms\n"; + ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; + + stringstream str; + str << "Interpolation Matrix Parameters :=\n" + "do symmetry 90degrees min phi := 0\n" + "do symmetry 180degrees min phi := 0\n" + "do_symmetry_swap_segment := 1\n" + "do_symmetry_swap_s := 1\n" + "do_symmetry_shift_z := 1\n" + "End Interpolation Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with all symmetries except swap_segment\n"; - ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; - - stringstream str; - str << - "Interpolation Matrix Parameters :=\n" - "do symmetry 90degrees min phi := 1\n" - "do symmetry 180degrees min phi := 1\n" - "do_symmetry_swap_segment := 0\n" - "do_symmetry_swap_s := 1\n" - "do_symmetry_shift_z := 1\n" - "End Interpolation Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with all symmetries except swap_segment\n"; + ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; + + stringstream str; + str << "Interpolation Matrix Parameters :=\n" + "do symmetry 90degrees min phi := 1\n" + "do symmetry 180degrees min phi := 1\n" + "do_symmetry_swap_segment := 0\n" + "do_symmetry_swap_s := 1\n" + "do_symmetry_shift_z := 1\n" + "End Interpolation Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with all symmetries except swap_s\n"; - ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; - - stringstream str; - str << - "Interpolation Matrix Parameters :=\n" - "do symmetry 90degrees min phi := 1\n" - "do symmetry 180degrees min phi := 1\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 0\n" - "do_symmetry_shift_z := 1\n" - "End Interpolation Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with all symmetries except swap_s\n"; + ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; + + stringstream str; + str << "Interpolation Matrix Parameters :=\n" + "do symmetry 90degrees min phi := 1\n" + "do symmetry 180degrees min phi := 1\n" + "do_symmetry_swap_segment := 1\n" + "do_symmetry_swap_s := 0\n" + "do_symmetry_shift_z := 1\n" + "End Interpolation Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with all symmetries except shift_z\n"; - ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; - - stringstream str; - str << - "Interpolation Matrix Parameters :=\n" - "do symmetry 90degrees min phi := 1\n" - "do symmetry 180degrees min phi := 1\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 1\n" - "do_symmetry_shift_z := 0\n" - "End Interpolation Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with all symmetries except shift_z\n"; + ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; + + stringstream str; + str << "Interpolation Matrix Parameters :=\n" + "do symmetry 90degrees min phi := 1\n" + "do symmetry 180degrees min phi := 1\n" + "do_symmetry_swap_segment := 1\n" + "do_symmetry_swap_s := 1\n" + "do_symmetry_shift_z := 0\n" + "End Interpolation Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with only shift_z\n"; - ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; - - stringstream str; - str << - "Interpolation Matrix Parameters :=\n" - "do symmetry 90degrees min phi := 0\n" - "do symmetry 180degrees min phi := 0\n" - "do_symmetry_swap_segment := 0\n" - "do_symmetry_swap_s := 0\n" - "do_symmetry_shift_z := 1\n" - "End Interpolation Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with only shift_z\n"; + ProjMatrixByBinUsingInterpolation proj_matrix_with_sym; + + stringstream str; + str << "Interpolation Matrix Parameters :=\n" + "do symmetry 90degrees min phi := 0\n" + "do symmetry 180degrees min phi := 0\n" + "do_symmetry_swap_segment := 0\n" + "do_symmetry_swap_s := 0\n" + "do_symmetry_shift_z := 1\n" + "End Interpolation Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } + } } void -ProjMatrixByBinUsingInterpolationTests:: -run_tests_for_1_projdata(const shared_ptr& proj_data_info_sptr) -{ - CartesianCoordinate3D origin (0,0,0); - const float zoom=1.F; +ProjMatrixByBinUsingInterpolationTests::run_tests_for_1_projdata(const shared_ptr& proj_data_info_sptr) { + CartesianCoordinate3D origin(0, 0, 0); + const float zoom = 1.F; cerr << "\tTests with usual image size\n"; - - shared_ptr > density_sptr = - new VoxelsOnCartesianGrid(*proj_data_info_sptr,zoom,origin); - VoxelsOnCartesianGrid & image = - dynamic_cast&>(*density_sptr); + shared_ptr> density_sptr = new VoxelsOnCartesianGrid(*proj_data_info_sptr, zoom, origin); + + VoxelsOnCartesianGrid& image = dynamic_cast&>(*density_sptr); run_tests_all_symmetries(proj_data_info_sptr, density_sptr); cerr << "\tTests with shifted origin\n"; - - density_sptr->set_origin(image.get_grid_spacing()* - CartesianCoordinate3D(3,0,0)); + + density_sptr->set_origin(image.get_grid_spacing() * CartesianCoordinate3D(3, 0, 0)); run_tests_all_symmetries(proj_data_info_sptr, density_sptr); - const int org_z_length = - density_sptr->get_length(); + const int org_z_length = density_sptr->get_length(); - cerr << "\tTests with non-standard range of planes (larger)\n"; - density_sptr->set_origin(CartesianCoordinate3D(0,0,0)); - density_sptr->grow(IndexRange3D(-2, org_z_length+3, - image.get_min_y(), image.get_max_y(), - image.get_min_x(), image.get_max_x())); + cerr << "\tTests with non-standard range of planes (larger)\n"; + density_sptr->set_origin(CartesianCoordinate3D(0, 0, 0)); + density_sptr->grow( + IndexRange3D(-2, org_z_length + 3, image.get_min_y(), image.get_max_y(), image.get_min_x(), image.get_max_x())); run_tests_all_symmetries(proj_data_info_sptr, density_sptr); + if (org_z_length > 2) { + cerr << "\tTests with non-standard range of planes (smaller)\n"; + density_sptr->set_origin(CartesianCoordinate3D(0, 0, 0)); + density_sptr->resize( + IndexRange3D(1, org_z_length - 1, image.get_min_y(), image.get_max_y(), image.get_min_x(), image.get_max_x())); + run_tests_all_symmetries(proj_data_info_sptr, density_sptr); + } - if (org_z_length>2) - { - cerr << "\tTests with non-standard range of planes (smaller)\n"; - density_sptr->set_origin(CartesianCoordinate3D(0,0,0)); - density_sptr->resize(IndexRange3D(1, org_z_length-1, - image.get_min_y(), image.get_max_y(), - image.get_min_x(), image.get_max_x())); - run_tests_all_symmetries(proj_data_info_sptr, density_sptr); - } - - cerr << "\tTests with usual z voxel size 3 times smaller\n"; - density_sptr->set_origin(CartesianCoordinate3D(0,0,0)); - image.set_grid_spacing(image.get_grid_spacing()/ - CartesianCoordinate3D(2,1,1)); - density_sptr->grow(IndexRange3D(0, density_sptr->get_length()*2, - image.get_min_y(), image.get_max_y(), - image.get_min_x(), image.get_max_x())); + cerr << "\tTests with usual z voxel size 3 times smaller\n"; + density_sptr->set_origin(CartesianCoordinate3D(0, 0, 0)); + image.set_grid_spacing(image.get_grid_spacing() / CartesianCoordinate3D(2, 1, 1)); + density_sptr->grow(IndexRange3D(0, density_sptr->get_length() * 2, image.get_min_y(), image.get_max_y(), image.get_min_x(), + image.get_max_x())); run_tests_all_symmetries(proj_data_info_sptr, density_sptr); } void -ProjMatrixByBinUsingInterpolationTests::run_tests() -{ +ProjMatrixByBinUsingInterpolationTests::run_tests() { cerr << "Tests for ProjMatrixByBinUsingInterpolation\n"; - if (template_proj_data_filename == 0) + if (template_proj_data_filename == 0) { { - { - cerr << "Testing span=1\n"; - shared_ptr scanner_sptr = new Scanner(Scanner::E953); - proj_data_info_sptr = - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/1, - /*max_delta=*/5, - /*num_views=*/32, - /*num_tang_poss=*/16); - - run_tests_for_1_projdata(proj_data_info_sptr); - } - { - cerr << "Testing span=3\n"; - // warning: make sure that parameters are ok such that hard-wired - // bins above are fine (e.g. segment 3 should be allowed) - shared_ptr scanner_sptr = new Scanner(Scanner::E953); - proj_data_info_sptr = - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/3, - /*max_delta=*/12, - /*num_views=*/32, - /*num_tang_poss=*/16); - - - run_tests_for_1_projdata(proj_data_info_sptr); - } + cerr << "Testing span=1\n"; + shared_ptr scanner_sptr = new Scanner(Scanner::E953); + proj_data_info_sptr = ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/1, + /*max_delta=*/5, + /*num_views=*/32, + /*num_tang_poss=*/16); + + run_tests_for_1_projdata(proj_data_info_sptr); } - else { - shared_ptr proj_data_sptr = - ProjData::read_from_file(template_proj_data_filename); - proj_data_info_sptr = - proj_data_sptr->get_proj_data_info_sptr()->clone(); + cerr << "Testing span=3\n"; + // warning: make sure that parameters are ok such that hard-wired + // bins above are fine (e.g. segment 3 should be allowed) + shared_ptr scanner_sptr = new Scanner(Scanner::E953); + proj_data_info_sptr = ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/3, + /*max_delta=*/12, + /*num_views=*/32, + /*num_tang_poss=*/16); + run_tests_for_1_projdata(proj_data_info_sptr); } + } else { + shared_ptr proj_data_sptr = ProjData::read_from_file(template_proj_data_filename); + proj_data_info_sptr = proj_data_sptr->get_proj_data_info_sptr()->clone(); + run_tests_for_1_projdata(proj_data_info_sptr); + } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main(int argc, char **argv) -{ - ProjMatrixByBinUsingInterpolationTests tests(argc==2? argv[1] : 0); +int +main(int argc, char** argv) { + ProjMatrixByBinUsingInterpolationTests tests(argc == 2 ? argv[1] : 0); tests.run_tests(); return tests.main_return_value(); } diff --git a/src/experimental/test/test_Fourier.cxx b/src/experimental/test/test_Fourier.cxx index eb0c0504ba..48b9a83cc3 100644 --- a/src/experimental/test/test_Fourier.cxx +++ b/src/experimental/test/test_Fourier.cxx @@ -2,7 +2,7 @@ // /*! - \file + \file \ingroup tests \brief Tests for function in the DFT group @@ -28,7 +28,6 @@ #include #include - using std::cin; using std::cout; using std::endl; @@ -37,353 +36,329 @@ START_NAMESPACE_STIR #define DOARRAY #ifdef DOARRAY - typedef Array<1,std::complex > ArrayC1; - typedef Array<1,float> ArrayF1; - typedef Array<2,float> ArrayF2; - typedef Array<2,std::complex > ArrayC2; - typedef Array<3,float> ArrayF3; - typedef Array<3,std::complex > ArrayC3; +typedef Array<1, std::complex> ArrayC1; +typedef Array<1, float> ArrayF1; +typedef Array<2, float> ArrayF2; +typedef Array<2, std::complex> ArrayC2; +typedef Array<3, float> ArrayF3; +typedef Array<3, std::complex> ArrayC3; #else - typedef VectorWithOffset > ArrayC1; - typedef VectorWithOffset ArrayF1; - typedef VectorWithOffset ArrayC2; +typedef VectorWithOffset> ArrayC1; +typedef VectorWithOffset ArrayF1; +typedef VectorWithOffset ArrayC2; #endif - - -const int FORWARDFFT=1; -const int INVERSEFFT=-1; - +const int FORWARDFFT = 1; +const int INVERSEFFT = -1; template -void discrete_fourier_transform(VectorWithOffset&data, int isign) -{ - const unsigned int nn = data.get_length()/2; - const double TPI=2*_PI; - unsigned int n,mmax,m,j,istep,i; - double wtemp,wr,wpr,wpi,wi,theta; - elemT tempr,tempi; - n=nn << 1; - j=1; - for (i=1;i& data, int isign) { + const unsigned int nn = data.get_length() / 2; + const double TPI = 2 * _PI; + unsigned int n, mmax, m, j, istep, i; + double wtemp, wr, wpr, wpi, wi, theta; + elemT tempr, tempi; + n = nn << 1; + j = 1; + for (i = 1; i < n; i += 2) { if (j > i) { - std::swap(data[j],data[i]); - std::swap(data[j+1],data[i+1]); + std::swap(data[j], data[i]); + std::swap(data[j + 1], data[i + 1]); } - m=n >> 1; + m = n >> 1; while (m >= 2 && j > m) { j -= m; m >>= 1; } j += m; } - mmax=2; + mmax = 2; while (n > mmax) { - istep=mmax << 1; - theta=isign*(TPI/mmax); - wtemp=sin(0.5*theta); - wpr = -2.0*wtemp*wtemp; - wpi=sin(theta); - wr=1.0; - wi=0.0; - for (m=1;m> sign; - + #if 1 - int repeat=1; + int repeat = 1; cout << "Enter repeat:"; cin >> repeat; { ArrayC1 c; -#if 0 +# if 0 cin >> c; -#else - { - int length=0; +# else + { + int length = 0; cout << "Enter length of array:"; cin >> length; - c.grow(0,length-1); - for (int i=0; i(rand1(), rand1()); + c.grow(0, length - 1); + for (int i = 0; i < c.get_length(); ++i) + c[i] = std::complex(rand1(), rand1()); } -#endif +# endif const ArrayC1 c_copy = c; - ArrayF1 nr_data(1,2*c.get_length()); + ArrayF1 nr_data(1, 2 * c.get_length()); stir_to_nr(c, nr_data); { CPUTimer timer; timer.start(); - for (int i=repeat; i; --i) - {fourier(c); c/=sqrt(static_cast(c.get_length()));} + for (int i = repeat; i; --i) { + fourier(c); + c /= sqrt(static_cast(c.get_length())); + } timer.stop(); - + cout << "fourier " << timer.value() << '\n'; - + timer.reset(); timer.start(); - for (int i=repeat; i; --i) - {discrete_fourier_transform(nr_data, FORWARDFFT); nr_data/=sqrt(static_cast(c.get_length()));} + for (int i = repeat; i; --i) { + discrete_fourier_transform(nr_data, FORWARDFFT); + nr_data /= sqrt(static_cast(c.get_length())); + } timer.stop(); cout << "NR " << timer.value() << '\n'; } // cout << '\n' << c << nr_c; - ArrayC1 nr_c(0,c.get_length()-1); + ArrayC1 nr_c(0, c.get_length() - 1); nr_to_stir(nr_data, nr_c); nr_c -= c; { - const float tmp = norm(nr_c.begin(), nr_c.end())/norm(c.begin(), c.end()); - cout << "\nResidual norm " << tmp << std::endl; - if (tmp > .1) - { - std::cout << "NR : " << nr_c - << "STIR " << c; - } + const float tmp = norm(nr_c.begin(), nr_c.end()) / norm(c.begin(), c.end()); + cout << "\nResidual norm " << tmp << std::endl; + if (tmp > .1) { + std::cout << "NR : " << nr_c << "STIR " << c; + } } stir_to_nr(c, nr_data); { CPUTimer timer; timer.start(); - for (int i=repeat; i; --i) - {inverse_fourier(c);c*=sqrt(static_cast(c.get_length()));} - timer.stop(); + for (int i = repeat; i; --i) { + inverse_fourier(c); + c *= sqrt(static_cast(c.get_length())); + } + timer.stop(); cout << "inverse fourier " << timer.value() << '\n'; timer.reset(); timer.start(); - for (int i=repeat; i; --i) - {discrete_fourier_transform(nr_data, INVERSEFFT);nr_data /= c.get_length();nr_data/=1/sqrt(static_cast(c.get_length()));} - + for (int i = repeat; i; --i) { + discrete_fourier_transform(nr_data, INVERSEFFT); + nr_data /= c.get_length(); + nr_data /= 1 / sqrt(static_cast(c.get_length())); + } + timer.stop(); cout << "NR " << timer.value() << '\n'; } nr_to_stir(nr_data, nr_c); nr_c -= c; - cout << "\nResidual norm " << norm(nr_c.begin(), nr_c.end())/norm(c.begin(), c.end()) << std::endl; + cout << "\nResidual norm " << norm(nr_c.begin(), nr_c.end()) / norm(c.begin(), c.end()) << std::endl; c -= c_copy; - cout << "\nResidual norm inverse (relative)" <> length; - int columns=0; + int columns = 0; cout << "Enter number of columns of array:"; cin >> columns; -#ifndef DOARRAY - c2d.grow(0,length-1); - for (int i=0; i(rand1(), rand1()); - } -#else +# ifndef DOARRAY + c2d.grow(0, length - 1); + for (int i = 0; i < c2d.get_length(); ++i) { + c2d[i].grow(0, columns - 1); + for (int j = 0; j < c2d[i].get_length(); ++j) + c2d[i][j] = std::complex(rand1(), rand1()); + } +# else c2d.grow(IndexRange2D(length, columns)); - for (ArrayC2::full_iterator iter= c2d.begin_all(); - iter!=c2d.end_all(); - ++iter) - *iter= std::complex(rand1(), rand1()); -#endif + for (ArrayC2::full_iterator iter = c2d.begin_all(); iter != c2d.end_all(); ++iter) + *iter = std::complex(rand1(), rand1()); +# endif } - //cout << c2d; + // cout << c2d; ArrayC2 nr_c2d(c2d); - Array<1,float> nr_data(1,2*c2d.get_length()*c2d[0].get_length()); + Array<1, float> nr_data(1, 2 * c2d.get_length() * c2d[0].get_length()); stir_to_nr(nr_c2d, nr_data); - const float - normfactor =sqrt(static_cast(c2d.get_length()*c2d[0].get_length())); + const float normfactor = sqrt(static_cast(c2d.get_length() * c2d[0].get_length())); { CPUTimer timer; timer.start(); - for (int i=repeat; i; --i) - {fourier(c2d); - c2d/= normfactor;} + for (int i = repeat; i; --i) { + fourier(c2d); + c2d /= normfactor; + } timer.stop(); - cout << "fourier 2D " << timer.value() << '\n'; + cout << "fourier 2D " << timer.value() << '\n'; } { CPUTimer timer; timer.reset(); timer.start(); - Array<1,int> dims(1,2); - dims[1]=c2d.get_length(); - dims[2]=c2d[0].get_length(); - for (int i=repeat; i; --i) - {fourn(nr_data, dims, 2, 1);nr_data/=normfactor;} + Array<1, int> dims(1, 2); + dims[1] = c2d.get_length(); + dims[2] = c2d[0].get_length(); + for (int i = repeat; i; --i) { + fourn(nr_data, dims, 2, 1); + nr_data /= normfactor; + } timer.stop(); cout << "NR " << timer.value() << '\n'; } - //cout << '\n' << c2d << '\n' << nr_data; - ArrayF1 nr_data_stir_fourier(1,2*c2d.get_length()*c2d[0].get_length()); + // cout << '\n' << c2d << '\n' << nr_data; + ArrayF1 nr_data_stir_fourier(1, 2 * c2d.get_length() * c2d[0].get_length()); stir_to_nr(c2d, nr_data_stir_fourier); - nr_data -= nr_data_stir_fourier; - - - cout << "\nResidual norm " - << norm(nr_data.begin(), nr_data.end())/ - norm(nr_data_stir_fourier.begin(), nr_data_stir_fourier.end()) - << std::endl; + nr_data -= nr_data_stir_fourier; + cout << "\nResidual norm " + << norm(nr_data.begin(), nr_data.end()) / norm(nr_data_stir_fourier.begin(), nr_data_stir_fourier.end()) << std::endl; } #endif // ********** REAL ************ { ArrayF1 v; - { - int length=0; + { + int length = 0; cout << "Enter length of array:"; cin >> length; - v.grow(0,length-1); - for (int i=0; i> length; - int columns=0; + int columns = 0; cout << "Enter number of columns of array:"; cin >> columns; v.grow(IndexRange2D(length, columns)); - for (ArrayF2::full_iterator iter= v.begin_all(); - iter!=v.end_all(); - ++iter) - *iter= rand1(); + for (ArrayF2::full_iterator iter = v.begin_all(); iter != v.end_all(); ++iter) + *iter = rand1(); } - ArrayC2 pos_frequencies = - fourier_for_real_data(v,sign); - const ArrayC2 all_frequencies = - pos_frequencies_to_all(pos_frequencies); + ArrayC2 pos_frequencies = fourier_for_real_data(v, sign); + const ArrayC2 all_frequencies = pos_frequencies_to_all(pos_frequencies); ArrayC2 c(v.get_index_range()); std::copy(v.begin_all(), v.end_all(), c.begin_all()); - fourier(c,sign); - //cout << pos_frequencies; - //cout << all_frequencies << c; - //cout << '\n' << c-all_frequencies; + fourier(c, sign); + // cout << pos_frequencies; + // cout << all_frequencies << c; + // cout << '\n' << c-all_frequencies; c -= all_frequencies; - cout << "\nReal FT Residual norm " << - norm(c.begin_all(), c.end_all())/norm(v.begin_all(), v.end_all()); + cout << "\nReal FT Residual norm " << norm(c.begin_all(), c.end_all()) / norm(v.begin_all(), v.end_all()); - ArrayF2 again_v = - inverse_fourier_for_real_data(pos_frequencies,sign); - //cout <<"\nv,test "<< v << again_v << again_v/v; + ArrayF2 again_v = inverse_fourier_for_real_data(pos_frequencies, sign); + // cout <<"\nv,test "<< v << again_v << again_v/v; again_v -= v; - cout << "\ninverse Real FT Residual norm " << - norm(again_v.begin_all(), again_v.end_all())/norm(v.begin_all(), v.end_all()); - + cout << "\ninverse Real FT Residual norm " << norm(again_v.begin_all(), again_v.end_all()) / norm(v.begin_all(), v.end_all()); } { ArrayF3 v; - { - int length=0; + { + int length = 0; cout << "Enter number of rows of array:"; cin >> length; - int columns=0; + int columns = 0; cout << "Enter number of columns of array:"; cin >> columns; - int planes=0; + int planes = 0; cout << "Enter number of planes of array:"; cin >> planes; - v.grow(IndexRange3D(planes,length, columns)); - for (ArrayF3::full_iterator iter= v.begin_all(); - iter!=v.end_all(); - ++iter) - *iter= rand1(); + v.grow(IndexRange3D(planes, length, columns)); + for (ArrayF3::full_iterator iter = v.begin_all(); iter != v.end_all(); ++iter) + *iter = rand1(); } - ArrayC3 pos_frequencies = - fourier_for_real_data(v,sign); - const ArrayC3 all_frequencies = - pos_frequencies_to_all(pos_frequencies); + ArrayC3 pos_frequencies = fourier_for_real_data(v, sign); + const ArrayC3 all_frequencies = pos_frequencies_to_all(pos_frequencies); ArrayC3 c(v.get_index_range()); std::copy(v.begin_all(), v.end_all(), c.begin_all()); - fourier(c,sign); - //cout << pos_frequencies; - //cout << all_frequencies << c; - //cout << '\n' << c-all_frequencies; + fourier(c, sign); + // cout << pos_frequencies; + // cout << all_frequencies << c; + // cout << '\n' << c-all_frequencies; c -= all_frequencies; - cout << "\nReal FT Residual norm " << - norm(c.begin_all(), c.end_all())/norm(v.begin_all(), v.end_all()); + cout << "\nReal FT Residual norm " << norm(c.begin_all(), c.end_all()) / norm(v.begin_all(), v.end_all()); - ArrayF3 again_v = - inverse_fourier_for_real_data(pos_frequencies,sign); - //cout <<"\nv,test "<< v << again_v << again_v/v; + ArrayF3 again_v = inverse_fourier_for_real_data(pos_frequencies, sign); + // cout <<"\nv,test "<< v << again_v << again_v/v; again_v -= v; - cout << "\ninverse Real FT Residual norm " << - norm(again_v.begin_all(), again_v.end_all())/norm(v.begin_all(), v.end_all()); - + cout << "\ninverse Real FT Residual norm " << norm(again_v.begin_all(), again_v.end_all()) / norm(v.begin_all(), v.end_all()); } return EXIT_SUCCESS; } - - - diff --git a/src/experimental/test/test_LmToProjdataWithMC.cxx b/src/experimental/test/test_LmToProjdataWithMC.cxx index 069c9bb89a..db88e747e8 100644 --- a/src/experimental/test/test_LmToProjdataWithMC.cxx +++ b/src/experimental/test/test_LmToProjdataWithMC.cxx @@ -23,71 +23,58 @@ using std::cerr; using std::endl; #endif - START_NAMESPACE_STIR -class LmToProjDataWithMCTests: public RunTests -{ -public: +class LmToProjDataWithMCTests : public RunTests { +public: void run_tests(); }; - - - void -LmToProjDataWithMCTests::run_tests() -{ - const char * const par_filename = "test.par"; +LmToProjDataWithMCTests::run_tests() { + const char* const par_filename = "test.par"; LmToProjDataWithMC LmToProjDataWithMCObject(par_filename); shared_ptr scanner = new Scanner(Scanner::E966); - for ( int Ring_A = 1; Ring_A < 10; Ring_A++) - for ( int Ring_B = 1; Ring_B < 10; Ring_B++) - for ( int det1 =1; det1 <=10; det1 ++) - for ( int det2 =100; det2 <=110; det2 ++) - - { - CartesianCoordinate3D coord_1; - CartesianCoordinate3D coord_2; - - // normally one cannot access private members of in the class but I have made it public while testing - LmToProjDataWithMCObject.find_cartesian_coordinates_given_scanner_coordinates (coord_1,coord_2, - Ring_A,Ring_B, - det1,det2, - *scanner); - - const CartesianCoordinate3D coord_1_new = coord_1 + (coord_2-coord_1)*5; - const CartesianCoordinate3D coord_2_new = coord_1 + (coord_2-coord_1)*2; - - int det1_f, det2_f,ring1_f, ring2_f; - - LmToProjDataWithMCObject.find_scanner_coordinates_given_cartesian_coordinates(det1_f, det2_f, ring1_f, ring2_f, - coord_1_new, coord_2_new, - *scanner); - if (det1_f == det1 && Ring_A == ring1_f) - { - check_if_equal( det1_f, det1, "test on det1"); - check_if_equal( Ring_A, ring1_f, "test on ring1"); - check_if_equal( det2_f, det2, "test on det2"); - check_if_equal( Ring_B, ring2_f, "test on ring1"); - } - else - { - check_if_equal( det2_f, det1, "test on det1"); - check_if_equal( Ring_B, ring1_f, "test on ring1"); - check_if_equal( det1_f, det2, "test on det2"); - check_if_equal( Ring_A, ring2_f, "test on ring1"); - } - } + for (int Ring_A = 1; Ring_A < 10; Ring_A++) + for (int Ring_B = 1; Ring_B < 10; Ring_B++) + for (int det1 = 1; det1 <= 10; det1++) + for (int det2 = 100; det2 <= 110; det2++) + + { + CartesianCoordinate3D coord_1; + CartesianCoordinate3D coord_2; + + // normally one cannot access private members of in the class but I have made it public while testing + LmToProjDataWithMCObject.find_cartesian_coordinates_given_scanner_coordinates(coord_1, coord_2, Ring_A, Ring_B, det1, + det2, *scanner); + + const CartesianCoordinate3D coord_1_new = coord_1 + (coord_2 - coord_1) * 5; + const CartesianCoordinate3D coord_2_new = coord_1 + (coord_2 - coord_1) * 2; + + int det1_f, det2_f, ring1_f, ring2_f; + + LmToProjDataWithMCObject.find_scanner_coordinates_given_cartesian_coordinates(det1_f, det2_f, ring1_f, ring2_f, + coord_1_new, coord_2_new, *scanner); + if (det1_f == det1 && Ring_A == ring1_f) { + check_if_equal(det1_f, det1, "test on det1"); + check_if_equal(Ring_A, ring1_f, "test on ring1"); + check_if_equal(det2_f, det2, "test on det2"); + check_if_equal(Ring_B, ring2_f, "test on ring1"); + } else { + check_if_equal(det2_f, det1, "test on det1"); + check_if_equal(Ring_B, ring1_f, "test on ring1"); + check_if_equal(det1_f, det2, "test on det2"); + check_if_equal(Ring_A, ring2_f, "test on ring1"); + } + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { LmToProjDataWithMCTests tests; tests.run_tests(); return tests.main_return_value(); } - diff --git a/src/experimental/test/test_Quaternion.cxx b/src/experimental/test/test_Quaternion.cxx index 9bd355f4b3..1fb613d1eb 100644 --- a/src/experimental/test/test_Quaternion.cxx +++ b/src/experimental/test/test_Quaternion.cxx @@ -8,8 +8,8 @@ \file \ingroup test -\brief Test program for class Quaternion -\author Sanida Mustafovic +\brief Test program for class Quaternion +\author Sanida Mustafovic */ #include "stir/RunTests.h" #include "stir_experimental/Quaternion.h" @@ -20,191 +20,187 @@ using std::cerr; using std::endl; #endif - START_NAMESPACE_STIR /*! \ingroup test \brief Test class for Quaternion */ -class QuaternionTests: public RunTests -{ -public: +class QuaternionTests : public RunTests { +public: void run_tests(); }; - void -QuaternionTests::run_tests() -{ - +QuaternionTests::run_tests() { + cerr << "Tests for Quaternions\n"; Quaternion test(0.00525584F, -0.999977F, -0.00166456F, 0.0039961F); - - + cerr << "Testing multiplication with a const" << endl; { - const float factor =5.0; - Quaternion multiplywithconst =test; - multiplywithconst *=factor; - - check_if_equal( test[1]*factor, multiplywithconst[1],"test on multiplication with a const (operator *=())--scalar"); - check_if_equal( test[2]*factor, multiplywithconst[2],"test on multiplication with a const (operator *=())--vector 1st"); - check_if_equal( test[3]*factor, multiplywithconst[3],"test on multiplication with a const (operator *=())--vector 2nd"); - check_if_equal( test[4]*factor, multiplywithconst[4],"test on multiplication with a const (operator *=())--vector 3rd"); + const float factor = 5.0; + Quaternion multiplywithconst = test; + multiplywithconst *= factor; + + check_if_equal(test[1] * factor, multiplywithconst[1], "test on multiplication with a const (operator *=())--scalar"); + check_if_equal(test[2] * factor, multiplywithconst[2], "test on multiplication with a const (operator *=())--vector 1st"); + check_if_equal(test[3] * factor, multiplywithconst[3], "test on multiplication with a const (operator *=())--vector 2nd"); + check_if_equal(test[4] * factor, multiplywithconst[4], "test on multiplication with a const (operator *=())--vector 3rd"); } { - const float factor =5.0; - const Quaternion multiplywithconst =test*factor; - - check_if_equal( test[1]*factor, multiplywithconst[1],"test on multiplication with a const (operator *())--scalar"); - check_if_equal( test[2]*factor, multiplywithconst[2],"test on multiplication with a const (operator *())--vector 1st"); - check_if_equal( test[3]*factor, multiplywithconst[3],"test on multiplication with a const (operator *())--vector 2nd"); - check_if_equal( test[4]*factor, multiplywithconst[4],"test on multiplication with a const (operator *())--vector 3rd"); + const float factor = 5.0; + const Quaternion multiplywithconst = test * factor; + + check_if_equal(test[1] * factor, multiplywithconst[1], "test on multiplication with a const (operator *())--scalar"); + check_if_equal(test[2] * factor, multiplywithconst[2], "test on multiplication with a const (operator *())--vector 1st"); + check_if_equal(test[3] * factor, multiplywithconst[3], "test on multiplication with a const (operator *())--vector 2nd"); + check_if_equal(test[4] * factor, multiplywithconst[4], "test on multiplication with a const (operator *())--vector 3rd"); } - + cerr << "Testing division by a const" << endl; { - const float factor =5.0; - Quaternion dividewithconst =test; - dividewithconst /=factor; - - check_if_equal( test[1]/factor, dividewithconst[1],"test on division with a const (operator /=())-- scalar"); - check_if_equal( test[2]/factor, dividewithconst[2],"test on division with a const (operator /=())-- vector 1st"); - check_if_equal( test[3]/factor, dividewithconst[3],"test on division with a const (operator /=())-- vector 2nd"); - check_if_equal( test[4]/factor, dividewithconst[4],"test on division with a const (operator /=())-- vector 3rd"); + const float factor = 5.0; + Quaternion dividewithconst = test; + dividewithconst /= factor; + + check_if_equal(test[1] / factor, dividewithconst[1], "test on division with a const (operator /=())-- scalar"); + check_if_equal(test[2] / factor, dividewithconst[2], "test on division with a const (operator /=())-- vector 1st"); + check_if_equal(test[3] / factor, dividewithconst[3], "test on division with a const (operator /=())-- vector 2nd"); + check_if_equal(test[4] / factor, dividewithconst[4], "test on division with a const (operator /=())-- vector 3rd"); } { - const float factor =5.0; - Quaternion dividewithconst = test/factor; - - check_if_equal( test[1]/factor, dividewithconst[1],"test on division with a const (operator /())-- scalar"); - check_if_equal( test[2]/factor, dividewithconst[2],"test on division with a const (operator /())-- vector 1st"); - check_if_equal( test[3]/factor, dividewithconst[3],"test on division with a const (operator /())-- vector 2nd"); - check_if_equal( test[4]/factor, dividewithconst[4],"test on division with a const (operator /())-- vector 3rd"); + const float factor = 5.0; + Quaternion dividewithconst = test / factor; + + check_if_equal(test[1] / factor, dividewithconst[1], "test on division with a const (operator /())-- scalar"); + check_if_equal(test[2] / factor, dividewithconst[2], "test on division with a const (operator /())-- vector 1st"); + check_if_equal(test[3] / factor, dividewithconst[3], "test on division with a const (operator /())-- vector 2nd"); + check_if_equal(test[4] / factor, dividewithconst[4], "test on division with a const (operator /())-- vector 3rd"); } cerr << "Testing adding a const" << endl; { - const float factor =5.0; - Quaternion result = test+factor; - - check_if_equal( test[1]+factor, result[1],"test on addition with a const (operator +())-- scalar"); - check_if_equal( test[2]+factor, result[2],"test on addition with a const (operator +())-- vector 1st"); - check_if_equal( test[3]+factor, result[3],"test on addition with a const (operator +())-- vector 2nd"); - check_if_equal( test[4]+factor, result[4],"test on addition with a const (operator +())-- vector 3rd"); + const float factor = 5.0; + Quaternion result = test + factor; + + check_if_equal(test[1] + factor, result[1], "test on addition with a const (operator +())-- scalar"); + check_if_equal(test[2] + factor, result[2], "test on addition with a const (operator +())-- vector 1st"); + check_if_equal(test[3] + factor, result[3], "test on addition with a const (operator +())-- vector 2nd"); + check_if_equal(test[4] + factor, result[4], "test on addition with a const (operator +())-- vector 3rd"); } - cerr << "Testing subtracing a const" << endl; + cerr << "Testing subtracing a const" << endl; { - const float factor =5.0; - Quaternion result = test-factor; - - check_if_equal( test[1]-factor, result[1],"test on subtraction with a const (operator -())-- scalar"); - check_if_equal( test[2]-factor, result[2],"test on subtraction with a const (operator -())-- vector 1st"); - check_if_equal( test[3]-factor, result[3],"test on subtraction with a const (operator -())-- vector 2nd"); - check_if_equal( test[4]-factor, result[4],"test on subtraction with a const (operator -())-- vector 3rd"); + const float factor = 5.0; + Quaternion result = test - factor; + + check_if_equal(test[1] - factor, result[1], "test on subtraction with a const (operator -())-- scalar"); + check_if_equal(test[2] - factor, result[2], "test on subtraction with a const (operator -())-- vector 1st"); + check_if_equal(test[3] - factor, result[3], "test on subtraction with a const (operator -())-- vector 2nd"); + check_if_equal(test[4] - factor, result[4], "test on subtraction with a const (operator -())-- vector 3rd"); } cerr << "Testing multiplication of two quaternions" << endl; - { + { Quaternion first_factor(1, 3, -2, 2); Quaternion second_factor(2, 0, -6, 3); - Quaternion result (-16, 12, -19, -11); - - first_factor *=second_factor; - check_if_equal( result[1], first_factor[1],"test on quaternion multiplication (operator*= (Quaternion& q)) -- scalar"); - check_if_equal( result[2], first_factor[2],"test on quaternion multiplication (operator*= (Quaternion& q)) -- vector 1st"); - check_if_equal( result[3], first_factor[3],"test on quaternion multiplication (operator*= (Quaternion& q)) -- vector 2nd"); - check_if_equal( result[4], first_factor[4],"test on quaternion multiplication (operator*= (Quaternion& q))-- vector 3rd"); + Quaternion result(-16, 12, -19, -11); + + first_factor *= second_factor; + check_if_equal(result[1], first_factor[1], "test on quaternion multiplication (operator*= (Quaternion& q)) -- scalar"); + check_if_equal(result[2], first_factor[2], "test on quaternion multiplication (operator*= (Quaternion& q)) -- vector 1st"); + check_if_equal(result[3], first_factor[3], "test on quaternion multiplication (operator*= (Quaternion& q)) -- vector 2nd"); + check_if_equal(result[4], first_factor[4], "test on quaternion multiplication (operator*= (Quaternion& q))-- vector 3rd"); } cerr << "Testing addition of two quaternions" << endl; - { + { const Quaternion first(1, 3, -2, 2); const Quaternion second(2, 0, -6, 3); const Quaternion result = first + second; - check_if_equal( result[1], first[1]+second[1],"test on quaternion addition (operator+ (Quaternion& q)) -- scalar"); - check_if_equal( result[2], first[2]+second[2],"test on quaternion addition (operator+ (Quaternion& q)) -- vector 1st"); - check_if_equal( result[3], first[3]+second[3],"test on quaternion addition (operator+ (Quaternion& q)) -- vector 2nd"); - check_if_equal( result[4], first[4]+second[4],"test on quaternion addition (operator+ (Quaternion& q)) -- vector 3rd"); + check_if_equal(result[1], first[1] + second[1], "test on quaternion addition (operator+ (Quaternion& q)) -- scalar"); + check_if_equal(result[2], first[2] + second[2], "test on quaternion addition (operator+ (Quaternion& q)) -- vector 1st"); + check_if_equal(result[3], first[3] + second[3], "test on quaternion addition (operator+ (Quaternion& q)) -- vector 2nd"); + check_if_equal(result[4], first[4] + second[4], "test on quaternion addition (operator+ (Quaternion& q)) -- vector 3rd"); } cerr << "Testing subtraction of two quaternions" << endl; - { + { const Quaternion first(1, 3, -2, 2); const Quaternion second(2, 0, -6, 3); const Quaternion result = first - second; - check_if_equal( result[1], first[1]-second[1],"test on quaternion subtraction (operator+ (Quaternion& q)) -- scalar"); - check_if_equal( result[2], first[2]-second[2],"test on quaternion subtraction (operator+ (Quaternion& q)) -- vector 1st"); - check_if_equal( result[3], first[3]-second[3],"test on quaternion subtraction (operator+ (Quaternion& q)) -- vector 2nd"); - check_if_equal( result[4], first[4]-second[4],"test on quaternion subtraction (operator+ (Quaternion& q)) -- vector 3rd"); + check_if_equal(result[1], first[1] - second[1], "test on quaternion subtraction (operator+ (Quaternion& q)) -- scalar"); + check_if_equal(result[2], first[2] - second[2], "test on quaternion subtraction (operator+ (Quaternion& q)) -- vector 1st"); + check_if_equal(result[3], first[3] - second[3], "test on quaternion subtraction (operator+ (Quaternion& q)) -- vector 2nd"); + check_if_equal(result[4], first[4] - second[4], "test on quaternion subtraction (operator+ (Quaternion& q)) -- vector 3rd"); } - + cerr << "Testing neg_quaternion ()" << endl; { - Quaternion neg_test =test; + Quaternion neg_test = test; neg_test.neg_quaternion(); - - check_if_equal( neg_test[1], -1*test[1],"test on neg_quaternion () -- scalar"); - check_if_equal( neg_test[2], -1*test[2],"test on neg_quaternion () -- vector 1st"); - check_if_equal( neg_test[3], -1*test[3],"test on neg_quaternion () -- vector 2nd"); - check_if_equal( neg_test[4], -1*test[4],"test on neg_quaternion () -- vector 3rd"); + + check_if_equal(neg_test[1], -1 * test[1], "test on neg_quaternion () -- scalar"); + check_if_equal(neg_test[2], -1 * test[2], "test on neg_quaternion () -- vector 1st"); + check_if_equal(neg_test[3], -1 * test[3], "test on neg_quaternion () -- vector 2nd"); + check_if_equal(neg_test[4], -1 * test[4], "test on neg_quaternion () -- vector 3rd"); } cerr << "Testing conjugate()" << endl; { - Quaternion conj_test =test; + Quaternion conj_test = test; conj_test.conjugate(); - - check_if_equal( conj_test[1], test[1], "test on conjugate() -- scalar"); - check_if_equal( conj_test[2], -1*test[2],"test on conjugate() -- vector 1st"); - check_if_equal( conj_test[3], -1*test[3],"test on conjugate() -- vector 2nd"); - check_if_equal( conj_test[4], -1*test[4],"test on conjugate() -- vector 3rd"); + + check_if_equal(conj_test[1], test[1], "test on conjugate() -- scalar"); + check_if_equal(conj_test[2], -1 * test[2], "test on conjugate() -- vector 1st"); + check_if_equal(conj_test[3], -1 * test[3], "test on conjugate() -- vector 2nd"); + check_if_equal(conj_test[4], -1 * test[4], "test on conjugate() -- vector 3rd"); } - + cerr << "Testing normalise()" << endl; { - const float test_squared = sqrt(square(test[1]) + square(test[2]) +square(test[3])+ square(test[4])); + const float test_squared = sqrt(square(test[1]) + square(test[2]) + square(test[3]) + square(test[4])); Quaternion test_norm = test; - test_norm /=test_squared; - Quaternion norm_test =test; + test_norm /= test_squared; + Quaternion norm_test = test; norm_test.normalise(); - - check_if_equal( norm_test[1], test_norm[1], "test on normalise() -- scalar"); - check_if_equal( norm_test[2], test_norm[2], "test on normalise() -- vector 1st"); - check_if_equal( norm_test[3], test_norm[3], "test on normalise() -- vector 2nd"); - check_if_equal( norm_test[4], test_norm[4], "test on normalise() -- vector 3rd"); + + check_if_equal(norm_test[1], test_norm[1], "test on normalise() -- scalar"); + check_if_equal(norm_test[2], test_norm[2], "test on normalise() -- vector 1st"); + check_if_equal(norm_test[3], test_norm[3], "test on normalise() -- vector 2nd"); + check_if_equal(norm_test[4], test_norm[4], "test on normalise() -- vector 3rd"); } - + cerr << "Testing inverse()" << endl; { - const Quaternion test_inverse (1, 3, -2, 2); - float dot_product =(test_inverse[1]*test_inverse[1])+(test_inverse[2]*test_inverse[2])+(test_inverse[3]*test_inverse[3])+(test_inverse[4]*test_inverse[4]); - Quaternion result_inverse =test_inverse; - result_inverse[1] /=dot_product; - result_inverse[2] *=-1;result_inverse[2] /=dot_product; - result_inverse[3] *=-1;result_inverse[3] /=dot_product; - result_inverse[4] *=-1;result_inverse[4] /=dot_product; - - Quaternion test_inverse_result =test_inverse; + const Quaternion test_inverse(1, 3, -2, 2); + float dot_product = (test_inverse[1] * test_inverse[1]) + (test_inverse[2] * test_inverse[2]) + + (test_inverse[3] * test_inverse[3]) + (test_inverse[4] * test_inverse[4]); + Quaternion result_inverse = test_inverse; + result_inverse[1] /= dot_product; + result_inverse[2] *= -1; + result_inverse[2] /= dot_product; + result_inverse[3] *= -1; + result_inverse[3] /= dot_product; + result_inverse[4] *= -1; + result_inverse[4] /= dot_product; + + Quaternion test_inverse_result = test_inverse; test_inverse_result.inverse(); - check_if_equal( test_inverse_result[1], result_inverse[1], "test on inverse() -- scalar"); - check_if_equal( test_inverse_result[2], result_inverse[2], "test on inverse() -- vector 1st"); - check_if_equal( test_inverse_result[3], result_inverse[3], "test on inverse() -- vector 2nd"); - check_if_equal( test_inverse_result[4], result_inverse[4], "test on inverse() -- vector 3rd"); + check_if_equal(test_inverse_result[1], result_inverse[1], "test on inverse() -- scalar"); + check_if_equal(test_inverse_result[2], result_inverse[2], "test on inverse() -- vector 1st"); + check_if_equal(test_inverse_result[3], result_inverse[3], "test on inverse() -- vector 2nd"); + check_if_equal(test_inverse_result[4], result_inverse[4], "test on inverse() -- vector 3rd"); const Quaternion unit = test_inverse * test_inverse_result; - - check_if_equal( unit[1], 1.F, "test on inverse(): multiplication -- scalar"); - check_if_equal( unit[2], 0.F, "test on inverse(): multiplication -- vector 1st"); - check_if_equal( unit[2], 0.F, "test on inverse(): multiplication -- vector 2nd"); - check_if_equal( unit[2], 0.F, "test on inverse(): multiplication -- vector 3rd"); + + check_if_equal(unit[1], 1.F, "test on inverse(): multiplication -- scalar"); + check_if_equal(unit[2], 0.F, "test on inverse(): multiplication -- vector 1st"); + check_if_equal(unit[2], 0.F, "test on inverse(): multiplication -- vector 2nd"); + check_if_equal(unit[2], 0.F, "test on inverse(): multiplication -- vector 3rd"); } - } END_NAMESPACE_STIR - - USING_NAMESPACE_STIR -int main() -{ +int +main() { QuaternionTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/experimental/test/test_RigidObject3DTransformation.cxx b/src/experimental/test/test_RigidObject3DTransformation.cxx index e51d2b1dce..212e64d3f8 100644 --- a/src/experimental/test/test_RigidObject3DTransformation.cxx +++ b/src/experimental/test/test_RigidObject3DTransformation.cxx @@ -11,7 +11,7 @@ \see stir::RigidObject3DTransformationTests \author Kris Thielemans \author Sanida Mustafovic - + */ #include "stir/RunTests.h" #include "stir_experimental/Quaternion.h" @@ -37,7 +37,7 @@ #include "stir/VoxelsOnCartesianGrid.h" #include "stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.h" // necessary for shared_ptr in ProjMatrixElemsForOneDensel.h #ifdef DO_TIMINGS -#include "stir/CPUTimer.h" +# include "stir/CPUTimer.h" #endif #include "stir/LORCoordinates.h" #include "stir/geometry/line_distances.h" @@ -47,34 +47,35 @@ #include #include #ifdef BOOST_NO_STDC_NAMESPACE -namespace std { using ::sqrt; using ::fabs; } +namespace std { +using ::sqrt; +using ::fabs; +} // namespace std #endif - START_NAMESPACE_STIR - /*! \ingroup motion_test \brief Various tests on RigidObject3DTransformation Indirectly tests ProjDataInfo::get_bin and ProjDataInfo::get_LOR. - Tests include checks on + Tests include checks on - compose() and inverse() - - if LORs through a voxel have a close distance to the central + - if LORs through a voxel have a close distance to the central centre of the voxel (before and after transformation), - consistency between moving a voxel and moving an LOR using the following - procedure: forward project voxel, move LOR, backproject voxel, + procedure: forward project voxel, move LOR, backproject voxel, find location of maximum, compare this with moving the voxel directly. - \todo tests on inverse of transform_bin fail with some rotations (too large + \todo tests on inverse of transform_bin fail with some rotations (too large difference in round-trip). */ -class RigidObject3DTransformationTests: public RunTests -{ -public: +class RigidObject3DTransformationTests : public RunTests { +public: void run_tests(); + private: void test_transform_bin(); void test_transform_bin_with_inverse(const ProjDataInfo& proj_data_info, const bool is_uncompressed); @@ -83,55 +84,48 @@ class RigidObject3DTransformationTests: public RunTests }; void -RigidObject3DTransformationTests::run_tests() -{ +RigidObject3DTransformationTests::run_tests() { std::cerr << "\nTesting RigidObject3DTransformation\n"; std::cerr << "\tTesting inverse and check if it's a rigid transformation\n"; { - Quaternion quat(1,-2,3,8); + Quaternion quat(1, -2, 3, 8); quat.normalise(); - const CartesianCoordinate3D translation(111,-12,152); - + const CartesianCoordinate3D translation(111, -12, 152); + const RigidObject3DTransformation ro3dtrans(quat, translation); - - RigidObject3DTransformation ro3dtrans_inverse =ro3dtrans; - ro3dtrans_inverse =ro3dtrans_inverse.inverse(); + + RigidObject3DTransformation ro3dtrans_inverse = ro3dtrans; + ro3dtrans_inverse = ro3dtrans_inverse.inverse(); { const Quaternion quat_original = ro3dtrans.get_quaternion(); const Quaternion quat_inverse = ro3dtrans_inverse.get_quaternion(); - + const Quaternion unity = quat_original * quat_inverse; - + check_if_equal(unity[1], 1.F, "test on inverse quat -- scalar"); check_if_equal(unity[2], 0.F, "test on inverse quat -- vector1"); check_if_equal(unity[3], 0.F, "test on inverse quat -- vector2"); check_if_equal(unity[4], 0.F, "test on inverse quat -- vector3"); - } + } - - const CartesianCoordinate3D transformed_origin = - ro3dtrans.transform_point(CartesianCoordinate3D(0,0,0)); - for (int i=0; i<100; ++i) - { - const CartesianCoordinate3D point(210.F*i,-55.F-i,2.F+2*i); - const CartesianCoordinate3D transformed_point =ro3dtrans.transform_point(point); - //Testing norm of the original and transformed point + const CartesianCoordinate3D transformed_origin = ro3dtrans.transform_point(CartesianCoordinate3D(0, 0, 0)); + for (int i = 0; i < 100; ++i) { + const CartesianCoordinate3D point(210.F * i, -55.F - i, 2.F + 2 * i); + const CartesianCoordinate3D transformed_point = ro3dtrans.transform_point(point); + // Testing norm of the original and transformed point { - const float original_distance = norm(point /* - origin*/); - const float transformed_distance = norm(transformed_point-transformed_origin); - check_if_equal(original_distance, transformed_distance, "test on distance to see if it's a rigid transformation"); + const float original_distance = norm(point /* - origin*/); + const float transformed_distance = norm(transformed_point - transformed_origin); + check_if_equal(original_distance, transformed_distance, "test on distance to see if it's a rigid transformation"); } // Testing to see if inverse gets us back { - - const CartesianCoordinate3D transformed_back_point = - ro3dtrans_inverse.transform_point(transformed_point); - // compare with original by checking norm of difference - // divide by norm(point) such that we're looking at a relative measure - check_if_zero(norm(point-transformed_back_point)/norm(point), - "test on inverse transformation of transformed point"); - + + const CartesianCoordinate3D transformed_back_point = ro3dtrans_inverse.transform_point(transformed_point); + // compare with original by checking norm of difference + // divide by norm(point) such that we're looking at a relative measure + check_if_zero(norm(point - transformed_back_point) / norm(point), "test on inverse transformation of transformed point"); } } } @@ -180,58 +174,49 @@ RigidObject3DTransformationTests::run_tests() #endif std::cerr << "\n\tTesting compose " << std::endl; { - Quaternion quat_1(1,-2,3,8); + Quaternion quat_1(1, -2, 3, 8); quat_1.normalise(); - const CartesianCoordinate3D translation_1(111,-12,152); + const CartesianCoordinate3D translation_1(111, -12, 152); const RigidObject3DTransformation ro3dtrans_1(quat_1, translation_1); - - Quaternion quat_2(1,-3,12,4); + + Quaternion quat_2(1, -3, 12, 4); quat_2.normalise(); - const CartesianCoordinate3D translation_2(1,-54,12); + const CartesianCoordinate3D translation_2(1, -54, 12); const RigidObject3DTransformation ro3dtrans_2(quat_2, translation_2); - - Quaternion quat_3(2,-7,24,1); + + Quaternion quat_3(2, -7, 24, 1); quat_3.normalise(); - const CartesianCoordinate3D translation_3(9,4,34); + const CartesianCoordinate3D translation_3(9, 4, 34); const RigidObject3DTransformation ro3dtrans_3(quat_3, translation_3); -#ifdef DO_TIMINGS +#ifdef DO_TIMINGS CPUTimer timer; timer.reset(); CPUTimer compose_timer; compose_timer.reset(); #endif - const RigidObject3DTransformation composed_ro3dtrans1= - compose(ro3dtrans_3, - compose(ro3dtrans_2,ro3dtrans_1)); - - for (int i=0; i<1000; ++i) - { - const CartesianCoordinate3D point(210.F*i,-55.F-i,2.F+2*i); + const RigidObject3DTransformation composed_ro3dtrans1 = compose(ro3dtrans_3, compose(ro3dtrans_2, ro3dtrans_1)); + + for (int i = 0; i < 1000; ++i) { + const CartesianCoordinate3D point(210.F * i, -55.F - i, 2.F + 2 * i); #ifdef DO_TIMINGS timer.start(); #endif const CartesianCoordinate3D transformed_point_3 = - ro3dtrans_3. - transform_point(ro3dtrans_2. - transform_point( - ro3dtrans_1. - transform_point(point))); -#ifdef DO_TIMINGS + ro3dtrans_3.transform_point(ro3dtrans_2.transform_point(ro3dtrans_1.transform_point(point))); +#ifdef DO_TIMINGS timer.stop(); - + compose_timer.start(); -#endif - const CartesianCoordinate3D transformed_point_composed = - composed_ro3dtrans1.transform_point(point); +#endif + const CartesianCoordinate3D transformed_point_composed = composed_ro3dtrans1.transform_point(point); #ifdef DO_TIMINGS compose_timer.stop(); #endif - check_if_zero(norm(transformed_point_3-transformed_point_composed)/norm(transformed_point_3), - "test on compose"); + check_if_zero(norm(transformed_point_3 - transformed_point_composed) / norm(transformed_point_3), "test on compose"); } #ifdef DO_TIMINGS - std::cerr << " Individual multiplications: " << timer.value() << " s CPU time"< scanner_ptr = new Scanner(Scanner::E953); - // we make the scanner longer to avoid problems with rotations - // (almost) orthogonal to the scanner axis. Otherwise most - // LORs would be transformed out of the scanner, and we won't get - // a get intersection of the backprojections - scanner_ptr->set_num_rings(40); - std::cerr << "\n\tTests with proj_data_info without mashing and axial compression, no arc-correction\n"; - shared_ptr proj_data_info_sptr = +void +RigidObject3DTransformationTests::test_transform_bin() { + shared_ptr scanner_ptr = new Scanner(Scanner::E953); + // we make the scanner longer to avoid problems with rotations + // (almost) orthogonal to the scanner axis. Otherwise most + // LORs would be transformed out of the scanner, and we won't get + // a get intersection of the backprojections + scanner_ptr->set_num_rings(40); + std::cerr << "\n\tTests with proj_data_info without mashing and axial compression, no arc-correction\n"; + shared_ptr proj_data_info_sptr = ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - /*span*/1, scanner_ptr->get_num_rings()-1, - /*views*/ scanner_ptr->get_num_detectors_per_ring()/2, - /*tang_pos*/scanner_ptr->get_num_detectors_per_ring()/2, - /*arc_corrected*/ false); - ProjDataInfoCylindricalNoArcCorr& proj_data_info = - dynamic_cast(*proj_data_info_sptr); - - test_transform_bin_with_inverse(proj_data_info, /*is_uncompressed=*/true); - // TODO ProjMatrixByDensel cannot do span=1 yet - // test_transform_bin_vs_transform_point(proj_data_info_sptr); + /*span*/ 1, scanner_ptr->get_num_rings() - 1, + /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2, + /*tang_pos*/ scanner_ptr->get_num_detectors_per_ring() / 2, + /*arc_corrected*/ false); + ProjDataInfoCylindricalNoArcCorr& proj_data_info = dynamic_cast(*proj_data_info_sptr); + + test_transform_bin_with_inverse(proj_data_info, /*is_uncompressed=*/true); + // TODO ProjMatrixByDensel cannot do span=1 yet + // test_transform_bin_vs_transform_point(proj_data_info_sptr); #ifdef NEW_ROT - // old get_bin() cannot handle spanned data, so tests disabled ifndef NEW_ROT - std::cerr << "\n\tTests with proj_data_info with mashing and axial compression, no arc-correction\n"; - proj_data_info_sptr = - ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - /*span*/3, scanner_ptr->get_num_rings()-1, - /*views*/ scanner_ptr->get_num_detectors_per_ring()/6, - /*tang_pos*/scanner_ptr->get_num_detectors_per_ring()/3, - /*arc_corrected*/ false); - test_transform_bin_with_inverse(*proj_data_info_sptr,/*is_uncompressed=*/false); - test_transform_bin_vs_transform_point(proj_data_info_sptr); - - std::cerr << "\n\tTests with proj_data_info without mashing and axial compression, arc-correction\n"; - proj_data_info_sptr = - ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - /*span*/1, scanner_ptr->get_num_rings()-1, - /*views*/ scanner_ptr->get_num_detectors_per_ring()/2, - /*tang_pos*/scanner_ptr->get_num_detectors_per_ring()/2, - /*arc_corrected*/ true); - test_transform_bin_with_inverse(*proj_data_info_sptr,/*is_uncompressed=*/true); - // TODO ProjMatrixByDensel cannot do span=1 yet - // test_transform_bin_vs_transform_point(proj_data_info_sptr); - - std::cerr << "\n\tTests with proj_data_info with mashing and axial compression, arc-correction\n"; - proj_data_info_sptr = - ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - /*span*/3, scanner_ptr->get_num_rings()-1, - /*views*/ scanner_ptr->get_num_detectors_per_ring()/6, - /*tang_pos*/scanner_ptr->get_num_detectors_per_ring()/3, - /*arc_corrected*/ true); - test_transform_bin_with_inverse(*proj_data_info_sptr,/*is_uncompressed=*/false); - test_transform_bin_vs_transform_point(proj_data_info_sptr); + // old get_bin() cannot handle spanned data, so tests disabled ifndef NEW_ROT + std::cerr << "\n\tTests with proj_data_info with mashing and axial compression, no arc-correction\n"; + proj_data_info_sptr = ProjDataInfo::ProjDataInfoCTI(scanner_ptr, + /*span*/ 3, scanner_ptr->get_num_rings() - 1, + /*views*/ scanner_ptr->get_num_detectors_per_ring() / 6, + /*tang_pos*/ scanner_ptr->get_num_detectors_per_ring() / 3, + /*arc_corrected*/ false); + test_transform_bin_with_inverse(*proj_data_info_sptr, /*is_uncompressed=*/false); + test_transform_bin_vs_transform_point(proj_data_info_sptr); + + std::cerr << "\n\tTests with proj_data_info without mashing and axial compression, arc-correction\n"; + proj_data_info_sptr = ProjDataInfo::ProjDataInfoCTI(scanner_ptr, + /*span*/ 1, scanner_ptr->get_num_rings() - 1, + /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2, + /*tang_pos*/ scanner_ptr->get_num_detectors_per_ring() / 2, + /*arc_corrected*/ true); + test_transform_bin_with_inverse(*proj_data_info_sptr, /*is_uncompressed=*/true); + // TODO ProjMatrixByDensel cannot do span=1 yet + // test_transform_bin_vs_transform_point(proj_data_info_sptr); + + std::cerr << "\n\tTests with proj_data_info with mashing and axial compression, arc-correction\n"; + proj_data_info_sptr = ProjDataInfo::ProjDataInfoCTI(scanner_ptr, + /*span*/ 3, scanner_ptr->get_num_rings() - 1, + /*views*/ scanner_ptr->get_num_detectors_per_ring() / 6, + /*tang_pos*/ scanner_ptr->get_num_detectors_per_ring() / 3, + /*arc_corrected*/ true); + test_transform_bin_with_inverse(*proj_data_info_sptr, /*is_uncompressed=*/false); + test_transform_bin_vs_transform_point(proj_data_info_sptr); #endif - - } +} // first define some functions to check 'closeness' of 2 bins static Bin -swap_direction(const Bin& bin, const int num_views) -{ - return Bin(-bin.segment_num(), - bin.view_num() < num_views/2? bin.view_num()+ num_views : bin.view_num() - num_views, - bin.axial_pos_num(), - -bin.tangential_pos_num()); +swap_direction(const Bin& bin, const int num_views) { + return Bin(-bin.segment_num(), bin.view_num() < num_views / 2 ? bin.view_num() + num_views : bin.view_num() - num_views, + bin.axial_pos_num(), -bin.tangential_pos_num()); } #if 0 @@ -355,162 +328,120 @@ bin_diff(const Bin& org_bin, const Bin& transformed_bin, const int num_views, co #else static Coordinate4D -bin_diff_no_reorder(const Bin& org_bin, const Bin& transformed_bin, const ProjDataInfo& proj_data_info) -{ +bin_diff_no_reorder(const Bin& org_bin, const Bin& transformed_bin, const ProjDataInfo& proj_data_info) { Coordinate4D diff; - diff[1] = - (org_bin.segment_num() - transformed_bin.segment_num()); - diff[2] = - (org_bin.view_num() - transformed_bin.view_num()); - diff[3] = - (proj_data_info.get_m(org_bin) - - proj_data_info.get_m(transformed_bin))/ - proj_data_info.get_sampling_in_m(org_bin); - diff[4] = - (proj_data_info.get_s(org_bin) - - proj_data_info.get_s(transformed_bin))/ - proj_data_info.get_sampling_in_s(org_bin); + diff[1] = (org_bin.segment_num() - transformed_bin.segment_num()); + diff[2] = (org_bin.view_num() - transformed_bin.view_num()); + diff[3] = (proj_data_info.get_m(org_bin) - proj_data_info.get_m(transformed_bin)) / proj_data_info.get_sampling_in_m(org_bin); + diff[4] = (proj_data_info.get_s(org_bin) - proj_data_info.get_s(transformed_bin)) / proj_data_info.get_sampling_in_s(org_bin); return diff; } -static float -sup_norm(const Coordinate4D& c) -{ - return std::max(std::fabs(c[1]), - std::max(std::fabs(c[2]), - std::max(std::fabs(c[3]), - std::fabs(c[4])))); +static float +sup_norm(const Coordinate4D& c) { + return std::max(std::fabs(c[1]), std::max(std::fabs(c[2]), std::max(std::fabs(c[3]), std::fabs(c[4])))); } static Coordinate4D -bin_diff(const Bin& org_bin, const Bin& transformed_bin, const ProjDataInfo& proj_data_info) -{ - const Coordinate4D diff1=bin_diff_no_reorder(org_bin, transformed_bin, proj_data_info); - const Coordinate4D diff2=bin_diff_no_reorder(org_bin, swap_direction(transformed_bin, proj_data_info.get_num_views()), proj_data_info); - return - sup_norm(diff1) diff1 = bin_diff_no_reorder(org_bin, transformed_bin, proj_data_info); + const Coordinate4D diff2 = + bin_diff_no_reorder(org_bin, swap_direction(transformed_bin, proj_data_info.get_num_views()), proj_data_info); + return sup_norm(diff1) < sup_norm(diff2) ? diff1 : diff2; } #endif void -RigidObject3DTransformationTests:: -test_transform_bin_with_inverse(const ProjDataInfo& proj_data_info, const bool is_uncompressed) -{ - std::cerr <<"\n\t\ttesting transform_bin and inverse()\n"; +RigidObject3DTransformationTests::test_transform_bin_with_inverse(const ProjDataInfo& proj_data_info, + const bool is_uncompressed) { + std::cerr << "\n\t\ttesting transform_bin and inverse()\n"; // std::cerr < quat(1.F,0.05F,-.03F,.1F); + Quaternion quat(1.F, 0.05F, -.03F, .1F); quat.normalise(); - const CartesianCoordinate3D translation(11,-12,15); - + const CartesianCoordinate3D translation(11, -12, 15); + const RigidObject3DTransformation ro3dtrans(quat, translation); const RigidObject3DTransformation ro3dtrans_inverse = ro3dtrans.inverse(); unsigned num_bins_checked = 0; unsigned num_bins_in_range = 0; - Coordinate4D max_diff(0,0,0,0); + Coordinate4D max_diff(0, 0, 0, 0); #ifdef NEW_ROT - const float allowed_diff = - is_uncompressed ? 1.1F : 1.1F; + const float allowed_diff = is_uncompressed ? 1.1F : 1.1F; #else - const float allowed_diff = - 2.1F; + const float allowed_diff = 2.1F; #endif - for (int segment_num=proj_data_info.get_min_segment_num(); - segment_num<=proj_data_info.get_max_segment_num(); - ++segment_num) - { - for (int view_num=proj_data_info.get_min_view_num(); - view_num<=proj_data_info.get_max_view_num(); - view_num+=5) - { - // loop over axial_positions. Avoid using first and last position, as - // the discretisation error can easily bring the transformed_bin back - // outside the range. We could test for that, but it would make - // the code much more complicated, and not give anything useful back. - for (int axial_pos_num=proj_data_info.get_min_axial_pos_num(segment_num)+1; - axial_pos_num<=proj_data_info.get_max_axial_pos_num(segment_num)-1; - axial_pos_num+=3) - { - for (int tangential_pos_num=proj_data_info.get_min_tangential_pos_num()+1; - tangential_pos_num<=proj_data_info.get_max_tangential_pos_num()-1; - tangential_pos_num+=17) - { - ++num_bins_checked; - - const Bin org_bin(segment_num,view_num,axial_pos_num,tangential_pos_num, /* value*/1); - Bin transformed_bin = org_bin; - ro3dtrans.transform_bin(transformed_bin, proj_data_info, proj_data_info); - - if (transformed_bin.get_bin_value()>0) // only check when the transformed_bin is within the range - { - ro3dtrans_inverse.transform_bin(transformed_bin, proj_data_info, proj_data_info); - // the inverse might still take it outside the range unfortunately - if (transformed_bin.get_bin_value()<=0) - continue; - - ++num_bins_in_range; - - const Coordinate4D diff = bin_diff(org_bin, transformed_bin, proj_data_info); - if (sup_norm(diff)>sup_norm(max_diff)) - max_diff = diff; - - if (!check(org_bin.get_bin_value() == transformed_bin.get_bin_value(), "transform_bin_with_inverse: value") || - !check(sup_norm(diff)<=allowed_diff, "transform_bin_with_inverse: different bin")) - { - std::cerr << "\tProblem at segment=" << org_bin.segment_num() - << ", axial pos=" << org_bin.axial_pos_num() - << ", view=" << org_bin.view_num() - << ", tangential_pos=" << org_bin.tangential_pos_num() - << '\n'; - std::cerr << "\tround-trip to segment=" << transformed_bin.segment_num() - << ", axial pos=" << transformed_bin.axial_pos_num() - << ", view= " << transformed_bin.view_num() - << ", tangential_pos=" << transformed_bin.tangential_pos_num() - << " value=" << transformed_bin.get_bin_value() - << " sup_norm(diff)=" << sup_norm(diff) - <<'\n'; - } - } - } // tangential_pos - } // axial_pos - } // view - } //segment + for (int segment_num = proj_data_info.get_min_segment_num(); segment_num <= proj_data_info.get_max_segment_num(); + ++segment_num) { + for (int view_num = proj_data_info.get_min_view_num(); view_num <= proj_data_info.get_max_view_num(); view_num += 5) { + // loop over axial_positions. Avoid using first and last position, as + // the discretisation error can easily bring the transformed_bin back + // outside the range. We could test for that, but it would make + // the code much more complicated, and not give anything useful back. + for (int axial_pos_num = proj_data_info.get_min_axial_pos_num(segment_num) + 1; + axial_pos_num <= proj_data_info.get_max_axial_pos_num(segment_num) - 1; axial_pos_num += 3) { + for (int tangential_pos_num = proj_data_info.get_min_tangential_pos_num() + 1; + tangential_pos_num <= proj_data_info.get_max_tangential_pos_num() - 1; tangential_pos_num += 17) { + ++num_bins_checked; + + const Bin org_bin(segment_num, view_num, axial_pos_num, tangential_pos_num, /* value*/ 1); + Bin transformed_bin = org_bin; + ro3dtrans.transform_bin(transformed_bin, proj_data_info, proj_data_info); + + if (transformed_bin.get_bin_value() > 0) // only check when the transformed_bin is within the range + { + ro3dtrans_inverse.transform_bin(transformed_bin, proj_data_info, proj_data_info); + // the inverse might still take it outside the range unfortunately + if (transformed_bin.get_bin_value() <= 0) + continue; + + ++num_bins_in_range; + + const Coordinate4D diff = bin_diff(org_bin, transformed_bin, proj_data_info); + if (sup_norm(diff) > sup_norm(max_diff)) + max_diff = diff; + + if (!check(org_bin.get_bin_value() == transformed_bin.get_bin_value(), "transform_bin_with_inverse: value") || + !check(sup_norm(diff) <= allowed_diff, "transform_bin_with_inverse: different bin")) { + std::cerr << "\tProblem at segment=" << org_bin.segment_num() << ", axial pos=" << org_bin.axial_pos_num() + << ", view=" << org_bin.view_num() << ", tangential_pos=" << org_bin.tangential_pos_num() << '\n'; + std::cerr << "\tround-trip to segment=" << transformed_bin.segment_num() + << ", axial pos=" << transformed_bin.axial_pos_num() << ", view= " << transformed_bin.view_num() + << ", tangential_pos=" << transformed_bin.tangential_pos_num() + << " value=" << transformed_bin.get_bin_value() << " sup_norm(diff)=" << sup_norm(diff) << '\n'; + } + } + } // tangential_pos + } // axial_pos + } // view + } // segment std::cerr << "\t\t" << num_bins_checked << " num_bins checked, " << num_bins_in_range << " transformed in range\n" - << "\t\tmax deviation (sup_norm):" - << sup_norm(max_diff) - << '\n'; + << "\t\tmax deviation (sup_norm):" << sup_norm(max_diff) << '\n'; } void -RigidObject3DTransformationTests:: -test_transform_bin_vs_transform_point(const shared_ptr& proj_data_info_sptr) -{ +RigidObject3DTransformationTests::test_transform_bin_vs_transform_point(const shared_ptr& proj_data_info_sptr) { std::cerr << "\n\t\ttesting consistency transform_point and transform_bin\n"; - shared_ptr > density_sptr = - new VoxelsOnCartesianGrid (*proj_data_info_sptr); - const CartesianCoordinate3D origin = - density_sptr->get_origin(); + shared_ptr> density_sptr = new VoxelsOnCartesianGrid(*proj_data_info_sptr); + const CartesianCoordinate3D origin = density_sptr->get_origin(); const CartesianCoordinate3D voxel_size = - dynamic_cast const&>(*density_sptr).get_grid_spacing(); + dynamic_cast const&>(*density_sptr).get_grid_spacing(); // somewhat arbitrary: not a lot more than a voxel - const float allowed_deviation=static_cast(norm(voxel_size)/std::sqrt(3.)*1.9); + const float allowed_deviation = static_cast(norm(voxel_size) / std::sqrt(3.) * 1.9); - Quaternion quat(.7F,.2F,-.1F,.1F); + Quaternion quat(.7F, .2F, -.1F, .1F); quat.normalise(); - const CartesianCoordinate3D translation(-11,-12,15); - + const CartesianCoordinate3D translation(-11, -12, 15); + const RigidObject3DTransformation ro3dtrans(quat, translation); - - //RigidObject3DTransformation ro3dtrans_inverse =ro3dtrans; - //ro3dtrans_inverse =ro3dtrans_inverse.inverse(); - + // RigidObject3DTransformation ro3dtrans_inverse =ro3dtrans; + // ro3dtrans_inverse =ro3dtrans_inverse.inverse(); + ProjMatrixByDenselUsingRayTracing pm_by_densel; pm_by_densel.set_up(proj_data_info_sptr, density_sptr); ProjMatrixByBinUsingRayTracing pm_by_bin; @@ -522,160 +453,126 @@ test_transform_bin_vs_transform_point(const shared_ptr& proj_data_ { ProjMatrixElemsForOneDensel bins; ProjMatrixElemsForOneBin lor; - - const Densel densel((density_sptr->get_min_index()+density_sptr->get_max_index())/2+5,5,10); - const CartesianCoordinate3D densel_coord = - BasicCoordinate<3,float>(densel) * voxel_size + origin; - const CartesianCoordinate3D transformed_densel_coord = - ro3dtrans.transform_point(densel_coord); - const CartesianCoordinate3D transformed_densel_float = - (transformed_densel_coord - origin)/voxel_size; + + const Densel densel((density_sptr->get_min_index() + density_sptr->get_max_index()) / 2 + 5, 5, 10); + const CartesianCoordinate3D densel_coord = BasicCoordinate<3, float>(densel) * voxel_size + origin; + const CartesianCoordinate3D transformed_densel_coord = ro3dtrans.transform_point(densel_coord); + const CartesianCoordinate3D transformed_densel_float = (transformed_densel_coord - origin) / voxel_size; const CartesianCoordinate3D image_centre = - CartesianCoordinate3D((density_sptr->get_min_index()+density_sptr->get_max_index())/2.F,0,0) - * voxel_size; + CartesianCoordinate3D((density_sptr->get_min_index() + density_sptr->get_max_index()) / 2.F, 0, 0) * voxel_size; density_sptr->fill(0); pm_by_densel.get_proj_matrix_elems_for_one_densel(bins, densel); - unsigned num_contributing_bins=0; + unsigned num_contributing_bins = 0; LORInAxialAndNoArcCorrSinogramCoordinates lorNAC; LORAs2Points lor2pts; - const double ring_radius = - static_cast(proj_data_info_sptr->get_scanner_ptr()->get_effective_ring_radius()); - for (ProjMatrixElemsForOneDensel::const_iterator bin_iter = bins.begin(); - bin_iter != bins.end(); - ++bin_iter) - { - { - proj_data_info_sptr->get_LOR(lorNAC, *bin_iter); - lorNAC.get_intersections_with_cylinder(lor2pts, ring_radius); - const float deviation_org = - distance_between_line_and_point(lor2pts, - CartesianCoordinate3D(densel_coord-image_centre)); - if (max_deviation_org < deviation_org) - max_deviation_org = deviation_org; - } - Bin transformed_bin = *bin_iter; - ro3dtrans.transform_bin(transformed_bin, *proj_data_info_sptr, *proj_data_info_sptr); - if (transformed_bin.get_bin_value()>0) - { - ++num_contributing_bins; - - { - proj_data_info_sptr->get_LOR(lorNAC, transformed_bin); - lorNAC.get_intersections_with_cylinder(lor2pts, ring_radius); - const float deviation_transformed = - distance_between_line_and_point(lor2pts, - CartesianCoordinate3D(transformed_densel_coord-image_centre)); - if (max_deviation_transformed < deviation_transformed) - max_deviation_transformed = deviation_transformed; - } - - transformed_bin.set_bin_value(bin_iter->get_bin_value()); - pm_by_bin.get_proj_matrix_elems_for_one_bin(lor, transformed_bin); - lor.back_project(*density_sptr, transformed_bin); - } - } - check(num_contributing_bins>30, - "num_contributing_bins should be large enough for the back-projection test to make sense"); - std::cerr << "\t\tnum_contributing_bins " << num_contributing_bins - << " out of " << bins.end() - bins.begin() << '\n'; - const CartesianCoordinate3D densel_from_bins = - indices_at_maximum(*density_sptr); - - const double deviation = - norm(BasicCoordinate<3,float>(densel_from_bins) - transformed_densel_float); - if (max_deviation < deviation) - max_deviation = deviation; - //display(*density_sptr,density_sptr->find_max()); - if (!check(deviation(proj_data_info_sptr->get_scanner_ptr()->get_effective_ring_radius()); + for (ProjMatrixElemsForOneDensel::const_iterator bin_iter = bins.begin(); bin_iter != bins.end(); ++bin_iter) { { - std::cerr << "Org: " << densel << " transformed: " << transformed_densel_float << " by bin: " << densel_from_bins << "\n" - << "\t(all are in index-units, not in mm)\n"; - (*density_sptr)[round(transformed_densel_float)] = - density_sptr->find_max()*2; - OutputFileFormat >::default_sptr()-> - write_to_file("STIRImage", *density_sptr); - std::cerr << "Image written as STIRImage.* (with transformed densel at twice max value)\n"; + proj_data_info_sptr->get_LOR(lorNAC, *bin_iter); + lorNAC.get_intersections_with_cylinder(lor2pts, ring_radius); + const float deviation_org = + distance_between_line_and_point(lor2pts, CartesianCoordinate3D(densel_coord - image_centre)); + if (max_deviation_org < deviation_org) + max_deviation_org = deviation_org; } - check(max_deviation_org 0) { + ++num_contributing_bins; + + { + proj_data_info_sptr->get_LOR(lorNAC, transformed_bin); + lorNAC.get_intersections_with_cylinder(lor2pts, ring_radius); + const float deviation_transformed = + distance_between_line_and_point(lor2pts, CartesianCoordinate3D(transformed_densel_coord - image_centre)); + if (max_deviation_transformed < deviation_transformed) + max_deviation_transformed = deviation_transformed; + } + + transformed_bin.set_bin_value(bin_iter->get_bin_value()); + pm_by_bin.get_proj_matrix_elems_for_one_bin(lor, transformed_bin); + lor.back_project(*density_sptr, transformed_bin); } + } + check(num_contributing_bins > 30, "num_contributing_bins should be large enough for the back-projection test to make sense"); + std::cerr << "\t\tnum_contributing_bins " << num_contributing_bins << " out of " << bins.end() - bins.begin() << '\n'; + const CartesianCoordinate3D densel_from_bins = indices_at_maximum(*density_sptr); + const double deviation = norm(BasicCoordinate<3, float>(densel_from_bins) - transformed_densel_float); + if (max_deviation < deviation) + max_deviation = deviation; + // display(*density_sptr,density_sptr->find_max()); + if (!check(deviation < allowed_deviation, "deviation determined via backprojection")) { + std::cerr << "Org: " << densel << " transformed: " << transformed_densel_float << " by bin: " << densel_from_bins << "\n" + << "\t(all are in index-units, not in mm)\n"; + (*density_sptr)[round(transformed_densel_float)] = density_sptr->find_max() * 2; + OutputFileFormat>::default_sptr()->write_to_file("STIRImage", *density_sptr); + std::cerr << "Image written as STIRImage.* (with transformed densel at twice max value)\n"; + } + check(max_deviation_org < allowed_deviation, "deviation of pixel with original LOR is too large"); + { std::cerr << "\t\tdeviation of pixel with original LOR (in mm): " << max_deviation_org << '\n'; } + check(max_deviation_transformed < allowed_deviation, "deviation of pixel with LOR after transformations is too large"); + { std::cerr << "\t\tdeviation of pixel with LOR after transformations (in mm): " << max_deviation_transformed << '\n'; } } std::cerr << "\t\tmax deviation via backprojection (in index units) : " << max_deviation << '\n'; - } void -RigidObject3DTransformationTests:: -test_find_closest_transformation() -{ +RigidObject3DTransformationTests::test_find_closest_transformation() { std::cerr << "\n\tTests for find_closest_transformation\n"; // set fairly low tolerance as we don't find the closest transformation to very high precision const double old_tolerance = this->get_tolerance(); this->set_tolerance(.01); - Quaternion quat(.7F,.2F,-.1F,.15F); + Quaternion quat(.7F, .2F, -.1F, .15F); quat.normalise(); - const CartesianCoordinate3D translation(-11,-12,15); + const CartesianCoordinate3D translation(-11, -12, 15); const RigidObject3DTransformation transformation(quat, translation); - std::vector > points; - points.push_back(CartesianCoordinate3D(1,2,3)); - points.push_back(CartesianCoordinate3D(1,3,-3)); - points.push_back(CartesianCoordinate3D(-1.4F,2,6)); - points.push_back(CartesianCoordinate3D(1,2,33.3F)); + std::vector> points; + points.push_back(CartesianCoordinate3D(1, 2, 3)); + points.push_back(CartesianCoordinate3D(1, 3, -3)); + points.push_back(CartesianCoordinate3D(-1.4F, 2, 6)); + points.push_back(CartesianCoordinate3D(1, 2, 33.3F)); - std::vector > transformed_points; - for (std::vector >::const_iterator iter = points.begin(); - iter != points.end(); - ++iter) + std::vector> transformed_points; + for (std::vector>::const_iterator iter = points.begin(); iter != points.end(); ++iter) transformed_points.push_back(transformation.transform_point(*iter)); check_if_zero(RigidObject3DTransformation::RMSE(transformation, points.begin(), points.end(), transformed_points.begin()), - "RMSE for exact match is too large"); + "RMSE for exact match is too large"); RigidObject3DTransformation result; - if (!check( - RigidObject3DTransformation:: - find_closest_transformation(result, - points.begin(), points.end(), transformed_points.begin(), - Quaternion(1,0,0,0)) == - Succeeded::yes, - "find_closest_transformation for exact match returned Succeeded::no")) + if (!check(RigidObject3DTransformation::find_closest_transformation(result, points.begin(), points.end(), + transformed_points.begin(), + Quaternion(1, 0, 0, 0)) == Succeeded::yes, + "find_closest_transformation for exact match returned Succeeded::no")) return; - if (!check_if_zero(norm(quat-result.get_quaternion()), - "find_closest_transformation for exact match: non-matching quaternion") || - !check_if_zero(norm(translation-result.get_translation()), - "find_closest_transformation for exact match: non-matching translation")) - { - std::cerr << "Transformation found: " << result - << "\nbut should have been " << transformation - << "\nInput was:\nPoints : \n" << points - << "Transformed points : \n" << transformed_points - << '\n'; - } + if (!check_if_zero(norm(quat - result.get_quaternion()), + "find_closest_transformation for exact match: non-matching quaternion") || + !check_if_zero(norm(translation - result.get_translation()), + "find_closest_transformation for exact match: non-matching translation")) { + std::cerr << "Transformation found: " << result << "\nbut should have been " << transformation << "\nInput was:\nPoints : \n" + << points << "Transformed points : \n" + << transformed_points << '\n'; + } check_if_zero(RigidObject3DTransformation::RMSE(result, points.begin(), points.end(), transformed_points.begin()), - "find_closest_transformation for exact match: RMSE is too large"); + "find_closest_transformation for exact match: RMSE is too large"); this->set_tolerance(old_tolerance); } END_NAMESPACE_STIR -int main() -{ +int +main() { stir::RigidObject3DTransformationTests tests; tests.run_tests(); - + return tests.main_return_value(); } diff --git a/src/experimental/test/test_proj_data_info_LOR.cxx b/src/experimental/test/test_proj_data_info_LOR.cxx index a5630c6bb2..8387bdb273 100644 --- a/src/experimental/test/test_proj_data_info_LOR.cxx +++ b/src/experimental/test/test_proj_data_info_LOR.cxx @@ -12,8 +12,8 @@ Tests detector points and LOR functions by checking intersections of LORs \warning Preliminary. Needs spanned but unmashed template projection data. - \warning When trying different scanners/dimensions/voxels, run only in debug mode to catch asserts. - \warning for some voxels, the round-trip in bin coordinates does not work + \warning When trying different scanners/dimensions/voxels, run only in debug mode to catch asserts. + \warning for some voxels, the round-trip in bin coordinates does not work (it ends up in the wrong plane). This is because the current axial-coordinate handling in this test is unsafe. \todo test stir::ProjDataInfo::get_LOR and stir::ProjDataInfo::get_bin @@ -38,81 +38,72 @@ using std::endl; #include "stir/geometry/line_distances.h" int -main(int argc,char *argv[]) -{ - USING_NAMESPACE_STIR +main(int argc, char* argv[]) { + USING_NAMESPACE_STIR - if(argc<=2 || (argc-1)%3!=0) - { - cerr<<"Usage: " << argv[0] << " z0 y0 x0 [ z1 y1 x1 [...]]\n"; + if (argc <= 2 || (argc - 1) % 3 != 0) { + cerr << "Usage: " << argv[0] << " z0 y0 x0 [ z1 y1 x1 [...]]\n"; exit(EXIT_FAILURE); } - --argc; ++argv; // skip program name - - // TODO ProjMatrixByDensel cannot do span=1 yet - // test_transform_bin_vs_transform_point(proj_data_info_sptr); - cerr << "\nTests with proj_data_info without mashing and but with axial compression, no arc-correction\n"; - shared_ptr scanner_sptr(new Scanner(Scanner::E962)); - shared_ptr proj_data_info_sptr = + --argc; + ++argv; // skip program name + + // TODO ProjMatrixByDensel cannot do span=1 yet + // test_transform_bin_vs_transform_point(proj_data_info_sptr); + cerr << "\nTests with proj_data_info without mashing and but with axial compression, no arc-correction\n"; + shared_ptr scanner_sptr(new Scanner(Scanner::E962)); + shared_ptr proj_data_info_sptr = ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span*/3, 1,// can only handle segment 0 right now - /*views*/ scanner_sptr->get_num_detectors_per_ring()/2, - /*tang_pos*/scanner_sptr->get_num_detectors_per_ring()/2, - /*arc_corrected*/ false); - + /*span*/ 3, 1, // can only handle segment 0 right now + /*views*/ scanner_sptr->get_num_detectors_per_ring() / 2, + /*tang_pos*/ scanner_sptr->get_num_detectors_per_ring() / 2, + /*arc_corrected*/ false); + const ProjDataInfoCylindricalNoArcCorr* proj_data_cyl_no_arc_ptr = - dynamic_cast(proj_data_info_sptr.get()); - if (proj_data_cyl_no_arc_ptr==0) - error("Currently only works with non-arccorrected data"); - - shared_ptr proj_matrix_ptr = - new ProjMatrixByDenselUsingRayTracing; - - shared_ptr > image_sptr = - new VoxelsOnCartesianGrid(*proj_data_info_sptr); - proj_matrix_ptr->set_up(proj_data_info_sptr, - image_sptr); - - cerr << proj_matrix_ptr->parameter_info(); - const CartesianCoordinate3D voxel_size = - static_cast&>(*image_sptr).get_voxel_size(); - - ProjMatrixElemsForOneDensel probs; - bool problem=false; - while (argc>0) - { - const int x = atoi(argv[0]); - const int y = atoi(argv[1]); - const int z = atoi(argv[2]); - Densel densel(z,y,x); - CartesianCoordinate3D voxel_coords = - CartesianCoordinate3D(z,y,x) * - voxel_size; - - proj_matrix_ptr->get_proj_matrix_elems_for_one_densel(probs, densel); - - Bin bin0(-1000,-1000,-1000,-1000,1), bin90(-10000,-10000,-10000,-10000,1); // note: initialise to crazy values to make the tests below fail in case the loop below doesn't find them - for (ProjMatrixElemsForOneDensel::const_iterator element_ptr = probs.begin(); - element_ptr != probs.end(); - ++element_ptr) - { - if (element_ptr->view_num()==0) - bin0 = *element_ptr; - if(element_ptr->view_num()==proj_data_info_sptr->get_num_views()/2) - bin90 = *element_ptr; - } - // note: set value to 1 for comparisons later - bin0.set_bin_value(1); - bin90.set_bin_value(1); - - int det1_0; - int det2_0; - int ring1_0; - int ring2_0; - int det1_90; - int det2_90; - int ring1_90; - int ring2_90; + dynamic_cast(proj_data_info_sptr.get()); + if (proj_data_cyl_no_arc_ptr == 0) + error("Currently only works with non-arccorrected data"); + + shared_ptr proj_matrix_ptr = new ProjMatrixByDenselUsingRayTracing; + + shared_ptr> image_sptr = new VoxelsOnCartesianGrid(*proj_data_info_sptr); + proj_matrix_ptr->set_up(proj_data_info_sptr, image_sptr); + + cerr << proj_matrix_ptr->parameter_info(); + const CartesianCoordinate3D voxel_size = static_cast&>(*image_sptr).get_voxel_size(); + + ProjMatrixElemsForOneDensel probs; + bool problem = false; + while (argc > 0) { + const int x = atoi(argv[0]); + const int y = atoi(argv[1]); + const int z = atoi(argv[2]); + Densel densel(z, y, x); + CartesianCoordinate3D voxel_coords = CartesianCoordinate3D(z, y, x) * voxel_size; + + proj_matrix_ptr->get_proj_matrix_elems_for_one_densel(probs, densel); + + Bin bin0(-1000, -1000, -1000, -1000, 1), + bin90(-10000, -10000, -10000, -10000, + 1); // note: initialise to crazy values to make the tests below fail in case the loop below doesn't find them + for (ProjMatrixElemsForOneDensel::const_iterator element_ptr = probs.begin(); element_ptr != probs.end(); ++element_ptr) { + if (element_ptr->view_num() == 0) + bin0 = *element_ptr; + if (element_ptr->view_num() == proj_data_info_sptr->get_num_views() / 2) + bin90 = *element_ptr; + } + // note: set value to 1 for comparisons later + bin0.set_bin_value(1); + bin90.set_bin_value(1); + + int det1_0; + int det2_0; + int ring1_0; + int ring2_0; + int det1_90; + int det2_90; + int ring1_90; + int ring2_90; #if 0 // TODO doesn't work yet because this can't handle span, while densel needs it... proj_data_cyl_no_arc_ptr->get_det_pair_for_bin(det1_0, ring1_0, @@ -122,46 +113,37 @@ main(int argc,char *argv[]) det2_90, ring2_90, bin90); #else - proj_data_cyl_no_arc_ptr->get_det_num_pair_for_view_tangential_pos_num(det1_0,det2_0, - bin0.view_num(), - bin0.tangential_pos_num()); - // warning: dangerous: - // only here because of span and works only for segment 0 - ring1_0 = bin0.axial_pos_num()/2; - ring2_0 = bin0.axial_pos_num()/2; - Bin bin_check_0; - proj_data_cyl_no_arc_ptr->get_bin_for_det_pair(bin_check_0, - det1_0,ring1_0, - det2_0,ring2_0); - bin_check_0.set_bin_value(1); - assert(bin0 == bin_check_0); - proj_data_cyl_no_arc_ptr->get_det_num_pair_for_view_tangential_pos_num(det1_90,det2_90, - bin90.view_num(), - bin90.tangential_pos_num()); - ring1_90 = bin90.axial_pos_num()/2; - ring2_90 = bin90.axial_pos_num()/2; - - Bin bin_check_90; - proj_data_cyl_no_arc_ptr->get_bin_for_det_pair(bin_check_90, - det1_90,ring1_90, - det2_90,ring2_90); - bin_check_90.set_bin_value(1); - assert(bin90 ==bin_check_90); + proj_data_cyl_no_arc_ptr->get_det_num_pair_for_view_tangential_pos_num(det1_0, det2_0, bin0.view_num(), + bin0.tangential_pos_num()); + // warning: dangerous: + // only here because of span and works only for segment 0 + ring1_0 = bin0.axial_pos_num() / 2; + ring2_0 = bin0.axial_pos_num() / 2; + Bin bin_check_0; + proj_data_cyl_no_arc_ptr->get_bin_for_det_pair(bin_check_0, det1_0, ring1_0, det2_0, ring2_0); + bin_check_0.set_bin_value(1); + assert(bin0 == bin_check_0); + proj_data_cyl_no_arc_ptr->get_det_num_pair_for_view_tangential_pos_num(det1_90, det2_90, bin90.view_num(), + bin90.tangential_pos_num()); + ring1_90 = bin90.axial_pos_num() / 2; + ring2_90 = bin90.axial_pos_num() / 2; + + Bin bin_check_90; + proj_data_cyl_no_arc_ptr->get_bin_for_det_pair(bin_check_90, det1_90, ring1_90, det2_90, ring2_90); + bin_check_90.set_bin_value(1); + assert(bin90 == bin_check_90); #endif - CartesianCoordinate3D coord_1_0; - CartesianCoordinate3D coord_2_0; - CartesianCoordinate3D coord_1_90; - CartesianCoordinate3D coord_2_90; - - proj_data_cyl_no_arc_ptr-> - find_cartesian_coordinates_given_scanner_coordinates (coord_1_0,coord_2_0, - ring1_0,ring2_0, - det1_0, det2_0); + CartesianCoordinate3D coord_1_0; + CartesianCoordinate3D coord_2_0; + CartesianCoordinate3D coord_1_90; + CartesianCoordinate3D coord_2_90; + + proj_data_cyl_no_arc_ptr->find_cartesian_coordinates_given_scanner_coordinates(coord_1_0, coord_2_0, ring1_0, ring2_0, det1_0, + det2_0); - proj_data_cyl_no_arc_ptr->find_cartesian_coordinates_given_scanner_coordinates (coord_1_90,coord_2_90, - ring1_90,ring2_90, - det1_90, det2_90); + proj_data_cyl_no_arc_ptr->find_cartesian_coordinates_given_scanner_coordinates(coord_1_90, coord_2_90, ring1_90, ring2_90, + det1_90, det2_90); #if 0 cout << coord_1_0< intersection; - const float distance_between_LORs = - coordinate_between_2_lines(intersection, - LORAs2Points(coord_1_0, coord_2_0), - LORAs2Points(coord_1_90, coord_2_90)); - if (distance_between_LORs > norm(voxel_size)/sqrt(3.) ) - { - problem = true; - warning("Problem:distance between LORs is too large %g", - distance_between_LORs); - } - const float diff = norm(intersection - voxel_coords); - cout << "distance between intersection and voxel (in mm) " << diff << endl; - if (diff > norm(voxel_size)) - cout << endl<< intersection << voxel_coords < intersection; + const float distance_between_LORs = coordinate_between_2_lines(intersection, LORAs2Points(coord_1_0, coord_2_0), + LORAs2Points(coord_1_90, coord_2_90)); + if (distance_between_LORs > norm(voxel_size) / sqrt(3.)) { + problem = true; + warning("Problem:distance between LORs is too large %g", distance_between_LORs); + } + const float diff = norm(intersection - voxel_coords); + cout << "distance between intersection and voxel (in mm) " << diff << endl; + if (diff > norm(voxel_size)) + cout << endl << intersection << voxel_coords << endl; + + argc -= 3; + argv += 3; + } + return problem ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/experimental/utilities/AVWROI.cxx b/src/experimental/utilities/AVWROI.cxx index 1bb7e06a77..30b1d082ec 100644 --- a/src/experimental/utilities/AVWROI.cxx +++ b/src/experimental/utilities/AVWROI.cxx @@ -1,4 +1,4 @@ -x// +x // // /* Copyright (C) 2001- 2008, Hammersmith Imanet Ltd @@ -20,7 +20,7 @@ x// \file \ingroup utilities \brief convert AVW ROI files to images. Images are read using the AVW library. -\author Kris Thielemans +\author Kris Thielemans */ #include "stir/IO/stir_AVW.h" @@ -35,10 +35,10 @@ x// #include "stir/shared_ptr.h" #include -USING_NAMESPACE_STIR + USING_NAMESPACE_STIR -void print_usage_and_exit( const char * const program_name) -{ + void + print_usage_and_exit(const char* const program_name) { { std::cerr << "Usage : " << program_name << " [ --flip_z ] Analyzeobjectfile.obj\n"; @@ -47,9 +47,8 @@ void print_usage_and_exit( const char * const program_name) } int -main(int argc, char **argv) -{ - const char * const program_name = argv[0]; +main(int argc, char** argv) { + const char* const program_name = argv[0]; // skip program name --argc; ++argv; @@ -57,88 +56,77 @@ main(int argc, char **argv) bool flip_z = false; // first process command line options - while (argc>0 && argv[0][0]=='-') - { - if (strcmp(argv[0], "--flip_z")==0) - { - flip_z = true; - argc-=1; argv+=1; - } - else - { - std::cerr << "Unknown option '" << argv[0] <<"'\n"; - print_usage_and_exit(program_name); + while (argc > 0 && argv[0][0] == '-') { + if (strcmp(argv[0], "--flip_z") == 0) { + flip_z = true; + argc -= 1; + argv += 1; + } else { + std::cerr << "Unknown option '" << argv[0] << "'\n"; + print_usage_and_exit(program_name); } } if (argc != 1) - print_usage_and_exit(program_name); + print_usage_and_exit(program_name); - char *objectfile = argv[0]; - stir::shared_ptr > > - output_file_format_sptr = - stir::OutputFileFormat >::default_sptr(); + char* objectfile = argv[0]; + stir::shared_ptr>> output_file_format_sptr = + stir::OutputFileFormat>::default_sptr(); { // open non-existent file first // this is necessary to get AVW_LoadObjectMap to work - AVW_ImageFile *avw_file= AVW_OpenImageFile("xxx non-existent I hope","r"); + AVW_ImageFile* avw_file = AVW_OpenImageFile("xxx non-existent I hope", "r"); + } + + AVW_ObjectMap* object_map = AVW_LoadObjectMap(objectfile); + if (!object_map) { + AVW_Error("AVW_LoadObjectMap"); + exit(EXIT_FAILURE); } - - AVW_ObjectMap *object_map = AVW_LoadObjectMap(objectfile); - if(!object_map) { AVW_Error("AVW_LoadObjectMap"); exit(EXIT_FAILURE); } - std::cerr << "Number of objects: " << object_map->NumberOfObjects << '\n'; + std::cerr << "Number of objects: " << object_map->NumberOfObjects << '\n'; { - AVW_Volume *volume = NULL; - for (int object_num=0; object_numNumberOfObjects; ++object_num) - { - const char * const object_name = object_map->Object[object_num]->Name; - std::cerr << "Object " << object_num << ": " << object_name << '\n'; - - if (ask("Write this one?",true)) - { + AVW_Volume* volume = NULL; + for (int object_num = 0; object_num < object_map->NumberOfObjects; ++object_num) { + const char* const object_name = object_map->Object[object_num]->Name; + std::cerr << "Object " << object_num << ": " << object_name << '\n'; + + if (ask("Write this one?", true)) { volume = AVW_GetObject(object_map, object_num, volume); - if(!volume) - { - AVW_Error("AVW_GetObject"); - stir::warning("Error in object. Skipping...");//, AVW_ErrorMessage); - continue; - } - - shared_ptr > stir_volume_sptr = - stir::AVW::AVW_Volume_to_VoxelsOnCartesianGrid(volume, flip_z); - if (stir::is_null_ptr(stir_volume_sptr)) - { - stir::warning("Error converting object to STIR format. Skipping...", object_num); - continue; - } - char *header_filename = new char[strlen(objectfile) + strlen(object_name) + 10]; - { - strcpy(header_filename, objectfile); - // append object_name, but after getting rid of the extension in objectfile - replace_extension(header_filename, "_"); - strcat(header_filename, object_name); - } - //warning("Setting voxel size to 962 defaults\n"); - //stir_volume_sptr->set_voxel_size(Coordinate3D(2.425F,2.25F,2.25F)); - if (output_file_format_sptr->write_to_file(header_filename, *stir_volume_sptr) - == stir::Succeeded::no) - { - stir::warning("Error writing %s", header_filename); - } - else - { - std::cout << "Wrote " << header_filename << '\n'; - } - - delete[] header_filename; + if (!volume) { + AVW_Error("AVW_GetObject"); + stir::warning("Error in object. Skipping..."); //, AVW_ErrorMessage); + continue; + } + + shared_ptr> stir_volume_sptr = + stir::AVW::AVW_Volume_to_VoxelsOnCartesianGrid(volume, flip_z); + if (stir::is_null_ptr(stir_volume_sptr)) { + stir::warning("Error converting object to STIR format. Skipping...", object_num); + continue; + } + char* header_filename = new char[strlen(objectfile) + strlen(object_name) + 10]; + { + strcpy(header_filename, objectfile); + // append object_name, but after getting rid of the extension in objectfile + replace_extension(header_filename, "_"); + strcat(header_filename, object_name); + } + // warning("Setting voxel size to 962 defaults\n"); + // stir_volume_sptr->set_voxel_size(Coordinate3D(2.425F,2.25F,2.25F)); + if (output_file_format_sptr->write_to_file(header_filename, *stir_volume_sptr) == stir::Succeeded::no) { + stir::warning("Error writing %s", header_filename); + } else { + std::cout << "Wrote " << header_filename << '\n'; + } + + delete[] header_filename; } } AVW_DestroyVolume(volume); } AVW_DestroyObjectMap(object_map); - return(EXIT_SUCCESS); + return (EXIT_SUCCESS); } - - diff --git a/src/experimental/utilities/Bland_Altman_plot.cxx b/src/experimental/utilities/Bland_Altman_plot.cxx index 7de376f132..8d41f153b3 100644 --- a/src/experimental/utilities/Bland_Altman_plot.cxx +++ b/src/experimental/utilities/Bland_Altman_plot.cxx @@ -16,23 +16,23 @@ See STIR/LICENSE.txt for details */ -/*! +/*! \file \ingroup utilities \brief Writes the Bland-Altman values for two images in a text file. \author Charalampos Tsoumpas \par Usage: - \code + \code Bland_Altman_plot output_filename_prefix image_1 image_2 xmin xmax ymin ymax zmin zmax \endcode - - \param image1/image2 must have the same sizes. + + \param image1/image2 must have the same sizes. \param x/y/zmin/max denote a rectangular region for which the Bland Altman Plot will be estimated. - - It writes two lists: Average-Bias of the two images to a text file \a (.txt) and the rest statistical values to another text file \a (.stat) - \note The Bias is estimated using the \a image1-image2 formula. + + It writes two lists: Average-Bias of the two images to a text file \a (.txt) and the rest statistical values to another text + file \a (.stat) \note The Bias is estimated using the \a image1-image2 formula. \todo Add to the Doxygen documentation a reference to their paper and how exactly this utility works. */ @@ -47,131 +47,117 @@ #include #include -//ChT::ToDo:Include stddev values!!! +// ChT::ToDo:Include stddev values!!! USING_NAMESPACE_STIR -using namespace std; -int main(int argc, char *argv[]) -{ - if (argc!=10) - { - std::cerr << "Returns results in a text file for Bland-Altman evaluation and a stat file.\n Usage:" << argv[0] - << " output_file_name_prefix image_1 image_2 xmin xmax ymin ymax zmin zmax\n "; - return EXIT_FAILURE; - } +using namespace std; +int +main(int argc, char* argv[]) { + if (argc != 10) { + std::cerr << "Returns results in a text file for Bland-Altman evaluation and a stat file.\n Usage:" << argv[0] + << " output_file_name_prefix image_1 image_2 xmin xmax ymin ymax zmin zmax\n "; + return EXIT_FAILURE; + } string output_txt_string(argv[1]); - const std::string name=output_txt_string+".txt"; - const std::string statname=output_txt_string+".stat"; + const std::string name = output_txt_string + ".txt"; + const std::string statname = output_txt_string + ".stat"; - ofstream output_stream(name.c_str(), ios::out); //output file // - if(!output_stream) - { - std::cerr << "Cannot open " << name << endl ; - return EXIT_FAILURE; - } - shared_ptr< DiscretisedDensity<3,float> > image_1_sptr = - DiscretisedDensity<3,float>::read_from_file(argv[2]); - DiscretisedDensity<3,float>& image_1 = *image_1_sptr; + ofstream output_stream(name.c_str(), ios::out); // output file // + if (!output_stream) { + std::cerr << "Cannot open " << name << endl; + return EXIT_FAILURE; + } + shared_ptr> image_1_sptr = DiscretisedDensity<3, float>::read_from_file(argv[2]); + DiscretisedDensity<3, float>& image_1 = *image_1_sptr; - shared_ptr< DiscretisedDensity<3,float> > image_2_sptr = - DiscretisedDensity<3,float>::read_from_file(argv[3]); - DiscretisedDensity<3,float>& image_2 = *image_2_sptr; + shared_ptr> image_2_sptr = DiscretisedDensity<3, float>::read_from_file(argv[3]); + DiscretisedDensity<3, float>& image_2 = *image_2_sptr; - const VoxelsOnCartesianGrid* image_1_cartesian_ptr = - dynamic_cast< VoxelsOnCartesianGrid* > (image_1_sptr.get()); + const VoxelsOnCartesianGrid* image_1_cartesian_ptr = dynamic_cast*>(image_1_sptr.get()); - const VoxelsOnCartesianGrid* image_2_cartesian_ptr = - dynamic_cast< VoxelsOnCartesianGrid* > (image_2_sptr.get()); + const VoxelsOnCartesianGrid* image_2_cartesian_ptr = dynamic_cast*>(image_2_sptr.get()); CartesianCoordinate3D grid_spacing; - if (image_1_cartesian_ptr==0 && image_2_cartesian_ptr==0) - { - warning("Something strange is going on: at least one input image is not DiscretisedDensityOnCartesianGrid objects.\n"); - return EXIT_FAILURE; - } - else if(image_1_cartesian_ptr->get_grid_spacing()!=image_2_cartesian_ptr->get_grid_spacing() && //or is it better to put an assert? - (image_1_cartesian_ptr->get_max_x()-image_1_cartesian_ptr->get_min_x())!= - (image_2_cartesian_ptr->get_max_x()-image_2_cartesian_ptr->get_min_x()) && - (image_1_cartesian_ptr->get_max_y()-image_1_cartesian_ptr->get_min_y())!= - (image_2_cartesian_ptr->get_max_y()-image_2_cartesian_ptr->get_min_y()) && - (image_1_cartesian_ptr->get_max_z()-image_1_cartesian_ptr->get_min_z())!= - (image_1_cartesian_ptr->get_max_z()-image_2_cartesian_ptr->get_min_z()) && - image_1_cartesian_ptr->get_x_size()!=image_2_cartesian_ptr->get_x_size() && - image_1_cartesian_ptr->get_y_size()!=image_2_cartesian_ptr->get_y_size() && - image_1_cartesian_ptr->get_z_size()!=image_2_cartesian_ptr->get_z_size()) - { - warning("Input images have different grid or/and voxel sizes.\n"); + if (image_1_cartesian_ptr == 0 && image_2_cartesian_ptr == 0) { + warning("Something strange is going on: at least one input image is not DiscretisedDensityOnCartesianGrid objects.\n"); + return EXIT_FAILURE; + } else if (image_1_cartesian_ptr->get_grid_spacing() != + image_2_cartesian_ptr->get_grid_spacing() && // or is it better to put an assert? + (image_1_cartesian_ptr->get_max_x() - image_1_cartesian_ptr->get_min_x()) != + (image_2_cartesian_ptr->get_max_x() - image_2_cartesian_ptr->get_min_x()) && + (image_1_cartesian_ptr->get_max_y() - image_1_cartesian_ptr->get_min_y()) != + (image_2_cartesian_ptr->get_max_y() - image_2_cartesian_ptr->get_min_y()) && + (image_1_cartesian_ptr->get_max_z() - image_1_cartesian_ptr->get_min_z()) != + (image_1_cartesian_ptr->get_max_z() - image_2_cartesian_ptr->get_min_z()) && + image_1_cartesian_ptr->get_x_size() != image_2_cartesian_ptr->get_x_size() && + image_1_cartesian_ptr->get_y_size() != image_2_cartesian_ptr->get_y_size() && + image_1_cartesian_ptr->get_z_size() != image_2_cartesian_ptr->get_z_size()) { + warning("Input images have different grid or/and voxel sizes.\n"); + return EXIT_FAILURE; + } else { + const int min_i_index = atoi(argv[4]); + const int max_i_index = atoi(argv[5]); + const int min_j_index = atoi(argv[6]); + const int max_j_index = atoi(argv[7]); + const int min_k_index = atoi(argv[8]); + const int max_k_index = atoi(argv[9]); + const int num_voxels = (max_k_index - min_k_index + 1) * (max_j_index - min_j_index + 1) * (max_i_index - min_i_index + 1); + + VectorWithOffset bias(0, num_voxels - 1); + VectorWithOffset average(0, num_voxels - 1); + VectorWithOffset residual(0, num_voxels - 1); + VectorWithOffset weights(0, num_voxels - 1); + VectorWithOffset fit_values(0, 6); + VectorWithOffset residual_fit_values(0, 6); + std::cerr << "Writing into text file the Bland-Altman values...\n"; + output_stream << " Average " + << "\t" + << "Bias\n"; + + int voxel_num = 0; + for (int k = min_k_index; k <= max_k_index; ++k) + for (int j = min_j_index; j <= max_j_index; ++j) + for (int i = min_i_index; i <= max_i_index; ++i) { + average[voxel_num] = (image_1[k][j][i] + image_2[k][j][i]) / 2.; + bias[voxel_num] = image_1[k][j][i] - image_2[k][j][i]; + weights[voxel_num] = 1; + output_stream << std::setw(8) << (image_1[k][j][i] + image_2[k][j][i]) / 2. << "\t" << std::setw(8) + << image_1[k][j][i] - image_2[k][j][i] << "\n"; + ++voxel_num; + } + output_stream.close(); + assert(voxel_num == num_voxels); + + linear_regression(fit_values.begin(), bias.begin(), bias.end(), average.begin(), weights.begin()); + + for (int voxel_num = 0; voxel_num < num_voxels; ++voxel_num) + residual[voxel_num] = fabs(fit_values[0] + fit_values[1] * average[voxel_num] - bias[voxel_num]); + + linear_regression(residual_fit_values.begin(), residual.begin(), residual.end(), average.begin(), weights.begin()); + + ofstream stat_stream(statname.c_str(), ios::out); // output file // + if (!stat_stream) { + std::cerr << "Cannot open " << statname << endl; return EXIT_FAILURE; } - else - { - const int min_i_index= atoi(argv[4]); - const int max_i_index= atoi(argv[5]); - const int min_j_index= atoi(argv[6]); - const int max_j_index= atoi(argv[7]); - const int min_k_index= atoi(argv[8]); - const int max_k_index= atoi(argv[9]); - const int num_voxels = (max_k_index-min_k_index+1) * (max_j_index - min_j_index+1) * (max_i_index-min_i_index+1); - - VectorWithOffset bias(0,num_voxels-1); - VectorWithOffset average(0,num_voxels-1); - VectorWithOffset residual(0,num_voxels-1); - VectorWithOffset weights(0,num_voxels-1); - VectorWithOffset fit_values(0,6); - VectorWithOffset residual_fit_values(0,6); - std::cerr << "Writing into text file the Bland-Altman values...\n"; - output_stream << " Average " << "\t" << "Bias\n" ; - - int voxel_num=0; - for ( int k = min_k_index; k<= max_k_index; ++k) - for ( int j = min_j_index; j<= max_j_index; ++j) - for ( int i = min_i_index; i<= max_i_index; ++i) - { - average[voxel_num]=(image_1[k][j][i]+image_2[k][j][i])/2.; - bias[voxel_num]=image_1[k][j][i]-image_2[k][j][i]; - weights[voxel_num]=1; - output_stream << std::setw(8) << (image_1[k][j][i]+image_2[k][j][i])/2. << "\t" - << std::setw(8) << image_1[k][j][i]-image_2[k][j][i] << "\n"; - ++voxel_num; - } - output_stream.close(); - assert(voxel_num==num_voxels); - - linear_regression(fit_values.begin(), - bias.begin(), bias.end(), - average.begin(), weights.begin()); - - for ( int voxel_num = 0 ; voxel_num > - density_ptr = DiscretisedDensity<3,float>::read_from_file(argv[2]); - VoxelsOnCartesianGrid * const image_ptr = - dynamic_cast * const>(density_ptr.get()); - if (image_ptr == 0) - { - warning("Can only handle images of type VoxelsOnCartesianGrid\n"); - exit(EXIT_FAILURE); - } + const shared_ptr> density_ptr = DiscretisedDensity<3, float>::read_from_file(argv[2]); + VoxelsOnCartesianGrid* const image_ptr = dynamic_cast* const>(density_ptr.get()); + if (image_ptr == 0) { + warning("Can only handle images of type VoxelsOnCartesianGrid\n"); + exit(EXIT_FAILURE); + } - VectorWithOffset< CartesianCoordinate3D > allCoG; + VectorWithOffset> allCoG; VectorWithOffset weights; - find_centre_of_gravity_in_mm_per_plane(allCoG, - weights, - *image_ptr); + find_centre_of_gravity_in_mm_per_plane(allCoG, weights, *image_ptr); { const string filename = output_filename_prefix + ".x"; ofstream xout(filename.c_str()); xout << image_ptr->get_length() << "\n"; - for (int z=image_ptr->get_min_index(); z<=image_ptr->get_max_index(); z++) - xout << allCoG[z].z()<< "\n"; - for (int z=image_ptr->get_min_index(); z<=image_ptr->get_max_index(); z++) + for (int z = image_ptr->get_min_index(); z <= image_ptr->get_max_index(); z++) + xout << allCoG[z].z() << "\n"; + for (int z = image_ptr->get_min_index(); z <= image_ptr->get_max_index(); z++) xout << allCoG[z].x() << "\n"; - for (int z=image_ptr->get_min_index(); z<=image_ptr->get_max_index(); z++) - xout << weights[z] << "\n"; + for (int z = image_ptr->get_min_index(); z <= image_ptr->get_max_index(); z++) + xout << weights[z] << "\n"; } { @@ -108,20 +100,15 @@ main(int argc, char *argv[]) ofstream yout(filename.c_str()); yout << image_ptr->get_length() << "\n"; - for (int z=image_ptr->get_min_index(); z<=image_ptr->get_max_index(); z++) + for (int z = image_ptr->get_min_index(); z <= image_ptr->get_max_index(); z++) yout << allCoG[z].z() << "\n"; - for (int z=image_ptr->get_min_index(); z<=image_ptr->get_max_index(); z++) + for (int z = image_ptr->get_min_index(); z <= image_ptr->get_max_index(); z++) yout << allCoG[z].y() << "\n"; - for (int z=image_ptr->get_min_index(); z<=image_ptr->get_max_index(); z++) + for (int z = image_ptr->get_min_index(); z <= image_ptr->get_max_index(); z++) yout << weights[z] << "\n"; } - - cout << "output written in \"" - < @@ -25,114 +24,94 @@ USING_NAMESPACE_STIR USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 -static void update_main_header(Main_header& mh, const bool is_3d_scan) - { - strcpy(mh.study_description, "listmode"); - mh.acquisition_type = DynamicEmission; - mh.septa_state = - is_3d_scan ? SeptaRetracted : SeptaExtended; - // we set this to a sinogram-type such that header_doc can display the data - mh.file_type = Short3dSinogram; - } - - -void print_usage_and_exit(const char * const program_name) - { - std::cerr<< "\nPrepend contents of ECAT7 header to a sgl file.\n" - << "Usage: \n" - << "\t" << program_name << " [--2d|--3d] output_sgl_name input_sgl_name input_ECAT7_name \n" - << "Defaults to 3D (is used to set septa_state)\n"; - exit(EXIT_FAILURE); - } +static void +update_main_header(Main_header& mh, const bool is_3d_scan) { + strcpy(mh.study_description, "listmode"); + mh.acquisition_type = DynamicEmission; + mh.septa_state = is_3d_scan ? SeptaRetracted : SeptaExtended; + // we set this to a sinogram-type such that header_doc can display the data + mh.file_type = Short3dSinogram; +} +void +print_usage_and_exit(const char* const program_name) { + std::cerr << "\nPrepend contents of ECAT7 header to a sgl file.\n" + << "Usage: \n" + << "\t" << program_name << " [--2d|--3d] output_sgl_name input_sgl_name input_ECAT7_name \n" + << "Defaults to 3D (is used to set septa_state)\n"; + exit(EXIT_FAILURE); +} -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { bool is_3d_scan = true; - const char * const program_name = argv[0]; - - if (argc >= 3 && argv[1][0] == '-') - { - if (strcmp(argv[1], "--2d") == 0) - { - is_3d_scan = false; - --argc; ++argv; - } - else if (strcmp(argv[1], "--3d") == 0) - { - is_3d_scan = true; - --argc; ++argv; - } - else - print_usage_and_exit(program_name); - } - if(argc!=4) + const char* const program_name = argv[0]; + + if (argc >= 3 && argv[1][0] == '-') { + if (strcmp(argv[1], "--2d") == 0) { + is_3d_scan = false; + --argc; + ++argv; + } else if (strcmp(argv[1], "--3d") == 0) { + is_3d_scan = true; + --argc; + ++argv; + } else + print_usage_and_exit(program_name); + } + if (argc != 4) print_usage_and_exit(program_name); const std::string output_name = argv[1]; const std::string input_name_sgl = argv[2]; const std::string input_name_ecat7 = argv[3]; - + + { + FILE* sgl_fptr = fopen(input_name_sgl.c_str(), "rb"); + if (!sgl_fptr) { + error("Error opening '%s' for reading: %s", input_name_sgl.c_str(), strerror(errno)); + } + FILE* out_fptr = fopen(output_name.c_str(), "wb"); + if (!out_fptr) { + error("Error opening '%s' for writing: %s", output_name.c_str(), strerror(errno)); + } + // get ECAT7 header + Main_header mh_in; { - FILE * sgl_fptr = fopen(input_name_sgl.c_str(), "rb"); - if (!sgl_fptr) - { - error("Error opening '%s' for reading: %s", - input_name_sgl.c_str(), strerror(errno)); - } - FILE * out_fptr = fopen(output_name.c_str(), "wb"); - if (!out_fptr) - { - error("Error opening '%s' for writing: %s", - output_name.c_str(), strerror(errno)); - } - // get ECAT7 header - Main_header mh_in; - { - FILE * ecat7_fptr = fopen(input_name_ecat7.c_str(), "rb"); - if (!ecat7_fptr) - { - error("Error opening '%s' for reading: %s", - input_name_ecat7.c_str(), strerror(errno)); - } - if (mat_read_main_header(ecat7_fptr, &mh_in)!=0) - error("Error reading main header from %s", input_name_ecat7.c_str()); - fclose(ecat7_fptr); + FILE* ecat7_fptr = fopen(input_name_ecat7.c_str(), "rb"); + if (!ecat7_fptr) { + error("Error opening '%s' for reading: %s", input_name_ecat7.c_str(), strerror(errno)); } + if (mat_read_main_header(ecat7_fptr, &mh_in) != 0) + error("Error reading main header from %s", input_name_ecat7.c_str()); + fclose(ecat7_fptr); + } - update_main_header(mh_in, is_3d_scan); - if (mat_write_main_header(out_fptr, &mh_in)) - error("Error writing main header to %s", output_name.c_str()); - // copy rest of sgl file into output - - char buffer[512]; - int success = EXIT_SUCCESS; - while (!feof(sgl_fptr)) - { - size_t num_read = - fread(buffer, 1, 512, sgl_fptr); - if (ferror(sgl_fptr)) - { - warning("Error reading '%s' : %s", - input_name_sgl.c_str(), strerror(errno)); - success = EXIT_FAILURE; - break; - } - size_t num_written = - fwrite(buffer, 1, num_read, out_fptr); - if (ferror(sgl_fptr) || num_read!=num_written) - { - warning("Error writing '%s' : %s", - output_name.c_str(), strerror(errno)); - success = EXIT_FAILURE; - break; - } + update_main_header(mh_in, is_3d_scan); + if (mat_write_main_header(out_fptr, &mh_in)) + error("Error writing main header to %s", output_name.c_str()); + // copy rest of sgl file into output + + char buffer[512]; + int success = EXIT_SUCCESS; + while (!feof(sgl_fptr)) { + size_t num_read = fread(buffer, 1, 512, sgl_fptr); + if (ferror(sgl_fptr)) { + warning("Error reading '%s' : %s", input_name_sgl.c_str(), strerror(errno)); + success = EXIT_FAILURE; + break; + } + size_t num_written = fwrite(buffer, 1, num_read, out_fptr); + if (ferror(sgl_fptr) || num_read != num_written) { + warning("Error writing '%s' : %s", output_name.c_str(), strerror(errno)); + success = EXIT_FAILURE; + break; } - - fclose(out_fptr); - fclose(sgl_fptr); - return success; } + fclose(out_fptr); + fclose(sgl_fptr); + return success; + } } diff --git a/src/experimental/utilities/add_side_shields.cxx b/src/experimental/utilities/add_side_shields.cxx index c77860e123..23ecc050a0 100644 --- a/src/experimental/utilities/add_side_shields.cxx +++ b/src/experimental/utilities/add_side_shields.cxx @@ -34,117 +34,85 @@ #include "stir/VoxelsOnCartesianGrid.h" #include - - - -int main(int argc, char * argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR; using namespace std; - if ( argc!=3) { + if (argc != 3) { cerr << "Usage: " << argv[0] << " output_filename input_filename\n"; exit(EXIT_FAILURE); } - const char * const output_filename = argv[1]; - const char * const input_filename = argv[2]; - shared_ptr > density_ptr = - DiscretisedDensity<3,float>::read_from_file(input_filename); - VoxelsOnCartesianGrid current_image = - dynamic_cast& >(*density_ptr); + const char* const output_filename = argv[1]; + const char* const input_filename = argv[2]; + shared_ptr> density_ptr = DiscretisedDensity<3, float>::read_from_file(input_filename); + VoxelsOnCartesianGrid current_image = dynamic_cast&>(*density_ptr); const float distance_of_shield_inner_to_centre = 78.35F; const float distance_of_shield_outer_to_centre = 150.F; - const float shield_thickness = - distance_of_shield_outer_to_centre - distance_of_shield_inner_to_centre; + const float shield_thickness = distance_of_shield_outer_to_centre - distance_of_shield_inner_to_centre; const float shield_outer_radius = 433.F; const float shield_inner_radius = 379.F; const float mu_value_for_shield = 1.76568F; // in cm^-1 - const CartesianCoordinate3D - front_shield_centre(-(distance_of_shield_inner_to_centre+shield_thickness/2), - 0, - 0); - const CartesianCoordinate3D - back_shield_centre(+(distance_of_shield_inner_to_centre+shield_thickness/2), - 0, - 0); - - shared_ptr - front_shield_outer_sptr = - new EllipsoidalCylinder(shield_thickness, shield_outer_radius, shield_outer_radius, - front_shield_centre); - shared_ptr - front_shield_inner_sptr = - new EllipsoidalCylinder(shield_thickness, shield_inner_radius, shield_inner_radius, - front_shield_centre); + const CartesianCoordinate3D front_shield_centre(-(distance_of_shield_inner_to_centre + shield_thickness / 2), 0, 0); + const CartesianCoordinate3D back_shield_centre(+(distance_of_shield_inner_to_centre + shield_thickness / 2), 0, 0); + + shared_ptr front_shield_outer_sptr = + new EllipsoidalCylinder(shield_thickness, shield_outer_radius, shield_outer_radius, front_shield_centre); + shared_ptr front_shield_inner_sptr = + new EllipsoidalCylinder(shield_thickness, shield_inner_radius, shield_inner_radius, front_shield_centre); // CombinedShape3D > front_shield(front_shield_outer_sptr, // front_shield_inner_sptr); - shared_ptr - back_shield_outer_sptr = - new EllipsoidalCylinder(shield_thickness, 433, 433, - back_shield_centre); - shared_ptr - back_shield_inner_sptr = - new EllipsoidalCylinder(shield_thickness, 379, 379, - back_shield_centre); - //CombinedShape3D > back_shield(back_shield_outer_sptr, + shared_ptr back_shield_outer_sptr = new EllipsoidalCylinder(shield_thickness, 433, 433, back_shield_centre); + shared_ptr back_shield_inner_sptr = new EllipsoidalCylinder(shield_thickness, 379, 379, back_shield_centre); + // CombinedShape3D > back_shield(back_shield_outer_sptr, // back_shield_inner_sptr); - - - BasicCoordinate<3,int> min_indices, max_indices; + BasicCoordinate<3, int> min_indices, max_indices; current_image.get_regular_range(min_indices, max_indices); const CartesianCoordinate3D voxel_size = current_image.get_voxel_size(); const CartesianCoordinate3D origin = current_image.get_origin(); - const float shift_z_to_centre = - (min_indices[1]+max_indices[1])/2.F*voxel_size[1]; + const float shift_z_to_centre = (min_indices[1] + max_indices[1]) / 2.F * voxel_size[1]; const int old_num_planes = current_image.size(); - if (old_num_planes%2==0) + if (old_num_planes % 2 == 0) error("Cannot handle odd number of planes in input image yet"); - int new_num_planes = - std::max(current_image.get_z_size(), - static_cast(ceil(2* distance_of_shield_outer_to_centre / voxel_size.z()))); - if (new_num_planes%2==0) + int new_num_planes = + std::max(current_image.get_z_size(), static_cast(ceil(2 * distance_of_shield_outer_to_centre / voxel_size.z()))); + if (new_num_planes % 2 == 0) ++new_num_planes; - const int old_index_to_new = - old_num_planes/2 - new_num_planes/2; + const int old_index_to_new = old_num_planes / 2 - new_num_planes / 2; - int new_max_xy = - std::max(current_image[0].size()/2+1, - std::max(current_image[0][0].size()/2+1, - std::max(static_cast(ceil(shield_outer_radius / voxel_size.x())), - static_cast(ceil(shield_outer_radius / voxel_size.y()))))); - //const BasicCoordinate<3,int> new_min_indices = + int new_max_xy = std::max( + current_image[0].size() / 2 + 1, + std::max(current_image[0][0].size() / 2 + 1, std::max(static_cast(ceil(shield_outer_radius / voxel_size.x())), + static_cast(ceil(shield_outer_radius / voxel_size.y()))))); + // const BasicCoordinate<3,int> new_min_indices = // make_coord(old_index_to_new, -new_max_xy, -new_max_xy); - //const BasicCoordinate<3,int> new_max_indices = + // const BasicCoordinate<3,int> new_max_indices = // make_coord(new_num_planes + old_index_to_new - 1, new_max_xy, new_max_xy); - const Coordinate3D new_min_indices (old_index_to_new, -new_max_xy, -new_max_xy); - const Coordinate3D new_max_indices (new_num_planes + old_index_to_new - 1, new_max_xy, new_max_xy); + const Coordinate3D new_min_indices(old_index_to_new, -new_max_xy, -new_max_xy); + const Coordinate3D new_max_indices(new_num_planes + old_index_to_new - 1, new_max_xy, new_max_xy); CartesianCoordinate3D new_origin = origin; new_origin.z() -= shift_z_to_centre; - VoxelsOnCartesianGrid output_image(IndexRange<3>(new_min_indices, new_max_indices), - new_origin, - voxel_size); + VoxelsOnCartesianGrid output_image(IndexRange<3>(new_min_indices, new_max_indices), new_origin, voxel_size); + + VoxelsOnCartesianGrid temp_image(IndexRange<3>(new_min_indices, new_max_indices), new_origin, voxel_size); - VoxelsOnCartesianGrid temp_image(IndexRange<3>(new_min_indices, new_max_indices), - new_origin, - voxel_size); - output_image.fill(0); - //const BasicCoordinate<3,int> num_samples = make_coord(5,5,5); - const Coordinate3D num_samples(5,5,5); - //const Coordinate3D num_samples(1,1,1); - - //front_shield.construct_volume(output_image, num_samples); - //back_shield.construct_volume(temp_image, num_samples); - //output_image += temp_image; + // const BasicCoordinate<3,int> num_samples = make_coord(5,5,5); + const Coordinate3D num_samples(5, 5, 5); + // const Coordinate3D num_samples(1,1,1); + + // front_shield.construct_volume(output_image, num_samples); + // back_shield.construct_volume(temp_image, num_samples); + // output_image += temp_image; front_shield_outer_sptr->construct_volume(output_image, num_samples); temp_image.fill(0); @@ -160,15 +128,13 @@ int main(int argc, char * argv[]) output_image *= mu_value_for_shield; // now fill in old data - for (int z=current_image.get_min_index(); z<= current_image.get_max_index(); ++z) - for (int y=current_image[z].get_min_index(); y<= current_image[z].get_max_index(); ++y) - for (int x=current_image[z][y].get_min_index(); x<= current_image[z][y].get_max_index(); ++x) - output_image[z][y][x] += current_image[z][y][x]; + for (int z = current_image.get_min_index(); z <= current_image.get_max_index(); ++z) + for (int y = current_image[z].get_min_index(); y <= current_image[z].get_max_index(); ++y) + for (int x = current_image[z][y].get_min_index(); x <= current_image[z][y].get_max_index(); ++x) + output_image[z][y][x] += current_image[z][y][x]; + Succeeded success = + OutputFileFormat>::default_sptr()->write_to_file(output_filename, output_image); - Succeeded success = - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, output_image); - - return success==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/utilities/add_time_frame_info.cxx b/src/experimental/utilities/add_time_frame_info.cxx index e8ceac953e..2e81470a1a 100644 --- a/src/experimental/utilities/add_time_frame_info.cxx +++ b/src/experimental/utilities/add_time_frame_info.cxx @@ -44,31 +44,29 @@ using std::istream; using std::setw; #endif -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR - - if (argc!=3) - { - std::cerr << "Usage:" << argv[0] << "\n" - << "\t[dynamic_image_filename]\n" - << "\t[time_frames_filename]\n\n"; - return EXIT_FAILURE; - } - //Read Dynamic Sequence of ECAT7 Images, in respect to their center in x, y axes as origin - const shared_ptr< DynamicDiscretisedDensity > dyn_image_sptr= - DynamicDiscretisedDensity::read_from_file(argv[1]); + if (argc != 3) { + std::cerr << "Usage:" << argv[0] << "\n" + << "\t[dynamic_image_filename]\n" + << "\t[time_frames_filename]\n\n"; + return EXIT_FAILURE; + } + + // Read Dynamic Sequence of ECAT7 Images, in respect to their center in x, y axes as origin + const shared_ptr dyn_image_sptr = DynamicDiscretisedDensity::read_from_file(argv[1]); DynamicDiscretisedDensity dyn_image = *dyn_image_sptr; const TimeFrameDefinitions frame_defs(argv[2]); - assert(frame_defs.get_num_frames()==dyn_image.get_num_time_frames()); + assert(frame_defs.get_num_frames() == dyn_image.get_num_time_frames()); dyn_image.set_time_frame_definitions(frame_defs); - const TimeFrameDefinitions time_defs=dyn_image.get_time_frame_definitions(); - assert(frame_defs.get_duration(1)==time_defs.get_duration(1)); + const TimeFrameDefinitions time_defs = dyn_image.get_time_frame_definitions(); + assert(frame_defs.get_duration(1) == time_defs.get_duration(1)); std::cerr << "Duration Time " << dyn_image.get_time_frame_definitions().get_duration(2) << "\n"; - Succeeded writing_succeeded=dyn_image.write_to_ecat7(argv[1]); - if(writing_succeeded==Succeeded::yes) - return EXIT_SUCCESS ; - else - return EXIT_FAILURE ; + Succeeded writing_succeeded = dyn_image.write_to_ecat7(argv[1]); + if (writing_succeeded == Succeeded::yes) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; } diff --git a/src/experimental/utilities/apply_plane_rescale_factors.cxx b/src/experimental/utilities/apply_plane_rescale_factors.cxx index bd7d54e1af..1715472a4f 100644 --- a/src/experimental/utilities/apply_plane_rescale_factors.cxx +++ b/src/experimental/utilities/apply_plane_rescale_factors.cxx @@ -1,9 +1,9 @@ // // /*! - \file + \file \ingroup utilities - + \brief This program rescales planes of an image according to a file with scale factors @@ -34,52 +34,41 @@ using std::vector; USING_NAMESPACE_STIR - -int main(int argc, char **argv) -{ - if(argc!=4) { - cerr<<"Usage: " << argv[0] << " \n"; +int +main(int argc, char** argv) { + if (argc != 4) { + cerr << "Usage: " << argv[0] << " \n"; exit(EXIT_FAILURE); } - + // get parameters from command line - char const * const output_filename = argv[1]; - char const * const input_filename = argv[2]; - char const * const rescale_factors_filename = argv[3]; - - // read image + char const* const output_filename = argv[1]; + char const* const input_filename = argv[2]; + char const* const rescale_factors_filename = argv[3]; - shared_ptr > density_ptr - (read_from_file >(input_filename)); + // read image + + shared_ptr> density_ptr(read_from_file>(input_filename)); // read factors vector rescale_factors; { ifstream factors(rescale_factors_filename); factors >> rescale_factors; - if (rescale_factors.size() != static_cast(density_ptr->get_length())) - { - warning("%s: wrong number of scale factors (%d) found in file %s, should be %d\n", - argv[0], rescale_factors.size(), - rescale_factors_filename, density_ptr->get_length()); - return(EXIT_FAILURE); + if (rescale_factors.size() != static_cast(density_ptr->get_length())) { + warning("%s: wrong number of scale factors (%d) found in file %s, should be %d\n", argv[0], rescale_factors.size(), + rescale_factors_filename, density_ptr->get_length()); + return (EXIT_FAILURE); } } { - multiply_plane_scale_factorsImageProcessor - image_processor(rescale_factors); + multiply_plane_scale_factorsImageProcessor image_processor(rescale_factors); image_processor.apply(*density_ptr); } - Succeeded res = write_basic_interfile(output_filename, *density_ptr); - return res==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; - + return res == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } - - - - diff --git a/src/experimental/utilities/change_mhead_file_type.cxx b/src/experimental/utilities/change_mhead_file_type.cxx index 2b069c69c1..c6d182a703 100644 --- a/src/experimental/utilities/change_mhead_file_type.cxx +++ b/src/experimental/utilities/change_mhead_file_type.cxx @@ -1,7 +1,7 @@ // // -/*! +/*! \file \ingroup utilities \brief A small utility that changes the file type in an ECAT7 main header. @@ -12,7 +12,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/Succeeded.h" #include "matrix.h" @@ -25,39 +24,29 @@ using std::endl; USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) { - - -int main(int argc, char *argv[]) -{ - - if(argc!=3) - { - cerr<< "\nChange file type in ECAT7 CTI main header.\n" - << "Usage: \n" - << "\t" <mhptr->file_type = static_cast(file_type); - Succeeded success = - mat_write_main_header(mptr->fptr, mptr->mhptr)==0?Succeeded::yes : Succeeded::no; + Succeeded success = mat_write_main_header(mptr->fptr, mptr->mhptr) == 0 ? Succeeded::yes : Succeeded::no; matrix_close(mptr); - - return success==Succeeded::yes ?EXIT_SUCCESS:EXIT_FAILURE; + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } - - diff --git a/src/experimental/utilities/compute_gradient.cxx b/src/experimental/utilities/compute_gradient.cxx index ca38028cb2..ee73f7fdec 100644 --- a/src/experimental/utilities/compute_gradient.cxx +++ b/src/experimental/utilities/compute_gradient.cxx @@ -18,10 +18,10 @@ */ /*! - \file + \file \ingroup utilities - - \brief + + \brief \author Kris Thielemans @@ -33,7 +33,6 @@ #include "stir/recon_buildblock/GeneralisedObjectiveFunction.h" #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.h" - /* example compute gradient parameters:= @@ -86,49 +85,41 @@ output filename:= end:= */ -int main(int argc, char **argv) -{ +int +main(int argc, char** argv) { USING_NAMESPACE_STIR; - typedef DiscretisedDensity<3,float> data_type; + typedef DiscretisedDensity<3, float> data_type; - shared_ptr - obj_function_sptr; + shared_ptr < GeneralisedObjectiveFunction obj_function_sptr; std::string input_filename; std::string output_filename; - shared_ptr density_sptr, gradient_sptr; - - KeyParser parser; - parser.add_start_key("compute gradient parameters"); - parser.add_parsing_key("objective function type", &obj_function_sptr); - parser.add_key("input filename", &input_filename); - parser.add_key("output filename", &output_filename); - parser.add_stop_key("END"); - if (parser.parse(argv[1]) == false || is_null_ptr(obj_function_sptr)) - { - std::cerr << "Error parsing output file format from " << argv[1]<set_up(density_sptr) != Succeeded::yes) - { - error(); - } - - PoissonLogLikelihoodWithLinearModelForMean& - obj_func = - dynamic_cast&> - (*obj_function_sptr); - - gradient_sptr = density_sptr->get_empty_copy(); - - obj_func.compute_sub_gradient_without_penalty_plus_sensitivity(*gradient_sptr, - *density_sptr, - 0); - - OutputFileFormat::default_sptr()-> - write_to_file(*gradient_sptr, output_filename); - - return EXIT_SUCCESS; + shared_ptr density_sptr, gradient_sptr; + + KeyParser parser; + parser.add_start_key("compute gradient parameters"); + parser.add_parsing_key("objective function type", &obj_function_sptr); + parser.add_key("input filename", &input_filename); + parser.add_key("output filename", &output_filename); + parser.add_stop_key("END"); + if (parser.parse(argv[1]) == false || is_null_ptr(obj_function_sptr)) { + std::cerr << "Error parsing output file format from " << argv[1] << endl; + exit(EXIT_FAILURE); + } + + density_sptr = data_type::read_from_file(input_filename); + + if (obj_function_sptr->set_up(density_sptr) != Succeeded::yes) { + error(); + } + + PoissonLogLikelihoodWithLinearModelForMean& obj_func = + dynamic_cast&>(*obj_function_sptr); + + gradient_sptr = density_sptr->get_empty_copy(); + + obj_func.compute_sub_gradient_without_penalty_plus_sensitivity(*gradient_sptr, *density_sptr, 0); + + OutputFileFormat::default_sptr()->write_to_file(*gradient_sptr, output_filename); + + return EXIT_SUCCESS; } diff --git a/src/experimental/utilities/compute_plane_rescale_factors.cxx b/src/experimental/utilities/compute_plane_rescale_factors.cxx index 99da75a263..dd91d44cc7 100644 --- a/src/experimental/utilities/compute_plane_rescale_factors.cxx +++ b/src/experimental/utilities/compute_plane_rescale_factors.cxx @@ -1,12 +1,12 @@ // // /*! - \file + \file \ingroup utilities - + \brief This programme finds plane rescaling factors - It requires an input image where each plane total should be rescaled to + It requires an input image where each plane total should be rescaled to the same number (e.g. a reconstruction of a uniform cylinder). Scale factors are computed as 1/(plane_total/average_plane_total). @@ -31,51 +31,41 @@ using std::ofstream; USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if(argc!=3) { - cerr<<"Usage: " << argv[0] << " \n"; +int +main(int argc, char** argv) { + if (argc != 3) { + cerr << "Usage: " << argv[0] << " \n"; exit(EXIT_FAILURE); } - + // get parameters from command line - char const * const output_filename = argv[1]; - char const * const input_filename = argv[2]; - - // read image + char const* const output_filename = argv[1]; + char const* const input_filename = argv[2]; - shared_ptr > density_ptr - (read_from_file >(input_filename)); + // read image + shared_ptr> density_ptr(read_from_file>(input_filename)); // store plane sums - Array<1,float> rescale_factors(density_ptr->get_min_index(), density_ptr->get_max_index()); - for (int z=density_ptr->get_min_index(); - z<=density_ptr->get_max_index(); - ++z) - { + Array<1, float> rescale_factors(density_ptr->get_min_index(), density_ptr->get_max_index()); + for (int z = density_ptr->get_min_index(); z <= density_ptr->get_max_index(); ++z) { rescale_factors[z] = (*density_ptr)[z].sum(); } // normalise to an average of 1 - const float average = rescale_factors.sum()/ rescale_factors.get_length(); + const float average = rescale_factors.sum() / rescale_factors.get_length(); rescale_factors /= average; // invert - for (int z=density_ptr->get_min_index(); - z<=density_ptr->get_max_index(); - ++z) - { - if (rescale_factors[z]<1E-4) - { + for (int z = density_ptr->get_min_index(); z <= density_ptr->get_max_index(); ++z) { + if (rescale_factors[z] < 1E-4) { warning("%s: plane total for plane %d is less than 1E-4 the average.\n" "Setting scale factor to 1E4\n", - argv[0], z-density_ptr->get_min_index()+1); + argv[0], z - density_ptr->get_min_index() + 1); rescale_factors[z] = 10000.F; - } - else - rescale_factors[z] = 1/rescale_factors[z]; + } else + rescale_factors[z] = 1 / rescale_factors[z]; } // write to file @@ -85,9 +75,4 @@ int main(int argc, char **argv) } return EXIT_SUCCESS; - } - - - - diff --git a/src/experimental/utilities/create_normfactors.cxx b/src/experimental/utilities/create_normfactors.cxx index ce0deca8d1..3890908093 100644 --- a/src/experimental/utilities/create_normfactors.cxx +++ b/src/experimental/utilities/create_normfactors.cxx @@ -37,112 +37,95 @@ using std::string; USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc!=4) - { - cerr << "Usage: " << argv[0] - << " out_filename_prefix measured_data noise\n" - << "\t noise is a float factor: 0: effs all 1 etc.\n"; - return EXIT_FAILURE; - } +int +main(int argc, char** argv) { + if (argc != 4) { + cerr << "Usage: " << argv[0] << " out_filename_prefix measured_data noise\n" + << "\t noise is a float factor: 0: effs all 1 etc.\n"; + return EXIT_FAILURE; + } const float noise = static_cast(atof(argv[3])); shared_ptr measured_data = ProjData::read_from_file(argv[2]); const string out_filename_prefix = argv[1]; - const int num_detectors = - measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_detectors = measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); const int num_crystals_per_block = 8; - const int num_blocks = num_detectors/num_crystals_per_block; + const int num_blocks = num_detectors / num_crystals_per_block; const int segment_num = 0; DetPairData det_pair_data; - Array<1,float> efficiencies(num_detectors); - assert(num_crystals_per_block%2 == 0); - GeoData norm_geo_data(IndexRange2D(num_crystals_per_block/2, num_detectors)); + Array<1, float> efficiencies(num_detectors); + assert(num_crystals_per_block % 2 == 0); + GeoData norm_geo_data(IndexRange2D(num_crystals_per_block / 2, num_detectors)); BlockData norm_block_data(IndexRange2D(num_blocks, num_blocks)); - const int iter_num=0; + const int iter_num = 0; const int eff_iter_num = 0; for (int ax_pos_num = measured_data->get_min_axial_pos_num(segment_num); - ax_pos_num <= measured_data->get_max_axial_pos_num(segment_num); - ++ax_pos_num) - { + ax_pos_num <= measured_data->get_max_axial_pos_num(segment_num); ++ax_pos_num) { - - // efficiencies - { - for (int b = 0; b < num_detectors; ++b) - efficiencies[b] = exp(noise*((2.F*rand())/RAND_MAX - 1)); - { - char *out_filename = new char[out_filename_prefix.size() + 30]; - sprintf(out_filename, "%s_%s_%d_%d_%d.out", - out_filename_prefix.c_str(), "eff", ax_pos_num, iter_num, eff_iter_num); - ofstream out(out_filename); - out << efficiencies; - delete[] out_filename; - } - // geo norm - { - // insert known geo factors - for (int a = 0; a < num_crystals_per_block/2; ++a) - for (int b = 0; b < num_detectors; ++b) - { - norm_geo_data[a][b] =(a+1)*cos(exp(-ax_pos_num)*(b-num_detectors/2)*_PI/num_detectors)+.1; - } - // it's for direct sinograms, so apply transpose symmetry - { - GeoData tmp = norm_geo_data; - for (int a = 0; a < num_crystals_per_block/2; ++a) - for (int b = 0; b < num_detectors; ++b) - { - int transposeda=b; - int transposedb=a; - int newa = transposeda % num_crystals_per_block; - int newb = transposedb - (transposeda - newa); - if (newa > num_crystals_per_block - 1 - newa) - { - newa = num_crystals_per_block - 1 - newa; - newb = - newb + num_crystals_per_block - 1; - } - norm_geo_data[a][b] = - (tmp[a][b] + - tmp[newa][(2*num_detectors + newb)%num_detectors])/2; - } + // efficiencies + { + for (int b = 0; b < num_detectors; ++b) + efficiencies[b] = exp(noise * ((2.F * rand()) / RAND_MAX - 1)); + { + char* out_filename = new char[out_filename_prefix.size() + 30]; + sprintf(out_filename, "%s_%s_%d_%d_%d.out", out_filename_prefix.c_str(), "eff", ax_pos_num, iter_num, eff_iter_num); + ofstream out(out_filename); + out << efficiencies; + delete[] out_filename; + } + // geo norm + { + // insert known geo factors + for (int a = 0; a < num_crystals_per_block / 2; ++a) + for (int b = 0; b < num_detectors; ++b) { + norm_geo_data[a][b] = (a + 1) * cos(exp(-ax_pos_num) * (b - num_detectors / 2) * _PI / num_detectors) + .1; + } + // it's for direct sinograms, so apply transpose symmetry + { + GeoData tmp = norm_geo_data; + for (int a = 0; a < num_crystals_per_block / 2; ++a) + for (int b = 0; b < num_detectors; ++b) { + int transposeda = b; + int transposedb = a; + int newa = transposeda % num_crystals_per_block; + int newb = transposedb - (transposeda - newa); + if (newa > num_crystals_per_block - 1 - newa) { + newa = num_crystals_per_block - 1 - newa; + newb = -newb + num_crystals_per_block - 1; + } + norm_geo_data[a][b] = (tmp[a][b] + tmp[newa][(2 * num_detectors + newb) % num_detectors]) / 2; } - { - char *out_filename = new char[out_filename_prefix.size() + 30]; - sprintf(out_filename, "%s_%s_%d_%d.out", - out_filename_prefix.c_str(), "geo", ax_pos_num, iter_num); - ofstream out(out_filename); - out << norm_geo_data; - delete[] out_filename; - } - } - // block norm - { - // it's for direct sinograms, so apply transpose symmetry - for (int a = 0; a < num_blocks; ++a) - for (int b = 0; b <=a; ++b) - { - - norm_block_data[a][b] = - norm_block_data[b][a] = - exp(noise*((1.F*rand())/RAND_MAX - 0.5F)); - } - - { - char *out_filename = new char[out_filename_prefix.size() + 30]; - sprintf(out_filename, "%s_%s_%d_%d.out", - out_filename_prefix.c_str(), "block", ax_pos_num, iter_num); - ofstream out(out_filename); - out << norm_block_data; - delete[] out_filename; - } - } - } + } + { + char* out_filename = new char[out_filename_prefix.size() + 30]; + sprintf(out_filename, "%s_%s_%d_%d.out", out_filename_prefix.c_str(), "geo", ax_pos_num, iter_num); + ofstream out(out_filename); + out << norm_geo_data; + delete[] out_filename; + } + } + // block norm + { + // it's for direct sinograms, so apply transpose symmetry + for (int a = 0; a < num_blocks; ++a) + for (int b = 0; b <= a; ++b) { + + norm_block_data[a][b] = norm_block_data[b][a] = exp(noise * ((1.F * rand()) / RAND_MAX - 0.5F)); + } + + { + char* out_filename = new char[out_filename_prefix.size() + 30]; + sprintf(out_filename, "%s_%s_%d_%d.out", out_filename_prefix.c_str(), "block", ax_pos_num, iter_num); + ofstream out(out_filename); + out << norm_block_data; + delete[] out_filename; + } + } } + } return EXIT_SUCCESS; } diff --git a/src/experimental/utilities/create_normfactors3D.cxx b/src/experimental/utilities/create_normfactors3D.cxx index 212f9819e9..6e107012f2 100644 --- a/src/experimental/utilities/create_normfactors3D.cxx +++ b/src/experimental/utilities/create_normfactors3D.cxx @@ -38,81 +38,69 @@ using std::string; USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc!=4) - { - cerr << "Usage: " << argv[0] - << " out_filename_prefix measured_data noise\n" - << "\t noise is a float factor: 0: effs all 1 etc.\n"; - return EXIT_FAILURE; - } +int +main(int argc, char** argv) { + if (argc != 4) { + cerr << "Usage: " << argv[0] << " out_filename_prefix measured_data noise\n" + << "\t noise is a float factor: 0: effs all 1 etc.\n"; + return EXIT_FAILURE; + } const float noise = static_cast(atof(argv[3])); shared_ptr measured_data = ProjData::read_from_file(argv[2]); const string out_filename_prefix = argv[1]; - const int num_rings = - measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings(); - const int num_detectors_per_ring = - measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_rings = measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings(); + const int num_detectors_per_ring = measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); const int num_tangential_crystals_per_block = 8; - const int num_tangential_blocks = num_detectors_per_ring/num_tangential_crystals_per_block; - const int num_axial_crystals_per_block = num_rings/2; + const int num_tangential_blocks = num_detectors_per_ring / num_tangential_crystals_per_block; + const int num_axial_crystals_per_block = num_rings / 2; warning("TODO num_axial_crystals_per_block == num_rings/2\n"); - const int num_axial_blocks = num_rings/num_axial_crystals_per_block; + const int num_axial_blocks = num_rings / num_axial_crystals_per_block; - BlockData3D norm_block_data(num_axial_blocks, num_tangential_blocks, - num_axial_blocks-1, num_tangential_blocks-1); + BlockData3D norm_block_data(num_axial_blocks, num_tangential_blocks, num_axial_blocks - 1, num_tangential_blocks - 1); DetectorEfficiencies efficiencies(IndexRange2D(num_rings, num_detectors_per_ring)); - const int iter_num=1; + const int iter_num = 1; const int eff_iter_num = 0; - { - + { - // efficiencies - { - for (int ra = 0; ra < num_rings; ++ra) - for (int a = 0; a < num_detectors_per_ring; ++a) - efficiencies[ra][a] = - static_cast((2+sin(2*_PI*a/num_detectors_per_ring))* - exp(noise*((2.F*rand())/RAND_MAX - 1))); - { - char *out_filename = new char[out_filename_prefix.size() + 30]; - sprintf(out_filename, "%s_%s_%d_%d.out", - out_filename_prefix.c_str(), "eff", iter_num, eff_iter_num); - ofstream out(out_filename); - out << efficiencies; - delete[] out_filename; - } - } // end efficiencies - // block norm - { - for (int ra = norm_block_data.get_min_ra(); ra <= norm_block_data.get_max_ra(); ++ra) - for (int a = norm_block_data.get_min_a(); a <= norm_block_data.get_max_a(); ++a) - // loop rb from ra to avoid double counting - for (int rb = std::max(ra,norm_block_data.get_min_rb(ra)); rb <= norm_block_data.get_max_rb(ra); ++rb) - for (int b = norm_block_data.get_min_b(a); b <= norm_block_data.get_max_b(a); ++b) - { - norm_block_data(ra,a,rb,b) = - exp(noise*((1.F*rand())/RAND_MAX - 0.5F)); - if (ra==rb) // it's for direct sinograms, so apply transpose symmetry - norm_block_data(ra,b,rb,a) = norm_block_data(ra,a,rb,b); - } - - { - char *out_filename = new char[out_filename_prefix.size() + 30]; - sprintf(out_filename, "%s_%s_%d.out", - out_filename_prefix.c_str(), "block", iter_num); - ofstream out(out_filename); - out << norm_block_data; - delete[] out_filename; - } - - } // end block - - } + // efficiencies + { + for (int ra = 0; ra < num_rings; ++ra) + for (int a = 0; a < num_detectors_per_ring; ++a) + efficiencies[ra][a] = + static_cast((2 + sin(2 * _PI * a / num_detectors_per_ring)) * exp(noise * ((2.F * rand()) / RAND_MAX - 1))); + { + char* out_filename = new char[out_filename_prefix.size() + 30]; + sprintf(out_filename, "%s_%s_%d_%d.out", out_filename_prefix.c_str(), "eff", iter_num, eff_iter_num); + ofstream out(out_filename); + out << efficiencies; + delete[] out_filename; + } + } // end efficiencies + // block norm + { + for (int ra = norm_block_data.get_min_ra(); ra <= norm_block_data.get_max_ra(); ++ra) + for (int a = norm_block_data.get_min_a(); a <= norm_block_data.get_max_a(); ++a) + // loop rb from ra to avoid double counting + for (int rb = std::max(ra, norm_block_data.get_min_rb(ra)); rb <= norm_block_data.get_max_rb(ra); ++rb) + for (int b = norm_block_data.get_min_b(a); b <= norm_block_data.get_max_b(a); ++b) { + norm_block_data(ra, a, rb, b) = exp(noise * ((1.F * rand()) / RAND_MAX - 0.5F)); + if (ra == rb) // it's for direct sinograms, so apply transpose symmetry + norm_block_data(ra, b, rb, a) = norm_block_data(ra, a, rb, b); + } + + { + char* out_filename = new char[out_filename_prefix.size() + 30]; + sprintf(out_filename, "%s_%s_%d.out", out_filename_prefix.c_str(), "block", iter_num); + ofstream out(out_filename); + out << norm_block_data; + delete[] out_filename; + } + + } // end block + } return EXIT_SUCCESS; } diff --git a/src/experimental/utilities/fillwith1.cxx b/src/experimental/utilities/fillwith1.cxx index 5eb649e282..af506093fb 100644 --- a/src/experimental/utilities/fillwith1.cxx +++ b/src/experimental/utilities/fillwith1.cxx @@ -14,40 +14,28 @@ */ - #include "stir/ProjData.h" #include "stir/SegmentByView.h" #include "stir/Succeeded.h" -#include - - +#include USING_NAMESPACE_STIR -int main(int argc, char *argv[]) -{ - - if(argc!=2) - { - std::cerr<<"Usage: " << argv[0] << " projdata_file\n" - << std::endl; +int +main(int argc, char* argv[]) { + + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " projdata_file\n" << std::endl; } - shared_ptr projdata_ptr = - ProjData::read_from_file(argv[1], ios::in|ios::out); - - - for (int segment_num=projdata_ptr->get_min_segment_num(); - segment_num<=projdata_ptr->get_max_segment_num(); - ++segment_num) - { - SegmentByView segment = projdata_ptr->get_empty_segment_by_view(segment_num,false); - segment.fill(1); - if (projdata_ptr->set_segment(segment) != Succeeded::yes) - error("fillwith1 failed writing segment %d of file %s", - segment_num, argv[1]); - } - return EXIT_SUCCESS; + shared_ptr projdata_ptr = ProjData::read_from_file(argv[1], ios::in | ios::out); + for (int segment_num = projdata_ptr->get_min_segment_num(); segment_num <= projdata_ptr->get_max_segment_num(); ++segment_num) { + SegmentByView segment = projdata_ptr->get_empty_segment_by_view(segment_num, false); + segment.fill(1); + if (projdata_ptr->set_segment(segment) != Succeeded::yes) + error("fillwith1 failed writing segment %d of file %s", segment_num, argv[1]); + } + return EXIT_SUCCESS; } diff --git a/src/experimental/utilities/fillwithotherprojdata.cxx b/src/experimental/utilities/fillwithotherprojdata.cxx index 71aebf67eb..e417626bb4 100644 --- a/src/experimental/utilities/fillwithotherprojdata.cxx +++ b/src/experimental/utilities/fillwithotherprojdata.cxx @@ -5,7 +5,8 @@ \file \ingroup utilities - \brief A utility that just fills the projection data with input from somewhere else. Only useful when the first file is an a different file format (i.e. ECAT 7) + \brief A utility that just fills the projection data with input from somewhere else. Only useful when the first file is an a + different file format (i.e. ECAT 7) \author Kris Thielemans @@ -15,12 +16,11 @@ See STIR/LICENSE.txt for details */ - #include "stir/ProjData.h" #include "stir/SegmentByView.h" #include "stir/Succeeded.h" -#include +#include #include #ifndef STIR_NO_NAMESPACES @@ -31,39 +31,32 @@ using std::ifstream; using std::cout; #endif - USING_NAMESPACE_STIR -int main(int argc, char *argv[]) -{ - - if(argc!=3) - { - cerr<<"Usage: " << argv[0] << " output_projdata_file input_projdata_file\n" - <<"The output_projdata_file must exist already, and will be overwritten.\n" - << endl; +int +main(int argc, char* argv[]) { + + if (argc != 3) { + cerr << "Usage: " << argv[0] << " output_projdata_file input_projdata_file\n" + << "The output_projdata_file must exist already, and will be overwritten.\n" + << endl; } - shared_ptr out_projdata_ptr = - ProjData::read_from_file(argv[1], ios::in|ios::out); - shared_ptr in_projdata_ptr = - ProjData::read_from_file(argv[2]); - - if (*out_projdata_ptr->get_proj_data_info_sptr() != - *in_projdata_ptr->get_proj_data_info_sptr()) - { - error("Projection data infos are incompatible\n"); - } + shared_ptr out_projdata_ptr = ProjData::read_from_file(argv[1], ios::in | ios::out); + shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); - for (int segment_num=out_projdata_ptr->get_min_segment_num(); - segment_num<=out_projdata_ptr->get_max_segment_num(); - ++segment_num) - { - SegmentByView segment = in_projdata_ptr->get_segment_by_view(segment_num); + if (*out_projdata_ptr->get_proj_data_info_sptr() != *in_projdata_ptr->get_proj_data_info_sptr()) { + error("Projection data infos are incompatible\n"); + } + + for (int segment_num = out_projdata_ptr->get_min_segment_num(); segment_num <= out_projdata_ptr->get_max_segment_num(); + ++segment_num) { + for (int timing_pos_num = out_projdata_ptr->get_min_tof_pos_num(); timing_pos_num <= out_projdata_ptr->get_max_tof_pos_num(); + ++timing_pos_num) { + SegmentByView segment = in_projdata_ptr->get_segment_by_view(segment_num, timing_pos_num); if (out_projdata_ptr->set_segment(segment) == Succeeded::no) return EXIT_FAILURE; - } + } return EXIT_SUCCESS; - } diff --git a/src/experimental/utilities/find_sinogram_rescaling_factors.cxx b/src/experimental/utilities/find_sinogram_rescaling_factors.cxx index 4844949dd3..8472692bfb 100644 --- a/src/experimental/utilities/find_sinogram_rescaling_factors.cxx +++ b/src/experimental/utilities/find_sinogram_rescaling_factors.cxx @@ -15,7 +15,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/ProjData.h" #include "stir/ProjDataInfo.h" #include "stir/ProjDataInterfile.h" @@ -32,29 +31,24 @@ using std::endl; using std::ofstream; #endif - int -main( int argc, char* argv[]) -{ +main(int argc, char* argv[]) { USING_NAMESPACE_STIR; - if ( argc !=4) - { - cerr << " Usage: " << argv[0] << " output_filename numerator_proj_data denominator" << endl; - return EXIT_FAILURE; - } + if (argc != 4) { + cerr << " Usage: " << argv[0] << " output_filename numerator_proj_data denominator" << endl; + return EXIT_FAILURE; + } - const string scaling_factors_filename = argv[1]; + const string scaling_factors_filename = argv[1]; shared_ptr numerator_sptr = ProjData::read_from_file(argv[2]); shared_ptr denominator_sptr = ProjData::read_from_file(argv[3]); - if (*numerator_sptr->get_proj_data_info_sptr() != - *denominator_sptr->get_proj_data_info_sptr()) - { - warning("Input files should have same characteristics (such as sizes etc).\n"); - return EXIT_FAILURE; - } + if (*numerator_sptr->get_proj_data_info_sptr() != *denominator_sptr->get_proj_data_info_sptr()) { + warning("Input files should have same characteristics (such as sizes etc).\n"); + return EXIT_FAILURE; + } #if 0 shared_ptr rescaling_factors_sptr = @@ -62,91 +56,64 @@ main( int argc, char* argv[]) scaling_factors_filename); #endif - const int min_segment_num = numerator_sptr->get_min_segment_num(); const int max_segment_num = numerator_sptr->get_max_segment_num(); - + // define array of scaling_factors of appropriate range - Array<3,float> scaling_factors; + Array<3, float> scaling_factors; { // sorry, this is pretty horrible... IndexRange<3> scaling_factor_index_range; scaling_factor_index_range.grow(min_segment_num, max_segment_num); - for ( int segment_num = numerator_sptr->get_min_segment_num(); - segment_num <= numerator_sptr->get_max_segment_num(); - ++segment_num) - { - const int min_axial_pos_num = - numerator_sptr->get_min_axial_pos_num(segment_num); - const int max_axial_pos_num = - numerator_sptr->get_max_axial_pos_num(segment_num); - scaling_factor_index_range[segment_num].grow(min_axial_pos_num, max_axial_pos_num); - for (int axial_pos_num = numerator_sptr->get_min_axial_pos_num(segment_num); - axial_pos_num <= numerator_sptr->get_max_axial_pos_num(segment_num); - ++axial_pos_num) - { - scaling_factor_index_range[segment_num][axial_pos_num] = - IndexRange<1>(numerator_sptr->get_min_view_num(), - numerator_sptr->get_max_view_num()); - } + for (int segment_num = numerator_sptr->get_min_segment_num(); segment_num <= numerator_sptr->get_max_segment_num(); + ++segment_num) { + const int min_axial_pos_num = numerator_sptr->get_min_axial_pos_num(segment_num); + const int max_axial_pos_num = numerator_sptr->get_max_axial_pos_num(segment_num); + scaling_factor_index_range[segment_num].grow(min_axial_pos_num, max_axial_pos_num); + for (int axial_pos_num = numerator_sptr->get_min_axial_pos_num(segment_num); + axial_pos_num <= numerator_sptr->get_max_axial_pos_num(segment_num); ++axial_pos_num) { + scaling_factor_index_range[segment_num][axial_pos_num] = + IndexRange<1>(numerator_sptr->get_min_view_num(), numerator_sptr->get_max_view_num()); } + } scaling_factors.grow(scaling_factor_index_range); } - for ( int segment_num = numerator_sptr->get_min_segment_num(); - segment_num <= numerator_sptr->get_max_segment_num(); - ++segment_num) - { - - for (int axial_pos = numerator_sptr->get_min_axial_pos_num(segment_num); - axial_pos <= numerator_sptr->get_max_axial_pos_num(segment_num); - ++axial_pos) - { - - const Sinogram numerator_sinogram = - numerator_sptr->get_sinogram(axial_pos, segment_num); - const Sinogram denominator_sinogram = - denominator_sptr->get_sinogram(axial_pos, segment_num); - - - for ( int view_num = numerator_sinogram.get_min_view_num(); - view_num <= numerator_sinogram.get_max_view_num(); - view_num++) - { - float numerator_sum =0; - float denominator_sum =0; - - for ( int tang_pos = numerator_sinogram.get_min_tangential_pos_num(); - tang_pos <= numerator_sinogram.get_max_tangential_pos_num(); - tang_pos++) - { - numerator_sum += numerator_sinogram[view_num][tang_pos]; - denominator_sum += denominator_sinogram[view_num][tang_pos]; - } - - scaling_factors[segment_num][axial_pos][view_num] = - numerator_sum/denominator_sum; - } - - } - + for (int segment_num = numerator_sptr->get_min_segment_num(); segment_num <= numerator_sptr->get_max_segment_num(); + ++segment_num) { + + for (int axial_pos = numerator_sptr->get_min_axial_pos_num(segment_num); + axial_pos <= numerator_sptr->get_max_axial_pos_num(segment_num); ++axial_pos) { + + const Sinogram numerator_sinogram = numerator_sptr->get_sinogram(axial_pos, segment_num); + const Sinogram denominator_sinogram = denominator_sptr->get_sinogram(axial_pos, segment_num); + + for (int view_num = numerator_sinogram.get_min_view_num(); view_num <= numerator_sinogram.get_max_view_num(); view_num++) { + float numerator_sum = 0; + float denominator_sum = 0; + + for (int tang_pos = numerator_sinogram.get_min_tangential_pos_num(); + tang_pos <= numerator_sinogram.get_max_tangential_pos_num(); tang_pos++) { + numerator_sum += numerator_sinogram[view_num][tang_pos]; + denominator_sum += denominator_sinogram[view_num][tang_pos]; + } + + scaling_factors[segment_num][axial_pos][view_num] = numerator_sum / denominator_sum; + } } - + } + ofstream outfile(scaling_factors_filename.c_str()); - if(!outfile) - { - warning("Error opening output file %d\n", scaling_factors_filename.c_str()); - return EXIT_FAILURE; - } + if (!outfile) { + warning("Error opening output file %d\n", scaling_factors_filename.c_str()); + return EXIT_FAILURE; + } outfile << scaling_factors; - if(!outfile) - { - warning("Error writing to output file %d\n", scaling_factors_filename.c_str()); - return EXIT_FAILURE; - } + if (!outfile) { + warning("Error writing to output file %d\n", scaling_factors_filename.c_str()); + return EXIT_FAILURE; + } return EXIT_SUCCESS; - } - diff --git a/src/experimental/utilities/fit_cylinder.cxx b/src/experimental/utilities/fit_cylinder.cxx index f7cce445da..ac81ea98a9 100644 --- a/src/experimental/utilities/fit_cylinder.cxx +++ b/src/experimental/utilities/fit_cylinder.cxx @@ -1,7 +1,7 @@ // // /*! - \file + \file \ingroup utilities \author Kris Thielemans @@ -35,85 +35,64 @@ using std::string; #endif int -main(int argc, char *argv[]) -{ +main(int argc, char* argv[]) { USING_NAMESPACE_STIR; - if (argc!=5) - { - cerr <<"Usage: " << argv[0] << " output_filename_prefix image_input_filename radius length\n"; - cerr <<"output will be in files output_filename_prefix.par\n"; - return (EXIT_FAILURE); - } + if (argc != 5) { + cerr << "Usage: " << argv[0] << " output_filename_prefix image_input_filename radius length\n"; + cerr << "output will be in files output_filename_prefix.par\n"; + return (EXIT_FAILURE); + } const string output_filename_prefix = argv[1]; - const shared_ptr > - density_ptr = DiscretisedDensity<3,float>::read_from_file(argv[2]); - VoxelsOnCartesianGrid * const image_ptr = - dynamic_cast * const>(density_ptr.get()); - if (image_ptr == 0) - { - warning("Can only handle images of type VoxelsOnCartesianGrid\n"); - exit(EXIT_FAILURE); - } + const shared_ptr> density_ptr = DiscretisedDensity<3, float>::read_from_file(argv[2]); + VoxelsOnCartesianGrid* const image_ptr = dynamic_cast* const>(density_ptr.get()); + if (image_ptr == 0) { + warning("Can only handle images of type VoxelsOnCartesianGrid\n"); + exit(EXIT_FAILURE); + } const float cylinder_radius = static_cast(atof(argv[3])); const float cylinder_length = static_cast(atof(argv[4])); - VectorWithOffset< CartesianCoordinate3D > allCoG; + VectorWithOffset> allCoG; VectorWithOffset weights; - find_centre_of_gravity_in_mm_per_plane(allCoG, - weights, - *image_ptr); - float cst_x=0, scale_x=0, cst_y=0, scale_y=0; + find_centre_of_gravity_in_mm_per_plane(allCoG, weights, *image_ptr); + float cst_x = 0, scale_x = 0, cst_y = 0, scale_y = 0; float chi_square, variance_of_constant, variance_of_scale, covariance_of_constant_with_scale; VectorWithOffset CoG_x(allCoG.get_min_index(), allCoG.get_max_index()); VectorWithOffset CoG_y(allCoG.get_min_index(), allCoG.get_max_index()); VectorWithOffset CoG_z(allCoG.get_min_index(), allCoG.get_max_index()); - for (int z=allCoG.get_min_index(); z<=allCoG.get_max_index(); ++z) - { - CoG_x[z] = allCoG[z].x(); - CoG_y[z] = allCoG[z].y(); - CoG_z[z] = allCoG[z].z(); - } - linear_regression(cst_x, scale_x, - chi_square, variance_of_constant, variance_of_scale, - covariance_of_constant_with_scale, - CoG_x, - CoG_z, - weights); - cout << "scale_x = " << scale_x << " +- " << sqrt(variance_of_scale) - << ", cst_x = " << cst_x << " +- " << sqrt(variance_of_constant) - << "\nchi_square = " << chi_square - << "\ncovariance = " << covariance_of_constant_with_scale + for (int z = allCoG.get_min_index(); z <= allCoG.get_max_index(); ++z) { + CoG_x[z] = allCoG[z].x(); + CoG_y[z] = allCoG[z].y(); + CoG_z[z] = allCoG[z].z(); + } + linear_regression(cst_x, scale_x, chi_square, variance_of_constant, variance_of_scale, covariance_of_constant_with_scale, CoG_x, + CoG_z, weights); + cout << "scale_x = " << scale_x << " +- " << sqrt(variance_of_scale) << ", cst_x = " << cst_x << " +- " + << sqrt(variance_of_constant) << "\nchi_square = " << chi_square << "\ncovariance = " << covariance_of_constant_with_scale << endl; - linear_regression(cst_y, scale_y, - chi_square, variance_of_constant, variance_of_scale, - covariance_of_constant_with_scale, - CoG_y, - CoG_z, - weights); - cout << "scale_y = " << scale_y << " +- " << sqrt(variance_of_scale) - << ", cst_y = " << cst_y << " +- " << sqrt(variance_of_constant) - << "\nchi_square = " << chi_square - << "\ncovariance = " << covariance_of_constant_with_scale + linear_regression(cst_y, scale_y, chi_square, variance_of_constant, variance_of_scale, covariance_of_constant_with_scale, CoG_y, + CoG_z, weights); + cout << "scale_y = " << scale_y << " +- " << sqrt(variance_of_scale) << ", cst_y = " << cst_y << " +- " + << sqrt(variance_of_constant) << "\nchi_square = " << chi_square << "\ncovariance = " << covariance_of_constant_with_scale << endl; /* Line is given as x = ax z + bx y = ay z + by - + so, dir_z = {1,ay,ax}/norm dir_y and dir_x are construct such that they form a left-handed coordinate system with dir_z */ - CartesianCoordinate3D dir_z(1,scale_y, scale_x); + CartesianCoordinate3D dir_z(1, scale_y, scale_x); // shift origin to somewhere roughly in the middle of the image - const CartesianCoordinate3D cylinder_origin = - CartesianCoordinate3D(0, cst_y, cst_x) + - dir_z * (image_ptr->get_z_size() * image_ptr->get_voxel_size().z()); + const CartesianCoordinate3D cylinder_origin = + CartesianCoordinate3D(0, cst_y, cst_x) + dir_z * (image_ptr->get_z_size() * image_ptr->get_voxel_size().z()); dir_z /= static_cast(norm(dir_z)); CartesianCoordinate3D dir_y(-scale_y, 1, 0); @@ -124,30 +103,29 @@ main(int argc, char *argv[]) const string parfile_name = output_filename_prefix + ".par"; ofstream parfile(parfile_name.c_str()); parfile << "generate_image Parameters :=\n" - << "output filename:=" << output_filename_prefix << '\n' - << "X output image size (in pixels):=" << image_ptr->get_x_size() << '\n' - << "Y output image size (in pixels):=" << image_ptr->get_y_size() << '\n' - << "Z output image size (in pixels):=" << image_ptr->get_z_size() << '\n' - << "X voxel size (in mm):= " << image_ptr->get_voxel_size().x() << '\n' - << "Y voxel size (in mm):= " << image_ptr->get_voxel_size().y() << '\n' - << "Z voxel size (in mm) :=" << image_ptr->get_voxel_size().z() << '\n'; + << "output filename:=" << output_filename_prefix << '\n' + << "X output image size (in pixels):=" << image_ptr->get_x_size() << '\n' + << "Y output image size (in pixels):=" << image_ptr->get_y_size() << '\n' + << "Z output image size (in pixels):=" << image_ptr->get_z_size() << '\n' + << "X voxel size (in mm):= " << image_ptr->get_voxel_size().x() << '\n' + << "Y voxel size (in mm):= " << image_ptr->get_voxel_size().y() << '\n' + << "Z voxel size (in mm) :=" << image_ptr->get_voxel_size().z() << '\n'; parfile << "shape type:= ellipsoidal cylinder\n" - << "Ellipsoidal Cylinder Parameters:=\n" - << " radius-x (in mm):=" << cylinder_radius << '\n' - << " radius-y (in mm):=" << cylinder_radius << '\n' - << " length-z (in mm):=" << cylinder_length << '\n' - << " origin-x (in mm):=" << cylinder_origin.x() << '\n' - << " origin-y (in mm):=" << cylinder_origin.y() << '\n' - << " origin-z (in mm):=" << cylinder_origin.z() << '\n' - << " direction-x (in mm):=" << dir_x << '\n' - << " direction-y (in mm):=" << dir_y << '\n' - << " direction-z (in mm):=" << dir_z << '\n' - << " END:=\n" - << "value :=" << 1 << '\n' - << "END:=\n"; + << "Ellipsoidal Cylinder Parameters:=\n" + << " radius-x (in mm):=" << cylinder_radius << '\n' + << " radius-y (in mm):=" << cylinder_radius << '\n' + << " length-z (in mm):=" << cylinder_length << '\n' + << " origin-x (in mm):=" << cylinder_origin.x() << '\n' + << " origin-y (in mm):=" << cylinder_origin.y() << '\n' + << " origin-z (in mm):=" << cylinder_origin.z() << '\n' + << " direction-x (in mm):=" << dir_x << '\n' + << " direction-y (in mm):=" << dir_y << '\n' + << " direction-z (in mm):=" << dir_z << '\n' + << " END:=\n" + << "value :=" << 1 << '\n' + << "END:=\n"; if (!parfile) warning("Error writing %s\n", parfile_name.c_str()); return (parfile ? EXIT_SUCCESS : EXIT_FAILURE); - } diff --git a/src/experimental/utilities/image_flip_x.cxx b/src/experimental/utilities/image_flip_x.cxx index 872c7f56ea..58eddbf0d7 100644 --- a/src/experimental/utilities/image_flip_x.cxx +++ b/src/experimental/utilities/image_flip_x.cxx @@ -32,69 +32,55 @@ #include #include -int main(int argc, char * argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR; - const char * output_filename = 0; - const char * input_filename = 0; + const char* output_filename = 0; + const char* input_filename = 0; - const char * const usage = "image_flip_x -o output_filename -i input_filename\n"; + const char* const usage = "image_flip_x -o output_filename -i input_filename\n"; opterr = 0; { char c; - while ((c = getopt (argc, argv, "i:o:")) != -1) - switch (c) - { + while ((c = getopt(argc, argv, "i:o:")) != -1) + switch (c) { case 'i': - input_filename = optarg; - break; + input_filename = optarg; + break; case 'o': - output_filename = optarg; - break; + output_filename = optarg; + break; case '?': - std::cerr << usage; - return EXIT_FAILURE; + std::cerr << usage; + return EXIT_FAILURE; default: - if (isprint (optopt)) - fprintf (stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf (stderr, - "Unknown option character `\\x%x'.\n", - optopt); - std::cerr << usage; - return EXIT_FAILURE; + if (isprint(optopt)) + fprintf(stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); + std::cerr << usage; + return EXIT_FAILURE; } } - if (output_filename==0 || input_filename==0) - { - std::cerr << usage; - return EXIT_FAILURE; - } + if (output_filename == 0 || input_filename == 0) { + std::cerr << usage; + return EXIT_FAILURE; + } - shared_ptr > density_ptr - (read_from_file >(input_filename)); + shared_ptr> density_ptr(read_from_file>(input_filename)); - for (DiscretisedDensity<3,float>::iterator z_iter = density_ptr->begin(); - z_iter != density_ptr->end(); - ++z_iter) - { - for (Array<2,float>::iterator y_iter = z_iter->begin(); - y_iter != z_iter->end(); - ++y_iter) - { - for (int left=y_iter->get_min_index(), right=y_iter->get_max_index(); - left < right; - ++left, --right) - std::swap((*y_iter)[left], (*y_iter)[right]); - } + for (DiscretisedDensity<3, float>::iterator z_iter = density_ptr->begin(); z_iter != density_ptr->end(); ++z_iter) { + for (Array<2, float>::iterator y_iter = z_iter->begin(); y_iter != z_iter->end(); ++y_iter) { + for (int left = y_iter->get_min_index(), right = y_iter->get_max_index(); left < right; ++left, --right) + std::swap((*y_iter)[left], (*y_iter)[right]); } - + } + Succeeded success = - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, *density_ptr); - - return success==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + OutputFileFormat>::default_sptr()->write_to_file(output_filename, *density_ptr); + + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/utilities/interpolate_blocks.cxx b/src/experimental/utilities/interpolate_blocks.cxx index 0b7d824bfc..c1221aed88 100644 --- a/src/experimental/utilities/interpolate_blocks.cxx +++ b/src/experimental/utilities/interpolate_blocks.cxx @@ -4,7 +4,7 @@ \file \ingroup utilities - \brief A utility to set data corresponding to a certain detector block + \brief A utility to set data corresponding to a certain detector block by interpolating from neighbouring data. \author Kris Thielemans @@ -40,41 +40,31 @@ using std::max; #endif START_NAMESPACE_STIR - -void do_block(vector& list_of_bins_in_block, - const int axial_block_num, const int tangential_block_num, - const ProjDataInfoCylindricalNoArcCorr& proj_data_info, - const int axial_num_crystals_in_block, const int tangential_num_crystals_in_block) -{ +void +do_block(vector& list_of_bins_in_block, const int axial_block_num, const int tangential_block_num, + const ProjDataInfoCylindricalNoArcCorr& proj_data_info, const int axial_num_crystals_in_block, + const int tangential_num_crystals_in_block) { Bin bin; - const int num_rings = - proj_data_info.get_scanner_ptr()->get_num_rings(); - const int num_detectors_per_ring = - proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); - - const int tang_det_offset = tangential_block_num*tangential_num_crystals_in_block; - const int ax_det_offset = axial_block_num*axial_num_crystals_in_block; - const int max_ring_diff = - proj_data_info.get_max_ring_difference(proj_data_info.get_max_segment_num()); - const int min_ring_diff = - proj_data_info.get_min_ring_difference(proj_data_info.get_min_segment_num()); - for (int ax_crystal=0; ax_crystalget_num_rings(); + const int num_detectors_per_ring = proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); + + const int tang_det_offset = tangential_block_num * tangential_num_crystals_in_block; + const int ax_det_offset = axial_block_num * axial_num_crystals_in_block; + const int max_ring_diff = proj_data_info.get_max_ring_difference(proj_data_info.get_max_segment_num()); + const int min_ring_diff = proj_data_info.get_min_ring_difference(proj_data_info.get_min_segment_num()); + for (int ax_crystal = 0; ax_crystal < axial_num_crystals_in_block; ++ax_crystal) + for (int tang_crystal = 0; tang_crystal < tangential_num_crystals_in_block; ++tang_crystal) { const int det = tang_crystal + tang_det_offset; const int ring = ax_crystal + ax_det_offset; { - for (int other_det=0; other_det& list_of_bins_in_block, } } - -bool -bin_coordinates_by_view_less(const Bin& b1, const Bin& b2) -{ - return b1.segment_num()& list_of_bins) -{ +void +sort_and_make_unique(vector& list_of_bins) { // cannot use vector::sort as VC does not support member templates - sort(list_of_bins.begin(), list_of_bins.end(),bin_coordinates_by_view_less); - //list_of_bins.unique(); + sort(list_of_bins.begin(), list_of_bins.end(), bin_coordinates_by_view_less); + // list_of_bins.unique(); unique(list_of_bins.begin(), list_of_bins.end()); } - END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc < 3 || argc > 4) - { - cerr << "Usage:\n" - << argv[0] << " output_filename input_projdata_name [max_in_segment_num_to_process ]\n" - << "max_in_segment_num_to_process defaults to all segments\n" - << "Will ask for which blocks to where data will be replaced by interpolation, will then reset " - << "ANY bin that has a contribution of those blocks.\n"; - exit(EXIT_FAILURE); - } - const string output_filename = argv[1]; - shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); - const int max_segment_num_to_process = argc <=3 ? in_projdata_ptr->get_max_segment_num() : atoi(argv[3]); - - ProjDataInfoCylindricalNoArcCorr * proj_data_info_ptr = - dynamic_cast - (in_projdata_ptr->get_proj_data_info_sptr()->clone()); - if (proj_data_info_ptr == NULL) - { - cerr << argv[0] << " can only work on not-arccorrected data\n"; +int +main(int argc, char** argv) { + if (argc < 3 || argc > 4) { + cerr << "Usage:\n" + << argv[0] << " output_filename input_projdata_name [max_in_segment_num_to_process ]\n" + << "max_in_segment_num_to_process defaults to all segments\n" + << "Will ask for which blocks to where data will be replaced by interpolation, will then reset " + << "ANY bin that has a contribution of those blocks.\n"; exit(EXIT_FAILURE); } - proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process,max_segment_num_to_process); - + const string output_filename = argv[1]; + shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); + const int max_segment_num_to_process = argc <= 3 ? in_projdata_ptr->get_max_segment_num() : atoi(argv[3]); - ProjDataInterfile out_projdata(proj_data_info_ptr, output_filename, ios::out); + ProjDataInfoCylindricalNoArcCorr* proj_data_info_ptr = + dynamic_cast(in_projdata_ptr->get_proj_data_info_sptr()->clone()); + if (proj_data_info_ptr == NULL) { + cerr << argv[0] << " can only work on not-arccorrected data\n"; + exit(EXIT_FAILURE); + } + proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); + ProjDataInterfile out_projdata(proj_data_info_ptr, output_filename, ios::out); - const int num_rings = - proj_data_info_ptr->get_scanner_ptr()->get_num_rings(); - const int num_detectors_per_ring = - proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); - const int axial_num_crystals_in_block = - ask_num("Crystals in 1 block axially",1,num_rings,8); - const int tangential_num_crystals_in_block= - ask_num("Crystals in 1 block tangentially",1,num_detectors_per_ring,8); + const int num_rings = proj_data_info_ptr->get_scanner_ptr()->get_num_rings(); + const int num_detectors_per_ring = proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); + const int axial_num_crystals_in_block = ask_num("Crystals in 1 block axially", 1, num_rings, 8); + const int tangential_num_crystals_in_block = ask_num("Crystals in 1 block tangentially", 1, num_detectors_per_ring, 8); vector list_of_bins; - do - { - const int axial_block_num = - ask_num("Block number axially", - 0,num_rings/axial_num_crystals_in_block-1, 0); - const int tangential_block_num = - ask_num("Block number tangentially", - 0,num_detectors_per_ring/tangential_num_crystals_in_block-1, 0); - do_block(list_of_bins, - axial_block_num, tangential_block_num, - *proj_data_info_ptr, - axial_num_crystals_in_block, tangential_num_crystals_in_block); - } - while (ask("One more",false)); - + do { + const int axial_block_num = ask_num("Block number axially", 0, num_rings / axial_num_crystals_in_block - 1, 0); + const int tangential_block_num = + ask_num("Block number tangentially", 0, num_detectors_per_ring / tangential_num_crystals_in_block - 1, 0); + do_block(list_of_bins, axial_block_num, tangential_block_num, *proj_data_info_ptr, axial_num_crystals_in_block, + tangential_num_crystals_in_block); + } while (ask("One more", false)); sort_and_make_unique(list_of_bins); std::vector::const_iterator bin_iter = list_of_bins.begin(); - for (int segment_num = out_projdata.get_min_segment_num(); - segment_num <= out_projdata.get_max_segment_num(); - ++segment_num) - for (int view_num = in_projdata_ptr->get_min_view_num(); - view_num <= in_projdata_ptr->get_max_view_num(); - ++view_num) - { - Viewgram viewgram = - out_projdata.get_empty_viewgram(view_num, segment_num); - viewgram += in_projdata_ptr->get_viewgram(view_num, segment_num); + for (int segment_num = out_projdata.get_min_segment_num(); segment_num <= out_projdata.get_max_segment_num(); ++segment_num) + for (int view_num = in_projdata_ptr->get_min_view_num(); view_num <= in_projdata_ptr->get_max_view_num(); ++view_num) { + Viewgram viewgram = out_projdata.get_empty_viewgram(view_num, segment_num); + viewgram += in_projdata_ptr->get_viewgram(view_num, segment_num); const int max_ax_pos_num = viewgram.get_max_axial_pos_num(); const int min_ax_pos_num = viewgram.get_min_axial_pos_num(); const int max_tang_pos_num = viewgram.get_max_tangential_pos_num(); const int min_tang_pos_num = viewgram.get_min_tangential_pos_num(); - for (; bin_iter != list_of_bins.end(); ++bin_iter) - { - if (segment_num != bin_iter->segment_num() || - view_num != bin_iter->view_num()) + for (; bin_iter != list_of_bins.end(); ++bin_iter) { + if (segment_num != bin_iter->segment_num() || view_num != bin_iter->view_num()) break; - const int ax_pos_num = bin_iter->axial_pos_num(); - if (ax_pos_num >max_ax_pos_num || - ax_pos_num tangential_pos_num(); - int last_tang_pos_num = first_tang_pos_num; - ++bin_iter; - for (; bin_iter != list_of_bins.end(); ++bin_iter) - { - if (segment_num != bin_iter->segment_num() || - view_num != bin_iter->view_num() || - ax_pos_num != bin_iter->axial_pos_num() || - last_tang_pos_num+1 != bin_iter->tangential_pos_num()) - break; - ++last_tang_pos_num; - } - first_tang_pos_num = - max(first_tang_pos_num, min_tang_pos_num); - last_tang_pos_num = - min(last_tang_pos_num, max_tang_pos_num); + const int ax_pos_num = bin_iter->axial_pos_num(); + if (ax_pos_num > max_ax_pos_num || ax_pos_num < min_ax_pos_num) + continue; + int first_tang_pos_num = bin_iter->tangential_pos_num(); + int last_tang_pos_num = first_tang_pos_num; + ++bin_iter; + for (; bin_iter != list_of_bins.end(); ++bin_iter) { + if (segment_num != bin_iter->segment_num() || view_num != bin_iter->view_num() || + ax_pos_num != bin_iter->axial_pos_num() || last_tang_pos_num + 1 != bin_iter->tangential_pos_num()) + break; + ++last_tang_pos_num; + } + first_tang_pos_num = max(first_tang_pos_num, min_tang_pos_num); + last_tang_pos_num = min(last_tang_pos_num, max_tang_pos_num); if (first_tang_pos_num > last_tang_pos_num) - continue; + continue; #if 0 cerr << "s "<< segment_num << " v " << view_num @@ -216,23 +171,14 @@ int main(int argc, char **argv) << std::endl; #endif const float previous_value = - first_tang_pos_num-1 >= min_tang_pos_num - ? viewgram[ax_pos_num][first_tang_pos_num-1] - : 0; - const float next_value = - last_tang_pos_num+1 <= max_tang_pos_num - ? viewgram[ax_pos_num][last_tang_pos_num+1] - : 0; - const float increment = - (next_value-previous_value)/(last_tang_pos_num-first_tang_pos_num+1); - float current_value = previous_value; - for (int tang_pos_num=first_tang_pos_num; - tang_pos_num<=last_tang_pos_num; - ++tang_pos_num, current_value += increment) - viewgram[ax_pos_num][tang_pos_num] = current_value; - assert(fabs(current_value - next_value)< - max(fabs(previous_value), fabs(next_value))*10.E-5); - } + first_tang_pos_num - 1 >= min_tang_pos_num ? viewgram[ax_pos_num][first_tang_pos_num - 1] : 0; + const float next_value = last_tang_pos_num + 1 <= max_tang_pos_num ? viewgram[ax_pos_num][last_tang_pos_num + 1] : 0; + const float increment = (next_value - previous_value) / (last_tang_pos_num - first_tang_pos_num + 1); + float current_value = previous_value; + for (int tang_pos_num = first_tang_pos_num; tang_pos_num <= last_tang_pos_num; ++tang_pos_num, current_value += increment) + viewgram[ax_pos_num][tang_pos_num] = current_value; + assert(fabs(current_value - next_value) < max(fabs(previous_value), fabs(next_value)) * 10.E-5); + } out_projdata.set_viewgram(viewgram); } diff --git a/src/experimental/utilities/interpolate_projdata.cxx b/src/experimental/utilities/interpolate_projdata.cxx index f773a93d8d..e726fa449c 100644 --- a/src/experimental/utilities/interpolate_projdata.cxx +++ b/src/experimental/utilities/interpolate_projdata.cxx @@ -10,8 +10,8 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! @@ -21,21 +21,21 @@ \author Charalampos Tsoumpas \author Kris Thielemans - - + + \par Usage: \verbatim interpolate_projdata projdata_output_filename projdata_input projdata_template \ [spline_type1 [spline_type2 [spline_type3 [remove_interleaving [use_view_offset]]]] Output: [projdata_output_filename].hs [projdata_output_filename].s files - \endverbatim + \endverbatim Execute without arguments to get more detailed usage info. \par - This is a utility program which uses the stir::interpolate_projdata function in order to - interpolate a 3D set of projection data using B-Splines interpolation. + This is a utility program which uses the stir::interpolate_projdata function in order to + interpolate a 3D set of projection data using B-Splines interpolation. \sa "stir_experimental/interpolate_projdata.h" for more details. - + */ #include #include "stir/ProjDataInfo.h" @@ -48,57 +48,55 @@ using namespace stir; using namespace stir::BSpline; -/***********************************************************/ - -int main(int argc, const char *argv[]) -{ - - if (argc< 4 || argc>9) - { - std::cerr << "Usage:" << argv[0] << "\\\n" - << "\tprojdata_out_filename\\\n" - << "\tprojdata_in\\\n" - << "\tprojdata_out_template\\\n" - << "\t[spline_type1 [spline_type2 [spline_type3 [remove_interleaving [ use_view_offset]]]]\n" - << " Default for spline_type1 is cubic splines.\n" - << " For Nearest Neighbour set to: " << BSpline::near_n << "\n" - << " For Linear set to: " << BSpline::linear << "\n" - << " For Quadratic set to: " << BSpline::quadratic << "\n" - << " For Cubic set to: " << BSpline::cubic << "\n" - << " For Cubic oMoms set to: " << BSpline::oMoms << "\n" - << " Default for spline_type2 and spline_type3 is spline_type1.\n" - << " Default for remove_interleaving is 0.\n" - << " Default for use_view_offset is 0 (WARNING: enabling this is currently EXPERIMENTAL).\n"; - return EXIT_FAILURE; - } - - BasicCoordinate<3, BSplineType> these_types ; - BasicCoordinate<3, int> input_types ; - - input_types[1]= (argc==4) ? 3 : atoi(argv[4]) ; - input_types[2]= (argc>5 ? atoi(argv[5]) : input_types[1]); - input_types[3]= (argc>6 ? atoi(argv[6]) : input_types[1]); - - const bool remove_interleaving = argc>7 ? atoi(argv[7]) : 0 ; - const bool use_view_offset = argc>8 ? atoi(argv[8]) : 0 ; - these_types[1]= (BSplineType)input_types[1]; - these_types[2]= (BSplineType)input_types[2]; - these_types[3]= (BSplineType)input_types[3]; - - shared_ptr template_proj_data_sptr = ProjData::read_from_file(argv[3]); - const ProjDataInfo* proj_data_info_ptr = - template_proj_data_sptr->get_proj_data_info_sptr(); - +/***********************************************************/ + +int +main(int argc, const char* argv[]) { + + if (argc < 4 || argc > 9) { + std::cerr << "Usage:" << argv[0] << "\\\n" + << "\tprojdata_out_filename\\\n" + << "\tprojdata_in\\\n" + << "\tprojdata_out_template\\\n" + << "\t[spline_type1 [spline_type2 [spline_type3 [remove_interleaving [ use_view_offset]]]]\n" + << " Default for spline_type1 is cubic splines.\n" + << " For Nearest Neighbour set to: " << BSpline::near_n << "\n" + << " For Linear set to: " << BSpline::linear << "\n" + << " For Quadratic set to: " << BSpline::quadratic << "\n" + << " For Cubic set to: " << BSpline::cubic << "\n" + << " For Cubic oMoms set to: " << BSpline::oMoms << "\n" + << " Default for spline_type2 and spline_type3 is spline_type1.\n" + << " Default for remove_interleaving is 0.\n" + << " Default for use_view_offset is 0 (WARNING: enabling this is currently EXPERIMENTAL).\n"; + return EXIT_FAILURE; + } + + BasicCoordinate<3, BSplineType> these_types; + BasicCoordinate<3, int> input_types; + + input_types[1] = (argc == 4) ? 3 : atoi(argv[4]); + input_types[2] = (argc > 5 ? atoi(argv[5]) : input_types[1]); + input_types[3] = (argc > 6 ? atoi(argv[6]) : input_types[1]); + + const bool remove_interleaving = argc > 7 ? atoi(argv[7]) : 0; + const bool use_view_offset = argc > 8 ? atoi(argv[8]) : 0; + these_types[1] = (BSplineType)input_types[1]; + these_types[2] = (BSplineType)input_types[2]; + these_types[3] = (BSplineType)input_types[3]; + + shared_ptr template_proj_data_sptr = ProjData::read_from_file(argv[3]); + const ProjDataInfo* proj_data_info_ptr = template_proj_data_sptr->get_proj_data_info_sptr(); + string proj_data_out_filename(argv[1]); - ProjDataInterfile proj_data_out(proj_data_info_ptr->create_shared_clone(), proj_data_out_filename,std::ios::out); - - const shared_ptr proj_data_in_sptr = ProjData::read_from_file(argv[2],std::ios::in); - - if (proj_data_info_ptr==0 || proj_data_in_sptr==0) - error("Check the input files\n"); + ProjDataInterfile proj_data_out(proj_data_info_ptr->create_shared_clone(), proj_data_out_filename, std::ios::out); + + const shared_ptr proj_data_in_sptr = ProjData::read_from_file(argv[2], std::ios::in); + + if (proj_data_info_ptr == 0 || proj_data_in_sptr == 0) + error("Check the input files\n"); if (interpolate_projdata(proj_data_out, *proj_data_in_sptr, these_types, remove_interleaving, use_view_offset) == Succeeded::yes) return EXIT_SUCCESS; else return EXIT_FAILURE; -} +} diff --git a/src/experimental/utilities/inverse_SSRB.cxx b/src/experimental/utilities/inverse_SSRB.cxx index c7a379d4a6..1e97ec2348 100644 --- a/src/experimental/utilities/inverse_SSRB.cxx +++ b/src/experimental/utilities/inverse_SSRB.cxx @@ -6,12 +6,12 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! @@ -21,16 +21,16 @@ \author Charalampos Tsoumpas \author Kris Thielemans - - + + \par Usage: \code correct_for_scatter [4D_projdata_filename] [3D_projdata] [4D_template] -Output: 4D Projdata .hs .s files with name proj_data_4D -\endcode +Output: 4D Projdata .hs .s files with name proj_data_4D +\endcode -This is a utility program which uses the stir::inverse_SSRB function , in order to create a -4D set of projection data. +This is a utility program which uses the stir::inverse_SSRB function , in order to create a +4D set of projection data. */ #include "stir/ProjDataInfo.h" #include "stir/ProjDataInterfile.h" @@ -45,34 +45,31 @@ using std::cerr; #endif USING_NAMESPACE_STIR using namespace std; -/***********************************************************/ +/***********************************************************/ + +int +main(int argc, const char* argv[]) { -int main(int argc, const char *argv[]) -{ + if (argc < 3 || argc > 4) { + cerr << "Usage:" << argv[0] << "\n" + << "\t[projdata_4D_filename]\n" + << "\t[projdata_3D]\n" + << "\t[projdata_4D_template]\n"; - if (argc< 3 || argc>4) - { - cerr << "Usage:" << argv[0] << "\n" - << "\t[projdata_4D_filename]\n" - << "\t[projdata_3D]\n" - << "\t[projdata_4D_template]\n" ; + return EXIT_FAILURE; + } + shared_ptr template_proj_data_sptr = ProjData::read_from_file(argv[3]); + const ProjDataInfo* proj_data_info_ptr = dynamic_cast(template_proj_data_sptr->get_proj_data_info_sptr()); - return EXIT_FAILURE; - } - shared_ptr template_proj_data_sptr = ProjData::read_from_file(argv[3]); - const ProjDataInfo* proj_data_info_ptr = - dynamic_cast( - template_proj_data_sptr->get_proj_data_info_sptr()); + const shared_ptr proj_data_3D_sptr = ProjData::read_from_file(argv[2], ios::in); - const shared_ptr proj_data_3D_sptr = ProjData::read_from_file(argv[2],ios::in); + if (proj_data_info_ptr == 0 || proj_data_3D_sptr == 0) + error("Check the input files\n"); - if (proj_data_info_ptr==0 || proj_data_3D_sptr==0) - error("Check the input files\n"); - - string proj_data_4D_filename(argv[1]); - ProjDataInterfile proj_data_4D(proj_data_info_ptr->clone(), proj_data_4D_filename,ios::out); + string proj_data_4D_filename(argv[1]); + ProjDataInterfile proj_data_4D(proj_data_info_ptr->clone(), proj_data_4D_filename, ios::out); - const Succeeded success = inverse_SSRB(proj_data_4D, *proj_data_3D_sptr); + const Succeeded success = inverse_SSRB(proj_data_4D, *proj_data_3D_sptr); - return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; -} + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/experimental/utilities/inverse_proj_data.cxx b/src/experimental/utilities/inverse_proj_data.cxx index 3ac04ed23a..d27ff61e3e 100644 --- a/src/experimental/utilities/inverse_proj_data.cxx +++ b/src/experimental/utilities/inverse_proj_data.cxx @@ -9,7 +9,7 @@ \author Sanida Mustafovic - + */ /* Copyright (C) 2000- 2012, IRSL @@ -35,7 +35,6 @@ #include "stir/info.h" #include "stir/error.h" - #include #include #include @@ -48,122 +47,104 @@ using std::list; using std::find; #endif - START_NAMESPACE_STIR void find_inverse(ProjData* proj_data_ptr_out, const ProjData* proj_data_ptr_in); +void +find_inverse(ProjData* proj_data_ptr_out, const ProjData* proj_data_ptr_in) { + const ProjDataInfo* proj_data_info_ptr = proj_data_ptr_in->get_proj_data_info_sptr(); + + const ProjDataInfo* proj_data_info_ptr_out = proj_data_ptr_out->get_proj_data_info_sptr(); + const ProjDataFromStream* projdatafromstream_in = dynamic_cast(proj_data_ptr_in); -void -find_inverse( ProjData* proj_data_ptr_out, const ProjData* proj_data_ptr_in) -{ - const ProjDataInfo * proj_data_info_ptr = - proj_data_ptr_in->get_proj_data_info_sptr(); - - const ProjDataInfo * proj_data_info_ptr_out = - proj_data_ptr_out->get_proj_data_info_sptr(); - - const ProjDataFromStream* projdatafromstream_in = - dynamic_cast< const ProjDataFromStream*>(proj_data_ptr_in); - - ProjDataFromStream* projdatafromstream_out = - dynamic_cast(proj_data_ptr_out); + ProjDataFromStream* projdatafromstream_out = dynamic_cast(proj_data_ptr_out); float inv; float bin; - int min_segment_num = ask_num("Minimum segment number to invert", - proj_data_info_ptr->get_min_segment_num(), proj_data_info_ptr->get_max_segment_num(), 0); - int max_segment_num = ask_num("Maximum segment number to invert", - min_segment_num,proj_data_info_ptr->get_max_segment_num(), - min_segment_num); - - - float max_in_viewgram =0.F; - - for (int segment_num = min_segment_num; segment_num<= max_segment_num; - segment_num++) - { - SegmentByView segment_by_view = - projdatafromstream_in->get_segment_by_view(segment_num); - const float current_max_in_viewgram = segment_by_view.find_max(); - if ( current_max_in_viewgram >= max_in_viewgram) - max_in_viewgram = current_max_in_viewgram ; + int min_segment_num = ask_num("Minimum segment number to invert", proj_data_info_ptr->get_min_segment_num(), + proj_data_info_ptr->get_max_segment_num(), 0); + int max_segment_num = + ask_num("Maximum segment number to invert", min_segment_num, proj_data_info_ptr->get_max_segment_num(), min_segment_num); + int min_timing_pos_num = 0; // Default cases of non-TOF data + int max_timing_pos_num = 0; + if (proj_data_info_ptr->is_tof_data()) { + int min_timing_pos_num = ask_num("Minimum timing position index to invert", proj_data_info_ptr->get_min_tof_pos_num(), + proj_data_info_ptr->get_max_tof_pos_num(), 0); + int max_timing_pos_num = ask_num("Maximum timing position index to invert", min_timing_pos_num, + proj_data_info_ptr->get_max_tof_pos_num(), max_timing_pos_num); + } + + float max_in_viewgram = 0.F; + + for (int segment_num = min_segment_num; segment_num <= max_segment_num; segment_num++) { + for (int timing_pos_num = min_timing_pos_num; timing_pos_num <= max_timing_pos_num; timing_pos_num++) { + SegmentByView segment_by_view = projdatafromstream_in->get_segment_by_view(segment_num, timing_pos_num); + const float current_max_in_viewgram = segment_by_view.find_max(); + if (current_max_in_viewgram >= max_in_viewgram) + max_in_viewgram = current_max_in_viewgram; else - continue; + continue; + } } info(boost::format("Max number in viewgram is: %1%") % max_in_viewgram); - for (int segment_num = min_segment_num; segment_num<= max_segment_num; - segment_num++) - for ( int view_num = proj_data_info_ptr->get_min_view_num(); - view_num<=proj_data_info_ptr->get_max_view_num(); view_num++) - { - Viewgram viewgram_in = projdatafromstream_in->get_viewgram(view_num,segment_num); - Viewgram viewgram_out = proj_data_info_ptr_out->get_empty_viewgram(view_num,segment_num); - - // the following const was found in the ls_cyl.hs and the same value will - // be used for thresholding both kappa_0 and kappa_1. - // threshold = 10^-4/max_in_sinogram - // TODO - find out batter way of finding the threshold - // const float max_in_viewgram = 54.0F; - - //segment_by_view.find_max(); - - const float threshold = 0.0001F*max_in_viewgram; - - for (int i= viewgram_in.get_min_axial_pos_num(); i<=viewgram_in.get_max_axial_pos_num();i++) - for (int j= viewgram_in.get_min_tangential_pos_num(); j<=viewgram_in.get_max_tangential_pos_num();j++) - { - bin= viewgram_in[i][j]; - - if (bin >= threshold) - { - inv = 1.F/bin; - viewgram_out[i][j] = inv; - } - else - { - inv =1/threshold; - viewgram_out[i][j] = inv; - } - - } - projdatafromstream_out->set_viewgram(viewgram_out); - } - + for (int segment_num = min_segment_num; segment_num <= max_segment_num; segment_num++) + for (int timing_pos_num = min_timing_pos_num; timing_pos_num <= max_timing_pos_num; timing_pos_num++) + for (int view_num = proj_data_info_ptr->get_min_view_num(); view_num <= proj_data_info_ptr->get_max_view_num(); + view_num++) { + Viewgram viewgram_in = projdatafromstream_in->get_viewgram(view_num, segment_num, false, timing_pos_num); + Viewgram viewgram_out = proj_data_info_ptr_out->get_empty_viewgram(view_num, segment_num, false, timing_pos_num); + + // the following const was found in the ls_cyl.hs and the same value will + // be used for thresholding both kappa_0 and kappa_1. + // threshold = 10^-4/max_in_sinogram + // TODO - find out batter way of finding the threshold + // const float max_in_viewgram = 54.0F; + + // segment_by_view.find_max(); + + const float threshold = 0.0001F * max_in_viewgram; + + for (int i = viewgram_in.get_min_axial_pos_num(); i <= viewgram_in.get_max_axial_pos_num(); i++) + for (int j = viewgram_in.get_min_tangential_pos_num(); j <= viewgram_in.get_max_tangential_pos_num(); j++) { + bin = viewgram_in[i][j]; + + if (bin >= threshold) { + inv = 1.F / bin; + viewgram_out[i][j] = inv; + } else { + inv = 1 / threshold; + viewgram_out[i][j] = inv; + } + } + projdatafromstream_out->set_viewgram(viewgram_out); + } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int -main(int argc, char **argv) +int +main(int argc, char** argv) { shared_ptr proj_data_ptr; - - if (argc!=3) - { + + if (argc != 3) { cerr << " USAGE: Inverse_proj_data: input projdata filename, output projdata (extension .s) " << endl; - return(EXIT_FAILURE); + return (EXIT_FAILURE); + } else { + proj_data_ptr = ProjData::read_from_file(argv[1]); } - else - { - proj_data_ptr = ProjData::read_from_file(argv[1]); - } - - const ProjDataInfo * proj_data_info_ptr = - proj_data_ptr->get_proj_data_info_sptr(); - shared_ptr proj_data_inv_ptr - (new ProjDataInterfile (proj_data_info_ptr->create_shared_clone(),argv[2])); + const ProjDataInfo* proj_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr(); + shared_ptr proj_data_inv_ptr(new ProjDataInterfile(proj_data_info_ptr->create_shared_clone(), argv[2])); - find_inverse(proj_data_inv_ptr.get(),proj_data_ptr.get()); + find_inverse(proj_data_inv_ptr.get(), proj_data_ptr.get()); return EXIT_SUCCESS; - } diff --git a/src/experimental/utilities/line_profiles_through_projdata.cxx b/src/experimental/utilities/line_profiles_through_projdata.cxx index e6161bae85..b5664590fd 100644 --- a/src/experimental/utilities/line_profiles_through_projdata.cxx +++ b/src/experimental/utilities/line_profiles_through_projdata.cxx @@ -28,7 +28,7 @@ \par Usage: \code - line_profiles_through_projdata [proj_data_filename] [output_profile_filename] ax_min/max view_min/max tang_min/max + line_profiles_through_projdata [proj_data_filename] [output_profile_filename] ax_min/max view_min/max tang_min/max \endcode \par ax_min/max, view_min/max, tang_min/max: These are the minimum and maximum values of the profile for the correspondig direction (axial - angular - tangential). \n @@ -41,11 +41,11 @@ \attention Take special care of the min/max values of the direction that the profiles will be estimated. The should be the same. - This program extracts the profile of given input_projdata which should be on the center. - The results is the same as if we first run - \a ./extract_segments \a input_projdata.hs (by sinogram) - and then run - \a ./manip_image \a input_projdata.hs to extract the rows as the defaults. + This program extracts the profile of given input_projdata which should be on the center. + The results is the same as if we first run + \a ./extract_segments \a input_projdata.hs (by sinogram) + and then run + \a ./manip_image \a input_projdata.hs to extract the rows as the defaults. */ @@ -54,8 +54,8 @@ #include "stir/ProjData.h" #include "stir/ProjDataInfo.h" #include "stir/Bin.h" -#include -#include +#include +#include #include #ifndef STIR_NO_NAMESPACES using std::iostream; @@ -68,22 +68,20 @@ using std::cout; using std::setw; #endif -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR - using namespace std; - if (argc!=9) - { - cerr << "Usage:" << argv[0] << "\n" - << "\t[proj_data_filename]\n" - << "\t[output_profile_filename] ax_min/max view_min/max tang_min/max\n"; - return EXIT_FAILURE; - } - - const shared_ptr input_projdata_sptr = ProjData::read_from_file(argv[1]); - - const ProjDataInfo * projdata_info_ptr = - (*input_projdata_sptr).get_proj_data_info_sptr(); + using namespace std; + if (argc != 9) { + cerr << "Usage:" << argv[0] << "\n" + << "\t[proj_data_filename]\n" + << "\t[output_profile_filename] ax_min/max view_min/max tang_min/max\n"; + return EXIT_FAILURE; + } + + const shared_ptr input_projdata_sptr = ProjData::read_from_file(argv[1]); + + const ProjDataInfo* projdata_info_ptr = (*input_projdata_sptr).get_proj_data_info_sptr(); string output_profile_string(argv[2]); @@ -94,13 +92,13 @@ int main(int argc, char *argv[]) const int tangential_min = atoi(argv[7]); const int tangential_max = atoi(argv[8]); /* - int view_min, tangential_min, + int view_min, tangential_min, view_max, tangential_max; view_min= projdata_info_ptr->get_min_view_num(); view_max= - projdata_info_ptr->get_max_view_num(); + projdata_info_ptr->get_max_view_num(); axial_min= projdata_info_ptr->get_min_axial_pos_num(0); axial_max= @@ -109,67 +107,64 @@ int main(int argc, char *argv[]) projdata_info_ptr->get_min_tangential_pos_num(); tangential_max= projdata_info_ptr->get_max_tangential_pos_num(); - + */ /* int view_mean=static_cast(ceil((view_min+view_max)/2.F)); //int axial_mean=static_cast(floor((axial_min+axial_max)/2.F)); int tangential_mean=static_cast(floor((tangential_min+tangential_max)/2.F)); */ - Sinogram profile_sinogram = input_projdata_sptr->get_sinogram(axial_min,0); - for (int ax = axial_min+1; ax<=axial_max; ++ax) - profile_sinogram += input_projdata_sptr->get_sinogram(ax,0); - profile_sinogram /= (axial_max-axial_min+1); + Sinogram profile_sinogram = input_projdata_sptr->get_sinogram(axial_min, 0); + for (int ax = axial_min + 1; ax <= axial_max; ++ax) + profile_sinogram += input_projdata_sptr->get_sinogram(ax, 0); + profile_sinogram /= (axial_max - axial_min + 1); // along tangential direction { - const std::string name=output_profile_string+"_tang.prof"; - ofstream profile_stream(name.c_str(), ios::out); //output file // - if(!profile_stream) - cerr << "Cannot open " << name << endl ; + const std::string name = output_profile_string + "_tang.prof"; + ofstream profile_stream(name.c_str(), ios::out); // output file // + if (!profile_stream) + cerr << "Cannot open " << name << endl; else - // " X-axis"<< - { - profile_stream << " s-Value (mm)" << "\t" << "Value" << endl ; - Array<1,float> prof = profile_sinogram[view_min]; - for (int view_num=view_min+1 ; view_num<= view_max ; ++view_num) - prof +=profile_sinogram[view_num]; - prof /= (view_max-view_min+1); - for (int tang=projdata_info_ptr->get_min_tangential_pos_num() ; - tang<=projdata_info_ptr->get_max_tangential_pos_num() ; ++tang) - { - Bin bin(0,view_min,axial_min,tang,0); - profile_stream << std::setw(9) << projdata_info_ptr->get_s(bin) << "\t" - << std::setw(7) << prof[tang] << endl ; - } - profile_stream.close(); + // " X-axis"<< + { + profile_stream << " s-Value (mm)" + << "\t" + << "Value" << endl; + Array<1, float> prof = profile_sinogram[view_min]; + for (int view_num = view_min + 1; view_num <= view_max; ++view_num) + prof += profile_sinogram[view_num]; + prof /= (view_max - view_min + 1); + for (int tang = projdata_info_ptr->get_min_tangential_pos_num(); tang <= projdata_info_ptr->get_max_tangential_pos_num(); + ++tang) { + Bin bin(0, view_min, axial_min, tang, 0); + profile_stream << std::setw(9) << projdata_info_ptr->get_s(bin) << "\t" << std::setw(7) << prof[tang] << endl; } + profile_stream.close(); + } } // along view direction { - const std::string name=output_profile_string+"_view.prof"; - ofstream profile_stream(name.c_str(), ios::out); //output file // - if(!profile_stream) - cerr << "Cannot open " << name << endl ; + const std::string name = output_profile_string + "_view.prof"; + ofstream profile_stream(name.c_str(), ios::out); // output file // + if (!profile_stream) + cerr << "Cannot open " << name << endl; else - // " X-axis"<< - { - profile_stream << " phi (radians)" << "\t" << "Value" << endl ; - for (int view_num=projdata_info_ptr->get_min_view_num() ; - view_num<= projdata_info_ptr->get_max_view_num(); - ++view_num) - { - float value=0; - for (int tang=tangential_min ; tang<= tangential_max ; ++tang) - value += profile_sinogram[view_num][tang]; - value /= tangential_max-tangential_min+1; - Bin bin(0,view_num,axial_min,tangential_min,0); - profile_stream << std::setw(9) << projdata_info_ptr->get_phi(bin) << "\t" - << std::setw(7) << value << endl ; - } - profile_stream.close(); + // " X-axis"<< + { + profile_stream << " phi (radians)" + << "\t" + << "Value" << endl; + for (int view_num = projdata_info_ptr->get_min_view_num(); view_num <= projdata_info_ptr->get_max_view_num(); ++view_num) { + float value = 0; + for (int tang = tangential_min; tang <= tangential_max; ++tang) + value += profile_sinogram[view_num][tang]; + value /= tangential_max - tangential_min + 1; + Bin bin(0, view_num, axial_min, tangential_min, 0); + profile_stream << std::setw(9) << projdata_info_ptr->get_phi(bin) << "\t" << std::setw(7) << value << endl; } + profile_stream.close(); + } } return EXIT_SUCCESS; } - diff --git a/src/experimental/utilities/list_TAC_ROI_values.cxx b/src/experimental/utilities/list_TAC_ROI_values.cxx index 4569f9c61f..940411d268 100644 --- a/src/experimental/utilities/list_TAC_ROI_values.cxx +++ b/src/experimental/utilities/list_TAC_ROI_values.cxx @@ -25,7 +25,7 @@ \author Charalampos Tsoumpas \par Usage: - \code + \code list_TAC_ROI_values [--CV] output_filename data_filename [ ROI_filename.par ] \endcode \param output_filename a text file sorted in list form of: | Frame_num | Start Time | End Time | Mean | StdDev | CV | @@ -59,8 +59,8 @@ End:= \endverbatim - \todo Add the --V option to include the volume information for the sample region. - \todo Merge it with the list_ROI_values.cxx utility. + \todo Add the --V option to include the volume information for the sample region. + \todo Merge it with the list_ROI_values.cxx utility. */ #include "stir/utilities.h" @@ -82,100 +82,83 @@ using std::endl; using std::ofstream; #endif - START_NAMESPACE_STIR -//TODO repetition of postfilter.cxx to be able to use its .par file -class ROIValuesParameters : public KeyParser -{ +// TODO repetition of postfilter.cxx to be able to use its .par file +class ROIValuesParameters : public KeyParser { public: ROIValuesParameters(); virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - std::vector > shape_ptrs; + std::vector> shape_ptrs; std::vector shape_names; CartesianCoordinate3D num_samples; - shared_ptr > > filter_ptr; + shared_ptr>> filter_ptr; + private: shared_ptr current_shape_sptr; string current_shape_name; void increment_current_shape_num(); - - }; -ROIValuesParameters::ROIValuesParameters() -{ +ROIValuesParameters::ROIValuesParameters() { set_defaults(); initialise_keymap(); } -void ROIValuesParameters:: -increment_current_shape_num() -{ - if (!is_null_ptr( current_shape_sptr)) - { - shape_ptrs.push_back(current_shape_sptr); - shape_names.push_back(current_shape_name); - current_shape_sptr = 0; - current_shape_name = ""; - } +void +ROIValuesParameters::increment_current_shape_num() { + if (!is_null_ptr(current_shape_sptr)) { + shape_ptrs.push_back(current_shape_sptr); + shape_names.push_back(current_shape_name); + current_shape_sptr = 0; + current_shape_name = ""; + } } -void -ROIValuesParameters:: -set_defaults() -{ +void +ROIValuesParameters::set_defaults() { shape_ptrs.resize(0); shape_names.resize(0); filter_ptr = 0; current_shape_sptr = 0; current_shape_name = ""; - num_samples = CartesianCoordinate3D(1,1,1); + num_samples = CartesianCoordinate3D(1, 1, 1); } -void -ROIValuesParameters:: -initialise_keymap() -{ +void +ROIValuesParameters::initialise_keymap() { add_start_key("ROIValues Parameters"); add_key("ROI name", ¤t_shape_name); add_parsing_key("ROI Shape type", ¤t_shape_sptr); - add_key("next shape", KeyArgument::NONE, - (KeywordProcessor)&ROIValuesParameters::increment_current_shape_num); + add_key("next shape", KeyArgument::NONE, (KeywordProcessor)&ROIValuesParameters::increment_current_shape_num); add_key("number of samples to take for ROI template-z", &num_samples.z()); add_key("number of samples to take for ROI template-y", &num_samples.y()); add_key("number of samples to take for ROI template-x", &num_samples.x()); add_parsing_key("Image Filter type", &filter_ptr); - add_stop_key("END"); + add_stop_key("END"); } bool -ROIValuesParameters:: -post_processing() -{ +ROIValuesParameters::post_processing() { assert(shape_names.size() == shape_ptrs.size()); - if (!is_null_ptr( current_shape_sptr)) - { - increment_current_shape_num(); - } - if (num_samples.z()<=0) - { - warning("number of samples to take in z-direction should be strictly positive\n"); - return true; - } - if (num_samples.y()<=0) - { - warning("number of samples to take in y-direction should be strictly positive\n"); - return true; - } - if (num_samples.x()<=0) - { - warning("number of samples to take in x-direction should be strictly positive\n"); - return true; - } + if (!is_null_ptr(current_shape_sptr)) { + increment_current_shape_num(); + } + if (num_samples.z() <= 0) { + warning("number of samples to take in z-direction should be strictly positive\n"); + return true; + } + if (num_samples.y() <= 0) { + warning("number of samples to take in y-direction should be strictly positive\n"); + return true; + } + if (num_samples.x() <= 0) { + warning("number of samples to take in x-direction should be strictly positive\n"); + return true; + } return false; } @@ -184,112 +167,94 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR int -main(int argc, char *argv[]) -{ - bool do_CV=false; - bool do_V=false; - const char * const progname = argv[0]; - - if (argc>1 && strcmp(argv[1],"--CV")==0) - { - do_CV=true; - --argc; ++argv; - } - if (argc>1 && strcmp(argv[1],"--V")==0) - { - do_V=true; - --argc; ++argv; - if(strcmp(argv[1],"--CV")==0) - { - do_CV=true; - --argc;++argv; - } +main(int argc, char* argv[]) { + bool do_CV = false; + bool do_V = false; + const char* const progname = argv[0]; + + if (argc > 1 && strcmp(argv[1], "--CV") == 0) { + do_CV = true; + --argc; + ++argv; + } + if (argc > 1 && strcmp(argv[1], "--V") == 0) { + do_V = true; + --argc; + ++argv; + if (strcmp(argv[1], "--CV") == 0) { + do_CV = true; + --argc; + ++argv; } - if(argc<=2 || argc>8) - { - cerr<<"\nUsage: " << progname << " \\\n" - << "\t[--CV] [--V] output_filename data_filename [ ROI_filename.par ] start_frame_num end_frame_num \n"; + } + if (argc <= 2 || argc > 8) { + cerr << "\nUsage: " << progname << " \\\n" + << "\t[--CV] [--V] output_filename data_filename [ ROI_filename.par ] start_frame_num end_frame_num \n"; cerr << "Normally, only mean and stddev are listed.\n" - << "Use the option --CV to output the Coefficient of Variation as well.\n" - << "Use the option --V to output the Total Volume, as well.\n"; + << "Use the option --CV to output the Coefficient of Variation as well.\n" + << "Use the option --V to output the Total Volume, as well.\n"; cerr << "Frame number start from start_frame_num and ends to end_frame_num\n"; cerr << "When ROI_filename.par is not given, the user will be asked for the parameters.\n" - "Use this to see what a .par file should look like.\n."< dyn_image_sptr= - DynamicDiscretisedDensity::read_from_file(input_file); - const DynamicDiscretisedDensity & dyn_image = *dyn_image_sptr; - - const unsigned int num_frames=(dyn_image.get_time_frame_definitions()).get_num_frames(); - const unsigned int start_frame_num= argc>=5 ? atoi(argv[4]) : 1 ; - const unsigned int end_frame_num= argc>=6 ? atoi(argv[5]) : num_frames ; + + const shared_ptr dyn_image_sptr = DynamicDiscretisedDensity::read_from_file(input_file); + const DynamicDiscretisedDensity& dyn_image = *dyn_image_sptr; + + const unsigned int num_frames = (dyn_image.get_time_frame_definitions()).get_num_frames(); + const unsigned int start_frame_num = argc >= 5 ? atoi(argv[4]) : 1; + const unsigned int end_frame_num = argc >= 6 ? atoi(argv[5]) : num_frames; ROIValuesParameters parameters; - if (argc<4) + if (argc < 4) parameters.ask_parameters(); - else - { - if (parameters.parse(argv[3]) == false) - exit(EXIT_FAILURE); - } + else { + if (parameters.parse(argv[3]) == false) + exit(EXIT_FAILURE); + } cerr << "Parameters used (aside from names and ROIs):\n\n" << parameters.parameter_info() << endl; - + /* This needs a review if (parameters.filter_ptr!=0) for (unsigned int frame_num;frame_num<=num_frames;frame_num++) - parameters.filter_ptr->apply(dyn_image[frame_num]); + parameters.filter_ptr->apply(dyn_image[frame_num]); */ out << input_file << '\n'; - out << std::setw(15) << "ROI " - << std::setw(10) << "Frame_num " - << std::setw(15) << "Start Time " - << std::setw(15) << "End Time " - << std::setw(15) << "Mean " - << std::setw(15) << "Stddev "; + out << std::setw(15) << "ROI " << std::setw(10) << "Frame_num " << std::setw(15) << "Start Time " << std::setw(15) + << "End Time " << std::setw(15) << "Mean " << std::setw(15) << "Stddev "; if (do_CV) out << std::setw(15) << "CV"; if (do_V) out << std::setw(15) << "Volume"; - out <<'\n'; - + out << '\n'; + { - std::vector >::const_iterator current_shape_iter = - parameters.shape_ptrs.begin(); - std::vector::const_iterator current_name_iter = - parameters.shape_names.begin(); - for (; - current_shape_iter != parameters.shape_ptrs.end(); - ++current_shape_iter, ++current_name_iter) - { - for (unsigned int frame_num=start_frame_num;frame_num<=end_frame_num;frame_num++) - { - const float frame_start_time=(dyn_image.get_time_frame_definitions()).get_start_time(frame_num); - const float frame_end_time=(dyn_image.get_time_frame_definitions()).get_end_time(frame_num); - - ROIValues values; - values=compute_total_ROI_values(dyn_image[frame_num], **current_shape_iter, parameters.num_samples); - out << std::setw(15) << *current_name_iter - << std::setw(10) << frame_num - << std::setw(15) << frame_start_time - << std::setw(15) << frame_end_time - << std::setw(15) << values.get_mean() - << std::setw(15) << values.get_stddev(); - if (do_CV) - out << std::setw(15) << values.get_CV(); - if (do_V) - out << std::setw(15) << values.get_roi_volume(); - out <<'\n'; - } - + std::vector>::const_iterator current_shape_iter = parameters.shape_ptrs.begin(); + std::vector::const_iterator current_name_iter = parameters.shape_names.begin(); + for (; current_shape_iter != parameters.shape_ptrs.end(); ++current_shape_iter, ++current_name_iter) { + for (unsigned int frame_num = start_frame_num; frame_num <= end_frame_num; frame_num++) { + const float frame_start_time = (dyn_image.get_time_frame_definitions()).get_start_time(frame_num); + const float frame_end_time = (dyn_image.get_time_frame_definitions()).get_end_time(frame_num); + + ROIValues values; + values = compute_total_ROI_values(dyn_image[frame_num], **current_shape_iter, parameters.num_samples); + out << std::setw(15) << *current_name_iter << std::setw(10) << frame_num << std::setw(15) << frame_start_time + << std::setw(15) << frame_end_time << std::setw(15) << values.get_mean() << std::setw(15) << values.get_stddev(); + if (do_CV) + out << std::setw(15) << values.get_CV(); + if (do_V) + out << std::setw(15) << values.get_roi_volume(); + out << '\n'; + } + #if 0 for (VectorWithOffset::const_iterator iter = values.begin(); iter != values.end(); @@ -298,7 +263,7 @@ main(int argc, char *argv[]) std::cout << iter->report(); } #endif - } + } } return EXIT_SUCCESS; diff --git a/src/experimental/utilities/make_cylinder.cxx b/src/experimental/utilities/make_cylinder.cxx index b9902a1d11..ac07a16452 100644 --- a/src/experimental/utilities/make_cylinder.cxx +++ b/src/experimental/utilities/make_cylinder.cxx @@ -16,60 +16,50 @@ using std::cerr; using std::endl; #endif - USING_NAMESPACE_STIR -int -main(int argc, char **argv) -{ - +int +main(int argc, char** argv) { - if (argc!=3) - { - cerr <<"Usage: " << argv[0] << " outputfile_name template_image_filename\n"; - return (EXIT_FAILURE); - } + if (argc != 3) { + cerr << "Usage: " << argv[0] << " outputfile_name template_image_filename\n"; + return (EXIT_FAILURE); + } char* file_name = argv[1]; - + #if 1 - shared_ptr > template_density_ptr = - DiscretisedDensity<3,float>::read_from_file(argv[2]); + shared_ptr> template_density_ptr = DiscretisedDensity<3, float>::read_from_file(argv[2]); - VoxelsOnCartesianGrid * vox_template_image_ptr = - dynamic_cast *>(template_density_ptr.get()); + VoxelsOnCartesianGrid* vox_template_image_ptr = dynamic_cast*>(template_density_ptr.get()); VoxelsOnCartesianGrid& image = *vox_template_image_ptr; image.fill(0); #else - float voxel_z= ask_num("Voxel size in z ",0.,5.,1.6); - float voxel_y= ask_num("Voxel sixe in y ",0.,5.,0.976562); - float voxel_x= ask_num("Voxel size in x ",0.,5.,0.976562); - + float voxel_z = ask_num("Voxel size in z ", 0., 5., 1.6); + float voxel_y = ask_num("Voxel sixe in y ", 0., 5., 0.976562); + float voxel_x = ask_num("Voxel size in x ", 0., 5., 0.976562); - int min_plane= ask_num("Min axial position ",0,1000,1); - int max_plane= ask_num("Max axial position ",0,1000,114); - int min_y_dir= ask_num("Min y dir ",-300,300,-128); - int max_y_dir= ask_num("Max y dir ",-300,300,128); - int min_x_dir= ask_num("Min x dir ",-300,300,-128); - int max_x_dir= ask_num("Max x dir ",-300,300,128); + int min_plane = ask_num("Min axial position ", 0, 1000, 1); + int max_plane = ask_num("Max axial position ", 0, 1000, 114); + int min_y_dir = ask_num("Min y dir ", -300, 300, -128); + int max_y_dir = ask_num("Max y dir ", -300, 300, 128); + int min_x_dir = ask_num("Min x dir ", -300, 300, -128); + int max_x_dir = ask_num("Max x dir ", -300, 300, 128); /* int orig_z= ask_num("orig_z",min_plane,max_plane,(min_plane+max_plane)/2); int orig_y= ask_num("orig_y",min_y_dir,max_y_dir,(min_y_dir+max_y_dir)/2); int orig_x= ask_num("orig_x",min_x_dir,max_x_dir,(min_x_dir+max_x_dir)/2); */ - - CartesianCoordinate3D origin(0,0,0); - CartesianCoordinate3D voxel_size(voxel_z,voxel_y,voxel_x); + CartesianCoordinate3D origin(0, 0, 0); + CartesianCoordinate3D voxel_size(voxel_z, voxel_y, voxel_x); - VoxelsOnCartesianGrid image(IndexRange3D(min_plane,max_plane, - min_y_dir,max_y_dir, - min_x_dir,max_x_dir), - origin,voxel_size); + VoxelsOnCartesianGrid image(IndexRange3D(min_plane, max_plane, min_y_dir, max_y_dir, min_x_dir, max_x_dir), origin, + voxel_size); #endif @@ -77,53 +67,42 @@ main(int argc, char **argv) const float radius = ask_num("Radius (in mm)", 0.F, 500.F, 100.F); const float length = ask_num("Length (in mm)", 0.F, 1000.F, 1000.F); - const float velocity_x = ask_num("Velocity of x in z",-1000.F,1000.F,0.F); - const float velocity_y = ask_num("Velocity of y in z",-1000.F,1000.F,0.F); + const float velocity_x = ask_num("Velocity of x in z", -1000.F, 1000.F, 0.F); + const float velocity_y = ask_num("Velocity of y in z", -1000.F, 1000.F, 0.F); const float velocity_z = 1.F; - CartesianCoordinate3D dir_z(1.F,velocity_y, velocity_x); + CartesianCoordinate3D dir_z(1.F, velocity_y, velocity_x); dir_z /= norm(dir_z); - CartesianCoordinate3D dir_y(-velocity_y, velocity_z,0.F); + CartesianCoordinate3D dir_y(-velocity_y, velocity_z, 0.F); dir_y /= norm(dir_y); - CartesianCoordinate3D dir_x(-velocity_x*velocity_z, - -velocity_x*velocity_y, - square(velocity_y)+square(velocity_z) - ); + CartesianCoordinate3D dir_x(-velocity_x * velocity_z, -velocity_x * velocity_y, square(velocity_y) + square(velocity_z)); dir_x /= norm(dir_x); // std::cerr<< "dirx.diry: " << inner_product(dir_x,dir_y) << "\n"; - assert(fabs(inner_product(dir_x,dir_y))<1.E-4); - assert(fabs(inner_product(dir_x,dir_z))<1.E-4); - assert(fabs(inner_product(dir_y,dir_z))<1.E-4); - assert(fabs(norm(dir_x)-1)<1.E-4); - assert(fabs(norm(dir_y)-1)<1.E-4); - assert(fabs(norm(dir_z)-1)<1.E-4); - - const float shift_x = ask_num("Shift of x in z (in mm)",-1000.F,1000.F,0.F); - const float shift_y = ask_num("Shift of y in z (in mm)",-1000.F,1000.F,0.F); - - const float centre_z = image.get_length()*image.get_voxel_size().z()/2; - - const float origin_z= ask_num("z of centre of cylinder (w.r.t.z of centre of image)", - -centre_z, centre_z, 0.F); - - const CartesianCoordinate3D - cyl_origin(origin_z + centre_z, - shift_y + origin_z*velocity_y, - shift_x + origin_z*velocity_x); - - - EllipsoidalCylinder cylinder(length, radius, radius, - cyl_origin, - dir_x, dir_y, dir_z); - - const int num_samples = ask_num("Number of samples",1,10,5); - const float value = ask_num("Value for cylinder",0.F,10000000.F,1.F); - const CartesianCoordinate3D num_samples3D(num_samples,num_samples,num_samples); + assert(fabs(inner_product(dir_x, dir_y)) < 1.E-4); + assert(fabs(inner_product(dir_x, dir_z)) < 1.E-4); + assert(fabs(inner_product(dir_y, dir_z)) < 1.E-4); + assert(fabs(norm(dir_x) - 1) < 1.E-4); + assert(fabs(norm(dir_y) - 1) < 1.E-4); + assert(fabs(norm(dir_z) - 1) < 1.E-4); + + const float shift_x = ask_num("Shift of x in z (in mm)", -1000.F, 1000.F, 0.F); + const float shift_y = ask_num("Shift of y in z (in mm)", -1000.F, 1000.F, 0.F); + + const float centre_z = image.get_length() * image.get_voxel_size().z() / 2; + + const float origin_z = ask_num("z of centre of cylinder (w.r.t.z of centre of image)", -centre_z, centre_z, 0.F); + + const CartesianCoordinate3D cyl_origin(origin_z + centre_z, shift_y + origin_z * velocity_y, + shift_x + origin_z * velocity_x); + + EllipsoidalCylinder cylinder(length, radius, radius, cyl_origin, dir_x, dir_y, dir_z); + + const int num_samples = ask_num("Number of samples", 1, 10, 5); + const float value = ask_num("Value for cylinder", 0.F, 10000000.F, 1.F); + const CartesianCoordinate3D num_samples3D(num_samples, num_samples, num_samples); cylinder.construct_volume(image, num_samples3D); image *= value; write_basic_interfile(file_name, image); return EXIT_SUCCESS; - - } diff --git a/src/experimental/utilities/make_grid_image.cxx b/src/experimental/utilities/make_grid_image.cxx index aa9fe8fea7..51fa42325f 100644 --- a/src/experimental/utilities/make_grid_image.cxx +++ b/src/experimental/utilities/make_grid_image.cxx @@ -5,9 +5,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities - + \brief This program creates a simple grid image \author Kris Thielemans */ @@ -22,63 +22,52 @@ using std::cerr; USING_NAMESPACE_STIR - -int main(int argc, char **argv) -{ - if(argc<3 || argc>7) { - cerr<<"Usage: " << argv[0] << " [xy-spacing [xy-size][z-spacing [z-size] ] ] ]\n" - << "xy-spacing defaults to 2, xy-size to 1\n" - << "z-spacing defaults to 1, z-size to 1\n"; +int +main(int argc, char** argv) { + if (argc < 3 || argc > 7) { + cerr << "Usage: " << argv[0] + << " [xy-spacing [xy-size][z-spacing [z-size] ] ] ]\n" + << "xy-spacing defaults to 2, xy-size to 1\n" + << "z-spacing defaults to 1, z-size to 1\n"; exit(EXIT_FAILURE); } - + // get parameters from command line - char const * const output_filename = argv[1]; - char const * const input_filename = argv[2]; - const int xy_spacing = argc>3?atoi(argv[3]):2; - const int xy_size = argc>4?atoi(argv[4]):1; - const int z_spacing = argc>5?atoi(argv[5]):1; - const int z_size = argc>6?atoi(argv[6]):1; - // read image + char const* const output_filename = argv[1]; + char const* const input_filename = argv[2]; + const int xy_spacing = argc > 3 ? atoi(argv[3]) : 2; + const int xy_size = argc > 4 ? atoi(argv[4]) : 1; + const int z_spacing = argc > 5 ? atoi(argv[5]) : 1; + const int z_size = argc > 6 ? atoi(argv[6]) : 1; + // read image - shared_ptr > density_sptr = - DiscretisedDensity<3,float>::read_from_file(input_filename); + shared_ptr> density_sptr = DiscretisedDensity<3, float>::read_from_file(input_filename); - BasicCoordinate<3,int> c; - const int min1=density_sptr->get_min_index(); - const int max1=density_sptr->get_max_index(); - for (c[1]=min1; c[1]<=max1; ++c[1]) - { - const int min2=(*density_sptr)[c[1]].get_min_index(); - const int max2=(*density_sptr)[c[1]].get_max_index(); + BasicCoordinate<3, int> c; + const int min1 = density_sptr->get_min_index(); + const int max1 = density_sptr->get_max_index(); + for (c[1] = min1; c[1] <= max1; ++c[1]) { + const int min2 = (*density_sptr)[c[1]].get_min_index(); + const int max2 = (*density_sptr)[c[1]].get_max_index(); - if (modulo(c[1],z_spacing)>z_size) - continue; // just zeroes on this plane + if (modulo(c[1], z_spacing) > z_size) + continue; // just zeroes on this plane - for (c[2]=min2; c[2]<=max2; ++c[2]) - { - const int min3=(*density_sptr)[c[1]][c[2]].get_min_index(); - const int max3=(*density_sptr)[c[1]][c[2]].get_max_index(); - for (c[3]=min3; c[3]<=max3; ++c[3]) - { - if (modulo(c[2],xy_spacing) >::default_sptr()-> - write_to_file(output_filename, *density_sptr); + Succeeded res = OutputFileFormat>::default_sptr()->write_to_file(output_filename, *density_sptr); - return res==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + return res == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } - - - - diff --git a/src/experimental/utilities/mode.cxx b/src/experimental/utilities/mode.cxx index 31b0d82a0e..5d27fa1223 100644 --- a/src/experimental/utilities/mode.cxx +++ b/src/experimental/utilities/mode.cxx @@ -16,113 +16,100 @@ #include #include - #include using namespace std; - // utility function to output an vector to a stream +// utility function to output an vector to a stream template -ostream& -operator<<(ostream& str, const vector& v) -{ - str << '{'; - for (int i=0; i0) - str << (unsigned int)v[v.size()-1]; - str << '}' << endl; - return str; +ostream& +operator<<(ostream& str, const vector& v) { + str << '{'; + for (int i = 0; i < v.size() - 1; i++) + str << (unsigned int)v[i] << ", "; + if (v.size() > 0) + str << (unsigned int)v[v.size() - 1]; + str << '}' << endl; + return str; } typedef unsigned char elemT; //! computes modes in a vector -/*! +/*! The mode of a vector is defined as the element that occurs most frequently. It is not well-defined when more than 1 element occurs with this same frequency. This routine returns a vector with all such elements. */ template -vector compute_modes(vector& v) -{ +vector +compute_modes(vector& v) { - //sort the elements + // sort the elements sort(v.begin(), v.end()); - //cerr << v; + // cerr << v; vector current_modes; int current_mode_count = 0; - for (int i=0; i current_mode_count) - { - current_modes.clear(); - current_modes.push_back(current_elem); - current_mode_count = current_elem_count; - } - else if (current_elem_count == current_mode_count) - { - current_modes.push_back(current_elem); - } } + // store mode + if (current_elem_count > current_mode_count) { + current_modes.clear(); + current_modes.push_back(current_elem); + current_mode_count = current_elem_count; + } else if (current_elem_count == current_mode_count) { + current_modes.push_back(current_elem); + } + } - //cerr << "modes " < input_files(argc); - + --argc; + ++argv; + vector input_files(argc); // open input files - while (argc>0) - { + while (argc > 0) { --argc; - input_files[argc] = new ifstream(*argv, ios::in | ios::binary); - if (!input_files[argc]) - { + input_files[argc] = new ifstream(*argv, ios::in | ios::binary); + if (!input_files[argc]) { cerr << "Error opening input file " << *argv << endl; return EXIT_FAILURE; } - ++argv; + ++argv; } vector v(input_files.size()); @@ -131,64 +118,53 @@ int main(int argc, char **argv) bool any_error = false; streamsize elem_count = 0; streamsize multiple_count = 0; - while(!all_done) - { - // read next elements from files - for (int i=0; iread(&v[i], sizeof(v[i])); - // check if reading went ok - if (!*(input_files[i])) - { - // check if it was EOF for the first file. if not, issue warning. - if (i!=0 || !input_files[0]->eof()) - { - cerr << "Error reading file " << i+1 <<"\n.Exiting.\n"; - any_error = true; - } - // In any case, we break out of the loop - all_done = true; - break; - } - } - if (!all_done) - { - vector modes = compute_modes(v); - if (modes.size() != 1) - { - cerr << "\nWarning: multiple modes "<< modes <<" at elem " << elem_count; - ++multiple_count; - } - // write first mode to file - output.write(&modes[modes.size()-1], sizeof(modes[0])); - // check if writing went ok - if (!output) - { - cerr << "\nError writing to output at elem " << elem_count; - all_done = true; - any_error = true; - } - else - ++elem_count; - } + while (!all_done) { + // read next elements from files + for (int i = 0; i < input_files.size(); ++i) { + input_files[i]->read(&v[i], sizeof(v[i])); + // check if reading went ok + if (!*(input_files[i])) { + // check if it was EOF for the first file. if not, issue warning. + if (i != 0 || !input_files[0]->eof()) { + cerr << "Error reading file " << i + 1 << "\n.Exiting.\n"; + any_error = true; + } + // In any case, we break out of the loop + all_done = true; + break; + } } + if (!all_done) { + vector modes = compute_modes(v); + if (modes.size() != 1) { + cerr << "\nWarning: multiple modes " << modes << " at elem " << elem_count; + ++multiple_count; + } + // write first mode to file + output.write(&modes[modes.size() - 1], sizeof(modes[0])); + // check if writing went ok + if (!output) { + cerr << "\nError writing to output at elem " << elem_count; + all_done = true; + any_error = true; + } else + ++elem_count; + } + } cerr << "Wrote " << elem_count << " elements to file\n"; cerr << multiple_count << "multiples\n"; // close input files by deleting the pointers - for (int i=0; i v(argc); - while (argc>0) - { + while (argc > 0) { --argc; istrstream s(*argv); s >> (v[argc]); @@ -201,6 +177,4 @@ int main(int argc, char **argv) return EXIT_SUCCESS; #endif - } - diff --git a/src/experimental/utilities/normalizedbckproj.cxx b/src/experimental/utilities/normalizedbckproj.cxx index 3d692daac3..cd92e1a1c3 100644 --- a/src/experimental/utilities/normalizedbckproj.cxx +++ b/src/experimental/utilities/normalizedbckproj.cxx @@ -3,27 +3,26 @@ /*! \file - \ingroup + \ingroup \brief This programm was based on bck_project originnal code with the difference - that here we normalize the final value of a single pixel with a sum of all values + that here we normalize the final value of a single pixel with a sum of all values in the corresponding LOR. - BackProjectorByBinUsingSquareProjMatrixByBin was used which is modification of + BackProjectorByBinUsingSquareProjMatrixByBin was used which is modification of the BackProjectorByBinUsingProjMatrixByBin with the difference in the sum where one has out(b)= sqrt (sum square(p(d,b))* in(d) / sum square(p(d,b))) \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2012, IRSL See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.h" #include "stir/recon_buildblock/ProjMatrixByBin.h" #include "stir/IO/interfile.h" @@ -35,7 +34,6 @@ #include "stir/VoxelsOnCartesianGrid.h" #include "stir/Viewgram.h" - #include #include #include @@ -51,83 +49,58 @@ using std::cerr; using std::endl; #endif - - START_NAMESPACE_STIR void -do_segments(DiscretisedDensity<3,float>& image, - ProjData& proj_data_org, - const int start_segment_num, const int end_segment_num, - const int start_view, const int end_view, - BackProjectorByBin& back_projector, - bool fill_with_1) -{ - - shared_ptr symmetries_sptr - (back_projector.get_symmetries_used()->clone()); - - +do_segments(DiscretisedDensity<3, float>& image, ProjData& proj_data_org, const int start_segment_num, const int end_segment_num, + const int start_view, const int end_view, BackProjectorByBin& back_projector, bool fill_with_1) { + + shared_ptr symmetries_sptr(back_projector.get_symmetries_used()->clone()); + list already_processed; - + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - for (int view= start_view; view<=end_view; view++) - { - ViewSegmentNumbers vs(view, segment_num); - symmetries_sptr->find_basic_view_segment_numbers(vs); - if (find(already_processed.begin(), already_processed.end(), vs) - != already_processed.end()) - continue; - - already_processed.push_back(vs); - - cerr << "Processing view " << vs.view_num() - << " of segment " < viewgrams_empty= - proj_data_org.get_empty_related_viewgrams(vs, symmetries_sptr); + for (int view = start_view; view <= end_view; view++) { + ViewSegmentNumbers vs(view, segment_num); + symmetries_sptr->find_basic_view_segment_numbers(vs); + if (find(already_processed.begin(), already_processed.end(), vs) != already_processed.end()) + continue; - viewgrams_empty.fill(1.F); - - back_projector.back_project(image,viewgrams_empty); - } - else - { - RelatedViewgrams viewgrams = - proj_data_org.get_related_viewgrams(vs, symmetries_sptr); - - back_projector.back_project(image,viewgrams); - } // fill - } // for view_num, segment_num - -} + already_processed.push_back(vs); + cerr << "Processing view " << vs.view_num() << " of segment " << vs.segment_num() << endl; -END_NAMESPACE_STIR + if (fill_with_1) { + RelatedViewgrams viewgrams_empty = proj_data_org.get_empty_related_viewgrams(vs, symmetries_sptr); + + viewgrams_empty.fill(1.F); + back_projector.back_project(image, viewgrams_empty); + } else { + RelatedViewgrams viewgrams = proj_data_org.get_related_viewgrams(vs, symmetries_sptr); + + back_projector.back_project(image, viewgrams); + } // fill + } // for view_num, segment_num +} +END_NAMESPACE_STIR USING_NAMESPACE_STIR int -main(int argc, char *argv[]) -{ +main(int argc, char* argv[]) { shared_ptr proj_data_ptr; - + bool do_denominator; bool do_sqrt; - switch(argc) - { - case 3: - { - proj_data_ptr = ProjData::read_from_file(argv[1]); - do_denominator = ask("Do you want to normalise the result ?", true); - do_sqrt = ask("Do you want to take the sqrt ?", true); - break; - } + switch (argc) { + case 3: { + proj_data_ptr = ProjData::read_from_file(argv[1]); + do_denominator = ask("Do you want to normalise the result ?", true); + do_sqrt = ask("Do you want to take the sqrt ?", true); + break; + } /* case 2: { @@ -136,115 +109,75 @@ main(int argc, char *argv[]) shared_ptr data_info= ProjDataInfo::ask_parameters(); // create an empty ProjDataFromStream object // such that we don't have to differentiate between code later on - proj_data_ptr = - new ProjDataFromStream (data_info,static_cast(NULL)); + proj_data_ptr = + new ProjDataFromStream (data_info,static_cast(NULL)); fill = true; break; } */ - default: - { - cerr <<"Usage: " << argv[0] << "proj_data_file outputfile_name\n"; - return (EXIT_FAILURE); - } - - } + default: { + cerr << "Usage: " << argv[0] << "proj_data_file outputfile_name\n"; + return (EXIT_FAILURE); + } + } + bool projector_type = ask(" Which projector do you want to use Ray Tracing (Y) or Solid Angle (N) ", true); + const ProjDataInfo* proj_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr(); - bool projector_type = - ask ( " Which projector do you want to use Ray Tracing (Y) or Solid Angle (N) ", true) ; + VoxelsOnCartesianGrid* vox_image_ptr = new VoxelsOnCartesianGrid(*proj_data_info_ptr); + shared_ptr> image_sptr(vox_image_ptr); - - const ProjDataInfo * proj_data_info_ptr = - proj_data_ptr->get_proj_data_info_sptr(); - - VoxelsOnCartesianGrid * vox_image_ptr = - new VoxelsOnCartesianGrid(*proj_data_info_ptr); + string name; + if (projector_type) + name = "Ray Tracing"; + else + name = "Solid Angle"; - shared_ptr > image_sptr(vox_image_ptr); + shared_ptr PM(ProjMatrixByBin ::read_registered_object(0, name)); + PM->set_up(proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), image_sptr); + shared_ptr bck_projector_ptr(new BackProjectorByBinUsingSquareProjMatrixByBin(PM)); - string name ; - if ( projector_type ) - name = "Ray Tracing"; - else - name = "Solid Angle"; - - shared_ptr PM - (ProjMatrixByBin :: read_registered_object(0, name)); - - PM->set_up(proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(),image_sptr); - shared_ptr bck_projector_ptr - (new BackProjectorByBinUsingSquareProjMatrixByBin(PM)); - - - - { - const int max_segment_num = - ask_num("Maximum absolute segment number to backproject", - 0,proj_data_info_ptr->get_max_segment_num(), - proj_data_info_ptr->get_max_segment_num()); - + { + const int max_segment_num = ask_num("Maximum absolute segment number to backproject", 0, + proj_data_info_ptr->get_max_segment_num(), proj_data_info_ptr->get_max_segment_num()); image_sptr->fill(0); - + CPUTimer timer; timer.reset(); timer.start(); - - do_segments(*image_sptr, - *proj_data_ptr, - -max_segment_num, max_segment_num, - proj_data_info_ptr->get_min_view_num(), proj_data_info_ptr->get_max_view_num(), - *bck_projector_ptr, - false); - - if (do_denominator) - { - shared_ptr > denominator_ptr - (image_sptr->get_empty_discretised_density()); + + do_segments(*image_sptr, *proj_data_ptr, -max_segment_num, max_segment_num, proj_data_info_ptr->get_min_view_num(), + proj_data_info_ptr->get_max_view_num(), *bck_projector_ptr, false); + + if (do_denominator) { + shared_ptr> denominator_ptr(image_sptr->get_empty_discretised_density()); // set to non-zero value to avoid problems with division outside the FOV denominator_ptr->fill(image_sptr->find_max() * 1.E-10F); - do_segments(*denominator_ptr, - *proj_data_ptr, - -max_segment_num, max_segment_num, - proj_data_info_ptr->get_min_view_num(), proj_data_info_ptr->get_max_view_num(), - *bck_projector_ptr, - true); + do_segments(*denominator_ptr, *proj_data_ptr, -max_segment_num, max_segment_num, proj_data_info_ptr->get_min_view_num(), + proj_data_info_ptr->get_max_view_num(), *bck_projector_ptr, true); *image_sptr /= *denominator_ptr; } - if (do_sqrt) - { - //in_place_apply_function(*image_sptr, &sqrt); - for (DiscretisedDensity<3,float>::full_iterator iter = image_sptr->begin_all(); - iter != image_sptr->end_all(); - ++iter) - *iter = sqrt(*iter); + if (do_sqrt) { + // in_place_apply_function(*image_sptr, &sqrt); + for (DiscretisedDensity<3, float>::full_iterator iter = image_sptr->begin_all(); iter != image_sptr->end_all(); ++iter) + *iter = sqrt(*iter); } - timer.stop(); - cerr << timer.value() << " s CPU time"<find_min() - << ", " << image_sptr->find_max() << endl; - + cerr << timer.value() << " s CPU time" << endl; + cerr << "min and max in image " << image_sptr->find_min() << ", " << image_sptr->find_max() << endl; - { char* file = argv[2]; - - cerr <<" - Saving " << file << endl; + cerr << " - Saving " << file << endl; write_basic_interfile(file, *image_sptr); - - } - } - - return EXIT_SUCCESS; -} - + return EXIT_SUCCESS; +} diff --git a/src/experimental/utilities/precompute_denominator_SPS.cxx b/src/experimental/utilities/precompute_denominator_SPS.cxx index b82f547b82..1c42a00381 100644 --- a/src/experimental/utilities/precompute_denominator_SPS.cxx +++ b/src/experimental/utilities/precompute_denominator_SPS.cxx @@ -1,22 +1,22 @@ /* \file - \ingroup utilities + \ingroup utilities \brief precomputes denominator for SPS \author Sanida Mustafovic - - This program precomputes denominator for the SPS + + This program precomputes denominator for the SPS (separable paraboloidal surrogates) in ET. - the denominator is given by : + the denominator is given by : dj = sum Aij gamma h''(yi) where - h(l) = yi log (l) - l; h''(yi) = -1/yi; + h(l) = yi log (l) - l; h''(yi) = -1/yi; gamma = sum Aik; - + => dj = sum Aij(-i/yi) sum Aik - - if there is penalty added to it there is another term in the + + if there is penalty added to it there is another term in the denominator that includes penalty term */ @@ -39,7 +39,6 @@ #include "stir/ProjDataFromStream.h" #include "stir/SegmentByView.h" - #include #include #include @@ -55,236 +54,164 @@ using std::cerr; using std::endl; #endif - - START_NAMESPACE_STIR +void do_segments(DiscretisedDensity<3, float>& image, ProjData& proj_data_org, const int start_segment_num, + const int end_segment_num, const int start_view, const int end_view, BackProjectorByBin& back_projector, + bool fill_with_1); + void -do_segments(DiscretisedDensity<3,float>& image, - ProjData& proj_data_org, - const int start_segment_num, const int end_segment_num, - const int start_view, const int end_view, - BackProjectorByBin& back_projector, - bool fill_with_1); - - - -void -find_inverse( ProjData& proj_data_out, const ProjData& proj_data_in, - const int min_segment_num, const int max_segment_num) -{ - - float max_in_projdata =0.F; - - - for (int segment_num = min_segment_num; segment_num<= max_segment_num; - segment_num++) - { - SegmentByView segment_by_view = - proj_data_in.get_segment_by_view(segment_num); +find_inverse(ProjData& proj_data_out, const ProjData& proj_data_in, const int min_segment_num, const int max_segment_num) { + + float max_in_projdata = 0.F; + + for (int segment_num = min_segment_num; segment_num <= max_segment_num; segment_num++) { + SegmentByView segment_by_view = proj_data_in.get_segment_by_view(segment_num); const float current_max_in_projdata = segment_by_view.find_max(); - if ( current_max_in_projdata >= max_in_projdata) - max_in_projdata = current_max_in_projdata ; + if (current_max_in_projdata >= max_in_projdata) + max_in_projdata = current_max_in_projdata; else continue; } - - for (int segment_num = min_segment_num; segment_num<= max_segment_num; - segment_num++) - for ( int view_num = proj_data_in.get_min_view_num(); - view_num<=proj_data_in.get_max_view_num(); view_num++) - { - Viewgram viewgram_in = proj_data_in.get_viewgram(view_num,segment_num); - Viewgram viewgram_out = proj_data_in.get_empty_viewgram(view_num,segment_num); + + for (int segment_num = min_segment_num; segment_num <= max_segment_num; segment_num++) + for (int view_num = proj_data_in.get_min_view_num(); view_num <= proj_data_in.get_max_view_num(); view_num++) { + Viewgram viewgram_in = proj_data_in.get_viewgram(view_num, segment_num); + Viewgram viewgram_out = proj_data_in.get_empty_viewgram(view_num, segment_num); // the following const was found in the ls_cyl.hs and the same value will // be used for thresholding both kappa_0 and kappa_1. - - const float threshold = 0.000001F*max_in_projdata; - //cerr << threshold << endl; - - for (int i= viewgram_in.get_min_axial_pos_num(); i<=viewgram_in.get_max_axial_pos_num();i++) - for (int j= viewgram_in.get_min_tangential_pos_num(); j<=viewgram_in.get_max_tangential_pos_num();j++) - { - const float bin= viewgram_in[i][j]; - - if (bin >= threshold) - { - viewgram_out[i][j] = 1/bin; - } - else - { - viewgram_out[i][j] = 1/threshold; - } - - } - proj_data_out.set_viewgram(viewgram_out); + + const float threshold = 0.000001F * max_in_projdata; + // cerr << threshold << endl; + + for (int i = viewgram_in.get_min_axial_pos_num(); i <= viewgram_in.get_max_axial_pos_num(); i++) + for (int j = viewgram_in.get_min_tangential_pos_num(); j <= viewgram_in.get_max_tangential_pos_num(); j++) { + const float bin = viewgram_in[i][j]; + + if (bin >= threshold) { + viewgram_out[i][j] = 1 / bin; + } else { + viewgram_out[i][j] = 1 / threshold; + } + } + proj_data_out.set_viewgram(viewgram_out); } - } void -do_segments(DiscretisedDensity<3,float>& image, - ProjData& proj_data_org, - const int start_segment_num, const int end_segment_num, - const int start_view, const int end_view, - BackProjectorByBin& back_projector, - bool fill_with_1) -{ - - shared_ptr symmetries_sptr = - back_projector.get_symmetries_used()->clone(); - - +do_segments(DiscretisedDensity<3, float>& image, ProjData& proj_data_org, const int start_segment_num, const int end_segment_num, + const int start_view, const int end_view, BackProjectorByBin& back_projector, bool fill_with_1) { + + shared_ptr symmetries_sptr = back_projector.get_symmetries_used()->clone(); + list already_processed; - + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - for (int view= start_view; view<=end_view; view++) - { - ViewSegmentNumbers vs(view, segment_num); - symmetries_sptr->find_basic_view_segment_numbers(vs); - if (find(already_processed.begin(), already_processed.end(), vs) - != already_processed.end()) - continue; + for (int view = start_view; view <= end_view; view++) { + ViewSegmentNumbers vs(view, segment_num); + symmetries_sptr->find_basic_view_segment_numbers(vs); + if (find(already_processed.begin(), already_processed.end(), vs) != already_processed.end()) + continue; - already_processed.push_back(vs); - - cerr << "Processing view " << vs.view_num() - << " of segment " < viewgrams_empty= - proj_data_org.get_empty_related_viewgrams(vs, symmetries_sptr); - - viewgrams_empty.fill(1.F); - - back_projector.back_project(image,viewgrams_empty); - } - else - { - RelatedViewgrams viewgrams = - proj_data_org.get_related_viewgrams(vs, symmetries_sptr); - - back_projector.back_project(image,viewgrams); - } // fill - } // for view_num, segment_num - -} + already_processed.push_back(vs); + cerr << "Processing view " << vs.view_num() << " of segment " << vs.segment_num() << endl; -END_NAMESPACE_STIR + if (fill_with_1) { + RelatedViewgrams viewgrams_empty = proj_data_org.get_empty_related_viewgrams(vs, symmetries_sptr); + viewgrams_empty.fill(1.F); + back_projector.back_project(image, viewgrams_empty); + } else { + RelatedViewgrams viewgrams = proj_data_org.get_related_viewgrams(vs, symmetries_sptr); + back_projector.back_project(image, viewgrams); + } // fill + } // for view_num, segment_num +} +END_NAMESPACE_STIR USING_NAMESPACE_STIR int -main(int argc, char *argv[]) -{ +main(int argc, char* argv[]) { - if(argc<4 || argc>6) - { - cerr<< "Usage: " << argv[0] << "output_image_filename input_proj_data fwd_allones_projdata [normalisation_projdata [template_image]]\n"; + if (argc < 4 || argc > 6) { + cerr << "Usage: " << argv[0] + << "output_image_filename input_proj_data fwd_allones_projdata [normalisation_projdata [template_image]]\n"; exit(EXIT_FAILURE); } const string output_filename = argv[1]; shared_ptr proj_data_ptr = ProjData::read_from_file(argv[2]); - shared_ptr fwd_ones = ProjData::read_from_file(argv[3]); - shared_ptr norm_proj_data_ptr = - argc>=5 ? ProjData::read_from_file(argv[4]) : 0; - - const ProjDataInfo * proj_data_info_ptr = - proj_data_ptr->get_proj_data_info_sptr(); - shared_ptr > image_sptr; - if (argc >=6) - { - image_sptr = DiscretisedDensity<3,float>::read_from_file(argv[5]); - image_sptr->fill(0); - } - else - image_sptr = - new VoxelsOnCartesianGrid(*proj_data_info_ptr); - - - const int max_segment_num = - ask_num("Maximum absolute segment number to backproject", - 0,proj_data_ptr->get_max_segment_num(), - proj_data_ptr->get_max_segment_num()); - bool projector_type = - ask ( " Which back projector do you want to use Ray Tracing (Y) or Solid Angle (N) ", true) ; - string name ; - if ( projector_type ) - name = "Ray Tracing"; + shared_ptr fwd_ones = ProjData::read_from_file(argv[3]); + shared_ptr norm_proj_data_ptr = argc >= 5 ? ProjData::read_from_file(argv[4]) : 0; + + const ProjDataInfo* proj_data_info_ptr = proj_data_ptr->get_proj_data_info_sptr(); + shared_ptr> image_sptr; + if (argc >= 6) { + image_sptr = DiscretisedDensity<3, float>::read_from_file(argv[5]); + image_sptr->fill(0); + } else + image_sptr = new VoxelsOnCartesianGrid(*proj_data_info_ptr); + + const int max_segment_num = ask_num("Maximum absolute segment number to backproject", 0, proj_data_ptr->get_max_segment_num(), + proj_data_ptr->get_max_segment_num()); + bool projector_type = ask(" Which back projector do you want to use Ray Tracing (Y) or Solid Angle (N) ", true); + string name; + if (projector_type) + name = "Ray Tracing"; else - name = "Solid Angle"; - shared_ptr PM = - ProjMatrixByBin :: read_registered_object(0, name); + name = "Solid Angle"; + shared_ptr PM = ProjMatrixByBin ::read_registered_object(0, name); - // find the inverse - shared_ptr proj_data_inv_ptr; + shared_ptr proj_data_inv_ptr; { - shared_ptr< ProjDataInfo > data_info = proj_data_info_ptr->clone(); + shared_ptr data_info = proj_data_info_ptr->clone(); data_info->reduce_segment_range(-max_segment_num, max_segment_num); - + const string output_file_name = "inverse.s"; - proj_data_inv_ptr = - new ProjDataInterfile(data_info, output_file_name, ios::trunc|ios::out|ios::in|ios::binary); - - find_inverse(*proj_data_inv_ptr,*proj_data_ptr, - -max_segment_num, max_segment_num); - - for (int segment_num = -max_segment_num; segment_num<= max_segment_num;segment_num++) - { - SegmentByView segmnet_0 = proj_data_inv_ptr->get_segment_by_view(segment_num); - SegmentByView segmnet_1 = fwd_ones->get_segment_by_view(segment_num); - - segmnet_0 *=segmnet_1; - - if (!is_null_ptr(norm_proj_data_ptr)) - { - segmnet_1 = norm_proj_data_ptr->get_segment_by_view(segment_num); - segmnet_0 /=segmnet_1; - segmnet_0 /=segmnet_1; - } - if (!(proj_data_inv_ptr->set_segment(segmnet_0) == Succeeded::yes)) - warning("Error set_segment %d\n", segment_num); + proj_data_inv_ptr = new ProjDataInterfile(data_info, output_file_name, ios::trunc | ios::out | ios::in | ios::binary); + + find_inverse(*proj_data_inv_ptr, *proj_data_ptr, -max_segment_num, max_segment_num); + + for (int segment_num = -max_segment_num; segment_num <= max_segment_num; segment_num++) { + SegmentByView segmnet_0 = proj_data_inv_ptr->get_segment_by_view(segment_num); + SegmentByView segmnet_1 = fwd_ones->get_segment_by_view(segment_num); + + segmnet_0 *= segmnet_1; + + if (!is_null_ptr(norm_proj_data_ptr)) { + segmnet_1 = norm_proj_data_ptr->get_segment_by_view(segment_num); + segmnet_0 /= segmnet_1; + segmnet_0 /= segmnet_1; } + if (!(proj_data_inv_ptr->set_segment(segmnet_0) == Succeeded::yes)) + warning("Error set_segment %d\n", segment_num); + } } // end of inverse - - - PM->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(),image_sptr); - shared_ptr bck_projector_ptr = - new BackProjectorByBinUsingProjMatrixByBin(PM); - - + PM->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), image_sptr); + shared_ptr bck_projector_ptr = new BackProjectorByBinUsingProjMatrixByBin(PM); + CPUTimer timer; timer.reset(); timer.start(); - - do_segments(*image_sptr, - *proj_data_inv_ptr, - -max_segment_num, max_segment_num, - proj_data_info_ptr->get_min_view_num(), proj_data_info_ptr->get_max_view_num(), - *bck_projector_ptr, - false); - + + do_segments(*image_sptr, *proj_data_inv_ptr, -max_segment_num, max_segment_num, proj_data_info_ptr->get_min_view_num(), + proj_data_info_ptr->get_max_view_num(), *bck_projector_ptr, false); + timer.stop(); - cerr << timer.value() << " s CPU time"<find_min() - << ", " << image_sptr->find_max() << endl; - + cerr << timer.value() << " s CPU time" << endl; + cerr << "min and max in image " << image_sptr->find_min() << ", " << image_sptr->find_max() << endl; - cerr <<" - Saving " << output_filename << endl; + cerr << " - Saving " << output_filename << endl; write_basic_interfile(output_filename, *image_sptr); - + return EXIT_SUCCESS; } - diff --git a/src/experimental/utilities/prepare_projdata.cxx b/src/experimental/utilities/prepare_projdata.cxx index 74afe46898..47fd676458 100644 --- a/src/experimental/utilities/prepare_projdata.cxx +++ b/src/experimental/utilities/prepare_projdata.cxx @@ -8,7 +8,7 @@ \file \ingroup utilities - \brief A utility preparing some projection data for further processing with + \brief A utility preparing some projection data for further processing with iterative reconstructions. See stir::PrepareProjData. \author Kris Thielemans @@ -28,7 +28,7 @@ #include "stir/recon_buildblock/TrivialBinNormalisation.h" #include -#include +#include #include #include @@ -43,9 +43,6 @@ using std::string; START_NAMESPACE_STIR - - - /*! \ingroup recon_buildblock \brief A preliminary class to prepare files for iterative reconstruction @@ -59,8 +56,8 @@ START_NAMESPACE_STIR Prepare projdata Parameters:= ; next defaults to using all segments ; maximum absolute segment number to process:= ... - - ;;;;;;;;; input, some is optional depending on what you ask for as output + + ;;;;;;;;; input, some is optional depending on what you ask for as output prompts_projdata_filename:= ... trues_projdata_filename:= ... precorrected_projdata_filename:= ... @@ -85,15 +82,13 @@ START_NAMESPACE_STIR Shifted_Poisson_denominator_projdata_filename:= ... ; name for additive term in denominator of a prompts reconstruction prompts_denominator_projdata_filename:= ... - + END Prepare projdata Parameters:= \endverbatim */ -class PrepareProjData : public ParsingObject -{ +class PrepareProjData : public ParsingObject { public: - - PrepareProjData(const char * const par_filename); + PrepareProjData(const char* const par_filename); void doit(); private: @@ -103,18 +98,17 @@ class PrepareProjData : public ParsingObject shared_ptr precorrected_projdata_ptr; shared_ptr randoms_projdata_ptr; shared_ptr normalisation_ptr; - - + shared_ptr normatten_projdata_ptr; shared_ptr scatter_projdata_ptr; shared_ptr Shifted_Poisson_numerator_projdata_ptr; shared_ptr Shifted_Poisson_denominator_projdata_ptr; shared_ptr prompts_denominator_projdata_ptr; TimeFrameDefinitions frame_defs; - - + int max_segment_num_to_process; int current_frame_num; + private: bool can_make_trues; // if prompts and randoms are given bool do_Shifted_Poisson; @@ -122,7 +116,7 @@ class PrepareProjData : public ParsingObject bool do_scatter; // if we need to find scatter by subtracting precorrected data from the trues // used to create new viewgrams etc - shared_ptr output_data_info_ptr; + shared_ptr output_data_info_ptr; shared_ptr template_projdata_ptr; virtual void set_defaults(); @@ -132,20 +126,17 @@ class PrepareProjData : public ParsingObject string trues_projdata_filename; string precorrected_projdata_filename; string randoms_projdata_filename; - + string normatten_projdata_filename; string scatter_projdata_filename; string Shifted_Poisson_numerator_projdata_filename; string Shifted_Poisson_denominator_projdata_filename; string prompts_denominator_projdata_filename; string frame_definition_filename; - }; -void -PrepareProjData:: -set_defaults() -{ +void +PrepareProjData::set_defaults() { prompts_projdata_ptr.reset(); trues_projdata_ptr.reset(); precorrected_projdata_ptr.reset(); @@ -163,13 +154,11 @@ set_defaults() Shifted_Poisson_numerator_projdata_filename = ""; Shifted_Poisson_denominator_projdata_filename = ""; - current_frame_num = 1; + current_frame_num = 1; } -void -PrepareProjData:: -initialise_keymap() -{ +void +PrepareProjData::initialise_keymap() { parser.add_start_key("Prepare projdata Parameters"); parser.add_parsing_key("Bin Normalisation type", &normalisation_ptr); parser.add_key("prompts_projdata_filename", &prompts_projdata_filename); @@ -177,100 +166,83 @@ initialise_keymap() parser.add_key("precorrected_projdata_filename", &precorrected_projdata_filename); parser.add_key("randoms_projdata_filename", &randoms_projdata_filename); - parser.add_key("time frame definition filename", &frame_definition_filename); - parser.add_key("time frame number", ¤t_frame_num); - - + parser.add_key("time frame definition filename", &frame_definition_filename); + parser.add_key("time frame number", ¤t_frame_num); + parser.add_key("normatten_projdata_filename", &normatten_projdata_filename); parser.add_key("scatter_projdata_filename", &scatter_projdata_filename); parser.add_key("Shifted_Poisson_numerator_projdata_filename", &Shifted_Poisson_numerator_projdata_filename); parser.add_key("Shifted_Poisson_denominator_projdata_filename", &Shifted_Poisson_denominator_projdata_filename); parser.add_key("prompts_denominator_projdata_filename", &prompts_denominator_projdata_filename); parser.add_key("maximum absolute segment number to process", &max_segment_num_to_process); - + parser.add_stop_key("END Prepare projdata Parameters"); } -PrepareProjData:: -PrepareProjData(const char * const par_filename) -{ +PrepareProjData::PrepareProjData(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - parse(par_filename) ; + if (par_filename != 0) + parse(par_filename); else ask_parameters(); - if (is_null_ptr(normalisation_ptr)) - { - warning("Invalid normalisation type\n"); - exit(EXIT_FAILURE); - } - can_make_trues = - prompts_projdata_filename.size()!=0 && - randoms_projdata_filename.size()!=0; + if (is_null_ptr(normalisation_ptr)) { + warning("Invalid normalisation type\n"); + exit(EXIT_FAILURE); + } + can_make_trues = prompts_projdata_filename.size() != 0 && randoms_projdata_filename.size() != 0; - do_scatter = - (trues_projdata_filename.size()!=0 || can_make_trues) && - precorrected_projdata_filename.size()!=0; + do_scatter = (trues_projdata_filename.size() != 0 || can_make_trues) && precorrected_projdata_filename.size() != 0; - if (prompts_projdata_filename.size()!=0) + if (prompts_projdata_filename.size() != 0) prompts_projdata_ptr = ProjData::read_from_file(prompts_projdata_filename); - if (trues_projdata_filename.size()!=0) + if (trues_projdata_filename.size() != 0) trues_projdata_ptr = ProjData::read_from_file(trues_projdata_filename); - if (precorrected_projdata_filename.size()!=0) + if (precorrected_projdata_filename.size() != 0) precorrected_projdata_ptr = ProjData::read_from_file(precorrected_projdata_filename); - do_Shifted_Poisson = - Shifted_Poisson_numerator_projdata_filename.size() != 0; - if (do_Shifted_Poisson && randoms_projdata_filename.size()==0) - { - warning("Shifted Poisson data asked for, but no randoms present\n"); - exit(EXIT_FAILURE); - } - if (do_Shifted_Poisson && trues_projdata_filename.size()==0) - { - warning("Shifted Poisson data asked for, but no trues present\n"); - exit(EXIT_FAILURE); - } - - do_prompts = - prompts_denominator_projdata_filename.size() != 0; + do_Shifted_Poisson = Shifted_Poisson_numerator_projdata_filename.size() != 0; + if (do_Shifted_Poisson && randoms_projdata_filename.size() == 0) { + warning("Shifted Poisson data asked for, but no randoms present\n"); + exit(EXIT_FAILURE); + } + if (do_Shifted_Poisson && trues_projdata_filename.size() == 0) { + warning("Shifted Poisson data asked for, but no trues present\n"); + exit(EXIT_FAILURE); + } - if (do_prompts && randoms_projdata_filename.size()==0) - { - warning("Prompts data asked for, but no randoms present\n"); - exit(EXIT_FAILURE); - } + do_prompts = prompts_denominator_projdata_filename.size() != 0; + if (do_prompts && randoms_projdata_filename.size() == 0) { + warning("Prompts data asked for, but no randoms present\n"); + exit(EXIT_FAILURE); + } if (do_Shifted_Poisson || do_prompts) - randoms_projdata_ptr = ProjData::read_from_file(randoms_projdata_filename); + randoms_projdata_ptr = ProjData::read_from_file(randoms_projdata_filename); scatter_projdata_ptr.reset(); - if (!do_scatter && scatter_projdata_filename.size()!=0) + if (!do_scatter && scatter_projdata_filename.size() != 0) scatter_projdata_ptr = ProjData::read_from_file(scatter_projdata_filename); - // read time frame def - if (frame_definition_filename.size()!=0) + // read time frame def + if (frame_definition_filename.size() != 0) frame_defs = TimeFrameDefinitions(frame_definition_filename); - else - { - // make a single frame starting from 0 to 1 - warning("No time frame definitions present.\n" - "If the normalisation type needs time info for the dead-time correction,\n" - "you will get wrong results\n"); - vector > frame_times(1, pair(0,1)); - frame_defs = TimeFrameDefinitions(frame_times); - } + else { + // make a single frame starting from 0 to 1 + warning("No time frame definitions present.\n" + "If the normalisation type needs time info for the dead-time correction,\n" + "you will get wrong results\n"); + vector> frame_times(1, pair(0, 1)); + frame_defs = TimeFrameDefinitions(frame_times); + } - if (current_frame_num < 1 || - static_cast(current_frame_num) > frame_defs.get_num_frames()) - { - warning("\nFrame number %d is out of range for frame definitions\n", current_frame_num); - exit(EXIT_FAILURE); - } + if (current_frame_num < 1 || static_cast(current_frame_num) > frame_defs.get_num_frames()) { + warning("\nFrame number %d is out of range for frame definitions\n", current_frame_num); + exit(EXIT_FAILURE); + } // construct output projdata // and set_up normalisation @@ -278,70 +250,50 @@ PrepareProjData(const char * const par_filename) // get output_data_info_ptr from one of the input files if (!is_null_ptr(trues_projdata_ptr)) - output_data_info_ptr= - trues_projdata_ptr->get_proj_data_info_sptr()->create_shared_clone(); + output_data_info_ptr = trues_projdata_ptr->get_proj_data_info_sptr()->create_shared_clone(); else if (!is_null_ptr(randoms_projdata_ptr)) - output_data_info_ptr= - randoms_projdata_ptr->get_proj_data_info_sptr()->create_shared_clone(); + output_data_info_ptr = randoms_projdata_ptr->get_proj_data_info_sptr()->create_shared_clone(); else if (!is_null_ptr(precorrected_projdata_ptr)) - output_data_info_ptr= - precorrected_projdata_ptr->get_proj_data_info_sptr()->create_shared_clone(); - else - { - warning("\nAt least one of these input files must be set: trues, randoms, precorrected\n"); - exit(EXIT_FAILURE); - } + output_data_info_ptr = precorrected_projdata_ptr->get_proj_data_info_sptr()->create_shared_clone(); + else { + warning("\nAt least one of these input files must be set: trues, randoms, precorrected\n"); + exit(EXIT_FAILURE); + } // set segment range - const int max_segment_num_available = - output_data_info_ptr->get_max_segment_num(); - if (max_segment_num_to_process<0 || - max_segment_num_to_process > max_segment_num_available) + const int max_segment_num_available = output_data_info_ptr->get_max_segment_num(); + if (max_segment_num_to_process < 0 || max_segment_num_to_process > max_segment_num_available) max_segment_num_to_process = max_segment_num_available; - output_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, - max_segment_num_to_process); - + output_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); - if (normalisation_ptr->set_up(output_data_info_ptr) != Succeeded::yes) - { - warning("Error initialisation normalisation\n"); - exit(EXIT_FAILURE); - } + if (normalisation_ptr->set_up(output_data_info_ptr) != Succeeded::yes) { + warning("Error initialisation normalisation\n"); + exit(EXIT_FAILURE); + } // open other files - if (normatten_projdata_filename.size()!=0) - normatten_projdata_ptr. - reset(new ProjDataInterfile(output_data_info_ptr, normatten_projdata_filename)); + if (normatten_projdata_filename.size() != 0) + normatten_projdata_ptr.reset(new ProjDataInterfile(output_data_info_ptr, normatten_projdata_filename)); if (do_scatter) - scatter_projdata_ptr. - reset(new ProjDataInterfile(output_data_info_ptr, scatter_projdata_filename)); - if (do_Shifted_Poisson) - { - Shifted_Poisson_numerator_projdata_ptr. - reset(new ProjDataInterfile(output_data_info_ptr, Shifted_Poisson_numerator_projdata_filename)); - Shifted_Poisson_denominator_projdata_ptr. - reset(new ProjDataInterfile(output_data_info_ptr, Shifted_Poisson_denominator_projdata_filename)); + scatter_projdata_ptr.reset(new ProjDataInterfile(output_data_info_ptr, scatter_projdata_filename)); + if (do_Shifted_Poisson) { + Shifted_Poisson_numerator_projdata_ptr.reset( + new ProjDataInterfile(output_data_info_ptr, Shifted_Poisson_numerator_projdata_filename)); + Shifted_Poisson_denominator_projdata_ptr.reset( + new ProjDataInterfile(output_data_info_ptr, Shifted_Poisson_denominator_projdata_filename)); } - if (do_prompts) - { - prompts_denominator_projdata_ptr. - reset(new ProjDataInterfile(output_data_info_ptr, prompts_denominator_projdata_filename)); + if (do_prompts) { + prompts_denominator_projdata_ptr.reset(new ProjDataInterfile(output_data_info_ptr, prompts_denominator_projdata_filename)); } } - } - - void -PrepareProjData:: -doit() -{ - shared_ptr symmetries_ptr - (new TrivialDataSymmetriesForViewSegmentNumbers); +PrepareProjData::doit() { + shared_ptr symmetries_ptr(new TrivialDataSymmetriesForViewSegmentNumbers); // take these out of the loop to avoid reallocation (but it's ugly) RelatedViewgrams normatten_viewgrams; @@ -352,74 +304,60 @@ doit() RelatedViewgrams Shifted_Poisson_denominator_viewgrams; RelatedViewgrams prompts_denominator_viewgrams; - - for (int segment_num = -max_segment_num_to_process; segment_num <= max_segment_num_to_process; segment_num++) - { - cerr<get_min_view_num(); view_num<=normatten_projdata_ptr->get_max_view_num(); ++view_num) - { - const ViewSegmentNumbers view_seg_num(view_num,segment_num); + for (int segment_num = -max_segment_num_to_process; segment_num <= max_segment_num_to_process; segment_num++) { + cerr << endl << "Processing segment #" << segment_num << endl; + for (int view_num = normatten_projdata_ptr->get_min_view_num(); view_num <= normatten_projdata_ptr->get_max_view_num(); + ++view_num) { + const ViewSegmentNumbers view_seg_num(view_num, segment_num); if (!symmetries_ptr->is_basic(view_seg_num)) - continue; + continue; bool already_read_randoms = false; // ** first do normalisation (and fill in normatten) ** - - /*RelatedViewgrams*/ normatten_viewgrams = - output_data_info_ptr->get_empty_related_viewgrams(view_seg_num, symmetries_ptr); + + /*RelatedViewgrams*/ normatten_viewgrams = + output_data_info_ptr->get_empty_related_viewgrams(view_seg_num, symmetries_ptr); { - const double start_time = frame_defs.get_start_time(current_frame_num); - const double end_time = frame_defs.get_end_time(current_frame_num); + const double start_time = frame_defs.get_start_time(current_frame_num); + const double end_time = frame_defs.get_end_time(current_frame_num); normatten_viewgrams.fill(1.F); - normalisation_ptr->apply(normatten_viewgrams,start_time,end_time); - + normalisation_ptr->apply(normatten_viewgrams, start_time, end_time); + if (!is_null_ptr(normatten_projdata_ptr)) - normatten_projdata_ptr->set_related_viewgrams(normatten_viewgrams); + normatten_projdata_ptr->set_related_viewgrams(normatten_viewgrams); } // ** now compute scatter ** /*RelatedViewgrams*/ scatter_viewgrams = normatten_viewgrams; - if (do_scatter) - { + if (do_scatter) { // scatter = trues_emission * norm * atten - fully_precorrected_emission - if (!is_null_ptr(trues_projdata_ptr)) - { - trues_viewgrams = trues_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); - } - else - { - randoms_viewgrams = randoms_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); - already_read_randoms = true; - trues_viewgrams = prompts_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); - trues_viewgrams -= randoms_viewgrams; - } - scatter_viewgrams *= - trues_viewgrams; - scatter_viewgrams -= - precorrected_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); - + if (!is_null_ptr(trues_projdata_ptr)) { + trues_viewgrams = trues_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); + } else { + randoms_viewgrams = randoms_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); + already_read_randoms = true; + trues_viewgrams = prompts_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); + trues_viewgrams -= randoms_viewgrams; + } + scatter_viewgrams *= trues_viewgrams; + scatter_viewgrams -= precorrected_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); + scatter_projdata_ptr->set_related_viewgrams(scatter_viewgrams); - } - else - { - if (is_null_ptr(scatter_projdata_ptr)) - scatter_viewgrams.fill(0); - else - scatter_viewgrams = - scatter_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); + } else { + if (is_null_ptr(scatter_projdata_ptr)) + scatter_viewgrams.fill(0); + else + scatter_viewgrams = scatter_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); } - if (do_Shifted_Poisson) - { - if (!already_read_randoms) - { - randoms_viewgrams = - randoms_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); - } + if (do_Shifted_Poisson) { + if (!already_read_randoms) { + randoms_viewgrams = randoms_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); + } // multiply with 2 for Shifted Poisson randoms_viewgrams *= 2; @@ -428,9 +366,8 @@ doit() // numerator of Shifted_Poisson is trues+ 2*randoms /*RelatedViewgrams*/ Shifted_Poisson_numerator_viewgrams = - Shifted_Poisson_numerator_projdata_ptr->get_empty_related_viewgrams(view_seg_num, symmetries_ptr); - Shifted_Poisson_numerator_viewgrams += - trues_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); + Shifted_Poisson_numerator_projdata_ptr->get_empty_related_viewgrams(view_seg_num, symmetries_ptr); + Shifted_Poisson_numerator_viewgrams += trues_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); Shifted_Poisson_numerator_viewgrams += randoms_viewgrams; Shifted_Poisson_numerator_projdata_ptr->set_related_viewgrams(Shifted_Poisson_numerator_viewgrams); } @@ -442,18 +379,15 @@ doit() Shifted_Poisson_denominator_viewgrams += randoms_viewgrams; Shifted_Poisson_denominator_projdata_ptr->set_related_viewgrams(Shifted_Poisson_denominator_viewgrams); } - // we force re-reading the randoms as we modified them above + // we force re-reading the randoms as we modified them above already_read_randoms = false; } - - if (do_prompts) - { - if (!already_read_randoms) - { - randoms_viewgrams = - randoms_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); - } - + + if (do_prompts) { + if (!already_read_randoms) { + randoms_viewgrams = randoms_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); + } + { // denominator of prompts is scatter+ randoms*norm*atten @@ -463,42 +397,32 @@ doit() prompts_denominator_projdata_ptr->set_related_viewgrams(prompts_denominator_viewgrams); } } - } - } -} - - +} END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char *argv[]) -{ - - if(argc!=2) - { - cerr<<"Usage: " << argv[0] << " par_file\n" - << endl; +int +main(int argc, char* argv[]) { + + if (argc != 2) { + cerr << "Usage: " << argv[0] << " par_file\n" << endl; + } + PrepareProjData application(argc == 2 ? argv[1] : 0); + + if (argc != 2) { + cerr << "Corresponding .par file input \n" << application.parameter_info() << endl; } - PrepareProjData application( argc==2 ? argv[1] : 0); - - if (argc!=2) - { - cerr << "Corresponding .par file input \n" - << application.parameter_info() << endl; - } - CPUTimer timer; timer.start(); application.doit(); - + timer.stop(); cerr << "CPU time : " << timer.value() << "secs" << endl; return EXIT_SUCCESS; - } diff --git a/src/experimental/utilities/print_rdf_singles.cxx b/src/experimental/utilities/print_rdf_singles.cxx index 325ab94ad0..34d2d268b5 100644 --- a/src/experimental/utilities/print_rdf_singles.cxx +++ b/src/experimental/utilities/print_rdf_singles.cxx @@ -12,7 +12,6 @@ \author Kris Thielemans */ - #include "stir_experimental/IO/GE/SinglesRatesFromRDF.h" #include "stir/stream.h" #include "stir/IndexRange2D.h" @@ -21,15 +20,11 @@ USING_NAMESPACE_STIR +int +main(int argc, char** argv) { - - -int -main (int argc, char **argv) -{ - - // Check arguments. - // Singles filename + // Check arguments. + // Singles filename if (argc != 2) { cerr << "Program to print out values from a singles file.\n\n"; cerr << "Usage: " << argv[0] << " rdf_filename \n\n"; @@ -41,28 +36,23 @@ main (int argc, char **argv) GE_IO::SinglesRatesFromRDF singles_from_rdf; // Read the singles file. - if (singles_from_rdf.read_from_file(rdf_filename)==0) + if (singles_from_rdf.read_from_file(rdf_filename) == 0) error("Error while reading singles file"); - // Get total number of frames - //int num_frames = singles_from_rdf.get_num_frames(); - + // int num_frames = singles_from_rdf.get_num_frames(); + // Get scanner details and, from these, the number of singles units. const Scanner& scanner = *singles_from_rdf.get_scanner_ptr(); - Array<2,float> singles(IndexRange2D(scanner.get_num_axial_singles_units(), - scanner.get_num_transaxial_singles_units())); - for (int ax=0; ax singles(IndexRange2D(scanner.get_num_axial_singles_units(), scanner.get_num_transaxial_singles_units())); + for (int ax = 0; ax < scanner.get_num_axial_singles_units(); ++ax) { + for (int transax = 0; transax < scanner.get_num_transaxial_singles_units(); ++transax) { + const int singles_bin_index = scanner.get_singles_bin_index(ax, transax); + singles[ax][transax] = singles_from_rdf.get_singles_rate(singles_bin_index, 1); } + } - std::cout<< singles; + std::cout << singles; - return EXIT_SUCCESS; } diff --git a/src/experimental/utilities/remove_sinograms.cxx b/src/experimental/utilities/remove_sinograms.cxx index 8f8cff3eb4..e427f70dd7 100644 --- a/src/experimental/utilities/remove_sinograms.cxx +++ b/src/experimental/utilities/remove_sinograms.cxx @@ -31,88 +31,63 @@ using std::endl; USING_NAMESPACE_STIR +int +main(int argc, char** argv) { + if (argc < 4 || argc > 5) { + cerr << "Usage:\n" + << argv[0] + << " output_filename input_projdata_name num_axial_poss_to_remove_at_each_side [max_in_segment_num_to_process ]]\n" + << "max_in_segment_num_to_process defaults to all segments\n" + << "If num_axial_poss_to_remove_at_each_side is negative, sinograms will \n" + << "be added (they will be set to 0)\n"; + exit(EXIT_FAILURE); + } + + const string output_filename = argv[1]; + shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); + const int num_axial_poss_to_remove_at_each_side = atoi(argv[3]); + int max_segment_num_to_process = argc <= 4 ? in_projdata_ptr->get_max_segment_num() : atoi(argv[4]); -int main(int argc, char **argv) -{ - if (argc < 4 || argc > 5) - { - cerr << "Usage:\n" - << argv[0] << " output_filename input_projdata_name num_axial_poss_to_remove_at_each_side [max_in_segment_num_to_process ]]\n" - << "max_in_segment_num_to_process defaults to all segments\n" - << "If num_axial_poss_to_remove_at_each_side is negative, sinograms will \n" - << "be added (they will be set to 0)\n"; - exit(EXIT_FAILURE); - } - - const string output_filename = argv[1]; - shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); - const int num_axial_poss_to_remove_at_each_side = atoi(argv[3]); - int max_segment_num_to_process = argc <=4 ? in_projdata_ptr->get_max_segment_num() : atoi(argv[4]); - // construct new proj_data_info_ptr for output data - ProjDataInfo * proj_data_info_ptr = - in_projdata_ptr->get_proj_data_info_sptr()->clone(); + ProjDataInfo* proj_data_info_ptr = in_projdata_ptr->get_proj_data_info_sptr()->clone(); { // first check that max_segment_num_to_process is such that in the new // number of axial positions is positive. If not, decrease it - while (max_segment_num_to_process >=0 && - in_projdata_ptr->get_num_axial_poss(max_segment_num_to_process) - - 2*num_axial_poss_to_remove_at_each_side<=0) + while (max_segment_num_to_process >= 0 && + in_projdata_ptr->get_num_axial_poss(max_segment_num_to_process) - 2 * num_axial_poss_to_remove_at_each_side <= 0) --max_segment_num_to_process; - if (max_segment_num_to_process<0) - { - error("%s: there are not enough axial positions even in segment 0\n", - argv[0]); - } - + if (max_segment_num_to_process < 0) { + error("%s: there are not enough axial positions even in segment 0\n", argv[0]); + } - proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, - max_segment_num_to_process); + proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); // now set new number of axial positions - VectorWithOffset - new_num_axial_poss_per_segment(-max_segment_num_to_process, - max_segment_num_to_process); - for (int segment_num=-max_segment_num_to_process; - segment_num<=max_segment_num_to_process; - ++segment_num) + VectorWithOffset new_num_axial_poss_per_segment(-max_segment_num_to_process, max_segment_num_to_process); + for (int segment_num = -max_segment_num_to_process; segment_num <= max_segment_num_to_process; ++segment_num) new_num_axial_poss_per_segment[segment_num] = - in_projdata_ptr->get_num_axial_poss(segment_num) - - 2*num_axial_poss_to_remove_at_each_side; - + in_projdata_ptr->get_num_axial_poss(segment_num) - 2 * num_axial_poss_to_remove_at_each_side; proj_data_info_ptr->set_num_axial_poss_per_segment(new_num_axial_poss_per_segment); - } - - ProjDataInterfile out_projdata(proj_data_info_ptr, output_filename, ios::out); - Succeeded succes = Succeeded::yes; - for (int segment_num = out_projdata.get_min_segment_num(); - segment_num <= out_projdata.get_max_segment_num(); - ++segment_num) - { - SegmentBySinogram out_segment = - out_projdata.get_empty_segment_by_sinogram(segment_num); - const SegmentBySinogram in_segment = - in_projdata_ptr->get_segment_by_sinogram( segment_num); + ProjDataInterfile out_projdata(proj_data_info_ptr, output_filename, ios::out); - // 17/02/2002 SM corrected such that sinograms from both sides are removed not only from one side - for (int ax_pos_num=(in_segment.get_min_axial_pos_num()+num_axial_poss_to_remove_at_each_side); - ax_pos_num<=in_segment.get_max_axial_pos_num()-num_axial_poss_to_remove_at_each_side; - ++ax_pos_num) - { - cerr << ax_pos_num << " "; - out_segment[ax_pos_num-num_axial_poss_to_remove_at_each_side] = in_segment[ax_pos_num]; - - } - if (out_projdata.set_segment(out_segment) == Succeeded::no) - succes = Succeeded::no; - cerr << endl; + Succeeded succes = Succeeded::yes; + for (int segment_num = out_projdata.get_min_segment_num(); segment_num <= out_projdata.get_max_segment_num(); ++segment_num) { + SegmentBySinogram out_segment = out_projdata.get_empty_segment_by_sinogram(segment_num); + const SegmentBySinogram in_segment = in_projdata_ptr->get_segment_by_sinogram(segment_num); - - + // 17/02/2002 SM corrected such that sinograms from both sides are removed not only from one side + for (int ax_pos_num = (in_segment.get_min_axial_pos_num() + num_axial_poss_to_remove_at_each_side); + ax_pos_num <= in_segment.get_max_axial_pos_num() - num_axial_poss_to_remove_at_each_side; ++ax_pos_num) { + cerr << ax_pos_num << " "; + out_segment[ax_pos_num - num_axial_poss_to_remove_at_each_side] = in_segment[ax_pos_num]; } + if (out_projdata.set_segment(out_segment) == Succeeded::no) + succes = Succeeded::no; + cerr << endl; + } - return succes == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + return succes == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/utilities/set_blocks_to_value.cxx b/src/experimental/utilities/set_blocks_to_value.cxx index d809ceae02..6a7f56a2a0 100644 --- a/src/experimental/utilities/set_blocks_to_value.cxx +++ b/src/experimental/utilities/set_blocks_to_value.cxx @@ -39,41 +39,30 @@ using std::max; #endif START_NAMESPACE_STIR - - -void do_block(vector& list_of_bins_in_block, - const int axial_block_num, const int tangential_block_num, - const ProjDataInfoCylindricalNoArcCorr& proj_data_info, - const int axial_num_crystals_in_block, const int tangential_num_crystals_in_block) -{ +void +do_block(vector& list_of_bins_in_block, const int axial_block_num, const int tangential_block_num, + const ProjDataInfoCylindricalNoArcCorr& proj_data_info, const int axial_num_crystals_in_block, + const int tangential_num_crystals_in_block) { Bin bin; - const int num_rings = - proj_data_info.get_scanner_ptr()->get_num_rings(); - const int num_detectors_per_ring = - proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); - - const int tang_det_offset = tangential_block_num*tangential_num_crystals_in_block; - const int ax_det_offset = axial_block_num*axial_num_crystals_in_block; - const int max_ring_diff = - proj_data_info.get_max_ring_difference(proj_data_info.get_max_segment_num()); - const int min_ring_diff = - proj_data_info.get_min_ring_difference(proj_data_info.get_min_segment_num()); - for (int ax_crystal=0; ax_crystalget_num_rings(); + const int num_detectors_per_ring = proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); + + const int tang_det_offset = tangential_block_num * tangential_num_crystals_in_block; + const int ax_det_offset = axial_block_num * axial_num_crystals_in_block; + const int max_ring_diff = proj_data_info.get_max_ring_difference(proj_data_info.get_max_segment_num()); + const int min_ring_diff = proj_data_info.get_min_ring_difference(proj_data_info.get_min_segment_num()); + for (int ax_crystal = 0; ax_crystal < axial_num_crystals_in_block; ++ax_crystal) + for (int tang_crystal = 0; tang_crystal < tangential_num_crystals_in_block; ++tang_crystal) { const int det = tang_crystal + tang_det_offset; const int ring = ax_crystal + ax_det_offset; { - for (int other_det=0; other_det& list_of_bins_in_block, } } -bool -bin_coordinates_by_view_less(const Bin& b1, const Bin& b2) -{ - return b1.segment_num()& list_of_bins) -{ +void +sort_and_make_unique(vector& list_of_bins) { // cannot use vector::sort as VC does not support member templates - sort(list_of_bins.begin(), list_of_bins.end(),bin_coordinates_by_view_less); - //list_of_bins.unique(); + sort(list_of_bins.begin(), list_of_bins.end(), bin_coordinates_by_view_less); + // list_of_bins.unique(); unique(list_of_bins.begin(), list_of_bins.end()); } - END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc < 3 || argc > 5) - { - cerr << "Usage:\n" - << argv[0] << " output_filename input_projdata_name [value [max_in_segment_num_to_process ]]\n" - << "value defaults to 0\n" - << "max_in_segment_num_to_process defaults to all segments\n" - << "Will ask for which blocks to set to the value, will then set " - << "ANY bin that has a contribution of those blocks to that value.\n" - << "This might not be what you want for spanned/mashed data.\n"; - exit(EXIT_FAILURE); - } - const string output_filename = argv[1]; - shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); - const float value = argc <=3 ? 0.F: static_cast(atof(argv[3])); - const int max_segment_num_to_process = argc <=4 ? in_projdata_ptr->get_max_segment_num() : atoi(argv[4]); - - ProjDataInfoCylindricalNoArcCorr * proj_data_info_ptr = - dynamic_cast - (in_projdata_ptr->get_proj_data_info_sptr()->clone()); - if (proj_data_info_ptr == NULL) - { +int +main(int argc, char** argv) { + if (argc < 3 || argc > 5) { + cerr << "Usage:\n" + << argv[0] << " output_filename input_projdata_name [value [max_in_segment_num_to_process ]]\n" + << "value defaults to 0\n" + << "max_in_segment_num_to_process defaults to all segments\n" + << "Will ask for which blocks to set to the value, will then set " + << "ANY bin that has a contribution of those blocks to that value.\n" + << "This might not be what you want for spanned/mashed data.\n"; + exit(EXIT_FAILURE); + } + const string output_filename = argv[1]; + shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); + const float value = argc <= 3 ? 0.F : static_cast(atof(argv[3])); + const int max_segment_num_to_process = argc <= 4 ? in_projdata_ptr->get_max_segment_num() : atoi(argv[4]); + + ProjDataInfoCylindricalNoArcCorr* proj_data_info_ptr = + dynamic_cast(in_projdata_ptr->get_proj_data_info_sptr()->clone()); + if (proj_data_info_ptr == NULL) { cerr << argv[0] << " can only work on not-arccorrected data\n"; exit(EXIT_FAILURE); } - proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process,max_segment_num_to_process); + proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); - ProjDataInterfile out_projdata(proj_data_info_ptr, output_filename, ios::out); + ProjDataInterfile out_projdata(proj_data_info_ptr, output_filename, ios::out); - const int num_rings = - proj_data_info_ptr->get_scanner_ptr()->get_num_rings(); - const int num_detectors_per_ring = - proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); - const int axial_num_crystals_in_block = - ask_num("Crystals in 1 block axially",1,num_rings,8); - const int tangential_num_crystals_in_block= - ask_num("Crystals in 1 block tangentially",1,num_detectors_per_ring,8); + const int num_rings = proj_data_info_ptr->get_scanner_ptr()->get_num_rings(); + const int num_detectors_per_ring = proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); + const int axial_num_crystals_in_block = ask_num("Crystals in 1 block axially", 1, num_rings, 8); + const int tangential_num_crystals_in_block = ask_num("Crystals in 1 block tangentially", 1, num_detectors_per_ring, 8); vector list_of_bins; - do - { - const int axial_block_num = - ask_num("Block number axially", - 0,num_rings/axial_num_crystals_in_block-1, 0); - const int tangential_block_num = - ask_num("Block number tangentially", - 0,num_detectors_per_ring/tangential_num_crystals_in_block-1, 0); - do_block(list_of_bins, - axial_block_num, tangential_block_num, - *proj_data_info_ptr, - axial_num_crystals_in_block, tangential_num_crystals_in_block); - } - while (ask("One more",false)); - + do { + const int axial_block_num = ask_num("Block number axially", 0, num_rings / axial_num_crystals_in_block - 1, 0); + const int tangential_block_num = + ask_num("Block number tangentially", 0, num_detectors_per_ring / tangential_num_crystals_in_block - 1, 0); + do_block(list_of_bins, axial_block_num, tangential_block_num, *proj_data_info_ptr, axial_num_crystals_in_block, + tangential_num_crystals_in_block); + } while (ask("One more", false)); sort_and_make_unique(list_of_bins); std::vector::const_iterator bin_iter = list_of_bins.begin(); - for (int segment_num = out_projdata.get_min_segment_num(); - segment_num <= out_projdata.get_max_segment_num(); - ++segment_num) - for (int view_num = in_projdata_ptr->get_min_view_num(); - view_num <= in_projdata_ptr->get_max_view_num(); - ++view_num) - { - Viewgram viewgram = - out_projdata.get_empty_viewgram(view_num, segment_num); - viewgram += in_projdata_ptr->get_viewgram(view_num, segment_num); + for (int segment_num = out_projdata.get_min_segment_num(); segment_num <= out_projdata.get_max_segment_num(); ++segment_num) + for (int view_num = in_projdata_ptr->get_min_view_num(); view_num <= in_projdata_ptr->get_max_view_num(); ++view_num) { + Viewgram viewgram = out_projdata.get_empty_viewgram(view_num, segment_num); + viewgram += in_projdata_ptr->get_viewgram(view_num, segment_num); const int max_ax_pos_num = viewgram.get_max_axial_pos_num(); const int min_ax_pos_num = viewgram.get_min_axial_pos_num(); const int max_tang_pos_num = viewgram.get_max_tangential_pos_num(); const int min_tang_pos_num = viewgram.get_min_tangential_pos_num(); - for (; bin_iter != list_of_bins.end(); ++bin_iter) - { - if (segment_num != bin_iter->segment_num() || - view_num != bin_iter->view_num()) + for (; bin_iter != list_of_bins.end(); ++bin_iter) { + if (segment_num != bin_iter->segment_num() || view_num != bin_iter->view_num()) break; - const int ax_pos_num = bin_iter->axial_pos_num(); - const int tang_pos_num = bin_iter->tangential_pos_num(); - if (ax_pos_num <=max_ax_pos_num && - ax_pos_num >=min_ax_pos_num && - tang_pos_num <=max_tang_pos_num && - tang_pos_num >=min_tang_pos_num) - viewgram[ax_pos_num][tang_pos_num] = value; - } + const int ax_pos_num = bin_iter->axial_pos_num(); + const int tang_pos_num = bin_iter->tangential_pos_num(); + if (ax_pos_num <= max_ax_pos_num && ax_pos_num >= min_ax_pos_num && tang_pos_num <= max_tang_pos_num && + tang_pos_num >= min_tang_pos_num) + viewgram[ax_pos_num][tang_pos_num] = value; + } out_projdata.set_viewgram(viewgram); } diff --git a/src/experimental/utilities/shift_projdata_along_axis.cxx b/src/experimental/utilities/shift_projdata_along_axis.cxx index ec38097d7c..bda952d064 100644 --- a/src/experimental/utilities/shift_projdata_along_axis.cxx +++ b/src/experimental/utilities/shift_projdata_along_axis.cxx @@ -6,7 +6,7 @@ \ingroup utilities \brief A utility to shift projection data along the axial direction - This can be used as a crude way for motion correction, when the motion is only in + This can be used as a crude way for motion correction, when the motion is only in z-direction. \author Kris Thielemans @@ -33,45 +33,36 @@ using std::max; USING_NAMESPACE_STIR +int +main(int argc, char** argv) { + if (argc < 4 || argc > 5) { + cerr << "Usage:\n" + << argv[0] << " output_filename input_projdata_name number_of_axial_poss_to_shift [max_in_segment_num_to_process ]]\n" + << "max_in_segment_num_to_process defaults to all segments\n"; + exit(EXIT_FAILURE); + } + const string output_filename = argv[1]; + shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); + const int number_of_axial_poss_to_shift = atoi(argv[3]); + const int max_segment_num_to_process = argc <= 4 ? in_projdata_ptr->get_max_segment_num() : atoi(argv[4]); -int main(int argc, char **argv) -{ - if (argc < 4 || argc > 5) - { - cerr << "Usage:\n" - << argv[0] << " output_filename input_projdata_name number_of_axial_poss_to_shift [max_in_segment_num_to_process ]]\n" - << "max_in_segment_num_to_process defaults to all segments\n"; - exit(EXIT_FAILURE); - } - const string output_filename = argv[1]; - shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); - const int number_of_axial_poss_to_shift = atoi(argv[3]); - const int max_segment_num_to_process = argc <=4 ? in_projdata_ptr->get_max_segment_num() : atoi(argv[4]); + ProjDataInfo* proj_data_info_ptr = in_projdata_ptr->get_proj_data_info_sptr()->clone(); + proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); - ProjDataInfo * proj_data_info_ptr = - in_projdata_ptr->get_proj_data_info_sptr()->clone(); - proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process,max_segment_num_to_process); - - ProjDataInterfile out_projdata(proj_data_info_ptr, output_filename, ios::out); + ProjDataInterfile out_projdata(proj_data_info_ptr, output_filename, ios::out); Succeeded succes = Succeeded::yes; - for (int segment_num = out_projdata.get_min_segment_num(); - segment_num <= out_projdata.get_max_segment_num(); - ++segment_num) - { - SegmentBySinogram out_segment = - out_projdata.get_empty_segment_by_sinogram(segment_num); - const SegmentBySinogram in_segment = - in_projdata_ptr->get_segment_by_sinogram( segment_num); - const int max_ax_pos_num = out_segment.get_max_axial_pos_num(); - const int min_ax_pos_num = out_segment.get_min_axial_pos_num(); - for (int ax_pos_num=max(min_ax_pos_num, min_ax_pos_num-number_of_axial_poss_to_shift); - ax_pos_num<=min(max_ax_pos_num, max_ax_pos_num-number_of_axial_poss_to_shift); - ++ax_pos_num) - out_segment[ax_pos_num] = in_segment[ax_pos_num+number_of_axial_poss_to_shift]; - if (out_projdata.set_segment(out_segment) == Succeeded::no) - succes = Succeeded::no; - } + for (int segment_num = out_projdata.get_min_segment_num(); segment_num <= out_projdata.get_max_segment_num(); ++segment_num) { + SegmentBySinogram out_segment = out_projdata.get_empty_segment_by_sinogram(segment_num); + const SegmentBySinogram in_segment = in_projdata_ptr->get_segment_by_sinogram(segment_num); + const int max_ax_pos_num = out_segment.get_max_axial_pos_num(); + const int min_ax_pos_num = out_segment.get_min_axial_pos_num(); + for (int ax_pos_num = max(min_ax_pos_num, min_ax_pos_num - number_of_axial_poss_to_shift); + ax_pos_num <= min(max_ax_pos_num, max_ax_pos_num - number_of_axial_poss_to_shift); ++ax_pos_num) + out_segment[ax_pos_num] = in_segment[ax_pos_num + number_of_axial_poss_to_shift]; + if (out_projdata.set_segment(out_segment) == Succeeded::no) + succes = Succeeded::no; + } - return succes == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + return succes == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/utilities/show_ecat7_header.cxx b/src/experimental/utilities/show_ecat7_header.cxx index 809bcd2a36..f8bcda05f5 100644 --- a/src/experimental/utilities/show_ecat7_header.cxx +++ b/src/experimental/utilities/show_ecat7_header.cxx @@ -1,7 +1,7 @@ // // -/*! +/*! \file \ingroup utilities \ingroup ECAT @@ -13,7 +13,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/Succeeded.h" #include "stir/utilities.h" #include "stir/IO/stir_ecat7.h" @@ -32,41 +31,40 @@ USING_NAMESPACE_STIR USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 -void dump_subheader(const Scan3D_subheader& scan3dsub) -{ +void +dump_subheader(const Scan3D_subheader& scan3dsub) { /* - short data_type; - short num_dimensions; - short num_r_elements; - short num_angles; - short corrections_applied; - short num_z_elements[64]; - short ring_difference; - short storage_order; - short axial_compression; - float x_resolution; - float v_resolution; - float z_resolution; - float w_resolution; - unsigned int gate_duration; - int r_wave_offset; - int num_accepted_beats; - float scale_factor; - short scan_min; - short scan_max; - int prompts; - int delayed; - int multiples; - int net_trues; - float tot_avg_cor; - float tot_avg_uncor; - int total_coin_rate; - unsigned int frame_start_time; - unsigned int frame_duration; - float + short data_type; + short num_dimensions; + short num_r_elements; + short num_angles; + short corrections_applied; + short num_z_elements[64]; + short ring_difference; + short storage_order; + short axial_compression; + float x_resolution; + float v_resolution; + float z_resolution; + float w_resolution; + unsigned int gate_duration; + int r_wave_offset; + int num_accepted_beats; + float scale_factor; + short scan_min; + short scan_max; + int prompts; + int delayed; + int multiples; + int net_trues; + float tot_avg_cor; + float tot_avg_uncor; + int total_coin_rate; + unsigned int frame_start_time; + unsigned int frame_duration; + float */ -#define STIR_DUMPIT(x) \ - cout << "x = " << scan3dsub.x << '\n'; +#define STIR_DUMPIT(x) cout << "x = " << scan3dsub.x << '\n'; cout << "frame_start_time = " << scan3dsub.frame_start_time << '\n'; cout << "frame_duration = " << scan3dsub.frame_duration << '\n'; @@ -76,20 +74,13 @@ void dump_subheader(const Scan3D_subheader& scan3dsub) STIR_DUMPIT(multiples); STIR_DUMPIT(tot_avg_uncor); cout << "loss_correction_fctr = " << scan3dsub.loss_correction_fctr << '\n'; - for (int i=0; i<128; ++i) - cout << "uncor_singles[" << i << "] = " - << scan3dsub.uncor_singles[i] << '\n'; + for (int i = 0; i < 128; ++i) + cout << "uncor_singles[" << i << "] = " << scan3dsub.uncor_singles[i] << '\n'; } - void -dump_subheader(MatrixFile * mptr, - const int frame_num, - const int plane_num, - const int gate_num, - const int data_num, - const int bed_num) -{ +dump_subheader(MatrixFile* mptr, const int frame_num, const int plane_num, const int gate_num, const int data_num, + const int bed_num) { int matnum; struct MatDir matdir; Scan_subheader scansub; @@ -97,18 +88,17 @@ dump_subheader(MatrixFile * mptr, Norm_subheader normsub; Attn_subheader attnsub; Scan3D_subheader scan3dsub; - + if (mptr->mhptr->sw_version < V7) - matnum = mat_numcod (frame_num, plane_num, gate_num, data_num, bed_num); + matnum = mat_numcod(frame_num, plane_num, gate_num, data_num, bed_num); else - matnum = mat_numcod (frame_num, 1, gate_num, data_num, bed_num); - - if (matrix_find (mptr, matnum, &matdir) != 0) + matnum = mat_numcod(frame_num, 1, gate_num, data_num, bed_num); + + if (matrix_find(mptr, matnum, &matdir) != 0) return; - - const int strtblk = matdir.strtblk; - switch (mptr->mhptr->file_type) - { + + const int strtblk = matdir.strtblk; + switch (mptr->mhptr->file_type) { #if 0 case CTISinogram: { @@ -163,87 +153,70 @@ dump_subheader(MatrixFile * mptr, } #endif - case Byte3dSinogram: - case Short3dSinogram: - case Float3dSinogram : - { - if (mat_read_Scan3D_subheader (mptr->fptr, mptr->mhptr, strtblk, &scan3dsub)) - { - if (ferror(mptr->fptr)) - perror("dump_subheader: error in reading subheader"); - return; - } - - dump_subheader(scan3dsub); - break; - } - default: - case ByteProjection: - case PetProjection: - case PolarMap: - case Norm3d: - { - fprintf (stderr, "Not implemented yet\n"); - break; - } + case Byte3dSinogram: + case Short3dSinogram: + case Float3dSinogram: { + if (mat_read_Scan3D_subheader(mptr->fptr, mptr->mhptr, strtblk, &scan3dsub)) { + if (ferror(mptr->fptr)) + perror("dump_subheader: error in reading subheader"); + return; } + dump_subheader(scan3dsub); + break; + } + default: + case ByteProjection: + case PetProjection: + case PolarMap: + case Norm3d: { + fprintf(stderr, "Not implemented yet\n"); + break; + } + } } - - - -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { std::string cti_name; - - if(argc==2) - { - cti_name=argv[1]; - } - else - { - cerr<< "\nShow contents of ECAT7 headers.\n" - << "Usage: \n" - << "\t" << argv[0] << " ECAT7_name \n\n" - << "I will now ask you the same info interactively...\n\n"; - cti_name=ask_filename_with_extension("Name of the ECAT7 file? ", ".scn"); - } + if (argc == 2) { + cti_name = argv[1]; + } else { + cerr << "\nShow contents of ECAT7 headers.\n" + << "Usage: \n" + << "\t" << argv[0] << " ECAT7_name \n\n" + << "I will now ask you the same info interactively...\n\n"; + cti_name = ask_filename_with_extension("Name of the ECAT7 file? ", ".scn"); + } - MatrixFile *mptr= - matrix_open( cti_name.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); + MatrixFile* mptr = matrix_open(cti_name.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); if (!mptr) { matrix_perror(cti_name.c_str()); exit(EXIT_FAILURE); } - - const int num_frames = std::max(static_cast( mptr->mhptr->num_frames),1); + + const int num_frames = std::max(static_cast(mptr->mhptr->num_frames), 1); // funnily enough, num_bed_pos seems to be offset with 1 - // (That's to say, in a singled bed study, num_bed_pos==0) + // (That's to say, in a singled bed study, num_bed_pos==0) // TODO maybe not true for multi-bed studies - const int num_bed_poss = static_cast( mptr->mhptr->num_bed_pos) + 1; - const int num_gates = std::max(static_cast( mptr->mhptr->num_gates),1); - - if (ask("Attempt all data-sets (Y) or single data-set (N)", true)) - { - const int data_num=ask_num("Data number ? ",0,8, 0); - - for (int frame_num=1; frame_num<=num_frames;++frame_num) - for (int bed_num=0; bed_num(mptr->mhptr->num_bed_pos) + 1; + const int num_gates = std::max(static_cast(mptr->mhptr->num_gates), 1); + + if (ask("Attempt all data-sets (Y) or single data-set (N)", true)) { + const int data_num = ask_num("Data number ? ", 0, 8, 0); + + for (int frame_num = 1; frame_num <= num_frames; ++frame_num) + for (int bed_num = 0; bed_num < num_bed_poss; ++bed_num) + for (int gate_num = 1; gate_num <= num_gates; ++gate_num) + dump_subheader(mptr, frame_num, 1, gate_num, data_num, bed_num); + } else { + const int frame_num = ask_num("Frame number ? ", 1, num_frames, 1); + const int bed_num = ask_num("Bed number ? ", 0, num_bed_poss - 1, 0); + const int gate_num = ask_num("Gate number ? ", 1, num_gates, 1); + const int data_num = ask_num("Data number ? ", 0, 8, 0); + + dump_subheader(mptr, frame_num, 1, gate_num, data_num, bed_num); } matrix_close(mptr); return EXIT_SUCCESS; diff --git a/src/experimental/utilities/threshold_norm_data.cxx b/src/experimental/utilities/threshold_norm_data.cxx index 6a926a0b84..c27b843e8d 100644 --- a/src/experimental/utilities/threshold_norm_data.cxx +++ b/src/experimental/utilities/threshold_norm_data.cxx @@ -1,5 +1,5 @@ // -// $Id: +// $Id: // /*! @@ -7,7 +7,7 @@ \ingroup utilities \brief Threshold normalisation data -\author Kris Thielemans +\author Kris Thielemans */ @@ -16,8 +16,6 @@ See STIR/LICENSE.txt for details */ - - #include "stir/ProjDataInterfile.h" #include "stir/SegmentByView.h" #include "stir/utilities.h" @@ -25,69 +23,50 @@ #include "stir/Succeeded.h" #include -#include +#include #ifndef STIR_NO_NAMESPACES using std::cerr; using std::endl; #endif - - USING_NAMESPACE_STIR -int -main(int argc, char **argv) +int +main(int argc, char** argv) { - - - if (argc<3 || argc>5) - { + if (argc < 3 || argc > 5) { cerr << " USAGE: threshold_norm_data output_projdata_filename input_projdata_filename [min_threshold [new_value]]\n" - << " new_value defaults to 1E20\n" - << " min_threshold defaults to .01" - << endl; + << " new_value defaults to 1E20\n" + << " min_threshold defaults to .01" << endl; exit(EXIT_FAILURE); } const string output_file_name = argv[1]; - shared_ptr input_proj_data_ptr = - ProjData::read_from_file(argv[2]); - const float min_threshold = - argc>4 ? static_cast(atof(argv[3])) : .01F; - const float new_value = - argc>5 ? static_cast(atof(argv[4])) : 1.E20F; - + shared_ptr input_proj_data_ptr = ProjData::read_from_file(argv[2]); + const float min_threshold = argc > 4 ? static_cast(atof(argv[3])) : .01F; + const float new_value = argc > 5 ? static_cast(atof(argv[4])) : 1.E20F; - shared_ptr proj_data_ptr - (new ProjDataInterfile(input_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), - output_file_name)); + shared_ptr proj_data_ptr( + new ProjDataInterfile(input_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), output_file_name)); Succeeded success = Succeeded::yes; - - for (int segment_num = input_proj_data_ptr->get_min_segment_num(); - segment_num <=input_proj_data_ptr->get_max_segment_num(); - ++segment_num) - { - SegmentByView segment = - input_proj_data_ptr->get_segment_by_view(segment_num); - - for (SegmentByView::full_iterator iter = segment.begin_all(); - iter != segment.end_all(); - ++iter) - { - if (*iter < min_threshold) - *iter = new_value; - } - if (!(proj_data_ptr->set_segment(segment) == Succeeded::yes)) - { - warning("Error set_segment %d\n", segment_num); - success = Succeeded::no; - } + for (int segment_num = input_proj_data_ptr->get_min_segment_num(); segment_num <= input_proj_data_ptr->get_max_segment_num(); + ++segment_num) { + SegmentByView segment = input_proj_data_ptr->get_segment_by_view(segment_num); + + for (SegmentByView::full_iterator iter = segment.begin_all(); iter != segment.end_all(); ++iter) { + if (*iter < min_threshold) + *iter = new_value; + } + if (!(proj_data_ptr->set_segment(segment) == Succeeded::yes)) { + warning("Error set_segment %d\n", segment_num); + success = Succeeded::no; + } } - - return success==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/experimental/utilities/zero_projdata_from_norm.cxx b/src/experimental/utilities/zero_projdata_from_norm.cxx index 420e32f778..881bfd3340 100644 --- a/src/experimental/utilities/zero_projdata_from_norm.cxx +++ b/src/experimental/utilities/zero_projdata_from_norm.cxx @@ -1,5 +1,5 @@ // -// $Id: +// $Id: // /*! @@ -7,7 +7,7 @@ \ingroup utilities \brief Zero projection data when corresponding normalisation factors are too high -\author Kris Thielemans +\author Kris Thielemans */ @@ -22,69 +22,52 @@ #include "stir/Succeeded.h" #include -#include +#include #ifndef STIR_NO_NAMESPACES using std::cerr; using std::endl; #endif - - USING_NAMESPACE_STIR -int -main(int argc, char **argv) +int +main(int argc, char** argv) { - - if (argc<4 || argc>5) - { - cerr << " USAGE: " << argv[0] << " output_projdata_filename input_projdata_filename norm_projdata_filename [max_threshold_in_norm]\n" - << " max_threshold_in_norm defaults to 1E19" - << endl; + if (argc < 4 || argc > 5) { + cerr << " USAGE: " << argv[0] + << " output_projdata_filename input_projdata_filename norm_projdata_filename [max_threshold_in_norm]\n" + << " max_threshold_in_norm defaults to 1E19" << endl; exit(EXIT_FAILURE); } - const string output_file_name = argv[1]; - shared_ptr input_proj_data_ptr = - ProjData::read_from_file(argv[2]); - shared_ptr norm_proj_data_ptr = - ProjData::read_from_file(argv[3]); - const float max_threshold_in_norm = - argc>5 ? static_cast(atof(argv[4])) : 1.E19F; + shared_ptr input_proj_data_ptr = ProjData::read_from_file(argv[2]); + shared_ptr norm_proj_data_ptr = ProjData::read_from_file(argv[3]); + const float max_threshold_in_norm = argc > 5 ? static_cast(atof(argv[4])) : 1.E19F; - shared_ptr proj_data_ptr - (new ProjDataInterfile(input_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), - output_file_name)); + shared_ptr proj_data_ptr( + new ProjDataInterfile(input_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), output_file_name)); Succeeded success = Succeeded::yes; - for (int segment_num = input_proj_data_ptr->get_min_segment_num(); - segment_num <=input_proj_data_ptr->get_max_segment_num(); - ++segment_num) - { - SegmentByView segment = - input_proj_data_ptr->get_segment_by_view(segment_num); - const SegmentByView norm_segment = - norm_proj_data_ptr->get_segment_by_view(segment_num); + for (int segment_num = input_proj_data_ptr->get_min_segment_num(); segment_num <= input_proj_data_ptr->get_max_segment_num(); + ++segment_num) { + SegmentByView segment = input_proj_data_ptr->get_segment_by_view(segment_num); + const SegmentByView norm_segment = norm_proj_data_ptr->get_segment_by_view(segment_num); SegmentByView::full_iterator iter = segment.begin_all(); SegmentByView::const_full_iterator norm_iter = norm_segment.begin_all(); - for (; - iter != segment.end_all(); - ++iter, ++norm_iter) - { - if (*norm_iter > max_threshold_in_norm) - *iter = 0; - } - if (!(proj_data_ptr->set_segment(segment) == Succeeded::yes)) - { - warning("Error writing segment %d\n", segment_num); - success = Succeeded::no; - } + for (; iter != segment.end_all(); ++iter, ++norm_iter) { + if (*norm_iter > max_threshold_in_norm) + *iter = 0; + } + if (!(proj_data_ptr->set_segment(segment) == Succeeded::yes)) { + warning("Error writing segment %d\n", segment_num); + success = Succeeded::no; + } } - - return success==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/include/stir/ArcCorrection.h b/src/include/stir/ArcCorrection.h index cb4d5892f0..cac529d513 100644 --- a/src/include/stir/ArcCorrection.h +++ b/src/include/stir/ArcCorrection.h @@ -27,7 +27,6 @@ #ifndef __stir_ArcCorrection_H__ #define __stir_ArcCorrection_H__ - #include "stir/ProjDataInfo.h" #include "stir/Array.h" #include "stir/shared_ptr.h" @@ -37,17 +36,22 @@ START_NAMESPACE_STIR class Succeeded; class ProjDataInfoCylindricalArcCorr; class ProjDataInfoCylindricalNoArcCorr; -template class Sinogram; -template class Viewgram; -template class RelatedViewgrams; -template class SegmentBySinogram; -template class SegmentByView; +template +class Sinogram; +template +class Viewgram; +template +class RelatedViewgrams; +template +class SegmentBySinogram; +template +class SegmentByView; class ProjData; -/*! - \ingroup projdata +/*! + \ingroup projdata \brief A class to arc-correct projection data - Arc-correction is a common name for converting the non-uniform tangential + Arc-correction is a common name for converting the non-uniform tangential sampling from a cylindrical PET scanner to a uniform one. (GE terminology is 'geometric correction'). @@ -55,14 +59,13 @@ class ProjData; For given non-arccorrected data, the data will be first multiplied by the bin-sizes, then interpolated to the desired uniform sampling using overlap_interpolate, - and then divided by the new sampling. This ensures that the normalisation + and then divided by the new sampling. This ensures that the normalisation is preserved. Also, uniform data will result in uniform output. \warning You have to call one of the set_up() functions before use of any other member function. */ -class ArcCorrection -{ +class ArcCorrection { public: ArcCorrection(); @@ -74,65 +77,57 @@ class ArcCorrection */ //@{ //! Most general version - Succeeded - set_up(const shared_ptr& proj_data_info_sptr, - const int num_arccorrected_tangential_poss, const float bin_size); + Succeeded set_up(const shared_ptr& proj_data_info_sptr, const int num_arccorrected_tangential_poss, + const float bin_size); //! Using default bin-size of the scanner /*! If the default bin-size is 0, the tangential size of the central bin (i.e. Bin(0,0,0,0)) of the non-arccorrected data will be used. */ - Succeeded - set_up(const shared_ptr& proj_data_info_sptr, - const int num_arccorrected_tangential_poss); + Succeeded set_up(const shared_ptr& proj_data_info_sptr, const int num_arccorrected_tangential_poss); //! Using default bin-size of the scanner and covering the FOV /*! If the default bin-size is 0, the tangential size of the central bin (i.e. Bin(0,0,0,0)) of the non-arccorrected data will be used. \c num_arccorrected_bins is chosen such that the new (radial) FOV - is slightly larger than the one covered by the original data. + is slightly larger than the one covered by the original data. */ - Succeeded - set_up(const shared_ptr& proj_data_info_sptr); + Succeeded set_up(const shared_ptr& proj_data_info_sptr); //@} /*! \name functions returning a ProjDataInfoCylindricalArcCorr object describing to the arc-corrected data. */ //@{ - const ProjDataInfoCylindricalArcCorr& - get_arc_corrected_proj_data_info() const; + const ProjDataInfoCylindricalArcCorr& get_arc_corrected_proj_data_info() const; //! Returning a shared_ptr to the object /*! \todo return a shared_ptr after switching to boost::shared_ptr. */ - shared_ptr - get_arc_corrected_proj_data_info_sptr() const; + shared_ptr get_arc_corrected_proj_data_info_sptr() const; //@} /*! \name functions returning a ProjDataInfoCylindricalArcCorr object describing to the arc-corrected data. */ //@{ - const ProjDataInfoCylindricalNoArcCorr& - get_not_arc_corrected_proj_data_info() const; + const ProjDataInfoCylindricalNoArcCorr& get_not_arc_corrected_proj_data_info() const; //! Returning a shared_ptr to the object /*! \todo return a shared_ptr after switching to boost::shared_ptr. */ - shared_ptr - get_not_arc_corrected_proj_data_info_sptr() const; + shared_ptr get_not_arc_corrected_proj_data_info_sptr() const; //@} //! \name functions to do the arc-correction /*! Almost all these functions come in pairs (the exception being the - function that arc-corrects a whole ProjData). + function that arc-corrects a whole ProjData). The 1 argument version returns the arc-corrected data. In the 2 argument version, the first argument - will be filled with the arc-corrected data. - \warning In the 2 argument version, the output argument has to + will be filled with the arc-corrected data. + \warning In the 2 argument version, the output argument has to have a projection data info corresponding to the one returned by get_arc_corrected_proj_data_info(). This is (only) checked using assert(). @@ -154,14 +149,13 @@ class ArcCorrection private: shared_ptr _noarc_corr_proj_data_info_sptr; shared_ptr _arc_corr_proj_data_info_sptr; - Array<1,float> _arccorr_coords; - Array<1,float> _noarccorr_coords; - Array<1,float> _noarccorr_bin_sizes; + Array<1, float> _arccorr_coords; + Array<1, float> _noarccorr_coords; + Array<1, float> _noarccorr_bin_sizes; float tangential_sampling; - void do_arc_correction(Array<1,float>& out, const Array<1,float>& in) const; + void do_arc_correction(Array<1, float>& out, const Array<1, float>& in) const; }; END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/Array.h b/src/include/stir/Array.h index 9a2ec89530..9eb1bdd58c 100644 --- a/src/include/stir/Array.h +++ b/src/include/stir/Array.h @@ -22,44 +22,44 @@ #define __stir_Array_H__ #ifndef ARRAY_FULL -#define ARRAY_FULL +# define ARRAY_FULL #endif /*! - \file - \ingroup Array + \file + \ingroup Array \brief defines the Array class for multi-dimensional (numeric) arrays \author Kris Thielemans (with help from Alexey Zverovich) \author PARAPET project \author Gemma Fardell - Not all compilers support the full iterators, so you could disabled them by editing - the file and removing the define ARRAY_FULL. Lots of other things in the library + Not all compilers support the full iterators, so you could disabled them by editing + the file and removing the define ARRAY_FULL. Lots of other things in the library won't work then. */ #include "stir/NumericVectorWithOffset.h" #include "stir/ByteOrder.h" -#include "stir/IndexRange.h" +#include "stir/IndexRange.h" #include "stir/deprecated.h" START_NAMESPACE_STIR class NumericType; #ifdef ARRAY_FULL -#ifndef ARRAY_FULL2 +# ifndef ARRAY_FULL2 template class FullArrayIterator; -#else +# else template class FullArrayIterator; template class FullArrayConstIterator; -#endif +# endif #endif -/*! +/*! \ingroup Array \brief This class defines multi-dimensional (numeric) arrays. @@ -76,18 +76,17 @@ called, which initialises new elements first to 0. */ template -class Array : public NumericVectorWithOffset, elemT> -{ +class Array : public NumericVectorWithOffset, elemT> { #ifdef SWIG // work-around swig problem. It gets confused when using a private (or protected) // typedef in a definition of a public typedef/member public: #else - private: -#endif - typedef Array self; - typedef NumericVectorWithOffset, elemT> base_type; - +private: +#endif + typedef Array self; + typedef NumericVectorWithOffset, elemT> base_type; + public: //@{ //! typedefs such that we do not need to have \c typename wherever we use these types defined in the base class @@ -102,7 +101,7 @@ class Array : public NumericVectorWithOffset, ele #ifdef ARRAY_FULL /*! @name typedefs for full_iterator support Full iterators provide a 1-dimensional view on a multi-dimensional - Array. + Array. */ //@{ @@ -111,19 +110,23 @@ class Array : public NumericVectorWithOffset, ele typedef const full_value_type* const_full_pointer; typedef full_value_type& full_reference; typedef const full_value_type& const_full_reference; -#ifndef ARRAY_FULL2 +# ifndef ARRAY_FULL2 //! This defines an iterator type that iterates through all elements. - typedef FullArrayIterator::full_iterator, elemT, full_reference, full_pointer> full_iterator; + typedef FullArrayIterator::full_iterator, elemT, + full_reference, full_pointer> + full_iterator; //! As full_iterator, but for const objects. - typedef FullArrayIterator::const_full_iterator, elemT, const_full_reference, const_full_pointer> const_full_iterator; -#else // ARRAY_FULL2 + typedef FullArrayIterator::const_full_iterator, + elemT, const_full_reference, const_full_pointer> + const_full_iterator; +# else // ARRAY_FULL2 typedef FullArrayIterator full_iterator; typedef FullArrayConstIterator const_full_iterator; -#endif - //@} +# endif + //@} #endif public: //! Construct an empty Array @@ -131,18 +134,18 @@ class Array : public NumericVectorWithOffset, ele //! Construct an Array of given range of indices, elements are initialised to 0 inline explicit Array(const IndexRange&); - + #ifndef SWIG //! Construct an Array from an object of its base_type inline Array(const base_type& t); #else // swig 2.0.4 gets confused by base_type (due to numeric template arguments) - // therefore, we declare this constructor using the "self" type, + // therefore, we declare this constructor using the "self" type, // i.e. it's just a copy-constructor. // This is less powerful as in C++, but swig-generated interfaces don't need to know about the base_type anyway inline Array(const self& t); #endif - + //! virtual destructor, frees up any allocated memory inline virtual ~Array(); @@ -165,39 +168,37 @@ class Array : public NumericVectorWithOffset, ele inline IndexRange get_index_range() const; //! return the total number of elements in this array - inline size_t size_all() const; + inline size_t size_all() const; /* Implementation note: grow() and resize() are inline such that they are defined for any type you happen to use for elemT. Otherwise, we would need instantiation in Array.cxx. */ - //! change the array to a new range of indices, new elements are set to 0 - inline virtual void - resize(const IndexRange& range); - - //! grow the array to a new range of indices, new elements are set to 0 - virtual inline void - grow(const IndexRange& range); - + //! change the array to a new range of indices, new elements are set to 0 + inline virtual void resize(const IndexRange& range); + + //! grow the array to a new range of indices, new elements are set to 0 + virtual inline void grow(const IndexRange& range); + //! return sum of all elements - inline elemT sum() const ; - + inline elemT sum() const; + //! return sum of all positive elements - inline elemT sum_positive() const ; - + inline elemT sum_positive() const; + //! return maximum of all the elements inline elemT find_max() const; - + //! return minimum of all the elements inline elemT find_min() const; - + //! Fill elements with value n (overrides VectorWithOffset::fill) - inline void fill(const elemT &n); + inline void fill(const elemT& n); //! checks if the index range is 'regular' /*! Implementation note: this works by calling get_index_range().is_regular(). We cannot rely on remembering if it was a regular range at construction (or - even resizing) time as resize() could have been called on an element of the + even resizing) time as resize() could have been called on an element of the array. Checking for this would involve a performance penalty on operator[], which is definitely not a good idea. */ @@ -205,91 +206,73 @@ class Array : public NumericVectorWithOffset, ele //! find regular range, returns \c false if the range is not regular /*! \see class IndexRange for a definition of (ir)regular ranges */ - bool get_regular_range( - BasicCoordinate& min, - BasicCoordinate& max) const; - + bool get_regular_range(BasicCoordinate& min, BasicCoordinate& max) const; + //! allow array-style access, read/write - inline Array& - operator[] (int i); + inline Array& operator[](int i); //! array access, read-only - inline const Array& - operator[] (int i) const; + inline const Array& operator[](int i) const; - //! allow array-style access given a BasicCoordinate to specify the indices, read/write - inline elemT& - operator[](const BasicCoordinate &c) ; + //! allow array-style access given a BasicCoordinate to specify the indices, read/write + inline elemT& operator[](const BasicCoordinate& c); //! array access given a BasicCoordinate to specify the indices, read-only // TODO alternative return value: elemT - inline const elemT& - operator[](const BasicCoordinate &c) const; + inline const elemT& operator[](const BasicCoordinate& c) const; //! \name indexed access with range checking (throw std:out_of_range) //@{ - inline Array& - at (int i); + inline Array& at(int i); - inline const Array& - at (int i) const; + inline const Array& at(int i) const; - inline elemT& - at(const BasicCoordinate &c) ; + inline elemT& at(const BasicCoordinate& c); - inline const elemT& - at(const BasicCoordinate &c) const; + inline const elemT& at(const BasicCoordinate& c) const; //@} //! \deprecated a*x+b*y (\see xapyb) template - STIR_DEPRECATED inline void axpby(const elemT2 a, const Array& x, - const elemT2 b, const Array& y); - + STIR_DEPRECATED inline void axpby(const elemT2 a, const Array& x, const elemT2 b, const Array& y); + //! set values of the array to x*a+y*b, where a and b are scalar -inline void xapyb(const Array& x, const elemT a, - const Array& y, const elemT b); + inline void xapyb(const Array& x, const elemT a, const Array& y, const elemT b); - //! set values of the array to x*a+y*b, where a and b are arrays -inline void xapyb(const Array& x, const Array& a, - const Array& y, const Array& b); + //! set values of the array to x*a+y*b, where a and b are arrays + inline void xapyb(const Array& x, const Array& a, const Array& y, const Array& b); //! set values of the array to self*a+y*b where a and b are scalar or arrays -template -inline void sapyb(const T &a, - const Array& y, const T &b); - + template + inline void sapyb(const T& a, const Array& y, const T& b); }; - - /************************************************** (partial) specialisation for 1 dimensional arrays **************************************************/ #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -//! The 1-dimensional (partial) specialisation of Array. +//! The 1-dimensional (partial) specialisation of Array. template class Array<1, elemT> : public NumericVectorWithOffset -#ifdef STIR_USE_BOOST - , - boost::operators, NumericVectorWithOffset >, - boost::operators >, - boost::operators, elemT> -#endif +# ifdef STIR_USE_BOOST + , + boost::operators, NumericVectorWithOffset>, + boost::operators>, + boost::operators, elemT> +# endif { -#ifdef SWIG +# ifdef SWIG // work-around swig problem. It gets confused when using a private (or protected) // typedef in a definition of a public typedef/member public: -#else - private: -#endif - typedef NumericVectorWithOffset base_type; +# else +private: +# endif + typedef NumericVectorWithOffset base_type; typedef Array<1, elemT> self; - public: //! typedefs such that we do not need to have \c typename wherever we use these types defined in the base class //@{ @@ -310,21 +293,20 @@ class Array<1, elemT> : public NumericVectorWithOffset //! Iterator type for going through all elements of a const object typedef const_iterator const_full_iterator; - + public: - //! default constructor: array of length 0 inline Array(); - + //! constructor given an IndexRange<1>, initialising elements to 0 inline explicit Array(const IndexRange<1>& range); - + //! constructor given first and last indices, initialising elements to 0 inline Array(const int min_index, const int max_index); //! constructor from basetype - inline Array(const NumericVectorWithOffset &il); - + inline Array(const NumericVectorWithOffset& il); + //! virtual destructor inline virtual ~Array(); @@ -348,148 +330,140 @@ class Array<1, elemT> : public NumericVectorWithOffset inline IndexRange<1> get_index_range() const; //! return the total number of elements in this array - inline size_t size_all() const; + inline size_t size_all() const; //! Array::grow initialises new elements to 0 inline virtual void grow(const IndexRange<1>& range); - + // Array::grow initialises new elements to 0 inline virtual void grow(const int min_index, const int max_index); - + //! Array::resize initialises new elements to 0 inline virtual void resize(const IndexRange<1>& range); - + // Array::resize initialises new elements to 0 inline virtual void resize(const int min_index, const int max_index); - + //! return sum of all elements inline elemT sum() const; - + //! add up all positive elemTs in the vector inline elemT sum_positive() const; - + //! return maximum value of all elements inline elemT find_max() const; - + //! return minimum value of all elements inline elemT find_min() const; - + //! checks if the index range is 'regular' (always \c true as this is the 1D case) inline bool is_regular() const; - + //! find regular range, returns \c false if the range is not regular - bool get_regular_range( - BasicCoordinate<1, int>& min, - BasicCoordinate<1, int>& max) const; - -#ifndef STIR_USE_BOOST - - /* KT 31/01/2000 I had to add these functions here, although they are + bool get_regular_range(BasicCoordinate<1, int>& min, BasicCoordinate<1, int>& max) const; + +# ifndef STIR_USE_BOOST + + /* KT 31/01/2000 I had to add these functions here, although they are in NumericVectorWithOffset already. - Reason: we allow addition (and similar operations) of tensors of + Reason: we allow addition (and similar operations) of tensors of different sizes. This implies that operator+= can call a 'grow' - on retval. For this to work, retval should be an Array, not + on retval. For this to work, retval should be an Array, not its base_type (which happens if these function are not repeated in this class). Complicated... */ //! elem by elem addition - inline self operator+ (const base_type &iv) const; - + inline self operator+(const base_type& iv) const; + //! elem by elem subtraction - inline self operator- (const base_type &iv) const; - + inline self operator-(const base_type& iv) const; + //! elem by elem multiplication - inline self operator* (const base_type &iv) const; - + inline self operator*(const base_type& iv) const; + //! elem by elem division - inline self operator/ (const base_type &iv) const; - + inline self operator/(const base_type& iv) const; + //! addition with an 'elemT' - inline self operator+ (const elemT a) const; - + inline self operator+(const elemT a) const; + //! subtraction with an 'elemT' - inline self operator- (const elemT a) const; - + inline self operator-(const elemT a) const; + //! multiplication with an 'elemT' - inline self operator* (const elemT a) const; - + inline self operator*(const elemT a) const; + //! division with an 'elemT' - inline self operator/ (const elemT a) const; + inline self operator/(const elemT a) const; -#endif // boost +# endif // boost - //! allow array-style access, read/write - inline elemT& operator[] (int i); + //! allow array-style access, read/write + inline elemT& operator[](int i); //! array access, read-only - inline const elemT& operator[] (int i) const; - - //! allow array-style access giving its BasicCoordinate, read/write - inline const elemT& operator[](const BasicCoordinate<1,int>& c) const; + inline const elemT& operator[](int i) const; + + //! allow array-style access giving its BasicCoordinate, read/write + inline const elemT& operator[](const BasicCoordinate<1, int>& c) const; //! array access giving its BasicCoordinate, read-only - inline elemT& operator[](const BasicCoordinate<1,int>& c) ; + inline elemT& operator[](const BasicCoordinate<1, int>& c); //! \name indexed access with range checking (throw std:out_of_range) //@{ - inline elemT& - at (int i); + inline elemT& at(int i); - inline const elemT& - at (int i) const; + inline const elemT& at(int i) const; - inline elemT& - at(const BasicCoordinate<1,int> &c) ; + inline elemT& at(const BasicCoordinate<1, int>& c); - inline const elemT& - at(const BasicCoordinate<1,int> &c) const; + inline const elemT& at(const BasicCoordinate<1, int>& c) const; //@} }; - #else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -/* - If the compiler does not support partial template specialisation, +/* + If the compiler does not support partial template specialisation, we resort to multiple definitions of the class, for specific types of elemT. This of course means that if you want to use Array for 'elemT' - anything else then the types used defined here, you'll have to add + anything else then the types used defined here, you'll have to add similar repetitions yourself... Currently supported for signed char, float, int, short, unsigned short */ -#define elemT signed char -#include "stir/Array1d.h" -#define elemT short -#include "stir/Array1d.h" -#define elemT unsigned short -#include "stir/Array1d.h" -#define elemT int -#include "stir/Array1d.h" -#define elemT float -#include "stir/Array1d.h" +# define elemT signed char +# include "stir/Array1d.h" +# define elemT short +# include "stir/Array1d.h" +# define elemT unsigned short +# include "stir/Array1d.h" +# define elemT int +# include "stir/Array1d.h" +# define elemT float +# include "stir/Array1d.h" END_NAMESPACE_STIR -#include +# include START_NAMESPACE_STIR -#define __stir_Array1d_no_comparisons__ -#define elemT std::complex -#include "stir/Array1d.h" -#undef elemT +# define __stir_Array1d_no_comparisons__ +# define elemT std::complex +# include "stir/Array1d.h" +# undef elemT #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION END_NAMESPACE_STIR #ifdef ARRAY_FULL # ifndef ARRAY_FULL2 -# include "FullArrayIterator.h" +# include "FullArrayIterator.h" # else # include "FullArrayIterator2.h" -# include "FullArrayConstIterator.h" +# include "FullArrayConstIterator.h" # endif #endif #include "stir/Array.inl" - #endif // __Array_H__ diff --git a/src/include/stir/Array.inl b/src/include/stir/Array.inl index 02bf3f93f8..8380e85b7c 100644 --- a/src/include/stir/Array.inl +++ b/src/include/stir/Array.inl @@ -19,9 +19,9 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup Array - \brief inline implementations for the stir::Array class + \file + \ingroup Array + \brief inline implementations for the stir::Array class \author Kris Thielemans (with help from Alexey Zverovich) \author PARAPET project @@ -39,36 +39,26 @@ START_NAMESPACE_STIR **********************************************/ template -void -Array:: -resize(const IndexRange& range) -{ +void +Array::resize(const IndexRange& range) { base_type::resize(range.get_min_index(), range.get_max_index()); typename base_type::iterator iter = this->begin(); typename IndexRange::const_iterator range_iter = range.begin(); - for (; - iter != this->end(); - ++iter, ++range_iter) + for (; iter != this->end(); ++iter, ++range_iter) (*iter).resize(*range_iter); } template -void -Array:: -grow(const IndexRange& range) -{ +void +Array::grow(const IndexRange& range) { resize(range); } template -Array::Array() -: base_type() -{} +Array::Array() : base_type() {} template -Array::Array(const IndexRange& range) -: base_type() -{ +Array::Array(const IndexRange& range) : base_type() { grow(range); } @@ -79,161 +69,127 @@ Array::Array(const self& t) #else Array::Array(const base_type& t) #endif -: base_type(t) -{} +: base_type(t) { +} template -Array::~Array() -{} - +Array::~Array() {} template -typename Array::full_iterator -Array::end_all() -{ +typename Array::full_iterator +Array::end_all() { // note this value is fixed by the current convention in full_iterator::operator++() - return full_iterator(this->end(), this->end(), - typename Array::full_iterator(0), - typename Array::full_iterator(0)); + return full_iterator(this->end(), this->end(), typename Array::full_iterator(0), + typename Array::full_iterator(0)); } template -typename Array::const_full_iterator -Array::end_all_const() const -{ - return const_full_iterator(this->end(), this->end(), - typename Array::const_full_iterator(0), - typename Array::const_full_iterator(0)); +typename Array::const_full_iterator +Array::end_all_const() const { + return const_full_iterator(this->end(), this->end(), typename Array::const_full_iterator(0), + typename Array::const_full_iterator(0)); } template -typename Array::const_full_iterator -Array::end_all() const -{ +typename Array::const_full_iterator +Array::end_all() const { return this->end_all_const(); } template -typename Array::full_iterator -Array::begin_all() -{ - if (this->begin() == this->end()) - { +typename Array::full_iterator +Array::begin_all() { + if (this->begin() == this->end()) { // empty array - return end_all(); - } - else - return full_iterator(this->begin(), this->end(), - this->begin()->begin_all(), this->begin()->end_all()); + return end_all(); + } else + return full_iterator(this->begin(), this->end(), this->begin()->begin_all(), this->begin()->end_all()); } - + template -typename Array::const_full_iterator -Array::begin_all_const() const -{ - if (this->begin() == this->end()) - { +typename Array::const_full_iterator +Array::begin_all_const() const { + if (this->begin() == this->end()) { // empty array - return end_all(); - } - else - return const_full_iterator(this->begin(), this->end(), - this->begin()->begin_all_const(), this->begin()->end_all_const()); + return end_all(); + } else + return const_full_iterator(this->begin(), this->end(), this->begin()->begin_all_const(), this->begin()->end_all_const()); } template -typename Array::const_full_iterator -Array::begin_all() const -{ +typename Array::const_full_iterator +Array::begin_all() const { return begin_all_const(); } template IndexRange -Array::get_index_range() const -{ - VectorWithOffset > - range(this->get_min_index(), this->get_max_index()); +Array::get_index_range() const { + VectorWithOffset> range(this->get_min_index(), this->get_max_index()); - typename VectorWithOffset >::iterator range_iter = - range.begin(); + typename VectorWithOffset>::iterator range_iter = range.begin(); const_iterator array_iter = this->begin(); - for (; - range_iter != range.end(); - range_iter++, array_iter++) - { - *range_iter = (*array_iter).get_index_range(); + for (; range_iter != range.end(); range_iter++, array_iter++) { + *range_iter = (*array_iter).get_index_range(); } return IndexRange(range); } template size_t -Array::size_all() const -{ +Array::size_all() const { this->check_state(); - size_t acc=0; - for(int i=this->get_min_index(); i<=this->get_max_index(); i++) + size_t acc = 0; + for (int i = this->get_min_index(); i <= this->get_max_index(); i++) acc += this->num[i].size_all(); - return acc; + return acc; } - template -elemT -Array::sum() const -{ +elemT +Array::sum() const { this->check_state(); elemT acc; - assign(acc,0); - for(int i=this->get_min_index(); i<=this->get_max_index(); i++) + assign(acc, 0); + for (int i = this->get_min_index(); i <= this->get_max_index(); i++) acc += this->num[i].sum(); - return acc; + return acc; } template -elemT -Array::sum_positive() const -{ +elemT +Array::sum_positive() const { this->check_state(); elemT acc; - assign(acc,0); - for(int i=this->get_min_index(); i<=this->get_max_index(); i++) + assign(acc, 0); + for (int i = this->get_min_index(); i <= this->get_max_index(); i++) acc += this->num[i].sum_positive(); - return acc; + return acc; } template -elemT -Array::find_max() const -{ +elemT +Array::find_max() const { this->check_state(); - if (this->size() > 0) - { - elemT maxval= this->num[this->get_min_index()].find_max(); - for(int i=this->get_min_index()+1; i<=this->get_max_index(); i++) - { + if (this->size() > 0) { + elemT maxval = this->num[this->get_min_index()].find_max(); + for (int i = this->get_min_index() + 1; i <= this->get_max_index(); i++) { maxval = std::max(this->num[i].find_max(), maxval); } return maxval; - } - else - { - //TODO we should return elemT::minimum or something - return 0; + } else { + // TODO we should return elemT::minimum or something + return 0; } } template -elemT -Array::find_min() const -{ +elemT +Array::find_min() const { this->check_state(); - if (this->size() > 0) - { - elemT minval= this->num[this->get_min_index()].find_min(); - for(int i=this->get_min_index()+1; i<=this->get_max_index(); i++) - { + if (this->size() > 0) { + elemT minval = this->num[this->get_min_index()].find_min(); + for (int i = this->get_min_index() + 1; i <= this->get_max_index(); i++) { #ifndef STIR_NO_NAMESPACES minval = std::min(this->num[i].find_min(), minval); #else @@ -241,109 +197,90 @@ Array::find_min() const #endif } return minval; - } - else - { - //TODO we should return elemT::maximum or something - return 0; + } else { + // TODO we should return elemT::maximum or something + return 0; } } template -void -Array::fill(const elemT &n) -{ +void +Array::fill(const elemT& n) { this->check_state(); - for(int i=this->get_min_index(); i<=this->get_max_index(); i++) + for (int i = this->get_min_index(); i <= this->get_max_index(); i++) this->num[i].fill(n); this->check_state(); } template bool -Array::is_regular() const -{ +Array::is_regular() const { return get_index_range().is_regular(); } -//TODO terribly inefficient at the moment +// TODO terribly inefficient at the moment template bool -Array::get_regular_range( - BasicCoordinate& min, - BasicCoordinate& max) const -{ +Array::get_regular_range(BasicCoordinate& min, + BasicCoordinate& max) const { const IndexRange range = get_index_range(); - return range.get_regular_range(min,max); + return range.get_regular_range(min, max); } template -Array& -Array::operator[](int i) -{ - return base_type::operator[](i); -} +Array& +Array::operator[](int i) { + return base_type::operator[](i); +} template -const Array& -Array::operator[](int i) const -{ +const Array& +Array::operator[](int i) const { return base_type::operator[](i); -} +} template elemT& -Array::operator[](const BasicCoordinate &c) -{ - return (*this)[c[1]][cut_first_dimension(c)]; -} +Array::operator[](const BasicCoordinate& c) { + return (*this)[c[1]][cut_first_dimension(c)]; +} template const elemT& -Array::operator[](const BasicCoordinate &c) const -{ - return (*this)[c[1]][cut_first_dimension(c)] ; -} +Array::operator[](const BasicCoordinate& c) const { + return (*this)[c[1]][cut_first_dimension(c)]; +} template -Array& -Array::at(int i) -{ - return base_type::at(i); -} +Array& +Array::at(int i) { + return base_type::at(i); +} template -const Array& -Array::at(int i) const -{ +const Array& +Array::at(int i) const { return base_type::at(i); -} +} template elemT& -Array::at(const BasicCoordinate &c) -{ - return (*this).at(c[1]).at(cut_first_dimension(c)); -} +Array::at(const BasicCoordinate& c) { + return (*this).at(c[1]).at(cut_first_dimension(c)); +} template const elemT& -Array::at(const BasicCoordinate &c) const -{ - return (*this).at(c[1]).at(cut_first_dimension(c)); +Array::at(const BasicCoordinate& c) const { + return (*this).at(c[1]).at(cut_first_dimension(c)); } template template void -Array:: -axpby(const elemT2 a, const Array& x, - const elemT2 b, const Array& y) -{ - Array::xapyb(x,a,y,b); +Array::axpby(const elemT2 a, const Array& x, const elemT2 b, const Array& y) { + Array::xapyb(x, a, y, b); } template -void Array:: - xapyb(const Array &x, const elemT a, - const Array &y, const elemT b) -{ +void +Array::xapyb(const Array& x, const elemT a, const Array& y, const elemT b) { this->check_state(); if ((this->get_index_range() != x.get_index_range()) || (this->get_index_range() != y.get_index_range())) error("Array::xapyb: index ranges don't match"); @@ -351,22 +288,17 @@ void Array:: typename Array::full_iterator this_iter = this->begin_all(); typename Array::const_full_iterator x_iter = x.begin_all(); typename Array::const_full_iterator y_iter = y.begin_all(); - while (this_iter != this->end_all()) - { - *this_iter++ = (*x_iter++) * a + (*y_iter++) * b; + while (this_iter != this->end_all()) { + *this_iter++ = (*x_iter++) * a + (*y_iter++) * b; } } template -void Array:: - xapyb(const Array &x, const Array &a, - const Array &y, const Array &b) -{ +void +Array::xapyb(const Array& x, const Array& a, const Array& y, const Array& b) { this->check_state(); - if ((this->get_index_range() != x.get_index_range()) - || (this->get_index_range() != y.get_index_range()) - || (this->get_index_range() != a.get_index_range()) - || (this->get_index_range() != b.get_index_range())) + if ((this->get_index_range() != x.get_index_range()) || (this->get_index_range() != y.get_index_range()) || + (this->get_index_range() != a.get_index_range()) || (this->get_index_range() != b.get_index_range())) error("Array::xapyb: index ranges don't match"); typename Array::full_iterator this_iter = this->begin_all(); @@ -375,18 +307,15 @@ void Array:: typename Array::const_full_iterator a_iter = a.begin_all(); typename Array::const_full_iterator b_iter = b.begin_all(); - while (this_iter != this->end_all()) - { - *this_iter++ = (*x_iter++) * (*a_iter++) + (*y_iter++) * (*b_iter++); + while (this_iter != this->end_all()) { + *this_iter++ = (*x_iter++) * (*a_iter++) + (*y_iter++) * (*b_iter++); } } template template -void Array:: - sapyb(const T &a, - const Array &y, const T &b) -{ +void +Array::sapyb(const T& a, const Array& y, const T& b) { this->xapyb(*this, a, y, b); } @@ -398,242 +327,194 @@ void Array:: template void -Array<1, elemT>::resize(const int min_index, const int max_index) -{ +Array<1, elemT>::resize(const int min_index, const int max_index) { this->check_state(); const int oldstart = this->get_min_index(); const size_type oldlength = this->size(); - + base_type::resize(min_index, max_index); - if (oldlength == 0) - { - for (int i=this->get_min_index(); i<=this->get_max_index(); i++) + if (oldlength == 0) { + for (int i = this->get_min_index(); i <= this->get_max_index(); i++) assign(this->num[i], 0); - } - else - { - for (int i=this->get_min_index(); iget_max_index(); ++i) + } else { + for (int i = this->get_min_index(); i < oldstart && i <= this->get_max_index(); ++i) assign(this->num[i], 0); - for (int i=std::max(static_cast(oldstart + oldlength), this->get_min_index()); - i<=this->get_max_index(); - ++i) + for (int i = std::max(static_cast(oldstart + oldlength), this->get_min_index()); i <= this->get_max_index(); ++i) assign(this->num[i], 0); } - this->check_state(); + this->check_state(); } template void -Array<1, elemT>::resize(const IndexRange<1>& range) -{ +Array<1, elemT>::resize(const IndexRange<1>& range) { resize(range.get_min_index(), range.get_max_index()); } template void -Array<1, elemT>::grow(const int min_index, const int max_index) -{ +Array<1, elemT>::grow(const int min_index, const int max_index) { resize(min_index, max_index); } template void -Array<1, elemT>::grow(const IndexRange<1>& range) -{ +Array<1, elemT>::grow(const IndexRange<1>& range) { grow(range.get_min_index(), range.get_max_index()); } - template -Array<1, elemT>::Array() -: base_type() -{ } +Array<1, elemT>::Array() : base_type() {} template -Array<1, elemT>::Array(const IndexRange<1>& range) -: base_type() -{ +Array<1, elemT>::Array(const IndexRange<1>& range) : base_type() { grow(range); } template -Array<1, elemT>::Array(const int min_index, const int max_index) -: base_type() -{ +Array<1, elemT>::Array(const int min_index, const int max_index) : base_type() { grow(min_index, max_index); } - template -Array<1, elemT>::Array(const base_type &il) -: base_type(il) -{} +Array<1, elemT>::Array(const base_type& il) : base_type(il) {} template -Array<1, elemT>::~Array() -{} +Array<1, elemT>::~Array() {} template -typename Array<1, elemT>::full_iterator -Array<1, elemT>::begin_all() -{ +typename Array<1, elemT>::full_iterator +Array<1, elemT>::begin_all() { return this->begin(); } - + template -typename Array<1, elemT>::const_full_iterator -Array<1, elemT>::begin_all() const -{ +typename Array<1, elemT>::const_full_iterator +Array<1, elemT>::begin_all() const { return this->begin(); } template -typename Array<1, elemT>::full_iterator -Array<1, elemT>::end_all() -{ +typename Array<1, elemT>::full_iterator +Array<1, elemT>::end_all() { return this->end(); } - template -typename Array<1, elemT>::const_full_iterator -Array<1, elemT>::end_all() const -{ - return this->end(); +typename Array<1, elemT>::const_full_iterator +Array<1, elemT>::end_all() const { + return this->end(); } template -typename Array<1, elemT>::const_full_iterator -Array<1, elemT>::begin_all_const() const -{ +typename Array<1, elemT>::const_full_iterator +Array<1, elemT>::begin_all_const() const { return this->begin(); } template -typename Array<1, elemT>::const_full_iterator -Array<1, elemT>::end_all_const() const -{ - return this->end(); +typename Array<1, elemT>::const_full_iterator +Array<1, elemT>::end_all_const() const { + return this->end(); } template -IndexRange<1> -Array<1, elemT>::get_index_range() const -{ +IndexRange<1> +Array<1, elemT>::get_index_range() const { return IndexRange<1>(this->get_min_index(), this->get_max_index()); } template size_t -Array<1, elemT>::size_all() const -{ +Array<1, elemT>::size_all() const { return this->size(); } template elemT -Array<1, elemT>::sum() const -{ +Array<1, elemT>::sum() const { this->check_state(); elemT acc; - assign(acc,0); - for(int i=this->get_min_index(); i<=this->get_max_index(); acc+=this->num[i++]) - {} - return acc; + assign(acc, 0); + for (int i = this->get_min_index(); i <= this->get_max_index(); acc += this->num[i++]) { + } + return acc; }; - template elemT -Array<1, elemT>::sum_positive() const -{ +Array<1, elemT>::sum_positive() const { this->check_state(); elemT acc; - assign(acc,0); - for(int i=this->get_min_index(); i<=this->get_max_index(); i++) - { + assign(acc, 0); + for (int i = this->get_min_index(); i <= this->get_max_index(); i++) { if (this->num[i] > 0) acc += this->num[i]; } - return acc; + return acc; }; - template elemT -Array<1, elemT>::find_max() const -{ +Array<1, elemT>::find_max() const { this->check_state(); - if (this->size() > 0) - { -#ifndef STIR_NO_NAMESPACES - return *std::max_element(this->begin(), this->end()); -#else + if (this->size() > 0) { +# ifndef STIR_NO_NAMESPACES + return *std::max_element(this->begin(), this->end()); +# else return *max_element(this->begin(), this->end()); -#endif - } - else - { +# endif + } else { // TODO return elemT::minimum or so - return 0; - } + return 0; + } this->check_state(); }; - template elemT -Array<1, elemT>::find_min() const -{ +Array<1, elemT>::find_min() const { this->check_state(); - if (this->size() > 0) - { -#ifndef STIR_NO_NAMESPACES + if (this->size() > 0) { +# ifndef STIR_NO_NAMESPACES return *std::min_element(this->begin(), this->end()); -#else +# else return *min_element(this->begin(), this->end()); -#endif - } - else - { +# endif + } else { // TODO return elemT::maximum or so - return 0; - } + return 0; + } this->check_state(); -}; +}; template bool -Array<1, elemT>::is_regular() const -{ +Array<1, elemT>::is_regular() const { return true; } template bool -Array<1, elemT>::get_regular_range( - BasicCoordinate<1, int>& min, - BasicCoordinate<1, int>& max) const -{ +Array<1, elemT>::get_regular_range(BasicCoordinate<1, int>& min, BasicCoordinate<1, int>& max) const { const IndexRange<1> range = get_index_range(); - return range.get_regular_range(min,max); + return range.get_regular_range(min, max); } -#ifndef STIR_USE_BOOST +# ifndef STIR_USE_BOOST -/* KT 31/01/2000 I had to add these functions here, although they are +/* KT 31/01/2000 I had to add these functions here, although they are in NumericVectorWithOffset already. -Reason: we allow addition (and similar operations) of tensors of +Reason: we allow addition (and similar operations) of tensors of different sizes. This implies that operator+= can call a 'grow' -on retval. For this to work, retval should be a Array, not +on retval. For this to work, retval should be a Array, not its base_type (which happens if these function are not repeated in this class). Complicated... */ -template +template Array<1, elemT> -Array<1, elemT>::operator+ (const base_type &iv) const -{ +Array<1, elemT>::operator+(const base_type& iv) const { this->check_state(); Array<1, elemT> retval(*this); return retval += iv; @@ -641,34 +522,30 @@ Array<1, elemT>::operator+ (const base_type &iv) const template Array<1, elemT> -Array<1, elemT>::operator- (const base_type &iv) const -{ +Array<1, elemT>::operator-(const base_type& iv) const { this->check_state(); Array<1, elemT> retval(*this); - return retval -= iv; + return retval -= iv; } template Array<1, elemT> -Array<1, elemT>::operator* (const base_type &iv) const -{ +Array<1, elemT>::operator*(const base_type& iv) const { this->check_state(); Array<1, elemT> retval(*this); - return retval *= iv; + return retval *= iv; } template Array<1, elemT> -Array<1, elemT>::operator/ (const base_type &iv) const -{ +Array<1, elemT>::operator/(const base_type& iv) const { this->check_state(); Array<1, elemT> retval(*this); - return retval /= iv; + return retval /= iv; } template Array<1, elemT> -Array<1, elemT>::operator+ (const elemT a) const -{ +Array<1, elemT>::operator+(const elemT a) const { this->check_state(); Array<1, elemT> retval(*this); return (retval += a); @@ -676,8 +553,7 @@ Array<1, elemT>::operator+ (const elemT a) const template Array<1, elemT> -Array<1, elemT>::operator- (const elemT a) const -{ +Array<1, elemT>::operator-(const elemT a) const { this->check_state(); Array<1, elemT> retval(*this); return (retval -= a); @@ -685,8 +561,7 @@ Array<1, elemT>::operator- (const elemT a) const template Array<1, elemT> -Array<1, elemT>::operator* (const elemT a) const -{ +Array<1, elemT>::operator*(const elemT a) const { this->check_state(); Array<1, elemT> retval(*this); return (retval *= a); @@ -694,63 +569,61 @@ Array<1, elemT>::operator* (const elemT a) const template Array<1, elemT> -Array<1, elemT>::operator/ (const elemT a) const -{ +Array<1, elemT>::operator/(const elemT a) const { this->check_state(); Array<1, elemT> retval(*this); return (retval /= a); -}; +}; -#endif // boost +# endif // boost -template -const elemT& Array<1,elemT>:: operator[] (int i) const -{ - return base_type::operator[](i); +template +const elemT& +Array<1, elemT>::operator[](int i) const { + return base_type::operator[](i); }; -template -elemT& Array<1,elemT>:: operator[] (int i) -{ - return base_type::operator[](i); +template +elemT& +Array<1, elemT>::operator[](int i) { + return base_type::operator[](i); }; -template -const elemT& Array<1,elemT>:: operator[] (const BasicCoordinate<1,int>& c) const -{ +template +const elemT& +Array<1, elemT>::operator[](const BasicCoordinate<1, int>& c) const { return (*this)[c[1]]; -}; - -template -elemT& Array<1,elemT>::operator[] (const BasicCoordinate<1,int>& c) -{ +}; + +template +elemT& +Array<1, elemT>::operator[](const BasicCoordinate<1, int>& c) { return (*this)[c[1]]; -}; +}; -template -const elemT& Array<1,elemT>:: at (int i) const -{ - return base_type::at(i); +template +const elemT& +Array<1, elemT>::at(int i) const { + return base_type::at(i); }; -template -elemT& Array<1,elemT>:: at (int i) -{ - return base_type::at(i); +template +elemT& +Array<1, elemT>::at(int i) { + return base_type::at(i); }; -template -const elemT& Array<1,elemT>:: at (const BasicCoordinate<1,int>& c) const -{ +template +const elemT& +Array<1, elemT>::at(const BasicCoordinate<1, int>& c) const { return (*this).at(c[1]); -}; - -template -elemT& Array<1,elemT>::at (const BasicCoordinate<1,int>& c) -{ +}; + +template +elemT& +Array<1, elemT>::at(const BasicCoordinate<1, int>& c) { return (*this).at(c[1]); -}; - +}; #else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION diff --git a/src/include/stir/Array1d.h b/src/include/stir/Array1d.h index 6931e32b3b..b1d81d8b9f 100644 --- a/src/include/stir/Array1d.h +++ b/src/include/stir/Array1d.h @@ -17,8 +17,8 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup Array + \file + \ingroup Array \brief defines the 1D specialisation of the Array class for broken compilers \author Kris Thielemans (with help from Alexey Zverovich) @@ -28,45 +28,42 @@ */ #if !defined(__stir_Array_H__) || !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) || !defined(elemT) -#error This file should only be included in Array.h for half-broken compilers +# error This file should only be included in Array.h for half-broken compilers #endif -/* Lines here should really be identical to what you find as 1D specialisation +/* Lines here should really be identical to what you find as 1D specialisation in Array.h and Array.inl, except that template statements are dropped. */ -template<> +template <> class Array<1, elemT> : public NumericVectorWithOffset #ifdef STIR_USE_BOOST - , - boost::operators, NumericVectorWithOffset >, - boost::operators >, - boost::operators, elemT> + , + boost::operators, NumericVectorWithOffset>, + boost::operators>, + boost::operators, elemT> #endif { -protected: - typedef NumericVectorWithOffset base_type; +protected: + typedef NumericVectorWithOffset base_type; typedef Array<1, elemT> self; - public: +public: //! for 1D arrays, full iterators are equal to normal iterators typedef iterator full_iterator; //! for 1D arrays, full iterators are equal to normal iterators typedef const_iterator const_full_iterator; - public: - - //! default constructor: array of length 0 inline Array(); - + //! constructor given an IndexRange<1> inline explicit Array(const IndexRange<1>& range); - + //! constructor from basetype - inline Array(const base_type &il); - + inline Array(const base_type& il); + //! constructor given first and last indices inline Array(const int min_index, const int max_index); @@ -93,393 +90,326 @@ class Array<1, elemT> : public NumericVectorWithOffset inline IndexRange<1> get_index_range() const; //! return the total number of elements in this array - inline size_t size_all() const; + inline size_t size_all() const; //! Array::grow initialises new elements to 0 inline virtual void grow(const IndexRange<1>& range); - + // Array::grow initialises new elements to 0 inline virtual void grow(const int min_index, const int max_index); - + //! Array::resize initialises new elements to 0 inline virtual void resize(const IndexRange<1>& range); - + // Array::resize initialises new elements to 0 inline virtual void resize(const int min_index, const int max_index); - + //! return sum of all elements inline elemT sum() const; - + //! add up all positive elemTs in the vector inline elemT sum_positive() const; - + //! return maximum value of all elements inline elemT find_max() const; - + //! return minimum value of all elements inline elemT find_min() const; - + //! checks if the index range is 'regular' (always \c true as this is the 1D case) inline bool is_regular() const; - + //! find regular range, returns \c false if the range is not regular - inline bool get_regular_range( - BasicCoordinate<1, int>& min, - BasicCoordinate<1, int>& max) const; + inline bool get_regular_range(BasicCoordinate<1, int>& min, BasicCoordinate<1, int>& max) const; #ifndef STIR_USE_BOOST - - /* KT 31/01/2000 I had to add these functions here, although they are + + /* KT 31/01/2000 I had to add these functions here, although they are in NumericVectorWithOffset already. - Reason: we allow addition (and similar operations) of tensors of + Reason: we allow addition (and similar operations) of tensors of different sizes. This implies that operator+= can call a 'grow' - on retval. For this to work, retval should be a Array, not + on retval. For this to work, retval should be a Array, not its base_type (which happens if these function are not repeated in this class). Complicated... */ //! elem by elem addition - inline self operator+ (const base_type &iv) const; - + inline self operator+(const base_type& iv) const; + //! elem by elem subtraction - inline self operator- (const base_type &iv) const; - + inline self operator-(const base_type& iv) const; + //! elem by elem multiplication - inline self operator* (const base_type &iv) const; - + inline self operator*(const base_type& iv) const; + //! elem by elem division - inline self operator/ (const base_type &iv) const; - + inline self operator/(const base_type& iv) const; + //! addition with an 'elemT' - inline self operator+ (const elemT a) const; - + inline self operator+(const elemT a) const; + //! subtraction with an 'elemT' - inline self operator- (const elemT a) const; - + inline self operator-(const elemT a) const; + //! multiplication with an 'elemT' - inline self operator* (const elemT a) const; - + inline self operator*(const elemT a) const; + //! division with an 'elemT' - inline self operator/ (const elemT a) const; + inline self operator/(const elemT a) const; #endif // boost - - //! allow array-style access, read/write - inline elemT& operator[] (int i); + + //! allow array-style access, read/write + inline elemT& operator[](int i); //! array access, read-only - inline const elemT& operator[] (int i) const; - - //! allow array-style access giving its BasicCoordinate, read/write - inline const elemT& operator[](const BasicCoordinate<1,int>& c) const; + inline const elemT& operator[](int i) const; + + //! allow array-style access giving its BasicCoordinate, read/write + inline const elemT& operator[](const BasicCoordinate<1, int>& c) const; //! array access giving its BasicCoordinate, read-only - inline elemT& operator[](const BasicCoordinate<1,int>& c) ; - - + inline elemT& operator[](const BasicCoordinate<1, int>& c); }; - - void -Array<1, elemT>::resize(const int min_index, const int max_index) -{ +Array<1, elemT>::resize(const int min_index, const int max_index) { this->check_state(); const int oldstart = this->get_min_index(); const int oldlength = this->size(); - + base_type::resize(min_index, max_index); - if (oldlength == 0) - { - for (int i=this->get_min_index(); i<=this->get_max_index(); i++) + if (oldlength == 0) { + for (int i = this->get_min_index(); i <= this->get_max_index(); i++) this->num[i] = elemT(0); - } - else - { - for (int i=this->get_min_index(); iget_max_index(); ++i) + } else { + for (int i = this->get_min_index(); i < oldstart && i <= this->get_max_index(); ++i) this->num[i] = elemT(0); - for (int i=std::max(oldstart + oldlength, this->get_min_index()); i<=this->get_max_index(); ++i) + for (int i = std::max(oldstart + oldlength, this->get_min_index()); i <= this->get_max_index(); ++i) this->num[i] = elemT(0); } - this->check_state(); + this->check_state(); } void -Array<1, elemT>::resize(const IndexRange<1>& range) -{ +Array<1, elemT>::resize(const IndexRange<1>& range) { resize(range.get_min_index(), range.get_max_index()); } void -Array<1, elemT>::grow(const int min_index, const int max_index) -{ +Array<1, elemT>::grow(const int min_index, const int max_index) { resize(min_index, max_index); } void -Array<1, elemT>::grow(const IndexRange<1>& range) -{ +Array<1, elemT>::grow(const IndexRange<1>& range) { grow(range.get_min_index(), range.get_max_index()); } -Array<1, elemT>::Array() -: base_type() -{ } +Array<1, elemT>::Array() : base_type() {} +Array<1, elemT>::Array(const IndexRange<1>& range) : base_type() { grow(range); } -Array<1, elemT>::Array(const IndexRange<1>& range) -: base_type() -{ - grow(range); -} - -Array<1, elemT>::Array(const int min_index, const int max_index) -: base_type() -{ - grow(min_index, max_index); -} +Array<1, elemT>::Array(const int min_index, const int max_index) : base_type() { grow(min_index, max_index); } -Array<1, elemT>::Array(const base_type &il) -: base_type(il) -{} +Array<1, elemT>::Array(const base_type& il) : base_type(il) {} -Array<1, elemT>::~Array() -{} +Array<1, elemT>::~Array() {} -Array<1, elemT>::full_iterator -Array<1, elemT>::begin_all() -{ +Array<1, elemT>::full_iterator +Array<1, elemT>::begin_all() { return this->begin(); } - -Array<1, elemT>::const_full_iterator -Array<1, elemT>::begin_all() const -{ + +Array<1, elemT>::const_full_iterator +Array<1, elemT>::begin_all() const { return this->begin(); } -Array<1, elemT>::full_iterator -Array<1, elemT>::end_all() -{ +Array<1, elemT>::full_iterator +Array<1, elemT>::end_all() { return this->end(); } - -Array<1, elemT>::const_full_iterator -Array<1, elemT>::end_all() const -{ - return this->end(); +Array<1, elemT>::const_full_iterator +Array<1, elemT>::end_all() const { + return this->end(); } -Array<1, elemT>::const_full_iterator -Array<1, elemT>::begin_all_const() const -{ +Array<1, elemT>::const_full_iterator +Array<1, elemT>::begin_all_const() const { return this->begin(); } -Array<1, elemT>::const_full_iterator -Array<1, elemT>::end_all_const() const -{ - return this->end(); +Array<1, elemT>::const_full_iterator +Array<1, elemT>::end_all_const() const { + return this->end(); } IndexRange<1> -Array<1, elemT>::get_index_range() const -{ +Array<1, elemT>::get_index_range() const { return IndexRange<1>(this->get_min_index(), this->get_max_index()); } size_t -Array<1, elemT>::size_all() const -{ +Array<1, elemT>::size_all() const { return size(); } elemT -Array<1, elemT>::sum() const -{ +Array<1, elemT>::sum() const { this->check_state(); elemT acc = 0; - for(int i=this->get_min_index(); i<=this->get_max_index(); acc+=this->num[i++]) - {} - return acc; + for (int i = this->get_min_index(); i <= this->get_max_index(); acc += this->num[i++]) { + } + return acc; }; #ifndef __stir_Array1d_no_comparisons__ elemT -Array<1, elemT>::sum_positive() const -{ +Array<1, elemT>::sum_positive() const { this->check_state(); - elemT acc=0; - for(int i=this->get_min_index(); i<=this->get_max_index(); i++) - { + elemT acc = 0; + for (int i = this->get_min_index(); i <= this->get_max_index(); i++) { if (this->num[i] > 0) acc += this->num[i]; } - return acc; + return acc; }; - elemT -Array<1, elemT>::find_max() const -{ +Array<1, elemT>::find_max() const { this->check_state(); - if (this->size() > 0) - { -#ifndef STIR_NO_NAMESPACES - return *std::max_element(this->begin(), this->end()); -#else + if (this->size() > 0) { +# ifndef STIR_NO_NAMESPACES + return *std::max_element(this->begin(), this->end()); +# else return *max_element(this->begin(), this->end()); -#endif - } - else - { +# endif + } else { // TODO return elemT::minimum or so - return 0; - } + return 0; + } this->check_state(); }; elemT -Array<1, elemT>::find_min() const -{ +Array<1, elemT>::find_min() const { this->check_state(); - if (this->size() > 0) - { -#ifndef STIR_NO_NAMESPACES + if (this->size() > 0) { +# ifndef STIR_NO_NAMESPACES return *std::min_element(this->begin(), this->end()); -#else +# else return *min_element(this->begin(), this->end()); -#endif - } - else - { +# endif + } else { // TODO return elemT::maximum or so - return 0; - } + return 0; + } this->check_state(); -}; +}; #endif // end of __stir_Array1d_no_comparisons__ bool -Array<1, elemT>::is_regular() const -{ +Array<1, elemT>::is_regular() const { return true; } bool -Array<1, elemT>::get_regular_range( - BasicCoordinate<1, int>& min, - BasicCoordinate<1, int>& max) const -{ +Array<1, elemT>::get_regular_range(BasicCoordinate<1, int>& min, BasicCoordinate<1, int>& max) const { const IndexRange<1> range = get_index_range(); - return range.get_regular_range(min,max); + return range.get_regular_range(min, max); } #ifndef STIR_USE_BOOST -/* KT 31/01/2000 I had to add these functions here, although they are +/* KT 31/01/2000 I had to add these functions here, although they are in NumericVectorWithOffset already. -Reason: we allow addition (and similar operations) of tensors of +Reason: we allow addition (and similar operations) of tensors of different sizes. This implies that operator+= can call a 'grow' -on retval. For this to work, retval should be a Array, not +on retval. For this to work, retval should be a Array, not its base_type (which happens if these function are not repeated in this class). Complicated... */ - + Array<1, elemT> -Array<1, elemT>::operator+ (const base_type &iv) const -{ +Array<1, elemT>::operator+(const base_type& iv) const { this->check_state(); Array<1, elemT> retval(*this); return retval += iv; }; Array<1, elemT> -Array<1, elemT>::operator- (const base_type &iv) const -{ +Array<1, elemT>::operator-(const base_type& iv) const { this->check_state(); Array<1, elemT> retval(*this); - return retval -= iv; + return retval -= iv; } Array<1, elemT> -Array<1, elemT>::operator* (const base_type &iv) const -{ +Array<1, elemT>::operator*(const base_type& iv) const { this->check_state(); Array<1, elemT> retval(*this); - return retval *= iv; + return retval *= iv; } - Array<1, elemT> -Array<1, elemT>::operator/ (const base_type &iv) const -{ +Array<1, elemT>::operator/(const base_type& iv) const { this->check_state(); Array<1, elemT> retval(*this); - return retval /= iv; + return retval /= iv; } - Array<1, elemT> -Array<1, elemT>::operator+ (const elemT a) const -{ +Array<1, elemT>::operator+(const elemT a) const { this->check_state(); Array<1, elemT> retval(*this); return (retval += a); }; - Array<1, elemT> -Array<1, elemT>::operator- (const elemT a) const -{ +Array<1, elemT>::operator-(const elemT a) const { this->check_state(); Array<1, elemT> retval(*this); return (retval -= a); }; - Array<1, elemT> -Array<1, elemT>::operator* (const elemT a) const -{ +Array<1, elemT>::operator*(const elemT a) const { this->check_state(); Array<1, elemT> retval(*this); return (retval *= a); }; - Array<1, elemT> -Array<1, elemT>::operator/ (const elemT a) const -{ +Array<1, elemT>::operator/(const elemT a) const { this->check_state(); Array<1, elemT> retval(*this); return (retval /= a); }; - #endif // boost -const elemT& Array<1,elemT>:: operator[] (int i) const -{ - return base_type::operator[](i); +const elemT& +Array<1, elemT>::operator[](int i) const { + return base_type::operator[](i); }; -elemT& Array<1,elemT>:: operator[] (int i) -{ - return base_type::operator[](i); +elemT& +Array<1, elemT>::operator[](int i) { + return base_type::operator[](i); }; - -const elemT& Array<1,elemT>:: operator[] (const BasicCoordinate<1,int>& c) const -{ + +const elemT& +Array<1, elemT>::operator[](const BasicCoordinate<1, int>& c) const { return (*this)[c[1]]; -}; - -elemT& Array<1,elemT>::operator[] (const BasicCoordinate<1,int>& c) -{ +}; + +elemT& +Array<1, elemT>::operator[](const BasicCoordinate<1, int>& c) { return (*this)[c[1]]; -}; - -#undef elemT +}; +#undef elemT diff --git a/src/include/stir/ArrayFilter1DUsingConvolution.h b/src/include/stir/ArrayFilter1DUsingConvolution.h index 8b2628d1c1..30bda24edc 100644 --- a/src/include/stir/ArrayFilter1DUsingConvolution.h +++ b/src/include/stir/ArrayFilter1DUsingConvolution.h @@ -30,30 +30,30 @@ #ifndef __stir_ArrayFilter1DUsingConvolution_H__ #define __stir_ArrayFilter1DUsingConvolution_H__ - #include "stir/ArrayFunctionObject_2ArgumentImplementation.h" #include "stir/BoundaryConditions.h" START_NAMESPACE_STIR -template class VectorWithOffset; +template +class VectorWithOffset; /*! \ingroup Array - \brief This class implements convolution of a 1D array with an + \brief This class implements convolution of a 1D array with an arbitrary (i.e. potentially non-symmetric) kernel. Convolution is non-periodic: - \f[ out_i = \sum_j kernel_j in_{i-j} \f] + \f[ out_i = \sum_j kernel_j in_{i-j} \f] Note that for most kernels, the above convention means that the zero- - index of the kernel corresponds to the peak in the kernel. + index of the kernel corresponds to the peak in the kernel. - By default, zero boundary conditions are used, i.e. elements of the input array - that are outside its index range are considered to be 0. + By default, zero boundary conditions are used, i.e. elements of the input array + that are outside its index range are considered to be 0. - Currently, "constant" boundary conditions are also implemented, i.e. elements of the input array + Currently, "constant" boundary conditions are also implemented, i.e. elements of the input array that are outside its index range are considered to the same as the nearest element in the array (i.e. first element on the "left" and last element on the "right"). @@ -82,45 +82,33 @@ template class VectorWithOffset; \todo implement other boundary conditions */ template -class ArrayFilter1DUsingConvolution : - public ArrayFunctionObject_2ArgumentImplementation<1,elemT> -{ +class ArrayFilter1DUsingConvolution : public ArrayFunctionObject_2ArgumentImplementation<1, elemT> { public: - //! Construct a trivial filter ArrayFilter1DUsingConvolution(); //! Construct the filter given the kernel coefficients - /*! Currently \a bc has to be BoundaryConditions::zero or + /*! Currently \a bc has to be BoundaryConditions::zero or BoundaryConditions::constant */ - ArrayFilter1DUsingConvolution(const VectorWithOffset< elemT>& filter_kernel, const BoundaryConditions::BC bc= BoundaryConditions::zero); + ArrayFilter1DUsingConvolution(const VectorWithOffset& filter_kernel, + const BoundaryConditions::BC bc = BoundaryConditions::zero); //! checks if the kernel corresponds to a trivial filter operation - /*! + /*! trivial means, either the kernel has 0 length, or length 1 and its only element is 1 */ bool is_trivial() const; - virtual Succeeded - get_influencing_indices(IndexRange<1>& influencing_indices, - const IndexRange<1>& output_indices) const; + virtual Succeeded get_influencing_indices(IndexRange<1>& influencing_indices, const IndexRange<1>& output_indices) const; - virtual Succeeded - get_influenced_indices(IndexRange<1>& influenced_indices, - const IndexRange<1>& input_indices) const; + virtual Succeeded get_influenced_indices(IndexRange<1>& influenced_indices, const IndexRange<1>& input_indices) const; private: - VectorWithOffset< elemT> filter_coefficients; + VectorWithOffset filter_coefficients; BoundaryConditions::BC _bc; - void do_it(Array<1,elemT>& out_array, const Array<1,elemT>& in_array) const; - + void do_it(Array<1, elemT>& out_array, const Array<1, elemT>& in_array) const; }; - - END_NAMESPACE_STIR - -#endif //ArrayFilter1DUsingConvolution - - +#endif // ArrayFilter1DUsingConvolution diff --git a/src/include/stir/ArrayFilter1DUsingConvolutionSymmetricKernel.h b/src/include/stir/ArrayFilter1DUsingConvolutionSymmetricKernel.h index 4d96268a6d..b33e1c1f09 100644 --- a/src/include/stir/ArrayFilter1DUsingConvolutionSymmetricKernel.h +++ b/src/include/stir/ArrayFilter1DUsingConvolutionSymmetricKernel.h @@ -30,12 +30,12 @@ #ifndef __stir_ArrayFilter1DUsingConvolutionSymmetricKernel_H__ #define __stir_ArrayFilter1DUsingConvolutionSymmetricKernel_H__ - #include "stir/ArrayFunctionObject_2ArgumentImplementation.h" START_NAMESPACE_STIR -template class VectorWithOffset; +template +class VectorWithOffset; /*! \ingroup Array @@ -43,46 +43,37 @@ template class VectorWithOffset; Convolution is non-periodic: - \f[ out_i = \sum_j kernel_j in_{i+j} \f] + \f[ out_i = \sum_j kernel_j in_{i+j} \f] Elements of the input array that are outside its - index range are considered to be 0. + index range are considered to be 0. - \warning 2 argument operator() currently requires that out_array and in_array + \warning 2 argument operator() currently requires that out_array and in_array have the same index range */ template -class ArrayFilter1DUsingConvolutionSymmetricKernel : - public ArrayFunctionObject_2ArgumentImplementation<1,elemT> -{ +class ArrayFilter1DUsingConvolutionSymmetricKernel : public ArrayFunctionObject_2ArgumentImplementation<1, elemT> { public: - //! Construct the filter given the kernel coefficients - /*! + /*! Only one half of the kernel coefficients has to be passed. The implementation - uses a kernel whose coefficients are given by + uses a kernel whose coefficients are given by \code kernel[i] == filter_kernel[abs(i)] \endcode - \warning filter_kernel's indices must start from 0 + \warning filter_kernel's indices must start from 0 */ - ArrayFilter1DUsingConvolutionSymmetricKernel(const VectorWithOffset< elemT>& filter_kernel); + ArrayFilter1DUsingConvolutionSymmetricKernel(const VectorWithOffset& filter_kernel); //! checks if the kernel corresponds to a trivial filter operation - /*! + /*! trivial means, either the kernel has 0 length, or length 1 and its only element is 1 */ bool is_trivial() const; private: - VectorWithOffset< elemT> filter_coefficients; - void do_it(Array<1,elemT>& out_array, const Array<1,elemT>& in_array) const; - + VectorWithOffset filter_coefficients; + void do_it(Array<1, elemT>& out_array, const Array<1, elemT>& in_array) const; }; - - END_NAMESPACE_STIR - -#endif //ArrayFilter1DUsingConvolutionSymmetricKernel - - +#endif // ArrayFilter1DUsingConvolutionSymmetricKernel diff --git a/src/include/stir/ArrayFilter2DUsingConvolution.h b/src/include/stir/ArrayFilter2DUsingConvolution.h index 936ec35dc0..dbb83ddf5c 100644 --- a/src/include/stir/ArrayFilter2DUsingConvolution.h +++ b/src/include/stir/ArrayFilter2DUsingConvolution.h @@ -18,49 +18,36 @@ #ifndef __stir_ArrayFilter2DUsingConvolution_H__ #define __stir_ArrayFilter2DUsingConvolution_H__ - #include "stir/ArrayFunctionObject_2ArgumentImplementation.h" //#include "stir/VectorWithOffset.h" START_NAMESPACE_STIR -template class VectorWithOffset; +template +class VectorWithOffset; template -class ArrayFilter2DUsingConvolution : - public ArrayFunctionObject_2ArgumentImplementation<2,elemT> -{ +class ArrayFilter2DUsingConvolution : public ArrayFunctionObject_2ArgumentImplementation<2, elemT> { public: - //! Construct the filter given the kernel coefficients - /*! - All kernel coefficients have to be passed. + /*! + All kernel coefficients have to be passed. */ ArrayFilter2DUsingConvolution(); - ArrayFilter2DUsingConvolution(const Array <2, float>& filter_kernel); - + ArrayFilter2DUsingConvolution(const Array<2, float>& filter_kernel); + bool is_trivial() const; - virtual Succeeded - get_influencing_indices(IndexRange<1>& influencing_indices, - const IndexRange<1>& output_indices) const; + virtual Succeeded get_influencing_indices(IndexRange<1>& influencing_indices, const IndexRange<1>& output_indices) const; - virtual Succeeded - get_influenced_indices(IndexRange<1>& influenced_indices, - const IndexRange<1>& input_indices) const; + virtual Succeeded get_influenced_indices(IndexRange<1>& influenced_indices, const IndexRange<1>& input_indices) const; private: - Array <2, float> filter_coefficients; - void do_it(Array<2,elemT>& out_array, const Array<2,elemT>& in_array) const; - + Array<2, float> filter_coefficients; + void do_it(Array<2, elemT>& out_array, const Array<2, elemT>& in_array) const; }; - - END_NAMESPACE_STIR - -#endif //ArrayFilter2DUsingConvolution - - +#endif // ArrayFilter2DUsingConvolution diff --git a/src/include/stir/ArrayFilter3DUsingConvolution.h b/src/include/stir/ArrayFilter3DUsingConvolution.h index 8de90336f8..0e782cb3b2 100644 --- a/src/include/stir/ArrayFilter3DUsingConvolution.h +++ b/src/include/stir/ArrayFilter3DUsingConvolution.h @@ -18,50 +18,37 @@ #ifndef __stir_ArrayFilter3DUsingConvolution_H__ #define __stir_ArrayFilter3DUsingConvolution_H__ - #include "stir/ArrayFunctionObject_2ArgumentImplementation.h" //#include "stir/VectorWithOffset.h" START_NAMESPACE_STIR -template class VectorWithOffset; +template +class VectorWithOffset; template -class ArrayFilter3DUsingConvolution : - public ArrayFunctionObject_2ArgumentImplementation<3,elemT> -{ +class ArrayFilter3DUsingConvolution : public ArrayFunctionObject_2ArgumentImplementation<3, elemT> { public: - //! Construct the filter given the kernel coefficients - /*! - All kernel coefficients have to be passed. + /*! + All kernel coefficients have to be passed. */ ArrayFilter3DUsingConvolution(); - ArrayFilter3DUsingConvolution(const Array <3, float>& filter_kernel); - + ArrayFilter3DUsingConvolution(const Array<3, float>& filter_kernel); + bool is_trivial() const; - virtual Succeeded - get_influencing_indices(IndexRange<1>& influencing_indices, - const IndexRange<1>& output_indices) const; + virtual Succeeded get_influencing_indices(IndexRange<1>& influencing_indices, const IndexRange<1>& output_indices) const; - virtual Succeeded - get_influenced_indices(IndexRange<1>& influenced_indices, - const IndexRange<1>& input_indices) const; + virtual Succeeded get_influenced_indices(IndexRange<1>& influenced_indices, const IndexRange<1>& input_indices) const; private: - Array <3, float> filter_coefficients; - void do_it(Array<3,elemT>& out_array, const Array<3,elemT>& in_array) const; - void do_it_2d(Array<2,elemT>& out_array, const Array<2,elemT>& in_array) const; - + Array<3, float> filter_coefficients; + void do_it(Array<3, elemT>& out_array, const Array<3, elemT>& in_array) const; + void do_it_2d(Array<2, elemT>& out_array, const Array<2, elemT>& in_array) const; }; - - END_NAMESPACE_STIR - -#endif //ArrayFilter3DUsingConvolution - - +#endif // ArrayFilter3DUsingConvolution diff --git a/src/include/stir/ArrayFilterUsingRealDFTWithPadding.h b/src/include/stir/ArrayFilterUsingRealDFTWithPadding.h index f20932193a..b568ff66d5 100644 --- a/src/include/stir/ArrayFilterUsingRealDFTWithPadding.h +++ b/src/include/stir/ArrayFilterUsingRealDFTWithPadding.h @@ -31,45 +31,43 @@ #include "stir/IndexRange.h" #include -#if defined(_MSC_VER) && _MSC_VER<=1200 +#if defined(_MSC_VER) && _MSC_VER <= 1200 /* VC 6.0 cannot overload the real and complex constructors I just disable the complex version. */ -#define __stir_ArrayFilterUsingRealDFTWithPadding_no_complex_kernel__ +# define __stir_ArrayFilterUsingRealDFTWithPadding_no_complex_kernel__ #endif START_NAMESPACE_STIR class Succeeded; -template class Array; +template +class Array; /*! \ingroup Array - \brief This class implements convolution of an array of real numbers with an + \brief This class implements convolution of an array of real numbers with an arbitrary (i.e. potentially non-symmetric) kernel using DFTs. Convolution is periodic. Elements of the input array that are outside its - index range are considered to be 0. + index range are considered to be 0. If the input and output arrays are smaller than half the length of the kernel, then there is enough zero-padding such that aliasing cannot occur. - In this case, this class gives the same results as + In this case, this class gives the same results as ArrayFilter1DUsingConvolution. */ template -class ArrayFilterUsingRealDFTWithPadding : - public ArrayFunctionObject_2ArgumentImplementation -{ +class ArrayFilterUsingRealDFTWithPadding : public ArrayFunctionObject_2ArgumentImplementation { public: - //! Default constructor (trivial kernel) ArrayFilterUsingRealDFTWithPadding(); //! Construct the filter given the real kernel coefficients /*! \see set_kernel(const Array&) \warning Will call error() when sizes are not appropriate - */ + */ ArrayFilterUsingRealDFTWithPadding(const Array& real_filter_kernel); #ifndef __stir_ArrayFilterUsingRealDFTWithPadding_no_complex_kernel__ @@ -78,13 +76,13 @@ class ArrayFilterUsingRealDFTWithPadding : \warning Will call error() when sizes are not appropriate. \warning This function is disabled for VC 6.0 because of compiler limitations */ - ArrayFilterUsingRealDFTWithPadding(const Array >& kernel_in_frequency_space); + ArrayFilterUsingRealDFTWithPadding(const Array>& kernel_in_frequency_space); #endif //! set the real kernel coefficients /* - The kernel can be given with arbitrary (but regular) index range, - but will be wrapped-around, + The kernel can be given with arbitrary (but regular) index range, + but will be wrapped-around, assuming that it is periodic outside the indexrange of the kernel. So, normally, the 0- index corresponds to the middle of the PSF. @@ -92,36 +90,33 @@ class ArrayFilterUsingRealDFTWithPadding : DFT. If you want to avoid aliasing, make sure that the kernel is at least twice as long as the input and output arrays. - As this function uses fourier_for_real_data(), see there for restrictions + As this function uses fourier_for_real_data(), see there for restrictions on the possible kernel length, but at time of writing, it has to be a power of 2. */ - Succeeded - set_kernel(const Array& real_filter_kernel); + Succeeded set_kernel(const Array& real_filter_kernel); //! set the complex kernel coefficients /* The kernel has to be given with index ranges starting from 0. So, the 0- index corresponds to the DC component of the filter. \see fourier_for_real_data() for more info on the range of frequencies - Input data will be zero-padded to the index range as the corresponding + Input data will be zero-padded to the index range as the corresponding 'real' kernel before DFT. If you want to avoid aliasing, make sure that the kernel is at least twice as long as the input and output arrays. See fourier() for restrictions on the possible kernel length, but at time of writing, it has to be a power of 2. */ - Succeeded - set_kernel_in_frequency_space(const Array >& kernel_in_frequency_space); + Succeeded set_kernel_in_frequency_space(const Array>& kernel_in_frequency_space); //! checks if the kernel corresponds to a trivial filter operation - /*! + /*! trivial means, either the kernel has 0 length, or length 1 and its only element is 1 */ bool is_trivial() const; protected: - - Array > kernel_in_frequency_space; + Array> kernel_in_frequency_space; //! Performs the convolution /*! \a in_array and \a out_array can have arbitrary (even non-regular) @@ -130,16 +125,13 @@ class ArrayFilterUsingRealDFTWithPadding : an array with the same dimensions as the 'real' kernel. */ void do_it(Array& out_array, const Array& in_array) const; + private: IndexRange padding_range; - BasicCoordinate padded_sizes; + BasicCoordinate padded_sizes; Succeeded set_padding_range(); }; - END_NAMESPACE_STIR - -#endif //ArrayFilterUsingRealDFTWithPadding - - +#endif // ArrayFilterUsingRealDFTWithPadding diff --git a/src/include/stir/ArrayFunction.h b/src/include/stir/ArrayFunction.h index c08c346442..c1ae060f6f 100644 --- a/src/include/stir/ArrayFunction.h +++ b/src/include/stir/ArrayFunction.h @@ -28,7 +28,7 @@ This abstract class provides the general interface for accessing the - projection data. This works with get_ and set_ pairs. (Generally, + projection data. This works with get_ and set_ pairs. (Generally, the 4D dataset might be too big to be kept in memory.) In addition, there are get_empty_ functions that just create the corresponding object of appropriate sizes etc. but filled with 0. @@ -96,20 +105,15 @@ class Succeeded; \warning The arguments 'make_num_tangential_poss_odd' are temporary and will be deleted in the next release. */ -class ProjData : public ExamData -{ +class ProjData : public ExamData { public: + //! A static member to get the projection data from a file + static shared_ptr read_from_file(const std::string& filename, const std::ios::openmode open_mode = std::ios::in); - //! A static member to get the projection data from a file - static shared_ptr - read_from_file(const std::string& filename, - const std::ios::openmode open_mode = std::ios::in); - - //! Empty constructor + //! Empty constructor ProjData(); //! construct by specifying info. Data will be undefined. - ProjData(const shared_ptr& exam_info_sptr, - const shared_ptr& proj_data_info_ptr); + ProjData(const shared_ptr& exam_info_sptr, const shared_ptr& proj_data_info_ptr); #if 0 // it would be nice to have something like this. However, it's implementation // normally fails as we'd need to use set_viewgram or so, which is virtual, but @@ -120,69 +124,61 @@ class ProjData : public ExamData //! Destructor virtual ~ProjData() {} //! Get shared pointer to proj data info - inline shared_ptr - get_proj_data_info_sptr() const; + inline shared_ptr get_proj_data_info_sptr() const; //! Get viewgram - virtual Viewgram - get_viewgram(const int view, const int segment_num,const bool make_num_tangential_poss_odd = false) const=0; + virtual Viewgram get_viewgram(const int view, const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const = 0; //! Set viewgram - virtual Succeeded - set_viewgram(const Viewgram&) = 0; + virtual Succeeded set_viewgram(const Viewgram&) = 0; //! Get sinogram - virtual Sinogram - get_sinogram(const int ax_pos_num, const int segment_num,const bool make_num_tangential_poss_odd = false) const=0; + virtual Sinogram get_sinogram(const int ax_pos_num, const int segment_num, + const bool make_num_tangential_poss_odd = false, const int timing_pos = 0) const = 0; //! Set sinogram - virtual Succeeded - set_sinogram(const Sinogram&) = 0; + virtual Succeeded set_sinogram(const Sinogram&) = 0; + // //! Get Bin value + // virtual float get_bin_value(const Bin& this_bin) const = 0; //! Get empty viewgram - Viewgram get_empty_viewgram(const int view, const int segment_num, - const bool make_num_tangential_poss_odd = false) const; - + Viewgram get_empty_viewgram(const int view, const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; + //! Get empty_sinogram - Sinogram - get_empty_sinogram(const int ax_pos_num, const int segment_num, - const bool make_num_tangential_poss_odd = false) const; - - //! Get empty segment sino - SegmentByView - get_empty_segment_by_view(const int segment_num, - const bool make_num_tangential_poss_odd = false) const; - //! Get empty segment view - SegmentBySinogram - get_empty_segment_by_sinogram(const int segment_num, - const bool make_num_tangential_poss_odd = false) const; + Sinogram get_empty_sinogram(const int ax_pos_num, const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; + //! Get empty segment sino + SegmentByView get_empty_segment_by_view(const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; + //! Get empty segment view + SegmentBySinogram get_empty_segment_by_sinogram(const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; //! Get segment by sinogram - virtual SegmentBySinogram - get_segment_by_sinogram(const int segment_num) const; + virtual SegmentBySinogram get_segment_by_sinogram(const int segment_num, const int timing_pos = 0) const; //! Get segment by view - virtual SegmentByView - get_segment_by_view(const int segment_num) const; + virtual SegmentByView get_segment_by_view(const int segment_num, const int timing_pos = 0) const; //! Set segment by sinogram - virtual Succeeded - set_segment(const SegmentBySinogram&); - //! Set segment by view - virtual Succeeded - set_segment(const SegmentByView&); + virtual Succeeded set_segment(const SegmentBySinogram&); + //! Set segment by view + virtual Succeeded set_segment(const SegmentByView&); //! Get related viewgrams - virtual RelatedViewgrams - get_related_viewgrams(const ViewSegmentNumbers&, - const shared_ptr&, - const bool make_num_tangential_poss_odd = false) const; + virtual RelatedViewgrams get_related_viewgrams(const ViewSegmentNumbers&, + const shared_ptr&, + const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; //! Set related viewgrams virtual Succeeded set_related_viewgrams(const RelatedViewgrams& viewgrams); - + // //! Get related bin values + // //! \todo This function temporaliry has as input a vector instead this should be replaced by RelatedBins. + // std::vector get_related_bin_values(const std::vector&) const; //! Get empty related viewgrams, where the symmetries_ptr specifies the symmetries to use - RelatedViewgrams - get_empty_related_viewgrams(const ViewSegmentNumbers& view_segmnet_num, - //const int view_num, const int segment_num, - const shared_ptr& symmetries_ptr, - const bool make_num_tangential_poss_odd = false) const; - + RelatedViewgrams get_empty_related_viewgrams(const ViewSegmentNumbers& view_segmnet_num, + // const int view_num, const int segment_num, + const shared_ptr& symmetries_ptr, + const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; //! set all bins to the same value /*! will call error() if setting failed */ @@ -201,50 +197,46 @@ class ProjData : public ExamData the sequence just continues with valid segment numbers, e.g. \f$ [0, 1, -1, 2, 3 ] \f$. */ - static - std::vector - standard_segment_sequence(const ProjDataInfo& pdi); + static std::vector standard_segment_sequence(const ProjDataInfo& pdi); //! set all bins from an array iterator /*! \return \a array_iter advanced over the number of bins (as \c std::copy) - + Data are filled by `SegmentBySinogram`, with segment order given by standard_segment_sequence(). \warning there is no range-check on \a array_iter */ - template < typename iterT> - iterT fill_from( iterT array_iter) - { - // A type check would be useful. - // BOOST_STATIC_ASSERT((boost::is_same::value_type, Type>::value)); - - for (int s=0; s<= this->get_max_segment_num(); ++s) - { - SegmentBySinogram segment = this->get_empty_segment_by_sinogram(s); - // cannot use std::copy sadly as needs end-iterator for range - for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); - seg_iter != segment.end_all(); + template + iterT fill_from(iterT array_iter) { + // A type check would be useful. + // BOOST_STATIC_ASSERT((boost::is_same::value_type, Type>::value)); + + for (int s = 0; s <= this->get_max_segment_num(); ++s) { + for (int k = this->get_proj_data_info_sptr()->get_min_tof_pos_num(); + k <= this->get_proj_data_info_sptr()->get_max_tof_pos_num(); ++k) { + SegmentBySinogram segment = this->get_empty_segment_by_sinogram(s, false, k); + // cannot use std::copy sadly as needs end-iterator for range + for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); seg_iter != segment.end_all(); + /*empty*/) + *seg_iter++ = *array_iter++; + this->set_segment(segment); + + if (s != 0) { + segment = this->get_empty_segment_by_sinogram(-s, false, k); + for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); seg_iter != segment.end_all(); /*empty*/) - *seg_iter++ = *array_iter++; + *seg_iter++ = *array_iter++; this->set_segment(segment); - - if (s!=0) - { - segment = this->get_empty_segment_by_sinogram(-s); - for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); - seg_iter != segment.end_all(); - /*empty*/) - *seg_iter++ = *array_iter++; - this->set_segment(segment); - } + } } - return array_iter; + } + return array_iter; } //! Copy all bins to a range specified by a (forward) iterator - /*! + /*! \return \a array_iter advanced over the number of bins (as \c std::copy) Data are filled by `SegmentBySinogram`, with segment order given by @@ -252,20 +244,23 @@ class ProjData : public ExamData \warning there is no range-check on \a array_iter */ - template < typename iterT> - iterT copy_to(iterT array_iter) const - { - for (int s=0; s<= this->get_max_segment_num(); ++s) - { - SegmentBySinogram segment= this->get_segment_by_sinogram(s); - array_iter = std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); - if (s!=0) - { - segment=this->get_segment_by_sinogram(-s); - array_iter = std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); - } + template + iterT copy_to(iterT array_iter) const { + iterT init_pos = array_iter; + for (int k = this->get_proj_data_info_sptr()->get_min_tof_pos_num(); + k <= this->get_proj_data_info_sptr()->get_max_tof_pos_num(); ++k) { + for (int s = 0; s <= this->get_max_segment_num(); ++s) { + SegmentBySinogram segment = this->get_segment_by_sinogram(s, k); + std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); + std::advance(array_iter, segment.size_all()); + if (s != 0) { + segment = this->get_segment_by_sinogram(-s, k); + std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); + std::advance(array_iter, segment.size_all()); + } } - return array_iter; + } + return array_iter; } //! Get number of segments @@ -278,6 +273,12 @@ class ProjData : public ExamData inline int get_num_tangential_poss() const; //! Get number of TOF positions inline int get_num_tof_poss() const; + //! Get the index of the first timing position + inline int get_min_tof_pos_num() const; + //! Get the index of the last timgin position. + inline int get_max_tof_pos_num() const; + //! Get TOG mash factor + inline int get_tof_mash_factor() const; //! Get minimum segment number inline int get_min_segment_num() const; //! Get maximum segment number @@ -295,6 +296,9 @@ class ProjData : public ExamData //! Get maximum tangential position number inline int get_max_tangential_pos_num() const; //! Get the total number of sinograms + /*! Note that this will count TOF sinograms as well. + \see get_num_non_tof_sinograms() + */ inline int get_num_sinograms() const; //! Get the number of non-tof sinograms /*! Note that this is the sum of the number of axial poss over all segments. @@ -307,16 +311,13 @@ class ProjData : public ExamData Succeeded write_to_file(const std::string& filename) const; //! \deprecated a*x+b*y (\see xapyb) - STIR_DEPRECATED virtual void axpby(const float a, const ProjData& x, - const float b, const ProjData& y); + STIR_DEPRECATED virtual void axpby(const float a, const ProjData& x, const float b, const ProjData& y); //! set values of the array to x*a+y*b, where a and b are scalar, and x and y are ProjData - virtual void xapyb(const ProjData& x, const float a, - const ProjData& y, const float b); + virtual void xapyb(const ProjData& x, const float a, const ProjData& y, const float b); //! set values of the array to x*a+y*b, where a, b, x and y are ProjData - virtual void xapyb(const ProjData& x, const ProjData& a, - const ProjData& y, const ProjData& b); + virtual void xapyb(const ProjData& x, const ProjData& a, const ProjData& y, const ProjData& b); //! set values of the array to self*a+y*b where a and b are scalar, y is ProjData virtual void sapyb(const float a, const ProjData& y, const float b); @@ -325,13 +326,10 @@ class ProjData : public ExamData virtual void sapyb(const ProjData& a, const ProjData& y, const ProjData& b); protected: - - shared_ptr proj_data_info_sptr; + shared_ptr proj_data_info_sptr; }; - END_NAMESPACE_STIR #include "stir/ProjData.inl" #endif - diff --git a/src/include/stir/ProjData.inl b/src/include/stir/ProjData.inl index 2583f9b364..75a8656b6a 100644 --- a/src/include/stir/ProjData.inl +++ b/src/include/stir/ProjData.inl @@ -33,57 +33,103 @@ START_NAMESPACE_STIR shared_ptr -ProjData::get_proj_data_info_sptr() const -{ +ProjData::get_proj_data_info_sptr() const { return proj_data_info_sptr; } -int ProjData::get_num_segments() const -{ return proj_data_info_sptr->get_num_segments(); } +int +ProjData::get_num_segments() const { + return proj_data_info_sptr->get_num_segments(); +} + +int +ProjData::get_num_axial_poss(const int segment_num) const { + return proj_data_info_sptr->get_num_axial_poss(segment_num); +} -int ProjData::get_num_axial_poss(const int segment_num) const -{ return proj_data_info_sptr->get_num_axial_poss(segment_num); } +int +ProjData::get_num_views() const { + return proj_data_info_sptr->get_num_views(); +} -int ProjData::get_num_views() const -{ return proj_data_info_sptr->get_num_views(); } +int +ProjData::get_num_tangential_poss() const { + return proj_data_info_sptr->get_num_tangential_poss(); +} -int ProjData::get_num_tangential_poss() const -{ return proj_data_info_sptr->get_num_tangential_poss(); } +int +ProjData::get_num_tof_poss() const { + return proj_data_info_sptr->get_num_tof_poss(); +} -int ProjData::get_num_tof_poss() const -{ return proj_data_info_sptr->get_num_tof_poss(); } +int +ProjData::get_tof_mash_factor() const { + return proj_data_info_sptr->get_tof_mash_factor(); +} + +int +ProjData::get_min_segment_num() const { + return proj_data_info_sptr->get_min_segment_num(); +} + +int +ProjData::get_max_segment_num() const { + return proj_data_info_sptr->get_max_segment_num(); +} -int ProjData::get_min_segment_num() const -{ return proj_data_info_sptr->get_min_segment_num(); } +int +ProjData::get_min_axial_pos_num(const int segment_num) const { + return proj_data_info_sptr->get_min_axial_pos_num(segment_num); +} -int ProjData::get_max_segment_num() const -{ return proj_data_info_sptr->get_max_segment_num(); } +int +ProjData::get_max_axial_pos_num(const int segment_num) const { + return proj_data_info_sptr->get_max_axial_pos_num(segment_num); +} -int ProjData::get_min_axial_pos_num(const int segment_num) const -{ return proj_data_info_sptr->get_min_axial_pos_num(segment_num); } +int +ProjData::get_min_view_num() const { + return proj_data_info_sptr->get_min_view_num(); +} -int ProjData::get_max_axial_pos_num(const int segment_num) const -{ return proj_data_info_sptr->get_max_axial_pos_num(segment_num); } +int +ProjData::get_max_view_num() const { + return proj_data_info_sptr->get_max_view_num(); +} -int ProjData::get_min_view_num() const -{ return proj_data_info_sptr->get_min_view_num(); } +int +ProjData::get_min_tangential_pos_num() const { + return proj_data_info_sptr->get_min_tangential_pos_num(); +} -int ProjData::get_max_view_num() const -{ return proj_data_info_sptr->get_max_view_num(); } +int +ProjData::get_max_tangential_pos_num() const { + return proj_data_info_sptr->get_max_tangential_pos_num(); +} -int ProjData::get_min_tangential_pos_num() const -{ return proj_data_info_sptr->get_min_tangential_pos_num(); } +int +ProjData::get_min_tof_pos_num() const { + return proj_data_info_sptr->get_min_tof_pos_num(); +} -int ProjData::get_max_tangential_pos_num() const -{ return proj_data_info_sptr->get_max_tangential_pos_num(); } +int +ProjData::get_max_tof_pos_num() const { + return proj_data_info_sptr->get_max_tof_pos_num(); +} -int ProjData::get_num_non_tof_sinograms() const -{ return proj_data_info_sptr->get_num_non_tof_sinograms(); } +int +ProjData::get_num_non_tof_sinograms() const { + return proj_data_info_sptr->get_num_non_tof_sinograms(); +} -int ProjData::get_num_sinograms() const -{ return proj_data_info_sptr->get_num_sinograms(); } +int +ProjData::get_num_sinograms() const { + return proj_data_info_sptr->get_num_sinograms(); +} -std::size_t ProjData::size_all() const -{ return proj_data_info_sptr->size_all(); } +std::size_t +ProjData::size_all() const { + return proj_data_info_sptr->size_all(); +} END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataFromStream.h b/src/include/stir/ProjDataFromStream.h index 84a39f33a0..de07bc8030 100644 --- a/src/include/stir/ProjDataFromStream.h +++ b/src/include/stir/ProjDataFromStream.h @@ -17,6 +17,8 @@ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2013, Hammersmith Imanet Ltd + Copyright (C) 2016, University of Hull + This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -34,7 +36,7 @@ #ifndef __ProjDataFromStream_H__ #define __ProjDataFromStream_H__ -#include "stir/ProjData.h" +#include "stir/ProjData.h" #include "stir/NumericType.h" #include "stir/ByteOrder.h" #include "stir/shared_ptr.h" @@ -44,28 +46,28 @@ START_NAMESPACE_STIR - /*! \ingroup projdata \brief A class which reads/writes projection data from/to a (binary) stream. - At the end of every write (i.e., \ set_*) operation, the stream is flushed such that - subsequent read operations from the same file will be able this data even if the + At the end of every write (i.e., \ set_*) operation, the stream is flushed such that + subsequent read operations from the same file will be able this data even if the stream isn't closed yet. This is important in an interactive context, as the object owning the stream might not be deleted yet before we try to read the file again. \warning Data have to be contiguous. - \warning The parameter \c make_num_tangential_poss_odd (used in various - \c get_ functions) is temporary and will be removed soon. - + \warning The parameter make_num_tangential_poss_odd (used in various + get_ functions) is temporary and will be removed soon. + \warning Changing the sequence of the timing bins is not supported. */ -class ProjDataFromStream : public ProjData -{ +class ProjDataFromStream : public ProjData { public: - enum StorageOrder { - Segment_AxialPos_View_TangPos, Segment_View_AxialPos_TangPos, - Unsupported }; + Segment_AxialPos_View_TangPos, + Segment_View_AxialPos_TangPos, + Timing_Segment_View_AxialPos_TangPos, + Unsupported + }; #if 0 static ProjDataFromStream* ask_parameters(const bool on_disk = true); #endif @@ -74,80 +76,77 @@ class ProjDataFromStream : public ProjData //! Empty constructor ProjDataFromStream() {} -#endif - +#endif + //! constructor taking all necessary parameters - /*! + /*! \param segment_sequence_in_stream has to be set according to the order in which the segments occur in the stream. segment_sequence_in_stream[i] is the segment number of the i-th segment in the stream. */ - ProjDataFromStream (shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, - shared_ptr const& s, - const std::streamoff offs, - const std::vector& segment_sequence_in_stream, - StorageOrder o = Segment_View_AxialPos_TangPos, - NumericType data_type = NumericType::FLOAT, - ByteOrder byte_order = ByteOrder::native, - float scale_factor = 1 ); + ProjDataFromStream(shared_ptr const& exam_info_sptr, shared_ptr const& proj_data_info_ptr, + shared_ptr const& s, const std::streamoff offs, + const std::vector& segment_sequence_in_stream, StorageOrder o = Segment_View_AxialPos_TangPos, + NumericType data_type = NumericType::FLOAT, ByteOrder byte_order = ByteOrder::native, + float scale_factor = 1.f); //! as above, but with a default value for segment_sequence_in_stream /*! The default value for segment_sequence_in_stream is a vector with values min_segment_num, min_segment_num+1, ..., max_segment_num */ - ProjDataFromStream (shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, - shared_ptr const& s, - const std::streamoff offs = 0, - StorageOrder o = Segment_View_AxialPos_TangPos, - NumericType data_type = NumericType::FLOAT, - ByteOrder byte_order = ByteOrder::native, - float scale_factor = 1 ); + ProjDataFromStream(shared_ptr const& exam_info_sptr, shared_ptr const& proj_data_info_ptr, + shared_ptr const& s, const std::streamoff offs = 0, + StorageOrder o = Segment_View_AxialPos_TangPos, NumericType data_type = NumericType::FLOAT, + ByteOrder byte_order = ByteOrder::native, float scale_factor = 1.f); + //! Obtain the storage order inline StorageOrder get_storage_order() const; - + //! Get the offset -Changed into streamoff from int - //inline int get_offset_in_stream() const; + // inline int get_offset_in_stream() const; inline std::streamoff get_offset_in_stream() const; - - //! Get the data_type in the stream + + //! Get the data_type in the stream inline NumericType get_data_type_in_stream() const; - + //! Get the byte order - inline ByteOrder get_byte_order_in_stream() const; - + inline ByteOrder get_byte_order_in_stream() const; + //! Get the segment sequence inline std::vector get_segment_sequence_in_stream() const; - - //! Get & set viewgram - Viewgram get_viewgram(const int view_num, const int segment_num,const bool make_num_tangential_poss_odd=false) const; + //! Get the timing bins sequence + inline std::vector get_timing_poss_sequence_in_stream() const; + + //! Get & set viewgram + Viewgram get_viewgram(const int view_num, const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; Succeeded set_viewgram(const Viewgram& v); - - //! Get & set sinogram - Sinogram get_sinogram(const int ax_pos_num, const int segment_num,const bool make_num_tangential_poss_odd=false) const; + + //! Get & set sinogram + Sinogram get_sinogram(const int ax_pos_num, const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; + Succeeded set_sinogram(const Sinogram& s); - + //! Get all sinograms for the given segment - SegmentBySinogram get_segment_by_sinogram(const int segment_num) const; + SegmentBySinogram get_segment_by_sinogram(const int segment_num, const int timing_num = 0) const; //! Get all viewgrams for the given segment - SegmentByView get_segment_by_view(const int segment_num) const; - - + SegmentByView get_segment_by_view(const int segment_num, const int timing_pos = 0) const; + //! Set all sinograms for the given segment Succeeded set_segment(const SegmentBySinogram&); //! Set all viewgrams for the given segment Succeeded set_segment(const SegmentByView&); //! Get scale factor - float get_scale_factor() const; + float get_scale_factor() const; //! Get the value of bin. virtual float get_bin_value(const Bin& this_bin) const; - + //! Set the value of the bin - virtual void set_bin_value(const Bin &bin); - + virtual void set_bin_value(const Bin& bin); + protected: //! the stream with the data shared_ptr sino_stream; @@ -156,38 +155,48 @@ class ProjDataFromStream : public ProjData std::vector get_offsets_bin(const Bin) const; private: + void activate_TOF(); //! offset of the whole 3d sinogram in the stream - std::streamoff offset; - - - //!the order in which the segments occur in the stream + std::streamoff offset; + //! offset of a complete non-tof sinogram + std::streamoff offset_3d_data; + + //! the order in which the segments occur in the stream std::vector segment_sequence; - + //! the order in which the timing bins occur in the stream + std::vector timing_poss_sequence; + inline int find_segment_index_in_sequence(const int segment_num) const; - + StorageOrder storage_order; - + NumericType on_disk_data_type; - + ByteOrder on_disk_byte_order; - + // scale_factor is only used when reading data from file. Data are stored in // memory as float, with the scale factor multiplied out float scale_factor; - + + //! Calculate the offset of the give timing position + //! \warning N.E: This function might be one the major components of STIR's speeds + std::streamoff get_offset_timing(const int timing_num) const; + //! Calculate the offset for the given segmnet + //! \warning This function returns the offset of a segment *WITHING* a timing position + //! If you like to get the offset of a segment from different timing positions it has to + //! be combined with get_offset_timing(). std::streamoff get_offset_segment(const int segment_num) const; - - //! Calculate offsets for viewgram data - std::vector get_offsets(const int view_num, const int segment_num) const; + + //! Calculate offsets for viewgram data + std::vector get_offsets(const int view_num, const int segment_num, const int timing_num = 0) const; //! Calculate offsets for sinogram data - std::vector get_offsets_sino(const int ax_pos_num, const int segment_num) const; - + std::vector get_offsets_sino(const int ax_pos_num, const int segment_num, const int timing_num = 0) const; + private: #if __cplusplus > 199711L ProjDataFromStream& operator=(ProjDataFromStream&&) = delete; #endif - }; END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataFromStream.inl b/src/include/stir/ProjDataFromStream.inl index 07168b2046..ddcebf0928 100644 --- a/src/include/stir/ProjDataFromStream.inl +++ b/src/include/stir/ProjDataFromStream.inl @@ -33,45 +33,50 @@ START_NAMESPACE_STIR - -//ProjDataFromStream::ProjDataFromStream() +// ProjDataFromStream::ProjDataFromStream() //{} -ProjDataFromStream::StorageOrder -ProjDataFromStream::get_storage_order() const -{ return storage_order; } +ProjDataFromStream::StorageOrder +ProjDataFromStream::get_storage_order() const { + return storage_order; +} -int -ProjDataFromStream::find_segment_index_in_sequence(const int segment_num) const -{ +int +ProjDataFromStream::find_segment_index_in_sequence(const int segment_num) const { #ifndef STIR_NO_NAMESPACES - std::vector::const_iterator iter = - std::find(segment_sequence.begin(), segment_sequence.end(), segment_num); + std::vector::const_iterator iter = std::find(segment_sequence.begin(), segment_sequence.end(), segment_num); #else - vector::const_iterator iter = - find(segment_sequence.begin(), segment_sequence.end(), segment_num); + vector::const_iterator iter = find(segment_sequence.begin(), segment_sequence.end(), segment_num); #endif // TODO do some proper error handling here - assert(iter != segment_sequence.end()); + assert(iter != segment_sequence.end()); return static_cast(iter - segment_sequence.begin()); } +std::streamoff +ProjDataFromStream::get_offset_in_stream() const { + return offset; +} -std::streamoff -ProjDataFromStream::get_offset_in_stream() const -{ return offset; } +NumericType +ProjDataFromStream::get_data_type_in_stream() const { + return on_disk_data_type; +} -NumericType -ProjDataFromStream::get_data_type_in_stream() const -{ return on_disk_data_type; } +ByteOrder +ProjDataFromStream::get_byte_order_in_stream() const { + return on_disk_byte_order; +} -ByteOrder -ProjDataFromStream::get_byte_order_in_stream() const -{ return on_disk_byte_order; } +std::vector +ProjDataFromStream::get_segment_sequence_in_stream() const { + return segment_sequence; +} -std::vector -ProjDataFromStream::get_segment_sequence_in_stream() const -{ return segment_sequence; } +std::vector +ProjDataFromStream::get_timing_poss_sequence_in_stream() const { + return timing_poss_sequence; +} #if 0 // this does not make a lot of sense. How to compare files etc. ? @@ -87,10 +92,7 @@ ProjDataFromStream::operator ==(const ProjDataFromStream& proj) (on_disk_data_type == proj.get_data_type_in_stream())&& (get_byte_order_in_stream() == proj.get_byte_order_in_stream()) ; } - #endif - - END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataGEAdvance.h b/src/include/stir/ProjDataGEAdvance.h index ac4fb0cae8..1496b7b0f6 100644 --- a/src/include/stir/ProjDataGEAdvance.h +++ b/src/include/stir/ProjDataGEAdvance.h @@ -33,7 +33,7 @@ #ifndef __ProjDataGEAdvance_H__ #define __ProjDataGEAdvance_H__ -#include "stir/ProjData.h" +#include "stir/ProjData.h" #include "stir/NumericType.h" #include "stir/ByteOrder.h" #include "stir/Array.h" @@ -43,7 +43,6 @@ START_NAMESPACE_STIR - /*! \ingroup projdata \brief A class which reads projection data from a GE Advance @@ -56,50 +55,48 @@ START_NAMESPACE_STIR No writing yet. */ -class ProjDataGEAdvance : public ProjData -{ +class ProjDataGEAdvance : public ProjData { public: - - static ProjDataGEAdvance* ask_parameters(const bool on_disk = true); - - - ProjDataGEAdvance (std::iostream* s); - - //! Get & set viewgram - Viewgram get_viewgram(const int view_num, const int segment_num,const bool make_num_tangential_poss_odd=false) const; - Succeeded set_viewgram(const Viewgram& v); - - //! Get & set sinogram - Sinogram get_sinogram(const int ax_pos_num, const int sergment_num,const bool make_num_tangential_poss_odd=false) const; - Succeeded set_sinogram(const Sinogram& s); - - + static ProjDataGEAdvance* ask_parameters(const bool on_disk = true); + + ProjDataGEAdvance(std::iostream* s); + + //! Get & set viewgram + Viewgram get_viewgram(const int view_num, const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; + Succeeded set_viewgram(const Viewgram& v); + + //! Get & set sinogram + Sinogram get_sinogram(const int ax_pos_num, const int sergment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; + Succeeded set_sinogram(const Sinogram& s); + + // float get_bin_value(const Bin& this_bin) const + // { + // // Do nothing + // } private: - //the file with the data - //This has to be a reference (or pointer) to a stream, - //because assignment on streams is not defined; + // the file with the data + // This has to be a reference (or pointer) to a stream, + // because assignment on streams is not defined; // TODO make shared_ptr std::iostream* sino_stream; - //offset of the whole 3d sinogram in the stream - std::streamoff offset; - - + // offset of the whole 3d sinogram in the stream + std::streamoff offset; + NumericType on_disk_data_type; - + ByteOrder on_disk_byte_order; - + // view_scaling_factor is only used when reading data from file. Data are stored in // memory as float, with the scale factor multiplied out - - Array<1,float> view_scaling_factor; - - std::vector num_rings_orig; - std::vector segment_sequence_orig; + Array<1, float> view_scaling_factor; + std::vector num_rings_orig; + std::vector segment_sequence_orig; }; END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/ProjDataGEHDF5.h b/src/include/stir/ProjDataGEHDF5.h index 2adcb21bb2..c497299904 100644 --- a/src/include/stir/ProjDataGEHDF5.h +++ b/src/include/stir/ProjDataGEHDF5.h @@ -42,55 +42,53 @@ START_NAMESPACE_STIR namespace GE { namespace RDF_HDF5 { - /*! \ingroup projdata \ingroup GE \brief A class which reads projection data from a GE HDF5 sinogram file. */ -class ProjDataGEHDF5 : public ProjData -{ +class ProjDataGEHDF5 : public ProjData { public: + explicit ProjDataGEHDF5(const std::string& input_filename); - explicit ProjDataGEHDF5(const std::string& input_filename); - - explicit ProjDataGEHDF5(shared_ptr input_hdf5_sptr); + explicit ProjDataGEHDF5(shared_ptr input_hdf5_sptr); private: - //! called to get data from m_input_hdf5_sptr - void initialise_from_wrapper(); - - unsigned int find_segment_offset(const int segment_num) const; - //! Set Viewgram - Succeeded set_viewgram(const Viewgram& v); - //! Set Sinogram - Succeeded set_sinogram(const Sinogram& s); - //! Get Viewgram - Viewgram get_viewgram(const int view_num, const int segment_num,const bool make_num_tangential_poss_odd=false) const; - //! Get Sinogram - Sinogram get_sinogram(const int ax_pos_num, const int sergment_num,const bool make_num_tangential_poss_odd=false) const; - //! Get the segment sequence - std::vector get_segment_sequence_in_hdf5() const; - std::vector< unsigned int > seg_ax_offset; - unsigned int find_segment_index_in_sequence(const int segment_num) const; - //! Cache the segment sequence of the GE data. - //! \author Kris Thielemans - void initialise_segment_sequence(); - - void initialise_ax_pos_offset(); - - void initialise_viewgram_buffer(); - //! Handler of the HDF5 input data and header - shared_ptr m_input_hdf5_sptr; - - std::vector< int > segment_sequence; - std::vector > tof_data; + //! called to get data from m_input_hdf5_sptr + void initialise_from_wrapper(); + + unsigned int find_segment_offset(const int segment_num) const; + //! Set Viewgram + Succeeded set_viewgram(const Viewgram& v); + //! Set Sinogram + Succeeded set_sinogram(const Sinogram& s); + //! Get Viewgram + Viewgram get_viewgram(const int view_num, const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; + //! Get Sinogram + Sinogram get_sinogram(const int ax_pos_num, const int sergment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos = 0) const; + //! Get the segment sequence + std::vector get_segment_sequence_in_hdf5() const; + std::vector seg_ax_offset; + unsigned int find_segment_index_in_sequence(const int segment_num) const; + //! Cache the segment sequence of the GE data. + //! \author Kris Thielemans + void initialise_segment_sequence(); + + void initialise_ax_pos_offset(); + + void initialise_viewgram_buffer(); + //! Handler of the HDF5 input data and header + shared_ptr m_input_hdf5_sptr; + + std::vector segment_sequence; + std::vector> tof_data; }; -} // namespace -} +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/ProjDataInMemory.h b/src/include/stir/ProjDataInMemory.h index d832675e80..bf687b1b12 100644 --- a/src/include/stir/ProjDataInMemory.h +++ b/src/include/stir/ProjDataInMemory.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2016, UCL Copyright (C) 2002 - 2011-02-23, Hammersmith Imanet Ltd Copyright (C) 2019-2020, UCL This file is part of STIR. @@ -20,18 +21,19 @@ \ingroup projdata \brief Declaration of class stir::ProjDataInMemory + \author Nikos Efthimiou \author Kris Thielemans */ #ifndef __stir_ProjDataInMemory_H__ #define __stir_ProjDataInMemory_H__ -#include "stir/ProjDataFromStream.h" +#include "stir/ProjDataFromStream.h" #include "stir/Array.h" #include /* Implementation note (KT) - + I first used the std::stringstream class (when available). However, this class currently has a problem that you cannot preallocate a buffer size. This means that when we write to the stringstream, it will @@ -45,7 +47,7 @@ //#define STIR_USE_OLD_STRSTREAM #if defined(BOOST_NO_STRINGSTREAM) && !defined(STIR_USE_OLD_STRSTREAM) -#define STIR_USE_OLD_STRSTREAM +# define STIR_USE_OLD_STRSTREAM #endif START_NAMESPACE_STIR @@ -59,26 +61,23 @@ class Succeeded; Mainly useful for temporary storage of projection data. */ -class ProjDataInMemory : public ProjDataFromStream -{ -public: - +class ProjDataInMemory : public ProjDataFromStream { +public: //! constructor with only info, but no data - /*! + /*! \param proj_data_info_ptr object specifying all sizes etc. The ProjDataInfo object pointed to will not be modified. - \param initialise_with_0 specifies if the data should be set to 0. + \param initialise_with_0 specifies if the data should be set to 0. If \c false, the data is undefined until you set it yourself. */ - ProjDataInMemory (shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, - const bool initialise_with_0 = true); + ProjDataInMemory(shared_ptr const& exam_info_sptr, shared_ptr const& proj_data_info_ptr, + const bool initialise_with_0 = true); //! constructor that copies data from another ProjData - ProjDataInMemory (const ProjData& proj_data); + ProjDataInMemory(const ProjData& proj_data); //! Copy constructor - ProjDataInMemory (const ProjDataInMemory& proj_data); + ProjDataInMemory(const ProjDataInMemory& proj_data); //! set all bins to the same value /*! will call error() if setting failed */ @@ -93,76 +92,65 @@ class ProjDataInMemory : public ProjDataFromStream //! destructor deallocates all memory the object owns virtual ~ProjDataInMemory(); - + //! Returns a value of a bin float get_bin_value(Bin& bin); - - void set_bin_value(const Bin &bin); - + + void set_bin_value(const Bin& bin); + //! \deprecated a*x+b*y (\see xapyb) - STIR_DEPRECATED virtual void axpby(const float a, const ProjData& x, - const float b, const ProjData& y); + STIR_DEPRECATED virtual void axpby(const float a, const ProjData& x, const float b, const ProjData& y); //! set values of the array to x*a+y*b, where a and b are scalar, and x and y are ProjData. /// This implementation requires that x and y are ProjDataInMemory /// (else falls back on general method) - virtual void xapyb(const ProjData& x, const float a, - const ProjData& y, const float b); + virtual void xapyb(const ProjData& x, const float a, const ProjData& y, const float b); //! set values of the array to x*a+y*b, where a, b, x and y are ProjData. /// This implementation requires that a, b, x and y are ProjDataInMemory /// (else falls back on general method) - virtual void xapyb(const ProjData& x, const ProjData& a, - const ProjData& y, const ProjData& b); + virtual void xapyb(const ProjData& x, const ProjData& a, const ProjData& y, const ProjData& b); //! set values of the array to self*a+y*b where a and b are scalar, y is ProjData /// This implementation requires that a, b and y are ProjDataInMemory - /// (else falls back on general method) + /// (else falls back on general method) virtual void sapyb(const float a, const ProjData& y, const float b); //! set values of the array to self*a+y*b where a, b and y are ProjData - /// This implementation requires that a, b and y are ProjDataInMemory - /// (else falls back on general method) + /// This implementation requires that a, b and y are ProjDataInMemory + /// (else falls back on general method) virtual void sapyb(const ProjData& a, const ProjData& y, const ProjData& b); /** @name iterator typedefs * iterator typedefs */ ///@{ - typedef Array<1,float>::iterator iterator; - typedef Array<1,float>::const_iterator const_iterator; - typedef Array<1,float>::full_iterator full_iterator; - typedef Array<1,float>::const_full_iterator const_full_iterator; + typedef Array<1, float>::iterator iterator; + typedef Array<1, float>::const_iterator const_iterator; + typedef Array<1, float>::full_iterator full_iterator; + typedef Array<1, float>::const_full_iterator const_full_iterator; ///@} //! start value for iterating through all elements in the array, see iterator - inline iterator begin() - { return buffer.begin(); } + inline iterator begin() { return buffer.begin(); } //! start value for iterating through all elements in the (const) array, see iterator - inline const_iterator begin() const - { return buffer.begin(); } + inline const_iterator begin() const { return buffer.begin(); } //! end value for iterating through all elements in the array, see iterator - inline iterator end() - { return buffer.end(); } + inline iterator end() { return buffer.end(); } //! end value for iterating through all elements in the (const) array, see iterator - inline const_iterator end() const - { return buffer.end(); } + inline const_iterator end() const { return buffer.end(); } //! start value for iterating through all elements in the array, see iterator - inline iterator begin_all() - { return buffer.begin_all(); } + inline iterator begin_all() { return buffer.begin_all(); } //! start value for iterating through all elements in the (const) array, see iterator - inline const_iterator begin_all() const - { return buffer.begin_all(); } + inline const_iterator begin_all() const { return buffer.begin_all(); } //! end value for iterating through all elements in the array, see iterator - inline iterator end_all() - { return buffer.end_all(); } + inline iterator end_all() { return buffer.end_all(); } //! end value for iterating through all elements in the (const) array, see iterator - inline const_iterator end_all() const - { return buffer.end_all(); } + inline const_iterator end_all() const { return buffer.end_all(); } private: - Array<1,float> buffer; - + Array<1, float> buffer; + size_t get_size_of_buffer_in_bytes() const; //! allocates buffer for storing the data. Has to be called by constructors before create_stream() @@ -174,5 +162,4 @@ class ProjDataInMemory : public ProjDataFromStream END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/ProjDataInfo.h b/src/include/stir/ProjDataInfo.h index 95da16ddb2..fb10b27580 100644 --- a/src/include/stir/ProjDataInfo.h +++ b/src/include/stir/ProjDataInfo.h @@ -4,6 +4,7 @@ Copyright (C) 2000 PARAPET partners Copyright (C) 2000 - 2011-10-14, Hammersmith Imanet Ltd Copyright (C) 2011-07-01 - 2011, Kris Thielemans + Copyright (C) 2016-17, University of Hull Copyright (C) 2017-2018, 2020, University College London This file is part of STIR. @@ -24,8 +25,10 @@ \brief Declaration of class stir::ProjDataInfo + \author Nikos Efthimiou \author Sanida Mustafovic \author Kris Thielemans + \author Elise Emond \author PARAPET project */ @@ -41,56 +44,59 @@ START_NAMESPACE_STIR -template class Sinogram; -template class Viewgram; -template class SegmentByView; -template class SegmentBySinogram; -template class RelatedViewgrams; +template +class Sinogram; +template +class Viewgram; +template +class SegmentByView; +template +class SegmentBySinogram; +template +class RelatedViewgrams; class DataSymmetriesForViewSegmentNumbers; class ViewSegmentNumbers; class Bin; -template class LOR; -template class LORInAxialAndNoArcCorrSinogramCoordinates; +template +class LOR; +template +class LORInAxialAndNoArcCorrSinogramCoordinates; class PMessage; /*! \ingroup projdata - \brief An (abstract base) class that contains information on the + \brief An (abstract base) class that contains information on the projection data. This class supports a fixed horizontal and vertical bed position. Both are set to zero by default. Continuous bed motion is not supported. */ -class ProjDataInfo -{ +class ProjDataInfo { protected: typedef ProjDataInfo root_type; public: - /********** static members **************/ //! Ask for the details and return a ProjDataInfo pointer - static ProjDataInfo* - ask_parameters(); + static ProjDataInfo* ask_parameters(); //! Construct a ProjDataInfo with span=3 for segment 0, but span=1 for others. /*! This function implements our old understanding of GE data. An alternative is to use - construct_proj_data_info() with \c span=2.*/ - static ProjDataInfo* - ProjDataInfoGE(const shared_ptr& scanner_ptr, - const int max_delta, - const int num_views, const int num_tangential_poss, - const bool arc_corrected = true); + construct_proj_data_info() with \c span=2. + \warning N.E: TOF mash factor = 1, means possible many TOF bins + \warning N.E: TOF mash factor = 0 will produce nonTOF data +*/ + static ProjDataInfo* ProjDataInfoGE(const shared_ptr& scanner_ptr, const int max_delta, const int num_views, + const int num_tangential_poss, const bool arc_corrected = true, + const int tof_mash_factor = 0); //! Old name for construct_proj_data_info() /*! \deprecated - */ - static ProjDataInfo* - ProjDataInfoCTI(const shared_ptr& scanner_ptr, - const int span, const int max_delta, - const int num_views, const int num_tangential_poss, - const bool arc_corrected = true); + */ + static ProjDataInfo* ProjDataInfoCTI(const shared_ptr& scanner_ptr, const int span, const int max_delta, + const int num_views, const int num_tangential_poss, const bool arc_corrected = true, + const int tof_mash_factor = 0); //! Construct a ProjDataInfo suitable with a given span /*! \c span is used to denote the amount of axial compression (see the STIR glossary). @@ -98,36 +104,47 @@ class ProjDataInfo Siemens/CTI currently uses odd span. GE scanners use a mixed case where segment 0 has span 3, while other segments have span 2. We call this span 2. As a generalisation, this function supports any even span. + + \warning N.E: TOF mash factor = 1, means possible many TOF bins + \warning N.E: TOF mash factor = 0 will produce nonTOF data */ - static unique_ptr - construct_proj_data_info(const shared_ptr& scanner_sptr, - const int span, const int max_delta, - const int num_views, const int num_tangential_poss, - const bool arc_corrected = true); + static unique_ptr construct_proj_data_info(const shared_ptr& scanner_sptr, const int span, + const int max_delta, const int num_views, + const int num_tangential_poss, const bool arc_corrected = true, + const int tof_mash_factor = 0); + //! \name Conversion functions between TOF delta_time and mm + //@{ + inline static double mm_to_tof_delta_time(const float dist); + inline static float tof_delta_time_to_mm(const double delta_time); + //@} /************ constructors ***********/ // TODO should probably be protected //! Construct an empty object - ProjDataInfo(); - - //! Constructor setting all relevant info for a ProjDataInfo - /*! The num_axial_pos_per_segment argument should be such that - num_axial_pos_per_segment[segment_num] gives you the appropriate value - for a particular segment_num - */ - ProjDataInfo(const shared_ptr& scanner_ptr, - const VectorWithOffset& num_axial_pos_per_segment, - const int num_views, - const int num_tangential_poss); - + ProjDataInfo(); - //! Standard trick for a 'virtual copy-constructor' + //! Constructor setting all relevant info for a ProjDataInfo + /*! The num_axial_pos_per_segment argument should be such that + num_axial_pos_per_segment[segment_num] gives you the appropriate value + for a particular segment_num + */ + ProjDataInfo(const shared_ptr& scanner_ptr, const VectorWithOffset& num_axial_pos_per_segment, + const int num_views, const int num_tangential_poss); + + //! Overloaded Contructor with TOF initialisation + ProjDataInfo(const shared_ptr& scanner_ptr, const VectorWithOffset& num_axial_pos_per_segment, + const int num_views, const int num_tangential_poss, const int tof_mash_factor); + + //! Standard trick for a 'virtual copy-constructor' virtual ProjDataInfo* clone() const = 0; //! Like clone() but return a shared_ptr inline shared_ptr create_shared_clone() const; + //! Similar to create_shared_clone() but returns a non-tof version of ProjDataInfo setting tof mashing factor = 0 + inline shared_ptr create_non_tof_clone() const; + //! Destructor virtual ~ProjDataInfo() {} @@ -139,29 +156,29 @@ class ProjDataInfo //@{ //! Set a new range of segment numbers - /*! - This function is virtual in case a derived class needs to know the + /*! + This function is virtual in case a derived class needs to know the segment range changed. \warning the new range has to be 'smaller' than the old one. */ virtual void reduce_segment_range(const int min_segment_num, const int max_segment_num); //! Set number of views (min_view_num is set to 0). - /*! This function is virtual in case a derived class needs to know the + /*! This function is virtual in case a derived class needs to know the number of views changed. */ virtual void set_num_views(const int num_views); //! Set number of tangential positions - /*! This function is virtual in case a derived class needs to know the + /*! This function is virtual in case a derived class needs to know the number of tangential positions changed. */ virtual void set_num_tangential_poss(const int num_tang_poss); //! Set number of axial positions per segment - /*! + /*! \param num_axial_poss_per_segment is a vector with the new numbers, where the index into the vector is the segment_num (i.e. it is not related to the storage order of the segments or so). - This function is virtual in case a derived class needs to know the + This function is virtual in case a derived class needs to know the number of axial positions changed. */ - virtual void set_num_axial_poss_per_segment(const VectorWithOffset& num_axial_poss_per_segment); + virtual void set_num_axial_poss_per_segment(const VectorWithOffset& num_axial_poss_per_segment); //! Set minimum axial position number for 1 segment /*! This function is virtual in case a derived class needs to know the number changed. */ @@ -169,13 +186,15 @@ class ProjDataInfo //! Set maximum axial position number for 1 segment /*! This function is virtual in case a derived class needs to know the number changed. */ virtual void set_max_axial_pos_num(const int max_ax_pos_num, const int segment_num); - + //! Set minimum tangential position number /*! This function is virtual in case a derived class needs to know the number changed. */ virtual void set_min_tangential_pos_num(const int min_tang_poss); //! Set maximum tangential position number /*! This function is virtual in case a derived class needs to know the number changed. */ virtual void set_max_tangential_pos_num(const int max_tang_poss); + //! The the tof mashing factor. Min and Max timing position will be recalculated. + virtual void set_tof_mash_factor(const int new_num); //@} //! \name Functions that return info on the data size @@ -188,6 +207,10 @@ class ProjDataInfo inline int get_num_views() const; //! Get number of tangential positions inline int get_num_tangential_poss() const; + //! Get number of tof bin for a given time difference + inline int get_tof_bin(const double delta) const; + //! Get number of tof bin for a given time difference, ignoring the TOF mashing factor + inline int get_unmashed_tof_bin(const double delta) const; //! Get number of TOF bins inline int get_num_tof_poss() const; //! Get minimum segment number @@ -206,7 +229,22 @@ class ProjDataInfo inline int get_min_tangential_pos_num() const; //! Get maximum tangential position number inline int get_max_tangential_pos_num() const; + //! Get TOF mash factor + inline int get_tof_mash_factor() const; + //! Get the index of the first TOF position + inline int get_min_tof_pos_num() const; + //! Get the index of the last timgin position. + inline int get_max_tof_pos_num() const; + //! Get the coincide window in pico seconds + //! \warning Proposed convension: If the scanner is not TOF ready then + //! the coincidence windowis in the TOF bin size. + inline float get_coincidence_window_in_pico_sec() const; + //! Get the total width of the coincide window in mm + inline float get_coincidence_window_width() const; //! Get the total number of sinograms + /*! Note that this will count TOF sinograms as well. + \see get_num_non_tof_sinograms() + */ inline int get_num_sinograms() const; //! Get the number of non-tof sinograms /*! Note that this is the sum of the number of axial poss over all segments. @@ -217,24 +255,27 @@ class ProjDataInfo inline std::size_t size_all() const; //@} + //! Determine if TOF data from tof_mash_factor and num_tof_bins + inline bool is_tof_data() const; + //| \name Functions that return geometrical info for a Bin //@{ //! Get tangent of the co-polar angle of the normal to the projection plane /*! theta=0 for 'direct' planes (i.e. projection planes parallel to the scanner axis) */ - virtual float get_tantheta(const Bin&) const =0; - + virtual float get_tantheta(const Bin&) const = 0; + //! Get cosine of the co-polar angle of the normal to the projection plane /*! theta=0 for 'direct' planes (i.e. projection planes parallel to the scanner axis) */ inline float get_costheta(const Bin&) const; - + //! Get azimuthal angle phi of the normal to the projection plane /*! phi=0 when the normal vector has no component along the horizontal axis */ - virtual float get_phi(const Bin&) const =0; - + virtual float get_phi(const Bin&) const = 0; + //! Get value of the (roughly) axial coordinate in the projection plane (in mm) /*! t-axis is defined to be orthogonal to the s-axis (and to the vector normal to the projection plane */ - virtual float get_t(const Bin&) const =0; + virtual float get_t(const Bin&) const = 0; //! Return z-coordinate of the middle of the LOR (in mm) /*! @@ -248,13 +289,20 @@ class ProjDataInfo \code get_t(bin)/get_costheta(bin) \endcode - */ + */ virtual inline float get_m(const Bin&) const; //! Get value of the tangential coordinate in the projection plane (in mm) /*! s-axis is defined to be orthogonal to the scanner axis (and to the vector normal to the projection plane */ - virtual float get_s(const Bin&) const =0; + virtual float get_s(const Bin&) const = 0; + + //! Get value of the TOF location along the LOR (in mm) + //! k is a line segment connecting the centers of the two detectors. + float get_k(const Bin&) const; + + //! Get the value of the TOF timing difference (in ps) + double get_tof_delta_time(const Bin&) const; //! Get LOR corresponding to a given bin /*! @@ -262,16 +310,14 @@ class ProjDataInfo \warning This function might get a different type of arguments in the next release. */ - virtual void - get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates&, - const Bin&) const = 0; + virtual void get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates&, const Bin&) const = 0; //@} //! \name Functions that return info on the sampling in the different coordinates //@{ //! Get sampling distance in the \c t coordinate - /*! For some coordinate systems, this might depend on the Bin. The - default implementation computes it as + /*! For some coordinate systems, this might depend on the Bin. The + default implementation computes it as \code 1/2(get_t(..., ax_pos+1,...)-get_t(..., ax_pos-1,...))) \endcode @@ -279,8 +325,8 @@ class ProjDataInfo virtual float get_sampling_in_t(const Bin&) const; //! Get sampling distance in the \c m coordinate - /*! For some coordinate systems, this might depend on the Bin. The - default implementation computes it as + /*! For some coordinate systems, this might depend on the Bin. The + default implementation computes it as \code 1/2(get_m(..., ax_pos+1,...)-get_m(..., ax_pos-1,...))) \endcode @@ -288,18 +334,20 @@ class ProjDataInfo virtual float get_sampling_in_m(const Bin&) const; //! Get sampling distance in the \c s coordinate - /*! For some coordinate systems, this might depend on the Bin. The - default implementation computes it as + /*! For some coordinate systems, this might depend on the Bin. The + default implementation computes it as \code 1/2(get_s(..., tang_pos+1)-get_s(..., tang_pos_pos-1))) \endcode */ virtual float get_sampling_in_s(const Bin&) const; - //@} + //! Get sampling distance in the k \c coordinate + float get_sampling_in_k(const Bin&) const; + //@} //! Find the bin in the projection data that 'contains' an LOR - /*! Projection data corresponds to lines, so most Lines Of Response + /*! Projection data corresponds to lines, so most Lines Of Response (LORs) there is a bin in the projection data. Usually this will be the bin which has a central LOR that is 'closest' to the LOR that is passed as an argument. @@ -312,16 +360,14 @@ class ProjDataInfo in the next release. \see get_LOR() */ - virtual - Bin - get_bin(const LOR&) const = 0; + virtual Bin get_bin(const LOR&, const double delta_time = 0.0) const = 0; //! \name Equality of ProjDataInfo objects //@{ //! check equality - bool operator ==(const ProjDataInfo& proj) const; - - bool operator !=(const ProjDataInfo& proj) const; + bool operator==(const ProjDataInfo& proj) const; + + bool operator!=(const ProjDataInfo& proj) const; //! Check if \c *this contains \c proj virtual bool operator>=(const ProjDataInfo& proj) const; @@ -332,58 +378,71 @@ class ProjDataInfo //@{ //! Get empty viewgram - Viewgram get_empty_viewgram(const int view_num, const int segment_num, - const bool make_num_tangential_poss_odd = false) const; - + Viewgram get_empty_viewgram(const int view_num, const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos_num = 0) const; + //! Get empty_sinogram - Sinogram get_empty_sinogram(const int ax_pos_num, const int segment_num, - const bool make_num_tangential_poss_odd = false) const; + Sinogram get_empty_sinogram(const int ax_pos_num, const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos_num = 0) const; //! Get empty segment sino - SegmentByView get_empty_segment_by_view(const int segment_num, - const bool make_num_tangential_poss_odd = false) const; + SegmentByView get_empty_segment_by_view(const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos_num = 0) const; //! Get empty segment view - SegmentBySinogram get_empty_segment_by_sinogram(const int segment_num, - const bool make_num_tangential_poss_odd = false) const; - + SegmentBySinogram get_empty_segment_by_sinogram(const int segment_num, const bool make_num_tangential_poss_odd = false, + const int timing_pos_num = 0) const; //! Get empty related viewgrams, where the symmetries_ptr specifies the symmetries to use RelatedViewgrams get_empty_related_viewgrams(const ViewSegmentNumbers&, - const shared_ptr&, - const bool make_num_tangential_poss_odd = false) const; + const shared_ptr&, + const bool make_num_tangential_poss_odd = false, + const int timing_pos_num = 0) const; //@} - - //! Get scanner pointer + //! Get scanner pointer inline const Scanner* get_scanner_ptr() const; //! Get scanner shared pointer inline shared_ptr get_scanner_sptr() const; - + //! Return a string describing the object virtual std::string parameter_info() const; - + + //! Struct which holds two floating numbers + struct Float1Float2 { + float low_lim; + float high_lim; + }; + + //! Vector which holds the lower and higher boundary for each TOF position in mm, for faster access. + mutable VectorWithOffset tof_bin_boundaries_mm; + //! Vector which holds the lower and higher boundary for each TOF position in ps`, for faster access. + mutable VectorWithOffset tof_bin_boundaries_ps; + //! Vector which holds the lower and higher boundary for each TOF position, without the application of TOF mashing, in mm, for + //! faster access. + mutable VectorWithOffset tof_bin_unmashed_boundaries_mm; + //! Vector which holds the lower and higher boundary for each TOF position, without the application of TOF mashing, in ps`, for + //! faster access. + mutable VectorWithOffset tof_bin_unmashed_boundaries_ps; + //! Set horizontal bed position - void set_bed_position_horizontal(const float bed_position_horizontal_arg) - { bed_position_horizontal = bed_position_horizontal_arg; } + void set_bed_position_horizontal(const float bed_position_horizontal_arg) { + bed_position_horizontal = bed_position_horizontal_arg; + } //! Get horizontal bed position float get_bed_position_horizontal() const { return bed_position_horizontal; } //! Set vertical bed position - void set_bed_position_vertical(const float bed_position_vertical_arg) - { bed_position_vertical = bed_position_vertical_arg; } + void set_bed_position_vertical(const float bed_position_vertical_arg) { bed_position_vertical = bed_position_vertical_arg; } //! Get vertical bed position float get_bed_position_vertical() const { return bed_position_vertical; } - - inline bool has_energy_information() const - { - return scanner_ptr->has_energy_information(); - } + + inline bool has_energy_information() const { return scanner_ptr->has_energy_information(); } protected: - virtual bool blindly_equals(const root_type * const) const = 0; + virtual bool blindly_equals(const root_type* const) const = 0; private: shared_ptr scanner_ptr; @@ -391,11 +450,24 @@ class ProjDataInfo int max_view_num; int min_tangential_pos_num; int max_tangential_pos_num; - VectorWithOffset min_axial_pos_per_seg; + //! Minimum TOF pos + int min_tof_pos_num; + //! Maximum TOF pos + int max_tof_pos_num; + //! Minimum TOF pos regardless of the mashing factor + int min_unmashed_tof_pos_num; + //! Maximum TOF pos regardless of the mashing factor + int max_unmashed_tof_pos_num; + //! TOF mash factor. + int tof_mash_factor; + //! Finally (with any mashing factor) TOF bin increament. + float tof_increament_in_mm; + //! Number of tof bins (TOF mash factor applied) + int num_tof_bins; + VectorWithOffset min_axial_pos_per_seg; VectorWithOffset max_axial_pos_per_seg; float bed_position_horizontal; float bed_position_vertical; - }; END_NAMESPACE_STIR @@ -403,4 +475,3 @@ END_NAMESPACE_STIR #include "stir/ProjDataInfo.inl" #endif // __ProjDataInfo_H__ - diff --git a/src/include/stir/ProjDataInfo.inl b/src/include/stir/ProjDataInfo.inl index ca75d02fcc..3bc832545e 100644 --- a/src/include/stir/ProjDataInfo.inl +++ b/src/include/stir/ProjDataInfo.inl @@ -4,7 +4,8 @@ Copyright (C) 2000 PARAPET partners Copyright (C) 2000 - 2011-10-14, Hammersmith Imanet Ltd Copyright (C) 2011-07-01 - 2011, Kris Thielemans - Copyright (C) 2016, 2020, University College London + Copyright (C) 2016, University of Hull + Copyright (C) 2016, 2017, 2020, University College London This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -23,127 +24,214 @@ \ingroup projdata \brief Implementations of inline functions for class stir::ProjDataInfo + \author Nikos Efthimiou \author Sanida Mustafovic \author Kris Thielemans + \author Elise Emond \author Nikos Efthimiou \author PARAPET project */ +#include "boost/format.hpp" + START_NAMESPACE_STIR +double +ProjDataInfo::mm_to_tof_delta_time(const float dist) { + return dist / _c_light_div2; +} -shared_ptr -ProjDataInfo:: -create_shared_clone() const -{ +float +ProjDataInfo::tof_delta_time_to_mm(const double delta_time) { + return static_cast(delta_time * _c_light_div2); +} + +shared_ptr +ProjDataInfo::create_shared_clone() const { shared_ptr sptr(this->clone()); return sptr; } -int -ProjDataInfo::get_num_segments() const -{ return (max_axial_pos_per_seg.get_length());} +shared_ptr +ProjDataInfo::create_non_tof_clone() const { + shared_ptr sptr(this->clone()); + sptr->set_tof_mash_factor(0); // tof mashing factor = 0 is a trigger for non-tof data + return sptr; +} +int +ProjDataInfo::get_num_segments() const { + return (max_axial_pos_per_seg.get_length()); +} int -ProjDataInfo::get_num_axial_poss(const int segment_num) const -{ return max_axial_pos_per_seg[segment_num] - min_axial_pos_per_seg[segment_num]+1;} +ProjDataInfo::get_num_axial_poss(const int segment_num) const { + return max_axial_pos_per_seg[segment_num] - min_axial_pos_per_seg[segment_num] + 1; +} -int -ProjDataInfo::get_num_views() const -{ return max_view_num - min_view_num + 1; } +int +ProjDataInfo::get_num_views() const { + return max_view_num - min_view_num + 1; +} -int -ProjDataInfo::get_num_tangential_poss() const -{ return max_tangential_pos_num - min_tangential_pos_num + 1; } +int +ProjDataInfo::get_num_tangential_poss() const { + return max_tangential_pos_num - min_tangential_pos_num + 1; +} int -ProjDataInfo::get_num_tof_poss() const -{ return 1; /* always 1 at the moment */ } +ProjDataInfo::get_num_tof_poss() const { + return num_tof_bins; +} -int -ProjDataInfo::get_min_segment_num() const -{ return (max_axial_pos_per_seg.get_min_index()); } +int +ProjDataInfo::get_tof_bin(const double delta) const { + if (!is_tof_data()) + return 0; + + for (int i = min_tof_pos_num; i <= max_tof_pos_num; ++i) { + if (delta >= tof_bin_boundaries_ps[i].low_lim && delta < tof_bin_boundaries_ps[i].high_lim) + return i; + } + // TODO handle differently + warning(boost::format("TOF delta time %g out of range") % delta); + return min_tof_pos_num; +} -int -ProjDataInfo::get_max_segment_num()const -{ return (max_axial_pos_per_seg.get_max_index()); } +int +ProjDataInfo::get_unmashed_tof_bin(const double delta) const { + if (!is_tof_data()) + return 0; + + for (int i = min_unmashed_tof_pos_num; i <= max_unmashed_tof_pos_num; ++i) { + if (delta >= tof_bin_boundaries_ps[i].low_lim && delta < tof_bin_boundaries_ps[i].high_lim) + return i; + } + // TODO handle differently + warning(boost::format("TOF delta time %g out of range") % delta); + return min_tof_pos_num; +} int -ProjDataInfo::get_min_axial_pos_num(const int segment_num) const -{ return min_axial_pos_per_seg[segment_num];} +ProjDataInfo::get_tof_mash_factor() const { + return tof_mash_factor; +} +int +ProjDataInfo::get_min_segment_num() const { + return (max_axial_pos_per_seg.get_min_index()); +} int -ProjDataInfo::get_max_axial_pos_num(const int segment_num) const -{ return max_axial_pos_per_seg[segment_num];} +ProjDataInfo::get_max_segment_num() const { + return (max_axial_pos_per_seg.get_max_index()); +} +int +ProjDataInfo::get_min_axial_pos_num(const int segment_num) const { + return min_axial_pos_per_seg[segment_num]; +} -int -ProjDataInfo::get_min_view_num() const - { return min_view_num; } +int +ProjDataInfo::get_max_axial_pos_num(const int segment_num) const { + return max_axial_pos_per_seg[segment_num]; +} -int -ProjDataInfo::get_max_view_num() const -{ return max_view_num; } +int +ProjDataInfo::get_min_view_num() const { + return min_view_num; +} +int +ProjDataInfo::get_max_view_num() const { + return max_view_num; +} + +int +ProjDataInfo::get_min_tangential_pos_num() const { + return min_tangential_pos_num; +} -int -ProjDataInfo::get_min_tangential_pos_num()const -{ return min_tangential_pos_num; } +int +ProjDataInfo::get_max_tangential_pos_num() const { + return max_tangential_pos_num; +} -int -ProjDataInfo::get_max_tangential_pos_num()const -{ return max_tangential_pos_num; } +int +ProjDataInfo::get_min_tof_pos_num() const { + return min_tof_pos_num; +} -float -ProjDataInfo::get_costheta(const Bin& bin) const -{ - return - 1/sqrt(1+square(get_tantheta(bin))); +int +ProjDataInfo::get_max_tof_pos_num() const { + return max_tof_pos_num; } float -ProjDataInfo::get_m(const Bin& bin) const -{ - return - get_t(bin)/get_costheta(bin); +ProjDataInfo::get_coincidence_window_in_pico_sec() const { + return scanner_ptr->is_tof_ready() ? (scanner_ptr->get_max_num_timing_poss() * scanner_ptr->get_size_of_timing_pos()) + : (scanner_ptr->get_size_of_timing_pos()); } -const -Scanner* -ProjDataInfo::get_scanner_ptr() const -{ +float +ProjDataInfo::get_coincidence_window_width() const { + return tof_delta_time_to_mm(get_coincidence_window_in_pico_sec()); +} + +bool +ProjDataInfo::is_tof_data() const { + // First case: if tof_mash_factor == 0, scanner is not tof ready and no tof data + if (tof_mash_factor == 0) { + if (num_tof_bins != 1) { + error("Non-TOF data with inconsistent Time-of-Flight bin number - Aborted operation."); + } + return false; + } + // Second case: when tof_mash_factor is strictly positive, it means we have TOF data + else if (tof_mash_factor > 0) { + return true; + } + return false; +} + +float +ProjDataInfo::get_costheta(const Bin& bin) const { + return 1 / sqrt(1 + square(get_tantheta(bin))); +} + +float +ProjDataInfo::get_m(const Bin& bin) const { + return get_t(bin) / get_costheta(bin); +} + +const Scanner* +ProjDataInfo::get_scanner_ptr() const { return scanner_ptr.get(); } shared_ptr -ProjDataInfo::get_scanner_sptr() const -{ +ProjDataInfo::get_scanner_sptr() const { return scanner_ptr; } - int -ProjDataInfo::get_num_non_tof_sinograms() const -{ +ProjDataInfo::get_num_non_tof_sinograms() const { int num_sinos = 0; - for (int s=this->get_min_segment_num(); s<= this->get_max_segment_num(); ++s) + for (int s = this->get_min_segment_num(); s <= this->get_max_segment_num(); ++s) num_sinos += this->get_num_axial_poss(s); return num_sinos; } int -ProjDataInfo::get_num_sinograms() const -{ - return this->get_num_non_tof_sinograms()*this->get_num_tof_poss(); +ProjDataInfo::get_num_sinograms() const { + return this->get_num_non_tof_sinograms() * this->get_num_tof_poss(); } std::size_t -ProjDataInfo::size_all() const -{ return static_cast(this->get_num_sinograms()) * - static_cast(this->get_num_views() * this->get_num_tangential_poss()); } +ProjDataInfo::size_all() const { + return static_cast(this->get_num_sinograms()) * + static_cast(this->get_num_views() * this->get_num_tangential_poss()); +} END_NAMESPACE_STIR - diff --git a/src/include/stir/ProjDataInfoCylindrical.h b/src/include/stir/ProjDataInfoCylindrical.h index 225064dbe1..368321cd25 100644 --- a/src/include/stir/ProjDataInfoCylindrical.h +++ b/src/include/stir/ProjDataInfoCylindrical.h @@ -3,6 +3,7 @@ Copyright (C) 2000-2009, Hammersmith Imanet Ltd Copyright (C) 2013, University College London Copyright (C) 2013, Institute for Bioengineering of Catalonia + Copyright (C) 2016, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -23,6 +24,7 @@ \ingroup projdata \brief Declaration of class stir::ProjDataInfoCylindrical + \author Nikos Efthimiou \author Sanida Mustafovic \author Kris Thielemans \author Berta Marti Fuster @@ -31,8 +33,8 @@ #ifndef __stir_ProjDataInfoCylindrical_H__ #define __stir_ProjDataInfoCylindrical_H__ - #include "stir/ProjDataInfo.h" +#include "stir/CartesianCoordinate3D.h" #include #include @@ -41,8 +43,8 @@ START_NAMESPACE_STIR class Succeeded; /*! - \ingroup projdata - \brief projection data info for data corresponding to a + \ingroup projdata + \brief projection data info for data corresponding to a 'cylindrical' sampling. These data are organised by ring differences (allowing for @@ -51,15 +53,14 @@ class Succeeded; format. */ // TODOdoc more -class ProjDataInfoCylindrical: public ProjDataInfo -{ +class ProjDataInfoCylindrical : public ProjDataInfo { private: typedef ProjDataInfo base_type; typedef ProjDataInfoCylindrical self_type; public: //! Type used by get_all_ring_pairs_for_segment_axial_pos_num() - typedef std::vector > RingNumPairs; + typedef std::vector> RingNumPairs; //! Constructors ProjDataInfoCylindrical(); @@ -67,47 +68,53 @@ class ProjDataInfoCylindrical: public ProjDataInfo /*! The min and max ring difference in each segment are passed as VectorWithOffsets. All three vectors have to have index ranges from min_segment_num to max_segment_num. - + \warning Most of this library assumes that segment 0 corresponds to an average ring difference of 0. */ - ProjDataInfoCylindrical(const shared_ptr& scanner_ptr, - const VectorWithOffset& num_axial_poss_per_segment, - const VectorWithOffset& min_ring_diff, - const VectorWithOffset& max_ring_diff, - const int num_views,const int num_tangential_poss); - - inline virtual float get_tantheta(const Bin&) const; - - inline float get_phi(const Bin&) const; - + ProjDataInfoCylindrical(const shared_ptr& scanner_ptr, const VectorWithOffset& num_axial_poss_per_segment, + const VectorWithOffset& min_ring_diff, const VectorWithOffset& max_ring_diff, + const int num_views, const int num_tangential_poss); + + inline virtual float get_tantheta(const Bin&) const; + + inline float get_phi(const Bin&) const; + inline float get_t(const Bin&) const; //! Return z-coordinate of the middle of the LOR /*! The 0 of the z-axis is chosen in the middle of the scanner. - + \warning Current implementation assumes that the axial positions are always 'centred', i.e. get_m(Bin(..., min_axial_pos_num,...)) == - get_m(Bin(..., max_axial_pos_num,...)) - */ + */ inline float get_m(const Bin&) const; - virtual void - get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& lor, - const Bin& bin) const; + virtual void get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& lor, const Bin& bin) const; + + //! This function returns the two points connecting the two detectors of the LOR. + //! \warning there is not a specific guarantee that these are going to be the two + //! central points. This might be in the future a source of error. + void get_LOR_as_two_points(CartesianCoordinate3D& coord_1, CartesianCoordinate3D& coord_2, const Bin& bin) const; + + //! This function is the same as get_LOR_as_two_points() but should faster. + //! \warning More testing needed. + void get_LOR_as_two_points_alt(CartesianCoordinate3D& coord_1, CartesianCoordinate3D& coord_2, const int det1, + const int det2, const int ring1, const int ring2, const int timing_pos) const; - void set_azimuthal_angle_sampling(const float angle); - - //void set_axial_sampling(const float samp, int segment_num); + + // void set_axial_sampling(const float samp, int segment_num); //! set new number of views, covering the same azimuthal angle range /*! calls ProjDataInfo::set_num_views(), but makes sure that we cover the same range of angles as before (usually, but not necessarily, 180 degrees) by adjusting azimuthal_angle_sampling. */ - virtual void - set_num_views(const int new_num_views); + virtual void set_num_views(const int new_num_views); + + virtual void set_tof_mash_factor(const int new_num); //! Get the azimuthal sampling (in radians) inline float get_azimuthal_angle_sampling() const; @@ -115,19 +122,19 @@ class ProjDataInfoCylindrical: public ProjDataInfo virtual inline float get_sampling_in_m(const Bin&) const; //! Get the axial sampling (e.g in z_direction) - /*! + /*! \warning The implementation of this function currently assumes that the axial - sampling is equal to the ring spacing for non-spanned data - (i.e. no axial compression), while it is half the + sampling is equal to the ring spacing for non-spanned data + (i.e. no axial compression), while it is half the ring spacing for spanned data. */ inline float get_axial_sampling(int segment_num) const; - + //! Get average ring difference for the given segment inline float get_average_ring_difference(int segment_num) const; - //! Get minimum ring difference for the given segment + //! Get minimum ring difference for the given segment inline int get_min_ring_difference(int segment_num) const; - //! Get maximum ring difference for the given segment + //! Get maximum ring difference for the given segment inline int get_max_ring_difference(int segment_num) const; //! Set minimum ring difference @@ -135,21 +142,21 @@ class ProjDataInfoCylindrical: public ProjDataInfo //! Set maximum ring difference void set_max_ring_difference(int max_ring_diff_v, int segment_num); - virtual void set_num_axial_poss_per_segment(const VectorWithOffset& num_axial_poss_per_segment); + virtual void set_num_axial_poss_per_segment(const VectorWithOffset& num_axial_poss_per_segment); virtual void set_min_axial_pos_num(const int min_ax_pos_num, const int segment_num); virtual void set_max_axial_pos_num(const int max_ax_pos_num, const int segment_num); virtual void reduce_segment_range(const int min_segment_num, const int max_segment_num); //! Set detector ring radius for all views inline void set_ring_radii_for_all_views(const VectorWithOffset& new_ring_radius); - + //! Get detector ring radius for all views inline VectorWithOffset get_ring_radii_for_all_views() const; //! Get detector ring radius inline float get_ring_radius() const; - inline float get_ring_radius( const int view_num) const; + inline float get_ring_radius(const int view_num) const; //! Get detector ring spacing inline float get_ring_spacing() const; @@ -160,23 +167,22 @@ class ProjDataInfoCylindrical: public ProjDataInfo /*! This gets the result by comparing the number of detectors in the scanner_ptr with the actual number of views. - \warning In the debug version, it is checked with an assert() that the number of - detectors is an even multiple of the number of views. This is not checked in + \warning In the debug version, it is checked with an assert() that the number of + detectors is an even multiple of the number of views. This is not checked in the normal version though. */ inline int get_view_mashing_factor() const; //! Find which segment a particular ring difference belongs to /*! - \return Succeeded::yes when a corresponding segment was found. + \return Succeeded::yes when a corresponding segment was found. */ - inline Succeeded - get_segment_num_for_ring_difference(int& segment_num, const int ring_diff) const; + inline Succeeded get_segment_num_for_ring_difference(int& segment_num, const int ring_diff) const; //! Find to which segment and axial position a ring pair contributes /*! \a ring1, \a ring2 have to between 0 and scanner.get_num_rings()-1. - \return Succeeded::yes when a corresponding segment was found. + \return Succeeded::yes when a corresponding segment was found. \warning axial_pos_num returned might be outside the actual range in the proj_data_info. For CTI data with span, this essentially implements a 'michelogram'. @@ -185,38 +191,31 @@ class ProjDataInfoCylindrical: public ProjDataInfo the first ring-pair in the segment. \warning The implementation of this function currently assumes that the axial - sampling is equal to the ring spacing for non-spanned data - (i.e. no axial compression), while it is half the + sampling is equal to the ring spacing for non-spanned data + (i.e. no axial compression), while it is half the ring spacing for spanned data. */ - inline Succeeded - get_segment_axial_pos_num_for_ring_pair(int& segment_num, - int& axial_pos_num, - const int ring1, - const int ring2) const; + inline Succeeded get_segment_axial_pos_num_for_ring_pair(int& segment_num, int& axial_pos_num, const int ring1, + const int ring2) const; //! Find all ring pairs that contribute to a segment and axial position /*! \a ring1, \a ring2 will be between 0 and scanner.get_num_rings()-1. \warning The implementation of this function currently assumes that the axial - sampling is equal to the ring spacing for non-spanned data - (i.e. no axial compression), while it is half the + sampling is equal to the ring spacing for non-spanned data + (i.e. no axial compression), while it is half the ring spacing for spanned data. */ - inline const RingNumPairs& - get_all_ring_pairs_for_segment_axial_pos_num(const int segment_num, - const int axial_pos_num) const; + inline const RingNumPairs& get_all_ring_pairs_for_segment_axial_pos_num(const int segment_num, const int axial_pos_num) const; //! Find the number of ring pairs that contribute to a segment and axial position /*! \warning The implementation of this function currently assumes that the axial - sampling is equal to the ring spacing for non-spanned data - (i.e. no axial compression), while it is half the + sampling is equal to the ring spacing for non-spanned data + (i.e. no axial compression), while it is half the ring spacing for spanned data. */ - inline unsigned - get_num_ring_pairs_for_segment_axial_pos_num(const int segment_num, - const int axial_pos_num) const; + inline unsigned get_num_ring_pairs_for_segment_axial_pos_num(const int segment_num, const int axial_pos_num) const; //! Find a ring pair that contributes to a segment and axial position /*! @@ -226,55 +225,50 @@ class ProjDataInfoCylindrical: public ProjDataInfo min_ring_diff = max_ring_diff). Otherwise, a error() will be called. \warning The implementation of this function currently assumes that the axial - sampling is equal to the ring spacing for non-spanned data - (i.e. no axial compression), while it is half the + sampling is equal to the ring spacing for non-spanned data + (i.e. no axial compression), while it is half the ring spacing for spanned data. */ - void - get_ring_pair_for_segment_axial_pos_num(int& ring1, - int& ring2, - const int segment_num, - const int axial_pos_num) const; + void get_ring_pair_for_segment_axial_pos_num(int& ring1, int& ring2, const int segment_num, const int axial_pos_num) const; virtual std::string parameter_info() const; protected: - //! a variable that is set if the data corresponds to physical rings in the scanner /*! This is (only) used to prevent get_segment_axial_pos_num_for_ring_pair() et al to go wild. Indeed, for cases where there's cylindrical sampling, but not really any physical rings associated to the sampling, those functions will return invalid information. - The prime case where this is used is for data corresponding to (nearly) + The prime case where this is used is for data corresponding to (nearly) continuous detectors, such as DHCI systems, or the HiDAC. Ideally, this would be done by having a separate class for such systems which does not contain the ring-difference et al information. This seems to make the hierarchy too complicated though. - \bug The value of this variable is currently set by checking if the scanner + \bug The value of this variable is currently set by checking if the scanner is a HiDAC scanner. This needs to be changed. */ bool sampling_corresponds_to_physical_rings; - + protected: - virtual bool blindly_equals(const root_type * const) const = 0; + virtual bool blindly_equals(const root_type* const) const = 0; private: float azimuthal_angle_sampling; VectorWithOffset ring_radius; float ring_spacing; - VectorWithOffset min_ring_diff; + VectorWithOffset min_ring_diff; VectorWithOffset max_ring_diff; /* - Next members have to be mutable as they can be modified by const member + Next members have to be mutable as they can be modified by const member functions. We need this because of the presence of set_min_ring_difference() which invalidates these precalculated arrays. If your compiler does not support mutable (and you don't want to upgrade - it to something more sensible), your best bet is to remove the - set_*ring_difference functions, and move the content of + it to something more sensible), your best bet is to remove the + set_*ring_difference functions, and move the content of initialise_ring_diff_arrays() to the constructor. (Not recommended!) */ @@ -288,7 +282,7 @@ class ProjDataInfoCylindrical: public ProjDataInfo //! This member stores a table converting ring differences to segment numbers mutable VectorWithOffset ring_diff_to_segment_num; //! This member stores a table converting segment/axial_pos to ring1+ring2 - mutable VectorWithOffset > segment_axial_pos_to_ring1_plus_ring2; + mutable VectorWithOffset> segment_axial_pos_to_ring1_plus_ring2; //! This function sets all of the above void initialise_ring_diff_arrays() const; @@ -302,18 +296,15 @@ class ProjDataInfoCylindrical: public ProjDataInfo //! This member will signal if the array below contain sensible info or not mutable bool segment_axial_pos_to_ring_pair_allocated; //! This member stores a table used by get_all_ring_pairs_for_segment_axial_pos_num() - mutable VectorWithOffset< VectorWithOffset < shared_ptr > > - segment_axial_pos_to_ring_pair; + mutable VectorWithOffset>> segment_axial_pos_to_ring_pair; //! allocate table void allocate_segment_axial_pos_to_ring_pair() const; //! initialise one element of the above table void compute_segment_axial_pos_to_ring_pair(const int segment_num, const int axial_pos_num) const; - }; - END_NAMESPACE_STIR #include "stir/ProjDataInfoCylindrical.inl" diff --git a/src/include/stir/ProjDataInfoCylindrical.inl b/src/include/stir/ProjDataInfoCylindrical.inl index 3b4a0125b6..082947d921 100644 --- a/src/include/stir/ProjDataInfoCylindrical.inl +++ b/src/include/stir/ProjDataInfoCylindrical.inl @@ -40,189 +40,162 @@ START_NAMESPACE_STIR -void -ProjDataInfoCylindrical:: -initialise_ring_diff_arrays_if_not_done_yet() const -{ +void +ProjDataInfoCylindrical::initialise_ring_diff_arrays_if_not_done_yet() const { // for efficiency reasons, use "Double-Checked-Locking(DCL) pattern" with OpenMP atomic operation // OpenMP v3.1 or later required - // thanks to yohjp: http://stackoverflow.com/questions/27975737/how-to-handle-cached-data-structures-with-multi-threading-e-g-openmp -#if defined(STIR_OPENMP) && _OPENMP >=201012 + // thanks to yohjp: + // http://stackoverflow.com/questions/27975737/how-to-handle-cached-data-structures-with-multi-threading-e-g-openmp +#if defined(STIR_OPENMP) && _OPENMP >= 201012 bool initialised; -#pragma omp atomic read +# pragma omp atomic read initialised = ring_diff_arrays_computed; if (!initialised) #endif - { + { #if defined(STIR_OPENMP) -#pragma omp critical(PROJDATAINFOCYLINDRICALRINGDIFFARRAY) +# pragma omp critical(PROJDATAINFOCYLINDRICALRINGDIFFARRAY) #endif - { - if (!ring_diff_arrays_computed) - initialise_ring_diff_arrays(); - } + { + if (!ring_diff_arrays_computed) + initialise_ring_diff_arrays(); } + } } float -ProjDataInfoCylindrical::get_phi(const Bin& bin)const -{ return bin.view_num()*azimuthal_angle_sampling;} - +ProjDataInfoCylindrical::get_phi(const Bin& bin) const { + return bin.view_num() * azimuthal_angle_sampling; +} float -ProjDataInfoCylindrical::get_m(const Bin& bin) const -{ +ProjDataInfoCylindrical::get_m(const Bin& bin) const { this->initialise_ring_diff_arrays_if_not_done_yet(); - return - bin.axial_pos_num()*get_axial_sampling(bin.segment_num()) - - m_offset[bin.segment_num()]; + return bin.axial_pos_num() * get_axial_sampling(bin.segment_num()) - m_offset[bin.segment_num()]; } float -ProjDataInfoCylindrical::get_t(const Bin& bin) const -{ - return - get_m(bin)*get_costheta(bin); +ProjDataInfoCylindrical::get_t(const Bin& bin) const { + return get_m(bin) * get_costheta(bin); } float -ProjDataInfoCylindrical::get_tantheta(const Bin& bin) const -{ - const float delta=get_average_ring_difference(bin.segment_num()); - if (fabs(delta)<0.0001F) +ProjDataInfoCylindrical::get_tantheta(const Bin& bin) const { + const float delta = get_average_ring_difference(bin.segment_num()); + if (fabs(delta) < 0.0001F) return 0; - const float R=get_ring_radius(bin.view_num()); - assert(R>=fabs(get_s(bin))); - return delta*ring_spacing/(2*sqrt(square(R)-square(get_s(bin)))); + const float R = get_ring_radius(bin.view_num()); + assert(R >= fabs(get_s(bin))); + return delta * ring_spacing / (2 * sqrt(square(R) - square(get_s(bin)))); } - -float -ProjDataInfoCylindrical::get_sampling_in_m(const Bin& bin) const -{ +float +ProjDataInfoCylindrical::get_sampling_in_m(const Bin& bin) const { return get_axial_sampling(bin.segment_num()); } -float -ProjDataInfoCylindrical::get_sampling_in_t(const Bin& bin) const -{ - return get_axial_sampling(bin.segment_num())*get_costheta(bin); +float +ProjDataInfoCylindrical::get_sampling_in_t(const Bin& bin) const { + return get_axial_sampling(bin.segment_num()) * get_costheta(bin); } -int -ProjDataInfoCylindrical:: -get_num_axial_poss_per_ring_inc(const int segment_num) const -{ - return - max_ring_diff[segment_num] != min_ring_diff[segment_num] ? - 2 : 1; +int +ProjDataInfoCylindrical::get_num_axial_poss_per_ring_inc(const int segment_num) const { + return max_ring_diff[segment_num] != min_ring_diff[segment_num] ? 2 : 1; } float -ProjDataInfoCylindrical::get_azimuthal_angle_sampling() const -{return azimuthal_angle_sampling;} +ProjDataInfoCylindrical::get_azimuthal_angle_sampling() const { + return azimuthal_angle_sampling; +} float -ProjDataInfoCylindrical::get_axial_sampling(int segment_num) const -{ - return ring_spacing/get_num_axial_poss_per_ring_inc(segment_num); +ProjDataInfoCylindrical::get_axial_sampling(int segment_num) const { + return ring_spacing / get_num_axial_poss_per_ring_inc(segment_num); } -float -ProjDataInfoCylindrical::get_average_ring_difference(int segment_num) const -{ - // KT 05/07/2001 use float division here. +float +ProjDataInfoCylindrical::get_average_ring_difference(int segment_num) const { + // KT 05/07/2001 use float division here. // In any reasonable case, min+max_ring_diff will be even. // But some day, an unreasonable case will walk in. - return (min_ring_diff[segment_num] + max_ring_diff[segment_num])/2.F; + return (min_ring_diff[segment_num] + max_ring_diff[segment_num]) / 2.F; } +int +ProjDataInfoCylindrical::get_min_ring_difference(int segment_num) const { + return min_ring_diff[segment_num]; +} -int -ProjDataInfoCylindrical::get_min_ring_difference(int segment_num) const -{ return min_ring_diff[segment_num]; } - -int -ProjDataInfoCylindrical::get_max_ring_difference(int segment_num) const -{ return max_ring_diff[segment_num]; } +int +ProjDataInfoCylindrical::get_max_ring_difference(int segment_num) const { + return max_ring_diff[segment_num]; +} float -ProjDataInfoCylindrical::get_ring_radius() const -{ - if (this->ring_radius.get_min_index()!=0 || this->ring_radius.get_max_index()!=0) - { - // check if all elements are equal - for (VectorWithOffset::const_iterator iter=this->ring_radius.begin(); iter!= this->ring_radius.end(); ++iter) - { - if (*iter != *this->ring_radius.begin()) - error("get_ring_radius called for non-circular ring"); - } +ProjDataInfoCylindrical::get_ring_radius() const { + if (this->ring_radius.get_min_index() != 0 || this->ring_radius.get_max_index() != 0) { + // check if all elements are equal + for (VectorWithOffset::const_iterator iter = this->ring_radius.begin(); iter != this->ring_radius.end(); ++iter) { + if (*iter != *this->ring_radius.begin()) + error("get_ring_radius called for non-circular ring"); } + } return *this->ring_radius.begin(); } void -ProjDataInfoCylindrical::set_ring_radii_for_all_views(const VectorWithOffset& new_ring_radius) -{ +ProjDataInfoCylindrical::set_ring_radii_for_all_views(const VectorWithOffset& new_ring_radius) { if (new_ring_radius.get_min_index() != this->get_min_view_num() || - new_ring_radius.get_max_index() != this->get_max_view_num()) - { - error("error set_ring_radii_for_all_views: you need to use correct range of view numbers"); - } + new_ring_radius.get_max_index() != this->get_max_view_num()) { + error("error set_ring_radii_for_all_views: you need to use correct range of view numbers"); + } this->ring_radius = new_ring_radius; } VectorWithOffset -ProjDataInfoCylindrical::get_ring_radii_for_all_views() const -{ - if (this->ring_radius.get_min_index()==0 && this->ring_radius.get_max_index()==0) - { - VectorWithOffset out(this->get_min_view_num(), this->get_max_view_num()); - out.fill(this->ring_radius[0]); - return out; - } - else +ProjDataInfoCylindrical::get_ring_radii_for_all_views() const { + if (this->ring_radius.get_min_index() == 0 && this->ring_radius.get_max_index() == 0) { + VectorWithOffset out(this->get_min_view_num(), this->get_max_view_num()); + out.fill(this->ring_radius[0]); + return out; + } else return this->ring_radius; } float -ProjDataInfoCylindrical::get_ring_radius( const int view_num) const -{ - if (this->ring_radius.get_min_index()==0 && this->ring_radius.get_max_index()==0) +ProjDataInfoCylindrical::get_ring_radius(const int view_num) const { + if (this->ring_radius.get_min_index() == 0 && this->ring_radius.get_max_index() == 0) return ring_radius[0]; else return ring_radius[view_num]; } float -ProjDataInfoCylindrical::get_ring_spacing() const -{ return ring_spacing;} +ProjDataInfoCylindrical::get_ring_spacing() const { + return ring_spacing; +} int -ProjDataInfoCylindrical:: -get_view_mashing_factor() const -{ +ProjDataInfoCylindrical::get_view_mashing_factor() const { // KT 10/05/2002 new assert assert(get_scanner_ptr()->get_num_detectors_per_ring() > 0); // KT 10/05/2002 moved assert here from constructor - assert(get_scanner_ptr()->get_num_detectors_per_ring() % (2*get_num_views()) == 0); + assert(get_scanner_ptr()->get_num_detectors_per_ring() % (2 * get_num_views()) == 0); // KT 28/11/2001 do not pre-store anymore as set_num_views would invalidate it - return get_scanner_ptr()->get_num_detectors_per_ring()/2 / get_num_views(); + return get_scanner_ptr()->get_num_detectors_per_ring() / 2 / get_num_views(); } Succeeded -ProjDataInfoCylindrical:: -get_segment_num_for_ring_difference(int& segment_num, const int ring_diff) const -{ +ProjDataInfoCylindrical::get_segment_num_for_ring_difference(int& segment_num, const int ring_diff) const { if (!sampling_corresponds_to_physical_rings) return Succeeded::no; // check currently necessary as reduce_segment does not reduce the size of the ring_diff arrays - if (ring_diff > get_max_ring_difference(get_max_segment_num()) || - ring_diff < get_min_ring_difference(get_min_segment_num())) + if (ring_diff > get_max_ring_difference(get_max_segment_num()) || ring_diff < get_min_ring_difference(get_min_segment_num())) return Succeeded::no; this->initialise_ring_diff_arrays_if_not_done_yet(); @@ -235,34 +208,25 @@ get_segment_num_for_ring_difference(int& segment_num, const int ring_diff) const return Succeeded::no; } - Succeeded -ProjDataInfoCylindrical:: -get_segment_axial_pos_num_for_ring_pair(int& segment_num, - int& ax_pos_num, - const int ring1, - const int ring2) const -{ - assert(0<=ring1); - assert(ring1get_num_rings()); - assert(0<=ring2); - assert(ring2get_num_rings()); +ProjDataInfoCylindrical::get_segment_axial_pos_num_for_ring_pair(int& segment_num, int& ax_pos_num, const int ring1, + const int ring2) const { + assert(0 <= ring1); + assert(ring1 < get_scanner_ptr()->get_num_rings()); + assert(0 <= ring2); + assert(ring2 < get_scanner_ptr()->get_num_rings()); // KT 01/08/2002 swapped rings - if (get_segment_num_for_ring_difference(segment_num, ring2-ring1) == Succeeded::no) + if (get_segment_num_for_ring_difference(segment_num, ring2 - ring1) == Succeeded::no) return Succeeded::no; // see initialise_ring_diff_arrays() for some info - ax_pos_num = (ring1 + ring2 - ax_pos_num_offset[segment_num])* - get_num_axial_poss_per_ring_inc(segment_num)/2; + ax_pos_num = (ring1 + ring2 - ax_pos_num_offset[segment_num]) * get_num_axial_poss_per_ring_inc(segment_num) / 2; return Succeeded::yes; } const ProjDataInfoCylindrical::RingNumPairs& -ProjDataInfoCylindrical:: -get_all_ring_pairs_for_segment_axial_pos_num(const int segment_num, - const int axial_pos_num) const -{ +ProjDataInfoCylindrical::get_all_ring_pairs_for_segment_axial_pos_num(const int segment_num, const int axial_pos_num) const { this->initialise_ring_diff_arrays_if_not_done_yet(); if (is_null_ptr(segment_axial_pos_to_ring_pair[segment_num][axial_pos_num])) compute_segment_axial_pos_to_ring_pair(segment_num, axial_pos_num); @@ -270,16 +234,8 @@ get_all_ring_pairs_for_segment_axial_pos_num(const int segment_num, } unsigned -ProjDataInfoCylindrical:: -get_num_ring_pairs_for_segment_axial_pos_num(const int segment_num, - const int axial_pos_num) const -{ - return - static_cast( - this->get_all_ring_pairs_for_segment_axial_pos_num(segment_num,axial_pos_num).size()); +ProjDataInfoCylindrical::get_num_ring_pairs_for_segment_axial_pos_num(const int segment_num, const int axial_pos_num) const { + return static_cast(this->get_all_ring_pairs_for_segment_axial_pos_num(segment_num, axial_pos_num).size()); } END_NAMESPACE_STIR - - - diff --git a/src/include/stir/ProjDataInfoCylindricalArcCorr.h b/src/include/stir/ProjDataInfoCylindricalArcCorr.h index 2375f75461..6828ebee6e 100644 --- a/src/include/stir/ProjDataInfoCylindricalArcCorr.h +++ b/src/include/stir/ProjDataInfoCylindricalArcCorr.h @@ -34,20 +34,18 @@ #ifndef __stir_ProjDataInfoCylindricalArcCorr_H__ #define __stir_ProjDataInfoCylindricalArcCorr_H__ - #include "stir/ProjDataInfoCylindrical.h" START_NAMESPACE_STIR /*! - \ingroup projdata + \ingroup projdata \brief Projection data info for arc-corrected data This means that 'tangential_pos_num' actually indexes a linear coordinate with a particular sampling distance (usually called the 'bin_size'). */ -class ProjDataInfoCylindricalArcCorr : public ProjDataInfoCylindrical -{ +class ProjDataInfoCylindricalArcCorr : public ProjDataInfoCylindrical { typedef ProjDataInfoCylindrical base_type; #ifdef SWIG // SWIG needs this typedef to be public @@ -58,14 +56,13 @@ class ProjDataInfoCylindricalArcCorr : public ProjDataInfoCylindrical public: //! Constructors ProjDataInfoCylindricalArcCorr(); - ProjDataInfoCylindricalArcCorr(const shared_ptr scanner_ptr,float bin_size, - const VectorWithOffset& num_axial_pos_per_segment, - const VectorWithOffset& min_ring_diff_v, - const VectorWithOffset& max_ring_diff_v, - const int num_views,const int num_tangential_poss); + ProjDataInfoCylindricalArcCorr(const shared_ptr scanner_ptr, float bin_size, + const VectorWithOffset& num_axial_pos_per_segment, + const VectorWithOffset& min_ring_diff_v, const VectorWithOffset& max_ring_diff_v, + const int num_views, const int num_tangential_poss, const int tof_mash_factor = 0); ProjDataInfo* clone() const; - + bool operator==(const self_type&) const; inline virtual float get_s(const Bin&) const; @@ -73,20 +70,16 @@ class ProjDataInfoCylindricalArcCorr : public ProjDataInfoCylindrical void set_tangential_sampling(const float bin_size); //! Get tangential sampling inline float get_tangential_sampling() const; - virtual float get_sampling_in_s(const Bin&) const - {return bin_size; } + virtual float get_sampling_in_s(const Bin&) const { return bin_size; } - virtual - Bin - get_bin(const LOR&) const; + virtual Bin get_bin(const LOR&, const double delta_time = 0.0) const; virtual std::string parameter_info() const; + private: - float bin_size; - virtual bool blindly_equals(const root_type * const) const; - + virtual bool blindly_equals(const root_type* const) const; }; END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataInfoCylindricalArcCorr.inl b/src/include/stir/ProjDataInfoCylindricalArcCorr.inl index 53ac04a2d7..7f6470340d 100644 --- a/src/include/stir/ProjDataInfoCylindricalArcCorr.inl +++ b/src/include/stir/ProjDataInfoCylindricalArcCorr.inl @@ -36,13 +36,13 @@ START_NAMESPACE_STIR float -ProjDataInfoCylindricalArcCorr::get_s(const Bin& bin) const -{return bin.tangential_pos_num()*bin_size;} - +ProjDataInfoCylindricalArcCorr::get_s(const Bin& bin) const { + return bin.tangential_pos_num() * bin_size; +} float -ProjDataInfoCylindricalArcCorr::get_tangential_sampling() const -{return bin_size;} +ProjDataInfoCylindricalArcCorr::get_tangential_sampling() const { + return bin_size; +} END_NAMESPACE_STIR - diff --git a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h index 1a03be4af2..780d37e613 100644 --- a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h +++ b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h @@ -3,6 +3,7 @@ /* Copyright (C) 2000- 2011-06-24, Hammersmith Imanet Ltd Copyright (C) 2011-07-01 - 2011, Kris Thielemans + Copyright (C) 2016, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -23,13 +24,13 @@ \brief Declaration of class stir::ProjDataInfoCylindricalNoArcCorr + \author Nikos Efthimiou \author Kris Thielemans */ #ifndef __stir_ProjDataInfoCylindricalNoArcCorr_H__ #define __stir_ProjDataInfoCylindricalNoArcCorr_H__ - #include "stir/ProjDataInfoCylindrical.h" #include "stir/DetectionPositionPair.h" #include "stir/VectorWithOffset.h" @@ -39,7 +40,7 @@ START_NAMESPACE_STIR class Succeeded; /*! - \ingroup projdata + \ingroup projdata \brief Projection data info for data which are not arc-corrected. For this class, 'tangential_pos_num' actually indexes an angular coordinate @@ -49,7 +50,7 @@ class Succeeded; get_s(Bin(..., tang_pos_num)) == ring_radius * sin(tang_pos_num*angular_increment) \endcode - This class also contains some functions specific for (static) full-ring PET + This class also contains some functions specific for (static) full-ring PET scanners. In this case, it is assumed that for 'raw' data (i.e. no mashing) sinogram space is 'interleaved': 2 adjacent LOR_angles are merged to 1 'view', while the corresponding bins are @@ -61,13 +62,13 @@ class Succeeded; a10 a11 ... a20 a21 a22 ... view 1: a20 a30 a21 a31 ... a30 a31 ... - \endverbatim + \endverbatim This (standard) interleaving is done because for 'odd' LOR_angles there is no LOR which goes through the origin. \par Interchanging the 2 detectors - + When the ring difference = 0 (i.e. a 2D - or direct - sinogram), interchanging the 2 detectors does not change the LOR. This is why (in 2D) one gets away with a full sinogram size of @@ -80,14 +81,13 @@ class Succeeded; - have 2 sinograms of the same size as in 2D, together with the rings as 'ordered pair' (i.e. ring_difference can be positive and negative). In STIR, we use the second convention. - + \todo The detector specific functions possibly do not belong in this class. One can easily imagine a case where the theta,phi,s,t coordinates are as described, but there is no real correspondence with detectors (for instance, a rotating system). Maybe they should be moved somewhere else? */ -class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical -{ +class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical { private: typedef ProjDataInfoCylindrical base_type; #ifdef SWIG @@ -101,29 +101,25 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical ProjDataInfoCylindricalNoArcCorr(); //! Constructor completely specifying all parameters /*! \see ProjDataInfoCylindrical class documentation for info on parameters */ - ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_ptr, - const float ring_radius, const float angular_increment, - const VectorWithOffset& num_axial_pos_per_segment, - const VectorWithOffset& min_ring_diff_v, - const VectorWithOffset& max_ring_diff_v, - const int num_views,const int num_tangential_poss); + ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_ptr, const float ring_radius, const float angular_increment, + const VectorWithOffset& num_axial_pos_per_segment, + const VectorWithOffset& min_ring_diff_v, const VectorWithOffset& max_ring_diff_v, + const int num_views, const int num_tangential_poss, const int tof_mash_factor = 0); //! Constructor which gets \a ring_radius and \a angular_increment from the scanner /*! \a angular_increment is determined as Pi divided by the number of detectors in a ring. \todo only suitable for full-ring PET scanners*/ - ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_ptr, - const VectorWithOffset& num_axial_pos_per_segment, - const VectorWithOffset& min_ring_diff_v, - const VectorWithOffset& max_ring_diff_v, - const int num_views,const int num_tangential_poss); + ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_ptr, const VectorWithOffset& num_axial_pos_per_segment, + const VectorWithOffset& min_ring_diff_v, const VectorWithOffset& max_ring_diff_v, + const int num_views, const int num_tangential_poss, const int tof_mash_factor = 0); ProjDataInfo* clone() const; bool operator==(const self_type&) const; //! Gets s coordinate in mm - /*! \warning - This does \c not take the 'interleaving' into account which is + /*! \warning + This does \c not take the 'interleaving' into account which is customarily applied to raw PET data. */ inline virtual float get_s(const Bin&) const; @@ -134,17 +130,17 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical virtual std::string parameter_info() const; //! \name Functions that convert between bins and detection positions - //@{ + //@{ //! This gets view_num and tang_pos_num for a particular detector pair - /*! This function makes only sense if the scanner is a full-ring scanner + /*! This function makes only sense if the scanner is a full-ring scanner with discrete detectors and there is no rotation or wobble. \arg view runs currently from 0 to num_views-1 \arg tang_pos_num is centred around 0, where 0 corresponds to opposing detectors. The maximum range of tangential positions for any - scanner is -(num_detectors)/2&) const; - + */ + inline Succeeded get_bin_for_det_pos_pair(Bin&, const DetectionPositionPair<>&) const; //! This routine gets the detector pair corresponding to a bin. - /*! + /*! \see get_det_pair_for_view_tangential_pos_num() for restrictions. In addition, this routine only works for span=1 data, i.e. no axial compression. \todo use member template for the coordT type to support continuous detectors. \warning Will call error() if certain conditions are not met. */ - inline void - get_det_pos_pair_for_bin(DetectionPositionPair<>&, - const Bin&) const; + inline void get_det_pos_pair_for_bin(DetectionPositionPair<>&, const Bin&) const; //! This routine returns the number of detector pairs that correspond to a bin - unsigned int - get_num_det_pos_pairs_for_bin(const Bin&) const; + unsigned int get_num_det_pos_pairs_for_bin(const Bin&) const; //! This routine fills a vector with all the detector pairs that correspond to a bin. - /*! + /*! \see ProjDataInfoCylindrical::get_all_ring_pairs_for_segment_axial_pos_num - for restrictions. - \todo It might be possible to return some weight factors in case there is - no many-to-one correspondence between detection positions and bins - (for instance for continuous detectors, or rotating scanners, or + for restrictions. + \todo It might be possible to return some weight factors in case there is + no many-to-one correspondence between detection positions and bins + (for instance for continuous detectors, or rotating scanners, or arc-corrected data). */ - void - get_all_det_pos_pairs_for_bin(std::vector >&, - const Bin&) const; + void get_all_det_pos_pairs_for_bin(std::vector>&, const Bin&) const; //! This gets Bin coordinates for a particular detector pair - /*! + /*! \return Succeeded::yes when a corresponding segment is found \see get_view_tangential_pos_num_for_det_num_pair() for restrictions \obsolete - */ - inline Succeeded - get_bin_for_det_pair(Bin&, - const int det1_num, const int ring1_num, - const int det2_num, const int ring2_num) const; - + */ + inline Succeeded get_bin_for_det_pair(Bin&, const int det1_num, const int ring1_num, const int det2_num, const int ring2_num, + const int timing_pos_num = 0) const; //! This routine gets the detector pair corresponding to a bin. - /*! - \see get_det_pair_for_view_tangential_pos_num() for - restrictions. In addition, this routine only works for span=1 data, - i.e. no axial compression. - \obsolete + /*! + \see get_det_pair_for_view_tangential_pos_num() for + restrictions. In addition, this routine only works for span=1 data, + i.e. no axial compression. + \obsolete */ - inline void - get_det_pair_for_bin( - int& det1_num, int& ring1_num, - int& det2_num, int& ring2_num, - const Bin&) const; - //@} + inline void get_det_pair_for_bin(int& det_num1, int& ring_num1, int& det_num2, int& ring_num2, const Bin& bin) const; - virtual - Bin - get_bin(const LOR&) const; + //@} + virtual Bin get_bin(const LOR&, const double delta_time) const; //! \name set of obsolete functions to go between bins<->LORs (will disappear!) //@{ @@ -268,39 +240,47 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical \obsolete */ Succeeded find_scanner_coordinates_given_cartesian_coordinates(int& det1, int& det2, int& ring1, int& ring2, - const CartesianCoordinate3D& c1, - const CartesianCoordinate3D& c2) const; - - void find_cartesian_coordinates_of_detection(CartesianCoordinate3D& coord_1, - CartesianCoordinate3D& coord_2, - const Bin& bin) const; - - void find_cartesian_coordinates_given_scanner_coordinates (CartesianCoordinate3D& coord_1, - CartesianCoordinate3D& coord_2, - const int Ring_A,const int Ring_B, - const int det1, const int det2) const; - - void find_bin_given_cartesian_coordinates_of_detection(Bin& bin, - const CartesianCoordinate3D& coord_1, - const CartesianCoordinate3D& coord_2) const; + const CartesianCoordinate3D& c1, + const CartesianCoordinate3D& c2) const; + + void find_cartesian_coordinates_given_scanner_coordinates_of_the_front_surface(CartesianCoordinate3D& coord_1, + CartesianCoordinate3D& coord_2, + const int Ring_A, const int Ring_B, + const int det1, const int det2) const; + + void find_cartesian_coordinates_of_detection(CartesianCoordinate3D& coord_1, CartesianCoordinate3D& coord_2, + const Bin& bin) const; + + void find_cartesian_coordinates_given_scanner_coordinates(CartesianCoordinate3D& coord_1, + CartesianCoordinate3D& coord_2, const int Ring_A, + const int Ring_B, const int det1, const int det2) const; + + void find_bin_given_cartesian_coordinates_of_detection(Bin& bin, const CartesianCoordinate3D& coord_1, + const CartesianCoordinate3D& coord_2) const; //@} private: - float ring_radius; float angular_increment; // used in get_view_tangential_pos_num_for_det_num_pair() - struct Det1Det2 { int det1_num; int det2_num; }; - mutable VectorWithOffset< VectorWithOffset > uncompressed_view_tangpos_to_det1det2; + struct Det1Det2 { + int det1_num; + int det2_num; + }; + mutable VectorWithOffset> uncompressed_view_tangpos_to_det1det2; mutable bool uncompressed_view_tangpos_to_det1det2_initialised; //! build look-up table for get_view_tangential_pos_num_for_det_num_pair() void initialise_uncompressed_view_tangpos_to_det1det2() const; // used in get_view_tangential_pos_num_for_det_num_pair() // we prestore a lookup-table in terms for unmashed view/tangpos - struct ViewTangPosSwap { int view_num; int tang_pos_num; bool swap_detectors; }; - mutable VectorWithOffset< VectorWithOffset > det1det2_to_uncompressed_view_tangpos; + struct ViewTangPosSwap { + int view_num; + int tang_pos_num; + bool swap_detectors; + }; + mutable VectorWithOffset> det1det2_to_uncompressed_view_tangpos; mutable bool det1det2_to_uncompressed_view_tangpos_initialised; //! build look-up table for get_view_tangential_pos_num_for_det_num_pair() void initialise_det1det2_to_uncompressed_view_tangpos() const; @@ -310,8 +290,7 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical //! build look-up table unless already done before inline void initialise_det1det2_to_uncompressed_view_tangpos_if_not_done_yet() const; - virtual bool blindly_equals(const root_type * const) const; - + virtual bool blindly_equals(const root_type* const) const; }; END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl index 10442913e0..6ab654a47d 100644 --- a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl +++ b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl @@ -5,7 +5,7 @@ \file \ingroup projdata - \brief Implementation of inline functions of class + \brief Implementation of inline functions of class ProjDataInfoCylindricalNoArcCorr \author Kris Thielemans @@ -30,80 +30,69 @@ #include "stir/Bin.h" #include "stir/Succeeded.h" +#include "stir/round.h" #include START_NAMESPACE_STIR -void -ProjDataInfoCylindricalNoArcCorr:: -initialise_uncompressed_view_tangpos_to_det1det2_if_not_done_yet() const -{ +void +ProjDataInfoCylindricalNoArcCorr::initialise_uncompressed_view_tangpos_to_det1det2_if_not_done_yet() const { // for efficiency reasons, use "Double-Checked-Locking(DCL) pattern" with OpenMP atomic operation // OpenMP v3.1 or later required - // thanks to yohjp: http://stackoverflow.com/questions/27975737/how-to-handle-cached-data-structures-with-multi-threading-e-g-openmp -#if defined(STIR_OPENMP) && _OPENMP >=201012 + // thanks to yohjp: + // http://stackoverflow.com/questions/27975737/how-to-handle-cached-data-structures-with-multi-threading-e-g-openmp +#if defined(STIR_OPENMP) && _OPENMP >= 201012 bool initialised; -#pragma omp atomic read +# pragma omp atomic read initialised = uncompressed_view_tangpos_to_det1det2_initialised; if (!initialised) #endif - { + { #if defined(STIR_OPENMP) -#pragma omp critical(PROJDATAINFOCYLINDRICALNOARCCORR_VIEWTANGPOS_TO_DETS) +# pragma omp critical(PROJDATAINFOCYLINDRICALNOARCCORR_VIEWTANGPOS_TO_DETS) #endif - { - if (!uncompressed_view_tangpos_to_det1det2_initialised) - initialise_uncompressed_view_tangpos_to_det1det2(); - } + { + if (!uncompressed_view_tangpos_to_det1det2_initialised) + initialise_uncompressed_view_tangpos_to_det1det2(); } + } } -void -ProjDataInfoCylindricalNoArcCorr:: -initialise_det1det2_to_uncompressed_view_tangpos_if_not_done_yet() const -{ +void +ProjDataInfoCylindricalNoArcCorr::initialise_det1det2_to_uncompressed_view_tangpos_if_not_done_yet() const { // as above -#if defined(STIR_OPENMP) && _OPENMP >=201012 +#if defined(STIR_OPENMP) && _OPENMP >= 201012 bool initialised; -#pragma omp atomic read +# pragma omp atomic read initialised = det1det2_to_uncompressed_view_tangpos_initialised; if (!initialised) #endif - { + { #if defined(STIR_OPENMP) -#pragma omp critical(PROJDATAINFOCYLINDRICALNOARCCORR_DETS_TO_VIEWTANGPOS) +# pragma omp critical(PROJDATAINFOCYLINDRICALNOARCCORR_DETS_TO_VIEWTANGPOS) #endif - { - if (!det1det2_to_uncompressed_view_tangpos_initialised) - initialise_det1det2_to_uncompressed_view_tangpos(); - } + { + if (!det1det2_to_uncompressed_view_tangpos_initialised) + initialise_det1det2_to_uncompressed_view_tangpos(); } + } } float -ProjDataInfoCylindricalNoArcCorr:: -get_s(const Bin& bin) const -{ - return ring_radius * sin(bin.tangential_pos_num()*angular_increment); +ProjDataInfoCylindricalNoArcCorr::get_s(const Bin& bin) const { + return ring_radius * sin(bin.tangential_pos_num() * angular_increment); } float -ProjDataInfoCylindricalNoArcCorr:: -get_angular_increment() const -{ +ProjDataInfoCylindricalNoArcCorr::get_angular_increment() const { return angular_increment; } void -ProjDataInfoCylindricalNoArcCorr:: -get_det_num_pair_for_view_tangential_pos_num( - int& det1_num, - int& det2_num, - const int view_num, - const int tang_pos_num) const -{ +ProjDataInfoCylindricalNoArcCorr::get_det_num_pair_for_view_tangential_pos_num(int& det1_num, int& det2_num, const int view_num, + const int tang_pos_num) const { assert(get_view_mashing_factor() == 1); this->initialise_uncompressed_view_tangpos_to_det1det2_if_not_done_yet(); @@ -111,88 +100,69 @@ get_det_num_pair_for_view_tangential_pos_num( det2_num = uncompressed_view_tangpos_to_det1det2[view_num][tang_pos_num].det2_num; } - -bool -ProjDataInfoCylindricalNoArcCorr:: -get_view_tangential_pos_num_for_det_num_pair(int& view_num, - int& tang_pos_num, - const int det1_num, - const int det2_num) const -{ - assert(det1_num!=det2_num); +bool +ProjDataInfoCylindricalNoArcCorr::get_view_tangential_pos_num_for_det_num_pair(int& view_num, int& tang_pos_num, + const int det1_num, const int det2_num) const { + assert(det1_num != det2_num); this->initialise_det1det2_to_uncompressed_view_tangpos_if_not_done_yet(); - view_num = - det1det2_to_uncompressed_view_tangpos[det1_num][det2_num].view_num/get_view_mashing_factor(); - tang_pos_num = - det1det2_to_uncompressed_view_tangpos[det1_num][det2_num].tang_pos_num; - return - det1det2_to_uncompressed_view_tangpos[det1_num][det2_num].swap_detectors; + view_num = det1det2_to_uncompressed_view_tangpos[det1_num][det2_num].view_num / get_view_mashing_factor(); + tang_pos_num = det1det2_to_uncompressed_view_tangpos[det1_num][det2_num].tang_pos_num; + return det1det2_to_uncompressed_view_tangpos[det1_num][det2_num].swap_detectors; } - -Succeeded -ProjDataInfoCylindricalNoArcCorr:: -get_bin_for_det_pair(Bin& bin, - const int det_num1, const int ring_num1, - const int det_num2, const int ring_num2) const -{ - if (get_view_tangential_pos_num_for_det_num_pair(bin.view_num(), bin.tangential_pos_num(), det_num1, det_num2)) +Succeeded +ProjDataInfoCylindricalNoArcCorr::get_bin_for_det_pair(Bin& bin, const int det_num1, const int ring_num1, const int det_num2, + const int ring_num2, const int timing_pos_num) const { + if (get_view_tangential_pos_num_for_det_num_pair(bin.view_num(), bin.tangential_pos_num(), det_num1, det_num2)) { + bin.timing_pos_num() = timing_pos_num; return get_segment_axial_pos_num_for_ring_pair(bin.segment_num(), bin.axial_pos_num(), ring_num1, ring_num2); - else + } else { + bin.timing_pos_num() = -timing_pos_num; return get_segment_axial_pos_num_for_ring_pair(bin.segment_num(), bin.axial_pos_num(), ring_num2, ring_num1); + } } -Succeeded -ProjDataInfoCylindricalNoArcCorr:: -get_bin_for_det_pos_pair(Bin& bin, - const DetectionPositionPair<>& dp) const -{ - return - get_bin_for_det_pair(bin, - dp.pos1().tangential_coord(), - dp.pos1().axial_coord(), - dp.pos2().tangential_coord(), - dp.pos2().axial_coord()); +Succeeded +ProjDataInfoCylindricalNoArcCorr::get_bin_for_det_pos_pair(Bin& bin, const DetectionPositionPair<>& dp) const { + return get_bin_for_det_pair( + bin, dp.pos1().tangential_coord(), dp.pos1().axial_coord(), dp.pos2().tangential_coord(), dp.pos2().axial_coord(), + this->get_tof_mash_factor() == 0 ? 0 // use timing_pos==0 in the nonTOF case + : stir::round((float)dp.timing_pos() / this->get_tof_mash_factor())); } void -ProjDataInfoCylindricalNoArcCorr:: -get_det_pair_for_bin( - int& det_num1, int& ring_num1, - int& det_num2, int& ring_num2, - const Bin& bin) const -{ +ProjDataInfoCylindricalNoArcCorr::get_det_pair_for_bin(int& det_num1, int& ring_num1, int& det_num2, int& ring_num2, + const Bin& bin) const { + // if (bin.timing_pos_num()>=0) + // { get_det_num_pair_for_view_tangential_pos_num(det_num1, det_num2, bin.view_num(), bin.tangential_pos_num()); - get_ring_pair_for_segment_axial_pos_num( ring_num1, ring_num2, bin.segment_num(), bin.axial_pos_num()); + get_ring_pair_for_segment_axial_pos_num(ring_num1, ring_num2, bin.segment_num(), bin.axial_pos_num()); + //} + // else + //{ + // get_det_num_pair_for_view_tangential_pos_num(det_num2, det_num1, bin.view_num(), bin.tangential_pos_num()); + // get_ring_pair_for_segment_axial_pos_num( ring_num2, ring_num1, bin.segment_num(), bin.axial_pos_num()); + // } } void -ProjDataInfoCylindricalNoArcCorr:: -get_det_pos_pair_for_bin( - DetectionPositionPair<>& dp, - const Bin& bin) const -{ - //lousy work around because types don't match TODO remove! +ProjDataInfoCylindricalNoArcCorr::get_det_pos_pair_for_bin(DetectionPositionPair<>& dp, const Bin& bin) const { + // lousy work around because types don't match TODO remove! #if 1 - int t1=dp.pos1().tangential_coord(), - a1=dp.pos1().axial_coord(), - t2=dp.pos2().tangential_coord(), - a2=dp.pos2().axial_coord(); + int t1 = dp.pos1().tangential_coord(), a1 = dp.pos1().axial_coord(), t2 = dp.pos2().tangential_coord(), + a2 = dp.pos2().axial_coord(); get_det_pair_for_bin(t1, a1, t2, a2, bin); - dp.pos1().tangential_coord()=t1; - dp.pos1().axial_coord()=a1; - dp.pos2().tangential_coord()=t2; - dp.pos2().axial_coord()=a2; + dp.pos1().tangential_coord() = t1; + dp.pos1().axial_coord() = a1; + dp.pos2().tangential_coord() = t2; + dp.pos2().axial_coord() = a2; + dp.timing_pos() = std::abs(bin.timing_pos_num()) * this->get_tof_mash_factor(); #else - get_det_pair_for_bin(dp.pos1().tangential_coord(), - dp.pos1().axial_coord(), - dp.pos2().tangential_coord(), - dp.pos2().axial_coord(), - bin); + get_det_pair_for_bin(dp.pos1().tangential_coord(), dp.pos1().axial_coord(), dp.pos2().tangential_coord(), + dp.pos2().axial_coord(), bin); #endif } END_NAMESPACE_STIR - diff --git a/src/include/stir/ProjDataInterfile.h b/src/include/stir/ProjDataInterfile.h index 864a406a5e..1375ab51e8 100644 --- a/src/include/stir/ProjDataInterfile.h +++ b/src/include/stir/ProjDataInterfile.h @@ -27,16 +27,14 @@ #ifndef __stir_ProjDataInterfile_H__ #define __stir_ProjDataInterfile_H__ -#include "stir/ProjDataFromStream.h" +#include "stir/ProjDataFromStream.h" #include "stir/shared_ptr.h" #include #include - START_NAMESPACE_STIR - /*! \ingroup projdata \brief A class which reads/writes projection data from/to a (binary) stream, but creates the @@ -45,12 +43,10 @@ START_NAMESPACE_STIR \warning The class can ONLY be used to create a new file. Use ProjData::read_from_file() to read a projection data file. */ -class ProjDataInterfile : public ProjDataFromStream -{ +class ProjDataInterfile : public ProjDataFromStream { public: - //! constructor taking all necessary parameters - /*! + /*! \param filename The name to use for the files. See below. \param segment_sequence_in_stream has to be set according to the order in which the segments will occur in the stream. segment_sequence_in_stream[i] @@ -59,41 +55,33 @@ class ProjDataInterfile : public ProjDataFromStream \par file names that will be used
      -
    • if \a filename has no extension or if \a filename has an extension .hs, +
    • if \a filename has no extension or if \a filename has an extension .hs, the extensions .s and .hs will be used for binary file and header file.
    • otherwise, \a filename will be used for the binary data, and its extension will be replaced with .hs for the header file.
    - + \warning This call will create a new file for the binary data and the Interfile header. Any existing files with the same file names will be overwritten without warning. */ - ProjDataInterfile (shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, - const std::string& filename, const std::ios::openmode, - const std::vector& segment_sequence_in_stream, - StorageOrder o = Segment_View_AxialPos_TangPos, - NumericType data_type = NumericType::FLOAT, - ByteOrder byte_order = ByteOrder::native, - float scale_factor = 1 ); + ProjDataInterfile(shared_ptr const& exam_info_sptr, shared_ptr const& proj_data_info_ptr, + const std::string& filename, const std::ios::openmode, const std::vector& segment_sequence_in_stream, + StorageOrder o = Segment_View_AxialPos_TangPos, NumericType data_type = NumericType::FLOAT, + ByteOrder byte_order = ByteOrder::native, float scale_factor = 1); //! as above, but with a default value for segment_sequence_in_stream /*! The default value for segment_sequence_in_stream is a vector with values min_segment_num, min_segment_num+1, ..., max_segment_num */ - ProjDataInterfile (shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, - const std::string& filename, - const std::ios::openmode open_mode = std::ios::out, - StorageOrder o = Segment_View_AxialPos_TangPos, - NumericType data_type = NumericType::FLOAT, - ByteOrder byte_order = ByteOrder::native, - float scale_factor = 1 ); + ProjDataInterfile(shared_ptr const& exam_info_sptr, shared_ptr const& proj_data_info_ptr, + const std::string& filename, const std::ios::openmode open_mode = std::ios::out, + StorageOrder o = Segment_View_AxialPos_TangPos, NumericType data_type = NumericType::FLOAT, + ByteOrder byte_order = ByteOrder::native, float scale_factor = 1); + private: void create_stream(const std::string& filename, const std::ios::openmode open_mode); }; END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/RegisteredObject.h b/src/include/stir/RegisteredObject.h index 20e2da7ffa..d3167ec46e 100644 --- a/src/include/stir/RegisteredObject.h +++ b/src/include/stir/RegisteredObject.h @@ -36,8 +36,6 @@ START_NAMESPACE_STIR - - /*! \brief Helper class to provide registry mechanisms to a \c Base class \ingroup buildblock @@ -45,18 +43,18 @@ START_NAMESPACE_STIR Suppose you have a hierarchy of classes with (nearly) all public functionality provided by virtual functions of the \c Base (here called \c Root) class. - The aim is then to be able to select at run-time which - of the nodes will be used. + The aim is then to be able to select at run-time which + of the nodes will be used. To do this, one needs to enter all node classes in a registry. This registry contains a key and a "Root factory" for every node-class. The factory for - the node-class returns (a pointer to) a new node-class object, + the node-class returns (a pointer to) a new node-class object, which of course is also a Root object. In STIR, FactoryRegistry provides the type for the registry. - In many cases, the factory constructs the new object from a stream. + In many cases, the factory constructs the new object from a stream. The current class provides the basic mechanisms for this, i.e. a registry, and a function that looks up the relevant factory in the registry and uses it to construct the object from a stream. @@ -88,11 +86,11 @@ START_NAMESPACE_STIR RegisteredParsingObject Derived \endcode - + \see RegisteredParsingObject \todo Currently there is a hard-wired value of "None" - for the default key (with a 0 factory). This is inappropriate + for the default key (with a 0 factory). This is inappropriate in some cases. \warning old versions of Visual C++ cannot inline the registry() function. As a result, @@ -100,28 +98,28 @@ START_NAMESPACE_STIR defined in RegisteredObject.cxx file(s). You will have link errors if you forgot to do this. - \par Limitation: + \par Limitation: In the previous (including STIR 4.x) version of this hierarchy, ParsingObject wasn't at the root of everything. However, the current hierarchy is simpler to use, and you can still override relevant members such that ParsingObject is effectively not used. */ template -class RegisteredObject : public RegisteredObjectBase -{ +class RegisteredObject : public RegisteredObjectBase { public: inline RegisteredObject(); /*! - \brief Construct a new object (of a type derived from Root, its actual type determined by the registered_name parameter) by parsing the istream - + \brief Construct a new object (of a type derived from Root, its actual type determined by the registered_name parameter) by + parsing the istream + This works by finding the 'root factory' object in a registry that corresponds to \a registered_name, and calling the factory on this istream*. */ inline static Root* read_registered_object(std::istream* in, const std::string& registered_name); //! \brief ask the user for the type, and then calls read_registered_object(0, type) - /*! + /*! \warning Relies on read_registered_object to be interactive when its first argument is 0. Sadly, this function cannot be called ask_parameters() because of conflicts with @@ -133,14 +131,13 @@ class RegisteredObject : public RegisteredObjectBase /*! Names are separated with newlines. */ inline static void list_registered_names(std::ostream& stream); - protected: //! The type of a root factory is a function, taking an istream* as argument, and returning a Root* - typedef Root * (*RootFactory)(std::istream*); + typedef Root* (*RootFactory)(std::istream*); //! The type of the registry typedef FactoryRegistry RegistryType; -#if defined(_MSC_VER) && _MSC_VER<=1300 +#if defined(_MSC_VER) && _MSC_VER <= 1300 # define __STIR_REGISTRY_NOT_INLINE #endif @@ -152,13 +149,11 @@ class RegisteredObject : public RegisteredObjectBase #ifndef __STIR_REGISTRY_NOT_INLINE inline #endif - static RegistryType& registry(); - + static RegistryType& + registry(); }; - END_NAMESPACE_STIR #include "stir/RegisteredObject.inl" #endif - diff --git a/src/include/stir/RegisteredObject.inl b/src/include/stir/RegisteredObject.inl index b8a5f463b9..4b9284a6cd 100644 --- a/src/include/stir/RegisteredObject.inl +++ b/src/include/stir/RegisteredObject.inl @@ -30,18 +30,15 @@ #include "stir/utilities.h" #include -START_NAMESPACE_STIR +START_NAMESPACE_STIR template -RegisteredObject::RegisteredObject() -{} - +RegisteredObject::RegisteredObject() {} #ifndef __STIR_REGISTRY_NOT_INLINE template -typename RegisteredObject::RegistryType& -RegisteredObject::registry () -{ +typename RegisteredObject::RegistryType& +RegisteredObject::registry() { static RegistryType the_registry("None", 0); return the_registry; } @@ -49,29 +46,24 @@ RegisteredObject::registry () template Root* -RegisteredObject::read_registered_object(std::istream* in, const std::string& registered_name) -{ +RegisteredObject::read_registered_object(std::istream* in, const std::string& registered_name) { RootFactory factory = registry().find_factory(registered_name); - return factory==0 ? 0 : (*factory)(in); + return factory == 0 ? 0 : (*factory)(in); } template Root* -RegisteredObject::ask_type_and_parameters() -{ +RegisteredObject::ask_type_and_parameters() { std::cout << "Which type do you want? Possible values are:\n"; list_registered_names(std::cout); const std::string registered_name = ask_string("Enter type", "None"); return read_registered_object(0, registered_name); } - + template -void -RegisteredObject:: -list_registered_names(std::ostream& stream) -{ +void +RegisteredObject::list_registered_names(std::ostream& stream) { registry().list_keys(stream); } - END_NAMESPACE_STIR diff --git a/src/include/stir/RegisteredObjectBase.h b/src/include/stir/RegisteredObjectBase.h index 40136edb8f..8480958658 100644 --- a/src/include/stir/RegisteredObjectBase.h +++ b/src/include/stir/RegisteredObjectBase.h @@ -7,7 +7,7 @@ \brief Declaration of class stir::RegisteredObjectBase \author Kris Thielemans - + */ /* @@ -32,11 +32,11 @@ #include #ifndef __stir_RegisteredObjectBase_H__ -#define __stir_RegisteredObjectBase_H__ +# define __stir_RegisteredObjectBase_H__ START_NAMESPACE_STIR -/*! \brief Base class for all classes that can parse .par files (and more?) +/*! \brief Base class for all classes that can parse .par files (and more?) \ingroup buildblock The only reason that this class exists is such that KeyParser can store different types of objects, and get some basic info from it. @@ -45,8 +45,7 @@ START_NAMESPACE_STIR for parsing.. */ -class RegisteredObjectBase : public ParsingObject -{ +class RegisteredObjectBase : public ParsingObject { public: virtual ~RegisteredObjectBase() {} @@ -57,8 +56,7 @@ class RegisteredObjectBase : public ParsingObject KeyParser::parameter_info() needs to know this name such that it can fill it in. */ - virtual std::string get_registered_name() const= 0; + virtual std::string get_registered_name() const = 0; }; END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/RegisteredParsingObject.h b/src/include/stir/RegisteredParsingObject.h index c879975088..fbf2ab150a 100644 --- a/src/include/stir/RegisteredParsingObject.h +++ b/src/include/stir/RegisteredParsingObject.h @@ -29,7 +29,6 @@ #ifndef __stir_RegisteredParsingObject_H__ #define __stir_RegisteredParsingObject_H__ - #include "stir/ParsingObject.h" #include @@ -39,7 +38,7 @@ START_NAMESPACE_STIR do parsing of parameter files. \ingroup buildblock \see RegisteredObject for an explanation why you would use this class. - + RegisteredParsingObject::read_from_stream is implemented in terms of ParsingObject::parse. @@ -57,7 +56,7 @@ START_NAMESPACE_STIR Use the 2 parameter form if there is no ParsingObject anywhere in the hierarchy yet. However, we recommend to immediately derive \a Base from - ParsingObject. + ParsingObject. \par How to add a leaf to the registry at run-time. Constructing the hierarchy as above makes sure that everything is @@ -72,7 +71,7 @@ START_NAMESPACE_STIR Derived::RegisterIt dummy; \endcode As soon as the variable is destructed, the leaf will be taken out of - the registry (but see todo). If you want to add it as long as the program runs, use + the registry (but see todo). If you want to add it as long as the program runs, use a static variable. Currently, STIR has static variables in files for each module @@ -83,18 +82,17 @@ START_NAMESPACE_STIR it in the final executable (to try to remove redundant object files). */ template -class RegisteredParsingObject : public Parent -{ +class RegisteredParsingObject : public Parent { public: //! Construct a new object (of type Derived) by parsing the istream - /*! When the istream * is 0, questions are asked interactively. - - \todo Currently, the return value is a \a Base*. Preferably, it should be a - \a Derived*, but it seems the registration machinery would need extra + /*! When the istream * is 0, questions are asked interactively. + + \todo Currently, the return value is a \a Base*. Preferably, it should be a + \a Derived*, but it seems the registration machinery would need extra (unsafe) reinterpret_casts to get that to work. (TODO find a remedy). */ -inline static Base* read_from_stream(std::istream*); + inline static Base* read_from_stream(std::istream*); //! Returns Derived::registered_name inline std::string get_registered_name() const; @@ -102,25 +100,21 @@ inline static Base* read_from_stream(std::istream*); inline std::string parameter_info(); public: - //! A helper class to allow automatic registration. - struct RegisterIt - { + struct RegisterIt { //! Default constructor adds the type to the registry. - RegisterIt() - { - //std::cerr << "Adding " << Derived::registered_name <<" to registry"< -std::string -RegisteredParsingObject:: get_registered_name() const - { return Derived::registered_name; } +std::string +RegisteredParsingObject::get_registered_name() const { + return Derived::registered_name; +} template Base* -RegisteredParsingObject::read_from_stream(std::istream* in) -{ - Derived * der_ptr = new Derived; - if (in != NULL) - { - if(der_ptr->parse(*in)==false) - { - //parsing failed, return 0 pointer +RegisteredParsingObject::read_from_stream(std::istream* in) { + Derived* der_ptr = new Derived; + if (in != NULL) { + if (der_ptr->parse(*in) == false) { + // parsing failed, return 0 pointer delete der_ptr; return 0; } - } - else + } else der_ptr->ask_parameters(); return der_ptr; } template std::string -RegisteredParsingObject::parameter_info() -{ +RegisteredParsingObject::parameter_info() { return ParsingObject::parameter_info(); } diff --git a/src/include/stir/RelatedViewgrams.h b/src/include/stir/RelatedViewgrams.h index 84d65c3b5e..dc77692df8 100644 --- a/src/include/stir/RelatedViewgrams.h +++ b/src/include/stir/RelatedViewgrams.h @@ -40,18 +40,15 @@ START_NAMESPACE_STIR class ProjData; class ProjDataInfo; - - /*! - \brief A class for storing viewgrams which are related by symmetry + \brief A class for storing viewgrams which are related by symmetry \ingroup projdata */ template -class RelatedViewgrams -{ +class RelatedViewgrams { private: #ifdef SWIG -public: +public: #endif typedef RelatedViewgrams self_type; @@ -65,24 +62,22 @@ class RelatedViewgrams typedef std::ptrdiff_t difference_type; typedef std::size_t size_type; - typedef typename std::vector >::iterator iterator; - typedef typename std::vector >::const_iterator const_iterator; + typedef typename std::vector>::iterator iterator; + typedef typename std::vector>::const_iterator const_iterator; //@} - // --- constructors --- //! default constructor (sets everything empty) - inline RelatedViewgrams(); + inline RelatedViewgrams(); // implicit copy constructor (just element-by-element copy) // RelatedViewgrams(const RelatedViewgrams&); - + //! a private constructor which simply sets the members /*! \todo Currently public for the STIR_MPI version */ - inline RelatedViewgrams(const std::vector >& viewgrams, - const shared_ptr& symmetries_used); - + inline RelatedViewgrams(const std::vector>& viewgrams, + const shared_ptr& symmetries_used); // --- const members returning info --- @@ -92,6 +87,9 @@ class RelatedViewgrams //! get 'basic' segment_num /*! see DataSymmetriesForViewSegmentNumbers for definition of 'basic' */ inline int get_basic_segment_num() const; + //! get 'basic' timing_pos_num + /*! see DataSymmetriesForViewSegmentNumbers for definition of 'basic' */ + inline int get_basic_timing_pos_num() const; //! get 'basic' view_segment_num /*! see DataSymmetriesForViewSegmentNumbers for definition of 'basic' */ inline ViewSegmentNumbers get_basic_view_segment_num() const; @@ -106,10 +104,9 @@ class RelatedViewgrams inline int get_max_tangential_pos_num() const; //! Get shared pointer to proj data info - inline shared_ptr - get_proj_data_info_sptr() const; + inline shared_ptr get_proj_data_info_sptr() const; //! Get a pointer to the symmetries used in constructing this object - inline const DataSymmetriesForViewSegmentNumbers * get_symmetries_ptr() const; + inline const DataSymmetriesForViewSegmentNumbers* get_symmetries_ptr() const; //! Get a shared pointer to the symmetries used in constructing this object /*! \warning It is dangerous to modify the shared symmetries object */ inline shared_ptr get_symmetries_sptr() const; @@ -118,58 +115,53 @@ class RelatedViewgrams //! Grow each viewgram void grow(const IndexRange<2>& range); - //TODOvoid zoom(const float zoom, const float Xoffp, const float Yoffp, + // TODOvoid zoom(const float zoom, const float Xoffp, const float Yoffp, // const int size, const float itophi); - - // -- basic iterator support -- //! use to initialise an iterator to the first element of the vector - inline iterator begin(); - //! iterator 'past' the last element of the vector - inline iterator end(); - //! use to initialise an iterator to the first element of the (const) vector - inline const_iterator begin() const; - //! iterator 'past' the last element of the (const) vector - inline const_iterator end() const; - - - - // numeric operators - - //! Multiplication of all data elements with a constant - RelatedViewgrams& operator*= (const elemT); - //! Division of all data elements by a constant - RelatedViewgrams& operator/= (const elemT); - //! Addition of all data elements by a constant - RelatedViewgrams& operator+= (const elemT); - //! Subtraction of all data elements by a constant - RelatedViewgrams& operator-= (const elemT); - - - //! Element-wise multiplication with another RelatedViewgram object - RelatedViewgrams& operator*= (const RelatedViewgrams&); - //! Element-wise division by another RelatedViewgram object - RelatedViewgrams& operator/= (const RelatedViewgrams&); - //! Element-wise addition by another RelatedViewgram object - RelatedViewgrams& operator+= (const RelatedViewgrams&); - //! Element-wise subtraction by another RelatedViewgram object - RelatedViewgrams& operator-= (const RelatedViewgrams&); - - // numeric functions - - //! Find the maximum of all data elements - elemT find_max() const; - //! Find the maximum of all data elements - elemT find_min() const; - //! Set all data elements to n - void fill(const elemT &n); - - // other - - //! Return a new object with ProjDataInfo etc., but all data elements set to 0 - RelatedViewgrams get_empty_copy() const; + inline iterator begin(); + //! iterator 'past' the last element of the vector + inline iterator end(); + //! use to initialise an iterator to the first element of the (const) vector + inline const_iterator begin() const; + //! iterator 'past' the last element of the (const) vector + inline const_iterator end() const; + + // numeric operators + + //! Multiplication of all data elements with a constant + RelatedViewgrams& operator*=(const elemT); + //! Division of all data elements by a constant + RelatedViewgrams& operator/=(const elemT); + //! Addition of all data elements by a constant + RelatedViewgrams& operator+=(const elemT); + //! Subtraction of all data elements by a constant + RelatedViewgrams& operator-=(const elemT); + + //! Element-wise multiplication with another RelatedViewgram object + RelatedViewgrams& operator*=(const RelatedViewgrams&); + //! Element-wise division by another RelatedViewgram object + RelatedViewgrams& operator/=(const RelatedViewgrams&); + //! Element-wise addition by another RelatedViewgram object + RelatedViewgrams& operator+=(const RelatedViewgrams&); + //! Element-wise subtraction by another RelatedViewgram object + RelatedViewgrams& operator-=(const RelatedViewgrams&); + + // numeric functions + + //! Find the maximum of all data elements + elemT find_max() const; + //! Find the maximum of all data elements + elemT find_min() const; + //! Set all data elements to n + void fill(const elemT& n); + + // other + + //! Return a new object with ProjDataInfo etc., but all data elements set to 0 + RelatedViewgrams get_empty_copy() const; //! \name Equality //@{ @@ -177,34 +169,30 @@ class RelatedViewgrams /*! If they do \c not have the same characteristics, the string \a explanation explains why. */ - bool - has_same_characteristics(self_type const&, - std::string& explanation) const; + bool has_same_characteristics(self_type const&, std::string& explanation) const; //! Checks if the 2 objects have the proj_data_info, segment_num etc. /*! Use this version if you do not need to know why they do not match. */ - bool - has_same_characteristics(self_type const&) const; + bool has_same_characteristics(self_type const&) const; //! check equality (data has to be identical) /*! Uses has_same_characteristics() and Array::operator==. - \warning This function uses \c ==, which might not be what you + \warning This function uses \c ==, which might not be what you need to check when \c elemT has data with float or double numbers. */ - bool operator ==(const self_type&) const; - + bool operator==(const self_type&) const; + //! negation of operator== - bool operator !=(const self_type&) const; + bool operator!=(const self_type&) const; //@} - + private: - friend class ProjData; friend class ProjDataInfo; // members - std::vector > viewgrams; + std::vector> viewgrams; shared_ptr symmetries_used; //! a function which is called internally to see if the object is valid @@ -213,13 +201,10 @@ class RelatedViewgrams //! actual implementation of the above function void debug_check_state() const; - }; END_NAMESPACE_STIR #include "stir/RelatedViewgrams.inl" - #endif // __RelatedViewgrams_h__ - diff --git a/src/include/stir/RelatedViewgrams.inl b/src/include/stir/RelatedViewgrams.inl index 1e45bd97a8..10ef160618 100644 --- a/src/include/stir/RelatedViewgrams.inl +++ b/src/include/stir/RelatedViewgrams.inl @@ -33,149 +33,150 @@ START_NAMESPACE_STIR template -RelatedViewgrams::RelatedViewgrams() : - viewgrams(), symmetries_used() - {} - -template -RelatedViewgrams::RelatedViewgrams(const std::vector >& viewgrams, - const shared_ptr& symmetries_used) - : viewgrams(viewgrams), - symmetries_used(symmetries_used) - { - check_state(); - } - -template -void RelatedViewgrams::check_state() const -{ +RelatedViewgrams::RelatedViewgrams() : viewgrams(), symmetries_used() {} + +template +RelatedViewgrams::RelatedViewgrams(const std::vector>& viewgrams, + const shared_ptr& symmetries_used) + : viewgrams(viewgrams), symmetries_used(symmetries_used) { + check_state(); +} + +template +void +RelatedViewgrams::check_state() const { #ifndef NDEBUG debug_check_state(); #endif } template -int RelatedViewgrams::get_num_viewgrams() const -{ +int +RelatedViewgrams::get_num_viewgrams() const { check_state(); return static_cast(viewgrams.size()); } - template -int RelatedViewgrams::get_basic_view_num() const -{ - assert(viewgrams.size()>0); +int +RelatedViewgrams::get_basic_view_num() const { + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_view_num(); } template -int RelatedViewgrams::get_basic_segment_num() const -{ - assert(viewgrams.size()>0); +int +RelatedViewgrams::get_basic_segment_num() const { + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_segment_num(); } template -ViewSegmentNumbers RelatedViewgrams:: -get_basic_view_segment_num() const -{ +int +RelatedViewgrams::get_basic_timing_pos_num() const { + assert(viewgrams.size() > 0); + check_state(); + return viewgrams[0].get_timing_pos_num(); +} + +template +ViewSegmentNumbers +RelatedViewgrams::get_basic_view_segment_num() const { return ViewSegmentNumbers(get_basic_view_num(), get_basic_segment_num()); } template -int RelatedViewgrams::get_num_axial_poss() const -{ - assert(viewgrams.size()>0); +int +RelatedViewgrams::get_num_axial_poss() const { + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_num_axial_poss(); } template -int RelatedViewgrams::get_num_tangential_poss() const -{ - assert(viewgrams.size()>0); +int +RelatedViewgrams::get_num_tangential_poss() const { + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_num_tangential_poss(); } template -int RelatedViewgrams::get_min_axial_pos_num() const -{ - assert(viewgrams.size()>0); +int +RelatedViewgrams::get_min_axial_pos_num() const { + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_min_axial_pos_num(); } template -int RelatedViewgrams::get_max_axial_pos_num() const -{ - assert(viewgrams.size()>0); +int +RelatedViewgrams::get_max_axial_pos_num() const { + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_max_axial_pos_num(); } template -int RelatedViewgrams::get_min_tangential_pos_num() const -{ - assert(viewgrams.size()>0); +int +RelatedViewgrams::get_min_tangential_pos_num() const { + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_min_tangential_pos_num(); } template -int RelatedViewgrams::get_max_tangential_pos_num() const -{ - assert(viewgrams.size()>0); +int +RelatedViewgrams::get_max_tangential_pos_num() const { + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_max_tangential_pos_num(); } template shared_ptr -RelatedViewgrams:: -get_proj_data_info_sptr() const -{ - assert(viewgrams.size()>0); +RelatedViewgrams::get_proj_data_info_sptr() const { + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_proj_data_info_sptr(); } template -const DataSymmetriesForViewSegmentNumbers * -RelatedViewgrams::get_symmetries_ptr() const -{ +const DataSymmetriesForViewSegmentNumbers* +RelatedViewgrams::get_symmetries_ptr() const { return symmetries_used.get(); } template shared_ptr -RelatedViewgrams::get_symmetries_sptr() const -{ +RelatedViewgrams::get_symmetries_sptr() const { return symmetries_used; } template -typename RelatedViewgrams::iterator -RelatedViewgrams::begin() -{ return viewgrams.begin();} +typename RelatedViewgrams::iterator +RelatedViewgrams::begin() { + return viewgrams.begin(); +} template -typename RelatedViewgrams::iterator -RelatedViewgrams::end() -{return viewgrams.end();} +typename RelatedViewgrams::iterator +RelatedViewgrams::end() { + return viewgrams.end(); +} template -typename RelatedViewgrams::const_iterator -RelatedViewgrams::begin() const -{return viewgrams.begin();} +typename RelatedViewgrams::const_iterator +RelatedViewgrams::begin() const { + return viewgrams.begin(); +} template -typename RelatedViewgrams::const_iterator -RelatedViewgrams::end() const -{return viewgrams.end();} - +typename RelatedViewgrams::const_iterator +RelatedViewgrams::end() const { + return viewgrams.end(); +} END_NAMESPACE_STIR diff --git a/src/include/stir/RunTests.h b/src/include/stir/RunTests.h index ef20b83e94..ef81111368 100644 --- a/src/include/stir/RunTests.h +++ b/src/include/stir/RunTests.h @@ -19,9 +19,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup test - \ingroup buildblock + \ingroup buildblock \brief defines the stir::RunTests class \author Nikos Efthimiou @@ -59,25 +59,24 @@ int main(int argc, char **argv, char **env) \par Implementation notes At present, the various check* functions are overloaded on most basic - types, and in some STIR specific types such as VectorWithOffset. + types, and in some STIR specific types such as VectorWithOffset. This creates problems when the arguments are not exactly of one of those types, as then the compilation might break. A potential solution for this would be to use member templates and the addition of a 'generic' function as a template. However, then that function would take precedence for other cases which are currently resolved - by overloading (such as when using stir::Array which is currently handled via - stir::VectorWithOffset). + by overloading (such as when using stir::Array which is currently handled via + stir::VectorWithOffset). In summary, if you need to check a different type that's not provided for, either use check(), add an appropriate function to your derived class, or if useful for other cases to this class of course. */ -class RunTests -{ +class RunTests { public: //! Default constructor - explicit RunTests( const double tolerance = 1E-4); + explicit RunTests(const double tolerance = 1E-4); //! Destructor, outputs a diagnostic message virtual ~RunTests(); @@ -85,23 +84,23 @@ class RunTests //! Function (to be overloaded) which does the actual tests. /*! This function is expected to do a series of calls to check(), check_if_equal() etc. */ virtual void run_tests() = 0; - + //! Returns if all checks were fine upto now. bool is_everything_ok() const; //! Handy return value for a main() function /*! Returns EXIT_SUCCESS if is_everything_ok(), EXIT_FAILURE otherwise */ int main_return_value() const; - + //! Set value used in floating point comparisons (see check_* functions) void set_tolerance(const double tolerance); //! Get value used in floating point comparisons (see check_* functions) - double get_tolerance() const; + double get_tolerance() const; //! Tests if true, str can be used to tell what you are testing /*! \return if this test worked. - If the test failed, writes diagnostic to \c std::cerr (including value of str) and + If the test failed, writes diagnostic to \c std::cerr (including value of str) and modifies internal variable \c everything_ok. */ bool check(const bool, const std::string& str = ""); @@ -127,28 +126,19 @@ class RunTests // VC 6.0 needs definition of template members in the class def unfortunately. //! check equality by calling check_if_equal on real and imaginary parts template - bool check_if_equal(const std::complex a, const std::complex b, const std::string& str = "") - { - return - check_if_equal(a.real(), b.real(), str) && - check_if_equal(a.imag(), b.imag(), str); - } + bool check_if_equal(const std::complex a, const std::complex b, const std::string& str = "") { + return check_if_equal(a.real(), b.real(), str) && check_if_equal(a.imag(), b.imag(), str); + } //! check equality by comparing ranges and calling check_if_equal on all elements template - bool check_if_equal(const VectorWithOffset& t1, const VectorWithOffset& t2, - const std::string& str = "") - { - if (t1.get_min_index() != t2.get_min_index() || - t1.get_max_index() != t2.get_max_index()) - { + bool check_if_equal(const VectorWithOffset& t1, const VectorWithOffset& t2, const std::string& str = "") { + if (t1.get_min_index() != t2.get_min_index() || t1.get_max_index() != t2.get_max_index()) { std::cerr << "Error: unequal ranges. " << str << std::endl; return everything_ok = false; } - for (int i=t1.get_min_index(); i<= t1.get_max_index(); i++) - { - if(!check_if_equal(t1[i], t2[i], str)) - { + for (int i = t1.get_min_index(); i <= t1.get_max_index(); i++) { + if (!check_if_equal(t1[i], t2[i], str)) { std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n"; return false; } @@ -158,55 +148,40 @@ class RunTests // VC 6.0 needs definition of template members in the class def unfortunately. //! check equality by comparing size and calling check_if_equal on all elements template - bool check_if_equal(const std::vector& t1, const std::vector& t2, - const std::string& str = "") - { - if (t1.size() != t2.size()) - { + bool check_if_equal(const std::vector& t1, const std::vector& t2, const std::string& str = "") { + if (t1.size() != t2.size()) { std::cerr << "Error: unequal ranges. " << str << std::endl; return everything_ok = false; } - bool all_equal=true; - for (unsigned int i=0; i< t1.size(); i++) - { - if(!check_if_equal(t1[i], t2[i], str)) - { + bool all_equal = true; + for (unsigned int i = 0; i < t1.size(); i++) { + if (!check_if_equal(t1[i], t2[i], str)) { std::cerr << "(at vector<" << typeid(T).name() << "> mismatch at index " << i << ")\n"; - all_equal=false; + all_equal = false; } } return all_equal; } - + // VC 6.0 needs definition of template members in the class def unfortunately. template - bool check_if_equal(const IndexRange& t1, const IndexRange& t2, - const std::string& str = "") - { - if (t1 != t2) - { + bool check_if_equal(const IndexRange& t1, const IndexRange& t2, const std::string& str = "") { + if (t1 != t2) { std::cerr << "Error: unequal ranges. " << str << std::endl; return everything_ok = false; - } - else + } else return true; } //! check equality by comparing norm(a-b) with tolerance - template - bool - check_if_equal(const BasicCoordinate& a, - const BasicCoordinate& b, - const std::string& str = "" ) - { - if (norm(a-b) > tolerance) - { - std::cerr << "Error : Unequal Coordinate value are " - << a << " and " << b << ". " << str << std::endl; + template + bool check_if_equal(const BasicCoordinate& a, const BasicCoordinate& b, + const std::string& str = "") { + if (norm(a - b) > tolerance) { + std::cerr << "Error : Unequal Coordinate value are " << a << " and " << b << ". " << str << std::endl; everything_ok = false; return false; - } - else + } else return true; } //@} @@ -231,38 +206,31 @@ class RunTests // VC needs definition of template members in the class def unfortunately. //! use check_if_zero on all elements template - bool check_if_zero(const VectorWithOffset& t, const std::string& str = "") - { - for (int i=t.get_min_index(); i<= t.get_max_index(); i++) - { - if(!check_if_zero(t[i], str)) - { + bool check_if_zero(const VectorWithOffset& t, const std::string& str = "") { + for (int i = t.get_min_index(); i <= t.get_max_index(); i++) { + if (!check_if_zero(t[i], str)) { std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n"; return false; } } return true; } - + //! compare norm with tolerance - template - bool - check_if_zero(const BasicCoordinate& a, const std::string& str = "" ) - { - if (norm(a) > tolerance) - { - std::cerr << "Error : Coordinate value is " << a<< " expected 0s. " << str << std::endl; + template + bool check_if_zero(const BasicCoordinate& a, const std::string& str = "") { + if (norm(a) > tolerance) { + std::cerr << "Error : Coordinate value is " << a << " expected 0s. " << str << std::endl; everything_ok = false; return false; - } - else + } else return true; } //@} //! check if a - inline bool check_if_less(T1 a, T2 b, const std::string& str = ""); + inline bool check_if_less(T1 a, T2 b, const std::string& str = ""); protected: //! tolerance for comparisons with real values @@ -271,52 +239,38 @@ class RunTests bool everything_ok; //! function that is called by some check_if_equal implementations. It just uses operator!= - template - bool - check_if_equal_generic(const T& a, const T& b, const std::string& str) - { - if (a != b) - { - std::cerr << "Error : unequal values are " << a << " and " << b - << ". " << str<< std::endl; - everything_ok = false; - return false; - } - else - return true; - } + template + bool check_if_equal_generic(const T& a, const T& b, const std::string& str) { + if (a != b) { + std::cerr << "Error : unequal values are " << a << " and " << b << ". " << str << std::endl; + everything_ok = false; + return false; + } else + return true; + } //! function that is called by some check_if_zero implementations. It just uses operator!= - template - bool - check_if_zero_generic(T a, const std::string& str) - { - if ((a!=static_cast(0))) - { - std::cerr << "Error : 0 value is " << a << " ." << str << std::endl; - everything_ok = false; - return false; - } - else - return true; - } - + template + bool check_if_zero_generic(T a, const std::string& str) { + if ((a != static_cast(0))) { + std::cerr << "Error : 0 value is " << a << " ." << str << std::endl; + everything_ok = false; + return false; + } else + return true; + } }; END_NAMESPACE_STIR - START_NAMESPACE_STIR -RunTests::RunTests(const double tolerance) - : tolerance(tolerance), everything_ok(true) -{} +RunTests::RunTests(const double tolerance) : tolerance(tolerance), everything_ok(true) {} -RunTests::~RunTests() -{ +RunTests::~RunTests() { #if defined(_DEBUG) && defined(__MSL__) DebugNewReportLeaks(); -#endif +#endif if (everything_ok) std::cerr << "\nAll tests ok !\n\n" << std::endl; @@ -324,31 +278,35 @@ RunTests::~RunTests() std::cerr << "\nEnd of tests. Please correct errors !\n\n" << std::endl; } -bool RunTests::is_everything_ok() const -{ return everything_ok ; } +bool +RunTests::is_everything_ok() const { + return everything_ok; +} -int RunTests::main_return_value() const -{ return everything_ok ? EXIT_SUCCESS : EXIT_FAILURE; } +int +RunTests::main_return_value() const { + return everything_ok ? EXIT_SUCCESS : EXIT_FAILURE; +} -void RunTests::set_tolerance(const double tolerance_v) -{ +void +RunTests::set_tolerance(const double tolerance_v) { tolerance = tolerance_v; } -double RunTests::get_tolerance() const -{ return tolerance; } +double +RunTests::get_tolerance() const { + return tolerance; +} -bool RunTests::check(const bool result, const std::string& str) -{ - if (!result) - { +bool +RunTests::check(const bool result, const std::string& str) { + if (!result) { std::cerr << "Error. " << str << std::endl; everything_ok = false; } return result; } - /*! tolerance is used to account for floating point rounding error. First the absolute difference * is checked and afterwards the relative. \code @@ -364,91 +322,111 @@ bool RunTests::check(const bool result, const std::string& str) \endcode */ bool -RunTests::check_if_equal(const double a, const double b, const std::string& str) -{ - const double diff = fabs(b-a); - if (diff <= tolerance) - return true; +RunTests::check_if_equal(const double a, const double b, const std::string& str) { + const double diff = fabs(b - a); + if (diff <= tolerance) + return true; - const double largest = (std::max(fabs(b), fabs(a))); + const double largest = (std::max(fabs(b), fabs(a))); - if ( diff > tolerance*largest) - { - std::cerr << "Error : unequal values are " << a << " and " << b - << ". " << str<< std::endl; + if (diff > tolerance * largest) { + std::cerr << "Error : unequal values are " << a << " and " << b << ". " << str << std::endl; everything_ok = false; return false; - } - else + } else return true; } - -bool RunTests::check_if_equal(const short a, const short b, const std::string& str) -{ return this->check_if_equal_generic(a,b,str);} -bool RunTests::check_if_equal(const unsigned short a, const unsigned short b, const std::string& str) -{ return this->check_if_equal_generic(a,b,str);} -bool RunTests::check_if_equal(const int a, const int b, const std::string& str) -{ return this->check_if_equal_generic(a,b,str);} -bool RunTests::check_if_equal(const unsigned int a, const unsigned int b, const std::string& str) -{ return this->check_if_equal_generic(a,b,str);} -bool RunTests::check_if_equal(const long a, const long b, const std::string& str) -{ return this->check_if_equal_generic(a,b,str);} -bool RunTests::check_if_equal(const unsigned long a, const unsigned long b, const std::string& str) -{ return this->check_if_equal_generic(a,b,str);} +bool +RunTests::check_if_equal(const short a, const short b, const std::string& str) { + return this->check_if_equal_generic(a, b, str); +} +bool +RunTests::check_if_equal(const unsigned short a, const unsigned short b, const std::string& str) { + return this->check_if_equal_generic(a, b, str); +} +bool +RunTests::check_if_equal(const int a, const int b, const std::string& str) { + return this->check_if_equal_generic(a, b, str); +} +bool +RunTests::check_if_equal(const unsigned int a, const unsigned int b, const std::string& str) { + return this->check_if_equal_generic(a, b, str); +} +bool +RunTests::check_if_equal(const long a, const long b, const std::string& str) { + return this->check_if_equal_generic(a, b, str); +} +bool +RunTests::check_if_equal(const unsigned long a, const unsigned long b, const std::string& str) { + return this->check_if_equal_generic(a, b, str); +} #ifdef BOOST_HAS_LONG_LONG -bool RunTests::check_if_equal(const long long a, const long long b, const std::string& str) -{ return this->check_if_equal_generic(a,b,str);} -bool RunTests::check_if_equal(const unsigned long long a, const unsigned long long b, const std::string& str) -{ return this->check_if_equal_generic(a,b,str);} +bool +RunTests::check_if_equal(const long long a, const long long b, const std::string& str) { + return this->check_if_equal_generic(a, b, str); +} +bool +RunTests::check_if_equal(const unsigned long long a, const unsigned long long b, const std::string& str) { + return this->check_if_equal_generic(a, b, str); +} #endif -bool RunTests::check_if_zero(const short a, const std::string& str) -{ return this->check_if_zero_generic(a,str);} -bool RunTests::check_if_zero(const unsigned short a, const std::string& str) -{ return this->check_if_zero_generic(a,str);} -bool RunTests::check_if_zero(const int a, const std::string& str) -{ return this->check_if_zero_generic(a,str);} -bool RunTests::check_if_zero(const unsigned int a, const std::string& str) -{ return this->check_if_zero_generic(a,str);} -bool RunTests::check_if_zero(const long a, const std::string& str) -{ return this->check_if_zero_generic(a,str);} -bool RunTests::check_if_zero(const unsigned long a, const std::string& str) -{ return this->check_if_zero_generic(a,str);} +bool +RunTests::check_if_zero(const short a, const std::string& str) { + return this->check_if_zero_generic(a, str); +} +bool +RunTests::check_if_zero(const unsigned short a, const std::string& str) { + return this->check_if_zero_generic(a, str); +} +bool +RunTests::check_if_zero(const int a, const std::string& str) { + return this->check_if_zero_generic(a, str); +} +bool +RunTests::check_if_zero(const unsigned int a, const std::string& str) { + return this->check_if_zero_generic(a, str); +} +bool +RunTests::check_if_zero(const long a, const std::string& str) { + return this->check_if_zero_generic(a, str); +} +bool +RunTests::check_if_zero(const unsigned long a, const std::string& str) { + return this->check_if_zero_generic(a, str); +} #ifdef BOOST_HAS_LONG_LONG -bool RunTests::check_if_zero(const long long a, const std::string& str) -{ return this->check_if_zero_generic(a,str);} -bool RunTests::check_if_zero(const unsigned long long a, const std::string& str) -{ return this->check_if_zero_generic(a,str);} +bool +RunTests::check_if_zero(const long long a, const std::string& str) { + return this->check_if_zero_generic(a, str); +} +bool +RunTests::check_if_zero(const unsigned long long a, const std::string& str) { + return this->check_if_zero_generic(a, str); +} #endif /*! check if \code fabs(a)<=tolerance \endcode */ -bool -RunTests::check_if_zero(const double a, const std::string& str ) -{ - if (fabs(a) > tolerance) - { - std::cerr << "Error : 0 value is " << a << " ." << str<< std::endl; +bool +RunTests::check_if_zero(const double a, const std::string& str) { + if (fabs(a) > tolerance) { + std::cerr << "Error : 0 value is " << a << " ." << str << std::endl; everything_ok = false; return false; - } - else + } else return true; } - template bool - RunTests::check_if_less(T1 a, T2 b, const std::string& str) -{ - if (a>=b) - { - std::cerr << "Error : " << a << " is larger than " << b << ", " << str<< std::endl; - everything_ok = false; - return false; - } - else +RunTests::check_if_less(T1 a, T2 b, const std::string& str) { + if (a >= b) { + std::cerr << "Error : " << a << " is larger than " << b << ", " << str << std::endl; + everything_ok = false; + return false; + } else return true; } - + END_NAMESPACE_STIR diff --git a/src/include/stir/SSRB.h b/src/include/stir/SSRB.h index d2f137d110..1b55c99919 100644 --- a/src/include/stir/SSRB.h +++ b/src/include/stir/SSRB.h @@ -43,64 +43,60 @@ class ProjDataInfo; \ingroup projdata \param in_proj_data_info input projection data information. \param num_segments_to_combine how many segments will be combined into 1 output segment. - \param num_views_to_combine how many views will be combined in the output + \param num_views_to_combine how many views will be combined in the output (i.e. mashing) \param num_tangential_poss_to_trim can be used to throw away some bins. Half of the bins will be thrown away at each 'side' of a sinogram (see below). \param max_in_segment_num_to_process rebinned in_proj_data only upto this segment. Default value -1 means 'do all segments'. - \param num_tof_bins_to_combine currently has to be 1. + \param num_tof_bins_to_combine can be used to increase TOF mashing. - The original SSRB algorithm was developed in M.E. Daube-Witherspoon and + The original SSRB algorithm was developed in M.E. Daube-Witherspoon and G. Muehllehner, (1987) Treatment of axial data in three-dimensional PET, - J. Nucl. Med. 28, 171-1724. It essentially ignores the obliqueness of a - Line of Response and moves data to the axial position in segment 0 such + J. Nucl. Med. 28, 171-1724. It essentially ignores the obliqueness of a + Line of Response and moves data to the axial position in segment 0 such that z-resolution on the axis of the scanner is preserved. The STIR implementation of SSRB is a generalisation that applies the same - idea while still allowing preserving some of the obliqueness. For instance, - for a dataset with 9 segments, SSRB can produce a new dataset with only 3 - segments. This essentially increases the axial compression (or span in CTI - terminology), see the STIR Glossary on axial compression. In addition, SSRB - can introduce extra mashing (see the STIR Glossary) of the data, i.e. add + idea while still allowing preserving some of the obliqueness. For instance, + for a dataset with 9 segments, SSRB can produce a new dataset with only 3 + segments. This essentially increases the axial compression (or span in CTI + terminology), see the STIR Glossary on axial compression. In addition, SSRB + can introduce extra mashing (see the STIR Glossary) of the data, i.e. add views together. Here is how to determine which bins are discarded when trimming is used. - For a certain num_tangential_poss, the range is from -\verbatim + For a certain num_tangential_poss, the range is from +\verbatim -(num_tangential_poss/2) to -(num_tangential_poss/2) + num_tangential_poss - 1. \endverbatim - The new num_tangential_poss is simply set to old_num_tangential_poss - + The new num_tangential_poss is simply set to old_num_tangential_poss - num_tang_poss_to_trim. Note that because of this, if num_tang_poss_to_trim is negative, more (zero) bins will be added. \warning in_proj_data_info has to be (at least) of type ProjDataInfoCylindrical - \warning This function can only handle in_proj_data_info where all segments have - identical 'num_segments_to_combine'. So it cannot handle standard + \warning This function can only handle in_proj_data_info where all segments have + identical 'num_segments_to_combine'. So it cannot handle standard GE Advance data. \todo get rid of both restrictions flagged as warnings in the documentation for this function. \todo rename to something much more general than \c SSRB */ -ProjDataInfo * -SSRB(const ProjDataInfo& in_proj_data_info, - const int num_segments_to_combine, - const int num_views_to_combine = 1, - const int num_tangential_poss_to_trim = 0, - const int max_in_segment_num_to_process=-1, - const int num_tof_bins_to_combine=1 - ); +ProjDataInfo* SSRB(const ProjDataInfo& in_proj_data_info, const int num_segments_to_combine, const int num_views_to_combine = 1, + const int num_tangential_poss_to_trim = 0, const int max_in_segment_num_to_process = -1, + const int num_tof_bins_to_combine = 1); //! Perform Single Slice Rebinning and write output to file /*! \ingroup projdata - \param output_filename filename to write output projection data (will be in + \param output_filename filename to write output projection data (will be in Interfile format) \param in_projdata input data \param num_segments_to_combine how many segments will be combined into 1 output segment. \param max_in_segment_num_to_process rebinned in_proj_data only upto this segment. Default value -1 means 'do all segments'. - \param do_normalisation (default true) wether to normalise the output sinograms + \param do_normalisation (default true) wether to normalise the output sinograms corresponding to how many input sinograms contribute to them. + \param num_tof_bins_to_combine currently has to be 1. If it doesn't, error() will be called. \see SSRB(const ProjDataInfo& in_proj_data_info, const int num_segments_to_combine, @@ -110,36 +106,25 @@ SSRB(const ProjDataInfo& in_proj_data_info, const int num_tof_bins_to_combine ) for restrictions */ -void -SSRB(const std::string& output_filename, - const ProjData& in_projdata, - const int num_segments_to_combine, - const int num_views_to_combine = 1, - const int num_tangential_poss_to_trim = 0, - const bool do_normalisation = true, - const int max_in_segment_num_to_process = -1, - const int num_tof_bins_to_combine = 1 - ); +void SSRB(const std::string& output_filename, const ProjData& in_projdata, const int num_segments_to_combine, + const int num_views_to_combine = 1, const int num_tangential_poss_to_trim = 0, const bool do_normalisation = true, + const int max_in_segment_num_to_process = -1, const int num_tof_bins_to_combine = 1); //! Perform Single Slice Rebinning and write output to ProjData -/*! +/*! \ingroup projdata - \param out_projdata Output projection data. Its projection_data_info is used to - determine output characteristics. Data will be 'put' in here using + \param out_projdata Output projection data. Its projection_data_info is used to + determine output characteristics. Data will be 'put' in here using ProjData::set_sinogram(). \param in_projdata input data - \param do_normalisation (default true) wether to normalise the output sinograms + \param do_normalisation (default true) wether to normalise the output sinograms corresponding to how many input sinograms contribute to them. - + \warning in_proj_data_info has to be (at least) of type ProjDataInfoCylindrical -*/ -void -SSRB(ProjData& out_projdata, - const ProjData& in_projdata, - const bool do_normalisation = true - ); + \warning TOF info has to match currently. If it doesn't, error() will be called. +*/ +void SSRB(ProjData& out_projdata, const ProjData& in_projdata, const bool do_normalisation = true); END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/Scanner.h b/src/include/stir/Scanner.h index 6780bcc4cf..51793f7e60 100644 --- a/src/include/stir/Scanner.h +++ b/src/include/stir/Scanner.h @@ -2,9 +2,10 @@ Copyright (C) 2000 PARAPET partners Copyright (C) 2000-2010, Hammersmith Imanet Ltd Copyright (C) 2011-2013, King's College London + Copyright (C) 2016, University of Hull Copyright (C) 2016, 2019, UCL Copyright (C 2017-2018, University of Leeds - + This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -26,6 +27,7 @@ \brief Declaration of class stir::Scanner + \author Nikos Efthimiou \author Claire Labbe \author Kris Thielemans \author Sanida Mustafovic @@ -55,13 +57,13 @@ class Succeeded; \par information on blocks, buckets etc This class gives some informations on crystals, blocks etc. However, this is currently (i.e. at least up to STIR 2.1) used in very few places. - For ECAT scanners, this information is used to read the normalisation .n + For ECAT scanners, this information is used to read the normalisation .n files and computed dead-time correction etc. For all other scanners, STIR currently ignores this info. This might change in the future of course. - + At present, these functions follow CTI terminology, but the concepts are similar for other scanners. - + \li \c crystal the smallest detection unit \li \c block several crystals are grouped in a block, this can be in 3 dimensions (see layer). This information could be useful for finding the @@ -76,32 +78,35 @@ class Succeeded; \li \c singles_unit (non-standard terminology) Most scanners report the singles detected during the acquisition. Some scanners (such as GE scanners) report singles for every crystal, - while others (such as CTI scanners) give only singles for a + while others (such as CTI scanners) give only singles for a collection of blocks. A \c singles_unit is then a set of crystals for which we can get singles rates. - A further complication is that some scanners (including many Siemens scanners) + A further complication is that some scanners (including many Siemens scanners) insert virtual crystals in the sinogram data (corresponding to gaps between detector blocks). We currently define the blocks as the "virtual" ones, but provide extra members to find out how many of these virtual crystals there are. \warning This information is only sensible for discrete detector-based scanners. + \warning Currently, in a TOF compatible scanner template, the last three types have to + be explicitly defined to avoid ambiguity. + \warning The energy resolution has to be specified but it is used only for scatter correction. + \warning In order to define a nonTOF scanner the timing resolution has to be set to 0 or 1. + Anything else will trigger a TOF reconstruction. \todo Some scanners do not have all info filled in at present. Values are then set to 0. - \todo + \todo a hierarchy distinguishing between different types of scanners \todo derive from ParsingObject */ -class Scanner -{ - public: - - /************* static members*****************************/ - static Scanner * ask_parameters(); +class Scanner { +public: + /************* static members*****************************/ + static Scanner* ask_parameters(); //! get the scanner pointer from the name - static Scanner * get_scanner_from_name(const std::string& name); + static Scanner* get_scanner_from_name(const std::string& name); //! get the list of all names for the particular scanner static std::string list_all_names(); @@ -112,58 +117,80 @@ class Scanner // 08-3-2004, zlong, add user defined scanner //! enum for all predefined scanners /* \a Userdefined_scanner can be used to set arbitrary scanner geometry info. - \a Unknown_scanner will be used when parsing (e.g. from an Interfile header) - to flag up an error and do some guess work in trying to recognise the scanner from + \a Unknown_scanner will be used when parsing (e.g. from an Interfile header) + to flag up an error and do some guess work in trying to recognise the scanner from any given parameters. */ - enum Type {E931, E951, E953, E921, E925, E961, E962, E966, E1080, Siemens_mMR,Siemens_mCT, RPT,HiDAC, - Advance, DiscoveryLS, DiscoveryST, DiscoverySTE, DiscoveryRX, Discovery600, PETMR_Signa, Discovery690, DiscoveryMI3ring, DiscoveryMI4ring, - HZLR, RATPET, PANDA, HYPERimage, nanoPET, HRRT, Allegro, GeminiTF, User_defined_scanner, - Unknown_scanner}; - + + enum Type { + E931, + E951, + E953, + E921, + E925, + E961, + E962, + E966, + E1080, + test_scanner, + Siemens_mMR, + Siemens_mCT, + Vision_600, + RPT, + HiDAC, + Advance, + DiscoveryLS, + DiscoveryST, + DiscoverySTE, + DiscoverySTE_nonTOF, + DiscoveryRX, + Discovery600, + Discovery690, + PETMR_Signa, + PETMR_Signa_nonTOF, + DiscoveryMI3ring, + DiscoveryMI4ring, + HZLR, + RATPET, + PANDA, + HYPERimage, + nanoPET, + HRRT, + Allegro, + GeminiTF, + User_defined_scanner, + ntest_TOF_50, + Unknown_scanner + }; + //! constructor that takes scanner type as an input argument Scanner(Type scanner_type); - //! constructor -(list of names) /*! size info is in mm \param intrinsic_tilt_v value in radians, \see get_default_intrinsic_tilt() \warning calls error() when block/bucket info are inconsistent */ - Scanner(Type type_v, const std::list& list_of_names_v, - int num_detectors_per_ring_v, int num_rings_v, - int max_num_non_arccorrected_bins_v, - int default_num_arccorrected_bins_v, - float inner_ring_radius_v, float average_depth_of_interaction_v, - float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, - int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, - int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, - int num_axial_crystals_per_singles_unit_v, - int num_transaxial_crystals_per_singles_unit_v, - int num_detector_layers_v, - float energy_resolution_v = -1.0f, - float reference_energy_v = -1.0f); + Scanner(Type type_v, const std::list& list_of_names_v, int num_detectors_per_ring_v, int num_rings_v, + int max_num_non_arccorrected_bins_v, int default_num_arccorrected_bins_v, float inner_ring_radius_v, + float average_depth_of_interaction_v, float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, + int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, + int num_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, + int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, float energy_resolution_v, + float reference_energy_v, short int max_num_of_timing_poss, float size_timing_pos, float timing_resolution); //! constructor ( a single name) /*! size info is in mm \param intrinsic_tilt value in radians, \see get_default_intrinsic_tilt() \warning calls error() when block/bucket info are inconsistent */ - Scanner(Type type_v, const std::string& name, - int num_detectors_per_ring_v, int num_rings_v, - int max_num_non_arccorrected_bins_v, - int default_num_arccorrected_bins_v, - float inner_ring_radius_v, float average_depth_of_interaction_v, - float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, - int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, - int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, - int num_axial_crystals_per_singles_unit_v, - int num_transaxial_crystals_per_singles_unit_v, - int num_detector_layers_v, - float energy_resolution_v = -1.0f, - float reference_energy_v = -1.0f); - - + Scanner(Type type_v, const std::string& name, int num_detectors_per_ring_v, int num_rings_v, + int max_num_non_arccorrected_bins_v, int default_num_arccorrected_bins_v, float inner_ring_radius_v, + float average_depth_of_interaction_v, float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, + int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, + int num_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, + int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, float energy_resolution_v, + float reference_energy_v, short int max_num_of_timing_poss, float size_timing_pos, float timing_resolution); //! get scanner parameters as a std::string std::string parameter_info() const; @@ -175,13 +202,14 @@ class Scanner std::string list_names() const; //! comparison operator - bool operator ==(const Scanner& scanner) const; - inline bool operator !=(const Scanner& scanner) const; + bool operator==(const Scanner& scanner) const; + inline bool operator!=(const Scanner& scanner) const; //! get scanner type inline Type get_type() const; - //! checks consistency + //! checks consistency /*! Calls warning() with diagnostics when there are problems + * N.E: Should something check be added for TOF information? */ Succeeded check_consistency() const; @@ -205,7 +233,7 @@ class Scanner //! get the default number of arccorrected tangential positions /*! \warning name is not in standard STIR terminology. Should be \c get_max_default_num_arccorrected_tangential_poss() or so. - \todo change name, mabe refering to the fan of detectors + \todo change name, mabe refering to the fan of detectors in coincidence or so */ inline int get_default_num_arccorrected_bins() const; @@ -218,7 +246,7 @@ class Scanner inline float get_effective_ring_radius() const; //! get average depth of interaction inline float get_average_depth_of_interaction() const; - //! get ring spacing + //! get ring spacing inline float get_ring_spacing() const; //! get default arc-corrected bin size inline float get_default_bin_size() const; @@ -228,7 +256,7 @@ class Scanner image will be rotated when this tilt is ignored in the reconstruction algorithm. It uses the same coordinate system as ProjDataInfo::get_phi(). - \todo we still have to decide if ProjDataInfo::get_phi() will take + \todo we still have to decide if ProjDataInfo::get_phi() will take this tilt into account or not. At present, STIR ignores the intrinsic tilt. */ inline float get_default_intrinsic_tilt() const; @@ -237,25 +265,25 @@ class Scanner //! get number of transaxial blocks per bucket inline int get_num_transaxial_blocks_per_bucket() const; //! get number of axial blocks per bucket - inline int get_num_axial_blocks_per_bucket() const; + inline int get_num_axial_blocks_per_bucket() const; //! get number of crystals in the axial direction - inline int get_num_axial_crystals_per_block() const; - //! get number of transaxial crystals + inline int get_num_axial_crystals_per_block() const; + //! get number of transaxial crystals inline int get_num_transaxial_crystals_per_block() const; //! get crystals in a bucket inline int get_num_transaxial_crystals_per_bucket() const; //! get crystals in a bucket inline int get_num_axial_crystals_per_bucket() const; //! get number of crystal layers (for DOI) - inline int get_num_detector_layers() const; + inline int get_num_detector_layers() const; //! get number of axial blocks - inline int get_num_axial_blocks() const; + inline int get_num_axial_blocks() const; //! get number of axial blocks - inline int get_num_transaxial_blocks() const; + inline int get_num_transaxial_blocks() const; //! get number of axial buckets - inline int get_num_axial_buckets() const; + inline int get_num_axial_buckets() const; //! get number of axial buckets - inline int get_num_transaxial_buckets() const; + inline int get_num_transaxial_buckets() const; //! get number of axial crystals per singles unit inline int get_num_axial_crystals_per_singles_unit() const; @@ -269,13 +297,19 @@ class Scanner inline int get_num_transaxial_singles_units() const; /* inline int get_num_layers_singles_units() const; */ inline int get_num_singles_units() const; + //! Get the maximum number of TOF bins. + inline int get_max_num_timing_poss() const; + //! Get the delta t which correspnds to the max number of TOF bins in picosecs. + inline float get_size_of_timing_pos() const; + //! Get the timing resolution of the scanner. + inline float get_timing_resolution() const; //! \name number of "fake" crystals per block, inserted by the scanner /*! Some scanners (including many Siemens scanners) insert virtual crystals in the sinogram data. The other members of the class return the size of the "virtual" block. With these functions you can find its true size (or set it). */ - //@{! + //@{! int get_num_virtual_axial_crystals_per_block() const; int get_num_virtual_transaxial_crystals_per_block() const; void set_num_virtual_axial_crystals_per_block(int); @@ -286,7 +320,7 @@ class Scanner //@} (end of get geometrical info) - //! \name Functions to get detector responce info + //! \name Functions to get detector responce info //@{ //! get the energy resolution of the system @@ -301,41 +335,41 @@ class Scanner //@{ // zlong, 08-04-2004, add set_methods //! set scanner type - inline void set_type(const Type & new_type); + inline void set_type(const Type& new_type); //! set number of rings - inline void set_num_rings(const int & new_num); + inline void set_num_rings(const int& new_num); //! set the namber of detectors per ring - inline void set_num_detectors_per_ring(const int & new_num) ; + inline void set_num_detectors_per_ring(const int& new_num); //! set the maximum number of arccorrected bins - inline void set_max_num_non_arccorrected_bins(const int & new_num) ; + inline void set_max_num_non_arccorrected_bins(const int& new_num); //! set the default number of arccorrected_bins - inline void set_default_num_arccorrected_bins(const int & new_num) ; + inline void set_default_num_arccorrected_bins(const int& new_num); //! set inner ring radius - inline void set_inner_ring_radius(const float & new_radius); + inline void set_inner_ring_radius(const float& new_radius); //! set average depth of interaction inline void set_average_depth_of_interaction(const float& new_depth_of_interaction); - //! set ring spacing - inline void set_ring_spacing(const float & new_spacing); + //! set ring spacing + inline void set_ring_spacing(const float& new_spacing); //! set default arc-corrected bin size - inline void set_default_bin_size(const float &new_size); + inline void set_default_bin_size(const float& new_size); //! in degrees - inline void set_default_intrinsic_tilt(const float & new_tilt); + inline void set_default_intrinsic_tilt(const float& new_tilt); //! \name Info on crystals per block etc. //@{ //! set number of transaxial blocks per bucket - inline void set_num_transaxial_blocks_per_bucket(const int & new_num); + inline void set_num_transaxial_blocks_per_bucket(const int& new_num); //! set number of axial blocks per bucket - inline void set_num_axial_blocks_per_bucket(const int & new_num); + inline void set_num_axial_blocks_per_bucket(const int& new_num); //! set number of crystals in the axial direction - inline void set_num_axial_crystals_per_block(const int & new_num); - //! set number of transaxial crystals - inline void set_num_transaxial_crystals_per_block(const int & new_num); + inline void set_num_axial_crystals_per_block(const int& new_num); + //! set number of transaxial crystals + inline void set_num_transaxial_crystals_per_block(const int& new_num); //! set number of crystal layers (for DOI) - inline void set_num_detector_layers(const int& new_num); + inline void set_num_detector_layers(const int& new_num); //! set number of axial crystals per singles unit - inline void set_num_axial_crystals_per_singles_unit(const int & new_num); + inline void set_num_axial_crystals_per_singles_unit(const int& new_num); //! set number of transaxial crystals per singles unit - inline void set_num_transaxial_crystals_per_singles_unit(const int & new_num); + inline void set_num_transaxial_crystals_per_singles_unit(const int& new_num); // TODO accomodate more complex geometries of singles units. //@} (end of block/bucket info) @@ -345,101 +379,77 @@ class Scanner //! set the reference energy of the energy resolution //! A negative value indicates, unknown || not set inline void set_reference_energy(const float new_num); + //! Set the maximum number of TOF bins. + inline void set_num_max_of_timing_poss(int new_num); + //! Set the delta t which correspnds to the max number of TOF bins. + inline void set_size_of_timing_poss(float new_num); + //! Set timing resolution + inline void set_timing_resolution(float new_num_in_ps); + //@} (end of set info) inline bool has_energy_information() const; - //@} (end of set info) - //@} (end of set info) - - // Calculate a singles bin index from axial and transaxial singles bin coordinates. + + //! Calculate a singles bin index from axial and transaxial singles bin coordinates. inline int get_singles_bin_index(int axial_index, int transaxial_index) const; - // Method used to calculate a singles bin index from - // a detection position. - inline int get_singles_bin_index(const DetectionPosition<>& det_pos) const; - + //! Method used to calculate a singles bin index from + //! a detection position. + inline int get_singles_bin_index(const DetectionPosition<>& det_pos) const; - // Get the axial singles bin coordinate from a singles bin. + //! Get the axial singles bin coordinate from a singles bin. inline int get_axial_singles_unit(int singles_bin_index) const; - // Get the transaxial singles bin coordinate from a singles bin. + //! Get the transaxial singles bin coordinate from a singles bin. inline int get_transaxial_singles_unit(int singles_bin_index) const; - + + //! True if it is TOF compatible. + inline bool is_tof_ready() const; private: Type type; std::list list_of_names; - int num_rings; /* number of direct planes */ - int max_num_non_arccorrected_bins; + int num_rings; /* number of direct planes */ + int max_num_non_arccorrected_bins; int default_num_arccorrected_bins; /* default number of bins */ - int num_detectors_per_ring; + int num_detectors_per_ring; - float inner_ring_radius; /*! detector inner radius in mm*/ + float inner_ring_radius; /*! detector inner radius in mm*/ float average_depth_of_interaction; /*! Average interaction depth in detector crystal */ - float ring_spacing; /*! ring separation in mm*/ - float bin_size; /*! arc-corrected bin size in mm (spacing of transaxial elements) */ - float intrinsic_tilt; /*! intrinsic tilt in radians*/ - - int num_transaxial_blocks_per_bucket; /* transaxial blocks per bucket */ - int num_axial_blocks_per_bucket; /* axial blocks per bucket */ - int num_axial_crystals_per_block; /* number of crystals in the axial direction */ - int num_transaxial_crystals_per_block;/* number of transaxial crystals */ + float ring_spacing; /*! ring separation in mm*/ + float bin_size; /*! arc-corrected bin size in mm (spacing of transaxial elements) */ + float intrinsic_tilt; /*! intrinsic tilt in radians*/ + + int num_transaxial_blocks_per_bucket; /* transaxial blocks per bucket */ + int num_axial_blocks_per_bucket; /* axial blocks per bucket */ + int num_axial_crystals_per_block; /* number of crystals in the axial direction */ + int num_transaxial_crystals_per_block; /* number of transaxial crystals */ int num_detector_layers; int num_axial_crystals_per_singles_unit; int num_transaxial_crystals_per_singles_unit; - //! - //! \brief energy_resolution - //! \author Nikos Efthimiou - //! \details This is the energy resolution of the system. + //! This is the energy resolution of the system. //! A negative value indicates, unknown. //! This value is dominated by the material of the scintilation crystal float energy_resolution; - - //! - //! \brief reference_energy - //! \author Nikos Efthimiou - //! \details In PET application this should always be 511 keV. + //! In PET application this should always be 511 keV. //! A negative value indicates, unknown. float reference_energy; - - - // ! set all parameters, case where default_num_arccorrected_bins==max_num_non_arccorrected_bins - void set_params(Type type_v, const std::list& list_of_names_v, - int num_rings_v, - int max_num_non_arccorrected_bins_v, - int num_detectors_per_ring_v, - float inner_ring_radius_v, - float average_depth_of_interaction_v, - float ring_spacing_v, - float bin_size_v, float intrinsic_tilt_v, - int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, - int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, - int num_axial_crystals_per_singles_unit_v, - int num_transaxial_crystals_per_singles_unit_v, - int num_detector_layers_v, - float energy_resolution_v = -1.0f, - float reference_energy = -1.0f); - - // ! set all parameters - void set_params(Type type_v, const std::list& list_of_names_v, - int num_rings_v, - int max_num_non_arccorrected_bins_v, - int default_num_arccorrected_bins_v, - int num_detectors_per_ring_v, - float inner_ring_radius_v, - float average_depth_of_interaction_v, - float ring_spacing_v, - float bin_size_v, float intrinsic_tilt_v, - int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, + //! The timing resolution of the scanner, in psec. + float timing_resolution; + //! The number of TOF bins. Without any mash factors + int max_num_of_timing_poss; + //! This number corresponds the the least significant clock digit. + float size_timing_pos; + + void set_params(Type type_v, const std::list& list_of_names_v, int num_rings_v, + int max_num_non_arccorrected_bins_v, int default_num_arccorrected_bins_v, int num_detectors_per_ring_v, + float inner_ring_radius_v, float average_depth_of_interaction_v, float ring_spacing_v, float bin_size_v, + float intrinsic_tilt_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, - int num_axial_crystals_per_singles_unit_v, - int num_transaxial_crystals_per_singles_unit_v, - int num_detector_layers_v, - float energy_resolution_v = -1.0f, - float reference_energy = -1.0f); - - + int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, + int num_detector_layers_v, float energy_resolution_v, float reference_energy, + short int max_num_of_timing_poss_v, float size_timing_pos_v, float timing_resolution_v); }; END_NAMESPACE_STIR @@ -447,4 +457,3 @@ END_NAMESPACE_STIR #include "stir/Scanner.inl" #endif - diff --git a/src/include/stir/Scanner.inl b/src/include/stir/Scanner.inl index 4ce80d1c20..68d0c5c7a3 100644 --- a/src/include/stir/Scanner.inl +++ b/src/include/stir/Scanner.inl @@ -34,357 +34,340 @@ START_NAMESPACE_STIR -bool -Scanner::operator !=(const Scanner& scanner) const -{ +bool +Scanner::operator!=(const Scanner& scanner) const { return !(*this == scanner); } Scanner::Type -Scanner::get_type() const -{return type;} +Scanner::get_type() const { + return type; +} int -Scanner::get_num_rings() const -{ return num_rings;} +Scanner::get_num_rings() const { + return num_rings; +} int -Scanner::get_num_detectors_per_ring() const -{ - return num_detectors_per_ring;} +Scanner::get_num_detectors_per_ring() const { + return num_detectors_per_ring; +} int -Scanner::get_max_num_non_arccorrected_bins() const -{ return max_num_non_arccorrected_bins;} +Scanner::get_max_num_non_arccorrected_bins() const { + return max_num_non_arccorrected_bins; +} -int -Scanner::get_max_num_views() const -{ return get_num_detectors_per_ring()/2; } +int +Scanner::get_max_num_views() const { + return get_num_detectors_per_ring() / 2; +} int -Scanner::get_default_num_arccorrected_bins() const -{ - return default_num_arccorrected_bins; +Scanner::get_default_num_arccorrected_bins() const { + return default_num_arccorrected_bins; } float -Scanner::get_inner_ring_radius() const -{ +Scanner::get_inner_ring_radius() const { return inner_ring_radius; } float -Scanner::get_average_depth_of_interaction() const -{ +Scanner::get_average_depth_of_interaction() const { return average_depth_of_interaction; } - float -Scanner::get_effective_ring_radius() const -{ +Scanner::get_effective_ring_radius() const { return inner_ring_radius + average_depth_of_interaction; } - float -Scanner::get_ring_spacing() const -{ +Scanner::get_ring_spacing() const { return ring_spacing; } - float -Scanner::get_default_bin_size() const -{ return bin_size;} +Scanner::get_default_bin_size() const { + return bin_size; +} float -Scanner::get_default_intrinsic_tilt() const -{ - return intrinsic_tilt;} +Scanner::get_default_intrinsic_tilt() const { + return intrinsic_tilt; +} -int -Scanner::get_num_transaxial_blocks_per_bucket() const -{ +int +Scanner::get_num_transaxial_blocks_per_bucket() const { return num_transaxial_blocks_per_bucket; } int -Scanner::get_num_axial_blocks_per_bucket() const -{ +Scanner::get_num_axial_blocks_per_bucket() const { return num_axial_blocks_per_bucket; } int -Scanner::get_num_axial_crystals_per_block() const -{ +Scanner::get_num_axial_crystals_per_block() const { return num_axial_crystals_per_block; } int -Scanner::get_num_transaxial_crystals_per_block()const -{ +Scanner::get_num_transaxial_crystals_per_block() const { return num_transaxial_crystals_per_block; } - int -Scanner::get_num_axial_crystals_per_bucket() const -{ - return - get_num_axial_blocks_per_bucket() * - get_num_axial_crystals_per_block(); +Scanner::get_num_axial_crystals_per_bucket() const { + return get_num_axial_blocks_per_bucket() * get_num_axial_crystals_per_block(); } - int -Scanner::get_num_transaxial_crystals_per_bucket() const -{ - return - get_num_transaxial_blocks_per_bucket() * - get_num_transaxial_crystals_per_block(); +Scanner::get_num_transaxial_crystals_per_bucket() const { + return get_num_transaxial_blocks_per_bucket() * get_num_transaxial_crystals_per_block(); } int -Scanner::get_num_detector_layers() const -{ +Scanner::get_num_detector_layers() const { return num_detector_layers; } int -Scanner::get_num_axial_blocks() const -{ +Scanner::get_num_axial_blocks() const { // when using virtual crystals between blocks, there won't be one at the end, so we // need to take this into account. - return (num_rings+get_num_virtual_axial_crystals_per_block())/num_axial_crystals_per_block; + return (num_rings + get_num_virtual_axial_crystals_per_block()) / num_axial_crystals_per_block; } int -Scanner::get_num_transaxial_blocks() const -{ - return num_detectors_per_ring/num_transaxial_crystals_per_block; +Scanner::get_num_transaxial_blocks() const { + return num_detectors_per_ring / num_transaxial_crystals_per_block; } int -Scanner::get_num_axial_buckets() const -{ - return get_num_axial_blocks()/num_axial_blocks_per_bucket; +Scanner::get_num_axial_buckets() const { + return get_num_axial_blocks() / num_axial_blocks_per_bucket; } int -Scanner::get_num_transaxial_buckets() const -{ - return get_num_transaxial_blocks()/num_transaxial_blocks_per_bucket; +Scanner::get_num_transaxial_buckets() const { + return get_num_transaxial_blocks() / num_transaxial_blocks_per_bucket; } - - int -Scanner::get_num_axial_crystals_per_singles_unit() const -{ +Scanner::get_num_axial_crystals_per_singles_unit() const { return num_axial_crystals_per_singles_unit; } int -Scanner::get_num_transaxial_crystals_per_singles_unit() const -{ +Scanner::get_num_transaxial_crystals_per_singles_unit() const { return num_transaxial_crystals_per_singles_unit; } - int -Scanner::get_num_axial_singles_units() const -{ - if ( num_axial_crystals_per_singles_unit == 0 ) { +Scanner::get_num_axial_singles_units() const { + if (num_axial_crystals_per_singles_unit == 0) { return 0; } else { - return (num_rings+get_num_virtual_axial_crystals_per_block()) / num_axial_crystals_per_singles_unit; + return (num_rings + get_num_virtual_axial_crystals_per_block()) / num_axial_crystals_per_singles_unit; } } - int -Scanner::get_num_transaxial_singles_units() const -{ - if ( num_transaxial_crystals_per_singles_unit == 0 ) { +Scanner::get_num_transaxial_singles_units() const { + if (num_transaxial_crystals_per_singles_unit == 0) { return 0; } else { return num_detectors_per_ring / num_transaxial_crystals_per_singles_unit; } } - -int -Scanner::get_num_singles_units () const -{ +int +Scanner::get_num_singles_units() const { // TODO Accomodate more complex (multi-layer) geometries. return get_num_axial_singles_units() * get_num_transaxial_singles_units(); } float -Scanner::get_energy_resolution() const -{ - return energy_resolution; +Scanner::get_energy_resolution() const { + return energy_resolution; +} + +float +Scanner::get_reference_energy() const { + return reference_energy; +} + +int +Scanner::get_max_num_timing_poss() const { + return max_num_of_timing_poss; +} + +float +Scanner::get_size_of_timing_pos() const { + return size_timing_pos; } float -Scanner::get_reference_energy() const -{ - return reference_energy; +Scanner::get_timing_resolution() const { + return timing_resolution; +} + +bool +Scanner::is_tof_ready() const { + return (max_num_of_timing_poss > 0 && size_timing_pos > 0.0f && timing_resolution > 0.0f); } //************************ set ******************************8 -void Scanner::set_type(const Type & new_type) -{ - type = new_type; +void +Scanner::set_type(const Type& new_type) { + type = new_type; } -void Scanner::set_num_rings(const int & new_num) -{ +void +Scanner::set_num_rings(const int& new_num) { num_rings = new_num; } - -void Scanner::set_num_detectors_per_ring(const int & new_num) -{ - num_detectors_per_ring = new_num; + +void +Scanner::set_num_detectors_per_ring(const int& new_num) { + num_detectors_per_ring = new_num; } -void Scanner::set_max_num_non_arccorrected_bins(const int& new_num) -{ +void +Scanner::set_max_num_non_arccorrected_bins(const int& new_num) { max_num_non_arccorrected_bins = new_num; } -void Scanner::set_default_num_arccorrected_bins(const int& new_num) -{ +void +Scanner::set_default_num_arccorrected_bins(const int& new_num) { default_num_arccorrected_bins = new_num; } - -void Scanner::set_inner_ring_radius(const float & new_radius) -{ +void +Scanner::set_inner_ring_radius(const float& new_radius) { inner_ring_radius = new_radius; } -void Scanner::set_average_depth_of_interaction(const float & new_depth_of_interaction) -{ +void +Scanner::set_average_depth_of_interaction(const float& new_depth_of_interaction) { average_depth_of_interaction = new_depth_of_interaction; } -bool Scanner::has_energy_information() const -{ - return (energy_resolution <= 0.0 || - reference_energy <= 0.0) ? false : true; +bool +Scanner::has_energy_information() const { + return (energy_resolution <= 0.0 || reference_energy <= 0.0) ? false : true; } -void Scanner::set_ring_spacing(const float& new_spacing) -{ +void +Scanner::set_ring_spacing(const float& new_spacing) { ring_spacing = new_spacing; } -void Scanner::set_default_bin_size(const float & new_size) -{ +void +Scanner::set_default_bin_size(const float& new_size) { bin_size = new_size; } -void Scanner::set_default_intrinsic_tilt(const float & new_tilt) -{ +void +Scanner::set_default_intrinsic_tilt(const float& new_tilt) { intrinsic_tilt = new_tilt; } -void Scanner::set_num_transaxial_blocks_per_bucket(const int& new_num) -{ +void +Scanner::set_num_transaxial_blocks_per_bucket(const int& new_num) { num_transaxial_blocks_per_bucket = new_num; } -void Scanner::set_num_axial_blocks_per_bucket(const int& new_num) -{ +void +Scanner::set_num_axial_blocks_per_bucket(const int& new_num) { num_axial_blocks_per_bucket = new_num; } -void Scanner::set_num_detector_layers(const int& new_num) -{ +void +Scanner::set_num_detector_layers(const int& new_num) { num_detector_layers = new_num; } - -void Scanner::set_num_axial_crystals_per_block(const int& new_num) -{ +void +Scanner::set_num_axial_crystals_per_block(const int& new_num) { num_axial_crystals_per_block = new_num; } -void Scanner::set_num_transaxial_crystals_per_block(const int& new_num) -{ +void +Scanner::set_num_transaxial_crystals_per_block(const int& new_num) { num_transaxial_crystals_per_block = new_num; } - - -void Scanner::set_num_axial_crystals_per_singles_unit(const int& new_num) -{ +void +Scanner::set_num_axial_crystals_per_singles_unit(const int& new_num) { num_axial_crystals_per_singles_unit = new_num; } -void Scanner::set_num_transaxial_crystals_per_singles_unit(const int& new_num) -{ +void +Scanner::set_num_transaxial_crystals_per_singles_unit(const int& new_num) { num_transaxial_crystals_per_singles_unit = new_num; } void -Scanner::set_energy_resolution(const float new_num) -{ - energy_resolution = new_num; +Scanner::set_energy_resolution(const float new_num) { + energy_resolution = new_num; } void -Scanner::set_reference_energy(const float new_num) -{ - reference_energy = new_num; +Scanner::set_reference_energy(const float new_num) { + reference_energy = new_num; } -/******** Calculate singles bin index from detection position *********/ +void +Scanner::set_num_max_of_timing_poss(const int new_num) { + max_num_of_timing_poss = new_num; +} +void +Scanner::set_size_of_timing_poss(const float new_num) { + size_timing_pos = new_num; +} + +void +Scanner::set_timing_resolution(const float new_num_in_ps) { + timing_resolution = new_num_in_ps; +} + +/******** Calculate singles bin index from detection position *********/ int Scanner::get_singles_bin_index(int axial_index, int transaxial_index) const { // TODO: Accomodate more complex geometry. - return(transaxial_index + (axial_index * get_num_transaxial_singles_units())); + return (transaxial_index + (axial_index * get_num_transaxial_singles_units())); } - - int Scanner::get_singles_bin_index(const DetectionPosition<>& det_pos) const { // TODO: Accomodate more complex geometry. - + int axial_index = det_pos.axial_coord() / get_num_axial_crystals_per_singles_unit(); - int transaxial_index = det_pos.tangential_coord() / - get_num_transaxial_crystals_per_singles_unit(); - - //return(transaxial_index + (axial_index * get_num_transaxial_singles_units())); - return(get_singles_bin_index(axial_index, transaxial_index)); + int transaxial_index = det_pos.tangential_coord() / get_num_transaxial_crystals_per_singles_unit(); + // return(transaxial_index + (axial_index * get_num_transaxial_singles_units())); + return (get_singles_bin_index(axial_index, transaxial_index)); } - - // Get the axial singles bin coordinate from a singles bin. -int +int Scanner::get_axial_singles_unit(int singles_bin_index) const { // TODO: Accomodate more complex geometry. - return(singles_bin_index / get_num_transaxial_singles_units()); + return (singles_bin_index / get_num_transaxial_singles_units()); } - - // Get the transaxial singles bin coordinate from a singles bin. -int +int Scanner::get_transaxial_singles_unit(int singles_bin_index) const { // TODO: Accomodate more complex geometry. - return(singles_bin_index % get_num_transaxial_singles_units()); + return (singles_bin_index % get_num_transaxial_singles_units()); } - - END_NAMESPACE_STIR - diff --git a/src/include/stir/Segment.h b/src/include/stir/Segment.h index 588e874060..faa4e48bd6 100644 --- a/src/include/stir/Segment.h +++ b/src/include/stir/Segment.h @@ -27,14 +27,14 @@ #ifndef __Segment_H__ #define __Segment_H__ - -#include "stir/ProjDataInfo.h" +#include "stir/ProjDataInfo.h" #include "stir/shared_ptr.h" START_NAMESPACE_STIR -template class Sinogram; -template class Viewgram; - +template +class Sinogram; +template +class Viewgram; /*! \brief An (abstract base) class for storing 3d projection data @@ -46,40 +46,40 @@ template class Viewgram; At the moment, 2 'storage modes' are supported (and implemented as derived classes). - The template argument \c elemT is used to specify the data-type of the + The template argument \c elemT is used to specify the data-type of the elements of the 3d object. */ - + template -class Segment -{ +class Segment { #ifdef SWIG // need to make typedef public for swig public: #endif typedef Segment self_type; + public: - - enum StorageOrder{ StorageByView, StorageBySino }; - + enum StorageOrder { StorageByView, StorageBySino }; + virtual ~Segment() {} //! Get shared pointer to proj data info - inline shared_ptr - get_proj_data_info_sptr() const; + inline shared_ptr get_proj_data_info_sptr() const; virtual StorageOrder get_storage_order() const = 0; //! Get the segment number inline int get_segment_num() const; + //! Get the timing position index + inline int get_timing_pos_num() const; virtual int get_min_axial_pos_num() const = 0; virtual int get_max_axial_pos_num() const = 0; virtual int get_min_view_num() const = 0; virtual int get_max_view_num() const = 0; - virtual int get_min_tangential_pos_num() const = 0; - virtual int get_max_tangential_pos_num() const = 0; + virtual int get_min_tangential_pos_num() const = 0; + virtual int get_max_tangential_pos_num() const = 0; virtual int get_num_axial_poss() const = 0; virtual int get_num_views() const = 0; - virtual int get_num_tangential_poss() const = 0; + virtual int get_num_tangential_poss() const = 0; //! return a new sinogram, with data set as in the segment virtual Sinogram get_sinogram(int axial_pos_num) const = 0; @@ -89,7 +89,7 @@ class Segment //! set data in segment according to sinogram \c s virtual void set_sinogram(const Sinogram& s) = 0; //! set sinogram at a different axial_pos_num - virtual void set_sinogram(const Sinogram &s, int axial_pos_num) = 0; + virtual void set_sinogram(const Sinogram& s, int axial_pos_num) = 0; //! set data in segment according to viewgram \c v virtual void set_viewgram(const Viewgram& v) = 0; @@ -99,32 +99,30 @@ class Segment /*! If they do \c not have the same characteristics, the string \a explanation explains why. */ - bool - has_same_characteristics(self_type const&, - std::string& explanation) const; + bool has_same_characteristics(self_type const&, std::string& explanation) const; //! Checks if the 2 objects have the proj_data_info, segment_num etc. /*! Use this version if you do not need to know why they do not match. */ - bool - has_same_characteristics(self_type const&) const; + bool has_same_characteristics(self_type const&) const; //! check equality (data has to be identical) /*! Uses has_same_characteristics() and Array::operator==. - \warning This function uses \c ==, which might not be what you + \warning This function uses \c ==, which might not be what you need to check when \c elemT has data with float or double numbers. */ - virtual bool operator ==(const self_type&) const = 0; - + virtual bool operator==(const self_type&) const = 0; + //! negation of operator== - bool operator !=(const self_type&) const; + bool operator!=(const self_type&) const; //@} protected: shared_ptr proj_data_info_sptr; int segment_num; - - inline Segment(const shared_ptr& proj_data_info_sptr_v,const int s_num); + int timing_pos_num; + + inline Segment(const shared_ptr& proj_data_info_ptr_v, const int s_num, const int t_num = 0); }; END_NAMESPACE_STIR @@ -132,5 +130,3 @@ END_NAMESPACE_STIR #include "stir/Segment.inl" #endif - - diff --git a/src/include/stir/Segment.inl b/src/include/stir/Segment.inl index a98d362063..61188aa308 100644 --- a/src/include/stir/Segment.inl +++ b/src/include/stir/Segment.inl @@ -32,22 +32,24 @@ START_NAMESPACE_STIR template -Segment:: -Segment( const shared_ptr& proj_data_info_sptr_v,const int s_num) - : - proj_data_info_sptr(proj_data_info_sptr_v), - segment_num(s_num) - {} +Segment::Segment(const shared_ptr& proj_data_info_ptr_v, const int s_num, const int t_num) + : proj_data_info_sptr(proj_data_info_ptr_v), segment_num(s_num), timing_pos_num(t_num) {} template int -Segment:: get_segment_num() const -{ return segment_num; } +Segment::get_segment_num() const { + return segment_num; +} + +template +int +Segment::get_timing_pos_num() const { + return timing_pos_num; +} template shared_ptr -Segment::get_proj_data_info_sptr() const -{ +Segment::get_proj_data_info_sptr() const { return proj_data_info_sptr; } diff --git a/src/include/stir/SegmentBySinogram.h b/src/include/stir/SegmentBySinogram.h index cd763f8913..fdaa6c644d 100644 --- a/src/include/stir/SegmentBySinogram.h +++ b/src/include/stir/SegmentBySinogram.h @@ -26,7 +26,7 @@ \author Sanida Mustafovic \author Kris Thielemans - \author Claire Labbe + \author Claire Labbe \author PARAPET project @@ -40,9 +40,9 @@ START_NAMESPACE_STIR -//forward declaration for use in convertion -template class SegmentByView; - +// forward declaration for use in convertion +template +class SegmentByView; /*! \ingroup projdata @@ -51,11 +51,10 @@ template class SegmentByView; Storage order is as follows: \code segment_by_sino[view_num][axial_pos_num][tangential_pos_num] - \endcode + \endcode */ template -class SegmentBySinogram : public Segment, public Array<3,elemT> -{ +class SegmentBySinogram : public Segment, public Array<3, elemT> { private: typedef SegmentBySinogram self_type; @@ -64,24 +63,22 @@ class SegmentBySinogram : public Segment, public Array<3,elemT> typedef typename Segment::StorageOrder StorageOrder; //! Constructor that sets the data to a given 3d Array - SegmentBySinogram(const Array<3,elemT>& v, - const shared_ptr& proj_data_info_ptr_v, - const int segment_num); - + SegmentBySinogram(const Array<3, elemT>& v, const shared_ptr& proj_data_info_ptr_v, const int segment_num, + const int timing_pos_num = 0); + //! Constructor that sets sizes via the ProjDataInfo object, initialising data to 0 - SegmentBySinogram(const shared_ptr& proj_data_info_ptr_v, - const int segment_num); + SegmentBySinogram(const shared_ptr& proj_data_info_ptr_v, const int segment_num, + const int timing_pos_num = 0); - //! Conversion from 1 storage order to the other - SegmentBySinogram (const SegmentByView& ); - //! Get storage order + SegmentBySinogram(const SegmentByView&); + //! Get storage order inline StorageOrder get_storage_order() const; //! Get number of axial positions inline int get_num_axial_poss() const; //! Get number of views inline int get_num_views() const; - //! Get number of tangetial positions + //! Get number of tangential positions inline int get_num_tangential_poss() const; //! Get minimum axial position number inline int get_min_axial_pos_num() const; @@ -92,17 +89,17 @@ class SegmentBySinogram : public Segment, public Array<3,elemT> //! Get maximum view number inline int get_max_view_num() const; //! Get minimum tangetial position number - inline int get_min_tangential_pos_num() const; + inline int get_min_tangential_pos_num() const; //! Get maximum tangential position number - inline int get_max_tangential_pos_num() const; + inline int get_max_tangential_pos_num() const; //! Get sinogram - inline Sinogram get_sinogram(int axial_pos_num) const; + inline Sinogram get_sinogram(int axial_pos_num) const; //! Get viewgram Viewgram get_viewgram(int view_num) const; //! Set viewgram void set_viewgram(const Viewgram&); //! Set sinogram - inline void set_sinogram(Sinogram const &s, int axial_pos_num); + inline void set_sinogram(Sinogram const& s, int axial_pos_num); inline void set_sinogram(const Sinogram& s); //! Overloading Array::grow @@ -110,7 +107,7 @@ class SegmentBySinogram : public Segment, public Array<3,elemT> //! Overloading Array::resize void resize(const IndexRange<3>& range); - virtual bool operator ==(const Segment&) const; + virtual bool operator==(const Segment&) const; }; END_NAMESPACE_STIR diff --git a/src/include/stir/SegmentBySinogram.inl b/src/include/stir/SegmentBySinogram.inl index dde4040c4b..1af7947780 100644 --- a/src/include/stir/SegmentBySinogram.inl +++ b/src/include/stir/SegmentBySinogram.inl @@ -35,92 +35,82 @@ START_NAMESPACE_STIR template -int -SegmentBySinogram ::get_num_axial_poss() const -{ - return this->get_length(); +int +SegmentBySinogram::get_num_axial_poss() const { + return this->get_length(); } template int -SegmentBySinogram::get_min_axial_pos_num() const -{ +SegmentBySinogram::get_min_axial_pos_num() const { return this->get_min_index(); } template -int -SegmentBySinogram::get_max_axial_pos_num() const -{ +int +SegmentBySinogram::get_max_axial_pos_num() const { return this->get_max_index(); } template int -SegmentBySinogram::get_num_views() const -{ - return this->get_length()==0 ? 0 : (*this)[get_min_axial_pos_num()].get_length(); +SegmentBySinogram::get_num_views() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_axial_pos_num()].get_length(); } template int -SegmentBySinogram::get_min_view_num() const -{ - return this->get_length()==0 ? 0 : (*this)[get_min_axial_pos_num()].get_min_index(); +SegmentBySinogram::get_min_view_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_axial_pos_num()].get_min_index(); } template int -SegmentBySinogram::get_max_view_num() const -{ -return this->get_length()==0 ? 0 : (*this)[get_min_axial_pos_num()].get_max_index(); +SegmentBySinogram::get_max_view_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_axial_pos_num()].get_max_index(); } template int -SegmentBySinogram::get_num_tangential_poss() const -{ - return this->get_length()==0 ? 0 : (*this)[get_min_axial_pos_num()][get_min_view_num()].get_length(); +SegmentBySinogram::get_num_tangential_poss() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_axial_pos_num()][get_min_view_num()].get_length(); } template int -SegmentBySinogram::get_min_tangential_pos_num() const -{ - return this->get_length()==0 ? 0 : (*this)[get_min_axial_pos_num()][get_min_view_num()].get_min_index(); +SegmentBySinogram::get_min_tangential_pos_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_axial_pos_num()][get_min_view_num()].get_min_index(); } template int -SegmentBySinogram::get_max_tangential_pos_num() const -{ -return this->get_length()==0 ? 0 : (*this)[get_min_axial_pos_num()][get_min_view_num()].get_max_index(); +SegmentBySinogram::get_max_tangential_pos_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_axial_pos_num()][get_min_view_num()].get_max_index(); } - + template -typename SegmentBySinogram::StorageOrder -SegmentBySinogram:: -get_storage_order() const - { return Segment::StorageBySino; } +typename SegmentBySinogram::StorageOrder +SegmentBySinogram::get_storage_order() const { + return Segment::StorageBySino; +} template -Sinogram -SegmentBySinogram:: -get_sinogram(int axial_pos_num) const -{ return Sinogram(Array<3,elemT>::operator[](axial_pos_num), - Segment::proj_data_info_sptr, axial_pos_num, - Segment::get_segment_num()); } +Sinogram +SegmentBySinogram::get_sinogram(int axial_pos_num) const { + return Sinogram(Array<3, elemT>::operator[](axial_pos_num), Segment::proj_data_info_sptr, axial_pos_num, + Segment::get_segment_num(), Segment::get_timing_pos_num()); +} template -void -SegmentBySinogram:: -set_sinogram(Sinogram const &s, int axial_pos_num) -{ Array<3,elemT>::operator[](axial_pos_num) = s; } +void +SegmentBySinogram::set_sinogram(Sinogram const& s, int axial_pos_num) { + Array<3, elemT>::operator[](axial_pos_num) = s; +} template -void -SegmentBySinogram:: -set_sinogram(const Sinogram& s) - { set_sinogram(s, s.get_axial_pos_num()); } +void +SegmentBySinogram::set_sinogram(const Sinogram& s) { + set_sinogram(s, s.get_axial_pos_num()); +} END_NAMESPACE_STIR diff --git a/src/include/stir/SegmentByView.h b/src/include/stir/SegmentByView.h index 584d43acce..14a8d9f36b 100644 --- a/src/include/stir/SegmentByView.h +++ b/src/include/stir/SegmentByView.h @@ -25,7 +25,7 @@ \author Sanida Mustafovic \author Kris Thielemans - \author Claire Labbe + \author Claire Labbe \author PARAPET project @@ -33,15 +33,16 @@ #ifndef __stir_SegmentByView_H__ #define __stir_SegmentByView_H__ - #include "stir/Segment.h" #include "stir/Array.h" #include "stir/Viewgram.h" START_NAMESPACE_STIR -template class SegmentBySinogram; -template class Sinogram; +template +class SegmentBySinogram; +template +class Sinogram; /*! \ingroup projdata @@ -50,11 +51,11 @@ template class Sinogram; Storage order is as follows: \code segment_by_view[axial_pos_num][view_num][tangential_pos_num] - \endcode + \endcode */ -template class SegmentByView : public Segment, public Array<3,elemT> -{ +template +class SegmentByView : public Segment, public Array<3, elemT> { private: typedef SegmentByView self_type; @@ -63,27 +64,24 @@ template class SegmentByView : public Segment, public Ar typedef typename Segment::StorageOrder StorageOrder; //! Constructor that sets the data to a given 3d Array - SegmentByView(const Array<3,elemT>& v, - const shared_ptr& proj_data_info_ptr, - const int segment_num); + SegmentByView(const Array<3, elemT>& v, const shared_ptr& proj_data_info_ptr, const int segment_num, + const int timing_pos_num = 0); //! Constructor that sets sizes via the ProjDataInfo object, initialising data to 0 - SegmentByView(const shared_ptr& proj_data_info_ptr, - const int segment_num); + SegmentByView(const shared_ptr& proj_data_info_ptr, const int segment_num, const int timing_pos_num = 0); - //! Conversion from 1 storage order to the other - SegmentByView(const SegmentBySinogram& ); - - //TODO ? how to declare a conversion routine that works for any Segment ? + SegmentByView(const SegmentBySinogram&); + + // TODO ? how to declare a conversion routine that works for any Segment ? //! Get storage order inline StorageOrder get_storage_order() const; - //! Get view number + //! Get view number inline int get_num_views() const; //! Get number of axial positions inline int get_num_axial_poss() const; //! Get number of tangetial positions - inline int get_num_tangential_poss() const; + inline int get_num_tangential_poss() const; //! Get minimum view number inline int get_min_view_num() const; //! Get maximum view number @@ -96,24 +94,24 @@ template class SegmentByView : public Segment, public Ar inline int get_min_tangential_pos_num() const; //! Get maximum tangetial position number inline int get_max_tangential_pos_num() const; - + //! Get sinogram Sinogram get_sinogram(int axial_pos_num) const; //! Get viewgram inline Viewgram get_viewgram(int view_num) const; //! Set sinogram - inline void set_sinogram(const Sinogram &s); + inline void set_sinogram(const Sinogram& s); //! Set sinogram - void set_sinogram(Sinogram const &s, int axial_pos_num); + void set_sinogram(Sinogram const& s, int axial_pos_num); //! Set viewgram - inline void set_viewgram(const Viewgram &v); + inline void set_viewgram(const Viewgram& v); //! Overloading Array::grow void grow(const IndexRange<3>& range); //! Overloading Array::resize void resize(const IndexRange<3>& range); - virtual bool operator ==(const Segment&) const; + virtual bool operator==(const Segment&) const; }; END_NAMESPACE_STIR diff --git a/src/include/stir/SegmentByView.inl b/src/include/stir/SegmentByView.inl index 63316d4e6e..905b4d3d84 100644 --- a/src/include/stir/SegmentByView.inl +++ b/src/include/stir/SegmentByView.inl @@ -35,88 +35,81 @@ START_NAMESPACE_STIR template int -SegmentByView::get_num_views() const -{ +SegmentByView::get_num_views() const { return this->get_length(); } template -int -SegmentByView::get_min_view_num() const -{ +int +SegmentByView::get_min_view_num() const { return this->get_min_index(); } template -int -SegmentByView::get_max_view_num() const -{ +int +SegmentByView::get_max_view_num() const { return this->get_max_index(); } template int -SegmentByView::get_num_axial_poss() const - { - return this->get_length()==0 ? 0 : (*this)[get_min_view_num()].get_length(); - } +SegmentByView::get_num_axial_poss() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()].get_length(); +} template int -SegmentByView::get_min_axial_pos_num() const -{ - return this->get_length()==0 ? 0 : (*this)[get_min_view_num()].get_min_index(); +SegmentByView::get_min_axial_pos_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()].get_min_index(); } template int -SegmentByView::get_max_axial_pos_num() const -{ - return this->get_length()==0 ? 0 : (*this)[get_min_view_num()].get_max_index(); +SegmentByView::get_max_axial_pos_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()].get_max_index(); } template -int -SegmentByView::get_num_tangential_poss() const -{ - return this->get_length()==0 ? 0 : (*this)[get_min_view_num()][get_min_axial_pos_num()].get_length(); +int +SegmentByView::get_num_tangential_poss() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()][get_min_axial_pos_num()].get_length(); } template int -SegmentByView::get_min_tangential_pos_num() const -{ -return this->get_length()==0 ? 0 : (*this)[get_min_view_num()][get_min_axial_pos_num()].get_min_index(); +SegmentByView::get_min_tangential_pos_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()][get_min_axial_pos_num()].get_min_index(); } template -int -SegmentByView::get_max_tangential_pos_num()const -{ -return this->get_length()==0 ? 0 : (*this)[get_min_view_num()][get_min_axial_pos_num()].get_max_index(); +int +SegmentByView::get_max_tangential_pos_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()][get_min_axial_pos_num()].get_max_index(); } template -typename SegmentByView::StorageOrder -SegmentByView::get_storage_order() const -{ return Segment::StorageByView; } +typename SegmentByView::StorageOrder +SegmentByView::get_storage_order() const { + return Segment::StorageByView; +} template -Viewgram -SegmentByView::get_viewgram(int view_num) const -{ - return Viewgram(Array<3,elemT>::operator[](view_num), - this->proj_data_info_sptr->create_shared_clone(), view_num, - this->get_segment_num()); } +Viewgram +SegmentByView::get_viewgram(int view_num) const { + return Viewgram(Array<3, elemT>::operator[](view_num), this->proj_data_info_sptr->create_shared_clone(), view_num, + this->get_segment_num(), this->get_timing_pos_num()); +} template -void -SegmentByView::set_sinogram(const Sinogram &s) -{ set_sinogram(s, s.get_axial_pos_num()); } +void +SegmentByView::set_sinogram(const Sinogram& s) { + set_sinogram(s, s.get_axial_pos_num()); +} template -void -SegmentByView::set_viewgram(const Viewgram &v/*, int view_num*/) -{ Array<3,elemT>::operator[](v.get_view_num()) = v; } +void +SegmentByView::set_viewgram(const Viewgram& v /*, int view_num*/) { + Array<3, elemT>::operator[](v.get_view_num()) = v; +} END_NAMESPACE_STIR diff --git a/src/include/stir/SeparableArrayFunctionObject.h b/src/include/stir/SeparableArrayFunctionObject.h index b1337c1b65..4fe81dd11a 100644 --- a/src/include/stir/SeparableArrayFunctionObject.h +++ b/src/include/stir/SeparableArrayFunctionObject.h @@ -26,7 +26,6 @@ See STIR/LICENSE.txt for details */ - #ifndef __stir_SeparableArrayFunctionObject_H__ #define __stir_SeparableArrayFunctionObject_H__ @@ -36,46 +35,37 @@ START_NAMESPACE_STIR - - /*! \ingroup Array \brief This class implements an \c n -dimensional ArrayFunctionObject whose operation is separable. 'Separable' means that its operation consists of \c n 1D operations, one on each - index of the \c n -dimensional array. + index of the \c n -dimensional array. \see in_place_apply_array_functions_on_each_index() - + */ template -class SeparableArrayFunctionObject : - public ArrayFunctionObject_1ArgumentImplementation -{ +class SeparableArrayFunctionObject : public ArrayFunctionObject_1ArgumentImplementation { public: //! Default constructor, results in a trivial ArrayFunctionObject - SeparableArrayFunctionObject (); + SeparableArrayFunctionObject(); //! Constructor taking 1D ArrayFunctionObjects /*! - The 1d functino objects are passed in a VectorWithOffset which needs to + The 1d functino objects are passed in a VectorWithOffset which needs to have num_dimensions elements. (The starting index is irrelevant). The shared_ptr's have to be either all null (a trivial object) or all non-null. */ - SeparableArrayFunctionObject (const VectorWithOffset< shared_ptr > >&); + SeparableArrayFunctionObject(const VectorWithOffset>>&); bool is_trivial() const; protected: - - VectorWithOffset< shared_ptr > > all_1d_array_filters; - virtual void do_it(Array& array) const; - + VectorWithOffset>> all_1d_array_filters; + virtual void do_it(Array& array) const; }; - END_NAMESPACE_STIR - -#endif //SeparableArrayFunctionObject - +#endif // SeparableArrayFunctionObject diff --git a/src/include/stir/SeparableCartesianMetzImageFilter.h b/src/include/stir/SeparableCartesianMetzImageFilter.h index 1b91662077..b2f4d78c5b 100644 --- a/src/include/stir/SeparableCartesianMetzImageFilter.h +++ b/src/include/stir/SeparableCartesianMetzImageFilter.h @@ -3,12 +3,12 @@ /*! \file - \ingroup ImageProcessor + \ingroup ImageProcessor \brief Declaration of class stir::SeparableCartesianMetzImageFilter - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2009, Hammersmith Imanet @@ -30,13 +30,11 @@ #ifndef __stir_SeparableCartesianMetzImageFilter_H__ #define __stir_SeparableCartesianMetzImageFilter_H__ - #include "stir/SeparableMetzArrayFilter.h" #include "stir/RegisteredParsingObject.h" #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" - START_NAMESPACE_STIR // TODO!! remove define @@ -44,14 +42,14 @@ START_NAMESPACE_STIR #define num_dimensions 3 /*! - \ingroup ImageProcessor + \ingroup ImageProcessor \brief A class in the DataProcessor hierarchy that implements Metz filtering (which includes Gaussian filtering). - - As it is derived from RegisteredParsingObject, it implements all the + + As it is derived from RegisteredParsingObject, it implements all the necessary things to parse parameter files etc. - The discretised densities that will be filtered are supposed to be on a + The discretised densities that will be filtered are supposed to be on a Cartesian grid. The filtering operation is then performed as 3 separate 1d filters in every direction. @@ -63,56 +61,47 @@ START_NAMESPACE_STIR */ template -class SeparableCartesianMetzImageFilter : - public - RegisteredParsingObject< - SeparableCartesianMetzImageFilter, - DataProcessor >, - DataProcessor > - > -{ - private: - typedef - RegisteredParsingObject< - SeparableCartesianMetzImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; +class SeparableCartesianMetzImageFilter + : public RegisteredParsingObject, DataProcessor>, + DataProcessor>> { +private: + typedef RegisteredParsingObject, DataProcessor>, + DataProcessor>> + base_type; + public: - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor SeparableCartesianMetzImageFilter(); - - // Construct metz filter given parameters - //SeparableCartesianMetzImageFilter(const double fwhm_x,const double fwhm_y, const double fwhm_z,const int metz_power_x,const int metz_power_y, const int metz_power_z); - - //Succeeded consistency_check( const DiscretisedDensity& image) const; - - + + // Construct metz filter given parameters + // SeparableCartesianMetzImageFilter(const double fwhm_x,const double fwhm_y, const double fwhm_z,const int metz_power_x,const + // int metz_power_y, const int metz_power_z); + + // Succeeded consistency_check( const DiscretisedDensity& image) const; + VectorWithOffset get_metz_fwhms() const; VectorWithOffset get_metz_powers() const; //! Maximum number of elements in the kernels /*! -1 means unrestricted*/ - VectorWithOffset get_max_kernel_sizes() const; - + VectorWithOffset get_max_kernel_sizes() const; + private: - VectorWithOffset fwhms; VectorWithOffset metz_powers; - VectorWithOffset max_kernel_sizes; - - SeparableMetzArrayFilter metz_filter; + VectorWithOffset max_kernel_sizes; + + SeparableMetzArrayFilter metz_filter; virtual void set_defaults(); virtual void initialise_keymap(); - - Succeeded virtual_set_up(const DiscretisedDensity& image); + + Succeeded virtual_set_up(const DiscretisedDensity& image); // new - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const; - void virtual_apply(DiscretisedDensity& density) const ; - + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const; + void virtual_apply(DiscretisedDensity& density) const; }; #undef num_dimensions @@ -120,5 +109,3 @@ class SeparableCartesianMetzImageFilter : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/SeparableConvolutionImageFilter.h b/src/include/stir/SeparableConvolutionImageFilter.h index d2740fc50f..5096dd5119 100644 --- a/src/include/stir/SeparableConvolutionImageFilter.h +++ b/src/include/stir/SeparableConvolutionImageFilter.h @@ -3,11 +3,11 @@ /*! \file - \ingroup ImageProcessor + \ingroup ImageProcessor \brief Declaration of class stir::SeparableConvolutionImageFilter - + \author Kris Thielemans - + */ /* Copyright (C) 2002- 2009, Hammersmith Imanet Ltd @@ -29,7 +29,6 @@ #ifndef __stir_SeparableConvolutionImageFilter_H__ #define __stir_SeparableConvolutionImageFilter_H__ - #include "stir/SeparableArrayFunctionObject.h" #include "stir/RegisteredParsingObject.h" #include "stir/DataProcessor.h" @@ -40,38 +39,38 @@ START_NAMESPACE_STIR // TODO!! remove define -// currently fixed at 3 because I didn't really have a good idea for the parsing +// currently fixed at 3 because I didn't really have a good idea for the parsing // keywords in n dimensions. // #define num_dimensions 3 /*! - \ingroup ImageProcessor + \ingroup ImageProcessor \brief A class derived from DataProcessor for performing separable non-periodic convolutions. This filter applies a 1D convolution in all directions (z,y,x) with potentially a different filter kernel for every direction. - When parsing, the filter coefficients are read as a list of numbers for each + When parsing, the filter coefficients are read as a list of numbers for each direction. The following conventions is used:
    1. A list of 0 length (which is the default) corresponds to no filtering.
    2. When the list contains an even number of data, a 0 is appended (at the end). -
    3. After this, the central element of the list corresponds to the 0-th element +
    4. After this, the central element of the list corresponds to the 0-th element in the kernel, see below.
    Convolution is non-periodic. In each direction, the following is applied: - - \f[ out_i = \sum_j kernelforthisdirection_j in_{i-j} \f] + + \f[ out_i = \sum_j kernelforthisdirection_j in_{i-j} \f] Note that for most kernels, the above convention means that the zero- - index of the kernel corresponds to the peak in the kernel. + index of the kernel corresponds to the peak in the kernel. Elements of the input array that are outside its - index range are considered to be 0. + index range are considered to be 0. - \warning There is NO check if the kernel coefficients add up to 1. This is + \warning There is NO check if the kernel coefficients add up to 1. This is because not all filters need this (e.g. edge enhancing filters). \par Example input for a low-pass filter in x,y, no filtering in z @@ -86,59 +85,49 @@ START_NAMESPACE_STIR The filter is implemented using the class ArrayFilter1DUsingConvolution. */ template -class SeparableConvolutionImageFilter : - public - RegisteredParsingObject< - SeparableConvolutionImageFilter, - DataProcessor >, - DataProcessor > - > -{ - private: - typedef - RegisteredParsingObject< - SeparableConvolutionImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; +class SeparableConvolutionImageFilter + : public RegisteredParsingObject, DataProcessor>, + DataProcessor>> { +private: + typedef RegisteredParsingObject, DataProcessor>, + DataProcessor>> + base_type; + public: //! Name for parsing registry - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor SeparableConvolutionImageFilter(); //! Constructor taking filter coefficients explicitly. - /*! These filter coefficients are passed to the + /*! These filter coefficients are passed to the ArrayFilter1DUsingConvolution constructor. \a filter_coefficients has to have length 3. (Start index is irrelevant). Its first element will be applied to the 'first dimension', i.e. the first index. */ - SeparableConvolutionImageFilter(const VectorWithOffset< VectorWithOffset >& filter_coefficients); + SeparableConvolutionImageFilter(const VectorWithOffset>& filter_coefficients); + + // VectorWithOffset get_filter_coefficients(); - //VectorWithOffset get_filter_coefficients(); - - private: // silly business because KeyParser supports only LIST_OF_DOUBLES // TODO remove - std::vector< std::vector > filter_coefficients_for_parsing; + std::vector> filter_coefficients_for_parsing; + + VectorWithOffset> filter_coefficients; - VectorWithOffset< VectorWithOffset > filter_coefficients; - - SeparableArrayFunctionObject filter; + SeparableArrayFunctionObject filter; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - - Succeeded virtual_set_up(const DiscretisedDensity& image); - void virtual_apply(DiscretisedDensity& out_density, - const DiscretisedDensity& in_density) const; - void virtual_apply(DiscretisedDensity& density) const ; - + + Succeeded virtual_set_up(const DiscretisedDensity& image); + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const; + void virtual_apply(DiscretisedDensity& density) const; }; #undef num_dimensions @@ -146,5 +135,3 @@ class SeparableConvolutionImageFilter : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/SeparableGaussianArrayFilter.h b/src/include/stir/SeparableGaussianArrayFilter.h index 95e6670ac2..f497432a52 100644 --- a/src/include/stir/SeparableGaussianArrayFilter.h +++ b/src/include/stir/SeparableGaussianArrayFilter.h @@ -44,43 +44,34 @@ START_NAMESPACE_STIR */ template -class SeparableGaussianArrayFilter: - public SeparableArrayFunctionObject -{ -public: - +class SeparableGaussianArrayFilter : public SeparableArrayFunctionObject { +public: //! Default constructor - SeparableGaussianArrayFilter(); - + SeparableGaussianArrayFilter(); + //! Constructor /*! \param fwhms: the FWHM of the Gaussian 1D filters (in mm) \param max_kernel_sizes maximum number of elements in the kernels. - -1 means that the size will be determined such that the smallest element is approximately 1E-6 times the largest (in each dimension) + -1 means that the size will be determined such that the smallest element is approximately 1E-6 times the largest (in + each dimension) */ - SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& fwhm, - const BasicCoordinate< num_dimensions,int>& max_kernel_sizes, - bool normalise = true); - - SeparableGaussianArrayFilter(const float fwhm, - const float max_kernel_sizes, - bool normalise = true); -private: + SeparableGaussianArrayFilter(const BasicCoordinate& fwhm, + const BasicCoordinate& max_kernel_sizes, bool normalise = true); - void construct_filter(bool normalise = true); + SeparableGaussianArrayFilter(const float fwhm, const float max_kernel_sizes, bool normalise = true); - void calculate_coefficients(VectorWithOffset& filter_coefficients, - const int max_kernel_sizes, - const float fwhm, bool normalise); +private: + void construct_filter(bool normalise = true); + void calculate_coefficients(VectorWithOffset& filter_coefficients, const int max_kernel_sizes, const float fwhm, + bool normalise); - BasicCoordinate< num_dimensions,float> fwhms; - BasicCoordinate< num_dimensions,int> max_kernel_sizes; - + BasicCoordinate fwhms; + BasicCoordinate max_kernel_sizes; }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir/SeparableGaussianImageFilter.h b/src/include/stir/SeparableGaussianImageFilter.h index 56bf624777..c4da7b3e71 100644 --- a/src/include/stir/SeparableGaussianImageFilter.h +++ b/src/include/stir/SeparableGaussianImageFilter.h @@ -1,13 +1,13 @@ /*! \file - \ingroup buildblock + \ingroup buildblock \brief Declaration of class stir::SeparableGaussianImageFilter - + \author Kris Thielemans \author Sanida Mustafovic \author Ludovica Brusaferri - + */ /* Copyright (C) 2000- 2007, Hammersmith Imanet @@ -18,13 +18,11 @@ #ifndef __stir_SeparableGaussianImageFilter_H__ #define __stir_SeparableGaussianImageFilter_H__ - #include "stir/SeparableGaussianArrayFilter.h" #include "stir/RegisteredParsingObject.h" #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" - START_NAMESPACE_STIR // TODO!! remove define @@ -50,55 +48,47 @@ START_NAMESPACE_STIR */ template -class SeparableGaussianImageFilter : - public - RegisteredParsingObject< - SeparableGaussianImageFilter, - DataProcessor >, - DataProcessor > - > -{ - private: - typedef - RegisteredParsingObject< - SeparableGaussianImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; +class SeparableGaussianImageFilter : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { +private: + typedef RegisteredParsingObject, DataProcessor>, + DataProcessor>> + base_type; + public: - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor SeparableGaussianImageFilter(); - BasicCoordinate< num_dimensions,float> get_fwhms(); - BasicCoordinate< num_dimensions,int> get_max_kernel_sizes(); + BasicCoordinate get_fwhms(); + BasicCoordinate get_max_kernel_sizes(); bool get_normalised_filter(); - - void set_fwhms(const BasicCoordinate< num_dimensions,float>&); - void set_max_kernel_sizes(const BasicCoordinate< num_dimensions,int>&); - void set_normalise(const bool); - + + void set_fwhms(const BasicCoordinate&); + void set_max_kernel_sizes(const BasicCoordinate&); + void set_normalise(const bool); + private: - BasicCoordinate< num_dimensions,float> fwhms; + BasicCoordinate fwhms; protected: - - BasicCoordinate< num_dimensions,int> max_kernel_sizes; + BasicCoordinate max_kernel_sizes; bool normalise; - - SeparableGaussianArrayFilter gaussian_filter; + + SeparableGaussianArrayFilter gaussian_filter; virtual void set_defaults(); virtual void initialise_keymap(); - //virtual bool post_processing(); - - Succeeded virtual_set_up(const DiscretisedDensity& image); + // virtual bool post_processing(); + + Succeeded virtual_set_up(const DiscretisedDensity& image); // new - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const; - void virtual_apply(DiscretisedDensity& density) const ; + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const; + void virtual_apply(DiscretisedDensity& density) const; }; #undef num_dimensions @@ -106,5 +96,3 @@ class SeparableGaussianImageFilter : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/SeparableMetzArrayFilter.h b/src/include/stir/SeparableMetzArrayFilter.h index 845a16cd63..a499b31682 100644 --- a/src/include/stir/SeparableMetzArrayFilter.h +++ b/src/include/stir/SeparableMetzArrayFilter.h @@ -35,34 +35,32 @@ START_NAMESPACE_STIR - - /*! \ingroup Array \brief Separable Metz filtering in \c n - dimensions - + The Metz filter is easiest defined in frequency space. For a \c fwhm \c s and power \c P, its (continuous) Fourier transform is given by - \f[ + \f[ M(k,s,P) = (1 - (1 - G(k, s)^2)^{(P + 1)})/ G(k, s) \f] - where \f$ G(k,s) \f$ is the Fourier transform of a Gaussian with FWHM \c s, - normalised such that \f$G(0,s) = 1\f$. + where \f$ G(k,s) \f$ is the Fourier transform of a Gaussian with FWHM \c s, + normalised such that \f$G(0,s) = 1\f$. - For power 0, the Metz filter is just a Gaussian. For higher power, mid-range + For power 0, the Metz filter is just a Gaussian. For higher power, mid-range frequencies are more and more amplified. The first figure shows the FT of the Metz filter with \c fwhm 1, for powers 0, 0.5, 1, ... 3 (lowest curve is Gaussian). \image html FTMetz.jpg \image latex FTMetz.eps width=10cm - Spatially, the Metz filter has negative lobes. The 2nd figure shows the Metz kernel + Spatially, the Metz filter has negative lobes. The 2nd figure shows the Metz kernel in space, again with \c fwhm 1, powers 0 (long dashes),1,2,3 (no dashes) \image html Metz.jpg \image latex Metz.eps width=10cm - Note that from the definition it follows that + Note that from the definition it follows that \f[ Metz(x,s,P) = Metz(x/s, 1 ,P)/s \f] - The final figure illustrates the relation between the actual FWHM of the Metz + The final figure illustrates the relation between the actual FWHM of the Metz filter and the FWHM of the underlying Gaussian. \image html MetzFWHM.jpg \image latex MetzFWHM.eps width=10cm @@ -70,43 +68,39 @@ START_NAMESPACE_STIR This implementation discretises the Metz filter currently in the following way. it assumes that the input data are band-limited. For such data, it is possible to compute the filtering with the continuous Metz filter exactly. This is - done with linear convolution of the sampled data with samples of the + done with linear convolution of the sampled data with samples of the spatial Metz cut off at the same frequency as the input data. \warning Currently, this implements a Metz filter cut off at 1/\c sampling_distance. \warning The Metz filter does \e not preserve positivity. */ template -class SeparableMetzArrayFilter: public SeparableArrayFunctionObject -{ +class SeparableMetzArrayFilter : public SeparableArrayFunctionObject { public: /*! \brief Default constructor \warning This currently does not set things properly for a trivial filter. */ SeparableMetzArrayFilter() {} - + //! Constructor - /*! + /*! \param fwhms the FWHM of the underlying Gauss 1D filters (in mm) \param metz_powers the powers of the 1D Metz filters \param sampling_distances in each dimensions (in mm) \param max_kernel_sizes maximum number of elements in the kernels. -1 means unrestricted - For each of these parameters, the index range should be from 1 to num_dimensions, + For each of these parameters, the index range should be from 1 to num_dimensions, with 1 corresponding to the 1st (i.e. slowest) index. \warning the fwhms parameter does \c not give the FWHM of the Metz filter, but of the underlying Gauss. */ - SeparableMetzArrayFilter(const VectorWithOffset& fwhms, - const VectorWithOffset& metz_powers, - const BasicCoordinate& sampling_distances, - const VectorWithOffset& max_kernel_sizes); - - - + SeparableMetzArrayFilter(const VectorWithOffset& fwhms, const VectorWithOffset& metz_powers, + const BasicCoordinate& sampling_distances, + const VectorWithOffset& max_kernel_sizes); + private: VectorWithOffset fwhms; VectorWithOffset metz_powers; @@ -114,9 +108,6 @@ class SeparableMetzArrayFilter: public SeparableArrayFunctionObject max_kernel_sizes; }; - END_NAMESPACE_STIR #endif // SeparableMetzArrayFilter - - diff --git a/src/include/stir/Shape/Box3D.h b/src/include/stir/Shape/Box3D.h index ed359a2b2f..1fbc8cc15c 100644 --- a/src/include/stir/Shape/Box3D.h +++ b/src/include/stir/Shape/Box3D.h @@ -19,9 +19,9 @@ /*! \file \ingroup Shape - + \brief Declaration of class stir::Box3D - + \author C. Ross Schmidtlein */ @@ -43,7 +43,7 @@ START_NAMESPACE_STIR \f[ abs(x), abs(y), abs(z) <= length_x/2, length_y/2, length_z/2 \f] - + \par Parameters \verbatim Box3D Parameters:= @@ -54,13 +54,11 @@ START_NAMESPACE_STIR End:= \endverbatim */ -class Box3D: -public RegisteredParsingObject -{ - public: +class Box3D : public RegisteredParsingObject { +public: //! Name which will be used when parsing a Shape3D object - static const char * const registered_name; - + static const char* const registered_name; + Box3D(); #if 0 Box3D( const float length_x, @@ -72,39 +70,34 @@ public RegisteredParsingObject const float gamma); #endif - Box3D( const float length_x, - const float length_y, - const float length_z, - const CartesianCoordinate3D& centre, - const Array<2,float>& direction_vectors = diagonal_matrix(3,1.F)); + Box3D(const float length_x, const float length_y, const float length_z, const CartesianCoordinate3D& centre, + const Array<2, float>& direction_vectors = diagonal_matrix(3, 1.F)); float get_geometric_volume() const; // float get_geometric_area() const; - + bool is_inside_shape(const CartesianCoordinate3D& coord) const; - + Shape3D* clone() const; //! Compare boxes /*! Uses a tolerance determined by the smallest dimension of the object divided by 1000.*/ - bool - operator==(const Box3D&) const; + bool operator==(const Box3D&) const; - virtual bool - operator==(const Shape3D& shape) const; - - protected: + virtual bool operator==(const Shape3D& shape) const; + +protected: //! Length in x-direction if the shape is not rotated float length_x; //! Length in y-direction if the shape is not rotated float length_y; //! Length in z-direction if the shape is not rotated float length_z; - private: - virtual void set_defaults(); + +private: + virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - }; END_NAMESPACE_STIR diff --git a/src/include/stir/Shape/CombinedShape3D.h b/src/include/stir/Shape/CombinedShape3D.h index 3e487991bd..bdb78e012a 100644 --- a/src/include/stir/Shape/CombinedShape3D.h +++ b/src/include/stir/Shape/CombinedShape3D.h @@ -35,21 +35,15 @@ START_NAMESPACE_STIR +template +struct logical_and_not : public std::binary_function { + inline bool operator()(const T& x, const T& y) const { return x && !y; } +}; -template -struct logical_and_not : public std::binary_function - { - inline bool operator()(const T& x, const T& y) const - { return x && !y; } - }; - - -template -struct logical_and : public std::binary_function - { - inline bool operator()(const T& x, const T& y) const - { return x || y; } - }; +template +struct logical_and : public std::binary_function { + inline bool operator()(const T& x, const T& y) const { return x || y; } +}; /*! \ingroup Shape \brief A class that allows combining several shapes using logical operations @@ -57,15 +51,13 @@ struct logical_and : public std::binary_function \todo Parsing cannot work yet because of template (can be solved by explicit instantiation) */ -template > -class CombinedShape3D : - public RegisteredParsingObject -{ +template > +class CombinedShape3D : public RegisteredParsingObject { public: // Name which will be used when parsing a Shape3D object - //static const char * const registered_name; + // static const char * const registered_name; - inline CombinedShape3D( shared_ptr object1_v, shared_ptr object2_v); + inline CombinedShape3D(shared_ptr object1_v, shared_ptr object2_v); inline bool is_inside_shape(const CartesianCoordinate3D& coord) const; inline void translate(const CartesianCoordinate3D& direction); inline void scale(const CartesianCoordinate3D& scale3D); @@ -74,10 +66,8 @@ class CombinedShape3D : private: shared_ptr object1_ptr; shared_ptr object2_ptr; - }; - END_NAMESPACE_STIR #include "stir/Shape/CombinedShape3D.inl" diff --git a/src/include/stir/Shape/CombinedShape3D.inl b/src/include/stir/Shape/CombinedShape3D.inl index c75fc4ebb4..3d42c30f0d 100644 --- a/src/include/stir/Shape/CombinedShape3D.inl +++ b/src/include/stir/Shape/CombinedShape3D.inl @@ -27,23 +27,19 @@ */ START_NAMESPACE_STIR -template -CombinedShape3D::CombinedShape3D( shared_ptr object1_v, shared_ptr object2_v) - :object1_ptr(object1_v), - object2_ptr(object2_v) - {} +template +CombinedShape3D::CombinedShape3D(shared_ptr object1_v, shared_ptr object2_v) + : object1_ptr(object1_v), object2_ptr(object2_v) {} - -template -bool CombinedShape3D::is_inside_shape(const CartesianCoordinate3D& index) const - { - return operation()(object1_ptr->is_inside_shape(index), - object2_ptr->is_inside_shape(index)); +template +bool +CombinedShape3D::is_inside_shape(const CartesianCoordinate3D& index) const { + return operation()(object1_ptr->is_inside_shape(index), object2_ptr->is_inside_shape(index)); } -template -Shape3D* CombinedShape3D::clone() const -{ +template +Shape3D* +CombinedShape3D::clone() const { // TODO alright ? #if 0 Shape3D* tmp = static_cast(new CombinedShape3D(*this)); @@ -51,14 +47,14 @@ Shape3D* CombinedShape3D::clone() const ", new " << tmp << endl; return tmp; #else - return static_cast(new CombinedShape3D(*this)); + return static_cast(new CombinedShape3D(*this)); #endif } -template -void CombinedShape3D::translate(const CartesianCoordinate3D& direction) -{ - // TODO alright ? +template +void +CombinedShape3D::translate(const CartesianCoordinate3D& direction) { + // TODO alright ? shared_ptr new_object1_ptr = object1_ptr->clone(); shared_ptr new_object2_ptr = object2_ptr->clone(); object1_ptr = new_object1_ptr; @@ -67,11 +63,10 @@ void CombinedShape3D::translate(const CartesianCoordinate3D& d object2_ptr->translate(direction); } - -template -void CombinedShape3D::scale(const CartesianCoordinate3D& scale3D) -{ - // TODO alright ? +template +void +CombinedShape3D::scale(const CartesianCoordinate3D& scale3D) { + // TODO alright ? #if 0 cerr << "scale: " << object1_ptr.ptr->data << ", " << object2_ptr.ptr->data << endl; diff --git a/src/include/stir/Shape/DiscretisedShape3D.h b/src/include/stir/Shape/DiscretisedShape3D.h index 675f7b6936..fa307c9cc4 100644 --- a/src/include/stir/Shape/DiscretisedShape3D.h +++ b/src/include/stir/Shape/DiscretisedShape3D.h @@ -33,7 +33,8 @@ START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; /*! \ingroup Shape \brief A class for shapes that have been discretised @@ -41,7 +42,7 @@ template class DiscretisedDensity; Currently only supports discretisation via VoxelsOnCartesianGrid. For DiscretisedShaped3D objects with smooth edges, voxel values - will vary between 0 and 1. + will vary between 0 and 1. \par Parameters for parsing \verbatim @@ -51,17 +52,15 @@ template class DiscretisedDensity; \endverbatim where \a filename needs to specify a volume that can be read by STIR. */ -class DiscretisedShape3D: - public RegisteredParsingObject -{ +class DiscretisedShape3D : public RegisteredParsingObject { public: //! Name which will be used when parsing a Shape3D object - static const char * const registered_name; + static const char* const registered_name; DiscretisedShape3D(); //! Constructor that will copy the image to an internal member - /*! The \c filename member is set to "FROM MEMORY" such that parameter_info() + /*! The \c filename member is set to "FROM MEMORY" such that parameter_info() returns somewhat useful info. This has a consequence that the object cannot be constructed from its own parameter_info(). This is in contrast with most other shapes. @@ -69,79 +68,78 @@ class DiscretisedShape3D: DiscretisedShape3D(const VoxelsOnCartesianGrid& image); //! Constructor that will copy the shared_ptr image - /*! The \c filename member is set to "FROM MEMORY" such that parameter_info() + /*! The \c filename member is set to "FROM MEMORY" such that parameter_info() returns somewhat useful info. This has a consequence that the object cannot be constructed from its own parameter_info(). This is in contrast with most other shapes. */ - DiscretisedShape3D(const shared_ptr >& density_sptr); + DiscretisedShape3D(const shared_ptr>& density_sptr); //! Compare shapes /*! \todo currently not implemented (will call error() */ - virtual bool - operator==(const Shape3D&) const - { error("DiscretisedShape3D::operator== not implemented. Sorry"); return false;} + virtual bool operator==(const Shape3D&) const { + error("DiscretisedShape3D::operator== not implemented. Sorry"); + return false; + } //! set origin of the shape virtual void set_origin(const CartesianCoordinate3D&); //! Scale shape /*! \todo Not implemented (will call error()) */ - virtual void scale(const CartesianCoordinate3D& scale3D) - { error ("TODO: DiscretisedShape3D::scale not implemented. Sorry.");} + virtual void scale(const CartesianCoordinate3D& scale3D) { + error("TODO: DiscretisedShape3D::scale not implemented. Sorry."); + } //! determine if a point is inside a non-zero voxel or not - /*! + /*! \warning For voxels at the edges, it is somewhat ill-defined if a point in the voxel is inside the shape. The current - implementation will return true for every point in the voxel, + implementation will return true for every point in the voxel, even if the voxel value is .001. In particular, this means that this definition of is_inside_shape() - cannot be used to find the voxel_weight. So, we have to redefine + cannot be used to find the voxel_weight. So, we have to redefine get_voxel_weight() in the present class. */ bool is_inside_shape(const CartesianCoordinate3D& index) const; //! get weight for a voxel centred around \a coord - /*! + /*! \warning Presently only works when \a coord is the centre of a voxel and \a voxel_size is identical to the image's voxel_size The argument \a num_samples is ignored. */ - virtual float get_voxel_weight( - const CartesianCoordinate3D& coord, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& num_samples) const; + virtual float get_voxel_weight(const CartesianCoordinate3D& coord, const CartesianCoordinate3D& voxel_size, + const CartesianCoordinate3D& num_samples) const; - //! Construct a new image (using zoom_image) from the underlying density - /*! - If the images do not have the same characteristics, zoom_image is called for interpolation. - The result is scaled such that mean ROI values remain the same (at least for ROIs which avoid edges). + //! Construct a new image (using zoom_image) from the underlying density + /*! + If the images do not have the same characteristics, zoom_image is called for interpolation. + The result is scaled such that mean ROI values remain the same (at least for ROIs which avoid edges). + + The argument \a num_samples is ignored. + */ + void construct_volume(VoxelsOnCartesianGrid& image, const CartesianCoordinate3D& num_samples) const; + // void construct_slice(PixelsOnCartesianGrid &plane, const CartesianCoordinate3D& num_samples) const; + + virtual Shape3D* clone() const; + + //! provide access to the underlying density + DiscretisedDensity<3, float>& get_discretised_density(); + + //! provide (const) access to the underlying density + const DiscretisedDensity<3, float>& get_discretised_density() const; - The argument \a num_samples is ignored. - */ - void construct_volume(VoxelsOnCartesianGrid &image, const CartesianCoordinate3D& num_samples) const; - //void construct_slice(PixelsOnCartesianGrid &plane, const CartesianCoordinate3D& num_samples) const; - - - virtual Shape3D* clone() const; - - //! provide access to the underlying density - DiscretisedDensity<3,float>& get_discretised_density(); - - //! provide (const) access to the underlying density - const DiscretisedDensity<3,float>& get_discretised_density() const; - private: - shared_ptr > density_sptr; - + shared_ptr> density_sptr; + inline const VoxelsOnCartesianGrid& image() const; // inline VoxelsOnCartesianGrid& image(); //! \name Parsing functions //@{ - virtual void set_defaults(); + virtual void set_defaults(); virtual void initialise_keymap(); //! Checks validity of parameters /*! As currently there are 2 origin parameters (in Shape3D and @@ -153,7 +151,6 @@ class DiscretisedShape3D: std::string filename; }; - END_NAMESPACE_STIR #include "stir/Shape/DiscretisedShape3D.inl" diff --git a/src/include/stir/Shape/DiscretisedShape3D.inl b/src/include/stir/Shape/DiscretisedShape3D.inl index 8d93b34499..bf2a6e88b8 100644 --- a/src/include/stir/Shape/DiscretisedShape3D.inl +++ b/src/include/stir/Shape/DiscretisedShape3D.inl @@ -28,14 +28,11 @@ START_NAMESPACE_STIR - -const VoxelsOnCartesianGrid& -DiscretisedShape3D:: -image() const -{ +const VoxelsOnCartesianGrid& +DiscretisedShape3D::image() const { return static_cast&>(*density_sptr); } - + #if 0 VoxelsOnCartesianGrid& DiscretisedShape3D:: diff --git a/src/include/stir/Shape/Ellipsoid.h b/src/include/stir/Shape/Ellipsoid.h index 5980c39286..443afec4e2 100644 --- a/src/include/stir/Shape/Ellipsoid.h +++ b/src/include/stir/Shape/Ellipsoid.h @@ -27,7 +27,6 @@ #ifndef __stir_Shape_Ellipsoid_h__ #define __stir_Shape_Ellipsoid_h__ - #include "stir/RegisteredParsingObject.h" #include "stir/Shape/Shape3DWithOrientation.h" @@ -36,7 +35,7 @@ START_NAMESPACE_STIR /*! \ingroup Shape \brief Three-dimensional ellipsoid - + \par Description A point with coordinates \a coord is inside the shape if for @@ -57,17 +56,14 @@ START_NAMESPACE_STIR End:= \endverbatim */ -class Ellipsoid: - public RegisteredParsingObject -{ +class Ellipsoid : public RegisteredParsingObject { public: //! Name which will be used when parsing a Shape3D object - static const char * const registered_name; + static const char* const registered_name; - Ellipsoid(); - Ellipsoid( const CartesianCoordinate3D& radii, - const CartesianCoordinate3D& centre, - const Array<2,float>& direction_vectors = diagonal_matrix(3,1.F)); + Ellipsoid(); + Ellipsoid(const CartesianCoordinate3D& radii, const CartesianCoordinate3D& centre, + const Array<2, float>& direction_vectors = diagonal_matrix(3, 1.F)); //! get volume float get_geometric_volume() const; #if 0 @@ -81,22 +77,15 @@ class Ellipsoid: //! Compare cylinders /*! Uses a tolerance determined by the smallest dimension of the object divided by 1000.*/ - bool - operator==(const Ellipsoid&) const; - - virtual bool - operator==(const Shape3D& shape) const; - - inline float get_radius_x() const - { return radii.x(); } - inline float get_radius_y() const - { return radii.y(); } - inline float get_radius_z() const - { return radii.z(); } - inline CartesianCoordinate3D get_radii() const - { return radii; } - void set_radii(const CartesianCoordinate3D& new_radii); + bool operator==(const Ellipsoid&) const; + virtual bool operator==(const Shape3D& shape) const; + + inline float get_radius_x() const { return radii.x(); } + inline float get_radius_y() const { return radii.y(); } + inline float get_radius_z() const { return radii.z(); } + inline CartesianCoordinate3D get_radii() const { return radii; } + void set_radii(const CartesianCoordinate3D& new_radii); protected: //! Radii in 3 directions (before using the direction vectors) @@ -104,13 +93,11 @@ class Ellipsoid: //! set defaults before parsing /*! sets radii to 0 and calls Shape3DWithOrientation::set_defaults() */ - virtual void set_defaults(); + virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir/Shape/EllipsoidalCylinder.h b/src/include/stir/Shape/EllipsoidalCylinder.h index 8510dea510..819c52dabf 100644 --- a/src/include/stir/Shape/EllipsoidalCylinder.h +++ b/src/include/stir/Shape/EllipsoidalCylinder.h @@ -35,7 +35,7 @@ START_NAMESPACE_STIR /*! \ingroup Shape \brief Three-dimensional ellipsoidal cylinder - + \par Description A point with coordinates \a coord is inside the shape if for @@ -56,10 +56,10 @@ START_NAMESPACE_STIR Shape3DWithOrientation. \par Parameters - To specify an ellipsoidal cylinder with the dimensions + To specify an ellipsoidal cylinder with the dimensions (radius_x,radius_y,length, theta_1, theta_2), where radius_x is in x direction, radius_y in y direction, length in z-direction, - theta_1 and theta_2 are defined counter clockwise from the positive x-axis + theta_1 and theta_2 are defined counter clockwise from the positive x-axis about the z-axis (before any rotations), use: \verbatim Ellipsoidal Cylinder Parameters:= @@ -72,46 +72,36 @@ START_NAMESPACE_STIR End:= \endverbatim */ -class EllipsoidalCylinder: - public RegisteredParsingObject -{ +class EllipsoidalCylinder : public RegisteredParsingObject { public: //! Name which will be used when parsing a Shape3D object - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor (calls set_defaults()) EllipsoidalCylinder(); //! Constructor /*! \warning: note order of arguments */ - EllipsoidalCylinder(const float length_z, - const float radius_y, - const float radius_x, + EllipsoidalCylinder(const float length_z, const float radius_y, const float radius_x, const CartesianCoordinate3D& centre, - const Array<2,float>& direction_vectors = diagonal_matrix(3,1.F)); - + const Array<2, float>& direction_vectors = diagonal_matrix(3, 1.F)); + //! Constructor /*! \warning: note order of arguments. \bug angles \a theta_1 and \a theta_2 are currently in degrees, while STIR conventions dictate radians. */ - EllipsoidalCylinder(const float length_z, - const float radius_y, - const float radius_x, - const float theta_1, - const float theta_2, + EllipsoidalCylinder(const float length_z, const float radius_y, const float radius_x, const float theta_1, const float theta_2, const CartesianCoordinate3D& centre, - const Array<2,float>& direction_vectors = diagonal_matrix(3,1.F)); + const Array<2, float>& direction_vectors = diagonal_matrix(3, 1.F)); - Shape3D* clone() const; + Shape3D* clone() const; //! Compare cylinders /*! Uses a tolerance determined by the smallest dimension of the object divided by 1000.*/ - bool - operator==(const EllipsoidalCylinder& cylinder) const; + bool operator==(const EllipsoidalCylinder& cylinder) const; - virtual bool - operator==(const Shape3D& shape) const; + virtual bool operator==(const Shape3D& shape) const; //! get volume float get_geometric_volume() const; @@ -121,20 +111,16 @@ class EllipsoidalCylinder: #endif bool is_inside_shape(const CartesianCoordinate3D& coord) const; - - inline float get_length() const - { return length; } - inline float get_radius_x() const - { return radius_x; } - inline float get_radius_y() const - { return radius_y; } - //TODOXXX add theta_1,2 + + inline float get_length() const { return length; } + inline float get_radius_x() const { return radius_x; } + inline float get_radius_y() const { return radius_y; } + // TODOXXX add theta_1,2 void set_length(const float); void set_radius_x(const float); void set_radius_y(const float); protected: - //! Length of the cylinder float length; //! Radius in x-direction if the shape is not rotated @@ -142,14 +128,14 @@ class EllipsoidalCylinder: //! Radius in y-direction if the shape is not rotated float radius_y; //! initial theta if the shape is not rotated (in degrees) - float theta_1; + float theta_1; //! final theta if the shape is not rotated (in degrees) - float theta_2; + float theta_2; //! set defaults before parsing /*! sets radii and length to 0, theta_1=0, theta_2=360 and calls Shape3DWithOrientation::set_defaults() */ - virtual void set_defaults(); - virtual void initialise_keymap(); + virtual void set_defaults(); + virtual void initialise_keymap(); virtual bool post_processing(); }; diff --git a/src/include/stir/Shape/EllipsoidalCylinder.inl b/src/include/stir/Shape/EllipsoidalCylinder.inl index d0a68d7514..758b3cb080 100644 --- a/src/include/stir/Shape/EllipsoidalCylinder.inl +++ b/src/include/stir/Shape/EllipsoidalCylinder.inl @@ -27,18 +27,17 @@ */ START_NAMESPACE_STIR -float EllipsoidalCylinder:: get_geometric_volume()const - { - return (radius_a*radius_b*_PI*length); - } - -Shape3D* EllipsoidalCylinder:: clone() const -{ - return static_cast(new EllipsoidalCylinder(*this)); +float +EllipsoidalCylinder::get_geometric_volume() const { + return (radius_a * radius_b * _PI * length); } -void -EllipsoidalCylinder::scale(const CartesianCoordinate3D& scale3D) -{ + +Shape3D* +EllipsoidalCylinder::clone() const { + return static_cast(new EllipsoidalCylinder(*this)); +} +void +EllipsoidalCylinder::scale(const CartesianCoordinate3D& scale3D) { origin *= scale3D; length *= scale3D.z(); radius_b *= scale3D.y(); diff --git a/src/include/stir/Shape/Shape3D.h b/src/include/stir/Shape/Shape3D.h index f9b8e46956..a836ba4bb5 100644 --- a/src/include/stir/Shape/Shape3D.h +++ b/src/include/stir/Shape/Shape3D.h @@ -35,8 +35,8 @@ START_NAMESPACE_STIR -template class VoxelsOnCartesianGrid; - +template +class VoxelsOnCartesianGrid; /*! \ingroup Shape @@ -47,12 +47,12 @@ template class VoxelsOnCartesianGrid; no fuzzyness). The only derived class where this is relaxed is DiscretisedShape3D. - However, this then needs some special treatment for some member + However, this then needs some special treatment for some member functions, and you have to be somewhat careful with that class. \todo This could/should be generalised to allow general fuzzy shapes. Probably the only thing to change is to let is_inside_shape() return - a float (between 0 and 1). This would solve some issues with + a float (between 0 and 1). This would solve some issues with DiscretisedDhape3D. \todo The restriction to the 3D case for this base class largely comes @@ -70,29 +70,24 @@ template class VoxelsOnCartesianGrid; origin (in mm):= ;defaults to {0,0,0} \endverbatim */ -class Shape3D : - public RegisteredObject -{ +class Shape3D : public RegisteredObject { public: - - virtual ~Shape3D() {} - + //! Compare shapes /*! \par Implementation note - + This virtual function has to be implemented in each final class of the hierarchy. However, Shape3D::operator== has an implementation that checks equality of the origin (up-to a tolerance of .001). Derived classes can call this implementation. */ - virtual - inline bool operator==(const Shape3D&) const = 0; + virtual inline bool operator==(const Shape3D&) const = 0; //! Compare shapes inline bool operator!=(const Shape3D&) const; - /*! + /*! \brief Determine (approximately) the intersection volume of a voxel with the shape. \param voxel_centre is a cartesian coordinate in 'absolute' coordinates, @@ -105,36 +100,33 @@ class Shape3D : In the Shape3D implementation, this is simply done by calling is_inside_shape() at various points in the voxel, and returning - the average value. Obviously, this will only approximate the + the average value. Obviously, this will only approximate the intersection volume for very large \a num_samples, or when the voxel is completely inside the shape. */ - virtual float get_voxel_weight( - const CartesianCoordinate3D& voxel_centre, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& num_samples) const; - - + virtual float get_voxel_weight(const CartesianCoordinate3D& voxel_centre, const CartesianCoordinate3D& voxel_size, + const CartesianCoordinate3D& num_samples) const; + //! determine if a point is inside the shape or not (up to floating point errors) - /*! + /*! \param coord is a cartesian coordinate in 'absolute' coordinates, i.e. in mm and not relative to the \a origin member. - - This is really only well defined for shapes with sharp boundaries. + + This is really only well defined for shapes with sharp boundaries. \see DiscretisedShape3D::is_inside_shape for some discussion. \todo replace by floating point return value? */ virtual bool is_inside_shape(const CartesianCoordinate3D& coord) const = 0; - - //! translate the whole shape by shifting its origin + + //! translate the whole shape by shifting its origin /*! Uses set_origin(). \see scale() */ virtual void translate(const CartesianCoordinate3D& direction); - //! scale the whole shape - /*! - Scaling the shape also shifts the origin of the shape: + //! scale the whole shape + /*! + Scaling the shape also shifts the origin of the shape: new_origin = old_origin * scale3D. This is necessary such that combined shapes keep their correct relative positions. This means that scaling and translating is non-commutative. @@ -147,10 +139,10 @@ class Shape3D : \endcode */ virtual void scale(const CartesianCoordinate3D& scale3D) = 0; - + //! scale the whole shape, keeping the centre at the same place inline void scale_around_origin(const CartesianCoordinate3D& scale3D); - + /*! \brief construct an image representation the shape in a discretised manner @@ -165,12 +157,12 @@ class Shape3D : (but that's rather hard) \todo Potentially this should fill a DiscretisedShape3D. */ - virtual void construct_volume(VoxelsOnCartesianGrid &image, const CartesianCoordinate3D& num_samples) const; - //virtual void construct_slice(PixelsOnCartesianGrid &plane, const CartesianCoordinate3D& num_samples) const; + virtual void construct_volume(VoxelsOnCartesianGrid& image, const CartesianCoordinate3D& num_samples) const; + // virtual void construct_slice(PixelsOnCartesianGrid &plane, const CartesianCoordinate3D& num_samples) const; //! Compute approximate volume - /*! As this is not possible/easy for all shapes, the default implementation - returns a negative number. The user should check this to see if the returned + /*! As this is not possible/easy for all shapes, the default implementation + returns a negative number. The user should check this to see if the returned value makes sense. */ virtual float get_geometric_volume() const; @@ -182,17 +174,16 @@ class Shape3D : */ virtual float get_geometric_area() const; #endif - - //TODO get_bounding_box() const; + + // TODO get_bounding_box() const; //! get the origin of the shape-coordinate system inline CartesianCoordinate3D get_origin() const; //! set the origin of the shape-coordinate system virtual void set_origin(const CartesianCoordinate3D&); - + //! Allocate a new Shape3D object which is a copy of the current one. virtual Shape3D* clone() const = 0; - // need to overload this to avoid ambiguity between Object::parameter_info and ParsingObject::parameter_info() virtual std::string parameter_info(); @@ -203,13 +194,12 @@ class Shape3D : //! \name Parsing functions //@{ - virtual void set_defaults(); + virtual void set_defaults(); virtual void initialise_keymap(); //@} private: //! origin of the shape CartesianCoordinate3D origin; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/Shape/Shape3D.inl b/src/include/stir/Shape/Shape3D.inl index df591cd9e8..ee90a0e499 100644 --- a/src/include/stir/Shape/Shape3D.inl +++ b/src/include/stir/Shape/Shape3D.inl @@ -28,42 +28,32 @@ START_NAMESPACE_STIR -Shape3D::Shape3D() -: origin(0,0,0) -{} +Shape3D::Shape3D() : origin(0, 0, 0) {} -Shape3D::Shape3D(const CartesianCoordinate3D& origin) -: origin(origin) -{} +Shape3D::Shape3D(const CartesianCoordinate3D& origin) : origin(origin) {} bool -Shape3D:: -operator==(const Shape3D& s) const -{ +Shape3D::operator==(const Shape3D& s) const { return norm(this->origin - s.origin) < .001F; } - bool -Shape3D:: -operator!=(const Shape3D& s) const -{ +Shape3D::operator!=(const Shape3D& s) const { return !(*this == s); } - -void -Shape3D::scale_around_origin(const CartesianCoordinate3D& scale3D) -{ + +void +Shape3D::scale_around_origin(const CartesianCoordinate3D& scale3D) { CartesianCoordinate3D old_origin = get_origin(); translate(old_origin * (-1)); scale(scale3D); translate(old_origin); - assert((norm(get_origin())==0 && norm(old_origin)==0)|| - norm(get_origin() - old_origin) < norm(get_origin())*10E-5); + assert((norm(get_origin()) == 0 && norm(old_origin) == 0) || norm(get_origin() - old_origin) < norm(get_origin()) * 10E-5); } - -CartesianCoordinate3D Shape3D::get_origin() const -{ return origin; } +CartesianCoordinate3D +Shape3D::get_origin() const { + return origin; +} END_NAMESPACE_STIR diff --git a/src/include/stir/Shape/Shape3DWithOrientation.h b/src/include/stir/Shape/Shape3DWithOrientation.h index a9d1998ec7..2da80d9482 100644 --- a/src/include/stir/Shape/Shape3DWithOrientation.h +++ b/src/include/stir/Shape/Shape3DWithOrientation.h @@ -47,7 +47,7 @@ class Succeeded; in the calculation as matrix_multiply(direction_vectors, coord-origin), or best practice is to call transform_to_shape_coords(coords). - \todo A previous release had Euler angle code. However, it is currently disabled as + \todo A previous release had Euler angle code. However, it is currently disabled as there were bugs in it. \par Parameters @@ -63,19 +63,16 @@ class Succeeded; */ -class Shape3DWithOrientation: public Shape3D -{ +class Shape3DWithOrientation : public Shape3D { typedef Shape3D base_type; public: - bool operator==(const Shape3DWithOrientation& s) const; virtual void scale(const CartesianCoordinate3D& scale3D); //! get direction vectors currently in use /*! Index offsets will always be 1 */ - const Array<2,float>& get_direction_vectors() const - { return _directions; } + const Array<2, float>& get_direction_vectors() const { return _directions; } //! set direction vectors /*! Any index offset will be accepted. @@ -83,7 +80,7 @@ class Shape3DWithOrientation: public Shape3D Note that scaling the direction vectors is equivalent to a call to scale_around_origin() */ - Succeeded set_direction_vectors(const Array<2,float>&); + Succeeded set_direction_vectors(const Array<2, float>&); #if 0 // TODO non-sensical after non-uniform scale @@ -93,20 +90,18 @@ class Shape3DWithOrientation: public Shape3D #endif protected: - //! default constructor (NO initialisation of values) Shape3DWithOrientation(); - + #if 0 / Shape3DWithOrientation(const CartesianCoordinate3D& origin, const float alpha, const float beta, const float gamma); -#endif - Shape3DWithOrientation(const CartesianCoordinate3D& origin, - const Array<2,float>& directions = diagonal_matrix(3,1.F)); - +#endif + Shape3DWithOrientation(const CartesianCoordinate3D& origin, const Array<2, float>& directions = diagonal_matrix(3, 1.F)); + #if 0 void set_directions_from_Euler_angles( @@ -120,12 +115,11 @@ class Shape3DWithOrientation: public Shape3D float get_volume_of_unit_cell() const; //! Transform a 'real-world' coordinate to the coordinate system used by the shape - CartesianCoordinate3D - transform_to_shape_coords(const CartesianCoordinate3D&) const; + CartesianCoordinate3D transform_to_shape_coords(const CartesianCoordinate3D&) const; //! sets defaults for parsing /*! sets direction vectors to the normal unit vectors. */ - virtual void set_defaults(); + virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); virtual void set_key_values(); @@ -138,11 +132,9 @@ class Shape3DWithOrientation: public Shape3D float gamma_in_degrees; #endif - Array<2,float> _directions; - + Array<2, float> _directions; }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir/Sinogram.h b/src/include/stir/Sinogram.h index 5387c62744..f03693820a 100644 --- a/src/include/stir/Sinogram.h +++ b/src/include/stir/Sinogram.h @@ -34,32 +34,27 @@ #ifndef __Sinogram_h__ #define __Sinogram_h__ - #include "stir/Array.h" -#include "stir/ProjDataInfo.h" +#include "stir/ProjDataInfo.h" #include "stir/shared_ptr.h" - - - START_NAMESPACE_STIR /*! \ingroup projdata \brief A class for 2d projection data. - This represents a subset of the full projection. segment_num and axial_pos_num + This represents a subset of the full projection. segment_num and axial_pos_num are fixed. - + */ template -class Sinogram : public Array<2,elemT> -{ +class Sinogram : public Array<2, elemT> { private: - typedef Array<2,elemT> base_type; + typedef Array<2, elemT> base_type; #ifdef SWIG // SWIG needs the next typedef to be public -public: +public: #endif typedef Sinogram self_type; #ifdef SWIG @@ -69,17 +64,19 @@ class Sinogram : public Array<2,elemT> public: //! Construct sinogram from proj_data_info pointer, ring and segment number. Data are set to 0. - inline Sinogram(const shared_ptr& proj_data_info_ptr, - const int ax_pos_num, const int segment_num); + inline Sinogram(const shared_ptr& proj_data_info_ptr, const int ax_pos_num, const int segment_num, + const int timing_pos_num = 0); //! Construct sinogram with data set to the array. - inline Sinogram(const Array<2,elemT>& p,const shared_ptr& proj_data_info_ptr, - const int ax_pos_num, const int segment_num); - + inline Sinogram(const Array<2, elemT>& p, const shared_ptr& proj_data_info_ptr, const int ax_pos_num, + const int segment_num, const int timing_pos_num = 0); + //! Get segment number - inline int get_segment_num() const; + inline int get_segment_num() const; //! Get number of axial positions inline int get_axial_pos_num() const; + //! Get timing position index + inline int get_timing_pos_num() const; //! Get minimum view number inline int get_min_view_num() const; //! Get maximum view number @@ -92,20 +89,19 @@ class Sinogram : public Array<2,elemT> inline int get_max_tangential_pos_num() const; //! Get number of tangential positions inline int get_num_tangential_poss() const; - + //! Get an empty sinogram of the same dimensions, segment_num etc. inline Sinogram get_empty_copy(void) const; - + //! Overloading Array::grow void grow(const IndexRange<2>& range); //! Overloading Array::resize void resize(const IndexRange<2>& range); //! Get shared pointer to proj data info - inline shared_ptr - get_proj_data_info_sptr() const; + inline shared_ptr get_proj_data_info_sptr() const; - //inline Sinogram operator = (const Sinogram &s) const; + // inline Sinogram operator = (const Sinogram &s) const; //! \name Equality //@{ @@ -113,33 +109,29 @@ class Sinogram : public Array<2,elemT> /*! If they do \c not have the same characteristics, the string \a explanation explains why. */ - bool - has_same_characteristics(self_type const&, - std::string& explanation) const; + bool has_same_characteristics(self_type const&, std::string& explanation) const; //! Checks if the 2 objects have the proj_data_info, segment_num etc. /*! Use this version if you do not need to know why they do not match. */ - bool - has_same_characteristics(self_type const&) const; + bool has_same_characteristics(self_type const&) const; //! check equality (data has to be identical) /*! Uses has_same_characteristics() and Array::operator==. - \warning This function uses \c ==, which might not be what you + \warning This function uses \c ==, which might not be what you need to check when \c elemT has data with float or double numbers. */ - bool operator ==(const self_type&) const; - + bool operator==(const self_type&) const; + //! negation of operator== - bool operator !=(const self_type&) const; + bool operator!=(const self_type&) const; //@} - + private: - - shared_ptr proj_data_info_ptr; + shared_ptr proj_data_info_ptr; int axial_pos_num; int segment_num; - + int timing_pos_num; }; END_NAMESPACE_STIR diff --git a/src/include/stir/Sinogram.inl b/src/include/stir/Sinogram.inl index 63b473e5ac..f95edddf9f 100644 --- a/src/include/stir/Sinogram.inl +++ b/src/include/stir/Sinogram.inl @@ -35,104 +35,95 @@ START_NAMESPACE_STIR - template int -Sinogram::get_segment_num() const -{ return segment_num; } +Sinogram::get_segment_num() const { + return segment_num; +} template int -Sinogram::get_axial_pos_num() const -{ return axial_pos_num; } +Sinogram::get_axial_pos_num() const { + return axial_pos_num; +} template int -Sinogram::get_min_view_num() const - {return this->get_min_index();} +Sinogram::get_timing_pos_num() const { + return timing_pos_num; +} template int -Sinogram::get_max_view_num() const - { return this->get_max_index(); } +Sinogram::get_min_view_num() const { + return this->get_min_index(); +} template int -Sinogram::get_num_views() const - { return this->get_length();} +Sinogram::get_max_view_num() const { + return this->get_max_index(); +} template int -Sinogram::get_num_tangential_poss()const - { return this->get_length()==0 ? 0 : (*this)[get_min_view_num()].get_length();} +Sinogram::get_num_views() const { + return this->get_length(); +} template int -Sinogram::get_min_tangential_pos_num() const - { return this->get_length()==0 ? 0 :(*this)[get_min_view_num()].get_min_index();} +Sinogram::get_num_tangential_poss() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()].get_length(); +} template int -Sinogram::get_max_tangential_pos_num() const -{ return this->get_length()==0 ? 0 :(*this)[get_min_view_num()].get_max_index(); } - +Sinogram::get_min_tangential_pos_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()].get_min_index(); +} +template +int +Sinogram::get_max_tangential_pos_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()].get_max_index(); +} template Sinogram -Sinogram::get_empty_copy(void) const -{ - Sinogram copy(proj_data_info_ptr, get_axial_pos_num(), get_segment_num()); - return copy; +Sinogram::get_empty_copy(void) const { + Sinogram copy(proj_data_info_ptr, get_axial_pos_num(), get_segment_num(), get_timing_pos_num()); + return copy; } template shared_ptr -Sinogram::get_proj_data_info_sptr() const -{ +Sinogram::get_proj_data_info_sptr() const { return proj_data_info_ptr; } template -Sinogram:: -Sinogram(const Array<2,elemT>& p, - const shared_ptr& pdi_ptr, - const int ax_pos_num, const int s_num) - : - Array<2,elemT>(p), - proj_data_info_ptr(pdi_ptr), - axial_pos_num(ax_pos_num), - segment_num(s_num) -{ +Sinogram::Sinogram(const Array<2, elemT>& p, const shared_ptr& pdi_ptr, const int ax_pos_num, + const int s_num, const int t_num) + : Array<2, elemT>(p), proj_data_info_ptr(pdi_ptr), axial_pos_num(ax_pos_num), segment_num(s_num), timing_pos_num(t_num) { assert(axial_pos_num <= proj_data_info_ptr->get_max_axial_pos_num(segment_num)); assert(axial_pos_num >= proj_data_info_ptr->get_min_axial_pos_num(segment_num)); // segment_num is already checked by doing get_max_axial_pos_num(s_num) - assert( get_min_view_num() == pdi_ptr->get_min_view_num()); - assert( get_max_view_num() == pdi_ptr->get_max_view_num()); - assert( get_min_tangential_pos_num() == pdi_ptr->get_min_tangential_pos_num()); - assert( get_max_tangential_pos_num() == pdi_ptr->get_max_tangential_pos_num()); + assert(get_min_view_num() == pdi_ptr->get_min_view_num()); + assert(get_max_view_num() == pdi_ptr->get_max_view_num()); + assert(get_min_tangential_pos_num() == pdi_ptr->get_min_tangential_pos_num()); + assert(get_max_tangential_pos_num() == pdi_ptr->get_max_tangential_pos_num()); } - - template -Sinogram:: -Sinogram(const shared_ptr& pdi_ptr, - const int ax_pos_num, const int s_num) - : - Array<2,elemT>(IndexRange2D (pdi_ptr->get_min_view_num(), - pdi_ptr->get_max_view_num(), - pdi_ptr->get_min_tangential_pos_num(), - pdi_ptr->get_max_tangential_pos_num())), - proj_data_info_ptr(pdi_ptr), - axial_pos_num(ax_pos_num), - segment_num(s_num) -{ +Sinogram::Sinogram(const shared_ptr& pdi_ptr, const int ax_pos_num, const int s_num, const int t_num) + : Array<2, elemT>(IndexRange2D(pdi_ptr->get_min_view_num(), pdi_ptr->get_max_view_num(), + pdi_ptr->get_min_tangential_pos_num(), pdi_ptr->get_max_tangential_pos_num())), + proj_data_info_ptr(pdi_ptr), axial_pos_num(ax_pos_num), segment_num(s_num), timing_pos_num(t_num) { assert(axial_pos_num <= proj_data_info_ptr->get_max_axial_pos_num(segment_num)); assert(axial_pos_num >= proj_data_info_ptr->get_min_axial_pos_num(segment_num)); // segment_num is already checked by doing get_max_axial_pos_num(s_num) } - END_NAMESPACE_STIR diff --git a/src/include/stir/StirException.h b/src/include/stir/StirException.h index 1d3a76d351..f66931c1de 100644 --- a/src/include/stir/StirException.h +++ b/src/include/stir/StirException.h @@ -8,35 +8,27 @@ class StirException : public std::exception { public: - StirException(const char* reason, const char* file, int line) { - size_t len = strlen(reason) + 1; - _reason = new char[len]; - memcpy(_reason, reason, len); - len = strlen(file) + 1; - _file = new char[len]; - memcpy(_file, file, len); - _line = line; - } - virtual ~StirException() throw() { - delete[] _reason; - delete[] _file; - } - virtual const char* what() const throw() - { - return _reason; - } - const char* file() const throw() - { - return _file; - } - int line() const throw() { - return _line; - } + StirException(const char* reason, const char* file, int line) { + size_t len = strlen(reason) + 1; + _reason = new char[len]; + memcpy(_reason, reason, len); + len = strlen(file) + 1; + _file = new char[len]; + memcpy(_file, file, len); + _line = line; + } + virtual ~StirException() throw() { + delete[] _reason; + delete[] _file; + } + virtual const char* what() const throw() { return _reason; } + const char* file() const throw() { return _file; } + int line() const throw() { return _line; } + private: - char* _reason; - char* _file; - int _line; + char* _reason; + char* _file; + int _line; }; #endif - diff --git a/src/include/stir/Succeeded.h b/src/include/stir/Succeeded.h index 4cd61e0d3b..7360cbde04 100644 --- a/src/include/stir/Succeeded.h +++ b/src/include/stir/Succeeded.h @@ -34,9 +34,9 @@ START_NAMESPACE_STIR -/*! - \brief - a class containing an enumeration type that can be used by functions to signal +/*! + \brief + a class containing an enumeration type that can be used by functions to signal successful operation or not Example: @@ -45,13 +45,13 @@ START_NAMESPACE_STIR void g() { if (f() == Succeeded::no) error("Error calling f"); } \endcode */ -class Succeeded -{ +class Succeeded { public: enum value { yes, no }; Succeeded(const value& v) : v(v) {} - bool operator==(const Succeeded &v2) const { return v == v2.v; } - bool operator!=(const Succeeded &v2) const { return v != v2.v; } + bool operator==(const Succeeded& v2) const { return v == v2.v; } + bool operator!=(const Succeeded& v2) const { return v != v2.v; } + private: value v; }; diff --git a/src/include/stir/TextWriter.h b/src/include/stir/TextWriter.h index 2244446abb..1cd7eda645 100644 --- a/src/include/stir/TextWriter.h +++ b/src/include/stir/TextWriter.h @@ -13,107 +13,94 @@ START_NAMESPACE_STIR -enum OUTPUT_CHANNEL {INFORMATION_CHANNEL, WARNING_CHANNEL, ERROR_CHANNEL}; +enum OUTPUT_CHANNEL { INFORMATION_CHANNEL, WARNING_CHANNEL, ERROR_CHANNEL }; class aTextWriter { public: - virtual ~aTextWriter() {} - virtual void write(const char* text) const = 0; + virtual ~aTextWriter() {} + virtual void write(const char* text) const = 0; }; class TextPrinter : public aTextWriter { public: - TextPrinter(const char* s = 0) : _stream(0) { - if (s) { - if (strcmp(s, "stdout") == 0 || strcmp(s, "cout") == 0) - _stream = 1; - else if (strcmp(s, "stderr") == 0 || strcmp(s, "cerr") == 0) - _stream = 2; - } - } - virtual void write(const char* text) const { - switch (_stream) { - case 1: - std::cout << text; - break; - case 2: - std::cerr << text; - break; - default: - DEFAULT_STREAM << text; - } - } + TextPrinter(const char* s = 0) : _stream(0) { + if (s) { + if (strcmp(s, "stdout") == 0 || strcmp(s, "cout") == 0) + _stream = 1; + else if (strcmp(s, "stderr") == 0 || strcmp(s, "cerr") == 0) + _stream = 2; + } + } + virtual void write(const char* text) const { + switch (_stream) { + case 1: + std::cout << text; + break; + case 2: + std::cerr << text; + break; + default: + DEFAULT_STREAM << text; + } + } + private: - int _stream; + int _stream; }; class TextWriter : public aTextWriter { public: - std::ostream* out; - TextWriter(std::ostream* os = 0) : out(os) {} - virtual void write(const char* text) const { - if (out) { - (*out) << text; - (*out).flush(); - } - } + std::ostream* out; + TextWriter(std::ostream* os = 0) : out(os) {} + virtual void write(const char* text) const { + if (out) { + (*out) << text; + (*out).flush(); + } + } }; class TextWriterHandle { public: - TextWriterHandle() { - init_(); - } - void set_information_channel(aTextWriter* info) { - information_channel_ = info; - } - void* information_channel_ptr() { - return (void*)information_channel_; - } - void set_warning_channel(aTextWriter* warn) { - warning_channel_ = warn; - } - void* warning_channel_ptr() { - return (void*)warning_channel_; - } - void set_error_channel(aTextWriter* errr) { - error_channel_ = errr; - } - void* error_channel_ptr() { - return (void*)error_channel_; - } - void print_information(const char* text) { - if (information_channel_) - information_channel_->write(text); - else - std::cout << text; - } - void print_warning(const char* text) { - if (warning_channel_) - warning_channel_->write(text); - else - std::cerr << text; - } - void print_error(const char* text) { - if (error_channel_) - error_channel_->write(text); - else - std::cerr << text; - } + TextWriterHandle() { init_(); } + void set_information_channel(aTextWriter* info) { information_channel_ = info; } + void* information_channel_ptr() { return (void*)information_channel_; } + void set_warning_channel(aTextWriter* warn) { warning_channel_ = warn; } + void* warning_channel_ptr() { return (void*)warning_channel_; } + void set_error_channel(aTextWriter* errr) { error_channel_ = errr; } + void* error_channel_ptr() { return (void*)error_channel_; } + void print_information(const char* text) { + if (information_channel_) + information_channel_->write(text); + else + std::cout << text; + } + void print_warning(const char* text) { + if (warning_channel_) + warning_channel_->write(text); + else + std::cerr << text; + } + void print_error(const char* text) { + if (error_channel_) + error_channel_->write(text); + else + std::cerr << text; + } private: - static aTextWriter* information_channel_; - static aTextWriter* warning_channel_; - static aTextWriter* error_channel_; - static void init_() { - static bool initialized = false; - if (!initialized) { - information_channel_ = 0; - warning_channel_ = 0; - error_channel_ = 0; - initialized = true; - } - } + static aTextWriter* information_channel_; + static aTextWriter* warning_channel_; + static aTextWriter* error_channel_; + static void init_() { + static bool initialized = false; + if (!initialized) { + information_channel_ = 0; + warning_channel_ = 0; + error_channel_ = 0; + initialized = true; + } + } }; void writeText(const char* text, OUTPUT_CHANNEL channel = INFORMATION_CHANNEL); diff --git a/src/include/stir/ThresholdMinToSmallPositiveValueDataProcessor.h b/src/include/stir/ThresholdMinToSmallPositiveValueDataProcessor.h index fde052d801..4b5ec38a0a 100644 --- a/src/include/stir/ThresholdMinToSmallPositiveValueDataProcessor.h +++ b/src/include/stir/ThresholdMinToSmallPositiveValueDataProcessor.h @@ -19,30 +19,28 @@ /*! \file - \ingroup DataProcessor + \ingroup DataProcessor \brief Declaration of class stir::ThresholdMinToSmallPositiveValueDataProcessor - + \author Kris Thielemans - + */ #ifndef __stir_ThresholdMinToSmallPositiveValueDataProcessor_H__ #define __stir_ThresholdMinToSmallPositiveValueDataProcessor_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/DataProcessor.h" - START_NAMESPACE_STIR /*! - \ingroup DataProcessor + \ingroup DataProcessor \brief A class in the DataProcessor hierarchy for making sure all elements are strictly positive. Works by calling threshold_min_to_small_positive_value(). - - As it is derived from RegisteredParsingObject, it implements all the + + As it is derived from RegisteredParsingObject, it implements all the necessary things to parse parameter files etc. \par Parsing parameters @@ -59,46 +57,32 @@ START_NAMESPACE_STIR */ template -class ThresholdMinToSmallPositiveValueDataProcessor : - public - RegisteredParsingObject< - ThresholdMinToSmallPositiveValueDataProcessor, - DataProcessor, - DataProcessor - > -{ +class ThresholdMinToSmallPositiveValueDataProcessor + : public RegisteredParsingObject, DataProcessor, + DataProcessor> { private: - typedef - RegisteredParsingObject< - ThresholdMinToSmallPositiveValueDataProcessor, - DataProcessor, - DataProcessor - > - base_type; + typedef RegisteredParsingObject, DataProcessor, + DataProcessor> + base_type; + public: - static const char * const registered_name; - + static const char* const registered_name; + //! Construct by calling set_defaults() ThresholdMinToSmallPositiveValueDataProcessor(); - - + private: - int rim_truncation_image; - + virtual void set_defaults(); virtual void initialise_keymap(); - + Succeeded virtual_set_up(const DataT&); - void virtual_apply(DataT& out_data, const DataT& in_data) const; - void virtual_apply(DataT& data) const ; - + void virtual_apply(DataT& out_data, const DataT& in_data) const; + void virtual_apply(DataT& data) const; }; - END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/TimeFrameDefinitions.h b/src/include/stir/TimeFrameDefinitions.h index 7d76b93cca..57fccc02b0 100644 --- a/src/include/stir/TimeFrameDefinitions.h +++ b/src/include/stir/TimeFrameDefinitions.h @@ -18,9 +18,9 @@ /*! \file - \ingroup buildblock + \ingroup buildblock \brief Declaration of class stir::TimeFrameDefinitions - + \author Kris Thielemans */ #ifndef __stir_TimeFrameDefinitions_H__ @@ -43,14 +43,13 @@ START_NAMESPACE_STIR Currently this class can read frame info from an ECAT6, ECAT7 and a 'frame definition' file. See the documentation for the constructor. */ -class TimeFrameDefinitions -{ +class TimeFrameDefinitions { public: //! Default constructor: no time frames at all TimeFrameDefinitions(); //! Read the frame definitions from a file - /*! + /*! \deprecated The filename can point to an ECAT6 file, and ECAT7 file (if you have installed the LLN library), an Interfile file, or a simple ASCII text file. @@ -62,22 +61,22 @@ class TimeFrameDefinitions \endverbatim This duration is a double number. - This class in fact allows an extension of the above. Setting + This class in fact allows an extension of the above. Setting \a num_frames_of_this_duration to 0 allows skipping a time period of the corresponding \a duration_in_secs. */ explicit TimeFrameDefinitions(const std::string& fdef_filename); - + //! Construct from a list of time frames /*! Each frame is specified as a std::pair with start and end time (in seconds). Start times have to be in increasing order*/ - TimeFrameDefinitions(const std::vector >&); + TimeFrameDefinitions(const std::vector>&); //! Construct from a list of start times and durations /*! start times have to be in increasing order*/ TimeFrameDefinitions(const std::vector& start_times, const std::vector& durations); - //! Construct from a single time frame of an existing object + //! Construct from a single time frame of an existing object TimeFrameDefinitions(const TimeFrameDefinitions&, unsigned int frame_num); //! \name get info for 1 frame (frame_num is 1 based) @@ -96,25 +95,24 @@ class TimeFrameDefinitions unsigned int get_num_frames() const; //! Get number of frames unsigned int get_num_time_frames() const; - + //! Get the frame number associated with a frame starting and start_time and ending at end_time. /*! \return frame number (between 1 and get_num_time_frames()) or 0 if frame not found. */ - unsigned int get_time_frame_num(const double start_time, const double end_time) const; + unsigned int get_time_frame_num(const double start_time, const double end_time) const; + + //! Set number of time frames + void set_num_time_frames(int num_time_frames) { frame_times.resize(num_time_frames); } - //! Set number of time frames - void set_num_time_frames(int num_time_frames) { frame_times.resize(num_time_frames); } + //! Set time frame + void set_time_frame(const int frame_num, const double start, const double end); - //! Set time frame - void set_time_frame(const int frame_num, const double start, const double end); - - bool operator == (const TimeFrameDefinitions &t) const; + bool operator==(const TimeFrameDefinitions& t) const; private: //! Stores start and end time for each frame - std::vector > frame_times; - void read_fdef_file(const std::string& filename); - + std::vector> frame_times; + void read_fdef_file(const std::string& filename); }; END_NAMESPACE_STIR diff --git a/src/include/stir/TimeGateDefinitions.h b/src/include/stir/TimeGateDefinitions.h index a442045cf7..43517708b9 100644 --- a/src/include/stir/TimeGateDefinitions.h +++ b/src/include/stir/TimeGateDefinitions.h @@ -3,29 +3,29 @@ Copyright (C) 2000- 2008, Hammersmith Imanet Ltd Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details - */ + */ /*! \file - \ingroup buildblock + \ingroup buildblock \brief Declaration of class stir::TimeGateDefinitions - + \author Charalampos Tsoumpas \author Kris Thielemans - + \todo This files needs proper test - + */ #ifndef __stir_TimeGateDefinitions_H__ #define __stir_TimeGateDefinitions_H__ @@ -47,18 +47,16 @@ START_NAMESPACE_STIR Will probably be superseded by Study classes. */ -class TimeGateDefinitions -{ - public: +class TimeGateDefinitions { +public: //! Default constructor: no time gates at all TimeGateDefinitions(); - TimeGateDefinitions(const std::vector& gate_num_vector, - const std::vector& duration_vector); - TimeGateDefinitions(const std::vector >& gate_sequence); + TimeGateDefinitions(const std::vector& gate_num_vector, const std::vector& duration_vector); + TimeGateDefinitions(const std::vector>& gate_sequence); explicit TimeGateDefinitions(const std::string& gdef_filename); //! Read the gate definitions from a file - /*! + /*! The filename can point to a simple ASCII text file. The format is a number of lines, each existing of 2 numbers \verbatim @@ -66,7 +64,7 @@ class TimeGateDefinitions \endverbatim This duration is a double number. - This class in fact allows an extension of the above. Setting + This class in fact allows an extension of the above. Setting \a gate_num_of_this_duration to 0 allows skipping a time period of the corresponding \a duration_in_secs. */ @@ -75,7 +73,7 @@ class TimeGateDefinitions //! \name get info for a gate //@{ double get_gate_duration(unsigned int num) const; - unsigned int get_gate_num(unsigned int num) const; + unsigned int get_gate_num(unsigned int num) const; //@} @@ -84,9 +82,9 @@ class TimeGateDefinitions //! Get number of gates unsigned int get_num_time_gates() const; - private: +private: //! Stores start and end time for each gate - std::vector > _gate_sequence; + std::vector> _gate_sequence; }; END_NAMESPACE_STIR diff --git a/src/include/stir/TimedBlock.h b/src/include/stir/TimedBlock.h index f7a34e4c30..31cd493f9c 100644 --- a/src/include/stir/TimedBlock.h +++ b/src/include/stir/TimedBlock.h @@ -18,7 +18,7 @@ */ /*! - \file + \file \ingroup buildblock \brief Class stir::TimedBlock @@ -31,74 +31,66 @@ #define _stir_TimedBlock_H_ namespace stir { - class Timer; +class Timer; - /*! \brief Helper class for measuring execution time of a block of code. - \ingroup buildblock +/*! \brief Helper class for measuring execution time of a block of code. +\ingroup buildblock - It starts the timer in ctor, stops in dtor. - Do not create unnamed instances of this class, as they are quite - useless: you cannot predict destruction time. +It starts the timer in ctor, stops in dtor. +Do not create unnamed instances of this class, as they are quite +useless: you cannot predict destruction time. - \par Usage: +\par Usage: - \code +\code - SomeTimer t; - // do whatever you want here - { - TimedBlock tb(t); - do_something_1(); - do_something_2(); - }; - // do whatever you want here - { - TimedBlock tb(t); - do_something_3(); - }; - // do whatever you want here - cout << "It took " << t.GetTime() << "sec to execute do_something_1..3()" << endl; +SomeTimer t; +// do whatever you want here +{ +TimedBlock tb(t); +do_something_1(); +do_something_2(); +}; +// do whatever you want here +{ +TimedBlock tb(t); +do_something_3(); +}; +// do whatever you want here +cout << "It took " << t.GetTime() << "sec to execute do_something_1..3()" << endl; - \endcode +\endcode - \par Template argument requirements +\par Template argument requirements - \c TimerT has to have a start() and stop() member function. This is the case for - stir::Timer (and derived functions) and stir::HighResWallClockTimer. - */ - template - class TimedBlock - { - public: - - //! Create a timed block - inline TimedBlock(TimerT& Timer); - //! Destroy a timed block - inline virtual ~TimedBlock(void); - - protected: - private: - - TimedBlock(const TimedBlock&); // Not defined - TimedBlock& operator=(const TimedBlock&); // Not defined - - TimerT& m_Timer; - - }; - - - template - TimedBlock::TimedBlock(TimerT& timer) - : m_Timer(timer) - { - m_Timer.start(); - } +\c TimerT has to have a start() and stop() member function. This is the case for +stir::Timer (and derived functions) and stir::HighResWallClockTimer. +*/ +template +class TimedBlock { +public: + //! Create a timed block + inline TimedBlock(TimerT& Timer); + //! Destroy a timed block + inline virtual ~TimedBlock(void); + +protected: +private: + TimedBlock(const TimedBlock&); // Not defined + TimedBlock& operator=(const TimedBlock&); // Not defined + + TimerT& m_Timer; +}; + +template +TimedBlock::TimedBlock(TimerT& timer) : m_Timer(timer) { + m_Timer.start(); +} - template - TimedBlock::~TimedBlock(void) - { - m_Timer.stop(); - } +template +TimedBlock::~TimedBlock(void) { + m_Timer.stop(); } +} // namespace stir #endif diff --git a/src/include/stir/TimedObject.h b/src/include/stir/TimedObject.h index 38e082bee4..edb642d2b5 100644 --- a/src/include/stir/TimedObject.h +++ b/src/include/stir/TimedObject.h @@ -1,12 +1,12 @@ #ifndef __TimedObject_H__ #define __TimedObject_H__ /*! - \file + \file \ingroup buildblock - + \brief declares the stir::TimedObject class - \author Kris Thielemans + \author Kris Thielemans \author PARAPET project */ @@ -33,16 +33,14 @@ START_NAMESPACE_STIR /*! \ingroup buildblock - \brief base class for all objects which need timers. + \brief base class for all objects which need timers. At the moment, there's only a CPU timer. - It is the responsibility of the derived class to start and + It is the responsibility of the derived class to start and stop the timer. */ -class TimedObject -{ +class TimedObject { public: - //! reset all timers kept by this object inline void reset_timers(); @@ -62,14 +60,12 @@ class TimedObject inline double get_CPU_timer_value() const; private: - //! A timer that measured CPU time. /*! Note: member is mutable such that it can be modified in a const function. - */ + */ mutable CPUTimer cpu_timer; // TODO include other times (such as wall-clock) - }; END_NAMESPACE_STIR diff --git a/src/include/stir/TimedObject.inl b/src/include/stir/TimedObject.inl index ac3adfe9bc..b51cf8ea82 100644 --- a/src/include/stir/TimedObject.inl +++ b/src/include/stir/TimedObject.inl @@ -30,25 +30,23 @@ START_NAMESPACE_STIR -void TimedObject::reset_timers() -{ +void +TimedObject::reset_timers() { cpu_timer.reset(); } -void TimedObject::start_timers() const -{ +void +TimedObject::start_timers() const { cpu_timer.start(); } - -void TimedObject::stop_timers() const -{ +void +TimedObject::stop_timers() const { cpu_timer.stop(); } - -double TimedObject::get_CPU_timer_value() const -{ +double +TimedObject::get_CPU_timer_value() const { return cpu_timer.value(); } diff --git a/src/include/stir/Timer.h b/src/include/stir/Timer.h index 6aacd5d3ef..244c5da787 100644 --- a/src/include/stir/Timer.h +++ b/src/include/stir/Timer.h @@ -1,4 +1,4 @@ -// +// // /* Copyright (C) 2000 PARAPET partners @@ -54,14 +54,13 @@ START_NAMESPACE_STIR // etc \endcode - Derived classes simply have to implement the virtual function + Derived classes simply have to implement the virtual function double get_current_value() */ -class Timer -{ +class Timer { public: inline Timer(); - inline virtual ~Timer(); + inline virtual ~Timer(); inline void start(); inline void stop(); inline void reset(); @@ -72,13 +71,12 @@ class Timer bool running; double previous_value; double previous_total_value; - + virtual double get_current_value() const = 0; }; END_NAMESPACE_STIR - #include "stir/Timer.inl" #endif // __TIMER_H__ diff --git a/src/include/stir/Timer.inl b/src/include/stir/Timer.inl index 2d86148e6b..169ebb36c0 100644 --- a/src/include/stir/Timer.inl +++ b/src/include/stir/Timer.inl @@ -30,56 +30,50 @@ */ START_NAMESPACE_STIR -Timer::Timer() -{ +Timer::Timer() { running = false; previous_total_value = 0.; - } -Timer::~Timer() -{} +Timer::~Timer() {} -void Timer::start() -{ - if (!running) - { +void +Timer::start() { + if (!running) { running = true; previous_value = get_current_value(); } } -void Timer::stop() -{ - if (running) - { +void +Timer::stop() { + if (running) { previous_total_value += get_current_value() - previous_value; running = false; } } #ifdef OLDDESIGN -void Timer::restart() -{ +void +Timer::restart() { previous_total_value = 0.; running = false; start(); } #endif -void Timer::reset() -{ +void +Timer::reset() { assert(running == false); previous_total_value = 0.; } -double Timer::value() const -{ - double tmp = previous_total_value; +double +Timer::value() const { + double tmp = previous_total_value; if (running) tmp += get_current_value() - previous_value; return tmp; } - END_NAMESPACE_STIR diff --git a/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.h b/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.h index 08e2a625ea..44c527a19b 100644 --- a/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.h +++ b/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.h @@ -42,12 +42,9 @@ START_NAMESPACE_STIR object (e.g. for RelatedViewgrams), but do not need/have projectors. */ -class TrivialDataSymmetriesForViewSegmentNumbers : public DataSymmetriesForViewSegmentNumbers -{ +class TrivialDataSymmetriesForViewSegmentNumbers : public DataSymmetriesForViewSegmentNumbers { public: - - virtual inline DataSymmetriesForViewSegmentNumbers * clone() const; - + virtual inline DataSymmetriesForViewSegmentNumbers* clone() const; #if 0 // TODO @@ -56,23 +53,19 @@ class TrivialDataSymmetriesForViewSegmentNumbers : public DataSymmetriesForViewS get_basic_view_segment_index_range() const; #endif - virtual inline void - get_related_view_segment_numbers(std::vector&, const ViewSegmentNumbers& v_s) const; + virtual inline void get_related_view_segment_numbers(std::vector&, const ViewSegmentNumbers& v_s) const; - virtual inline int - num_related_view_segment_numbers(const ViewSegmentNumbers& v_s) const; + virtual inline int num_related_view_segment_numbers(const ViewSegmentNumbers& v_s) const; /*! \brief given an arbitrary view/segment, find the basic view/segment - + in this class, \a v_s is unchanged, and the return value is always false. 'v_s' is changed (i.e. it was NOT a basic view/segment). - */ - virtual inline bool - find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const; + */ + virtual inline bool find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const; private: - virtual bool blindly_equals(const root_type * const) const; - + virtual bool blindly_equals(const root_type* const) const; }; END_NAMESPACE_STIR @@ -80,4 +73,3 @@ END_NAMESPACE_STIR #include "stir/TrivialDataSymmetriesForViewSegmentNumbers.inl" #endif - diff --git a/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.inl b/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.inl index 5027c880b5..2087b7d526 100644 --- a/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.inl +++ b/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.inl @@ -30,40 +30,29 @@ START_NAMESPACE_STIR DataSymmetriesForViewSegmentNumbers* -TrivialDataSymmetriesForViewSegmentNumbers:: -clone() const -{ +TrivialDataSymmetriesForViewSegmentNumbers::clone() const { return new TrivialDataSymmetriesForViewSegmentNumbers; } - void -TrivialDataSymmetriesForViewSegmentNumbers:: -get_related_view_segment_numbers(std::vector& all, const ViewSegmentNumbers& v_s) const -{ +TrivialDataSymmetriesForViewSegmentNumbers::get_related_view_segment_numbers(std::vector& all, + const ViewSegmentNumbers& v_s) const { all.resize(1); all[0] = v_s; } - int -TrivialDataSymmetriesForViewSegmentNumbers:: -num_related_view_segment_numbers(const ViewSegmentNumbers& v_s) const -{ +TrivialDataSymmetriesForViewSegmentNumbers::num_related_view_segment_numbers(const ViewSegmentNumbers& v_s) const { return 1; } bool -TrivialDataSymmetriesForViewSegmentNumbers:: -find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const -{ +TrivialDataSymmetriesForViewSegmentNumbers::find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const { return false; } -bool -TrivialDataSymmetriesForViewSegmentNumbers:: -blindly_equals(const root_type * const) const -{ +bool +TrivialDataSymmetriesForViewSegmentNumbers::blindly_equals(const root_type* const) const { return true; } diff --git a/src/include/stir/TruncateToCylindricalFOVImageProcessor.h b/src/include/stir/TruncateToCylindricalFOVImageProcessor.h index 56fea5af49..65e13e9dc9 100644 --- a/src/include/stir/TruncateToCylindricalFOVImageProcessor.h +++ b/src/include/stir/TruncateToCylindricalFOVImageProcessor.h @@ -19,11 +19,11 @@ /*! \file - \ingroup ImageProcessor + \ingroup ImageProcessor \brief Declaration of class stir::TruncateToCylindricalFOVImageProcessor - + \author Kris Thielemans - + */ #ifndef __stir_TruncateToCylindricalFOVImageProcessor_H__ @@ -33,68 +33,50 @@ #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" - START_NAMESPACE_STIR - /*! - \ingroup ImageProcessor + \ingroup ImageProcessor \brief A class in the DataProcessor hierarchy that sets voxels to 0 outside a given radius. - - As it is derived from RegisteredParsingObject, it implements all the + + As it is derived from RegisteredParsingObject, it implements all the necessary things to parse parameter files etc. - The discretised densities that will be filtered are supposed to be on a - Cartesian grid. + The discretised densities that will be filtered are supposed to be on a + Cartesian grid. */ template -class TruncateToCylindricalFOVImageProcessor : - public - RegisteredParsingObject< - TruncateToCylindricalFOVImageProcessor, - DataProcessor >, - DataProcessor > - > -{ - private: - typedef - RegisteredParsingObject< - TruncateToCylindricalFOVImageProcessor, - DataProcessor >, - DataProcessor > - > - base_type; +class TruncateToCylindricalFOVImageProcessor + : public RegisteredParsingObject, DataProcessor>, + DataProcessor>> { +private: + typedef RegisteredParsingObject, DataProcessor>, + DataProcessor>> + base_type; + public: - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor TruncateToCylindricalFOVImageProcessor(); - void set_strictly_less_than_radius(const bool arg) { - this->_strictly_less_than_radius = arg; - } - bool get_strictly_less_than_radius() const { - return this->_strictly_less_than_radius; - } + void set_strictly_less_than_radius(const bool arg) { this->_strictly_less_than_radius = arg; } + bool get_strictly_less_than_radius() const { return this->_strictly_less_than_radius; } private: bool _strictly_less_than_radius; virtual void set_defaults(); virtual void initialise_keymap(); - - Succeeded virtual_set_up(const DiscretisedDensity<3,elemT>& image); + + Succeeded virtual_set_up(const DiscretisedDensity<3, elemT>& image); // new - void virtual_apply(DiscretisedDensity<3,elemT>& out_density, const DiscretisedDensity<3,elemT>& in_density) const; - void virtual_apply(DiscretisedDensity<3,elemT>& density) const ; - + void virtual_apply(DiscretisedDensity<3, elemT>& out_density, const DiscretisedDensity<3, elemT>& in_density) const; + void virtual_apply(DiscretisedDensity<3, elemT>& density) const; }; - END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/VectorWithOffset.h b/src/include/stir/VectorWithOffset.h index 814af9f097..23df4a4e35 100644 --- a/src/include/stir/VectorWithOffset.h +++ b/src/include/stir/VectorWithOffset.h @@ -22,8 +22,8 @@ #define __stir_VectorWithOffset_H__ /*! - \file - \ingroup Array + \file + \ingroup Array \brief defines the stir::VectorWithOffset class \author Kris Thielemans @@ -45,42 +45,39 @@ namespace detail { VectorWithOffset::iterator or VectorWithOffset::const_iterator. */ template -class VectorWithOffset_iter - : public boost::iterator_adaptor< - VectorWithOffset_iter // Derived - , elemT* // Base - , boost::use_default // Value - , boost::random_access_traversal_tag // CategoryOrTraversal - > -{ - private: +class VectorWithOffset_iter : public boost::iterator_adaptor // Derived + , + elemT* // Base + , + boost::use_default // Value + , + boost::random_access_traversal_tag // CategoryOrTraversal + > { +private: // abbreviation of the type of this class typedef VectorWithOffset_iter self_t; - public: - VectorWithOffset_iter() - : VectorWithOffset_iter::iterator_adaptor_(0) {} - + +public: + VectorWithOffset_iter() : VectorWithOffset_iter::iterator_adaptor_(0) {} + //! allow assignment from ordinary pointer /*! really should be used within VectorWithOffset It is explicit such that you can't do this by accident. */ - explicit VectorWithOffset_iter(elemT* p) - : VectorWithOffset_iter::iterator_adaptor_(p) {} - + explicit VectorWithOffset_iter(elemT* p) : VectorWithOffset_iter::iterator_adaptor_(p) {} + //! some magic trickery to be able to assign iterators to const iterators, but not to incompatible types /*! See the boost documentation for more info. */ template - VectorWithOffset_iter( - VectorWithOffset_iter const& other, - typename boost::enable_if_convertible::type* = 0) - : VectorWithOffset_iter::iterator_adaptor_(other.base()) {} + VectorWithOffset_iter(VectorWithOffset_iter const& other, + typename boost::enable_if_convertible::type* = 0) + : VectorWithOffset_iter::iterator_adaptor_(other.base()) {} }; } // end of namespace detail - -/*! +/*! \ingroup Array \brief A templated class for vectors, but with indices starting not from 0 @@ -88,7 +85,7 @@ class VectorWithOffset_iter are provided for accessing the data via a \c T*. This class tries to mimic std::vector for the most common methods, but - it is much more conservative in its memory allocations. + it is much more conservative in its memory allocations. The only memory that is allocated is what you asked for (although the allocated memory hardly ever shrinks, except when calling recycle()). So, std::vector::push_back() etc are not provided, as they would be @@ -97,7 +94,7 @@ class VectorWithOffset_iter It is possible to construct a VectorWithOffset that uses existing memory. It will then never deallocate that memory obviously. Note that when growing - the vector (or assigning a bigger vector), the vector will allocate new + the vector (or assigning a bigger vector), the vector will allocate new memory. Any modifications to the vector then will no longer be connected to the original data block. This can always be tested using owns_memory_for_data(). @@ -112,8 +109,7 @@ class VectorWithOffset_iter */ template -class VectorWithOffset -{ +class VectorWithOffset { public: //! \name typedefs for iterator support /*! Most of these should really not be needed because we use boost::iterator_adaptor now. @@ -131,53 +127,46 @@ class VectorWithOffset typedef boost::reverse_iterator const_reverse_iterator; //@} typedef size_t size_type; -public: - +public: //! Default constructor: creates a vector of length 0 inline VectorWithOffset(); - + //! Construct a VectorWithOffset of given length (initialised with \c T()) inline explicit VectorWithOffset(const int hsz); - + //! Construct a VectorWithOffset with offset \c min_index (initialised with \c T()) inline VectorWithOffset(const int min_index, const int max_index); //! Construct a VectorWithOffset of given length using existing data (no initialisation) - inline explicit - VectorWithOffset(const int hsz, - T * const data_ptr, - T * const end_of_data_ptr); - + inline explicit VectorWithOffset(const int hsz, T* const data_ptr, T* const end_of_data_ptr); + //! Construct a VectorWithOffset with offset \c min_index using existing data (no initialisation) - inline - VectorWithOffset(const int min_index, const int max_index, - T * const data_ptr, - T * const end_of_data_ptr); + inline VectorWithOffset(const int min_index, const int max_index, T* const data_ptr, T* const end_of_data_ptr); //! copy constructor - inline VectorWithOffset(const VectorWithOffset &il) ; + inline VectorWithOffset(const VectorWithOffset& il); + + //! Destructor + inline virtual ~VectorWithOffset(); - //! Destructor - inline virtual ~VectorWithOffset(); - //! Free all memory and make object as if default-constructed - /*! This is not the same as resize(0), as the latter does not + /*! This is not the same as resize(0), as the latter does not deallocate the memory (i.e. does not change the capacity()). */ inline void recycle(); //! assignment operator with another vector - inline VectorWithOffset & operator= (const VectorWithOffset &il) ; + inline VectorWithOffset& operator=(const VectorWithOffset& il); //! \name index range operations - //@{ + //@{ //! return number of elements in this vector /*! \deprecated Use size() instead. */ - inline int get_length() const; - + inline int get_length() const; + //! return number of elements in this vector - inline size_t size() const; + inline size_t size() const; //! get value of first valid index inline int get_min_index() const; @@ -187,16 +176,16 @@ class VectorWithOffset //! change value of starting index inline void set_offset(const int min_index); - + //! identical to set_offset() inline void set_min_index(const int min_index); //! grow the range of the vector, new elements are set to \c T() - /*! Currently, it is only checked with assert() if old range is + /*! Currently, it is only checked with assert() if old range is a subinterval of the new range. grow() currently simply calls resize(). However, if you overload - resize() in a derived class, it is probably safest to overload + resize() in a derived class, it is probably safest to overload grow() as well. */ inline virtual void grow(const int min_index, const int max_index); @@ -217,7 +206,6 @@ class VectorWithOffset //! change the range of the vector from 0 to new_size-1, new elements are set to \c T() inline void resize(const unsigned int new_size); - //! make the allocated range at least from \a min_index to \a max_index inline void reserve(const int min_index, const int max_index); @@ -230,49 +218,48 @@ class VectorWithOffset //! check if this object owns the memory for the data /*! Will be false if one of the constructors is used that passes in a data block. */ - inline bool - owns_memory_for_data() const; + inline bool owns_memory_for_data() const; //! get min_index within allocated range - /*! This value depends on get_min_index() and hence will change - after calling set_min_index(). + /*! This value depends on get_min_index() and hence will change + after calling set_min_index(). For a vector of 0 length, this function returns 0. */ inline int get_capacity_min_index() const; //! get max_index within allocated range - /*! This value depends on get_min_index() and hence will change + /*! This value depends on get_min_index() and hence will change after calling set_min_index(). For a vector of 0 length, this function returns capacity()-1. */ inline int get_capacity_max_index() const; //@} - + //! allow array-style access, read/write - inline T& operator[] (int i); + inline T& operator[](int i); //! array access, read-only - inline const T& operator[] (int i) const; + inline const T& operator[](int i) const; //! allow array-style access, read/write, but with range checking (throws std::out_of_range) - inline T& at (int i); + inline T& at(int i); //! array access, read-only, but with range checking (throws std::out_of_range) inline const T& at(int i) const; - + //! checks if the vector is empty inline bool empty() const; //! \name comparison operators //@{ - inline bool operator== (const VectorWithOffset &iv) const; - inline bool operator!= (const VectorWithOffset &iv) const; + inline bool operator==(const VectorWithOffset& iv) const; + inline bool operator!=(const VectorWithOffset& iv) const; //@} //! fill elements with value \a n - inline void fill(const T &n); + inline void fill(const T& n); //! \name access to the data via a pointer //@{ @@ -281,9 +268,9 @@ class VectorWithOffset //! member function for access to the data via a const T* #ifndef STIR_NO_MUTABLE - inline const T * get_const_data_ptr() const; + inline const T* get_const_data_ptr() const; #else - inline const T * get_const_data_ptr(); + inline const T* get_const_data_ptr(); #endif //! signal end of access to T* @@ -315,20 +302,20 @@ class VectorWithOffset //@} /*! \name arithmetic assignment operators with objects of the same type - \warning Arguments must have matching index ranges. Otherwise error() is called. + \warning Arguments must have matching index ranges. Otherwise error() is called. */ //@{ //! adding elements of \c v to the current vector - inline VectorWithOffset & operator+= (const VectorWithOffset &v); + inline VectorWithOffset& operator+=(const VectorWithOffset& v); //! subtracting elements of \c v from the current vector - inline VectorWithOffset & operator-= (const VectorWithOffset &v); + inline VectorWithOffset& operator-=(const VectorWithOffset& v); - //! multiplying elements of the current vector with elements of \c v - inline VectorWithOffset & operator*= (const VectorWithOffset &v); + //! multiplying elements of the current vector with elements of \c v + inline VectorWithOffset& operator*=(const VectorWithOffset& v); //! dividing all elements of the current vector by elements of \c v - inline VectorWithOffset & operator/= (const VectorWithOffset &v); + inline VectorWithOffset& operator/=(const VectorWithOffset& v); //@} #if 0 // next operators are disabled for now @@ -355,38 +342,37 @@ class VectorWithOffset #endif /*! \name arithmetic operators with objects of the same type - - \warning Arguments must have matching index ranges. Otherwise error() is called. + + \warning Arguments must have matching index ranges. Otherwise error() is called. \warning current implementation involves a temporary copy of the data, unless you have a really smart compiler. */ //@{ //! adding vectors, element by element - inline VectorWithOffset operator+ (const VectorWithOffset &v) const; + inline VectorWithOffset operator+(const VectorWithOffset& v) const; //! subtracting vectors, element by element - inline VectorWithOffset operator- (const VectorWithOffset &v) const; + inline VectorWithOffset operator-(const VectorWithOffset& v) const; //! multiplying vectors, element by element - inline VectorWithOffset operator* (const VectorWithOffset &v) const; + inline VectorWithOffset operator*(const VectorWithOffset& v) const; //! dividing vectors, element by element - inline VectorWithOffset operator/ (const VectorWithOffset &v) const; + inline VectorWithOffset operator/(const VectorWithOffset& v) const; //@} - + protected: - //! pointer to (*this)[0] (taking get_min_index() into account that is). - T *num; - + T* num; + //! Called internally to see if all variables are consistent inline void check_state() const; private: //! length of vector - unsigned int length; + unsigned int length; //! starting index - int start; + int start; T* begin_allocated_memory; T* end_allocated_memory; @@ -396,13 +382,13 @@ class VectorWithOffset //! call destructors and deallocate inline void _destruct_and_deallocate(); - + //! boolean to test if get_data_ptr is called // This variable is declared mutable such that get_const_data_ptr() can change it. #ifndef STIR_NO_MUTABLE mutable #endif - bool pointer_access; + bool pointer_access; bool _owns_memory_for_data; }; diff --git a/src/include/stir/VectorWithOffset.inl b/src/include/stir/VectorWithOffset.inl index f17d331254..42cd898f52 100644 --- a/src/include/stir/VectorWithOffset.inl +++ b/src/include/stir/VectorWithOffset.inl @@ -19,7 +19,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup Array \brief inline implementations of stir::VectorWithOffset @@ -35,20 +35,18 @@ START_NAMESPACE_STIR template -void -VectorWithOffset::init() -{ - length =0; // i.e. an empty row of zero length, - start = 0; // no offsets - num = 0; // and no data. +void +VectorWithOffset::init() { + length = 0; // i.e. an empty row of zero length, + start = 0; // no offsets + num = 0; // and no data. begin_allocated_memory = 0; end_allocated_memory = 0; } template bool -VectorWithOffset::owns_memory_for_data() const -{ +VectorWithOffset::owns_memory_for_data() const { return this->_owns_memory_for_data; } @@ -57,231 +55,191 @@ This function (only non-empty when debugging) is used before and after any modification of the object */ template -void -VectorWithOffset::check_state() const -{ +void +VectorWithOffset::check_state() const { // disable for normal debugging -#if _DEBUG>1 - assert(((length > 0) || - (length == 0 && start == 0 && - num == begin_allocated_memory))); - +#if _DEBUG > 1 + assert(((length > 0) || (length == 0 && start == 0 && num == begin_allocated_memory))); + #endif - assert(begin_allocated_memory <= num+start); - assert(end_allocated_memory>=begin_allocated_memory); - assert(static_cast(end_allocated_memory-begin_allocated_memory) >= length); + assert(begin_allocated_memory <= num + start); + assert(end_allocated_memory >= begin_allocated_memory); + assert(static_cast(end_allocated_memory - begin_allocated_memory) >= length); } template -void -VectorWithOffset:: -_destruct_and_deallocate() -{ +void +VectorWithOffset::_destruct_and_deallocate() { // check if data is being accessed via a pointer (see get_data_ptr()) assert(pointer_access == false); // TODO when reserve() no longer initialises new elements, // we'll have to be careful to delete only initialised elements // and just de-allocate the rest - + // Check on capacity probably not really necessary // as begin_allocated_memory is == 0 in that case, and delete[] 0 doesn't do anything // (I think). Anyway, we're on the safe side now... if (this->owns_memory_for_data() && this->capacity() != 0) - delete[] this->begin_allocated_memory; + delete[] this->begin_allocated_memory; } template -void -VectorWithOffset::recycle() -{ +void +VectorWithOffset::recycle() { this->check_state(); this->_destruct_and_deallocate(); this->init(); } template -int VectorWithOffset::get_min_index() const -{ - return start; +int +VectorWithOffset::get_min_index() const { + return start; } template -int VectorWithOffset::get_max_index() const -{ - return start + length - 1; +int +VectorWithOffset::get_max_index() const { + return start + length - 1; } /*! Out of range errors are detected using assert() */ template -T& -VectorWithOffset::operator[] (int i) -{ +T& +VectorWithOffset::operator[](int i) { this->check_state(); - assert(i>=this->get_min_index()); - assert(i<=this->get_max_index()); - + assert(i >= this->get_min_index()); + assert(i <= this->get_max_index()); + return num[i]; } /*! Out of range errors are detected using assert() */ template -const T& -VectorWithOffset::operator[] (int i) const -{ +const T& +VectorWithOffset::operator[](int i) const { this->check_state(); - assert(i>=this->get_min_index()); - assert(i<=this->get_max_index()); - + assert(i >= this->get_min_index()); + assert(i <= this->get_max_index()); + return num[i]; } template -T& -VectorWithOffset::at(int i) -{ - if (length==0 || iget_min_index() || i>this->get_max_index()) +T& +VectorWithOffset::at(int i) { + if (length == 0 || i < this->get_min_index() || i > this->get_max_index()) throw std::out_of_range("index out of range"); this->check_state(); return num[i]; } template -const T& -VectorWithOffset::at(int i) const -{ - if (length==0 || iget_min_index() || i>this->get_max_index()) +const T& +VectorWithOffset::at(int i) const { + if (length == 0 || i < this->get_min_index() || i > this->get_max_index()) throw std::out_of_range("index out of range"); this->check_state(); - + return num[i]; } template bool -VectorWithOffset::empty() const -{ - return length==0; +VectorWithOffset::empty() const { + return length == 0; } template -typename VectorWithOffset::iterator -VectorWithOffset::begin() -{ +typename VectorWithOffset::iterator +VectorWithOffset::begin() { this->check_state(); - return typename VectorWithOffset::iterator(num+this->get_min_index()); + return typename VectorWithOffset::iterator(num + this->get_min_index()); } template -typename VectorWithOffset::const_iterator -VectorWithOffset::begin() const -{ +typename VectorWithOffset::const_iterator +VectorWithOffset::begin() const { this->check_state(); - return typename VectorWithOffset::const_iterator(num+this->get_min_index()); + return typename VectorWithOffset::const_iterator(num + this->get_min_index()); } template -typename VectorWithOffset::iterator -VectorWithOffset::end() -{ +typename VectorWithOffset::iterator +VectorWithOffset::end() { this->check_state(); - return typename VectorWithOffset::iterator(num+this->get_max_index()+1); + return typename VectorWithOffset::iterator(num + this->get_max_index() + 1); } template -typename VectorWithOffset::const_iterator -VectorWithOffset::end() const -{ +typename VectorWithOffset::const_iterator +VectorWithOffset::end() const { this->check_state(); - return typename VectorWithOffset::const_iterator(num+this->get_max_index()+1); + return typename VectorWithOffset::const_iterator(num + this->get_max_index() + 1); } template -typename VectorWithOffset::reverse_iterator -VectorWithOffset::rbegin() -{ +typename VectorWithOffset::reverse_iterator +VectorWithOffset::rbegin() { this->check_state(); return boost::make_reverse_iterator(end()); } template -typename VectorWithOffset::const_reverse_iterator -VectorWithOffset::rbegin() const -{ +typename VectorWithOffset::const_reverse_iterator +VectorWithOffset::rbegin() const { this->check_state(); return boost::make_reverse_iterator(end()); } template -typename VectorWithOffset::reverse_iterator -VectorWithOffset::rend() -{ +typename VectorWithOffset::reverse_iterator +VectorWithOffset::rend() { this->check_state(); return boost::make_reverse_iterator(begin()); } template -typename VectorWithOffset::const_reverse_iterator -VectorWithOffset::rend() const -{ +typename VectorWithOffset::const_reverse_iterator +VectorWithOffset::rend() const { this->check_state(); return boost::make_reverse_iterator(begin()); } template -VectorWithOffset::VectorWithOffset() -: _owns_memory_for_data(true) -{ - pointer_access = false; +VectorWithOffset::VectorWithOffset() : _owns_memory_for_data(true) { + pointer_access = false; this->init(); } template -VectorWithOffset::VectorWithOffset(const int hsz) - : length(hsz), - start(0), - pointer_access(false), - _owns_memory_for_data(true) -{ - if ((hsz > 0)) - { +VectorWithOffset::VectorWithOffset(const int hsz) : length(hsz), start(0), pointer_access(false), _owns_memory_for_data(true) { + if ((hsz > 0)) { num = new T[hsz]; begin_allocated_memory = num; end_allocated_memory = num + length; - } - else + } else this->init(); this->check_state(); -} +} template -VectorWithOffset::VectorWithOffset(const int min_index, const int max_index) - : length(static_cast(max_index - min_index) + 1), - start(min_index), - pointer_access(false), - _owns_memory_for_data(true) -{ - if (max_index >= min_index) - { +VectorWithOffset::VectorWithOffset(const int min_index, const int max_index) + : length(static_cast(max_index - min_index) + 1), start(min_index), pointer_access(false), + _owns_memory_for_data(true) { + if (max_index >= min_index) { num = new T[length]; begin_allocated_memory = num; end_allocated_memory = num + length; num -= min_index; - } - else - this->init(); + } else + this->init(); this->check_state(); } - template -VectorWithOffset:: -VectorWithOffset(const int sz, - T * const data_ptr, T * const end_of_data_ptr) - : length(static_cast(sz)), - start(0), - pointer_access(false), - _owns_memory_for_data(false) -{ +VectorWithOffset::VectorWithOffset(const int sz, T* const data_ptr, T* const end_of_data_ptr) + : length(static_cast(sz)), start(0), pointer_access(false), _owns_memory_for_data(false) { this->begin_allocated_memory = data_ptr; this->end_allocated_memory = end_of_data_ptr; this->num = this->begin_allocated_memory - this->start; @@ -289,14 +247,9 @@ VectorWithOffset(const int sz, } template -VectorWithOffset:: -VectorWithOffset(const int min_index, const int max_index, - T * const data_ptr, T * const end_of_data_ptr) - : length(static_cast(max_index - min_index) + 1), - start(min_index), - pointer_access(false), - _owns_memory_for_data(false) -{ +VectorWithOffset::VectorWithOffset(const int min_index, const int max_index, T* const data_ptr, T* const end_of_data_ptr) + : length(static_cast(max_index - min_index) + 1), start(min_index), pointer_access(false), + _owns_memory_for_data(false) { this->begin_allocated_memory = data_ptr; this->end_allocated_memory = end_of_data_ptr; this->num = this->begin_allocated_memory - this->start; @@ -304,209 +257,171 @@ VectorWithOffset(const int min_index, const int max_index, } template -VectorWithOffset::~VectorWithOffset() -{ +VectorWithOffset::~VectorWithOffset() { // check if data is being accessed via a pointer (see get_data_ptr()) assert(pointer_access == false); _destruct_and_deallocate(); -} +} template -void -VectorWithOffset::set_offset(const int min_index) -{ +void +VectorWithOffset::set_offset(const int min_index) { this->check_state(); // only do something when non-zero length - if (length == 0) return; + if (length == 0) + return; num += start - min_index; start = min_index; } template -void -VectorWithOffset:: -set_min_index(const int min_index) -{ +void +VectorWithOffset::set_min_index(const int min_index) { this->set_offset(min_index); } template size_t -VectorWithOffset:: -capacity() const -{ - return size_t(end_allocated_memory-begin_allocated_memory); +VectorWithOffset::capacity() const { + return size_t(end_allocated_memory - begin_allocated_memory); } template int -VectorWithOffset:: -get_capacity_min_index() const -{ +VectorWithOffset::get_capacity_min_index() const { // the behaviour for length==0 depends on num==begin_allocated_memory - assert(length>0 || num==begin_allocated_memory); + assert(length > 0 || num == begin_allocated_memory); return static_cast(begin_allocated_memory - num); } template int -VectorWithOffset:: -get_capacity_max_index() const -{ +VectorWithOffset::get_capacity_max_index() const { // the behaviour for length==0 depends on num==begin_allocated_memory - assert(length>0 || num==begin_allocated_memory); + assert(length > 0 || num == begin_allocated_memory); return static_cast(end_allocated_memory - num - 1); } -//the new members will be initialised with the default constructor for T +// the new members will be initialised with the default constructor for T // but this should change in the future template -void -VectorWithOffset:: -reserve(const int new_capacity_min_index, const int new_capacity_max_index) -{ - this->check_state(); - const int actual_capacity_min_index = - length==0 - ? new_capacity_min_index - : std::min(this->get_capacity_min_index(), new_capacity_min_index); - const int actual_capacity_max_index = - length==0 - ? new_capacity_max_index - : std::max(this->get_capacity_max_index(), new_capacity_max_index); +void +VectorWithOffset::reserve(const int new_capacity_min_index, const int new_capacity_max_index) { + this->check_state(); + const int actual_capacity_min_index = + length == 0 ? new_capacity_min_index : std::min(this->get_capacity_min_index(), new_capacity_min_index); + const int actual_capacity_max_index = + length == 0 ? new_capacity_max_index : std::max(this->get_capacity_max_index(), new_capacity_max_index); if (actual_capacity_min_index > actual_capacity_max_index) return; - - const unsigned int new_capacity = - static_cast(actual_capacity_max_index - actual_capacity_min_index) + 1; + + const unsigned int new_capacity = static_cast(actual_capacity_max_index - actual_capacity_min_index) + 1; if (new_capacity <= this->capacity()) return; // check if data is being accessed via a pointer (see get_data_ptr()) assert(pointer_access == false); // TODO use allocator here instead of new - T *newmem = new T[new_capacity]; - const unsigned extra_at_the_left = - length==0 - ? 0U - : std::max(0, this->get_min_index() - actual_capacity_min_index); - std::copy(this->begin(), this->end(), - newmem + extra_at_the_left); + T* newmem = new T[new_capacity]; + const unsigned extra_at_the_left = length == 0 ? 0U : std::max(0, this->get_min_index() - actual_capacity_min_index); + std::copy(this->begin(), this->end(), newmem + extra_at_the_left); this->_destruct_and_deallocate(); begin_allocated_memory = newmem; end_allocated_memory = begin_allocated_memory + new_capacity; - _owns_memory_for_data =true; - num = begin_allocated_memory + extra_at_the_left - (length>0?start:0); + _owns_memory_for_data = true; + num = begin_allocated_memory + extra_at_the_left - (length > 0 ? start : 0); this->check_state(); } template -void -VectorWithOffset:: -reserve(const unsigned int new_size) -{ +void +VectorWithOffset::reserve(const unsigned int new_size) { // note: for 0 new_size, we avoid a wrap-around // otherwise we would be reserving quite a lot of memory! - if (new_size!=0) - reserve(0, static_cast(new_size-1)); + if (new_size != 0) + reserve(0, static_cast(new_size - 1)); } -//the new members will be initialised with the default constructor for T +// the new members will be initialised with the default constructor for T template -void -VectorWithOffset:: -resize(const int min_index, const int max_index) -{ +void +VectorWithOffset::resize(const int min_index, const int max_index) { this->check_state(); - if (min_index > max_index) - { - length = 0; start = 0; num = begin_allocated_memory; + if (min_index > max_index) { + length = 0; + start = 0; + num = begin_allocated_memory; + return; + } + const unsigned old_length = length; + if (old_length > 0) { + if (min_index == this->get_min_index() && max_index == this->get_max_index()) return; + // determine overlapping range to avoid copying too much data when calling reserve() + const int overlap_min_index = std::max(this->get_min_index(), min_index); + const int overlap_max_index = std::min(this->get_max_index(), max_index); + // TODO when using non-initialised memory, call delete here on elements that go out of range + length = overlap_max_index - overlap_min_index < 0 ? 0 : static_cast(overlap_max_index - overlap_min_index) + 1; + if (length == 0) { + start = 0; + num = begin_allocated_memory; + } else { + // do not change num as num[0] should remain the same + start = overlap_min_index; } - const unsigned old_length = length; - if (old_length>0) - { - if (min_index == this->get_min_index() && max_index == this->get_max_index()) - return; - // determine overlapping range to avoid copying too much data when calling reserve() - const int overlap_min_index = std::max(this->get_min_index(), min_index); - const int overlap_max_index = std::min(this->get_max_index(), max_index); - // TODO when using non-initialised memory, call delete here on elements that go out of range - length = - overlap_max_index - overlap_min_index < 0 ? - 0 : - static_cast(overlap_max_index - overlap_min_index) + 1; - if (length==0) - { - start = 0; num = begin_allocated_memory; - } - else - { - // do not change num as num[0] should remain the same - start = overlap_min_index; - } - } // end if (length>0) + } // end if (length>0) const unsigned overlapping_length = length; this->reserve(min_index, max_index); // TODO when using allocator, call default constructor for new elements here // (and delete the ones that go out of range!) - length = - static_cast(max_index - min_index) + 1; + length = static_cast(max_index - min_index) + 1; start = min_index; - if (overlapping_length>0) - { - // do not change num as num[0] should remain the same - } - else - { - // we have reallocated the whole array, so set num correctly - num = begin_allocated_memory - min_index; - } + if (overlapping_length > 0) { + // do not change num as num[0] should remain the same + } else { + // we have reallocated the whole array, so set num correctly + num = begin_allocated_memory - min_index; + } this->check_state(); } template -void -VectorWithOffset::resize(const unsigned new_size) -{ - if (new_size==0) - { - length = 0; start = 0; num = begin_allocated_memory; - } - else - this->resize(0,static_cast(new_size-1)); +void +VectorWithOffset::resize(const unsigned new_size) { + if (new_size == 0) { + length = 0; + start = 0; + num = begin_allocated_memory; + } else + this->resize(0, static_cast(new_size - 1)); } -//the new members will be initialised with the default constructor for T +// the new members will be initialised with the default constructor for T template -void -VectorWithOffset:: -grow(const int min_index, const int max_index) -{ +void +VectorWithOffset::grow(const int min_index, const int max_index) { // allow grow arbitrary when it's zero length assert(length == 0 || (min_index <= this->get_min_index() && max_index >= this->get_max_index())); this->resize(min_index, max_index); } template -void -VectorWithOffset::grow(const unsigned new_size) -{ - this->grow(0,static_cast(new_size-1)); +void +VectorWithOffset::grow(const unsigned new_size) { + this->grow(0, static_cast(new_size - 1)); } template -VectorWithOffset & -VectorWithOffset::operator= (const VectorWithOffset &il) -{ +VectorWithOffset& +VectorWithOffset::operator=(const VectorWithOffset& il) { this->check_state(); - if (this == &il) return *this; // in case of x=x - { - if (this->capacity() < il.size()) - { + if (this == &il) + return *this; // in case of x=x + { + if (this->capacity() < il.size()) { // first truncate current and then reserve space length = 0; - start = 0; + start = 0; num = begin_allocated_memory; this->reserve(il.get_min_index(), il.get_max_index()); } @@ -519,65 +434,59 @@ VectorWithOffset::operator= (const VectorWithOffset &il) return *this; } - template -VectorWithOffset::VectorWithOffset(const VectorWithOffset &il) - : pointer_access(false), - _owns_memory_for_data(true) -{ +VectorWithOffset::VectorWithOffset(const VectorWithOffset& il) : pointer_access(false), _owns_memory_for_data(true) { this->init(); - *this = il; // Uses assignment operator (above) + *this = il; // Uses assignment operator (above) } template -int VectorWithOffset::get_length() const -{ - this->check_state(); - return static_cast(length); +int +VectorWithOffset::get_length() const { + this->check_state(); + return static_cast(length); } template -size_t VectorWithOffset::size() const -{ - this->check_state(); - return size_t(length); +size_t +VectorWithOffset::size() const { + this->check_state(); + return size_t(length); } template -bool -VectorWithOffset::operator== (const VectorWithOffset &iv) const -{ +bool +VectorWithOffset::operator==(const VectorWithOffset& iv) const { this->check_state(); - if (length != iv.length || start != iv.start) return false; + if (length != iv.length || start != iv.start) + return false; return std::equal(this->begin(), this->end(), iv.begin()); } template -bool -VectorWithOffset::operator!= (const VectorWithOffset &iv) const -{ return !(*this == iv); } +bool +VectorWithOffset::operator!=(const VectorWithOffset& iv) const { + return !(*this == iv); +} template -void -VectorWithOffset::fill(const T &n) -{ +void +VectorWithOffset::fill(const T& n) { this->check_state(); - //TODO use std::fill() if we can use namespaces (to avoid name conflicts) - //std::fill(begin(), end(), n); - for(int i=this->get_min_index(); i<=this->get_max_index(); i++) + // TODO use std::fill() if we can use namespaces (to avoid name conflicts) + // std::fill(begin(), end(), n); + for (int i = this->get_min_index(); i <= this->get_max_index(); i++) num[i] = n; this->check_state(); } - - -/*! - This returns a \c T* to the first element of a, +/*! + This returns a \c T* to the first element of a, members are guaranteed to be stored contiguously in memory. Use only in emergency cases... - To prevent invalidating the safety checks (and making + To prevent invalidating the safety checks (and making reimplementation more difficult), NO manipulation with the vector is allowed between the pairs get_data_ptr() and release_data_ptr() @@ -586,20 +495,19 @@ VectorWithOffset::fill(const T &n) (This is checked with assert() in DEBUG mode.) */ template -T* -VectorWithOffset::get_data_ptr() -{ +T* +VectorWithOffset::get_data_ptr() { assert(!pointer_access); - + pointer_access = true; - return (num+start); - - // if implementation changes, this would need to keep track + return (num + start); + + // if implementation changes, this would need to keep track // if which pointer it returns. }; -/*! - This returns a \c const \c T* to the first element of a, +/*! + This returns a \c const \c T* to the first element of a, members are guaranteed to be stored contiguously in memory. Use get_const_data_ptr() when you are not going to modify @@ -608,41 +516,40 @@ VectorWithOffset::get_data_ptr() \see get_data_ptr() */ template -const T * +const T* VectorWithOffset::get_const_data_ptr() #ifndef STIR_NO_MUTABLE -const + const #endif { assert(!pointer_access); - + pointer_access = true; - return (num+start); - - // if implementation changes, this would need to keep track + return (num + start); + + // if implementation changes, this would need to keep track // if which pointer it returns. }; -/*! - This has to be used when access to the T* returned by get_data_ptr() is +/*! + This has to be used when access to the T* returned by get_data_ptr() is finished. It updates - the vector with any changes you made, and allows access to + the vector with any changes you made, and allows access to the other member functions again. \see get_data_ptr() */ template -void -VectorWithOffset::release_data_ptr() -{ +void +VectorWithOffset::release_data_ptr() { assert(pointer_access); - + pointer_access = false; } -/*! - This has to be used when access to the const T* returned by get_const_data_ptr() is - finished. It allows access to +/*! + This has to be used when access to the const T* returned by get_const_data_ptr() is + finished. It allows access to the other member functions again. \see get_const_data_ptr() @@ -652,110 +559,98 @@ template void VectorWithOffset::release_const_data_ptr() #ifndef STIR_NO_MUTABLE -const + const #endif { assert(pointer_access); - + pointer_access = false; } /********************** arithmetic operators ****************/ template -inline VectorWithOffset& -VectorWithOffset::operator+= (const VectorWithOffset &v) -{ +inline VectorWithOffset& +VectorWithOffset::operator+=(const VectorWithOffset& v) { this->check_state(); #if 1 - if (this->get_min_index() != v.get_min_index() && - this->get_max_index() != v.get_max_index()) + if (this->get_min_index() != v.get_min_index() && this->get_max_index() != v.get_max_index()) error("VectorWithOffset::+= with non-matching range"); #else // first check if *this is empty - if (this->get_length() == 0) - { + if (this->get_length() == 0) { return *this = v; } - this->grow (std::min(get_min_index(),v.get_min_index()), std::max(get_max_index(),v.get_max_index())); + this->grow(std::min(get_min_index(), v.get_min_index()), std::max(get_max_index(), v.get_max_index())); #endif - for (int i=v.get_min_index(); i<=v.get_max_index(); i++) + for (int i = v.get_min_index(); i <= v.get_max_index(); i++) num[i] += v.num[i]; this->check_state(); - return *this; + return *this; } template -inline VectorWithOffset& -VectorWithOffset::operator-= (const VectorWithOffset &v) -{ +inline VectorWithOffset& +VectorWithOffset::operator-=(const VectorWithOffset& v) { this->check_state(); #if 1 - if (this->get_min_index() != v.get_min_index() && - this->get_max_index() != v.get_max_index()) + if (this->get_min_index() != v.get_min_index() && this->get_max_index() != v.get_max_index()) error("VectorWithOffset::-= with non-matching range"); #else // first check if *this is empty - if (get_length() == 0) - { + if (get_length() == 0) { *this = v; return *this *= -1; } - grow (std::min(get_min_index(),v.get_min_index()), std::max(get_max_index(),v.get_max_index())); + grow(std::min(get_min_index(), v.get_min_index()), std::max(get_max_index(), v.get_max_index())); #endif - for (int i=v.get_min_index(); i<=v.get_max_index(); i++) + for (int i = v.get_min_index(); i <= v.get_max_index(); i++) num[i] -= v.num[i]; this->check_state(); - return *this; + return *this; } template -inline VectorWithOffset& -VectorWithOffset::operator*= (const VectorWithOffset &v) -{ +inline VectorWithOffset& +VectorWithOffset::operator*=(const VectorWithOffset& v) { this->check_state(); #if 1 - if (this->get_min_index() != v.get_min_index() && - this->get_max_index() != v.get_max_index()) + if (this->get_min_index() != v.get_min_index() && this->get_max_index() != v.get_max_index()) error("VectorWithOffset::*= with non-matching range"); #else // first check if *this is empty - if (get_length() == 0) - { - // we have to return an object of the same dimensions as v, but filled with 0. - *this =v; + if (get_length() == 0) { + // we have to return an object of the same dimensions as v, but filled with 0. + *this = v; return *this *= 0; } - grow (std::min(get_min_index(),v.get_min_index()), std::max(get_max_index(),v.get_max_index())); + grow(std::min(get_min_index(), v.get_min_index()), std::max(get_max_index(), v.get_max_index())); #endif - for (int i=v.get_min_index(); i<=v.get_max_index(); i++) + for (int i = v.get_min_index(); i <= v.get_max_index(); i++) num[i] *= v.num[i]; this->check_state(); - return *this; + return *this; } template -inline VectorWithOffset& -VectorWithOffset::operator/= (const VectorWithOffset &v) -{ +inline VectorWithOffset& +VectorWithOffset::operator/=(const VectorWithOffset& v) { this->check_state(); #if 1 - if (this->get_min_index() != v.get_min_index() && - this->get_max_index() != v.get_max_index()) + if (this->get_min_index() != v.get_min_index() && this->get_max_index() != v.get_max_index()) error("VectorWithOffset::/= with non-matching range"); #else // first check if *this is empty - if (get_length() == 0) - { - // we have to return an object of the same dimensions as v, but filled with 0. - *this =v; + if (get_length() == 0) { + // we have to return an object of the same dimensions as v, but filled with 0. + *this = v; return *this *= 0; } - grow (std::min(get_min_index(),v.get_min_index()), std::max(get_max_index(),v.get_max_index())); + grow(std::min(get_min_index(), v.get_min_index()), std::max(get_max_index(), v.get_max_index())); #endif - for (int i=v.get_min_index(); i<=v.get_max_index(); i++) + for (int i = v.get_min_index(); i <= v.get_max_index(); i++) num[i] /= v.num[i]; this->check_state(); - return *this; + return *this; } /**** operator+=(T) etc *****/ @@ -807,38 +702,34 @@ VectorWithOffset::operator/= (const T &t) // addition template inline VectorWithOffset -VectorWithOffset::operator+ (const VectorWithOffset &v) const -{ +VectorWithOffset::operator+(const VectorWithOffset& v) const { this->check_state(); VectorWithOffset retval(*this); - return retval += v; + return retval += v; } // subtraction template -inline VectorWithOffset -VectorWithOffset::operator- (const VectorWithOffset &v) const -{ +inline VectorWithOffset +VectorWithOffset::operator-(const VectorWithOffset& v) const { this->check_state(); VectorWithOffset retval(*this); - return retval -= v; + return retval -= v; } // elem by elem multiplication template -inline VectorWithOffset -VectorWithOffset::operator* (const VectorWithOffset &v) const -{ +inline VectorWithOffset +VectorWithOffset::operator*(const VectorWithOffset& v) const { this->check_state(); VectorWithOffset retval(*this); - return retval *= v; + return retval *= v; } // elem by elem division template -inline VectorWithOffset -VectorWithOffset::operator/ (const VectorWithOffset &v) const -{ +inline VectorWithOffset +VectorWithOffset::operator/(const VectorWithOffset& v) const { this->check_state(); VectorWithOffset retval(*this); return retval /= v; diff --git a/src/include/stir/Verbosity.h b/src/include/stir/Verbosity.h index 0328cc05dd..e2b3d49956 100644 --- a/src/include/stir/Verbosity.h +++ b/src/include/stir/Verbosity.h @@ -39,13 +39,12 @@ START_NAMESPACE_STIR \ingroup buildblock \brief This class enables the user to control the on-screen output */ -class Verbosity -{ - public: +class Verbosity { +public: static int get(); static void set(int level); - private: +private: Verbosity(); // Private so that it can not be called int _verbosity_level; diff --git a/src/include/stir/ViewSegmentNumbers.h b/src/include/stir/ViewSegmentNumbers.h index 8fb271be85..32e54c1fd6 100644 --- a/src/include/stir/ViewSegmentNumbers.h +++ b/src/include/stir/ViewSegmentNumbers.h @@ -9,7 +9,7 @@ \author Kris Thielemans \author Sanida Mustafovic \author PARAPET project - + */ /* Copyright (C) 2000 PARAPET partners @@ -29,8 +29,6 @@ See STIR/LICENSE.txt for details */ - - #ifndef __stir_ViewSegmentNumbers_h__ #define __stir_ViewSegmentNumbers_h__ @@ -39,29 +37,30 @@ START_NAMESPACE_STIR /*! - \brief A very simple class to store view and segment numbers - \ingroup projdata + \brief A very simple class to store view and segment numbers + \ingroup projdata */ -class ViewSegmentNumbers -{ +class ViewSegmentNumbers { public: - //! an empty constructor (sets everything to 0) - inline ViewSegmentNumbers(); + inline ViewSegmentNumbers(); //! constructor taking view and segment number as arguments - inline ViewSegmentNumbers( const int view_num,const int segment_num); + inline ViewSegmentNumbers(const int view_num, const int segment_num, const int tof_num = 0); //! get segment number for const objects inline int segment_num() const; //! get view number for const objects inline int view_num() const; + //! get tof number for const objects + inline int tof_pos_num() const; //! get reference to segment number - inline int& segment_num(); + inline int& segment_num(); //! get reference to view number - inline int& view_num(); + inline int& view_num(); + //! get reference to timing position index + inline int& tof_pos_num(); - //! comparison operator, only useful for sorting /*! order : (0,1) < (0,-1) < (1,1) ...*/ inline bool operator<(const ViewSegmentNumbers& other) const; @@ -73,7 +72,7 @@ class ViewSegmentNumbers private: int segment; int view; - + int tof; }; END_NAMESPACE_STIR diff --git a/src/include/stir/ViewSegmentNumbers.inl b/src/include/stir/ViewSegmentNumbers.inl index 198bd32999..6761b078f2 100644 --- a/src/include/stir/ViewSegmentNumbers.inl +++ b/src/include/stir/ViewSegmentNumbers.inl @@ -7,7 +7,7 @@ \author Kris Thielemans \author Sanida Mustafovic \author PARAPET project - + */ /* @@ -28,54 +28,53 @@ See STIR/LICENSE.txt for details */ - START_NAMESPACE_STIR -ViewSegmentNumbers::ViewSegmentNumbers() -:segment(0),view(0) - {} +ViewSegmentNumbers::ViewSegmentNumbers() : segment(0), view(0) {} -ViewSegmentNumbers::ViewSegmentNumbers( const int view_num,const int segment_num) - : segment(segment_num),view(view_num) - {} +ViewSegmentNumbers::ViewSegmentNumbers(const int view_num, const int segment_num, const int tof_num) + : segment(segment_num), view(view_num), tof(tof_num) {} + +int +ViewSegmentNumbers::segment_num() const { + return segment; +} +int +ViewSegmentNumbers::view_num() const { + return view; +} int -ViewSegmentNumbers::segment_num() const -{ - return segment;} -int -ViewSegmentNumbers::view_num() const -{ - return view;} +ViewSegmentNumbers::tof_pos_num() const { + return tof; +} +int& +ViewSegmentNumbers::segment_num() { + return segment; +} +int& +ViewSegmentNumbers::view_num() { + return view; +} int& -ViewSegmentNumbers::segment_num() -{ return segment;} - -int& -ViewSegmentNumbers::view_num() -{ return view;} - -bool -ViewSegmentNumbers:: -operator<(const ViewSegmentNumbers& other) const -{ - return (view< other.view) || - ((view == other.view) && (segment > other.segment)); +ViewSegmentNumbers::tof_pos_num() { + return tof; +} + +bool +ViewSegmentNumbers::operator<(const ViewSegmentNumbers& other) const { + return (view < other.view) || ((view == other.view) && (segment > other.segment)); } -bool -ViewSegmentNumbers:: -operator==(const ViewSegmentNumbers& other) const -{ - return (view == other.view) && (segment == other.segment); +bool +ViewSegmentNumbers::operator==(const ViewSegmentNumbers& other) const { + return (view == other.view) && (segment == other.segment) && (tof == other.tof); } -bool -ViewSegmentNumbers:: -operator!=(const ViewSegmentNumbers& other) const -{ +bool +ViewSegmentNumbers::operator!=(const ViewSegmentNumbers& other) const { return !(*this == other); } END_NAMESPACE_STIR diff --git a/src/include/stir/Viewgram.h b/src/include/stir/Viewgram.h index 41d12b792b..567a2346c0 100644 --- a/src/include/stir/Viewgram.h +++ b/src/include/stir/Viewgram.h @@ -34,32 +34,29 @@ #ifndef __Viewgram_h__ #define __Viewgram_h__ - #include "stir/Array.h" -#include "stir/ProjDataInfo.h" +#include "stir/ProjDataInfo.h" #include "stir/IndexRange.h" #include "stir/shared_ptr.h" - START_NAMESPACE_STIR /*! \ingroup projdata \brief A class for 2d projection data. - This represents a subset of the full projection. segment_num and view_num + This represents a subset of the full projection. segment_num and view_num are fixed. - + */ template -class Viewgram : public Array<2,elemT> -{ +class Viewgram : public Array<2, elemT> { private: - typedef Array<2,elemT> base_type; + typedef Array<2, elemT> base_type; #ifdef SWIG // SWIG needs the next typedef to be public -public: +public: #endif typedef Viewgram self_type; #ifdef SWIG @@ -69,21 +66,22 @@ class Viewgram : public Array<2,elemT> public: //! Construct from proj_data_info pointer, view and segment number. Data are set to 0. - inline Viewgram(const shared_ptr& proj_data_info_ptr, - const int v_num, const int s_num); + inline Viewgram(const shared_ptr& proj_data_info_ptr, const int v_num, const int s_num, + const int t_num = 0); //! Construct with data set to the array. - inline Viewgram(const Array<2,elemT>& p,const shared_ptr& proj_data_info_ptr, - const int v_num, const int s_num); - + inline Viewgram(const Array<2, elemT>& p, const shared_ptr& proj_data_info_ptr, const int v_num, + const int s_num, const int t_num = 0); //! Get segment number - inline int get_segment_num() const; + inline int get_segment_num() const; //! Get number of views inline int get_view_num() const; + //! Get timing position index + inline int get_timing_pos_num() const; //! Get minimum number of axial positions inline int get_min_axial_pos_num() const; - //! Get maximum number of axial positions + //! Get maximum number of axial positions inline int get_max_axial_pos_num() const; //! Get number of axial positions inline int get_num_axial_poss() const; @@ -93,9 +91,9 @@ class Viewgram : public Array<2,elemT> inline int get_max_tangential_pos_num() const; //! Get number of tangential positions inline int get_num_tangential_poss() const; - + //! Get an empty viewgram of the same dimensions, segment_num etc. - inline Viewgram get_empty_copy(void) const; + inline Viewgram get_empty_copy(void) const; //! Overloading Array::grow void grow(const IndexRange<2>& range); @@ -103,41 +101,37 @@ class Viewgram : public Array<2,elemT> void resize(const IndexRange<2>& range); //! Get shared pointer to proj data info - inline shared_ptr - get_proj_data_info_sptr() const; - + inline shared_ptr get_proj_data_info_sptr() const; + //! \name Equality //@{ //! Checks if the 2 objects have the proj_data_info, segment_num etc. /*! If they do \c not have the same characteristics, the string \a explanation explains why. */ - bool - has_same_characteristics(self_type const&, - std::string& explanation) const; + bool has_same_characteristics(self_type const&, std::string& explanation) const; //! Checks if the 2 objects have the proj_data_info, segment_num etc. /*! Use this version if you do not need to know why they do not match. */ - bool - has_same_characteristics(self_type const&) const; + bool has_same_characteristics(self_type const&) const; //! check equality (data has to be identical) /*! Uses has_same_characteristics() and Array::operator==. - \warning This function uses \c ==, which might not be what you + \warning This function uses \c ==, which might not be what you need to check when \c elemT has data with float or double numbers. */ - bool operator ==(const self_type&) const; - + bool operator==(const self_type&) const; + //! negation of operator== - bool operator !=(const self_type&) const; + bool operator!=(const self_type&) const; //@} - + private: - shared_ptr proj_data_info_sptr; int view_num; - int segment_num; + int segment_num; + int timing_pos_num; }; END_NAMESPACE_STIR diff --git a/src/include/stir/Viewgram.inl b/src/include/stir/Viewgram.inl index 1acc00b4f8..298c122820 100644 --- a/src/include/stir/Viewgram.inl +++ b/src/include/stir/Viewgram.inl @@ -37,99 +37,93 @@ START_NAMESPACE_STIR template int -Viewgram::get_segment_num() const -{ return segment_num; } +Viewgram::get_segment_num() const { + return segment_num; +} template int -Viewgram::get_view_num() const -{ return view_num; } +Viewgram::get_view_num() const { + return view_num; +} template int -Viewgram::get_min_axial_pos_num() const - {return this->get_min_index();} +Viewgram::get_timing_pos_num() const { + return timing_pos_num; +} template int -Viewgram::get_max_axial_pos_num() const - { return this->get_max_index(); } +Viewgram::get_min_axial_pos_num() const { + return this->get_min_index(); +} template int -Viewgram::get_num_axial_poss() const - { return this->get_length();} - +Viewgram::get_max_axial_pos_num() const { + return this->get_max_index(); +} template int -Viewgram::get_num_tangential_poss() const - { return this->get_length()==0 ? 0 : (*this)[get_min_axial_pos_num()].get_length();} - +Viewgram::get_num_axial_poss() const { + return this->get_length(); +} template int -Viewgram::get_min_tangential_pos_num() const - { return this->get_length()==0 ? 0 :(*this)[get_min_axial_pos_num()].get_min_index();} +Viewgram::get_num_tangential_poss() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_axial_pos_num()].get_length(); +} template int -Viewgram::get_max_tangential_pos_num() const -{ return this->get_length()==0 ? 0 :(*this)[get_min_axial_pos_num()].get_max_index(); } +Viewgram::get_min_tangential_pos_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_axial_pos_num()].get_min_index(); +} +template +int +Viewgram::get_max_tangential_pos_num() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_axial_pos_num()].get_max_index(); +} template Viewgram -Viewgram::get_empty_copy(void) const - { - Viewgram copy(proj_data_info_sptr, get_view_num(), get_segment_num()); - return copy; +Viewgram::get_empty_copy(void) const { + Viewgram copy(proj_data_info_sptr, get_view_num(), get_segment_num(), get_timing_pos_num()); + return copy; } template shared_ptr -Viewgram::get_proj_data_info_sptr() const -{ +Viewgram::get_proj_data_info_sptr() const { return proj_data_info_sptr; } - template -Viewgram:: -Viewgram(const Array<2,elemT>& p, - const shared_ptr& pdi_sptr, - const int v_num, const int s_num) - : - Array<2,elemT>(p), proj_data_info_sptr(pdi_sptr), - view_num(v_num), segment_num(s_num) -{ +Viewgram::Viewgram(const Array<2, elemT>& p, const shared_ptr& pdi_sptr, const int v_num, + const int s_num, const int t_num) + : Array<2, elemT>(p), proj_data_info_sptr(pdi_sptr), view_num(v_num), segment_num(s_num), timing_pos_num(t_num) { assert(view_num <= proj_data_info_sptr->get_max_view_num()); assert(view_num >= proj_data_info_sptr->get_min_view_num()); // segment_num is already checked by doing get_max_axial_pos_num(s_num) - assert( get_min_axial_pos_num() == pdi_sptr->get_min_axial_pos_num(s_num)); - assert( get_max_axial_pos_num() == pdi_sptr->get_max_axial_pos_num(s_num)); - assert( get_min_tangential_pos_num() == pdi_sptr->get_min_tangential_pos_num()); - assert( get_max_tangential_pos_num() == pdi_sptr->get_max_tangential_pos_num()); + assert(get_min_axial_pos_num() == pdi_sptr->get_min_axial_pos_num(s_num)); + assert(get_max_axial_pos_num() == pdi_sptr->get_max_axial_pos_num(s_num)); + assert(get_min_tangential_pos_num() == pdi_sptr->get_min_tangential_pos_num()); + assert(get_max_tangential_pos_num() == pdi_sptr->get_max_tangential_pos_num()); } template -Viewgram:: -Viewgram(const shared_ptr& pdi_sptr, - const int v_num, const int s_num) - : - Array<2,elemT>(IndexRange2D (pdi_sptr->get_min_axial_pos_num(s_num), - pdi_sptr->get_max_axial_pos_num(s_num), - pdi_sptr->get_min_tangential_pos_num(), - pdi_sptr->get_max_tangential_pos_num())), - proj_data_info_sptr(pdi_sptr), - view_num(v_num), - segment_num(s_num) -{ +Viewgram::Viewgram(const shared_ptr& pdi_sptr, const int v_num, const int s_num, const int t_num) + : Array<2, elemT>(IndexRange2D(pdi_sptr->get_min_axial_pos_num(s_num), pdi_sptr->get_max_axial_pos_num(s_num), + pdi_sptr->get_min_tangential_pos_num(), pdi_sptr->get_max_tangential_pos_num())), + proj_data_info_sptr(pdi_sptr), view_num(v_num), segment_num(s_num), timing_pos_num(t_num) { assert(view_num <= proj_data_info_sptr->get_max_view_num()); assert(view_num >= proj_data_info_sptr->get_min_view_num()); // segment_num is already checked by doing get_max_axial_pos_num(s_num) } - END_NAMESPACE_STIR diff --git a/src/include/stir/VoxelsOnCartesianGrid.h b/src/include/stir/VoxelsOnCartesianGrid.h index e657210891..17bf1127a8 100644 --- a/src/include/stir/VoxelsOnCartesianGrid.h +++ b/src/include/stir/VoxelsOnCartesianGrid.h @@ -23,11 +23,11 @@ #define __stir_VoxelsOnCartesianGrid_H__ /*! - \file - \ingroup densitydata - \brief defines the stir::VoxelsOnCartesianGrid class + \file + \ingroup densitydata + \brief defines the stir::VoxelsOnCartesianGrid class - \author Sanida Mustafovic + \author Sanida Mustafovic \author Kris Thielemans (with help from Alexey Zverovich) \author PARAPET project @@ -39,7 +39,8 @@ START_NAMESPACE_STIR class ProjDataInfo; -template class PixelsOnCartesianGrid; +template +class PixelsOnCartesianGrid; /*! \ingroup densitydata @@ -48,183 +49,155 @@ template class PixelsOnCartesianGrid; This class represents 'normal' data. Basisfunctions are just voxels. */ -template -class VoxelsOnCartesianGrid:public DiscretisedDensityOnCartesianGrid<3,elemT> -{ +template +class VoxelsOnCartesianGrid : public DiscretisedDensityOnCartesianGrid<3, elemT> { public: - #if 0 //! Asks for filename etc, and returns an image static VoxelsOnCartesianGrid ask_parameters(); #endif -//! Construct an empty VoxelsOnCartesianGrid (empty range, 0 origin, 0 grid_spacing) -VoxelsOnCartesianGrid(); - -//! Construct a VoxelsOnCartesianGrid, initialising data from the Array<3,elemT> object. -VoxelsOnCartesianGrid(const Array<3,elemT>& v, - const CartesianCoordinate3D& origin, - const BasicCoordinate<3,float>& grid_spacing); - -//! Construct a VoxelsOnCartesianGrid from an index range -/*! All elements are set 0. */ -VoxelsOnCartesianGrid(const IndexRange<3>& range, - const CartesianCoordinate3D& origin, - const BasicCoordinate<3,float>& grid_spacing); - - //! Construct a VoxelsOnCartesianGrid, initialising data from the Array<3,elemT> object. -VoxelsOnCartesianGrid(const shared_ptr < const ExamInfo > & exam_info_sptr, - const Array<3,elemT>& v, - const CartesianCoordinate3D& origin, - const BasicCoordinate<3,float>& grid_spacing); - -//! Construct a VoxelsOnCartesianGrid from an index range -/*! All elements are set 0. */ -VoxelsOnCartesianGrid(const shared_ptr < const ExamInfo > & exam_info_sptr, - const IndexRange<3>& range, - const CartesianCoordinate3D& origin, - const BasicCoordinate<3,float>& grid_spacing); + //! Construct an empty VoxelsOnCartesianGrid (empty range, 0 origin, 0 grid_spacing) + VoxelsOnCartesianGrid(); + + //! Construct a VoxelsOnCartesianGrid, initialising data from the Array<3,elemT> object. + VoxelsOnCartesianGrid(const Array<3, elemT>& v, const CartesianCoordinate3D& origin, + const BasicCoordinate<3, float>& grid_spacing); + + //! Construct a VoxelsOnCartesianGrid from an index range + /*! All elements are set 0. */ + VoxelsOnCartesianGrid(const IndexRange<3>& range, const CartesianCoordinate3D& origin, + const BasicCoordinate<3, float>& grid_spacing); + + //! Construct a VoxelsOnCartesianGrid, initialising data from the Array<3,elemT> object. + VoxelsOnCartesianGrid(const shared_ptr& exam_info_sptr, const Array<3, elemT>& v, + const CartesianCoordinate3D& origin, const BasicCoordinate<3, float>& grid_spacing); + + //! Construct a VoxelsOnCartesianGrid from an index range + /*! All elements are set 0. */ + VoxelsOnCartesianGrid(const shared_ptr& exam_info_sptr, const IndexRange<3>& range, + const CartesianCoordinate3D& origin, const BasicCoordinate<3, float>& grid_spacing); // KT 10/12/2001 replace 2 constructors with the more general one below -//! use ProjDataInfo to obtain the size information -/*! - When sizes.x() is -1, a default size in x is found by taking the diameter - of the FOV spanned by the projection data. Similar for sizes.y(). + //! use ProjDataInfo to obtain the size information + /*! + When sizes.x() is -1, a default size in x is found by taking the diameter + of the FOV spanned by the projection data. Similar for sizes.y(). - When sizes.z() is -1, a default size in z is found by taking the number of planes as -
      -
    • $N_0$ when segment 0 is axially compressed,
    • -
    • $2N_0-1$ when segment 0 is not axially compressed,
    • -
    - where $N_0$ is the number of sinograms in segment 0. + When sizes.z() is -1, a default size in z is found by taking the number of planes as +
      +
    • $N_0$ when segment 0 is axially compressed,
    • +
    • $2N_0-1$ when segment 0 is not axially compressed,
    • +
    + where $N_0$ is the number of sinograms in segment 0. - Actual index ranges start from 0 for z, but from -(x_size_used/2) for x (and similar for y). + Actual index ranges start from 0 for z, but from -(x_size_used/2) for x (and similar for y). - x,y grid spacing are set to the - proj_data_info_ptr-\>get_scanner_ptr()-\>get_default_bin_size()/zoom. - This is to make sure that the voxel size is independent on if arc-correction is used or not. - If the default bin size is 0, the sampling distance in s (for bin 0) is used. + x,y grid spacing are set to the + proj_data_info_ptr-\>get_scanner_ptr()-\>get_default_bin_size()/zoom. + This is to make sure that the voxel size is independent on if arc-correction is used or not. + If the default bin size is 0, the sampling distance in s (for bin 0) is used. - z grid spacing is set to half the scanner ring distance. + z grid spacing is set to half the scanner ring distance. - All voxel values are set 0. + All voxel values are set 0. -*/ -VoxelsOnCartesianGrid(const ProjDataInfo& proj_data_info_ptr, - const float zoom = 1.F, - const CartesianCoordinate3D& origin = CartesianCoordinate3D(0.F,0.F,0.F), - const CartesianCoordinate3D& sizes = CartesianCoordinate3D(-1,-1,-1)); - -//! Constructor from exam_info and proj_data_info -/*! \see VoxelsOnCartesianGrid(const ProjDataInfo&, - const float zoom, - const CartesianCoordinate3D&, - const CartesianCoordinate3D& ); -*/ -VoxelsOnCartesianGrid(const shared_ptr < const ExamInfo > & exam_info_sptr, - const ProjDataInfo& proj_data_info, - const float zoom = 1.F, - const CartesianCoordinate3D& origin = CartesianCoordinate3D(0.F,0.F,0.F), - const CartesianCoordinate3D& sizes = CartesianCoordinate3D(-1,-1,-1)); - -//! Constructor from exam_info and proj_data_info -/*! \see VoxelsOnCartesianGrid(const ProjDataInfo&, - const float zoom, - const CartesianCoordinate3D&, - const CartesianCoordinate3D& ); -*/ -VoxelsOnCartesianGrid(const shared_ptr < const ExamInfo > & exam_info_sptr_v, - const ProjDataInfo& proj_data_info, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& origin = CartesianCoordinate3D(0.F,0.F,0.F), - const CartesianCoordinate3D& sizes = CartesianCoordinate3D(-1,-1,-1)); + */ + VoxelsOnCartesianGrid(const ProjDataInfo& proj_data_info_ptr, const float zoom = 1.F, + const CartesianCoordinate3D& origin = CartesianCoordinate3D(0.F, 0.F, 0.F), + const CartesianCoordinate3D& sizes = CartesianCoordinate3D(-1, -1, -1)); + + //! Constructor from exam_info and proj_data_info + /*! \see VoxelsOnCartesianGrid(const ProjDataInfo&, + const float zoom, + const CartesianCoordinate3D&, + const CartesianCoordinate3D& ); + */ + VoxelsOnCartesianGrid(const shared_ptr& exam_info_sptr, const ProjDataInfo& proj_data_info, + const float zoom = 1.F, + const CartesianCoordinate3D& origin = CartesianCoordinate3D(0.F, 0.F, 0.F), + const CartesianCoordinate3D& sizes = CartesianCoordinate3D(-1, -1, -1)); + + //! Constructor from exam_info and proj_data_info + /*! \see VoxelsOnCartesianGrid(const ProjDataInfo&, + const float zoom, + const CartesianCoordinate3D&, + const CartesianCoordinate3D& ); + */ + VoxelsOnCartesianGrid(const shared_ptr& exam_info_sptr_v, const ProjDataInfo& proj_data_info, + const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& origin = CartesianCoordinate3D(0.F, 0.F, 0.F), + const CartesianCoordinate3D& sizes = CartesianCoordinate3D(-1, -1, -1)); //! Definition of the pure virtual defined in DiscretisedDensity #ifdef STIR_NO_COVARIANT_RETURN_TYPES -DiscretisedDensity<3,elemT>* + DiscretisedDensity<3, elemT>* #else -VoxelsOnCartesianGrid* + VoxelsOnCartesianGrid* #endif - get_empty_copy() const; + get_empty_copy() const; -//! Like get_empty_copy, but returning a pointer to a VoxelsOnCartesianGrid -VoxelsOnCartesianGrid* get_empty_voxels_on_cartesian_grid() const; + //! Like get_empty_copy, but returning a pointer to a VoxelsOnCartesianGrid + VoxelsOnCartesianGrid* get_empty_voxels_on_cartesian_grid() const; #ifdef STIR_NO_COVARIANT_RETURN_TYPES -virtual DiscretisedDensity<3,elemT>* + virtual DiscretisedDensity<3, elemT>* #else -virtual VoxelsOnCartesianGrid* + virtual VoxelsOnCartesianGrid* #endif -clone() const; + clone() const; -//! Extract a single plane -PixelsOnCartesianGrid get_plane(const int z) const; + //! Extract a single plane + PixelsOnCartesianGrid get_plane(const int z) const; -//! Set a single plane -void set_plane(const PixelsOnCartesianGrid& plane, const int z); + //! Set a single plane + void set_plane(const PixelsOnCartesianGrid& plane, const int z); -//! is the same as get_grid_spacing(), but now returns CartesianCoordinate3D for convenience -inline CartesianCoordinate3D get_voxel_size() const; + //! is the same as get_grid_spacing(), but now returns CartesianCoordinate3D for convenience + inline CartesianCoordinate3D get_voxel_size() const; -//! is the same as set_grid_spacing() -void set_voxel_size(const BasicCoordinate<3,float>&); + //! is the same as set_grid_spacing() + void set_voxel_size(const BasicCoordinate<3, float>&); -//! Growing of outer dimension only -void grow_z_range(const int min_z, const int max_z); + //! Growing of outer dimension only + void grow_z_range(const int min_z, const int max_z); //! \name Convenience functions for regular grids in 3D /*! It is assumed that \c z is the highest dimension and \c x the lowest. - */ + */ //@{ inline int get_x_size() const; - + inline int get_y_size() const; - + inline int get_z_size() const; - + inline int get_min_x() const; - + inline int get_min_y() const; inline int get_min_z() const; - + inline int get_max_x() const; - + inline int get_max_y() const; - + inline int get_max_z() const; - BasicCoordinate<3,int> get_lengths() const; - BasicCoordinate<3,int> get_min_indices() const; - BasicCoordinate<3,int> get_max_indices() const; + BasicCoordinate<3, int> get_lengths() const; + BasicCoordinate<3, int> get_min_indices() const; + BasicCoordinate<3, int> get_max_indices() const; //@} private: - void - construct_from_projdata_info(const shared_ptr < const ExamInfo > & exam_info_sptr_v, - const ProjDataInfo& proj_data_info, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& origin, - const CartesianCoordinate3D& sizes); - + void construct_from_projdata_info(const shared_ptr& exam_info_sptr_v, const ProjDataInfo& proj_data_info, + const CartesianCoordinate3D& zooms, const CartesianCoordinate3D& origin, + const CartesianCoordinate3D& sizes); }; - END_NAMESPACE_STIR #include "stir/VoxelsOnCartesianGrid.inl" #endif - - - - - - - - - - - - diff --git a/src/include/stir/VoxelsOnCartesianGrid.inl b/src/include/stir/VoxelsOnCartesianGrid.inl index 9d84001474..ba5116169b 100644 --- a/src/include/stir/VoxelsOnCartesianGrid.inl +++ b/src/include/stir/VoxelsOnCartesianGrid.inl @@ -18,83 +18,76 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup densitydata - \brief inline implementations for the stir::VoxelsOnCartesianGrid class + \file + \ingroup densitydata + \brief inline implementations for the stir::VoxelsOnCartesianGrid class - \author Sanida Mustafovic - \author Kris Thielemans + \author Sanida Mustafovic + \author Kris Thielemans \author PARAPET project */ START_NAMESPACE_STIR - -template -CartesianCoordinate3D -VoxelsOnCartesianGrid::get_voxel_size() const -{ +template +CartesianCoordinate3D +VoxelsOnCartesianGrid::get_voxel_size() const { return CartesianCoordinate3D(this->get_grid_spacing()); } -template +template int -VoxelsOnCartesianGrid:: -get_min_z() const -{ return this->get_min_index();} - +VoxelsOnCartesianGrid::get_min_z() const { + return this->get_min_index(); +} -template +template int -VoxelsOnCartesianGrid:: -get_min_y() const -{ return this->get_length()==0 ? 0 : (*this)[get_min_z()].get_min_index(); } +VoxelsOnCartesianGrid::get_min_y() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_z()].get_min_index(); +} -template +template int -VoxelsOnCartesianGrid:: -get_min_x() const -{ return this->get_length()==0 ? 0 : (*this)[get_min_z()][get_min_y()].get_min_index(); } - - -template -int -VoxelsOnCartesianGrid:: -get_x_size() const -{ return this->get_length()==0 ? 0 : (*this)[get_min_z()][get_min_y()].get_length(); } +VoxelsOnCartesianGrid::get_min_x() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_z()][get_min_y()].get_min_index(); +} -template +template int -VoxelsOnCartesianGrid:: -get_y_size() const -{ return this->get_length()==0 ? 0 : (*this)[get_min_z()].get_length();} +VoxelsOnCartesianGrid::get_x_size() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_z()][get_min_y()].get_length(); +} -template +template int -VoxelsOnCartesianGrid:: -get_z_size() const -{ return this->get_length(); } - +VoxelsOnCartesianGrid::get_y_size() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_z()].get_length(); +} -template +template int -VoxelsOnCartesianGrid:: -get_max_x() const -{ return this->get_length()==0 ? 0 : (*this)[get_min_z()][get_min_y()].get_max_index();} +VoxelsOnCartesianGrid::get_z_size() const { + return this->get_length(); +} -template +template int -VoxelsOnCartesianGrid:: -get_max_y() const -{ return this->get_length()==0 ? 0 : (*this)[get_min_z()].get_max_index();} +VoxelsOnCartesianGrid::get_max_x() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_z()][get_min_y()].get_max_index(); +} -template +template int -VoxelsOnCartesianGrid:: -get_max_z() const -{ return this->get_max_index(); } - +VoxelsOnCartesianGrid::get_max_y() const { + return this->get_length() == 0 ? 0 : (*this)[get_min_z()].get_max_index(); +} +template +int +VoxelsOnCartesianGrid::get_max_z() const { + return this->get_max_index(); +} END_NAMESPACE_STIR diff --git a/src/include/stir/ZoomOptions.h b/src/include/stir/ZoomOptions.h index 0f01101fdb..7c2c0a632e 100644 --- a/src/include/stir/ZoomOptions.h +++ b/src/include/stir/ZoomOptions.h @@ -16,7 +16,7 @@ */ #ifndef __stir_ZOOMOPTIONS_H__ -#define __stir_ZOOMOPTIONS_H__ +#define __stir_ZOOMOPTIONS_H__ /*! \file @@ -26,7 +26,7 @@ \author Ludovica Brusaferri \author Kris Thielemans - + */ #include "stir/error.h" @@ -37,33 +37,32 @@ START_NAMESPACE_STIR \brief This class enables the user to choose between different zooming options \ingroup buildblock - + The 3 possible values determine a global scale factor used for the end result: (i) preserve sum (locally) (ii) preserve values (like interpolation) (iii) preserve projections: using a STIR forward projector on the zoomed image will give (approximately) the same projections. - + \see zoom_image */ -class ZoomOptions{ - public: - enum Scaling {preserve_sum, preserve_values, preserve_projections}; +class ZoomOptions { +public: + enum Scaling { preserve_sum, preserve_values, preserve_projections }; //! constructor from Scaling /*! calls error() if out-of-range */ - ZoomOptions(const Scaling v = preserve_sum) : v(v) - { - // need to catch out-of-range in case somebody did a static_cast from an int (e.g. SWIG does) - if ((v < preserve_sum) || (v > preserve_projections)) - error("ZoomOptions initialised with out-of-range value"); - } + ZoomOptions(const Scaling v = preserve_sum) : v(v) { + // need to catch out-of-range in case somebody did a static_cast from an int (e.g. SWIG does) + if ((v < preserve_sum) || (v > preserve_projections)) + error("ZoomOptions initialised with out-of-range value"); + } Scaling get_scaling_option() const { return v; } - private: + +private: Scaling v; }; END_NAMESPACE_STIR - #endif // ZOOMOPTIONS_H diff --git a/src/include/stir/analytic/FBP2D/FBP2DReconstruction.h b/src/include/stir/analytic/FBP2D/FBP2DReconstruction.h index f09d0933e1..60a347f8a3 100644 --- a/src/include/stir/analytic/FBP2D/FBP2DReconstruction.h +++ b/src/include/stir/analytic/FBP2D/FBP2DReconstruction.h @@ -21,9 +21,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup FBP2D - + \brief declares the stir::FBP2DReconstruction class \author Kris Thielemans @@ -39,7 +39,8 @@ START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; class Succeeded; class ProjData; @@ -67,7 +68,7 @@ xy output image size (in pixels) := 180 alpha parameter for ramp filter := 1 cut-off for ramp filter (in cycles) := 0.5 -; allow less padding. DO NOT USE +; allow less padding. DO NOT USE ; (unless you're sure that the object occupies only half the FOV) ;Transaxial extension for FFT:=1 @@ -76,73 +77,59 @@ cut-off for ramp filter (in cycles) := 0.5 ; display data during processing for debugging purposes ; Display level := 0 -end := +end := \endverbatim - alpha specifies the usual Hamming window (although I'm not so sure about the terminology here). So, + alpha specifies the usual Hamming window (although I'm not so sure about the terminology here). So, for the "ramp filter" alpha =1. In frequency space, something like (from RampFilter.cxx) \code (alpha + (1 - alpha) * cos(_PI * f / fc)) \endcode - + */ -class FBP2DReconstruction : - public - RegisteredParsingObject< - FBP2DReconstruction, - Reconstruction < DiscretisedDensity < 3,float> >, - AnalyticReconstruction - > -{ - //typedef AnalyticReconstruction base_type; - typedef - RegisteredParsingObject< - FBP2DReconstruction, - Reconstruction < DiscretisedDensity < 3,float> >, - AnalyticReconstruction - > base_type; +class FBP2DReconstruction + : public RegisteredParsingObject>, AnalyticReconstruction> { + // typedef AnalyticReconstruction base_type; + typedef RegisteredParsingObject>, AnalyticReconstruction> + base_type; #ifdef SWIG // work-around swig problem. It gets confused when using a private (or protected) // typedef in a definition of a public typedef/member public: #else - private: -#endif - typedef DiscretisedDensity < 3,float> TargetT; +private: +#endif + typedef DiscretisedDensity<3, float> TargetT; + public: - //! Name which will be used when parsing a ProjectorByBinPair object - static const char * const registered_name; + //! Name which will be used when parsing a ProjectorByBinPair object + static const char* const registered_name; //! Default constructor (calls set_defaults()) - FBP2DReconstruction (); + FBP2DReconstruction(); /*! \brief Constructor, initialises everything from parameter file, or (when parameter_filename == "") by calling ask_parameters(). */ - explicit - FBP2DReconstruction(const std::string& parameter_filename); - - FBP2DReconstruction(const shared_ptr&, - const double alpha_ramp=1., - const double fc_ramp=.5, - const int pad_in_s=2, - const int num_segments_to_combine=-1 - ); - + explicit FBP2DReconstruction(const std::string& parameter_filename); + + FBP2DReconstruction(const shared_ptr&, const double alpha_ramp = 1., const double fc_ramp = .5, + const int pad_in_s = 2, const int num_segments_to_combine = -1); + virtual std::string method_info() const; virtual void ask_parameters(); - virtual Succeeded set_up(shared_ptr const& target_data_sptr); + virtual Succeeded set_up(shared_ptr const& target_data_sptr); - protected: // make parameters protected such that doc shows always up in doxygen +protected: // make parameters protected such that doc shows always up in doxygen // parameters used for parsing //! Ramp filter: Alpha value double alpha_ramp; //! Ramp filter: Cut off frequency - double fc_ramp; + double fc_ramp; //! amount of padding for the filter (has to be 0,1 or 2) int pad_in_s; //! number of segments to combine (with SSRB) before starting 2D reconstruction @@ -153,25 +140,21 @@ class FBP2DReconstruction : */ int num_segments_to_combine; //! potentially display data - /*! allowed values: \c display_level=0 (no display), 1 (only final image), + /*! allowed values: \c display_level=0 (no display), 1 (only final image), 2 (filtered-viewgrams). Defaults to 0. */ int display_level; - private: - Succeeded actual_reconstruct(shared_ptr > const & target_image_ptr); + +private: + Succeeded actual_reconstruct(shared_ptr> const& target_image_ptr); shared_ptr back_projector_sptr; virtual void set_defaults(); virtual void initialise_keymap(); - virtual bool post_processing(); + virtual bool post_processing(); }; - - - END_NAMESPACE_STIR - #endif - diff --git a/src/include/stir/analytic/FBP2D/RampFilter.h b/src/include/stir/analytic/FBP2D/RampFilter.h index 83038685ca..35b37541d1 100644 --- a/src/include/stir/analytic/FBP2D/RampFilter.h +++ b/src/include/stir/analytic/FBP2D/RampFilter.h @@ -31,10 +31,10 @@ #define __stir_FBP2D_RampFilter_H__ #ifdef NRFFT -#include "stir_experimental/Filter.h" +# include "stir_experimental/Filter.h" #else -#include "stir/ArrayFilterUsingRealDFTWithPadding.h" -#include "stir/TimedObject.h" +# include "stir/ArrayFilterUsingRealDFTWithPadding.h" +# include "stir/TimedObject.h" #endif #include @@ -43,36 +43,36 @@ START_NAMESPACE_STIR \ingroup FBP2D \brief The ramp filter used for (2D) FBP - The filter has 2 parameters: a cut-off frequency \c fc and \c alpha which specifies the usual - Hamming window (although I'm not so sure about the terminology here). So, + The filter has 2 parameters: a cut-off frequency \c fc and \c alpha which specifies the usual + Hamming window (although I'm not so sure about the terminology here). So, for the "ramp filter" alpha =1. In frequency space, something like (from RampFilter.cxx) \code (alpha + (1 - alpha) * cos(_PI * f / fc)) \endcode - The actual implementation works differently to overcome problems with defining the ramp in frequency - space (with a well-known DC offset as consequence). We therefore compute the ramp*Hanning in - "ordinary" space in continuous form, do the sampling there, and then DFT it. + The actual implementation works differently to overcome problems with defining the ramp in frequency + space (with a well-known DC offset as consequence). We therefore compute the ramp*Hanning in + "ordinary" space in continuous form, do the sampling there, and then DFT it. */ -class RampFilter : +class RampFilter : #ifdef NRFFT - public Filter1D + public Filter1D #else - public ArrayFilterUsingRealDFTWithPadding<1,float>, - public TimedObject + public ArrayFilterUsingRealDFTWithPadding<1, float>, + public TimedObject #endif { private: float fc; float alpha; - float sampledist; - public: - RampFilter(float sampledist_v, int length_v , float alpha_v=1, float fc_v=.5); + float sampledist; - virtual std::string parameter_info() const; - +public: + RampFilter(float sampledist_v, int length_v, float alpha_v = 1, float fc_v = .5); + + virtual std::string parameter_info() const; }; END_NAMESPACE_STIR diff --git a/src/include/stir/analytic/FBP3DRP/ColsherFilter.h b/src/include/stir/analytic/FBP3DRP/ColsherFilter.h index 15756d93bc..9c6539cac8 100644 --- a/src/include/stir/analytic/FBP3DRP/ColsherFilter.h +++ b/src/include/stir/analytic/FBP3DRP/ColsherFilter.h @@ -1,8 +1,8 @@ // // -/*! - \file +/*! + \file \ingroup FBP3DRP \brief Colsher filter class \author Claire LABBE @@ -32,15 +32,16 @@ #define __ColsherFilter_H__ #ifdef NRFFT -#include "stir_experimental/Filter.h" +# include "stir_experimental/Filter.h" #else -#include "stir/ArrayFilterUsingRealDFTWithPadding.h" -#include "stir/TimedObject.h" +# include "stir/ArrayFilterUsingRealDFTWithPadding.h" +# include "stir/TimedObject.h" #endif START_NAMESPACE_STIR #ifdef NRFFT -template class Viewgram; +template +class Viewgram; #endif /*! @@ -49,92 +50,81 @@ template class Viewgram; The Colsher filter is combined with a 2-dimensional apodising Hamming filter. */ -class ColsherFilter: +class ColsherFilter : #ifdef NRFFT - public Filter2D + public Filter2D #else - public ArrayFilterUsingRealDFTWithPadding<2,float>, - public TimedObject + public ArrayFilterUsingRealDFTWithPadding<2, float>, + public TimedObject #endif { public: -#ifndef NRFFT +#ifndef NRFFT //! Default constructor /*! \warning Leaves object in ill-defined state*/ ColsherFilter() {} /*! \brief constructor for the ColsherFilter. - + \param theta_max - the polar angle corresponding to the maximum oblique angle - included in the reconstruction. + the polar angle corresponding to the maximum oblique angle + included in the reconstruction. - The \c alpha and \c fc parameters are designed to minimize the + The \c alpha and \c fc parameters are designed to minimize the amplification of noise. The \c stretch_factor parameters can be used to define the Colsher - filter via a finer grid to avoid the problems with sampling a - continuous filter in frequency space. For the ramp-filter, this can - be done using analytic integration, but here we have to do it numerically. + filter via a finer grid to avoid the problems with sampling a + continuous filter in frequency space. For the ramp-filter, this can + be done using analytic integration, but here we have to do it numerically. */ - explicit ColsherFilter(float theta_max, - float alpha_colsher_axial=1.F, float fc_colsher_axial=0.5F, - float alpha_colsher_radial=1.F, float fc_colsher_radial=0.5F, - const int stretch_factor_axial=2, - const int stretch_factor_planar=2); + explicit ColsherFilter(float theta_max, float alpha_colsher_axial = 1.F, float fc_colsher_axial = 0.5F, + float alpha_colsher_radial = 1.F, float fc_colsher_radial = 0.5F, const int stretch_factor_axial = 2, + const int stretch_factor_planar = 2); //! Initialise filter values /*! creates a 2D Colsher filter of size height*width, \param theta the polar angle \param d_a the sampling distance in the 's' coordinate \param d_b the sampling distance in the 't' coordinate */ - Succeeded - set_up(int height, int width, float theta, - float d_a, float d_b); + Succeeded set_up(int height, int width, float theta, float d_a, float d_b); #else - ColsherFilter(int height, int width, float gamma, float theta_max, - float d_a, float d_b, - float alpha_colsher_axial, float fc_colsher_axial, - float alpha_colsher_radial, float fc_colsher_radial); + ColsherFilter(int height, int width, float gamma, float theta_max, float d_a, float d_b, float alpha_colsher_axial, + float fc_colsher_axial, float alpha_colsher_radial, float fc_colsher_radial); #endif virtual std::string parameter_info() const; - - ~ColsherFilter() {} + ~ColsherFilter() {} - private: +private: #ifdef NRFFT - //! gamma is the polar angle - float gamma; - /* d_a, d_b are used to convert to millimeter.*/ - //! d_a is initialised with the sampling distance - float d_a; - //! d_b is initialised with ring spacing * sin(theta) - float d_b; + //! gamma is the polar angle + float gamma; + /* d_a, d_b are used to convert to millimeter.*/ + //! d_a is initialised with the sampling distance + float d_a; + //! d_b is initialised with ring spacing * sin(theta) + float d_b; #endif - //! theta_max corresponds to the maximum aperture in the reconstruction - float theta_max; - //! value of the axial alpha parameter for apodized Hamming window - float alpha_axial; - //! value of the axial cut-off frequency of the Colsher filter - float fc_axial; - //! value of the planar alpha parameter for apodized Hamming window - float alpha_planar; - //! value of the planar cut-off frequency of the Colsher filter - float fc_planar; - int stretch_factor_axial; - int stretch_factor_planar; + //! theta_max corresponds to the maximum aperture in the reconstruction + float theta_max; + //! value of the axial alpha parameter for apodized Hamming window + float alpha_axial; + //! value of the axial cut-off frequency of the Colsher filter + float fc_axial; + //! value of the planar alpha parameter for apodized Hamming window + float alpha_planar; + //! value of the planar cut-off frequency of the Colsher filter + float fc_planar; + int stretch_factor_axial; + int stretch_factor_planar; }; #ifdef NRFFT -void Filter_proj_Colsher(Viewgram & view_i, - Viewgram & view_i1, - ColsherFilter& CFilter, - int PadS, int PadZ); +void Filter_proj_Colsher(Viewgram& view_i, Viewgram& view_i1, ColsherFilter& CFilter, int PadS, int PadZ); #endif END_NAMESPACE_STIR #endif // __ColsherFilter_H__ - diff --git a/src/include/stir/analytic/FBP3DRP/FBP3DRPReconstruction.h b/src/include/stir/analytic/FBP3DRP/FBP3DRPReconstruction.h index 757d4025de..76dd24a7b5 100644 --- a/src/include/stir/analytic/FBP3DRP/FBP3DRPReconstruction.h +++ b/src/include/stir/analytic/FBP3DRP/FBP3DRPReconstruction.h @@ -18,8 +18,8 @@ See STIR/LICENSE.txt for details */ -/*! - \file +/*! + \file \ingroup FBP3DRP \brief Declaration of class stir::FBP3DRPReconstruction \author Claire LABBE @@ -30,8 +30,6 @@ #ifndef __stir_analytic_FBP3DRP_FBP3DRPRECONSTRUCTION_H__ #define __stir_analytic_FBP3DRP_FBP3DRPRECONSTRUCTION_H__ - - #include "stir/recon_buildblock/AnalyticReconstruction.h" #include "stir/ProjDataInfoCylindrical.h" #include "stir/recon_buildblock/ForwardProjectorByBin.h" @@ -43,11 +41,16 @@ START_NAMESPACE_STIR -template class RelatedViewgrams; -template class Sinogram; -template class SegmentBySinogram; -template class VoxelsOnCartesianGrid; -template class DiscretisedDensity; +template +class RelatedViewgrams; +template +class Sinogram; +template +class SegmentBySinogram; +template +class VoxelsOnCartesianGrid; +template +class DiscretisedDensity; class Succeeded; /* KT 180899 forget about PETAnalyticReconstruction for the moment @@ -59,7 +62,7 @@ class Succeeded; \brief This class contains the implementation of the FBP3DRP algorithm. This class implements the 3DRP algorithm (Kinahan and Rogers) as a specific - case of a 3D FBP reconstruction algorithm. + case of a 3D FBP reconstruction algorithm. Some care is taken to achieve a fairly general implementation. For instance, the number of sinograms @@ -69,8 +72,8 @@ class Succeeded; the same scale independent of the number of segments that is used. Nevertheless, this is an analytic algorithm, and it implements a discrete - version of a continuous inversion formula. This will work best (but of - course slowest) when the number of segments is large. + version of a continuous inversion formula. This will work best (but of + course slowest) when the number of segments is large. This implementation is specific for data using sampling corresponding to cylindrical PET scanners. @@ -80,47 +83,37 @@ class Succeeded; to make a version that works on e.g. spherical sampling. \par About zooming (rescaling + offset): - 1) The 2D FBP process works at full resolution, i.e on the original + 1) The 2D FBP process works at full resolution, i.e on the original number of bins, and with a pixel size equal to the bin size. 2) For the process of oblique sinograms: - - Forward projection works at full resolution i.e forward projection works - from images without zooming and complete missing projection data on normal sinograms - - Colsher filter is then applied on complete data - - 3D backprojection then puts this data into an image with - appropriate voxel sizes, i.e. it is up to the backprojector to perform - the zooming. - - So, no zooming is needed on the final image. - + - Forward projection works at full resolution i.e forward projection works + from images without zooming and complete missing projection data on normal sinograms + - Colsher filter is then applied on complete data + - 3D backprojection then puts this data into an image with + appropriate voxel sizes, i.e. it is up to the backprojector to perform + the zooming. + - So, no zooming is needed on the final image. -*/ -class FBP3DRPReconstruction: public - RegisteredParsingObject< - FBP3DRPReconstruction, - Reconstruction >, - AnalyticReconstruction - > -{ - //typedef AnalyticReconstruction base_type; - typedef RegisteredParsingObject< - FBP3DRPReconstruction, - Reconstruction >, - AnalyticReconstruction - > base_type; -public: - //! Name which will be used when parsing a ProjectorByBinPair object - static const char * const registered_name; +*/ +class FBP3DRPReconstruction : public RegisteredParsingObject>, + AnalyticReconstruction> { + // typedef AnalyticReconstruction base_type; + typedef RegisteredParsingObject>, AnalyticReconstruction> + base_type; +public: + //! Name which will be used when parsing a ProjectorByBinPair object + static const char* const registered_name; //! Default constructor (calls set_defaults()) - FBP3DRPReconstruction (); + FBP3DRPReconstruction(); /*! \brief Constructor, initialises everything from parameter file, or (when parameter_filename == "") by calling ask_parameters(). */ - explicit - FBP3DRPReconstruction(const std::string& parameter_filename); + explicit FBP3DRPReconstruction(const std::string& parameter_filename); // explicitly implement destructor (NOT inline) to avoid funny problems with // the shared_ptr > destructor with gcc. @@ -128,96 +121,80 @@ class FBP3DRPReconstruction: public // because it doesn't know ~DiscretisedDensity. ~FBP3DRPReconstruction(); -//! This method returns the type of the reconstruction algorithm during the reconstruction, here it is FBP3DRP + //! This method returns the type of the reconstruction algorithm during the reconstruction, here it is FBP3DRP virtual std::string method_info() const; - Succeeded - set_up(shared_ptr > const& target_image_sptr); + Succeeded set_up(shared_ptr> const& target_image_sptr); protected: -/*! - \brief Implementation of the reconstruction - - This method implements the reconstruction by giving as input the emission sinogram data corrected for attenuation, - scatter, dead time, - and returns the output reconstructed image -*/ + /*! + \brief Implementation of the reconstruction + + This method implements the reconstruction by giving as input the emission sinogram data corrected for attenuation, + scatter, dead time, + and returns the output reconstructed image + */ - virtual Succeeded actual_reconstruct(shared_ptr > const&); - -//! Best fit of forward projected sinograms - void do_best_fit(const Sinogram &sino_measured, const Sinogram &sino_calculated); + virtual Succeeded actual_reconstruct(shared_ptr> const&); + //! Best fit of forward projected sinograms + void do_best_fit(const Sinogram& sino_measured, const Sinogram& sino_calculated); -//! 2D FBP implementation. - void do_2D_reconstruction(); - -//! Save image data. - void do_save_img(const char *file, const VoxelsOnCartesianGrid &data) const; + //! 2D FBP implementation. + void do_2D_reconstruction(); -//! Read image estimated from 2D FBP - void do_read_image2D(); + //! Save image data. + void do_save_img(const char* file, const VoxelsOnCartesianGrid& data) const; - -//! 3D reconstruction implementation. - void do_3D_Reconstruction( VoxelsOnCartesianGrid &image); + //! Read image estimated from 2D FBP + void do_read_image2D(); -//! Arc-correction viewgrams - void do_arc_correction(RelatedViewgrams & viewgrams) const; - -//! Growing 8 viewgrams in both ring and bin directions. - void do_grow3D_viewgram(RelatedViewgrams & viewgrams, - int rmin, int rmax); -//! 3D forward projection implentation by view. - void do_forward_project_view(RelatedViewgrams & viewgrams, - int rmin, int rmax, - int orig_min_ring, int orig_max_ring) const; -//! Apply Colsher filter to 8 viewgrams. - void do_colsher_filter_view( RelatedViewgrams & viewgrams); -//! 3D backprojection implentation for 8 viewgrams. - void do_3D_backprojection_view(RelatedViewgrams const & viewgrams, - int rmin, int rmax); -//! Saving CPU timing and values of reconstruction parameters into a log file. - void do_log_file(const VoxelsOnCartesianGrid &image); + //! 3D reconstruction implementation. + void do_3D_Reconstruction(VoxelsOnCartesianGrid& image); + //! Arc-correction viewgrams + void do_arc_correction(RelatedViewgrams& viewgrams) const; + //! Growing 8 viewgrams in both ring and bin directions. + void do_grow3D_viewgram(RelatedViewgrams& viewgrams, int rmin, int rmax); + //! 3D forward projection implentation by view. + void do_forward_project_view(RelatedViewgrams& viewgrams, int rmin, int rmax, int orig_min_ring, + int orig_max_ring) const; + //! Apply Colsher filter to 8 viewgrams. + void do_colsher_filter_view(RelatedViewgrams& viewgrams); + //! 3D backprojection implentation for 8 viewgrams. + void do_3D_backprojection_view(RelatedViewgrams const& viewgrams, int rmin, int rmax); + //! Saving CPU timing and values of reconstruction parameters into a log file. + void do_log_file(const VoxelsOnCartesianGrid& image); + virtual void do_byview_initialise(const VoxelsOnCartesianGrid& image) const {}; - virtual void do_byview_initialise(const VoxelsOnCartesianGrid& image) const - {}; + virtual void do_byview_finalise(VoxelsOnCartesianGrid& image){}; - virtual void do_byview_finalise(VoxelsOnCartesianGrid& image) {}; public: - // KT 230899 this has to be public to let the Para stuff access it (sadly) - - virtual void do_process_viewgrams( - RelatedViewgrams & viewgrams, - int rmin, int rmax, - int orig_min_ring, int orig_max_ring); + // KT 230899 this has to be public to let the Para stuff access it (sadly) - // parameters stuff - public: + virtual void do_process_viewgrams(RelatedViewgrams& viewgrams, int rmin, int rmax, int orig_min_ring, int orig_max_ring); - + // parameters stuff +public: void ask_parameters(); - protected: - //! Switch to display intermediate images, 0,1,2 int display_level; //! Switch to save files after each segment, 0 or 1 int save_intermediate_files; - + //! Filename of image used in the reprojection step (default is empty) - /*! If the filename is empty, FBP is used (with filter parameters as - specified further). + /*! If the filename is empty, FBP is used (with filter parameters as + specified further). - \warning This image must have the correct scale. That is, if you use the - forward projector on it, you get sinograms of the same scale as the + \warning This image must have the correct scale. That is, if you use the + forward projector on it, you get sinograms of the same scale as the input sinograms. There is NO check on this. - */ + */ std::string image_for_reprojection_filename; //! Number of segments to combine with SSRB before calling FBP @@ -225,58 +202,55 @@ class FBP3DRPReconstruction: public int num_segments_to_combine; //! Transaxial extension for FFT - int PadS; + int PadS; //! Axial extension for FFT int PadZ; //! Ramp filter: Alpha value double alpha_ramp; //! Ramp filter: Cut off frequency - double fc_ramp; + double fc_ramp; //! Alpha parameter for Colsher filter in axial direction double alpha_colsher_axial; //! Cut-off frequency for Colsher filter in axial direction double fc_colsher_axial; //! Alpha parameter for Colsher filter in planar direction - double alpha_colsher_planar; + double alpha_colsher_planar; //! Cut-off frequency for Colsher filter in planar direction - double fc_colsher_planar; + double fc_colsher_planar; //! Define Colsher at larger size than used for filtering, axial direction int colsher_stretch_factor_axial; //! Define Colsher at larger size than used for filtering, planar direction int colsher_stretch_factor_planar; - //! =1 => apply additional fitting procedure to forward projected data (DISABLED) - int fit_projections; -private: + int fit_projections; +private: virtual void set_defaults(); virtual void initialise_keymap(); - //! access to input proj_data_info cast to cylindrical type const ProjDataInfoCylindrical& input_proj_data_info_cyl() const; //! Size info for the projection data with missing data filled in shared_ptr proj_data_info_with_missing_data_sptr; - shared_ptr > image_estimate_density_ptr; + shared_ptr> image_estimate_density_ptr; // convenience access functions to the above member - inline VoxelsOnCartesianGrid& estimated_image(); - inline const VoxelsOnCartesianGrid& estimated_image() const; + inline VoxelsOnCartesianGrid& estimated_image(); + inline const VoxelsOnCartesianGrid& estimated_image() const; - shared_ptr forward_projector_sptr; + shared_ptr forward_projector_sptr; shared_ptr back_projector_sptr; #ifndef NRFFT ColsherFilter colsher_filter; #endif float alpha_fit; float beta_fit; - + shared_ptr arc_correction_sptr; }; END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/array_index_functions.h b/src/include/stir/array_index_functions.h index f66358ba0f..1de1bcb140 100644 --- a/src/include/stir/array_index_functions.h +++ b/src/include/stir/array_index_functions.h @@ -21,53 +21,45 @@ #define __stir_array_index_functions_h_ /*! - \file + \file \ingroup Array - + \brief a variety of useful functions for indexing stir::Array objects \author Kris Thielemans */ - #include "stir/Array.h" #include "stir/BasicCoordinate.h" START_NAMESPACE_STIR -#if !defined(_MSC_VER) || _MSC_VER>1200 +#if !defined(_MSC_VER) || _MSC_VER > 1200 // VC 6.0 needs ugly work-arounds. We'll put these in the .inl file /* \ingroup Array \name Functions for writing generic code with indexing of multi-dimensional arrays */ -//@{ +//@{ //! an alternative for array indexing using BasicCoordinate objects /*! Case where the index has lower dimension than the array*/ template -inline -const Array& -get(const Array& a, const BasicCoordinate &c); +inline const Array& get(const Array& a, + const BasicCoordinate& c); //! an alternative for array indexing using BasicCoordinate objects /*! Case where the index has the same dimension as the array*/ template -inline -const elemT& -get(const Array& a, const BasicCoordinate &c); - +inline const elemT& get(const Array& a, const BasicCoordinate& c); //! Get the first multi-dimensional index of the array /*! \todo If the array \arg a is empty, we return an object where all indices are 0. It would be better to throw an exception. */ template -inline -BasicCoordinate -get_min_indices(const Array& a); - +inline BasicCoordinate get_min_indices(const Array& a); //! Given an index into an array, increment it to the next one /*! @@ -78,22 +70,18 @@ get_min_indices(const Array& a); Array array = ...; BasicCoordinate indices = get_min_indices(array); - do + do { something with indices } while (next(indices, array)); \endcode \warning The above loop will fail for empty arrays */ template -inline -bool -next(BasicCoordinate& indices, - const Array& a); +inline bool next(BasicCoordinate& indices, const Array& a); //@} #endif // end of VC 6.0 conditional - END_NAMESPACE_STIR #include "stir/array_index_functions.inl" diff --git a/src/include/stir/array_index_functions.inl b/src/include/stir/array_index_functions.inl index 5e5501216c..567720dd61 100644 --- a/src/include/stir/array_index_functions.inl +++ b/src/include/stir/array_index_functions.inl @@ -17,9 +17,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup Array - + \brief implementation of functions in stir/array_index_functions.h \author Kris Thielemans @@ -36,122 +36,96 @@ START_NAMESPACE_STIR /* First we define the functions that actually do the work. - The code is a bit more complicated than need be because we try to accomodate - older compilers that have trouble with function overloading of templates. + The code is a bit more complicated than need be because we try to accomodate + older compilers that have trouble with function overloading of templates. See test_if_1d for some info. */ -namespace detail -{ +namespace detail { template -inline -BasicCoordinate -get_min_indices_help(is_not_1d, const Array& a) -{ - if (a.get_min_index()<=a.get_max_index()) +inline BasicCoordinate +get_min_indices_help(is_not_1d, const Array& a) { + if (a.get_min_index() <= a.get_max_index()) return join(a.get_min_index(), get_min_indices(*a.begin())); - else - { - // a is empty. Not clear what to return, so we just return 0 - // It would be better to throw an exception. - BasicCoordinate tmp(0); - return tmp; - } + else { + // a is empty. Not clear what to return, so we just return 0 + // It would be better to throw an exception. + BasicCoordinate tmp(0); + return tmp; + } } template -inline -BasicCoordinate<1, int> -get_min_indices_help(is_1d, const Array<1, T>& a) -{ +inline BasicCoordinate<1, int> +get_min_indices_help(is_1d, const Array<1, T>& a) { BasicCoordinate<1, int> result; result[1] = a.get_min_index(); return result; } template -inline -bool -next_help(is_1d, BasicCoordinate<1, int>& index, - const Array& a) -{ - if (a.get_min_index()>a.get_max_index()) +inline bool +next_help(is_1d, BasicCoordinate<1, int>& index, const Array& a) { + if (a.get_min_index() > a.get_max_index()) return false; - assert(index[1]>=a.get_min_index()); - assert(index[1]<=a.get_max_index()); + assert(index[1] >= a.get_min_index()); + assert(index[1] <= a.get_max_index()); index[1]++; - return index[1]<=a.get_max_index(); + return index[1] <= a.get_max_index(); } template -inline -bool -next_help(is_not_1d, - BasicCoordinate& index, - const Array& a) -{ - if (a.get_min_index()>a.get_max_index()) +inline bool +next_help(is_not_1d, BasicCoordinate& index, const Array& a) { + if (a.get_min_index() > a.get_max_index()) return false; - BasicCoordinate upper_index= cut_last_dimension(index); - assert(index[num_dimensions]>=get(a,upper_index).get_min_index()); - assert(index[num_dimensions]<=get(a,upper_index).get_max_index()); + BasicCoordinate upper_index = cut_last_dimension(index); + assert(index[num_dimensions] >= get(a, upper_index).get_min_index()); + assert(index[num_dimensions] <= get(a, upper_index).get_max_index()); index[num_dimensions]++; - if (index[num_dimensions]<=get(a,upper_index).get_max_index()) + if (index[num_dimensions] <= get(a, upper_index).get_max_index()) return true; if (!next(upper_index, a)) return false; - index=join(upper_index, get(a,upper_index).get_min_index()); + index = join(upper_index, get(a, upper_index).get_min_index()); return true; } } // end of namespace detail - /* Now define the functions in the stir namespace in terms of the above. Also define get() for which I didn't bother to try the work-arounds, as they don't work for VC 6.0 anyway... */ template -inline -BasicCoordinate -get_min_indices(const Array& a) -{ +inline BasicCoordinate +get_min_indices(const Array& a) { return detail::get_min_indices_help(detail::test_if_1d(), a); } -#if !defined(_MSC_VER) || _MSC_VER>1200 +#if !defined(_MSC_VER) || _MSC_VER > 1200 template -inline -bool -next(BasicCoordinate& index, - const Array& a) -{ +inline bool +next(BasicCoordinate& index, const Array& a) { return detail::next_help(detail::test_if_1d(), index, a); } template -inline -const Array& -get(const Array& a, const BasicCoordinate &c) -{ - return get(a[c[1]],cut_first_dimension(c)); +inline const Array& +get(const Array& a, const BasicCoordinate& c) { + return get(a[c[1]], cut_first_dimension(c)); } template -inline -const elemT& -get(const Array& a, const BasicCoordinate &c) -{ +inline const elemT& +get(const Array& a, const BasicCoordinate& c) { return a[c]; -} +} template -inline -const Array& -get(const Array& a, const BasicCoordinate<1,int> &c) -{ - return a[c[1]]; -} - +inline const Array& +get(const Array& a, const BasicCoordinate<1, int>& c) { + return a[c[1]]; +} #else @@ -165,88 +139,73 @@ get(const Array& a, const BasicCoordinate<1,int> &c) Aside from that, the actual code really should be the same. */ -#define GET(num_dimensions, num_dimensions2) \ -template \ -inline \ -const Array& \ -get(const Array& a, const BasicCoordinate &c) \ -{ \ - return get(a[c[1]],cut_first_dimension(c)); \ -} +# define GET(num_dimensions, num_dimensions2) \ + template \ + inline const Array& get(const Array& a, \ + const BasicCoordinate& c) { \ + return get(a[c[1]], cut_first_dimension(c)); \ + } -#define GET_EQUAL_DIM(num_dimensions) \ -template \ -inline \ -const elemT& \ -get(const Array& a, const BasicCoordinate &c) \ -{ \ - return a[c]; \ -} - -#define GET_1D(num_dimensions) \ -template \ -inline \ -const Array& \ -get(const Array& a, const BasicCoordinate<1,int> &c) \ -{ \ - return a[c[1]]; \ -} +# define GET_EQUAL_DIM(num_dimensions) \ + template \ + inline const elemT& get(const Array& a, const BasicCoordinate& c) { \ + return a[c]; \ + } + +# define GET_1D(num_dimensions) \ + template \ + inline const Array& get(const Array& a, \ + const BasicCoordinate<1, int>& c) { \ + return a[c[1]]; \ + } GET_1D(2) GET_1D(3) GET_EQUAL_DIM(1) GET_EQUAL_DIM(2) GET_EQUAL_DIM(3) -GET(3,2) - -#undef GET_1D -#undef GET_EQUAL_DIM -#undef GET - - -#define DEFINE_NEXT_1D(num_dimensions2) \ -template \ -inline bool \ -next(BasicCoordinate<1, int>& index, \ - const Array& a) \ -{ if (a.get_min_index()>a.get_max_index())\ - return false;\ - assert(index[1]>=a.get_min_index()); \ - assert(index[1]<=a.get_max_index()); \ - index[1]++;\ - return index[1]<=a.get_max_index();\ -} - -#define DEFINE_NEXT(num_dimensions, num_dimensions2) \ -template \ -inline bool \ -next(BasicCoordinate& index, \ - const Array& a) \ -{\ - if (a.get_min_index()>a.get_max_index()) \ - return false; \ - BasicCoordinate upper_index= cut_last_dimension(index);\ - assert(index[num_dimensions]>=get(a,upper_index).get_min_index());\ - assert(index[num_dimensions]<=get(a,upper_index).get_max_index());\ - index[num_dimensions]++;\ - if (index[num_dimensions]<=get(a,upper_index).get_max_index())\ - return true;\ - if (!next(upper_index, a))\ - return false;\ - index=join(upper_index, get(a,upper_index).get_min_index());\ -} - +GET(3, 2) + +# undef GET_1D +# undef GET_EQUAL_DIM +# undef GET + +# define DEFINE_NEXT_1D(num_dimensions2) \ + template \ + inline bool next(BasicCoordinate<1, int>& index, const Array& a) { \ + if (a.get_min_index() > a.get_max_index()) \ + return false; \ + assert(index[1] >= a.get_min_index()); \ + assert(index[1] <= a.get_max_index()); \ + index[1]++; \ + return index[1] <= a.get_max_index(); \ + } +# define DEFINE_NEXT(num_dimensions, num_dimensions2) \ + template \ + inline bool next(BasicCoordinate& index, const Array& a) { \ + if (a.get_min_index() > a.get_max_index()) \ + return false; \ + BasicCoordinate upper_index = cut_last_dimension(index); \ + assert(index[num_dimensions] >= get(a, upper_index).get_min_index()); \ + assert(index[num_dimensions] <= get(a, upper_index).get_max_index()); \ + index[num_dimensions]++; \ + if (index[num_dimensions] <= get(a, upper_index).get_max_index()) \ + return true; \ + if (!next(upper_index, a)) \ + return false; \ + index = join(upper_index, get(a, upper_index).get_min_index()); \ + } DEFINE_NEXT_1D(1) DEFINE_NEXT_1D(2) DEFINE_NEXT_1D(3) -DEFINE_NEXT(2,2) -DEFINE_NEXT(2,3) -DEFINE_NEXT(3,3) +DEFINE_NEXT(2, 2) +DEFINE_NEXT(2, 3) +DEFINE_NEXT(3, 3) -#undef DEFINE_NEXT_1D -#undef DEFINE_NEXT +# undef DEFINE_NEXT_1D +# undef DEFINE_NEXT #endif // end of VC 6.0 code diff --git a/src/include/stir/assign.h b/src/include/stir/assign.h index 05694d3815..2aa2a02d30 100644 --- a/src/include/stir/assign.h +++ b/src/include/stir/assign.h @@ -20,26 +20,26 @@ #define __stir_assign_H__ /*! - \file + \file \ingroup buildblock \brief defines the stir::assign function to assign values to different data types - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/VectorWithOffset.h" #include "stir/Array.h" -#include "stir/BasicCoordinate.h" +#include "stir/BasicCoordinate.h" #include START_NAMESPACE_STIR /*! \ingroup buildblock \name templated functions for assigning values - When writing templated code, it is sometimes not possible to use \c operator=() + When writing templated code, it is sometimes not possible to use \c operator=() for assignment, e.g. when the classes do not support that operator. The \c assign template tries to alleviate this problem by providing several - overloads when the first argument is a (STIR) container. + overloads when the first argument is a (STIR) container. \par Usage \code @@ -52,78 +52,65 @@ START_NAMESPACE_STIR */ //@{ // TODO hopefully next ifdef is not necessary. Otherwise we need to have more for ints etc -#if defined(_MSC_VER) && _MSC_VER<=1300 -inline -void assign(double& x, const double y) -{ - x=y; +#if defined(_MSC_VER) && _MSC_VER <= 1300 +inline void +assign(double& x, const double y) { + x = y; } -static inline -void assign(float& x, const float y) -{ - x=y; +static inline void +assign(float& x, const float y) { + x = y; } #else template - inline - void assign(T& x, const T2& y) -{ - x=y; +inline void +assign(T& x, const T2& y) { + x = y; } #endif template -inline -void assign(std::vector& v, const T2& y) -{ - for (typename std::vector::iterator iter = v.begin(); - iter != v.end(); ++iter) +inline void +assign(std::vector& v, const T2& y) { + for (typename std::vector::iterator iter = v.begin(); iter != v.end(); ++iter) assign(*iter, y); } template -inline -void assign(BasicCoordinate& v, const T2& y) -{ - for (typename BasicCoordinate::iterator iter = v.begin(); - iter != v.end(); ++iter) +inline void +assign(BasicCoordinate& v, const T2& y) { + for (typename BasicCoordinate::iterator iter = v.begin(); iter != v.end(); ++iter) assign(*iter, y); } template -inline -void assign(VectorWithOffset& v, const T2& y) -{ - for (typename VectorWithOffset::iterator iter = v.begin(); - iter != v.end(); ++iter) +inline void +assign(VectorWithOffset& v, const T2& y) { + for (typename VectorWithOffset::iterator iter = v.begin(); iter != v.end(); ++iter) assign(*iter, y); } -// Even though we have VectorWithOffset above, we still seem to need a version for Arrays as well +// Even though we have VectorWithOffset above, we still seem to need a version for Arrays as well // for when calling assign(vector >, 0). // We're not sure why... template -inline - void assign(Array& v, const T2& y) -{ - for (typename Array::full_iterator iter = v.begin_all(); - iter != v.end_all(); ++iter) +inline void +assign(Array& v, const T2& y) { + for (typename Array::full_iterator iter = v.begin_all(); iter != v.end_all(); ++iter) assign(*iter, y); } // a few common cases given explictly here such that we don't get conversion warnings all the time. -inline -void assign(double& x, const int y) -{ - x=static_cast(y); +inline void +assign(double& x, const int y) { + x = static_cast(y); } -inline -void assign(float& x, const int y) -{ - x=static_cast(y); +inline void +assign(float& x, const int y) { + x = static_cast(y); } //@} diff --git a/src/include/stir/assign_to_subregion.h b/src/include/stir/assign_to_subregion.h index 8a686c186f..e54f2c346d 100644 --- a/src/include/stir/assign_to_subregion.h +++ b/src/include/stir/assign_to_subregion.h @@ -20,8 +20,8 @@ #define __stir_assign_to_subregion_H__ /*! - \file - \ingroup Array + \file + \ingroup Array \brief declares the stir::assign_to_subregion function \author Kris Thielemans @@ -31,23 +31,18 @@ START_NAMESPACE_STIR -/*! +/*! \ingroup Array \brief assign a value to a sub-region of an array sets all values for indices between \a mask_location - \a half_size and \a mask_location + \a half_size to \a value, taking care of staying inside the index-range of the array. */ -template -inline void -assign_to_subregion(Array<3,elemT>& input_array, - const BasicCoordinate<3,int>& mask_location, - const BasicCoordinate<3,int>& half_size, - const elemT& value); +template +inline void assign_to_subregion(Array<3, elemT>& input_array, const BasicCoordinate<3, int>& mask_location, + const BasicCoordinate<3, int>& half_size, const elemT& value); END_NAMESPACE_STIR #include "stir/assign_to_subregion.inl" #endif - - diff --git a/src/include/stir/assign_to_subregion.inl b/src/include/stir/assign_to_subregion.inl index 916951f052..a8edd28736 100644 --- a/src/include/stir/assign_to_subregion.inl +++ b/src/include/stir/assign_to_subregion.inl @@ -16,8 +16,8 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup Array + \file + \ingroup Array \brief implementation of the stir::assign_to_subregion function \author Kris Thielemans @@ -27,30 +27,25 @@ START_NAMESPACE_STIR -template -void -assign_to_subregion(Array<3,elemT>& input_array, - const BasicCoordinate<3,int>& mask_location, - const BasicCoordinate<3,int>& half_mask_size, - const elemT& value) -{ +template +void +assign_to_subregion(Array<3, elemT>& input_array, const BasicCoordinate<3, int>& mask_location, + const BasicCoordinate<3, int>& half_mask_size, const elemT& value) { const int min_k_index = input_array.get_min_index(); const int max_k_index = input_array.get_max_index(); - for ( int k = std::max(mask_location[1]-half_mask_size[1],min_k_index); k<= std::min(mask_location[1]+half_mask_size[1],max_k_index); ++k) - { - const int min_j_index = input_array[k].get_min_index(); - const int max_j_index = input_array[k].get_max_index(); - for ( int j = std::max(mask_location[2]-half_mask_size[2],min_j_index); j<= std::min(mask_location[2]+half_mask_size[2],max_j_index); ++j) - { - const int min_i_index = input_array[k][j].get_min_index(); - const int max_i_index = input_array[k][j].get_max_index(); - for ( int i = std::max(mask_location[3]-half_mask_size[3],min_i_index); i<= std::min(mask_location[3]+half_mask_size[3],max_i_index); ++i) - input_array[k][j][i] = value; - } - } -} - -END_NAMESPACE_STIR - - + for (int k = std::max(mask_location[1] - half_mask_size[1], min_k_index); + k <= std::min(mask_location[1] + half_mask_size[1], max_k_index); ++k) { + const int min_j_index = input_array[k].get_min_index(); + const int max_j_index = input_array[k].get_max_index(); + for (int j = std::max(mask_location[2] - half_mask_size[2], min_j_index); + j <= std::min(mask_location[2] + half_mask_size[2], max_j_index); ++j) { + const int min_i_index = input_array[k][j].get_min_index(); + const int max_i_index = input_array[k][j].get_max_index(); + for (int i = std::max(mask_location[3] - half_mask_size[3], min_i_index); + i <= std::min(mask_location[3] + half_mask_size[3], max_i_index); ++i) + input_array[k][j][i] = value; + } + } +} +END_NAMESPACE_STIR diff --git a/src/include/stir/centre_of_gravity.h b/src/include/stir/centre_of_gravity.h index c7e62ec2b3..51b4ecf5cd 100644 --- a/src/include/stir/centre_of_gravity.h +++ b/src/include/stir/centre_of_gravity.h @@ -17,9 +17,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup Array - + \brief This file contains functions to compute the centre of gravity of arrays and images. \author Kris Thielemans @@ -30,11 +30,16 @@ START_NAMESPACE_STIR // predeclerations to avoid having to include the files and create unnecessary // dependencies -template class BasicCoordinate; -template class Array; -template class VectorWithOffset; -template class CartesianCoordinate3D; -template class VoxelsOnCartesianGrid; +template +class BasicCoordinate; +template +class Array; +template +class VectorWithOffset; +template +class CartesianCoordinate3D; +template +class VoxelsOnCartesianGrid; //! Compute centre of gravity of a vector but without dividing by its sum /*! \ingroup Array @@ -44,8 +49,7 @@ template class VoxelsOnCartesianGrid; \f] */ template -T -find_unweighted_centre_of_gravity_1d(const VectorWithOffset& row); +T find_unweighted_centre_of_gravity_1d(const VectorWithOffset& row); //! Compute centre of gravity of an Array but without dividing by its sum /*! \ingroup Array @@ -55,24 +59,22 @@ find_unweighted_centre_of_gravity_1d(const VectorWithOffset& row); \f] */ template -BasicCoordinate -find_unweighted_centre_of_gravity(const Array& ); +BasicCoordinate find_unweighted_centre_of_gravity(const Array&); //! Compute centre of gravity of a 1D Array but without dividing by its sum /*! \ingroup Array Conceptually the same as the n-dimensional version, but returns a \c T, not a BasicCoordinate\<1,T\>. -*/ +*/ #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template #else -#define T float +# define T float #endif -T -find_unweighted_centre_of_gravity(const Array<1,T>& ); +T find_unweighted_centre_of_gravity(const Array<1, T>&); #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -#undef T +# undef T #endif //! Compute centre of gravity of an Array @@ -84,8 +86,7 @@ find_unweighted_centre_of_gravity(const Array<1,T>& ); \todo better error handling */ template -BasicCoordinate -find_centre_of_gravity(const Array& ); +BasicCoordinate find_centre_of_gravity(const Array&); //! Computes centre of gravity for each plane /*! \ingroup Array @@ -100,17 +101,14 @@ find_centre_of_gravity(const Array& ); simply set to 0. */ template -void -find_centre_of_gravity_in_mm_per_plane( VectorWithOffset< CartesianCoordinate3D >& allCoG, - VectorWithOffset& weights, - const VoxelsOnCartesianGrid& image); +void find_centre_of_gravity_in_mm_per_plane(VectorWithOffset>& allCoG, VectorWithOffset& weights, + const VoxelsOnCartesianGrid& image); //! Computes centre of gravity of an image /*! \ingroup Array The result is in mm in STIR physical coordinates, i.e. taking the origin into account. */ template -CartesianCoordinate3D -find_centre_of_gravity_in_mm(const VoxelsOnCartesianGrid& image); +CartesianCoordinate3D find_centre_of_gravity_in_mm(const VoxelsOnCartesianGrid& image); END_NAMESPACE_STIR diff --git a/src/include/stir/common.h b/src/include/stir/common.h index 7ce119080d..ef3c7a7308 100644 --- a/src/include/stir/common.h +++ b/src/include/stir/common.h @@ -15,15 +15,15 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - See STIR/LICENSE.txt for details + See STIR/LICENSE.txt for details */ #ifndef __stir_common_H__ #define __stir_common_H__ /*! - \file - \ingroup buildblock - \brief basic configuration include file + \file + \ingroup buildblock + \brief basic configuration include file \author Kris Thielemans \author Alexey Zverovich @@ -34,14 +34,14 @@ - This include file defines some commonly used macros, templates + This include file defines some commonly used macros, templates and functions in an attempt to smooth out some system dependencies. It also defines some functions which are used very often.

    Macros and system dependencies:

      -
    • macros for namespace support: +
    • macros for namespace support: #defines STIR_NO_NAMESPACES if the compiler does not support namespaces #defines START_NAMESPACE_STIR etc. @@ -54,7 +54,7 @@ class B:A { virtual B* f(); } \endcode -
    • preprocessor definitions which attempt to determine the +
    • preprocessor definitions which attempt to determine the operating system this is going to run on. use as #ifdef __OS_WIN__ ... #elif ... #endif Possible values are __OS_WIN__, __OS_MAC__, __OS_VAX__, __OS_UNIX__ @@ -62,7 +62,7 @@ out on __OS_AIX__, __OS_SUN__, __OS_OSF__, __OS_LINUX__. (If the attempts fail to determine the correct OS, you can pass the correct value as a preprocessor definition to the compiler) - +
    • #includes cstdio, cstdlib, cstring, cmath
    • a trick to get ANSI C++ 'for' scoping rules work for compilers @@ -75,12 +75,12 @@

      Speeding up std::copy

        -
      • For old compilers (check the source!), overloads of std::copy for built-in +
      • For old compilers (check the source!), overloads of std::copy for built-in types to use memmove (so it's faster)

      stir namespace members declared here

      - +
      • const double _PI
      • @@ -106,142 +106,164 @@ //*************** namespace macros #ifndef STIR_NO_NAMESPACES -# define START_NAMESPACE_STIR namespace stir { -# define END_NAMESPACE_STIR } -# define USING_NAMESPACE_STIR using namespace stir; -# define START_NAMESPACE_STD namespace std { -# define END_NAMESPACE_STD } -# define USING_NAMESPACE_STD using namespace std; +# define START_NAMESPACE_STIR namespace stir { +# define END_NAMESPACE_STIR } +# define USING_NAMESPACE_STIR using namespace stir; +# define START_NAMESPACE_STD namespace std { +# define END_NAMESPACE_STD } +# define USING_NAMESPACE_STD using namespace std; #else -# define START_NAMESPACE_STIR -# define END_NAMESPACE_STIR -# define USING_NAMESPACE_STIR -# define START_NAMESPACE_STD -# define END_NAMESPACE_STD -# define USING_NAMESPACE_STD +# define START_NAMESPACE_STIR +# define END_NAMESPACE_STIR +# define USING_NAMESPACE_STIR +# define START_NAMESPACE_STD +# define END_NAMESPACE_STD +# define USING_NAMESPACE_STD #endif - //*************** define __OS_xxx__ -#if !defined(__OS_WIN__) && !defined(__OS_MAC__) && !defined(__OS_VAX__) && !defined(__OS_UNIX__) +#if !defined(__OS_WIN__) && !defined(__OS_MAC__) && !defined(__OS_VAX__) && !defined(__OS_UNIX__) // if none of these macros is defined externally, we attempt to guess, defaulting to UNIX -#ifdef __MSL__ - // Metrowerks CodeWarrior - // first set its own macro -# if macintosh && !defined(__dest_os) -# define __dest_os __mac_os -# endif -# if __dest_os == __mac_os -# define __OS_MAC__ -# else +# ifdef __MSL__ +// Metrowerks CodeWarrior +// first set its own macro +# if macintosh && !defined(__dest_os) +# define __dest_os __mac_os +# endif +# if __dest_os == __mac_os +# define __OS_MAC__ +# else +# define __OS_WIN__ +# endif + +# elif defined(_WIN32) || defined(WIN32) || defined(_WINDOWS) || defined(_DOS) +// Visual C++, MSC, cygwin gcc and hopefully some others # define __OS_WIN__ -# endif -#elif defined(_WIN32) || defined(WIN32) || defined(_WINDOWS) || defined(_DOS) - // Visual C++, MSC, cygwin gcc and hopefully some others -# define __OS_WIN__ - -#elif defined(VAX) - // Just in case anyone is still using VAXes... -# define __OS_VAX__ - -#else // default - -# define __OS_UNIX__ - // subcases -# if defined(_AIX) -# define __OS_AIX__ -# elif defined(__sun) - // should really branch on SunOS and Solaris... -# define __OS_SUN__ -# elif defined(__linux__) -# define __OS_LINUX__ -# elif defined(__osf__) -# defined __OS_OSF__ -# endif +# elif defined(VAX) +// Just in case anyone is still using VAXes... +# define __OS_VAX__ + +# else // default + +# define __OS_UNIX__ +// subcases +# if defined(_AIX) +# define __OS_AIX__ +# elif defined(__sun) +// should really branch on SunOS and Solaris... +# define __OS_SUN__ +# elif defined(__linux__) +# define __OS_LINUX__ +# elif defined(__osf__) +# defined __OS_OSF__ +# endif -#endif // __OS_UNIX_ case +# endif // __OS_UNIX_ case #endif // !defined(__OS_xxx_) //*************** overload std::copy for built-in types -/* If you have an older compiler, chages are that std::copy is - implemented in the obvious way of iterating and copying along - the way. However, for simple types (such as floats), calling +/* If you have an older compiler, chages are that std::copy is + implemented in the obvious way of iterating and copying along + the way. However, for simple types (such as floats), calling memmove (not memcpy as the ranges could overlap) is faster. So, we overload std::copy for some built-in types. - + However, newer compilers (in particular gcc from version 2.8) - take care of this themselves. So, we only do this + take care of this themselves. So, we only do this conditionally. */ #ifdef STIR_SPEED_UP_STD_COPY -#include +# include START_NAMESPACE_STD //! overloads std::copy for faster performance template <> -inline double * -copy(const double * first, const double * last, double * to) -{ memmove(to, first, (last-first)*sizeof(double)); return to+(last-first); } +inline double* +copy(const double* first, const double* last, double* to) { + memmove(to, first, (last - first) * sizeof(double)); + return to + (last - first); +} template <> -inline float * -copy(const float * first, const float * last, float * to) -{ memmove(to, first, (last-first)*sizeof(float)); return to+(last-first); } +inline float* +copy(const float* first, const float* last, float* to) { + memmove(to, first, (last - first) * sizeof(float)); + return to + (last - first); +} template <> -inline unsigned long int * -copy(const unsigned long int * first, const unsigned long int * last, unsigned long int * to) -{ memmove(to, first, (last-first)*sizeof(unsigned long int)); return to+(last-first); } +inline unsigned long int* +copy(const unsigned long int* first, const unsigned long int* last, unsigned long int* to) { + memmove(to, first, (last - first) * sizeof(unsigned long int)); + return to + (last - first); +} template <> -inline signed long int * -copy(const signed long int * first, const signed long int * last, signed long int * to) -{ memmove(to, first, (last-first)*sizeof(signed long int)); return to+(last-first); } +inline signed long int* +copy(const signed long int* first, const signed long int* last, signed long int* to) { + memmove(to, first, (last - first) * sizeof(signed long int)); + return to + (last - first); +} template <> -inline unsigned int * -copy(const unsigned int * first, const unsigned int * last, unsigned int * to) -{ memmove(to, first, (last-first)*sizeof(unsigned int)); return to+(last-first); } +inline unsigned int* +copy(const unsigned int* first, const unsigned int* last, unsigned int* to) { + memmove(to, first, (last - first) * sizeof(unsigned int)); + return to + (last - first); +} template <> -inline signed int * -copy(const signed int * first, const signed int * last, signed int * to) -{ memmove(to, first, (last-first)*sizeof(signed int)); return to+(last-first); } +inline signed int* +copy(const signed int* first, const signed int* last, signed int* to) { + memmove(to, first, (last - first) * sizeof(signed int)); + return to + (last - first); +} template <> -inline unsigned short int * -copy(const unsigned short int * first, const unsigned short int * last, unsigned short int * to) -{ memmove(to, first, (last-first)*sizeof(unsigned short int)); return to+(last-first); } +inline unsigned short int* +copy(const unsigned short int* first, const unsigned short int* last, unsigned short int* to) { + memmove(to, first, (last - first) * sizeof(unsigned short int)); + return to + (last - first); +} template <> -inline signed short int * -copy(const signed short int * first, const signed short int * last, signed short int * to) -{ memmove(to, first, (last-first)*sizeof(signed short int)); return to+(last-first); } +inline signed short int* +copy(const signed short int* first, const signed short int* last, signed short int* to) { + memmove(to, first, (last - first) * sizeof(signed short int)); + return to + (last - first); +} template <> -inline unsigned char * -copy(const unsigned char * first, const unsigned char * last, unsigned char * to) -{ memmove(to, first, (last-first)*sizeof(unsigned char)); return to+(last-first); } +inline unsigned char* +copy(const unsigned char* first, const unsigned char* last, unsigned char* to) { + memmove(to, first, (last - first) * sizeof(unsigned char)); + return to + (last - first); +} template <> -inline signed char * -copy(const signed char * first, const signed char * last, signed char * to) -{ memmove(to, first, (last-first)*sizeof(signed char)); return to+(last-first); } +inline signed char* +copy(const signed char* first, const signed char* last, signed char* to) { + memmove(to, first, (last - first) * sizeof(signed char)); + return to + (last - first); +} template <> -inline char * -copy(const char * first, const char * last, char * to) -{ memmove(to, first, (last-first)*sizeof(char)); return to+(last-first); } - +inline char* +copy(const char* first, const char* last, char* to) { + memmove(to, first, (last - first) * sizeof(char)); + return to + (last - first); +} template <> -inline bool * -copy(const bool * first, const bool * last, bool * to) -{ memmove(to, first, (last-first)*sizeof(bool)); return to+(last-first); } +inline bool* +copy(const bool* first, const bool* last, bool* to) { + memmove(to, first, (last - first) * sizeof(bool)); + return to + (last - first); +} END_NAMESPACE_STD @@ -254,15 +276,18 @@ END_NAMESPACE_STD for (int i=0; ...) do_something; The next trick (by AZ) solves this problem. - At the moment, we only need it for VC++ + At the moment, we only need it for VC++ */ - + #if defined(STIR_ENABLE_FOR_SCOPE_WORKAROUND) -# ifndef for -# define for if (0) ; else for -# else -# error 'for' is already #defined to something -# endif +# ifndef for +# define for \ + if (0) \ + ; \ + else for +# else +# error 'for' is already #defined to something +# endif #endif //*************** assert @@ -270,33 +295,44 @@ END_NAMESPACE_STD #ifndef STIR_ASSERT # include #else - // use our own assert +// use our own assert # ifdef assert # undef assert # endif # if !defined(NDEBUG) -# define assert(x) {if (!(x)) { \ - fprintf(stderr,"Assertion \"%s\" failed in file %s:%d\n", # x,__FILE__, __LINE__); \ - abort();} } -# else -# define assert(x) +# define assert(x) \ + { \ + if (!(x)) { \ + fprintf(stderr, "Assertion \"%s\" failed in file %s:%d\n", #x, __FILE__, __LINE__); \ + abort(); \ + } \ + } +# else +# define assert(x) # endif #endif // STIR_ASSERT -//*************** +//*************** START_NAMESPACE_STIR //! The constant pi to high precision. /*! \ingroup buildblock */ #ifndef _PI -#define _PI boost::math::constants::pi() +# define _PI boost::math::constants::pi() #endif +//! Define the speed of light in mm / ps +const double _c_light = 0.299792458; +//! This ratio is used often. +const double _c_light_div2 = _c_light * 0.5; + //! returns the square of a number, templated. /*! \ingroup buildblock */ -template -inline NUMBER square(const NUMBER &x) { return x*x; } - +template +inline NUMBER +square(const NUMBER& x) { + return x * x; +} END_NAMESPACE_STIR @@ -304,4 +340,4 @@ END_NAMESPACE_STIR #include "stir/error.h" #include "stir/warning.h" -#endif +#endif diff --git a/src/include/stir/config/gcc.h b/src/include/stir/config/gcc.h index cee178ab50..876d803a42 100644 --- a/src/include/stir/config/gcc.h +++ b/src/include/stir/config/gcc.h @@ -15,15 +15,15 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - See STIR/LICENSE.txt for details + See STIR/LICENSE.txt for details */ #ifndef __stir_config_gcc_H__ #define __stir_config_gcc_H__ /*! - \file - \ingroup buildblock + \file + \ingroup buildblock \brief configuration for gcc \author Kris Thielemans @@ -39,10 +39,10 @@ */ #if defined __GNUC__ -# if __GNUC__ == 2 && __GNUC_MINOR__ <= 8 -# define STIR_NO_NAMESPACES -# define STIR_NO_AUTO_PTR -# endif +# if __GNUC__ == 2 && __GNUC_MINOR__ <= 8 +# define STIR_NO_NAMESPACES +# define STIR_NO_AUTO_PTR +# endif #endif -#endif +#endif diff --git a/src/include/stir/config/visualc.h b/src/include/stir/config/visualc.h index 084de984f2..2dc7946cc0 100644 --- a/src/include/stir/config/visualc.h +++ b/src/include/stir/config/visualc.h @@ -15,15 +15,15 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - See STIR/LICENSE.txt for details + See STIR/LICENSE.txt for details */ #ifndef __stir_config_visualc_H__ #define __stir_config_visualc_H__ /*! - \file - \ingroup buildblock + \file + \ingroup buildblock \brief configuration for Visual C++ \author Kris Thielemans @@ -38,28 +38,28 @@ It is included by sitr/common.h. You should never include it directly. */ -#if defined(_MSC_VER) && _MSC_VER<=1300 +#if defined(_MSC_VER) && _MSC_VER <= 1300 // do this only up to VC 7.0 -#define STIR_NO_COVARIANT_RETURN_TYPES -#define STIR_SPEED_UP_STD_COPY -#define STIR_ENABLE_FOR_SCOPE_WORKAROUND +# define STIR_NO_COVARIANT_RETURN_TYPES +# define STIR_SPEED_UP_STD_COPY +# define STIR_ENABLE_FOR_SCOPE_WORKAROUND #endif #if defined(_MSC_VER) // set _SCL_SECURE_NO_WARNINGS -// otherwise we get a load of messages that std::copy and std::equal are unsafe +// otherwise we get a load of messages that std::copy and std::equal are unsafe // in VectorWithOffset and IndexRange etc because they use C-style arrays internally -#pragma warning( disable : 4996) +# pragma warning(disable : 4996) // enable secure versions of standard C functions such as sprintf etc // this will cause a run-time error when overwriting memory etc // hopefully this is enough to avoid a lot of warnings // otherwise we'll need to set define _CTR_SECURE_NO_WARNINGS -#ifdef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES - // it's already defined. let's get rid of it. -# undef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES +# ifdef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES +// it's already defined. let's get rid of it. +# undef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES +# endif +# define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 #endif -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#endif #endif diff --git a/src/include/stir/convert_array.h b/src/include/stir/convert_array.h index f6692ce007..4ebd00b669 100644 --- a/src/include/stir/convert_array.h +++ b/src/include/stir/convert_array.h @@ -18,12 +18,12 @@ See STIR/LICENSE.txt for details */ #ifndef __stir_convert_array_H__ -#define __stir_convert_array_H__ +#define __stir_convert_array_H__ /*! - \file + \file \ingroup Array - + \brief This file declares the stir::convert_array functions. This is a function to convert stir::Array objects to a different numeric type. @@ -37,30 +37,31 @@ START_NAMESPACE_STIR -template class NumericInfo; -template class Array; - +template +class NumericInfo; +template +class Array; /*! \ingroup Array \brief A function that finds a scale factor to use when converting data to a new type - The scale factor is such that + The scale factor is such that (\a data_in / \a scale_factor) will fit in the maximum range for the output type. When input and output types are identical, \a scale_factor is set to 1. - \param scale_factor + \param scale_factor a reference to a (float or double) variable which will be - set to the scale factor such that (ignoring types) - \code data_in == data_out * scale_factor \endcode - If scale_factor is initialised to 0, the maximum range of \a T2 - is used. If scale_factor != 0, find_scale_factor attempts to use the - given scale_factor, unless the T2 range doesn't fit. - In that case, the same scale_factor is used as in the 0 case. - - \param data_in + set to the scale factor such that (ignoring types) + \code data_in == data_out * scale_factor \endcode + If scale_factor is initialised to 0, the maximum range of \a T2 + is used. If scale_factor != 0, find_scale_factor attempts to use the + given scale_factor, unless the T2 range doesn't fit. + In that case, the same scale_factor is used as in the 0 case. + + \param data_in some Array object, elements are of some numeric type \a T1 \param info_for_out_type \a T2 is the desired output type @@ -71,10 +72,8 @@ template class Array; \see convert_array */ template -inline void -find_scale_factor(scaleT& scale_factor, - const Array& data_in, - const NumericInfo info_for_out_type); +inline void find_scale_factor(scaleT& scale_factor, const Array& data_in, + const NumericInfo info_for_out_type); /*! \ingroup Array @@ -82,23 +81,23 @@ find_scale_factor(scaleT& scale_factor, Result is (approximately) \a data_in / \a scale_factor. - \par example + \par example \code Array<2,float> data_out = convert_array(scale_factor, data_in, NumericInfo()) \endcode - \param scale_factor + \param scale_factor a reference to a (float or double) variable which will be - set to the scale factor such that (ignoring types) - \code data_in == data_out * scale_factor \endcode + set to the scale factor such that (ignoring types) + \code data_in == data_out * scale_factor \endcode \see find_scale_factor for more info on the determination of \a scale_factor. - - \param data_in + + \param data_in some Array object, elements are of some numeric type \a T1 \param info2 \a T2 is the desired output type - \return + \return data_out : an Array object whose elements are of numeric type T2. @@ -109,16 +108,14 @@ find_scale_factor(scaleT& scale_factor, */ template -inline -Array -convert_array(scaleT& scale_factor, - const Array& data_in, - const NumericInfo info2); +inline Array convert_array(scaleT& scale_factor, const Array& data_in, + const NumericInfo info2); /*! \ingroup Array - \brief Converts the \c data_in Array to \c data_out (with elements of different types) such that \c data_in == \c data_out * \c scale_factor + \brief Converts the \c data_in Array to \c data_out (with elements of different types) such that \c data_in == \c data_out * \c + scale_factor - \par example + \par example \code convert_array(data_out, scale_factor, data_in); \endcode @@ -127,15 +124,10 @@ convert_array(scaleT& scale_factor, */ template -inline void -convert_array(Array& data_out, - scaleT& scale_factor, - const Array& data_in); - +inline void convert_array(Array& data_out, scaleT& scale_factor, const Array& data_in); END_NAMESPACE_STIR #include "stir/convert_array.inl" #endif - diff --git a/src/include/stir/convert_array.inl b/src/include/stir/convert_array.inl index 0d35fb125a..51f0268787 100644 --- a/src/include/stir/convert_array.inl +++ b/src/include/stir/convert_array.inl @@ -17,7 +17,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup Array \brief implementation of stir::convert_array @@ -33,35 +33,23 @@ START_NAMESPACE_STIR template void -find_scale_factor(scaleT& scale_factor, - const Array& data_in, - const NumericInfo info_for_out_type) -{ +find_scale_factor(scaleT& scale_factor, const Array& data_in, const NumericInfo info_for_out_type) { find_scale_factor(scale_factor, data_in.begin_all(), data_in.end_all(), info_for_out_type); } - - template Array -convert_array(scaleT& scale_factor, - const Array& data_in, - const NumericInfo info_for_out_type) -{ - Array data_out(data_in.get_index_range()); +convert_array(scaleT& scale_factor, const Array& data_in, const NumericInfo info_for_out_type) { + Array data_out(data_in.get_index_range()); convert_array(data_out, scale_factor, data_in); - return data_out; + return data_out; } template -void -convert_array(Array& data_out, - scaleT& scale_factor, - const Array& data_in) -{ - convert_range(data_out.begin_all(), scale_factor, - data_in.begin_all(), data_in.end_all()); +void +convert_array(Array& data_out, scaleT& scale_factor, const Array& data_in) { + convert_range(data_out.begin_all(), scale_factor, data_in.begin_all(), data_in.end_all()); } END_NAMESPACE_STIR diff --git a/src/include/stir/convert_range.h b/src/include/stir/convert_range.h index eb35897d01..543f9c9523 100644 --- a/src/include/stir/convert_range.h +++ b/src/include/stir/convert_range.h @@ -20,9 +20,9 @@ #define __stir_convert_range_H__ /*! - \file + \file \ingroup Array - + \brief This file declares the stir::convert_range and stir::find_scale_factor functions. \author Kris Thielemans @@ -34,7 +34,8 @@ START_NAMESPACE_STIR -template class NumericInfo; +template +class NumericInfo; /*! \ingroup Array @@ -44,19 +45,18 @@ template class NumericInfo; \see find_scale_factor(scale_factor,data_in,info_for_out_type) */ template -inline void -find_scale_factor(scaleT& scale_factor, - const InputIteratorT& begin, const InputIteratorT& end, - const NumericInfo info_for_out_type); +inline void find_scale_factor(scaleT& scale_factor, const InputIteratorT& begin, const InputIteratorT& end, + const NumericInfo info_for_out_type); /*! \ingroup Array - \brief Converts the data in the input range to the output range (with elements of different types) such that \c data_in == \c data_out * \c scale_factor + \brief Converts the data in the input range to the output range (with elements of different types) such that \c data_in == \c + data_out * \c scale_factor Note order of arguments. Output-range occurs first (as standard in STIR). - \par example + \par example \code - convert_range(data_out.begin_all(), scale_factor, + convert_range(data_out.begin_all(), scale_factor, data_in.begin_all(), data_in.end_all()); \endcode @@ -64,15 +64,11 @@ find_scale_factor(scaleT& scale_factor, */ template -inline void - convert_range(const OutputIteratorT& out_begin, - scaleT& scale_factor, - const InputIteratorT& in_begin, const InputIteratorT& in_end); - +inline void convert_range(const OutputIteratorT& out_begin, scaleT& scale_factor, const InputIteratorT& in_begin, + const InputIteratorT& in_end); END_NAMESPACE_STIR #include "stir/convert_range.inl" #endif - diff --git a/src/include/stir/convert_range.inl b/src/include/stir/convert_range.inl index 2d3dc7f42f..33a36d1beb 100644 --- a/src/include/stir/convert_range.inl +++ b/src/include/stir/convert_range.inl @@ -18,7 +18,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup Array \brief implementation of stir::convert_range @@ -36,152 +36,128 @@ START_NAMESPACE_STIR // anonymous namespace for local functions -namespace -{ - - /* Declaration of auxiliary function is_negative() with the obvious - implementation. - However, we overload it for unsigned types to return always false. - The compiler would do this automatically for us. However, many - compilers (including gcc) will warn when you do - unsigned x=...; - if (x<0) - { - // never get here - } - This file relies on templated definitions of convert_array. So, - if we use if-statements as above with templated code, we will get - warnings when instantiating the code with unsigned types. - - Summary, instead of the above if, write - T x; - if (is_negative(x)) - { - // never get here if T is an unsigned type - } - and you won't get a warning message - */ - - template - inline bool is_negative(const T x) - { return x<0; } - - inline bool is_negative(const unsigned char x) - { return false; } - - inline bool is_negative(const unsigned short x) - { return false; } - - inline bool is_negative(const unsigned int x) - { return false; } - - inline bool is_negative(const unsigned long x) - { return false; } +namespace { + +/* Declaration of auxiliary function is_negative() with the obvious + implementation. + However, we overload it for unsigned types to return always false. + The compiler would do this automatically for us. However, many + compilers (including gcc) will warn when you do + unsigned x=...; + if (x<0) + { + // never get here + } + This file relies on templated definitions of convert_array. So, + if we use if-statements as above with templated code, we will get + warnings when instantiating the code with unsigned types. + + Summary, instead of the above if, write + T x; + if (is_negative(x)) + { + // never get here if T is an unsigned type + } + and you won't get a warning message +*/ + +template +inline bool +is_negative(const T x) { + return x < 0; +} + +inline bool +is_negative(const unsigned char x) { + return false; +} + +inline bool +is_negative(const unsigned short x) { + return false; +} + +inline bool +is_negative(const unsigned int x) { + return false; +} +inline bool +is_negative(const unsigned long x) { + return false; } +} // namespace + template inline void -find_scale_factor(scaleT& scale_factor, - const InputIteratorT& begin, const InputIteratorT& end, - const NumericInfo info_for_out_type) -{ +find_scale_factor(scaleT& scale_factor, const InputIteratorT& begin, const InputIteratorT& end, + const NumericInfo info_for_out_type) { typedef typename boost::iterator_value::type T1; NumericInfo info1; - if (info1.type_id() == info_for_out_type.type_id()) - { + if (info1.type_id() == info_for_out_type.type_id()) { // TODO could use different scale factor in this case as well, but at the moment we don't) scale_factor = scaleT(1); return; } // find the scale factor to use when converting to the maximum range in T2 - const double data_in_max = - *std::max_element(begin, end); - double tmp_scale = - data_in_max / - static_cast(info_for_out_type.max_value()); - if (info_for_out_type.signed_type() && info1.signed_type()) - { - const double data_in_min = - *std::min_element(begin, end); - tmp_scale = - std::max(tmp_scale, - data_in_min /static_cast(info_for_out_type.min_value())); + const double data_in_max = *std::max_element(begin, end); + double tmp_scale = data_in_max / static_cast(info_for_out_type.max_value()); + if (info_for_out_type.signed_type() && info1.signed_type()) { + const double data_in_min = *std::min_element(begin, end); + tmp_scale = std::max(tmp_scale, data_in_min / static_cast(info_for_out_type.min_value())); } // use an extra factor of 1.01. Otherwise, rounding errors can - // cause data_in.find_max() / scale_factor to be bigger than the + // cause data_in.find_max() / scale_factor to be bigger than the // max_value tmp_scale *= 1.01; - - if (scale_factor == 0 || tmp_scale > scale_factor) - { + + if (scale_factor == 0 || tmp_scale > scale_factor) { // We need to convert to the maximum range in T2 scale_factor = scaleT(tmp_scale); } } - template void - convert_range(const OutputIteratorT& out_begin, - scaleT& scale_factor, - const InputIteratorT& in_begin, const InputIteratorT& in_end) -{ - typedef typename boost::iterator_value::type OutType; - - find_scale_factor(scale_factor, in_begin, in_end, NumericInfo()); - if (scale_factor == 0) - { - // data_in contains only 0 - OutputIteratorT out_iter = out_begin; - InputIteratorT in_iter = in_begin; - for (; - in_iter != in_end; - ++in_iter, ++out_iter) - { - *out_iter = static_cast(0); - } - return; - } - - // do actual conversion +convert_range(const OutputIteratorT& out_begin, scaleT& scale_factor, const InputIteratorT& in_begin, + const InputIteratorT& in_end) { + typedef typename boost::iterator_value::type OutType; + + find_scale_factor(scale_factor, in_begin, in_end, NumericInfo()); + if (scale_factor == 0) { + // data_in contains only 0 OutputIteratorT out_iter = out_begin; InputIteratorT in_iter = in_begin; - if (!std::numeric_limits::is_integer) - { - for (; - in_iter != in_end; - ++in_iter, ++out_iter) - { - *out_iter = - static_cast(*in_iter / scale_factor); - } - } - else - { - for (; - in_iter != in_end; - ++in_iter, ++out_iter) - { - // KT coded the checks on the data types in the loop. - // This is presumably slow, but all these conditionals can be - // resolved at compile time, so a good compiler does the work for me. - if (!std::numeric_limits::is_signed - && is_negative(*in_iter)) - { - // truncate negatives - *out_iter = 0; - } - else - { - // convert using rounding - *out_iter = - static_cast(round(*in_iter / scale_factor)); - } - } + for (; in_iter != in_end; ++in_iter, ++out_iter) { + *out_iter = static_cast(0); + } + return; + } + + // do actual conversion + OutputIteratorT out_iter = out_begin; + InputIteratorT in_iter = in_begin; + if (!std::numeric_limits::is_integer) { + for (; in_iter != in_end; ++in_iter, ++out_iter) { + *out_iter = static_cast(*in_iter / scale_factor); + } + } else { + for (; in_iter != in_end; ++in_iter, ++out_iter) { + // KT coded the checks on the data types in the loop. + // This is presumably slow, but all these conditionals can be + // resolved at compile time, so a good compiler does the work for me. + if (!std::numeric_limits::is_signed && is_negative(*in_iter)) { + // truncate negatives + *out_iter = 0; + } else { + // convert using rounding + *out_iter = static_cast(round(*in_iter / scale_factor)); } + } + } } #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION @@ -190,14 +166,10 @@ void // etc, but that requires some template trickery template void - convert_range(const IteratorT& out_begin, - scaleT& scale_factor, - const IteratorT& in_begin, const IteratorT& in_end) -{ +convert_range(const IteratorT& out_begin, scaleT& scale_factor, const IteratorT& in_begin, const IteratorT& in_end) { scale_factor = scaleT(1); std::copy(in_begin, in_end, out_begin); } #endif - END_NAMESPACE_STIR diff --git a/src/include/stir/copy_fill.h b/src/include/stir/copy_fill.h index 43d554cf92..8e3bb66031 100644 --- a/src/include/stir/copy_fill.h +++ b/src/include/stir/copy_fill.h @@ -35,23 +35,17 @@ START_NAMESPACE_STIR @{ */ - //! Helper class for stir::copy_to and stir::fill_from /*! Default implementation that uses STIR iterators \c stir_object.begin_all(). */ -template < typename T> -struct CopyFill -{ +template +struct CopyFill { template - static - iterT copy_to(const T& stir_object, iterT iter) - { - return std::copy(stir_object.begin_all(), stir_object.end_all(), iter); - } + static iterT copy_to(const T& stir_object, iterT iter) { + return std::copy(stir_object.begin_all(), stir_object.end_all(), iter); + } template - static - void fill_from(T& stir_object, iterT iter, iterT iter_end) - { + static void fill_from(T& stir_object, iterT iter, iterT iter_end) { std::copy(iter, iter_end, stir_object.begin_all()); } }; @@ -59,58 +53,51 @@ struct CopyFill //! Helper class for stir::copy_to and stir::fill_from /*! Specialisation that uses ProjData::copy_to etc, unless it's a ProjDataInMemory */ -template<> -struct CopyFill -{ - template < typename iterT> - static - iterT copy_to(const ProjData& stir_object, iterT iter) - { +template <> +struct CopyFill { + template + static iterT copy_to(const ProjData& stir_object, iterT iter) { #if 1 - if (auto pdm_ptr = dynamic_cast(&stir_object)) - { - // std::cerr<<"Using stir::copy_to\n"; - return CopyFill::copy_to(*pdm_ptr, iter); - } - else + if (auto pdm_ptr = dynamic_cast(&stir_object)) { + // std::cerr<<"Using stir::copy_to\n"; + return CopyFill::copy_to(*pdm_ptr, iter); + } else #endif - { - // std::cerr<<"Using member copy_to\n"; - return stir_object.copy_to(iter); - } - } - - template < typename iterT> - static - void fill_from(ProjData& stir_object, iterT iter, iterT iter_end) { - if (auto pdm_ptr = dynamic_cast(&stir_object)) - CopyFill::fill_from(*pdm_ptr, iter, iter_end); - else - stir_object.fill_from(iter); + // std::cerr<<"Using member copy_to\n"; + return stir_object.copy_to(iter); } + } + + template + static void fill_from(ProjData& stir_object, iterT iter, iterT iter_end) { + if (auto pdm_ptr = dynamic_cast(&stir_object)) + CopyFill::fill_from(*pdm_ptr, iter, iter_end); + else + stir_object.fill_from(iter); + } }; //! Copy all bins to a range specified by a iterator -/*! +/*! \return \a iter advanced over the range (as std::copy) - + \warning there is no range-check on \a iter */ template - inline iterT copy_to(const T& stir_object, iterT iter) -{ +inline iterT +copy_to(const T& stir_object, iterT iter) { return CopyFill::copy_to(stir_object, iter); } //! set all elements of \a stir_object from an iterator -/*! +/*! \warning there is no size/range-check on \a iter */ template - inline void fill_from(T& stir_object, iterT iter, iterT iter_end) -{ - //return +inline void +fill_from(T& stir_object, iterT iter, iterT iter_end) { + // return CopyFill::fill_from(stir_object, iter, iter_end); } diff --git a/src/include/stir/cross_product.h b/src/include/stir/cross_product.h index 5b022873a2..37fc974535 100644 --- a/src/include/stir/cross_product.h +++ b/src/include/stir/cross_product.h @@ -19,11 +19,11 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup buildblock + \file + \ingroup buildblock \brief defines the cross-product of 2 CartesianCoordinate3D numbers - \author Kris Thielemans + \author Kris Thielemans */ @@ -35,23 +35,18 @@ START_NAMESPACE_STIR \ingroup buildblock \brief the cross-product for 3-dimensional coordinates. - \warning This implements minus the 'usual' definition - of the cross-product. This is done because STIR uses a left-handed - coordinate system. The definition of \a cross_product is such that + \warning This implements minus the 'usual' definition + of the cross-product. This is done because STIR uses a left-handed + coordinate system. The definition of \a cross_product is such that \f$ {a, b, a\times b}\f$ forms a left-handed coordinate system. */ - template CartesianCoordinate3D -cross_product(const CartesianCoordinate3D& a, - const CartesianCoordinate3D& b) -{ - return - CartesianCoordinate3D(a.y()*b.x() - a.x()*b.y(), - -a.z()*b.x() + a.x()*b.z(), - a.z()*b.y() - a.y()*b.z()); +cross_product(const CartesianCoordinate3D& a, const CartesianCoordinate3D& b) { + return CartesianCoordinate3D(a.y() * b.x() - a.x() * b.y(), -a.z() * b.x() + a.x() * b.z(), + a.z() * b.y() - a.y() * b.z()); }; END_NAMESPACE_STIR diff --git a/src/include/stir/data/SinglesRates.h b/src/include/stir/data/SinglesRates.h index 6d8adb889e..8936de0996 100644 --- a/src/include/stir/data/SinglesRates.h +++ b/src/include/stir/data/SinglesRates.h @@ -39,86 +39,64 @@ START_NAMESPACE_STIR - - - - - /*! \ingroup singles_buildblock \brief A single frame of singles information. */ -class FrameSinglesRates -{ +class FrameSinglesRates { - public: +public: typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; - //! Constructor taking all arguments - /*! \warning only checks sizes with an \c assert. - */ - FrameSinglesRates(std::vector& avg_singles_rates, - double start_time, - double end_time, - shared_ptr scanner); - //! Constructor without singles rates - /*! Initialises the size of the internal object that stores the singles rates - but does not initialise its values. - */ - FrameSinglesRates(double start_time, - double end_time, - shared_ptr scanner); - - - //! Get singles rate for a particular singles bin index. - // - // The singles rate returned is the rate for a whole singles unit. - // - float get_singles_rate(int singles_bin_index) const; - - //! Get singles rate for a detection position. - // - // The singles rate returned is the rate for a whole singles unit. - // - float get_singles_rate(const DetectionPosition<>& det_pos) const; - - const_iterator begin() const - { return this->_singles.begin(); } - - iterator begin() - { return this->_singles.begin(); } - - const_iterator end() const - { return this->_singles.end(); } - - iterator end() - { return this->_singles.end(); } - - //! Get the start time of the frame whose rates are recorded. - double get_start_time() const; - - //! Get the end time of the frame whose rates are recorded. - double get_end_time() const; - - //! Get the scanner information. - inline const Scanner * get_scanner_ptr() const; - - private: - - double _start_time; - double _end_time; - std::vector _singles; - - // Scanner specifics - shared_ptr _scanner_sptr; - -}; + //! Constructor taking all arguments + /*! \warning only checks sizes with an \c assert. + */ + FrameSinglesRates(std::vector& avg_singles_rates, double start_time, double end_time, shared_ptr scanner); + //! Constructor without singles rates + /*! Initialises the size of the internal object that stores the singles rates + but does not initialise its values. + */ + FrameSinglesRates(double start_time, double end_time, shared_ptr scanner); + + //! Get singles rate for a particular singles bin index. + // + // The singles rate returned is the rate for a whole singles unit. + // + float get_singles_rate(int singles_bin_index) const; + + //! Get singles rate for a detection position. + // + // The singles rate returned is the rate for a whole singles unit. + // + float get_singles_rate(const DetectionPosition<>& det_pos) const; + + const_iterator begin() const { return this->_singles.begin(); } + + iterator begin() { return this->_singles.begin(); } + + const_iterator end() const { return this->_singles.end(); } + + iterator end() { return this->_singles.end(); } + + //! Get the start time of the frame whose rates are recorded. + double get_start_time() const; + //! Get the end time of the frame whose rates are recorded. + double get_end_time() const; + //! Get the scanner information. + inline const Scanner* get_scanner_ptr() const; +private: + double _start_time; + double _end_time; + std::vector _singles; + // Scanner specifics + shared_ptr _scanner_sptr; +}; /*! \ingroup singles_buildblock @@ -131,22 +109,17 @@ class FrameSinglesRates There will be 1 rate per singles unit. See Scanner for some more info. */ -class SinglesRates : public RegisteredObject -{ -public: - - virtual ~SinglesRates () {} - //! Get the singles rate for a particular singles unit and a frame with the specified start and end times. +class SinglesRates : public RegisteredObject { +public: + virtual ~SinglesRates() {} + //! Get the singles rate for a particular singles unit and a frame with the specified start and end times. /*! The behaviour of this function is specified by the derived classes. \warning Currently might return -1 if the \a start_time, \a end_time are invalid (e.g. out of the measured range). */ - virtual float - get_singles_rate(const int singles_bin_index, - const double start_time, - const double end_time) const = 0; - - //! Virtual function that returns the average singles rate given the detection positions and time-interval of detection + virtual float get_singles_rate(const int singles_bin_index, const double start_time, const double end_time) const = 0; + + //! Virtual function that returns the average singles rate given the detection positions and time-interval of detection /*! The behaviour of this function is specified by the derived classes. \warning Currently might return -1 if the \a start_time, \a end_time are invalid (e.g. out of the measured range). @@ -154,34 +127,21 @@ class SinglesRates : public RegisteredObject Default implementation uses Scanner::get_singles_bin_index(). */ - virtual float get_singles_rate(const DetectionPosition<>& det_pos, - const double start_time, - const double end_time) const; - + virtual float get_singles_rate(const DetectionPosition<>& det_pos, const double start_time, const double end_time) const; + //! Get the scanner pointer - inline const Scanner * get_scanner_ptr() const; - + inline const Scanner* get_scanner_ptr() const; //! Generate a FramesSinglesRate - containing the average rates // for a frame begining at start_time and ending at end_time. - //virtual FrameSinglesRates get_rates_for_frame(double start_time, + // virtual FrameSinglesRates get_rates_for_frame(double start_time, // double end_time) const = 0; - - + protected: shared_ptr scanner_sptr; - }; - - - - - - - END_NAMESPACE_STIR #include "stir/data/SinglesRates.inl" #endif - diff --git a/src/include/stir/data/SinglesRates.inl b/src/include/stir/data/SinglesRates.inl index a72ba0f4e3..cd5f379c1c 100644 --- a/src/include/stir/data/SinglesRates.inl +++ b/src/include/stir/data/SinglesRates.inl @@ -25,23 +25,16 @@ \author Kris Thielemans and Sanida Mustafovic */ - START_NAMESPACE_STIR - -const -Scanner* SinglesRates::get_scanner_ptr() const -{ +const Scanner* +SinglesRates::get_scanner_ptr() const { return scanner_sptr.get(); } - - -const Scanner * -FrameSinglesRates:: -get_scanner_ptr() const { +const Scanner* +FrameSinglesRates::get_scanner_ptr() const { return _scanner_sptr.get(); } - END_NAMESPACE_STIR diff --git a/src/include/stir/data/SinglesRatesForTimeFrames.h b/src/include/stir/data/SinglesRatesForTimeFrames.h index 4ada69f978..cd1a75ba60 100644 --- a/src/include/stir/data/SinglesRatesForTimeFrames.h +++ b/src/include/stir/data/SinglesRatesForTimeFrames.h @@ -38,65 +38,50 @@ START_NAMESPACE_STIR \ingroup singles_buildblock \brief A class for singles rates that are recorded in time frames. */ -class SinglesRatesForTimeFrames -: public SinglesRates -{ +class SinglesRatesForTimeFrames : public SinglesRates { public: - - //! Default constructor - SinglesRatesForTimeFrames (); - - //SinglesRatesForTimeFrames(const TimeFrameDefinitions& time_frame_definitions, - // const shared_ptr& scanner_sptr); - - - //! get the singles rate for a particular singles unit and frame number. - // - // The singles rate returned is the rate for a whole singles unit. - // - float get_singles_rate(int singles_bin_index, unsigned int frame_number) const; - - - //! get the singles rate for a particular singles unit and a frame with - // the specified start and end times. - // - // The singles rate returned is the rate for a whole singles unit. - // - /*! \warning Currently returns -1 if the \a start_time, \a end_time - does not corresponds to a time frame. - */ - float get_singles_rate(const int singles_bin_index, - const double start_time, const double end_time) const; - - //! Generate a FramesSinglesRate - containing the average rates - // for a frame begining at start_time and ending at end_time. - FrameSinglesRates get_rates_for_frame(double start_time, - double end_time) const; - - //! Set a singles rate by singles bin index and time frame number. - /*! \warning No error checking is doing on validity of the indices. - */ - void set_singles_rate(const int singles_bin_index, - const unsigned time_frame_num, - const float new_rate); - - //! Get the number of frames for which singles rates are recorded. - unsigned int get_num_frames() const; - - //! Get the time frame definitions - const TimeFrameDefinitions& - get_time_frame_definitions() const; + //! Default constructor + SinglesRatesForTimeFrames(); + + // SinglesRatesForTimeFrames(const TimeFrameDefinitions& time_frame_definitions, + // const shared_ptr& scanner_sptr); + + //! get the singles rate for a particular singles unit and frame number. + // + // The singles rate returned is the rate for a whole singles unit. + // + float get_singles_rate(int singles_bin_index, unsigned int frame_number) const; + + //! get the singles rate for a particular singles unit and a frame with + // the specified start and end times. + // + // The singles rate returned is the rate for a whole singles unit. + // + /*! \warning Currently returns -1 if the \a start_time, \a end_time + does not corresponds to a time frame. + */ + float get_singles_rate(const int singles_bin_index, const double start_time, const double end_time) const; + + //! Generate a FramesSinglesRate - containing the average rates + // for a frame begining at start_time and ending at end_time. + FrameSinglesRates get_rates_for_frame(double start_time, double end_time) const; + + //! Set a singles rate by singles bin index and time frame number. + /*! \warning No error checking is doing on validity of the indices. + */ + void set_singles_rate(const int singles_bin_index, const unsigned time_frame_num, const float new_rate); + + //! Get the number of frames for which singles rates are recorded. + unsigned int get_num_frames() const; + + //! Get the time frame definitions + const TimeFrameDefinitions& get_time_frame_definitions() const; protected: - - Array<2,float> _singles; + Array<2, float> _singles; TimeFrameDefinitions _time_frame_defs; - - - }; END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/data/SinglesRatesFromECAT7.h b/src/include/stir/data/SinglesRatesFromECAT7.h index 0e50f42fe6..e26b905772 100644 --- a/src/include/stir/data/SinglesRatesFromECAT7.h +++ b/src/include/stir/data/SinglesRatesFromECAT7.h @@ -38,36 +38,28 @@ START_NAMESPACE_ECAT7 \ingroup singles_buildblock \brief A class that extracts singles info from an ECAT7 sinogram file. */ -class SinglesRatesFromECAT7 : -public RegisteredParsingObject -{ +class SinglesRatesFromECAT7 : public RegisteredParsingObject { public: + //! Name which will be used when parsing a SinglesRatesFromECAT7 object + static const char* const registered_name; - //! Name which will be used when parsing a SinglesRatesFromECAT7 object - static const char * const registered_name; - - //! Default constructor - SinglesRatesFromECAT7 (); + //! Default constructor + SinglesRatesFromECAT7(); + + //! The function that reads singles from ECAT7 file + /*! \return The number of frames found. 0 if failed. + */ + int read_singles_from_file(const std::string& ECAT7_filename, const std::ios::openmode open_mode = std::ios::in); - - //! The function that reads singles from ECAT7 file - /*! \return The number of frames found. 0 if failed. - */ - int read_singles_from_file(const std::string& ECAT7_filename, - const std::ios::openmode open_mode = std::ios::in); - - private: std::string ECAT7_filename; virtual void set_defaults(); virtual void initialise_keymap(); - virtual bool post_processing(); + virtual bool post_processing(); }; END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/data/SinglesRatesFromGEHDF5.h b/src/include/stir/data/SinglesRatesFromGEHDF5.h old mode 100755 new mode 100644 index 3d3487599c..5d1599ca6d --- a/src/include/stir/data/SinglesRatesFromGEHDF5.h +++ b/src/include/stir/data/SinglesRatesFromGEHDF5.h @@ -35,7 +35,6 @@ #include "stir/RegisteredParsingObject.h" #include "stir/IO/GEHDF5Wrapper.h" - START_NAMESPACE_STIR namespace GE { namespace RDF_HDF5 { @@ -51,162 +50,141 @@ namespace RDF_HDF5 { \todo construct_randoms_from_GEsingles.cxx needs to reorder data. This should be moved to this class */ -class SinglesRatesFromGEHDF5 : -public RegisteredParsingObject +class SinglesRatesFromGEHDF5 : public RegisteredParsingObject -{ +{ public: - - //! Name which will be used when parsing a SinglesRatesFromGEHDF5 object - static const char * const registered_name; - -//PW Would not touch this. - //! Default constructor - explicit SinglesRatesFromGEHDF5(); - - // implementation of pure virtual in SinglesRates - virtual float - get_singles_rate(const int singles_bin_index, - const double start_time, const double end_time) const; - - //! Generate a FramesSinglesRate - containing the average rates - // for a frame begining at start_time and ending at end_time. - FrameSinglesRates get_rates_for_frame(double start_time, - double end_time) const; - - - /* - *! Get time slice index for a time slice ending at or after t. - * - * Each slice of singles data has a corresponing time recorded with - * the singles counts. This time is considered to represent the time - * at the end of the slice. - * - * For a given double precision number of seconds, t, this function - * will return the slice index for the first time slice that has a - * corresponding time greater than or equal to t. - * - * Assuming contiguous slices that end at the time recorded for the slice, - * this function returns the slice in which t is contained. - * - * This function assumes that all slices are continguous. - * If the supplied t does not actually fall within a frame, the closest - * frame (ending after t) is returned. Values of t before the first time - * slice will result in the index to the first slice being returned. - */ - virtual int get_end_time_slice_index(double t) const; - - - /* - *! Get time slice index for a time slice ending after t. - * - * Each slice of singles data has a corresponing time recorded with - * the singles counts. This time is considered to represent the time - * at the end of the slice. - * - * For a given double precision number of seconds, t, this function - * will return the slice index for the first time slice that has a - * correspdoning time greater than t. - * - * Assuming contiguous slices that end at the time recorded for the slice, - * this function returns the slice which starts before t. A time interval - * that begins at t should contain only time slices that end _after_ t - * not at t. - * - * This function assumes that all slices are continguous. - * If the supplied t does not actually fall within a frame, the closest - * frame (ending after t) is returned. Values of t before the first time - * slice will result in the index to the first slice being returned. - */ - virtual int get_start_time_slice_index(double t) const; - - - //! Get rates using time slice and singles bin indices. - // - // The singles rate returned is the rate for a whole singles unit. - // - int get_singles_rate(int singles_bin_index, int time_slice) const; - - float get_singles_rate(const DetectionPosition<>& det_pos, - const double start_time, - const double end_time) const; - - //! Set a singles rate by singles bin index and time slice. - // - // The singles rate returned is the rate for a whole singles unit. - // - void set_singles_rate(int singles_bin_index, int time_slice, int new_rate); - - - //! Rebin the .BLF slices into a different set of consecutive slices. - // - // Returns the number of new bins. - unsigned int rebin(std::vector& new_end_times); - - - //! Get the vector of time values for each time slice index. - std::vector get_times() const; - - - // Some inspectors - - //! Return the number of time slices. - unsigned int get_num_time_slices() const; - - - //! Return the time interval per slice of singles data. - double get_singles_time_interval() const; - - - // IO Methods -//PW Reading singles from .sgl changed to .BLF file format. Adapt from GE HDF5 listmode file read. - //! The function that reads singles from *.sgl file. - unsigned int read_singles_from_listmode_file(const std::string& _listmode_filename); - - /*! - * \brief Write the SinglesRatesFromGEHDF5 object to a stream. - * \param[in] output The ostream to which the object will be written. - */ - //PW Here writing of singles in output stream; unsure - std::ostream& write(std::ostream& output); - - + //! Name which will be used when parsing a SinglesRatesFromGEHDF5 object + static const char* const registered_name; + + // PW Would not touch this. + //! Default constructor + explicit SinglesRatesFromGEHDF5(); + + // implementation of pure virtual in SinglesRates + virtual float get_singles_rate(const int singles_bin_index, const double start_time, const double end_time) const; + + //! Generate a FramesSinglesRate - containing the average rates + // for a frame begining at start_time and ending at end_time. + FrameSinglesRates get_rates_for_frame(double start_time, double end_time) const; + + /* + *! Get time slice index for a time slice ending at or after t. + * + * Each slice of singles data has a corresponing time recorded with + * the singles counts. This time is considered to represent the time + * at the end of the slice. + * + * For a given double precision number of seconds, t, this function + * will return the slice index for the first time slice that has a + * corresponding time greater than or equal to t. + * + * Assuming contiguous slices that end at the time recorded for the slice, + * this function returns the slice in which t is contained. + * + * This function assumes that all slices are continguous. + * If the supplied t does not actually fall within a frame, the closest + * frame (ending after t) is returned. Values of t before the first time + * slice will result in the index to the first slice being returned. + */ + virtual int get_end_time_slice_index(double t) const; + + /* + *! Get time slice index for a time slice ending after t. + * + * Each slice of singles data has a corresponing time recorded with + * the singles counts. This time is considered to represent the time + * at the end of the slice. + * + * For a given double precision number of seconds, t, this function + * will return the slice index for the first time slice that has a + * correspdoning time greater than t. + * + * Assuming contiguous slices that end at the time recorded for the slice, + * this function returns the slice which starts before t. A time interval + * that begins at t should contain only time slices that end _after_ t + * not at t. + * + * This function assumes that all slices are continguous. + * If the supplied t does not actually fall within a frame, the closest + * frame (ending after t) is returned. Values of t before the first time + * slice will result in the index to the first slice being returned. + */ + virtual int get_start_time_slice_index(double t) const; + + //! Get rates using time slice and singles bin indices. + // + // The singles rate returned is the rate for a whole singles unit. + // + int get_singles_rate(int singles_bin_index, int time_slice) const; + + float get_singles_rate(const DetectionPosition<>& det_pos, const double start_time, const double end_time) const; + + //! Set a singles rate by singles bin index and time slice. + // + // The singles rate returned is the rate for a whole singles unit. + // + void set_singles_rate(int singles_bin_index, int time_slice, int new_rate); + + //! Rebin the .BLF slices into a different set of consecutive slices. + // + // Returns the number of new bins. + unsigned int rebin(std::vector& new_end_times); + + //! Get the vector of time values for each time slice index. + std::vector get_times() const; + + // Some inspectors + + //! Return the number of time slices. + unsigned int get_num_time_slices() const; + + //! Return the time interval per slice of singles data. + double get_singles_time_interval() const; + + // IO Methods + // PW Reading singles from .sgl changed to .BLF file format. Adapt from GE HDF5 listmode file read. + //! The function that reads singles from *.sgl file. + unsigned int read_singles_from_listmode_file(const std::string& _listmode_filename); + + /*! + * \brief Write the SinglesRatesFromGEHDF5 object to a stream. + * \param[in] output The ostream to which the object will be written. + */ + // PW Here writing of singles in output stream; unsure + std::ostream& write(std::ostream& output); private: - - // Indexed by time slice and singles bin index. - shared_ptr > m_singles_sptr; - - shared_ptr m_input_sptr; - - std::vector _times; - std::vector _total_prompts; - std::vector _total_randoms; - - unsigned int m_num_time_slices = 0; - - // A value of zero for _singles_time_interval indicates that the time slices - // are of different lengths. - double _singles_time_interval; -//PW change this to BLF filename - std::string _listmode_filename; - - // Calculate and set _singles_time_interval. - void set_time_interval(); - - // get slice start time. - double get_slice_start(int slice_index) const; - - - virtual void set_defaults(); - virtual void initialise_keymap(); - virtual bool post_processing(); - + // Indexed by time slice and singles bin index. + shared_ptr> m_singles_sptr; + + shared_ptr m_input_sptr; + + std::vector _times; + std::vector _total_prompts; + std::vector _total_randoms; + + unsigned int m_num_time_slices = 0; + + // A value of zero for _singles_time_interval indicates that the time slices + // are of different lengths. + double _singles_time_interval; + // PW change this to BLF filename + std::string _listmode_filename; + + // Calculate and set _singles_time_interval. + void set_time_interval(); + + // get slice start time. + double get_slice_start(int slice_index) const; + + virtual void set_defaults(); + virtual void initialise_keymap(); + virtual bool post_processing(); }; -} // namespace -} +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/data/SinglesRatesFromSglFile.h b/src/include/stir/data/SinglesRatesFromSglFile.h index bfe3f5a864..eceaee559f 100644 --- a/src/include/stir/data/SinglesRatesFromSglFile.h +++ b/src/include/stir/data/SinglesRatesFromSglFile.h @@ -35,191 +35,157 @@ #include "stir/RegisteredParsingObject.h" #include "stir/IO/stir_ecat7.h" - START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 - - - /*! \ingroup singles_buildblock \brief A class for reading/writing singles from an ECAT7 .sgl file .sgl files are generated by CTI/Siemens PET scanners when doing a list mode scan */ -class SinglesRatesFromSglFile : -public RegisteredParsingObject +class SinglesRatesFromSglFile : public RegisteredParsingObject -{ +{ public: - - struct sgl_str - { - long int time; - long int num_sgl; - long int sgl[126]; // Total prompts and total randoms at the end. - }; - - static const unsigned SIZE_OF_SINGLES_RECORD; - - //! Name which will be used when parsing a SinglesRatesFromSglFile object - static const char * const registered_name; - - - //! Default constructor - SinglesRatesFromSglFile(); - - // implementation of pure virtual in SinglesRates - virtual float - get_singles_rate(const int singles_bin_index, - const double start_time, const double end_time) const; - - - //! Generate a FramesSinglesRate - containing the average rates - // for a frame begining at start_time and ending at end_time. - FrameSinglesRates get_rates_for_frame(double start_time, - double end_time) const; - - - /* - *! Get time slice index for a time slice ending at or after t. - * - * Each slice of singles data has a corresponing time recorded with - * the singles counts. This time is considered to represent the time - * at the end of the slice. - * - * For a given double precision number of seconds, t, this function - * will return the slice index for the first time slice that has a - * corresponding time greater than or equal to t. - * - * Assuming contiguous slices that end at the time recorded for the slice, - * this function returns the slice in which t is contained. - * - * This function assumes that all slices are continguous. - * If the supplied t does not actually fall within a frame, the closest - * frame (ending after t) is returned. Values of t before the first time - * slice will result in the index to the first slice being returned. - */ - virtual int get_end_time_slice_index(double t) const; - - - /* - *! Get time slice index for a time slice ending after t. - * - * Each slice of singles data has a corresponing time recorded with - * the singles counts. This time is considered to represent the time - * at the end of the slice. - * - * For a given double precision number of seconds, t, this function - * will return the slice index for the first time slice that has a - * correspdoning time greater than t. - * - * Assuming contiguous slices that end at the time recorded for the slice, - * this function returns the slice which starts before t. A time interval - * that begins at t should contain only time slices that end _after_ t - * not at t. - * - * This function assumes that all slices are continguous. - * If the supplied t does not actually fall within a frame, the closest - * frame (ending after t) is returned. Values of t before the first time - * slice will result in the index to the first slice being returned. - */ - virtual int get_start_time_slice_index(double t) const; - - - //! Get rates using time slice and singles bin indices. - // - // The singles rate returned is the rate for a whole singles unit. - // - int get_singles_rate(int singles_bin_index, int time_slice) const; - - //! Set a singles rate by singles bin index and time slice. - // - // The singles rate returned is the rate for a whole singles unit. - // - void set_singles_rate(int singles_bin_index, int time_slice, int new_rate); - - - //! Rebin the sgl slices into a different set of consecutive slices. - // - // Returns the number of new bins. - int rebin(std::vector& new_end_times); - - - //! Get the vector of time values for each time slice index. - std::vector get_times() const; - - - // Some inspectors - - //! Return the number of time slices. - int get_num_time_slices() const; - - - //! Return the time interval per slice of singles data. - double get_singles_time_interval() const; - - - // IO Methods - - //! The function that reads singles from *.sgl file. - int read_singles_from_sgl_file(const std::string& sgl_filename); - - /*! - * \brief Write the SinglesRatesFromSglFile object to a stream. - * \param[in] output The ostream to which the object will be written. - */ - std::ostream& write(std::ostream& output); - - + struct sgl_str { + long int time; + long int num_sgl; + long int sgl[126]; // Total prompts and total randoms at the end. + }; + + static const unsigned SIZE_OF_SINGLES_RECORD; + + //! Name which will be used when parsing a SinglesRatesFromSglFile object + static const char* const registered_name; + + //! Default constructor + SinglesRatesFromSglFile(); + + // implementation of pure virtual in SinglesRates + virtual float get_singles_rate(const int singles_bin_index, const double start_time, const double end_time) const; + + //! Generate a FramesSinglesRate - containing the average rates + // for a frame begining at start_time and ending at end_time. + FrameSinglesRates get_rates_for_frame(double start_time, double end_time) const; + + /* + *! Get time slice index for a time slice ending at or after t. + * + * Each slice of singles data has a corresponing time recorded with + * the singles counts. This time is considered to represent the time + * at the end of the slice. + * + * For a given double precision number of seconds, t, this function + * will return the slice index for the first time slice that has a + * corresponding time greater than or equal to t. + * + * Assuming contiguous slices that end at the time recorded for the slice, + * this function returns the slice in which t is contained. + * + * This function assumes that all slices are continguous. + * If the supplied t does not actually fall within a frame, the closest + * frame (ending after t) is returned. Values of t before the first time + * slice will result in the index to the first slice being returned. + */ + virtual int get_end_time_slice_index(double t) const; + + /* + *! Get time slice index for a time slice ending after t. + * + * Each slice of singles data has a corresponing time recorded with + * the singles counts. This time is considered to represent the time + * at the end of the slice. + * + * For a given double precision number of seconds, t, this function + * will return the slice index for the first time slice that has a + * correspdoning time greater than t. + * + * Assuming contiguous slices that end at the time recorded for the slice, + * this function returns the slice which starts before t. A time interval + * that begins at t should contain only time slices that end _after_ t + * not at t. + * + * This function assumes that all slices are continguous. + * If the supplied t does not actually fall within a frame, the closest + * frame (ending after t) is returned. Values of t before the first time + * slice will result in the index to the first slice being returned. + */ + virtual int get_start_time_slice_index(double t) const; + + //! Get rates using time slice and singles bin indices. + // + // The singles rate returned is the rate for a whole singles unit. + // + int get_singles_rate(int singles_bin_index, int time_slice) const; + + //! Set a singles rate by singles bin index and time slice. + // + // The singles rate returned is the rate for a whole singles unit. + // + void set_singles_rate(int singles_bin_index, int time_slice, int new_rate); + + //! Rebin the sgl slices into a different set of consecutive slices. + // + // Returns the number of new bins. + int rebin(std::vector& new_end_times); + + //! Get the vector of time values for each time slice index. + std::vector get_times() const; + + // Some inspectors + + //! Return the number of time slices. + int get_num_time_slices() const; + + //! Return the time interval per slice of singles data. + double get_singles_time_interval() const; + + // IO Methods + + //! The function that reads singles from *.sgl file. + int read_singles_from_sgl_file(const std::string& sgl_filename); + + /*! + * \brief Write the SinglesRatesFromSglFile object to a stream. + * \param[in] output The ostream to which the object will be written. + */ + std::ostream& write(std::ostream& output); private: - - // Indexed by time slice and singles bin index. - Array<2, int> _singles; - - std::vector _times; - std::vector _total_prompts; - std::vector _total_randoms; + // Indexed by time slice and singles bin index. + Array<2, int> _singles; + std::vector _times; + std::vector _total_prompts; + std::vector _total_randoms; #ifdef HAVE_LLN_MATRIX - Main_header _singles_main_header; + Main_header _singles_main_header; #endif - - int _num_time_slices; - - // A value of zero for _singles_time_interval indicates that the time slices - // are of different lengths. - double _singles_time_interval; - - std::string _sgl_filename; - - // Calculate and set _singles_time_interval. - void set_time_interval(); - - // get slice start time. - double get_slice_start(int slice_index) const; - - - virtual void set_defaults(); - virtual void initialise_keymap(); - virtual bool post_processing(); - -}; - + int _num_time_slices; + // A value of zero for _singles_time_interval indicates that the time slices + // are of different lengths. + double _singles_time_interval; + std::string _sgl_filename; + // Calculate and set _singles_time_interval. + void set_time_interval(); + // get slice start time. + double get_slice_start(int slice_index) const; + virtual void set_defaults(); + virtual void initialise_keymap(); + virtual bool post_processing(); +}; END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/date_time_functions.h b/src/include/stir/date_time_functions.h index 6e3c784e65..853884c77e 100644 --- a/src/include/stir/date_time_functions.h +++ b/src/include/stir/date_time_functions.h @@ -16,9 +16,9 @@ */ /*! - \file + \file \ingroup date_time - + \brief Functions for date-time conversions \author Kris Thielemans @@ -53,7 +53,7 @@ int current_time_zone_and_DST_offset_in_secs(); Minimal checks on format are performed, calling \c error() if input is incorrect. */ -std::string DICOM_date_time_to_DT(const std::string& date, const std::string& time, const std::string& TZ =""); +std::string DICOM_date_time_to_DT(const std::string& date, const std::string& time, const std::string& TZ = ""); /*! \brief convert DICOM DT string to seconds since the Unix epoch (i.e. 1 Jan 1970 00:00:00 UTC) @@ -64,27 +64,22 @@ std::string DICOM_date_time_to_DT(const std::string& date, const std::string& ti Time_Zone info is given by "&ZZXX", with & = "+" or "-", and ZZ = Hours and XX = Minutes of offset w.r.t. UTC. If no TZ is given, the local time_zone with DST is used. A warning() is then issued, unless \c silent=true. */ -double DICOM_datetime_to_secs_since_Unix_epoch(const std::string& str, bool silent=false); +double DICOM_datetime_to_secs_since_Unix_epoch(const std::string& str, bool silent = false); /*! \brief convert epoch to DICOM DT string in specified time zone (+3600 is CET) \ingroup date_time */ -std::string -secs_since_Unix_epoch_to_DICOM_datetime(double secs, - int time_zone_offset_in_secs = current_time_zone_and_DST_offset_in_secs()); +std::string secs_since_Unix_epoch_to_DICOM_datetime(double secs, + int time_zone_offset_in_secs = current_time_zone_and_DST_offset_in_secs()); -/*! +/*! \brief A simple structure to hold 2 strings (\c date and \time) \ingroup date_time */ -struct DateTimeStrings -{ - DateTimeStrings() - {} - DateTimeStrings(const std::string& date, const std::string& time) - : date(date), time(time) - {} +struct DateTimeStrings { + DateTimeStrings() {} + DateTimeStrings(const std::string& date, const std::string& time) : date(date), time(time) {} std::string date, time; }; @@ -92,14 +87,12 @@ struct DateTimeStrings //! Convert from DICOM DT to Interfile /*! \ingroup date_time */ -DateTimeStrings -DICOM_datetime_to_Interfile(const std::string& str); +DateTimeStrings DICOM_datetime_to_Interfile(const std::string& str); //! Convert from Interfile to DICOM DT /*! \ingroup date_time */ -std::string -Interfile_datetime_to_DICOM(const DateTimeStrings&); +std::string Interfile_datetime_to_DICOM(const DateTimeStrings&); /*! \brief convert Interfile DateTime strings to seconds since the Unix epoch (i.e. 1 Jan 1970 00:00:00 UTC) @@ -109,7 +102,7 @@ Interfile_datetime_to_DICOM(const DateTimeStrings&); Uses DICOM conventions for specifying the time_zone, i.e. appending "&ZZXX", with & = "+" or "-", and ZZ = Hours and XX = Minutes of offset w.r.t. UTC. */ -double Interfile_datetime_to_secs_since_Unix_epoch(const DateTimeStrings&, bool silent=false); +double Interfile_datetime_to_secs_since_Unix_epoch(const DateTimeStrings&, bool silent = false); /*! \brief convert epoch to Interfile date-times string in specified time zone (+3600 is CET) diff --git a/src/include/stir/decay_correction_factor.h b/src/include/stir/decay_correction_factor.h index 7927d8409a..a12eac5d65 100644 --- a/src/include/stir/decay_correction_factor.h +++ b/src/include/stir/decay_correction_factor.h @@ -19,9 +19,9 @@ #ifndef __stir_decay_correction_factor_H__ #define __stir_decay_correction_factor_H__ /*! - \file + \file \ingroup buildblock - \brief Simple functions to compute the decay correction factor. + \brief Simple functions to compute the decay correction factor. \author Charalampos Tsoumpas \author Kris Thielemans @@ -35,22 +35,19 @@ START_NAMESPACE_STIR //! Compute decay-correction factor for a time frame /*! - \ingroup buildblock + \ingroup buildblock This function computes the factor eneded to convert average number of counts per second to activity at time 0, i.e. it returns \f[ \frac{(t_2-t_1)}{ \int_{t_1}^{t_2} \! 2^{-t/\mathrm{halflife}} \, dt} \f] */ inline double -decay_correction_factor(const double isotope_halflife, const double start_time, const double end_time) -{ - assert(end_time-start_time>0); - const double lambda=std::log(2.)/isotope_halflife; +decay_correction_factor(const double isotope_halflife, const double start_time, const double end_time) { + assert(end_time - start_time > 0); + const double lambda = std::log(2.) / isotope_halflife; - return - std::fabs(lambda*(end_time-start_time)) < .01 - ? std::exp(-start_time*lambda) // if very short frame, we can ignore the duration - : lambda*(end_time-start_time)/ - (std::exp(-start_time*lambda)-std::exp(-end_time*lambda)); + return std::fabs(lambda * (end_time - start_time)) < .01 + ? std::exp(-start_time * lambda) // if very short frame, we can ignore the duration + : lambda * (end_time - start_time) / (std::exp(-start_time * lambda) - std::exp(-end_time * lambda)); } //! Computes the decay-correction factor for activity at a given time point @@ -58,9 +55,9 @@ decay_correction_factor(const double isotope_halflife, const double start_time, This function computes the correction factor to convert activity at t0 + \a rel_time to activity at t0, i.e. \f[ 2^{(\mathrm{rel\_time} / \mathrm{halflife})} \f] */ -inline double decay_correction_factor(const double isotope_halflife, const double rel_time) -{ - return std::exp(rel_time*std::log(2.)/isotope_halflife); +inline double +decay_correction_factor(const double isotope_halflife, const double rel_time) { + return std::exp(rel_time * std::log(2.) / isotope_halflife); } END_NAMESPACE_STIR diff --git a/src/include/stir/deprecated.h b/src/include/stir/deprecated.h index 7e7a54eb0f..96bc351292 100644 --- a/src/include/stir/deprecated.h +++ b/src/include/stir/deprecated.h @@ -1,6 +1,6 @@ /* Copyright (C) 2020, UCL - Copyright (C) 2020, UKRI + Copyright (C) 2020, UKRI This file is part of STIR. This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -15,7 +15,7 @@ #ifndef __stir_deprecated_H__ #define __stir_deprecated_H__ /*! - \file + \file \ingroup buildblock \brief This file declares a deprecation macro. */ @@ -23,15 +23,14 @@ START_NAMESPACE_STIR //! Deprecation macro #if defined(__GNUC__) || defined(__clang__) -#define STIR_DEPRECATED __attribute__((deprecated)) +# define STIR_DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) -#define STIR_DEPRECATED __declspec(deprecated) +# define STIR_DEPRECATED __declspec(deprecated) #else -#pragma message("WARNING: You need to implement DEPRECATED for this compiler") -#define STIR_DEPRECATED +# pragma message("WARNING: You need to implement DEPRECATED for this compiler") +# define STIR_DEPRECATED #endif END_NAMESPACE_STIR - #endif // __stir_deprecated_H__ \ No newline at end of file diff --git a/src/include/stir/detail/test_if_1d.h b/src/include/stir/detail/test_if_1d.h index 1ad64ba4df..2693a31456 100644 --- a/src/include/stir/detail/test_if_1d.h +++ b/src/include/stir/detail/test_if_1d.h @@ -1,6 +1,6 @@ /*! - \file - \ingroup buildblock_detail + \file + \ingroup buildblock_detail \brief Classes for use in implementation of stir::Array, stir::BasicCoordinate etc to test if it's a 1D array. \author Kris Thielemans @@ -26,56 +26,56 @@ #ifndef __stir_detail_test_if_1d_H__ #define __stir_detail_test_if_1d_H__ namespace stir { - namespace detail { - /*! \ingroup buildblock_detail - \brief a class used to signify it's a 1D array - \see test_if_1d - */ - struct is_1d{}; - /*! \ingroup buildblock_detail - \brief a class used to signify it's not a 1D array - \see test_if_1d - */ - struct is_not_1d{}; +namespace detail { +/*! \ingroup buildblock_detail + \brief a class used to signify it's a 1D array + \see test_if_1d +*/ +struct is_1d {}; +/*! \ingroup buildblock_detail + \brief a class used to signify it's not a 1D array + \see test_if_1d +*/ +struct is_not_1d {}; - /*! \ingroup buildblock_detail - \brief a templated class used to check if it's a 1D array or not - This class only exists to allow a work-around for older compilers - (such as VC 6.0) that do not implement partial ordering of - function templates or partial template specialisation. +/*! \ingroup buildblock_detail + \brief a templated class used to check if it's a 1D array or not + This class only exists to allow a work-around for older compilers + (such as VC 6.0) that do not implement partial ordering of + function templates or partial template specialisation. - For modern compilers one can write - \code - // generic case - template void f(Array&); - // 1D case - template void f(Array<1,T>&); - \endcode - The work-around is as follows - \code - // generic case - template void f_help(is_not_1d, Array&); - // 1D case - template void f_help(is_1d, Array<1,T>&); - // function that will dispatch - template void f(Array& a) - { f_help(test_if_1d(), a); } - \endcode - So, the same effect is achieved by having one extra function. - Of course, the name f_help is arbitrary, and could just as well - be f. However, it's best to hide these away from the user, as they - should never be used explicitly. - */ - // note: should be Num_dimensions and not num_dimensions - // because for old compilers, num_dimensions is sometimes #defined (sigh) - template - struct test_if_1d : is_not_1d {}; - /*! \ingroup buildblock_detail - \brief 1D specialisation of a templated class used to check if it's a 1D array or not - */ - template <> - struct test_if_1d<1> : is_1d {}; - } -} + For modern compilers one can write + \code + // generic case + template void f(Array&); + // 1D case + template void f(Array<1,T>&); + \endcode + The work-around is as follows + \code + // generic case + template void f_help(is_not_1d, Array&); + // 1D case + template void f_help(is_1d, Array<1,T>&); + // function that will dispatch + template void f(Array& a) + { f_help(test_if_1d(), a); } + \endcode + So, the same effect is achieved by having one extra function. + Of course, the name f_help is arbitrary, and could just as well + be f. However, it's best to hide these away from the user, as they + should never be used explicitly. +*/ +// note: should be Num_dimensions and not num_dimensions +// because for old compilers, num_dimensions is sometimes #defined (sigh) +template +struct test_if_1d : is_not_1d {}; +/*! \ingroup buildblock_detail + \brief 1D specialisation of a templated class used to check if it's a 1D array or not +*/ +template <> +struct test_if_1d<1> : is_1d {}; +} // namespace detail +} // namespace stir #endif diff --git a/src/include/stir/display.h b/src/include/stir/display.h index a802d5a645..ac14c710b7 100644 --- a/src/include/stir/display.h +++ b/src/include/stir/display.h @@ -2,11 +2,11 @@ #ifndef __DISPLAY_H__ #define __DISPLAY_H__ -/*! +/*! \file \ingroup display - + \brief Functions to display 2D and 3D stir::Array and stir::RelatedViewgrams objects \author Kris Thielemans @@ -33,13 +33,12 @@ See STIR/LICENSE.txt for details */ - #include "stir/VectorWithOffset.h" #include "stir/Array.h" START_NAMESPACE_STIR -# if defined(__GNUC__) && (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +#if defined(__GNUC__) && (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) // gcc 2.95.2 is the only compiler we've used that handles the defaults properly /*! \brief The main function to display Array<3,elemT> objects. @@ -51,24 +50,24 @@ START_NAMESPACE_STIR \param plane_stack the Array object - \param scale_factors + \param scale_factors a VectorWithOffset of factors which are multiplied with the numbers - in the Array object to give the "real" values + in the Array object to give the "real" values \param text a VectorWithOffset of strings that are displayed below the images \param maxi a double which gives the ("real") value that will correspond to the - maximum of the color scale. All bigger values are displayed with the - same color. - If maxi is 0, all planes are scaled independently. + maximum of the color scale. All bigger values are displayed with the + same color. + If maxi is 0, all planes are scaled independently. \param title text that will be used as a title for the display. title==0 means no text. - \param zoom + \param zoom an int giving the number of times the image should be enlarged. - Enlargement currently is with linear interpolation, giving - reasonably smooth images (although one could want to see the - 'pixels', but I didn't implement that yet). - If zoom = 0, maximum enlargement is used. + Enlargement currently is with linear interpolation, giving + reasonably smooth images (although one could want to see the + 'pixels', but I didn't implement that yet). + If zoom = 0, maximum enlargement is used. Note that the scale_factors and text arrays are required to have the same range is the outer dimension of the Array<3,elemT> object. @@ -81,116 +80,78 @@ START_NAMESPACE_STIR */ // TODO, make version with CHARP ='string' but requires function overloading template -void display(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi = 0, - const char * const title = 0, - int zoom = 0); +void display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi = 0, const char* const title = 0, int zoom = 0); //! \brief display for Array<3,elemT> without scale factors and text. template -inline void display(const Array<3,elemT>& plane_stack, - double maxi = 0, - const char * const title = 0, int zoom = 0); - +inline void display(const Array<3, elemT>& plane_stack, double maxi = 0, const char* const title = 0, int zoom = 0); -//! \brief display for Array<2,elemT> objects, text==0 means no text. +//! \brief display for Array<2,elemT> objects, text==0 means no text. template -inline void display(const Array<2,elemT>& plane, - const char * const text = 0, - double maxi = 0, int zoom = 0); +inline void display(const Array<2, elemT>& plane, const char* const text = 0, double maxi = 0, int zoom = 0); #else // !gcc 2.95 - // VC and gcc 2.8.1 have problems with the defaults in the above declarations. // So, we have to do them by hand... template -void display(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, - const char * const title , - int zoom); +void display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi, const char* const title, int zoom); template -inline void display(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, - const char * const title); +inline void display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi, const char* const title); template -inline void display(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi); - +inline void display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text, double maxi); template -inline void display(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text); +inline void display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, + const VectorWithOffset& text); template -inline void display(const Array<3,elemT>& plane_stack, - double maxi, - const char * const title, - int zoom); +inline void display(const Array<3, elemT>& plane_stack, double maxi, const char* const title, int zoom); template -inline void display(const Array<3,elemT>& plane_stack, - double maxi, - const char * const title); +inline void display(const Array<3, elemT>& plane_stack, double maxi, const char* const title); template -inline void display(const Array<3,elemT>& plane_stack, - double maxi); +inline void display(const Array<3, elemT>& plane_stack, double maxi); template -inline void display(const Array<3,elemT>& plane_stack); +inline void display(const Array<3, elemT>& plane_stack); template -inline void display(const Array<2,elemT>& plane, - const char * const text, - double maxi, int zoom); +inline void display(const Array<2, elemT>& plane, const char* const text, double maxi, int zoom); template -inline void display(const Array<2,elemT>& plane, - const char * const text, - double maxi); +inline void display(const Array<2, elemT>& plane, const char* const text, double maxi); template -inline void display(const Array<2,elemT>& plane, - const char * const text); +inline void display(const Array<2, elemT>& plane, const char* const text); template -inline void display(const Array<2,elemT>& plane); +inline void display(const Array<2, elemT>& plane); #endif - - -template class RelatedViewgrams; +template +class RelatedViewgrams; //! Convenience function to display all viewgrams in a RelatedViewgrams object template -void display(const RelatedViewgrams& v1, - double maxi = 0, - const char * const title = 0, - int zoom = 0); +void display(const RelatedViewgrams& v1, double maxi = 0, const char* const title = 0, int zoom = 0); class DetPairData; class FanProjData; -void display(const DetPairData&,const char * const); -void display(const FanProjData&,const char * const); - - +void display(const DetPairData&, const char* const); +void display(const FanProjData&, const char* const); END_NAMESPACE_STIR #include "stir/display.inl" -#endif +#endif diff --git a/src/include/stir/display.inl b/src/include/stir/display.inl index f0c1d570c8..84a711bd8f 100644 --- a/src/include/stir/display.inl +++ b/src/include/stir/display.inl @@ -1,9 +1,9 @@ // // -/*! +/*! \file \ingroup display - + \brief functions to display 2D and 3D stir::Array objects \author Kris Thielemans @@ -38,126 +38,117 @@ START_NAMESPACE_STIR const VectorWithOffset& , const VectorWithOffset& , double, - const char * const , + const char * const , int zoom) for more info. This function sets the 'text' parameter to a sequence of numbers. */ template -void -display(const Array<3,elemT>& plane_stack, - double maxi, - const char * const title, - int zoom) +void +display(const Array<3, elemT>& plane_stack, double maxi, const char* const title, int zoom) { - VectorWithOffset scale_factors(plane_stack.get_min_index(), - plane_stack.get_max_index()); + VectorWithOffset scale_factors(plane_stack.get_min_index(), plane_stack.get_max_index()); scale_factors.fill(1.); - VectorWithOffset text(plane_stack.get_min_index(), - plane_stack.get_max_index()); - - for (int i=plane_stack.get_min_index();i<= plane_stack.get_max_index();i++) - { - text[i]=new char[10]; - sprintf(text[i],"%d", i); + VectorWithOffset text(plane_stack.get_min_index(), plane_stack.get_max_index()); + + for (int i = plane_stack.get_min_index(); i <= plane_stack.get_max_index(); i++) { + text[i] = new char[10]; + sprintf(text[i], "%d", i); } - - display(plane_stack, scale_factors, text, - maxi, title,zoom); + + display(plane_stack, scale_factors, text, maxi, title, zoom); // clean up memory afterwards - for (int i=plane_stack.get_min_index();i<= plane_stack.get_max_index();i++) + for (int i = plane_stack.get_min_index(); i <= plane_stack.get_max_index(); i++) delete[] text[i]; - } -/*! +/*! \see display(const Array<3,elemT>&, const VectorWithOffset& , const VectorWithOffset& , double, - const char * const , + const char * const , int zoom) for more info.*/ template -void -display(const Array<2,elemT>& plane, - const char * const text, - double maxi, int zoom ) -{ - - if (plane.get_length()==0) +void +display(const Array<2, elemT>& plane, const char* const text, double maxi, int zoom) { + + if (plane.get_length() == 0) return; // make a 3D array with arbitrary dimensions for its first and only plane - Array<3,elemT> stack(IndexRange3D(0,0,0,0,0,0)); + Array<3, elemT> stack(IndexRange3D(0, 0, 0, 0, 0, 0)); // this assignment sets correct dimensions for the 2 lowest dimensions stack[0] = plane; VectorWithOffset scale_factors(1); scale_factors[0] = 1.F; VectorWithOffset texts(1); texts[0] = ""; - + display(stack, scale_factors, texts, maxi, text, zoom); } -# if defined(__GNUC__) && (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +#if defined(__GNUC__) && (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) // gcc 2.95.2 is the only compiler we've used that handles the defaults properly -#else +#else // VC and gcc 2.8.1 have problems with the defaults in the above declarations. // So, we have to do them by hand... - template -void display(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi, - const char * const title) -{ display(plane_stack, scale_factors, text, maxi, title, 0); } +void +display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, const VectorWithOffset& text, + double maxi, const char* const title) { + display(plane_stack, scale_factors, text, maxi, title, 0); +} template -void display(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text, - double maxi) -{ display(plane_stack, scale_factors, text, maxi, 0, 0); } - +void +display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, const VectorWithOffset& text, + double maxi) { + display(plane_stack, scale_factors, text, maxi, 0, 0); +} template -void display(const Array<3,elemT>& plane_stack, - const VectorWithOffset& scale_factors, - const VectorWithOffset& text) -{ display(plane_stack, scale_factors, text, 0., 0, 0); } +void +display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, const VectorWithOffset& text) { + display(plane_stack, scale_factors, text, 0., 0, 0); +} template -void display(const Array<3,elemT>& plane_stack, - double maxi, - const char * const title) -{ display(plane_stack, maxi, title, 0); } +void +display(const Array<3, elemT>& plane_stack, double maxi, const char* const title) { + display(plane_stack, maxi, title, 0); +} template -void display(const Array<3,elemT>& plane_stack, - double maxi) -{ display(plane_stack, maxi, 0, 0); } +void +display(const Array<3, elemT>& plane_stack, double maxi) { + display(plane_stack, maxi, 0, 0); +} template -void display(const Array<3,elemT>& plane_stack) -{ display(plane_stack, 0., 0, 0); } +void +display(const Array<3, elemT>& plane_stack) { + display(plane_stack, 0., 0, 0); +} template -void display(const Array<2,elemT>& plane, - const char * const text, - double maxi) -{ display(plane, text, maxi, 0); } +void +display(const Array<2, elemT>& plane, const char* const text, double maxi) { + display(plane, text, maxi, 0); +} template -void display(const Array<2,elemT>& plane, - const char * const text) -{ display(plane, text, 0., 0); } +void +display(const Array<2, elemT>& plane, const char* const text) { + display(plane, text, 0., 0); +} template -void display(const Array<2,elemT>& plane) -{ display(plane, 0, 0., 0); } - +void +display(const Array<2, elemT>& plane) { + display(plane, 0, 0., 0); +} #endif diff --git a/src/include/stir/doxygen_doc_for_boost.h b/src/include/stir/doxygen_doc_for_boost.h index e0ffe180b3..a749398147 100644 --- a/src/include/stir/doxygen_doc_for_boost.h +++ b/src/include/stir/doxygen_doc_for_boost.h @@ -4,14 +4,14 @@ /*! \file \ingroup boost - + \brief Documentation for some boost functions - + \author Kris Thielemans \author PARAPET project - - -*/ + + +*/ /* Copyright (C) 2000 PARAPET project @@ -32,7 +32,7 @@ */ /*! \namespace boost - \brief Namespace for the boost library + \brief Namespace for the boost library see http://www.boost.org */ @@ -46,33 +46,31 @@ See http://www.boost.org for more info. */ -namespace boost -{ - namespace detail { - /*! \ingroup boost - \brief Boost class for chaining of operators (see operators.hpp) - */ - class empty_base {}; - } +namespace boost { +namespace detail { +/*! \ingroup boost +\brief Boost class for chaining of operators (see operators.hpp) +*/ +class empty_base {}; +} // namespace detail /*! \ingroup boost \brief Boost class to define all comparison operators given only 2 (see operators.hpp) */ template - struct partially_ordered {}; +struct partially_ordered {}; /*! \ingroup boost \brief Boost class to define operator!= in terms of operator== (see operators.hpp) */ template - struct equality_comparable {}; - +struct equality_comparable {}; /*! \ingroup boost \brief A smart pointer class: multiple shared_ptr's refer to one object This class keeps a reference counter to see how many shared_ptr's refer - to the object. When a shared_ptr is deleted, the reference counter is + to the object. When a shared_ptr is deleted, the reference counter is decremented and if the object is longer referenced, it is deleted. \par Advantages: (it's easy) @@ -84,7 +82,7 @@ template \par Disadvantages: (you have to be careful)
          -
        • If the object which a shared_ptr refers to gets modified, it affects all +
        • If the object which a shared_ptr refers to gets modified, it affects all shared_ptrs sharing the object.
        • Constructing 2 shared_ptr's from the same ordinary pointer gives trouble.
        @@ -92,8 +90,8 @@ template \par Example: \code - - { + + { // ok shared_ptr i_ptr1(new int (2)); shared_ptr i_ptr2(i_ptr1); @@ -106,7 +104,7 @@ template // now never use i_ptr anymore } } - { + { // trouble! *i_ptr will be deleted twice ! int * i_ptr = new int (2); shared_ptr i_ptr1 (i_ptr); @@ -115,7 +113,6 @@ template \endcode */ template - class shared_ptr {}; - +class shared_ptr {}; -} +} // namespace boost diff --git a/src/include/stir/doxygengroups.h b/src/include/stir/doxygengroups.h index 0b1d3b8735..1ac0a900c7 100644 --- a/src/include/stir/doxygengroups.h +++ b/src/include/stir/doxygengroups.h @@ -42,7 +42,7 @@ /*! \namespace stir::ecat \brief Namespace for the ECAT IO part of the STIR library (and some/most of its applications) - This namespace contains all routines that are common to the ECAT6 and + This namespace contains all routines that are common to the ECAT6 and ECAT7 format. */ @@ -50,16 +50,16 @@ \brief Namespace for the ECAT7 IO part of the STIR library (and some/most of its applications) This namespace is only non-empty when the HAVE_LLN_MATRIX preprocessor - symbol is defined during compilation. + symbol is defined during compilation. */ // have to define it here, otherwise doxygen ignores the \def command below -#define HAVE_LLN_MATRIX +#define HAVE_LLN_MATRIX /*! \def HAVE_LLN_MATRIX \brief Preprocessor symbol that needs to be defined to enable ECAT7 support. - You need to have the ecat matrix library developed originally at the - UCL of Louvain la Neuve. If the STIR Makefiles can find this + You need to have the ecat matrix library developed originally at the + UCL of Louvain la Neuve. If the STIR Makefiles can find this library, HAVE_LLN_MATRIX will be automatically defined for you. See the User's guide for instructions. */ @@ -67,7 +67,6 @@ \brief Namespace for the ECAT6 IO part of the STIR library (and some/most of its applications) */ - /*! \namespace stir::GE \brief Namespace for the part of the STIR library that handles GE data (and some/most of its applications) @@ -94,11 +93,11 @@ The whole collection of libraries in STIR. \defgroup buildblock Basic building blocks \ingroup STIR_library Library with things that are not specific to reconstructions. -This includes multi-dimensional arrays, images, image processors, +This includes multi-dimensional arrays, images, image processors, projection data,... */ /*! -\defgroup buildblock_detail Implementation details for buildblock +\defgroup buildblock_detail Implementation details for buildblock \ingroup buildblock */ /*! @@ -141,7 +140,7 @@ Classes for LORs. /*! \defgroup densitydata Items related to image data \ingroup buildblock -Basic support for image (or discretised density) data. +Basic support for image (or discretised density) data. */ /*! \defgroup resolution Items related to finding image resolution based on point or line sources @@ -180,7 +179,7 @@ be selected at run-time. Library with building blocks for reading scan data \todo move projection data etc in here */ -/*! +/*! \defgroup singles_buildblock Singles rates etc \ingroup data_buildblock */ @@ -189,18 +188,18 @@ Library with building blocks for reading scan data \defgroup numerics Numerical algorithms \ingroup STIR_library */ -/*! +/*! \defgroup DFT Discrete Fourier transforms \ingroup numerics */ -/*! +/*! \defgroup BSpline Classes and functions for B-spline interpolation. \ingroup numerics */ /*! \defgroup IO Input/Output Library \ingroup STIR_library -Library with classes and functions to read and write images and projection +Library with classes and functions to read and write images and projection from/to file. */ /*! @@ -217,19 +216,19 @@ from/to file. \ingroup IO */ -/*! +/*! \defgroup listmode Support classes for reading list mode data \ingroup STIR_library */ -/*! +/*! \defgroup Shape Classes for describing geometric shapes such as cylinders etc. \ingroup STIR_library */ -/*! +/*! \defgroup evaluation Classes for computing ROI values and other FOMs - For image evaluation, it is often necessary to compute ROI values, + For image evaluation, it is often necessary to compute ROI values, or other simple Figures of Merits (FOMs). These classes and functions allow you do to this directly in STIR. This is mainly useful for automation, as there is no nice graphical interface in STIR @@ -247,18 +246,18 @@ Library with 'general' reconstruction building blocks \ingroup recon_buildblock Everything (?) related to projection matrices, forward and back projection. -In the context of image reconstruction, 'forward projection' means going from -the image to an estimate of the (mean of the) data. This is because in -SPECT and PET, the measurements can be seen to be approximations of line +In the context of image reconstruction, 'forward projection' means going from +the image to an estimate of the (mean of the) data. This is because in +SPECT and PET, the measurements can be seen to be approximations of line integrals through the object. -STIR keeps this terminology, even though it is unfortunate. (For instance, +STIR keeps this terminology, even though it is unfortunate. (For instance, a stir::ProjMatrix is not a projection matrix in the mathematical sense.) */ /*! \defgroup symmetries Symmetries building blocks \ingroup projection -Usually, there are (geometric) symmetries between the image and the projection +Usually, there are (geometric) symmetries between the image and the projection data. This means that various elements of the projection matrix will be equal. The classes in this module convert this concept into code, such that projection matrices need only be computed for the 'independent' bins. @@ -269,7 +268,7 @@ matrices need only be computed for the 'independent' bins. Everything related to BinNormalisation classes. In PET 'normalisation' is used to describe a multiplicative calibration of -every detector-pair. More generally, it can be used to the process of +every detector-pair. More generally, it can be used to the process of 'correcting' projection data by multiplying every bin with a factor. */ /*! @@ -351,7 +350,7 @@ building blocks for scatter estimation Library for displaying of images */ /*! -\defgroup para Parallel library +\defgroup para Parallel library \ingroup STIR_library */ @@ -372,9 +371,6 @@ Library for displaying of images \ingroup alltest */ - - - /*! \defgroup main_programs Executables \ingroup STIR @@ -394,8 +390,6 @@ Almost all programs that can be executed by the user. Includes conversion programs etc. */ - - /*! \defgroup examples Example files \ingroup STIR diff --git a/src/include/stir/doxygenmain.h b/src/include/stir/doxygenmain.h index b88cd304e5..be9524a431 100644 --- a/src/include/stir/doxygenmain.h +++ b/src/include/stir/doxygenmain.h @@ -24,16 +24,16 @@ \section intro Introduction This is the detailed documentation for STIR: Software for Tomographic - Image Reconstruction. Additional documentation - (sometimes overlapping) is given in the User's Guide, - Overview documents etc are available on the + Image Reconstruction. Additional documentation + (sometimes overlapping) is given in the User's Guide, + Overview documents etc are available on the STIR website (http://stir.sourceforge.net). You should probably read those first before looking into the documentation on this page. The current pages are automatically generated by doxygen from text comments in the files. - As the amount of software is rather large, some guidance is + As the amount of software is rather large, some guidance is needed. The best place to start is probably the Modules section. This attempts to group files in a sensible way. In particular, a User might only be interested in the Executables module. (Note however that the doxygen @@ -41,16 +41,16 @@ just executing the utility should give a usage message). Another way to navigate through this is the Class Hierarchy page, or indeed - any of the other alphabetical lists. + any of the other alphabetical lists. However, this is not structured at all, and even contains some classes - which we'd rather not have in there. So, in the beginning, this might be + which we'd rather not have in there. So, in the beginning, this might be somewhat confusing. \section docproblems Problems to keep in mind when reading this documentation - All documentation depends on the person who writes it. In the end, only + All documentation depends on the person who writes it. In the end, only the code is what matters... - + */ diff --git a/src/include/stir/error.h b/src/include/stir/error.h index 491030a5e4..565ad1d58d 100644 --- a/src/include/stir/error.h +++ b/src/include/stir/error.h @@ -37,7 +37,7 @@ START_NAMESPACE_STIR /*! \ingroup buildblock The arguments are the same as if you would call printf(). The error message is written to stderr, - preceeded by "ERROR:", a std::string is constructed with the error message, and + preceeded by "ERROR:", a std::string is constructed with the error message, and throw is called with the string as argument. Note that because we throw an exception, the caller can catch it. Prior to STIR 2.1, this was @@ -52,9 +52,7 @@ START_NAMESPACE_STIR \deprecated (use 1 argument version instead) */ -void -error(const char *const s, ...); - +void error(const char* const s, ...); //! Use this function for writing error messages and throwing an exception /*! \ingroup buildblock @@ -79,12 +77,9 @@ error(const char *const s, ...); template inline void -error(const STRING& string) -{ +error(const STRING& string) { std::stringstream sstr; - sstr << "\nERROR: " - << string - << std::endl; + sstr << "\nERROR: " << string << std::endl; std::cerr << sstr.str(); throw sstr.str(); } diff --git a/src/include/stir/evaluation/ROIValues.h b/src/include/stir/evaluation/ROIValues.h index 1dd570cd3d..67623e8525 100644 --- a/src/include/stir/evaluation/ROIValues.h +++ b/src/include/stir/evaluation/ROIValues.h @@ -37,86 +37,68 @@ START_NAMESPACE_STIR - /*! \ingroup evaluation \brief A class to store and get results of an ROI calculation. - + This class stores the volume of the ROI (in cubic mm), the integral over the ROI of the functions and - its square and the min and max values in the ROI. These values are used to compute mean, + its square and the min and max values in the ROI. These values are used to compute mean, standard deviation and coefficient of variance. */ -class ROIValues -{ +class ROIValues { public: - - ROIValues() - {init();}; + ROIValues() { init(); }; ROIValues(float roi_volume, float integral, float integral_of_square, float min_value, float max_value) - : roi_volume(roi_volume), integral(integral), integral_of_square(integral_of_square), - min_value(min_value), max_value(max_value) - { - update(); - }; + : roi_volume(roi_volume), integral(integral), integral_of_square(integral_of_square), min_value(min_value), + max_value(max_value) { + update(); + }; //! Combine the ROI values appropriately - ROIValues operator+= (const ROIValues &iv) - { - roi_volume += iv.roi_volume; - integral += iv.integral; - integral_of_square += iv.integral_of_square; - + ROIValues operator+=(const ROIValues& iv) { + roi_volume += iv.roi_volume; + integral += iv.integral; + integral_of_square += iv.integral_of_square; #ifndef STIR_NO_NAMESPACES - min_value = std::min(min_value, iv.min_value); - max_value = std::max(max_value, iv.max_value); + min_value = std::min(min_value, iv.min_value); + max_value = std::max(max_value, iv.max_value); #else - min_value = min(min_value, iv.min_value); - max_value = max(max_value, iv.max_value); + min_value = min(min_value, iv.min_value); + max_value = max(max_value, iv.max_value); #endif - update(); - return *this; - }; + update(); + return *this; + }; //! Return a string with all info, one per line std::string report() const; //! Total valume (in mm^3) - float get_roi_volume() const - { return roi_volume; } + float get_roi_volume() const { return roi_volume; } //! Sum of elements times voxel volume - float get_integral() const - { return integral; } + float get_integral() const { return integral; } //! Sum of squares times voxel volume - float get_integral_of_square() const - { return integral_of_square; } + float get_integral_of_square() const { return integral_of_square; } //! Mean value - float get_mean() const - { return mean_value; } + float get_mean() const { return mean_value; } //! Variance - float get_variance() const - { return variance_value; } + float get_variance() const { return variance_value; } //! Standard deviation - float get_stddev() const - {return std_value; } + float get_stddev() const { return std_value; } //! Coefficient of Variance =stddev/mean) - float get_CV() const - {return std_value/mean_value; } + float get_CV() const { return std_value / mean_value; } //! Minimum value in the ROI - float get_min() const - { return min_value; } + float get_min() const { return min_value; } //! Maximum value in the ROI - float get_max() const - { return max_value; } + float get_max() const { return max_value; } - -//friend ostream &operator <<( ostream &stream, ROIValues val); + // friend ostream &operator <<( ostream &stream, ROIValues val); private: - float roi_volume; float integral; float integral_of_square; @@ -127,7 +109,7 @@ class ROIValues float min_value; float max_value; - + void init(); void update(); }; diff --git a/src/include/stir/evaluation/compute_ROI_values.h b/src/include/stir/evaluation/compute_ROI_values.h index 15d9c6a4c2..b4d2f3460e 100644 --- a/src/include/stir/evaluation/compute_ROI_values.h +++ b/src/include/stir/evaluation/compute_ROI_values.h @@ -1,10 +1,10 @@ // // /*! - \file + \file \ingroup evaluation - \brief Declaration of various function that computes ROI values + \brief Declaration of various function that computes ROI values \author Kris Thielemans */ @@ -31,61 +31,49 @@ START_NAMESPACE_STIR -template class CartesianCoordinate2D; -template class CartesianCoordinate3D; -template class VectorWithOffset; -template class DiscretisedDensity; +template +class CartesianCoordinate2D; +template +class CartesianCoordinate3D; +template +class VectorWithOffset; +template +class DiscretisedDensity; class Shape3D; /*! \ingroup evaluation \name Functions to compute ROI values - - Shapes are first discretised using Shape3D::construct_volume. This can make fuzzy - boundaries (when the \a num_samples argument is not (1,1,1), or when DiscretisedShape3D - needs zooming). Mean and stddev are computed using weighted versions, taking this smoothness + + Shapes are first discretised using Shape3D::construct_volume. This can make fuzzy + boundaries (when the \a num_samples argument is not (1,1,1), or when DiscretisedShape3D + needs zooming). Mean and stddev are computed using weighted versions, taking this smoothness into account, while ROI_min and max are ignore those weights. */ //@{ // TODO doc -void -compute_ROI_values_per_plane(VectorWithOffset& values, - const DiscretisedDensity<3,float>& image, - const Shape3D& shape, - const CartesianCoordinate3D& num_samples); -ROIValues -compute_total_ROI_values(const VectorWithOffset& values); - -ROIValues -compute_total_ROI_values(const DiscretisedDensity<3,float>& image, - const Shape3D& shape, - const CartesianCoordinate3D& num_samples - ); - -// function that calculate the -void -compute_plane_range_ROI_values_per_plane(VectorWithOffset& values, - const DiscretisedDensity<3,float>& image, - const CartesianCoordinate2D& plane_range, - const Shape3D& shape, - const CartesianCoordinate3D& num_samples); - -float -compute_CR_hot(ROIValues& val1, ROIValues& val2); -float -compute_CR_cold(ROIValues& val1, ROIValues& val2); -float -compute_uniformity(ROIValues& val); - -VectorWithOffset -compute_CR_hot_per_plane(VectorWithOffset& val1,VectorWithOffset& val2); - -VectorWithOffset -compute_CR_cold_per_plane(VectorWithOffset& val1,VectorWithOffset& val2); - -VectorWithOffset -compute_uniformity_per_plane(VectorWithOffset& val); +void compute_ROI_values_per_plane(VectorWithOffset& values, const DiscretisedDensity<3, float>& image, + const Shape3D& shape, const CartesianCoordinate3D& num_samples); +ROIValues compute_total_ROI_values(const VectorWithOffset& values); + +ROIValues compute_total_ROI_values(const DiscretisedDensity<3, float>& image, const Shape3D& shape, + const CartesianCoordinate3D& num_samples); + +// function that calculate the +void compute_plane_range_ROI_values_per_plane(VectorWithOffset& values, const DiscretisedDensity<3, float>& image, + const CartesianCoordinate2D& plane_range, const Shape3D& shape, + const CartesianCoordinate3D& num_samples); + +float compute_CR_hot(ROIValues& val1, ROIValues& val2); +float compute_CR_cold(ROIValues& val1, ROIValues& val2); +float compute_uniformity(ROIValues& val); + +VectorWithOffset compute_CR_hot_per_plane(VectorWithOffset& val1, VectorWithOffset& val2); + +VectorWithOffset compute_CR_cold_per_plane(VectorWithOffset& val1, VectorWithOffset& val2); + +VectorWithOffset compute_uniformity_per_plane(VectorWithOffset& val); // end of doxygen group //@} diff --git a/src/include/stir/extend_projdata.h b/src/include/stir/extend_projdata.h index bc5fd1b7fd..64f3e221b0 100644 --- a/src/include/stir/extend_projdata.h +++ b/src/include/stir/extend_projdata.h @@ -19,7 +19,7 @@ /* \ingroup projdata \file Functions that extend a direct sinogram or segment in the view direction - + \author Charalampos Tsoumpas \author Kris Thielemans @@ -27,24 +27,19 @@ START_NAMESPACE_STIR //@{ -/*! +/*! \ingroup projdata \brief Extension of direct projection data in view direction. -Functions that extend the given sinogram or segment in the view direction taking +Functions that extend the given sinogram or segment in the view direction taking periodicity into account, if exists. If the sinogram is not symmetric in tangential position, the values are extrapolated by nearest neighbour known values. This is probably only useful before calling interpolation routines, or for FORE. */ -Array<3,float> -extend_segment_in_views(const SegmentBySinogram& sino, - const int min_view_extension, const int max_view_extension); -Array<2,float> -extend_sinogram_in_views(const Sinogram& sino, - const int min_view_extension, const int max_view_extension); +Array<3, float> extend_segment_in_views(const SegmentBySinogram& sino, const int min_view_extension, + const int max_view_extension); +Array<2, float> extend_sinogram_in_views(const Sinogram& sino, const int min_view_extension, const int max_view_extension); //@} END_NAMESPACE_STIR - - diff --git a/src/include/stir/extract_line.h b/src/include/stir/extract_line.h index 802b2cf963..b70e415405 100644 --- a/src/include/stir/extract_line.h +++ b/src/include/stir/extract_line.h @@ -31,18 +31,14 @@ #include "stir/Array.h" #include "stir/BasicCoordinate.h" START_NAMESPACE_STIR - + /*! \ingroup buildblock \brief extracts a line from an array in the direction of the specified dimension. \todo make n-dimensional version -*/ +*/ template -Array<1,elemT> -inline -extract_line(const Array<3,elemT> &, - const BasicCoordinate<3,int>& index, - const int dimension); +Array<1, elemT> inline extract_line(const Array<3, elemT>&, const BasicCoordinate<3, int>& index, const int dimension); END_NAMESPACE_STIR #include "stir/extract_line.inl" diff --git a/src/include/stir/extract_line.inl b/src/include/stir/extract_line.inl index 909847ecf6..227dfa1acc 100644 --- a/src/include/stir/extract_line.inl +++ b/src/include/stir/extract_line.inl @@ -29,24 +29,21 @@ START_NAMESPACE_STIR template -Array<1,elemT> -extract_line(const Array<3,elemT>& input_array, - const BasicCoordinate<3,int>& index, - const int dimension) -{ - BasicCoordinate<3,int> min_index,max_index; +Array<1, elemT> +extract_line(const Array<3, elemT>& input_array, const BasicCoordinate<3, int>& index, const int dimension) { + BasicCoordinate<3, int> min_index, max_index; min_index[1] = input_array.get_min_index(); max_index[1] = input_array.get_max_index(); min_index[2] = input_array[index[1]].get_min_index(); max_index[2] = input_array[index[1]].get_max_index(); min_index[3] = input_array[index[1]][index[2]].get_min_index(); - max_index[3] = input_array[index[1]][index[2]].get_max_index(); - Array<1,elemT> line(min_index[dimension],max_index[dimension]); - BasicCoordinate<3,int> running_index = index; - int &counter = running_index[dimension]; - for (counter=min_index[dimension]; counter<= max_index[dimension] ; ++counter) - line[counter]= input_array[running_index]; - return line ; -} - + max_index[3] = input_array[index[1]][index[2]].get_max_index(); + Array<1, elemT> line(min_index[dimension], max_index[dimension]); + BasicCoordinate<3, int> running_index = index; + int& counter = running_index[dimension]; + for (counter = min_index[dimension]; counter <= max_index[dimension]; ++counter) + line[counter] = input_array[running_index]; + return line; +} + END_NAMESPACE_STIR diff --git a/src/include/stir/find_fwhm_in_image.h b/src/include/stir/find_fwhm_in_image.h index 99ee3f6111..797924049c 100644 --- a/src/include/stir/find_fwhm_in_image.h +++ b/src/include/stir/find_fwhm_in_image.h @@ -26,8 +26,8 @@ */ -#ifndef __find_fwhm_in_image_H__ -#define __find_fwhm_in_image_H__ +#ifndef __find_fwhm_in_image_H__ +#define __find_fwhm_in_image_H__ #include "stir/shared_ptr.h" #include "stir/DiscretisedDensity.h" @@ -35,18 +35,18 @@ #include START_NAMESPACE_STIR - + /*! \ingroup resolution \brief find width at a level \param[in] begin_iterator start of sequence to check - \param[in] max_iterator location from where the search will start, should be close + \param[in] max_iterator location from where the search will start, should be close to the location of the (local) maximum you want to investigate \param[in] end_iterator end of sequence to check \param[in] level_height intensity level at which to find the width \return width of the level set (in pixel units) - The implementation assumes uniform spacing between the samples. + The implementation assumes uniform spacing between the samples. We use linear interpolation between samples to estimate where the function value reaches the \a level_height value. @@ -55,10 +55,8 @@ START_NAMESPACE_STIR is estimated using linear extrapolation. */ template -inline float find_level_width(const RandomAccessIterType& begin_iterator, - const RandomAccessIterType& max_iterator, - const RandomAccessIterType& end_iterator, - const float level_height); +inline float find_level_width(const RandomAccessIterType& begin_iterator, const RandomAccessIterType& max_iterator, + const RandomAccessIterType& end_iterator, const float level_height); /*! \ingroup resolution \brief find width at a level @@ -67,88 +65,78 @@ inline float find_level_width(const RandomAccessIterType& begin_iterator, \param[in] level_height intensity level at which to find the width \return width of the level set (in pixel units) - This function finds the maximum in the sequence and calls + This function finds the maximum in the sequence and calls find_level_width(const RandomAccessIterType& begin_iterator, const RandomAccessIterType& max_iterator, const RandomAccessIterType& end_iterator, const float level_height) */ template -inline float find_level_width(const RandomAccessIterType& begin_iterator, - const RandomAccessIterType& end_iterator, - const float level_height); +inline float find_level_width(const RandomAccessIterType& begin_iterator, const RandomAccessIterType& end_iterator, + const float level_height); /*! \ingroup resolution - \brief + \brief finds the maximum of the Input_Array in the given slice at the given - dimension (z=1, y=2, x=3), and returns its location as a vector in BasicCoordinate Field + dimension (z=1, y=2, x=3), and returns its location as a vector in BasicCoordinate Field (only 3D implementation). -*/ -template -BasicCoordinate<3,int> -maximum_location_per_slice(const Array<3,elemT>& input_array, - const int slice, const int dimension); +*/ +template +BasicCoordinate<3, int> maximum_location_per_slice(const Array<3, elemT>& input_array, const int slice, const int dimension); /*! \ingroup resolution \brief extract a line from the given array after determining its locatin with a parabolic fit - It finds the real maximum location, using the 3 points parabolic fit. Then, tri-linear interpolation is used + It finds the real maximum location, using the 3 points parabolic fit. Then, tri-linear interpolation is used to find the whole line at the given dimension (z:1,y:2,x:3) taking into account the voxels that intersects the voxel which has in its center the point with the real maximum_value. -*/ +*/ template -Array<1,elemT> -interpolate_line(const Array<3,elemT>& input_array, - const BasicCoordinate<3,int>& max_location, - const BasicCoordinate<3,bool>& do_direction, - const int dimension); +Array<1, elemT> interpolate_line(const Array<3, elemT>& input_array, const BasicCoordinate<3, int>& max_location, + const BasicCoordinate<3, bool>& do_direction, const int dimension); /*! \ingroup resolution \brief a structure that is used to hold the output of the function find_fwhm_in_image. */ template -struct ResolutionIndex -{ - elemT voxel_value; - BasicCoordinate voxel_location; - BasicCoordinate resolution; -}; +struct ResolutionIndex { + elemT voxel_value; + BasicCoordinate voxel_location; + BasicCoordinate resolution; +}; /*! \ingroup resolution - \brief Finds FWHM, FWTM etc (in mm) for a number of point sources or a line source - + \brief Finds FWHM, FWTM etc (in mm) for a number of point sources or a line source + \param[in] input_image \param[in] num_maxima the number of maxima to find (see below) \param[in] level level at which to compute the width (2 for half maximum, 10 for tenth maximum etc.) \param[in] dimension the dimension along which the line source is oriented, or 0 for point sources - \param[in] nema enables the calculation based on the NEMA Standards Publication - NU 2-2001. - \return a list containing the maximum_value, its location per slice and resolution. - For line sources, sorted by minimum to maximum slice of the requested dimension, or for point sources, - sorted by maximum to minimum value. + \param[in] nema enables the calculation based on the NEMA Standards Publication + NU 2-2001. + \return a list containing the maximum_value, its location per slice and resolution. + For line sources, sorted by minimum to maximum slice of the requested dimension, or for point sources, + sorted by maximum to minimum value. For line sources, \a num_maxima slices are sampled (from first to last slice, with steps given by num_slices/(num_maxima+1) For point sources, if \a num_maxima is larger than 1, after finding a maximum and the resolution, the data is masked out in - a neigbhourhood of half-size (resolution*2/level). This will only ork properly if the point sources are not too close to eachother - and have roughly the maximum. + a neigbhourhood of half-size (resolution*2/level). This will only ork properly if the point sources are not too close to + eachother and have roughly the maximum. The value of the maximum is computed using a parabolic fit through the 3 points around the maximum as specified - in NEMA 2001. + in NEMA 2001. If nema=false, the interpolate_line() function is used to find a line, otherwise we use extract_line(). */ -template -std::list > -find_fwhm_in_image(DiscretisedDensity<3,elemT> & input_image, - const unsigned int num_maxima, const float level, - const int dimension, const bool nema); +template +std::list> find_fwhm_in_image(DiscretisedDensity<3, elemT>& input_image, const unsigned int num_maxima, + const float level, const int dimension, const bool nema); END_NAMESPACE_STIR #include "stir/find_fwhm_in_image.inl" - #endif // __find_fwhm_in_image_H__ diff --git a/src/include/stir/find_fwhm_in_image.inl b/src/include/stir/find_fwhm_in_image.inl index 38130d1e3d..fc9fbb3e72 100644 --- a/src/include/stir/find_fwhm_in_image.inl +++ b/src/include/stir/find_fwhm_in_image.inl @@ -29,51 +29,43 @@ #include START_NAMESPACE_STIR - - + template -float find_level_width(const RandomAccessIterType& begin_iterator, - const RandomAccessIterType& current_max_iterator, - const RandomAccessIterType& end_iterator, - const float level_height) -{ +float +find_level_width(const RandomAccessIterType& begin_iterator, const RandomAccessIterType& current_max_iterator, + const RandomAccessIterType& end_iterator, const float level_height) { const int max_position = static_cast(current_max_iterator - begin_iterator + 1); RandomAccessIterType current_iter = current_max_iterator; - while(current_iter!= end_iterator && *current_iter > level_height) ++current_iter; - if (current_iter==end_iterator) - { - warning("find_level_width: level extends beyond border." - "Cannot find the real level-width of this point source!"); - // go 1 back to remain inside the range - --current_iter; - } + while (current_iter != end_iterator && *current_iter > level_height) + ++current_iter; + if (current_iter == end_iterator) { + warning("find_level_width: level extends beyond border." + "Cannot find the real level-width of this point source!"); + // go 1 back to remain inside the range + --current_iter; + } + + // do linear interpolation to find position of level_height + float right_level_max = (*current_iter - level_height) / (*current_iter - *(current_iter - 1)); + right_level_max = float(current_iter - (begin_iterator + max_position)) - right_level_max; - // do linear interpolation to find position of level_height - float right_level_max = (*current_iter - level_height)/(*current_iter-*(current_iter-1)); - right_level_max = float(current_iter-(begin_iterator+max_position)) - right_level_max ; - current_iter = current_max_iterator; - while(current_iter!=begin_iterator && *current_iter > level_height) --current_iter; - if (current_iter == begin_iterator && *current_iter > level_height) - { - warning("find_level_width: level extends beyond border." - "Cannot find the real level-width of this point source!"); - } - - float left_level_max = (*current_iter - level_height)/(*current_iter-*(current_iter+1)); - left_level_max += float(current_iter-(begin_iterator+max_position)); + while (current_iter != begin_iterator && *current_iter > level_height) + --current_iter; + if (current_iter == begin_iterator && *current_iter > level_height) { + warning("find_level_width: level extends beyond border." + "Cannot find the real level-width of this point source!"); + } + + float left_level_max = (*current_iter - level_height) / (*current_iter - *(current_iter + 1)); + left_level_max += float(current_iter - (begin_iterator + max_position)); + + return right_level_max - left_level_max; +} - return right_level_max - left_level_max; -} - template -float find_level_width(const RandomAccessIterType& begin_iterator, - const RandomAccessIterType& end_iterator, - const float level_height) -{ - return find_level_width(begin_iterator, - std::max_element(begin_iterator,end_iterator), - end_iterator, - level_height); +float +find_level_width(const RandomAccessIterType& begin_iterator, const RandomAccessIterType& end_iterator, const float level_height) { + return find_level_width(begin_iterator, std::max_element(begin_iterator, end_iterator), end_iterator, level_height); } END_NAMESPACE_STIR diff --git a/src/include/stir/geometry/line_distances.h b/src/include/stir/geometry/line_distances.h index 949d310eec..e63f388c07 100644 --- a/src/include/stir/geometry/line_distances.h +++ b/src/include/stir/geometry/line_distances.h @@ -1,15 +1,17 @@ // // -/*! - \file +/*! + \file \ingroup geometry \brief A few functions to compute distances between lines etc \todo move implementations to .cxx + \author Nikos Efthimiou \author Kris Thielemans */ /* Copyright (C) 2005- 2005, Hammersmith Imanet Ltd + Copyright (C) 2016, University of Hull This file is part of STIR. @@ -30,10 +32,12 @@ #include "stir/LORCoordinates.h" #include #ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::sqrt; using ::fabs; } +namespace std { +using ::sqrt; +using ::fabs; +} // namespace std #endif - START_NAMESPACE_STIR /*! \ingroup geometry @@ -41,16 +45,13 @@ START_NAMESPACE_STIR The point is found by minimising the distance with both lines. - If the lines are parallel, the point returned is still valid, although it is of course + If the lines are parallel, the point returned is still valid, although it is of course not unique in practice. */ template -inline -coordT -coordinate_between_2_lines(CartesianCoordinate3D& result, - const LORAs2Points& line0, - const LORAs2Points& line1) -{ +inline coordT +coordinate_between_2_lines(CartesianCoordinate3D& result, const LORAs2Points& line0, + const LORAs2Points& line1) { /* Rationale: parametrise points on the lines as r0 + a0 d0, r1 + a1 d1 @@ -61,72 +62,60 @@ coordinate_between_2_lines(CartesianCoordinate3D& result, This can be written using inner products of all the vectors. Minimising it (by computing derivatives) results in a linear eq in a0, a1: - a0 d0d0 == a1 d0d1 + r10d0, - a0 d0d1 == a1 d1d1 + r10d1 + a0 d0d0 == a1 d0d1 + r10d0, + a0 d0d1 == a1 d1d1 + r10d1 which is easily solved. - The half-way point can then be found by using + The half-way point can then be found by using (r0 + a0 d0 + r1 + a1 d1)/2 for the a0,a1 found. */ const CartesianCoordinate3D& r0 = line0.p1(); const CartesianCoordinate3D& r1 = line1.p1(); - const CartesianCoordinate3D r10 = r1-r0; + const CartesianCoordinate3D r10 = r1 - r0; const CartesianCoordinate3D d0 = line0.p2() - line0.p1(); const CartesianCoordinate3D d1 = line1.p2() - line1.p1(); - const coordT d0d0 = inner_product(d0,d0); - const coordT d0d1 = inner_product(d0,d1); - const coordT d1d1 = inner_product(d1,d1); - const coordT r10d0 = inner_product(r10,d0); - const coordT r10r10 = inner_product(r10,r10); + const coordT d0d0 = inner_product(d0, d0); + const coordT d0d1 = inner_product(d0, d1); + const coordT d1d1 = inner_product(d1, d1); + const coordT r10d0 = inner_product(r10, d0); + const coordT r10r10 = inner_product(r10, r10); - const coordT eps=d0d0*10E-5; // small number for comparisons + const coordT eps = d0d0 * 10E-5; // small number for comparisons - const coordT denom = square(d0d1) - d0d0*d1d1; + const coordT denom = square(d0d1) - d0d0 * d1d1; coordT distance_squared; - if (std::fabs(denom) <= eps) - { - //parallel lines - const coordT a0 = r10d0/d0d0; - result = r0 + d0*a0; - distance_squared = r10r10 - square(r10d0)/d0d0; - } - else - { - const coordT r10d1 = inner_product(r10,d1); - const coordT a0 = (-d1d1*r10d0 + d0d1*r10d1)/denom; - const coordT a1 = (-d0d1*r10d0 + d0d0*r10d1)/denom; - - result = ((r0 + d0*a0) + (r1 + d1*a1))/2; - distance_squared = - (d1d1*square(r10d0) - 2*d0d1*r10d0*r10d1 + d0d0*square(r10d1))/denom + - r10r10; - } + if (std::fabs(denom) <= eps) { + // parallel lines + const coordT a0 = r10d0 / d0d0; + result = r0 + d0 * a0; + distance_squared = r10r10 - square(r10d0) / d0d0; + } else { + const coordT r10d1 = inner_product(r10, d1); + const coordT a0 = (-d1d1 * r10d0 + d0d1 * r10d1) / denom; + const coordT a1 = (-d0d1 * r10d0 + d0d0 * r10d1) / denom; + + result = ((r0 + d0 * a0) + (r1 + d1 * a1)) / 2; + distance_squared = (d1d1 * square(r10d0) - 2 * d0d1 * r10d0 * r10d1 + d0d0 * square(r10d1)) / denom + r10r10; + } if (distance_squared >= 0) return std::sqrt(distance_squared); - else - { - if (-distance_squared < eps) - return 0; - else - { - assert(false); - return std::sqrt(distance_squared); // will return NaN - } + else { + if (-distance_squared < eps) + return 0; + else { + assert(false); + return std::sqrt(distance_squared); // will return NaN } + } } - /*! \ingroup geometry \brief find the distance between a point and a line */ template -inline -coordT -distance_between_line_and_point( - const LORAs2Points& line, - const CartesianCoordinate3D& r1 ) -{ +inline coordT +distance_between_line_and_point(const LORAs2Points& line, const CartesianCoordinate3D& r1) { /* Rationale: parametrise points on the lines as r0 + a0 d0 @@ -138,29 +127,68 @@ distance_between_line_and_point( a0^2 d0d0 - 2 a0 r10d0 + r10r10 Minimising it (by computing derivatives) results in a linear eq in a0, a1: a0 d0d0 == r10d0 - */ + */ const CartesianCoordinate3D& r0 = line.p1(); - const CartesianCoordinate3D r10 = r1-r0; + const CartesianCoordinate3D r10 = r1 - r0; const CartesianCoordinate3D d0 = line.p2() - line.p1(); - const coordT d0d0 = inner_product(d0,d0); - const coordT r10d0 = inner_product(r10,d0); - const coordT r10r10 = inner_product(r10,r10); + const coordT d0d0 = inner_product(d0, d0); + const coordT r10d0 = inner_product(r10, d0); + const coordT r10r10 = inner_product(r10, r10); - //const coordT a0 = r10d0/d0d0; - //result = r0 + d0*a0; - const coordT distance_squared = r10r10 - square(r10d0)/d0d0; + // const coordT a0 = r10d0/d0d0; + // result = r0 + d0*a0; + const coordT distance_squared = r10r10 - square(r10d0) / d0d0; if (distance_squared >= 0) return std::sqrt(distance_squared); - else - { - if (-distance_squared < d0d0*10E-5) - return 0; - else - { - assert(false); - return std::sqrt(distance_squared); // will return NaN - } + else { + if (-distance_squared < d0d0 * 10E-5) + return 0; + else { + assert(false); + return std::sqrt(distance_squared); // will return NaN } + } +} + +/*! \ingroup geometry + \brief Project a point on a line. + + \author Nikos Efthimiou +*/ +template +inline void +project_point_on_a_line(const CartesianCoordinate3D& p1, const CartesianCoordinate3D& p2, + CartesianCoordinate3D& r1) { + + const CartesianCoordinate3D difference = p2 - p1; + + const CartesianCoordinate3D r10 = r1 - p1; + + float inner_prod = inner_product(difference, difference); + + const float u = inner_product(r10, difference) / inner_prod; + + r1.x() = p1.x() + u * difference.x(); + r1.y() = p1.y() + u * difference.y(); + r1.z() = p1.z() + u * difference.z(); +} + +template +inline void +project_point_on_a_line2(const CartesianCoordinate3D& p1, const CartesianCoordinate3D& p2, + CartesianCoordinate3D& r1, bool& sign) { + + const CartesianCoordinate3D difference = p2 - p1; + + const CartesianCoordinate3D r10 = r1 - p1; + + const float u = inner_product(r10, difference) / inner_product(difference, difference); + + r1[3] = u * difference[3]; + r1[2] = u * difference[2]; + r1[1] = u * difference[1]; + + sign = u > 0 ? true : false; } END_NAMESPACE_STIR diff --git a/src/include/stir/getopt.h b/src/include/stir/getopt.h index e937537e22..5cb87e09a2 100644 --- a/src/include/stir/getopt.h +++ b/src/include/stir/getopt.h @@ -1,33 +1,31 @@ /* Declarations for getopt. - Copyright (C) 1989-1994, 1996-1999, 2001 Free Software + Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. - The GNU C Library is free software; you can redistribute - it and/or modify it under the terms of the GNU Lesser - General Public License as published by the Free Software - Foundation; either version 2.1 of the License, or + The GNU C Library is free software; you can redistribute + it and/or modify it under the terms of the GNU Lesser + General Public License as published by the Free Software + Foundation; either version 2.1 of the License, or (at your option) any later version. - The GNU C Library is distributed in the hope that it will - be useful, but WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A - PARTICULAR PURPOSE. See the GNU Lesser General Public + The GNU C Library is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A + PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General - Public License along with the GNU C Library; if not, write + You should have received a copy of the GNU Lesser General + Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ - - #ifndef _stir_GETOPT_H #define _stir_GETOPT_H #ifdef HAVE_SYSTEM_GETOPT /* use system getopt */ -#include +# include #else @@ -38,13 +36,13 @@ not defined, include , which will pull in for us if it's from glibc. (Why ctype.h? It's guaranteed to exist and it doesn't flood the namespace with stuff the way some other headers do.) */ -#if !defined __GNU_LIBRARY__ -# include -#endif +# if !defined __GNU_LIBRARY__ +# include +# endif -#ifdef __cplusplus +# ifdef __cplusplus extern "C" { -#endif +# endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, @@ -52,7 +50,7 @@ extern "C" { Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ -extern char *optarg; +extern char* optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller @@ -77,7 +75,7 @@ extern int opterr; extern int optopt; -#ifndef __need_getopt +# ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is @@ -99,27 +97,25 @@ extern int optopt; one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ -struct option -{ -# if (defined __STDC__ && __STDC__) || defined __cplusplus - const char *name; -# else - char *name; -# endif +struct option { +# if (defined __STDC__ && __STDC__) || defined __cplusplus + const char* name; +# else + char* name; +# endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; - int *flag; + int* flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ -# define no_argument 0 -# define required_argument 1 -# define optional_argument 2 -#endif /* need getopt */ - +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +# endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for @@ -145,48 +141,43 @@ struct option arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ -#if (defined __STDC__ && __STDC__) || defined __cplusplus - //# ifdef __GNU_LIBRARY__ +# if (defined __STDC__ && __STDC__) || defined __cplusplus +//# ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ -extern int getopt (int ___argc, char *const *___argv, const char *__shortopts); - //# else /* not __GNU_LIBRARY__ */ - //extern int getopt (); - //# endif /* __GNU_LIBRARY__ */ - -# ifndef __need_getopt -extern int getopt_long (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); -extern int getopt_long_only (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); +extern int getopt(int ___argc, char* const* ___argv, const char* __shortopts); +//# else /* not __GNU_LIBRARY__ */ +// extern int getopt (); +//# endif /* __GNU_LIBRARY__ */ + +# ifndef __need_getopt +extern int getopt_long(int ___argc, char* const* ___argv, const char* __shortopts, const struct option* __longopts, + int* __longind); +extern int getopt_long_only(int ___argc, char* const* ___argv, const char* __shortopts, const struct option* __longopts, + int* __longind); /* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind, - int __long_only); -# endif -#else /* not __STDC__ */ -extern int getopt (); -# ifndef __need_getopt -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -# endif -#endif /* __STDC__ */ - -#ifdef __cplusplus +extern int _getopt_internal(int ___argc, char* const* ___argv, const char* __shortopts, const struct option* __longopts, + int* __longind, int __long_only); +# endif +# else /* not __STDC__ */ +extern int getopt(); +# ifndef __need_getopt +extern int getopt_long(); +extern int getopt_long_only(); + +extern int _getopt_internal(); +# endif +# endif /* __STDC__ */ + +# ifdef __cplusplus } -#endif +# endif /* Make sure we later can get all the definitions and declarations. */ -#undef __need_getopt +# undef __need_getopt #endif /* HAVE_SYSTEM_GETOPT */ #endif /* getopt.h */ - diff --git a/src/include/stir/index_at_maximum.h b/src/include/stir/index_at_maximum.h index c8454d05fa..12fa31796f 100644 --- a/src/include/stir/index_at_maximum.h +++ b/src/include/stir/index_at_maximum.h @@ -46,63 +46,56 @@ START_NAMESPACE_STIR */ template -int index_at_maximum(const VectorWithOffset& v) -{ +int +index_at_maximum(const VectorWithOffset& v) { if (v.size() == 0) return 0; - int index_at_max=v.get_min_index(); - elemT max_value=v[index_at_max]; - for (int index=v.get_min_index(); index<=v.get_max_index(); ++index) - { - const elemT value = v[index]; - if (value>max_value) - { - index_at_max=index; - max_value=value; - } + int index_at_max = v.get_min_index(); + elemT max_value = v[index_at_max]; + for (int index = v.get_min_index(); index <= v.get_max_index(); ++index) { + const elemT value = v[index]; + if (value > max_value) { + index_at_max = index; + max_value = value; } + } return index_at_max; } /*! \ingroup array - \brief Finds the first (3-dimensional) index where the maximum occurs + \brief Finds the first (3-dimensional) index where the maximum occurs in a (3-dimensional) array. \todo generalise to arbitrary dimensions \todo implementation currently cycles through the data twice */ -template -BasicCoordinate<3,int> -indices_at_maximum(const Array<3,elemT>& input_array) -{ +template +BasicCoordinate<3, int> +indices_at_maximum(const Array<3, elemT>& input_array) { const elemT current_maximum = input_array.find_max(); - BasicCoordinate<3,int> max_location, min_index, max_index; - - bool found=false; + BasicCoordinate<3, int> max_location, min_index, max_index; + + bool found = false; min_index[1] = input_array.get_min_index(); max_index[1] = input_array.get_max_index(); - for ( int k = min_index[1]; k<= max_index[1] && !found; ++k) - { - min_index[2] = input_array[k].get_min_index(); - max_index[2] = input_array[k].get_max_index(); - for ( int j = min_index[2]; j<= max_index[2] && !found; ++j) - { - min_index[3] = input_array[k][j].get_min_index(); - max_index[3] = input_array[k][j].get_max_index(); - for ( int i = min_index[3]; i<= max_index[3] && !found; ++i) - { - if (input_array[k][j][i] == current_maximum) - { - max_location[1] = k; - max_location[2] = j; - max_location[3] = i; - } - } - } - } - found = true; - return max_location; -} + for (int k = min_index[1]; k <= max_index[1] && !found; ++k) { + min_index[2] = input_array[k].get_min_index(); + max_index[2] = input_array[k].get_max_index(); + for (int j = min_index[2]; j <= max_index[2] && !found; ++j) { + min_index[3] = input_array[k][j].get_min_index(); + max_index[3] = input_array[k][j].get_max_index(); + for (int i = min_index[3]; i <= max_index[3] && !found; ++i) { + if (input_array[k][j][i] == current_maximum) { + max_location[1] = k; + max_location[2] = j; + max_location[3] = i; + } + } + } + } + found = true; + return max_location; +} END_NAMESPACE_STIR diff --git a/src/include/stir/info.h b/src/include/stir/info.h index 242c0bc076..0a73e7cc04 100644 --- a/src/include/stir/info.h +++ b/src/include/stir/info.h @@ -41,7 +41,7 @@ START_NAMESPACE_STIR std::ostream::operator\<\< would work. This function currently first writes a newline, then \c INFO, then \c string - and then another newline to std::cerr. + and then another newline to std::cerr. \todo At a later stage, it will also write to a log-file. @@ -56,13 +56,12 @@ START_NAMESPACE_STIR */ template void -info(const STRING& string, const int verbosity_level = 1) -{ - if (Verbosity::get() >= verbosity_level) { - std::stringstream ss; - ss << "\nINFO: " << string << std::endl; - writeText(ss.str().c_str(), INFORMATION_CHANNEL); - } +info(const STRING& string, const int verbosity_level = 1) { + if (Verbosity::get() >= verbosity_level) { + std::stringstream ss; + ss << "\nINFO: " << string << std::endl; + writeText(ss.str().c_str(), INFORMATION_CHANNEL); + } } END_NAMESPACE_STIR diff --git a/src/include/stir/interfile_keyword_functions.h b/src/include/stir/interfile_keyword_functions.h index 1f1334a142..3a750b383c 100644 --- a/src/include/stir/interfile_keyword_functions.h +++ b/src/include/stir/interfile_keyword_functions.h @@ -23,11 +23,10 @@ See STIR/LICENSE.txt for details */ -#ifndef __stir_interfile_keyword_functions_H__ -#define __stir_interfile_keyword_functions_H__ +#ifndef __stir_interfile_keyword_functions_H__ +#define __stir_interfile_keyword_functions_H__ #include "stir/common.h" - #include #include @@ -38,29 +37,24 @@ START_NAMESPACE_STIR This follows Interfile 3.3 conventions:
        • The characters \c space, \c tab, \c underscore, \c ! are all - treated as white space. + treated as white space.
        • Starting and trailing white space is trimmed.
        • Repeated white space is replaced with a single space
        • All letters are made lowercase. -
        +
      */ -std::string -standardise_interfile_keyword(const std::string& keyword); +std::string standardise_interfile_keyword(const std::string& keyword); //! A function object that compares Interfile keywords -/*! This is similar to std::less, except that it applies +/*! This is similar to std::less, except that it applies standardise_interfile_keyword() on its arguments before doing the comparison. Useful for constructing a std::map for instance. */ -struct interfile_less : public std::binary_function -{ - bool operator()(const std::string& a, const std::string& b) const - { - return - standardise_interfile_keyword(a) < - standardise_interfile_keyword(b); +struct interfile_less : public std::binary_function { + bool operator()(const std::string& a, const std::string& b) const { + return standardise_interfile_keyword(a) < standardise_interfile_keyword(b); } }; diff --git a/src/include/stir/interpolate.h b/src/include/stir/interpolate.h index b10aba6680..7dac04b59d 100644 --- a/src/include/stir/interpolate.h +++ b/src/include/stir/interpolate.h @@ -20,9 +20,9 @@ #ifndef __interpolate_H__ #define __interpolate_H__ /*! - \file + \file \ingroup buildblock - + \brief declares functions for interpolation \warning will be moved to numerics @@ -31,7 +31,6 @@ */ - #include "stir/numerics/overlap_interpolate.h" #endif diff --git a/src/include/stir/interpolate_projdata.h b/src/include/stir/interpolate_projdata.h index 0355557bac..1c3ff0eab4 100644 --- a/src/include/stir/interpolate_projdata.h +++ b/src/include/stir/interpolate_projdata.h @@ -19,7 +19,7 @@ /* \ingroup projdata \file Declaration of stir::interpolate_projdata - + \author Charalampos Tsoumpas \author Kris Thielemans @@ -30,48 +30,40 @@ START_NAMESPACE_STIR class ProjData; -template class BasicCoordinate; -template class Sinogram; -template class SegmentBySinogram; - +template +class BasicCoordinate; +template +class Sinogram; +template +class SegmentBySinogram; //! \brief Perform B-Splines Interpolation -/*! +/*! \ingroup projdata - \param[out] proj_data_out Its projection_data_info is used to - determine output characteristics. Data will be 'put' in here using + \param[out] proj_data_out Its projection_data_info is used to + determine output characteristics. Data will be 'put' in here using ProjData::set_sinogram(). - \param[in] proj_data_in input data + \param[in] proj_data_in input data \param[in] spline_type determines which type of BSpline will be used - \param[in] remove_interleaving - The STIR implementation of interpolating 3D (for the moment) projdata is a generalisation that applies - B-Splines Interpolation to projdata supposing that every dimension is a regular grid. For instance, for - a 3D dataset, interpolating can produce a new expanded 3D dataset based on the given information + \param[in] remove_interleaving + The STIR implementation of interpolating 3D (for the moment) projdata is a generalisation that applies + B-Splines Interpolation to projdata supposing that every dimension is a regular grid. For instance, for + a 3D dataset, interpolating can produce a new expanded 3D dataset based on the given information (proj_data_out). This mostly is useful in the scatter sinogram expansion. - See STIR documentation about B-Spline interpolation or scatter correction. + See STIR documentation about B-Spline interpolation or scatter correction. \todo This currently only works for direct sinograms (i.e. segment 0). \warning Because of the boundary conditions in the B-spline interpolation, - strange results can occur if the output sinogram has a larger range than + strange results can occur if the output sinogram has a larger range than the input sinogram. -*/ +*/ //@{ -Succeeded -interpolate_projdata(ProjData& proj_data_out, - const ProjData& proj_data_in, - const BSpline::BSplineType spline_type, - const bool remove_interleaving = false, - const bool use_view_offset = false); -Succeeded -interpolate_projdata(ProjData& proj_data_out, - const ProjData& proj_data_in, - const BasicCoordinate<3, BSpline::BSplineType> & spline_type, - const bool remove_interleaving = false, - const bool use_view_offset = false); +Succeeded interpolate_projdata(ProjData& proj_data_out, const ProjData& proj_data_in, const BSpline::BSplineType spline_type, + const bool remove_interleaving = false, const bool use_view_offset = false); +Succeeded interpolate_projdata(ProjData& proj_data_out, const ProjData& proj_data_in, + const BasicCoordinate<3, BSpline::BSplineType>& spline_type, + const bool remove_interleaving = false, const bool use_view_offset = false); //@} END_NAMESPACE_STIR - - - diff --git a/src/include/stir/inverse_SSRB.h b/src/include/stir/inverse_SSRB.h index 06c41464ab..6f5c9a36c4 100644 --- a/src/include/stir/inverse_SSRB.h +++ b/src/include/stir/inverse_SSRB.h @@ -19,13 +19,12 @@ /* \ingroup projdata \file Declaration of stir::inverse_SSRB - + \author Charalampos Tsoumpas \author Kris Thielemans */ - #include "stir/common.h" START_NAMESPACE_STIR @@ -33,16 +32,16 @@ START_NAMESPACE_STIR class ProjData; class Succeeded; //! Perform Inverse Single Slice Rebinning and write output to ProjData4D format -/*! +/*! \ingroup projdata - \param[out] proj_data_4D Its projection_data_info is used to - determine output characteristics (e.g. number of segments). Data will be 'put' in here using + \param[out] proj_data_4D Its projection_data_info is used to + determine output characteristics (e.g. number of segments). Data will be 'put' in here using ProjData::set_sinogram(). \param[in] proj_data_3D input data - The STIR implementation of Inverse SSRB applies the - inverse idea of SSRB. inverse_SSRB will produce oblique - sinograms by finding the sinogram that has the same + The STIR implementation of Inverse SSRB applies the + inverse idea of SSRB. inverse_SSRB will produce oblique + sinograms by finding the sinogram that has the same 'm'-coordinate (i.e. the intersection with the z-axis of the central LOR). In addition, if the output sinogram would lie 'half-way' 2 input sinograms, it will be set to the average of the 2 input sinograms. @@ -50,11 +49,8 @@ class Succeeded; Note that any oblique segments in \a proj_data_3D are currently ignored. Input and output projectino data should have the same number of views and tangential positions. - -*/ -Succeeded -inverse_SSRB(ProjData& proj_data_4D, - const ProjData& proj_data_3D); -END_NAMESPACE_STIR +*/ +Succeeded inverse_SSRB(ProjData& proj_data_4D, const ProjData& proj_data_3D); +END_NAMESPACE_STIR diff --git a/src/include/stir/is_null_ptr.h b/src/include/stir/is_null_ptr.h index 429fd5e3a3..b2dba01a1c 100644 --- a/src/include/stir/is_null_ptr.h +++ b/src/include/stir/is_null_ptr.h @@ -34,40 +34,36 @@ START_NAMESPACE_STIR /*! \ingroup buildblock \name testing of (smart) pointers - + A utility function that checks if an ordinary or smart pointer is null with identical syntax for all types. */ //@{ template -inline -bool -is_null_ptr(T const * const ptr) -{ +inline bool +is_null_ptr(T const* const ptr) { #ifdef BOOST_NO_CXX11_NULLPTR - return ptr==0; + return ptr == 0; #else - return ptr==nullptr; + return ptr == nullptr; #endif } template -inline -bool -is_null_ptr(shared_ptr const& sptr) -{ return is_null_ptr(sptr.get()); } +inline bool +is_null_ptr(shared_ptr const& sptr) { + return is_null_ptr(sptr.get()); +} template -inline -bool -is_null_ptr(unique_ptr const& aptr) -{ return is_null_ptr(aptr.get()); } +inline bool +is_null_ptr(unique_ptr const& aptr) { + return is_null_ptr(aptr.get()); +} #ifndef BOOST_NO_CXX11_NULLPTR -inline -bool -is_null_ptr(const std::nullptr_t) -{ +inline bool +is_null_ptr(const std::nullptr_t) { return true; } #endif diff --git a/src/include/stir/line.h b/src/include/stir/line.h index c9aaacbf9b..0a63d8dbd5 100644 --- a/src/include/stir/line.h +++ b/src/include/stir/line.h @@ -32,7 +32,6 @@ #ifndef __stir_LINE_H__ #define __stir_LINE_H__ - #include "stir/common.h" #include @@ -44,31 +43,27 @@ START_NAMESPACE_STIR \brief A class used by the Interfile parser. \warning This will be removed soon. Do NOT USE. */ -class Line : public std::string -{ - -public : - Line() : std::string() - {} - - Line& operator=(const char* ch); - - std::string get_keyword(); - int get_index(); - int get_param(std::vector& v); - // KT 29/10/98 new - int get_param(std::vector& v); - int get_param(std::vector& v); - int get_param(std::string& s); - int get_param(int& i); - // KT 01/08/98 new - int get_param(unsigned long& i); - // KT 01/08/98 new - int get_param(double& i); +class Line : public std::string { + +public: + Line() : std::string() {} + + Line& operator=(const char* ch); + + std::string get_keyword(); + int get_index(); + int get_param(std::vector& v); + // KT 29/10/98 new + int get_param(std::vector& v); + int get_param(std::vector& v); + int get_param(std::string& s); + int get_param(int& i); + // KT 01/08/98 new + int get_param(unsigned long& i); + // KT 01/08/98 new + int get_param(double& i); }; END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/linear_regression.h b/src/include/stir/linear_regression.h index a8038430a0..57ab0bc791 100644 --- a/src/include/stir/linear_regression.h +++ b/src/include/stir/linear_regression.h @@ -39,35 +39,35 @@ START_NAMESPACE_STIR \ingroup buildblock \brief Implements standard linear regression on VectorWithOffset data - The linear_regression function does straightforward + The linear_regression function does straightforward (1 dimensional) weighted least squares fitting. - \par input - + \par input + 3 VectorWithOffsets of measured_data, coordinates, weights
      1 optional boolean value use_estimated_variance (default=true) \par output - + fitted parameters : constant, scale
      goodness of fit measures : chi_square and the (co)variances - + This solves the minimisation problem: \verbatim Find constant, scale such that - chi_square = + chi_square = sum_i weights[i]* (constant + scale*coordinates[i] - measured_data[i])^2 is minimal. \endverbatim - When use_estimated_variance == false, the (co)variances are computed - assuming that 1/weights[i] is the standard deviation on measured_data[i]. - In particular, this means that the (co)variances depend only on the + When use_estimated_variance == false, the (co)variances are computed + assuming that 1/weights[i] is the standard deviation on measured_data[i]. + In particular, this means that the (co)variances depend only on the weights and the coordinates. - Alternatively, when use_estimated_variance == true, the weights are - considered to be really only proportional to the + Alternatively, when use_estimated_variance == true, the weights are + considered to be really only proportional to the 1/variance. Then the estimated variance is used to get sensible estimates of the errors: \verbatim @@ -77,21 +77,15 @@ START_NAMESPACE_STIR */ template -inline void -linear_regression(Value& constant, Value& scale, - Value& chi_square, - Value& variance_of_constant, - Value& variance_of_scale, - Value& covariance_of_constant_with_scale, - const VectorWithOffset& measured_data, - const VectorWithOffset& coordinates, - const VectorWithOffset& weights, - const bool use_estimated_variance = true - ); +inline void linear_regression(Value& constant, Value& scale, Value& chi_square, Value& variance_of_constant, + Value& variance_of_scale, Value& covariance_of_constant_with_scale, + const VectorWithOffset& measured_data, + const VectorWithOffset& coordinates, const VectorWithOffset& weights, + const bool use_estimated_variance = true); /*! \ingroup buildblock - \brief Implements standard linear regression + \brief Implements standard linear regression This function takes the data as iterators for maximum flexibility. Note that it is assumed (but not checked) that the @@ -111,29 +105,17 @@ linear_regression(Value& constant, Value& scale, */ template -inline void -linear_regression(Value& constant, Value& scale, - Value& chi_square, - Value& variance_of_constant, - Value& variance_of_scale, - Value& covariance_of_constant_with_scale, - DataIter measured_data_begin, DataIter measured_data_end, - CoordinatesIter coords_begin, - WeightsIter weights_begin, - const bool use_estimated_variance = true); +inline void linear_regression(Value& constant, Value& scale, Value& chi_square, Value& variance_of_constant, + Value& variance_of_scale, Value& covariance_of_constant_with_scale, DataIter measured_data_begin, + DataIter measured_data_end, CoordinatesIter coords_begin, WeightsIter weights_begin, + const bool use_estimated_variance = true); template -inline void -linear_regression(ValueIter regression_values_begin, - DataIter data_begin, DataIter data_end, - CoordinatesIter coords_begin, - WeightsIter weights_begin, - const bool use_estimated_variance = true); +inline void linear_regression(ValueIter regression_values_begin, DataIter data_begin, DataIter data_end, + CoordinatesIter coords_begin, WeightsIter weights_begin, const bool use_estimated_variance = true); END_NAMESPACE_STIR #include "stir/linear_regression.inl" #endif // __linear_regression_h__ - - diff --git a/src/include/stir/linear_regression.inl b/src/include/stir/linear_regression.inl index 8f8d963b76..615532bc92 100644 --- a/src/include/stir/linear_regression.inl +++ b/src/include/stir/linear_regression.inl @@ -7,7 +7,7 @@ \brief Implementation of inline functions for stir::linear_regression() \author Kris Thielemans - \author Charalampos Tsoumpas + \author Charalampos Tsoumpas \author PARAPET project @@ -31,79 +31,58 @@ #include // for size_t START_NAMESPACE_STIR -namespace detail -{ - /* - We compute the linear regression using - Numerical Recipes formulas for numerical stability - - Correspondence with their notation: - y_i = measured_data[i] - x_i = coordinates[i] - sigma_i = 1/sqrt(weights[i]) - - t_i = sqrt(weights[i]) (x[i] - Sx/S) - - This last one is computed here in terms of - wti = (x[i] - Sx/S) - - Further notation: - S = sum of the weights - Sx = weights . coordinates - Sy = weights . measured - Sty = weights . (wt*measured) - etc. - (Syy is used to compute chi_square in the current implementation) - - The fit is split up into 2 functions: - - linear_regression_compute_S - - linear_regression_compute_fit_from_S - - The main reason for this is that *compute_S needs to be - templated in 3 different argument types for maximum - flexibility. This in practice means it needs to be - an inline function (to avoid problems at linking time). - In contrast, linear_regression_compute_fit_from_S - is only templated in the Value type, which will be - float or double anyway. - */ - - // defined in .cxx +namespace detail { +/* + We compute the linear regression using + Numerical Recipes formulas for numerical stability + + Correspondence with their notation: + y_i = measured_data[i] + x_i = coordinates[i] + sigma_i = 1/sqrt(weights[i]) + + t_i = sqrt(weights[i]) (x[i] - Sx/S) + + This last one is computed here in terms of + wti = (x[i] - Sx/S) + + Further notation: + S = sum of the weights + Sx = weights . coordinates + Sy = weights . measured + Sty = weights . (wt*measured) + etc. + (Syy is used to compute chi_square in the current implementation) + + The fit is split up into 2 functions: + - linear_regression_compute_S + - linear_regression_compute_fit_from_S + + The main reason for this is that *compute_S needs to be + templated in 3 different argument types for maximum + flexibility. This in practice means it needs to be + an inline function (to avoid problems at linking time). + In contrast, linear_regression_compute_fit_from_S + is only templated in the Value type, which will be + float or double anyway. +*/ + +// defined in .cxx template -void -linear_regression_compute_fit_from_S(Value& constant, Value& scale, - Value& chi_square, - Value& variance_of_constant, - Value& variance_of_scale, - Value& covariance_of_constant_with_scale, - const double S, - const double Sx, - const double Sy, - const double Syy, - const double Stt, - const double Sty, - const std::size_t data_size, - const bool use_estimated_variance - ); +void linear_regression_compute_fit_from_S(Value& constant, Value& scale, Value& chi_square, Value& variance_of_constant, + Value& variance_of_scale, Value& covariance_of_constant_with_scale, const double S, + const double Sx, const double Sy, const double Syy, const double Stt, const double Sty, + const std::size_t data_size, const bool use_estimated_variance); template -inline void -linear_regression_compute_S(double& S, - double& Sx, - double& Sy, - double& Syy, - double& Stt, - double& Sty, - const DataIter data_begin, const DataIter data_end, - const CoordinatesIter coords_begin, - const WeightsIter weights_begin) -{ +inline void +linear_regression_compute_S(double& S, double& Sx, double& Sy, double& Syy, double& Stt, double& Sty, const DataIter data_begin, + const DataIter data_end, const CoordinatesIter coords_begin, const WeightsIter weights_begin) { DataIter data_iter = data_begin; CoordinatesIter coords_iter = coords_begin; WeightsIter weights_iter = weights_begin; - - for (; data_iter != data_end; ++data_iter, ++coords_iter, ++weights_iter) - { + + for (; data_iter != data_end; ++data_iter, ++coords_iter, ++weights_iter) { const double weight = static_cast(*weights_iter); S += weight; Sx += weight * (*coords_iter); @@ -114,11 +93,10 @@ linear_regression_compute_S(double& S, data_iter = data_begin; coords_iter = coords_begin; weights_iter = weights_begin; - - for (; data_iter != data_end; ++data_iter, ++coords_iter, ++weights_iter) - { - const double wti = ( *coords_iter - Sx/S); - Stt += *weights_iter * wti * wti; + + for (; data_iter != data_end; ++data_iter, ++coords_iter, ++weights_iter) { + const double wti = (*coords_iter - Sx / S); + Stt += *weights_iter * wti * wti; Sty += *weights_iter * wti * *data_iter; } } @@ -126,99 +104,58 @@ linear_regression_compute_S(double& S, } // end namespace detail template -inline void -linear_regression(Value& constant, Value& scale, - Value& chi_square, - Value& variance_of_constant, - Value& variance_of_scale, - Value& covariance_of_constant_with_scale, - DataIter data_begin, DataIter data_end, - CoordinatesIter coords_begin, - WeightsIter weights_begin, - const bool use_estimated_variance) -{ +inline void +linear_regression(Value& constant, Value& scale, Value& chi_square, Value& variance_of_constant, Value& variance_of_scale, + Value& covariance_of_constant_with_scale, DataIter data_begin, DataIter data_end, CoordinatesIter coords_begin, + WeightsIter weights_begin, const bool use_estimated_variance) { double Sy = 0; - double Sx = 0; + double Sx = 0; double S = 0; double Syy = 0; double Stt = 0; double Sty = 0; - detail::linear_regression_compute_S(S,Sx,Sy, Syy, Stt, Sty, - data_begin, data_end, - coords_begin, - weights_begin); - - detail::linear_regression_compute_fit_from_S(constant, scale, - chi_square, - variance_of_constant, - variance_of_scale, - covariance_of_constant_with_scale, - S,Sx,Sy, Syy, Stt, Sty, - static_cast(data_end - data_begin), - use_estimated_variance); - + detail::linear_regression_compute_S(S, Sx, Sy, Syy, Stt, Sty, data_begin, data_end, coords_begin, weights_begin); + + detail::linear_regression_compute_fit_from_S(constant, scale, chi_square, variance_of_constant, variance_of_scale, + covariance_of_constant_with_scale, S, Sx, Sy, Syy, Stt, Sty, + static_cast(data_end - data_begin), use_estimated_variance); } template -inline void -linear_regression(Value& constant, Value& scale, - Value& chi_square, - Value& variance_of_constant, - Value& variance_of_scale, - Value& covariance_of_constant_with_scale, - const VectorWithOffset& measured_data, - const VectorWithOffset& coordinates, - const VectorWithOffset& weights, - const bool use_estimated_variance - ) -{ +inline void +linear_regression(Value& constant, Value& scale, Value& chi_square, Value& variance_of_constant, Value& variance_of_scale, + Value& covariance_of_constant_with_scale, const VectorWithOffset& measured_data, + const VectorWithOffset& coordinates, const VectorWithOffset& weights, + const bool use_estimated_variance) { assert(measured_data.get_min_index() == coordinates.get_min_index()); assert(measured_data.get_min_index() == weights.get_min_index()); assert(measured_data.get_max_index() == coordinates.get_max_index()); assert(measured_data.get_max_index() == weights.get_max_index()); - - - linear_regression(constant, scale, - chi_square, - variance_of_constant, - variance_of_scale, - covariance_of_constant_with_scale, - measured_data.begin(), measured_data.end(), - coordinates.begin(), - weights.begin(), - use_estimated_variance); + + linear_regression(constant, scale, chi_square, variance_of_constant, variance_of_scale, covariance_of_constant_with_scale, + measured_data.begin(), measured_data.end(), coordinates.begin(), weights.begin(), use_estimated_variance); } template -inline void -linear_regression(ValueIter value_begin, - DataIter data_begin, DataIter data_end, - CoordinatesIter coords_begin, - WeightsIter weights_begin, - const bool use_estimated_variance) -{ +inline void +linear_regression(ValueIter value_begin, DataIter data_begin, DataIter data_end, CoordinatesIter coords_begin, + WeightsIter weights_begin, const bool use_estimated_variance) { double Sy = 0; - double Sx = 0; + double Sx = 0; double S = 0; double Syy = 0; double Stt = 0; double Sty = 0; - detail::linear_regression_compute_S(S,Sx,Sy, Syy, Stt, Sty, - data_begin, data_end, - coords_begin, - weights_begin); + detail::linear_regression_compute_S(S, Sx, Sy, Syy, Stt, Sty, data_begin, data_end, coords_begin, weights_begin); - ValueIter value_iter=value_begin; + ValueIter value_iter = value_begin; - detail::linear_regression_compute_fit_from_S(*value_iter, *(value_iter+1), - *(value_iter+2),*(value_iter+3), - *(value_iter+4),*(value_iter+5), - S, Sx, Sy, Syy, Stt, Sty, - data_end - data_begin, - use_estimated_variance); - *(value_iter+6)= *(value_iter)*Sx/Sy; + detail::linear_regression_compute_fit_from_S(*value_iter, *(value_iter + 1), *(value_iter + 2), *(value_iter + 3), + *(value_iter + 4), *(value_iter + 5), S, Sx, Sy, Syy, Stt, Sty, + data_end - data_begin, use_estimated_variance); + *(value_iter + 6) = *(value_iter)*Sx / Sy; } END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListEventCylindricalScannerWithDiscreteDetectors.h b/src/include/stir/listmode/CListEventCylindricalScannerWithDiscreteDetectors.h index 771b5e6b4c..326d44c30d 100644 --- a/src/include/stir/listmode/CListEventCylindricalScannerWithDiscreteDetectors.h +++ b/src/include/stir/listmode/CListEventCylindricalScannerWithDiscreteDetectors.h @@ -4,9 +4,9 @@ \file \ingroup listmode \brief Declarations of class stir::CListEventCylindricalScannerWithDiscreteDetectors - + \author Kris Thielemans - + */ /* Copyright (C) 2003- 2011, Hammersmith Imanet Ltd @@ -40,16 +40,13 @@ START_NAMESPACE_STIR in some way. This class provides access mechanisms to those detection positions, and also provides more efficient implementations of some virtual members of CListEvent. */ -class CListEventCylindricalScannerWithDiscreteDetectors : public CListEvent -{ +class CListEventCylindricalScannerWithDiscreteDetectors : public CListEvent { public: - inline explicit - CListEventCylindricalScannerWithDiscreteDetectors(const shared_ptr& scanner_sptr); + inline explicit CListEventCylindricalScannerWithDiscreteDetectors(const shared_ptr& proj_data_info); - const Scanner * get_scanner_ptr() const - { return this->scanner_sptr.get(); } + const Scanner* get_scanner_ptr() const { return this->uncompressed_proj_data_info_sptr->get_scanner_ptr(); } - //! This routine returns the corresponding detector pair + //! This routine returns the corresponding detector pair virtual void get_detection_position(DetectionPositionPair<>&) const = 0; //! This routine sets in a coincidence event from detector "indices" @@ -65,7 +62,7 @@ class CListEventCylindricalScannerWithDiscreteDetectors : public CListEvent /*! Overrides the default implementation to use get_detection_position() which should be faster. - \warning This implementation is only valid for \c proj_data_info of + \warning This implementation is only valid for \c proj_data_info of type ProjDataInfoCylindricalNoArcCorr. However, because of efficiency reasons this is only checked in debug mode (NDEBUG not defined). */ @@ -78,18 +75,14 @@ class CListEventCylindricalScannerWithDiscreteDetectors : public CListEvent */ inline virtual bool is_valid_template(const ProjDataInfo&) const; - protected: - shared_ptr - get_uncompressed_proj_data_info_sptr() const - { - return uncompressed_proj_data_info_sptr; - } +protected: + shared_ptr get_uncompressed_proj_data_info_sptr() const { + return uncompressed_proj_data_info_sptr; + } - shared_ptr scanner_sptr; - private: - shared_ptr - uncompressed_proj_data_info_sptr; + // shared_ptr scanner_sptr; + shared_ptr uncompressed_proj_data_info_sptr; }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListEventCylindricalScannerWithDiscreteDetectors.inl b/src/include/stir/listmode/CListEventCylindricalScannerWithDiscreteDetectors.inl index 97bd44df29..4034552d2a 100644 --- a/src/include/stir/listmode/CListEventCylindricalScannerWithDiscreteDetectors.inl +++ b/src/include/stir/listmode/CListEventCylindricalScannerWithDiscreteDetectors.inl @@ -4,9 +4,9 @@ \file \ingroup listmode \brief Implementations of class stir::CListEventCylindricalScannerWithDiscreteDetectors - + \author Kris Thielemans - + */ /* Copyright (C) 2003- 2011, Hammersmith Imanet Ltd @@ -29,24 +29,17 @@ START_NAMESPACE_STIR -CListEventCylindricalScannerWithDiscreteDetectors:: -CListEventCylindricalScannerWithDiscreteDetectors(const shared_ptr& scanner_sptr) - : scanner_sptr(scanner_sptr) -{ - this->uncompressed_proj_data_info_sptr.reset - (dynamic_cast - ( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - 1, scanner_sptr->get_num_rings()-1, - scanner_sptr->get_num_detectors_per_ring()/2, - scanner_sptr->get_default_num_arccorrected_bins(), - false))); +CListEventCylindricalScannerWithDiscreteDetectors::CListEventCylindricalScannerWithDiscreteDetectors( + const shared_ptr& proj_data_info_sptr) { + this->uncompressed_proj_data_info_sptr = + std::dynamic_pointer_cast(proj_data_info_sptr->create_shared_clone()); + + if (is_null_ptr(this->uncompressed_proj_data_info_sptr)) + error("CListEventCylindricalScannerWithDiscreteDetectors takes only ProjDataInfoCylindricalNoArcCorr. Abord."); } LORAs2Points -CListEventCylindricalScannerWithDiscreteDetectors:: -get_LOR() const -{ +CListEventCylindricalScannerWithDiscreteDetectors::get_LOR() const { LORAs2Points lor; // provide somewhat shorter names for the 2 coordinates CartesianCoordinate3D& coord_1 = lor.p1(); @@ -54,47 +47,41 @@ get_LOR() const DetectionPositionPair<> det_pos; this->get_detection_position(det_pos); - assert(det_pos.pos1().radial_coord()==0); - assert(det_pos.pos2().radial_coord()==0); - + assert(det_pos.pos1().radial_coord() == 0); + assert(det_pos.pos2().radial_coord() == 0); + // TODO we're using an obsolete function here which uses a different coordinate system - this->get_uncompressed_proj_data_info_sptr()-> - find_cartesian_coordinates_given_scanner_coordinates(coord_1, coord_2, - det_pos.pos1().axial_coord(), - det_pos.pos2().axial_coord(), - det_pos.pos1().tangential_coord(), - det_pos.pos2().tangential_coord()); + this->get_uncompressed_proj_data_info_sptr()->find_cartesian_coordinates_given_scanner_coordinates( + coord_1, coord_2, det_pos.pos1().axial_coord(), det_pos.pos2().axial_coord(), det_pos.pos1().tangential_coord(), + det_pos.pos2().tangential_coord()); // find shift in z - const float shift = this->scanner_sptr->get_ring_spacing()* - (this->scanner_sptr->get_num_rings()-1)/2.F; + const float shift = this->get_uncompressed_proj_data_info_sptr()->get_ring_spacing() * + (this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings() - 1) / 2.F; coord_1.z() -= shift; coord_2.z() -= shift; - + return lor; } -void -CListEventCylindricalScannerWithDiscreteDetectors:: -get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const -{ +void +CListEventCylindricalScannerWithDiscreteDetectors::get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const { assert(dynamic_cast(&proj_data_info) != 0); DetectionPositionPair<> det_pos; this->get_detection_position(det_pos); - if (static_cast(proj_data_info). - get_bin_for_det_pos_pair(bin, det_pos) == Succeeded::no) + if (static_cast(proj_data_info).get_bin_for_det_pos_pair(bin, det_pos) == + Succeeded::no) bin.set_bin_value(0); - else + else { bin.set_bin_value(1); + } } bool -CListEventCylindricalScannerWithDiscreteDetectors:: -is_valid_template(const ProjDataInfo& proj_data_info) const -{ - if (dynamic_cast(&proj_data_info)!= 0) - return true; +CListEventCylindricalScannerWithDiscreteDetectors::is_valid_template(const ProjDataInfo& proj_data_info) const { + if (dynamic_cast(&proj_data_info) != 0) + return true; - return false; + return false; } END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.h b/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.h index a0827e7c4e..2ab80ad6e1 100644 --- a/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.h +++ b/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.h @@ -20,9 +20,9 @@ \file \ingroup listmode \brief Definition of class stir::CListEventCylindricalScannerWithViewTangRingRingEncoding - + \author Kris Thielemans - + */ #ifndef __stir_listmode_CListEventCylindricalScannerWithViewTangRingRingEncoding_H__ @@ -33,15 +33,14 @@ START_NAMESPACE_STIR - //! Helper class for listmode events when using 2d sinograms and ring-pairs is most efficient /*! \ingroup listmode - This class simplifies coding of a CListEventCylindricalScannerWithDiscreteDetectors - class in case the coordinates are stored in the raw data as + This class simplifies coding of a CListEventCylindricalScannerWithDiscreteDetectors + class in case the coordinates are stored in the raw data as \c view_num, \c tangential_pos_num, \c ring_a and \c ring_b. - The default implementations for get_detection_position() etc are somewhat inefficient in such + The default implementations for get_detection_position() etc are somewhat inefficient in such case. This helper class provides faster implementations. For example usage, see ecat::ecat7::CListEventECAT966, but it's intended to be used as follows @@ -58,33 +57,28 @@ START_NAMESPACE_STIR class someType { void get_sinogram_and_ring_coordinates(int& view, int& tangential_pos_num, unsigned int& ring_a, unsigned int& ring_b) const; - + void set_sinogram_and_ring_coordinates( - const int view_num, const int tangential_pos_num, - const int ring_a, const int ring_b); + const int view_num, const int tangential_pos_num, + const int ring_a, const int ring_b); // etc }; \endcode */ template -class CListEventCylindricalScannerWithViewTangRingRingEncoding : -public CListEventCylindricalScannerWithDiscreteDetectors -{ - public: - CListEventCylindricalScannerWithViewTangRingRingEncoding(const shared_ptr& scanner_sptr) : - CListEventCylindricalScannerWithDiscreteDetectors(scanner_sptr) - {} - - //! This routine returns the corresponding detector pair +class CListEventCylindricalScannerWithViewTangRingRingEncoding : public CListEventCylindricalScannerWithDiscreteDetectors { +public: + CListEventCylindricalScannerWithViewTangRingRingEncoding(const shared_ptr& proj_data_info) + : CListEventCylindricalScannerWithDiscreteDetectors(proj_data_info) {} + + //! This routine returns the corresponding detector pair inline void get_detection_position(DetectionPositionPair<>&) const; -/*! This routine constructs a (prompt) coincidence event */ + /*! This routine constructs a (prompt) coincidence event */ inline void set_detection_position(const DetectionPositionPair<>&); //! warning only ProjDataInfoCylindricalNoArcCorr - inline virtual - void - get_bin(Bin&, const ProjDataInfo&) const; + inline virtual void get_bin(Bin&, const ProjDataInfo&) const; //! This method checks if the template is valid for LmToProjData /*! Used before the actual processing of the data (see issue #61), before calling get_bin() @@ -94,7 +88,6 @@ public CListEventCylindricalScannerWithDiscreteDetectors inline virtual bool is_valid_template(const ProjDataInfo&) const; inline void get_uncompressed_bin(Bin& bin) const; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.inl b/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.inl index 15b5fdf2b2..5770edf494 100644 --- a/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.inl +++ b/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.inl @@ -20,120 +20,96 @@ \file \ingroup listmode \brief Implementation for stir::CListEventCylindricalScannerWithViewTangRingRingEncoding - + \author Kris Thielemans - + */ START_NAMESPACE_STIR template -void -CListEventCylindricalScannerWithViewTangRingRingEncoding:: -get_detection_position(DetectionPositionPair<>& det_pos) const -{ - det_pos.pos1().radial_coord()=0; - det_pos.pos2().radial_coord()=0; +void +CListEventCylindricalScannerWithViewTangRingRingEncoding::get_detection_position( + DetectionPositionPair<>& det_pos) const { + det_pos.pos1().radial_coord() = 0; + det_pos.pos2().radial_coord() = 0; int tangential_pos_num; int view_num; - static_cast(this)-> - get_data().get_sinogram_and_ring_coordinates(view_num, tangential_pos_num, - det_pos.pos1().axial_coord(), - det_pos.pos2().axial_coord()); + static_cast(this)->get_data().get_sinogram_and_ring_coordinates( + view_num, tangential_pos_num, det_pos.pos1().axial_coord(), det_pos.pos2().axial_coord()); int det_num_1, det_num_2; - this->get_uncompressed_proj_data_info_sptr()-> - get_det_num_pair_for_view_tangential_pos_num(det_num_1, det_num_2, - view_num, tangential_pos_num); + this->get_uncompressed_proj_data_info_sptr()->get_det_num_pair_for_view_tangential_pos_num(det_num_1, det_num_2, view_num, + tangential_pos_num); det_pos.pos1().tangential_coord() = det_num_1; det_pos.pos2().tangential_coord() = det_num_2; + det_pos.timing_pos() = this->get_uncompressed_proj_data_info_sptr()->get_tof_bin(delta_time); } template -void -CListEventCylindricalScannerWithViewTangRingRingEncoding:: -set_detection_position(const DetectionPositionPair<>& det_pos) -{ +void +CListEventCylindricalScannerWithViewTangRingRingEncoding::set_detection_position( + const DetectionPositionPair<>& det_pos) { int tangential_pos_num; int view_num; - const bool swap_rings = - this-> - get_uncompressed_proj_data_info_sptr()-> - get_view_tangential_pos_num_for_det_num_pair(view_num, tangential_pos_num, - det_pos.pos1().tangential_coord(), - det_pos.pos2().tangential_coord()); - - if (swap_rings) - { - static_cast(this)->get_data(). - set_sinogram_and_ring_coordinates(view_num, tangential_pos_num, - det_pos.pos1().axial_coord(), - det_pos.pos2().axial_coord()); - } - else - { - static_cast(this)->get_data(). - set_sinogram_and_ring_coordinates(view_num, tangential_pos_num, - det_pos.pos2().axial_coord(), - det_pos.pos1().axial_coord()); + const bool swap_rings = this->get_uncompressed_proj_data_info_sptr()->get_view_tangential_pos_num_for_det_num_pair( + view_num, tangential_pos_num, det_pos.pos1().tangential_coord(), det_pos.pos2().tangential_coord()); + + if (swap_rings) { + static_cast(this)->get_data().set_sinogram_and_ring_coordinates( + view_num, tangential_pos_num, det_pos.pos1().axial_coord(), det_pos.pos2().axial_coord()); + } else { + static_cast(this)->get_data().set_sinogram_and_ring_coordinates( + view_num, tangential_pos_num, det_pos.pos2().axial_coord(), det_pos.pos1().axial_coord()); } } static void -sinogram_coordinates_to_bin(Bin& bin, const int view_num, const int tang_pos_num, - const int ring_a, const int ring_b, - const ProjDataInfoCylindrical& proj_data_info) -{ +sinogram_coordinates_to_bin(Bin& bin, const int view_num, const int tang_pos_num, const int ring_a, const int ring_b, + const ProjDataInfoCylindrical& proj_data_info) { if (proj_data_info.get_segment_axial_pos_num_for_ring_pair(bin.segment_num(), bin.axial_pos_num(), ring_a, ring_b) == - Succeeded::no) - { - bin.set_bin_value(-1); - return; - } + Succeeded::no) { + bin.set_bin_value(-1); + return; + } bin.set_bin_value(1); - bin.view_num() = view_num / proj_data_info.get_view_mashing_factor(); + bin.view_num() = view_num / proj_data_info.get_view_mashing_factor(); bin.tangential_pos_num() = tang_pos_num; } template -void -CListEventCylindricalScannerWithViewTangRingRingEncoding:: -get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const -{ - assert (dynamic_cast(&proj_data_info)!=0); +void +CListEventCylindricalScannerWithViewTangRingRingEncoding::get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const { + assert(dynamic_cast(&proj_data_info) != 0); int tangential_pos_num; int view_num; unsigned int ring_a; unsigned int ring_b; - static_cast(this)->get_data(). - get_sinogram_and_ring_coordinates(view_num, tangential_pos_num, ring_a, ring_b); - sinogram_coordinates_to_bin(bin, view_num, tangential_pos_num, ring_a, ring_b, - static_cast(proj_data_info)); + static_cast(this)->get_data().get_sinogram_and_ring_coordinates(view_num, tangential_pos_num, ring_a, ring_b); + sinogram_coordinates_to_bin(bin, view_num, tangential_pos_num, ring_a, ring_b, + static_cast(proj_data_info)); + if (proj_data_info.get_num_tof_poss() > 1) + bin.timing_pos_num() = proj_data_info.get_tof_bin(delta_time); } template bool -CListEventCylindricalScannerWithViewTangRingRingEncoding:: -is_valid_template(const ProjDataInfo& proj_data_info) const -{ - if (dynamic_cast(&proj_data_info)!= 0) - return true; +CListEventCylindricalScannerWithViewTangRingRingEncoding::is_valid_template(const ProjDataInfo& proj_data_info) const { + if (dynamic_cast(&proj_data_info) != 0) + return true; - return false; + return false; } template -void -CListEventCylindricalScannerWithViewTangRingRingEncoding:: -get_uncompressed_bin(Bin& bin) const -{ +void +CListEventCylindricalScannerWithViewTangRingRingEncoding::get_uncompressed_bin(Bin& bin) const { unsigned int ring_a; unsigned int ring_b; this->get_sinogram_and_ring_coordinates(bin.view_num(), bin.tangential_pos_num(), ring_a, ring_b); - this->get_uncompressed_proj_data_info_sptr()-> - get_segment_axial_pos_num_for_ring_pair(bin.segment_num(), bin.axial_pos_num(), - ring_a, ring_b); -} - + this->get_uncompressed_proj_data_info_sptr()->get_segment_axial_pos_num_for_ring_pair(bin.segment_num(), bin.axial_pos_num(), + ring_a, ring_b); +} + END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListModeData.h b/src/include/stir/listmode/CListModeData.h index 903cdb27fd..25321d5b86 100644 --- a/src/include/stir/listmode/CListModeData.h +++ b/src/include/stir/listmode/CListModeData.h @@ -20,7 +20,7 @@ \file \ingroup listmode \brief Declaration of class stir::CListModeData - + \author Daniel Deidda \author Kris Thielemans */ @@ -36,8 +36,10 @@ #include "stir/listmode/ListModeData.h" #include "stir/listmode/CListRecord.h" -# ifdef BOOST_NO_STDC_NAMESPACE -namespace std { using ::time_t; } +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::time_t; +} #endif START_NAMESPACE_STIR @@ -55,36 +57,32 @@ class ExamInfo; Potentially, we make classes ListModeData etc which would work for SPECT (and other count-based modalities?). Alternatively, SPECT can be handled by calling all single photon events 'prompts'. - + \par Notes for developers */ -class CListModeData : public ListModeData -{ +class CListModeData : public ListModeData { public: //! Get a pointer to an empty record /*! This is mainly/only useful to get a record of the correct type, that can then be passed to get_next_record(). */ - virtual - shared_ptr get_empty_record_sptr() const = 0; + virtual shared_ptr get_empty_record_sptr() const = 0; //! Gets the next record in the listmode sequence - virtual - Succeeded get_next_record(CListRecord& event) const = 0; + virtual Succeeded get_next_record(CListRecord& event) const = 0; //! Return if the file stores delayed events as well (as opposed to prompts) virtual bool has_delayeds() const = 0; protected: - virtual shared_ptr get_empty_record_helper_sptr() const - { - shared_ptr sptr(this->get_empty_record_sptr()); - shared_ptr sptr1(static_pointer_cast(sptr)); - return sptr1;} - - virtual Succeeded get_next(ListRecord& event) const - {return this->get_next_record((CListRecord&)(event));} + virtual shared_ptr get_empty_record_helper_sptr() const { + shared_ptr sptr(this->get_empty_record_sptr()); + shared_ptr sptr1(static_pointer_cast(sptr)); + return sptr1; + } + + virtual Succeeded get_next(ListRecord& event) const { return this->get_next_record((CListRecord&)(event)); } }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListModeDataECAT.h b/src/include/stir/listmode/CListModeDataECAT.h index a1bd4953b9..e88254d74f 100644 --- a/src/include/stir/listmode/CListModeDataECAT.h +++ b/src/include/stir/listmode/CListModeDataECAT.h @@ -19,7 +19,7 @@ \file \ingroup listmode \brief Declaration of class stir::CListModeDataECAT - + \author Kris Thielemans */ @@ -29,9 +29,9 @@ #include "stir/listmode/CListModeData.h" #include "stir/IO/InputStreamWithRecords.h" #ifdef HAVE_LLN_MATRIX -#include "stir/IO/stir_ecat7.h" +# include "stir/IO/stir_ecat7.h" #else -#include "stir/IO/stir_ecat_common.h" // for namespace macros +# include "stir/IO/stir_ecat_common.h" // for namespace macros #endif #include #include @@ -45,7 +45,7 @@ START_NAMESPACE_ECAT7 This file format is currently used by the HR+ and HR++. It stores the coincidence data in multiple .lm files, with a maximum filesize of about 2 GB (to avoid problems with OS limits on filesize). - In addition, there is a .sgl file with the singles rate per 'bucket'-per-ring + In addition, there is a .sgl file with the singles rate per 'bucket'-per-ring (roughly every 2 seconds). The .sgl also contains a 'main_header' with some scanner and patient info. @@ -53,52 +53,47 @@ START_NAMESPACE_ECAT7 vector<>::size_type == SavedPosition */ template -class CListModeDataECAT : public CListModeData -{ +class CListModeDataECAT : public CListModeData { public: //! Constructor taking a prefix for the filename /*! If the listmode files are called something_1.lm, something_2.lm etc. - Then this constructor should be called with the argument "something" + Then this constructor should be called with the argument "something" \todo Maybe allow for passing e.g. something_2.lm in case the first lm file is missing. */ CListModeDataECAT(const std::string& listmode_filename_prefix); - virtual std::string - get_name() const; + virtual std::string get_name() const; - virtual - shared_ptr get_empty_record_sptr() const; + virtual shared_ptr get_empty_record_sptr() const; - virtual - Succeeded get_next_record(CListRecord& record) const; + virtual Succeeded get_next_record(CListRecord& record) const; - virtual - Succeeded reset(); + virtual Succeeded reset(); - virtual - SavedPosition save_get_position(); + virtual SavedPosition save_get_position(); - virtual - Succeeded set_get_position(const SavedPosition&); + virtual Succeeded set_get_position(const SavedPosition&); //! returns \c true, as ECAT listmode data stores delayed events (and prompts) /*! \todo this might depend on the acquisition parameters */ virtual bool has_delayeds() const { return true; } + virtual shared_ptr get_proj_data_info_sptr() const; + private: std::string listmode_filename_prefix; mutable unsigned int current_lm_file; - mutable shared_ptr > current_lm_data_ptr; + mutable shared_ptr> current_lm_data_ptr; //! a vector that stores the saved_get_positions for ever .lm file - mutable std::vector > saved_get_positions_for_each_lm_data; + mutable std::vector> saved_get_positions_for_each_lm_data; typedef std::pair GetPosition; - std::vector saved_get_positions; + std::vector saved_get_positions; // const as it modifies only mutable elements // It has to be const as e.g. get_next_record calls it - Succeeded open_lm_file(unsigned int) const; - //shared_ptr scanner_sptr; + Succeeded open_lm_file(unsigned int) const; + // shared_ptr scanner_sptr; }; END_NAMESPACE_ECAT7 diff --git a/src/include/stir/listmode/CListModeDataECAT8_32bit.h b/src/include/stir/listmode/CListModeDataECAT8_32bit.h index 97fc66ee7d..ca85151d5e 100644 --- a/src/include/stir/listmode/CListModeDataECAT8_32bit.h +++ b/src/include/stir/listmode/CListModeDataECAT8_32bit.h @@ -18,7 +18,7 @@ \file \ingroup listmode \brief Declaration of class stir::ecat::CListModeDataECAT8_32bit - + \author Kris Thielemans */ @@ -38,7 +38,7 @@ namespace ecat { //! A class that reads the listmode data for Siemens scanners /*! \ingroup listmode - This file format is currently used by the Siemens Biograph PET/CT and mMR scanners. + This file format is currently used by the Siemens Biograph PET/CT and mMR scanners. There's an Interfile-like header and a binary file with the actual list mode data. The name of the binary file is given by the value of the "name of data file" keyword in the header. @@ -46,29 +46,22 @@ namespace ecat { Currently, the class only supports the 32bit version of the list mode format, see http://usa.healthcare.siemens.com/siemens_hwem-hwem_ssxa_websites-context-root/wcm/idc/groups/public/@us/@imaging/@molecular/documents/download/mdax/mjky/~edisp/petlink_guideline_j1-00672485.pdf */ -class CListModeDataECAT8_32bit : public CListModeData -{ +class CListModeDataECAT8_32bit : public CListModeData { public: //! Construct fron the filename of the Interfile header CListModeDataECAT8_32bit(const std::string& listmode_filename_prefix); - virtual std::string - get_name() const; + virtual std::string get_name() const; - virtual - shared_ptr get_empty_record_sptr() const; + virtual shared_ptr get_empty_record_sptr() const; - virtual - Succeeded get_next_record(CListRecord& record) const; + virtual Succeeded get_next_record(CListRecord& record) const; - virtual - Succeeded reset(); + virtual Succeeded reset(); - virtual - SavedPosition save_get_position(); + virtual SavedPosition save_get_position(); - virtual - Succeeded set_get_position(const SavedPosition&); + virtual Succeeded set_get_position(const SavedPosition&); //! returns \c true, as ECAT listmode data stores delayed events (and prompts) /*! \todo this might depend on the acquisition parameters */ @@ -77,15 +70,13 @@ class CListModeDataECAT8_32bit : public CListModeData private: typedef CListRecordECAT8_32bit CListRecordT; std::string listmode_filename; - shared_ptr > current_lm_data_ptr; + shared_ptr> current_lm_data_ptr; InterfileListmodeHeaderSiemens interfile_parser; // std::vector segment_table; Succeeded open_lm_file(); - - }; } // namespace ecat diff --git a/src/include/stir/listmode/CListModeDataGEHDF5.h b/src/include/stir/listmode/CListModeDataGEHDF5.h index 3275128ae0..d3e879987a 100644 --- a/src/include/stir/listmode/CListModeDataGEHDF5.h +++ b/src/include/stir/listmode/CListModeDataGEHDF5.h @@ -7,7 +7,7 @@ \ingroup listmode \ingroup GE \brief Declaration of class stir::GE::RDF_HDF5::CListModeDataGEHDF5 - + \author Kris Thielemans \author Ottavia Bertolli \author Palak Wadhwa @@ -24,7 +24,6 @@ #include #include - START_NAMESPACE_STIR namespace GE { namespace RDF_HDF5 { @@ -35,52 +34,44 @@ namespace RDF_HDF5 { This file format is used by GE Signa PET/MR and can be used by GE PET/CT scanners (D690 up to DMI) depending on software version. */ -class CListModeDataGEHDF5 : public CListModeData -{ +class CListModeDataGEHDF5 : public CListModeData { public: //! Constructor taking a filename CListModeDataGEHDF5(const std::string& listmode_filename); - virtual std::string - get_name() const; + virtual std::string get_name() const; - virtual - std::time_t get_scan_start_time_in_secs_since_1970() const; + virtual std::time_t get_scan_start_time_in_secs_since_1970() const; - virtual - shared_ptr get_empty_record_sptr() const; + virtual shared_ptr get_empty_record_sptr() const; - virtual - Succeeded get_next_record(CListRecord& record) const; + virtual Succeeded get_next_record(CListRecord& record) const; - virtual - Succeeded reset(); + virtual Succeeded reset(); - virtual - SavedPosition save_get_position(); + virtual SavedPosition save_get_position(); - virtual - Succeeded set_get_position(const SavedPosition&); + virtual Succeeded set_get_position(const SavedPosition&); //! returns \c false, as GEHDF5 listmode data does not store delayed events (and prompts) /*! \todo this depends on the acquisition parameters */ virtual bool has_delayeds() const { return false; } private: - -// shared_ptr input_sptr; + // shared_ptr input_sptr; typedef CListRecordGEHDF5 CListRecordT; std::string listmode_filename; - shared_ptr > current_lm_data_ptr; + shared_ptr proj_data_info_sptr; + shared_ptr> current_lm_data_ptr; unsigned long first_time_stamp; unsigned long lm_duration_in_millisecs; - - Succeeded open_lm_file(); + + Succeeded open_lm_file(); }; -} // namespace -} +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR #endif diff --git a/src/include/stir/listmode/CListModeDataROOT.h b/src/include/stir/listmode/CListModeDataROOT.h index e8298e077e..56056acc6b 100644 --- a/src/include/stir/listmode/CListModeDataROOT.h +++ b/src/include/stir/listmode/CListModeDataROOT.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2015, 2016 University of Leeds Copyright (C) 2016, 2017 UCL + Copyright (C) 2016, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -45,7 +46,7 @@ START_NAMESPACE_STIR We tend to name this header something.hroot but this is not mandatory. \warning There is currently no check if the scanner information is correct. This - is dangerous for the geometry, but can also lead to crashes if the actual number of + is dangerous for the geometry, but can also lead to crashes if the actual number of blocks/crystals etc is larger than what is specified in the scanner info. We currently support only ROOT output using the 'Cylindrical PET' and 'ECAT' systems @@ -68,7 +69,7 @@ START_NAMESPACE_STIR \par Example headers If the scanner is known to stir::Scanner, you can use this \verbatim -ROOT header := +ROOT header := Originating system := Siemens mMR ; specify GATE output format (could be GATE_ECAT_PET as well) @@ -80,11 +81,11 @@ GATE_Cylindrical_PET Parameters := ; See elsewhere for other parameters End GATE_Cylindrical_PET Parameters := -end ROOT header := +end ROOT header := \endverbatim - Below is an example using a user-defined scanner. + Below is an example using a user-defined scanner. \verbatim -ROOT header := +ROOT header := Originating system := User_defined_scanner Number of rings := 4 Number of detectors per ring := 504 @@ -107,87 +108,88 @@ GATE_Cylindrical_PET Parameters := ; See elsewhere for other parameters End GATE_Cylindrical_PET Parameters := -end ROOT header := +end ROOT header := \endverbatim */ -class CListModeDataROOT : public CListModeData -{ +class CListModeDataROOT : public CListModeData { public: - //! construct from the filename of the Interfile header - CListModeDataROOT(const std::string& hroot_filename_prefix); + //! construct from the filename of the Interfile header + CListModeDataROOT(const std::string& hroot_filename_prefix); - //! returns the header filename - virtual std::string - get_name() const; - //! Set private members default values; - void set_defaults(); + //! returns the header filename + virtual std::string get_name() const; + //! Set private members default values; + void set_defaults(); - virtual - shared_ptr get_empty_record_sptr() const; + virtual shared_ptr get_empty_record_sptr() const; - virtual - Succeeded get_next_record(CListRecord& record) const; + virtual Succeeded get_next_record(CListRecord& record) const; - virtual - Succeeded reset(); + virtual Succeeded reset(); - virtual - SavedPosition save_get_position(); + virtual SavedPosition save_get_position(); - virtual - Succeeded set_get_position(const SavedPosition&); + virtual Succeeded set_get_position(const SavedPosition&); - virtual - bool has_delayeds() const { return true; } + virtual bool has_delayeds() const { return true; } - virtual inline - unsigned long int - get_total_number_of_events() const ; + virtual inline unsigned long int get_total_number_of_events() const; private: - //! Check if the hroot contains a full scanner description - Succeeded check_scanner_definition(std::string& ret); - //! Check if the scanner_sptr matches the geometry in root_file_sptr - Succeeded check_scanner_match_geometry(std::string& ret, const shared_ptr& scanner_sptr); - - //! The header file - std::string hroot_filename; - - //! Pointer to the listmode data - shared_ptr root_file_sptr; - -//! \name Variables that can be set in the hroot file to define a scanner's geometry. -//! They are compared to the Scanner (if set) and the InputStreamFromROOTFile -//! geometry, as given by the repeaters. Can be used to check for inconsistencies. -//@{ - //! The name of the originating scanner - std::string originating_system; - //! Number of rings, set in the hroot file (optional) - int num_rings; - //! Number of detectors per ring, set in the hroot file (optional) - int num_detectors_per_ring; - //! Number of non arc corrected bins, set in the hroot file (optional) - int max_num_non_arccorrected_bins; - //! Default number of arc corrected bins, set in the hroot file (optional) - int default_num_arccorrected_bins; - //! Angle in degrees corresponding to view offset (optional) - float view_offset; - //! Inner ring diameter, set in the hroot file (optional) - float inner_ring_diameter; - //! Average depth of interaction, set in the hroot file (optional) - float average_depth_of_interaction; - //! Ring spacing, set in the hroot file (optional) - float ring_spacing; - //! Bin size, set in the hroot file (optional) - float bin_size; -//@} - - KeyParser parser; - - Succeeded open_lm_file(); + //! Check if the hroot contains a full scanner description + Succeeded check_scanner_definition(std::string& ret); + //! Check if the scanner_sptr matches the geometry in root_file_sptr + Succeeded check_scanner_match_geometry(std::string& ret, const shared_ptr& scanner_sptr); + + //! The header file + std::string hroot_filename; + + //! Pointer to the listmode data + shared_ptr root_file_sptr; + + //! \name Variables that can be set in the hroot file to define a scanner's geometry. + //! They are compared to the Scanner (if set) and the InputStreamFromROOTFile + //! geometry, as given by the repeaters. Can be used to check for inconsistencies. + //@{ + //! The name of the originating scanner + std::string originating_system; + //! Number of rings, set in the hroot file (optional) + int num_rings; + //! Number of detectors per ring, set in the hroot file (optional) + int num_detectors_per_ring; + //! Number of non arc corrected bins, set in the hroot file (optional) + int max_num_non_arccorrected_bins; + //! Default number of arc corrected bins, set in the hroot file (optional) + int default_num_arccorrected_bins; + //! Angle in degrees corresponding to view offset (optional) + float view_offset; + //! Inner ring diameter, set in the hroot file (optional) + float inner_ring_diameter; + //! Average depth of interaction, set in the hroot file (optional) + float average_depth_of_interaction; + //! Ring spacing, set in the hroot file (optional) + float ring_spacing; + //! Bin size, set in the hroot file (optional) + float bin_size; + + int max_num_timing_bins; + + float size_timing_bin; + + float timing_resolution; + + float energy_resolution; + + float reference_energy; + //@} + + int tof_mash_factor; + + KeyParser parser; + + Succeeded open_lm_file(); }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir/listmode/CListModeDataSAFIR.h b/src/include/stir/listmode/CListModeDataSAFIR.h index a7018c0894..56b18a52c9 100644 --- a/src/include/stir/listmode/CListModeDataSAFIR.h +++ b/src/include/stir/listmode/CListModeDataSAFIR.h @@ -2,21 +2,21 @@ Coincidence LM Data Class for SAFIR: Header File Jannis Fischer - - Copyright 2015 ETH Zurich, Institute of Particle Physics - Copyright 2020 Positrigo AG, Zurich - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + Copyright 2015 ETH Zurich, Institute of Particle Physics + Copyright 2020 Positrigo AG, Zurich - http://www.apache.org/licenses/LICENSE-2.0 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ @@ -50,49 +50,50 @@ START_NAMESPACE_STIR /*! - \brief Class for reading SAFIR listmode data with variable geometry + \brief Class for reading SAFIR listmode data with variable geometry \ingroup listmode \par - By providing crystal map and template projection data files, the coordinates are read from files and used defining the LOR coordinates. + By providing crystal map and template projection data files, the coordinates are read from files and used defining the LOR + coordinates. */ -template class CListModeDataSAFIR : public CListModeData -{ +template +class CListModeDataSAFIR : public CListModeData { public: - /*! Constructor - \par - Takes as arguments the filenames of the coicidence listmode file, the crystal map (text) file, and the template projection data file - */ - CListModeDataSAFIR( const std::string& listmode_filename, const std::string& crystal_map_filename, const std::string& template_proj_data_filename, const double lor_randomization_sigma = 0.0); - - virtual std::string get_name() const; - virtual shared_ptr get_empty_record_sptr() const; - virtual Succeeded get_next_record(CListRecord& record_of_general_type) const; - virtual Succeeded reset(); - - /*! - This function should save the position in input file. This is not implemented but disabled. - Returns 0 in the moement. - \todo Maybe provide real implementation? - */ - virtual SavedPosition save_get_position() - { return static_cast(current_lm_data_ptr->save_get_position()); } - virtual Succeeded set_get_position(const SavedPosition& pos) - { return current_lm_data_ptr->set_get_position(pos); } - - /*! - Returns just false in the moment. - \todo Implement this properly to check for delayed events in LM files. - */ - virtual bool has_delayeds() const { return false; } + /*! Constructor + \par + Takes as arguments the filenames of the coicidence listmode file, the crystal map (text) file, and the template projection data + file + */ + CListModeDataSAFIR(const std::string& listmode_filename, const std::string& crystal_map_filename, + const std::string& template_proj_data_filename, const double lor_randomization_sigma = 0.0); + + virtual std::string get_name() const; + virtual shared_ptr get_empty_record_sptr() const; + virtual Succeeded get_next_record(CListRecord& record_of_general_type) const; + virtual Succeeded reset(); + + /*! + This function should save the position in input file. This is not implemented but disabled. + Returns 0 in the moement. + \todo Maybe provide real implementation? + */ + virtual SavedPosition save_get_position() { return static_cast(current_lm_data_ptr->save_get_position()); } + virtual Succeeded set_get_position(const SavedPosition& pos) { return current_lm_data_ptr->set_get_position(pos); } + + /*! + Returns just false in the moment. + \todo Implement this properly to check for delayed events in LM files. + */ + virtual bool has_delayeds() const { return false; } private: - std::string listmode_filename; - mutable shared_ptr > current_lm_data_ptr; - mutable std::vector< unsigned int> saved_get_positions; - Succeeded open_lm_file() const; - shared_ptr map; + std::string listmode_filename; + mutable shared_ptr> current_lm_data_ptr; + mutable std::vector saved_get_positions; + Succeeded open_lm_file() const; + shared_ptr map; }; - + END_NAMESPACE_STIR #endif diff --git a/src/include/stir/listmode/CListRecord.h b/src/include/stir/listmode/CListRecord.h index 6ab64f58f6..aa26c0cf3f 100644 --- a/src/include/stir/listmode/CListRecord.h +++ b/src/include/stir/listmode/CListRecord.h @@ -5,12 +5,16 @@ \ingroup listmode \brief Declarations of classes stir::CListRecord, and stir::CListEvent which are used for list mode data. - + + + \author Nikos Efthimiou \author Daniel Deidda \author Kris Thielemans */ /* + Copyright (C) 2003- 2011, Hammersmith Imanet Ltd + Copyright (C) 2016, University of Hull Copyright (C) 2019, National Physical Laboratory Copyright (C) 2019, University College of London This file is part of STIR. @@ -37,8 +41,10 @@ START_NAMESPACE_STIR class Bin; class ProjDataInfo; class Succeeded; -template class CartesianCoordinate3D; -template class LORAs2Points; +template +class CartesianCoordinate3D; +template +class LORAs2Points; //! Class for storing and using a coincidence event from a list mode file /*! \ingroup listmode @@ -49,27 +55,40 @@ template class LORAs2Points; energy windows and time-of-flight info. Also, get_bin() would need time info or so for rotating scanners. - \see CListModeData for more info on list mode data. + \see CListModeData for more info on list mode data. */ -class CListEvent : public ListEvent -{ +class CListEvent : public ListEvent { public: - //! Changes the event from prompt to delayed or vice versa /*! Default implementation just returns Succeeded::no. */ - virtual - Succeeded - set_prompt(const bool prompt = true); + virtual Succeeded set_prompt(const bool prompt = true); + + //! Returns true is the delta_time has been swapped. + bool get_swapped() const { return swapped; } + + double get_delta_time() const { return delta_time; } + +protected: + //! The detection time difference, between the two photons. + //! This will work for ROOT files, but not so sure about acquired data. + double delta_time; + + //! Indicates if the detectors' order has been swapped. + bool swapped; }; /*-coincidence event*/ -class CListRecord : public ListRecord -{ +class CListRecord : public ListRecord { public: + //! Used in TOF reconstruction to get both the geometric and the timing + //! component of the event + virtual void full_event(Bin&, const ProjDataInfo&) const { + error("CListRecord::full_event() is implemented only for records which " + "hold timing and spatial information."); + } }; -class CListRecordWithGatingInput : public CListRecord -{}; +class CListRecordWithGatingInput : public CListRecord {}; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListRecordECAT8_32bit.h b/src/include/stir/listmode/CListRecordECAT8_32bit.h index 55e17234cd..5311de9217 100644 --- a/src/include/stir/listmode/CListRecordECAT8_32bit.h +++ b/src/include/stir/listmode/CListRecordECAT8_32bit.h @@ -19,7 +19,7 @@ \file \ingroup listmode \brief Classes for listmode events for the ECAT 8 format - + \author Kris Thielemans */ @@ -51,146 +51,128 @@ namespace ecat { In the 32-bit event format, the listmode data just stores on offset into a (3D) sinogram. Its characteristics are given in the Interfile header. */ -class CListEventDataECAT8_32bit -{ - public: - - /* 'random' bit: - 0 if event is Random (it fell in delayed time window) */ +class CListEventDataECAT8_32bit { +public: + /* 'random' bit: + 0 if event is Random (it fell in delayed time window) */ #if STIRIsNativeByteOrderBigEndian - unsigned type : 1; /* 0-coincidence event, 1-time tick */ - unsigned delayed : 1; - unsigned offset : 30; + unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned delayed : 1; + unsigned offset : 30; #else // Do byteswapping first before using this bit field. - unsigned offset : 30; - unsigned delayed : 1; - unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned offset : 30; + unsigned delayed : 1; + unsigned type : 1; /* 0-coincidence event, 1-time tick */ #endif }; /*-coincidence event*/ //! Class for storing and using a coincidence event from a listmode file from Siemens scanners using the ECAT 8_32bit format /*! \todo This implementation only works if the list-mode data is stored without axial compression. - \todo If the target sinogram has the same characteristics as the sinogram encoding used in the list file - (via the offset), the code could be sped-up dramatically by using the information. + \todo If the target sinogram has the same characteristics as the sinogram encoding used in the list file + (via the offset), the code could be sped-up dramatically by using the information. At present, we go a huge round-about (offset->sinogram->detectors->sinogram->offset) */ -class CListEventECAT8_32bit : public CListEventCylindricalScannerWithDiscreteDetectors -{ - private: - public: +class CListEventECAT8_32bit : public CListEventCylindricalScannerWithDiscreteDetectors { +private: +public: typedef CListEventDataECAT8_32bit DataType; DataType get_data() const { return this->data; } - public: +public: CListEventECAT8_32bit(const shared_ptr& proj_data_info_sptr); - //! This routine returns the corresponding detector pair + //! This routine returns the corresponding detector pair virtual void get_detection_position(DetectionPositionPair<>&) const; //! This routine sets in a coincidence event from detector "indices" virtual void set_detection_position(const DetectionPositionPair<>&); - Succeeded init_from_data_ptr(const void * const ptr) - { - const char * const data_ptr = reinterpret_cast(ptr); - std::copy(data_ptr, data_ptr+sizeof(this->raw), reinterpret_cast(&this->raw)); - return Succeeded::yes; - } + Succeeded init_from_data_ptr(const void* const ptr) { + const char* const data_ptr = reinterpret_cast(ptr); + std::copy(data_ptr, data_ptr + sizeof(this->raw), reinterpret_cast(&this->raw)); + return Succeeded::yes; + } inline bool is_prompt() const { return this->data.delayed == 1; } - inline Succeeded set_prompt(const bool prompt = true) - { if (prompt) this->data.delayed=1; else this->data.delayed=0; return Succeeded::yes; } - - private: - BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT8_32bit)==4); - union - { - CListEventDataECAT8_32bit data; - boost::int32_t raw; + inline Succeeded set_prompt(const bool prompt = true) { + if (prompt) + this->data.delayed = 1; + else + this->data.delayed = 0; + return Succeeded::yes; + } + +private: + BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT8_32bit) == 4); + union { + CListEventDataECAT8_32bit data; + boost::int32_t raw; }; std::vector segment_sequence; std::vector sizes; - }; //! A class for decoding a raw events that is neither time or coincidence in a listmode file from the ECAT 8_32bit scanner /*! \ingroup listmode */ -class CListTimeDataECAT8_32bit -{ - public: - +class CListTimeDataECAT8_32bit { +public: #if STIRIsNativeByteOrderBigEndian - unsigned type : 1; /* 0-coincidence event, 1-time tick */ - unsigned deadtimeetc : 2; /* extra bits differentiating between timing or other stuff, zero if timing event */ - unsigned time : 29 ; /* since scan start */ + unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned deadtimeetc : 2; /* extra bits differentiating between timing or other stuff, zero if timing event */ + unsigned time : 29; /* since scan start */ #else // Do byteswapping first before using this bit field. - unsigned time : 29 ; /* since scan start */ - unsigned deadtimeetc : 2; /* extra bits differentiating between timing or other stuff, zero if timing event */ - unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned time : 29; /* since scan start */ + unsigned deadtimeetc : 2; /* extra bits differentiating between timing or other stuff, zero if timing event */ + unsigned type : 1; /* 0-coincidence event, 1-time tick */ #endif }; - -class CListDataAnyECAT8_32bit -{ +class CListDataAnyECAT8_32bit { public: - Succeeded init_from_data_ptr(const void * const ptr) - { - const char * const data_ptr = reinterpret_cast(ptr); - std::copy(data_ptr, data_ptr+sizeof(this->raw), reinterpret_cast(&this->raw)); - return Succeeded::yes; - } - bool is_time() const - { return this->data.type == 1U && this->data.deadtimeetc == 0U; } - bool is_other() const - { return this->data.type == 1U && this->data.deadtimeetc != 0U; } - bool is_event() const - { return this->data.type == 0U; } - - - private: - BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT8_32bit)==4); - union - { - CListTimeDataECAT8_32bit data; - boost::int32_t raw; + Succeeded init_from_data_ptr(const void* const ptr) { + const char* const data_ptr = reinterpret_cast(ptr); + std::copy(data_ptr, data_ptr + sizeof(this->raw), reinterpret_cast(&this->raw)); + return Succeeded::yes; + } + bool is_time() const { return this->data.type == 1U && this->data.deadtimeetc == 0U; } + bool is_other() const { return this->data.type == 1U && this->data.deadtimeetc != 0U; } + bool is_event() const { return this->data.type == 0U; } + +private: + BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT8_32bit) == 4); + union { + CListTimeDataECAT8_32bit data; + boost::int32_t raw; }; }; - //! A class for storing and using a timing 'event' from a listmode file from the ECAT 8_32bit scanner /*! \ingroup listmode */ -class CListTimeECAT8_32bit : public ListTime -{ - public: - Succeeded init_from_data_ptr(const void * const ptr) - { - const char * const data_ptr = reinterpret_cast(ptr); - std::copy(data_ptr, data_ptr+sizeof(this->raw), reinterpret_cast(&this->raw)); - return Succeeded::yes; - } - bool is_time() const - { return this->data.type == 1U && this->data.deadtimeetc == 0U; } - inline unsigned long get_time_in_millisecs() const - { return static_cast(this->data.time); } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) - { - this->data.time = ((1U<<30)-1) & static_cast(time_in_millisecs); +class CListTimeECAT8_32bit : public ListTime { +public: + Succeeded init_from_data_ptr(const void* const ptr) { + const char* const data_ptr = reinterpret_cast(ptr); + std::copy(data_ptr, data_ptr + sizeof(this->raw), reinterpret_cast(&this->raw)); + return Succeeded::yes; + } + bool is_time() const { return this->data.type == 1U && this->data.deadtimeetc == 0U; } + inline unsigned long get_time_in_millisecs() const { return static_cast(this->data.time); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { + this->data.time = ((1U << 30) - 1) & static_cast(time_in_millisecs); // TODO return more useful value return Succeeded::yes; } - private: - BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT8_32bit)==4); - union - { - CListTimeDataECAT8_32bit data; - boost::int32_t raw; +private: + BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT8_32bit) == 4); + union { + CListTimeDataECAT8_32bit data; + boost::int32_t raw; }; }; @@ -203,74 +185,63 @@ class CListTimeECAT8_32bit : public ListTime http://usa.healthcare.siemens.com/siemens_hwem-hwem_ssxa_websites-context-root/wcm/idc/groups/public/@us/@imaging/@molecular/documents/download/mdax/mjky/~edisp/petlink_guideline_j1-00672485.pdf */ - class CListRecordECAT8_32bit : public CListRecord // currently no gating yet +class CListRecordECAT8_32bit : public CListRecord // currently no gating yet { - //public: + // public: - bool is_time() const - { return this->any_data.is_time(); } + bool is_time() const { return this->any_data.is_time(); } /* bool is_gating_input() const { return this->is_time(); } */ - bool is_event() const - { return this->any_data.is_event(); } - virtual CListEventECAT8_32bit& event() - { return this->event_data; } - virtual const CListEventECAT8_32bit& event() const - { return this->event_data; } - virtual CListTimeECAT8_32bit& time() - { return this->time_data; } - virtual const CListTimeECAT8_32bit& time() const - { return this->time_data; } - - bool operator==(const CListRecord& e2) const - { - return dynamic_cast(&e2) != 0 && - raw == dynamic_cast(e2).raw; - } - - public: - CListRecordECAT8_32bit(const shared_ptr& proj_data_info_sptr) : - event_data(proj_data_info_sptr) - {} - - virtual Succeeded init_from_data_ptr(const char * const data_ptr, + bool is_event() const { return this->any_data.is_event(); } + virtual CListEventECAT8_32bit& event() { return this->event_data; } + virtual const CListEventECAT8_32bit& event() const { return this->event_data; } + virtual CListTimeECAT8_32bit& time() { return this->time_data; } + virtual const CListTimeECAT8_32bit& time() const { return this->time_data; } + + bool operator==(const CListRecord& e2) const { + return dynamic_cast(&e2) != 0 && raw == dynamic_cast(e2).raw; + } + +public: + CListRecordECAT8_32bit(const shared_ptr& proj_data_info_sptr) : event_data(proj_data_info_sptr) {} + + virtual Succeeded init_from_data_ptr(const char* const data_ptr, const std::size_t #ifndef NDEBUG - size // only used within assert, so commented-out otherwise to avoid compiler warnings + size // only used within assert, so commented-out otherwise to avoid compiler warnings #endif - , const bool do_byte_swap) - { + , + const bool do_byte_swap) { assert(size >= 4); - std::copy(data_ptr, data_ptr+4, reinterpret_cast(&raw)); + std::copy(data_ptr, data_ptr + 4, reinterpret_cast(&raw)); if (do_byte_swap) ByteOrder::swap_order(raw); this->any_data.init_from_data_ptr(&raw); // should in principle check return value, but it's always Succeeded::yes anyway if (this->any_data.is_time()) return this->time_data.init_from_data_ptr(&raw); - else if (this->any_data.is_event()) + else if (this->any_data.is_event()) return this->event_data.init_from_data_ptr(&raw); else return Succeeded::yes; } - virtual std::size_t size_of_record_at_ptr(const char * const /*data_ptr*/, const std::size_t /*size*/, - const bool /*do_byte_swap*/) const - { return 4; } - - private: - CListEventECAT8_32bit event_data; - CListTimeECAT8_32bit time_data; - CListDataAnyECAT8_32bit any_data; - boost::int32_t raw; // this raw field isn't strictly necessary, get rid of it? + virtual std::size_t size_of_record_at_ptr(const char* const /*data_ptr*/, const std::size_t /*size*/, + const bool /*do_byte_swap*/) const { + return 4; + } +private: + CListEventECAT8_32bit event_data; + CListTimeECAT8_32bit time_data; + CListDataAnyECAT8_32bit any_data; + boost::int32_t raw; // this raw field isn't strictly necessary, get rid of it? }; } // namespace ecat END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/listmode/CListRecordECAT962.h b/src/include/stir/listmode/CListRecordECAT962.h index c3985caa4b..2235b5c99c 100644 --- a/src/include/stir/listmode/CListRecordECAT962.h +++ b/src/include/stir/listmode/CListRecordECAT962.h @@ -20,9 +20,9 @@ \file \ingroup listmode \brief Classes for listmode events for the ECAT 962 (aka Exact HR+) - + \author Kris Thielemans - + */ #ifndef __stir_listmode_CListRecordECAT962_H__ @@ -46,7 +46,6 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 - //! Class for storing and using a coincidence event from a listmode file /*! \ingroup listmode The private definition is specific to the 962. Public members are generic @@ -62,62 +61,64 @@ START_NAMESPACE_ECAT7 \todo use DetectionPosition etc. */ -class CListEventDataECAT962 -{ - public: +class CListEventDataECAT962 { +public: inline bool is_prompt() const { return random == 0; } - inline Succeeded set_prompt(const bool prompt = true) - { if (prompt) random=0; else random=1; return Succeeded::yes; } + inline Succeeded set_prompt(const bool prompt = true) { + if (prompt) + random = 0; + else + random = 1; + return Succeeded::yes; + } -/*! This routine returns the corresponding tangential_pos_num,view_num,ring_a and ring_b + /*! This routine returns the corresponding tangential_pos_num,view_num,ring_a and ring_b */ void get_sinogram_and_ring_coordinates(int& view, int& tangential_pos_num, unsigned int& ring_a, unsigned int& ring_b) const; - -/*! This routine constructs a coincidence event */ - void set_sinogram_and_ring_coordinates( - const int view_num, const int tangential_pos_num, - const unsigned int ring_a, const unsigned int ring_b); + /*! This routine constructs a coincidence event */ + void set_sinogram_and_ring_coordinates(const int view_num, const int tangential_pos_num, const unsigned int ring_a, + const unsigned int ring_b); - private: - /* ring encoding. use as follows: - This organisation corresponds to physical detector blocks (which - have 8 crystal rings). Names are not very good probably... - */ - /* 'random' bit: - 1 if event is Random (it fell in delayed time window) */ - /* bin field is shifted in a funny way, use the following code to find - bin_number: - if ( bin > NumProjBinsBy2 ) bin -= NumProjBins ; - */ +private: + /* ring encoding. use as follows: + This organisation corresponds to physical detector blocks (which + have 8 crystal rings). Names are not very good probably... + */ + /* 'random' bit: + 1 if event is Random (it fell in delayed time window) */ + /* bin field is shifted in a funny way, use the following code to find + bin_number: + if ( bin > NumProjBinsBy2 ) bin -= NumProjBins ; + */ #if STIRIsNativeByteOrderBigEndian - unsigned type : 1; /* 0-coincidence event, 1-time tick */ - unsigned block_A_ring_bit1 : 1; - unsigned block_B_ring_bit1 : 1; - unsigned block_A_ring_bit0 : 1; - unsigned block_B_ring_bit0 : 1; - unsigned block_B_detector : 3; - unsigned block_A_detector : 3; - unsigned scatter : 1; - unsigned random : 1; - unsigned multiple : 1; - unsigned bin : 9; - unsigned view : 9; + unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned block_A_ring_bit1 : 1; + unsigned block_B_ring_bit1 : 1; + unsigned block_A_ring_bit0 : 1; + unsigned block_B_ring_bit0 : 1; + unsigned block_B_detector : 3; + unsigned block_A_detector : 3; + unsigned scatter : 1; + unsigned random : 1; + unsigned multiple : 1; + unsigned bin : 9; + unsigned view : 9; #else // Do byteswapping first before using this bit field. - unsigned view : 9; - unsigned bin : 9; - unsigned multiple : 1; - unsigned random : 1; - unsigned scatter : 1; - unsigned block_A_detector : 3; - unsigned block_B_detector : 3; - unsigned block_B_ring_bit0 : 1; - unsigned block_A_ring_bit0 : 1; - unsigned block_B_ring_bit1 : 1; - unsigned block_A_ring_bit1 : 1; - unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned view : 9; + unsigned bin : 9; + unsigned multiple : 1; + unsigned random : 1; + unsigned scatter : 1; + unsigned block_A_detector : 3; + unsigned block_B_detector : 3; + unsigned block_B_ring_bit0 : 1; + unsigned block_A_ring_bit0 : 1; + unsigned block_B_ring_bit1 : 1; + unsigned block_A_ring_bit1 : 1; + unsigned type : 1; /* 0-coincidence event, 1-time tick */ #endif }; /*-coincidence event*/ @@ -154,122 +155,104 @@ class CListEventECAT962 : public CListEventCylindricalScannerWithViewTangRingRin //! A class for storing and using a timing 'event' from a listmode file /*! \ingroup listmode */ -class CListTimeDataECAT962 -{ - public: - inline unsigned long get_time_in_millisecs() const - { return static_cast(time); } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) - { - time = ((1U<<28)-1) & static_cast(time_in_millisecs); +class CListTimeDataECAT962 { +public: + inline unsigned long get_time_in_millisecs() const { return static_cast(time); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { + time = ((1U << 28) - 1) & static_cast(time_in_millisecs); // TODO return more useful value return Succeeded::yes; } - inline unsigned int get_gating() const - { return gating; } - inline Succeeded set_gating(unsigned int g) - { gating = g & 0xf; return gating==g ? Succeeded::yes : Succeeded::no;}// TODONK check + inline unsigned int get_gating() const { return gating; } + inline Succeeded set_gating(unsigned int g) { + gating = g & 0xf; + return gating == g ? Succeeded::yes : Succeeded::no; + } // TODONK check private: friend class CListRecordECAT962; // to give access to type field #if STIRIsNativeByteOrderBigEndian - unsigned type : 1; /* 0-coincidence event, 1-time tick */ - unsigned gating : 4; /* some info about the gating signals */ - unsigned time : 27 ; /* since scan start */ + unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned gating : 4; /* some info about the gating signals */ + unsigned time : 27; /* since scan start */ #else // Do byteswapping first before using this bit field. - unsigned time : 27 ; /* since scan start */ - unsigned gating : 4; /* some info about the gating signals */ - unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned time : 27; /* since scan start */ + unsigned gating : 4; /* some info about the gating signals */ + unsigned type : 1; /* 0-coincidence event, 1-time tick */ #endif }; //! A class for a general element of a listmode file /*! \ingroup listmode For the 962 it's either a coincidence event, or a timing flag.*/ -class CListRecordECAT962 : public CListRecordWithGatingInput, public ListTime, public ListGatingInput, - public CListEventCylindricalScannerWithViewTangRingRingEncoding -{ - public: +class CListRecordECAT962 : public CListRecordWithGatingInput, + public ListTime, + public ListGatingInput, + public CListEventCylindricalScannerWithViewTangRingRingEncoding { +public: typedef CListEventDataECAT962 DataType; DataType get_data() const { return this->event_data; } - public: - CListRecordECAT962() : - CListEventCylindricalScannerWithViewTangRingRingEncoding(shared_ptr(new Scanner(Scanner::E962))) - {} - - bool is_time() const - { return time_data.type == 1U; } - bool is_gating_input() const - { return this->is_time(); } - bool is_event() const - { return time_data.type == 0U; } - virtual CListEvent& event() - { return *this; } - virtual const CListEvent& event() const - { return *this; } - virtual ListTime& time() - { return *this; } - virtual const ListTime& time() const - { return *this; } - virtual ListGatingInput& gating_input() - { return *this; } - virtual const ListGatingInput& gating_input() const - { return *this; } - - bool operator==(const CListRecord& e2) const - { - return dynamic_cast(&e2) != 0 && - raw == static_cast(e2).raw; - } +public: + CListRecordECAT962() + : CListEventCylindricalScannerWithViewTangRingRingEncoding( + shared_ptr(new Scanner(Scanner::E962))) {} + + bool is_time() const { return time_data.type == 1U; } + bool is_gating_input() const { return this->is_time(); } + bool is_event() const { return time_data.type == 0U; } + virtual CListEvent& event() { return *this; } + virtual const CListEvent& event() const { return *this; } + virtual ListTime& time() { return *this; } + virtual const ListTime& time() const { return *this; } + virtual ListGatingInput& gating_input() { return *this; } + virtual const ListGatingInput& gating_input() const { return *this; } + + bool operator==(const CListRecord& e2) const { + return dynamic_cast(&e2) != 0 && raw == static_cast(e2).raw; + } - // time - inline unsigned long get_time_in_millisecs() const - { return time_data.get_time_in_millisecs(); } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) - { return time_data.set_time_in_millisecs(time_in_millisecs); } - inline unsigned int get_gating() const - { return time_data.get_gating(); } - inline Succeeded set_gating(unsigned int g) - { return time_data.set_gating(g); } + // time + inline unsigned long get_time_in_millisecs() const { return time_data.get_time_in_millisecs(); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { + return time_data.set_time_in_millisecs(time_in_millisecs); + } + inline unsigned int get_gating() const { return time_data.get_gating(); } + inline Succeeded set_gating(unsigned int g) { return time_data.set_gating(g); } // event inline bool is_prompt() const { return event_data.is_prompt(); } - inline Succeeded set_prompt(const bool prompt = true) - { return event_data.set_prompt(prompt); } - + inline Succeeded set_prompt(const bool prompt = true) { return event_data.set_prompt(prompt); } - virtual Succeeded init_from_data_ptr(const char * const data_ptr, + virtual Succeeded init_from_data_ptr(const char* const data_ptr, const std::size_t #ifndef NDEBUG - size // only used within assert, so don't define otherwise to avoid compiler warning + size // only used within assert, so don't define otherwise to avoid compiler warning #endif - , const bool do_byte_swap) - { + , + const bool do_byte_swap) { assert(size >= 4); - std::copy(data_ptr, data_ptr+4, reinterpret_cast(&raw));// TODO necessary for operator== + std::copy(data_ptr, data_ptr + 4, reinterpret_cast(&raw)); // TODO necessary for operator== if (do_byte_swap) ByteOrder::swap_order(raw); return Succeeded::yes; } - virtual std::size_t size_of_record_at_ptr(const char * const /*data_ptr*/, const std::size_t /*size*/, - const bool /*do_byte_swap*/) const - { return 4; } + virtual std::size_t size_of_record_at_ptr(const char* const /*data_ptr*/, const std::size_t /*size*/, + const bool /*do_byte_swap*/) const { + return 4; + } private: union { - CListEventDataECAT962 event_data; - CListTimeDataECAT962 time_data; - boost::int32_t raw; + CListEventDataECAT962 event_data; + CListTimeDataECAT962 time_data; + boost::int32_t raw; }; - BOOST_STATIC_ASSERT(sizeof(boost::int32_t)==4); - BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT962)==4); - BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT962)==4); - + BOOST_STATIC_ASSERT(sizeof(boost::int32_t) == 4); + BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT962) == 4); + BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT962) == 4); }; - - END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListRecordECAT966.h b/src/include/stir/listmode/CListRecordECAT966.h index 52078bc713..025792b2c4 100644 --- a/src/include/stir/listmode/CListRecordECAT966.h +++ b/src/include/stir/listmode/CListRecordECAT966.h @@ -20,9 +20,9 @@ \file \ingroup listmode \brief Classes for listmode events for the ECAT 966 (aka Exact 3d) - + \author Kris Thielemans - + */ #ifndef __stir_listmode_CListRecordECAT966_H__ @@ -59,18 +59,14 @@ START_NAMESPACE_ECAT7 512 values, which is fine for the 966 (which needs only 288). */ -class CListEventDataECAT966 -{ - public: - +class CListEventDataECAT966 { +public: /*! This routine returns the corresponding tangential_pos_num,view_num,ring_a and ring_b */ void get_sinogram_and_ring_coordinates(int& view, int& tangential_pos_num, unsigned int& ring_a, unsigned int& ring_b) const; - + /*! This routine constructs a coincidence event */ - void set_sinogram_and_ring_coordinates( - const int view_num, const int tangential_pos_num, - const int ring_a, const int ring_b); + void set_sinogram_and_ring_coordinates(const int view_num, const int tangential_pos_num, const int ring_a, const int ring_b); /* ring encoding. use as follows: #define CRYSTALRINGSPERDETECTOR 8 @@ -79,66 +75,68 @@ class CListEventDataECAT966 This organisation corresponds to physical detector blocks (which have 8 crystal rings). Names are not very good probably... - */ - /* 'random' bit: - 1 if event is Random (it fell in delayed time window) */ - /* bin field is shifted in a funny way, use the following code to find - bin_number: - if ( bin > NumProjBinsBy2 ) bin -= NumProjBins ; - */ + */ + /* 'random' bit: + 1 if event is Random (it fell in delayed time window) */ + /* bin field is shifted in a funny way, use the following code to find + bin_number: + if ( bin > NumProjBinsBy2 ) bin -= NumProjBins ; + */ #if STIRIsNativeByteOrderBigEndian - unsigned type : 1; /* 0-coincidence event, 1-time tick */ - unsigned block_B_ring : 3; - unsigned block_A_ring : 3; - unsigned block_B_detector : 3; - unsigned block_A_detector : 3; - unsigned random : 1; - unsigned bin : 9; - unsigned view : 9; + unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned block_B_ring : 3; + unsigned block_A_ring : 3; + unsigned block_B_detector : 3; + unsigned block_A_detector : 3; + unsigned random : 1; + unsigned bin : 9; + unsigned view : 9; #else // Do byteswapping first before using this bit field. - unsigned view : 9; - unsigned bin : 9; - unsigned random : 1; - unsigned block_A_detector : 3; - unsigned block_B_detector : 3; - unsigned block_A_ring : 3; - unsigned block_B_ring : 3; - unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned view : 9; + unsigned bin : 9; + unsigned random : 1; + unsigned block_A_detector : 3; + unsigned block_B_detector : 3; + unsigned block_A_ring : 3; + unsigned block_B_ring : 3; + unsigned type : 1; /* 0-coincidence event, 1-time tick */ #endif }; /*-coincidence event*/ //! Class for storing and using a coincidence event from a listmode file from the ECAT 966 scanner -class CListEventECAT966 : public CListEventCylindricalScannerWithViewTangRingRingEncoding -{ - private: - public: +class CListEventECAT966 : public CListEventCylindricalScannerWithViewTangRingRingEncoding { +private: +public: typedef CListEventDataECAT966 DataType; DataType get_data() const { return this->data; } - public: - CListEventECAT966() : - CListEventCylindricalScannerWithViewTangRingRingEncoding(shared_ptr(new Scanner(Scanner::E966))) - {} +public: + CListEventECAT966() + : CListEventCylindricalScannerWithViewTangRingRingEncoding( + shared_ptr(new Scanner(Scanner::E966))) {} - Succeeded init_from_data_ptr(const void * const ptr) - { - const char * const data_ptr = reinterpret_cast(ptr); - std::copy(data_ptr, data_ptr+sizeof(this->raw), reinterpret_cast(&this->raw)); - return Succeeded::yes; - } + Succeeded init_from_data_ptr(const void* const ptr) { + const char* const data_ptr = reinterpret_cast(ptr); + std::copy(data_ptr, data_ptr + sizeof(this->raw), reinterpret_cast(&this->raw)); + return Succeeded::yes; + } inline bool is_prompt() const { return this->data.random == 0; } - inline Succeeded set_prompt(const bool prompt = true) - { if (prompt) this->data.random=0; else this->data.random=1; return Succeeded::yes; } - - private: - BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT966)==4); - union - { - CListEventDataECAT966 data; - boost::int32_t raw; + inline Succeeded set_prompt(const bool prompt = true) { + if (prompt) + this->data.random = 0; + else + this->data.random = 1; + return Succeeded::yes; + } + +private: + BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT966) == 4); + union { + CListEventDataECAT966 data; + boost::int32_t raw; }; }; @@ -147,102 +145,82 @@ class CListEventECAT966 : public CListEventCylindricalScannerWithViewTangRingRin This class just provides the bit-field definitions. You should normally use CListTimeECAT966. */ -class CListTimeDataECAT966 -{ - public: - +class CListTimeDataECAT966 { +public: #if STIRIsNativeByteOrderBigEndian - unsigned type : 1; /* 0-coincidence event, 1-time tick */ - unsigned gating : 4; /* some info about the gating signals */ - unsigned time : 27 ; /* since scan start */ + unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned gating : 4; /* some info about the gating signals */ + unsigned time : 27; /* since scan start */ #else // Do byteswapping first before using this bit field. - unsigned time : 27 ; /* since scan start */ - unsigned gating : 4; /* some info about the gating signals */ - unsigned type : 1; /* 0-coincidence event, 1-time tick */ + unsigned time : 27; /* since scan start */ + unsigned gating : 4; /* some info about the gating signals */ + unsigned type : 1; /* 0-coincidence event, 1-time tick */ #endif }; - //! A class for storing and using a timing 'event' from a listmode file from the ECAT 966 scanner /*! \ingroup listmode */ -class CListTimeECAT966 : public ListTime, public ListGatingInput -{ - public: - Succeeded init_from_data_ptr(const void * const ptr) - { - const char * const data_ptr = reinterpret_cast(ptr); - std::copy(data_ptr, data_ptr+sizeof(this->raw), reinterpret_cast(&this->raw)); - return Succeeded::yes; - } - bool is_time() const - { return this->data.type == 1U; } - inline unsigned long get_time_in_millisecs() const - { return static_cast(this->data.time); } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) - { - this->data.time = ((1U<<28)-1) & static_cast(time_in_millisecs); +class CListTimeECAT966 : public ListTime, public ListGatingInput { +public: + Succeeded init_from_data_ptr(const void* const ptr) { + const char* const data_ptr = reinterpret_cast(ptr); + std::copy(data_ptr, data_ptr + sizeof(this->raw), reinterpret_cast(&this->raw)); + return Succeeded::yes; + } + bool is_time() const { return this->data.type == 1U; } + inline unsigned long get_time_in_millisecs() const { return static_cast(this->data.time); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { + this->data.time = ((1U << 28) - 1) & static_cast(time_in_millisecs); // TODO return more useful value return Succeeded::yes; } - inline unsigned int get_gating() const - { return this->data.gating; } - inline Succeeded set_gating(unsigned int g) - { this->data.gating = g & 0xf; return this->data.gating==g ? Succeeded::yes : Succeeded::no;} - - private: - BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT966)==4); - union - { - CListTimeDataECAT966 data; - boost::int32_t raw; + inline unsigned int get_gating() const { return this->data.gating; } + inline Succeeded set_gating(unsigned int g) { + this->data.gating = g & 0xf; + return this->data.gating == g ? Succeeded::yes : Succeeded::no; + } + +private: + BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT966) == 4); + union { + CListTimeDataECAT966 data; + boost::int32_t raw; }; }; //! A class for a general element of a listmode file /*! \ingroup listmode For the 966 it's either a coincidence event, or a timing flag.*/ -class CListRecordECAT966 : public CListRecordWithGatingInput -{ - - //public: - - bool is_time() const - { return this->time_data.is_time(); } - bool is_gating_input() const - { return this->is_time(); } - bool is_event() const - { return !this->is_time(); } - virtual CListEventECAT966& event() - { return this->event_data; } - virtual const CListEventECAT966& event() const - { return this->event_data; } - virtual CListTimeECAT966& time() - { return this->time_data; } - virtual const CListTimeECAT966& time() const - { return this->time_data; } - virtual CListTimeECAT966& gating_input() - { return this->time_data; } - virtual const CListTimeECAT966& gating_input() const - { return this->time_data; } - - bool operator==(const CListRecord& e2) const - { - return dynamic_cast(&e2) != 0 && - raw == dynamic_cast(e2).raw; - } - - public: - virtual Succeeded init_from_data_ptr(const char * const data_ptr, +class CListRecordECAT966 : public CListRecordWithGatingInput { + + // public: + + bool is_time() const { return this->time_data.is_time(); } + bool is_gating_input() const { return this->is_time(); } + bool is_event() const { return !this->is_time(); } + virtual CListEventECAT966& event() { return this->event_data; } + virtual const CListEventECAT966& event() const { return this->event_data; } + virtual CListTimeECAT966& time() { return this->time_data; } + virtual const CListTimeECAT966& time() const { return this->time_data; } + virtual CListTimeECAT966& gating_input() { return this->time_data; } + virtual const CListTimeECAT966& gating_input() const { return this->time_data; } + + bool operator==(const CListRecord& e2) const { + return dynamic_cast(&e2) != 0 && raw == dynamic_cast(e2).raw; + } + +public: + virtual Succeeded init_from_data_ptr(const char* const data_ptr, const std::size_t #ifndef NDEBUG - size // only use within assert + size // only use within assert #endif - , const bool do_byte_swap) - { + , + const bool do_byte_swap) { assert(size >= 4); - std::copy(data_ptr, data_ptr+4, reinterpret_cast(&raw));// TODO necessary for operator== + std::copy(data_ptr, data_ptr + 4, reinterpret_cast(&raw)); // TODO necessary for operator== if (do_byte_swap) ByteOrder::swap_order(raw); this->time_data.init_from_data_ptr(&raw); @@ -253,18 +231,17 @@ class CListRecordECAT966 : public CListRecordWithGatingInput return Succeeded::yes; } - virtual std::size_t size_of_record_at_ptr(const char * const /*data_ptr*/, const std::size_t /*size*/, - const bool /*do_byte_swap*/) const - { return 4; } - - private: - CListEventECAT966 event_data; - CListTimeECAT966 time_data; - boost::int32_t raw; + virtual std::size_t size_of_record_at_ptr(const char* const /*data_ptr*/, const std::size_t /*size*/, + const bool /*do_byte_swap*/) const { + return 4; + } +private: + CListEventECAT966 event_data; + CListTimeECAT966 time_data; + boost::int32_t raw; }; - END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListRecordGEHDF5.h b/src/include/stir/listmode/CListRecordGEHDF5.h index 86a0bec20b..b187368ed4 100644 --- a/src/include/stir/listmode/CListRecordGEHDF5.h +++ b/src/include/stir/listmode/CListRecordGEHDF5.h @@ -32,148 +32,187 @@ START_NAMESPACE_STIR namespace GE { namespace RDF_HDF5 { - namespace detail { - /*********************************** - * Supported Event Length Modes - ***********************************/ - enum EventLength - { - /* RESERVED = 0x0, */ - LENGTH_6_EVT = 0x1, - LENGTH_8_EVT = 0x2, - LENGTH_16_EVT = 0x3 - }; - - /*********************************** - * Supported Event Types - ***********************************/ - enum EventType - { - EXTENDED_EVT = 0x0, - COINC_EVT = 0x1 - }; +namespace detail { +/*********************************** + * Supported Event Length Modes + ***********************************/ +enum EventLength { + /* RESERVED = 0x0, */ + LENGTH_6_EVT = 0x1, + LENGTH_8_EVT = 0x2, + LENGTH_16_EVT = 0x3 +}; - /*********************************** - * Supported Extended Event Types - ***********************************/ - enum ExtendedEvtType - { - TIME_MARKER_EVT = 0x0, - COINC_COUNT_EVT = 0x1, - EXTERN_TRIG_EVT = 0x2, - TABLE_POS_EVT = 0x3, - /* RESERVED = 0x4 to 0xE */ - /* 0xE is temporary taken here to mark end of it. */ - END_LIST_EVT = 0xE, - SINGLE_EVT = 0xF - }; +/*********************************** + * Supported Event Types + ***********************************/ +enum EventType { EXTENDED_EVT = 0x0, COINC_EVT = 0x1 }; + +/*********************************** + * Supported Extended Event Types + ***********************************/ +enum ExtendedEvtType { + TIME_MARKER_EVT = 0x0, + COINC_COUNT_EVT = 0x1, + EXTERN_TRIG_EVT = 0x2, + TABLE_POS_EVT = 0x3, + /* RESERVED = 0x4 to 0xE */ + /* 0xE is temporary taken here to mark end of it. */ + END_LIST_EVT = 0xE, + SINGLE_EVT = 0xF +}; - //! Class for finding out what the event/size-type is in a GE RDF9 listmode file - /*! \ingroup listmode - \ingroup GE - */ - class CListAnyRecordDataGEHDF5 - { - public: +//! Class for finding out what the event/size-type is in a GE RDF9 listmode file +/*! \ingroup listmode + \ingroup GE +*/ +class CListAnyRecordDataGEHDF5 { +public: #if STIRIsNativeByteOrderBigEndian - // Do byteswapping first before using this bit field. - TODO; + // Do byteswapping first before using this bit field. + TODO; #else - boost::uint16_t eventLength:2; /* Event Length : Enum for the number of bytes in the event */ - boost::uint16_t eventType:1; /* Event Type : Coin or Extended types */ - boost::uint16_t eventTypeExt:4; /* If not a coincidence, Extended Event Type : Time Marker, Trigger, Single..etc */ - boost::uint16_t dummy:9; + boost::uint16_t eventLength : 2; /* Event Length : Enum for the number of bytes in the event */ + boost::uint16_t eventType : 1; /* Event Type : Coin or Extended types */ + boost::uint16_t eventTypeExt : 4; /* If not a coincidence, Extended Event Type : Time Marker, Trigger, Single..etc */ + boost::uint16_t dummy : 9; #endif - }; /*any record */ - - //! Class for storing and using a coincidence event from a GE RDF9 listmode file - /*! \ingroup listmode - \ingroup GE - This class cannot have virtual functions, as it needs to just store the data 6 bytes for CListRecordGEHDF5 to work. - */ - class CListEventDataGEHDF5 - { - public: - inline bool is_prompt() const { return true; } // TODO - inline Succeeded set_prompt(const bool prompt = true) - { - //if (prompt) random=1; else random=0; return Succeeded::yes; - return Succeeded::no; - } - inline bool is_event() const - { - return (eventType==COINC_EVT)/* && eventTypeExt==COINC_COUNT_EVT)*/; - } // TODO need to find out how to see if it's a coincidence event +}; /*any record */ + +//! Class for storing and using a coincidence event from a GE RDF9 listmode file +/*! \ingroup listmode + \ingroup GE + This class cannot have virtual functions, as it needs to just store the data 6 bytes for CListRecordGEHDF5 to work. +*/ +class CListEventDataGEHDF5 { +public: + inline bool is_prompt() const { return true; } // TODO + inline Succeeded set_prompt(const bool prompt = true) { + // if (prompt) random=1; else random=0; return Succeeded::yes; + return Succeeded::no; + } + inline void get_detection_position(DetectionPositionPair<>& det_pos) const { + // TODO 447->get_num_detectors_per_ring()-1 + det_pos.pos1().tangential_coord() = 447 - loXtalTransAxID; + det_pos.pos1().axial_coord() = loXtalAxialID; + det_pos.pos2().tangential_coord() = 447 - hiXtalTransAxID; + // std::cout << hiXtalTransAxID << " " << loXtalTransAxID << std::endl; + det_pos.pos2().axial_coord() = hiXtalAxialID; + } + inline bool is_event() const { + return (eventType == COINC_EVT) /* && eventTypeExt==COINC_COUNT_EVT)*/; + } // TODO need to find out how to see if it's a coincidence event + inline int get_tof_bin() const { return static_cast(deltaTime); } #if STIRIsNativeByteOrderBigEndian - // Do byteswapping first before using this bit field. - TODO + // Do byteswapping first before using this bit field. + TODO #else - boost::uint16_t eventLength:2; /* Event Length : Enum for the number of bytes in the event */ - boost::uint16_t eventType:1; /* Event Type : Coin or Extended types */ - boost::uint16_t hiXtalShortInteg:1; /* High Crystal Short Integration on / off */ - boost::uint16_t loXtalShortInteg:1; /* Low Crystal Short Integration on / off */ - boost::uint16_t hiXtalScatterRec:1; /* High Crystal Scatter Recovered on / off */ - boost::uint16_t loXtalScatterRec:1; /* Low Crystal Scatter Recovered on / off */ - boost::int16_t deltaTime:9; /* TOF 'signed' delta time (units defined by electronics */ - boost::uint16_t hiXtalAxialID:6; /* High Crystal Axial Id */ - boost::uint16_t hiXtalTransAxID:10; /* High Crystal Trans-Axial Id */ - boost::uint16_t loXtalAxialID:6; /* Low Crystal Axial Id */ - boost::uint16_t loXtalTransAxID:10; /* Low Crystal Trans-Axial Id */ + boost::uint16_t eventLength : 2; /* Event Length : Enum for the number of bytes in the event */ + boost::uint16_t eventType : 1; /* Event Type : Coin or Extended types */ + boost::uint16_t hiXtalShortInteg : 1; /* High Crystal Short Integration on / off */ + boost::uint16_t loXtalShortInteg : 1; /* Low Crystal Short Integration on / off */ + boost::uint16_t hiXtalScatterRec : 1; /* High Crystal Scatter Recovered on / off */ + boost::uint16_t loXtalScatterRec : 1; /* Low Crystal Scatter Recovered on / off */ + boost::int16_t deltaTime : 9; /* TOF 'signed' delta time (units defined by electronics */ + boost::uint16_t hiXtalAxialID : 6; /* High Crystal Axial Id */ + boost::uint16_t hiXtalTransAxID : 10; /* High Crystal Trans-Axial Id */ + boost::uint16_t loXtalAxialID : 6; /* Low Crystal Axial Id */ + boost::uint16_t loXtalTransAxID : 10; /* Low Crystal Trans-Axial Id */ #endif - }; /*-coincidence event*/ - +}; /*-coincidence event*/ - //! A class for storing and using a timing 'event' from a GE RDF9 listmode file - /*! \ingroup listmode - \ingroup GE - This class cannot have virtual functions, as it needs to just store the data 6 bytes for CListRecordGEHDF5 to work. - */ - class ListTimeDataGEHDF5 +#if 0 +//! A class for storing and using a trigger 'event' from a GE Signa PET/MR listmode file +/*! \ingroup listmode + \ingroup GE + This class cannot have virtual functions, as it needs to just store the data 6 bytes for CListRecordGESigna to work. + */ +class CListGatingDataGESigna +{ + public: +# if 0 + inline unsigned long get_time_in_millisecs() const + { return (time_hi()<<24) | time_lo(); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { - public: - inline unsigned long get_time_in_millisecs() const - { return (time_hi()<<16) | time_lo(); } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) - { - data.timeMarkerLS = ((1UL<<16)-1) & (time_in_millisecs); - data.timeMarkerMS = (time_in_millisecs) >> 16; - // TODO return more useful value - return Succeeded::yes; - } - inline bool is_time() const - { // TODO need to find out how to see if it's a timing event - return (data.eventType==EXTENDED_EVT) && (data.eventTypeExt==TIME_MARKER_EVT); - }// TODO - - private: - typedef union{ - struct { + words[0].value = ((1UL<<24)-1) & (time_in_millisecs); + words[1].value = (time_in_millisecs) >> 24; + // TODO return more useful value + return Succeeded::yes; + } +# endif + inline bool is_gating_input() const + { return (words[0].signature==21) && (words[1].signature==29); } + inline unsigned int get_gating() const + { return words[0].reserved; } // return "reserved" bits. might be something in there + inline Succeeded set_gating(unsigned int g) + { words[0].reserved = g&7; return Succeeded::yes; } + +private: + typedef union{ + struct { +# if STIRIsNativeByteOrderBigEndian + boost::uint32_t signature : 5; + boost::uint32_t reserved : 3; + boost::uint32_t value : 24; // timing info here in the first word, but we're ignoring it +# else + boost::uint32_t value : 24; + boost::uint32_t reserved : 3; + boost::uint32_t signature : 5; +# endif + }; + boost::uint32_t raw; + } oneword_t; + oneword_t words[2]; +}; + +#endif + +//! A class for storing and using a timing 'event' from a GE RDF9 listmode file +/*! \ingroup listmode + \ingroup GE + This class cannot have virtual functions, as it needs to just store the data 6 bytes for CListRecordGEHDF5 to work. +*/ +class ListTimeDataGEHDF5 { +public: + inline unsigned long get_time_in_millisecs() const { return (time_hi() << 16) | time_lo(); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { + data.timeMarkerLS = ((1UL << 16) - 1) & (time_in_millisecs); + data.timeMarkerMS = (time_in_millisecs) >> 16; + // TODO return more useful value + return Succeeded::yes; + } + inline bool is_time() const { // TODO need to find out how to see if it's a timing event + return (data.eventType == EXTENDED_EVT) && (data.eventTypeExt == TIME_MARKER_EVT); + } // TODO + +private: + typedef union { + struct { #if STIRIsNativeByteOrderBigEndian - TODO + TODO #else - boost::uint16_t eventLength:2; /* Event Length : Enum for the number of bytes in the event */ - boost::uint16_t eventType:1; /* Event Type : Coin or Extended types */ - boost::uint16_t eventTypeExt:4; /* Extended Event Type : Time Marker, Trigger, Single..etc */ - boost::uint16_t unused1:5; /* Unused */ - boost::uint16_t externEvt3:1; /* External Event Input 3 Level */ - boost::uint16_t externEvt2:1; /* External Event Input 2 Level */ - boost::uint16_t externEvt1:1; /* External Event Input 1 Level */ - boost::uint16_t externEvt0:1; /* External Event Input 0 Level */ - boost::uint16_t timeMarkerLS:16; /* Least Significant 16 bits of 32-bit Time Marker */ - boost::uint16_t timeMarkerMS:16; /* Most Significant 16 bits of 32-bitTime Marker */ + boost::uint16_t eventLength : 2; /* Event Length : Enum for the number of bytes in the event */ + boost::uint16_t eventType : 1; /* Event Type : Coin or Extended types */ + boost::uint16_t eventTypeExt : 4; /* Extended Event Type : Time Marker, Trigger, Single..etc */ + boost::uint16_t unused1 : 5; /* Unused */ + boost::uint16_t externEvt3 : 1; /* External Event Input 3 Level */ + boost::uint16_t externEvt2 : 1; /* External Event Input 2 Level */ + boost::uint16_t externEvt1 : 1; /* External Event Input 1 Level */ + boost::uint16_t externEvt0 : 1; /* External Event Input 0 Level */ + boost::uint16_t timeMarkerLS : 16; /* Least Significant 16 bits of 32-bit Time Marker */ + boost::uint16_t timeMarkerMS : 16; /* Most Significant 16 bits of 32-bitTime Marker */ #endif - }; - } data_t; - data_t data; - - unsigned long time_lo() const - { return data.timeMarkerLS; } - unsigned long time_hi() const - { return data.timeMarkerMS; } }; + } data_t; + data_t data; - } + unsigned long time_lo() const { return data.timeMarkerLS; } + unsigned long time_hi() const { return data.timeMarkerMS; } +}; + +} // namespace detail //! A class for a general element (or "record") of a GE RDF9 listmode file /*! \ingroup listmode @@ -181,29 +220,24 @@ namespace RDF_HDF5 { All types of records are stored in a (private) union with the "basic" classes such as CListEventDataGEHDF5. This class essentially just forwards the work to the "basic" classes. */ -class CListRecordGEHDF5 : public CListRecord, public ListTime, // public CListGatingInput, - public CListEventCylindricalScannerWithDiscreteDetectors -{ +class CListRecordGEHDF5 : public CListRecord, + public ListTime, // public CListGatingInput, + public CListEventCylindricalScannerWithDiscreteDetectors { typedef detail::CListEventDataGEHDF5 DataType; typedef detail::ListTimeDataGEHDF5 TimeType; - //typedef CListGatingDataGEHDF5 GatingType; + // typedef CListGatingDataGEHDF5 GatingType; - public: +public: //! constructor /*! Takes the scanner and first_time stamp. The former will be used for checking and swapping, the latter for adjusting the time of each event, as GE listmode files do not start with time-stamp 0. get_time_in_millisecs() should therefore be zero at the first time stamp. */ - CListRecordGEHDF5(const shared_ptr& scanner_sptr, const unsigned long first_time_stamp) : - CListEventCylindricalScannerWithDiscreteDetectors(scanner_sptr), - first_time_stamp(first_time_stamp) - {} - - bool is_time() const - { - return this->time_data.is_time(); - } + CListRecordGEHDF5(const shared_ptr& proj_data_info_sptr, const unsigned long first_time_stamp) + : CListEventCylindricalScannerWithDiscreteDetectors(proj_data_info_sptr), first_time_stamp(first_time_stamp) {} + + bool is_time() const { return this->time_data.is_time(); } #if 0 bool is_gating_input() const { @@ -211,24 +245,18 @@ class CListRecordGEHDF5 : public CListRecord, public ListTime, // public CListGa } #endif - bool is_event() const - { return this->event_data.is_event(); } - virtual CListEvent& event() - { return *this; } - virtual const CListEvent& event() const - { return *this; } - virtual ListTime& time() - { return *this; } - virtual const ListTime& time() const - { return *this; } + bool is_event() const { return this->event_data.is_event(); } + virtual CListEvent& event() { return *this; } + virtual const CListEvent& event() const { return *this; } + virtual ListTime& time() { return *this; } + virtual const ListTime& time() const { return *this; } #if 0 virtual CListGatingInput& gating_input() { return *this; } virtual const CListGatingInput& gating_input() const { return *this; } #endif - bool operator==(const CListRecord& e2) const - { + bool operator==(const CListRecord& e2) const { return false; #if 0 // TODO @@ -236,96 +264,102 @@ dynamic_cast(&e2) != 0 && raw[0] == static_cast(e2).raw[0] && (this->is_event() || (raw[1] == static_cast(e2).raw[1])); #endif - } + } - // time - inline unsigned long get_time_in_millisecs() const - { return time_data.get_time_in_millisecs() - first_time_stamp; } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) - { return time_data.set_time_in_millisecs(time_in_millisecs); } + // time + inline unsigned long get_time_in_millisecs() const { return time_data.get_time_in_millisecs() - first_time_stamp; } + + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { + return time_data.set_time_in_millisecs(time_in_millisecs); + } #if 0 inline unsigned int get_gating() const { return gating_data.get_gating(); } - inline Succeeded set_gating(unsigned int g) + inline Succeeded set_gating(unsigned int g) { return gating_data.set_gating(g); } #endif // event inline bool is_prompt() const { return event_data.is_prompt(); } - inline Succeeded set_prompt(const bool prompt = true) - { return event_data.set_prompt(prompt); } + inline Succeeded set_prompt(const bool prompt = true) { return event_data.set_prompt(prompt); } - virtual void get_detection_position(DetectionPositionPair<>& det_pos) const - { - det_pos.pos1().tangential_coord() = scanner_sptr->get_num_detectors_per_ring() - 1 - event_data.loXtalTransAxID; + virtual void get_detection_position(DetectionPositionPair<>& det_pos) const { + det_pos.pos1().tangential_coord() = + this->uncompressed_proj_data_info_sptr->get_scanner_sptr()->get_num_detectors_per_ring() - 1 - event_data.loXtalTransAxID; det_pos.pos1().axial_coord() = event_data.loXtalAxialID; - det_pos.pos2().tangential_coord() = scanner_sptr->get_num_detectors_per_ring() - 1 - event_data.hiXtalTransAxID; + det_pos.pos2().tangential_coord() = + this->uncompressed_proj_data_info_sptr->get_scanner_sptr()->get_num_detectors_per_ring() - 1 - event_data.hiXtalTransAxID; det_pos.pos2().axial_coord() = event_data.hiXtalAxialID; } //! This routine sets in a coincidence event from detector "indices" - virtual void set_detection_position(const DetectionPositionPair<>&) - { - error("TODO"); - } + virtual void set_detection_position(const DetectionPositionPair<>&) { error("TODO"); } - virtual std::size_t size_of_record_at_ptr(const char * const data_ptr, const std::size_t, - const bool do_byte_swap) const - { + virtual std::size_t size_of_record_at_ptr(const char* const data_ptr, const std::size_t, const bool do_byte_swap) const { // TODO don't know what to do with byteswap. assert(do_byte_swap == false); // Figure out the actual size from the eventLength bits. - union - { + union { detail::CListAnyRecordDataGEHDF5 rec; boost::uint16_t raw; }; - std::copy(data_ptr, data_ptr+2, &raw); - switch(rec.eventLength) - { - case detail::LENGTH_6_EVT: return std::size_t(6); - case detail::LENGTH_8_EVT: return std::size_t(8); - case detail::LENGTH_16_EVT: return std::size_t(16); - default: - error("ClistRecordGEHDF5: error decoding event (eventLength bits are incorrect)"); - return std::size_t(0); // avoid compiler warnings - } + std::copy(data_ptr, data_ptr + 2, &raw); + switch (rec.eventLength) { + case detail::LENGTH_6_EVT: + return std::size_t(6); + case detail::LENGTH_8_EVT: + return std::size_t(8); + case detail::LENGTH_16_EVT: + return std::size_t(16); + default: + error("ClistRecordGEHDF5: error decoding event (eventLength bits are incorrect)"); + return std::size_t(0); // avoid compiler warnings + } } - virtual Succeeded init_from_data_ptr(const char * const data_ptr, - const std::size_t size, - const bool do_byte_swap) - { + virtual Succeeded init_from_data_ptr(const char* const data_ptr, const std::size_t size, const bool do_byte_swap) { assert(size >= 6); assert(size <= 16); - std::copy(data_ptr, data_ptr+size, reinterpret_cast(&this->raw[0])); - - if (do_byte_swap) - { - error("ClistRecordGEHDF5: byte-swapping not supported yet. sorry"); - //ByteOrder::swap_order(this->raw[0]); - } + std::copy(data_ptr, data_ptr + size, reinterpret_cast(&this->raw[0])); + + if (do_byte_swap) { + ByteOrder::swap_order(this->raw[0]); + } + if (this->is_event() || this->is_time()) { + // std::cout << "This is an event \n" ; + assert(size >= 6); + + std::copy(data_ptr + 6, data_ptr + 6, reinterpret_cast(&this->raw[1])); + // std::cout << "after assert an event \n" ; + } + if (do_byte_swap) { + error("don't know how to byteswap"); + ByteOrder::swap_order(this->raw[1]); + } + + if (this->is_event()) { + // set TOF info in ps + this->delta_time = this->event_data.get_tof_bin() * this->get_scanner_ptr()->get_size_of_timing_pos(); + } return Succeeded::yes; } private: unsigned long first_time_stamp; union { - DataType event_data; - TimeType time_data; - //GatingType gating_data; - boost::int32_t raw[16/4]; + DataType event_data; + TimeType time_data; + // GatingType gating_data; + boost::int32_t raw[16 / 4]; }; - BOOST_STATIC_ASSERT(sizeof(boost::int32_t)==4); - BOOST_STATIC_ASSERT(sizeof(DataType)==6); - BOOST_STATIC_ASSERT(sizeof(TimeType)==6); - //BOOST_STATIC_ASSERT(sizeof(GatingType)==8); - + BOOST_STATIC_ASSERT(sizeof(boost::int32_t) == 4); + BOOST_STATIC_ASSERT(sizeof(DataType) == 6); + BOOST_STATIC_ASSERT(sizeof(TimeType) == 6); + // BOOST_STATIC_ASSERT(sizeof(GatingType)==8); }; - -} // namespace -} // namespace +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index afd11ec401..2292070f90 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -1,6 +1,7 @@ /* Copyright (C) 2015-2016 University of Leeds Copyright (C) 2016 UCL + Copyright (C) 2016-17, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -37,169 +38,108 @@ START_NAMESPACE_STIR -class CListEventROOT : public CListEventCylindricalScannerWithDiscreteDetectors -{ +class CListEventROOT : public CListEventCylindricalScannerWithDiscreteDetectors { public: + CListEventROOT(const shared_ptr& proj_data_info); - CListEventROOT(const shared_ptr& scanner_sptr); - - //! This routine returns the corresponding detector pair - virtual void get_detection_position(DetectionPositionPair<>&) const; + //! This routine returns the corresponding detector pair + virtual void get_detection_position(DetectionPositionPair<>&) const; - //! This routine sets in a coincidence event from detector "indices" - virtual void set_detection_position(const DetectionPositionPair<>&); + //! This routine sets in a coincidence event from detector "indices" + virtual void set_detection_position(const DetectionPositionPair<>&); - //! \details This is the main function which transform GATE coordinates to STIR - void init_from_data(const int &_ring1, const int &_ring2, - const int &crystal1, const int &crystal2); + //! \details This is the main function which transform GATE coordinates to STIR + void init_from_data(const int& _ring1, const int& _ring2, const int& crystal1, const int& crystal2, const double& _delta_time); - inline bool is_prompt() const - { return true; } + inline bool is_prompt() const { return true; } - bool inline is_swapped() const - { return swapped; } + bool inline is_swapped() const { return swapped; } private: - //! First ring, in order to detector tangestial index - int ring1; - //! Second ring, in order to detector tangestial index - int ring2; - //! First detector, in order to detector tangestial index - int det1; - //! Second detector, in order to detector tangestial index - int det2; - //! Indicates if swap segments - bool swapped; - //! This is the number of detector we have to rotate in order to - //! align GATE and STIR. - int quarter_of_detectors; + //! First ring, in order to detector tangestial index + int ring1; + //! Second ring, in order to detector tangestial index + int ring2; + //! First detector, in order to detector tangestial index + int det1; + //! Second detector, in order to detector tangestial index + int det2; + + //! This is the number of detector we have to rotate in order to + //! align GATE and STIR. + int quarter_of_detectors; }; //! A class for storing and using a timing 'event' from a listmode file from the ECAT 8_32bit scanner /*! \ingroup listmode */ -class CListTimeROOT : public ListTime -{ +class CListTimeROOT : public ListTime { public: - void init_from_data(double time1, double time2) - { - timeA = time1; - timeB = time2; - } - - //! Returns always true - bool is_time() const - { return true; } - //! Returns the detection time of the first photon - //! in milliseconds. - inline unsigned long get_time_in_millisecs() const - { return timeA * 1e3; } - //! Get the detection time of the first photon - //! in milliseconds - inline double get_timeA_in_millisecs() const - { return timeA * 1e3; } - //! Get the detection time of the second photon - //! in milliseconds - inline double get_timeB_in_millisecs() const - { return timeB * 1e3; } - //! Get the delta Time between the two events - inline double get_delta_time_in_millisecs() const - { return (timeB - timeA) * 1e3; } - //! Get delta time in picoseconds - inline double get_delta_time_in_picosecs() const - { return (timeB - timeA) * 1e12; } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) - { - warning("set_time_in_millisecs: Not implemented for ROOT files. Aborting."); - return Succeeded::no; - } + void init_from_data(double time1) { timeA = time1; } + + //! Returns always true + bool is_time() const { return true; } + //! Returns the detection time of the first photon + //! in milliseconds. + inline unsigned long get_time_in_millisecs() const { return static_cast(timeA * 1e3); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { + warning("set_time_in_millisecs: Not implemented for ROOT files. Aborting."); + return Succeeded::no; + } private: - - //! - //! \brief timeA - //! \details The detection time of the first of the two photons, in seconds - double timeA; - - //! - //! \brief timeB - //! \details The detection time of the second of the two photons - double timeB; + //! + //! \brief timeA + //! \details The detection time of the first of the two photons, in seconds + double timeA; }; //! A class for a general element of a listmode file for a Siemens scanner using the ROOT files class CListRecordROOT : public CListRecord // currently no gating yet { public: - //! Returns always true - bool inline is_time() const; - //! Returns always true - bool inline is_event() const; - //! Returns always true - bool inline is_full_event() const; - - virtual CListEventROOT& event() - { - return this->event_data; - } - - virtual const CListEventROOT& event() const - { - return this->event_data; - } - - virtual CListTimeROOT& time() - { - return this->time_data; - } - - virtual const CListTimeROOT& time() const - { - return this->time_data; - } - - bool operator==(const CListRecord& e2) const - { - return dynamic_cast(&e2) != 0 && - raw[0] == dynamic_cast(e2).raw[0] && - raw[1] == dynamic_cast(e2).raw[1]; - } - - CListRecordROOT(const shared_ptr& scanner_sptr) : - event_data(scanner_sptr) - {} - - virtual Succeeded init_from_data( const int& ring1, - const int& ring2, - const int& crystal1, - const int& crystal2, - double time1, double time2, - const int& event1, const int& event2) - { - /// \warning ROOT data are time and event at the same time. - - this->event_data.init_from_data(ring1, ring2, - crystal1, crystal2); - - this->time_data.init_from_data( - time1,time2); - - // We can make a singature raw based on the two events IDs. - // It is pretty unique. - raw[0] = event1; - raw[1] = event2; - - return Succeeded::yes; - } + //! Returns always true + bool inline is_time() const; + //! Returns always true + bool inline is_event() const; -private: - CListEventROOT event_data; - CListTimeROOT time_data; - boost::int32_t raw[2]; // this raw field isn't strictly necessary, get rid of it? + virtual CListEventROOT& event() { return this->event_data; } + + virtual const CListEventROOT& event() const { return this->event_data; } + + virtual CListTimeROOT& time() { return this->time_data; } + + virtual const CListTimeROOT& time() const { return this->time_data; } + bool operator==(const CListRecord& e2) const { + return dynamic_cast(&e2) != 0 && raw[0] == dynamic_cast(e2).raw[0] && + raw[1] == dynamic_cast(e2).raw[1]; + } + + CListRecordROOT(const shared_ptr& proj_data_info_sptr) : event_data(proj_data_info_sptr) {} + + virtual Succeeded init_from_data(const int& ring1, const int& ring2, const int& crystal1, const int& crystal2, + const double& time1, const double& delta_time, const int& event1, const int& event2) { + /// \warning ROOT data are time and event at the same time. + + this->event_data.init_from_data(ring1, ring2, crystal1, crystal2, delta_time); + + this->time_data.init_from_data(time1); + + // We can make a singature raw based on the two events IDs. + // It is pretty unique. + raw[0] = event1; + raw[1] = event2; + + return Succeeded::yes; + } + +private: + CListEventROOT event_data; + CListTimeROOT time_data; + boost::int32_t raw[2]; // this raw field isn't strictly necessary, get rid of it? }; END_NAMESPACE_STIR #include "stir/listmode/CListRecordROOT.inl" #endif - diff --git a/src/include/stir/listmode/CListRecordROOT.inl b/src/include/stir/listmode/CListRecordROOT.inl index 26270593c4..97395b43da 100644 --- a/src/include/stir/listmode/CListRecordROOT.inl +++ b/src/include/stir/listmode/CListRecordROOT.inl @@ -27,13 +27,14 @@ START_NAMESPACE_STIR -bool CListRecordROOT::is_time() const -{ return true; } - -bool CListRecordROOT::is_event() const -{ return true; } - -bool CListRecordROOT::is_full_event() const -{ return true; } +bool +CListRecordROOT::is_time() const { + return true; +} + +bool +CListRecordROOT::is_event() const { + return true; +} END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListRecordSAFIR.h b/src/include/stir/listmode/CListRecordSAFIR.h index f951a4b87b..aac36b5081 100644 --- a/src/include/stir/listmode/CListRecordSAFIR.h +++ b/src/include/stir/listmode/CListRecordSAFIR.h @@ -2,20 +2,20 @@ Coincidence Event Class for SAFIR: Header File - Copyright 2015 ETH Zurich, Institute of Particle Physics - Copyright 2020 Positrigo AG, Zurich + Copyright 2015 ETH Zurich, Institute of Particle Physics + Copyright 2020 Positrigo AG, Zurich - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ @@ -31,7 +31,7 @@ #ifndef __stir_listmode_CListRecordSAFIR_H__ #define __stir_listmode_CListRecordSAFIR_H__ -#include +#include #include "stir/listmode/CListRecord.h" #include "stir/DetectionPositionPair.h" @@ -44,212 +44,187 @@ #include "stir/listmode/DetectorCoordinateMapFromFile.h" - START_NAMESPACE_STIR /*! -Provides interface of the record class to STIR by implementing get_LOR(). It uses a map from detector indices to coordinates to specify LORAs2Points from given detection pair indices. +Provides interface of the record class to STIR by implementing get_LOR(). It uses a map from detector indices to coordinates to +specify LORAs2Points from given detection pair indices. The record has the following format (for little-endian byte order) \code - unsigned ringA : 8; - unsigned ringB : 8; - unsigned detA : 16; - unsigned detB : 16; - unsigned layerA : 4; - unsigned layerB : 4; - unsigned reserved : 6; - unsigned isRandom : 1; - unsigned type : 1; + unsigned ringA : 8; + unsigned ringB : 8; + unsigned detA : 16; + unsigned detB : 16; + unsigned layerA : 4; + unsigned layerB : 4; + unsigned reserved : 6; + unsigned isRandom : 1; + unsigned type : 1; \endcode */ template -class CListEventSAFIR : public CListEvent -{ +class CListEventSAFIR : public CListEvent { public: - /*! Constructor which initializes map upon construction. - */ - inline CListEventSAFIR( shared_ptr map ) : map(map) {} - - //! Returns LOR corresponding to the given event. - inline virtual LORAs2Points get_LOR() const; + /*! Constructor which initializes map upon construction. + */ + inline CListEventSAFIR(shared_ptr map) : map(map) {} + + //! Returns LOR corresponding to the given event. + inline virtual LORAs2Points get_LOR() const; //! This method checks if the template is valid for LmToProjData /*! Used before the actual processing of the data (see issue #61), before calling get_bin() * Most scanners have listmode data that correspond to non arc-corrected data and * this check avoids a crash when an unsupported template is used as input. */ - inline virtual bool is_valid_template(const ProjDataInfo&) const {return true;} + inline virtual bool is_valid_template(const ProjDataInfo&) const { return true; } + + //! Returns 0 if event is prompt and 1 if random/delayed + inline bool is_prompt() const { return !(static_cast(this)->is_prompt()); } + //! Function to set map for detector indices to coordinates. + inline void set_map(shared_ptr new_map) { map = new_map; } - //! Returns 0 if event is prompt and 1 if random/delayed - inline bool is_prompt() - const { return !(static_cast(this)->is_prompt()); } - //! Function to set map for detector indices to coordinates. - inline void set_map( shared_ptr new_map ) { map = new_map; } private: - friend class CListRecordSAFIR; - /*! Default constructor will not work as it does not initialize a map to relate - detector indices and space coordinates. Always use other constructor with a map pointer. Or use set_map( shared_ptr new_map ) after default construction. - */ - inline CListEventSAFIR( ) {} - shared_ptr map; + friend class CListRecordSAFIR; + /*! Default constructor will not work as it does not initialize a map to relate + detector indices and space coordinates. Always use other constructor with a map pointer. Or use set_map( + shared_ptr new_map ) after default construction. + */ + inline CListEventSAFIR() {} + shared_ptr map; }; - - //! Class for record with coincidence data -class CListEventDataSAFIR -{ +class CListEventDataSAFIR { public: - //! Writes detection position pair to reference given as argument. - inline void get_detection_position_pair(DetectionPositionPair<>& det_pos_pair); - - //! Returns 0 if event is prompt and 1 if random/delayed - inline bool is_prompt() - const { return !isRandom; } + //! Writes detection position pair to reference given as argument. + inline void get_detection_position_pair(DetectionPositionPair<>& det_pos_pair); - //! Can be used to set "promptness" of event. - inline Succeeded set_prompt( const bool prompt = true ) { - isRandom = !prompt; - return Succeeded::yes; - } + //! Returns 0 if event is prompt and 1 if random/delayed + inline bool is_prompt() const { return !isRandom; } + //! Can be used to set "promptness" of event. + inline Succeeded set_prompt(const bool prompt = true) { + isRandom = !prompt; + return Succeeded::yes; + } private: - friend class CListRecordSAFIR; + friend class CListRecordSAFIR; #if STIRIsNativeByteOrderBigEndian - unsigned type : 1; - unsigned isRandom : 1; - unsigned reserved : 6; - unsigned layerB : 4; - unsigned layerA : 4; - unsigned detB : 16; - unsigned detA : 16; - unsigned ringB : 8; - unsigned ringA : 8; + unsigned type : 1; + unsigned isRandom : 1; + unsigned reserved : 6; + unsigned layerB : 4; + unsigned layerA : 4; + unsigned detB : 16; + unsigned detA : 16; + unsigned ringB : 8; + unsigned ringA : 8; #else - unsigned ringA : 8; - unsigned ringB : 8; - unsigned detA : 16; - unsigned detB : 16; - unsigned layerA : 4; - unsigned layerB : 4; - unsigned reserved : 6; - unsigned isRandom : 1; - unsigned type : 1; + unsigned ringA : 8; + unsigned ringB : 8; + unsigned detA : 16; + unsigned detB : 16; + unsigned layerA : 4; + unsigned layerB : 4; + unsigned reserved : 6; + unsigned isRandom : 1; + unsigned type : 1; #endif }; - //! Class for record with time data -class CListTimeDataSAFIR -{ +class CListTimeDataSAFIR { public: - inline unsigned long get_time_in_millisecs() const - { return static_cast(time); } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) - { - time = ((boost::uint64_t(1)<<49)-1) & static_cast(time_in_millisecs); - return Succeeded::yes; - } + inline unsigned long get_time_in_millisecs() const { return static_cast(time); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { + time = ((boost::uint64_t(1) << 49) - 1) & static_cast(time_in_millisecs); + return Succeeded::yes; + } + private: - friend class CListRecordSAFIR; + friend class CListRecordSAFIR; #if STIRIsNativeByteOrderBigEndian - boost::uint64_t type : 1; - boost::uint64_t reserved : 15; - boost::uint64_t time : 48; + boost::uint64_t type : 1; + boost::uint64_t reserved : 15; + boost::uint64_t time : 48; #else - boost::uint64_t time : 48; - boost::uint64_t reserved : 15; - boost::uint64_t type : 1; + boost::uint64_t time : 48; + boost::uint64_t reserved : 15; + boost::uint64_t type : 1; #endif }; //! Class for general record, containing a union of data, time and raw record and providing access to certain elements. -class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventSAFIR -{ +class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventSAFIR { public: - typedef CListEventDataSAFIR DataType; - - //! Returns event_data (without checking if the type is really event and not time). - DataType get_data() const - { return this->event_data; } + typedef CListEventDataSAFIR DataType; - CListRecordSAFIR() : CListEventSAFIR() {} + //! Returns event_data (without checking if the type is really event and not time). + DataType get_data() const { return this->event_data; } - virtual ~CListRecordSAFIR() {} + CListRecordSAFIR() : CListEventSAFIR() {} - virtual bool is_time() const - { return time_data.type == 1; } + virtual ~CListRecordSAFIR() {} - virtual bool is_event() const - { return time_data.type == 0; } + virtual bool is_time() const { return time_data.type == 1; } - virtual CListEvent& event() - { return *this; } + virtual bool is_event() const { return time_data.type == 0; } - virtual const CListEvent& event() const - { return *this; } + virtual CListEvent& event() { return *this; } - virtual CListEventSAFIR& event_SAFIR() - { return *this; } + virtual const CListEvent& event() const { return *this; } - virtual const CListEventSAFIR& event_SAFIR() const - { return *this; } + virtual CListEventSAFIR& event_SAFIR() { return *this; } - virtual ListTime& time() - { return *this; } + virtual const CListEventSAFIR& event_SAFIR() const { return *this; } - virtual const ListTime& time() const - { return *this; } + virtual ListTime& time() { return *this; } - virtual bool operator==(const CListRecord& e2) const - { - return dynamic_cast(&e2) != 0 && - raw == static_cast(e2).raw; - } + virtual const ListTime& time() const { return *this; } - inline unsigned long get_time_in_millisecs() const - { return time_data.get_time_in_millisecs(); } + virtual bool operator==(const CListRecord& e2) const { + return dynamic_cast(&e2) != 0 && raw == static_cast(e2).raw; + } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) - { return time_data.set_time_in_millisecs(time_in_millisecs); } + inline unsigned long get_time_in_millisecs() const { return time_data.get_time_in_millisecs(); } - inline bool is_prompt() const { return !(event_data.isRandom); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { + return time_data.set_time_in_millisecs(time_in_millisecs); + } - Succeeded - init_from_data_ptr(const char * const data_ptr, - const std::size_t size_of_record, - const bool do_byte_swap) - { - assert(size_of_record >= 8); - std::copy(data_ptr, data_ptr+8, reinterpret_cast(&raw));// TODO necessary for operator== - if (do_byte_swap) ByteOrder::swap_order(raw); - return Succeeded::yes; - } + inline bool is_prompt() const { return !(event_data.isRandom); } + Succeeded init_from_data_ptr(const char* const data_ptr, const std::size_t size_of_record, const bool do_byte_swap) { + assert(size_of_record >= 8); + std::copy(data_ptr, data_ptr + 8, reinterpret_cast(&raw)); // TODO necessary for operator== + if (do_byte_swap) + ByteOrder::swap_order(raw); + return Succeeded::yes; + } - std::size_t - size_of_record_at_ptr(const char * const /*data_ptr*/, const std::size_t /*size*/, - const bool /*do_byte_swap*/) const - { return 8; } + std::size_t size_of_record_at_ptr(const char* const /*data_ptr*/, const std::size_t /*size*/, + const bool /*do_byte_swap*/) const { + return 8; + } private: -// use C++ union to save data, you can only use one at a time, -// but compiler will not check which one was used! -// Be careful not to read event data from time record and vice versa!! -// However, this is used as a feature if comparing events over the 'raw' type. - union { - CListEventDataSAFIR event_data; - CListTimeDataSAFIR time_data; - boost::int64_t raw; - }; - BOOST_STATIC_ASSERT(sizeof(boost::uint64_t)==8); - BOOST_STATIC_ASSERT(sizeof(CListEventDataSAFIR)==8); - BOOST_STATIC_ASSERT(sizeof(CListTimeDataSAFIR)==8); + // use C++ union to save data, you can only use one at a time, + // but compiler will not check which one was used! + // Be careful not to read event data from time record and vice versa!! + // However, this is used as a feature if comparing events over the 'raw' type. + union { + CListEventDataSAFIR event_data; + CListTimeDataSAFIR time_data; + boost::int64_t raw; + }; + BOOST_STATIC_ASSERT(sizeof(boost::uint64_t) == 8); + BOOST_STATIC_ASSERT(sizeof(CListEventDataSAFIR) == 8); + BOOST_STATIC_ASSERT(sizeof(CListTimeDataSAFIR) == 8); }; - END_NAMESPACE_STIR #include "CListRecordSAFIR.inl" diff --git a/src/include/stir/listmode/CListRecordSAFIR.inl b/src/include/stir/listmode/CListRecordSAFIR.inl index c63fb3eb69..41871d9689 100644 --- a/src/include/stir/listmode/CListRecordSAFIR.inl +++ b/src/include/stir/listmode/CListRecordSAFIR.inl @@ -2,23 +2,23 @@ Coincidence Event Class for SAFIR: Inline File - Copyright 2015 ETH Zurich, Institute of Particle Physics - Copyright 2020 Positrigo AG, Zurich + Copyright 2015 ETH Zurich, Institute of Particle Physics + Copyright 2020 Positrigo AG, Zurich - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ -#include +#include #include "stir/LORCoordinates.h" #include "stir/listmode/CListRecord.h" @@ -31,31 +31,31 @@ START_NAMESPACE_STIR template LORAs2Points -CListEventSAFIR::get_LOR() const -{ - LORAs2Points lor; - DetectionPositionPair<> det_pos_pair; +CListEventSAFIR::get_LOR() const { + LORAs2Points lor; + DetectionPositionPair<> det_pos_pair; - static_cast(this)->get_data().get_detection_position_pair(det_pos_pair); + static_cast(this)->get_data().get_detection_position_pair(det_pos_pair); - if(!map) stir::error("Crystal map not set."); + if (!map) + stir::error("Crystal map not set."); - lor.p1() = map->get_detector_coordinate(det_pos_pair.pos1()); - lor.p2() = map->get_detector_coordinate(det_pos_pair.pos2()); + lor.p1() = map->get_detector_coordinate(det_pos_pair.pos1()); + lor.p2() = map->get_detector_coordinate(det_pos_pair.pos2()); - return lor; + return lor; } -void CListEventDataSAFIR::get_detection_position_pair(DetectionPositionPair<>& det_pos_pair) -{ - det_pos_pair.pos1().radial_coord() = layerA; - det_pos_pair.pos2().radial_coord() = layerB; +void +CListEventDataSAFIR::get_detection_position_pair(DetectionPositionPair<>& det_pos_pair) { + det_pos_pair.pos1().radial_coord() = layerA; + det_pos_pair.pos2().radial_coord() = layerB; - det_pos_pair.pos1().axial_coord() = ringA; - det_pos_pair.pos2().axial_coord() = ringB; + det_pos_pair.pos1().axial_coord() = ringA; + det_pos_pair.pos2().axial_coord() = ringB; - det_pos_pair.pos1().tangential_coord() = detA; - det_pos_pair.pos2().tangential_coord() = detB; + det_pos_pair.pos1().tangential_coord() = detA; + det_pos_pair.pos2().tangential_coord() = detB; } END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/DetectorCoordinateMapFromFile.h b/src/include/stir/listmode/DetectorCoordinateMapFromFile.h index ac746bddd0..047080e9a7 100644 --- a/src/include/stir/listmode/DetectorCoordinateMapFromFile.h +++ b/src/include/stir/listmode/DetectorCoordinateMapFromFile.h @@ -1,20 +1,20 @@ /* DetectorCoordinateMapFromFile.h Read List-Mode Event Data using map from file: Header File - Copyright 2015 ETH Zurich, Institute of Particle Physics - Copyright 2020 Positrigo AG, Zurich + Copyright 2015 ETH Zurich, Institute of Particle Physics + Copyright 2020 Positrigo AG, Zurich - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ /*! @@ -37,56 +37,48 @@ #include "stir/DetectionPosition.h" #ifndef __stir_listmode_DetectorCoordinateMapFromFile_H__ -#define __stir_listmode_DetectorCoordinateMapFromFile_H__ +# define __stir_listmode_DetectorCoordinateMapFromFile_H__ START_NAMESPACE_STIR -/*! Class providing map functionality to convert detector indices to spatial coordinates. - Map files can have 5 or 6 tab- or comma-separated columns. Lines beginning with '#' are ignored. The layer column is optional - \par Format: - ring,detector,(layer,)x,y,z - An empty line will terminate the reading at that line. +/*! Class providing map functionality to convert detector indices to spatial coordinates. + Map files can have 5 or 6 tab- or comma-separated columns. Lines beginning with '#' are ignored. The layer column is + optional \par Format: ring,detector,(layer,)x,y,z An empty line will terminate the reading at that line. */ -class DetectorCoordinateMapFromFile -{ +class DetectorCoordinateMapFromFile { public: - //! Constructor calls read_detectormap_from_file( filename ). - DetectorCoordinateMapFromFile(const std::string& filename, double sigma = 0.0) : - sigma(sigma), - distribution(0.0, sigma) - { read_detectormap_from_file( filename ); } - - //! Reads map from file and stores it. - void read_detectormap_from_file( const std::string& filename ); - - //! Returns a cartesian coordinate given a detection position. - stir::CartesianCoordinate3D get_detector_coordinate( const stir::DetectionPosition<>& det_pos ) - { - auto coord = coord_map.at(det_pos); - coord.x() += distribution(generator); - coord.y() += distribution(generator); - coord.z() += distribution(generator); - return coord; - } + //! Constructor calls read_detectormap_from_file( filename ). + DetectorCoordinateMapFromFile(const std::string& filename, double sigma = 0.0) : sigma(sigma), distribution(0.0, sigma) { + read_detectormap_from_file(filename); + } + + //! Reads map from file and stores it. + void read_detectormap_from_file(const std::string& filename); + + //! Returns a cartesian coordinate given a detection position. + stir::CartesianCoordinate3D get_detector_coordinate(const stir::DetectionPosition<>& det_pos) { + auto coord = coord_map.at(det_pos); + coord.x() += distribution(generator); + coord.y() += distribution(generator); + coord.z() += distribution(generator); + return coord; + } private: - struct ihash - : std::unary_function , std::size_t> - { - std::size_t operator()(stir::DetectionPosition<> const& detpos) const - { - std::size_t seed = 0; - boost::hash_combine(seed, detpos.axial_coord()); - boost::hash_combine(seed, detpos.radial_coord()); - boost::hash_combine(seed, detpos.tangential_coord()); - return seed; - } - }; - - boost::unordered_map< stir::DetectionPosition<>, stir::CartesianCoordinate3D, ihash > coord_map; - const double sigma; - std::default_random_engine generator; - std::normal_distribution distribution; + struct ihash : std::unary_function, std::size_t> { + std::size_t operator()(stir::DetectionPosition<> const& detpos) const { + std::size_t seed = 0; + boost::hash_combine(seed, detpos.axial_coord()); + boost::hash_combine(seed, detpos.radial_coord()); + boost::hash_combine(seed, detpos.tangential_coord()); + return seed; + } + }; + + boost::unordered_map, stir::CartesianCoordinate3D, ihash> coord_map; + const double sigma; + std::default_random_engine generator; + std::normal_distribution distribution; }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/ListEvent.h b/src/include/stir/listmode/ListEvent.h index 4829b1f3f5..c0adcc3b8c 100644 --- a/src/include/stir/listmode/ListEvent.h +++ b/src/include/stir/listmode/ListEvent.h @@ -52,11 +52,10 @@ START_NAMESPACE_STIR \see ListModeData for more info on list mode data. */ -class ListEvent -{ +class ListEvent { public: virtual ~ListEvent() {} - virtual bool is_prompt() const =0;// {return helper_is_prompt();} + virtual bool is_prompt() const = 0; // {return helper_is_prompt();} //! Finds the LOR between the coordinates where the detection took place /*! Obviously, these coordinates are only estimates which depend on the @@ -70,8 +69,7 @@ class ListEvent \todo This function might need time info or so for rotating scanners. */ - virtual LORAs2Points - get_LOR() const = 0; + virtual LORAs2Points get_LOR() const = 0; //! Finds the bin coordinates of this event for some characteristics of the projection data /*! bin.get_bin_value() will be <=0 when the event corresponds to @@ -90,18 +88,14 @@ class ListEvent \todo get_bin() might need time info or so for rotating scanners. */ - virtual - void - get_bin(Bin& bin, const ProjDataInfo&) const; + virtual void get_bin(Bin& bin, const ProjDataInfo&) const; //! This method checks if the template is valid for LmToProjData /*! Used before the actual processing of the data (see issue #61), before calling get_bin() * Most scanners have listmode data that correspond to non arc-corrected data and * this check avoids a crash when an unsupported template is used as input. */ - virtual - bool - is_valid_template(const ProjDataInfo&) const =0; + virtual bool is_valid_template(const ProjDataInfo&) const = 0; }; /*-coincidence event*/ diff --git a/src/include/stir/listmode/ListGatingInput.h b/src/include/stir/listmode/ListGatingInput.h index 263d06a658..4d59bd188f 100644 --- a/src/include/stir/listmode/ListGatingInput.h +++ b/src/include/stir/listmode/ListGatingInput.h @@ -43,8 +43,7 @@ class Succeeded; If your scanner has more data available, you can provide it in the derived class. */ -class ListGatingInput -{ +class ListGatingInput { public: virtual ~ListGatingInput() {} diff --git a/src/include/stir/listmode/ListModeData.h b/src/include/stir/listmode/ListModeData.h index 75e0e20ba7..4efb7f481d 100644 --- a/src/include/stir/listmode/ListModeData.h +++ b/src/include/stir/listmode/ListModeData.h @@ -35,8 +35,10 @@ #include "stir/ExamData.h" #include "stir/RegisteredParsingObject.h" #include "stir/listmode/ListRecord.h" -# ifdef BOOST_NO_STDC_NAMESPACE -namespace std { using ::time_t; } +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::time_t; +} #endif START_NAMESPACE_STIR @@ -124,8 +126,7 @@ class ExamInfo; make sure that read_from_file recognises your data. This normally involves creating a new InputFileFormat class. */ -class ListModeData : public ExamData -{ +class ListModeData : public ExamData { public: //! typedef used by read_from_file typedef ListModeData hierarchy_base_type; @@ -136,8 +137,7 @@ class ListModeData : public ExamData //! Default constructor ListModeData(); - virtual - ~ListModeData(); + virtual ~ListModeData(); //! Returns the name of the list mode data /*! This name is not necessarily unique, and might be empty. However, it is expected @@ -148,17 +148,16 @@ class ListModeData : public ExamData The reason this cannot be guaranteed is largely in case the list mode data is not really on disk, but the object corresponds for instance to a Monte Carlo simulator. */ - virtual std::string - get_name() const = 0; - -// //! Get const pointer to exam info -// const ExamInfo* -// get_exam_info_ptr() const; -// //! Get shared pointer to exam info -// /*! \warning Use with care. If you modify the object pointer to by a shared ptr, all objects using the same -// shared pointer will be affected. */ -// shared_ptr -// get_exam_info_sptr() const; + virtual std::string get_name() const = 0; + + // //! Get const pointer to exam info + // const ExamInfo* + // get_exam_info_ptr() const; + // //! Get shared pointer to exam info + // /*! \warning Use with care. If you modify the object pointer to by a shared ptr, all objects using the same + // shared pointer will be affected. */ + // shared_ptr + // get_exam_info_sptr() const; #if 0 //! Scan start time @@ -178,17 +177,13 @@ class ListModeData : public ExamData passed to get_next_record(). */ - shared_ptr get_empty_record_sptr() const - {return this->get_empty_record_helper_sptr();} + shared_ptr get_empty_record_sptr() const { return this->get_empty_record_helper_sptr(); } //! Gets the next record in the listmode sequence - virtual - Succeeded get_next_record(ListRecord& event) const - { return get_next(event);} + virtual Succeeded get_next_record(ListRecord& event) const { return get_next(event); } //! Call this function if you want to re-start reading at the beginning. - virtual - Succeeded reset() = 0; + virtual Succeeded reset() = 0; //! Save the current reading position /*! @@ -208,38 +203,35 @@ class ListModeData : public ExamData \warning A derived class might disable this facility. It will/should then always return Succeeded::no when calling set_get_position(). */ - virtual - SavedPosition save_get_position() = 0; + virtual SavedPosition save_get_position() = 0; //! Set the position for reading to a previously saved point - virtual - Succeeded set_get_position(const SavedPosition&) = 0; + virtual Succeeded set_get_position(const SavedPosition&) = 0; //! Get scanner pointer /*! Returns a pointer to a scanner object that is appropriate for the list mode data that is being read. \warning This member is obsolete and might be removed soon. */ - virtual const Scanner* get_scanner_ptr() const ; + virtual shared_ptr get_scanner_ptr() const; //! Return if the file stores delayed events as well (as opposed to prompts) virtual bool has_delayeds() const = 0; //! Returns the total number of events in the listmode file. //! \warning This function currently works only with ROOT input files. By default //! it will throw an error. - virtual inline unsigned long int get_total_number_of_events() const - { - error("ListModeData: The function get_total_number_of_events() is currently not supported for this file format."); - return 0; + virtual inline unsigned long int get_total_number_of_events() const { + error("ListModeData: The function get_total_number_of_events() is currently not supported for this file format."); + return 0; } - virtual shared_ptr get_proj_data_info_sptr() const ; + virtual shared_ptr get_proj_data_info_sptr() const; protected: - virtual shared_ptr get_empty_record_helper_sptr() const = 0; + virtual shared_ptr get_empty_record_helper_sptr() const = 0; virtual Succeeded get_next(ListRecord& event) const = 0; - virtual void set_proj_data_info_sptr(shared_ptr) ; + virtual void set_proj_data_info_sptr(shared_ptr); //! Has to be set by the derived class // shared_ptr exam_info_sptr; //! Has to be initialised by the derived class diff --git a/src/include/stir/listmode/ListRecord.h b/src/include/stir/listmode/ListRecord.h index 78c255f63e..ece1fbef41 100644 --- a/src/include/stir/listmode/ListRecord.h +++ b/src/include/stir/listmode/ListRecord.h @@ -50,20 +50,18 @@ START_NAMESPACE_STIR \see ListModeData for more info on list mode data. */ -class ListRecord -{ +class ListRecord { public: - - virtual ~ListRecord(){} + virtual ~ListRecord() {} virtual bool is_time() const = 0; virtual bool is_event() const = 0; - virtual ListEvent& event() = 0; - virtual const ListEvent& event() const = 0; - virtual ListTime& time() = 0; - virtual const ListTime& time() const = 0; + virtual ListEvent& event() = 0; + virtual const ListEvent& event() const = 0; + virtual ListTime& time() = 0; + virtual const ListTime& time() const = 0; }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/ListRecordWithGatingInput.h b/src/include/stir/listmode/ListRecordWithGatingInput.h index e048c0c40a..7ad1838871 100644 --- a/src/include/stir/listmode/ListRecordWithGatingInput.h +++ b/src/include/stir/listmode/ListRecordWithGatingInput.h @@ -38,12 +38,11 @@ START_NAMESPACE_STIR -class ListRecordWithGatingInput : public virtual ListRecord -{ - public: +class ListRecordWithGatingInput : public virtual ListRecord { +public: virtual bool is_gating_input() const { return false; } - virtual ListGatingInput& gating_input() = 0; - virtual const ListGatingInput& gating_input() const = 0; + virtual ListGatingInput& gating_input() = 0; + virtual const ListGatingInput& gating_input() const = 0; }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/ListTime.h b/src/include/stir/listmode/ListTime.h index 1803dbb1fb..0f663063a3 100644 --- a/src/include/stir/listmode/ListTime.h +++ b/src/include/stir/listmode/ListTime.h @@ -37,7 +37,7 @@ #include "stir/round.h" START_NAMESPACE_STIR -//class Succeeded; +// class Succeeded; //! A class for storing and using a timing record from a listmode file /*! \ingroup listmode @@ -51,23 +51,19 @@ START_NAMESPACE_STIR (and actual?) number of gates would be useful. \see ListModeData for more info on list mode data. */ -class ListTime -{ +class ListTime { public: virtual ~ListTime() {} virtual unsigned long get_time_in_millisecs() const = 0; - inline double get_time_in_secs() const - { return get_time_in_millisecs()/1000.; } + inline double get_time_in_secs() const { return get_time_in_millisecs() / 1000.; } virtual Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) = 0; - inline Succeeded set_time_in_secs(const double time_in_secs) - { - unsigned long time_in_millisecs; - round_to(time_in_millisecs, time_in_secs/1000.); - return set_time_in_millisecs(time_in_millisecs); - } - + inline Succeeded set_time_in_secs(const double time_in_secs) { + unsigned long time_in_millisecs; + round_to(time_in_millisecs, time_in_secs / 1000.); + return set_time_in_millisecs(time_in_millisecs); + } }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/LmToProjData.h b/src/include/stir/listmode/LmToProjData.h index 7f2cc7bfdd..a4ffd68770 100644 --- a/src/include/stir/listmode/LmToProjData.h +++ b/src/include/stir/listmode/LmToProjData.h @@ -3,18 +3,20 @@ // // /*! - \file + \file \ingroup listmode \brief Declaration of the stir::LmToProjData class which is used to bin listmode data to (3d) sinograms - + + \author Nikos Efthimiou \author Kris Thielemans \author Sanida Mustafovic \author Daniel Deidda - + */ /* Copyright (C) 2000- 2009, Hammersmith Imanet Ltd + Copyright (C) 2017, University of Hull Copyright (C) 2019, National Physical Laboratory Copyright (C) 2019, University College of London This file is part of STIR. @@ -32,7 +34,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/listmode/LmToProjDataAbstract.h" #include "stir/ProjDataInfo.h" #include "stir/listmode/ListModeData.h" @@ -53,7 +54,7 @@ class ListTime; i.e. (3d) sinograms. It provides the basic machinery to go through a list mode data file, - and write projection data for each time frame. + and write projection data for each time frame. The class can parse its parameters from an input file. This has the following format: @@ -67,9 +68,9 @@ class ListTime; ; parameters that determine the sizes etc of the output template_projdata := some_projdata_file - ; the next can be used to use a smaller number of segments than given + ; the next can be used to use a smaller number of segments than given ; in the template - maximum absolute segment number to process := + maximum absolute segment number to process := ; parameters for saying which events will be stored @@ -94,7 +95,7 @@ class ListTime; ; default settings mean no normalisation ; Use with care! - ; in pre normalisation, each event will contribute its + ; in pre normalisation, each event will contribute its ; 'normalisation factor' to the bin ; in post normalisation, an average factor for the bin will be used do pre normalisation := 0 ; default is 0 @@ -112,10 +113,11 @@ class ListTime; ; if you're short of RAM (i.e. a single projdata does not fit into memory), ; you can use this to process the list mode data in multiple passes. num_segments_in_memory := -1 - - End := + ; same for TOF bins + num_TOF_bins_in_memory := 1 + End := \endverbatim - + Hopefully the only thing that needs explaining are the parameters related to prompts and delayeds. These are used to allow different ways of processing the data. There are really only 3 useful cases: @@ -124,22 +126,22 @@ class ListTime;
    • 'online' subtraction of delayeds
      This is the default, and adds prompts but subtracts delayeds. \code - store prompts := 1 + store prompts := 1 store delayeds := 1 \endcode
    • store prompts only
      - Use + Use \code - store prompts := 1 + store prompts := 1 store delayeds := 0 \endcode
    • store delayeds only
      - Use + Use \code - store prompts := 0 + store prompts := 0 store delayeds := 1 \endcode Note that now the delayted events will be added, @@ -158,31 +160,35 @@ class ListTime; to do it here. \todo Timing info or so for get_bin_from_event() for rotating scanners etc. \todo There is overlap between the normalisation and the current treatment - of bin.get_bin_value(). This is really because we should be using + of bin.get_bin_value(). This is really because we should be using something like a EventNormalisation class for pre-normalisation. \see ListModeData for more info on list mode data. */ -class LmToProjData : public LmToProjDataAbstract -{ +class LmToProjData : public LmToProjDataAbstract { public: - //! Constructor taking a filename for a parameter file /*! Will attempt to open and parse the file. */ - LmToProjData(const char * const par_filename); + LmToProjData(const char* const par_filename); //! Default constructor /*! \warning leaves parameters ill-defined. Set them by parsing. */ LmToProjData(); //! This function does the actual work + //! N.E: In order to keep the ToF functions separate from the non-TOF + //! STIR this function just call the appropriate actual_process_data_with(out)_tof(). virtual void process_data(); - -protected: - + //! A test function for time-of-flight data. At this moment we lack a lot of infrastructure in + //! order to be able to develope a viable test function of class anywhere else. At a future point + //! I should develope a proper test function. This function is going to fill the proj_data with + //! the index number of the respective TOF position, for every TOF position. + void run_tof_test_function(); + +protected: //! will be called when a new time frame starts /*! The frame numbers start from 1. */ virtual void start_new_time_frame(const unsigned int new_frame_num); @@ -192,8 +198,8 @@ class LmToProjData : public LmToProjDataAbstract //! will be called to get the bin for a coincidence event /*! If bin.get_bin_value()<=0, the event will be ignored. Otherwise, - the value will be used as a bin-normalisation factor - (on top of anything done by normalisation_ptr). + the value will be used as a bin-normalisation factor + (on top of anything done by normalisation_ptr). \todo Would need timing info or so for e.g. time dependent normalisation or angle info for a rotating scanner.*/ virtual void get_bin_from_event(Bin& bin, const ListEvent&) const; @@ -203,10 +209,10 @@ class LmToProjData : public LmToProjDataAbstract (more ProjDataInfo?) */ int get_compression_count(const Bin& bin) const; - + //! Computes a post-normalisation factor (if any) for this bin /*! This uses get_compression_count() when do_pre_normalisation=true, or - post_normalisation_ptr otherwise. + post_normalisation_ptr otherwise. */ void do_post_normalisation(Bin& bin) const; @@ -228,7 +234,9 @@ class LmToProjData : public LmToProjDataAbstract bool do_pre_normalisation; bool store_prompts; bool store_delayeds; + int num_segments_in_memory; + int num_timing_poss_in_memory; long int num_events_to_store; int max_segment_num_to_process; @@ -260,14 +268,12 @@ class LmToProjData : public LmToProjDataAbstract /*! Will be removed when we have EventNormalisation (or similar) hierarchy */ shared_ptr proj_data_info_cyl_uncompressed_ptr; - - /*! \brief variable that will be set according to if we are using + /*! \brief variable that will be set according to if we are using time frames or num_events_to_store */ bool do_time_frame; //! A variable that will be set to 1,0 or -1, according to store_prompts and store_delayeds int delayed_increment; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/LmToProjDataAbstract.h b/src/include/stir/listmode/LmToProjDataAbstract.h index a5407e60d3..9309ae224d 100644 --- a/src/include/stir/listmode/LmToProjDataAbstract.h +++ b/src/include/stir/listmode/LmToProjDataAbstract.h @@ -2,13 +2,13 @@ // // /*! - \file + \file \ingroup listmode \brief Abstract base class for listmode to projection data conversion. - + \author Richard Brown - + */ /* Copyright (C) 2020, University College of London @@ -40,21 +40,19 @@ START_NAMESPACE_STIR i.e. (3d) sinograms. It provides the basic machinery to go through a list mode data file, - and write projection data for each time frame. + and write projection data for each time frame. */ -class LmToProjDataAbstract : public ParsingObject -{ +class LmToProjDataAbstract : public ParsingObject { public: + /// Destructor + virtual ~LmToProjDataAbstract() {} - /// Destructor - virtual ~LmToProjDataAbstract() {} - - /// Set up - virtual Succeeded set_up() { return Succeeded::yes; } + /// Set up + virtual Succeeded set_up() { return Succeeded::yes; } - //! This function does the actual work - virtual void process_data() = 0; + //! This function does the actual work + virtual void process_data() = 0; }; END_NAMESPACE_STIR \ No newline at end of file diff --git a/src/include/stir/listmode/LmToProjDataBootstrap.h b/src/include/stir/listmode/LmToProjDataBootstrap.h index eb21dd054c..7c89271d39 100644 --- a/src/include/stir/listmode/LmToProjDataBootstrap.h +++ b/src/include/stir/listmode/LmToProjDataBootstrap.h @@ -5,10 +5,10 @@ \file \ingroup listmode \brief Class for binning list mode files with the bootstrap method - + \author Kris Thielemans \author Daniel Deidda - + */ /* Copyright (C) 2003- 2011, Hammersmith Imanet @@ -32,20 +32,19 @@ #ifndef __stir_listmode_LmToProjDataBootstrap_H__ #define __stir_listmode_LmToProjDataBootstrap_H__ - #include "stir/listmode/LmToProjData.h" #include START_NAMESPACE_STIR /*! \ingroup listmode - \brief Class for binning list mode data into projection data using the + \brief Class for binning list mode data into projection data using the bootstrap procedure. The bootstrap method allows estimating the variance of an estimator based on a single data-set (magic!). This class can be used to generate multiple equivalent projdata, which can then be reconstructed. - The sample variance computed on these images will be an estimate of + The sample variance computed on these images will be an estimate of the variance on the reconstructions. For list mode data, bootstrapping works by selecting random events @@ -73,17 +72,15 @@ START_NAMESPACE_STIR bootstrapping mechanism does not depend on how LmToProjData actually works. */ -template< typename LmToProjDataT> -class LmToProjDataBootstrap : public LmToProjDataT -{ +template +class LmToProjDataBootstrap : public LmToProjDataT { public: - //! Constructor that parses from a file - LmToProjDataBootstrap(const char * const par_filename); + LmToProjDataBootstrap(const char* const par_filename); //! Constructor that parses from a file but with explicit seed /*! The \a seed argument will override any value found in the par file */ - LmToProjDataBootstrap(const char * const par_filename, const unsigned int seed); + LmToProjDataBootstrap(const char* const par_filename, const unsigned int seed); protected: //! will be called when a new time frame starts @@ -92,7 +89,6 @@ class LmToProjDataBootstrap : public LmToProjDataT virtual void get_bin_from_event(Bin& bin, const ListEvent&) const; - // \name parsing variables //@{ //! used to seed the pseudo-random number generator @@ -104,17 +100,13 @@ class LmToProjDataBootstrap : public LmToProjDataT typedef LmToProjDataT base_type; typedef std::vector replication_type; - replication_type num_times_to_replicate; mutable replication_type::const_iterator num_times_to_replicate_iter; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - - }; END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/listmode/LmToProjDataWithRandomRejection.h b/src/include/stir/listmode/LmToProjDataWithRandomRejection.h index fe20a5b664..5e0d6da07f 100644 --- a/src/include/stir/listmode/LmToProjDataWithRandomRejection.h +++ b/src/include/stir/listmode/LmToProjDataWithRandomRejection.h @@ -5,7 +5,7 @@ \file \ingroup listmode \brief Class for binning list mode files with the bootstrap method - + \author Kris Thielemans\author Daniel Deidda */ @@ -31,7 +31,6 @@ #ifndef __stir_listmode_LmToProjDataWithRandomRejection_H__ #define __stir_listmode_LmToProjDataWithRandomRejection_H__ - #include "stir/listmode/LmToProjData.h" #include #include @@ -39,13 +38,13 @@ START_NAMESPACE_STIR /*! \ingroup listmode - \brief Class for binning list mode data into projection data using the + \brief Class for binning list mode data into projection data using the bootstrap procedure. The bootstrap method allows estimating the variance of an estimator based on a single data-set (magic!). This class can be used to generate multiple equivalent projdata, which can then be reconstructed. - The sample variance computed on these images will be an estimate of + The sample variance computed on these images will be an estimate of the variance on the reconstructions. For list mode data, bootstrapping works by selecting random events @@ -73,19 +72,17 @@ START_NAMESPACE_STIR bootstrapping mechanism does not depend on how LmToProjData actually works. */ -template< typename LmToProjDataT> -class LmToProjDataWithRandomRejection : public LmToProjDataT -{ +template +class LmToProjDataWithRandomRejection : public LmToProjDataT { public: - //! Constructor that parses from a file - LmToProjDataWithRandomRejection(const char * const par_filename); + LmToProjDataWithRandomRejection(const char* const par_filename); //! Constructor that parses from a file but with explicit seed /*! The \a seed argument will override any value found in the par file */ - LmToProjDataWithRandomRejection(const char * const par_filename, const unsigned int seed); + LmToProjDataWithRandomRejection(const char* const par_filename, const unsigned int seed); - //void set_seed(const unsigned int seed); + // void set_seed(const unsigned int seed); float set_reject_if_above(const float); protected: @@ -95,7 +92,6 @@ class LmToProjDataWithRandomRejection : public LmToProjDataT virtual void get_bin_from_event(Bin& bin, const ListEvent&) const; - // \name parsing variables //@{ //! used to seed the pseudo-random number generator @@ -107,17 +103,13 @@ class LmToProjDataWithRandomRejection : public LmToProjDataT private: typedef LmToProjDataT base_type; typedef boost::mt19937 random_generator_type; - random_generator_type random_generator; - + random_generator_type random_generator; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - - }; END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/listmode/NiftyPET_listmode/LmToProjDataNiftyPET.h b/src/include/stir/listmode/NiftyPET_listmode/LmToProjDataNiftyPET.h index 06f42b5210..874ce9c5a1 100644 --- a/src/include/stir/listmode/NiftyPET_listmode/LmToProjDataNiftyPET.h +++ b/src/include/stir/listmode/NiftyPET_listmode/LmToProjDataNiftyPET.h @@ -2,11 +2,11 @@ // // /*! - \file + \file \ingroup listmode \brief Wrapper to NiftyPET's listmode to projection data converter - + \author Richard Brown \todo NiftyPET limitations - currently limited @@ -18,7 +18,7 @@ wrapper has only been tested for span-11. DOI - https://doi.org/10.1007/s12021-017-9352-y - + */ /* Copyright (C) 2020, University College of London @@ -50,82 +50,68 @@ START_NAMESPACE_STIR class ProjData; -class LmToProjDataNiftyPET : public LmToProjDataAbstract -{ +class LmToProjDataNiftyPET : public LmToProjDataAbstract { public: + /// Constructor + LmToProjDataNiftyPET(); - /// Constructor - LmToProjDataNiftyPET(); + /// Destructor + virtual ~LmToProjDataNiftyPET() {} - /// Destructor - virtual ~LmToProjDataNiftyPET() {} + /// Set span + void set_span(const int span) { _span = span; } - /// Set span - void set_span(const int span) - { _span = span; } + /// Set CUDA device + void set_cuda_device(const char cuda_device) { _cuda_device = cuda_device; } - /// Set CUDA device - void set_cuda_device(const char cuda_device) - { _cuda_device = cuda_device; } + /// Set CUDA verbosity + void set_cuda_verbosity(const bool cuda_verbosity) { _cuda_verbosity = cuda_verbosity; } - /// Set CUDA verbosity - void set_cuda_verbosity(const bool cuda_verbosity) - { _cuda_verbosity = cuda_verbosity; } + /// Set start time + void set_start_time(const int start_time) { _start_time = start_time; } - /// Set start time - void set_start_time(const int start_time) - { _start_time = start_time; } + /// Set stop time + void set_stop_time(const int stop_time) { _stop_time = stop_time; } - /// Set stop time - void set_stop_time(const int stop_time) - { _stop_time = stop_time; } + /// Set listmode binary file + void set_listmode_binary_file(const std::string& listmode_binary_file) { _listmode_binary_file = listmode_binary_file; } - /// Set listmode binary file - void set_listmode_binary_file(const std::string &listmode_binary_file) - { _listmode_binary_file = listmode_binary_file; } + /// Set norm binary file + void set_norm_binary_file(const std::string& norm_binary_file) { _norm_binary_file = norm_binary_file; } - /// Set norm binary file - void set_norm_binary_file(const std::string &norm_binary_file) - { _norm_binary_file = norm_binary_file; } + /// This function does the actual work + virtual void process_data(); - /// This function does the actual work - virtual void process_data(); + /// Get prompts + shared_ptr get_prompts_sptr() const { return _prompts_sptr; } - /// Get prompts - shared_ptr get_prompts_sptr() const - { return _prompts_sptr; } + /// Get delayeds + shared_ptr get_delayeds_sptr() const { return _delayeds_sptr; } - /// Get delayeds - shared_ptr get_delayeds_sptr() const - { return _delayeds_sptr; } + /// Get randoms + shared_ptr get_randoms_sptr() const { return _randoms_sptr; } - /// Get randoms - shared_ptr get_randoms_sptr() const - { return _randoms_sptr; } - - /// Get norm - shared_ptr get_norm_sptr() const - { - if (_norm_binary_file.empty()) - error("Set norm binary filename before extracting listmode."); - return _norm_sptr; - } + /// Get norm + shared_ptr get_norm_sptr() const { + if (_norm_binary_file.empty()) + error("Set norm binary filename before extracting listmode."); + return _norm_sptr; + } private: - - /// Check input values are as expected - void check_input() const; - - int _span; - char _cuda_device; - bool _cuda_verbosity; - int _start_time, _stop_time; - std::string _listmode_binary_file; - std::string _norm_binary_file; - shared_ptr _prompts_sptr; - shared_ptr _delayeds_sptr; - shared_ptr _randoms_sptr; - shared_ptr _norm_sptr; + /// Check input values are as expected + void check_input() const; + + int _span; + char _cuda_device; + bool _cuda_verbosity; + int _start_time, _stop_time; + std::string _listmode_binary_file; + std::string _norm_binary_file; + shared_ptr _prompts_sptr; + shared_ptr _delayeds_sptr; + shared_ptr _randoms_sptr; + shared_ptr _norm_sptr; }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/SPECTListEvent.h b/src/include/stir/listmode/SPECTListEvent.h index ca90a4c29d..dcdb15c207 100644 --- a/src/include/stir/listmode/SPECTListEvent.h +++ b/src/include/stir/listmode/SPECTListEvent.h @@ -52,12 +52,9 @@ START_NAMESPACE_STIR \see SPECTListModeData for more info on list mode data. */ -class SPECTListEvent: public ListEvent -{ +class SPECTListEvent : public ListEvent { public: - virtual - bool - is_prompt() const {return true;} + virtual bool is_prompt() const { return true; } }; /*-gamma event*/ diff --git a/src/include/stir/listmode/SPECTListModeData.h b/src/include/stir/listmode/SPECTListModeData.h index 76d8da6e3a..c969b87444 100644 --- a/src/include/stir/listmode/SPECTListModeData.h +++ b/src/include/stir/listmode/SPECTListModeData.h @@ -30,8 +30,10 @@ #include "stir/listmode/ListModeData.h" #include "stir/listmode/SPECTListRecord.h" -# ifdef BOOST_NO_STDC_NAMESPACE -namespace std { using ::time_t; } +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::time_t; +} #endif START_NAMESPACE_STIR @@ -49,34 +51,28 @@ class ExamInfo; SPECT is handled by calling all single photon events 'prompts'. */ -class SPECTListModeData : virtual public ListModeData -{ +class SPECTListModeData : virtual public ListModeData { public: - //! Get a pointer to an empty record /*! This is mainly/only useful to get a record of the correct type, that can then be passed to get_next_record(). */ - virtual - shared_ptr get_empty_record_sptr() const = 0; + virtual shared_ptr get_empty_record_sptr() const = 0; //! Gets the next record in the listmode sequence - virtual - Succeeded get_next_record(SPECTListRecord& event) const = 0; + virtual Succeeded get_next_record(SPECTListRecord& event) const = 0; //! Return if the file stores delayed events as well (as opposed to prompts) - virtual bool has_delayeds() const {return false;} + virtual bool has_delayeds() const { return false; } protected: + virtual shared_ptr get_empty_record_helper_sptr() const { + shared_ptr sptr(this->get_empty_record_sptr()); + shared_ptr sptr1(static_pointer_cast(sptr)); + return sptr1; + } - virtual shared_ptr get_empty_record_helper_sptr() const - { - shared_ptr sptr(this->get_empty_record_sptr()); - shared_ptr sptr1(static_pointer_cast(sptr)); - return sptr1;} - - virtual Succeeded get_next(ListRecord& event) const - {return this->get_next_record(reinterpret_cast(event));} + virtual Succeeded get_next(ListRecord& event) const { return this->get_next_record(reinterpret_cast(event)); } }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/SPECTListRecord.h b/src/include/stir/listmode/SPECTListRecord.h index 0e8c4182e9..4752d71c1f 100644 --- a/src/include/stir/listmode/SPECTListRecord.h +++ b/src/include/stir/listmode/SPECTListRecord.h @@ -31,7 +31,6 @@ #ifndef __stir_listmode_SPECTListRecord_H__ #define __stir_listmode_SPECTListRecord_H__ - #include "stir/listmode/ListTime.h" #include "ListRecord.h" #include "stir/listmode/SPECTListEvent.h" @@ -50,23 +49,21 @@ START_NAMESPACE_STIR \see SPECTListModeData for more info on list mode data. */ -class SPECTListRecord : public ListRecord -{ +class SPECTListRecord : public ListRecord { public: -// virtual ~SPECTListRecord() {} + // virtual ~SPECTListRecord() {} virtual bool is_time() const = 0; virtual bool is_event() const = 0; - virtual SPECTListEvent& event() = 0; - virtual const SPECTListEvent& event() const = 0; - virtual ListTime& time() = 0; - virtual const ListTime& time() const = 0; + virtual SPECTListEvent& event() = 0; + virtual const SPECTListEvent& event() const = 0; + virtual ListTime& time() = 0; + virtual const ListTime& time() const = 0; virtual bool operator==(const SPECTListRecord& e2) const = 0; bool operator!=(const SPECTListRecord& e2) const { return !(*this == e2); } - }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/SPECTListRecordWithGatingInput.h b/src/include/stir/listmode/SPECTListRecordWithGatingInput.h index 40675c1f04..67fb9920ea 100644 --- a/src/include/stir/listmode/SPECTListRecordWithGatingInput.h +++ b/src/include/stir/listmode/SPECTListRecordWithGatingInput.h @@ -37,12 +37,11 @@ START_NAMESPACE_STIR -class SPECTListRecordWithGatingInput : public virtual SPECTListRecord -{ - public: +class SPECTListRecordWithGatingInput : public virtual SPECTListRecord { +public: virtual bool is_gating_input() const { return false; } - virtual ListGatingInput& gating_input() = 0; - virtual const ListGatingInput& gating_input() const = 0; + virtual ListGatingInput& gating_input() = 0; + virtual const ListGatingInput& gating_input() const = 0; }; END_NAMESPACE_STIR diff --git a/src/include/stir/make_array.h b/src/include/stir/make_array.h index a6b5a60063..5999bef953 100644 --- a/src/include/stir/make_array.h +++ b/src/include/stir/make_array.h @@ -21,9 +21,9 @@ /*! \file \ingroup Array - + \brief Declaration of functions for constructing arrays stir::make_1d_array etc - + \author Kris Thielemans */ @@ -31,178 +31,120 @@ START_NAMESPACE_STIR - template -inline -VectorWithOffset -make_vector(const T& a0); +inline VectorWithOffset make_vector(const T& a0); template -inline -VectorWithOffset -make_vector(const T& a0, const T& a1); +inline VectorWithOffset make_vector(const T& a0, const T& a1); template -inline -VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2); +inline VectorWithOffset make_vector(const T& a0, const T& a1, const T& a2); template -inline -VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3); +inline VectorWithOffset make_vector(const T& a0, const T& a1, const T& a2, const T& a3); template -inline -VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4); +inline VectorWithOffset make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4); template -inline -VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5); +inline VectorWithOffset make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5); template -inline -VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6); +inline VectorWithOffset make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6); template -inline -VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7); - +inline VectorWithOffset make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, + const T& a7); template -inline -VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7, const T& a8); +inline VectorWithOffset make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, + const T& a7, const T& a8); template -inline -VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7, const T& a8, const T& a9); - +inline VectorWithOffset make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, + const T& a7, const T& a8, const T& a9); template -inline -Array<1,T> -make_1d_array(const T& a0); +inline Array<1, T> make_1d_array(const T& a0); template -inline -Array<1,T> -make_1d_array(const T& a0, const T& a1); +inline Array<1, T> make_1d_array(const T& a0, const T& a1); template -inline -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2); +inline Array<1, T> make_1d_array(const T& a0, const T& a1, const T& a2); template -inline -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3); +inline Array<1, T> make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3); template -inline -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4); +inline Array<1, T> make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4); template -inline -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5); +inline Array<1, T> make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5); template -inline -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6); +inline Array<1, T> make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6); template -inline -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7); - +inline Array<1, T> make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, + const T& a7); template -inline -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7, const T& a8); +inline Array<1, T> make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, + const T& a7, const T& a8); template -inline -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7, const T& a8, const T& a9); - - +inline Array<1, T> make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, + const T& a7, const T& a8, const T& a9); template -inline -Array -make_array(const Array& a0); +inline Array make_array(const Array& a0); template -inline -Array -make_array(const Array& a0, const Array& a1); +inline Array make_array(const Array& a0, const Array& a1); template -inline -Array -make_array(const Array& a0, const Array& a1, const Array& a2); +inline Array make_array(const Array& a0, const Array& a1, + const Array& a2); template -inline -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3); +inline Array make_array(const Array& a0, const Array& a1, + const Array& a2, const Array& a3); template -inline -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4); +inline Array make_array(const Array& a0, const Array& a1, + const Array& a2, const Array& a3, + const Array& a4); template -inline -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4, - Array& a5); +inline Array make_array(const Array& a0, const Array& a1, + const Array& a2, const Array& a3, + const Array& a4, Array& a5); template -inline -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4, - Array& a5, const Array& a6); +inline Array make_array(const Array& a0, const Array& a1, + const Array& a2, const Array& a3, + const Array& a4, Array& a5, + const Array& a6); template -inline -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4, - Array& a5, const Array& a6, const Array& a7); - +inline Array make_array(const Array& a0, const Array& a1, + const Array& a2, const Array& a3, + const Array& a4, Array& a5, + const Array& a6, const Array& a7); template -inline -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4, - Array& a5, const Array& a6, const Array& a7, const Array& a8); +inline Array +make_array(const Array& a0, const Array& a1, const Array& a2, + const Array& a3, const Array& a4, Array& a5, + const Array& a6, const Array& a7, const Array& a8); template -inline -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4, - Array& a5, const Array& a6, const Array& a7, const Array& a8, const Array& a9); - +inline Array make_array(const Array& a0, const Array& a1, + const Array& a2, const Array& a3, + const Array& a4, Array& a5, + const Array& a6, const Array& a7, + const Array& a8, const Array& a9); END_NAMESPACE_STIR diff --git a/src/include/stir/make_array.inl b/src/include/stir/make_array.inl index 35acae0213..96b5ad4c19 100644 --- a/src/include/stir/make_array.inl +++ b/src/include/stir/make_array.inl @@ -19,9 +19,9 @@ /*! \file \ingroup Array - + \brief Implementation of functions for constructing arrays stir::make_1d_array etc - + \author Kris Thielemans */ @@ -30,309 +30,287 @@ START_NAMESPACE_STIR template VectorWithOffset -make_vector(const T& a0) -{ +make_vector(const T& a0) { VectorWithOffset a(1); - a[0]=a0; + a[0] = a0; return a; } template VectorWithOffset -make_vector(const T& a0, const T& a1) -{ +make_vector(const T& a0, const T& a1) { VectorWithOffset a(2); - a[0]=a0; a[1]=a1; + a[0] = a0; + a[1] = a1; return a; } template VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2) -{ +make_vector(const T& a0, const T& a1, const T& a2) { VectorWithOffset a(3); - a[0]=a0; a[1]=a1; a[2]=a2; + a[0] = a0; + a[1] = a1; + a[2] = a2; return a; } template VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3) -{ +make_vector(const T& a0, const T& a1, const T& a2, const T& a3) { VectorWithOffset a(4); - a[0]=a0; a[1]=a1; a[2]=a2; a[3]=a3; + a[0] = a0; + a[1] = a1; + a[2] = a2; + a[3] = a3; return a; } template VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) -{ +make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) { VectorWithOffset a(5); - a[0]=a0; a[1]=a1; a[2]=a2; a[3]=a3; a[4]=a4; + a[0] = a0; + a[1] = a1; + a[2] = a2; + a[3] = a3; + a[4] = a4; return a; } template VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5) -{ +make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) { VectorWithOffset a(6); - a[0]=a0; a[1]=a1; a[2]=a2; a[3]=a3; a[4]=a4; a[5]=a5; + a[0] = a0; + a[1] = a1; + a[2] = a2; + a[3] = a3; + a[4] = a4; + a[5] = a5; return a; } template VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6) -{ +make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) { VectorWithOffset a(7); - a[0]=a0; a[1]=a1; a[2]=a2; a[3]=a3; a[4]=a4; a[5]=a5; a[6]=a6; + a[0] = a0; + a[1] = a1; + a[2] = a2; + a[3] = a3; + a[4] = a4; + a[5] = a5; + a[6] = a6; return a; } template VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7) -{ +make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7) { VectorWithOffset a(8); - a[0]=a0; a[1]=a1; a[2]=a2; a[3]=a3; a[4]=a4; a[5]=a5; a[6]=a6; a[7]=a7; + a[0] = a0; + a[1] = a1; + a[2] = a2; + a[3] = a3; + a[4] = a4; + a[5] = a5; + a[6] = a6; + a[7] = a7; return a; } - template VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7, const T& a8) -{ +make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8) { VectorWithOffset a(9); - a[0]=a0; a[1]=a1; a[2]=a2; a[3]=a3; a[4]=a4; - a[5]=a5; a[6]=a6; a[7]=a7; a[8]=a8; + a[0] = a0; + a[1] = a1; + a[2] = a2; + a[3] = a3; + a[4] = a4; + a[5] = a5; + a[6] = a6; + a[7] = a7; + a[8] = a8; return a; } template VectorWithOffset -make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7, const T& a8, const T& a9) -{ +make_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, + const T& a9) { VectorWithOffset a(10); - a[0]=a0; a[1]=a1; a[2]=a2; a[3]=a3; a[4]=a4; - a[5]=a5; a[6]=a6; a[7]=a7; a[8]=a8; a[9]=a9; + a[0] = a0; + a[1] = a1; + a[2] = a2; + a[3] = a3; + a[4] = a4; + a[5] = a5; + a[6] = a6; + a[7] = a7; + a[8] = a8; + a[9] = a9; return a; } - template -Array<1,T> -make_1d_array(const T& a0) -{ - const Array<1,T> a = NumericVectorWithOffset(make_vector(a0)); +Array<1, T> +make_1d_array(const T& a0) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0)); return a; } template -Array<1,T> -make_1d_array(const T& a0, const T& a1) -{ - const Array<1,T> a = NumericVectorWithOffset(make_vector(a0, a1)); +Array<1, T> +make_1d_array(const T& a0, const T& a1) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1)); return a; } - template -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2) -{ - const Array<1,T> a = NumericVectorWithOffset(make_vector(a0, a1, a2)); +Array<1, T> +make_1d_array(const T& a0, const T& a1, const T& a2) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1, a2)); return a; } - template -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3) -{ - const Array<1,T> a = NumericVectorWithOffset(make_vector(a0, a1, a2, a3)); +Array<1, T> +make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1, a2, a3)); return a; } template -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) -{ - const Array<1,T> a = - NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4)); +Array<1, T> +make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4)); return a; } - template -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5) -{ - const Array<1,T> a = - NumericVectorWithOffset (make_vector(a0, a1, a2, a3, a4, a5)); +Array<1, T> +make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4, a5)); return a; } - template -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6) -{ - const Array<1,T> a = - NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4, - a5, a6)); +Array<1, T> +make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4, a5, a6)); return a; } - template -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7) -{ - const Array<1,T> a = - NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4, - a5, a6, a7)); +Array<1, T> +make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4, a5, a6, a7)); return a; } - - template -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7, const T& a8) -{ - const Array<1,T> a = - NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4, - a5, a6, a7, a8)); +Array<1, T> +make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, + const T& a8) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4, a5, a6, a7, a8)); return a; } - template -Array<1,T> -make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7, const T& a8, const T& a9) -{ - const Array<1,T> a = - NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4, - a5, a6, a7, a8, a9)); +Array<1, T> +make_1d_array(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, + const T& a9) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); return a; } - template -Array -make_array(const Array& a0) -{ - const Array<1,T> a = NumericVectorWithOffset(make_vector(a0)); +Array +make_array(const Array& a0) { + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0)); return a; } template -Array -make_array(const Array& a0, const Array& a1) -{ - const Array a = NumericVectorWithOffset,T>(make_vector(a0, a1)); +Array +make_array(const Array& a0, const Array& a1) { + const Array a = NumericVectorWithOffset, T>(make_vector(a0, a1)); return a; } - template -Array -make_array(const Array& a0, const Array& a1, const Array& a2) -{ - const Array a = NumericVectorWithOffset,T>(make_vector(a0, a1, a2)); +Array +make_array(const Array& a0, const Array& a1, const Array& a2) { + const Array a = NumericVectorWithOffset, T>(make_vector(a0, a1, a2)); return a; } - template -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3) -{ - const Array a = NumericVectorWithOffset,T>(make_vector(a0, a1, a2, a3)); +Array +make_array(const Array& a0, const Array& a1, const Array& a2, + const Array& a3) { + const Array a = NumericVectorWithOffset, T>(make_vector(a0, a1, a2, a3)); return a; } template -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4) -{ - const Array a = - NumericVectorWithOffset,T>(make_vector(a0, a1, a2, a3, a4)); +Array +make_array(const Array& a0, const Array& a1, const Array& a2, + const Array& a3, const Array& a4) { + const Array a = NumericVectorWithOffset, T>(make_vector(a0, a1, a2, a3, a4)); return a; } - template -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4, - Array& a5) -{ - const Array a = - NumericVectorWithOffset,T> (make_vector(a0, a1, a2, a3, a4, a5)); +Array +make_array(const Array& a0, const Array& a1, const Array& a2, + const Array& a3, const Array& a4, Array& a5) { + const Array a = + NumericVectorWithOffset, T>(make_vector(a0, a1, a2, a3, a4, a5)); return a; } - template -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4, - Array& a5, const Array& a6) -{ - const Array a = - NumericVectorWithOffset,T>(make_vector(a0, a1, a2, a3, a4, - a5, a6)); +Array +make_array(const Array& a0, const Array& a1, const Array& a2, + const Array& a3, const Array& a4, Array& a5, + const Array& a6) { + const Array a = + NumericVectorWithOffset, T>(make_vector(a0, a1, a2, a3, a4, a5, a6)); return a; } - template -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4, - Array& a5, const Array& a6, const Array& a7) -{ - const Array a = - NumericVectorWithOffset,T>(make_vector(a0, a1, a2, a3, a4, - a5, a6, a7)); +Array +make_array(const Array& a0, const Array& a1, const Array& a2, + const Array& a3, const Array& a4, Array& a5, + const Array& a6, const Array& a7) { + const Array a = + NumericVectorWithOffset, T>(make_vector(a0, a1, a2, a3, a4, a5, a6, a7)); return a; } - - template -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4, - Array& a5, const Array& a6, const Array& a7, const Array& a8) -{ - const Array a = - NumericVectorWithOffset,T>(make_vector(a0, a1, a2, a3, a4, - a5, a6, a7, a8)); +Array +make_array(const Array& a0, const Array& a1, const Array& a2, + const Array& a3, const Array& a4, Array& a5, + const Array& a6, const Array& a7, const Array& a8) { + const Array a = + NumericVectorWithOffset, T>(make_vector(a0, a1, a2, a3, a4, a5, a6, a7, a8)); return a; } - template -Array -make_array(const Array& a0, const Array& a1, const Array& a2, const Array& a3, const Array& a4, - Array& a5, const Array& a6, const Array& a7, const Array& a8, const Array& a9) -{ - const Array a = - NumericVectorWithOffset,T>(make_vector(a0, a1, a2, a3, a4, - a5, a6, a7, a8, a9)); +Array +make_array(const Array& a0, const Array& a1, const Array& a2, + const Array& a3, const Array& a4, Array& a5, + const Array& a6, const Array& a7, const Array& a8, + const Array& a9) { + const Array a = + NumericVectorWithOffset, T>(make_vector(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); return a; } - END_NAMESPACE_STIR diff --git a/src/include/stir/min_positive_element.h b/src/include/stir/min_positive_element.h index 1cdbfc8ef7..a3d03b50e0 100644 --- a/src/include/stir/min_positive_element.h +++ b/src/include/stir/min_positive_element.h @@ -21,9 +21,9 @@ #define __stir_min_positive_element_h_ /*! - \file + \file \ingroup buildblock - + \brief Declares the stir::min_positive_element() function \author Kris Thielemans @@ -40,27 +40,27 @@ START_NAMESPACE_STIR \param start start of the sequence. Usually object.begin(). \param end end of the sequence in iterator sense (so actually one beyond the last element). Usually object.end(). - \return an iterator that points to the element in the sequence which + \return an iterator that points to the element in the sequence which has the smallest (strictly) positive value. If no (strictly) positive element is found, or if the sequence is empty, the \a end argument is returned. The iterator type has to satisfy the requirements of a forward iterator, and its value_type has to be comparable using < and <=. -*/ +*/ template -ForwardIter_t -min_positive_element(ForwardIter_t start, ForwardIter_t end) -{ +ForwardIter_t +min_positive_element(ForwardIter_t start, ForwardIter_t end) { // go and look for the first (strictly) positive number - while (start != end && *start <= 0) + while (start != end && *start <= 0) ++start; - if (start==end) return end; + if (start == end) + return end; // now look through the rest for a smaller positive number ForwardIter_t result = start; while (++start != end) - if(!(*start<=0) && *start<*result) + if (!(*start <= 0) && *start < *result) result = start; return result; diff --git a/src/include/stir/modelling/KineticModel.h b/src/include/stir/modelling/KineticModel.h index 6f23891c32..6abb184b13 100644 --- a/src/include/stir/modelling/KineticModel.h +++ b/src/include/stir/modelling/KineticModel.h @@ -23,7 +23,7 @@ \brief Definition of class stir::KineticModel \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_KineticModel_H__ @@ -34,18 +34,17 @@ START_NAMESPACE_STIR -/*! +/*! \brief base class for all kinetic models \ingroup modelling At present very basic. It just provides the parsing mechanism. */ -class KineticModel: public RegisteredObject -{ +class KineticModel : public RegisteredObject { public: - static const char * const registered_name ; - //! default constructor + static const char* const registered_name; + //! default constructor KineticModel(); //! default destructor @@ -58,7 +57,6 @@ class KineticModel: public RegisteredObject // protected: // void initialise_keymap(); - }; END_NAMESPACE_STIR diff --git a/src/include/stir/modelling/KineticParameters.h b/src/include/stir/modelling/KineticParameters.h index a9dd06a372..8a394cc46e 100644 --- a/src/include/stir/modelling/KineticParameters.h +++ b/src/include/stir/modelling/KineticParameters.h @@ -23,7 +23,7 @@ \brief Declaration of class stir::KineticParameters \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_KineticParameters_H__ @@ -35,25 +35,19 @@ START_NAMESPACE_STIR template -class KineticParameters:public BasicCoordinate -{ - typedef BasicCoordinate base_type; - public: - KineticParameters() - {} +class KineticParameters : public BasicCoordinate { + typedef BasicCoordinate base_type; - KineticParameters(const base_type& c) - : base_type(c) - {} +public: + KineticParameters() {} + KineticParameters(const base_type& c) : base_type(c) {} }; template -inline -void assign(KineticParameters& v, const T2& y) -{ - for (typename KineticParameters::iterator iter = v.begin(); - iter != v.end(); ++iter) +inline void +assign(KineticParameters& v, const T2& y) { + for (typename KineticParameters::iterator iter = v.begin(); iter != v.end(); ++iter) assign(*iter, y); } diff --git a/src/include/stir/modelling/KineticParameters.inl b/src/include/stir/modelling/KineticParameters.inl index 6702c06568..8d95bc48b6 100644 --- a/src/include/stir/modelling/KineticParameters.inl +++ b/src/include/stir/modelling/KineticParameters.inl @@ -27,31 +27,30 @@ START_NAMESPACE_STIR - //! default constructor +//! default constructor template -KineticParameters::KineticParameters() -{ } - //! constructor -//template -//KineticParameters::KineticParameters() +KineticParameters::KineticParameters() {} +//! constructor +// template +// KineticParameters::KineticParameters() //{} - //! default destructor +//! default destructor template -KineticParameters::~KineticParameters() -{ } +KineticParameters::~KineticParameters() {} - //! set the blood counts of the sample -template -void KineticParameters:: -set_parameter_value( const elemT param_value, const int param_num) -{ KineticParameters::_kin_params[param_num]=param_value ; } - - //! get the blood counts of the sample -template -elemT KineticParameters:: -get_parameter_value(const int param_num) const -{ return KineticParameters::_kin_params[param_num] ; } +//! set the blood counts of the sample +template +void +KineticParameters::set_parameter_value(const elemT param_value, const int param_num) { + KineticParameters::_kin_params[param_num] = param_value; +} +//! get the blood counts of the sample +template +elemT +KineticParameters::get_parameter_value(const int param_num) const { + return KineticParameters::_kin_params[param_num]; +} END_NAMESPACE_STIR diff --git a/src/include/stir/modelling/ModelMatrix.h b/src/include/stir/modelling/ModelMatrix.h index cae4c78ce2..e61472d8b2 100644 --- a/src/include/stir/modelling/ModelMatrix.h +++ b/src/include/stir/modelling/ModelMatrix.h @@ -21,7 +21,7 @@ \ingroup modelling \brief Declaration of class stir::ModelMatrix \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_ModelMatrix_H__ @@ -41,92 +41,87 @@ START_NAMESPACE_STIR /*! \ingroup modelling */ template -class ModelMatrix -{ +class ModelMatrix { public: - inline ModelMatrix(); //!< default constructor + inline ModelMatrix(); //!< default constructor - inline ~ModelMatrix(); //!< default destructor + inline ~ModelMatrix(); //!< default destructor - /*! Implementation to read the model matrix from a text file - \warning In this way the information about the calibration _is_uncalibrated and the counts _is_converted is not passed. - */ - inline void read_from_file(const std::string input_string); + /*! Implementation to read the model matrix from a text file + \warning In this way the information about the calibration _is_uncalibrated and the counts _is_converted is not passed. + */ + inline void read_from_file(const std::string input_string); //! Implementation to write the model matrix to a text file - inline Succeeded write_to_file(const std::string output_string); + inline Succeeded write_to_file(const std::string output_string); - //! \name Functions to get parameters @{ - inline Array<2,float> get_model_array() const; - inline const VectorWithOffset get_model_array_sum() const; - inline VectorWithOffset get_time_vector() const; + //! \name Functions to get parameters @{ + inline Array<2, float> get_model_array() const; + inline const VectorWithOffset get_model_array_sum() const; + inline VectorWithOffset get_time_vector() const; //!@} - //! \name Functions to set parameters @{ - inline void set_model_array(const Array<2,float>& model_array); - inline void set_time_vector(const VectorWithOffset& time_vector); + //! \name Functions to set parameters @{ + inline void set_model_array(const Array<2, float>& model_array); + inline void set_time_vector(const VectorWithOffset& time_vector); //! Function to set _is_calibrated boolean true or false - inline void set_is_uncalibrated(const bool is_uncalibrated); - inline void set_is_in_correct_scale(const bool in_correct_scale); + inline void set_is_uncalibrated(const bool is_uncalibrated); + inline void set_is_in_correct_scale(const bool in_correct_scale); //!@} - //! Function to give the threshold_value to the all elements of the model_array which lower value than the threshold_value. - inline void threshold_model_array(const float threshold_value) ; - - /*! Function to divide with the calibration factor the model array. - Calibrated ModelMatrix means that the counts are in kBq/ml, while uncalibrated means that it will be to the same units as the reconstructed images. - */ - inline void uncalibrate(const float cal_factor); - - /*! Function to multiply with the scale factor the model array. - Scaled ModelMatrix means that the counts are already scaled to the correct, while not scaled means that it needs to be scaled. - */ - inline void scale_model_matrix(const float scale_factor); - - /*! Multiply with the duration to convert the count rate to total counts in the time frame. - Converted ModelMatrix means that it is in total counts in respect to the time_frame_duration, - while not converted sets the _is_converted to false and means that it will be in "mean count rate". - */ - inline void convert_to_total_frame_counts(const TimeFrameDefinitions& time_frame_definitions); + //! Function to give the threshold_value to the all elements of the model_array which lower value than the threshold_value. + inline void threshold_model_array(const float threshold_value); - /*! Multiplications of the model with the dynamic or the parametric images. - /todo Maybe it will be better to lie in a linear models class. + /*! Function to divide with the calibration factor the model array. + Calibrated ModelMatrix means that the counts are in kBq/ml, while uncalibrated means that it will be to the same units as the + reconstructed images. */ - //@{ - //! multiply (transpose) model-matrix with dynamic image and add result to original \c parametric_image - inline void - multiply_dynamic_image_with_model_and_add_to_input(ParametricVoxelsOnCartesianGrid & parametric_image, - const DynamicDiscretisedDensity & dynamic_image) const ; - //! multiply (transpose) model-matrix with dynamic image (overwriting original content of \c parametric_image) - /*! \todo current implementation first fills first argument with 0 and then calls - multiply_dynamic_image_with_model_and_add_to_input(). This is somewhat inefficient. - */ - inline void - multiply_dynamic_image_with_model(ParametricVoxelsOnCartesianGrid & parametric_image, - const DynamicDiscretisedDensity & dynamic_image) const ; - //! multiply model-matrix with parametric image and add result to original \c dynamic_image - inline void - multiply_parametric_image_with_model_and_add_to_input(DynamicDiscretisedDensity & dynamic_image, - const ParametricVoxelsOnCartesianGrid & parametric_image ) const ; - //! multiply model-matrix with parametric image (overwriting original content of \c dynamic_image) - /*! \todo current implementation first fills first argument with 0 and then calls - multiply_dynamic_image_with_model_and_add_to_input(). This is somewhat inefficient. + inline void uncalibrate(const float cal_factor); + + /*! Function to multiply with the scale factor the model array. + Scaled ModelMatrix means that the counts are already scaled to the correct, while not scaled means that it needs to be scaled. */ - inline void - multiply_parametric_image_with_model(DynamicDiscretisedDensity & dynamic_image, - const ParametricVoxelsOnCartesianGrid & parametric_image ) const ; + inline void scale_model_matrix(const float scale_factor); - inline void - normalise_parametric_image_with_model_sum( ParametricVoxelsOnCartesianGrid & parametric_image_out, - const ParametricVoxelsOnCartesianGrid & parametric_image ) const ; + /*! Multiply with the duration to convert the count rate to total counts in the time frame. + Converted ModelMatrix means that it is in total counts in respect to the time_frame_duration, + while not converted sets the _is_converted to false and means that it will be in "mean count rate". + */ + inline void convert_to_total_frame_counts(const TimeFrameDefinitions& time_frame_definitions); + + /*! Multiplications of the model with the dynamic or the parametric images. + /todo Maybe it will be better to lie in a linear models class. + */ + //@{ + //! multiply (transpose) model-matrix with dynamic image and add result to original \c parametric_image + inline void multiply_dynamic_image_with_model_and_add_to_input(ParametricVoxelsOnCartesianGrid& parametric_image, + const DynamicDiscretisedDensity& dynamic_image) const; + //! multiply (transpose) model-matrix with dynamic image (overwriting original content of \c parametric_image) + /*! \todo current implementation first fills first argument with 0 and then calls + multiply_dynamic_image_with_model_and_add_to_input(). This is somewhat inefficient. + */ + inline void multiply_dynamic_image_with_model(ParametricVoxelsOnCartesianGrid& parametric_image, + const DynamicDiscretisedDensity& dynamic_image) const; + //! multiply model-matrix with parametric image and add result to original \c dynamic_image + inline void + multiply_parametric_image_with_model_and_add_to_input(DynamicDiscretisedDensity& dynamic_image, + const ParametricVoxelsOnCartesianGrid& parametric_image) const; + //! multiply model-matrix with parametric image (overwriting original content of \c dynamic_image) + /*! \todo current implementation first fills first argument with 0 and then calls + multiply_dynamic_image_with_model_and_add_to_input(). This is somewhat inefficient. + */ + inline void multiply_parametric_image_with_model(DynamicDiscretisedDensity& dynamic_image, + const ParametricVoxelsOnCartesianGrid& parametric_image) const; + + inline void normalise_parametric_image_with_model_sum(ParametricVoxelsOnCartesianGrid& parametric_image_out, + const ParametricVoxelsOnCartesianGrid& parametric_image) const; //@} private: - - //! At the moment it has the form of _model_array[param_num][frame_num]. - Array<2,float> _model_array; - VectorWithOffset _time_vector; - bool _is_uncalibrated ; - bool _in_correct_scale ; - bool _is_converted_to_total_counts; + //! At the moment it has the form of _model_array[param_num][frame_num]. + Array<2, float> _model_array; + VectorWithOffset _time_vector; + bool _is_uncalibrated; + bool _in_correct_scale; + bool _is_converted_to_total_counts; }; END_NAMESPACE_STIR diff --git a/src/include/stir/modelling/ModelMatrix.inl b/src/include/stir/modelling/ModelMatrix.inl index 20f2ff736e..a76fea55e0 100644 --- a/src/include/stir/modelling/ModelMatrix.inl +++ b/src/include/stir/modelling/ModelMatrix.inl @@ -29,342 +29,306 @@ START_NAMESPACE_STIR //! default constructor -template -ModelMatrix::ModelMatrix() -{ - // Calibrated ModelMatrix means that the counts are in kBq/ml, while uncalibrated means that it will be to the same units as the reconstructed images. - this->_is_uncalibrated=false; - // Converted ModelMatrix means that it is in total counts in respect to the time_frame_duration, while false means that it will be in mean count rate. - this->_in_correct_scale=false; - this->_is_converted_to_total_counts=false; +template +ModelMatrix::ModelMatrix() { + // Calibrated ModelMatrix means that the counts are in kBq/ml, while uncalibrated means that it will be to the same units as the + // reconstructed images. + this->_is_uncalibrated = false; + // Converted ModelMatrix means that it is in total counts in respect to the time_frame_duration, while false means that it will + // be in mean count rate. + this->_in_correct_scale = false; + this->_is_converted_to_total_counts = false; } //! default destructor -template -ModelMatrix::~ModelMatrix() -{ } +template +ModelMatrix::~ModelMatrix() {} //! Implementation to read the model matrix -template -void ModelMatrix::read_from_file(const std::string input_string) -{ - std::ifstream data_stream(input_string.c_str()); - unsigned int starting_frame, last_frame; - if(!data_stream) - error("cannot read model matrix from file.\n"); - else - { - data_stream >> starting_frame ; - data_stream >> last_frame ; - } - - BasicCoordinate<2,int> min_range; - BasicCoordinate<2,int> max_range; - min_range[1]=1; min_range[2]=starting_frame; - max_range[1]=num_param; max_range[2]=last_frame; - IndexRange<2> data_range(min_range,max_range); - Array<2,float> input_array(data_range); - while(true) - { - for(unsigned int frame_num=starting_frame; frame_num<=last_frame; ++frame_num) - for(int param_num=1;param_num<=num_param;++param_num) - data_stream >> input_array[param_num][frame_num] ; - if(!data_stream) - break; - } - this->_model_array=input_array; // I do not pass info if it is calibrated and if it includes time frame_duration, yet. -} +template +void +ModelMatrix::read_from_file(const std::string input_string) { + std::ifstream data_stream(input_string.c_str()); + unsigned int starting_frame, last_frame; + if (!data_stream) + error("cannot read model matrix from file.\n"); + else { + data_stream >> starting_frame; + data_stream >> last_frame; + } + + BasicCoordinate<2, int> min_range; + BasicCoordinate<2, int> max_range; + min_range[1] = 1; + min_range[2] = starting_frame; + max_range[1] = num_param; + max_range[2] = last_frame; + IndexRange<2> data_range(min_range, max_range); + Array<2, float> input_array(data_range); + while (true) { + for (unsigned int frame_num = starting_frame; frame_num <= last_frame; ++frame_num) + for (int param_num = 1; param_num <= num_param; ++param_num) + data_stream >> input_array[param_num][frame_num]; + if (!data_stream) + break; + } + this->_model_array = input_array; // I do not pass info if it is calibrated and if it includes time frame_duration, yet. +} //! Implementation to write the model matrix -template -Succeeded ModelMatrix::write_to_file(const std::string output_string) -{ +template +Succeeded +ModelMatrix::write_to_file(const std::string output_string) { - BasicCoordinate<2,int> model_array_min, model_array_max; - if(!(this->_model_array).get_regular_range(model_array_min,model_array_max)) + BasicCoordinate<2, int> model_array_min, model_array_max; + if (!(this->_model_array).get_regular_range(model_array_min, model_array_max)) error("Model array has not regular range"); - unsigned int starting_frame=model_array_min[2], last_frame=model_array_max[2]; + unsigned int starting_frame = model_array_min[2], last_frame = model_array_max[2]; - std::ofstream data_stream(output_string.c_str(),std::ios::out); - if(!data_stream) - { - warning("ModelMatrix::write_to_file: error opening output file %s\n", - output_string.c_str()); + std::ofstream data_stream(output_string.c_str(), std::ios::out); + if (!data_stream) { + warning("ModelMatrix::write_to_file: error opening output file %s\n", output_string.c_str()); return Succeeded::no; - } - else - { - data_stream << starting_frame << " " ; - data_stream << last_frame << " " ; - } - + } else { + data_stream << starting_frame << " "; + data_stream << last_frame << " "; + } + // It will be good to assert that there will be no writing error. - for(unsigned int frame_num=starting_frame; frame_num<=last_frame; ++frame_num) - { - data_stream << "\n"; - for(int param_num=1;param_num<=num_param;++param_num) - data_stream << this->_model_array[param_num][frame_num] << " "; - } + for (unsigned int frame_num = starting_frame; frame_num <= last_frame; ++frame_num) { + data_stream << "\n"; + for (int param_num = 1; param_num <= num_param; ++param_num) + data_stream << this->_model_array[param_num][frame_num] << " "; + } data_stream.close(); return Succeeded::yes; -} - +} -template -void ModelMatrix:: -set_model_array(const Array<2,float>& model_array) -{ this->_model_array=model_array ; } +template +void +ModelMatrix::set_model_array(const Array<2, float>& model_array) { + this->_model_array = model_array; +} -template -Array<2,float> -ModelMatrix:: -get_model_array() const -{ return this->_model_array ; } +template +Array<2, float> +ModelMatrix::get_model_array() const { + return this->_model_array; +} -template +template const VectorWithOffset -ModelMatrix:: -get_model_array_sum() const -{ - BasicCoordinate<2,int> model_array_min, model_array_max; - if(!(this->_model_array).get_regular_range(model_array_min,model_array_max)) +ModelMatrix::get_model_array_sum() const { + BasicCoordinate<2, int> model_array_min, model_array_max; + if (!(this->_model_array).get_regular_range(model_array_min, model_array_max)) error("Model array has not regular range"); - VectorWithOffset sum(model_array_min[1],model_array_max[1]); - for(int param_num = model_array_min[1];param_num<=model_array_max[1] ; ++param_num) - { - sum[param_num]=0.F; - for(int frame_num = model_array_min[2];frame_num<=model_array_max[2] ; ++frame_num) - sum[param_num] += this->_model_array[param_num][frame_num] ; - } - return - sum; + VectorWithOffset sum(model_array_min[1], model_array_max[1]); + for (int param_num = model_array_min[1]; param_num <= model_array_max[1]; ++param_num) { + sum[param_num] = 0.F; + for (int frame_num = model_array_min[2]; frame_num <= model_array_max[2]; ++frame_num) + sum[param_num] += this->_model_array[param_num][frame_num]; + } + return sum; } -template -void ModelMatrix:: -threshold_model_array(const float threshold_value) -{ - BasicCoordinate<2,int> model_array_min, model_array_max; - if(!(this->_model_array).get_regular_range(model_array_min,model_array_max)) +template +void +ModelMatrix::threshold_model_array(const float threshold_value) { + BasicCoordinate<2, int> model_array_min, model_array_max; + if (!(this->_model_array).get_regular_range(model_array_min, model_array_max)) error("Model array has not regular range"); - for(int param_num = model_array_min[1];param_num<=model_array_max[1] ; ++param_num) - for(int frame_num = model_array_min[2];frame_num<=model_array_max[2] ; ++frame_num) - if(this->_model_array[param_num][frame_num]<=0) - this->_model_array[param_num][frame_num]=threshold_value; + for (int param_num = model_array_min[1]; param_num <= model_array_max[1]; ++param_num) + for (int frame_num = model_array_min[2]; frame_num <= model_array_max[2]; ++frame_num) + if (this->_model_array[param_num][frame_num] <= 0) + this->_model_array[param_num][frame_num] = threshold_value; +} +template +void +ModelMatrix::set_is_uncalibrated(const bool is_uncalibrated) { + this->_is_uncalibrated = is_uncalibrated; } -template -void ModelMatrix:: -set_is_uncalibrated(const bool is_uncalibrated) -{ this->_is_uncalibrated=is_uncalibrated; } - -template -void ModelMatrix:: -set_is_in_correct_scale(const bool in_correct_scale) -{ this->_in_correct_scale=in_correct_scale; } - -template -void ModelMatrix:: -uncalibrate(const float cal_factor) -{ - if(this->_is_uncalibrated) +template +void +ModelMatrix::set_is_in_correct_scale(const bool in_correct_scale) { + this->_in_correct_scale = in_correct_scale; +} + +template +void +ModelMatrix::uncalibrate(const float cal_factor) { + if (this->_is_uncalibrated) warning("ModelMatrix is already uncalibrated, so it will be not re-uncalibrated."); - else - { - BasicCoordinate<2,int> model_array_min, model_array_max; - if(!(this->_model_array).get_regular_range(model_array_min,model_array_max)) - error("Model array has not regular range"); - - for(int param_num = model_array_min[1];param_num<=model_array_max[1] ; ++param_num) - for(int frame_num = model_array_min[2];frame_num<=model_array_max[2] ; ++frame_num) - this->_model_array[param_num][frame_num]/=cal_factor; - - ModelMatrix::set_is_uncalibrated(true); - } + else { + BasicCoordinate<2, int> model_array_min, model_array_max; + if (!(this->_model_array).get_regular_range(model_array_min, model_array_max)) + error("Model array has not regular range"); + + for (int param_num = model_array_min[1]; param_num <= model_array_max[1]; ++param_num) + for (int frame_num = model_array_min[2]; frame_num <= model_array_max[2]; ++frame_num) + this->_model_array[param_num][frame_num] /= cal_factor; + + ModelMatrix::set_is_uncalibrated(true); + } } -template -void ModelMatrix:: -scale_model_matrix(const float scale_factor) -{ +template +void +ModelMatrix::scale_model_matrix(const float scale_factor) { if (this->_in_correct_scale) - warning("ModelMatrix is already scaled, so it will not be re-scaled. "); - else - { - BasicCoordinate<2,int> model_array_min, model_array_max; - if(!(this->_model_array).get_regular_range(model_array_min,model_array_max)) - error("Model array has not regular range"); - for(int param_num = model_array_min[1];param_num<=model_array_max[1] ; ++param_num) - for(int frame_num = model_array_min[2];frame_num<=model_array_max[2] ; ++frame_num) - this->_model_array[param_num][frame_num]*= scale_factor; - - this->_in_correct_scale=true; - } + warning("ModelMatrix is already scaled, so it will not be re-scaled. "); + else { + BasicCoordinate<2, int> model_array_min, model_array_max; + if (!(this->_model_array).get_regular_range(model_array_min, model_array_max)) + error("Model array has not regular range"); + for (int param_num = model_array_min[1]; param_num <= model_array_max[1]; ++param_num) + for (int frame_num = model_array_min[2]; frame_num <= model_array_max[2]; ++frame_num) + this->_model_array[param_num][frame_num] *= scale_factor; + + this->_in_correct_scale = true; + } } -template -void ModelMatrix:: -convert_to_total_frame_counts(const TimeFrameDefinitions& time_frame_definitions) -{ - if (ModelMatrix::_is_converted_to_total_counts==true) +template +void +ModelMatrix::convert_to_total_frame_counts(const TimeFrameDefinitions& time_frame_definitions) { + if (ModelMatrix::_is_converted_to_total_counts == true) warning("ModelMatrix is already converted to total counts, so it will not be re-converted. "); - else - { - BasicCoordinate<2,int> model_array_min, model_array_max; - if(!(this->_model_array).get_regular_range(model_array_min,model_array_max)) - error("Model array has not regular range"); - for(int param_num = model_array_min[1];param_num<=model_array_max[1] ; ++param_num) - for(int frame_num = model_array_min[2];frame_num<=model_array_max[2] ; ++frame_num) - this->_model_array[param_num][frame_num]*= static_cast(time_frame_definitions.get_duration(frame_num)); - - this->_is_converted_to_total_counts=true; - } + else { + BasicCoordinate<2, int> model_array_min, model_array_max; + if (!(this->_model_array).get_regular_range(model_array_min, model_array_max)) + error("Model array has not regular range"); + for (int param_num = model_array_min[1]; param_num <= model_array_max[1]; ++param_num) + for (int frame_num = model_array_min[2]; frame_num <= model_array_max[2]; ++frame_num) + this->_model_array[param_num][frame_num] *= static_cast(time_frame_definitions.get_duration(frame_num)); + + this->_is_converted_to_total_counts = true; + } } -template -void ModelMatrix:: -set_time_vector(const VectorWithOffset& time_vector) -{this->_time_vector=time_vector;} +template +void +ModelMatrix::set_time_vector(const VectorWithOffset& time_vector) { + this->_time_vector = time_vector; +} -template +template VectorWithOffset -ModelMatrix:: -get_time_vector() const -{return this->_time_vector;} - -template -void -ModelMatrix:: -multiply_dynamic_image_with_model_and_add_to_input(ParametricVoxelsOnCartesianGrid & parametric_image, - const DynamicDiscretisedDensity & dynamic_image ) const -{ - BasicCoordinate<2,int> model_array_min, model_array_max; - if(!this->_model_array.get_regular_range(model_array_min,model_array_max)) +ModelMatrix::get_time_vector() const { + return this->_time_vector; +} + +template +void +ModelMatrix::multiply_dynamic_image_with_model_and_add_to_input(ParametricVoxelsOnCartesianGrid& parametric_image, + const DynamicDiscretisedDensity& dynamic_image) const { + BasicCoordinate<2, int> model_array_min, model_array_max; + if (!this->_model_array.get_regular_range(model_array_min, model_array_max)) error("Model array has not regular range"); // Assert that the sizes of the one frame of the dynamic image is equal with the parametric image size. // ChT::ToDo::Might be better to assert that each of the dimensions sizes with their voxle sizes are equal. // Could probably use has_same_characteristics()? - assert(dynamic_image[1].size_all()==parametric_image.size_all()); - assert(dynamic_image.get_time_frame_definitions().get_num_frames()==static_cast (model_array_max[2])); - assert(model_array_max[1]-model_array_min[1]+1==num_param); + assert(dynamic_image[1].size_all() == parametric_image.size_all()); + assert(dynamic_image.get_time_frame_definitions().get_num_frames() == static_cast(model_array_max[2])); + assert(model_array_max[1] - model_array_min[1] + 1 == num_param); - const int min_k_index = dynamic_image[1].get_min_index(); + const int min_k_index = dynamic_image[1].get_min_index(); const int max_k_index = dynamic_image[1].get_max_index(); - for ( int k = min_k_index; k<= max_k_index; ++k) - { - const int min_j_index = dynamic_image[1][k].get_min_index(); - const int max_j_index = dynamic_image[1][k].get_max_index(); - for ( int j = min_j_index; j<= max_j_index; ++j) - { - const int min_i_index = dynamic_image[1][k][j].get_min_index(); - const int max_i_index = dynamic_image[1][k][j].get_max_index(); - for ( int i = min_i_index; i<= max_i_index; ++i) - for(int param_num = model_array_min[1];param_num<=model_array_max[1] ; ++param_num) - { - float sum_over_frames=0.F; - for(int frame_num = model_array_min[2];frame_num<=model_array_max[2] ; ++frame_num) - sum_over_frames+=this->_model_array[param_num][frame_num]*dynamic_image[frame_num][k][j][i]; - parametric_image[k][j][i][param_num]+=sum_over_frames; - } + for (int k = min_k_index; k <= max_k_index; ++k) { + const int min_j_index = dynamic_image[1][k].get_min_index(); + const int max_j_index = dynamic_image[1][k].get_max_index(); + for (int j = min_j_index; j <= max_j_index; ++j) { + const int min_i_index = dynamic_image[1][k][j].get_min_index(); + const int max_i_index = dynamic_image[1][k][j].get_max_index(); + for (int i = min_i_index; i <= max_i_index; ++i) + for (int param_num = model_array_min[1]; param_num <= model_array_max[1]; ++param_num) { + float sum_over_frames = 0.F; + for (int frame_num = model_array_min[2]; frame_num <= model_array_max[2]; ++frame_num) + sum_over_frames += this->_model_array[param_num][frame_num] * dynamic_image[frame_num][k][j][i]; + parametric_image[k][j][i][param_num] += sum_over_frames; } } + } } -template -void -ModelMatrix:: -multiply_dynamic_image_with_model(ParametricVoxelsOnCartesianGrid & parametric_image, - const DynamicDiscretisedDensity & dynamic_image ) const -{ +template +void +ModelMatrix::multiply_dynamic_image_with_model(ParametricVoxelsOnCartesianGrid& parametric_image, + const DynamicDiscretisedDensity& dynamic_image) const { std::fill(parametric_image.begin_all(), parametric_image.end_all(), 0.F); - this->multiply_dynamic_image_with_model_and_add_to_input(parametric_image,dynamic_image ); + this->multiply_dynamic_image_with_model_and_add_to_input(parametric_image, dynamic_image); } -template -void -ModelMatrix:: -multiply_parametric_image_with_model_and_add_to_input(DynamicDiscretisedDensity & dynamic_image, - const ParametricVoxelsOnCartesianGrid & parametric_image ) const -{ - BasicCoordinate<2,int> model_array_min, model_array_max; - if(!(this->_model_array).get_regular_range(model_array_min,model_array_max)) +template +void +ModelMatrix::multiply_parametric_image_with_model_and_add_to_input( + DynamicDiscretisedDensity& dynamic_image, const ParametricVoxelsOnCartesianGrid& parametric_image) const { + BasicCoordinate<2, int> model_array_min, model_array_max; + if (!(this->_model_array).get_regular_range(model_array_min, model_array_max)) error("Model array does not have a regular range"); // Assert that the sizes of the one frame of the dynamic image is equal with the parametric image size. // ChT::ToDo::Might be better to assert that each of the dimensions sizes with their voxle sizes are equal. // Maybe this will be easier if I clone the single images for the two and then compare them. - assert(dynamic_image[1].size_all()==parametric_image.size_all()); - assert(dynamic_image.get_time_frame_definitions().get_num_frames()==static_cast (model_array_max[2])); - assert(model_array_max[1]-model_array_min[1]+1==num_param); + assert(dynamic_image[1].size_all() == parametric_image.size_all()); + assert(dynamic_image.get_time_frame_definitions().get_num_frames() == static_cast(model_array_max[2])); + assert(model_array_max[1] - model_array_min[1] + 1 == num_param); - const int min_k_index = dynamic_image[1].get_min_index(); + const int min_k_index = dynamic_image[1].get_min_index(); const int max_k_index = dynamic_image[1].get_max_index(); - for ( int k = min_k_index; k<= max_k_index; ++k) - { - const int min_j_index = dynamic_image[1][k].get_min_index(); - const int max_j_index = dynamic_image[1][k].get_max_index(); - for ( int j = min_j_index; j<= max_j_index; ++j) - { - const int min_i_index = dynamic_image[1][k][j].get_min_index(); - const int max_i_index = dynamic_image[1][k][j].get_max_index(); - for ( int i = min_i_index; i<= max_i_index; ++i) - for(int frame_num = model_array_min[2];frame_num<=model_array_max[2] ; ++frame_num) - { - float sum_over_param=0.F; - for(int param_num = model_array_min[1];param_num<=model_array_max[1] ; ++param_num) - sum_over_param+=parametric_image[k][j][i][param_num]*this->_model_array[param_num][frame_num]; - dynamic_image[frame_num][k][j][i]=sum_over_param; - } + for (int k = min_k_index; k <= max_k_index; ++k) { + const int min_j_index = dynamic_image[1][k].get_min_index(); + const int max_j_index = dynamic_image[1][k].get_max_index(); + for (int j = min_j_index; j <= max_j_index; ++j) { + const int min_i_index = dynamic_image[1][k][j].get_min_index(); + const int max_i_index = dynamic_image[1][k][j].get_max_index(); + for (int i = min_i_index; i <= max_i_index; ++i) + for (int frame_num = model_array_min[2]; frame_num <= model_array_max[2]; ++frame_num) { + float sum_over_param = 0.F; + for (int param_num = model_array_min[1]; param_num <= model_array_max[1]; ++param_num) + sum_over_param += parametric_image[k][j][i][param_num] * this->_model_array[param_num][frame_num]; + dynamic_image[frame_num][k][j][i] = sum_over_param; } } + } } -template -void -ModelMatrix:: -multiply_parametric_image_with_model(DynamicDiscretisedDensity & dynamic_image, - const ParametricVoxelsOnCartesianGrid & parametric_image ) const -{ +template +void +ModelMatrix::multiply_parametric_image_with_model(DynamicDiscretisedDensity& dynamic_image, + const ParametricVoxelsOnCartesianGrid& parametric_image) const { std::fill(dynamic_image.begin_all(), dynamic_image.end_all(), 0.F); this->multiply_parametric_image_with_model_and_add_to_input(dynamic_image, parametric_image); } -template -void -ModelMatrix:: -normalise_parametric_image_with_model_sum( ParametricVoxelsOnCartesianGrid & parametric_image_out, - const ParametricVoxelsOnCartesianGrid & parametric_image ) const -{ - BasicCoordinate<2,int> model_array_min, model_array_max; - if(!(this->_model_array).get_regular_range(model_array_min,model_array_max)) +template +void +ModelMatrix::normalise_parametric_image_with_model_sum(ParametricVoxelsOnCartesianGrid& parametric_image_out, + const ParametricVoxelsOnCartesianGrid& parametric_image) const { + BasicCoordinate<2, int> model_array_min, model_array_max; + if (!(this->_model_array).get_regular_range(model_array_min, model_array_max)) error("Model array has not regular range"); - assert(parametric_image_out.size_all()==parametric_image.size_all()); - assert(model_array_max[1]-model_array_min[1]+1==num_param); + assert(parametric_image_out.size_all() == parametric_image.size_all()); + assert(model_array_max[1] - model_array_min[1] + 1 == num_param); - const int min_k_index = parametric_image.construct_single_density(num_param).get_min_index(); + const int min_k_index = parametric_image.construct_single_density(num_param).get_min_index(); const int max_k_index = parametric_image.construct_single_density(num_param).get_max_index(); - for ( int k = min_k_index; k<= max_k_index; ++k) - { - const int min_j_index = (parametric_image.construct_single_density(num_param))[k].get_min_index(); - const int max_j_index = (parametric_image.construct_single_density(num_param))[k].get_max_index(); - for ( int j = min_j_index; j<= max_j_index; ++j) - { - const int min_i_index = (parametric_image.construct_single_density(num_param))[k][j].get_min_index(); - const int max_i_index = (parametric_image.construct_single_density(num_param))[k][j].get_max_index(); - for ( int i = min_i_index; i<= max_i_index; ++i) - { - parametric_image_out[k][j][i][1]=parametric_image[k][j][i][1]/((this->get_model_array_sum())[2]); - parametric_image_out[k][j][i][2]=parametric_image[k][j][i][2]/((this->get_model_array_sum())[1]); - } - } + for (int k = min_k_index; k <= max_k_index; ++k) { + const int min_j_index = (parametric_image.construct_single_density(num_param))[k].get_min_index(); + const int max_j_index = (parametric_image.construct_single_density(num_param))[k].get_max_index(); + for (int j = min_j_index; j <= max_j_index; ++j) { + const int min_i_index = (parametric_image.construct_single_density(num_param))[k][j].get_min_index(); + const int max_i_index = (parametric_image.construct_single_density(num_param))[k][j].get_max_index(); + for (int i = min_i_index; i <= max_i_index; ++i) { + parametric_image_out[k][j][i][1] = parametric_image[k][j][i][1] / ((this->get_model_array_sum())[2]); + parametric_image_out[k][j][i][2] = parametric_image[k][j][i][2] / ((this->get_model_array_sum())[1]); + } } + } } - - END_NAMESPACE_STIR - diff --git a/src/include/stir/modelling/ParametricDiscretisedDensity.h b/src/include/stir/modelling/ParametricDiscretisedDensity.h index 3b4d06da0e..23694567f4 100644 --- a/src/include/stir/modelling/ParametricDiscretisedDensity.h +++ b/src/include/stir/modelling/ParametricDiscretisedDensity.h @@ -25,12 +25,12 @@ \brief Declaration of class stir::ParametricDiscretisedDensity \author Kris Thielemans \author Richard Brown - + */ #include "stir/DiscretisedDensity.h" #include "stir/NestedIterator.h" -// for ParametricVoxelsOnCartesianGrid typedef +// for ParametricVoxelsOnCartesianGrid typedef #include "stir/VoxelsOnCartesianGrid.h" #include "stir/modelling/KineticParameters.h" START_NAMESPACE_STIR @@ -45,14 +45,12 @@ template struct Parametric2Single; template -struct Parametric2Single > -{ +struct Parametric2Single> { typedef typename Parametric2Single::type type; }; template -struct Parametric2Single > > -{ +struct Parametric2Single>> { typedef VoxelsOnCartesianGrid type; }; @@ -69,13 +67,12 @@ struct Parametric2Single -class ParametricDiscretisedDensity: -public DiscDensT -{ - private: +class ParametricDiscretisedDensity : public DiscDensT { +private: // typedef DiscretisedDensity base_type; typedef DiscDensT base_type; - public: + +public: //! A typedef that can be used what the base of the hierarchy is /*! For these purposes, we don't use DiscDensT (even though it's the base_type). @@ -88,20 +85,16 @@ public DiscDensT typedef typename base_type::full_iterator full_densel_iterator; typedef typename base_type::const_full_iterator const_full_densel_iterator; - typedef NestedIterator > full_iterator; - typedef NestedIterator > - const_full_iterator; + typedef NestedIterator> full_iterator; + typedef NestedIterator> const_full_iterator; //! A static member to read an image from file - static ParametricDiscretisedDensity * read_from_file(const std::string& filename); + static ParametricDiscretisedDensity* read_from_file(const std::string& filename); //! Get number of parameters in a single densel - static unsigned int - get_num_params(); + static unsigned int get_num_params(); - ParametricDiscretisedDensity(const base_type& density) - : base_type(density) - {} + ParametricDiscretisedDensity(const base_type& density) : base_type(density) {} /// Create blank parametric image from a dynamic image /*! Uses only its geometric/exam info and timing */ @@ -117,43 +110,35 @@ public DiscDensT // implementation works, but not needed for now // void update_parametric_image(const VectorWithOffset > & densities); - void update_parametric_image(const SingleDiscretisedDensityType & single_density, const unsigned int param_num); + void update_parametric_image(const SingleDiscretisedDensityType& single_density, const unsigned int param_num); - full_iterator begin_all() - { return full_iterator(base_type::begin_all(), base_type::end_all()); } + full_iterator begin_all() { return full_iterator(base_type::begin_all(), base_type::end_all()); } - const_full_iterator begin_all_const() const - { return const_full_iterator(base_type::begin_all_const(), base_type::end_all_const()); } + const_full_iterator begin_all_const() const { + return const_full_iterator(base_type::begin_all_const(), base_type::end_all_const()); + } - full_iterator end_all() - { return full_iterator(base_type::end_all(), base_type::end_all()); } + full_iterator end_all() { return full_iterator(base_type::end_all(), base_type::end_all()); } - const_full_iterator end_all_const() const - { return const_full_iterator(base_type::end_all_const(), base_type::end_all_const()); } + const_full_iterator end_all_const() const { + return const_full_iterator(base_type::end_all_const(), base_type::end_all_const()); + } - const_full_iterator begin_all() const - { return this->begin_all_const(); } + const_full_iterator begin_all() const { return this->begin_all_const(); } - const_full_iterator end_all() const - { return this->end_all_const(); } + const_full_iterator end_all() const { return this->end_all_const(); } - full_densel_iterator begin_all_densel() - { return base_type::begin_all(); } + full_densel_iterator begin_all_densel() { return base_type::begin_all(); } - const_full_densel_iterator begin_all_densel_const() const - { return base_type::begin_all_const(); } + const_full_densel_iterator begin_all_densel_const() const { return base_type::begin_all_const(); } - full_densel_iterator end_all_densel() - { return base_type::end_all(); } + full_densel_iterator end_all_densel() { return base_type::end_all(); } - const_full_densel_iterator end_all_densel_const() const - { return base_type::end_all_const(); } + const_full_densel_iterator end_all_densel_const() const { return base_type::end_all_const(); } - const_full_densel_iterator begin_all_densel() const - { return this->begin_all_densel_const(); } + const_full_densel_iterator begin_all_densel() const { return this->begin_all_densel_const(); } - const_full_densel_iterator end_all_densel() const - { return this->end_all_densel_const(); } + const_full_densel_iterator end_all_densel() const { return this->end_all_densel_const(); } //! Allocate a new object with same characteristics as the current one. virtual ParametricDiscretisedDensity* get_empty_copy() const; @@ -161,39 +146,31 @@ public DiscDensT //! Allocate a new object which is a copy of the current one. virtual ParametricDiscretisedDensity* clone() const; - //! construct a single image by applying a function object on each KineticParameter + //! construct a single image by applying a function object on each KineticParameter template - void - construct_single_density_using_function(SingleDiscretisedDensityType& density, KPFunctionObject f) const; + void construct_single_density_using_function(SingleDiscretisedDensityType& density, KPFunctionObject f) const; template - const SingleDiscretisedDensityType - construct_single_density_using_function(KPFunctionObject f) const; + const SingleDiscretisedDensityType construct_single_density_using_function(KPFunctionObject f) const; //! construct a single image corresponding to the parameter with index \c i - //@{ - void - construct_single_density(SingleDiscretisedDensityType& density, const int i) const; + //@{ + void construct_single_density(SingleDiscretisedDensityType& density, const int i) const; - const SingleDiscretisedDensityType - construct_single_density(const int index) const; -#if 0 //!< Implementation of non-const functions - which should be able to update a single parameter of a parametric image. + const SingleDiscretisedDensityType construct_single_density(const int index) const; +#if 0 //!< Implementation of non-const functions - which should be able to update a single parameter of a parametric image. // can't be done really SingleDiscretisedDensityType & construct_single_density(const int index); #endif - //@} + //@} }; -//! Convenience typedef for base-type of Cartesian Voxelised Parametric Images with just two parameters -typedef VoxelsOnCartesianGrid > - ParametricVoxelsOnCartesianGridBaseType; - - -//! Convenience typedef for Cartesian Voxelised Parametric Images with just two parameters -typedef ParametricDiscretisedDensity - ParametricVoxelsOnCartesianGrid; +//! Convenience typedef for base-type of Cartesian Voxelised Parametric Images with just two parameters +typedef VoxelsOnCartesianGrid> ParametricVoxelsOnCartesianGridBaseType; +//! Convenience typedef for Cartesian Voxelised Parametric Images with just two parameters +typedef ParametricDiscretisedDensity ParametricVoxelsOnCartesianGrid; END_NAMESPACE_STIR //#include "stir/modelling/ParametricDiscretisedDensity.inl" diff --git a/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.h b/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.h index ed64106a05..8bda540982 100644 --- a/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.h +++ b/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.h @@ -1,17 +1,17 @@ /* Copyright (C) 2019, University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! @@ -39,15 +39,11 @@ class KeyParser; \see ParseAndCreateFrom, ExamDataT> */ template - class ParseAndCreateFrom >, - ExamDataT> - : public ParseDiscretisedDensityParameters -{ - public: - typedef ParametricDiscretisedDensity > output_type; - inline - output_type* - create(const ExamDataT&) const; +class ParseAndCreateFrom>, ExamDataT> + : public ParseDiscretisedDensityParameters { +public: + typedef ParametricDiscretisedDensity> output_type; + inline output_type* create(const ExamDataT&) const; }; END_NAMESPACE_STIR diff --git a/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.inl b/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.inl index b7c48a9d42..2275383f4a 100644 --- a/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.inl +++ b/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.inl @@ -1,17 +1,17 @@ /* Copyright (C) 2019, University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! @@ -20,7 +20,7 @@ \brief implementation of the stir::ParseAndCreateFrom class for stir:ParametricDiscretisedDensity - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/VoxelsOnCartesianGrid.h" @@ -29,28 +29,16 @@ START_NAMESPACE_STIR - template -ParametricDiscretisedDensity >* -ParseAndCreateFrom >, ExamDataT>:: -create(const ExamDataT& exam_data) const -{ - - return - new ParametricDiscretisedDensity > - (VoxelsOnCartesianGrid - (exam_data.get_exam_info_sptr(), - *exam_data.get_proj_data_info_sptr(), - CartesianCoordinate3D(this->get_zoom_z(), - this->get_zoom_xy(), - this->get_zoom_xy()), - this->get_offset(), - CartesianCoordinate3D(this->get_output_image_size_z(), - this->get_output_image_size_xy(), - this->get_output_image_size_xy()) - ) - ); +ParametricDiscretisedDensity>* +ParseAndCreateFrom>, ExamDataT>::create( + const ExamDataT& exam_data) const { + + return new ParametricDiscretisedDensity>(VoxelsOnCartesianGrid( + exam_data.get_exam_info_sptr(), *exam_data.get_proj_data_info_sptr(), + CartesianCoordinate3D(this->get_zoom_z(), this->get_zoom_xy(), this->get_zoom_xy()), this->get_offset(), + CartesianCoordinate3D(this->get_output_image_size_z(), this->get_output_image_size_xy(), + this->get_output_image_size_xy()))); } END_NAMESPACE_STIR - diff --git a/src/include/stir/modelling/PatlakPlot.h b/src/include/stir/modelling/PatlakPlot.h index 124be0a701..84768a2c7e 100644 --- a/src/include/stir/modelling/PatlakPlot.h +++ b/src/include/stir/modelling/PatlakPlot.h @@ -25,7 +25,6 @@ */ - #ifndef __stir_modelling_PatlakPlot_H__ #define __stir_modelling_PatlakPlot_H__ @@ -43,13 +42,14 @@ START_NAMESPACE_STIR \brief Patlak kinetic model Model suitable for irreversible tracers such as FDG and FLT. See - - - Patlak C S, Blasberg R G, Fenstermacher J D (1985) - Graphical evaluation of blood-to-brain transfer constants from multiple-time uptake data, {J Cereb Blood Flow Metab 3(1): p. 1-7. + + - Patlak C S, Blasberg R G, Fenstermacher J D (1985) + Graphical evaluation of blood-to-brain transfer constants from multiple-time uptake data, {J Cereb Blood Flow Metab + 3(1): p. 1-7. - Patlak C S, Blasberg R G (1985) - Experimental and Graphical evaluation of blood-to-brain transfer constant from multiple-time uptake data: Generalizations, - J Cereb Blood Flow Metab 5: p. 584-90. + Experimental and Graphical evaluation of blood-to-brain transfer constant from multiple-time uptake data: + Generalizations, J Cereb Blood Flow Metab 5: p. 584-90. \par Example .par file @@ -68,94 +68,87 @@ START_NAMESPACE_STIR \endverbatim \warning - - The dynamic images will be calibrated only if the calibration factor is given. - - The [if_total_cnt] is set to true the Dynamic Image will have the total number of + - The dynamic images will be calibrated only if the calibration factor is given. + - The [if_total_cnt] is set to true the Dynamic Image will have the total number of counts while if set to false it will have the total_number_of_counts/get_duration(frame_num). - The dynamic images will always be in decaying counts. - The plasma data is assumed to be in decaying counts. - \todo Should be derived from LinearModels, but when non-linear models will be introduced, as well. + \todo Should be derived from LinearModels, but when non-linear models will be introduced, as well. */ -class PatlakPlot : public RegisteredParsingObject -{ - public: +class PatlakPlot : public RegisteredParsingObject { +public: //! Name which will be used when parsing a PatlakPlot object - static const char * const registered_name; - - PatlakPlot(); //!< Default constructor (calls set_defaults()) - ~PatlakPlot(); //!< default destructor - /*! \name Functions to get parameters */ - //@{ - //! Simply gets model matrix, if it has been already stored. - ModelMatrix<2> get_model_matrix() const; - //! Creates model matrix from plasma data (Must be already sorted in appropriate frames). - ModelMatrix<2> get_model_matrix(const PlasmaData& plasma_data, - const TimeFrameDefinitions& time_frame_definitions, - const unsigned int starting_frame); - //! Returns the frame that the PatlakPlot linearization is assumed to be valid. - unsigned int - get_starting_frame() const ; - //! Returns the TimeFrameDefinitions that the PatlakPlot linearization is assumed to be valid: ChT::Check - TimeFrameDefinitions - get_time_frame_definitions() const ; - //!@} - /*! \name Functions to set parameters*/ - //@{ - void set_model_matrix(ModelMatrix<2> model_matrix) ; //!< Simply set model matrix - //@} - - //! Multiplies the dynamic image with the model gradient. - /*! For a linear model the model gradient is the transpose of the model matrix. - So, the dynamic image is "projected" from time domain to the parameter domain. - - \todo Should be a virtual function declared in the KineticModel class. - */ - virtual void - multiply_dynamic_image_with_model_gradient(ParametricVoxelsOnCartesianGrid & parametric_image, - const DynamicDiscretisedDensity & dyn_image) const; - //! Multiplies the dynamic image with the model gradient and add to original \c parametric_image - /*! \todo Should be a virtual function declared in the KineticModel class. - */ - virtual void - multiply_dynamic_image_with_model_gradient_and_add_to_input(ParametricVoxelsOnCartesianGrid & parametric_image, - const DynamicDiscretisedDensity & dyn_image) const; - - //! Multiplies the parametric image with the model matrix to get the corresponding dynamic image. - /*! \todo Should be a virtual function declared in the KineticModel class. - */ - virtual void - get_dynamic_image_from_parametric_image(DynamicDiscretisedDensity & dyn_image, - const ParametricVoxelsOnCartesianGrid & par_image) const; - - //! This is the common method used to estimate the parametric images from the dynamic images. - /*! \todo There is currently no check if the time frame definitions from \a dyn_image are - the same as the ones encoded in the model. - */ - void - apply_linear_regression(ParametricVoxelsOnCartesianGrid & par_image, const DynamicDiscretisedDensity & dyn_image) const; - - void set_defaults(); - - Succeeded set_up(); - - bool _if_cardiac; //!< Switches between cardiac and brain data - unsigned int _starting_frame; //!< Starting frame to apply the model - float _cal_factor; //!< Calibration Factor, maybe to be removed. - float _time_shift; //!< Shifts the time to fit the timing of Plasma Data with the Projection Data. - bool _in_correct_scale; //!< Switch to scale or not the model_matrix to the correct scale, according to the appropriate scale factor. - bool _in_total_cnt; //!< Switch to choose the values of the model to be in total counts or in mean counts. - std::string _blood_data_filename; //!< Name of file in which the input function is stored - PlasmaData _plasma_frame_data; //!< Stores the plasma data into frames for brain studies - std::string _time_frame_definition_filename; //!< name of file to get frame definitions - TimeFrameDefinitions _frame_defs; //!< TimeFrameDefinitions - - private: - void create_model_matrix(); //!< Creates model matrix from private members + static const char* const registered_name; + + PatlakPlot(); //!< Default constructor (calls set_defaults()) + ~PatlakPlot(); //!< default destructor + /*! \name Functions to get parameters */ + //@{ + //! Simply gets model matrix, if it has been already stored. + ModelMatrix<2> get_model_matrix() const; + //! Creates model matrix from plasma data (Must be already sorted in appropriate frames). + ModelMatrix<2> get_model_matrix(const PlasmaData& plasma_data, const TimeFrameDefinitions& time_frame_definitions, + const unsigned int starting_frame); + //! Returns the frame that the PatlakPlot linearization is assumed to be valid. + unsigned int get_starting_frame() const; + //! Returns the TimeFrameDefinitions that the PatlakPlot linearization is assumed to be valid: ChT::Check + TimeFrameDefinitions get_time_frame_definitions() const; + //!@} + /*! \name Functions to set parameters*/ + //@{ + void set_model_matrix(ModelMatrix<2> model_matrix); //!< Simply set model matrix + //@} + + //! Multiplies the dynamic image with the model gradient. + /*! For a linear model the model gradient is the transpose of the model matrix. + So, the dynamic image is "projected" from time domain to the parameter domain. + + \todo Should be a virtual function declared in the KineticModel class. + */ + virtual void multiply_dynamic_image_with_model_gradient(ParametricVoxelsOnCartesianGrid& parametric_image, + const DynamicDiscretisedDensity& dyn_image) const; + //! Multiplies the dynamic image with the model gradient and add to original \c parametric_image + /*! \todo Should be a virtual function declared in the KineticModel class. + */ + virtual void multiply_dynamic_image_with_model_gradient_and_add_to_input(ParametricVoxelsOnCartesianGrid& parametric_image, + const DynamicDiscretisedDensity& dyn_image) const; + + //! Multiplies the parametric image with the model matrix to get the corresponding dynamic image. + /*! \todo Should be a virtual function declared in the KineticModel class. + */ + virtual void get_dynamic_image_from_parametric_image(DynamicDiscretisedDensity& dyn_image, + const ParametricVoxelsOnCartesianGrid& par_image) const; + + //! This is the common method used to estimate the parametric images from the dynamic images. + /*! \todo There is currently no check if the time frame definitions from \a dyn_image are + the same as the ones encoded in the model. + */ + void apply_linear_regression(ParametricVoxelsOnCartesianGrid& par_image, const DynamicDiscretisedDensity& dyn_image) const; + + void set_defaults(); + + Succeeded set_up(); + + bool _if_cardiac; //!< Switches between cardiac and brain data + unsigned int _starting_frame; //!< Starting frame to apply the model + float _cal_factor; //!< Calibration Factor, maybe to be removed. + float _time_shift; //!< Shifts the time to fit the timing of Plasma Data with the Projection Data. + bool _in_correct_scale; //!< Switch to scale or not the model_matrix to the correct scale, according to the appropriate scale + //!< factor. + bool _in_total_cnt; //!< Switch to choose the values of the model to be in total counts or in mean counts. + std::string _blood_data_filename; //!< Name of file in which the input function is stored + PlasmaData _plasma_frame_data; //!< Stores the plasma data into frames for brain studies + std::string _time_frame_definition_filename; //!< name of file to get frame definitions + TimeFrameDefinitions _frame_defs; //!< TimeFrameDefinitions + +private: + void create_model_matrix(); //!< Creates model matrix from private members void initialise_keymap(); bool post_processing(); mutable ModelMatrix<2> _model_matrix; bool _matrix_is_stored; - typedef RegisteredParsingObject base_type; + typedef RegisteredParsingObject base_type; }; END_NAMESPACE_STIR diff --git a/src/include/stir/modelling/PlasmaData.h b/src/include/stir/modelling/PlasmaData.h index 135b051576..61626f1baf 100644 --- a/src/include/stir/modelling/PlasmaData.h +++ b/src/include/stir/modelling/PlasmaData.h @@ -21,7 +21,7 @@ \ingroup modelling \brief Declaration of class stir::PlasmaData \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_PlasmaData_H__ @@ -38,91 +38,93 @@ START_NAMESPACE_STIR \see PlasmaSample */ -class PlasmaData -{ - typedef std::vector plot_type; - - public: +class PlasmaData { + typedef std::vector plot_type; + +public: //! constructor giving a vector \todo Better to use iterators - inline PlasmaData(const std::vector & plasma_blood_plot); - inline PlasmaData(); //!< default constructor - inline ~PlasmaData(); //!< default constructor + inline PlasmaData(const std::vector& plasma_blood_plot); + inline PlasmaData(); //!< default constructor + inline ~PlasmaData(); //!< default constructor - typedef plot_type::const_iterator const_iterator; + typedef plot_type::const_iterator const_iterator; //!\todo Implementation to set the input units. - /* - enum VolumeUnits - { ml , litre }; - enum SamplingTimeUnits - { seconds , minutes }; - enum RadioactivityUnits - { counts_per_sec , counts_per_min , kBq }; - */ + /* + enum VolumeUnits + { ml , litre }; + enum SamplingTimeUnits + { seconds , minutes }; + enum RadioactivityUnits + { counts_per_sec , counts_per_min , kBq }; + */ // Implementation to set the input units not currently used. Always, it assumed to use kBq, seconds, ml. - /* inline void set_input_units(const SamplingTimeUnits input_sampling_time_units, - const VolumeUnits input_volume_units, + /* inline void set_input_units(const SamplingTimeUnits input_sampling_time_units, + const VolumeUnits input_volume_units, const RadioactivityUnits input_radioactivity_units ) ; */ + /*! Implementation to read the input function from ONLY a 3-columns data file + (Time-InputFunctionRadioactivity-TotalBloodRadioactivity). \warning Assumes that the input function is not corrected for + decay. + */ + inline void read_plasma_data(const std::string input_string); - /*! Implementation to read the input function from ONLY a 3-columns data file (Time-InputFunctionRadioactivity-TotalBloodRadioactivity). - \warning Assumes that the input function is not corrected for decay. - */ - inline void read_plasma_data(const std::string input_string) ; - - inline void set_plot(const std::vector & plasma_blood_plot); + inline void set_plot(const std::vector& plasma_blood_plot); /*! Sorts the plasma_data into frames - \warning It corrects for decay if the data are not decay corrected. - \return PlasmaData are in start-end frames time mode. + \warning It corrects for decay if the data are not decay corrected. + \return PlasmaData are in start-end frames time mode. */ inline PlasmaData get_sample_data_in_frames(TimeFrameDefinitions time_frame_def); /*!Function to shift the time data - This is useful if the start time of the scan and the start time of the plasma are not precisely correct. - This can be measured by the plasma peak and the very first frames of the dynamic images. + This is useful if the start time of the scan and the start time of the plasma are not precisely correct. + This can be measured by the plasma peak and the very first frames of the dynamic images. \note This cannot be estimated in the current implementation of the direct reconstructions. Thus, it is given externally. */ - //! \name Functions to get parameters @{ + //! \name Functions to get parameters @{ inline double get_time_shift(); - inline bool get_is_decay_corrected() const ; - inline double get_isotope_halflife() const; - inline TimeFrameDefinitions get_time_frame_definitions() const; //!@} - //! \name Functions to set parameters + inline bool get_is_decay_corrected() const; + inline double get_isotope_halflife() const; + inline TimeFrameDefinitions get_time_frame_definitions() const; //!@} + //! \name Functions to set parameters //!@{ - inline void set_time_frame_definitions(const TimeFrameDefinitions & plasma_fdef); //!<\note The set_time_frame_definitions() is prefered than giving directly the Scan TimeFrameDefinitions since the sample may not be measured for all the frames \n For example at the beginning or at the end of the scan. + inline void set_time_frame_definitions( + const TimeFrameDefinitions& plasma_fdef); //!<\note The set_time_frame_definitions() is prefered than giving directly the + //!< Scan TimeFrameDefinitions since the sample may not be measured for all the + //!< frames \n For example at the beginning or at the end of the scan. inline void set_is_decay_corrected(const bool is_decay_corrected); - inline void set_isotope_halflife(const double isotope_halflife); + inline void set_isotope_halflife(const double isotope_halflife); inline void shift_time(const double time_shift); //!@} - //!Function to decay correct the data + //! Function to decay correct the data inline void decay_correct_PlasmaData(); - //! begin() and end() iterators for the plasma curve and the size() function + //! begin() and end() iterators for the plasma curve and the size() function //@{ - inline const_iterator begin() const ; - inline const_iterator end() const ; - inline unsigned int size() const ; + inline const_iterator begin() const; + inline const_iterator end() const; + inline unsigned int size() const; //!@} - //!\todo non const_iterator should be defined if the plasma data needs to be changed - //inline iterator begin() ; - //inline iterator end() ; + //!\todo non const_iterator should be defined if the plasma data needs to be changed + // inline iterator begin() ; + // inline iterator end() ; - private: +private: // PlasmaSample _plasma_type ; - // VolumeUnits _input_volume_units ; + // VolumeUnits _input_volume_units ; // SamplingTimeUnits _input_sampling_time_units ; // RadioactivityUnits _input_radioactivity_units ; - bool _is_decay_corrected ; - std::vector _plasma_blood_plot ; + bool _is_decay_corrected; + std::vector _plasma_blood_plot; TimeFrameDefinitions _plasma_fdef; double _isotope_halflife; int _sample_size; - double _time_shift ; + double _time_shift; }; END_NAMESPACE_STIR diff --git a/src/include/stir/modelling/PlasmaData.inl b/src/include/stir/modelling/PlasmaData.inl index b4e7433939..7df42667a2 100644 --- a/src/include/stir/modelling/PlasmaData.inl +++ b/src/include/stir/modelling/PlasmaData.inl @@ -30,251 +30,243 @@ START_NAMESPACE_STIR //! default constructor -PlasmaData::PlasmaData() -{ - this->set_is_decay_corrected(false); -} +PlasmaData::PlasmaData() { this->set_is_decay_corrected(false); } -//! constructor giving a vector -//ChT::ToDO: Better to use iterators -PlasmaData::PlasmaData(const std::vector & plasma_blood_plot) -{ - this->_plasma_blood_plot=plasma_blood_plot; - this->set_is_decay_corrected(false); - this->_isotope_halflife=-1.; +//! constructor giving a vector +// ChT::ToDO: Better to use iterators +PlasmaData::PlasmaData(const std::vector& plasma_blood_plot) { + this->_plasma_blood_plot = plasma_blood_plot; + this->set_is_decay_corrected(false); + this->_isotope_halflife = -1.; } //! default destructor -PlasmaData::~PlasmaData() -{ } +PlasmaData::~PlasmaData() {} -//! Implementation to read the input function from ONLY a 3-columns data file (Time-InputFunctionRadioactivity-WholeBloodRadioactivity). -void PlasmaData::read_plasma_data(const std::string input_string) -{ - std::ifstream data_stream(input_string.c_str()); - if(!data_stream) - error("cannot read plasma data from file.\n"); - else - { +//! Implementation to read the input function from ONLY a 3-columns data file +//! (Time-InputFunctionRadioactivity-WholeBloodRadioactivity). +void +PlasmaData::read_plasma_data(const std::string input_string) { + std::ifstream data_stream(input_string.c_str()); + if (!data_stream) + error("cannot read plasma data from file.\n"); + else { // Get the first line, which should be the number of samples std::string first_line; - if (std::getline(data_stream, first_line)) - { - // replace leading/trailing whitespace - first_line.erase(std::find_if(first_line.rbegin(), first_line.rend(), std::bind1st(std::not_equal_to(), ' ')).base(), first_line.end()); - first_line.erase(first_line.begin(), std::find_if(first_line.begin(), first_line.end(), std::bind1st(std::not_equal_to(), ' '))); - // now first, check if the first line is a single character. + if (std::getline(data_stream, first_line)) { + // replace leading/trailing whitespace + first_line.erase(std::find_if(first_line.rbegin(), first_line.rend(), std::bind1st(std::not_equal_to(), ' ')).base(), + first_line.end()); + first_line.erase(first_line.begin(), + std::find_if(first_line.begin(), first_line.end(), std::bind1st(std::not_equal_to(), ' '))); + // now first, check if the first line is a single character. // this is best done in C style, cleaner than iterating over chars char* p; long converted = strtol(first_line.c_str(), &p, 10); if (*p) - error("First line of input function file ("+ input_string + ") is not number of samples"); + error("First line of input function file (" + input_string + ") is not number of samples"); else - _sample_size=converted; - } - else - { - error("Input function file ("+ input_string + ") is empty"); + _sample_size = converted; + } else { + error("Input function file (" + input_string + ") is empty"); } } - while(true) - { - float sample_time=0, blood_sample_radioactivity=0, plasma_sample_radioactivity=0; - data_stream >> sample_time ; - data_stream >> plasma_sample_radioactivity ; - data_stream >> blood_sample_radioactivity ; - if(!data_stream) - break; - const PlasmaSample current_sample(sample_time,plasma_sample_radioactivity,blood_sample_radioactivity); - (this->_plasma_blood_plot).push_back(current_sample); - // Comment: The input function is generally not corrected for decay. - this->set_is_decay_corrected(false); - } -} + while (true) { + float sample_time = 0, blood_sample_radioactivity = 0, plasma_sample_radioactivity = 0; + data_stream >> sample_time; + data_stream >> plasma_sample_radioactivity; + data_stream >> blood_sample_radioactivity; + if (!data_stream) + break; + const PlasmaSample current_sample(sample_time, plasma_sample_radioactivity, blood_sample_radioactivity); + (this->_plasma_blood_plot).push_back(current_sample); + // Comment: The input function is generally not corrected for decay. + this->set_is_decay_corrected(false); + } +} // Implementation to set the input units not currently used. /* void - PlasmaData::set_input_units( SamplingTimeUnits input_sampling_time_units, - VolumeUnits input_volume_units, + PlasmaData::set_input_units( SamplingTimeUnits input_sampling_time_units, + VolumeUnits input_volume_units, RadioactivityUnits input_radioactivity_units ) { _input_sampling_time_units=input_sampling_time_units ; _input_volume_units=input_volume_units ; _input_radioactivity_units=input_radioactivity_units ; -} +} */ -//! Function to set the plasma_blood_plot -void PlasmaData::set_plot(const std::vector & plasma_blood_plot) -{ this->_plasma_blood_plot = plasma_blood_plot; } +//! Function to set the plasma_blood_plot +void +PlasmaData::set_plot(const std::vector& plasma_blood_plot) { + this->_plasma_blood_plot = plasma_blood_plot; +} -//!Function to shift the time data -void PlasmaData::shift_time(const double time_shift) -{ - _time_shift=time_shift; - for(std::vector::iterator cur_iter=this->_plasma_blood_plot.begin() ; - cur_iter!=this->_plasma_blood_plot.end() ; ++cur_iter) - cur_iter->set_time_in_s(cur_iter->get_time_in_s()+time_shift); +//! Function to shift the time data +void +PlasmaData::shift_time(const double time_shift) { + _time_shift = time_shift; + for (std::vector::iterator cur_iter = this->_plasma_blood_plot.begin(); + cur_iter != this->_plasma_blood_plot.end(); ++cur_iter) + cur_iter->set_time_in_s(cur_iter->get_time_in_s() + time_shift); } -//!Function to get the time shift -double PlasmaData::get_time_shift() -{ return PlasmaData::_time_shift ; } +//! Function to get the time shift +double +PlasmaData::get_time_shift() { + return PlasmaData::_time_shift; +} -//!Function to get the isotope halflife +//! Function to get the isotope halflife double -PlasmaData::get_isotope_halflife() const -{ return this->_isotope_halflife; } +PlasmaData::get_isotope_halflife() const { + return this->_isotope_halflife; +} -//!Function to set the isotope halflife -void PlasmaData::set_isotope_halflife(const double isotope_halflife) -{ this->_isotope_halflife=isotope_halflife; } +//! Function to set the isotope halflife +void +PlasmaData::set_isotope_halflife(const double isotope_halflife) { + this->_isotope_halflife = isotope_halflife; +} -void PlasmaData:: -set_time_frame_definitions(const TimeFrameDefinitions & plasma_fdef) -{ this->_plasma_fdef=plasma_fdef; } +void +PlasmaData::set_time_frame_definitions(const TimeFrameDefinitions& plasma_fdef) { + this->_plasma_fdef = plasma_fdef; +} -TimeFrameDefinitions PlasmaData:: -get_time_frame_definitions() const -{ return this->_plasma_fdef; } +TimeFrameDefinitions +PlasmaData::get_time_frame_definitions() const { + return this->_plasma_fdef; +} -void -PlasmaData:: -set_is_decay_corrected(const bool is_decay_corrected) -{ this->_is_decay_corrected=is_decay_corrected; } +void +PlasmaData::set_is_decay_corrected(const bool is_decay_corrected) { + this->_is_decay_corrected = is_decay_corrected; +} -bool -PlasmaData:: -get_is_decay_corrected() const -{ return this->_is_decay_corrected; } +bool +PlasmaData::get_is_decay_corrected() const { + return this->_is_decay_corrected; +} -void -PlasmaData:: -decay_correct_PlasmaData() -{ - - if (this->_is_decay_corrected==true) +void +PlasmaData::decay_correct_PlasmaData() { + + if (this->_is_decay_corrected == true) warning("PlasmaData are already decay corrected"); - else - { - assert(this->_isotope_halflife>0); - for(std::vector::iterator cur_iter=this->_plasma_blood_plot.begin() ; - cur_iter!=this->_plasma_blood_plot.end() ; ++cur_iter) - { - cur_iter->set_plasma_counts_in_kBq( static_cast(cur_iter->get_plasma_counts_in_kBq()*decay_correction_factor(_isotope_halflife,cur_iter->get_time_in_s()))); - cur_iter->set_blood_counts_in_kBq( static_cast(cur_iter->get_blood_counts_in_kBq()*decay_correction_factor(_isotope_halflife,cur_iter->get_time_in_s()))); - } - PlasmaData::set_is_decay_corrected(true); + else { + assert(this->_isotope_halflife > 0); + for (std::vector::iterator cur_iter = this->_plasma_blood_plot.begin(); + cur_iter != this->_plasma_blood_plot.end(); ++cur_iter) { + cur_iter->set_plasma_counts_in_kBq(static_cast( + cur_iter->get_plasma_counts_in_kBq() * decay_correction_factor(_isotope_halflife, cur_iter->get_time_in_s()))); + cur_iter->set_blood_counts_in_kBq(static_cast( + cur_iter->get_blood_counts_in_kBq() * decay_correction_factor(_isotope_halflife, cur_iter->get_time_in_s()))); } + PlasmaData::set_is_decay_corrected(true); + } } //! Sorts the plasma_data into frames -PlasmaData -PlasmaData::get_sample_data_in_frames(TimeFrameDefinitions time_frame_def) -{ - if (this->_is_decay_corrected==false) - { - this->decay_correct_PlasmaData(); - warning("Correcting for decay while sampling into frames."); - this->set_is_decay_corrected(true); - } - std::vector start_times_vector ; - std::vector durations_vector ; - const unsigned int num_frames=time_frame_def.get_num_frames(); +PlasmaData +PlasmaData::get_sample_data_in_frames(TimeFrameDefinitions time_frame_def) { + if (this->_is_decay_corrected == false) { + this->decay_correct_PlasmaData(); + warning("Correcting for decay while sampling into frames."); + this->set_is_decay_corrected(true); + } + std::vector start_times_vector; + std::vector durations_vector; + const unsigned int num_frames = time_frame_def.get_num_frames(); std::vector samples_in_frames_vector(num_frames); PlasmaData::const_iterator cur_iter; - std::vector::iterator frame_iter=samples_in_frames_vector.begin(); + std::vector::iterator frame_iter = samples_in_frames_vector.begin(); // Estimate the plasma_frame_vector and the plasma_frame_sum_vector using the integrate_discrete_function() implementation - for (unsigned int frame_num=1; frame_num<=num_frames && frame_iter!=samples_in_frames_vector.end() ; ++frame_num, ++frame_iter ) - { - std::vector time_frame_vector ; - std::vector plasma_frame_vector ; - std::vector blood_frame_vector ; - const double frame_start_time=time_frame_def.get_start_time(frame_num);//t1 - const double frame_end_time=time_frame_def.get_end_time(frame_num);//t2 + for (unsigned int frame_num = 1; frame_num <= num_frames && frame_iter != samples_in_frames_vector.end(); + ++frame_num, ++frame_iter) { + std::vector time_frame_vector; + std::vector plasma_frame_vector; + std::vector blood_frame_vector; + const double frame_start_time = time_frame_def.get_start_time(frame_num); // t1 + const double frame_end_time = time_frame_def.get_end_time(frame_num); // t2 - for(cur_iter=(this->_plasma_blood_plot).begin() ; cur_iter!=(this->_plasma_blood_plot).end() ; ++cur_iter) - { - const double cur_time=(*cur_iter).get_time_in_s() ; - if (cur_timeset_blood_counts_in_kBq( - static_cast(integrate_discrete_function(time_frame_vector,blood_frame_vector)/ - (time_frame_vector[time_frame_vector.size()-1]-time_frame_vector[0]))) ; - frame_iter->set_plasma_counts_in_kBq( - static_cast(integrate_discrete_function(time_frame_vector,plasma_frame_vector)/ - (time_frame_vector[time_frame_vector.size()-1]-time_frame_vector[0]))); - frame_iter->set_time_in_s(0.5*(time_frame_vector[time_frame_vector.size()-1]+time_frame_vector[0])); - start_times_vector.push_back(time_frame_vector[0]); - durations_vector.push_back(time_frame_vector[time_frame_vector.size()-1]-time_frame_vector[0]) ; - } - else if(time_frame_vector.size()==1) + for (cur_iter = (this->_plasma_blood_plot).begin(); cur_iter != (this->_plasma_blood_plot).end(); ++cur_iter) { + const double cur_time = (*cur_iter).get_time_in_s(); + if (cur_time < frame_start_time) + continue; + const double cur_plasma_cnt = (*cur_iter).get_plasma_counts_in_kBq(); + const double cur_blood_cnt = (*cur_iter).get_blood_counts_in_kBq(); + if (cur_time < frame_end_time) { + plasma_frame_vector.push_back(cur_plasma_cnt); + blood_frame_vector.push_back(cur_blood_cnt); + time_frame_vector.push_back(cur_time); + } else { + if (plasma_frame_vector.size() < 1) /* In case of no plasma data inside a frame, e.g. when there is large time_shift. */ { - frame_iter->set_plasma_counts_in_kBq( static_cast(plasma_frame_vector[0])); - frame_iter->set_blood_counts_in_kBq( static_cast(blood_frame_vector[0])); - frame_iter->set_time_in_s(time_frame_vector[0]); - start_times_vector.push_back(frame_start_time); - durations_vector.push_back(frame_end_time-frame_start_time) ; + plasma_frame_vector.push_back(0.); + blood_frame_vector.push_back(0.); + time_frame_vector.push_back((frame_start_time + frame_end_time) * .5); + } else { + plasma_frame_vector.push_back(cur_plasma_cnt); + blood_frame_vector.push_back(cur_blood_cnt); + time_frame_vector.push_back(cur_time); } + break; + } + } + if (time_frame_vector.size() != 1) { + frame_iter->set_blood_counts_in_kBq( + static_cast(integrate_discrete_function(time_frame_vector, blood_frame_vector) / + (time_frame_vector[time_frame_vector.size() - 1] - time_frame_vector[0]))); + frame_iter->set_plasma_counts_in_kBq( + static_cast(integrate_discrete_function(time_frame_vector, plasma_frame_vector) / + (time_frame_vector[time_frame_vector.size() - 1] - time_frame_vector[0]))); + frame_iter->set_time_in_s(0.5 * (time_frame_vector[time_frame_vector.size() - 1] + time_frame_vector[0])); + start_times_vector.push_back(time_frame_vector[0]); + durations_vector.push_back(time_frame_vector[time_frame_vector.size() - 1] - time_frame_vector[0]); + } else if (time_frame_vector.size() == 1) { + frame_iter->set_plasma_counts_in_kBq(static_cast(plasma_frame_vector[0])); + frame_iter->set_blood_counts_in_kBq(static_cast(blood_frame_vector[0])); + frame_iter->set_time_in_s(time_frame_vector[0]); + start_times_vector.push_back(frame_start_time); + durations_vector.push_back(frame_end_time - frame_start_time); } - PlasmaData plasma_data_in_frames(samples_in_frames_vector); - TimeFrameDefinitions plasma_fdef(start_times_vector,durations_vector); - plasma_data_in_frames.set_is_decay_corrected(this->_is_decay_corrected); - plasma_data_in_frames.set_isotope_halflife(this->_isotope_halflife); - plasma_data_in_frames.set_time_frame_definitions(plasma_fdef); - return plasma_data_in_frames; + } + PlasmaData plasma_data_in_frames(samples_in_frames_vector); + TimeFrameDefinitions plasma_fdef(start_times_vector, durations_vector); + plasma_data_in_frames.set_is_decay_corrected(this->_is_decay_corrected); + plasma_data_in_frames.set_isotope_halflife(this->_isotope_halflife); + plasma_data_in_frames.set_time_frame_definitions(plasma_fdef); + return plasma_data_in_frames; } -//PlasmaData begin() and end() of the PlasmaData ; +// PlasmaData begin() and end() of the PlasmaData ; PlasmaData::const_iterator -PlasmaData::begin() const -{ return this->_plasma_blood_plot.begin() ; } +PlasmaData::begin() const { + return this->_plasma_blood_plot.begin(); +} PlasmaData::const_iterator -PlasmaData::end() const -{ return this->_plasma_blood_plot.end() ; } +PlasmaData::end() const { + return this->_plasma_blood_plot.end(); +} unsigned int -PlasmaData::size() const -{ return static_cast(this->_plasma_blood_plot.size()) ; } +PlasmaData::size() const { + return static_cast(this->_plasma_blood_plot.size()); +} /* //PlasmaData begin() and end() of the PlasmaData ; PlasmaData::iterator -PlasmaData::begin() +PlasmaData::begin() { return this->_plasma_blood_plot.begin() ; } PlasmaData::iterator -PlasmaData::end() +PlasmaData::end() { return this->_plasma_blood_plot.end() ; } */ diff --git a/src/include/stir/modelling/PlasmaSample.h b/src/include/stir/modelling/PlasmaSample.h index f8efd1e849..bb576f45ff 100644 --- a/src/include/stir/modelling/PlasmaSample.h +++ b/src/include/stir/modelling/PlasmaSample.h @@ -21,7 +21,7 @@ \ingroup modelling \brief Declaration of class stir::PlasmaData \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_PlasmaSample_H__ @@ -42,45 +42,42 @@ START_NAMESPACE_STIR \todo This currently assumes sampling, while in practice we often have data accumulated over time, but this can currently not be encoded. */ -class PlasmaSample -{ +class PlasmaSample { public: - //! default constructor + //! default constructor inline PlasmaSample(); /*! A constructor : constructs a PlasmaSample object \n \param sample_time is the time in \a seconds relativily to the start of the scan. \param plasma_sample_counts is the activity of plasma at the sample_time (assumed to be in \a kBq/ml) - \param blood_sample_counts is the activity of blood at the sample_time (assumed to be in \a kBq/ml) - */ - inline PlasmaSample( const double sample_time, const float plasma_sample_counts, const float blood_sample_counts); + \param blood_sample_counts is the activity of blood at the sample_time (assumed to be in \a kBq/ml) + */ + inline PlasmaSample(const double sample_time, const float plasma_sample_counts, const float blood_sample_counts); //! default destructor inline ~PlasmaSample(); - //! \name Functions to get parameters + //! \name Functions to get parameters //@{ //! get the time of the sample - inline double get_time_in_s() const; + inline double get_time_in_s() const; //! get the blood counts of the sample - inline float get_blood_counts_in_kBq() const; - //! get the plasma counts of the sample - inline float get_plasma_counts_in_kBq() const; + inline float get_blood_counts_in_kBq() const; + //! get the plasma counts of the sample + inline float get_plasma_counts_in_kBq() const; //@} - //! \name Functions to set parameters + //! \name Functions to set parameters //@{ //! set the time of the sample - inline void set_time_in_s( const double time ); + inline void set_time_in_s(const double time); //! set the blood counts of the sample - inline void set_blood_counts_in_kBq( const float blood_counts ); + inline void set_blood_counts_in_kBq(const float blood_counts); //! set the plasma counts of the sample - inline void set_plasma_counts_in_kBq( const float plasma_counts ); + inline void set_plasma_counts_in_kBq(const float plasma_counts); //@} - - -private : +private: float _blood_counts; float _plasma_counts; double _time; diff --git a/src/include/stir/modelling/PlasmaSample.inl b/src/include/stir/modelling/PlasmaSample.inl index 0635e131a0..e2bf447d79 100644 --- a/src/include/stir/modelling/PlasmaSample.inl +++ b/src/include/stir/modelling/PlasmaSample.inl @@ -27,46 +27,52 @@ START_NAMESPACE_STIR - //! default constructor -PlasmaSample::PlasmaSample() -{ } - //! constructor, time in s -PlasmaSample:: -PlasmaSample(const double sample_time, const float plasma_sample_counts, const float blood_sample_counts) -{ - PlasmaSample::set_time_in_s( sample_time ); - PlasmaSample::set_blood_counts_in_kBq( blood_sample_counts ); - PlasmaSample::set_plasma_counts_in_kBq( plasma_sample_counts ); +//! default constructor +PlasmaSample::PlasmaSample() {} +//! constructor, time in s +PlasmaSample::PlasmaSample(const double sample_time, const float plasma_sample_counts, const float blood_sample_counts) { + PlasmaSample::set_time_in_s(sample_time); + PlasmaSample::set_blood_counts_in_kBq(blood_sample_counts); + PlasmaSample::set_plasma_counts_in_kBq(plasma_sample_counts); } - //! default destructor -PlasmaSample::~PlasmaSample() -{ } - - //! set the time of the sample -void PlasmaSample::set_time_in_s( const double time ) -{ PlasmaSample::_time=time ; } +//! default destructor +PlasmaSample::~PlasmaSample() {} - //! get the time of the sample -double PlasmaSample::get_time_in_s() const -{ return PlasmaSample::_time ; } - - //! set the blood counts of the sample -void PlasmaSample::set_blood_counts_in_kBq( const float blood_counts ) -{ PlasmaSample::_blood_counts=blood_counts ; } +//! set the time of the sample +void +PlasmaSample::set_time_in_s(const double time) { + PlasmaSample::_time = time; +} - //! get the blood counts of the sample -float PlasmaSample::get_blood_counts_in_kBq() const -{ return PlasmaSample::_blood_counts ; } +//! get the time of the sample +double +PlasmaSample::get_time_in_s() const { + return PlasmaSample::_time; +} - //! get the plasma counts of the sample -void PlasmaSample::set_plasma_counts_in_kBq( const float plasma_counts ) -{ PlasmaSample::_plasma_counts=plasma_counts ; } +//! set the blood counts of the sample +void +PlasmaSample::set_blood_counts_in_kBq(const float blood_counts) { + PlasmaSample::_blood_counts = blood_counts; +} - //! get the plasma counts of the sample -float PlasmaSample::get_plasma_counts_in_kBq() const -{ return PlasmaSample::_plasma_counts ; } +//! get the blood counts of the sample +float +PlasmaSample::get_blood_counts_in_kBq() const { + return PlasmaSample::_blood_counts; +} +//! get the plasma counts of the sample +void +PlasmaSample::set_plasma_counts_in_kBq(const float plasma_counts) { + PlasmaSample::_plasma_counts = plasma_counts; +} +//! get the plasma counts of the sample +float +PlasmaSample::get_plasma_counts_in_kBq() const { + return PlasmaSample::_plasma_counts; +} END_NAMESPACE_STIR diff --git a/src/include/stir/modulo.h b/src/include/stir/modulo.h index c809d318be..3f4098a27c 100644 --- a/src/include/stir/modulo.h +++ b/src/include/stir/modulo.h @@ -4,8 +4,8 @@ #define __stir_modulo_H__ /*! - \file - \ingroup buildblock + \file + \ingroup buildblock \brief defines stir::modulo() and related functions \author Kris Thielemans @@ -39,14 +39,14 @@ START_NAMESPACE_STIR //@{ //! Like std::fmod() but with guaranteed nonnegative result -/*! - std::fmod(a,b) return a number of the same sign as \a a. This is often +/*! + std::fmod(a,b) return a number of the same sign as \a a. This is often inconvenient as the result of this is that the range of std::fmod(a,b) is from \a -fabs(b) to \a +fabs(b). In contrast, modulo(a,b) always returns a nonnegative result. To be precise: - \c modulo(a,b) returns the value \c a-i*b, for the integer \c i + \c modulo(a,b) returns the value \c a-i*b, for the integer \c i such that, if \c b is nonzero, the result is greater or equal to 0 and less than the magnitude of \c b. @@ -56,102 +56,90 @@ START_NAMESPACE_STIR give you float which is (a tiny bit) larger than fabs(b). */ -inline -double -modulo(const double a, const double b) -{ - const double res = fmod(a,b); - return res<0 ? res + fabs(b) : res; +inline double +modulo(const double a, const double b) { + const double res = fmod(a, b); + return res < 0 ? res + fabs(b) : res; } //! modulo for floats -/*! +/*! \see modulo(double,double) The reason for this function is that rounding from double to float might make the result of the calculation with doubles larger than b. \warning Because of C++ promotion of floats to doubles, it is very easy to call the modulo(double,double) version inadvertently. - So, you should probably not rely too much on the result being less than + So, you should probably not rely too much on the result being less than \a b. */ -inline -float -modulo(const float a, const float b) -{ - float res = - static_cast(modulo(static_cast(a),static_cast(b))); - assert(res>=0); - const float abs_b = b>=0 ? b : -b; - if (res>=abs_b) res -= abs_b; - assert(res>=0); +inline float +modulo(const float a, const float b) { + float res = static_cast(modulo(static_cast(a), static_cast(b))); + assert(res >= 0); + const float abs_b = b >= 0 ? b : -b; + if (res >= abs_b) + res -= abs_b; + assert(res >= 0); return res; } //! Like the normal modulus operator (%) but with guaranteed nonnegative result -/*! +/*! Result will be larger than or equal to 0, and (strictly) smaller than \a abs(b). */ -inline -int -modulo(const int a, const int b) -{ - const int res = a%b; - const int res2 = res<0 ? res + (b>=0 ? b : -b) : res; - assert(res2>=0); - assert(res2<(b>=0?b:-b)); +inline int +modulo(const int a, const int b) { + const int res = a % b; + const int res2 = res < 0 ? res + (b >= 0 ? b : -b) : res; + assert(res2 >= 0); + assert(res2 < (b >= 0 ? b : -b)); return res2; } //! Performs the modulus operation on each element of the coordinates -/*! +/*! \return A BasicCoordinate such that for all d \code result[d] = modulo(a[d], b[d] \endcode */ template -inline -BasicCoordinate -modulo(const BasicCoordinate& a, const BasicCoordinate& b) -{ +inline BasicCoordinate +modulo(const BasicCoordinate& a, const BasicCoordinate& b) { BasicCoordinate result; - for (int d=1; d<=num_dimensions; ++d) + for (int d = 1; d <= num_dimensions; ++d) result[d] = modulo(a[d], b[d]); return result; } //! A function to convert an angle from one range to another -/*! - This is mainly useful for converting results from e.g. std::atan2 to +/*! + This is mainly useful for converting results from e.g. std::atan2 to a range \f$[0,2\pi)\f$. */ template -inline -FloatOrDouble -from_min_pi_plus_pi_to_0_2pi(const FloatOrDouble phi) -{ - static const FloatOrDouble two_pi =static_cast(2*_PI); - assert(phi>= -two_pi); - assert(phi< two_pi); - if (phi>=0) +inline FloatOrDouble +from_min_pi_plus_pi_to_0_2pi(const FloatOrDouble phi) { + static const FloatOrDouble two_pi = static_cast(2 * _PI); + assert(phi >= -two_pi); + assert(phi < two_pi); + if (phi >= 0) return phi; - FloatOrDouble res = phi+two_pi; + FloatOrDouble res = phi + two_pi; // due to floating point finite precision, the following check is needed... - if (res>=two_pi) - res -= two_pi; - assert(res>=0); - assert(res= two_pi) + res -= two_pi; + assert(res >= 0); + assert(res < two_pi); return res; } //! Convert angle to standard range /*! Identical to modulo(phi, static_cast(2*_PI)) */ template -inline -FloatOrDouble -to_0_2pi(const FloatOrDouble phi) -{ - return modulo(phi, static_cast(2*_PI)); +inline FloatOrDouble +to_0_2pi(const FloatOrDouble phi) { + return modulo(phi, static_cast(2 * _PI)); } //@} diff --git a/src/include/stir/more_algorithms.h b/src/include/stir/more_algorithms.h index 58270acb49..baeb14c4f0 100644 --- a/src/include/stir/more_algorithms.h +++ b/src/include/stir/more_algorithms.h @@ -21,9 +21,9 @@ /*! \file \ingroup buildblock - + \brief Declaration of some functions missing from std::algorithm - + \author Kris Thielemans */ @@ -37,54 +37,47 @@ START_NAMESPACE_STIR This function using stir::norm_squared(), so works for complex numbers as well. */ -template -inline -iterT abs_max_element(iterT start, iterT end); +template +inline iterT abs_max_element(iterT start, iterT end); /*! \ingroup buildblock \brief Compute the sum of a sequence using operator+=(), using an initial value. Sadly std::accumulate uses operator+(). For non-trivial objects, - this might call an inefficient version for the addition. + this might call an inefficient version for the addition. As an alternative, std::accumulate could be called with a function object that calls operator+=. */ template -inline -elemT -sum(IterT start, IterT end, elemT init); +inline elemT sum(IterT start, IterT end, elemT init); /*! \ingroup buildblock \brief Compute the sum of a sequence using operator+=(). Sadly std::accumulate uses operator+(). For non-trivial objects, - this might call an inefficient version for the addition. + this might call an inefficient version for the addition. Alternatively, std::accumulate could be called with a function object that calls operator+=. Still, in that case you need to specify an - initial value. + initial value. If the range is empty, this function calls operator*=(0) to initialise the object to 0. - \warning Currently, no work-around is present for old compilers that do not support + \warning Currently, no work-around is present for old compilers that do not support std::iterator_traits. */ -template -inline -typename std::iterator_traits::value_type -sum(IterT start, IterT end); +template +inline typename std::iterator_traits::value_type sum(IterT start, IterT end); /*! \ingroup buildblock \brief Compute the average of a sequence using sum(start,end). - \warning Currently, no work-around is present for old compilers that do not support + \warning Currently, no work-around is present for old compilers that do not support std::iterator_traits. */ -template -inline -typename std::iterator_traits::value_type -average(IterT start, IterT end); +template +inline typename std::iterator_traits::value_type average(IterT start, IterT end); END_NAMESPACE_STIR diff --git a/src/include/stir/more_algorithms.inl b/src/include/stir/more_algorithms.inl index de17be4cf1..804f9c6eb7 100644 --- a/src/include/stir/more_algorithms.inl +++ b/src/include/stir/more_algorithms.inl @@ -19,9 +19,9 @@ /*! \file \ingroup buildblock - + \brief Implementation of some functions missing from std::algorithm - + \author Kris Thielemans */ @@ -31,63 +31,53 @@ START_NAMESPACE_STIR -template -iterT abs_max_element(iterT start, iterT end) -{ +template +iterT +abs_max_element(iterT start, iterT end) { if (start == end) return start; - iterT current_max_iter=start; - double current_max=norm_squared(*start); - iterT iter=start; ++iter; + iterT current_max_iter = start; + double current_max = norm_squared(*start); + iterT iter = start; + ++iter; - while(iter != end) - { - const double n=norm_squared(*iter); - if (n>current_max) - { - current_max=n; current_max_iter=iter; - } - ++iter; + while (iter != end) { + const double n = norm_squared(*iter); + if (n > current_max) { + current_max = n; + current_max_iter = iter; } + ++iter; + } return current_max_iter; } -template -inline -elemT -sum(IterT start, IterT end, elemT init) -{ +template +inline elemT +sum(IterT start, IterT end, elemT init) { elemT tmp = init; - for (IterT iter=start; iter!=end; ++iter) + for (IterT iter = start; iter != end; ++iter) tmp += *iter; return tmp; } -template -inline -typename std::iterator_traits::value_type -sum(IterT start, IterT end) -{ - if (start==end) - { - typename std::iterator_traits::value_type tmp; - tmp *= 0; - return tmp; - } - return sum(start+1,end,*start); +template +inline typename std::iterator_traits::value_type +sum(IterT start, IterT end) { + if (start == end) { + typename std::iterator_traits::value_type tmp; + tmp *= 0; + return tmp; + } + return sum(start + 1, end, *start); } -template -inline -typename std::iterator_traits::value_type -average(IterT start, IterT end) -{ - typename std::iterator_traits::value_type tmp = - sum(start, end); +template +inline typename std::iterator_traits::value_type +average(IterT start, IterT end) { + typename std::iterator_traits::value_type tmp = sum(start, end); tmp /= (end - start); return tmp; } - END_NAMESPACE_STIR - diff --git a/src/include/stir/num_threads.h b/src/include/stir/num_threads.h index 68f0978672..dd6fbffaa0 100644 --- a/src/include/stir/num_threads.h +++ b/src/include/stir/num_threads.h @@ -21,7 +21,7 @@ \brief Implementation of functions related to setting/getting the number of threads - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/common.h" @@ -32,7 +32,7 @@ START_NAMESPACE_STIR /*! \ingroup threads This returns the maxmimum number of threads to be used by STIR. Usually this should be equal to what you set earlier via set_num_threads(). - + Currently only useful when compiled with OpenMP support. Corresponds then to omp_get_max_threads() */ @@ -59,8 +59,8 @@ void set_num_threads(const int num_threads = 0); If OpenMP support is enabled, the default is normally set from the \c OMP_NUM_THREADS environment variable. However, if this is is not set, we use ~90% of the available processors. - - Currently only useful when compiled with OpenMP support. + + Currently only useful when compiled with OpenMP support. */ int get_default_num_threads(); @@ -68,7 +68,7 @@ int get_default_num_threads(); /*! \ingroup threads \see get_default_num_threads() - Currently only useful when compiled with OpenMP support. + Currently only useful when compiled with OpenMP support. */ void set_default_num_threads(); diff --git a/src/include/stir/numerics/BSplines.h b/src/include/stir/numerics/BSplines.h index adfa6653ce..277ac37790 100644 --- a/src/include/stir/numerics/BSplines.h +++ b/src/include/stir/numerics/BSplines.h @@ -7,21 +7,21 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ #ifndef __stir_numerics_BSplines__H__ #define __stir_numerics_BSplines__H__ /*! -\file +\file \ingroup BSpline -\brief Implementation of the basic components and declarations for B-Splines Interpolation +\brief Implementation of the basic components and declarations for B-Splines Interpolation \author Charalampos Tsoumpas \author Kris Thielemans @@ -33,50 +33,40 @@ START_NAMESPACE_STIR namespace BSpline { - /*! \brief The type used for relative positions between the grid points. - \ingroup BSpline - */ - typedef double pos_type; - - /*! \brief enum providing constants to define the type of B-Spline used for interpolation - \ingroup BSpline - */ - enum BSplineType - {near_n, linear, quadratic, cubic, quartic, quintic, oMoms} ; +/*! \brief The type used for relative positions between the grid points. + \ingroup BSpline +*/ +typedef double pos_type; - /*! \brief compute BSpline coefficients that gives the BSpline that interpolates the given data - \internal +/*! \brief enum providing constants to define the type of B-Spline used for interpolation \ingroup BSpline - You should never have to use this function yourself. - */ - template - inline - void - BSplines_coef(RandIterOut c_begin_iterator, - RandIterOut c_end_iterator, - IterT input_begin_iterator, - IterT input_end_iterator, - const constantsT z1, const constantsT z2, const constantsT lambda); // to be taken from the class - - /*! \brief return value of the first derivative of the spline - \ingroup BSpline - */ - template - inline - pos_type - BSplines_1st_der_weight(const pos_type relative_position, const BSplineType spline_type) ; - - /*! \brief return spline value - \ingroup BSpline - */ - template - inline - pos_type - BSplines_weights(const pos_type relative_position, const BSplineType spline_type); - - - //*/ -} // end BSpline namespace +*/ +enum BSplineType { near_n, linear, quadratic, cubic, quartic, quintic, oMoms }; + +/*! \brief compute BSpline coefficients that gives the BSpline that interpolates the given data +\internal +\ingroup BSpline +You should never have to use this function yourself. +*/ +template +inline void BSplines_coef(RandIterOut c_begin_iterator, RandIterOut c_end_iterator, IterT input_begin_iterator, + IterT input_end_iterator, const constantsT z1, const constantsT z2, + const constantsT lambda); // to be taken from the class + +/*! \brief return value of the first derivative of the spline + \ingroup BSpline +*/ +template +inline pos_type BSplines_1st_der_weight(const pos_type relative_position, const BSplineType spline_type); + +/*! \brief return spline value + \ingroup BSpline +*/ +template +inline pos_type BSplines_weights(const pos_type relative_position, const BSplineType spline_type); + +//*/ +} // namespace BSpline END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/BSplines1DRegularGrid.h b/src/include/stir/numerics/BSplines1DRegularGrid.h index 40eddfc18c..40b02d2210 100644 --- a/src/include/stir/numerics/BSplines1DRegularGrid.h +++ b/src/include/stir/numerics/BSplines1DRegularGrid.h @@ -7,21 +7,21 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ #ifndef __stir_numerics_BSplines1DRegularGrid__H__ #define __stir_numerics_BSplines1DRegularGrid__H__ /*! -\file +\file \ingroup BSpline -\brief Implementation of the B-Splines Interpolation +\brief Implementation of the B-Splines Interpolation \author Charalampos Tsoumpas \author Kris Thielemans @@ -32,107 +32,80 @@ START_NAMESPACE_STIR -namespace BSpline -{ - - /*! \ingroup BSpline - \brief Temporary class for 1D B-splines - - This class works with std::vector objects, while BSplinesRegularGrid works with - stir::Array objects. - \todo remove overlap with the n-dimensional version BSplinesRegularGrid - */ - template - class BSplines1DRegularGrid - { - private: - typedef typename std::vector::iterator RandIterOut; - int input_size; // create in the constructor - constantsT z1; - constantsT z2; - constantsT lambda; - - - inline - out_elemT - BSplines_product(const int index, const pos_type relative_position, const bool if_deriv) const; - - inline - void - set_private_values(BSplineType); - - inline - out_elemT - compute_BSplines_value(const pos_type relative_position, const bool if_deriv) const; - - // sadly,VC6.0 needs definition of template members in the class definition - template - inline - void - set_coef(IterT input_begin_iterator, IterT input_end_iterator) - { - BSplines1DRegularGrid::input_size = static_cast(input_end_iterator - input_begin_iterator); - BSplines_coef_vector.resize(input_size); - BSplines_coef(BSplines_coef_vector.begin(),BSplines_coef_vector.end(), - input_begin_iterator, input_end_iterator, z1, z2, lambda); - } - - public: - std::vector BSplines_coef_vector; - BSplineType spline_type; - - - //! default constructor: no input - inline BSplines1DRegularGrid(); - - //! constructor given a vector as an input, estimates the Coefficients - inline explicit BSplines1DRegularGrid(const std::vector & input_vector); - - //! constructor given a begin_ and end_ iterator as input, estimates the Coefficients - template - inline BSplines1DRegularGrid(const IterT input_begin_iterator, - const IterT input_end_iterator) - { - set_private_values(cubic); - set_coef(input_begin_iterator, input_end_iterator); - } - //! constructor given a begin_ and end_ iterator as input, estimates the Coefficients - template - inline BSplines1DRegularGrid(const IterT input_begin_iterator, - const IterT input_end_iterator, const BSplineType this_type) - { - set_private_values(this_type); - set_coef(input_begin_iterator, input_end_iterator); - } - - inline - BSplines1DRegularGrid(const std::vector & input_vector, const BSplineType this_type); - - //! destructor - inline ~BSplines1DRegularGrid(); - - inline - out_elemT - BSplines(const pos_type relative_position) const; - - inline - out_elemT - BSplines_1st_der(const pos_type relative_position) const; - - //! same as BSplines() - inline - const out_elemT - operator() (const pos_type relative_position) const; - - inline - const std::vector - BSplines_output_sequence(RandIterOut output_relative_position_begin_iterator, //relative_position might be better float - RandIterOut output_relative_position_end_iterator); - inline - const std::vector - BSplines_output_sequence(std::vector output_relative_position); - }; -} // end BSpline namespace +namespace BSpline { + +/*! \ingroup BSpline + \brief Temporary class for 1D B-splines + + This class works with std::vector objects, while BSplinesRegularGrid works with + stir::Array objects. + \todo remove overlap with the n-dimensional version BSplinesRegularGrid +*/ +template +class BSplines1DRegularGrid { +private: + typedef typename std::vector::iterator RandIterOut; + int input_size; // create in the constructor + constantsT z1; + constantsT z2; + constantsT lambda; + + inline out_elemT BSplines_product(const int index, const pos_type relative_position, const bool if_deriv) const; + + inline void set_private_values(BSplineType); + + inline out_elemT compute_BSplines_value(const pos_type relative_position, const bool if_deriv) const; + + // sadly,VC6.0 needs definition of template members in the class definition + template + inline void set_coef(IterT input_begin_iterator, IterT input_end_iterator) { + BSplines1DRegularGrid::input_size = static_cast(input_end_iterator - input_begin_iterator); + BSplines_coef_vector.resize(input_size); + BSplines_coef(BSplines_coef_vector.begin(), BSplines_coef_vector.end(), input_begin_iterator, input_end_iterator, z1, z2, + lambda); + } + +public: + std::vector BSplines_coef_vector; + BSplineType spline_type; + + //! default constructor: no input + inline BSplines1DRegularGrid(); + + //! constructor given a vector as an input, estimates the Coefficients + inline explicit BSplines1DRegularGrid(const std::vector& input_vector); + + //! constructor given a begin_ and end_ iterator as input, estimates the Coefficients + template + inline BSplines1DRegularGrid(const IterT input_begin_iterator, const IterT input_end_iterator) { + set_private_values(cubic); + set_coef(input_begin_iterator, input_end_iterator); + } + //! constructor given a begin_ and end_ iterator as input, estimates the Coefficients + template + inline BSplines1DRegularGrid(const IterT input_begin_iterator, const IterT input_end_iterator, const BSplineType this_type) { + set_private_values(this_type); + set_coef(input_begin_iterator, input_end_iterator); + } + + inline BSplines1DRegularGrid(const std::vector& input_vector, const BSplineType this_type); + + //! destructor + inline ~BSplines1DRegularGrid(); + + inline out_elemT BSplines(const pos_type relative_position) const; + + inline out_elemT BSplines_1st_der(const pos_type relative_position) const; + + //! same as BSplines() + inline const out_elemT operator()(const pos_type relative_position) const; + + inline const std::vector + BSplines_output_sequence(RandIterOut output_relative_position_begin_iterator, // relative_position might be better float + RandIterOut output_relative_position_end_iterator); + inline const std::vector BSplines_output_sequence(std::vector output_relative_position); +}; +} // namespace BSpline END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/BSplines1DRegularGrid.inl b/src/include/stir/numerics/BSplines1DRegularGrid.inl index abcccaf9be..dbba7e89fa 100644 --- a/src/include/stir/numerics/BSplines1DRegularGrid.inl +++ b/src/include/stir/numerics/BSplines1DRegularGrid.inl @@ -16,9 +16,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup BSpline - \brief Implementation of the B-Splines Interpolation + \brief Implementation of the B-Splines Interpolation \author Charalampos Tsoumpas \author Kris Thielemans @@ -30,40 +30,31 @@ START_NAMESPACE_STIR namespace BSpline { - template - BSplines1DRegularGrid:: - BSplines1DRegularGrid() - { } - - template - BSplines1DRegularGrid:: - BSplines1DRegularGrid(const std::vector & input_vector) - { - set_private_values(cubic); - set_coef(input_vector.begin(), input_vector.end()); - } - ///* - template - BSplines1DRegularGrid:: - BSplines1DRegularGrid(const std::vector & input_vector, const BSplineType this_type) - { - set_private_values(this_type); - set_coef(input_vector.begin(), input_vector.end()); - } - - template - BSplines1DRegularGrid:: - ~BSplines1DRegularGrid() - {} - - template - void - BSplines1DRegularGrid:: - set_private_values(BSplineType this_type) - { - this->spline_type = this_type; - detail::set_BSpline_values(this->z1,this->z2,this->lambda,this_type); - } +template +BSplines1DRegularGrid::BSplines1DRegularGrid() {} + +template +BSplines1DRegularGrid::BSplines1DRegularGrid(const std::vector& input_vector) { + set_private_values(cubic); + set_coef(input_vector.begin(), input_vector.end()); +} +///* +template +BSplines1DRegularGrid::BSplines1DRegularGrid(const std::vector& input_vector, + const BSplineType this_type) { + set_private_values(this_type); + set_coef(input_vector.begin(), input_vector.end()); +} + +template +BSplines1DRegularGrid::~BSplines1DRegularGrid() {} + +template +void +BSplines1DRegularGrid::set_private_values(BSplineType this_type) { + this->spline_type = this_type; + detail::set_BSpline_values(this->z1, this->z2, this->lambda, this_type); +} #if 0 // needs to be in .h for VC 6.0 @@ -82,16 +73,15 @@ namespace BSpline { } #endif - template - out_elemT - BSplines1DRegularGrid:: - compute_BSplines_value(const pos_type relative_position, const bool if_deriv) const - { - assert(relative_position>-input_size+2); - assert(relative_position<2*input_size-4); - out_elemT BSplines_value; - assign(BSplines_value,0); - const int int_pos =(int)floor(relative_position); +template +out_elemT +BSplines1DRegularGrid::compute_BSplines_value(const pos_type relative_position, + const bool if_deriv) const { + assert(relative_position > -input_size + 2); + assert(relative_position < 2 * input_size - 4); + out_elemT BSplines_value; + assign(BSplines_value, 0); + const int int_pos = (int)floor(relative_position); #if 0 for (int k=int_pos-2; k - out_elemT - BSplines1DRegularGrid:: - BSplines(const pos_type relative_position) const - { - return compute_BSplines_value(relative_position, false); - } - - template - out_elemT - BSplines1DRegularGrid:: - BSplines_1st_der(const pos_type relative_position) const - { - return compute_BSplines_value(relative_position, true); - } - - template - out_elemT - BSplines1DRegularGrid:: - BSplines_product(const int index, const pos_type relative_position, const bool if_deriv) const - { - if (if_deriv==true) - return BSplines_coef_vector[index]*BSplines_1st_der_weight(relative_position, spline_type); - else - return BSplines_coef_vector[index]*BSplines_weights(relative_position,spline_type); + const int kmin = int_pos - 2; + const int kmax = int_pos + 2; + const int kmax_in_range = std::min(kmax, input_size - 1); + int k = kmin; + for (; k < 0; ++k) { + const int index = -k; + assert(0 <= index && index < input_size); + BSplines_value += BSplines_product(index, relative_position - k, if_deriv); } - - template - const out_elemT BSplines1DRegularGrid:: - operator() (const pos_type relative_position) const - { - return BSplines1DRegularGrid:: - BSplines(relative_position); + for (; k <= kmax_in_range; ++k) { + const int index = k; + assert(0 <= index && index < input_size); + BSplines_value += BSplines_product(index, relative_position - k, if_deriv); } - - //* - template - const std::vector BSplines1DRegularGrid:: - BSplines_output_sequence(RandIterOut output_relative_position_begin_iterator, //relative_position might be better float - RandIterOut output_relative_position_end_iterator) - { - std::vector output_vector(output_relative_position_end_iterator- - output_relative_position_begin_iterator); - - for(RandIterOut current_iterator=output_vector.begin(), - current_relative_position_iterator=output_relative_position_begin_iterator; - current_iterator!=output_vector.end() && - current_relative_position_iterator!=output_relative_position_end_iterator; - ++current_iterator,++current_relative_position_iterator) - *current_iterator = BSplines1DRegularGrid:: - BSplines(*current_relative_position_iterator); - - return output_vector; - } - template - const std::vector BSplines1DRegularGrid:: - BSplines_output_sequence(std::vector output_relative_position) - { - return BSplines_output_sequence(output_relative_position.begin(), - output_relative_position.end()); + for (; k <= kmax; ++k) { + const int index = 2 * input_size - 2 - k; + assert(0 <= index && index < input_size); + BSplines_value += BSplines_product(index, relative_position - k, if_deriv); } - -} // end BSpline namespace +#endif + return BSplines_value; +} + +template +out_elemT +BSplines1DRegularGrid::BSplines(const pos_type relative_position) const { + return compute_BSplines_value(relative_position, false); +} + +template +out_elemT +BSplines1DRegularGrid::BSplines_1st_der(const pos_type relative_position) const { + return compute_BSplines_value(relative_position, true); +} + +template +out_elemT +BSplines1DRegularGrid::BSplines_product(const int index, const pos_type relative_position, + const bool if_deriv) const { + if (if_deriv == true) + return BSplines_coef_vector[index] * BSplines_1st_der_weight(relative_position, spline_type); + else + return BSplines_coef_vector[index] * BSplines_weights(relative_position, spline_type); +} + +template +const out_elemT +BSplines1DRegularGrid::operator()(const pos_type relative_position) const { + return BSplines1DRegularGrid::BSplines(relative_position); +} + +//* +template +const std::vector +BSplines1DRegularGrid::BSplines_output_sequence( + RandIterOut output_relative_position_begin_iterator, // relative_position might be better float + RandIterOut output_relative_position_end_iterator) { + std::vector output_vector(output_relative_position_end_iterator - output_relative_position_begin_iterator); + + for (RandIterOut current_iterator = output_vector.begin(), + current_relative_position_iterator = output_relative_position_begin_iterator; + current_iterator != output_vector.end() && current_relative_position_iterator != output_relative_position_end_iterator; + ++current_iterator, ++current_relative_position_iterator) + *current_iterator = BSplines1DRegularGrid::BSplines(*current_relative_position_iterator); + + return output_vector; +} +template +const std::vector +BSplines1DRegularGrid::BSplines_output_sequence(std::vector output_relative_position) { + return BSplines_output_sequence(output_relative_position.begin(), output_relative_position.end()); +} + +} // namespace BSpline END_NAMESPACE_STIR - diff --git a/src/include/stir/numerics/BSplinesDetail.inl b/src/include/stir/numerics/BSplinesDetail.inl index 3a56e168fe..0cea1cc11d 100644 --- a/src/include/stir/numerics/BSplinesDetail.inl +++ b/src/include/stir/numerics/BSplinesDetail.inl @@ -7,19 +7,19 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics_buildblock - \brief Implementation of the B-Splines Interpolation - + \brief Implementation of the B-Splines Interpolation + \author Kris Thielemans \author Charalampos Tsoumpas */ @@ -28,84 +28,67 @@ START_NAMESPACE_STIR namespace BSpline { - ///// implementation functions Out Of the Class //////// - namespace detail { - template - static inline void - set_BSpline_values(constantsT& z1, constantsT& z2, constantsT& lambda, - const BSplineType spline_type) - { - switch(spline_type) - { - case near_n: - z1=static_cast(0); - z2=static_cast(0); - break; - case linear: - z1=static_cast(0); - z2=static_cast(0); - break; - case quadratic: - z1 = static_cast(sqrt(8.)-3); - z2=static_cast(0); - break; - case cubic: - z1 = static_cast(sqrt(3.)-2); - z2=static_cast(0); - break; - case quartic: - z1 = static_cast(sqrt(664.-sqrt(438976.))+sqrt(304.)-19.); - z2 = static_cast(sqrt(664.-sqrt(438976.))-sqrt(304.)-19.); - break; - case quintic: - z1 = static_cast(0.5*(sqrt(270.-sqrt(70980.))+sqrt(105.)-13.)); - z2 = static_cast(0.5*(sqrt(270.-sqrt(70980.))-sqrt(105.)-13.)); - break; - case oMoms: - z1 = static_cast((sqrt(105.)-13.)/8.); - z2 = static_cast(0); - break; - } - lambda = static_cast((1.-z1)*(1. - (1./z1))); - if (z2!=static_cast(0)) - lambda *= static_cast((1.-z2)*(1. - (1./z2))); - } - - - // 1d specialisation - template - void - set_coef(Array<1, out_elemT>& coeffs, const Array<1, in_elemT>& input, - const BasicCoordinate<1,constantsT>& z1s, - const BasicCoordinate<1,constantsT>& z2s, - const BasicCoordinate<1,constantsT>& lambdas) - { - BSplines_coef(coeffs.begin(), coeffs.end(), - input.begin(), input.end(), z1s[1], z2s[1], lambdas[1]); +///// implementation functions Out Of the Class //////// +namespace detail { +template +static inline void +set_BSpline_values(constantsT& z1, constantsT& z2, constantsT& lambda, const BSplineType spline_type) { + switch (spline_type) { + case near_n: + z1 = static_cast(0); + z2 = static_cast(0); + break; + case linear: + z1 = static_cast(0); + z2 = static_cast(0); + break; + case quadratic: + z1 = static_cast(sqrt(8.) - 3); + z2 = static_cast(0); + break; + case cubic: + z1 = static_cast(sqrt(3.) - 2); + z2 = static_cast(0); + break; + case quartic: + z1 = static_cast(sqrt(664. - sqrt(438976.)) + sqrt(304.) - 19.); + z2 = static_cast(sqrt(664. - sqrt(438976.)) - sqrt(304.) - 19.); + break; + case quintic: + z1 = static_cast(0.5 * (sqrt(270. - sqrt(70980.)) + sqrt(105.) - 13.)); + z2 = static_cast(0.5 * (sqrt(270. - sqrt(70980.)) - sqrt(105.) - 13.)); + break; + case oMoms: + z1 = static_cast((sqrt(105.) - 13.) / 8.); + z2 = static_cast(0); + break; + } + lambda = static_cast((1. - z1) * (1. - (1. / z1))); + if (z2 != static_cast(0)) + lambda *= static_cast((1. - z2) * (1. - (1. / z2))); +} + +// 1d specialisation +template +void +set_coef(Array<1, out_elemT>& coeffs, const Array<1, in_elemT>& input, const BasicCoordinate<1, constantsT>& z1s, + const BasicCoordinate<1, constantsT>& z2s, const BasicCoordinate<1, constantsT>& lambdas) { + BSplines_coef(coeffs.begin(), coeffs.end(), input.begin(), input.end(), z1s[1], z2s[1], lambdas[1]); +} + +template +void +set_coef(Array& coeffs, const Array& input, + const BasicCoordinate& z1s, const BasicCoordinate& z2s, + const BasicCoordinate& lambdas) { + Array temp(input.get_index_range()); + BSplines_coef(temp.begin(), temp.end(), input.begin(), input.end(), z1s[1], z2s[1], lambdas[1]); + + for (int i = coeffs.get_min_index(); i <= coeffs.get_max_index(); ++i) { + set_coef(coeffs[i], temp[i], cut_first_dimension(z1s), cut_first_dimension(z2s), cut_first_dimension(lambdas)); } +} - template - void - set_coef(Array& coeffs, - const Array& input, - const BasicCoordinate& z1s, - const BasicCoordinate& z2s, - const BasicCoordinate& lambdas) - { - Array temp ( input.get_index_range()); - BSplines_coef(temp.begin(),temp.end(), - input.begin(), input.end(), z1s[1], z2s[1], lambdas[1]); - - for (int i=coeffs.get_min_index(); i<=coeffs.get_max_index(); ++i) - { - set_coef(coeffs[i], - temp[i], - cut_first_dimension(z1s), - cut_first_dimension(z2s), - cut_first_dimension(lambdas)); - } - } - #if 0 template struct BW @@ -127,227 +110,186 @@ namespace BSpline { } }; #else - template - struct BW - { - typedef pos_type result_type; - pos_type operator()(const pos_type pos, int piece, const PieceWiseFunction& f) - { - return f.function_piece(pos, piece); - } - }; +template +struct BW { + typedef pos_type result_type; + pos_type operator()(const pos_type pos, int piece, const PieceWiseFunction& f) { + return f.function_piece(pos, piece); + } +}; - template - struct Bder - { - typedef pos_type result_type; - pos_type operator()(const pos_type pos, int piece, const PieceWiseFunction& f) - { - return f.derivative_piece(pos, piece); - } - }; +template +struct Bder { + typedef pos_type result_type; + pos_type operator()(const pos_type pos, int piece, const PieceWiseFunction& f) { + return f.derivative_piece(pos, piece); + } +}; #endif - // TODO later - /* - get_value could be used normally to say get_value(coeffs,index) == coeffs[index], - but would allows to use e.g. periodic boundary conditions or extrapolation - */ - template - inline - typename SplineFunctionT::result_type - spline_convolution(const Array& coeffs, - const BasicCoordinate& relative_positions, - const BasicCoordinate& spline_types, - FunctionT f, - SplineFunctionT g) - { - const int current_dimension = num_dimensions2 - num_dimensions + 1; - const PieceWiseFunction& bspline = - bspline_function(spline_types[current_dimension]); +// TODO later +/* + get_value could be used normally to say get_value(coeffs,index) == coeffs[index], + but would allows to use e.g. periodic boundary conditions or extrapolation +*/ +template +inline typename SplineFunctionT::result_type +spline_convolution(const Array& coeffs, const BasicCoordinate& relative_positions, + const BasicCoordinate& spline_types, FunctionT f, SplineFunctionT g) { + const int current_dimension = num_dimensions2 - num_dimensions + 1; + const PieceWiseFunction& bspline = bspline_function(spline_types[current_dimension]); - typename SplineFunctionT::result_type value; - assign(value,0); - const int kmin= static_cast(std::ceil(relative_positions[current_dimension]-bspline.kernel_length_right())); - const int kmax=kmin+bspline.kernel_total_length()-1; - int k=kmin; - pos_type current_pos=relative_positions[current_dimension]-k; - #define NNN + typename SplineFunctionT::result_type value; + assign(value, 0); + const int kmin = static_cast(std::ceil(relative_positions[current_dimension] - bspline.kernel_length_right())); + const int kmax = kmin + bspline.kernel_total_length() - 1; + int k = kmin; + pos_type current_pos = relative_positions[current_dimension] - k; +#define NNN #ifdef NNN - // TODO doesn't work yet when relative_position is an integer: kmin then becomes highest_piece+1 - //int p=bspline.find_highest_piece(); - //assert(p == bspline.find_piece(current_pos)); - int p=bspline.find_piece(current_pos); -#define DECR_P , --p + // TODO doesn't work yet when relative_position is an integer: kmin then becomes highest_piece+1 + // int p=bspline.find_highest_piece(); + // assert(p == bspline.find_piece(current_pos)); + int p = bspline.find_piece(current_pos); +# define DECR_P , --p #else -#define DECR_P +# define DECR_P #endif - for (; k<=kmax; ++k, --current_pos DECR_P) - { - int index; - if (kcoeffs.get_max_index()) index=2*coeffs.get_max_index()-k; - else index = k; - assert(coeffs.get_min_index()<=index && index<=coeffs.get_max_index()); - value += static_cast( - g(coeffs[index], relative_positions, spline_types) * + for (; k <= kmax; ++k, --current_pos DECR_P) { + int index; + if (k < coeffs.get_min_index()) + index = 2 * coeffs.get_min_index() - k; + else if (k > coeffs.get_max_index()) + index = 2 * coeffs.get_max_index() - k; + else + index = k; + assert(coeffs.get_min_index() <= index && index <= coeffs.get_max_index()); + value += static_cast(g(coeffs[index], relative_positions, spline_types) * #ifdef NNN - f(current_pos, p, bspline) + f(current_pos, p, bspline) #else - f(current_pos, spline_types[current_dimension]) + f(current_pos, spline_types[current_dimension]) #endif - ); - } - return value ; + ); } + return value; +} - template - inline - T - spline_convolution(const Array<1, T>& coeffs, - const BasicCoordinate& relative_positions, - const BasicCoordinate& spline_types, - FunctionT f) - { - const int current_dimension = num_dimensions2; - const PieceWiseFunction& bspline = - bspline_function(spline_types[current_dimension]); - T value; - assign(value,0); - //x-1.5(std::ceil(relative_positions[current_dimension]-bspline.kernel_length_right())); - const int kmax=kmin+bspline.kernel_total_length()-1; - int k=kmin; - pos_type current_pos=relative_positions[current_dimension]-k; +template +inline T +spline_convolution(const Array<1, T>& coeffs, const BasicCoordinate& relative_positions, + const BasicCoordinate& spline_types, FunctionT f) { + const int current_dimension = num_dimensions2; + const PieceWiseFunction& bspline = bspline_function(spline_types[current_dimension]); + T value; + assign(value, 0); + // x-1.5(std::ceil(relative_positions[current_dimension] - bspline.kernel_length_right())); + const int kmax = kmin + bspline.kernel_total_length() - 1; + int k = kmin; + pos_type current_pos = relative_positions[current_dimension] - k; #ifdef NNN - // TODO doesn't work yet when relative_position is an integer: kmin then becomes highest_piece+1 - //int p=bspline.find_highest_piece(); - //assert(p == bspline.find_piece(current_pos)); - int p=bspline.find_piece(current_pos); -#define DECR_P , --p + // TODO doesn't work yet when relative_position is an integer: kmin then becomes highest_piece+1 + // int p=bspline.find_highest_piece(); + // assert(p == bspline.find_piece(current_pos)); + int p = bspline.find_piece(current_pos); +# define DECR_P , --p #else -#define DECR_P +# define DECR_P #endif - for (; k<=kmax; ++k, --current_pos DECR_P) - { - int index; - if (kcoeffs.get_max_index()) index=2*coeffs.get_max_index()-k; - else index = k; - assert(coeffs.get_min_index()<=index && index<=coeffs.get_max_index()); - value += - static_cast( - coeffs[index] * + for (; k <= kmax; ++k, --current_pos DECR_P) { + int index; + if (k < coeffs.get_min_index()) + index = 2 * coeffs.get_min_index() - k; + else if (k > coeffs.get_max_index()) + index = 2 * coeffs.get_max_index() - k; + else + index = k; + assert(coeffs.get_min_index() <= index && index <= coeffs.get_max_index()); + value += static_cast(coeffs[index] * #ifdef NNN - f(current_pos, p, bspline) - // bspline.function_piece(current_pos, p) + f(current_pos, p, bspline) + // bspline.function_piece(current_pos, p) #else - f(current_pos, spline_types[current_dimension]) + f(current_pos, spline_types[current_dimension]) #endif - ); - } - return value ; + ); } + return value; +} - template - struct - compute_BSplines_value - { - typedef T result_type; - T operator()(const Array& coeffs, - const BasicCoordinate& relative_positions, - const BasicCoordinate& spline_types) const - { - return - spline_convolution(coeffs, relative_positions, spline_types, - BW(), - //BSplineFunction(), - compute_BSplines_value()); - } - }; +template +struct compute_BSplines_value { + typedef T result_type; + T operator()(const Array& coeffs, const BasicCoordinate& relative_positions, + const BasicCoordinate& spline_types) const { + return spline_convolution(coeffs, relative_positions, spline_types, BW(), + // BSplineFunction(), + compute_BSplines_value()); + } +}; #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) -#define T float - template <> +# define T float +template <> #else - template +template #endif - struct - compute_BSplines_value<1, num_dimensions2,T> - { - typedef T result_type; - T operator()(const Array<1, T>& coeffs, - const BasicCoordinate& relative_positions, - const BasicCoordinate& spline_types) const - { - return - spline_convolution(coeffs, relative_positions, spline_types, - BW() - //BSplineFunction() - ); - } - }; +struct compute_BSplines_value<1, num_dimensions2, T> { + typedef T result_type; + T operator()(const Array<1, T>& coeffs, const BasicCoordinate& relative_positions, + const BasicCoordinate& spline_types) const { + return spline_convolution(coeffs, relative_positions, spline_types, BW() + // BSplineFunction() + ); + } +}; #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) -#undef T -#endif +# undef T +#endif - template - struct - compute_BSplines_gradient - { - typedef BasicCoordinate result_type; +template +struct compute_BSplines_gradient { + typedef BasicCoordinate result_type; - BasicCoordinate - operator()(const Array& coeffs, - const BasicCoordinate& relative_positions, - const BasicCoordinate& spline_types) const - { - const T first_value = - spline_convolution(coeffs, relative_positions, spline_types, - Bder(), - //BSplineFunction(), - compute_BSplines_value()); - const BasicCoordinate rest_value = - spline_convolution(coeffs, relative_positions, spline_types, - BW(), - //BSplineFunction(), - compute_BSplines_gradient()); - return join(first_value, rest_value); - } - }; + BasicCoordinate operator()(const Array& coeffs, + const BasicCoordinate& relative_positions, + const BasicCoordinate& spline_types) const { + const T first_value = spline_convolution(coeffs, relative_positions, spline_types, Bder(), + // BSplineFunction(), + compute_BSplines_value()); + const BasicCoordinate rest_value = + spline_convolution(coeffs, relative_positions, spline_types, BW(), + // BSplineFunction(), + compute_BSplines_gradient()); + return join(first_value, rest_value); + } +}; #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) -#define T float - template <> +# define T float +template <> #else - template +template #endif - struct - compute_BSplines_gradient<1,num_dimensions2,T> - { - typedef BasicCoordinate<1,T> result_type; +struct compute_BSplines_gradient<1, num_dimensions2, T> { + typedef BasicCoordinate<1, T> result_type; - BasicCoordinate<1,T> - operator()(const Array<1, T>& coeffs, - const BasicCoordinate& relative_positions, - const BasicCoordinate& spline_types) const - { - BasicCoordinate<1,T> result; - result[1] = - spline_convolution(coeffs, relative_positions, spline_types, - Bder() - //BSplineFunction() - ); - return result; - } - }; + BasicCoordinate<1, T> operator()(const Array<1, T>& coeffs, + const BasicCoordinate& relative_positions, + const BasicCoordinate& spline_types) const { + BasicCoordinate<1, T> result; + result[1] = spline_convolution(coeffs, relative_positions, spline_types, Bder() + // BSplineFunction() + ); + return result; + } +}; #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) -#undef T -#endif - - +# undef T +#endif -} // end of namespace detail +} // end of namespace detail } // end of namespace BSpline END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/BSplinesRegularGrid.h b/src/include/stir/numerics/BSplinesRegularGrid.h index 4b9a4856f0..843319f7b3 100644 --- a/src/include/stir/numerics/BSplinesRegularGrid.h +++ b/src/include/stir/numerics/BSplinesRegularGrid.h @@ -7,20 +7,20 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ #ifndef __stir_numerics_BSplinesRegularGrid__H__ #define __stir_numerics_BSplinesRegularGrid__H__ /*! - \file + \file \ingroup BSpline - \brief Implementation of the n-dimensional B-Splines Interpolation + \brief Implementation of the n-dimensional B-Splines Interpolation \author Charalampos Tsoumpas \author Kris Thielemans @@ -33,137 +33,109 @@ START_NAMESPACE_STIR namespace BSpline { - /*! \ingroup BSpline - \brief A class for n-dimensional BSpline interpolation when the input samples - are on a regular grid. - - This class provides essentially an n-dimensional function, so can be used as a function object. - - \par Example - \code - Array<3,float> some_data = ....; - - BSplinesRegularGrid<3, float> interpolator(cubic); - - interpolator.set_coef(some_data); - - Coordinate3D position(1.2, 3.4, 5.6); - - float value = interpolator(position); - \endcode - - \warning The implementation currently uses mirror boundary conditions. This means you - can ask for values of the interpolator outside the original grid, but the results - might not be what you expect. - */ - template - class BSplinesRegularGrid - { - - public: - // only there for tests - Array get_coefficients() const - { return this->_coeffs; } - - - - //! constructor given an array of samples and the spline type - inline - explicit - BSplinesRegularGrid(const Array & input, - const BSplineType & this_type = cubic) - { - this->set_private_values(this_type); - this->set_coef(input); - } - - //! constructor given an array of samples and a different spline type for every dimension - inline - BSplinesRegularGrid(const Array & input, - const BasicCoordinate & this_type) - { - this->set_private_values(this_type); - this->set_coef(input); - } - - //! constructor that only sets the spline type - /*! You need to call set_coef() first before you will get a sensible result.*/ - inline - explicit - BSplinesRegularGrid( - const BSplineType & this_type = cubic) - { - this->set_private_values(this_type); - } - - //! constructor that only sets a different spline type for every dimension - /*! You need to call set_coef() first before you will get a sensible result.*/ - inline - explicit - BSplinesRegularGrid(const BasicCoordinate & this_type) - { - this->set_private_values(this_type); - } - - //! destructor - inline ~BSplinesRegularGrid(); - - //! Compute the coefficients for the B-splines from an array of samples. - /*! When the order of the spline is larger than 1, the coefficients multiplying - the basic splines are not equal to the samples. This variable stores them - for further use. - \todo rename - */ - inline - void - set_coef(const Array & input); - - //! Compute value of the interpolator - /*! \param relative_positions - A coordinate with respect to the original grid coordinates as used by the - input array. In particular, if the input array was not 0-based, your - \c relative_positions should not be either. - \return the interpolated value. - - - \todo should probably be templated in pos_type. - */ - inline - const out_elemT - operator() (const BasicCoordinate& relative_positions) const; - - //! Compute gradient of the interpolator - /*! \param relative_positions - A coordinate with respect to the original grid coordinates as used by the - input array. In particular, if the input array was not 0-based, your - \c relative_positions should not be either. - \return the gradient - - \todo should probably be templated in pos_type. - */ - inline - const BasicCoordinate - gradient(const BasicCoordinate& relative_positions) const; - - private: - - // variables that store numbers for the spline type - // TODO these coefficients and the spline type could/should be integrated into 1 class - BasicCoordinate _spline_types; - BasicCoordinate _z1s; - BasicCoordinate _z2s; - BasicCoordinate _lambdas; - //! coefficients for B-splines - Array _coeffs; - - inline void - set_private_values(const BasicCoordinate & this_type); - inline void - set_private_values(const BSplineType & this_type); - - }; - -} // end BSpline namespace +/*! \ingroup BSpline + \brief A class for n-dimensional BSpline interpolation when the input samples + are on a regular grid. + + This class provides essentially an n-dimensional function, so can be used as a function object. + + \par Example + \code + Array<3,float> some_data = ....; + + BSplinesRegularGrid<3, float> interpolator(cubic); + + interpolator.set_coef(some_data); + + Coordinate3D position(1.2, 3.4, 5.6); + + float value = interpolator(position); + \endcode + + \warning The implementation currently uses mirror boundary conditions. This means you + can ask for values of the interpolator outside the original grid, but the results + might not be what you expect. + */ +template +class BSplinesRegularGrid { + +public: + // only there for tests + Array get_coefficients() const { return this->_coeffs; } + + //! constructor given an array of samples and the spline type + inline explicit BSplinesRegularGrid(const Array& input, const BSplineType& this_type = cubic) { + this->set_private_values(this_type); + this->set_coef(input); + } + + //! constructor given an array of samples and a different spline type for every dimension + inline BSplinesRegularGrid(const Array& input, + const BasicCoordinate& this_type) { + this->set_private_values(this_type); + this->set_coef(input); + } + + //! constructor that only sets the spline type + /*! You need to call set_coef() first before you will get a sensible result.*/ + inline explicit BSplinesRegularGrid(const BSplineType& this_type = cubic) { this->set_private_values(this_type); } + + //! constructor that only sets a different spline type for every dimension + /*! You need to call set_coef() first before you will get a sensible result.*/ + inline explicit BSplinesRegularGrid(const BasicCoordinate& this_type) { + this->set_private_values(this_type); + } + + //! destructor + inline ~BSplinesRegularGrid(); + + //! Compute the coefficients for the B-splines from an array of samples. + /*! When the order of the spline is larger than 1, the coefficients multiplying + the basic splines are not equal to the samples. This variable stores them + for further use. + \todo rename + */ + inline void set_coef(const Array& input); + + //! Compute value of the interpolator + /*! \param relative_positions + A coordinate with respect to the original grid coordinates as used by the + input array. In particular, if the input array was not 0-based, your + \c relative_positions should not be either. + \return the interpolated value. + + + \todo should probably be templated in pos_type. + */ + inline const out_elemT operator()(const BasicCoordinate& relative_positions) const; + + //! Compute gradient of the interpolator + /*! \param relative_positions + A coordinate with respect to the original grid coordinates as used by the + input array. In particular, if the input array was not 0-based, your + \c relative_positions should not be either. + \return the gradient + + \todo should probably be templated in pos_type. + */ + inline const BasicCoordinate + gradient(const BasicCoordinate& relative_positions) const; + +private: + // variables that store numbers for the spline type + // TODO these coefficients and the spline type could/should be integrated into 1 class + BasicCoordinate _spline_types; + BasicCoordinate _z1s; + BasicCoordinate _z2s; + BasicCoordinate _lambdas; + //! coefficients for B-splines + Array _coeffs; + + inline void set_private_values(const BasicCoordinate& this_type); + inline void set_private_values(const BSplineType& this_type); +}; + +} // namespace BSpline END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/BSplinesRegularGrid.inl b/src/include/stir/numerics/BSplinesRegularGrid.inl index e921873f5e..305b2046c9 100644 --- a/src/include/stir/numerics/BSplinesRegularGrid.inl +++ b/src/include/stir/numerics/BSplinesRegularGrid.inl @@ -7,18 +7,18 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics_buildblock - \brief Implementation of the B-Splines Interpolation + \brief Implementation of the B-Splines Interpolation \author Kris Thielemans \author Charalampos Tsoumpas @@ -29,58 +29,50 @@ START_NAMESPACE_STIR namespace BSpline { - template -BSplinesRegularGrid:: -~BSplinesRegularGrid() -{} - - template - void BSplinesRegularGrid:: - set_private_values(const BasicCoordinate & this_type) - { - this->_spline_types = this_type; - for ( int i = 1 ; i<=num_dimensions; ++i) - detail::set_BSpline_values(this->_z1s[i],this->_z2s[i],this->_lambdas[i],this_type[i]); - } - - template - void BSplinesRegularGrid:: - set_private_values(const BSplineType & this_type) - { - for ( int i = 1 ; i<=num_dimensions; ++i) - { - this->_spline_types[i] = this_type; - detail::set_BSpline_values(this->_z1s[i],this->_z2s[i],this->_lambdas[i],this_type); - } - } - - template - void BSplinesRegularGrid :: - set_coef(const Array & input) - { - this->_coeffs = Array(input.get_index_range()); - detail::set_coef(this->_coeffs, input, this->_z1s, this->_z2s, this->_lambdas); - } - - - template - const out_elemT - BSplinesRegularGrid:: - operator() (const BasicCoordinate& relative_positions) const - { - return detail::compute_BSplines_value()(this->_coeffs, relative_positions, this->_spline_types); - } +BSplinesRegularGrid::~BSplinesRegularGrid() {} + +template +void +BSplinesRegularGrid::set_private_values( + const BasicCoordinate& this_type) { + this->_spline_types = this_type; + for (int i = 1; i <= num_dimensions; ++i) + detail::set_BSpline_values(this->_z1s[i], this->_z2s[i], this->_lambdas[i], this_type[i]); +} - template - const BasicCoordinate - BSplinesRegularGrid:: - gradient(const BasicCoordinate& relative_positions) const - { - return detail::compute_BSplines_gradient()(this->_coeffs, relative_positions, this->_spline_types); +template +void +BSplinesRegularGrid::set_private_values(const BSplineType& this_type) { + for (int i = 1; i <= num_dimensions; ++i) { + this->_spline_types[i] = this_type; + detail::set_BSpline_values(this->_z1s[i], this->_z2s[i], this->_lambdas[i], this_type); } - +} + +template +void +BSplinesRegularGrid::set_coef(const Array& input) { + this->_coeffs = Array(input.get_index_range()); + detail::set_coef(this->_coeffs, input, this->_z1s, this->_z2s, this->_lambdas); +} + +template +const out_elemT +BSplinesRegularGrid::operator()( + const BasicCoordinate& relative_positions) const { + return detail::compute_BSplines_value()(this->_coeffs, relative_positions, + this->_spline_types); +} + +template +const BasicCoordinate +BSplinesRegularGrid::gradient( + const BasicCoordinate& relative_positions) const { + return detail::compute_BSplines_gradient()(this->_coeffs, relative_positions, + this->_spline_types); +} + } // end of namespace BSpline END_NAMESPACE_STIR - diff --git a/src/include/stir/numerics/BSplines_coef.inl b/src/include/stir/numerics/BSplines_coef.inl index 10a32e1b3c..09ee31e3bd 100644 --- a/src/include/stir/numerics/BSplines_coef.inl +++ b/src/include/stir/numerics/BSplines_coef.inl @@ -15,9 +15,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup BSpline - \brief Implementation of the (cubic) B-Splines Interpolation + \brief Implementation of the (cubic) B-Splines Interpolation \author Charalampos Tsoumpas \author Kris Thielemans @@ -30,114 +30,94 @@ START_NAMESPACE_STIR namespace BSpline { - namespace detail - { - template - inline -#if defined(_MSC_VER) && _MSC_VER<=1300 +namespace detail { +template +inline +#if defined(_MSC_VER) && _MSC_VER <= 1300 float #else - typename std::iterator_traits::value_type + typename std::iterator_traits::value_type #endif - cplus0(const IterT input_begin_iterator, - const IterT input_end_iterator, - const constantsT z1, const constantsT precision, const bool periodicity) - { -#if defined(_MSC_VER) && _MSC_VER<=1300 - typedef float out_elemT; + cplus0(const IterT input_begin_iterator, const IterT input_end_iterator, const constantsT z1, const constantsT precision, + const bool periodicity) { +#if defined(_MSC_VER) && _MSC_VER <= 1300 + typedef float out_elemT; #else - typedef typename std::iterator_traits::value_type out_elemT; + typedef typename std::iterator_traits::value_type out_elemT; #endif - - const int input_size = static_cast(input_end_iterator - input_begin_iterator); - // assert(input_size>BSplines_coef_vector.size()); - out_elemT sum=*input_begin_iterator; - for(int i=1; - i<(int)ceil(log(precision)/log(fabs(z1))) && i<=2*input_size-3; - ++i) - { - int index = i; - if (periodicity==0 && i >= input_size) - index = 2*input_size-2-i; - sum += static_cast(*(input_begin_iterator+index)*pow(z1,i)); - } - //if (periodicity==1) - - return static_cast(sum/(1-pow(z1,2*input_size-2))); - } - } // end of namespace detail - - template - void - BSplines_coef(RandIterOut c_begin_iterator, - RandIterOut c_end_iterator, - IterT input_begin_iterator, - IterT input_end_iterator, - const constantsT z1, const constantsT z2, const constantsT lamda) - { -#if defined(_MSC_VER) && _MSC_VER<=1300 - typedef float out_elemT; - // typedef float in_elemT; - //typedef typename _Val_Type(c_begin_iterator) out_elemT; - //typedef typename _Val_Type(c_begin_iterator) in_elemT; + const int input_size = static_cast(input_end_iterator - input_begin_iterator); + // assert(input_size>BSplines_coef_vector.size()); + out_elemT sum = *input_begin_iterator; + for (int i = 1; i < (int)ceil(log(precision) / log(fabs(z1))) && i <= 2 * input_size - 3; ++i) { + int index = i; + if (periodicity == 0 && i >= input_size) + index = 2 * input_size - 2 - i; + sum += static_cast(*(input_begin_iterator + index) * pow(z1, i)); + } + // if (periodicity==1) + + return static_cast(sum / (1 - pow(z1, 2 * input_size - 2))); +} +} // end of namespace detail + +template +void +BSplines_coef(RandIterOut c_begin_iterator, RandIterOut c_end_iterator, IterT input_begin_iterator, IterT input_end_iterator, + const constantsT z1, const constantsT z2, const constantsT lamda) { + +#if defined(_MSC_VER) && _MSC_VER <= 1300 + typedef float out_elemT; + // typedef float in_elemT; + // typedef typename _Val_Type(c_begin_iterator) out_elemT; + // typedef typename _Val_Type(c_begin_iterator) in_elemT; #else - typedef typename std::iterator_traits::value_type out_elemT; - // typedef typename std::iterator_traits::value_type in_elemT; + typedef typename std::iterator_traits::value_type out_elemT; + // typedef typename std::iterator_traits::value_type in_elemT; #endif - - /* - cplus(c_end_iterator-c_begin_iterator, 0) - cminus(c_end_iterator-c_begin_iterator, 0), - */ - //const int input_size = c_end_iterator-c_begin_iterator ; //-1; //!!! - - if (z1==0 && z2==0) //Linear and Nearest Neighbour coefficients are the same to the input data - { - IterT current_input_iterator = input_begin_iterator; - for(RandIterOut current_iterator=c_begin_iterator; - current_iterator!=c_end_iterator && current_input_iterator!=input_end_iterator; - ++current_iterator,++current_input_iterator) - *current_iterator= (out_elemT)(*current_input_iterator); - - // copy(input_begin_iterator, input_end_iterator, c_begin_iterator); - } - else - { - typedef std::vector c_vector_type; - c_vector_type cplus(c_end_iterator-c_begin_iterator), - cminus(c_end_iterator-c_begin_iterator); - std::vector - input_factor_for_cminus(1, -z1), pole_for_cplus(1, -z1), pole_for_cminus(1,-z1); - assign(cplus,0); - assign(cminus,0); - std::vector input_factor_for_cplus(1, (constantsT)1); - - *(cplus.begin())=detail::cplus0( - input_begin_iterator,input_end_iterator, z1,static_cast(.00001),0); //k or Nmax_precision - - IIR_filter(cplus.begin(), cplus.end(), - input_begin_iterator, input_end_iterator, - input_factor_for_cplus.begin(), input_factor_for_cplus.end(), - pole_for_cplus.begin(), pole_for_cplus.end(), 1); - - *(cminus.end()-1) = static_cast((*(cplus.end()-1) + (*(cplus.end()-2))*z1)*z1/(z1*z1-1)); - IIR_filter(cminus.rbegin(), cminus.rend(), - cplus.rbegin(), cplus.rend(), - input_factor_for_cminus.begin(), input_factor_for_cminus.end(), - pole_for_cminus.begin(), pole_for_cminus.end(), 1); - - RandIterOut current_iterator=c_begin_iterator; - typename c_vector_type::const_iterator current_cminus_iterator=cminus.begin(); - for(; - current_iterator!=c_end_iterator && current_cminus_iterator!=cminus.end(); - ++current_iterator,++current_cminus_iterator) - { - *current_iterator=static_cast(*current_cminus_iterator*lamda); - } - } + + /* + cplus(c_end_iterator-c_begin_iterator, 0) + cminus(c_end_iterator-c_begin_iterator, 0), + */ + // const int input_size = c_end_iterator-c_begin_iterator ; //-1; //!!! + + if (z1 == 0 && z2 == 0) // Linear and Nearest Neighbour coefficients are the same to the input data + { + IterT current_input_iterator = input_begin_iterator; + for (RandIterOut current_iterator = c_begin_iterator; + current_iterator != c_end_iterator && current_input_iterator != input_end_iterator; + ++current_iterator, ++current_input_iterator) + *current_iterator = (out_elemT)(*current_input_iterator); + + // copy(input_begin_iterator, input_end_iterator, c_begin_iterator); + } else { + typedef std::vector c_vector_type; + c_vector_type cplus(c_end_iterator - c_begin_iterator), cminus(c_end_iterator - c_begin_iterator); + std::vector input_factor_for_cminus(1, -z1), pole_for_cplus(1, -z1), pole_for_cminus(1, -z1); + assign(cplus, 0); + assign(cminus, 0); + std::vector input_factor_for_cplus(1, (constantsT)1); + + *(cplus.begin()) = + detail::cplus0(input_begin_iterator, input_end_iterator, z1, static_cast(.00001), 0); // k or Nmax_precision + + IIR_filter(cplus.begin(), cplus.end(), input_begin_iterator, input_end_iterator, input_factor_for_cplus.begin(), + input_factor_for_cplus.end(), pole_for_cplus.begin(), pole_for_cplus.end(), 1); + + *(cminus.end() - 1) = static_cast((*(cplus.end() - 1) + (*(cplus.end() - 2)) * z1) * z1 / (z1 * z1 - 1)); + IIR_filter(cminus.rbegin(), cminus.rend(), cplus.rbegin(), cplus.rend(), input_factor_for_cminus.begin(), + input_factor_for_cminus.end(), pole_for_cminus.begin(), pole_for_cminus.end(), 1); + + RandIterOut current_iterator = c_begin_iterator; + typename c_vector_type::const_iterator current_cminus_iterator = cminus.begin(); + for (; current_iterator != c_end_iterator && current_cminus_iterator != cminus.end(); + ++current_iterator, ++current_cminus_iterator) { + *current_iterator = static_cast(*current_cminus_iterator * lamda); + } } +} -} // end BSpline namespace +} // namespace BSpline END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/BSplines_weights.inl b/src/include/stir/numerics/BSplines_weights.inl index ac79587173..f2c3f74067 100644 --- a/src/include/stir/numerics/BSplines_weights.inl +++ b/src/include/stir/numerics/BSplines_weights.inl @@ -18,212 +18,159 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup BSpline - \brief Implementation of the B-Splines Interpolation + \brief Implementation of the B-Splines Interpolation \author Charalampos Tsoumpas \author Kris Thielemans */ - START_NAMESPACE_STIR -namespace BSpline -{ - - template - class PieceWiseFunction - { - public: - typedef posT result_type; - - virtual ~PieceWiseFunction() {} - - virtual posT kernel_length_left() const = 0; - virtual int kernel_total_length() const = 0; - posT kernel_length_right() const - { return -this->kernel_length_left() + this->kernel_total_length(); } - - virtual posT function_piece(const posT x, int p) const = 0; - virtual posT derivative_piece(const posT x, int p) const = 0; - virtual int find_piece(const posT x) const = 0; - virtual int find_highest_piece() const = 0; - posT function(const posT x) const - { - return this->function_piece(x, find_piece(x)); - } - posT derivative(const posT x) const - { - return this->derivative_piece(x, find_piece(x)); - } - posT operator()(const posT x) const - { - return this->function(x); - } - posT operator()(const posT p, const BSplineType) - { - return this->function(p); - } - - }; - - template - class BSplineFunction : public PieceWiseFunction - {}; - - template - class BSplineFunction: public PieceWiseFunction - { - public: - BSplineFunction() {} - posT kernel_length_left() const { return static_cast(.5); } - BOOST_STATIC_CONSTANT(int, kernel_total_length_value=1); - int kernel_total_length() const { return kernel_total_length_value; } - posT function_piece(const posT x, int p) const - { - switch (p) - { - case 0: - return static_cast(1); - // todo probably should add another piece containing a just .5, now returns 0 - default: - return 0; - } - } - posT derivative_piece(const posT, int ) const - { +namespace BSpline { + +template +class PieceWiseFunction { +public: + typedef posT result_type; + + virtual ~PieceWiseFunction() {} + + virtual posT kernel_length_left() const = 0; + virtual int kernel_total_length() const = 0; + posT kernel_length_right() const { return -this->kernel_length_left() + this->kernel_total_length(); } + + virtual posT function_piece(const posT x, int p) const = 0; + virtual posT derivative_piece(const posT x, int p) const = 0; + virtual int find_piece(const posT x) const = 0; + virtual int find_highest_piece() const = 0; + posT function(const posT x) const { return this->function_piece(x, find_piece(x)); } + posT derivative(const posT x) const { return this->derivative_piece(x, find_piece(x)); } + posT operator()(const posT x) const { return this->function(x); } + posT operator()(const posT p, const BSplineType) { return this->function(p); } +}; + +template +class BSplineFunction : public PieceWiseFunction {}; + +template +class BSplineFunction : public PieceWiseFunction { +public: + BSplineFunction() {} + posT kernel_length_left() const { return static_cast(.5); } + BOOST_STATIC_CONSTANT(int, kernel_total_length_value = 1); + int kernel_total_length() const { return kernel_total_length_value; } + posT function_piece(const posT x, int p) const { + switch (p) { + case 0: + return static_cast(1); + // todo probably should add another piece containing a just .5, now returns 0 + default: return 0; } - - int find_abs_piece(const posT absx) const - { - return static_cast(absx+.5); - } - int find_piece(const posT x) const - { - const int abs_p = this->find_abs_piece(fabs(x)); - if (x>0) - return abs_p; - else - return -abs_p; + } + posT derivative_piece(const posT, int) const { return 0; } + + int find_abs_piece(const posT absx) const { return static_cast(absx + .5); } + int find_piece(const posT x) const { + const int abs_p = this->find_abs_piece(fabs(x)); + if (x > 0) + return abs_p; + else + return -abs_p; + } + int find_highest_piece() const { return 0; } +}; + +template +class BSplineFunction : public PieceWiseFunction { +public: + BSplineFunction() {} + posT kernel_length_left() const { return static_cast(1); } + BOOST_STATIC_CONSTANT(int, kernel_total_length_value = 2); + int kernel_total_length() const { return kernel_total_length_value; } + posT function_piece(const posT x, int p) const { + switch (p) { + case 0: + return 1 - x; + case -1: + return 1 + x; + default: + return 0; } - int find_highest_piece() const - { + } + posT derivative_piece(const posT x, int p) const { + switch (p) { + case 0: + return -1; + case -1: + return 1; + default: return 0; } - }; - - template - class BSplineFunction: public PieceWiseFunction - { - public: - BSplineFunction() {} - posT kernel_length_left() const { return static_cast(1); } - BOOST_STATIC_CONSTANT(int, kernel_total_length_value=2); - int kernel_total_length() const { return kernel_total_length_value; } - posT function_piece(const posT x, int p) const - { - switch (p) - { - case 0: - return 1-x; - case -1: - return 1+x; - default: - return 0; - } + } + int find_piece(const posT x) const { return static_cast(floor(x)); } + + int find_highest_piece() const { return 0; } +}; + +template +class BSplineFunction : public PieceWiseFunction { +public: + BSplineFunction() {} + posT kernel_length_left() const { return static_cast(1.5); } + BOOST_STATIC_CONSTANT(int, kernel_total_length_value = 3); + int kernel_total_length() const { return kernel_total_length_value; } + posT function_piece(const posT x, int p) const { + switch (std::abs(p)) { + case 0: + return static_cast(3) / 4 - square(x); + case 1: { + const posT absx = std::fabs(x); + return square(2 * absx - 3) / 8; } - posT derivative_piece(const posT x, int p) const - { - switch (p) - { - case 0: - return -1; - case -1: - return 1; - default: - return 0; - } + default: + return 0; } - int find_piece(const posT x) const - { - return static_cast(floor(x)); + } + posT derivative_piece(const posT x, int p) const { + switch (std::abs(p)) { + case 0: + return -2 * x; + case 1: { + const int sign = x > 0 ? 1 : -1; + return x - sign * static_cast(1.5); } - - int find_highest_piece() const - { + default: return 0; } - }; + } - template - class BSplineFunction: public PieceWiseFunction - { - public: - BSplineFunction() {} - posT kernel_length_left() const { return static_cast(1.5); } - BOOST_STATIC_CONSTANT(int, kernel_total_length_value=3); - int kernel_total_length() const { return kernel_total_length_value; } - posT function_piece(const posT x, int p) const - { - switch (std::abs(p)) - { - case 0: - return static_cast(3)/4 - square(x); - case 1: - { - const posT absx = std::fabs(x); - return square(2*absx - 3)/8; - } - default: - return 0; - } - } - posT derivative_piece(const posT x, int p) const - { - switch (std::abs(p)) - { - case 0: - return -2*x; - case 1: - { - const int sign= x>0?1:-1; - return x - sign*static_cast(1.5); - } - default: - return 0; - } - } - private: - int find_abs_piece(const posT absx) const - { +private: + int find_abs_piece(const posT absx) const { #if 1 - return static_cast(absx+.5); + return static_cast(absx + .5); #else - // can use this if guaranteed never out of range - if (absx<=.5) - return 0; - else if (absx<=1.5) - return 1; - else - return 2; + // can use this if guaranteed never out of range + if (absx <= .5) + return 0; + else if (absx <= 1.5) + return 1; + else + return 2; #endif + } - } - public: - int find_piece(const posT x) const - { - const int abs_p = this->find_abs_piece(fabs(x)); - if (x>0) - return abs_p; - else - return -abs_p; - } - int find_highest_piece() const - { - return 1; - } +public: + int find_piece(const posT x) const { + const int abs_p = this->find_abs_piece(fabs(x)); + if (x > 0) + return abs_p; + else + return -abs_p; + } + int find_highest_piece() const { return 1; } #if 0 posT function(const posT x) const @@ -240,243 +187,200 @@ namespace BSpline return 0; } #endif - }; - - template - class BSplineFunction: public PieceWiseFunction - { - public: - BSplineFunction() {} - posT kernel_length_left() const { return static_cast(2); } - BOOST_STATIC_CONSTANT(int, kernel_total_length_value=4); - int kernel_total_length() const { return kernel_total_length_value; } - posT function_piece(const posT x, int p) const - { - const posT absx = std::fabs(x); - switch (p) - { - case 0: - case -1: - return 2./3. + (absx/2-1)*absx*absx; - case 1: - case -2: - { - const posT tmp=2-absx; - return tmp*tmp*tmp/6; - } - default: - return 0; - } +}; + +template +class BSplineFunction : public PieceWiseFunction { +public: + BSplineFunction() {} + posT kernel_length_left() const { return static_cast(2); } + BOOST_STATIC_CONSTANT(int, kernel_total_length_value = 4); + int kernel_total_length() const { return kernel_total_length_value; } + posT function_piece(const posT x, int p) const { + const posT absx = std::fabs(x); + switch (p) { + case 0: + case -1: + return 2. / 3. + (absx / 2 - 1) * absx * absx; + case 1: + case -2: { + const posT tmp = 2 - absx; + return tmp * tmp * tmp / 6; } - posT derivative_piece(const posT x, int p) const - { - switch (p) - { - case 0: - return x*(1.5*x-2); - case -1: - return -x*(1.5*x+2); - case 1: - return -square(x-2)/2; - case -2: - return square(x+2)/2; - default: - return 0; - } - } - int find_piece(const posT x) const - { - return static_cast(floor(x)); - } - int find_highest_piece() const - { - return 1; - } - }; - - - template - class BSplineFunction: public PieceWiseFunction - { - public: - BSplineFunction() {} - posT kernel_length_left() const { return static_cast(2); } - BOOST_STATIC_CONSTANT(int, kernel_total_length_value=4); - int kernel_total_length() const { return kernel_total_length_value; } - posT function_piece(const posT x, int p) const - { - const posT absx = std::fabs(x); - switch (p) - { - case 0: - case -1: - return 13./21. + absx*(1./14. +absx*(absx/2-1)) ; - case 1: - case -2: - return 29./21. + absx*(-85./42. + absx*(1-absx/6)) ; - default: - return 0; - } - } - posT derivative_piece(const posT x, int p) const - { - const posT absx = std::fabs(x); - const int sign=x>0?1:-1; - switch (p) - { - case 0: - case -1: - return sign*(1/14. + absx*(-2+3*absx/2)); - case 1: - case -2: - return sign*(-85/42. + absx*(2-absx/2)); - default: - return 0; - } - } - int find_piece(const posT x) const - { - return static_cast(floor(x)); + default: + return 0; } - int find_highest_piece() const - { - return 1; + } + posT derivative_piece(const posT x, int p) const { + switch (p) { + case 0: + return x * (1.5 * x - 2); + case -1: + return -x * (1.5 * x + 2); + case 1: + return -square(x - 2) / 2; + case -2: + return square(x + 2) / 2; + default: + return 0; } - }; - - static const BSplineFunction near_n_BSpline_function; - static const BSplineFunction linear_BSpline_function; - static const BSplineFunction quadratic_BSpline_function; - static const BSplineFunction cubic_BSpline_function; - static const BSplineFunction oMoms_BSpline_function; - - inline - const PieceWiseFunction& - bspline_function(BSplineType type) - { - switch (type) - { - case near_n: - return near_n_BSpline_function; - case linear: - return linear_BSpline_function; - case quadratic: - return quadratic_BSpline_function; - case cubic: - return cubic_BSpline_function; - case oMoms: - return oMoms_BSpline_function; - default: - std::cerr << "quartic,quantic to do\n"; - exit(EXIT_FAILURE); - return cubic_BSpline_function;//WARNING WRONG - } } - - template - inline - posT - cubic_BSplines_weight(const posT relative_position) - { - const posT abs_relative_position = fabs(relative_position); - assert(abs_relative_position>=0); - if (abs_relative_position<1) - return 2./3. + (0.5*abs_relative_position-1)*abs_relative_position*abs_relative_position; - if (abs_relative_position>=2) + int find_piece(const posT x) const { return static_cast(floor(x)); } + int find_highest_piece() const { return 1; } +}; + +template +class BSplineFunction : public PieceWiseFunction { +public: + BSplineFunction() {} + posT kernel_length_left() const { return static_cast(2); } + BOOST_STATIC_CONSTANT(int, kernel_total_length_value = 4); + int kernel_total_length() const { return kernel_total_length_value; } + posT function_piece(const posT x, int p) const { + const posT absx = std::fabs(x); + switch (p) { + case 0: + case -1: + return 13. / 21. + absx * (1. / 14. + absx * (absx / 2 - 1)); + case 1: + case -2: + return 29. / 21. + absx * (-85. / 42. + absx * (1 - absx / 6)); + default: return 0; - const posT tmp=2-abs_relative_position; - return tmp*tmp*tmp/6; - + } } - - - template - inline - posT - oMoms_weight(const posT relative_position) - { - const posT abs_relative_position = fabs(relative_position); - assert(abs_relative_position>=0); - if (abs_relative_position>=2) + posT derivative_piece(const posT x, int p) const { + const posT absx = std::fabs(x); + const int sign = x > 0 ? 1 : -1; + switch (p) { + case 0: + case -1: + return sign * (1 / 14. + absx * (-2 + 3 * absx / 2)); + case 1: + case -2: + return sign * (-85 / 42. + absx * (2 - absx / 2)); + default: return 0; - if (abs_relative_position>=1) - return 29./21. + abs_relative_position*(-85./42. + - abs_relative_position*(1.-abs_relative_position/6)) ; - else - return 13./21. + abs_relative_position*(1./14. + - abs_relative_position*(0.5*abs_relative_position-1.)) ; + } } - - template - inline - posT - cubic_BSplines_1st_der_weight(const posT relative_position) - { - const posT abs_relative_position = fabs(relative_position); - if (abs_relative_position>=2) + int find_piece(const posT x) const { return static_cast(floor(x)); } + int find_highest_piece() const { return 1; } +}; + +static const BSplineFunction near_n_BSpline_function; +static const BSplineFunction linear_BSpline_function; +static const BSplineFunction quadratic_BSpline_function; +static const BSplineFunction cubic_BSpline_function; +static const BSplineFunction oMoms_BSpline_function; + +inline const PieceWiseFunction& +bspline_function(BSplineType type) { + switch (type) { + case near_n: + return near_n_BSpline_function; + case linear: + return linear_BSpline_function; + case quadratic: + return quadratic_BSpline_function; + case cubic: + return cubic_BSpline_function; + case oMoms: + return oMoms_BSpline_function; + default: + std::cerr << "quartic,quantic to do\n"; + exit(EXIT_FAILURE); + return cubic_BSpline_function; // WARNING WRONG + } +} + +template +inline posT +cubic_BSplines_weight(const posT relative_position) { + const posT abs_relative_position = fabs(relative_position); + assert(abs_relative_position >= 0); + if (abs_relative_position < 1) + return 2. / 3. + (0.5 * abs_relative_position - 1) * abs_relative_position * abs_relative_position; + if (abs_relative_position >= 2) + return 0; + const posT tmp = 2 - abs_relative_position; + return tmp * tmp * tmp / 6; +} + +template +inline posT +oMoms_weight(const posT relative_position) { + const posT abs_relative_position = fabs(relative_position); + assert(abs_relative_position >= 0); + if (abs_relative_position >= 2) + return 0; + if (abs_relative_position >= 1) + return 29. / 21. + abs_relative_position * (-85. / 42. + abs_relative_position * (1. - abs_relative_position / 6)); + else + return 13. / 21. + abs_relative_position * (1. / 14. + abs_relative_position * (0.5 * abs_relative_position - 1.)); +} + +template +inline posT +cubic_BSplines_1st_der_weight(const posT relative_position) { + const posT abs_relative_position = fabs(relative_position); + if (abs_relative_position >= 2) + return 0; + int sign = relative_position > 0 ? 1 : -1; + if (abs_relative_position >= 1) + return -0.5 * sign * (abs_relative_position - 2) * (abs_relative_position - 2); + return sign * abs_relative_position * (1.5 * abs_relative_position - 2.); +} + +template +posT +BSplines_1st_der_weight(const posT relative_position, const BSplineType spline_type) { + switch (spline_type) { + case cubic: + return cubic_BSplines_1st_der_weight(relative_position); + default: + error("BSplines_1st_der_weight currently only implemented for cubic splines."); + return 0; + // TODO + } +} + +template +posT +BSplines_weights(const posT relative_position, const BSplineType spline_type) { + // double relative_position = rel_position; + switch (spline_type) { + case cubic: + return cubic_BSplines_weight(relative_position); + case near_n: { + if (fabs(relative_position) < 0.5) + return 1; + if (fabs(relative_position) == 0.5) + return 0.5; + else return 0; - int sign = relative_position>0?1:-1; - if (abs_relative_position>=1) - return -0.5*sign*(abs_relative_position-2)*(abs_relative_position-2); - return sign*abs_relative_position*(1.5*abs_relative_position-2.); } - - template - posT - BSplines_1st_der_weight(const posT relative_position, const BSplineType spline_type) - { - switch(spline_type) - { - case cubic: - return cubic_BSplines_1st_der_weight(relative_position); - default: - error("BSplines_1st_der_weight currently only implemented for cubic splines."); - return 0; - // TODO - } + case linear: { + if (fabs(relative_position) < 1) + return 1 - fabs(relative_position); + else + return 0; } - - template - posT - BSplines_weights(const posT relative_position, const BSplineType spline_type) - { - // double relative_position = rel_position; - switch(spline_type) - { - case cubic: - return cubic_BSplines_weight(relative_position); - case near_n: - { - if (fabs(relative_position)<0.5) - return 1; - if (fabs(relative_position)==0.5) - return 0.5; - else return 0; - } - case linear: - { - if (fabs(relative_position)<1) - return 1-fabs(relative_position); - else - return 0; - } - case quadratic: - return BSplineFunction().function(relative_position); - case quintic: - return - (pow(std::max(0.,-3. + relative_position),5) - 6*pow(std::max(0.,-2. + relative_position),5) + - 15*pow(std::max(0.,-1. + relative_position),5) - 20*pow(std::max(static_cast(0),relative_position),5) + - 15*pow(std::max(0.,1. + relative_position),5) - 6*pow(std::max(0.,2. + relative_position),5) + - pow(std::max(0.,3. + relative_position),5))/ 120. ; - case oMoms: - return oMoms_weight(relative_position); - default: - error("Not implemented b-spline type"); - return -1000000; - } + case quadratic: + return BSplineFunction().function(relative_position); + case quintic: + return (pow(std::max(0., -3. + relative_position), 5) - 6 * pow(std::max(0., -2. + relative_position), 5) + + 15 * pow(std::max(0., -1. + relative_position), 5) - 20 * pow(std::max(static_cast(0), relative_position), 5) + + 15 * pow(std::max(0., 1. + relative_position), 5) - 6 * pow(std::max(0., 2. + relative_position), 5) + + pow(std::max(0., 3. + relative_position), 5)) / + 120.; + case oMoms: + return oMoms_weight(relative_position); + default: + error("Not implemented b-spline type"); + return -1000000; } +} -} // end BSpline namespace +} // namespace BSpline END_NAMESPACE_STIR - diff --git a/src/include/stir/numerics/IR_filters.h b/src/include/stir/numerics/IR_filters.h index e9742b23f3..3873de9532 100644 --- a/src/include/stir/numerics/IR_filters.h +++ b/src/include/stir/numerics/IR_filters.h @@ -17,7 +17,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics \brief Implementation of the IIR and FIR filters @@ -36,37 +36,19 @@ START_NAMESPACE_STIR /*\ingroup numerics \brief IIR filter */ -template -void -inline -IIR_filter(RandIter1 output_begin_iterator, - RandIter1 output_end_iterator, - const RandIter2 input_begin_iterator, - const RandIter2 input_end_iterator, - const RandIter3 input_factor_begin_iterator, - const RandIter3 input_factor_end_iterator, - const RandIter4 pole_begin_iterator, - const RandIter4 pole_end_iterator, - const bool if_initial_exists); +template +void inline IIR_filter(RandIter1 output_begin_iterator, RandIter1 output_end_iterator, const RandIter2 input_begin_iterator, + const RandIter2 input_end_iterator, const RandIter3 input_factor_begin_iterator, + const RandIter3 input_factor_end_iterator, const RandIter4 pole_begin_iterator, + const RandIter4 pole_end_iterator, const bool if_initial_exists); /*\ingroup numerics \brief IIR filter */ -template -void -inline -FIR_filter(RandIter1 output_begin_iterator, - RandIter1 output_end_iterator, - const RandIter2 input_begin_iterator, - const RandIter2 input_end_iterator, - const RandIter3 input_factor_begin_iterator, - const RandIter3 input_factor_end_iterator, - const bool if_initial_exists); +template +void inline FIR_filter(RandIter1 output_begin_iterator, RandIter1 output_end_iterator, const RandIter2 input_begin_iterator, + const RandIter2 input_end_iterator, const RandIter3 input_factor_begin_iterator, + const RandIter3 input_factor_end_iterator, const bool if_initial_exists); END_NAMESPACE_STIR #include "stir/numerics/IR_filters.inl" diff --git a/src/include/stir/numerics/IR_filters.inl b/src/include/stir/numerics/IR_filters.inl index d9d0a5aa26..95ad257044 100644 --- a/src/include/stir/numerics/IR_filters.inl +++ b/src/include/stir/numerics/IR_filters.inl @@ -16,7 +16,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics \brief implements the IR_filters @@ -26,101 +26,67 @@ START_NAMESPACE_STIR -template -void -inline -IIR_filter(RandIter1 output_begin_iterator, - RandIter1 output_end_iterator, - const RandIter2 input_begin_iterator, - const RandIter2 input_end_iterator, - const RandIter3 input_factor_begin_iterator, - const RandIter3 input_factor_end_iterator, - const RandIter4 pole_begin_iterator, - const RandIter4 pole_end_iterator, - const bool if_initial_exists) -{ +template +void inline IIR_filter(RandIter1 output_begin_iterator, RandIter1 output_end_iterator, const RandIter2 input_begin_iterator, + const RandIter2 input_end_iterator, const RandIter3 input_factor_begin_iterator, + const RandIter3 input_factor_end_iterator, const RandIter4 pole_begin_iterator, + const RandIter4 pole_end_iterator, const bool if_initial_exists) { // The input should be initialised to 0 // if(output_begin_iterator==output_end_iterator) // warning("No output signal is given./n"); #if 1 - if(if_initial_exists==false) - *output_begin_iterator=(*input_begin_iterator)*(*input_factor_begin_iterator); + if (if_initial_exists == false) + *output_begin_iterator = (*input_begin_iterator) * (*input_factor_begin_iterator); #else // an attempt to remove warnings by VC++, but it doesn't work for higher-dimensional arrays typedef typename CastScalarForOperation::value_type>::type cast_type; - if(if_initial_exists==false) - *output_begin_iterator=(*input_begin_iterator)*static_cast(*input_factor_begin_iterator); + if (if_initial_exists == false) + *output_begin_iterator = (*input_begin_iterator) * static_cast(*input_factor_begin_iterator); #endif - RandIter1 current_output_iterator = output_begin_iterator ; - RandIter2 current_input_iterator = input_begin_iterator ; - - for(++current_output_iterator, ++current_input_iterator; - current_output_iterator != output_end_iterator && - current_input_iterator != input_end_iterator; - ++current_output_iterator, ++current_input_iterator) - { - RandIter2 current_current_input_iterator = current_input_iterator; - for(RandIter3 current_input_factor_iterator = input_factor_begin_iterator; - current_input_factor_iterator != input_factor_end_iterator; - ++current_input_factor_iterator,--current_current_input_iterator - ) - { + RandIter1 current_output_iterator = output_begin_iterator; + RandIter2 current_input_iterator = input_begin_iterator; + + for (++current_output_iterator, ++current_input_iterator; + current_output_iterator != output_end_iterator && current_input_iterator != input_end_iterator; + ++current_output_iterator, ++current_input_iterator) { + RandIter2 current_current_input_iterator = current_input_iterator; + for (RandIter3 current_input_factor_iterator = input_factor_begin_iterator; + current_input_factor_iterator != input_factor_end_iterator; + ++current_input_factor_iterator, --current_current_input_iterator) { #if 1 - (*current_output_iterator) += - (*current_current_input_iterator) * - (*current_input_factor_iterator); + (*current_output_iterator) += (*current_current_input_iterator) * (*current_input_factor_iterator); #else - (*current_output_iterator) += - (*current_current_input_iterator) * - static_cast(*current_input_factor_iterator); + (*current_output_iterator) += (*current_current_input_iterator) * static_cast(*current_input_factor_iterator); #endif - if (current_current_input_iterator==input_begin_iterator) - break; - } + if (current_current_input_iterator == input_begin_iterator) + break; + } + + RandIter4 current_pole_iterator = pole_begin_iterator; + RandIter1 current_feedback_iterator = current_output_iterator; - RandIter4 current_pole_iterator = pole_begin_iterator; - RandIter1 current_feedback_iterator = current_output_iterator ; - - for(--current_feedback_iterator ; - current_pole_iterator != pole_end_iterator - ;++current_pole_iterator,--current_feedback_iterator) - { - (*current_output_iterator) -= + for (--current_feedback_iterator; current_pole_iterator != pole_end_iterator; + ++current_pole_iterator, --current_feedback_iterator) { + (*current_output_iterator) -= #if 1 - (*current_feedback_iterator) * - (*current_pole_iterator); + (*current_feedback_iterator) * (*current_pole_iterator); #else - (*current_feedback_iterator) * - static_cast(*current_pole_iterator); + (*current_feedback_iterator) * static_cast(*current_pole_iterator); #endif - if(current_feedback_iterator==output_begin_iterator) - break; - } + if (current_feedback_iterator == output_begin_iterator) + break; } + } } -template -void -inline -FIR_filter(RandIter1 output_begin_iterator, - RandIter1 output_end_iterator, - const RandIter2 input_begin_iterator, - const RandIter2 input_end_iterator, - const RandIter3 input_factor_begin_iterator, - const RandIter3 input_factor_end_iterator, - const bool if_initial_exists) -{ - IIR_filter(output_begin_iterator, output_end_iterator, - input_begin_iterator, input_end_iterator, - input_factor_begin_iterator, input_factor_end_iterator, - output_begin_iterator, output_begin_iterator,if_initial_exists); +template +void inline FIR_filter(RandIter1 output_begin_iterator, RandIter1 output_end_iterator, const RandIter2 input_begin_iterator, + const RandIter2 input_end_iterator, const RandIter3 input_factor_begin_iterator, + const RandIter3 input_factor_end_iterator, const bool if_initial_exists) { + IIR_filter(output_begin_iterator, output_end_iterator, input_begin_iterator, input_end_iterator, input_factor_begin_iterator, + input_factor_end_iterator, output_begin_iterator, output_begin_iterator, if_initial_exists); } END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/MatrixFunction.h b/src/include/stir/numerics/MatrixFunction.h index 08b9f09b2d..fcb19a568d 100644 --- a/src/include/stir/numerics/MatrixFunction.h +++ b/src/include/stir/numerics/MatrixFunction.h @@ -21,9 +21,9 @@ /*! \file \ingroup numerics - + \brief Declaration of functions for matrices - + \author Kris Thielemans \author Sanida Mustafovic @@ -33,7 +33,6 @@ START_NAMESPACE_STIR - //---------------------------------------------------------------------- /*! \ingroup numerics \name functions specific for 1D Arrays @@ -41,27 +40,24 @@ START_NAMESPACE_STIR //@{ //! Inner product of 2 1D arrays -/*! \ingroup numerics +/*! \ingroup numerics This returns the sum of multiplication of elements of \a conjugate(v1) and \a v2. Implementation is appropriate for complex numbers. Arguments must have the same index range. */ -template -inline elemT -inner_product (const Array<1,elemT> & v1, const Array<1,elemT> &v2); +template +inline elemT inner_product(const Array<1, elemT>& v1, const Array<1, elemT>& v2); //! angle between 2 1D arrays -/*! \ingroup numbers +/*! \ingroup numbers */ -template -inline double -angle (const Array<1,elemT> & v1, const Array<1,elemT> &v2); +template +inline double angle(const Array<1, elemT>& v1, const Array<1, elemT>& v2); //@} end of 1D functions - //---------------------------------------------------------------------- /*! \ingroup numerics \name functions for matrices @@ -71,33 +67,29 @@ angle (const Array<1,elemT> & v1, const Array<1,elemT> &v2); //! matrix with vector multiplication /*! Index ranges have to be compatible (checked with assert). */ -template -inline Array<1,elemT> - matrix_multiply(const Array<2,elemT>& m, const Array<1,elemT>& vec); +template +inline Array<1, elemT> matrix_multiply(const Array<2, elemT>& m, const Array<1, elemT>& vec); -//! matrix multiplication with vector (given as BasicCoordinate) +//! matrix multiplication with vector (given as BasicCoordinate) /*! matrix size has to be compatible with \c dimension. Matrix index range has to start from 1. All of this is only checked with assert(). */ -template -inline BasicCoordinate - matrix_multiply(const Array<2,elemT>& m, const BasicCoordinate& vec); +template +inline BasicCoordinate matrix_multiply(const Array<2, elemT>& m, const BasicCoordinate& vec); //! matrix multiplication /*! Index ranges have to be compatible (checked with assert). */ -template -inline Array<2,elemT> - matrix_multiply(const Array<2,elemT> &m1, const Array<2,elemT>& m2); +template +inline Array<2, elemT> matrix_multiply(const Array<2, elemT>& m1, const Array<2, elemT>& m2); //! matrix transposition template -inline Array<2,elemT> - matrix_transpose (const Array<2,elemT>& m); +inline Array<2, elemT> matrix_transpose(const Array<2, elemT>& m); //! construct a diagonal matrix with all elements on the diagonal equal /*! \param[in] dimension specifies the size of the matrix - \param[in] value gives the value on the diagonal. Note that its + \param[in] value gives the value on the diagonal. Note that its type determines the type of the return value. \par Example @@ -106,17 +98,15 @@ inline Array<2,elemT> Array<2,float> iden = diagonal_matrix(3, 1.F); \endcode - Index-range of the matrix will be 0 till + Index-range of the matrix will be 0 till dimensions-1. */ template -inline -Array<2,elemT> - diagonal_matrix(const unsigned dimension, const elemT value); +inline Array<2, elemT> diagonal_matrix(const unsigned dimension, const elemT value); -//! construct a diagonal matrix -/*! - \param[in] values gives the values on the diagonal. Note that its +//! construct a diagonal matrix +/*! + \param[in] values gives the values on the diagonal. Note that its type determines the type of the return value. \par Example @@ -125,15 +115,12 @@ Array<2,elemT> Array<2,float> diag = diagonal_matrix(Coordinate3D(1,2,3)); \endcode - Index-range of the matrix will be 0 till + Index-range of the matrix will be 0 till dimensions-1. (Note that this is different from \a values). */ template -inline -Array<2,elemT> - diagonal_matrix(const BasicCoordinate& values); - +inline Array<2, elemT> diagonal_matrix(const BasicCoordinate& values); //@} diff --git a/src/include/stir/numerics/MatrixFunction.inl b/src/include/stir/numerics/MatrixFunction.inl index 36f41f24e3..b861cdd9ed 100644 --- a/src/include/stir/numerics/MatrixFunction.inl +++ b/src/include/stir/numerics/MatrixFunction.inl @@ -19,9 +19,9 @@ /*! \file \ingroup numerics - + \brief Implementation of functions for matrices - + \author Kris Thielemans \author Sanida Mustafovic @@ -29,112 +29,104 @@ #include "stir/IndexRange2D.h" #include #include -# ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::acos; } -# endif +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::acos; +} +#endif START_NAMESPACE_STIR - //---------------------------------------------------------------------- // some functions specific for 1D Arrays //---------------------------------------------------------------------- -template -inline elemT -inner_product (const Array<1,elemT> & v1, const Array<1,elemT> &v2) -{ +template +inline elemT +inner_product(const Array<1, elemT>& v1, const Array<1, elemT>& v2) { assert(v1.get_index_range() == v2.get_index_range()); elemT tmp = 0; - typename Array<1,elemT>::const_iterator i1=v1.begin(); - typename Array<1,elemT>::const_iterator i2=v2.begin(); - for (; i1!=v1.end(); ++i1, ++i2) + typename Array<1, elemT>::const_iterator i1 = v1.begin(); + typename Array<1, elemT>::const_iterator i2 = v2.begin(); + for (; i1 != v1.end(); ++i1, ++i2) tmp += ((*i1) * (*i2)); return tmp; } -template -inline std::complex -inner_product (const Array<1,std::complex > & v1, const Array<1,std::complex > &v2) -{ +template +inline std::complex +inner_product(const Array<1, std::complex>& v1, const Array<1, std::complex>& v2) { assert(v1.get_index_range() == v2.get_index_range()); std::complex tmp = 0; - typename Array<1,std::complex >::const_iterator i1=v1.begin(); - typename Array<1,std::complex >::const_iterator i2=v2.begin(); - for (; i1!=v1.end(); ++i1, ++i2) + typename Array<1, std::complex>::const_iterator i1 = v1.begin(); + typename Array<1, std::complex>::const_iterator i2 = v2.begin(); + for (; i1 != v1.end(); ++i1, ++i2) tmp += (std::conj(*i1) * (*i2)); return tmp; } -template +template inline double -angle (const Array<1,elemT> & v1, const Array<1,elemT> &v2) -{ - return std::acos(inner_product(v1,v2)/norm(v1)/ norm(v2)); +angle(const Array<1, elemT>& v1, const Array<1, elemT>& v2) { + return std::acos(inner_product(v1, v2) / norm(v1) / norm(v2)); } - - //---------------------------------------------------------------------- // functions for matrices // matrix with vector multiplication // first define a help function that works with both types of vectors) -namespace detail -{ - template - inline - void - matrix_multiply_help(vecT& retval, const Array<2,elemT>& m, const vecT& vec) - { - assert(m.is_regular()); - if (m.size()==0) - { return; } - - const int m_min_row = m.get_min_index(); - const int m_max_row = m.get_max_index(); - const int m_min_col = m[m_min_row].get_min_index(); - const int m_max_col = m[m_min_row].get_max_index(); - // make sure matrices are conformable for multiplication - assert(vec.get_min_index() == m_min_col); - assert(vec.get_max_index() == m_max_col); - for(int i=m_min_row; i<=m_max_row; ++i) - { - int j=m_min_col; - retval[i] = m[i][j]*vec[j]; - for(++j; j<=m_max_col; ++j) - retval[i] += m[i][j]*vec[j]; - } +namespace detail { +template +inline void +matrix_multiply_help(vecT& retval, const Array<2, elemT>& m, const vecT& vec) { + assert(m.is_regular()); + if (m.size() == 0) { + return; + } + + const int m_min_row = m.get_min_index(); + const int m_max_row = m.get_max_index(); + const int m_min_col = m[m_min_row].get_min_index(); + const int m_max_col = m[m_min_row].get_max_index(); + // make sure matrices are conformable for multiplication + assert(vec.get_min_index() == m_min_col); + assert(vec.get_max_index() == m_max_col); + for (int i = m_min_row; i <= m_max_row; ++i) { + int j = m_min_col; + retval[i] = m[i][j] * vec[j]; + for (++j; j <= m_max_col; ++j) + retval[i] += m[i][j] * vec[j]; } } +} // namespace detail -template -inline Array<1,elemT> -matrix_multiply(const Array<2,elemT>& m, const Array<1,elemT>& vec) -{ - Array<1,elemT> ret(m.get_min_index(), m.get_max_index()); +template +inline Array<1, elemT> +matrix_multiply(const Array<2, elemT>& m, const Array<1, elemT>& vec) { + Array<1, elemT> ret(m.get_min_index(), m.get_max_index()); detail::matrix_multiply_help(ret, m, vec); return ret; } -template -inline BasicCoordinate -matrix_multiply(const Array<2,elemT>& m, const BasicCoordinate& vec) -{ - BasicCoordinate ret; +template +inline BasicCoordinate +matrix_multiply(const Array<2, elemT>& m, const BasicCoordinate& vec) { + BasicCoordinate ret; detail::matrix_multiply_help(ret, m, vec); return ret; } // matrix multiplication -template -inline Array<2,elemT> -matrix_multiply(const Array<2,elemT> &m1, const Array<2,elemT>& m2) -{ +template +inline Array<2, elemT> +matrix_multiply(const Array<2, elemT>& m1, const Array<2, elemT>& m2) { assert(m1.is_regular()); assert(m2.is_regular()); - if (m1.size()==0 || m2.size()==0) - { Array<2,elemT> retval; return retval; } + if (m1.size() == 0 || m2.size() == 0) { + Array<2, elemT> retval; + return retval; + } const int m1_min_row = m1.get_min_index(); const int m1_max_row = m1.get_max_index(); @@ -145,61 +137,53 @@ matrix_multiply(const Array<2,elemT> &m1, const Array<2,elemT>& m2) // make sure matrices are conformable for multiplication assert(m1[m1_min_row].get_min_index() == m2_min_row); assert(m1[m1_min_row].get_max_index() == m2_max_row); - - Array<2,elemT> retval(IndexRange2D(m1_min_row, m1_max_row, - m2_min_col, m2_max_col)); - - for (int i=m1_min_row; i<=m1_max_row; ++i) - { - for(int j=m2_min_col; j<=m2_max_col; ++j) - { - for(int k=m2_min_row; k<=m2_max_row; ++k) - retval[i][j] += m1[i][k]*m2[k][j]; - } + + Array<2, elemT> retval(IndexRange2D(m1_min_row, m1_max_row, m2_min_col, m2_max_col)); + + for (int i = m1_min_row; i <= m1_max_row; ++i) { + for (int j = m2_min_col; j <= m2_max_col; ++j) { + for (int k = m2_min_row; k <= m2_max_row; ++k) + retval[i][j] += m1[i][k] * m2[k][j]; } + } return retval; } - -template -inline Array<2,elemT> -matrix_transpose (const Array<2,elemT>& m) -{ +template +inline Array<2, elemT> +matrix_transpose(const Array<2, elemT>& m) { assert(m.is_regular()); - if (m.size()==0) - { Array<2,elemT> retval; return retval; } + if (m.size() == 0) { + Array<2, elemT> retval; + return retval; + } const int m_min_row = m.get_min_index(); const int m_max_row = m.get_max_index(); const int m_min_col = m[m_min_row].get_min_index(); const int m_max_col = m[m_min_row].get_max_index(); - Array<2,elemT> new_m(IndexRange2D(m_min_col, m_max_col, - m_min_row, m_max_row)); - for(int j=m_min_row; j<=m_max_row; ++j) - for(int i=m_min_col; i<=m_max_col; ++i) + Array<2, elemT> new_m(IndexRange2D(m_min_col, m_max_col, m_min_row, m_max_row)); + for (int j = m_min_row; j <= m_max_row; ++j) + for (int i = m_min_col; i <= m_max_col; ++i) new_m[i][j] = m[j][i]; - return new_m; + return new_m; } template -inline -Array<2,elemT> - diagonal_matrix(const unsigned dimension, const elemT value) -{ - Array<2,elemT> m(IndexRange2D(dimension,dimension)); - for (unsigned int i=0; i +diagonal_matrix(const unsigned dimension, const elemT value) { + Array<2, elemT> m(IndexRange2D(dimension, dimension)); + for (unsigned int i = 0; i < dimension; ++i) + m[i][i] = value; return m; } template -inline -Array<2,elemT> - diagonal_matrix(const BasicCoordinate& values) -{ - Array<2,elemT> m(IndexRange2D(dimension,dimension)); - for (unsigned int i=0; i +diagonal_matrix(const BasicCoordinate& values) { + Array<2, elemT> m(IndexRange2D(dimension, dimension)); + for (unsigned int i = 0; i < dimension; ++i) + m[i][i] = values[i + 1]; return m; } diff --git a/src/include/stir/numerics/determinant.h b/src/include/stir/numerics/determinant.h index 50f715be1e..d0054e4101 100644 --- a/src/include/stir/numerics/determinant.h +++ b/src/include/stir/numerics/determinant.h @@ -21,9 +21,9 @@ /*! \file \ingroup numerics - + \brief Declaration of stir::determinant() function for matrices - + \author Kris Thielemans */ @@ -31,18 +31,18 @@ START_NAMESPACE_STIR -template class Array; +template +class Array; /*! \ingroup numerics \brief Compute the determinant of a matrix - + Matrix indices can start from any number. \todo Only works for low dimensions for now. */ template -elemT -determinant(const Array<2,elemT>& m); +elemT determinant(const Array<2, elemT>& m); END_NAMESPACE_STIR #endif diff --git a/src/include/stir/numerics/divide.h b/src/include/stir/numerics/divide.h index 4ee1981b91..19d032bb2e 100644 --- a/src/include/stir/numerics/divide.h +++ b/src/include/stir/numerics/divide.h @@ -27,34 +27,28 @@ \author Matthew Jacobson \author Kris Thielemans \author PARAPET project - + */ START_NAMESPACE_STIR //! division of two ranges, 0/0 = 0 -/*! +/*! \ingroup numerics This function sets 0/0 to 0 (not the usual NaN). It is for instance useful in Poisson log-likelihood computation. - Because of potential numerical rounding problems, we test if a number is + Because of potential numerical rounding problems, we test if a number is 0 by comparing its absolute value with a small value, which is determined by multiplying the maximum in the \c numerator range with \a small_num. - \warning This function does not test for non-zero numbers by 0. Results in + \warning This function does not test for non-zero numbers by 0. Results in that case will likely depend on your processor and/or compiler settings. */ -template -inline -void -divide(const NumeratorIterT& numerator_begin, - const NumeratorIterT& numerator_end, - const DenominatorIterT& denominator_begin, - const small_numT small_num); +template +inline void divide(const NumeratorIterT& numerator_begin, const NumeratorIterT& numerator_end, + const DenominatorIterT& denominator_begin, const small_numT small_num); END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/divide.inl b/src/include/stir/numerics/divide.inl index d5ba32e932..22ea6f790a 100644 --- a/src/include/stir/numerics/divide.inl +++ b/src/include/stir/numerics/divide.inl @@ -25,38 +25,29 @@ \author Matthew Jacobson \author Kris Thielemans \author PARAPET project - + */ #include START_NAMESPACE_STIR -template -void -divide( - const NumeratorIterT& numerator_begin, - const NumeratorIterT& numerator_end, - const DenominatorIterT& denominator_begin, - const small_numT small_num) -{ - small_numT small_value= - *std::max_element(numerator_begin, numerator_end) - *small_num; - small_value=(small_value>0)?small_value:0; +template +void +divide(const NumeratorIterT& numerator_begin, const NumeratorIterT& numerator_end, const DenominatorIterT& denominator_begin, + const small_numT small_num) { + small_numT small_value = *std::max_element(numerator_begin, numerator_end) * small_num; + small_value = (small_value > 0) ? small_value : 0; NumeratorIterT numerator_iter = numerator_begin; DenominatorIterT denominator_iter = denominator_begin; - while (numerator_iter != numerator_end) - { - if(std::fabs(*denominator_iter)<=small_value && std::fabs(*numerator_iter)<=small_value) - (*numerator_iter)=0; - else - (*numerator_iter)/=(*denominator_iter); - ++numerator_iter; - ++denominator_iter; - } + while (numerator_iter != numerator_end) { + if (std::fabs(*denominator_iter) <= small_value && std::fabs(*numerator_iter) <= small_value) + (*numerator_iter) = 0; + else + (*numerator_iter) /= (*denominator_iter); + ++numerator_iter; + ++denominator_iter; + } } END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/erf.h b/src/include/stir/numerics/erf.h index eadc054096..bf1772b5b6 100644 --- a/src/include/stir/numerics/erf.h +++ b/src/include/stir/numerics/erf.h @@ -19,7 +19,7 @@ /*! \file \ingroup numerics - + \author Charalampos Tsoumpas \author Kris Thielemans @@ -30,21 +30,18 @@ START_NAMESPACE_STIR /*! \ingroup numerics - \name A collection of error functions. + \name A collection of error functions. The erf() is a high precision implementation of the error function. - The erfc() is the complementary of the erf(), which should be equal to 1-erf(), but with + The erfc() is the complementary of the erf(), which should be equal to 1-erf(), but with higher precision when erf is close to 1. \todo replace with boost::erf */ //@{ -inline -double erf(double); -inline -double erfc(double); +inline double erf(double); +inline double erfc(double); //@} END_NAMESPACE_STIR #include "stir/numerics/erf.inl" - diff --git a/src/include/stir/numerics/erf.inl b/src/include/stir/numerics/erf.inl index 4a84e23389..a1de84aeae 100644 --- a/src/include/stir/numerics/erf.inl +++ b/src/include/stir/numerics/erf.inl @@ -1,141 +1,141 @@ // // /*- -* Copyright (c) 1992, 1993 -* The Regents of the University of California. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. Neither the name of the University nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -* SUCH DAMAGE. -*/ + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ /* Modified Nov 30, 1992 P. McILROY: -* Replaced expansions for x >= 1.25 (error 1.7ulp vs ~6ulp) -* Replaced even+odd with direct calculation for x < .84375, -* to avoid destructive cancellation. -* -* Performance of erfc(x): -* In 300000 trials in the range [.83, .84375] the -* maximum observed error was 3.6ulp. -* -* In [.84735,1.25] the maximum observed error was <2.5ulp in -* 100000 runs in the range [1.2, 1.25]. -* -* In [1.25,26] (Not including subnormal results) -* the error is < 1.7ulp. -*/ + * Replaced expansions for x >= 1.25 (error 1.7ulp vs ~6ulp) + * Replaced even+odd with direct calculation for x < .84375, + * to avoid destructive cancellation. + * + * Performance of erfc(x): + * In 300000 trials in the range [.83, .84375] the + * maximum observed error was 3.6ulp. + * + * In [.84735,1.25] the maximum observed error was <2.5ulp in + * 100000 runs in the range [1.2, 1.25]. + * + * In [1.25,26] (Not including subnormal results) + * the error is < 1.7ulp. + */ /* double erf(double x) -* double erfc(double x) -* x -* 2 |\ -* erf(x) = --------- | exp(-t*t)dt -* sqrt(pi) \| -* 0 -* -* erfc(x) = 1-erf(x) -* -* Method: -* 1. Reduce x to |x| by erf(-x) = -erf(x) -* 2. For x in [0, 0.84375] -* erf(x) = x + x*P(x^2) -* erfc(x) = 1 - erf(x) if x<=0.25 -* = 0.5 + ((0.5-x)-x*P) if x in [0.25,0.84375] -* where -* 2 2 4 20 -* P = P(x ) = (p0 + p1 * x + p2 * x + ... + p10 * x ) -* is an approximation to (erf(x)-x)/x with precision -* -* -56.45 -* | P - (erf(x)-x)/x | <= 2 -* -* -* Remark. The formula is derived by noting -* erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) -* and that -* 2/sqrt(pi) = 1.128379167095512573896158903121545171688 -* is close to one. The interval is chosen because the fixed -* point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is -* near 0.6174), and by some experiment, 0.84375 is chosen to -* guarantee the error is less than one ulp for erf. -* -* 3. For x in [0.84375,1.25], let s = x - 1, and -* c = 0.84506291151 rounded to single (24 bits) -* erf(x) = c + P1(s)/Q1(s) -* erfc(x) = (1-c) - P1(s)/Q1(s) -* |P1/Q1 - (erf(x)-c)| <= 2**-59.06 -* Remark: here we use the taylor series expansion at x=1. -* erf(1+s) = erf(1) + s*Poly(s) -* = 0.845.. + P1(s)/Q1(s) -* That is, we use rational approximation to approximate -* erf(1+s) - (c = (single)0.84506291151) -* Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] -* where -* P1(s) = degree 6 poly in s -* Q1(s) = degree 6 poly in s -* -* 4. For x in [1.25, 2]; [2, 4] -* erf(x) = 1.0 - tiny -* erfc(x) = (1/x)exp(-x*x-(.5*log(pi) -.5z + R(z)/S(z)) -* -* Where z = 1/(x*x), R is degree 9, and S is degree 3; -* -* 5. For x in [4,28] -* erf(x) = 1.0 - tiny -* erfc(x) = (1/x)exp(-x*x-(.5*log(pi)+eps + zP(z)) -* -* Where P is degree 14 polynomial in 1/(x*x). -* -* Notes: -* Here 4 and 5 make use of the asymptotic series -* exp(-x*x) -* erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) ); -* x*sqrt(pi) -* -* where for z = 1/(x*x) -* P(z) ~ z/2*(-1 + z*3/2*(1 + z*5/2*(-1 + z*7/2*(1 +...)))) -* -* Thus we use rational approximation to approximate -* erfc*x*exp(x*x) ~ 1/sqrt(pi); -* -* The error bound for the target function, G(z) for -* the interval -* [4, 28]: -* |eps + 1/(z)P(z) - G(z)| < 2**(-56.61) -* for [2, 4]: -* |R(z)/S(z) - G(z)| < 2**(-58.24) -* for [1.25, 2]: -* |R(z)/S(z) - G(z)| < 2**(-58.12) -* -* 6. For inf > x >= 28 -* erf(x) = 1 - tiny (raise inexact) -* erfc(x) = tiny*tiny (raise underflow) -* -* 7. Special cases: -* erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, -* erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, -* erfc/erf(NaN) is NaN -*/ + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * + * Method: + * 1. Reduce x to |x| by erf(-x) = -erf(x) + * 2. For x in [0, 0.84375] + * erf(x) = x + x*P(x^2) + * erfc(x) = 1 - erf(x) if x<=0.25 + * = 0.5 + ((0.5-x)-x*P) if x in [0.25,0.84375] + * where + * 2 2 4 20 + * P = P(x ) = (p0 + p1 * x + p2 * x + ... + p10 * x ) + * is an approximation to (erf(x)-x)/x with precision + * + * -56.45 + * | P - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fixed + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 3. For x in [0.84375,1.25], let s = x - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = c + P1(s)/Q1(s) + * erfc(x) = (1-c) - P1(s)/Q1(s) + * |P1/Q1 - (erf(x)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 4. For x in [1.25, 2]; [2, 4] + * erf(x) = 1.0 - tiny + * erfc(x) = (1/x)exp(-x*x-(.5*log(pi) -.5z + R(z)/S(z)) + * + * Where z = 1/(x*x), R is degree 9, and S is degree 3; + * + * 5. For x in [4,28] + * erf(x) = 1.0 - tiny + * erfc(x) = (1/x)exp(-x*x-(.5*log(pi)+eps + zP(z)) + * + * Where P is degree 14 polynomial in 1/(x*x). + * + * Notes: + * Here 4 and 5 make use of the asymptotic series + * exp(-x*x) + * erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) ); + * x*sqrt(pi) + * + * where for z = 1/(x*x) + * P(z) ~ z/2*(-1 + z*3/2*(1 + z*5/2*(-1 + z*7/2*(1 +...)))) + * + * Thus we use rational approximation to approximate + * erfc*x*exp(x*x) ~ 1/sqrt(pi); + * + * The error bound for the target function, G(z) for + * the interval + * [4, 28]: + * |eps + 1/(z)P(z) - G(z)| < 2**(-56.61) + * for [2, 4]: + * |R(z)/S(z) - G(z)| < 2**(-58.24) + * for [1.25, 2]: + * |R(z)/S(z) - G(z)| < 2**(-58.12) + * + * 6. For inf > x >= 28 + * erf(x) = 1 - tiny (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) + * + * 7. Special cases: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ /* Modified for STIR library Jun 05, 2005 Ch Tsoumpas and K Thielemans. @@ -147,278 +147,232 @@ and STIR_finite(). */ - #ifdef _IEEE_LIBM /* -* redefining "___function" to "function" in _IEEE_LIBM mode -*/ -#include "ieee_libm.h" + * redefining "___function" to "function" in _IEEE_LIBM mode + */ +# include "ieee_libm.h" #endif #if defined(__vax__) || defined(tahoe) // non-IEEE machines -#define _IEEE 0 -#define TRUNC(x) (double)(x) = (float)(x) +# define _IEEE 0 +# define TRUNC(x) (double)(x) = (float)(x) #else // assume everything uses IEEE floating point arithmetic -#define _IEEE 1 +# define _IEEE 1 // warning: strange definition of TRUNC that will go very weird on non-IEEE machines -#define TRUNC(x) *(((int *) &x) + 1) &= 0xf8000000 +# define TRUNC(x) *(((int*)&x) + 1) &= 0xf8000000 #endif - #include #include "stir/numerics/ieeefp.h" - START_NAMESPACE_STIR -static const double -tiny = 1e-300, -half = 0.5, -one = 1.0, -two = 2.0, -c = 8.45062911510467529297e-01, /* (float)0.84506291151 */ - /* - * Coefficients for approximation to erf in [0,0.84375] - */ - p0t8 = 1.02703333676410051049867154944018394163280, - p0 = 1.283791670955125638123339436800229927041e-0001, - p1 = -3.761263890318340796574473028946097022260e-0001, - p2 = 1.128379167093567004871858633779992337238e-0001, - p3 = -2.686617064084433642889526516177508374437e-0002, - p4 = 5.223977576966219409445780927846432273191e-0003, - p5 = -8.548323822001639515038738961618255438422e-0004, - p6 = 1.205520092530505090384383082516403772317e-0004, - p7 = -1.492214100762529635365672665955239554276e-0005, - p8 = 1.640186161764254363152286358441771740838e-0006, - p9 = -1.571599331700515057841960987689515895479e-0007, - p10= 1.073087585213621540635426191486561494058e-0008; +static const double tiny = 1e-300, half = 0.5, one = 1.0, two = 2.0, c = 8.45062911510467529297e-01, /* (float)0.84506291151 */ + /* + * Coefficients for approximation to erf in [0,0.84375] + */ + p0t8 = 1.02703333676410051049867154944018394163280, p0 = 1.283791670955125638123339436800229927041e-0001, + p1 = -3.761263890318340796574473028946097022260e-0001, p2 = 1.128379167093567004871858633779992337238e-0001, + p3 = -2.686617064084433642889526516177508374437e-0002, p4 = 5.223977576966219409445780927846432273191e-0003, + p5 = -8.548323822001639515038738961618255438422e-0004, p6 = 1.205520092530505090384383082516403772317e-0004, + p7 = -1.492214100762529635365672665955239554276e-0005, p8 = 1.640186161764254363152286358441771740838e-0006, + p9 = -1.571599331700515057841960987689515895479e-0007, p10 = 1.073087585213621540635426191486561494058e-0008; /* * Coefficients for approximation to erf in [0.84375,1.25] -*/ -static const double -pa0 = -2.362118560752659485957248365514511540287e-0003, -pa1 = 4.148561186837483359654781492060070469522e-0001, -pa2 = -3.722078760357013107593507594535478633044e-0001, -pa3 = 3.183466199011617316853636418691420262160e-0001, -pa4 = -1.108946942823966771253985510891237782544e-0001, -pa5 = 3.547830432561823343969797140537411825179e-0002, -pa6 = -2.166375594868790886906539848893221184820e-0003, -qa1 = 1.064208804008442270765369280952419863524e-0001, -qa2 = 5.403979177021710663441167681878575087235e-0001, -qa3 = 7.182865441419627066207655332170665812023e-0002, -qa4 = 1.261712198087616469108438860983447773726e-0001, -qa5 = 1.363708391202905087876983523620537833157e-0002, -qa6 = 1.198449984679910764099772682882189711364e-0002; + */ +static const double pa0 = -2.362118560752659485957248365514511540287e-0003, pa1 = 4.148561186837483359654781492060070469522e-0001, + pa2 = -3.722078760357013107593507594535478633044e-0001, pa3 = 3.183466199011617316853636418691420262160e-0001, + pa4 = -1.108946942823966771253985510891237782544e-0001, pa5 = 3.547830432561823343969797140537411825179e-0002, + pa6 = -2.166375594868790886906539848893221184820e-0003, qa1 = 1.064208804008442270765369280952419863524e-0001, + qa2 = 5.403979177021710663441167681878575087235e-0001, qa3 = 7.182865441419627066207655332170665812023e-0002, + qa4 = 1.261712198087616469108438860983447773726e-0001, qa5 = 1.363708391202905087876983523620537833157e-0002, + qa6 = 1.198449984679910764099772682882189711364e-0002; /* -* log(sqrt(pi)) for large x expansions. -* The tail (lsqrtPI_lo) is included in the rational -* approximations. -*/ -static const double -lsqrtPI_hi = .5723649429247000819387380943226; + * log(sqrt(pi)) for large x expansions. + * The tail (lsqrtPI_lo) is included in the rational + * approximations. + */ +static const double lsqrtPI_hi = .5723649429247000819387380943226; /* -* lsqrtPI_lo = .000000000000000005132975581353913; -* -* Coefficients for approximation to erfc in [2, 4] -*/ -static const double -rb0 = -1.5306508387410807582e-010, /* includes lsqrtPI_lo */ -rb1 = 2.15592846101742183841910806188e-008, -rb2 = 6.24998557732436510470108714799e-001, -rb3 = 8.24849222231141787631258921465e+000, -rb4 = 2.63974967372233173534823436057e+001, -rb5 = 9.86383092541570505318304640241e+000, -rb6 = -7.28024154841991322228977878694e+000, -rb7 = 5.96303287280680116566600190708e+000, -rb8 = -4.40070358507372993983608466806e+000, -rb9 = 2.39923700182518073731330332521e+000, -rb10 = -6.89257464785841156285073338950e-001, -sb1 = 1.56641558965626774835300238919e+001, -sb2 = 7.20522741000949622502957936376e+001, -sb3 = 9.60121069770492994166488642804e+001; + * lsqrtPI_lo = .000000000000000005132975581353913; + * + * Coefficients for approximation to erfc in [2, 4] + */ +static const double rb0 = -1.5306508387410807582e-010, /* includes lsqrtPI_lo */ + rb1 = 2.15592846101742183841910806188e-008, rb2 = 6.24998557732436510470108714799e-001, + rb3 = 8.24849222231141787631258921465e+000, rb4 = 2.63974967372233173534823436057e+001, + rb5 = 9.86383092541570505318304640241e+000, rb6 = -7.28024154841991322228977878694e+000, + rb7 = 5.96303287280680116566600190708e+000, rb8 = -4.40070358507372993983608466806e+000, + rb9 = 2.39923700182518073731330332521e+000, rb10 = -6.89257464785841156285073338950e-001, + sb1 = 1.56641558965626774835300238919e+001, sb2 = 7.20522741000949622502957936376e+001, + sb3 = 9.60121069770492994166488642804e+001; /* -* Coefficients for approximation to erfc in [1.25, 2] -*/ -static const double -rc0 = -2.47925334685189288817e-007, /* includes lsqrtPI_lo */ -rc1 = 1.28735722546372485255126993930e-005, -rc2 = 6.24664954087883916855616917019e-001, -rc3 = 4.69798884785807402408863708843e+000, -rc4 = 7.61618295853929705430118701770e+000, -rc5 = 9.15640208659364240872946538730e-001, -rc6 = -3.59753040425048631334448145935e-001, -rc7 = 1.42862267989304403403849619281e-001, -rc8 = -4.74392758811439801958087514322e-002, -rc9 = 1.09964787987580810135757047874e-002, -rc10 = -1.28856240494889325194638463046e-003, -sc1 = 9.97395106984001955652274773456e+000, -sc2 = 2.80952153365721279953959310660e+001, -sc3 = 2.19826478142545234106819407316e+001; + * Coefficients for approximation to erfc in [1.25, 2] + */ +static const double rc0 = -2.47925334685189288817e-007, /* includes lsqrtPI_lo */ + rc1 = 1.28735722546372485255126993930e-005, rc2 = 6.24664954087883916855616917019e-001, + rc3 = 4.69798884785807402408863708843e+000, rc4 = 7.61618295853929705430118701770e+000, + rc5 = 9.15640208659364240872946538730e-001, rc6 = -3.59753040425048631334448145935e-001, + rc7 = 1.42862267989304403403849619281e-001, rc8 = -4.74392758811439801958087514322e-002, + rc9 = 1.09964787987580810135757047874e-002, rc10 = -1.28856240494889325194638463046e-003, + sc1 = 9.97395106984001955652274773456e+000, sc2 = 2.80952153365721279953959310660e+001, + sc3 = 2.19826478142545234106819407316e+001; /* -* Coefficients for approximation to erfc in [4,28] -*/ -static const double -rd0 = -2.1491361969012978677e-016, /* includes lsqrtPI_lo */ -rd1 = -4.99999999999640086151350330820e-001, -rd2 = 6.24999999772906433825880867516e-001, -rd3 = -1.54166659428052432723177389562e+000, -rd4 = 5.51561147405411844601985649206e+000, -rd5 = -2.55046307982949826964613748714e+001, -rd6 = 1.43631424382843846387913799845e+002, -rd7 = -9.45789244999420134263345971704e+002, -rd8 = 6.94834146607051206956384703517e+003, -rd9 = -5.27176414235983393155038356781e+004, -rd10 = 3.68530281128672766499221324921e+005, -rd11 = -2.06466642800404317677021026611e+006, -rd12 = 7.78293889471135381609201431274e+006, -rd13 = -1.42821001129434127360582351685e+007; - + * Coefficients for approximation to erfc in [4,28] + */ +static const double rd0 = -2.1491361969012978677e-016, /* includes lsqrtPI_lo */ + rd1 = -4.99999999999640086151350330820e-001, rd2 = 6.24999999772906433825880867516e-001, + rd3 = -1.54166659428052432723177389562e+000, rd4 = 5.51561147405411844601985649206e+000, + rd5 = -2.55046307982949826964613748714e+001, rd6 = 1.43631424382843846387913799845e+002, + rd7 = -9.45789244999420134263345971704e+002, rd8 = 6.94834146607051206956384703517e+003, + rd9 = -5.27176414235983393155038356781e+004, rd10 = 3.68530281128672766499221324921e+005, + rd11 = -2.06466642800404317677021026611e+006, rd12 = 7.78293889471135381609201431274e+006, + rd13 = -1.42821001129434127360582351685e+007; -inline -double -erf(double x) -{ - double R,S,P,Q,ax,s,y,z,r; - if(!STIR_finite(x)) { /* erf(nan)=nan */ - if (STIR_isnan(x)) - return(x); - return (x > 0 ? one : -one); /* erf(+/-inf)= +/-1 */ - } - if ((ax = x) < 0) - ax = - ax; - if (ax < .84375) { - if (ax < 3.7e-09) { - if (ax < 1.0e-308) - return 0.125*(8.0*x+p0t8*x); /*avoid underflow */ - return x + p0*x; - } - y = x*x; - r = y*(p1+y*(p2+y*(p3+y*(p4+y*(p5+ - y*(p6+y*(p7+y*(p8+y*(p9+y*p10))))))))); - return x + x*(p0+r); - } - if (ax < 1.25) { /* 0.84375 <= |x| < 1.25 */ - s = std::fabs(x)-one; - P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); - Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); - if (x>=0) - return (c + P/Q); - else - return (-c - P/Q); - } - if (ax >= 6.0) { /* inf>|x|>=6 */ - if (x >= 0.0) - return (one-tiny); - else - return (tiny-one); - } - /* 1.25 <= |x| < 6 */ - z = -ax*ax; - s = -one/z; - if (ax < 2.0) { - R = rc0+s*(rc1+s*(rc2+s*(rc3+s*(rc4+s*(rc5+ - s*(rc6+s*(rc7+s*(rc8+s*(rc9+s*rc10))))))))); - S = one+s*(sc1+s*(sc2+s*sc3)); - } else { - R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+ - s*(rb6+s*(rb7+s*(rb8+s*(rb9+s*rb10))))))))); - S = one+s*(sb1+s*(sb2+s*sb3)); - } - y = (R/S -.5*s) - lsqrtPI_hi; - z += y; - z = std::exp(z)/ax; - if (x >= 0) - return (one-z); - else - return (z-one); +inline double +erf(double x) { + double R, S, P, Q, ax, s, y, z, r; + if (!STIR_finite(x)) { /* erf(nan)=nan */ + if (STIR_isnan(x)) + return (x); + return (x > 0 ? one : -one); /* erf(+/-inf)= +/-1 */ + } + if ((ax = x) < 0) + ax = -ax; + if (ax < .84375) { + if (ax < 3.7e-09) { + if (ax < 1.0e-308) + return 0.125 * (8.0 * x + p0t8 * x); /*avoid underflow */ + return x + p0 * x; + } + y = x * x; + r = y * (p1 + y * (p2 + y * (p3 + y * (p4 + y * (p5 + y * (p6 + y * (p7 + y * (p8 + y * (p9 + y * p10))))))))); + return x + x * (p0 + r); + } + if (ax < 1.25) { /* 0.84375 <= |x| < 1.25 */ + s = std::fabs(x) - one; + P = pa0 + s * (pa1 + s * (pa2 + s * (pa3 + s * (pa4 + s * (pa5 + s * pa6))))); + Q = one + s * (qa1 + s * (qa2 + s * (qa3 + s * (qa4 + s * (qa5 + s * qa6))))); + if (x >= 0) + return (c + P / Q); + else + return (-c - P / Q); + } + if (ax >= 6.0) { /* inf>|x|>=6 */ + if (x >= 0.0) + return (one - tiny); + else + return (tiny - one); + } + /* 1.25 <= |x| < 6 */ + z = -ax * ax; + s = -one / z; + if (ax < 2.0) { + R = rc0 + + s * (rc1 + s * (rc2 + s * (rc3 + s * (rc4 + s * (rc5 + s * (rc6 + s * (rc7 + s * (rc8 + s * (rc9 + s * rc10))))))))); + S = one + s * (sc1 + s * (sc2 + s * sc3)); + } else { + R = rb0 + + s * (rb1 + s * (rb2 + s * (rb3 + s * (rb4 + s * (rb5 + s * (rb6 + s * (rb7 + s * (rb8 + s * (rb9 + s * rb10))))))))); + S = one + s * (sb1 + s * (sb2 + s * sb3)); + } + y = (R / S - .5 * s) - lsqrtPI_hi; + z += y; + z = std::exp(z) / ax; + if (x >= 0) + return (one - z); + else + return (z - one); } -inline -double -erfc(double x) -{ - double R,S,P,Q,s,ax,y,z,r; - if (!STIR_finite(x)) { - if (STIR_isnan(x)) /* erfc(NaN) = NaN */ - return(x); - else if (x > 0) /* erfc(+-inf)=0,2 */ - return 0.0; - else - return 2.0; - } - if ((ax = x) < 0) - ax = -ax; - if (ax < .84375) { /* |x|<0.84375 */ - if (ax < 1.38777878078144568e-17) /* |x|<2**-56 */ - return one-x; - y = x*x; - r = y*(p1+y*(p2+y*(p3+y*(p4+y*(p5+ - y*(p6+y*(p7+y*(p8+y*(p9+y*p10))))))))); - if (ax < .0625) { /* |x|<2**-4 */ - return (one-(x+x*(p0+r))); - } else { - r = x*(p0+r); - r += (x-half); - return (half - r); - } - } - if (ax < 1.25) { /* 0.84375 <= |x| < 1.25 */ - s = ax-one; - P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); - Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); - if (x>=0) { - z = one-c; return z - P/Q; - } else { - z = c+P/Q; return one+z; - } - } - if (ax >= 28) { /* Out of range */ - if (x>0) - return (tiny*tiny); - else - return (two-tiny); - } - z = ax; - TRUNC(z); - y = z - ax; y *= (ax+z); - z *= -z; /* Here z + y = -x^2 */ - s = one/(-z-y); /* 1/(x*x) */ - if (ax >= 4) { /* 6 <= ax */ - R = s*(rd1+s*(rd2+s*(rd3+s*(rd4+s*(rd5+ - s*(rd6+s*(rd7+s*(rd8+s*(rd9+s*(rd10 - +s*(rd11+s*(rd12+s*rd13)))))))))))); - y += rd0; - } else if (ax >= 2) { - R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+ - s*(rb6+s*(rb7+s*(rb8+s*(rb9+s*rb10))))))))); - S = one+s*(sb1+s*(sb2+s*sb3)); - y += R/S; - R = -.5*s; - } else { - R = rc0+s*(rc1+s*(rc2+s*(rc3+s*(rc4+s*(rc5+ - s*(rc6+s*(rc7+s*(rc8+s*(rc9+s*rc10))))))))); - S = one+s*(sc1+s*(sc2+s*sc3)); - y += R/S; - R = -.5*s; - } - /* return std::exp(-x^2 - lsqrtPI_hi + R + y)/x; */ - // s = ((R + y) - lsqrtPI_hi) + z; - // y = (((z-s) - lsqrtPI_hi) + R) + y; - // r = std::exp(-x + s/x); - //r = __exp__D(s, y)/x; - if (x>0) - return - (std::exp(-x*x - lsqrtPI_hi + R + y))/x; - //return r; - else - return - 2. - (std::exp(-x*x - lsqrtPI_hi + R + y))/x; - // return two-r; +inline double +erfc(double x) { + double R, S, P, Q, s, ax, y, z, r; + if (!STIR_finite(x)) { + if (STIR_isnan(x)) /* erfc(NaN) = NaN */ + return (x); + else if (x > 0) /* erfc(+-inf)=0,2 */ + return 0.0; + else + return 2.0; + } + if ((ax = x) < 0) + ax = -ax; + if (ax < .84375) { /* |x|<0.84375 */ + if (ax < 1.38777878078144568e-17) /* |x|<2**-56 */ + return one - x; + y = x * x; + r = y * (p1 + y * (p2 + y * (p3 + y * (p4 + y * (p5 + y * (p6 + y * (p7 + y * (p8 + y * (p9 + y * p10))))))))); + if (ax < .0625) { /* |x|<2**-4 */ + return (one - (x + x * (p0 + r))); + } else { + r = x * (p0 + r); + r += (x - half); + return (half - r); + } + } + if (ax < 1.25) { /* 0.84375 <= |x| < 1.25 */ + s = ax - one; + P = pa0 + s * (pa1 + s * (pa2 + s * (pa3 + s * (pa4 + s * (pa5 + s * pa6))))); + Q = one + s * (qa1 + s * (qa2 + s * (qa3 + s * (qa4 + s * (qa5 + s * qa6))))); + if (x >= 0) { + z = one - c; + return z - P / Q; + } else { + z = c + P / Q; + return one + z; + } + } + if (ax >= 28) { /* Out of range */ + if (x > 0) + return (tiny * tiny); + else + return (two - tiny); + } + z = ax; + TRUNC(z); + y = z - ax; + y *= (ax + z); + z *= -z; /* Here z + y = -x^2 */ + s = one / (-z - y); /* 1/(x*x) */ + if (ax >= 4) { /* 6 <= ax */ + R = s * + (rd1 + + s * (rd2 + + s * (rd3 + + s * (rd4 + + s * (rd5 + + s * (rd6 + s * (rd7 + s * (rd8 + s * (rd9 + s * (rd10 + s * (rd11 + s * (rd12 + s * rd13)))))))))))); + y += rd0; + } else if (ax >= 2) { + R = rb0 + + s * (rb1 + s * (rb2 + s * (rb3 + s * (rb4 + s * (rb5 + s * (rb6 + s * (rb7 + s * (rb8 + s * (rb9 + s * rb10))))))))); + S = one + s * (sb1 + s * (sb2 + s * sb3)); + y += R / S; + R = -.5 * s; + } else { + R = rc0 + + s * (rc1 + s * (rc2 + s * (rc3 + s * (rc4 + s * (rc5 + s * (rc6 + s * (rc7 + s * (rc8 + s * (rc9 + s * rc10))))))))); + S = one + s * (sc1 + s * (sc2 + s * sc3)); + y += R / S; + R = -.5 * s; + } + /* return std::exp(-x^2 - lsqrtPI_hi + R + y)/x; */ + // s = ((R + y) - lsqrtPI_hi) + z; + // y = (((z-s) - lsqrtPI_hi) + R) + y; + // r = std::exp(-x + s/x); + // r = __exp__D(s, y)/x; + if (x > 0) + return (std::exp(-x * x - lsqrtPI_hi + R + y)) / x; + // return r; + else + return 2. - (std::exp(-x * x - lsqrtPI_hi + R + y)) / x; + // return two-r; } - #undef TRUNC #undef _IEEE END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/fourier.h b/src/include/stir/numerics/fourier.h index 24750f4f71..bd50d7755f 100644 --- a/src/include/stir/numerics/fourier.h +++ b/src/include/stir/numerics/fourier.h @@ -2,7 +2,7 @@ // /*! - \file + \file \ingroup DFT \brief Functions for computing FFTs @@ -26,13 +26,11 @@ See STIR/LICENSE.txt for details */ #ifndef __stir_numerics_stir_fourier_h__ -#define __stir_numerics_stir_fourier_h__ +#define __stir_numerics_stir_fourier_h__ #include "stir/VectorWithOffset.h" #include "stir/Array_complex_numbers.h" START_NAMESPACE_STIR - - /*! \ingroup DFT \brief Compute multi-dimensional discrete fourier transform. @@ -47,10 +45,8 @@ START_NAMESPACE_STIR \warning Currently, the array has to have \c get_min_index()==0 at each dimension. */ template -void -fourier(T& c, const int sign = 1); -//fourier(VectorWithOffset& c, const int sign = 1); - +void fourier(T& c, const int sign = 1); +// fourier(VectorWithOffset& c, const int sign = 1); /*! \ingroup DFT \brief Compute the inverse of the multi-dimensional discrete fourier transform. @@ -60,17 +56,17 @@ fourier(T& c, const int sign = 1); \see fourier */ template -inline void inverse_fourier(T& c, const int sign=1) -{ - fourier(c,-sign); +inline void +inverse_fourier(T& c, const int sign = 1) { + fourier(c, -sign); #ifdef _MSC_VER - // disable warning about conversion - #pragma warning(disable:4244) +// disable warning about conversion +# pragma warning(disable : 4244) #endif c /= c.size_all(); #ifdef _MSC_VER - // disable warning about conversion - #pragma warning(default:4244) +// disable warning about conversion +# pragma warning(default : 4244) #endif } @@ -86,16 +82,16 @@ inline void inverse_fourier(T& c, const int sign=1) \warning Currently, the array has to be indexed from 0. \warning Currently, the length of the array has to be a power of 2. - + The convention used is as follows. For a vector of length \a n, the result is \f[ r_s = \sum_{s=0}^{n-1} c_r e^{\mathrm{sign} 2\pi i r s/n} \f] This means that the zero-frequency will be returned in c[0] - + This function can be used with more general type of \a c (if instantiated in fourier.cxx). - The type \a T has to be such that \a T::value_type, \a T::reference and + The type \a T has to be such that \a T::value_type, \a T::reference and T::reference T::operator[](const int) exist. Moreover, numerical operations operator*=(T::reference, std::complex\), @@ -114,16 +110,16 @@ void fourier_1d(T& c, const int sign); \see fourier_1d() */ template -inline void inverse_fourier_1d(T& c, const int sign=1) -{ - fourier_1d(c,-sign); +inline void +inverse_fourier_1d(T& c, const int sign = 1) { + fourier_1d(c, -sign); #ifdef _MSC_VER - // disable warning about conversion - #pragma warning(disable:4244) +// disable warning about conversion +# pragma warning(disable : 4244) #endif c /= c.size(); #ifdef _MSC_VER - #pragma warning(default:4244) +# pragma warning(default : 4244) #endif } @@ -131,11 +127,11 @@ inline void inverse_fourier_1d(T& c, const int sign=1) \brief Compute one-dimensional discrete fourier transform of a real array (of even size). - \param[in] c The type of \a c should normally be Array\<1,float\> + \param[in] c The type of \a c should normally be Array\<1,float\> (or \c double). \param[in] sign This can be used to implement a different convention for the DFT. \return The positive frequencies of the DFT as an array of complex numbers. That is, - for c.size()==2*n, the returned array will have indices from 0 + for c.size()==2*n, the returned array will have indices from 0 to n, with the 0 frequency at 0. For a real array, the DFT is such that the values at negative frequencies are the @@ -150,20 +146,18 @@ inline void inverse_fourier_1d(T& c, const int sign=1) compiler that implements the Named-Return-Value-Optimisation, this should not be a problem in most cases. - Result is such that - pos_frequencies_to_all(fourier_1d_for_real_data(v,sign))==fourier(v,sign) + Result is such that + pos_frequencies_to_all(fourier_1d_for_real_data(v,sign))==fourier(v,sign) (this is meant symbolically. In code you'd have to make \c v into an array of complex numbers before passing to \c fourier). - + \see pos_frequencies_to_all() \see fourier_1d() for conventions and restrictions \warning Currently, the array has to have \c get_min_index()==0. */ template -Array<1,std::complex > -fourier_1d_for_real_data(const Array<1,T>& c, const int sign = 1); - +Array<1, std::complex> fourier_1d_for_real_data(const Array<1, T>& c, const int sign = 1); /*! \ingroup DFT @@ -173,8 +167,7 @@ fourier_1d_for_real_data(const Array<1,T>& c, const int sign = 1); \see fourier_1d_for_real_data() */ template -Array<1,T> -inverse_fourier_1d_for_real_data(const Array<1,std::complex >& c, const int sign = 1); +Array<1, T> inverse_fourier_1d_for_real_data(const Array<1, std::complex>& c, const int sign = 1); /*! \ingroup DFT @@ -184,14 +177,13 @@ inverse_fourier_1d_for_real_data(const Array<1,std::complex >& c, const int s \see inverse_fourier_1d_for_real_data() */ template -Array<1,T> - inverse_fourier_1d_for_real_data_corrupting_input(Array<1,std::complex >& c, const int sign); +Array<1, T> inverse_fourier_1d_for_real_data_corrupting_input(Array<1, std::complex>& c, const int sign); /*! \ingroup DFT \brief Compute discrete fourier transform of a real array (with the last dimensions of even size). - \param[in] c The type of \a c should normally be Array\ + \param[in] c The type of \a c should normally be Array\ (or \c double). \param[in] sign This can be used to implement a different convention for the DFT. \return The positive frequencies of the DFT as an array of complex numbers. That is, @@ -200,11 +192,11 @@ Array<1,T> (n1,n2,...,(nd/2)+1), with the 0 frequency at index (0,0,...0). For a real array, the DFT is such that the values at frequency - (k1,k2,...,kd) are the complex conjugate of the value at the corresponding - frequency (-k1,-k2,...,-kd). + (k1,k2,...,kd) are the complex conjugate of the value at the corresponding + frequency (-k1,-k2,...,-kd). \see fourier_1d_for_real_data() - This can be used to compute only the 'positive' half of the frequencies. For this + This can be used to compute only the 'positive' half of the frequencies. For this implementation, this means that only results for frequencies (k1,k2,...,kd) with 0\<=kd\<=(nd/2), i.e. the 'last' dimension has positive frequencies. @@ -212,8 +204,7 @@ Array<1,T> \see pos_frequencies_to_all() */ template - Array > - fourier_for_real_data(const Array& c, const int sign = 1); +Array> fourier_for_real_data(const Array& c, const int sign = 1); /*! \ingroup DFT @@ -223,9 +214,7 @@ template \see fourier_for_real_data() */ template - Array - inverse_fourier_for_real_data(const Array >& c, const int sign = 1); - +Array inverse_fourier_for_real_data(const Array>& c, const int sign = 1); /*! \ingroup DFT @@ -235,8 +224,8 @@ template \see inverse_fourier_for_real_data() */ template -Array - inverse_fourier_for_real_data_corrupting_input(Array >& c, const int sign=1); +Array inverse_fourier_for_real_data_corrupting_input(Array>& c, + const int sign = 1); /*! \ingroup DFT \brief Adds negative frequencies to the last dimension of a complex array by complex conjugation. @@ -244,9 +233,7 @@ Array \see fourier_for_real_data() */ template -Array > -pos_frequencies_to_all(const Array >& c); - +Array> pos_frequencies_to_all(const Array>& c); END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/ieeefp.h b/src/include/stir/numerics/ieeefp.h index 8f3cd2916d..7913c83f3a 100644 --- a/src/include/stir/numerics/ieeefp.h +++ b/src/include/stir/numerics/ieeefp.h @@ -21,8 +21,8 @@ /*! \file \ingroup numerics - - \brief Definition of work-around macros STIR_isnan and STIR_finite for a few non-portable IEEE floating point functions + + \brief Definition of work-around macros STIR_isnan and STIR_finite for a few non-portable IEEE floating point functions \warning The setting of these macros is tricky and only tested on a few systems. Hopefully, somebody else can find a better way. For example, @@ -33,20 +33,19 @@ #include "stir/common.h" - #if defined(_MSC_VER) # include -# define STIR_isnan _isnan -# define STIR_finite _finite +# define STIR_isnan _isnan +# define STIR_finite _finite #else # include - // attempt to get to find isnan but it might not work on some systems - // terrible hack to try and find isnan in std - // will only work for gcc +// attempt to get to find isnan but it might not work on some systems +// terrible hack to try and find isnan in std +// will only work for gcc # if _GLIBCPP_USE_C99 && !_GLIBCPP_USE_C99_FP_MACROS_DYNAMIC # define STIR_isnan std::isnan # define STIR_finite std::isfinite @@ -60,30 +59,30 @@ #endif -#if !defined(STIR_isnan) -# if defined(isnan) - #define STIR_isnan isnan -# else //portable version - // according to IEEE rules if x is NaN, then x!=x - // so, the following will work even on non-IEEE systems - #define STIR_isnan(x) (x)!=(x) -# endif +#if !defined(STIR_isnan) +# if defined(isnan) +# define STIR_isnan isnan +# else // portable version +// according to IEEE rules if x is NaN, then x!=x +// so, the following will work even on non-IEEE systems +# define STIR_isnan(x) (x) != (x) +# endif #endif -#if !defined(STIR_finite) -# if defined(finite) -# define STIR_finite finite -# else //portable version - // we give up and say all numbers are finite - #define STIR_finite(x) true -# endif +#if !defined(STIR_finite) +# if defined(finite) +# define STIR_finite finite +# else // portable version +// we give up and say all numbers are finite +# define STIR_finite(x) true +# endif #endif #ifdef DOXYGEN_SKIP // only when running doxygen - // doxygen doesn't execute above preprocessor commands, but then doesn't generate documentation - // so define something here - #define STIR_finite finite - #define STIR_isnan isnan +// doxygen doesn't execute above preprocessor commands, but then doesn't generate documentation +// so define something here +# define STIR_finite finite +# define STIR_isnan isnan #endif /*! \def STIR_isnan(x) @@ -97,5 +96,4 @@ A (hopefully) portable way to call \c finite. But problems can occur on your sys Current implementation does not always find \c finite and then reverts to \c true. */ - #endif diff --git a/src/include/stir/numerics/integrate_discrete_function.h b/src/include/stir/numerics/integrate_discrete_function.h index 5d10bbf2bd..db9cc28caf 100644 --- a/src/include/stir/numerics/integrate_discrete_function.h +++ b/src/include/stir/numerics/integrate_discrete_function.h @@ -22,7 +22,7 @@ \brief Declaration of stir::integrate_discrete_function function \author Charalampos Tsoumpas - + */ #ifndef __stir_integrate_discrete_function_H__ @@ -30,9 +30,9 @@ #include "stir/common.h" #include -#include +#include #include -#include +#include #include START_NAMESPACE_STIR @@ -49,8 +49,8 @@ START_NAMESPACE_STIR \warning Type \c elemT should not be an integral type. */ template -inline elemT -integrate_discrete_function(const std::vector & coordinates, const std::vector & values, const int interpolation_order = 1); +inline elemT integrate_discrete_function(const std::vector& coordinates, const std::vector& values, + const int interpolation_order = 1); END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/integrate_discrete_function.inl b/src/include/stir/numerics/integrate_discrete_function.inl index 6f40b24e0b..459060ad74 100644 --- a/src/include/stir/numerics/integrate_discrete_function.inl +++ b/src/include/stir/numerics/integrate_discrete_function.inl @@ -28,39 +28,37 @@ START_NAMESPACE_STIR template -elemT -integrate_discrete_function(const std::vector& t , const std::vector& f , const int interpolation_order ) -{ - const std::size_t num_samples=f.size(); - elemT integral_result=0; - assert(num_samples>1); - if(num_samples!=t.size()) +elemT +integrate_discrete_function(const std::vector& t, const std::vector& f, const int interpolation_order) { + const std::size_t num_samples = f.size(); + elemT integral_result = 0; + assert(num_samples > 1); + if (num_samples != t.size()) error("integrate_discrete_function requires equal size of the two input vectors!!!"); - - switch (interpolation_order) + + switch (interpolation_order) { + case 0: + // Rectangular Formula: + // If not at the borders apply: (t_next-t_previous)*0.5*f + // If at the borders apply: (t2-t1)*0.5*f, (tN-TN_previous)*0.5*f + { + integral_result = f[0] * (t[1] - t[0]) * 0.5F; + for (std::size_t i = 1; i < num_samples - 1; ++i) + integral_result += f[i] * (t[i + 1] - t[i - 1]) * 0.5F; + integral_result += f[num_samples - 1] * (t[num_samples - 1] - t[num_samples - 2]) * 0.5F; + } + break; + case 1: + // trapezoidal + // Simply apply the formula: (f_next+f)*(t_next-t)*0.5 { - case 0: - //Rectangular Formula: - // If not at the borders apply: (t_next-t_previous)*0.5*f - // If at the borders apply: (t2-t1)*0.5*f, (tN-TN_previous)*0.5*f - { - integral_result=f[0]*(t[1]-t[0])*0.5F; - for (std::size_t i=1;im.max_eigenvector and max_eigenvalue*max_eigenvector is small - (compared to max_eigenvalue). + (compared to max_eigenvalue). Computation uses the power method, see for instance http://www.maths.lth.se/na/courses/FMN050/FMN050-05/eigenE.pdf. - The method consists in computing + The method consists in computing \f[v^{n+1}=m.v^{n}\f] \f[v^{n+1}/=\mathrm{norm}(v^{n+1})\f] with \f$ v^{0}=\mathrm{start} \f$ - for \f$ n\f$ big enough such that - \f$ \mathrm{norm}(v^{n+1}-v^{n})\f$ becomes smaller + for \f$ n\f$ big enough such that + \f$ \mathrm{norm}(v^{n+1}-v^{n})\f$ becomes smaller than \a tolerance. The eigenvalue is then computed using the Rayleigh - quotient + quotient \f[v.m.v \over v.v \f] This will converge to the eigenvector which has @@ -73,54 +73,48 @@ START_NAMESPACE_STIR (e.g. with opposite sign). */ -template -inline -Succeeded -absolute_max_eigenvector_using_power_method(elemT& max_eigenvalue, - Array<1,elemT>& max_eigenvector, - const Array<2,elemT>& m, - const Array<1,elemT>& start, - const double tolerance = .01, - const unsigned long max_num_iterations = 10000UL) -{ +template +inline Succeeded +absolute_max_eigenvector_using_power_method(elemT& max_eigenvalue, Array<1, elemT>& max_eigenvector, const Array<2, elemT>& m, + const Array<1, elemT>& start, const double tolerance = .01, + const unsigned long max_num_iterations = 10000UL) { assert(m.is_regular()); - if (m.size()==0) - { max_eigenvalue=0; max_eigenvector=start; return Succeeded::yes; } + if (m.size() == 0) { + max_eigenvalue = 0; + max_eigenvector = start; + return Succeeded::yes; + } const double tolerance_squared = square(tolerance); - Array<1,elemT> current = start; + Array<1, elemT> current = start; current /= (*abs_max_element(current.begin(), current.end())); unsigned long remaining_num_iterations = max_num_iterations; double change; - do - { - max_eigenvector = matrix_multiply(m, current); - const elemT norm_factor = *abs_max_element(max_eigenvector.begin(), max_eigenvector.end()); - max_eigenvector /= norm_factor; - change = norm_squared(max_eigenvector - current); - current = max_eigenvector; - --remaining_num_iterations; - } - while (change > tolerance_squared && remaining_num_iterations!=0); - + do { + max_eigenvector = matrix_multiply(m, current); + const elemT norm_factor = *abs_max_element(max_eigenvector.begin(), max_eigenvector.end()); + max_eigenvector /= norm_factor; + change = norm_squared(max_eigenvector - current); + current = max_eigenvector; + --remaining_num_iterations; + } while (change > tolerance_squared && remaining_num_iterations != 0); + current /= static_cast(norm(current)); max_eigenvector = matrix_multiply(m, current); // compute eigenvalue using Rayleigh quotient - max_eigenvalue = - static_cast(inner_product(current,max_eigenvector) / - norm_squared(current)); + max_eigenvalue = static_cast(inner_product(current, max_eigenvector) / norm_squared(current)); max_eigenvector /= static_cast(norm(max_eigenvector)); - return remaining_num_iterations ==0 ? Succeeded::no : Succeeded::yes; + return remaining_num_iterations == 0 ? Succeeded::no : Succeeded::yes; /*norm( max_eigenvector*max_eigenvalue - - matrix_multiply(m, max_eigenvector));*/ + matrix_multiply(m, max_eigenvector));*/ } /*! \ingroup numerics - \brief Compute the eigenvalue with the largest absolute value + \brief Compute the eigenvalue with the largest absolute value and corresponding eigenvector of a matrix by using the shifted power method. \see absolute_max_eigenvector_using_shifted_power_method(). @@ -128,41 +122,31 @@ absolute_max_eigenvector_using_power_method(elemT& max_eigenvalue, The current method calls the normal power method for m-shift*I and shifts the eigenvalue back to the eigenvalue for m. - This method can be used to enhance the convergence rate if you know more + This method can be used to enhance the convergence rate if you know more about the eigenvalues. It can also be used to find another eigenvalue by shifting with the maximum eigenvalue. - */ -template -inline -Succeeded -absolute_max_eigenvector_using_shifted_power_method(elemT& max_eigenvalue, - Array<1,elemT>& max_eigenvector, - const Array<2,elemT>& m, - const Array<1,elemT>& start, - const elemT shift, - const double tolerance = .03, - const unsigned long max_num_iterations = 10000UL) -{ - if (m.get_min_index()!=0 || m[0].get_min_index()!=0) + */ +template +inline Succeeded +absolute_max_eigenvector_using_shifted_power_method(elemT& max_eigenvalue, Array<1, elemT>& max_eigenvector, + const Array<2, elemT>& m, const Array<1, elemT>& start, const elemT shift, + const double tolerance = .03, + const unsigned long max_num_iterations = 10000UL) { + if (m.get_min_index() != 0 || m[0].get_min_index() != 0) error("absolute_max_eigenvector_using_shifted_power_method:\n" - " implementation needs work for indices that don't start from 0. sorry"); + " implementation needs work for indices that don't start from 0. sorry"); - Succeeded success = - absolute_max_eigenvector_using_power_method(max_eigenvalue, - max_eigenvector, - // sadly need to explicitly convert result of subtraction back to Array - Array<2,elemT>(m - diagonal_matrix(static_cast(m.size()), shift)), - start, - tolerance, - max_num_iterations); + Succeeded success = absolute_max_eigenvector_using_power_method( + max_eigenvalue, max_eigenvector, + // sadly need to explicitly convert result of subtraction back to Array + Array<2, elemT>(m - diagonal_matrix(static_cast(m.size()), shift)), start, tolerance, max_num_iterations); max_eigenvalue += shift; return success; } - /*! \ingroup numerics - \brief Compute the eigenvalue with the largest value + \brief Compute the eigenvalue with the largest value and corresponding eigenvector of a matrix by using the power method. \warning This assumes that all eigenvalues are real. @@ -174,53 +158,37 @@ absolute_max_eigenvector_using_shifted_power_method(elemT& max_eigenvalue, This will attempt to find the eigenvector which has the largest eigenvalue. The method fails when the matrix - has a negative eigenvalue of the same magnitude as the + has a negative eigenvalue of the same magnitude as the largest eigenvalue. \todo the algorithm would work with hermitian matrices, but the code needs one small adjustment. -*/ -template -inline -Succeeded -max_eigenvector_using_power_method(elemT& max_eigenvalue, - Array<1,elemT>& max_eigenvector, - const Array<2,elemT>& m, - const Array<1,elemT>& start, - const double tolerance = .03, - const unsigned long max_num_iterations = 10000UL) -{ +*/ +template +inline Succeeded +max_eigenvector_using_power_method(elemT& max_eigenvalue, Array<1, elemT>& max_eigenvector, const Array<2, elemT>& m, + const Array<1, elemT>& start, const double tolerance = .03, + const unsigned long max_num_iterations = 10000UL) { Succeeded success = - absolute_max_eigenvector_using_power_method(max_eigenvalue, - max_eigenvector, - m, - start, - tolerance, - max_num_iterations); + absolute_max_eigenvector_using_power_method(max_eigenvalue, max_eigenvector, m, start, tolerance, max_num_iterations); if (success == Succeeded::no) return Succeeded::no; - if (max_eigenvalue>=0) // TODO would need to take real value for complex case + if (max_eigenvalue >= 0) // TODO would need to take real value for complex case return Succeeded::yes; // we found a negative eigenvalue // try again with a shift equal to the previously found max_eigenvalue // this shift will effectively put that eigenvalue to 0 during the // power method iterations - // also it will make all eigenvalues positive (as we subtract the + // also it will make all eigenvalues positive (as we subtract the // smallest negative eigenvalue) - success = - absolute_max_eigenvector_using_shifted_power_method(max_eigenvalue, - max_eigenvector, - m, - start, - max_eigenvalue, - tolerance, - max_num_iterations); + success = absolute_max_eigenvector_using_shifted_power_method(max_eigenvalue, max_eigenvector, m, start, max_eigenvalue, + tolerance, max_num_iterations); if (success == Succeeded::no) return Succeeded::no; - assert(max_eigenvalue>=0); + assert(max_eigenvalue >= 0); return Succeeded::yes; } diff --git a/src/include/stir/numerics/norm.h b/src/include/stir/numerics/norm.h index bc756382a9..2c077cf963 100644 --- a/src/include/stir/numerics/norm.h +++ b/src/include/stir/numerics/norm.h @@ -20,26 +20,28 @@ #ifndef __stir_numerics_norm_H__ #define __stir_numerics_norm_H__ /*! - \file + \file \ingroup numerics - \brief Declaration of the stir::norm(), stir::norm_squared() functions and + \brief Declaration of the stir::norm(), stir::norm_squared() functions and stir::NormSquared unary function \author Kris Thielemans */ - #include "stir/common.h" #include #include -# ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::fabs; } -# endif +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::fabs; +} +#endif START_NAMESPACE_STIR -template class Array; +template +class Array; /*! \ingroup numerics @@ -49,56 +51,53 @@ template class Array; //! A helper class that computes the square of the norm of numeric data /*! It's there to avoid unnecessary sqrts when computing norms of vectors. - - The default template just uses the square (with conversion to double), + + The default template just uses the square (with conversion to double), but we'll specialise it for complex numbers. It's derived from std::unary_function such that it follows the conventions for a function object. -*/ +*/ // specialisations for complex numbers are in .inl file for clarity of this file. template -struct NormSquared : - public std::unary_function -{ - double operator()(T x) const - { - return static_cast(x)*x; - } +struct NormSquared : public std::unary_function { + double operator()(T x) const { return static_cast(x) * x; } }; - //! Returns the square of the norm of a number /*! \see norm(elemT)*/ template inline double -norm_squared (const elemT t) -{ return NormSquared()(t); } - +norm_squared(const elemT t) { + return NormSquared()(t); +} //! Returns the norm of a number /*! This is the same as the absolute value, but works also for std::complex.*/ template inline double -norm (const elemT t) -{ return sqrt(norm_squared(t)); } +norm(const elemT t) { + return sqrt(norm_squared(t)); +} // 2 overloads to avoid doing sqrt(t*t) inline double -norm (const double t) -{ return std::fabs(t); } +norm(const double t) { + return std::fabs(t); +} inline double -norm (const float t) -{ return std::fabs(t); } +norm(const float t) { + return std::fabs(t); +} //! Returns the square of the l2-norm of a sequence /*! The l2-norm is defined as the sqrt of the sum of squares of the norms of each element in the sequence. */ template -inline double norm_squared (Iter begin, Iter end); +inline double norm_squared(Iter begin, Iter end); //! Returns the l2-norm of a sequence /*! The l2-norm is defined as the sqrt of the sum of squares of the norms @@ -107,26 +106,23 @@ inline double norm_squared (Iter begin, Iter end); \see norm(const Array<1,elemT>&) for a convenience function for Array objects. */ template -inline double norm (Iter begin, Iter end); +inline double norm(Iter begin, Iter end); //! l2 norm of a 1D array -/*! - This returns the sqrt of the sum of the square of the absolute values +/*! + This returns the sqrt of the sum of the square of the absolute values of the elements of \a v1. */ -template -inline double -norm (const Array<1,elemT> & v1); - +template +inline double norm(const Array<1, elemT>& v1); //! square of the l2 norm of a 1D array -/*! - This returns the sum of the square of the absolute values of the +/*! + This returns the sum of the square of the absolute values of the elements of \a v1. */ -template -inline double -norm_squared (const Array<1,elemT> & v1); +template +inline double norm_squared(const Array<1, elemT>& v1); //@} diff --git a/src/include/stir/numerics/norm.inl b/src/include/stir/numerics/norm.inl index 3b64199b10..7d276539d1 100644 --- a/src/include/stir/numerics/norm.inl +++ b/src/include/stir/numerics/norm.inl @@ -18,80 +18,68 @@ */ /*! - \file + \file \ingroup numerics - \brief Implementation of the stir::norm(), stir::norm_squared() functions and + \brief Implementation of the stir::norm(), stir::norm_squared() functions and stir::NormSquared unary function \author Kris Thielemans */ - #include #include -# ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::fabs; } -# endif +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::fabs; +} +#endif START_NAMESPACE_STIR - #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template -struct NormSquared > - : public std::unary_function&, double> -{ - double operator()(const std::complex& x) const - { return square(x.real())+ square(x.imag()); } +struct NormSquared> : public std::unary_function&, double> { + double operator()(const std::complex& x) const { return square(x.real()) + square(x.imag()); } }; #else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // handle float and double separately. (sigh) -#define INSTANTIATE_NormSquared(T) \ - template <> \ - struct NormSquared > \ - : public std::unary_function&, double> \ -{ \ - double operator()(const std::complex& x) const \ - { return square(x.real())+ square(x.imag()); } \ -}; -INSTANTIATE_NormSquared(float) -INSTANTIATE_NormSquared(double) -#undef INSTANTIATE_NormSquared +# define INSTANTIATE_NormSquared(T) \ + template <> \ + struct NormSquared> : public std::unary_function&, double> { \ + double operator()(const std::complex& x) const { return square(x.real()) + square(x.imag()); } \ + }; +INSTANTIATE_NormSquared(float) INSTANTIATE_NormSquared(double) +# undef INSTANTIATE_NormSquared #endif - template -double norm_squared (Iter begin, Iter end) -{ +double +norm_squared(Iter begin, Iter end) { double res = 0; - for (Iter iter= begin; iter != end; ++iter) - res+= norm_squared(*iter); + for (Iter iter = begin; iter != end; ++iter) + res += norm_squared(*iter); return res; } template -double norm (Iter begin, Iter end) -{ +double +norm(Iter begin, Iter end) { return sqrt(norm_squared(begin, end)); } - -template -inline double -norm (const Array<1,elemT> & v1) -{ +template +inline double +norm(const Array<1, elemT>& v1) { return norm(v1.begin(), v1.end()); } -template -inline double -norm_squared(const Array<1,elemT> & v1) -{ +template +inline double +norm_squared(const Array<1, elemT>& v1) { return norm_squared(v1.begin(), v1.end()); } END_NAMESPACE_STIR - diff --git a/src/include/stir/numerics/overlap_interpolate.h b/src/include/stir/numerics/overlap_interpolate.h index b2de77d584..41f53f919f 100644 --- a/src/include/stir/numerics/overlap_interpolate.h +++ b/src/include/stir/numerics/overlap_interpolate.h @@ -29,32 +29,28 @@ */ #ifndef __stir_numerics_overlap_interpolate__H__ -#define __stir_numerics_overlap_interpolate__H__ +#define __stir_numerics_overlap_interpolate__H__ #include "stir/common.h" START_NAMESPACE_STIR -template class VectorWithOffset; +template +class VectorWithOffset; /*! \ingroup numerics - + \brief 'overlap' interpolation (i.e. count preserving) for vectors. - \see overlap_interpolate(const out_iter_t out_begin, const out_iter_t out_end, - const out_coord_iter_t out_coord_begin, const out_coord_iter_t out_coord_end, - const in_iter_t in_begin, in_iter_t in_end, - const in_coord_iter_t in_coord_begin, const in_coord_iter_t in_coord_end, - const bool only_add_to_output=false, const bool assign_rest_with_zeroes) + \see overlap_interpolate(const out_iter_t out_begin, const out_iter_t out_end, + const out_coord_iter_t out_coord_begin, const out_coord_iter_t out_coord_end, + const in_iter_t in_begin, in_iter_t in_end, + const in_coord_iter_t in_coord_begin, const in_coord_iter_t in_coord_end, + const bool only_add_to_output=false, const bool assign_rest_with_zeroes) */ template -void -overlap_interpolate(VectorWithOffset& out_data, - const VectorWithOffset& in_data, - const float zoom, - const float offset, - const bool assign_rest_with_zeroes = true); - +void overlap_interpolate(VectorWithOffset& out_data, const VectorWithOffset& in_data, const float zoom, const float offset, + const bool assign_rest_with_zeroes = true); /*! \ingroup numerics \brief 'overlap' interpolation for iterators, with arbitrary 'bin' sizes. @@ -64,13 +60,13 @@ overlap_interpolate(VectorWithOffset& out_data, step-wise function, such that the counts (i.e. integrals) are preserved. - In and out data are specified using iterators. For each, there is + In and out data are specified using iterators. For each, there is also a pair of iterators specifying the coordinates of the edges - of the 'bins' (or 'boxes') in some arbitrary coordinate system + of the 'bins' (or 'boxes') in some arbitrary coordinate system (common between in and out parameters of course). Note that there should be one more coordinate than data (i.e. you have to specify the last edge as well). This is (only) checked with assert() statements. - + \param only_add_to_output If \c false will overwrite any data present in the output (aside from possibly the tails: see \c assign_rest_with_zeroes). @@ -78,9 +74,9 @@ overlap_interpolate(VectorWithOffset& out_data, \param assign_rest_with_zeroes If \c false does not set values in the \c out range which do not overlap with \c in range. - If \c true those data are set to 0. + If \c true those data are set to 0. - \warning when the out iterators point to an integral type, there is no + \warning when the out iterators point to an integral type, there is no rounding but truncation. \par Examples: @@ -104,12 +100,12 @@ overlap_interpolate(VectorWithOffset& out_data, for (int i=out_coords.get_min_index(); i<=out_coords.get_max_index(); ++i) out_coords[i]=(i-.5F)/zoom+offset; overlap_interpolate(out.begin(), out.end(), - out_coords.begin(), out_coords.end(), - in.begin(), in.end(), - in_coords.begin(), in_coords.end() - ); + out_coords.begin(), out_coords.end(), + in.begin(), in.end(), + in_coords.begin(), in_coords.end() + ); \endcode - + \par Implementation details: Because this implementation works for arbitrary (numeric) types, it @@ -117,7 +113,7 @@ overlap_interpolate(VectorWithOffset& out_data, In particular,
      • we do our best to avoid creating temporary objects
      • -
      • we zero values by using multiplication with 0. This is to allow +
      • we zero values by using multiplication with 0. This is to allow the case where assignment with an int (or float) does not exist (in particular, in our higher dimensional arrays).
      @@ -128,15 +124,11 @@ overlap_interpolate(VectorWithOffset& out_data,
    • first version by Kris Thielemans
    */ -template -inline -void - overlap_interpolate(const out_iter_t out_begin, const out_iter_t out_end, - const out_coord_iter_t out_coord_begin, const out_coord_iter_t out_coord_end, - const in_iter_t in_begin, in_iter_t in_end, - const in_coord_iter_t in_coord_begin, const in_coord_iter_t in_coord_end, - const bool only_add_to_output=false, const bool assign_rest_with_zeroes=true); +template +inline void overlap_interpolate(const out_iter_t out_begin, const out_iter_t out_end, const out_coord_iter_t out_coord_begin, + const out_coord_iter_t out_coord_end, const in_iter_t in_begin, in_iter_t in_end, + const in_coord_iter_t in_coord_begin, const in_coord_iter_t in_coord_end, + const bool only_add_to_output = false, const bool assign_rest_with_zeroes = true); END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/overlap_interpolate.inl b/src/include/stir/numerics/overlap_interpolate.inl index 1f05dc8732..fce65d5995 100644 --- a/src/include/stir/numerics/overlap_interpolate.inl +++ b/src/include/stir/numerics/overlap_interpolate.inl @@ -27,16 +27,12 @@ #include "boost/iterator/iterator_traits.hpp" START_NAMESPACE_STIR -template +template void - overlap_interpolate(const out_iter_t out_begin, const out_iter_t out_end, - const out_coord_iter_t out_coord_begin, const out_coord_iter_t out_coord_end, - const in_iter_t in_begin, in_iter_t in_end, - const in_coord_iter_t in_coord_begin, const in_coord_iter_t in_coord_end, - const bool only_add_to_output, - const bool assign_rest_with_zeroes) -{ +overlap_interpolate(const out_iter_t out_begin, const out_iter_t out_end, const out_coord_iter_t out_coord_begin, + const out_coord_iter_t out_coord_end, const in_iter_t in_begin, in_iter_t in_end, + const in_coord_iter_t in_coord_begin, const in_coord_iter_t in_coord_end, const bool only_add_to_output, + const bool assign_rest_with_zeroes) { if (out_begin == out_end) return; @@ -46,8 +42,8 @@ void // check sizes. // these asserts can be disabled if we ever use this function with iterators // that don't support the next 2 lines - assert(out_coord_end - out_coord_begin - 1 == (out_end - out_begin)); - assert(in_coord_end - in_coord_begin - 1 == (in_end - in_begin)); + assert(out_coord_end - out_coord_begin - 1 == (out_end - out_begin)); + assert(in_coord_end - in_coord_begin - 1 == (in_end - in_begin)); out_iter_t out_iter = out_begin; out_coord_iter_t out_coord_iter = out_coord_begin; @@ -56,110 +52,97 @@ void in_coord_iter_t in_coord_iter = in_coord_begin; // skip input to the left of the output range - assert(in_coord_iter+1 != in_coord_end); - while (*(in_coord_iter+1) <= *out_coord_iter) - { - ++in_coord_iter; ++in_iter; - if (in_coord_iter+1 == in_coord_end) - return; - } + assert(in_coord_iter + 1 != in_coord_end); + while (*(in_coord_iter + 1) <= *out_coord_iter) { + ++in_coord_iter; + ++in_iter; + if (in_coord_iter + 1 == in_coord_end) + return; + } // skip output to the left of the input range - assert(out_coord_iter+1 != out_coord_end); - while (*(out_coord_iter+1) <= *in_coord_iter) - { - if (!only_add_to_output && assign_rest_with_zeroes) - *out_iter *= 0; // note: use *= such that it works for multi-dim arrays - ++out_coord_iter; ++out_iter; - if (out_coord_iter+1 == out_coord_end) - return; - } + assert(out_coord_iter + 1 != out_coord_end); + while (*(out_coord_iter + 1) <= *in_coord_iter) { + if (!only_add_to_output && assign_rest_with_zeroes) + *out_iter *= 0; // note: use *= such that it works for multi-dim arrays + ++out_coord_iter; + ++out_iter; + if (out_coord_iter + 1 == out_coord_end) + return; + } // now first in-box overlaps guaranteed with first out-box - assert(*(out_coord_iter+1) > *in_coord_iter); - assert(*(in_coord_iter+1) > *out_coord_iter); + assert(*(out_coord_iter + 1) > *in_coord_iter); + assert(*(in_coord_iter + 1) > *out_coord_iter); // a typedef for the coordinate type typedef typename boost::iterator_value::type coord_t; // find small number for comparisons. // we'll take it 1000 times smaller than the minimum of the average out_box size or in_box size - const coord_t epsilon = - std::min(((*(out_coord_end-1)) - (*out_coord_begin)) / - ((out_coord_end-1 - out_coord_begin)*10000), - ((*(in_coord_end-1)) - (*in_coord_begin)) / - ((in_coord_end-1 - in_coord_begin)*10000)); - + const coord_t epsilon = + std::min(((*(out_coord_end - 1)) - (*out_coord_begin)) / ((out_coord_end - 1 - out_coord_begin) * 10000), + ((*(in_coord_end - 1)) - (*in_coord_begin)) / ((in_coord_end - 1 - in_coord_begin) * 10000)); + // do actual interpolation // we walk through the boxes, checking the overlap. // after each step, we'll advance either in_iter or out_iter. coord_t current_coord = std::max(*in_coord_iter, *out_coord_iter); bool first_time_for_this_out_box = true; - while (true) - { - // right edge of in-box is beyond out-box - const bool in_beyond_out = - *(in_coord_iter+1) > *(out_coord_iter+1); - const coord_t new_coord = - in_beyond_out ? *(out_coord_iter+1) : *(in_coord_iter+1); + while (true) { + // right edge of in-box is beyond out-box + const bool in_beyond_out = *(in_coord_iter + 1) > *(out_coord_iter + 1); + const coord_t new_coord = in_beyond_out ? *(out_coord_iter + 1) : *(in_coord_iter + 1); #ifndef STIR_OVERLAP_NORMALISATION - const coord_t overlap = (new_coord - current_coord); + const coord_t overlap = (new_coord - current_coord); #else - const coord_t overlap = (new_coord - current_coord)/ - (*(out_coord_iter+1) - *(out_coord_iter)); + const coord_t overlap = (new_coord - current_coord) / (*(out_coord_iter + 1) - *(out_coord_iter)); #endif - assert(overlap>-epsilon); - - if (!only_add_to_output && first_time_for_this_out_box) - { - if (overlap>epsilon) - *out_iter = *in_iter * overlap; - else - *out_iter *= 0; - first_time_for_this_out_box = false; - } - else - { - if (overlap>epsilon) - *out_iter += *in_iter * overlap; - } - current_coord = new_coord; - if (in_beyond_out) - { - ++out_coord_iter; ++out_iter; - if (out_iter == out_end) - { - assert(out_coord_iter+1 == out_coord_end); - return; // all out-boxes are done - } - first_time_for_this_out_box = true; - } + assert(overlap > -epsilon); + + if (!only_add_to_output && first_time_for_this_out_box) { + if (overlap > epsilon) + *out_iter = *in_iter * overlap; else - { - ++in_coord_iter; ++in_iter; - if (in_iter == in_end) - break; - } - } // end of while - - assert(in_coord_iter+1 == in_coord_end); + *out_iter *= 0; + first_time_for_this_out_box = false; + } else { + if (overlap > epsilon) + *out_iter += *in_iter * overlap; + } + current_coord = new_coord; + if (in_beyond_out) { + ++out_coord_iter; + ++out_iter; + if (out_iter == out_end) { + assert(out_coord_iter + 1 == out_coord_end); + return; // all out-boxes are done + } + first_time_for_this_out_box = true; + } else { + ++in_coord_iter; + ++in_iter; + if (in_iter == in_end) + break; + } + } // end of while + + assert(in_coord_iter + 1 == in_coord_end); // fill rest of output with 0 - if (!only_add_to_output && assign_rest_with_zeroes) - { - while (true) - { - ++out_iter; + if (!only_add_to_output && assign_rest_with_zeroes) { + while (true) { + ++out_iter; #ifndef NDEBUG - // increment just so we can check at the end that there is - // one more out_coord_iter than out_iter - ++out_coord_iter; + // increment just so we can check at the end that there is + // one more out_coord_iter than out_iter + ++out_coord_iter; #endif - if (out_iter == out_end) - break; - *out_iter *= 0; // note: use *= such that it works for multi-dim arrays - } - assert(out_coord_iter+1 == out_coord_end); + if (out_iter == out_end) + break; + *out_iter *= 0; // note: use *= such that it works for multi-dim arrays } + assert(out_coord_iter + 1 == out_coord_end); + } } END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/sampling_functions.h b/src/include/stir/numerics/sampling_functions.h index dab9a2be8c..5dbb90760a 100644 --- a/src/include/stir/numerics/sampling_functions.h +++ b/src/include/stir/numerics/sampling_functions.h @@ -17,7 +17,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics \brief Sampling functions (currently only stir::sample_function_on_regular_grid) @@ -36,11 +36,11 @@ START_NAMESPACE_STIR \param[in] func function to sample \param[in] offset offset to use for coordinates (see below) \param[in] step step size to use for coordinates (see below) - + Symbolically, this function does the following computation for every index in the array \code out(index) = func(index * step - offset) - \endcode + \endcode \par requirement for type FunctionType Due to the calling sequence above, the following has to be defined @@ -51,11 +51,8 @@ START_NAMESPACE_STIR \todo At the moment, only the 3D version is implemented, but this could be templated. */ template -inline -void sample_function_on_regular_grid(Array<3,elemT>& out, - FunctionType func, - const BasicCoordinate<3, positionT>& offset, - const BasicCoordinate<3, positionT>& step); +inline void sample_function_on_regular_grid(Array<3, elemT>& out, FunctionType func, const BasicCoordinate<3, positionT>& offset, + const BasicCoordinate<3, positionT>& step); END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 4ac29f321a..b3ecb1eeb3 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -8,12 +8,12 @@ This file is part of STIR. it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! @@ -26,40 +26,33 @@ This file is part of STIR. START_NAMESPACE_STIR template -void sample_function_on_regular_grid(Array<3,elemT>& out, - FunctionType func, - const BasicCoordinate<3, positionT>& offset, - const BasicCoordinate<3, positionT>& step) -{ - BasicCoordinate<3,int> min_out, max_out; - IndexRange<3> out_range = out.get_index_range(); - if (!out_range.get_regular_range(min_out,max_out)) +void +sample_function_on_regular_grid(Array<3, elemT>& out, FunctionType func, const BasicCoordinate<3, positionT>& offset, + const BasicCoordinate<3, positionT>& step) { + BasicCoordinate<3, int> min_out, max_out; + IndexRange<3> out_range = out.get_index_range(); + if (!out_range.get_regular_range(min_out, max_out)) warning("Output must be regular range!"); - + BasicCoordinate<3, int> index_out; - BasicCoordinate<3, positionT> relative_positions; - index_out[1]=min_out[1]; - relative_positions[1]= index_out[1] * step[1] - offset[1] ; - const BasicCoordinate<3, positionT> max_relative_positions= - (BasicCoordinate<3,positionT>(max_out)+static_cast(.001)) * step + offset; - for (; - index_out[1]<=max_out[1] && relative_positions[1]<=max_relative_positions[1]; - ++index_out[1], relative_positions[1]+= step[1]) - { - index_out[2]=min_out[2]; - relative_positions[2]= index_out[2] * step[2] + offset[2] ; - for (; - index_out[2]<=max_out[2] && relative_positions[2]<=max_relative_positions[2]; - ++index_out[2], relative_positions[2]+= step[2]) - { - index_out[3]=min_out[3]; - relative_positions[3]= index_out[3] * step[3] + offset[3] ; - for (; - index_out[3]<=max_out[3] && relative_positions[3]<=max_relative_positions[3]; - ++index_out[3], relative_positions[3]+= step[3]) - out[index_out] = func(relative_positions) ; - } - } + BasicCoordinate<3, positionT> relative_positions; + index_out[1] = min_out[1]; + relative_positions[1] = index_out[1] * step[1] - offset[1]; + const BasicCoordinate<3, positionT> max_relative_positions = + (BasicCoordinate<3, positionT>(max_out) + static_cast(.001)) * step + offset; + for (; index_out[1] <= max_out[1] && relative_positions[1] <= max_relative_positions[1]; + ++index_out[1], relative_positions[1] += step[1]) { + index_out[2] = min_out[2]; + relative_positions[2] = index_out[2] * step[2] + offset[2]; + for (; index_out[2] <= max_out[2] && relative_positions[2] <= max_relative_positions[2]; + ++index_out[2], relative_positions[2] += step[2]) { + index_out[3] = min_out[3]; + relative_positions[3] = index_out[3] * step[3] + offset[3]; + for (; index_out[3] <= max_out[3] && relative_positions[3] <= max_relative_positions[3]; + ++index_out[3], relative_positions[3] += step[3]) + out[index_out] = func(relative_positions); + } + } } END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/stir_NumericalRecipes.h b/src/include/stir/numerics/stir_NumericalRecipes.h index 535b2cef36..60b406b3c8 100644 --- a/src/include/stir/numerics/stir_NumericalRecipes.h +++ b/src/include/stir/numerics/stir_NumericalRecipes.h @@ -2,7 +2,7 @@ // /*! - \file + \file \ingroup numerics \brief functions to convert from data in Numerical Recipes format to STIR arrays. @@ -40,95 +40,76 @@ START_NAMESPACE_STIR */ //@{ -inline void stir_to_nr(const VectorWithOffset< std::complex >& c, - VectorWithOffset& nr_data) -{ - for (int i=0; i>& c, VectorWithOffset& nr_data) { + for (int i = 0; i < c.get_length(); ++i) { + nr_data[2 * i + 1] = c[i].real(); + nr_data[2 * i + 2] = c[i].imag(); } } -inline void stir_to_nr(const Array<2,std::complex >& c2d, - VectorWithOffset& nr_data) -{ - +inline void +stir_to_nr(const Array<2, std::complex>& c2d, VectorWithOffset& nr_data) { + VectorWithOffset::iterator nr_iter = nr_data.begin(); - - Array<2,std::complex >::const_full_iterator iter= - c2d.begin_all(); - - while(iter != c2d.end_all()) - { - *nr_iter++ = iter->real(); - *nr_iter++ = iter->imag(); - ++iter; - } + + Array<2, std::complex>::const_full_iterator iter = c2d.begin_all(); + + while (iter != c2d.end_all()) { + *nr_iter++ = iter->real(); + *nr_iter++ = iter->imag(); + ++iter; + } } +inline void +stir_to_nr(const VectorWithOffset>>& c2d, VectorWithOffset& nr_data) { -inline void stir_to_nr(const VectorWithOffset > >& c2d, - VectorWithOffset& nr_data) -{ - VectorWithOffset::iterator nr_iter = nr_data.begin(); - VectorWithOffset > >::const_iterator iter = - c2d.begin(); - while(iter != c2d.end()) - { - Array<1,std::complex >::const_iterator row_iter = iter->begin(); - while(row_iter != iter->end()) - { - *nr_iter++ = row_iter->real(); - *nr_iter++ = row_iter->imag(); - ++row_iter; - } - ++iter; + VectorWithOffset>>::const_iterator iter = c2d.begin(); + while (iter != c2d.end()) { + Array<1, std::complex>::const_iterator row_iter = iter->begin(); + while (row_iter != iter->end()) { + *nr_iter++ = row_iter->real(); + *nr_iter++ = row_iter->imag(); + ++row_iter; } + ++iter; + } } -void nr_to_stir(const VectorWithOffset& nr_data, - VectorWithOffset< std::complex >& c) -{ - for (int i=0; i(nr_data[2*i+1], nr_data[2*i+2]); +void +nr_to_stir(const VectorWithOffset& nr_data, VectorWithOffset>& c) { + for (int i = 0; i < c.get_length(); ++i) { + c[i] = std::complex(nr_data[2 * i + 1], nr_data[2 * i + 2]); } } -inline void nr_to_stir(const VectorWithOffset& nr_data, - Array<2,std::complex > & c2d) -{ +inline void +nr_to_stir(const VectorWithOffset& nr_data, Array<2, std::complex>& c2d) { VectorWithOffset::const_iterator nr_iter = nr_data.begin(); - Array<2,std::complex >::full_iterator iter= - c2d.begin_all(); - while(iter != c2d.end_all()) - { - *iter = std::complex(*nr_iter, *(nr_iter+1)); - nr_iter+= 2; - ++iter; - } + Array<2, std::complex>::full_iterator iter = c2d.begin_all(); + while (iter != c2d.end_all()) { + *iter = std::complex(*nr_iter, *(nr_iter + 1)); + nr_iter += 2; + ++iter; + } } -inline void nr_to_stir(const VectorWithOffset& nr_data, - VectorWithOffset > >& c2d) -{ +inline void +nr_to_stir(const VectorWithOffset& nr_data, VectorWithOffset>>& c2d) { VectorWithOffset::const_iterator nr_iter = nr_data.begin(); - VectorWithOffset > >::iterator iter = - c2d.begin(); - while(iter != c2d.end()) - { - Array<1,std::complex >::iterator row_iter = iter->begin(); - while(row_iter != iter->end()) - { - *row_iter = std::complex(*nr_iter, *(nr_iter+1)); - nr_iter+= 2; - ++row_iter; - } - ++iter; + VectorWithOffset>>::iterator iter = c2d.begin(); + while (iter != c2d.end()) { + Array<1, std::complex>::iterator row_iter = iter->begin(); + while (row_iter != iter->end()) { + *row_iter = std::complex(*nr_iter, *(nr_iter + 1)); + nr_iter += 2; + ++row_iter; } + ++iter; + } } #if 0 diff --git a/src/include/stir/recon_array_functions.h b/src/include/stir/recon_array_functions.h index bad1be95a4..68a5bb132a 100644 --- a/src/include/stir/recon_array_functions.h +++ b/src/include/stir/recon_array_functions.h @@ -22,9 +22,9 @@ #define __stir_recon_array_functions_h_ /*! - \file + \file \ingroup buildblock - + \brief a variety of useful functions \author Matthew Jacobson @@ -37,15 +37,18 @@ START_NAMESPACE_STIR - // TODO template this all in data type of Viewgram et al - -template class SegmentByView; -template class SegmentBySinogram; -template class Viewgram; -template class RelatedViewgrams; -template class DiscretisedDensity; +template +class SegmentByView; +template +class SegmentBySinogram; +template +class Viewgram; +template +class RelatedViewgrams; +template +class DiscretisedDensity; #if 0 //! scales an image and adds it to another @@ -55,9 +58,9 @@ void multiply_and_add(DiscretisedDensity<3,float> &image_res, const DiscretisedD //! truncates negative values to zero float neg_trunc(float x); -//MJ 17/05/2000 disabled +// MJ 17/05/2000 disabled // gives 1 if negative, 0 otherwise -//float neg_indicate(float x){return (x<=0.0)?1.0:0.0;} +// float neg_indicate(float x){return (x<=0.0)?1.0:0.0;} #if 0 //! sets non-positive voxel values to small positive ones AND truncate to circular FOV @@ -74,21 +77,16 @@ void divide_and_truncate(DiscretisedDensity<3,float>& numerator, #endif //! divide viewgrams and set 'edge bins' to zero, put answer in numerator -void divide_and_truncate(Viewgram& numerator, const Viewgram& denominator, - const int rim_truncation_sino, - int& count, int& count2, double* f = NULL); +void divide_and_truncate(Viewgram& numerator, const Viewgram& denominator, const int rim_truncation_sino, + int& count, int& count2, double* f = NULL); //! divide related viewgrams and set 'edge bins' to zero, put answer in numerator void divide_and_truncate(RelatedViewgrams& numerator, const RelatedViewgrams& denominator, - const int rim_truncation_sino, - int& count, int& count2, double* f = NULL); + const int rim_truncation_sino, int& count, int& count2, double* f = NULL); //! sets to zero voxels within rim_truncation_image of the FOV rim -void truncate_rim(DiscretisedDensity<3,float>& image_input, - const int rim_truncation_image, - const bool strictly_less_than_radius = true); - - +void truncate_rim(DiscretisedDensity<3, float>& image_input, const int rim_truncation_image, + const bool strictly_less_than_radius = true); //! sets the first and last rim_truncation_sino bins at the 'edges' to zero void truncate_rim(SegmentByView& seg, const int rim_truncation_sino); @@ -97,23 +95,19 @@ void truncate_rim(SegmentByView& seg, const int rim_truncation_sino); void truncate_rim(Viewgram& viewgram, const int rim_truncation_sino); //! sets the end planes of the image to zero -void truncate_end_planes(DiscretisedDensity<3,float> &input_image, int input_num_planes=1); +void truncate_end_planes(DiscretisedDensity<3, float>& input_image, int input_num_planes = 1); //! simple division of two sinograms, x/0 = 0 void divide_array(SegmentByView& numerator, const SegmentByView& denominator); //! simple division of two images, x/0 = 0 -void divide_array(DiscretisedDensity<3,float>& numerator, const DiscretisedDensity<3,float>& denominator); +void divide_array(DiscretisedDensity<3, float>& numerator, const DiscretisedDensity<3, float>& denominator); -//MJ 03/01/2000 Trying to adhoc parallelize a loglikelihood computation +// MJ 03/01/2000 Trying to adhoc parallelize a loglikelihood computation //! compute the log term of the loglikelihood function for given part of the projection space -void accumulate_loglikelihood(Viewgram& projection_data, - const Viewgram& estimated_projections, - const int rim_truncation_sino, - double* accum); - +void accumulate_loglikelihood(Viewgram& projection_data, const Viewgram& estimated_projections, + const int rim_truncation_sino, double* accum); END_NAMESPACE_STIR #endif // __recon_array_functions_h_ - diff --git a/src/include/stir/recon_buildblock/AnalyticReconstruction.h b/src/include/stir/recon_buildblock/AnalyticReconstruction.h index 093802caa8..e6e595f15c 100644 --- a/src/include/stir/recon_buildblock/AnalyticReconstruction.h +++ b/src/include/stir/recon_buildblock/AnalyticReconstruction.h @@ -2,28 +2,28 @@ // /* Copyright (C) 2000 PARAPET partners - Copyright (C) 2000- 2007, Hammersmith Imanet Ltd + Copyright (C) 2000- 2007, Hammersmith Imanet Ltd Copyright (C) 2016, 2018, 2019 University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ #ifndef __stir_recon_buildblock_AnalyticReconstruction_H__ #define __stir_recon_buildblock_AnalyticReconstruction_H__ /*! - \file + \file \ingroup recon_buildblock - + \brief declares the stir::AnalyticReconstruction class \author Kris Thielemans @@ -43,7 +43,6 @@ START_NAMESPACE_STIR - class Succeeded; /*! @@ -56,28 +55,25 @@ class Succeeded; because of conversion problems with stir::shared_ptr. Maybe it will be possible to correct this once we use boost:shared_ptr. */ -class AnalyticReconstruction : - public Reconstruction > -{ +class AnalyticReconstruction : public Reconstruction> { public: - typedef DiscretisedDensity<3,float> TargetT; + typedef DiscretisedDensity<3, float> TargetT; + private: - typedef Reconstruction base_type; -public: + typedef Reconstruction base_type; +public: //! construct an image from parameters set (e.g. during parsing) - virtual DiscretisedDensity<3,float>* - construct_target_image_ptr() const; + virtual DiscretisedDensity<3, float>* construct_target_image_ptr() const; //! reconstruct and write to file /*! Calls construct_target_image_ptr() and then actual_reconstruct(target_image_sptr). - At the end of the reconstruction, the final image is saved to file as given in - Reconstruction::output_filename_prefix. + At the end of the reconstruction, the final image is saved to file as given in + Reconstruction::output_filename_prefix. \return Succeeded::yes if everything was alright. */ - virtual Succeeded - reconstruct(); + virtual Succeeded reconstruct(); //! executes the reconstruction storing result in \c target_image_sptr /*! @@ -87,11 +83,10 @@ class AnalyticReconstruction : \par Developer\'s note Because of C++ rules, overloading one of the reconstruct() functions - in a derived class, hides the other. So, we need an implementation for + in a derived class, hides the other. So, we need an implementation for this function. This is the reason to use the actual_reconstruct function. - */ - virtual Succeeded - reconstruct(shared_ptr const& target_image_sptr); + */ + virtual Succeeded reconstruct(shared_ptr const& target_image_sptr); virtual void set_input_data(const shared_ptr&); virtual const ProjData& get_input_data() const; @@ -109,8 +104,7 @@ class AnalyticReconstruction : void set_offset(const CartesianCoordinate3D&); //@} - protected: - +protected: //! the input projection data file name std::string input_filename; //! the maximum absolute ring difference number to use in the reconstruction @@ -125,28 +119,21 @@ class AnalyticReconstruction : int num_views_to_add; #endif - - protected: ParseAndCreateFrom target_parameter_parser; //! executes the reconstruction storing result in \c target_image_sptr /*! \return Succeeded::yes if everything was alright. - */ - virtual Succeeded - actual_reconstruct(shared_ptr const& target_image_sptr) = 0; - + */ + virtual Succeeded actual_reconstruct(shared_ptr const& target_image_sptr) = 0; + //! used to check acceptable parameter ranges, etc... - virtual bool post_processing(); + virtual bool post_processing(); virtual void set_defaults(); virtual void initialise_keymap(); - - }; END_NAMESPACE_STIR - #endif - diff --git a/src/include/stir/recon_buildblock/BackProjectorByBin.h b/src/include/stir/recon_buildblock/BackProjectorByBin.h index 848806fee1..b9b5f6e99f 100644 --- a/src/include/stir/recon_buildblock/BackProjectorByBin.h +++ b/src/include/stir/recon_buildblock/BackProjectorByBin.h @@ -36,116 +36,110 @@ #include "stir/RegisteredObject.h" #include "stir/TimedObject.h" #include "stir/shared_ptr.h" +#include "stir/Bin.h" +#include "stir/recon_buildblock/ProjMatrixElemsForOneBin.h" START_NAMESPACE_STIR -template class RelatedViewgrams; -template class DiscretisedDensity; +template +class RelatedViewgrams; +template +class DiscretisedDensity; class ProjDataInfo; class ProjData; class DataSymmetriesForViewSegmentNumbers; -template class DataProcessor; - +template +class DataProcessor; /*! \ingroup projection \brief Abstract base class for all back projectors */ -class BackProjectorByBin : - public TimedObject, - public RegisteredObject -{ +class BackProjectorByBin : public TimedObject, public RegisteredObject { public: - //! Default constructor calls reset_timers() BackProjectorByBin(); virtual ~BackProjectorByBin(); //! Stores all necessary geometric info - /*! - If necessary, set_up() can be called more than once. + /*! + If necessary, set_up() can be called more than once. - Derived classes can assume that back_project() will be called - with input corresponding to the arguments of the last call to set_up(). + Derived classes can assume that back_project() will be called + with input corresponding to the arguments of the last call to set_up(). - \warning there is currently no check on this. - \warning Derived classes have to call set_up from the base class. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_sptr // TODO should be Info only - ) =0; + \warning there is currently no check on this. + \warning Derived classes have to call set_up from the base class. + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_sptr // TODO should be Info only + ) = 0; /*! \brief Informs on which symmetries the projector handles It should get data related by at least those symmetries. Otherwise, a run-time error will occur (unless the derived class has other behaviour). */ - virtual const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const = 0; + virtual const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const = 0; - //! project whole proj_data into the volume /*! it overwrites the data already present in the volume. - - The optional arguments can be used to back-project only a subset of the data. + + The optional arguments can be used to back-project only a subset of the data. Subsets are determined as per detail::find_basic_vs_nums_in_subset(). However, this usage will likely be phased out at later stage. */ - void back_project(DiscretisedDensity<3,float>&, - const ProjData&, int subset_num = 0, int num_subsets = 1); + void back_project(DiscretisedDensity<3, float>&, const ProjData&, int subset_num = 0, int num_subsets = 1); #ifdef STIR_PROJECTORS_AS_V3 /*! \brief projects the viewgrams into the volume it adds to the data already present in the volume.*/ - void back_project(DiscretisedDensity<3,float>&, - const RelatedViewgrams&); + void back_project(DiscretisedDensity<3, float>&, const RelatedViewgrams&); /*! \brief projects the specified range of the viewgrams into the volume it adds to the data already present in the volume.*/ - void back_project(DiscretisedDensity<3,float>&, - const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num); + void back_project(DiscretisedDensity<3, float>&, const RelatedViewgrams&, const int min_axial_pos_num, + const int max_axial_pos_num); /*! \brief projects the specified range of the viewgrams into the volume it adds to the data already present in the volume.*/ - void back_project(DiscretisedDensity<3,float>&, - const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + void back_project(DiscretisedDensity<3, float>&, const RelatedViewgrams&, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num); #endif - /*! \brief projects the viewgrams into the volume - it adds to the data backprojected since start_accumulating_in_new_target() was last called. */ - virtual void back_project(const ProjData&, int subset_num = 0, int num_subsets = 1); - - /*! \brief projects the viewgrams into the volume - it adds to the data backprojected since start_accumulating_in_new_target() was last called. */ -void back_project(const RelatedViewgrams&); + /*! \brief projects the viewgrams into the volume + it adds to the data backprojected since start_accumulating_in_new_target() was last called. */ + virtual void back_project(const ProjData&, int subset_num = 0, int num_subsets = 1); - /*! \brief projects the specified range of the viewgrams and axial positions into the volume - it adds to the data backprojected since start_accumulating_in_new_target() was last called. */ -void back_project(const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num); + /*! \brief projects the viewgrams into the volume + it adds to the data backprojected since start_accumulating_in_new_target() was last called. */ + void back_project(const RelatedViewgrams&); - /*! \brief projects the specified range of the viewgrams, axial positions and tangential positions into the volume + /*! \brief projects the specified range of the viewgrams and axial positions into the volume it adds to the data backprojected since start_accumulating_in_new_target() was last called. */ -void back_project(const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + void back_project(const RelatedViewgrams&, const int min_axial_pos_num, const int max_axial_pos_num); - /*! \brief tell the back projector to start accumulating into a new target. - This function has to be called before any back-projection is initiated.*/ - virtual void start_accumulating_in_new_target(); + /*! \brief projects the specified range of the viewgrams, axial positions and tangential positions into the volume + it adds to the data backprojected since start_accumulating_in_new_target() was last called. */ + void back_project(const RelatedViewgrams&, const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num); - /*! \brief Get output - This will overwrite the array-content of the argument with the result of all backprojections since calling `start_accumulating_in_new_target()`. Note that the argument has to have the same characteristics as what was used when calling `set_up()`. - */ - virtual void get_output(DiscretisedDensity<3,float> &) const; + /*! \brief tell the back projector to start accumulating into a new target. + This function has to be called before any back-projection is initiated.*/ + virtual void start_accumulating_in_new_target(); + + /*! \brief Get output + This will overwrite the array-content of the argument with the result of all backprojections since calling + `start_accumulating_in_new_target()`. Note that the argument has to have the same characteristics as what was used when calling + `set_up()`. + */ + virtual void get_output(DiscretisedDensity<3, float>&) const; /// Set data processor to use after back projection - void set_post_data_processor(shared_ptr > > post_data_processor_sptr); + void set_post_data_processor(shared_ptr>> post_data_processor_sptr); -protected: + virtual BackProjectorByBin* clone() const = 0; +protected: /*! \brief This actually does the back projection. There are two versions of this code to enable backwards compatibility. @@ -155,10 +149,9 @@ void back_project(const RelatedViewgrams&, If you are developing your own projector, one of these two needs to be overloaded. It doesn't matter which, but it might as well be the new one in case we one day decide to remove the old ones. */ - virtual void actual_back_project(DiscretisedDensity<3,float>&, - const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + virtual void actual_back_project(DiscretisedDensity<3, float>&, const RelatedViewgrams&, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num); /*! \brief This actually does the back projection. There are two versions of this code to enable backwards compatibility. @@ -169,41 +162,37 @@ void back_project(const RelatedViewgrams&, If you are developing your own projector, one of these two needs to be overloaded. It doesn't matter which, but it might as well be the new one in case we one day decide to remove the old ones. */ - virtual void actual_back_project(const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + virtual void actual_back_project(const RelatedViewgrams&, const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num); //! check if the argument is the same as what was used for set_up() /*! calls error() if anything is wrong. If overriding this function in a derived class, you need to call this one. */ - virtual void check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3,float>& density_info) const; + virtual void check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3, float>& density_info) const; bool _already_set_up; //! Clone of the density sptr set with set_up() - shared_ptr > _density_sptr; - shared_ptr > > _post_data_processor_sptr; + shared_ptr> _density_sptr; + shared_ptr>> _post_data_processor_sptr; virtual void set_defaults(); virtual void initialise_keymap(); - private: +private: shared_ptr _proj_data_info_sptr; - void do_segments(DiscretisedDensity<3,float>& image, - const ProjData& proj_data_org, - const int start_segment_num, const int end_segment_num, - const int start_axial_pos_num, const int end_axial_pos_num, - const int start_tang_pos_num,const int end_tang_pos_num, - const int start_view, const int end_view); + void do_segments(DiscretisedDensity<3, float>& image, const ProjData& proj_data_org, const int start_segment_num, + const int end_segment_num, const int start_axial_pos_num, const int end_axial_pos_num, + const int start_tang_pos_num, const int end_tang_pos_num, const int start_view, const int end_view, + const int start_timing_pos_num = 0, const int end_timing_pos_num = 0); #ifdef STIR_OPENMP //! A vector of back projected images that will be used with openMP. There will be as many images as openMP threads - std::vector< shared_ptr > > _local_output_image_sptrs; + std::vector>> _local_output_image_sptrs; #endif }; END_NAMESPACE_STIR - #endif // __BackProjectorByBin_h_ diff --git a/src/include/stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h b/src/include/stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h index f1d4534266..d30345d7bc 100644 --- a/src/include/stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h +++ b/src/include/stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h @@ -31,26 +31,30 @@ #ifndef __BackProjectorByBinUsingInterpolation_h_ #define __BackProjectorByBinUsingInterpolation_h_ -#include "stir/recon_buildblock/BackProjectorByBin.h" +#include "stir/recon_buildblock/BackProjectorByBin.h" #include "stir/RegisteredParsingObject.h" #include "stir/shared_ptr.h" START_NAMESPACE_STIR -template class Viewgram; -template class RelatedViewgrams; -template class VoxelsOnCartesianGrid; -template class Array; +template +class Viewgram; +template +class RelatedViewgrams; +template +class VoxelsOnCartesianGrid; +template +class Array; class ProjDataInfo; class ProjDataInfoCylindricalArcCorr; class DataSymmetriesForBins_PET_CartesianGrid; /*! \brief - The next class is used in BackProjectorByBinUsingInterpolation + The next class is used in BackProjectorByBinUsingInterpolation to take geometric things into account. It also includes some normalisation. (internal use only). - - \internal + + \internal Use as follows: \code @@ -59,9 +63,7 @@ class DataSymmetriesForBins_PET_CartesianGrid; \endcode */ - -class JacobianForIntBP -{ +class JacobianForIntBP { private: // store some scanner related data to avoid recomputation const float R2; @@ -77,19 +79,17 @@ class JacobianForIntBP const bool use_exact_Jacobian_now; public: - explicit JacobianForIntBP(const shared_ptr proj_data_info_sptr, bool exact); - - float operator()(const float delta, const float s) const - { - float tmp; - if (use_exact_Jacobian_now) - tmp = 4*(R2 - dxy2 * s*s); - else - tmp = 4*R2; - return tmp / pow(tmp + ring_spacing2*delta*delta, 1.5F)* backprojection_normalisation; - } -}; - + explicit JacobianForIntBP(const shared_ptr proj_data_info_sptr, bool exact); + + float operator()(const float delta, const float s) const { + float tmp; + if (use_exact_Jacobian_now) + tmp = 4 * (R2 - dxy2 * s * s); + else + tmp = 4 * R2; + return tmp / pow(tmp + ring_spacing2 * delta * delta, 1.5F) * backprojection_normalisation; + } +}; /*! \ingroup projection @@ -103,13 +103,13 @@ class JacobianForIntBP
  • piecewise linear interpolation in the axial direction
The former is an implementation of - "Incremental beamwise backprojection using geometrical symmetries for 3D PET reconstruction + "Incremental beamwise backprojection using geometrical symmetries for 3D PET reconstruction in a cylindrical scanner geometry" - M L Egger, C Joseph, C Morel, Phys. Med. Biol. (1998) 43 3009-3024 + M L Egger, C Joseph, C Morel, Phys. Med. Biol. (1998) 43 3009-3024 http://dx.doi.org/10.1088/0031-9155/43/10/023 - For the latter, see the extended abstract for 3D99 - "On various approximations for the projectors in iterative reconstruction algorithms for + For the latter, see the extended abstract for 3D99 + "On various approximations for the projectors in iterative reconstruction algorithms for 3D-PET", K. Thielemans, M.W. Jacobson, D. Belluzzo. Available on the STIR web-site. The piecewise linear interpolation is only used when the axial voxel size is half the @@ -118,7 +118,7 @@ class JacobianForIntBP \warning This implementation makes various assumptions (for optimal speed):
  • voxel_size.x() = voxel_size.y() -
  • arc-corrected data +
  • arc-corrected data
  • voxel_size.z() is either equal to or half the axial_sampling of the projection data
When the bin size is not equal to the voxel_size.x(), zoom_viewgrams() is first called to @@ -129,63 +129,59 @@ class JacobianForIntBP correct results, SunSparc has a problem at tangential_pos_num==0 (also HP stations give problems). */ -class BackProjectorByBinUsingInterpolation : - public RegisteredParsingObject +class BackProjectorByBinUsingInterpolation + : public RegisteredParsingObject -{ +{ public: //! Name which will be used when parsing a BackProjectorByBin object - static const char * const registered_name; + static const char* const registered_name; - //! The constructor defaults to using piecewise linear interpolation and the exact Jacobian - explicit - BackProjectorByBinUsingInterpolation( - const bool use_piecewise_linear_interpolation = true, - const bool use_exact_Jacobian = true); + //! The constructor defaults to using piecewise linear interpolation and the exact Jacobian + explicit BackProjectorByBinUsingInterpolation(const bool use_piecewise_linear_interpolation = true, + const bool use_exact_Jacobian = true); - //! The constructor defaults to using piecewise linear interpolation and the exact Jacobian + //! The constructor defaults to using piecewise linear interpolation and the exact Jacobian /*! \deprecated Use set_up() instead */ - BackProjectorByBinUsingInterpolation( - shared_ptrconst&, - shared_ptr > const& image_info_ptr, - const bool use_piecewise_linear_interpolation = true, const bool use_exact_Jacobian = true); + BackProjectorByBinUsingInterpolation(shared_ptr const&, + shared_ptr> const& image_info_ptr, + const bool use_piecewise_linear_interpolation = true, + const bool use_exact_Jacobian = true); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); /*! \brief Gets the symmetries used by this backprojector - \warning This BackProjectorByBin implementation requires that the + \warning This BackProjectorByBin implementation requires that the RelatedViewgrams data are constructed with symmetries corresponding - to the current member. Using another DataSymmetriesForViewSegmentNumbers + to the current member. Using another DataSymmetriesForViewSegmentNumbers object will likely crash the program. */ - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const; - /*! - \brief Use this to switch between the exact Jacobian and + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const; + /*! + \brief Use this to switch between the exact Jacobian and an approximate Jacobian (valid for s << R). */ void use_exact_Jacobian(const bool use_exact_Jacobian); - /*! \brief Use this to switch between ordinary linear interpolation and piece-wise linear interpolation in the axial direction. */ void use_piecewise_linear_interpolation(const bool use_piecewise_linear_interpolation); + BackProjectorByBinUsingInterpolation* clone() const; + private: - // KT 20/06/2001 changed type to enable use of more methods shared_ptr symmetries_ptr; - //const DataSymmetriesForViewSegmentNumbers * symmetries_ptr; - + // const DataSymmetriesForViewSegmentNumbers * symmetries_ptr; + bool use_piecewise_linear_interpolation_now; bool use_exact_Jacobian_now; @@ -223,41 +219,32 @@ struct ProjDataForIntBP }; #endif - void actual_back_project(DiscretisedDensity<3,float>&, - const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); - - - virtual void - back_project_all_symmetries( VoxelsOnCartesianGrid& image, - const Viewgram & pos_view, - const Viewgram & neg_view, - const Viewgram & pos_plus90, - const Viewgram & neg_plus90, - const Viewgram & pos_min180, - const Viewgram & neg_min180, - const Viewgram & pos_min90, - const Viewgram & neg_min90, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + void actual_back_project(DiscretisedDensity<3, float>&, const RelatedViewgrams&, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num); + + void actual_back_project(DiscretisedDensity<3, float>&, const Bin&); + + virtual void back_project_all_symmetries(VoxelsOnCartesianGrid& image, const Viewgram& pos_view, + const Viewgram& neg_view, const Viewgram& pos_plus90, + const Viewgram& neg_plus90, const Viewgram& pos_min180, + const Viewgram& neg_min180, const Viewgram& pos_min90, + const Viewgram& neg_min90, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num); /* This function projects 4 viewgrams related by symmetry. - It will be used for view=0 or 45 degrees - (or all others if the above version is not implemented in + It will be used for view=0 or 45 degrees + (or all others if the above version is not implemented in the derived class) Here 0<=view < num_views/2 (= 90 degrees) */ - virtual void - back_project_view_plus_90_and_delta(VoxelsOnCartesianGrid& image, - const Viewgram & pos_view, - const Viewgram & neg_view, - const Viewgram & pos_plus90, - const Viewgram & neg_plus90, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + virtual void back_project_view_plus_90_and_delta(VoxelsOnCartesianGrid& image, const Viewgram& pos_view, + const Viewgram& neg_view, const Viewgram& pos_plus90, + const Viewgram& neg_plus90, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num); /* void back_project_2D_view_plus_90(const PETSinogram &sino, PETPlane &image, int view, const int min_bin_num, const intmax_tangential_pos_num); @@ -265,47 +252,34 @@ struct ProjDataForIntBP const int min_bin_num, const intmax_tangential_pos_num); */ + /* -/* + These functions use a 3D version of Cho's algorithm for backprojecting incrementally. + See M. Egger's thesis for details. + In addition to the symmetries mentioned above, they also use s,-s symmetry + (while being careful when s=0 to avoid self-symmetric cases) + */ - These functions use a 3D version of Cho's algorithm for backprojecting incrementally. - See M. Egger's thesis for details. - In addition to the symmetries mentioned above, they also use s,-s symmetry - (while being careful when s=0 to avoid self-symmetric cases) - */ + static void piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90( + Array<4, float> const& Projptr, VoxelsOnCartesianGrid& image, + const shared_ptr proj_data_info_sptr, float delta, const double cphi, + const double sphi, int s, int ax_pos0, const int num_planes_per_axial_pos, const float axial_pos_to_z_offset); + + static void piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview( + Array<4, float> const& Projptr, VoxelsOnCartesianGrid& image, + const shared_ptr proj_data_info_sptr, float delta, const double cphi, + const double sphi, int s, int ax_pos0, const int num_planes_per_axial_pos, const float axial_pos_to_z_offset); + static void + linear_interpolation_backproj3D_Cho_view_viewplus90(Array<4, float> const& Projptr, VoxelsOnCartesianGrid& image, + const shared_ptr proj_data_info_sptr, + float delta, const double cphi, const double sphi, int s, int ax_pos0, + const int num_planes_per_axial_pos, const float axial_pos_to_z_offset); - static void piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90(Array<4, float > const & Projptr, - VoxelsOnCartesianGrid& image, - const shared_ptr proj_data_info_sptr, - float delta, - const double cphi, const double sphi, int s, int ax_pos0, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset); - - static void piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview(Array<4, float > const &Projptr, - VoxelsOnCartesianGrid& image, - const shared_ptr proj_data_info_sptr, - float delta, - const double cphi, const double sphi, int s, int ax_pos0, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset); - - static void linear_interpolation_backproj3D_Cho_view_viewplus90(Array<4, float > const & Projptr, - VoxelsOnCartesianGrid& image, - const shared_ptr proj_data_info_sptr, - float delta, - const double cphi, const double sphi, int s, int ax_pos0, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset); - - static void linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview(Array<4, float > const &Projptr, - VoxelsOnCartesianGrid& image, - const shared_ptr proj_data_info_sptr, - float delta, - const double cphi, const double sphi, int s, int ax_pos0, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset); + static void linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview( + Array<4, float> const& Projptr, VoxelsOnCartesianGrid& image, + const shared_ptr proj_data_info_sptr, float delta, const double cphi, + const double sphi, int s, int ax_pos0, const int num_planes_per_axial_pos, const float axial_pos_to_z_offset); /* static void backproj2D_Cho_view_viewplus90( PETPlane & image, @@ -319,11 +293,8 @@ static void backproj2D_Cho_view_viewplus90( PETPlane & image, */ virtual void set_defaults(); virtual void initialise_keymap(); - }; END_NAMESPACE_STIR - #endif // __BackProjectorByBinUsingInterpolation_h_ - diff --git a/src/include/stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h b/src/include/stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h index 88b5abeb9e..0e9bbead99 100644 --- a/src/include/stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h +++ b/src/include/stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h @@ -1,7 +1,6 @@ // // - #ifndef _BackProjectorByBinUsingProjMatrixByBin_ #define _BackProjectorByBinUsingProjMatrixByBin_ @@ -43,69 +42,61 @@ //#include "stir/RelatedViewgrams.h" class Viewgrams; -template class RelatedViewgrams; +template +class RelatedViewgrams; class ProjDataInfoCylindricalArcCorr; - START_NAMESPACE_STIR /*! - \brief This implements the BackProjectorByBin interface, given any + \brief This implements the BackProjectorByBin interface, given any ProjMatrixByBin object - + */ -class BackProjectorByBinUsingProjMatrixByBin: - public RegisteredParsingObject -{ +class BackProjectorByBinUsingProjMatrixByBin + : public RegisteredParsingObject { public: - //! Name which will be used when parsing a BackProjectorByBin object - static const char * const registered_name; + //! Name which will be used when parsing a BackProjectorByBin object + static const char* const registered_name; BackProjectorByBinUsingProjMatrixByBin(); - BackProjectorByBinUsingProjMatrixByBin ( - const shared_ptr& proj_matrix_ptr); + BackProjectorByBinUsingProjMatrixByBin(const shared_ptr& proj_matrix_ptr); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); - - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const; + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const; - virtual void actual_back_project(DiscretisedDensity<3,float>& image, - const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + virtual void actual_back_project(DiscretisedDensity<3, float>& image, const RelatedViewgrams&, + const int min_axial_pos_num, const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num); + shared_ptr& get_proj_matrix_sptr() { return proj_matrix_ptr; } - shared_ptr & - get_proj_matrix_sptr(){ return proj_matrix_ptr ;} - - -protected: + void enable_tof(ProjMatrixElemsForOneBin*); + + BackProjectorByBinUsingProjMatrixByBin* clone() const; +protected: shared_ptr proj_matrix_ptr; + void actual_back_project(DiscretisedDensity<3, float>& image, const Bin& bin); + private: virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); + ProjMatrixElemsForOneBin* tof_row; }; - - - END_NAMESPACE_STIR //#include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.inl" #endif - - diff --git a/src/include/stir/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.h b/src/include/stir/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.h index 413f59e21c..e58cb9170c 100644 --- a/src/include/stir/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.h +++ b/src/include/stir/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.h @@ -2,7 +2,6 @@ // $Id: BackProjectorByBinUsingSquareProjMatrixByBin.h // - #ifndef _BackProjectorByBinUsingSquareProjMatrixByBin_ #define _BackProjectorByBinUsingSquareProjMatrixByBin_ @@ -10,15 +9,15 @@ \file - \brief + \brief \author Mustapha Sadki \author Kris Thielemans \author PARAPET project - $Date: + $Date: - $Revision: + $Revision: */ /* Copyright (C) 2000 PARAPET partners @@ -34,63 +33,50 @@ //#include "stir/RelatedViewgrams.h" class Viewgrams; -template class RelatedViewgrams; +template +class RelatedViewgrams; class ProjDataInfoCylindricalArcCorr; - START_NAMESPACE_STIR /*! - \brief This implements the BackProjectorByBin interface, given any + \brief This implements the BackProjectorByBin interface, given any ProjMatrixByBin object - + */ -class BackProjectorByBinUsingSquareProjMatrixByBin: - public RegisteredParsingObject -{ -public: - static const char * const registered_name; +class BackProjectorByBinUsingSquareProjMatrixByBin + : public RegisteredParsingObject { +public: + static const char* const registered_name; BackProjectorByBinUsingSquareProjMatrixByBin(); - BackProjectorByBinUsingSquareProjMatrixByBin ( - const shared_ptr& proj_matrix_ptr); - - - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const; + BackProjectorByBinUsingSquareProjMatrixByBin(const shared_ptr& proj_matrix_ptr); - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const; + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); - virtual void actual_back_project(DiscretisedDensity<3,float>& image, - const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + virtual void actual_back_project(DiscretisedDensity<3, float>& image, const RelatedViewgrams&, + const int min_axial_pos_num, const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num); + shared_ptr& get_proj_matrix_sptr() { return proj_matrix_ptr; } - shared_ptr & - get_proj_matrix_sptr(){ return proj_matrix_ptr ;} - - protected: - +protected: shared_ptr proj_matrix_ptr; + void actual_back_project(DiscretisedDensity<3, float>& image, const Bin& bin); + private: virtual void set_defaults(); virtual void initialise_keymap(); }; - - - END_NAMESPACE_STIR //#include "stir/BackProjectorByBinUsingSquareProjMatrixByBin.inl" #endif - - diff --git a/src/include/stir/recon_buildblock/BinNormalisation.h b/src/include/stir/recon_buildblock/BinNormalisation.h index 2fdafeb02f..48a1a3ef30 100644 --- a/src/include/stir/recon_buildblock/BinNormalisation.h +++ b/src/include/stir/recon_buildblock/BinNormalisation.h @@ -29,14 +29,14 @@ #ifndef __stir_recon_buildblock_BinNormalisation_H__ #define __stir_recon_buildblock_BinNormalisation_H__ - #include "stir/RegisteredObject.h" #include "stir/Bin.h" #include "stir/shared_ptr.h" START_NAMESPACE_STIR -template class RelatedViewgrams; +template +class RelatedViewgrams; class Succeeded; class ProjDataInfo; class ProjData; @@ -46,105 +46,104 @@ class ExamInfo; \ingroup normalisation \brief Abstract base class for implementing bin-wise normalisation of data. - As part of the measurement model in PET, there usually is some multiplicative - correction for every bin, as in + As part of the measurement model in PET, there usually is some multiplicative + correction for every bin, as in \f[ P^\mathrm{full}_{bv} = \mathrm{norm}_b P^\mathrm{normalised}_{bv} \f] - This multiplicative correction is usually split in the \c normalisation - factors (which are scanner dependent) and the \c attenuation factors (which - are object dependent). + This multiplicative correction is usually split in the \c normalisation + factors (which are scanner dependent) and the \c attenuation factors (which + are object dependent). The present class can be used for both of these factors. */ -class BinNormalisation : public RegisteredObject -{ +class BinNormalisation : public RegisteredObject { public: - BinNormalisation(); virtual ~BinNormalisation(); - virtual float get_calibration_factor() const {return -1;} + virtual float get_calibration_factor() const { return -1; } //! check if we would be multiplying with 1 (i.e. do nothing) /*! This function can be used to check if the operations are guaranteed to do nothing (while potentially taking time and effort). The base-class sets this to always return false. It is up to the derived class to change this. */ - virtual inline bool is_trivial() const { return false;} + virtual inline bool is_trivial() const { return false; } //! initialises the object and checks if it can handle such projection data /*! Default version does nothing. */ - virtual Succeeded set_up(const shared_ptr& exam_info_sptr,const shared_ptr&); + virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&); //! Return the 'efficiency' factor for a single bin /*! With the notation of the class documentation, this returns the factor - \f$\mathrm{norm}_b \f$. + \f$\mathrm{norm}_b \f$. \warning Some derived classes might implement this very inefficiently. */ - virtual float get_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const =0; + virtual float get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const = 0; //! normalise some data - /*! + /*! This would be used for instance to precorrect unnormalised data. With the - notation of the class documentation, this would \c divide by the factors + notation of the class documentation, this would \c divide by the factors \f$\mathrm{norm}_b \f$. Default implementation divides with the factors returned by get_bin_efficiency() (after applying a threshold to avoid division by 0). */ - virtual void apply(RelatedViewgrams&,const double start_time, const double end_time) const; + virtual void apply(RelatedViewgrams&, const double start_time, const double end_time) const; //! undo the normalisation of some data - /*! - This would be used for instance to bring geometrically forward projected data to + /*! + This would be used for instance to bring geometrically forward projected data to the mean of the measured data. With the - notation of the class documentation, this would \c multiply by the factors + notation of the class documentation, this would \c multiply by the factors \f$\mathrm{norm}_b \f$. Default implementation multiplies with the factors returned by get_bin_efficiency(). */ - virtual void undo(RelatedViewgrams&,const double start_time, const double end_time) const; + virtual void undo(RelatedViewgrams&, const double start_time, const double end_time) const; //! normalise some data - /*! + /*! This would be used for instance to precorrect unnormalised data. With the - notation of the class documentation, this would \c divide by the factors + notation of the class documentation, this would \c divide by the factors \f$\mathrm{norm}_b \f$. - This just loops over all RelatedViewgrams. + This just loops over all RelatedViewgrams. The default value for the symmetries means that TrivialDataSymmetriesForBins will be used. */ - void apply(ProjData&, + void apply(ProjData&, shared_ptr = shared_ptr()) const; //! undo the normalisation of some data - /*! - This would be used for instance to bring geometrically forward projected data to + /*! + This would be used for instance to bring geometrically forward projected data to the mean of the measured data. With the - notation of the class documentation, this would \c multiply by the factors + notation of the class documentation, this would \c multiply by the factors \f$\mathrm{norm}_b \f$. - This just loops over all RelatedViewgrams. + This just loops over all RelatedViewgrams. The default value for the symmetries means that TrivialDataSymmetriesForBins will be used. */ - void undo(ProjData&,const double start_time, const double end_time, - shared_ptr = shared_ptr()) const; - + void undo(ProjData&, const double start_time, const double end_time, + shared_ptr = shared_ptr()) const; + void set_exam_info_sptr(const shared_ptr _exam_info_sptr); - shared_ptr get_exam_info_sptr() const ; + shared_ptr get_exam_info_sptr() const; - protected: +protected: //! check if the argument is the same as what was used for set_up() /*! calls error() if anything is wrong. If overriding this function in a derived class, you need to call this one. */ virtual void check(const ProjDataInfo& proj_data_info) const; - + virtual void check(const ExamInfo& exam_info) const; bool _already_set_up; + private: shared_ptr exam_info_sptr; shared_ptr _proj_data_info_sptr; diff --git a/src/include/stir/recon_buildblock/BinNormalisationFromAttenuationImage.h b/src/include/stir/recon_buildblock/BinNormalisationFromAttenuationImage.h index e5c64690dd..3884a4b0f9 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationFromAttenuationImage.h +++ b/src/include/stir/recon_buildblock/BinNormalisationFromAttenuationImage.h @@ -43,14 +43,14 @@ START_NAMESPACE_STIR an attenuation image This forwards projects the attenuation image, multiplies with -1, and exponentiates - to obtain the attenuation correction factors. + to obtain the attenuation correction factors. Default forward projector is ForwardProjectorByBinUsingRayTracing. - \warning Attenuation image data are supposed to be in units cm^-1. + \warning Attenuation image data are supposed to be in units cm^-1. (Reference: water has mu .096 cm^-1.) \todo Add mechanism for caching the attenuation correction factors, such that they will - be calculated only once. However, caching should by default be disabled, as most + be calculated only once. However, caching should by default be disabled, as most applications need them only once anyway. \par Parsing details @@ -61,16 +61,15 @@ START_NAMESPACE_STIR End Bin Normalisation From Attenuation Image := \endverbatim */ -class BinNormalisationFromAttenuationImage : - public RegisteredParsingObject -{ +class BinNormalisationFromAttenuationImage + : public RegisteredParsingObject { public: //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor - /*! - \warning You should not call any member functions for any object just + /*! + \warning You should not call any member functions for any object just constructed with this constructor. Initialise the object properly first by parsing. */ @@ -78,39 +77,40 @@ class BinNormalisationFromAttenuationImage : //! Constructor that reads the image from a file /*! Default forward projector is ForwardProjectorByBinUsingRayTracing. */ - BinNormalisationFromAttenuationImage(const std::string& filename, shared_ptr const& =shared_ptr()); + BinNormalisationFromAttenuationImage(const std::string& filename, + shared_ptr const& = shared_ptr()); //! Constructor that takes the image as an argument /*! Default forward projector is ForwardProjectorByBinUsingRayTracing. The image pointed to by attenuation_image_ptr is NOT modified. */ - BinNormalisationFromAttenuationImage(const shared_ptr >& attenuation_image_ptr, + BinNormalisationFromAttenuationImage(const shared_ptr>& attenuation_image_ptr, shared_ptr const& = shared_ptr()); //! Checks if we can handle certain projection data. - /*! This test is essentially checking if the forward projector can handle the data + /*! This test is essentially checking if the forward projector can handle the data by calling ForwardProjectorByBin::set_up(). */ - virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr& ); + virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&); //! Normalise some data - /*! - This means \c multiply with the data in the projdata object - passed in the constructor. + /*! + This means \c multiply with the data in the projdata object + passed in the constructor. */ - virtual void apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; //! Undo the normalisation of some data - /*! - This means \c divide with the data in the projdata object - passed in the constructor. + /*! + This means \c divide with the data in the projdata object + passed in the constructor. */ - virtual void undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; - virtual float get_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const; + virtual float get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const; private: - shared_ptr > attenuation_image_ptr; + shared_ptr> attenuation_image_ptr; shared_ptr forward_projector_ptr; // parsing stuff @@ -121,7 +121,6 @@ class BinNormalisationFromAttenuationImage : std::string attenuation_image_filename; }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir/recon_buildblock/BinNormalisationFromECAT7.h b/src/include/stir/recon_buildblock/BinNormalisationFromECAT7.h index fb3e1285a7..ca39facca7 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationFromECAT7.h +++ b/src/include/stir/recon_buildblock/BinNormalisationFromECAT7.h @@ -41,7 +41,7 @@ #include #ifndef HAVE_LLN_MATRIX -#error This file can only be compiled when HAVE_LLN_MATRIX is #defined +# error This file can only be compiled when HAVE_LLN_MATRIX is #defined #endif START_NAMESPACE_STIR @@ -75,18 +75,17 @@ START_NAMESPACE_ECAT7 ; use_crystal_interference_factors:=1 End Bin Normalisation From ECAT7:= \endverbatim - + */ -class BinNormalisationFromECAT7 : - public RegisteredParsingObject -{ +class BinNormalisationFromECAT7 + : public RegisteredParsingObject { public: //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor - /*! - \warning You should not call any member functions for any object just + /*! + \warning You should not call any member functions for any object just constructed with this constructor. Initialise the object properly first by parsing. */ @@ -95,7 +94,7 @@ class BinNormalisationFromECAT7 : //! Constructor that reads the projdata from a file BinNormalisationFromECAT7(const std::string& filename); - virtual Succeeded set_up(const shared_ptr &exam_info_sptr,const shared_ptr&); + virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&); float get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const; bool use_detector_efficiencies() const; @@ -104,19 +103,19 @@ class BinNormalisationFromECAT7 : bool use_crystal_interference_factors() const; private: - Array<1,float> axial_t1_array; - Array<1,float> axial_t2_array; - Array<1,float> trans_t1_array; + Array<1, float> axial_t1_array; + Array<1, float> axial_t2_array; + Array<1, float> trans_t1_array; shared_ptr singles_rates_ptr; - Array<2,float> geometric_factors; - Array<2,float> efficiency_factors; - Array<2,float> crystal_interference_factors; + Array<2, float> geometric_factors; + Array<2, float> efficiency_factors; + Array<2, float> crystal_interference_factors; shared_ptr scanner_ptr; int num_transaxial_crystals_per_block; // TODO move to Scanner int num_axial_blocks_per_singles_unit; shared_ptr proj_data_info_ptr; - ProjDataInfoCylindricalNoArcCorr const * proj_data_info_cyl_ptr; + ProjDataInfoCylindricalNoArcCorr const* proj_data_info_cyl_ptr; shared_ptr proj_data_info_cyl_uncompressed_ptr; int span; int mash; @@ -128,8 +127,7 @@ class BinNormalisationFromECAT7 : bool _use_crystal_interference_factors; void read_norm_data(const std::string& filename); - float get_dead_time_efficiency ( const DetectionPosition<>& det_pos, - const double start_time, const double end_time) const; + float get_dead_time_efficiency(const DetectionPosition<>& det_pos, const double start_time, const double end_time) const; // parsing stuff virtual void set_defaults(); diff --git a/src/include/stir/recon_buildblock/BinNormalisationFromECAT8.h b/src/include/stir/recon_buildblock/BinNormalisationFromECAT8.h index 8b60d71746..c26fe05ceb 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationFromECAT8.h +++ b/src/include/stir/recon_buildblock/BinNormalisationFromECAT8.h @@ -2,7 +2,7 @@ Copyright (C) 2000-2007, Hammersmith Imanet Ltd Copyright (C) 2013-2014 University College London - Largely a copy of the ECAT7 version. + Largely a copy of the ECAT7 version. This file is free software; you can redistribute that part and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,6 @@ \author Kris Thielemans */ - #ifndef __stir_recon_buildblock_BinNormalisationFromECAT8_H__ #define __stir_recon_buildblock_BinNormalisationFromECAT8_H__ @@ -73,18 +72,17 @@ START_NAMESPACE_ECAT \todo dead-time is not yet implemented - + */ -class BinNormalisationFromECAT8 : - public RegisteredParsingObject -{ +class BinNormalisationFromECAT8 + : public RegisteredParsingObject { public: //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor - /*! - \warning You should not call any member functions for any object just + /*! + \warning You should not call any member functions for any object just constructed with this constructor. Initialise the object properly first by parsing. */ @@ -93,7 +91,7 @@ class BinNormalisationFromECAT8 : //! Constructor that reads the projdata from a file BinNormalisationFromECAT8(const string& filename); - virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr& ); + virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&); float get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const; bool use_detector_efficiencies() const; @@ -102,19 +100,19 @@ class BinNormalisationFromECAT8 : bool use_crystal_interference_factors() const; private: - Array<1,float> axial_t1_array; - Array<1,float> axial_t2_array; - Array<1,float> trans_t1_array; + Array<1, float> axial_t1_array; + Array<1, float> axial_t2_array; + Array<1, float> trans_t1_array; shared_ptr singles_rates_ptr; - Array<2,float> geometric_factors; - Array<2,float> efficiency_factors; - Array<2,float> crystal_interference_factors; + Array<2, float> geometric_factors; + Array<2, float> efficiency_factors; + Array<2, float> crystal_interference_factors; shared_ptr scanner_ptr; int num_transaxial_crystals_per_block; // TODO move to Scanner int num_axial_blocks_per_singles_unit; shared_ptr proj_data_info_ptr; - ProjDataInfoCylindricalNoArcCorr const * proj_data_info_cyl_ptr; + ProjDataInfoCylindricalNoArcCorr const* proj_data_info_cyl_ptr; shared_ptr proj_data_info_cyl_uncompressed_ptr; int span; int mash; @@ -128,8 +126,7 @@ class BinNormalisationFromECAT8 : bool _use_crystal_interference_factors; void read_norm_data(const string& filename); - float get_dead_time_efficiency ( const DetectionPosition<>& det_pos, - const double start_time, const double end_time) const; + float get_dead_time_efficiency(const DetectionPosition<>& det_pos, const double start_time, const double end_time) const; // parsing stuff virtual void set_defaults(); diff --git a/src/include/stir/recon_buildblock/BinNormalisationFromGEHDF5.h b/src/include/stir/recon_buildblock/BinNormalisationFromGEHDF5.h index 94d4fe0554..2c1352bc85 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationFromGEHDF5.h +++ b/src/include/stir/recon_buildblock/BinNormalisationFromGEHDF5.h @@ -3,7 +3,7 @@ Copyright (C) 2013-2014, 2020 University College London Copyright (C) 2017-2019 University of Leeds - Largely a copy of the ECAT7 version. + Largely a copy of the ECAT7 version. This file is free software; you can redistribute that part and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -27,7 +27,6 @@ \author Palak Wadhwa */ - #ifndef __stir_recon_buildblock_BinNormalisationFromGEHDF5_H__ #define __stir_recon_buildblock_BinNormalisationFromGEHDF5_H__ @@ -77,18 +76,17 @@ namespace RDF_HDF5 { \todo dead-time is not yet implemented - + */ -class BinNormalisationFromGEHDF5 : - public RegisteredParsingObject -{ +class BinNormalisationFromGEHDF5 + : public RegisteredParsingObject { public: //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor - /*! - \warning You should not call any member functions for any object just + /*! + \warning You should not call any member functions for any object just constructed with this constructor. Initialise the object properly first by parsing. */ @@ -97,7 +95,7 @@ class BinNormalisationFromGEHDF5 : //! Constructor that reads the projdata from a file BinNormalisationFromGEHDF5(const string& filename); - virtual Succeeded set_up(const shared_ptr &exam_info_sptr, const shared_ptr&); + virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&); float get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const; bool use_detector_efficiencies() const; @@ -106,18 +104,18 @@ class BinNormalisationFromGEHDF5 : bool use_crystal_interference_factors() const; private: - Array<1,float> axial_t1_array; - Array<1,float> axial_t2_array; - Array<1,float> trans_t1_array; + Array<1, float> axial_t1_array; + Array<1, float> axial_t2_array; + Array<1, float> trans_t1_array; shared_ptr singles_rates_ptr; - Array<2,float> efficiency_factors; - shared_ptr geo_eff_factors_sptr; + Array<2, float> efficiency_factors; + shared_ptr geo_eff_factors_sptr; shared_ptr scanner_ptr; int num_transaxial_crystals_per_block; // TODO move to Scanner int num_axial_blocks_per_singles_unit; shared_ptr proj_data_info_ptr; - ProjDataInfoCylindricalNoArcCorr const * proj_data_info_cyl_ptr; + ProjDataInfoCylindricalNoArcCorr const* proj_data_info_cyl_ptr; shared_ptr proj_data_info_cyl_uncompressed_ptr; int span; int mash; @@ -128,11 +126,11 @@ class BinNormalisationFromGEHDF5 : bool _use_geometric_factors; void read_norm_data(const string& filename); - float get_dead_time_efficiency ( const DetectionPositionPair<>& detection_position_pair, - const double start_time, const double end_time) const; + float get_dead_time_efficiency(const DetectionPositionPair<>& detection_position_pair, const double start_time, + const double end_time) const; - float get_geometric_efficiency_factors (const DetectionPositionPair<>& detection_position_pair) const; - float get_efficiency_factors (const DetectionPositionPair<>& detection_position_pair) const; + float get_geometric_efficiency_factors(const DetectionPositionPair<>& detection_position_pair) const; + float get_efficiency_factors(const DetectionPositionPair<>& detection_position_pair) const; // parsing stuff virtual void set_defaults(); virtual void initialise_keymap(); @@ -143,8 +141,8 @@ class BinNormalisationFromGEHDF5 : GEHDF5Wrapper h5data; }; -} // namespace -} +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR #endif diff --git a/src/include/stir/recon_buildblock/BinNormalisationFromProjData.h b/src/include/stir/recon_buildblock/BinNormalisationFromProjData.h index 8092f573d0..be661228f6 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationFromProjData.h +++ b/src/include/stir/recon_buildblock/BinNormalisationFromProjData.h @@ -41,7 +41,7 @@ START_NAMESPACE_STIR \brief A BinNormalisation class that gets the normalisation factors from a ProjData object - \warning the ProjData object containing the normalisation factors should + \warning the ProjData object containing the normalisation factors should currently have exactly the same dimensions as the data it is applied on. \par Parsing details @@ -51,16 +51,14 @@ START_NAMESPACE_STIR End Bin Normalisation From ProjData:= \endverbatim */ -class BinNormalisationFromProjData : - public RegisteredParsingObject -{ +class BinNormalisationFromProjData : public RegisteredParsingObject { public: //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor - /*! - \warning You should not call any member functions for any object just + /*! + \warning You should not call any member functions for any object just constructed with this constructor. Initialise the object properly first by parsing. */ @@ -80,28 +78,28 @@ class BinNormalisationFromProjData : virtual bool is_trivial() const; //! Checks if we can handle certain projection data. - /*! Compares the ProjDataInfo from the ProjData object containing the normalisation factors + /*! Compares the ProjDataInfo from the ProjData object containing the normalisation factors with the ProjDataInfo supplied. */ - virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr& ); + virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&); //! Normalise some data - /*! - This means \c multiply with the data in the projdata object - passed in the constructor. + /*! + This means \c multiply with the data in the projdata object + passed in the constructor. */ - virtual void apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; //! Undo the normalisation of some data - /*! - This means \c divide with the data in the projdata object - passed in the constructor. + /*! + This means \c divide with the data in the projdata object + passed in the constructor. */ - virtual void undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; - virtual float get_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const; - //! Get a shared_ptr to the normalisation proj_data. + virtual float get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const; + //! Get a shared_ptr to the normalisation proj_data. virtual shared_ptr get_norm_proj_data_sptr() const; - + private: shared_ptr norm_proj_data_ptr; virtual void set_defaults(); @@ -111,7 +109,6 @@ class BinNormalisationFromProjData : std::string normalisation_projdata_filename; }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir/recon_buildblock/BinNormalisationSPECT.h b/src/include/stir/recon_buildblock/BinNormalisationSPECT.h index 2b20911230..fe543cb431 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationSPECT.h +++ b/src/include/stir/recon_buildblock/BinNormalisationSPECT.h @@ -29,53 +29,43 @@ START_NAMESPACE_STIR -class BinNormalisationSPECT : - public RegisteredParsingObject -{ +class BinNormalisationSPECT + : public RegisteredParsingObject { public: - - //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; + static const char* const registered_name; BinNormalisationSPECT(); BinNormalisationSPECT(const std::string& filename); void read_norm_data(const std::string& filename); - virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr& ); - void set_num_views(int num_views) const { this->num_views=num_views;} - - void set_uniformity(Array<3,float>& uniformity){ - this->down_sampled_uniformity=uniformity; - } + virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&); + void set_num_views(int num_views) const { this->num_views = num_views; } + void set_uniformity(Array<3, float>& uniformity) { this->down_sampled_uniformity = uniformity; } - bool use_dead_time() const; - bool use_detector_efficiencies() const; - double get_half_life() const; - bool use_uniformity_factors() const; - bool use_decay_correction_factors() const; - bool use_COR_factors() const; + bool use_dead_time() const; + bool use_detector_efficiencies() const; + double get_half_life() const; + bool use_uniformity_factors() const; + bool use_decay_correction_factors() const; + bool use_COR_factors() const; - float get_dead_time_efficiency (const DetectionPosition<>& det_pos, - const double start_time, - const double end_time) const; + float get_dead_time_efficiency(const DetectionPosition<>& det_pos, const double start_time, const double end_time) const; - virtual void apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; - virtual void undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; - virtual float get_uncalibrated_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const; + virtual float get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const; - void read_linearity_table(Array<3,float>& linearity) const; - void read_uniformity_table(Array<3,float>& uniformity) const; - void read_cor_table(Array<3,float>& cor) const; + void read_linearity_table(Array<3, float>& linearity) const; + void read_uniformity_table(Array<3, float>& uniformity) const; + void read_cor_table(Array<3, float>& cor) const; - void resample_uniformity(//Array<3,float>& down_sampled_uniformity, - Array<3,float> uniformity, - const int max_ax, - int zoom) const; + void resample_uniformity( // Array<3,float>& down_sampled_uniformity, + Array<3, float> uniformity, const int max_ax, int zoom) const; protected: // parsing stuff @@ -85,11 +75,11 @@ class BinNormalisationSPECT : int max_tang; shared_ptr norm_proj_data_info_ptr; - mutable Array<1,float> normalisation_spect; - Array<3,float> uniformity; - Array<3,float> cor; + mutable Array<1, float> normalisation_spect; + Array<3, float> uniformity; + Array<3, float> cor; mutable float map[1048576]; - mutable Array<3,float> down_sampled_uniformity; + mutable Array<3, float> down_sampled_uniformity; mutable RelatedViewgrams NCOR_viewgrams; std::string uniformity_filename, folder_prefix, projdata_filename; float bin_efficiency; @@ -101,7 +91,7 @@ class BinNormalisationSPECT : bool _use_dead_time; bool _use_cor_factors; double half_life, view_time_interval; - int num_detector_heads,rel_angle; + int num_detector_heads, rel_angle; mutable int num_views; mutable bool resampled; }; @@ -109,4 +99,3 @@ class BinNormalisationSPECT : END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/recon_buildblock/BinNormalisationWithCalibration.h b/src/include/stir/recon_buildblock/BinNormalisationWithCalibration.h index 1a21f2e4b8..abcb10b68f 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationWithCalibration.h +++ b/src/include/stir/recon_buildblock/BinNormalisationWithCalibration.h @@ -18,7 +18,6 @@ #ifndef __stir_recon_buildblock_BinNormalisationWithCalibration_H__ #define __stir_recon_buildblock_BinNormalisationWithCalibration_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/Bin.h" #include "stir/shared_ptr.h" @@ -31,44 +30,41 @@ START_NAMESPACE_STIR \ingroup normalisation This class provides the facility to use a calibration factor and branching ratio when normalising data. Therefore, if they are set correctly, the reconstructed image will be calibrated as well. - + Note that it is the responsibility of the derived classes to set these factors. */ -class BinNormalisationWithCalibration : - public BinNormalisation -{ +class BinNormalisationWithCalibration : public BinNormalisation { private: using base_type = BinNormalisation; + public: - - BinNormalisationWithCalibration(); float get_calib_decay_branching_ratio_factor(const Bin&) const; // TODO find a better name float get_calibration_factor() const; float get_branching_ratio() const; - + void set_calibration_factor(const float); void set_branching_ratio(const float); void set_radionuclide(const std::string&); - + // needs to be implemented by derived class - virtual float get_uncalibrated_bin_efficiency(const Bin&, const double start_time, const double end_time) const = 0; - - virtual float get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const - { return this->get_uncalibrated_bin_efficiency(bin, start_time, end_time)/get_calib_decay_branching_ratio_factor(bin); } - - protected: + virtual float get_uncalibrated_bin_efficiency(const Bin&, const double start_time, const double end_time) const = 0; + + virtual float get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { + return this->get_uncalibrated_bin_efficiency(bin, start_time, end_time) / get_calib_decay_branching_ratio_factor(bin); + } + +protected: // parsing stuff virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - private: // provide facility to switch off things? // need to be added to the parsing keywords -// bool use_calibration_factor; // default to true -// bool use_branching_ratio; // default to true + // bool use_calibration_factor; // default to true + // bool use_branching_ratio; // default to true float calibration_factor; float branching_ratio; std::string radionuclide; diff --git a/src/include/stir/recon_buildblock/ChainedBinNormalisation.h b/src/include/stir/recon_buildblock/ChainedBinNormalisation.h index d6675b5510..19566b1d24 100644 --- a/src/include/stir/recon_buildblock/ChainedBinNormalisation.h +++ b/src/include/stir/recon_buildblock/ChainedBinNormalisation.h @@ -38,7 +38,7 @@ START_NAMESPACE_STIR \brief A BinNormalisation class that simply multiplies the factors given by 2 BinNormalisation objects. - This is especially useful to combine the 'usual' normalisation factors and attenuation factors + This is especially useful to combine the 'usual' normalisation factors and attenuation factors in PET. As both are multiplicative corrections, they both belong in the BinNormalisation hierarchy. @@ -54,7 +54,7 @@ START_NAMESPACE_STIR \endverbatim \par Example This example shows how to construct the parameter file for the case that there - are normalisation factors in a file \a norm.hs and an attenuation image in a file + are normalisation factors in a file \a norm.hs and an attenuation image in a file \a atten.hv. \see BinNormalisationFromProjData, BinNormalisationFromAttenuationImage. @@ -64,7 +64,7 @@ START_NAMESPACE_STIR Bin Normalisation to apply first := from projdata Bin Normalisation From ProjData := normalisation projdata filename:= norm.hs - End Bin Normalisation From ProjData:= + End Bin Normalisation From ProjData:= Bin Normalisation to apply second := From Attenuation Image Bin Normalisation From Attenuation Image:= attenuation_image_filename := atten.hv @@ -75,71 +75,69 @@ START_NAMESPACE_STIR END Chained Bin Normalisation Parameters := \endverbatim */ -class ChainedBinNormalisation : - public RegisteredParsingObject -{ +class ChainedBinNormalisation : public RegisteredParsingObject { public: //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor - /*! - \warning You should not call any member functions for any object just + /*! + \warning You should not call any member functions for any object just constructed with this constructor. Initialise the object properly first by parsing. */ ChainedBinNormalisation(); -ChainedBinNormalisation(shared_ptr const& apply_first, - shared_ptr const& apply_second); + ChainedBinNormalisation(shared_ptr const& apply_first, shared_ptr const& apply_second); //! Checks if we can handle certain projection data. /*! Calls set_up for the BinNormalisation members. */ - virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr& ); + virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&); //! Normalise some data - /*! + /*! This calls apply() of the 2 BinNormalisation members */ - virtual void apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; virtual void apply(ProjData&) const; -virtual void apply_only_first(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void apply_only_first(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; -virtual void apply_only_first(ProjData&,const double start_time, const double end_time) const; + virtual void apply_only_first(ProjData&, const double start_time, const double end_time) const; -virtual void apply_only_second(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void apply_only_second(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; -virtual void apply_only_second(ProjData&,const double start_time, const double end_time) const; + virtual void apply_only_second(ProjData&, const double start_time, const double end_time) const; //! Undo the normalisation of some data - /*! - This calls undo() of the 2 BinNormalisation members. + /*! + This calls undo() of the 2 BinNormalisation members. */ - virtual void undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; - virtual void undo(ProjData&,const double start_time, const double end_time) const; + virtual void undo(ProjData&, const double start_time, const double end_time) const; -virtual void undo_only_first(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void undo_only_first(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; -virtual void undo_only_first(ProjData&,const double start_time, const double end_time) const; + virtual void undo_only_first(ProjData&, const double start_time, const double end_time) const; -virtual void undo_only_second(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void undo_only_second(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; -virtual void undo_only_second(ProjData&,const double start_time, const double end_time) const; + virtual void undo_only_second(ProjData&, const double start_time, const double end_time) const; - virtual float get_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const; - //! Returns the is_trivial() status of the first normalisation object. - //! \warning Currently, if the object has not been set the function throws an error. + virtual float get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const; + //! Returns the is_trivial() status of the first normalisation object. + //! \warning Currently, if the object has not been set the function throws an error. virtual bool is_first_trivial() const; -//! Returns the is_trivial() status of the second normalisation object. -//! \warning Currently, if the object has not been set the function throws an error. + //! Returns the is_trivial() status of the second normalisation object. + //! \warning Currently, if the object has not been set the function throws an error. virtual bool is_second_trivial() const; virtual shared_ptr get_first_norm() const; virtual shared_ptr get_second_norm() const; + private: shared_ptr apply_first; shared_ptr apply_second; diff --git a/src/include/stir/recon_buildblock/DataSymmetriesForBins.h b/src/include/stir/recon_buildblock/DataSymmetriesForBins.h index 82bd239cc4..60bc73653c 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForBins.h +++ b/src/include/stir/recon_buildblock/DataSymmetriesForBins.h @@ -47,12 +47,11 @@ class Bin; class SymmetryOperation; class ProjDataInfo; - #if 0 class BinIndexRange; #endif -/*! +/*! \brief AxTangPosNumbers as a class that provides the 2 remaining coordinates for a Bin, aside from ViewSegmentNumbers. @@ -60,22 +59,20 @@ class BinIndexRange; */ typedef Coordinate2D AxTangPosNumbers; - /*! \ingroup symmetries \brief A class for encoding/finding symmetries common to the geometry - of the projection data and the discretised density. + of the projection data and the discretised density. This class is mainly (only?) useful for ProjMatrixByBin classes and their - 'users'. Together with SymmetryOperation, it provides the basic - way to be able to write generic code without knowing which + 'users'. Together with SymmetryOperation, it provides the basic + way to be able to write generic code without knowing which particular symmetries the data have. - \todo I have used Bin here to have the 4 coordinates, but Bin has data as well + \todo I have used Bin here to have the 4 coordinates, but Bin has data as well which is not really necessary here. */ -class DataSymmetriesForBins : public DataSymmetriesForViewSegmentNumbers -{ +class DataSymmetriesForBins : public DataSymmetriesForViewSegmentNumbers { private: typedef DataSymmetriesForViewSegmentNumbers base_type; typedef DataSymmetriesForBins self_type; @@ -85,13 +82,14 @@ class DataSymmetriesForBins : public DataSymmetriesForViewSegmentNumbers virtual ~DataSymmetriesForBins(); - virtual + virtual #ifndef STIR_NO_COVARIANT_RETURN_TYPES - DataSymmetriesForBins + DataSymmetriesForBins #else - DataSymmetriesForViewSegmentNumbers + DataSymmetriesForViewSegmentNumbers #endif - * clone() const = 0; + * + clone() const = 0; #if 0 TODO! @@ -101,93 +99,81 @@ class DataSymmetriesForBins : public DataSymmetriesForViewSegmentNumbers #endif //! fills in a vector with all the bins that are related to 'b' (including itself) - /*! range for axial_pos_num and tangential_pos_num is taken from the ProjDataInfo object - passed in the constructor + /*! range for axial_pos_num and tangential_pos_num is taken from the ProjDataInfo object + passed in the constructor \warning \c b has to be a 'basic' bin */ // next return value could be a RelatedBins ??? // however, both Bin and RelatedBins have data in there (which is not needed here) - inline void - get_related_bins(std::vector&, const Bin& b) const; + inline void get_related_bins(std::vector&, const Bin& b) const; //! fills in a vector with all the bins (within the range) that are related to 'b' /*! \warning \c b has to be a 'basic' bin - */ - virtual void - get_related_bins(std::vector&, const Bin& b, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; + */ + virtual void get_related_bins(std::vector&, const Bin& b, const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num, + const int min_timing_pos_num = 0, const int max_timing_pos_num = 0) const; //! fills in a vector with the axial and tangential position numbers related to this bin - /*! range for axial_pos_num and tangential_pos_num is taken from the ProjDataInfo object - passed in the constructor + /*! range for axial_pos_num and tangential_pos_num is taken from the ProjDataInfo object + passed in the constructor \warning \c b has to be a 'basic' bin \see 6 argument version of get_related_bins_factorised() */ - inline void - get_related_bins_factorised(std::vector&, const Bin& b) const; + inline void get_related_bins_factorised(std::vector&, const Bin& b) const; - //! fills in a vector with the axial and tangential position numbers related to this bin + //! fills in a vector with the axial and tangential position numbers related to this bin /*! It is guaranteed (or at least, it should be by the implementation of the derived class) that these AxTangPosNumbers are related for all related ViewSegmentNumbers for this bin. So, you can find all related bins by calling get_related_ViewSegmentNumbers() - and get_related_bins_factorised(), which is what the default implementation + and get_related_bins_factorised(), which is what the default implementation does. (A derived class might do this in a more optimal way.) \warning \c b has to be a 'basic' bin */ - virtual void - get_related_bins_factorised(std::vector&, const Bin& b, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const = 0; + virtual void get_related_bins_factorised(std::vector&, const Bin& b, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) const = 0; //! returns the number of bins related to 'b' - virtual int - num_related_bins(const Bin& b) const; + virtual int num_related_bins(const Bin& b) const; /*! \brief given an arbitrary bin 'b', find the basic bin and the corresponding symmetry operation - - sets 'b' to the corresponding 'basic' bin and returns the symmetry + + sets 'b' to the corresponding 'basic' bin and returns the symmetry transformation from 'basic' to 'b'. */ - virtual unique_ptr - find_symmetry_operation_from_basic_bin(Bin&) const = 0; + virtual unique_ptr find_symmetry_operation_from_basic_bin(Bin&) const = 0; /*! \brief given an arbitrary bin 'b', find the basic bin - + sets 'b' to the corresponding 'basic' bin and returns true if 'b' is changed (i.e. it was NOT a basic bin). */ - virtual bool - find_basic_bin(Bin& b) const; + virtual bool find_basic_bin(Bin& b) const; - /*! \brief test if a bin is 'basic' + /*! \brief test if a bin is 'basic' The default implementation uses find_basic_bin */ - virtual bool - is_basic(const Bin& v_s) const; + virtual bool is_basic(const Bin& v_s) const; //! default implementation in terms of find_symmetry_operation_from_basic_bin - virtual unique_ptr - find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers&) const; - + virtual unique_ptr find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers&) const; protected: //! Member storing the info needed by get_related_bins() et al const shared_ptr proj_data_info_ptr; //! Check equality - virtual bool blindly_equals(const root_type * const) const = 0; + virtual bool blindly_equals(const root_type* const) const = 0; }; END_NAMESPACE_STIR #include "stir/recon_buildblock/DataSymmetriesForBins.inl" - #endif - diff --git a/src/include/stir/recon_buildblock/DataSymmetriesForBins.inl b/src/include/stir/recon_buildblock/DataSymmetriesForBins.inl index 9f56c6e730..d93ff472ca 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForBins.inl +++ b/src/include/stir/recon_buildblock/DataSymmetriesForBins.inl @@ -34,26 +34,18 @@ START_NAMESPACE_STIR void -DataSymmetriesForBins:: -get_related_bins(std::vector& rel_b, const Bin& b) const -{ - get_related_bins(rel_b, b, - proj_data_info_ptr->get_min_axial_pos_num(b.segment_num()), - proj_data_info_ptr->get_max_axial_pos_num(b.segment_num()), - proj_data_info_ptr->get_min_tangential_pos_num(), - proj_data_info_ptr->get_max_tangential_pos_num()); +DataSymmetriesForBins::get_related_bins(std::vector& rel_b, const Bin& b) const { + get_related_bins(rel_b, b, proj_data_info_ptr->get_min_axial_pos_num(b.segment_num()), + proj_data_info_ptr->get_max_axial_pos_num(b.segment_num()), proj_data_info_ptr->get_min_tangential_pos_num(), + proj_data_info_ptr->get_max_tangential_pos_num(), proj_data_info_ptr->get_min_tof_pos_num(), + proj_data_info_ptr->get_max_tof_pos_num()); } - void -DataSymmetriesForBins:: -get_related_bins_factorised(std::vector& ax_tang_poss, const Bin& b) const -{ - get_related_bins_factorised(ax_tang_poss, b, - proj_data_info_ptr->get_min_axial_pos_num(b.segment_num()), - proj_data_info_ptr->get_max_axial_pos_num(b.segment_num()), - proj_data_info_ptr->get_min_tangential_pos_num(), - proj_data_info_ptr->get_max_tangential_pos_num()); +DataSymmetriesForBins::get_related_bins_factorised(std::vector& ax_tang_poss, const Bin& b) const { + get_related_bins_factorised(ax_tang_poss, b, proj_data_info_ptr->get_min_axial_pos_num(b.segment_num()), + proj_data_info_ptr->get_max_axial_pos_num(b.segment_num()), + proj_data_info_ptr->get_min_tangential_pos_num(), proj_data_info_ptr->get_max_tangential_pos_num()); } END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.h b/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.h index 981c311673..fd3c52d9e7 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.h +++ b/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.h @@ -31,7 +31,6 @@ #ifndef __stir_recon_buildblock_DataSymmetriesForBins_PET_CartesianGrid_H__ #define __stir_recon_buildblock_DataSymmetriesForBins_PET_CartesianGrid_H__ - #include "stir/recon_buildblock/DataSymmetriesForBins.h" //#include "stir/SymmetryOperations_PET_CartesianGrid.h" //#include "stir/ViewSegmentNumbers.h" @@ -41,25 +40,25 @@ START_NAMESPACE_STIR -template class DiscretisedDensity; -template class DiscretisedDensityOnCartesianGrid; +template +class DiscretisedDensity; +template +class DiscretisedDensityOnCartesianGrid; /*! \ingroup symmetries - \brief Symmetries appropriate for a (cylindrical) PET scanner, and + \brief Symmetries appropriate for a (cylindrical) PET scanner, and a discretised density on a Cartesian grid. Nearly all operations (except the constructor) are inline as timing of the methods of this class is critical. */ -class DataSymmetriesForBins_PET_CartesianGrid : public DataSymmetriesForBins -{ +class DataSymmetriesForBins_PET_CartesianGrid : public DataSymmetriesForBins { private: typedef DataSymmetriesForBins base_type; typedef DataSymmetriesForBins_PET_CartesianGrid self_type; public: - //! Constructor with optional selection of symmetries /*! For the azimuthal angle phi, the following angles are symmetry related for a square grid: {phi, 180-phi, 90-phi, 90+phi}. @@ -70,10 +69,10 @@ class DataSymmetriesForBins_PET_CartesianGrid : public DataSymmetriesForBins
  • all 4: (\a do_symmetry_90degrees_min_phi=true)
  • only {phi, 180-phi} : - (\a do_symmetry_90degrees_min_phi=false, + (\a do_symmetry_90degrees_min_phi=false, \a do_symmetry_180degrees_min_phi = true)
  • none: - (\a do_symmetry_90degrees_min_phi=false, + (\a do_symmetry_90degrees_min_phi=false, \a do_symmetry_180degrees_min_phi = false)
  • axial (i.e. positive vs. negative segment): \a do_symmetry_swap_segment
  • @@ -87,23 +86,22 @@ class DataSymmetriesForBins_PET_CartesianGrid : public DataSymmetriesForBins The symmetry in phi is automatically reduced for non-square grids or when the number of views is not a multiple of 4. - */ + */ DataSymmetriesForBins_PET_CartesianGrid(const shared_ptr& proj_data_info_ptr, - const shared_ptr >& image_info_ptr, + const shared_ptr>& image_info_ptr, const bool do_symmetry_90degrees_min_phi = true, const bool do_symmetry_180degrees_min_phi = true, - const bool do_symmetry_swap_segment = true, - const bool do_symmetry_swap_s = true, - const bool do_symmetry_shift_z = true); + const bool do_symmetry_swap_segment = true, const bool do_symmetry_swap_s = true, + const bool do_symmetry_shift_z = true); - - virtual + virtual #ifndef STIR_NO_COVARIANT_RETURN_TYPES - DataSymmetriesForBins_PET_CartesianGrid + DataSymmetriesForBins_PET_CartesianGrid #else - DataSymmetriesForViewSegmentNumbers + DataSymmetriesForViewSegmentNumbers #endif - * clone() const; + * + clone() const; //! Check equality virtual bool operator==(const DataSymmetriesForBins_PET_CartesianGrid&) const; @@ -115,38 +113,29 @@ class DataSymmetriesForBins_PET_CartesianGrid : public DataSymmetriesForBins get_basic_bin_index_range() const; #endif - inline void - get_related_bins_factorised(std::vector&, const Bin& b, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; - - inline int - num_related_bins(const Bin& b) const; - - inline unique_ptr - find_symmetry_operation_from_basic_bin(Bin&) const; - - inline bool - find_basic_bin(Bin& b) const; - - inline int - num_related_view_segment_numbers(const ViewSegmentNumbers& vs) const; - - inline void - get_related_view_segment_numbers(std::vector& rel_vs, const ViewSegmentNumbers& vs) const; - - inline bool - find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const; + inline void get_related_bins_factorised(std::vector&, const Bin& b, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) const; - //! find out how many image planes there are for every scanner ring - inline float get_num_planes_per_scanner_ring() const; + inline int num_related_bins(const Bin& b) const; + + inline unique_ptr find_symmetry_operation_from_basic_bin(Bin&) const; + + inline bool find_basic_bin(Bin& b) const; + + inline int num_related_view_segment_numbers(const ViewSegmentNumbers& vs) const; + inline void get_related_view_segment_numbers(std::vector& rel_vs, const ViewSegmentNumbers& vs) const; + inline bool find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const; + + //! find out how many image planes there are for every scanner ring + inline float get_num_planes_per_scanner_ring() const; //! find correspondence between axial_pos_num and image coordinates /*! z = num_planes_per_axial_pos * axial_pos_num + axial_pos_to_z_offset - - compute the offset by matching up the centre of the scanner + + compute the offset by matching up the centre of the scanner in the 2 coordinate systems */ inline float get_num_planes_per_axial_pos(const int segment_num) const; @@ -154,16 +143,11 @@ class DataSymmetriesForBins_PET_CartesianGrid : public DataSymmetriesForBins //! \name Methods to find out which symmetries are used //@{ - inline bool using_symmetry_90degrees_min_phi() const - { return do_symmetry_90degrees_min_phi; } - inline bool using_symmetry_180degrees_min_phi() const - { return do_symmetry_180degrees_min_phi; } - inline bool using_symmetry_swap_segment() const - { return do_symmetry_swap_segment; } - inline bool using_symmetry_swap_s() const - { return do_symmetry_swap_s; } - inline bool using_symmetry_shift_z() const - { return do_symmetry_shift_z; } + inline bool using_symmetry_90degrees_min_phi() const { return do_symmetry_90degrees_min_phi; } + inline bool using_symmetry_180degrees_min_phi() const { return do_symmetry_180degrees_min_phi; } + inline bool using_symmetry_swap_segment() const { return do_symmetry_swap_segment; } + inline bool using_symmetry_swap_s() const { return do_symmetry_swap_s; } + inline bool using_symmetry_shift_z() const { return do_symmetry_shift_z; } //@} private: @@ -172,7 +156,7 @@ class DataSymmetriesForBins_PET_CartesianGrid : public DataSymmetriesForBins bool do_symmetry_swap_segment; bool do_symmetry_swap_s; bool do_symmetry_shift_z; - //const shared_ptr& proj_data_info_ptr; + // const shared_ptr& proj_data_info_ptr; int num_views; int num_planes_per_scanner_ring; //! a list of values for every segment_num @@ -191,30 +175,15 @@ class DataSymmetriesForBins_PET_CartesianGrid : public DataSymmetriesForBins cartesian_grid_info_ptr() const; #endif - virtual bool blindly_equals(const root_type * const) const; - - - inline bool - find_basic_bin(int &segment_num, int &view_num, int &axial_pos_num, int &tangential_pos_num) const; - - - inline int find_transform_z( - const int segment_num, - const int axial_pos_num) const; - - inline SymmetryOperation* - find_sym_op_general_bin( - int s, - int seg, - int view_num, - int axial_pos_num) const; - - inline SymmetryOperation* - find_sym_op_bin0( - int seg, - int view_num, - int axial_pos_num) const; - + virtual bool blindly_equals(const root_type* const) const; + + inline bool find_basic_bin(int& segment_num, int& view_num, int& axial_pos_num, int& tangential_pos_num) const; + + inline int find_transform_z(const int segment_num, const int axial_pos_num) const; + + inline SymmetryOperation* find_sym_op_general_bin(int s, int seg, int view_num, int axial_pos_num) const; + + inline SymmetryOperation* find_sym_op_bin0(int seg, int view_num, int axial_pos_num) const; }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.inl b/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.inl index 9478c769bc..158cc588a1 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.inl +++ b/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.inl @@ -34,7 +34,6 @@ #include "stir/ProjDataInfoCylindrical.h" #include "stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.h" - START_NAMESPACE_STIR #if 0 @@ -49,113 +48,87 @@ cartesian_grid_info_ptr() const #endif float -DataSymmetriesForBins_PET_CartesianGrid:: -get_num_planes_per_axial_pos(const int segment_num) const -{ +DataSymmetriesForBins_PET_CartesianGrid::get_num_planes_per_axial_pos(const int segment_num) const { return static_cast(num_planes_per_axial_pos[segment_num]); } float -DataSymmetriesForBins_PET_CartesianGrid:: -get_num_planes_per_scanner_ring() const -{ +DataSymmetriesForBins_PET_CartesianGrid::get_num_planes_per_scanner_ring() const { return static_cast(num_planes_per_scanner_ring); } -float -DataSymmetriesForBins_PET_CartesianGrid:: -get_axial_pos_to_z_offset(const int segment_num) const -{ +float +DataSymmetriesForBins_PET_CartesianGrid::get_axial_pos_to_z_offset(const int segment_num) const { return axial_pos_to_z_offset[segment_num]; -} +} int -DataSymmetriesForBins_PET_CartesianGrid:: -find_transform_z( - const int segment_num, - const int axial_pos_num) const -{ - const ProjDataInfoCylindrical* proj_data_info_cyl_ptr = - static_cast(proj_data_info_ptr.get()); +DataSymmetriesForBins_PET_CartesianGrid::find_transform_z(const int segment_num, const int axial_pos_num) const { + const ProjDataInfoCylindrical* proj_data_info_cyl_ptr = static_cast(proj_data_info_ptr.get()); const float delta = proj_data_info_cyl_ptr->get_average_ring_difference(segment_num); - // Find symmetric value in Z by 'mirroring' it around the centre z of the LOR: // Z+Q = 2*centre_of_LOR_in_image_coordinates == transform_z { // first compute it as floating point (although it has to be an int really) - const float transform_z_float = (2*num_planes_per_axial_pos[segment_num]*(axial_pos_num) - + num_planes_per_scanner_ring*delta - + 2*axial_pos_to_z_offset[segment_num]); + const float transform_z_float = (2 * num_planes_per_axial_pos[segment_num] * (axial_pos_num) + + num_planes_per_scanner_ring * delta + 2 * axial_pos_to_z_offset[segment_num]); // now use rounding to be safe int transform_z = (int)floor(transform_z_float + 0.5); - assert(fabs(transform_z-transform_z_float) < 10E-4); + assert(fabs(transform_z - transform_z_float) < 10E-4); return transform_z; } } SymmetryOperation* -DataSymmetriesForBins_PET_CartesianGrid:: -find_sym_op_bin0( - int segment_num, - int view_num, - int axial_pos_num) const -{ +DataSymmetriesForBins_PET_CartesianGrid::find_sym_op_bin0(int segment_num, int view_num, int axial_pos_num) const { // note: if do_symmetry_shift_z==true, then basic axial_pos_num will be 0 - const int transform_z = - find_transform_z(abs(segment_num), - do_symmetry_shift_z ? 0 : axial_pos_num); - - const int z_shift = - do_symmetry_shift_z ? - num_planes_per_axial_pos[segment_num]*axial_pos_num - : 0; - + const int transform_z = find_transform_z(abs(segment_num), do_symmetry_shift_z ? 0 : axial_pos_num); + + const int z_shift = do_symmetry_shift_z ? num_planes_per_axial_pos[segment_num] * axial_pos_num : 0; + const int view180 = num_views; // TODO get rid of next 2 restrictions - assert(!do_symmetry_180degrees_min_phi || view_num>=0); - assert(!do_symmetry_180degrees_min_phi || view_num= 0); + assert(!do_symmetry_180degrees_min_phi || view_num < num_views); #ifndef NDEBUG - // This variable is only used in assert() at the moment, so avoid compiler + // This variable is only used in assert() at the moment, so avoid compiler // warning by defining it only when in debug mode - const int view0 = 0; + const int view0 = 0; #endif - const int view135 = view180/4*3; - const int view90 = view180/2; - const int view45 = view180/4; - - if ( do_symmetry_90degrees_min_phi && view_num > view90 && view_num <= view135) { //(90, 135 ] - if ( !do_symmetry_swap_segment || segment_num >= 0) - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx(view180, axial_pos_num, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq(view180, axial_pos_num, z_shift, transform_z); // seg < 0 - } - else if ( do_symmetry_90degrees_min_phi && view_num > view45 && view_num <= view90 ) { // [ 45, 90] - if ( !do_symmetry_swap_segment || segment_num >= 0) - return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq(view180, axial_pos_num, z_shift, transform_z); + const int view135 = view180 / 4 * 3; + const int view90 = view180 / 2; + const int view45 = view180 / 4; + + if (do_symmetry_90degrees_min_phi && view_num > view90 && view_num <= view135) { //(90, 135 ] + if (!do_symmetry_swap_segment || segment_num >= 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx(view180, axial_pos_num, z_shift); else - return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx(view180, axial_pos_num, z_shift); // seg < 0 //KT???????????? different for view90, TODO - } - else if( do_symmetry_180degrees_min_phi && view_num > view90/* && view_num <= view180 */){ // (135, 180) but (90,180) for reduced symmetry case - if( !do_symmetry_swap_segment || segment_num >= 0) - return new SymmetryOperation_PET_CartesianGrid_swap_xmx_zq(view180, axial_pos_num, z_shift, transform_z); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xmx(view180, axial_pos_num, z_shift); // seg < 0 - } - else - { - assert( !do_symmetry_90degrees_min_phi || (view_num >= view0 && view_num <= view45)); - assert( !do_symmetry_180degrees_min_phi || (view_num >= view0 && view_num <= view90)); - if ( do_symmetry_swap_segment && segment_num < 0) - return new SymmetryOperation_PET_CartesianGrid_swap_zq(view180, axial_pos_num, z_shift, transform_z); + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq(view180, axial_pos_num, z_shift, transform_z); // seg < 0 + } else if (do_symmetry_90degrees_min_phi && view_num > view45 && view_num <= view90) { // [ 45, 90] + if (!do_symmetry_swap_segment || segment_num >= 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq(view180, axial_pos_num, z_shift, transform_z); else - { - if (z_shift==0) - return new TrivialSymmetryOperation(); + return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx( + view180, axial_pos_num, z_shift); // seg < 0 //KT???????????? different for view90, TODO + } else if (do_symmetry_180degrees_min_phi && + view_num > view90 /* && view_num <= view180 */) { // (135, 180) but (90,180) for reduced symmetry case + if (!do_symmetry_swap_segment || segment_num >= 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmx_zq(view180, axial_pos_num, z_shift, transform_z); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xmx(view180, axial_pos_num, z_shift); // seg < 0 + } else { + assert(!do_symmetry_90degrees_min_phi || (view_num >= view0 && view_num <= view45)); + assert(!do_symmetry_180degrees_min_phi || (view_num >= view0 && view_num <= view90)); + if (do_symmetry_swap_segment && segment_num < 0) + return new SymmetryOperation_PET_CartesianGrid_swap_zq(view180, axial_pos_num, z_shift, transform_z); + else { + if (z_shift == 0) + return new TrivialSymmetryOperation(); else return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num, z_shift); } @@ -163,329 +136,282 @@ find_sym_op_bin0( } // from symmetries -SymmetryOperation* -DataSymmetriesForBins_PET_CartesianGrid:: -find_sym_op_general_bin( - int s, - int segment_num, - int view_num, - int axial_pos_num) const -{ +SymmetryOperation* +DataSymmetriesForBins_PET_CartesianGrid::find_sym_op_general_bin(int s, int segment_num, int view_num, int axial_pos_num) const { // note: if do_symmetry_shift_z==true, then basic axial_pos_num will be 0 - const int transform_z = - find_transform_z(abs(segment_num), - do_symmetry_shift_z ? 0 : axial_pos_num); - - const int z_shift = - do_symmetry_shift_z ? - num_planes_per_axial_pos[segment_num]*axial_pos_num - : 0; - -// TODO get rid of next 2 restrictions - assert(!do_symmetry_180degrees_min_phi || view_num>=0); - assert(!do_symmetry_180degrees_min_phi || view_num= 0); + assert(!do_symmetry_180degrees_min_phi || view_num < num_views); const int view180 = num_views; #ifndef NDEBUG - // This variable is only used in assert() at the moment, so avoid compiler + // This variable is only used in assert() at the moment, so avoid compiler // warning by defining it only when in debug mode - const int view0 = 0; + const int view0 = 0; #endif - const int view135 = view180/4*3; - const int view90 = view180/2; - const int view45 = view180/4; - - - if ( do_symmetry_90degrees_min_phi && view_num > view90 && view_num <= view135) { //(90, 135 ] - if ( !do_symmetry_swap_segment || segment_num > 0) { // pos_plus90 - if ( !do_symmetry_swap_s || s > 0 ) - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx(view180, axial_pos_num, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq(view180, axial_pos_num, z_shift, transform_z); // s < 0 - } - else // neg_plus90 - ///// - if ( segment_num < 0 ) { - if ( !do_symmetry_swap_s || s > 0 ) - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq(view180, axial_pos_num, z_shift, transform_z); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx(view180, axial_pos_num, z_shift); - } - else { // segment_num == 0 - if ( !do_symmetry_swap_s || s > 0 ) - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx(view180, axial_pos_num, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx(view180, axial_pos_num, z_shift); - } - } - else if ( do_symmetry_90degrees_min_phi && view_num > view45 && view_num <= view90 ) // [ 45, 90] - { - if ( !do_symmetry_swap_segment || segment_num > 0){ - if ( !do_symmetry_swap_s || s > 0 ) - return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq(view180, axial_pos_num, z_shift, transform_z); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(view180, axial_pos_num, z_shift); + const int view135 = view180 / 4 * 3; + const int view90 = view180 / 2; + const int view45 = view180 / 4; + + if (do_symmetry_90degrees_min_phi && view_num > view90 && view_num <= view135) { //(90, 135 ] + if (!do_symmetry_swap_segment || segment_num > 0) { // pos_plus90 + if (!do_symmetry_swap_s || s > 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx(view180, axial_pos_num, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq(view180, axial_pos_num, z_shift, transform_z); // s < 0 + } else // neg_plus90 + ///// + if (segment_num < 0) { + if (!do_symmetry_swap_s || s > 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq(view180, axial_pos_num, z_shift, transform_z); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx(view180, axial_pos_num, z_shift); + } else { // segment_num == 0 + if (!do_symmetry_swap_s || s > 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx(view180, axial_pos_num, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx(view180, axial_pos_num, z_shift); } - else if ( segment_num < 0 ) { // {//101 segment_num < 0 - if ( !do_symmetry_swap_s || s > 0 ) - return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx(view180, axial_pos_num, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq(view180, axial_pos_num, z_shift, transform_z); - - } - else // segment_num == 0 + } else if (do_symmetry_90degrees_min_phi && view_num > view45 && view_num <= view90) // [ 45, 90] + { + if (!do_symmetry_swap_segment || segment_num > 0) { + if (!do_symmetry_swap_s || s > 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq(view180, axial_pos_num, z_shift, transform_z); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(view180, axial_pos_num, z_shift); + } else if (segment_num < 0) { // {//101 segment_num < 0 + if (!do_symmetry_swap_s || s > 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx(view180, axial_pos_num, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq(view180, axial_pos_num, z_shift, transform_z); + + } else // segment_num == 0 { - if ( !do_symmetry_swap_s || s > 0 ) - return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx(view180, axial_pos_num, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(view180, axial_pos_num, z_shift); + if (!do_symmetry_swap_s || s > 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx(view180, axial_pos_num, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(view180, axial_pos_num, z_shift); } - } - else if( do_symmetry_180degrees_min_phi && view_num > view90/* && view_num <= view180 */) // (135, 180) but (90,180) for reduced symmetry case + } else if (do_symmetry_180degrees_min_phi && + view_num > view90 /* && view_num <= view180 */) // (135, 180) but (90,180) for reduced symmetry case { - if( !do_symmetry_swap_segment || segment_num > 0){ - if ( !do_symmetry_swap_s || s > 0 ) - return new SymmetryOperation_PET_CartesianGrid_swap_xmx_zq(view180, axial_pos_num, z_shift, transform_z); - else - return new SymmetryOperation_PET_CartesianGrid_swap_ymy(view180, axial_pos_num, z_shift); // s <= 0 - } - else //if ( segment_num < 0 ) - {// segment_num <= 0 - if ( !do_symmetry_swap_s || s > 0 ) - return new SymmetryOperation_PET_CartesianGrid_swap_xmx(view180, axial_pos_num, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_ymy_zq(view180, axial_pos_num, z_shift, transform_z); - }// segment_num == 0 - // /*else{ if ( !do_symmetry_swap_s || s > 0 ) return new SymmetryOperation_PET_CartesianGrid_swap_xmx(); else return new SymmetryOperation_PET_CartesianGrid_swap_ymy(view180, axial_pos_num, z_shift);}*/ - } - else - { - assert( !do_symmetry_90degrees_min_phi || (view_num >= view0 && view_num <= view45)); - assert( !do_symmetry_180degrees_min_phi || (view_num >= view0 && view_num <= view90)); - if ( !do_symmetry_swap_segment || segment_num > 0) - { - if ( do_symmetry_swap_s && s < 0) - return new SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq(view180, axial_pos_num, z_shift, transform_z); + if (!do_symmetry_swap_segment || segment_num > 0) { + if (!do_symmetry_swap_s || s > 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmx_zq(view180, axial_pos_num, z_shift, transform_z); + else + return new SymmetryOperation_PET_CartesianGrid_swap_ymy(view180, axial_pos_num, z_shift); // s <= 0 + } else // if ( segment_num < 0 ) + { // segment_num <= 0 + if (!do_symmetry_swap_s || s > 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmx(view180, axial_pos_num, z_shift); else - { - if (z_shift==0) + return new SymmetryOperation_PET_CartesianGrid_swap_ymy_zq(view180, axial_pos_num, z_shift, transform_z); + } // segment_num == 0 + // /*else{ if ( !do_symmetry_swap_s || s > 0 ) return new SymmetryOperation_PET_CartesianGrid_swap_xmx(); else return new + // SymmetryOperation_PET_CartesianGrid_swap_ymy(view180, axial_pos_num, z_shift);}*/ + } else { + assert(!do_symmetry_90degrees_min_phi || (view_num >= view0 && view_num <= view45)); + assert(!do_symmetry_180degrees_min_phi || (view_num >= view0 && view_num <= view90)); + if (!do_symmetry_swap_segment || segment_num > 0) { + if (do_symmetry_swap_s && s < 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq(view180, axial_pos_num, z_shift, transform_z); + else { + if (z_shift == 0) return new TrivialSymmetryOperation(); else return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num, z_shift); } - } - else - if ( segment_num < 0 ) - { - /*KT if ( s == 0) - return new SymmetryOperation_PET_CartesianGrid_swap_zq(view180, axial_pos_num, z_shift, transform_z); - else*/ - if ( do_symmetry_swap_s && s < 0) - return new SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy(view180, axial_pos_num, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_zq(view180, axial_pos_num, z_shift, transform_z); // s > 0 - } - else // segment_num = 0 - { - if ( do_symmetry_swap_s && s < 0) return new SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy(view180, axial_pos_num, z_shift); + } else if (segment_num < 0) { + /*KT if ( s == 0) + return new SymmetryOperation_PET_CartesianGrid_swap_zq(view180, axial_pos_num, z_shift, transform_z); + else*/ + if (do_symmetry_swap_s && s < 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy(view180, axial_pos_num, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_zq(view180, axial_pos_num, z_shift, transform_z); // s > 0 + } else // segment_num = 0 + { + if (do_symmetry_swap_s && s < 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy(view180, axial_pos_num, z_shift); + else { + if (z_shift == 0) + return new TrivialSymmetryOperation(); else - { - if (z_shift==0) - return new TrivialSymmetryOperation(); - else - return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num, z_shift); - } + return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num, z_shift); } - } + } + } } +bool +DataSymmetriesForBins_PET_CartesianGrid::find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const { + bool change = false; + // TODO get rid of next 2 restrictions + assert(!do_symmetry_180degrees_min_phi || v_s.view_num() >= 0); + assert(!do_symmetry_180degrees_min_phi || v_s.view_num() < num_views); + + // const int view0= 0; + const int view90 = num_views >> 1; + const int view45 = view90 >> 1; + const int view135 = view90 + view45; + + if (do_symmetry_swap_segment && v_s.segment_num() < 0) { + v_s.segment_num() = -v_s.segment_num(); + change = true; + } + + if (do_symmetry_90degrees_min_phi) { + // if ( v_s.view_num() == num_views ) v_s.view_num() =0; // KT 30/05/2002 disabled as it should never happen + // else + if (v_s.view_num() >= view135) { + v_s.view_num() = num_views - v_s.view_num(); + return true; + } else if (v_s.view_num() >= view90) { + v_s.view_num() = v_s.view_num() - view90; + return true; + } else if (v_s.view_num() > view45) { + v_s.view_num() = view90 - v_s.view_num(); + return true; + } + } else if (do_symmetry_180degrees_min_phi) { + if (v_s.view_num() > view90) { + v_s.view_num() = num_views - v_s.view_num(); + return true; + } + } -bool -DataSymmetriesForBins_PET_CartesianGrid:: -find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const -{ - bool change=false; - // TODO get rid of next 2 restrictions - assert(!do_symmetry_180degrees_min_phi || v_s.view_num()>=0); - assert(!do_symmetry_180degrees_min_phi || v_s.view_num()>1; - const int view45 = view90>>1; - const int view135 = view90+view45; - - if ( do_symmetry_swap_segment && v_s.segment_num() < 0 ) { v_s.segment_num() = -v_s.segment_num(); change=true;} - - if (do_symmetry_90degrees_min_phi) - { - //if ( v_s.view_num() == num_views ) v_s.view_num() =0; // KT 30/05/2002 disabled as it should never happen - //else - if (v_s.view_num() >= view135) - { v_s.view_num() = num_views - v_s.view_num(); return true; } - else if (v_s.view_num() >= view90 ) - { v_s.view_num() = v_s.view_num() - view90; return true; } - else if (v_s.view_num() > view45 ) - { v_s.view_num() = view90 - v_s.view_num() ; return true; } - } - else if (do_symmetry_180degrees_min_phi) - { - if (v_s.view_num() > view90 ) - { v_s.view_num() = num_views - v_s.view_num(); return true; } - } - return change; } -bool -DataSymmetriesForBins_PET_CartesianGrid:: -find_basic_bin(int &segment_num, int &view_num, int &axial_pos_num, int &tangential_pos_num) const -{ +bool +DataSymmetriesForBins_PET_CartesianGrid::find_basic_bin(int& segment_num, int& view_num, int& axial_pos_num, + int& tangential_pos_num) const { ViewSegmentNumbers v_s(view_num, segment_num); - bool change=find_basic_view_segment_numbers(v_s); + bool change = find_basic_view_segment_numbers(v_s); view_num = v_s.view_num(); segment_num = v_s.segment_num(); - if ( do_symmetry_swap_s && tangential_pos_num < 0 ) { tangential_pos_num = - tangential_pos_num ; change=true;}; - if ( do_symmetry_shift_z && axial_pos_num != 0 ) { axial_pos_num = 0; change = true; } - + if (do_symmetry_swap_s && tangential_pos_num < 0) { + tangential_pos_num = -tangential_pos_num; + change = true; + }; + if (do_symmetry_shift_z && axial_pos_num != 0) { + axial_pos_num = 0; + change = true; + } + return change; } -bool -DataSymmetriesForBins_PET_CartesianGrid:: -find_basic_bin(Bin& b) const -{ - return - find_basic_bin(b.segment_num(), b.view_num(), b.axial_pos_num(), b.tangential_pos_num()); +bool +DataSymmetriesForBins_PET_CartesianGrid::find_basic_bin(Bin& b) const { + return find_basic_bin(b.segment_num(), b.view_num(), b.axial_pos_num(), b.tangential_pos_num()); } - // TODO, optimise unique_ptr -DataSymmetriesForBins_PET_CartesianGrid:: - find_symmetry_operation_from_basic_bin(Bin& b) const -{ - unique_ptr - sym_op( - (b.tangential_pos_num()==0) ? - find_sym_op_bin0(b.segment_num(), b.view_num(), b.axial_pos_num()) : - find_sym_op_general_bin(b.tangential_pos_num(), b.segment_num(), b.view_num(), b.axial_pos_num()) - ); +DataSymmetriesForBins_PET_CartesianGrid::find_symmetry_operation_from_basic_bin(Bin& b) const { + unique_ptr sym_op( + (b.tangential_pos_num() == 0) + ? find_sym_op_bin0(b.segment_num(), b.view_num(), b.axial_pos_num()) + : find_sym_op_general_bin(b.tangential_pos_num(), b.segment_num(), b.view_num(), b.axial_pos_num())); find_basic_bin(b); return sym_op; } - int -DataSymmetriesForBins_PET_CartesianGrid:: -num_related_view_segment_numbers(const ViewSegmentNumbers& vs) const -{ - int num = do_symmetry_180degrees_min_phi && (vs.view_num() % (num_views/2)) != 0 ? 2 : 1; - if (do_symmetry_90degrees_min_phi && (vs.view_num() % (num_views/2)) != num_views/4) +DataSymmetriesForBins_PET_CartesianGrid::num_related_view_segment_numbers(const ViewSegmentNumbers& vs) const { + int num = do_symmetry_180degrees_min_phi && (vs.view_num() % (num_views / 2)) != 0 ? 2 : 1; + if (do_symmetry_90degrees_min_phi && (vs.view_num() % (num_views / 2)) != num_views / 4) num *= 2; if (do_symmetry_swap_segment && vs.segment_num() != 0) num *= 2; - return num; + return num; } - int -DataSymmetriesForBins_PET_CartesianGrid:: -num_related_bins(const Bin& b) const -{ - int num = do_symmetry_180degrees_min_phi && (b.view_num() % (num_views/2)) != 0 ? 2 : 1; - if (do_symmetry_90degrees_min_phi && (b.view_num() % (num_views/2)) != num_views/4) +DataSymmetriesForBins_PET_CartesianGrid::num_related_bins(const Bin& b) const { + int num = do_symmetry_180degrees_min_phi && (b.view_num() % (num_views / 2)) != 0 ? 2 : 1; + if (do_symmetry_90degrees_min_phi && (b.view_num() % (num_views / 2)) != num_views / 4) num *= 2; if (do_symmetry_swap_segment && b.segment_num() != 0) num *= 2; if (do_symmetry_swap_s && b.tangential_pos_num() != 0) num *= 2; - + if (do_symmetry_shift_z) num *= proj_data_info_ptr->get_num_axial_poss(b.segment_num()); return num; } void -DataSymmetriesForBins_PET_CartesianGrid:: -get_related_bins_factorised(std::vector& ax_tang_poss, const Bin& b, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ - for (int axial_pos_num=do_symmetry_shift_z?min_axial_pos_num:b.axial_pos_num(); - axial_pos_num <= (do_symmetry_shift_z?max_axial_pos_num:b.axial_pos_num()); - ++axial_pos_num) - { - if (b.tangential_pos_num() >= min_tangential_pos_num && - b.tangential_pos_num() <= max_tangential_pos_num) - ax_tang_poss.push_back(AxTangPosNumbers(axial_pos_num, b.tangential_pos_num())); - if (do_symmetry_swap_s && b.tangential_pos_num()!=0 && - -b.tangential_pos_num() >= min_tangential_pos_num && - -b.tangential_pos_num() <= max_tangential_pos_num) - ax_tang_poss.push_back(AxTangPosNumbers(axial_pos_num, -b.tangential_pos_num())); - } +DataSymmetriesForBins_PET_CartesianGrid::get_related_bins_factorised(std::vector& ax_tang_poss, const Bin& b, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) const { + for (int axial_pos_num = do_symmetry_shift_z ? min_axial_pos_num : b.axial_pos_num(); + axial_pos_num <= (do_symmetry_shift_z ? max_axial_pos_num : b.axial_pos_num()); ++axial_pos_num) { + if (b.tangential_pos_num() >= min_tangential_pos_num && b.tangential_pos_num() <= max_tangential_pos_num) + ax_tang_poss.push_back(AxTangPosNumbers(axial_pos_num, b.tangential_pos_num())); + if (do_symmetry_swap_s && b.tangential_pos_num() != 0 && -b.tangential_pos_num() >= min_tangential_pos_num && + -b.tangential_pos_num() <= max_tangential_pos_num) + ax_tang_poss.push_back(AxTangPosNumbers(axial_pos_num, -b.tangential_pos_num())); + } } - + void -DataSymmetriesForBins_PET_CartesianGrid:: -get_related_view_segment_numbers(std::vector& rel_vs, const ViewSegmentNumbers& vs) const -{ +DataSymmetriesForBins_PET_CartesianGrid::get_related_view_segment_numbers(std::vector& rel_vs, + const ViewSegmentNumbers& vs) const { #ifndef NDEBUG { - ViewSegmentNumbers vstest=vs; - assert(find_basic_view_segment_numbers(vstest)==false); + ViewSegmentNumbers vstest = vs; + assert(find_basic_view_segment_numbers(vstest) == false); } #endif const int segment_num = vs.segment_num(); const int view_num = vs.view_num(); - const bool symz = - do_symmetry_swap_segment && (segment_num != 0); + const bool symz = do_symmetry_swap_segment && (segment_num != 0); rel_vs.reserve(num_related_view_segment_numbers(vs)); rel_vs.resize(0); - rel_vs.push_back(ViewSegmentNumbers(view_num,segment_num)); + rel_vs.push_back(ViewSegmentNumbers(view_num, segment_num)); if (symz) - rel_vs.push_back(ViewSegmentNumbers(view_num,-segment_num)); + rel_vs.push_back(ViewSegmentNumbers(view_num, -segment_num)); - if (do_symmetry_180degrees_min_phi && do_symmetry_90degrees_min_phi && (view_num % (num_views/2)) != num_views/4) - { - const int related_view_num = - view_num < num_views/2 ? - view_num + num_views/2 : - view_num - num_views/2; - rel_vs.push_back(ViewSegmentNumbers( related_view_num,segment_num)); + if (do_symmetry_180degrees_min_phi && do_symmetry_90degrees_min_phi && (view_num % (num_views / 2)) != num_views / 4) { + const int related_view_num = view_num < num_views / 2 ? view_num + num_views / 2 : view_num - num_views / 2; + rel_vs.push_back(ViewSegmentNumbers(related_view_num, segment_num)); if (symz) - rel_vs.push_back(ViewSegmentNumbers( related_view_num,-segment_num)); + rel_vs.push_back(ViewSegmentNumbers(related_view_num, -segment_num)); } - if (do_symmetry_180degrees_min_phi && (view_num % (num_views/2)) != 0) - { - rel_vs.push_back(ViewSegmentNumbers( num_views - view_num,segment_num)); + if (do_symmetry_180degrees_min_phi && (view_num % (num_views / 2)) != 0) { + rel_vs.push_back(ViewSegmentNumbers(num_views - view_num, segment_num)); if (symz) - rel_vs.push_back(ViewSegmentNumbers( num_views - view_num,-segment_num)); + rel_vs.push_back(ViewSegmentNumbers(num_views - view_num, -segment_num)); } - if (do_symmetry_90degrees_min_phi && (view_num % (num_views/4)) != 0) - { + if (do_symmetry_90degrees_min_phi && (view_num % (num_views / 4)) != 0) { // use trick to get related_view_num between 0 and num_views: // use modulo num_views (but add num_views first to ensure positivity) - const int related_view_num = - (num_views/2 - view_num + num_views) % num_views; - rel_vs.push_back(ViewSegmentNumbers( related_view_num,segment_num)); + const int related_view_num = (num_views / 2 - view_num + num_views) % num_views; + rel_vs.push_back(ViewSegmentNumbers(related_view_num, segment_num)); if (symz) - rel_vs.push_back(ViewSegmentNumbers( related_view_num,-segment_num)); + rel_vs.push_back(ViewSegmentNumbers(related_view_num, -segment_num)); } - - assert(rel_vs.size() == - static_cast(num_related_view_segment_numbers(vs))); + assert(rel_vs.size() == static_cast(num_related_view_segment_numbers(vs))); } END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/DataSymmetriesForDensels.h b/src/include/stir/recon_buildblock/DataSymmetriesForDensels.h index be46afff7f..082e7255f9 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForDensels.h +++ b/src/include/stir/recon_buildblock/DataSymmetriesForDensels.h @@ -23,7 +23,7 @@ \brief Declaration of class stir::DataSymmetriesForDensels \author Kris Thielemans - + */ #ifndef __stir_recon_buildblock_DataSymmetriesForDensels_H__ #define __stir_recon_buildblock_DataSymmetriesForDensels_H__ @@ -37,41 +37,35 @@ START_NAMESPACE_STIR -//class Densel; +// class Densel; class SymmetryOperation; - #if 0 class DenselIndexRange; #endif - - /*! \ingroup symmetries \brief A class for encoding/finding symmetries common to the geometry - of the projection data and the discretised density. + of the projection data and the discretised density. This class is mainly (only?) useful for ProjMatrixByDensel classes and their - 'users'. Together with SymmetryOperation, it provides the basic - way to be able to write generic code without knowing which + 'users'. Together with SymmetryOperation, it provides the basic + way to be able to write generic code without knowing which particular symmetries the data have. */ -class DataSymmetriesForDensels -{ +class DataSymmetriesForDensels { public: DataSymmetriesForDensels(); - virtual ~DataSymmetriesForDensels() {}; + virtual ~DataSymmetriesForDensels(){}; - virtual - DataSymmetriesForDensels - * clone() const = 0; + virtual DataSymmetriesForDensels* clone() const = 0; - bool operator ==(const DataSymmetriesForDensels&) const; + bool operator==(const DataSymmetriesForDensels&) const; - bool operator !=(const DataSymmetriesForDensels&) const; + bool operator!=(const DataSymmetriesForDensels&) const; #if 0 TODO! @@ -81,12 +75,11 @@ class DataSymmetriesForDensels #endif //! fills in a vector with all the Densels that are related to 'b' (including itself) - /*! + /*! \warning \c b has to be a 'basic' Densel */ // next return value could be a RelatedDensels ??? - virtual void - get_related_densels(std::vector&, const Densel& b) const = 0; + virtual void get_related_densels(std::vector&, const Densel& b) const = 0; #if 0 //! fills in a vector with all the Densels (within the range) that are related to 'b' @@ -98,36 +91,30 @@ class DataSymmetriesForDensels #endif //! returns the number of Densels related to 'b' - virtual int - num_related_densels(const Densel& b) const; + virtual int num_related_densels(const Densel& b) const; /*! \brief given an arbitrary Densel 'b', find the basic Densel - - sets 'b' to the corresponding 'basic' Densel and returns the symmetry + + sets 'b' to the corresponding 'basic' Densel and returns the symmetry transformation from 'basic' to 'b'. */ - virtual unique_ptr - find_symmetry_operation_from_basic_densel(Densel&) const = 0; + virtual unique_ptr find_symmetry_operation_from_basic_densel(Densel&) const = 0; /*! \brief given an arbitrary Densel 'b', find the basic Densel - + sets 'b' to the corresponding 'basic' Densel and returns true if 'b' is changed (i.e. it was NOT a basic Densel). */ - virtual bool - find_basic_densel(Densel& b) const; + virtual bool find_basic_densel(Densel& b) const; - protected: +protected: typedef DataSymmetriesForDensels root_type; - virtual bool blindly_equals(const root_type * const) const = 0; - + virtual bool blindly_equals(const root_type* const) const = 0; }; END_NAMESPACE_STIR //#include "stir/recon_buildblock/DataSymmetriesForDensels.inl" - #endif - diff --git a/src/include/stir/recon_buildblock/DataSymmetriesForDensels.inl b/src/include/stir/recon_buildblock/DataSymmetriesForDensels.inl index 242fe009b7..670a2767da 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForDensels.inl +++ b/src/include/stir/recon_buildblock/DataSymmetriesForDensels.inl @@ -8,7 +8,7 @@ \brief inline implementations for class stir::DataSymmetriesForDensels \author Kris Thielemans - + */ /* Copyright (C) 2001- 2009, Hammersmith Imanet Ltd @@ -31,16 +31,10 @@ START_NAMESPACE_STIR void -DataSymmetriesForDensels:: - get_related_densels(vector& rel_b, const Densel& b) const -{ - get_related_densels(rel_b, b, - proj_data_info_ptr->get_min_axial_pos_num(b.segment_num()), - proj_data_info_ptr->get_max_axial_pos_num(b.segment_num()), - proj_data_info_ptr->get_min_tangential_pos_num(), - proj_data_info_ptr->get_max_tangential_pos_num()); +DataSymmetriesForDensels::get_related_densels(vector& rel_b, const Densel& b) const { + get_related_densels(rel_b, b, proj_data_info_ptr->get_min_axial_pos_num(b.segment_num()), + proj_data_info_ptr->get_max_axial_pos_num(b.segment_num()), + proj_data_info_ptr->get_min_tangential_pos_num(), proj_data_info_ptr->get_max_tangential_pos_num()); } - - END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/DistributedCachingInformation.h b/src/include/stir/recon_buildblock/DistributedCachingInformation.h index e54c3b1c50..cdba6e8ce7 100644 --- a/src/include/stir/recon_buildblock/DistributedCachingInformation.h +++ b/src/include/stir/recon_buildblock/DistributedCachingInformation.h @@ -22,7 +22,7 @@ /*! \ingroup distributable - + \brief Declaration of class stir::DistributedCachingInformation \author Tobias Beisel @@ -40,39 +40,38 @@ START_NAMESPACE_STIR \ingroup distributable \brief This class implements the logic needed to support caching in a distributed manner. - To enable distributed caching, the master needs to store how the view segment numbers or the - related viewgrams respectively were distributed between the workers. Doing that, the master - is able to send those viegrams to a slave requesting for work, which that specific slave already - handled before and still has cached locally. + To enable distributed caching, the master needs to store how the view segment numbers or the + related viewgrams respectively were distributed between the workers. Doing that, the master + is able to send those viegrams to a slave requesting for work, which that specific slave already + handled before and still has cached locally. Additionally it is possible to only send the view segment number instead of the whole projection data, if the the worker stores the recieved related viewgrams. - + This class stores all needed information to determine a not yet processed view segment number - that will be sent to the requesting slave in such a way that the belonging data most likely - is stored in the slaves cache. - + that will be sent to the requesting slave in such a way that the belonging data most likely + is stored in the slaves cache. + The function \c get_unprocessed_vs_num() can be called by the master, passing the requesting worker and the current subset to determine the next processed view segment number - - The logic is a bit sophisticated, as it has to make sure, that every vs_num is + + The logic is a bit sophisticated, as it has to make sure, that every vs_num is only processed once and that load balancing is forced. T - + Process numbers are expected to be between 0 and \c num_workers - + Whether to use the cache enabled function or not can be set by the parsing parameter \verbatim enable distributed caching := 0 \endverbatim within the parameter specification for the objective function, where 1 activates it and 0 deactivates caching. The default is set to 0. - + */ -class DistributedCachingInformation -{ -public: +class DistributedCachingInformation { +public: //! constructor, calls initialise() explicit DistributedCachingInformation(const int num_processors); - + //! destructor to clean up data structures virtual ~DistributedCachingInformation(); @@ -83,31 +82,30 @@ class DistributedCachingInformation void initialise(); /*! \brief to be called at the beginning of the processing of a set of data * The caching data is kept, such that the cache will be re-used over multiple runs. - */ + */ void initialise_new_subiteration(const std::vector& vs_nums_to_process); - + /*! \brief get the next work-package for a given processor - * \warning this must only be called if there for sure is an unprocessed vs_num left, + * \warning this must only be called if there for sure is an unprocessed vs_num left, * otherwise it will call stir::error(). * \param[out] vs_num will be set accordingly * \param[in] proc the processor for which the View-Segment-Numbers are calculated * \return \c true if the vs_num was not in the cache of the processor * This function updates internal cache values etc. The user can just repeatedly call * the function without worrying about the caching algorithm. - */ + */ bool get_unprocessed_vs_num(ViewSegmentNumbers& vs_num, int proc); - -private: +private: //! Number of processors available int num_workers; //! stores which data that have to be processed in this subiteration - std::vector vs_nums_to_process; + std::vector vs_nums_to_process; + + //! stores the vs_nums in the cache of every processor + std::vector> proc_vs_nums; - //!stores the vs_nums in the cache of every processor - std::vector > proc_vs_nums; - //! marks the vs_num that still need to be processed /*! Has the same length as vs_nums_to_process */ std::vector still_to_process; @@ -117,7 +115,7 @@ class DistributedCachingInformation //! \brief find the first vs_num which has not be processed at all int find_position_of_first_unprocessed() const; - + //! count how many data-sets that are cached remain to be processed by processor \a proc int get_num_remaining_cached_data_to_process(int proc) const; @@ -136,33 +134,31 @@ class DistributedCachingInformation */ bool get_oldest_unprocessed_vs_num(ViewSegmentNumbers& vs_num, int proc) const; - /*! \brief gets a vs_num of the processor, which has the most work left - * \param proc processor that will not be checked (i.e. the one for which + * \param proc processor that will not be checked (i.e. the one for which * we are trying to find some work) - * - * this function is called if a processor requests work and already accomplished + * + * this function is called if a processor requests work and already accomplished * everything in its cache. Allocating work from the slave with most work left * encourages load balancing without having a lot of extra communicatrions. - * That way the probability of requesting already cached work is kept high. + * That way the probability of requesting already cached work is kept high. */ ViewSegmentNumbers get_vs_num_of_proc_with_most_work_left(int proc) const; - + /*! \brief set a ViewSegmentNumbers as already processed * \param vs_num the vs_num to be set processed */ void set_processed(const ViewSegmentNumbers& vs_num); - + /*! \brief reset all data to unprocessed */ void set_all_vs_num_unprocessed(); - + /*! \brief check if a vs_num is still to be processed or not * \param vs_num the view segment number to be checked * Also returns false if the \a vs_num is not in the list to process at all. */ bool is_still_to_be_processed(const ViewSegmentNumbers& vs_num) const; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/DistributedWorker.h b/src/include/stir/recon_buildblock/DistributedWorker.h index 8b0c8b9bb0..ca5c6e7c8c 100644 --- a/src/include/stir/recon_buildblock/DistributedWorker.h +++ b/src/include/stir/recon_buildblock/DistributedWorker.h @@ -17,27 +17,26 @@ */ #ifndef __stir_recon_buildblock_DistributedWorker_h__ -#define __stir_recon_buildblock_DistributedWorker_h__ - +# define __stir_recon_buildblock_DistributedWorker_h__ /*! - \file + \file \ingroup recon_buildblock - + \brief declares the stir::DistributedWorker class \author Tobias Beisel \author Kris Thielemans */ -#include "stir/shared_ptr.h" -#include "stir/TimedObject.h" +# include "stir/shared_ptr.h" +# include "stir/TimedObject.h" //#include "stir/ParsingObject.h" -#include "stir/ProjData.h" -#include "stir/recon_buildblock/ProjectorByBinPair.h" -#include "stir/recon_buildblock/distributable.h" -#include -#include +# include "stir/ProjData.h" +# include "stir/recon_buildblock/ProjectorByBinPair.h" +# include "stir/recon_buildblock/distributable.h" +# include +# include START_NAMESPACE_STIR @@ -49,16 +48,16 @@ class ExamInfo; The start() method is an infinite loop waiting for a task from the master. Very few tasks are implemented at the moment: set_up, compute, stop. - + The \c distributable_computation() function does the actual work. It is the slave-part - of stir::distributable_computation() which runs on the master. It is a loop receiving the related - viewgrams and calling an RPC_process_related_viewgrams_type function - with the received values. When an end_iteration_notification is received, it calls the + of stir::distributable_computation() which runs on the master. It is a loop receiving the related + viewgrams and calling an RPC_process_related_viewgrams_type function + with the received values. When an end_iteration_notification is received, it calls the reduction of the output_image. - - In each inner loop the worker first receives the vs_num and the information whether this is a - new viewgram or a previously received viewgram. The latter case only emerges if distributed caching is - enabled. If so, the worker does not have to receive the related viewgrams, but just gets it from + + In each inner loop the worker first receives the vs_num and the information whether this is a + new viewgram or a previously received viewgram. The latter case only emerges if distributed caching is + enabled. If so, the worker does not have to receive the related viewgrams, but just gets it from its saved viewgrams. \todo The log_likelihood_ptr argument to the RPC function is currently always NULL. @@ -67,73 +66,67 @@ class ExamInfo; */ template class DistributedWorker : public TimedObject //, public ParsingObject -{ - private: - +{ +private: double* log_likelihood_ptr; bool zero_seg0_end_planes; shared_ptr proj_pair_sptr; shared_ptr exam_info_sptr; shared_ptr proj_data_info_sptr; shared_ptr target_sptr; - - int image_buffer_size; //to save the image_size + + int image_buffer_size; // to save the image_size // cache variables bool cache_enabled; - shared_ptr proj_data_ptr; + shared_ptr proj_data_ptr; shared_ptr binwise_correction; shared_ptr mult_proj_data_sptr; - int my_rank; //rank of the worker + int my_rank; // rank of the worker - - public: - - //Default constructor +public: + // Default constructor DistributedWorker(); - - //Default destructor - ~DistributedWorker() ; - + + // Default destructor + ~DistributedWorker(); + /*! \brief Infinite loop waiting for tasks from the master */ void start(); - - protected: - + +protected: /*! - \brief sets defaults for this object + \brief sets defaults for this object */ void set_defaults(); /*! \brief Get basic information from the master. - - It sets up all needed objects by communicating with the - master. - + + It sets up all needed objects by communicating with the + master. + The following objects are set up: - bool zero_seg0_end_planes - target_image_sptr - ProjDataInfo pointer - ProjectorByBinPair pointer - ProjDataInMemory to save the received related viewgrams - - Additionally some values for testing are set up. - + + Additionally some values for testing are set up. + */ void setup_distributable_computation(); /*! \brief this does the actual computation corresponding to distributable_computation() */ - void distributable_computation(RPC_process_related_viewgrams_type * RPC_process_related_viewgrams); + void distributable_computation(RPC_process_related_viewgrams_type* RPC_process_related_viewgrams); }; - END_NAMESPACE_STIR #endif // __DistributedWorker_h__ - diff --git a/src/include/stir/recon_buildblock/FilterRootPrior.h b/src/include/stir/recon_buildblock/FilterRootPrior.h index 5b47f1215a..b8582889d8 100644 --- a/src/include/stir/recon_buildblock/FilterRootPrior.h +++ b/src/include/stir/recon_buildblock/FilterRootPrior.h @@ -29,29 +29,29 @@ #ifndef __stir_recon_buildblock_FilterRootPrior_H__ #define __stir_recon_buildblock_FilterRootPrior_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/recon_buildblock/GeneralisedPrior.h" #include "stir/shared_ptr.h" START_NAMESPACE_STIR -template class DataProcessor; +template +class DataProcessor; /*! \ingroup priors \brief - A class in the GeneralisedPrior hierarchy. This implements 'generalised' + A class in the GeneralisedPrior hierarchy. This implements 'generalised' priors a la the Median Root Prior (which was invented by Sakari Alenius). - This class takes an DataProcessor object (i.e. a filter), and computes + This class takes an DataProcessor object (i.e. a filter), and computes the prior 'gradient' as \f[ G_v = \beta ( {\lambda_v \over F_v} - 1) \f] where \f$ \lambda\f$ is the data where to compute the gradient, and \f$F\f$ is the data obtained by filtering \f$\lambda\f$. - However, we need to avoid division by 0, as it might cause a NaN or an + However, we need to avoid division by 0, as it might cause a NaN or an 'infinity'. So, we replace the quotient above by
    if \f$|\lambda_v| < M*|F_v| \f$ then \f${\lambda_v \over F_v}\f$ @@ -65,64 +65,46 @@ template class DataProcessor; of the gradient). For most (interesting) filters, the Hessian will no be symmetric. - The Median Root Prior is obtained by using a MedianImageFilter3D as + The Median Root Prior is obtained by using a MedianImageFilter3D as DataProcessor. */ template -class FilterRootPrior: public - RegisteredParsingObject< - FilterRootPrior, - GeneralisedPrior, - GeneralisedPrior - > -{ - private: - typedef - RegisteredParsingObject< - FilterRootPrior, - GeneralisedPrior, - GeneralisedPrior - > - base_type; +class FilterRootPrior : public RegisteredParsingObject, GeneralisedPrior, GeneralisedPrior> { +private: + typedef RegisteredParsingObject, GeneralisedPrior, GeneralisedPrior> base_type; + public: //! Name which will be used when parsing a GeneralisedPrior object - static const char * const registered_name; + static const char* const registered_name; //! Default constructor (no filter) FilterRootPrior(); //! Constructs it explicitly - FilterRootPrior(shared_ptr >const&, - const float penalization_factor); + FilterRootPrior(shared_ptr> const&, const float penalization_factor); - //! compute the value of the function + //! compute the value of the function /*! \warning Generally there is no function associated to this prior, so we just return 0 and write a warning the first time it's called. */ - virtual double - compute_value(const DataT ¤t_estimate); - + virtual double compute_value(const DataT& current_estimate); + //! compute gradient by applying the filter - void compute_gradient(DataT& prior_gradient, - const DataT ¤t_estimate); + void compute_gradient(DataT& prior_gradient, const DataT& current_estimate); //! Has to be called before using this object virtual Succeeded set_up(shared_ptr const& target_sptr); - -protected: +protected: //! Check that the prior is ready to be used virtual void check(DataT const& current_image_estimate) const; - -private: - shared_ptr > filter_ptr; - virtual void set_defaults(); - virtual void initialise_keymap(); +private: + shared_ptr> filter_ptr; + virtual void set_defaults(); + virtual void initialise_keymap(); }; - END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/recon_buildblock/ForwardProjectorByBin.h b/src/include/stir/recon_buildblock/ForwardProjectorByBin.h index 8d48846ae3..9c41e86456 100644 --- a/src/include/stir/recon_buildblock/ForwardProjectorByBin.h +++ b/src/include/stir/recon_buildblock/ForwardProjectorByBin.h @@ -7,7 +7,8 @@ \file \ingroup projection - \brief Base class for forward projectors which work on 'large' collections of bins: given the whole image, fill in a stir::RelatedViewgrams object. + \brief Base class for forward projectors which work on 'large' collections of bins: given the whole image, fill in a + stir::RelatedViewgrams object. \author Kris Thielemans \author Sanida Mustafovic @@ -38,123 +39,124 @@ #include "stir/TimedObject.h" #include "stir/VoxelsOnCartesianGrid.h" #include "stir/shared_ptr.h" +#include "stir/Bin.h" +#include "stir/recon_buildblock/ProjMatrixElemsForOneBin.h" START_NAMESPACE_STIR - -template class RelatedViewgrams; -template class DiscretisedDensity; +template +class RelatedViewgrams; +template +class DiscretisedDensity; class ProjDataInfo; class ProjData; class DataSymmetriesForViewSegmentNumbers; -template class DataProcessor; +template +class DataProcessor; /*! \ingroup projection \brief Abstract base class for all forward projectors */ -class ForwardProjectorByBin : - public TimedObject, - public RegisteredObject -{ +class ForwardProjectorByBin : public TimedObject, public RegisteredObject { public: - //! Default constructor calls reset_timers() - //inline - ForwardProjectorByBin(); + // inline + ForwardProjectorByBin(); //! Stores all necessary geometric info - /*! - If necessary, set_up() can be called more than once. + /*! + If necessary, set_up() can be called more than once. - Derived classes can assume that forward_project() will be called - with input corresponding to the arguments of the last call to set_up(). + Derived classes can assume that forward_project() will be called + with input corresponding to the arguments of the last call to set_up(). - \warning there is currently no check on this. - \warning Derived classes have to call set_up from the base class. - */ -virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_sptr // TODO should be Info only - ) =0; + \warning there is currently no check on this. + \warning Derived classes have to call set_up from the base class. + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_sptr // TODO should be Info only + ) = 0; //! Informs on which symmetries the projector handles /*! It should get data related by at least those symmetries. Otherwise, a run-time error will occur (unless the derived class has other behaviour). */ - virtual const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const = 0; + virtual const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const = 0; //! project the volume into the whole or a subset of proj_data, optionally zeroing the rest /*! it overwrites the data already present in the projection data. - - The optional arguments can be used to project only a subset of the data. + + The optional arguments can be used to project only a subset of the data. Subsets are determined as per detail::find_basic_vs_nums_in_subset(). However, this usage will likely be phased out at later stage.*/ - void forward_project(ProjData&, - const DiscretisedDensity<3,float>&, - int subset_num = 0, int num_subsets = 1, bool zero = true); + void forward_project(ProjData&, const DiscretisedDensity<3, float>&, int subset_num = 0, int num_subsets = 1, bool zero = true); #ifdef STIR_PROJECTORS_AS_V3 - //! project the volume into the viewgrams - /*! it overwrites the data already present in the viewgram */ - void forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&); - - void forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int min_axial_pos_num, const int max_axial_pos_num); - - void forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + //! project the volume into the viewgrams + /*! it overwrites the data already present in the viewgram */ + void forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>&); + + void forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>&, const int min_axial_pos_num, + const int max_axial_pos_num); + + void forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>&, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num); #endif - //! project the volume into the whole proj_data - /*! it overwrites the data already present in the projection data */ - virtual void forward_project(ProjData&, - int subset_num = 0, int num_subsets = 1, bool zero = true); + //! project the volume into the whole proj_data + /*! it overwrites the data already present in the projection data */ + virtual void forward_project(ProjData&, int subset_num = 0, int num_subsets = 1, bool zero = true); - //! project the volume into the viewgrams - /*! it overwrites the data already present in the viewgram */ - void forward_project(RelatedViewgrams&); + //! project the volume into the viewgrams + /*! it overwrites the data already present in the viewgram */ + void forward_project(RelatedViewgrams&); - void forward_project(RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num); + void forward_project(RelatedViewgrams&, const int min_axial_pos_num, const int max_axial_pos_num); - void forward_project(RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + void forward_project(RelatedViewgrams&, const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num); - virtual ~ForwardProjectorByBin(); +#if 0 // disabled as currently not used. needs to be written in the new style anyway + //! function mainly used in ListMode reconstruction. + /*! Calls actual_forward_project */ + void forward_project(Bin&, + const DiscretisedDensity<3,float>&); +#endif + virtual ~ForwardProjectorByBin(); - /// Set input - virtual void set_input(const DiscretisedDensity<3,float>&); + /// Set input + virtual void set_input(const DiscretisedDensity<3, float>&); - /// Set data processor to use before forward projection. MUST BE CALLED BEFORE SET_INPUT. - void set_pre_data_processor(shared_ptr > > pre_data_processor_sptr); + /// Set data processor to use before forward projection. MUST BE CALLED BEFORE SET_INPUT. + void set_pre_data_processor(shared_ptr>> pre_data_processor_sptr); protected: //! This virtual function has to be implemented by the derived class. - virtual void actual_forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); - - virtual void actual_forward_project(RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + virtual void actual_forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>&, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num); + + virtual void actual_forward_project(RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num); + +#if 0 // disabled as currently not used. needs to be written in the new style anyway + //! This virtual function has to be implemented by the derived class. + virtual void actual_forward_project(Bin&, + const DiscretisedDensity<3,float>&) = 0; +#endif //! check if the argument is the same as what was used for set_up() /*! calls error() if anything is wrong. If overriding this function in a derived class, you need to call this one. */ - virtual void check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3,float>& density_info) const; + virtual void check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3, float>& density_info) const; bool _already_set_up; //! The density ptr set with set_up() - shared_ptr > _density_sptr; - shared_ptr > > _pre_data_processor_sptr; + shared_ptr> _density_sptr; + shared_ptr>> _pre_data_processor_sptr; virtual void set_defaults(); virtual void initialise_keymap(); diff --git a/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h b/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h index c56f53efa5..ee7d5faebe 100644 --- a/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h +++ b/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h @@ -7,14 +7,14 @@ \file \ingroup projection - + \brief definition of stir::ForwardProjectorByBinUsingProjMatrixByBin - + \author Kris Thielemans \author Sanida Mustafovic \author Mustapha Sadki \author PARAPET project - + */ /* Copyright (C) 2000 PARAPET partners @@ -34,71 +34,58 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ProjMatrixByBin.h" #include "stir/recon_buildblock/ForwardProjectorByBin.h" #include "stir/RegisteredParsingObject.h" #include "stir/shared_ptr.h" - - START_NAMESPACE_STIR -template class RelatedViewgrams; +template +class RelatedViewgrams; /*! - \brief This implements the ForwardProjectorByBin interface, given any + \brief This implements the ForwardProjectorByBin interface, given any ProjMatrixByBin object \ingroup projection It stores a shared_ptr to a ProjMatrixByBin object, which will be used to get the relevant elements of the projection matrix. */ -class ForwardProjectorByBinUsingProjMatrixByBin: - public RegisteredParsingObject -{ +class ForwardProjectorByBinUsingProjMatrixByBin + : public RegisteredParsingObject { public: - //! Name which will be used when parsing a ForwardProjectorByBin object - static const char * const registered_name; + //! Name which will be used when parsing a ForwardProjectorByBin object + static const char* const registered_name; ForwardProjectorByBinUsingProjMatrixByBin(); - ForwardProjectorByBinUsingProjMatrixByBin( - const shared_ptr& proj_matrix_ptr - ); + ForwardProjectorByBinUsingProjMatrixByBin(const shared_ptr& proj_matrix_ptr); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); - - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const; + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const; - private: - shared_ptr proj_matrix_ptr; - + shared_ptr proj_matrix_ptr; - void actual_forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>& image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + void actual_forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>& image, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num); + +#if 0 // disabled as currently not used. needs to be written in the new style anyway + void actual_forward_project(Bin&, const DiscretisedDensity<3,float>&); +#endif virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - }; - END_NAMESPACE_STIR - #endif - - diff --git a/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h b/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h index 5efddda59c..947a2f1ada 100644 --- a/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h +++ b/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h @@ -4,12 +4,12 @@ \file \ingroup projection - + \brief Declaration of class stir::ForwardProjectorByBinUsingRayTracing - + \author Kris Thielemans \author PARAPET project - + */ /* Copyright (C) 2000 PARAPET partners @@ -39,29 +39,32 @@ #include "stir/shared_ptr.h" START_NAMESPACE_STIR -template class Viewgram; -template class RelatedViewgrams; -template class VoxelsOnCartesianGrid; -template class Array; +template +class Viewgram; +template +class RelatedViewgrams; +template +class VoxelsOnCartesianGrid; +template +class Array; class ProjDataInfo; class ProjDataInfoCylindrical; - /*! \ingroup projection \brief This class implements forward projection using Siddon's algorithm for ray tracing. That is, it computes length of intersection with the voxels. Currently, the LOIs are divided by voxel_size.x(), unless NEWSCALE is - #defined during compilation time of ForwardProjectorByBinUsingRayTracing_Siddon.cxx. + #defined during compilation time of ForwardProjectorByBinUsingRayTracing_Siddon.cxx. If the z voxel size is exactly twice the sampling in axial direction, multiple LORs are used, to avoid missing voxels. (TODOdoc describe how). - Currently, a FOV is used which is circular, and is slightly 'inside' the + Currently, a FOV is used which is circular, and is slightly 'inside' the image (i.e. the radius is about 1 voxel smaller than the maximum possible). - \warning Current implementation assumes that x,y voxel sizes are at least as + \warning Current implementation assumes that x,y voxel sizes are at least as large as the sampling in tangential direction, and that z voxel size is either equal to or exactly twice the sampling in axial direction of the segments. @@ -71,48 +74,43 @@ class ProjDataInfoCylindrical; \warning The implementation assumes that the \c s -coordinate is antisymmetric in terms of the tangential_pos_num, i.e. \code - proj_data_info_ptr->get_s(Bin(...,tang_pos_num)) == + proj_data_info_ptr->get_s(Bin(...,tang_pos_num)) == - proj_data_info_ptr->get_s(Bin(...,-tang_pos_num)) \endcode */ -class ForwardProjectorByBinUsingRayTracing : - public RegisteredParsingObject -{ +class ForwardProjectorByBinUsingRayTracing + : public RegisteredParsingObject { public: - //! Name which will be used when parsing a ForwardProjectorByBin object - static const char * const registered_name; - + //! Name which will be used when parsing a ForwardProjectorByBin object + static const char* const registered_name; ForwardProjectorByBinUsingRayTracing(); //! Constructor /*! \warning Obsolete */ - ForwardProjectorByBinUsingRayTracing( - const shared_ptr&, - const shared_ptr >&); + ForwardProjectorByBinUsingRayTracing(const shared_ptr&, + const shared_ptr>&); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); - virtual const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const; + virtual const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const; - protected: +protected: //! variable that determines if a cylindrical FOV or the whole image will be handled bool restrict_to_cylindrical_FOV; - private: - void actual_forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); - + void actual_forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>&, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num); +#if 0 // disabled as currently not used. needs to be written in the new style anyway + void actual_forward_project(Bin&, + const DiscretisedDensity<3,float>&); +#endif // KT 20/06/2001 changed type from 'const DataSymmetriesForViewSegmentNumbers *' shared_ptr symmetries_ptr; @@ -121,129 +119,86 @@ class ForwardProjectorByBinUsingRayTracing : Here 0<=view < num_views/4 (= 45 degrees) */ - void - forward_project_all_symmetries( - Viewgram & pos_view, - Viewgram & neg_view, - Viewgram & pos_plus90, - Viewgram & neg_plus90, - Viewgram & pos_min180, - Viewgram & neg_min180, - Viewgram & pos_min90, - Viewgram & neg_min90, - const VoxelsOnCartesianGrid& image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; - + void forward_project_all_symmetries(Viewgram& pos_view, Viewgram& neg_view, Viewgram& pos_plus90, + Viewgram& neg_plus90, Viewgram& pos_min180, Viewgram& neg_min180, + Viewgram& pos_min90, Viewgram& neg_min90, + const VoxelsOnCartesianGrid& image, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) const; /* This function projects 4 viewgrams related by symmetry. - It will be used for view=0 or 45 degrees + It will be used for view=0 or 45 degrees (or others if the number of views is not a multiple of 4) Here 0<=view < num_views/2 (= 90 degrees) */ - void - forward_project_view_plus_90_and_delta( - Viewgram & pos_view, - Viewgram & neg_view, - Viewgram & pos_plus90, - Viewgram & neg_plus90, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; + void forward_project_view_plus_90_and_delta(Viewgram& pos_view, Viewgram& neg_view, Viewgram& pos_plus90, + Viewgram& neg_plus90, const VoxelsOnCartesianGrid& image, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num) const; /* This function projects 4 viewgrams related by symmetry. - It will be used for view=0 or 45 degrees + It will be used for view=0 or 45 degrees (or others if the number of views is not a multiple of 4) Here 0<=view < num_views/2 (= 90 degrees) */ - void - forward_project_view_min_180_and_delta( - Viewgram & pos_view, - Viewgram & neg_view, - Viewgram & pos_min180, - Viewgram & neg_min180, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; + void forward_project_view_min_180_and_delta(Viewgram& pos_view, Viewgram& neg_view, Viewgram& pos_min180, + Viewgram& neg_min180, const VoxelsOnCartesianGrid& image, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num) const; /* This function projects 4 viewgrams related by symmetry. - It will be used for view=0 or 45 degrees + It will be used for view=0 or 45 degrees (or others if the number of views is not a multiple of 4) Here 0<=view < num_views/2 (= 90 degrees) */ - void - forward_project_delta( - Viewgram & pos_view, - Viewgram & neg_view, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; - - //////////////// 2D - void forward_project_all_symmetries_2D( - Viewgram & pos_view, - Viewgram & pos_plus90, - Viewgram & pos_min180, - Viewgram & pos_min90, - const VoxelsOnCartesianGrid& image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; - void -forward_project_view_plus_90_2D(Viewgram & pos_view, - Viewgram & pos_plus90, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; -void -forward_project_view_min_180_2D(Viewgram & pos_view, - Viewgram & pos_min180, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; -// no symmetries -void -forward_project_view_2D(Viewgram & pos_view, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; -#if defined(_MSC_VER) && _MSC_VER<1310 + void forward_project_delta(Viewgram& pos_view, Viewgram& neg_view, const VoxelsOnCartesianGrid& image, + const int min_axial_pos_num, const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) const; + + //////////////// 2D + void forward_project_all_symmetries_2D(Viewgram& pos_view, Viewgram& pos_plus90, Viewgram& pos_min180, + Viewgram& pos_min90, const VoxelsOnCartesianGrid& image, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num) const; + void forward_project_view_plus_90_2D(Viewgram& pos_view, Viewgram& pos_plus90, + const VoxelsOnCartesianGrid& image, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) const; + void forward_project_view_min_180_2D(Viewgram& pos_view, Viewgram& pos_min180, + const VoxelsOnCartesianGrid& image, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) const; + // no symmetries + void forward_project_view_2D(Viewgram& pos_view, const VoxelsOnCartesianGrid& image, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) const; +#if defined(_MSC_VER) && _MSC_VER < 1310 /* VC 6.0 (and 7.0 ?) cannot use the normal syntax unfortunately See also http://www.boost.org/more/microsoft_vcpp.html So, we forget about the template in this case. Sigh */ -#define STIR_SIDDON_NO_TEMPLATE +# define STIR_SIDDON_NO_TEMPLATE #endif #ifndef STIR_SIDDON_NO_TEMPLATE - //! The actual implementation of Siddon's algorithm - /*! \return true if the LOR intersected the image, i.e. of Projptr (potentially) changed */ - template - static bool - proj_Siddon(Array<4,float> &Projptr, const VoxelsOnCartesianGrid &, - const shared_ptr proj_data_info_sptr, - const float cphi, const float sphi, const float delta, - const float s_in_mm, - const float R, const int min_ax_pos_num, const int max_ax_pos_num, const float offset, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset, - const float norm_factor, - const bool restrict_to_cylindrical_FOV); + //! The actual implementation of Siddon's algorithm + /*! \return true if the LOR intersected the image, i.e. of Projptr (potentially) changed */ + template + static bool proj_Siddon(Array<4, float>& Projptr, const VoxelsOnCartesianGrid&, + const shared_ptr proj_data_info_sptr, const float cphi, const float sphi, + const float delta, const float s_in_mm, const float R, const int min_ax_pos_num, + const int max_ax_pos_num, const float offset, const int num_planes_per_axial_pos, + const float axial_pos_to_z_offset, const float norm_factor, const bool restrict_to_cylindrical_FOV); #else - static bool - proj_Siddon(int symmetry_type, - Array<4,float> &Projptr, const VoxelsOnCartesianGrid &, - const shared_ptr proj_data_info_ptr, - const float cphi, const float sphi, const float delta, - const float s_in_mm, - const float R, const int min_ax_pos_num, const int max_ax_pos_num, const float offset, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset, - const float norm_factor, - const bool restrict_to_cylindrical_FOV); + static bool proj_Siddon(int symmetry_type, Array<4, float>& Projptr, const VoxelsOnCartesianGrid&, + const shared_ptr proj_data_info_ptr, const float cphi, const float sphi, + const float delta, const float s_in_mm, const float R, const int min_ax_pos_num, + const int max_ax_pos_num, const float offset, const int num_planes_per_axial_pos, + const float axial_pos_to_z_offset, const float norm_factor, const bool restrict_to_cylindrical_FOV); #endif virtual void set_defaults(); diff --git a/src/include/stir/recon_buildblock/FourierRebinning.h b/src/include/stir/recon_buildblock/FourierRebinning.h index 398d78e45e..37eb438e0d 100644 --- a/src/include/stir/recon_buildblock/FourierRebinning.h +++ b/src/include/stir/recon_buildblock/FourierRebinning.h @@ -1,9 +1,9 @@ // // -/*! - \file - \brief Class for FORE Reconstruction +/*! + \file + \brief Class for FORE Reconstruction \ingroup recon_buildblock \author Claire LABBE \author Kris Thielemans @@ -38,48 +38,47 @@ #include "stir/RegisteredParsingObject.h" #include - START_NAMESPACE_STIR -template class SegmentByView; -template class SegmentBySinogram; -//template class Sinogram; -template class Array; +template +class SegmentByView; +template +class SegmentBySinogram; +// template class Sinogram; +template +class Array; class Succeeded; /* \class PETCount_rebinned - \brief Class for rebinned elements counter + \brief Class for rebinned elements counter \ingroup recon_buildblock */ -class PETCount_rebinned -{ - - public: -//! Total rebinned elements - int total; -//! Total missed rebinned elements - int miss; -//! Total SSRB rebinned elements - int ssrb; +class PETCount_rebinned { + +public: + //! Total rebinned elements + int total; + //! Total missed rebinned elements + int miss; + //! Total SSRB rebinned elements + int ssrb; #ifdef PARALLEL - friend PMessage& operator<<(PMessage&, PETCount_rebinned&); - friend PMessage& operator>>(PMessage&, PETCount_rebinned&); - - PETCount_rebinned & operator+= (const PETCount_rebinned &rebin) - { - total += rebin.total; - miss += rebin.miss; - ssrb += rebin.ssrb; - return *this; - } + friend PMessage& operator<<(PMessage&, PETCount_rebinned&); + friend PMessage& operator>>(PMessage&, PETCount_rebinned&); + + PETCount_rebinned& operator+=(const PETCount_rebinned& rebin) { + total += rebin.total; + miss += rebin.miss; + ssrb += rebin.ssrb; + return *this; + } #endif -// Default constructor by initialising all the elements conter to null - explicit PETCount_rebinned(int total_v=0, int miss_v =0, int ssrb_v = 0) - :total(total_v), miss(miss_v), ssrb(ssrb_v) - {} - - ; + // Default constructor by initialising all the elements conter to null + explicit PETCount_rebinned(int total_v = 0, int miss_v = 0, int ssrb_v = 0) + : total(total_v), miss(miss_v), ssrb(ssrb_v){} + + ; }; /*! @@ -92,140 +91,131 @@ class PETCount_rebinned a) Initialise the 2D Fourier transform of all rebinned sinograms Pr(w,k);
    b) Process sequentially each pair of oblique sinograms pij and pji for i,j (= 0..2*num_rings-2) as:
    - - merge pij and pji to get a sinogram sampled over 2p;
    - - calculates the 2D FFT Pij(w,k) of the merged sinogram;
    - - assign each frequency component (w,k) to the rebinned sinogram of the slice lying closest axially to - z - (tk/w): Pr(w,k) = Pr(w,k) + Pij(w,k), where r is the nearest integer to (i+j) - k(i-j)/wR;
    + - merge pij and pji to get a sinogram sampled over 2p;
    + - calculates the 2D FFT Pij(w,k) of the merged sinogram;
    + - assign each frequency component (w,k) to the rebinned sinogram of the slice lying closest axially to + z - (tk/w): Pr(w,k) = Pr(w,k) + Pij(w,k), where r is the nearest integer to (i+j) - k(i-j)/wR;
    c) Normalise Pr(w,k) for the variable number of contributions to each w, k, r ;
    d) Calculate the 2D inverse FFT of each Pr(w,k) to get the rebinned sinogram Pr(s,f); - As FORE is based on a high frequency approximation, it is necessary to handle separately low and high frequencies. - This is done by subdividing the (w,k) plane into three sub regions defined by two parameters - in Fourier space, w (the continuous frequency corresponding to the radial coordinates s) and k - (the integer Fourier index corresponding to the azimuthal angle f), and by applying in each region + As FORE is based on a high frequency approximation, it is necessary to handle separately low and high frequencies. + This is done by subdividing the (w,k) plane into three sub regions defined by two parameters + in Fourier space, w (the continuous frequency corresponding to the radial coordinates s) and k + (the integer Fourier index corresponding to the azimuthal angle f), and by applying in each region a different method to estimated the rebinned sinogram. - The rebinned data are represented in spatial space with |s|\<=R, 0<=f\=R; |w|\>wlim or |k|\>klim. - Finally, in the low-frequency (region 3), Fourier rebinning is not applicable. - Therefore the rebinned data are estimated using only the oblique sinograms with - a small value of d : dlim. Owing to the small value of d, the axial shift can be + Finally, in the low-frequency (region 3), Fourier rebinning is not applicable. + Therefore the rebinned data are estimated using only the oblique sinograms with + a small value of d : dlim. Owing to the small value of d, the axial shift can be neglected as in the SSRB approximation. */ -class FourierRebinning : public RegisteredParsingObject< - FourierRebinning, - ProjDataRebinning, - ProjDataRebinning> -{ - private: +class FourierRebinning : public RegisteredParsingObject { +private: typedef ProjDataRebinning base_type; - public: + +public: //! Name which will be used when parsing a ProjDataRebinning object - static const char * const registered_name; + static const char* const registered_name; virtual void set_defaults(); - protected: -//! Smallest angular freq. index minimum 2 ( 1 is zero frequency) - int kmin; -//! Smallest transax. freq. index minimum 2 ( 1 is zero frequency) - int wmin; -//! Delta max for small omega limiting delta for SSRB for small freq. - int deltamin; -//! kc index for consistency - int kc; -//! fore_debug_level. Setting it to >0 will produce some debug information - int fore_debug_level; - - public: -//! default constructor calls set_defaults(); - FourierRebinning(); - -//! This method returns the type of the algorithm for the rebinning - std::string method_info() const - { return("FORE"); } - - -//! This method creates a stack of 2D rebinned sinograms from the whole 3D data set (i.e. the ProjData data) and saves it. - Succeeded rebin(); - -//! A set of get and set utility functions to access the rebinning parameters - inline void set_kmin(int km){kmin = km;} - inline void set_wmin(int wm){wmin = wm;} - inline void set_deltamin(int dm){deltamin = dm;} - inline void set_kc(int kcc) {kc = kcc;} - inline void set_fore_debug_level(int fdebug){fore_debug_level = fdebug;} - - inline int get_kmin(){return kmin;} - inline int get_wmin(){return wmin;} - inline int get_deltamin(){return deltamin;} - inline int get_kc() {return kc;} - inline int get_fore_debug_level(){return fore_debug_level;} - - private: - -/*! - \brief Fourier rebinning - - This method takes as input the 3D data set (Array3D) in Fourier space of one sinogram - for a given delta as the data dimension are (1,fft_size,nviews_pow2), the scanner informations - and returns the updated stack of 2D rebinned sinograms still in Fourier space, - the updated weigthing factors as well as the new rebinned elements counter. - - -*/ - void rebinning(Array<3,std::complex > &FT_rebinned_data, Array<3,float> &Weights_for_FT_rebinned_data, - PETCount_rebinned &num_rebinned, const Array<2,std::complex > &FT_current_sinogram, const float z, - const float average_ring_difference_in_segment, const int num_views_pow2, const int num_tang_poss_pow2, - const float half_distance_between_rings, const float sampling_distance_in_s, const float radial_sampling_freq_w, - const float R_field_of_view_mm, const float ratio_ring_spacing_to_ring_radius); - -/*! - \brief This method takes as input the real 3D data set - (in which the number of views have been extended to a number of power of 2) - and returns the rebinned sinograms in Fourier space, their weighting factors - as well as the counter rebinned elements - - \b Rebinning
    - Assign each frequency component (w,k) to the rebinned sinogram of the slice lying closest axially to - z - (tk/w) with t=((ring0 -ring1)*ring_spacing/(2*R) with R=ring_radius, - Pm(w,k) = Pm(w,k) + Pij(w,k) (i=ring0 and j=ring1), and m is the nearest integer to (i+j) -k(i-j)/(Rw)). -*/ - - void do_rebinning(Array<3,std::complex > &FT_rebinned_data, Array<3,float> &Weights_for_FT_rebinned_data, - PETCount_rebinned &count_rebinned, const SegmentBySinogram &segment, const int num_tang_poss_pow2, - const int num_views_pow2, const int num_planes, const float average_ring_difference_in_segment, - const float half_distance_between_rings, const float sampling_distance_in_s, - const float radial_sampling_freq_w, const float R_field_of_view_mm, - const float ratio_ring_spacing_to_ring_radius); - -/*! - This method takes as input the information of the 3D data set (ProjData) - as well as the reconstruction parameters and prints out the informations of reconstruction - parameters implemented in FORE as well as the CPU and relative timing of differents process - (i.e I/O, rebinning, backprojection, matrix handling). - fore_debug_level must be set to a integer value > 0 -*/ - void do_log_file(); - -//! This is a function to display the current counter of all rebinned elements - void do_display_count(PETCount_rebinned &num_rebinned_total); - - -//! This is a function to adjust the number of views of a segment to the next power of 2 - void do_adjust_nb_views_to_pow2(SegmentBySinogram &segment) ; - -//! This function checks if the steering and input paramters for FORE are inside the possible range of parameters - Succeeded fore_check_parameters(int num_tang_poss_pow2, int num_views_pow2, int max_segment_num_to_process); - - - protected: - virtual bool post_processing(); +protected: + //! Smallest angular freq. index minimum 2 ( 1 is zero frequency) + int kmin; + //! Smallest transax. freq. index minimum 2 ( 1 is zero frequency) + int wmin; + //! Delta max for small omega limiting delta for SSRB for small freq. + int deltamin; + //! kc index for consistency + int kc; + //! fore_debug_level. Setting it to >0 will produce some debug information + int fore_debug_level; + +public: + //! default constructor calls set_defaults(); + FourierRebinning(); + + //! This method returns the type of the algorithm for the rebinning + std::string method_info() const { return ("FORE"); } + + //! This method creates a stack of 2D rebinned sinograms from the whole 3D data set (i.e. the ProjData data) and saves it. + Succeeded rebin(); + + //! A set of get and set utility functions to access the rebinning parameters + inline void set_kmin(int km) { kmin = km; } + inline void set_wmin(int wm) { wmin = wm; } + inline void set_deltamin(int dm) { deltamin = dm; } + inline void set_kc(int kcc) { kc = kcc; } + inline void set_fore_debug_level(int fdebug) { fore_debug_level = fdebug; } + + inline int get_kmin() { return kmin; } + inline int get_wmin() { return wmin; } + inline int get_deltamin() { return deltamin; } + inline int get_kc() { return kc; } + inline int get_fore_debug_level() { return fore_debug_level; } + +private: + /*! + \brief Fourier rebinning + + This method takes as input the 3D data set (Array3D) in Fourier space of one sinogram + for a given delta as the data dimension are (1,fft_size,nviews_pow2), the scanner informations + and returns the updated stack of 2D rebinned sinograms still in Fourier space, + the updated weigthing factors as well as the new rebinned elements counter. + + + */ + void rebinning(Array<3, std::complex>& FT_rebinned_data, Array<3, float>& Weights_for_FT_rebinned_data, + PETCount_rebinned& num_rebinned, const Array<2, std::complex>& FT_current_sinogram, const float z, + const float average_ring_difference_in_segment, const int num_views_pow2, const int num_tang_poss_pow2, + const float half_distance_between_rings, const float sampling_distance_in_s, const float radial_sampling_freq_w, + const float R_field_of_view_mm, const float ratio_ring_spacing_to_ring_radius); + + /*! + \brief This method takes as input the real 3D data set + (in which the number of views have been extended to a number of power of 2) + and returns the rebinned sinograms in Fourier space, their weighting factors + as well as the counter rebinned elements + + \b Rebinning
    + Assign each frequency component (w,k) to the rebinned sinogram of the slice lying closest axially to + z - (tk/w) with t=((ring0 -ring1)*ring_spacing/(2*R) with R=ring_radius, + Pm(w,k) = Pm(w,k) + Pij(w,k) (i=ring0 and j=ring1), and m is the nearest integer to (i+j) -k(i-j)/(Rw)). + */ + + void do_rebinning(Array<3, std::complex>& FT_rebinned_data, Array<3, float>& Weights_for_FT_rebinned_data, + PETCount_rebinned& count_rebinned, const SegmentBySinogram& segment, const int num_tang_poss_pow2, + const int num_views_pow2, const int num_planes, const float average_ring_difference_in_segment, + const float half_distance_between_rings, const float sampling_distance_in_s, + const float radial_sampling_freq_w, const float R_field_of_view_mm, + const float ratio_ring_spacing_to_ring_radius); + + /*! + This method takes as input the information of the 3D data set (ProjData) + as well as the reconstruction parameters and prints out the informations of reconstruction + parameters implemented in FORE as well as the CPU and relative timing of differents process + (i.e I/O, rebinning, backprojection, matrix handling). + fore_debug_level must be set to a integer value > 0 + */ + void do_log_file(); + + //! This is a function to display the current counter of all rebinned elements + void do_display_count(PETCount_rebinned& num_rebinned_total); + + //! This is a function to adjust the number of views of a segment to the next power of 2 + void do_adjust_nb_views_to_pow2(SegmentBySinogram& segment); + + //! This function checks if the steering and input paramters for FORE are inside the possible range of parameters + Succeeded fore_check_parameters(int num_tang_poss_pow2, int num_views_pow2, int max_segment_num_to_process); + +protected: + virtual bool post_processing(); virtual void initialise_keymap(); - }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/GeneralisedObjectiveFunction.h b/src/include/stir/recon_buildblock/GeneralisedObjectiveFunction.h index 4a88abab4e..1c4f3fdf00 100644 --- a/src/include/stir/recon_buildblock/GeneralisedObjectiveFunction.h +++ b/src/include/stir/recon_buildblock/GeneralisedObjectiveFunction.h @@ -3,6 +3,7 @@ /* Copyright (C) 2003- 2009, Hammersmith Imanet Ltd Copyright (C) 2018, University College London + Copyright (C) 2016, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -22,6 +23,7 @@ \ingroup GeneralisedObjectiveFunction \brief Declaration of class stir::GeneralisedObjectiveFunction + \author Nikos Efthimiou \author Kris Thielemans \author Sanida Mustafovic @@ -29,7 +31,6 @@ #ifndef __stir_recon_buildblock_GeneralisedObjectiveFunction_H__ #define __stir_recon_buildblock_GeneralisedObjectiveFunction_H__ - #include "stir/RegisteredObject.h" #include "stir/ParsingObject.h" #include "stir/shared_ptr.h" @@ -42,20 +43,19 @@ START_NAMESPACE_STIR - class Succeeded; /*! \ingroup GeneralisedObjectiveFunction \brief A base class for 'generalised' objective functions, i.e. objective - functions for which at least a 'gradient' is defined. + functions for which at least a 'gradient' is defined. - Some iterative algorithms use an 'objective function' only in a - loose sense. They might for instance allow generalisations + Some iterative algorithms use an 'objective function' only in a + loose sense. They might for instance allow generalisations which no longer optimise a function. For example in the case of PoissonLogLikelihoodWithLinearModelForMeanAndProjData - with non-matching forward and back projectors, the 'gradient' + with non-matching forward and back projectors, the 'gradient' that is computed is generally not the gradient of the log-likelihood that corresponds to the forward projector. However, one hopes that it still points towards the optimum. @@ -68,7 +68,7 @@ class Succeeded; In tomography, we often use subsets, where the objective function is written as a sum of sub-objective functions. This class has some - subset functionality. When using subsets, the + subset functionality. When using subsets, the penalty will be distributed evenly over all subsets. While this increases the computational cost, it makes the subsets more 'balanced' which is best for most algorithms. @@ -87,97 +87,76 @@ class Succeeded; \endverbatim */ template -class GeneralisedObjectiveFunction: - public RegisteredObject > -{ +class GeneralisedObjectiveFunction : public RegisteredObject> { public: - - //GeneralisedObjectiveFunction(); - - virtual ~GeneralisedObjectiveFunction(); + // GeneralisedObjectiveFunction(); + virtual ~GeneralisedObjectiveFunction(); //! Creates a suitable target as determined by the parameters - virtual TargetT * - construct_target_ptr() const = 0; + virtual TargetT* construct_target_ptr() const = 0; //! Has to be called before using this object - virtual Succeeded - set_up(shared_ptr const& target_sptr); + virtual Succeeded set_up(shared_ptr const& target_sptr); //! This should compute the sub-gradient of the objective function at the \a current_estimate /*! The subgradient is the gradient of the objective function restricted to the subset specified. What this means depends on how this function is implemented later on in the hierarchy. - Computed as the difference of + Computed as the difference of compute_sub_gradient_without_penalty - and + and get_prior_ptr()->compute_gradient()/num_subsets. \warning Any data in \a gradient will be overwritten. */ - virtual void - compute_sub_gradient(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num); + virtual void compute_sub_gradient(TargetT& gradient, const TargetT& current_estimate, const int subset_num); //! This should compute the sub-gradient of the unregularised objective function at the \a current_estimate - /*! + /*! \warning The derived class should overwrite any data in \a gradient. */ - virtual void - compute_sub_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) =0; + virtual void compute_sub_gradient_without_penalty(TargetT& gradient, const TargetT& current_estimate, const int subset_num) = 0; //! Compute the value of the unregularised sub-objective function at the \a current_estimate /*! Implemented in terms of actual_compute_objective_function_without_penalty. */ - virtual double - compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num); + virtual double compute_objective_function_without_penalty(const TargetT& current_estimate, const int subset_num); //! Compute the value of the unregularised objective function at the \a current_estimate /*! Computed by summing over all subsets. */ - virtual double - compute_objective_function_without_penalty(const TargetT& current_estimate); + virtual double compute_objective_function_without_penalty(const TargetT& current_estimate); //! Compute the value of the sub-penalty at the \a current_estimate /*! As each subset contains the same penalty, this function returns - the same as + the same as \code - compute_penalty(current_estimate)/num_subsets + compute_penalty(current_estimate)/num_subsets \endcode Implemented in terms of GeneralisedPrior::compute_value. \see compute_objective_function(const TargetT&) for sign conventions. */ - double - compute_penalty(const TargetT& current_estimate, - const int subset_num); + double compute_penalty(const TargetT& current_estimate, const int subset_num); //! Compute the value of the penalty at the \a current_estimate /*! Implemented in terms of GeneralisedPrior::compute_value. */ - double - compute_penalty(const TargetT& current_estimate); + double compute_penalty(const TargetT& current_estimate); //! Compute the value of the sub-objective function at the \a current_estimate - /*! Computed as the difference of + /*! Computed as the difference of compute_objective_function_without_penalty - and + and compute_penalty. - */ - double - compute_objective_function(const TargetT& current_estimate, - const int subset_num); + */ + double compute_objective_function(const TargetT& current_estimate, const int subset_num); //! Compute the value of the objective function at the \a current_estimate - /*! Computed as the difference of + /*! Computed as the difference of compute_objective_function_without_penalty - and + and compute_penalty. - */ - double - compute_objective_function(const TargetT& current_estimate); + */ + double compute_objective_function(const TargetT& current_estimate); //! Fill any elements that we cannot estimate with a fixed value /*! In many cases, it is easier to use a larger target than what we can @@ -193,86 +172,62 @@ class GeneralisedObjectiveFunction: \todo The type of the value should really be derived from e.g. TargetT::full_iterator. */ - virtual void - fill_nonidentifiable_target_parameters(TargetT& target, const float value ) const - {} + virtual void fill_nonidentifiable_target_parameters(TargetT& target, const float value) const {} //! \name multiplication with approximate (sub)Hessian /*! \brief Functions that multiply the approximate (sub)Hessian with a \'vector\'. - + All these functions add their result to any existing data in \a output. They all call actual_add_multiplication_with_approximate_sub_Hessian_without_penalty. */ //@{ - Succeeded - add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const; - Succeeded - add_multiplication_with_approximate_sub_Hessian(TargetT& output, - const TargetT& input, - const int subset_num) const; - Succeeded - add_multiplication_with_approximate_Hessian_without_penalty(TargetT& output, - const TargetT& input) const; - Succeeded - add_multiplication_with_approximate_Hessian(TargetT& output, - const TargetT& input) const; + Succeeded add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, const TargetT& input, + const int subset_num) const; + Succeeded add_multiplication_with_approximate_sub_Hessian(TargetT& output, const TargetT& input, const int subset_num) const; + Succeeded add_multiplication_with_approximate_Hessian_without_penalty(TargetT& output, const TargetT& input) const; + Succeeded add_multiplication_with_approximate_Hessian(TargetT& output, const TargetT& input) const; //@} - //! \name multiplication (sub)Hessian times input - /*! \brief Functions that multiply the True (sub)Hessian with a \'vector\'. - - All these functions add their result to any existing data in \a output. - - They all call actual_accumulate_sub_Hessian_times_input_without_penalty. - */ - //@{ - Succeeded - accumulate_Hessian_times_input(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input) const; - - Succeeded - accumulate_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input) const; + //! \name multiplication (sub)Hessian times input + /*! \brief Functions that multiply the True (sub)Hessian with a \'vector\'. + All these functions add their result to any existing data in \a output. - Succeeded - accumulate_sub_Hessian_times_input(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input, - const int subset_num) const; - Succeeded - accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input, - const int subset_num) const; + They all call actual_accumulate_sub_Hessian_times_input_without_penalty. + */ + //@{ + Succeeded accumulate_Hessian_times_input(TargetT& output, const TargetT& current_image_estimate, const TargetT& input) const; - //@} + Succeeded accumulate_Hessian_times_input_without_penalty(TargetT& output, const TargetT& current_image_estimate, + const TargetT& input) const; + Succeeded accumulate_sub_Hessian_times_input(TargetT& output, const TargetT& current_image_estimate, const TargetT& input, + const int subset_num) const; + Succeeded accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, const TargetT& current_image_estimate, + const TargetT& input, const int subset_num) const; + //@} //! Construct a string with info on the value of objective function with and without penalty - std::string - get_objective_function_values_report(const TargetT& current_estimate); + std::string get_objective_function_values_report(const TargetT& current_estimate); //! Return the number of subsets in-use int get_num_subsets() const; - -// //! Virtual get normalisation, it will be defined by the derived class -// virtual const shared_ptr & -// get_normalisation_sptr() const =0; - - virtual std::unique_ptr get_exam_info_uptr_for_target() const - { auto exam_info_uptr=unique_ptr(new ExamInfo(*(this->get_input_data().get_exam_info_sptr()))); - return exam_info_uptr; + + // //! Virtual get normalisation, it will be defined by the derived class + // virtual const shared_ptr & + // get_normalisation_sptr() const =0; + + virtual std::unique_ptr get_exam_info_uptr_for_target() const { + auto exam_info_uptr = unique_ptr(new ExamInfo(*(this->get_input_data().get_exam_info_sptr()))); + return exam_info_uptr; } + //! Return the status of TOF + bool get_tof_status() const; - //! Attempts to change the number of subsets. + //! Attempts to change the number of subsets. /*! \return The number of subsets that will be used later, which is not guaranteed to be what you asked for. */ virtual int set_num_subsets(const int num_subsets) = 0; @@ -283,12 +238,12 @@ class GeneralisedObjectiveFunction: This function tests if this is approximately true, such that a reconstruction algorithm can either adapt or abort. - + Implemented in terms of actual_subsets_are_approximately_balanced(std::string&). */ bool subsets_are_approximately_balanced() const; //! Checks of the current subset scheme is approximately balanced and constructs a warning message - /*! + /*! \see subsets_are_approximately_balanced() \param warning_message A string variable. If the subsets are not (approx.) balanced, this function will append @@ -301,23 +256,21 @@ class GeneralisedObjectiveFunction: //! Read-only access to the prior /*! \todo It would be nicer to not return a pointer. - */ - GeneralisedPrior * const - get_prior_ptr() const; + */ + GeneralisedPrior* const get_prior_ptr() const; - shared_ptr > - get_prior_sptr(); + shared_ptr> get_prior_sptr(); //! Change the prior /*! \warning You should call set_up() again after using this function. */ - void set_prior_sptr(const shared_ptr >&); + void set_prior_sptr(const shared_ptr>&); //! \brief set_input_data //! \author Nikos Efthimiou //! \details It can be used to set the data to be reconstructed //! within some other code, as opposed to via parsing. - virtual void set_input_data(const shared_ptr< ExamData > &) = 0; + virtual void set_input_data(const shared_ptr&) = 0; //! \brief get input data /*! Will throw an exception if it wasn't set first */ @@ -328,7 +281,7 @@ class GeneralisedObjectiveFunction: //! \details In the case the reconstruction process is called from another //! piece of code, the user should be able to set any additive sinogram //! - virtual void set_additive_proj_data_sptr(const shared_ptr&) = 0; + virtual void set_additive_proj_data_sptr(const shared_ptr&) = 0; //! \brief set_normalisation_sptr //! \author Nikos Efthimiou @@ -339,7 +292,10 @@ class GeneralisedObjectiveFunction: protected: int num_subsets; - shared_ptr > prior_sptr; + //! If set TOF information will be taken into account. + bool use_tof; + + shared_ptr> prior_sptr; //! sets any default values /*! Has to be called by set_defaults in the leaf-class */ @@ -348,7 +304,7 @@ class GeneralisedObjectiveFunction: /*! Has to be called by initialise_keymap in the leaf-class */ virtual void initialise_keymap(); - //virtual bool post_processing(); + // virtual bool post_processing(); //! Implementation of function that checks subset balancing /*! @@ -356,7 +312,7 @@ class GeneralisedObjectiveFunction: \par Developer\'s note - The reason we have this function is that overloading + The reason we have this function is that overloading subsets_are_approximately_balanced(std::string&) in a derived class would hide subsets_are_approximately_balanced(). */ @@ -368,13 +324,11 @@ class GeneralisedObjectiveFunction: \par Developer\'s note - The reason we have this function is that overloading a function - in a derived class, hides all functions of the + The reason we have this function is that overloading a function + in a derived class, hides all functions of the same name. */ - virtual double - actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num) = 0; + virtual double actual_compute_objective_function_without_penalty(const TargetT& current_estimate, const int subset_num) = 0; //! Implementation of the function that multiplies the approximate sub-Hessian with a vector. /*! @@ -385,33 +339,29 @@ class GeneralisedObjectiveFunction: \par Developer\'s note - The reason we have this function is that overloading a function - in a derived class, hides all functions of the + The reason we have this function is that overloading a function + in a derived class, hides all functions of the + same name. + */ + virtual Succeeded actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, const TargetT& input, + const int subset_num) const; + + //! Implementation of the function computes the sub-Hessian and multiplies by a vector. + /*! + \see accumulate_sub_Hessian_times_input_without_penalty(TargetT&,const TargetT&, TargetT&, const int). + + \warning The default implementation just calls error(). This behaviour has to be + overloaded by the derived classes. + + \par Developer\'s note + + The reason we have this function is that overloading a function + in a derived class, hides all functions of the same name. */ - virtual Succeeded - actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const; - - //! Implementation of the function computes the sub-Hessian and multiplies by a vector. - /*! - \see accumulate_sub_Hessian_times_input_without_penalty(TargetT&,const TargetT&, TargetT&, const int). - - \warning The default implementation just calls error(). This behaviour has to be - overloaded by the derived classes. - - \par Developer\'s note - - The reason we have this function is that overloading a function - in a derived class, hides all functions of the - same name. - */ - virtual Succeeded - actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input, - const int subset_num) const; + virtual Succeeded actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, + const TargetT& current_image_estimate, + const TargetT& input, const int subset_num) const; }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/GeneralisedPrior.h b/src/include/stir/recon_buildblock/GeneralisedPrior.h index 7e94a23fe1..dc3a7cc463 100644 --- a/src/include/stir/recon_buildblock/GeneralisedPrior.h +++ b/src/include/stir/recon_buildblock/GeneralisedPrior.h @@ -29,7 +29,6 @@ #ifndef __stir_recon_buildblock_GeneralisedPrior_H__ #define __stir_recon_buildblock_GeneralisedPrior_H__ - #include "stir/RegisteredObject.h" #include "stir/ParsingObject.h" @@ -41,32 +40,28 @@ class Succeeded; \ingroup priors \brief A base class for 'generalised' priors, i.e. priors for which at least - a 'gradient' is defined. + a 'gradient' is defined. This class exists to accomodate FilterRootPrior. Otherwise we could just live with Prior as a base class. */ template -class GeneralisedPrior: - public RegisteredObject > - +class GeneralisedPrior : public RegisteredObject> + { public: - - inline GeneralisedPrior(); + inline GeneralisedPrior(); //! compute the value of the function /*! For derived classes where this doesn't make sense, it's recommended to return 0. */ - virtual double - compute_value(const DataT ¤t_estimate) = 0; + virtual double compute_value(const DataT& current_estimate) = 0; //! This should compute the gradient of the log of the prior function at the \a current_estimate /*! The gradient is already multiplied with the penalisation_factor. \warning The derived class should overwrite any data in \a prior_gradient. */ - virtual void compute_gradient(DataT& prior_gradient, - const DataT ¤t_estimate) =0; + virtual void compute_gradient(DataT& prior_gradient, const DataT& current_estimate) = 0; //! This should compute the multiplication of the Hessian with a vector and add it to \a output /*! Default implementation just call error(). This function needs to be overridden by the @@ -75,27 +70,20 @@ class GeneralisedPrior: Instead, accumulate_Hessian_times_input() should be used. This method remains for backwards comparability. \warning The derived class should accumulate in \a output. */ - virtual Succeeded - add_multiplication_with_approximate_Hessian(DataT& output, - const DataT& input) const; - - //! This should compute the multiplication of the Hessian with a vector and add it to \a output - /*! Default implementation just call error(). This function needs to be overridden by the - derived class. - \warning The derived class should accumulate in \a output. - */ - virtual Succeeded - accumulate_Hessian_times_input(DataT& output, - const DataT& current_estimate, - const DataT& input) const; + virtual Succeeded add_multiplication_with_approximate_Hessian(DataT& output, const DataT& input) const; + //! This should compute the multiplication of the Hessian with a vector and add it to \a output + /*! Default implementation just call error(). This function needs to be overridden by the + derived class. + \warning The derived class should accumulate in \a output. + */ + virtual Succeeded accumulate_Hessian_times_input(DataT& output, const DataT& current_estimate, const DataT& input) const; inline float get_penalisation_factor() const; inline void set_penalisation_factor(float new_penalisation_factor); //! Has to be called before using this object - virtual Succeeded - set_up(shared_ptr const& target_sptr); + virtual Succeeded set_up(shared_ptr const& target_sptr); protected: float penalisation_factor; diff --git a/src/include/stir/recon_buildblock/GeneralisedPrior.inl b/src/include/stir/recon_buildblock/GeneralisedPrior.inl index 9a84a21261..9fcc0df525 100644 --- a/src/include/stir/recon_buildblock/GeneralisedPrior.inl +++ b/src/include/stir/recon_buildblock/GeneralisedPrior.inl @@ -28,25 +28,21 @@ START_NAMESPACE_STIR - template -GeneralisedPrior::GeneralisedPrior() -{ - penalisation_factor =0; +GeneralisedPrior::GeneralisedPrior() { + penalisation_factor = 0; } - template float -GeneralisedPrior:: -get_penalisation_factor() const -{ return penalisation_factor; } +GeneralisedPrior::get_penalisation_factor() const { + return penalisation_factor; +} template void -GeneralisedPrior:: -set_penalisation_factor(const float new_penalisation_factor) -{ penalisation_factor = new_penalisation_factor; } +GeneralisedPrior::set_penalisation_factor(const float new_penalisation_factor) { + penalisation_factor = new_penalisation_factor; +} END_NAMESPACE_STIR - diff --git a/src/include/stir/recon_buildblock/IterativeReconstruction.h b/src/include/stir/recon_buildblock/IterativeReconstruction.h index 28e0b23fd6..f587193335 100644 --- a/src/include/stir/recon_buildblock/IterativeReconstruction.h +++ b/src/include/stir/recon_buildblock/IterativeReconstruction.h @@ -19,12 +19,12 @@ See STIR/LICENSE.txt for details */ #ifndef __stir_recon_buildblock_IterativeReconstruction_h__ -#define __stir_recon_buildblock_IterativeReconstruction_h__ +# define __stir_recon_buildblock_IterativeReconstruction_h__ /*! - \file + \file \ingroup recon_buildblock - + \brief declares the stir::IterativeReconstruction class @@ -39,42 +39,42 @@ KT 10122001 - added get_initial_data_ptr and 0 argument reconstruct() */ -#include "stir/recon_buildblock/Reconstruction.h" -#include "stir/shared_ptr.h" -#include "stir/DataProcessor.h" -#include "stir/recon_buildblock/GeneralisedObjectiveFunction.h" +# include "stir/recon_buildblock/Reconstruction.h" +# include "stir/shared_ptr.h" +# include "stir/DataProcessor.h" +# include "stir/recon_buildblock/GeneralisedObjectiveFunction.h" START_NAMESPACE_STIR -/*! +/*! \brief base class for iterative reconstruction objects \ingroup recon_buildblock This is the base class for all iterative reconstruction methods. It provides the basic iteration mechanisms. What each iteration does has to be implemented in a derived class. - + \par Parsing parameters \verbatim ; any parameters from Reconstruction ; see GeneralisedObjectiveFunction - objective function type:= + objective function type:= + - number of subsets:= 1 start at subset:= 0 number of subiterations:= 1 save images at subiteration intervals:= 1 start at subiteration number:=2 - initial image := + initial image := enforce initial positivity condition:=1 ; specify processing after every few subiterations, see DataProcessor - inter-iteration filter subiteration interval:= - inter-iteration filter type := + inter-iteration filter subiteration interval:= + inter-iteration filter type := ; write objective function value to stderr at certain subiterations ; default value of 0 means: do not write it at all. @@ -86,17 +86,13 @@ START_NAMESPACE_STIR */ template -class IterativeReconstruction : public Reconstruction -{ - private: - typedef - Reconstruction - base_type; -public: +class IterativeReconstruction : public Reconstruction { +private: + typedef Reconstruction base_type; +public: //! accessor for the subiteration counter - int get_subiteration_num() const - {return subiteration_num;} + int get_subiteration_num() const { return subiteration_num; } //! accessor for finding the current subset number /*! The subset number is determined from the subiteration number. @@ -112,16 +108,15 @@ class IterativeReconstruction : public Reconstruction int get_subset_num(); //! Gets a pointer to the initial data - /*! This is either read from file, or constructed by construct_target_ptr(). + /*! This is either read from file, or constructed by construct_target_ptr(). In the latter case, its values are set to 0 or 1, depending on the value of IterativeReconstruction::initial_data_filename. - \todo Dependency on explicit strings "1" or "0" in - IterativeReconstruction::initial_data_filename is not nice. + \todo Dependency on explicit strings "1" or "0" in + IterativeReconstruction::initial_data_filename is not nice. \todo should not return a 'bare' pointer. */ - virtual TargetT * - get_initial_data_ptr() const; + virtual TargetT* get_initial_data_ptr() const; //! executes the reconstruction /*! @@ -130,9 +125,8 @@ class IterativeReconstruction : public Reconstruction See end_of_iteration_processing() for info on saving to file. \return Succeeded::yes if everything was alright. - */ - virtual Succeeded - reconstruct(); + */ + virtual Succeeded reconstruct(); //! executes the reconstruction with \a target_data_sptr as initial value /*! After calling set_up(), repeatedly calls update_estimate(); end_of_iteration_processing(); @@ -140,31 +134,26 @@ class IterativeReconstruction : public Reconstruction Final reconstruction is saved in \a target_data_sptr */ - virtual Succeeded - reconstruct(shared_ptr const& target_data_sptr); + virtual Succeeded reconstruct(shared_ptr const& target_data_sptr); //! A utility function that creates a filename_prefix by appending the current subiteration number /*! Only works when no extension is present. - */ - std::string - make_filename_prefix_subiteration_num(const std::string& filename_prefix) const; + */ + std::string make_filename_prefix_subiteration_num(const std::string& filename_prefix) const; //! A utility function that creates the output filename_prefix for the current subiteration number /*! Uses \a output_filename_prefix. Only works when no extension is present. */ - std::string - make_filename_prefix_subiteration_num() const; + std::string make_filename_prefix_subiteration_num() const; /*! \name Functions to get parameters - \warning Be careful with changing shared pointers. If you modify the objects in + \warning Be careful with changing shared pointers. If you modify the objects in one place, all objects that use the shared pointer will be affected. */ //@{ - GeneralisedObjectiveFunction const& - get_objective_function() const; + GeneralisedObjectiveFunction const& get_objective_function() const; - shared_ptr > - get_objective_function_sptr() const; + shared_ptr> get_objective_function_sptr() const; //! the maximum allowed number of full iterations const int get_max_num_full_iterations() const; @@ -172,7 +161,7 @@ class IterativeReconstruction : public Reconstruction //! the number of ordered subsets const int get_num_subsets() const; - //! the number of subiterations + //! the number of subiterations const int get_num_subiterations() const; //! value with which to initialize the subiteration counter @@ -181,7 +170,7 @@ class IterativeReconstruction : public Reconstruction //! the starting subset number const int get_start_subset_num() const; - //TODO rename + // TODO rename //! subiteration interval at which data will be saved const int get_save_interval() const; @@ -191,9 +180,9 @@ class IterativeReconstruction : public Reconstruction //! inter-iteration filter const DataProcessor& get_inter_iteration_filter() const; - shared_ptr > get_inter_iteration_filter_sptr(); + shared_ptr> get_inter_iteration_filter_sptr(); - //! subiteration interval at which to apply inter-iteration filters + //! subiteration interval at which to apply inter-iteration filters const int get_inter_iteration_filter_interval() const; //! subiteration interval at which to report the values of the objective function @@ -202,12 +191,12 @@ class IterativeReconstruction : public Reconstruction /*! \name Functions to set parameters This can be used as alternative to the parsing mechanism. - \warning Be careful with changing shared pointers. If you modify the objects in + \warning Be careful with changing shared pointers. If you modify the objects in one place, all objects that use the shared pointer will be affected. */ //@{ //! The objective function that will be optimised - void set_objective_function_sptr(const shared_ptr >&); + void set_objective_function_sptr(const shared_ptr>&); //! the maximum allowed number of full iterations void set_max_num_full_iterations(const int); @@ -215,7 +204,7 @@ class IterativeReconstruction : public Reconstruction //! the number of ordered subsets void set_num_subsets(const int); - //! the number of subiterations + //! the number of subiterations void set_num_subiterations(const int); //! value with which to initialize the subiteration counter @@ -224,7 +213,7 @@ class IterativeReconstruction : public Reconstruction //! the starting subset number void set_start_subset_num(const int); - //TODO rename + // TODO rename //! subiteration interval at which data will be saved void set_save_interval(const int); @@ -232,9 +221,9 @@ class IterativeReconstruction : public Reconstruction void set_randomise_subset_order(const bool); //! inter-iteration filter - void set_inter_iteration_filter_ptr(const shared_ptr >&); + void set_inter_iteration_filter_ptr(const shared_ptr>&); - //! subiteration interval at which to apply inter-iteration filters + //! subiteration interval at which to apply inter-iteration filters void set_inter_iteration_filter_interval(const int); //! subiteration interval at which to report the values of the objective function @@ -247,34 +236,32 @@ class IterativeReconstruction : public Reconstruction virtual const ExamData& get_input_data() const; //@} - virtual Succeeded set_up(shared_ptr const& target_data_ptr); + virtual Succeeded set_up(shared_ptr const& target_data_ptr); //! the principal operations for updating the data iterates at each iteration - virtual void update_estimate(TargetT ¤t_estimate)=0; + virtual void update_estimate(TargetT& current_estimate) = 0; protected: - IterativeReconstruction(); //! operations for the end of the iteration - /*! At specific subiteration numbers, this + /*! At specific subiteration numbers, this
    • applies the inter-filtering and/or post-filtering data processor,
    • -
    • writes the current data to file at the designated subiteration numbers +
    • writes the current data to file at the designated subiteration numbers (including the final one). Filenames used are determined by Reconstruction::output_filename_prefix,
    • -
    • writes the objective function values (using +
    • writes the objective function values (using GeneralisedObjectiveFunction::report_objective_function_values) to stderr.
    If your derived class redefines this virtual function, you will - probably want to call + probably want to call IterativeReconstruction::end_of_iteration_processing() in there anyway. */ // KT 14/12/2001 remove =0 as it's not a pure virtual and the default implementation is usually fine. - virtual void end_of_iteration_processing(TargetT ¤t_estimate); + virtual void end_of_iteration_processing(TargetT& current_estimate); - shared_ptr > - objective_function_sptr; + shared_ptr> objective_function_sptr; //! the subiteration counter int subiteration_num; @@ -282,16 +269,15 @@ class IterativeReconstruction : public Reconstruction //! used to abort the loop over iterations bool terminate_iterations; - // parameters - protected: +protected: //! the maximum allowed number of full iterations int max_num_full_iterations; //! the number of ordered subsets int num_subsets; - //! the number of subiterations + //! the number of subiterations int num_subiterations; //! value with which to initialize the subiteration counter @@ -303,7 +289,7 @@ class IterativeReconstruction : public Reconstruction //! the starting subset number int start_subset_num; - //TODO rename + // TODO rename //! subiteration interval at which data will be saved int save_interval; @@ -311,16 +297,12 @@ class IterativeReconstruction : public Reconstruction //! signals whether to randomise the subset order in each iteration bool randomise_subset_order; - //! inter-iteration filter - shared_ptr > inter_iteration_filter_ptr; - + shared_ptr> inter_iteration_filter_ptr; - - - //! subiteration interval at which to apply inter-iteration filters + //! subiteration interval at which to apply inter-iteration filters int inter_iteration_filter_interval; - + //! subiteration interval at which to report the values of the objective function /*! \warning This is generally time-consuming. */ @@ -334,19 +316,15 @@ class IterativeReconstruction : public Reconstruction //! used to check acceptable parameter ranges, etc... virtual bool post_processing(); - private: +private: //! member storing the order in which the subsets will be traversed in this iteration /*! Initialised and used by get_subset_num() */ VectorWithOffset _current_subset_array; //! used to randomly generate a subset sequence order for the current iteration VectorWithOffset randomly_permute_subset_order() const; - - }; END_NAMESPACE_STIR #endif // __IterativeReconstruction_h__ - - diff --git a/src/include/stir/recon_buildblock/LogcoshPrior.h b/src/include/stir/recon_buildblock/LogcoshPrior.h index ab426cecdd..496c4894fa 100644 --- a/src/include/stir/recon_buildblock/LogcoshPrior.h +++ b/src/include/stir/recon_buildblock/LogcoshPrior.h @@ -29,11 +29,9 @@ \author Zeljko Kereta */ - #ifndef __stir_recon_buildblock_LogcoshPrior_H__ #define __stir_recon_buildblock_LogcoshPrior_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/recon_buildblock/PriorWithParabolicSurrogate.h" #include "stir/Array.h" @@ -43,7 +41,6 @@ START_NAMESPACE_STIR - /*! \ingroup priors \brief @@ -89,164 +86,149 @@ START_NAMESPACE_STIR */ template -class LogcoshPrior: public - RegisteredParsingObject< - LogcoshPrior, - GeneralisedPrior >, - PriorWithParabolicSurrogate > - > -{ +class LogcoshPrior : public RegisteredParsingObject, GeneralisedPrior>, + PriorWithParabolicSurrogate>> { private: - typedef - RegisteredParsingObject< LogcoshPrior, - GeneralisedPrior >, - PriorWithParabolicSurrogate > > - base_type; + typedef RegisteredParsingObject, GeneralisedPrior>, + PriorWithParabolicSurrogate>> + base_type; public: - //! Name which will be used when parsing a GeneralisedPrior object - static const char * const registered_name; + //! Name which will be used when parsing a GeneralisedPrior object + static const char* const registered_name; - //! Default constructor - LogcoshPrior(); + //! Default constructor + LogcoshPrior(); - //! Constructs it explicitly - LogcoshPrior(const bool only_2D, float penalization_factor); + //! Constructs it explicitly + LogcoshPrior(const bool only_2D, float penalization_factor); - //! Constructs it explicitly with scalar - LogcoshPrior(const bool only_2D, float penalization_factor, const float scalar); + //! Constructs it explicitly with scalar + LogcoshPrior(const bool only_2D, float penalization_factor, const float scalar); - virtual bool - parabolic_surrogate_curvature_depends_on_argument() const - { return false; } + virtual bool parabolic_surrogate_curvature_depends_on_argument() const { return false; } - //! compute the value of the function - double - compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate); + //! compute the value of the function + double compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate); - //! compute gradient - void compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate); + //! compute gradient + void compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, const DiscretisedDensity<3, elemT>& current_image_estimate); - //! compute the parabolic surrogate for the prior - void parabolic_surrogate_curvature(DiscretisedDensity<3,elemT>& parabolic_surrogate_curvature, - const DiscretisedDensity<3,elemT> ¤t_image_estimate); + //! compute the parabolic surrogate for the prior + void parabolic_surrogate_curvature(DiscretisedDensity<3, elemT>& parabolic_surrogate_curvature, + const DiscretisedDensity<3, elemT>& current_image_estimate); - //! compute Hessian - void compute_Hessian(DiscretisedDensity<3,elemT>& prior_Hessian_for_single_densel, - const BasicCoordinate<3,int>& coords, - const DiscretisedDensity<3,elemT> ¤t_image_estimate); + //! compute Hessian + void compute_Hessian(DiscretisedDensity<3, elemT>& prior_Hessian_for_single_densel, const BasicCoordinate<3, int>& coords, + const DiscretisedDensity<3, elemT>& current_image_estimate); - //! Compute the multiplication of the hessian of the prior multiplied by the input. - virtual Succeeded accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& current_estimate, - const DiscretisedDensity<3,elemT>& input) const; + //! Compute the multiplication of the hessian of the prior multiplied by the input. + virtual Succeeded accumulate_Hessian_times_input(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& current_estimate, + const DiscretisedDensity<3, elemT>& input) const; - //! get penalty weights for the neigbourhood - Array<3,float> get_weights() const; + //! get penalty weights for the neigbourhood + Array<3, float> get_weights() const; - //! set penalty weights for the neigbourhood - void set_weights(const Array<3,float>&); + //! set penalty weights for the neigbourhood + void set_weights(const Array<3, float>&); - //! get current kappa image - /*! \warning As this function returns a shared_ptr, this is dangerous. You should not - modify the image by manipulating the image referred to by this pointer. - Unpredictable results will occur. - */ - shared_ptr > get_kappa_sptr() const; + //! get current kappa image + /*! \warning As this function returns a shared_ptr, this is dangerous. You should not + modify the image by manipulating the image referred to by this pointer. + Unpredictable results will occur. + */ + shared_ptr> get_kappa_sptr() const; - //! set kappa image - void set_kappa_sptr(const shared_ptr >&); + //! set kappa image + void set_kappa_sptr(const shared_ptr>&); - //! Get the scalar value - float get_scalar() const; + //! Get the scalar value + float get_scalar() const; - //! Set the scalar value - void set_scalar(float scalar_v); + //! Set the scalar value + void set_scalar(float scalar_v); protected: - //! can be set during parsing to restrict the weights to the 2D case - bool only_2D; + //! can be set during parsing to restrict the weights to the 2D case + bool only_2D; - //! controls the transition between the quadratic (smooth) and linear (edge-preserving) nature of the prior - float scalar; + //! controls the transition between the quadratic (smooth) and linear (edge-preserving) nature of the prior + float scalar; - //! filename prefix for outputting the gradient whenever compute_gradient() is called. - /*! An internal counter is used to keep track of the number of times the - gradient is computed. The filename will be constructed by concatenating - gradient_filename_prefix and the counter. - */ - std::string gradient_filename_prefix; + //! filename prefix for outputting the gradient whenever compute_gradient() is called. + /*! An internal counter is used to keep track of the number of times the + gradient is computed. The filename will be constructed by concatenating + gradient_filename_prefix and the counter. + */ + std::string gradient_filename_prefix; - //! penalty weights - /*! - \todo This member is mutable at present because some const functions initialise it. - That initialisation should be moved to a new set_up() function. - */ - mutable Array<3,float> weights; + //! penalty weights + /*! + \todo This member is mutable at present because some const functions initialise it. + That initialisation should be moved to a new set_up() function. + */ + mutable Array<3, float> weights; - //! Filename for the \f$\kappa\f$ image that will be read by post_processing() - std::string kappa_filename; + //! Filename for the \f$\kappa\f$ image that will be read by post_processing() + std::string kappa_filename; - virtual void set_defaults(); - virtual void initialise_keymap(); - virtual bool post_processing(); + virtual void set_defaults(); + virtual void initialise_keymap(); + virtual bool post_processing(); private: - //! Spatially variant penalty penalty image ptr - shared_ptr > kappa_ptr; - - //! The Log(cosh()) function and its approximation - /*! - Cosh(x) = 0.5(e^x + e^-x) is an exponential function and hence cannot be evaluated for large x. - Make the approximation: - log(Cosh(x)) = log(0.5) + |x| + log(1 + e^(-2|x|)) = log(0.5) + |x| + O(10^(-27)), for |x|>30 - */ - static inline float logcosh(const float d) - { - const float x = fabs(d); - if ( x < 30.f ){ - return log(cosh(x)); - } else { - return x + log(0.5f); - } + //! Spatially variant penalty penalty image ptr + shared_ptr> kappa_ptr; + + //! The Log(cosh()) function and its approximation + /*! + Cosh(x) = 0.5(e^x + e^-x) is an exponential function and hence cannot be evaluated for large x. + Make the approximation: + log(Cosh(x)) = log(0.5) + |x| + log(1 + e^(-2|x|)) = log(0.5) + |x| + O(10^(-27)), for |x|>30 + */ + static inline float logcosh(const float d) { + const float x = fabs(d); + if (x < 30.f) { + return log(cosh(x)); + } else { + return x + log(0.5f); } - - //! The surrogate of the logcosh function is tanh(x)/x - /*! - * @param d should be the difference between the ith and jth voxel. - However, it will use the taylor expansion if the x is too small (to prevent division by 0). - * @param scalar is the logcosh scalar value controlling the priors transition between the quadratic and linear behaviour - * @return the surrogate of the log-cosh function - */ - static inline float surrogate(const float d, const float scalar) - { - const float eps = 0.01; - const float x = d * scalar; - // If abs(x) is less than eps, - // use Taylor approximatation of tanh: tanh(x)/x ~= (x - x^3/3)/x = 1- x^2/3. - // Prevents divide by zeros - if (fabs(x) -{ +class BackProjectorByBinNiftyPET : public RegisteredParsingObject { public: - //! Name which will be used when parsing a BackProjectorByBin object - static const char * const registered_name; + //! Name which will be used when parsing a BackProjectorByBin object + static const char* const registered_name; //! Default constructor calls reset_timers() BackProjectorByBinNiftyPET(); @@ -73,23 +70,21 @@ class BackProjectorByBinNiftyPET : virtual void initialise_keymap(); //! Stores all necessary geometric info - /*! - If necessary, set_up() can be called more than once. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_sptr // TODO should be Info only - ); + /*! + If necessary, set_up() can be called more than once. + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_sptr // TODO should be Info only + ); //! Symmetries not used, so returns TrivialDataSymmetriesForBins. - virtual const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const; + virtual const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const; /// Back project void back_project(const ProjData&, int subset_num = 0, int num_subsets = 1); - /// Get output - virtual void get_output(DiscretisedDensity<3,float> &) const; - + /// Get output + virtual void get_output(DiscretisedDensity<3, float>&) const; /*! \brief tell the back projector to start accumulating into a new target. This function has to be called before any back-projection is initiated.*/ @@ -103,12 +98,10 @@ class BackProjectorByBinNiftyPET : void set_use_truncation(const bool use_truncation) { _use_truncation = use_truncation; } protected: + virtual void actual_back_project(const RelatedViewgrams&, const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num); - virtual void actual_back_project(const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); - - private: +private: shared_ptr _symmetries_sptr; NiftyPETHelper _helper; int _cuda_device; @@ -119,5 +112,4 @@ class BackProjectorByBinNiftyPET : END_NAMESPACE_STIR - #endif // __stir_gpu_BackProjectorByBinNiftyPET_h__ diff --git a/src/include/stir/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.h b/src/include/stir/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.h index 4724859231..637d46cb32 100644 --- a/src/include/stir/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.h +++ b/src/include/stir/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.h @@ -58,70 +58,65 @@ Current limitations: - Projects all of the data in one go - Only debugged for span 11. */ -class ForwardProjectorByBinNiftyPET: - public RegisteredParsingObject -{ +class ForwardProjectorByBinNiftyPET : public RegisteredParsingObject { public: //! Name which will be used when parsing a ForwardProjectorByBin object - static const char * const registered_name; + static const char* const registered_name; //! Default constructor calls reset_timers() - //inline - ForwardProjectorByBinNiftyPET(); + // inline + ForwardProjectorByBinNiftyPET(); - /// Constructor - virtual ~ForwardProjectorByBinNiftyPET(); + /// Constructor + virtual ~ForwardProjectorByBinNiftyPET(); - /// Keymap - virtual void initialise_keymap(); + /// Keymap + virtual void initialise_keymap(); //! Stores all necessary geometric info - /*! - If necessary, set_up() can be called more than once. + /*! + If necessary, set_up() can be called more than once. - Derived classes can assume that forward_project() will be called - with input corresponding to the arguments of the last call to set_up(). + Derived classes can assume that forward_project() will be called + with input corresponding to the arguments of the last call to set_up(). - \warning there is currently no check on this. - \warning Derived classes have to call set_up from the base class. - */ -virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_sptr // TODO should be Info only - ); + \warning there is currently no check on this. + \warning Derived classes have to call set_up from the base class. + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_sptr // TODO should be Info only + ); //! Symmetries not used, so returns TrivialDataSymmetriesForBins. - virtual const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const; + virtual const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const; - /// Set input - virtual void set_input(const DiscretisedDensity<3,float>&); + /// Set input + virtual void set_input(const DiscretisedDensity<3, float>&); - /// Set verbosity - void set_verbosity(const bool verbosity) { _cuda_verbosity = verbosity; } + /// Set verbosity + void set_verbosity(const bool verbosity) { _cuda_verbosity = verbosity; } - /// Set use truncation - truncate before forward - /// projection and after back projection - void set_use_truncation(const bool use_truncation) { _use_truncation = use_truncation; } + /// Set use truncation - truncate before forward + /// projection and after back projection + void set_use_truncation(const bool use_truncation) { _use_truncation = use_truncation; } protected: //! This virtual function has to be implemented by the derived class. - virtual void actual_forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + virtual void actual_forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>&, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num); - virtual void actual_forward_project(RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + virtual void actual_forward_project(RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num); private: - shared_ptr _symmetries_sptr; - shared_ptr _projected_data_sptr; - NiftyPETHelper _helper; - int _cuda_device; - bool _cuda_verbosity; - bool _use_truncation; + shared_ptr _symmetries_sptr; + shared_ptr _projected_data_sptr; + NiftyPETHelper _helper; + int _cuda_device; + bool _cuda_verbosity; + bool _use_truncation; }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/NiftyPET_projector/NiftyPETHelper.h b/src/include/stir/recon_buildblock/NiftyPET_projector/NiftyPETHelper.h index 0ce0147b9e..adf7740321 100644 --- a/src/include/stir/recon_buildblock/NiftyPET_projector/NiftyPETHelper.h +++ b/src/include/stir/recon_buildblock/NiftyPET_projector/NiftyPETHelper.h @@ -53,126 +53,124 @@ struct axialLUT; START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; class ProjData; -template class Viewgram; -template class VoxelsOnCartesianGrid; +template +class Viewgram; +template +class VoxelsOnCartesianGrid; /*! \ingroup projection \brief Helper class for the wrapped NiftyPET projectors. */ -class NiftyPETHelper -{ +class NiftyPETHelper { public: + /// Default constructor + NiftyPETHelper() : _already_set_up(false), _span(-1), _devid(0), _att(-1), _scanner_type(Scanner::Unknown_scanner) {} - /// Default constructor - NiftyPETHelper() : - _already_set_up(false), _span(-1), _devid(0), _att(-1), _scanner_type(Scanner::Unknown_scanner) - {} + /// Destructor + virtual ~NiftyPETHelper(); - /// Destructor - virtual ~NiftyPETHelper(); + /// Set CUDA device ID + void set_cuda_device_id(const int devid) { _devid = char(devid); } - /// Set CUDA device ID - void set_cuda_device_id(const int devid) { _devid = char(devid); } + /// Set span + void set_span(const char span) { _span = span; } - /// Set span - void set_span(const char span) { _span = span; } + /// Set emission (0) or transmission (1) - whether to exp{-result} for attenuation maps + void set_att(const char att) { _att = att; } - /// Set emission (0) or transmission (1) - whether to exp{-result} for attenuation maps - void set_att(const char att) { _att = att; } + /// Set verbosity level for CUDA output + void set_verbose(const bool verbose) { _verbose = verbose; } - /// Set verbosity level for CUDA output - void set_verbose(const bool verbose) { _verbose = verbose; } + /// Set scanner type + void set_scanner_type(const Scanner::Type scanner_type) { _scanner_type = scanner_type; } - /// Set scanner type - void set_scanner_type(const Scanner::Type scanner_type) { _scanner_type = scanner_type; } + /// Set up + void set_up(); - /// Set up - void set_up(); + /// Create NiftyPET image + static std::vector create_niftyPET_image(); - /// Create NiftyPET image - static std::vector create_niftyPET_image(); + /// Create STIR image with mMR dimensions + static shared_ptr> create_stir_im(); - /// Create STIR image with mMR dimensions - static shared_ptr > create_stir_im(); + /// Create NiftyPET singram with no gaps. Forward project into this + std::vector create_niftyPET_sinogram_no_gaps() const; - /// Create NiftyPET singram with no gaps. Forward project into this - std::vector create_niftyPET_sinogram_no_gaps() const; + /// Create NiftyPET sinogram with gaps. Use this before converting to stir. + std::vector create_niftyPET_sinogram_with_gaps() const; - /// Create NiftyPET sinogram with gaps. Use this before converting to stir. - std::vector create_niftyPET_sinogram_with_gaps() const; + /// Convert STIR image to NiftyPET image + static void convert_image_stir_to_niftyPET(std::vector& np, const DiscretisedDensity<3, float>& stir); - /// Convert STIR image to NiftyPET image - static void convert_image_stir_to_niftyPET(std::vector &np, const DiscretisedDensity<3,float> &stir); + /// Convert NiftyPET image to STIR image + static void convert_image_niftyPET_to_stir(DiscretisedDensity<3, float>& stir, const std::vector& np_vec); - /// Convert NiftyPET image to STIR image - static void convert_image_niftyPET_to_stir(DiscretisedDensity<3,float> &stir, const std::vector &np_vec); + /// Convert STIR proj data to NiftyPET proj data + void convert_proj_data_stir_to_niftyPET(std::vector& np_vec, const ProjData& stir) const; - /// Convert STIR proj data to NiftyPET proj data - void convert_proj_data_stir_to_niftyPET(std::vector &np_vec, const ProjData& stir) const; + /// Convert STIR viewgram to NiftyPET + void convert_viewgram_stir_to_niftyPET(std::vector& np_vec, const Viewgram& viewgram) const; - /// Convert STIR viewgram to NiftyPET - void convert_viewgram_stir_to_niftyPET(std::vector &np_vec, const Viewgram& viewgram) const; + /// Convert NiftyPET proj data to STIR proj data + void convert_proj_data_niftyPET_to_stir(ProjData& stir_sptr, const std::vector& np_vec) const; - /// Convert NiftyPET proj data to STIR proj data - void convert_proj_data_niftyPET_to_stir(ProjData &stir_sptr, const std::vector &np_vec) const; + /// Remove gaps from sinogram. Do some unavoidable const_casting as the wrapped methods don't use const + void remove_gaps(std::vector& sino_no_gaps, const std::vector& sino_w_gaps) const; - /// Remove gaps from sinogram. Do some unavoidable const_casting as the wrapped methods don't use const - void remove_gaps(std::vector &sino_no_gaps, const std::vector &sino_w_gaps) const; + /// Put gaps into sinogram. Do some unavoidable const_casting as the wrapped methods don't use const + void put_gaps(std::vector& sino_w_gaps, const std::vector& sino_no_gaps) const; - /// Put gaps into sinogram. Do some unavoidable const_casting as the wrapped methods don't use const - void put_gaps(std::vector &sino_w_gaps, const std::vector &sino_no_gaps) const; + /// Back project. Do some unavoidable const_casting as the wrapped methods don't use const + void back_project(std::vector& image, const std::vector& sino_no_gaps) const; - /// Back project. Do some unavoidable const_casting as the wrapped methods don't use const - void back_project(std::vector &image, const std::vector &sino_no_gaps) const; + /// Forward project, returns sinogram without gaps. Do some unavoidable const_casting as the wrapped methods don't use const + void forward_project(std::vector& sino_no_gaps, const std::vector& image) const; - /// Forward project, returns sinogram without gaps. Do some unavoidable const_casting as the wrapped methods don't use const - void forward_project(std::vector &sino_no_gaps, const std::vector &image) const; + /// Create a STIR sinogram + static shared_ptr create_stir_sino(); - /// Create a STIR sinogram - static shared_ptr create_stir_sino(); - - /// Listmode to sinogram - void lm_to_proj_data(shared_ptr &prompts_sptr, shared_ptr &delayeds_sptr, - shared_ptr &randoms_sptr, shared_ptr &norm_sptr, - const int tstart, const int tstop, - const std::string &lm_binary_file, const std::string &norm_binary_file="") const; + /// Listmode to sinogram + void lm_to_proj_data(shared_ptr& prompts_sptr, shared_ptr& delayeds_sptr, + shared_ptr& randoms_sptr, shared_ptr& norm_sptr, const int tstart, const int tstop, + const std::string& lm_binary_file, const std::string& norm_binary_file = "") const; private: - - /// Check that set up has been run before returning data - void check_set_up() const; - - /// Permute the data - void permute(std::vector &output_array, const std::vector &orig_array, const unsigned output_dims[3], const unsigned *permute_order) const; - - /// Convert 3d NiftyPET proj data index to 1d - unsigned convert_NiftyPET_proj_3d_to_1d_idx(const unsigned ang, const unsigned bins, const unsigned sino) const; - - /// Convert 1d NiftyPET proj data index to 3d - void convert_NiftyPET_proj_1d_to_3d_idx(unsigned &ang, unsigned &bins, unsigned &sino, const unsigned idx) const; - - bool _already_set_up; - char _span; - char _devid; - shared_ptr _cnt_sptr; - int _nsinos; - char _att; - std::vector _isub; - bool _verbose; - Scanner::Type _scanner_type; - shared_ptr _txlut_sptr; - shared_ptr _axlut_sptr; - - std::vector _crs; - std::vector _s2c; - - // Get axLUT - std::vector _li2rng; - std::vector _li2sn; - std::vector _li2nos; + /// Check that set up has been run before returning data + void check_set_up() const; + + /// Permute the data + void permute(std::vector& output_array, const std::vector& orig_array, const unsigned output_dims[3], + const unsigned* permute_order) const; + + /// Convert 3d NiftyPET proj data index to 1d + unsigned convert_NiftyPET_proj_3d_to_1d_idx(const unsigned ang, const unsigned bins, const unsigned sino) const; + + /// Convert 1d NiftyPET proj data index to 3d + void convert_NiftyPET_proj_1d_to_3d_idx(unsigned& ang, unsigned& bins, unsigned& sino, const unsigned idx) const; + + bool _already_set_up; + char _span; + char _devid; + shared_ptr _cnt_sptr; + int _nsinos; + char _att; + std::vector _isub; + bool _verbose; + Scanner::Type _scanner_type; + shared_ptr _txlut_sptr; + shared_ptr _axlut_sptr; + + std::vector _crs; + std::vector _s2c; + + // Get axLUT + std::vector _li2rng; + std::vector _li2sn; + std::vector _li2nos; }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.h b/src/include/stir/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.h index a816adac90..6d40245cf5 100644 --- a/src/include/stir/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.h +++ b/src/include/stir/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.h @@ -39,22 +39,16 @@ class Succeeded; \ingroup projection \brief A projector pair based on NiftyPET projectors */ -class ProjectorByBinPairUsingNiftyPET : - public RegisteredParsingObject -{ - private: - typedef - RegisteredParsingObject - base_type; +class ProjectorByBinPairUsingNiftyPET + : public RegisteredParsingObject { +private: + typedef RegisteredParsingObject base_type; + public: //! Name which will be used when parsing a ProjectorByBinPair object - static const char * const registered_name; + static const char* const registered_name; - //! Default constructor + //! Default constructor ProjectorByBinPairUsingNiftyPET(); /// Set verbosity @@ -65,7 +59,6 @@ class ProjectorByBinPairUsingNiftyPET : void set_use_truncation(const bool use_truncation); private: - void set_defaults(); void initialise_keymap(); bool post_processing(); @@ -75,5 +68,4 @@ class ProjectorByBinPairUsingNiftyPET : END_NAMESPACE_STIR - #endif // __stir_recon_buildblock_ProjectorByBinPairUsingNiftyPET_h_ diff --git a/src/include/stir/recon_buildblock/PLSPrior.h b/src/include/stir/recon_buildblock/PLSPrior.h index 372e0cd547..5dc9673b02 100644 --- a/src/include/stir/recon_buildblock/PLSPrior.h +++ b/src/include/stir/recon_buildblock/PLSPrior.h @@ -26,11 +26,9 @@ \author Yu-Jung Tsai */ - #ifndef __stir_recon_buildblock_PLSPrior_H__ #define __stir_recon_buildblock_PLSPrior_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/recon_buildblock/PriorWithParabolicSurrogate.h" #include "stir/Array.h" @@ -40,7 +38,6 @@ START_NAMESPACE_STIR - /*! \ingroup priors \brief @@ -102,22 +99,16 @@ START_NAMESPACE_STIR */ template -class PLSPrior: public - RegisteredParsingObject< PLSPrior, - GeneralisedPrior >, - GeneralisedPrior > - > -{ - private: - typedef - RegisteredParsingObject< PLSPrior, - GeneralisedPrior >, - GeneralisedPrior > > - base_type; - - public: +class PLSPrior : public RegisteredParsingObject, GeneralisedPrior>, + GeneralisedPrior>> { +private: + typedef RegisteredParsingObject, GeneralisedPrior>, + GeneralisedPrior>> + base_type; + +public: //! Name which will be used when parsing a GeneralisedPrior object - static const char * const registered_name; + static const char* const registered_name; //! Default constructor PLSPrior(); @@ -127,47 +118,44 @@ class PLSPrior: public //! Has to be called before using this object /*! \todo set the anatomical image to zero if not defined */ - virtual Succeeded set_up(shared_ptr > const& target_sptr); + virtual Succeeded set_up(shared_ptr> const& target_sptr); //! compute the value of the function - double - compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate); + double compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate); //! compute gradient - void compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate); + void compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, const DiscretisedDensity<3, elemT>& current_image_estimate); //! get current kappa image /*! \warning As this function returns a shared_ptr, this is dangerous. You should not modify the image by manipulating the image refered to by this pointer. Unpredictable results will occur. */ - shared_ptr > get_kappa_sptr() const; - shared_ptr > get_anatomical_grad_sptr(int direction) const; - shared_ptr > get_norm_sptr() const; + shared_ptr> get_kappa_sptr() const; + shared_ptr> get_anatomical_grad_sptr(int direction) const; + shared_ptr> get_norm_sptr() const; - //!get eta and alpha parameters + //! get eta and alpha parameters double get_eta() const; double get_alpha() const; - //!set eta parameter + //! set eta parameter void set_eta(const double); - //!set alpha parameter + //! set alpha parameter void set_alpha(const double); //! set anatomical pointer - void set_anatomical_image_sptr(const shared_ptr >&); + void set_anatomical_image_sptr(const shared_ptr>&); //! get anatomical pointer - shared_ptr > get_anatomical_image_sptr() const; + shared_ptr> get_anatomical_image_sptr() const; /// Set anatomical filename void set_anatomical_filename(const std::string& filename); //! set kappa image - void set_kappa_sptr(const shared_ptr >&); + void set_kappa_sptr(const shared_ptr>&); /// Set kappa filename void set_kappa_filename(const std::string& filename); - /// Set only 2D void set_only_2D(const bool arg) { only_2D = arg; } /// Get only 2D @@ -196,40 +184,34 @@ class PLSPrior: public virtual bool post_processing(); //! Check that the prior is ready to be used - virtual void check(DiscretisedDensity<3,elemT> const& current_image_estimate) const; - - private: + virtual void check(DiscretisedDensity<3, elemT> const& current_image_estimate) const; +private: //! compute the component x, y or z of the image gradient using forward difference - static void compute_image_gradient_element(DiscretisedDensity<3,elemT> & image_gradient_elem, - int direction, - const DiscretisedDensity<3,elemT> & image ); + static void compute_image_gradient_element(DiscretisedDensity<3, elemT>& image_gradient_elem, int direction, + const DiscretisedDensity<3, elemT>& image); //! compute normalisation for the gradient of the anatomical image (Eq. (5) of the paper) - void compute_normalisation_anatomical_gradient(DiscretisedDensity<3, elemT> &norm_im_grad, - const DiscretisedDensity<3,elemT> &image_grad_z, - const DiscretisedDensity<3,elemT> &image_grad_y, - const DiscretisedDensity<3,elemT> &image_grad_x); + void compute_normalisation_anatomical_gradient(DiscretisedDensity<3, elemT>& norm_im_grad, + const DiscretisedDensity<3, elemT>& image_grad_z, + const DiscretisedDensity<3, elemT>& image_grad_y, + const DiscretisedDensity<3, elemT>& image_grad_x); //! Inner product in Eq. (9) of the paper but also the penalty function. - void compute_inner_product_and_penalty(DiscretisedDensity<3,elemT> &inner_product, - DiscretisedDensity<3,elemT> &penalty, - DiscretisedDensity<3,elemT> &pet_im_grad_z, - DiscretisedDensity<3,elemT> &pet_im_grad_y, - DiscretisedDensity<3,elemT> &pet_im_grad_x, - const DiscretisedDensity<3,elemT> &pet_image); - - shared_ptr > anatomical_grad_x_sptr; - shared_ptr > anatomical_grad_y_sptr; - shared_ptr > anatomical_grad_z_sptr; - shared_ptr > anatomical_sptr; - shared_ptr > norm_sptr; - shared_ptr > kappa_ptr; - void set_anatomical_grad_sptr(const shared_ptr >&, int); - void set_anatomical_grad_norm_sptr(const shared_ptr >&); - }; - + void compute_inner_product_and_penalty(DiscretisedDensity<3, elemT>& inner_product, DiscretisedDensity<3, elemT>& penalty, + DiscretisedDensity<3, elemT>& pet_im_grad_z, DiscretisedDensity<3, elemT>& pet_im_grad_y, + DiscretisedDensity<3, elemT>& pet_im_grad_x, + const DiscretisedDensity<3, elemT>& pet_image); + + shared_ptr> anatomical_grad_x_sptr; + shared_ptr> anatomical_grad_y_sptr; + shared_ptr> anatomical_grad_z_sptr; + shared_ptr> anatomical_sptr; + shared_ptr> norm_sptr; + shared_ptr> kappa_ptr; + void set_anatomical_grad_sptr(const shared_ptr>&, int); + void set_anatomical_grad_norm_sptr(const shared_ptr>&); +}; END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h index 1415e7d8e1..1274a00922 100644 --- a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h +++ b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h @@ -46,7 +46,7 @@ START_NAMESPACE_STIR /*! \ingroup GeneralisedObjectiveFunction \ingroup modelling - \brief a base class for LogLikelihood of independent Poisson variables + \brief a base class for LogLikelihood of independent Poisson variables where the mean values are linear combinations of the kinetic parameters. \par Parameters for parsing @@ -54,21 +54,19 @@ START_NAMESPACE_STIR */ template -class PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData: -public RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > -{ - private: - typedef RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > base_type; - typedef PoissonLogLikelihoodWithLinearModelForMeanAndProjData > SingleFrameObjFunc ; +class PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData + : public RegisteredParsingObject, + GeneralisedObjectiveFunction, PoissonLogLikelihoodWithLinearModelForMean> { +private: + typedef RegisteredParsingObject, + GeneralisedObjectiveFunction, PoissonLogLikelihoodWithLinearModelForMean> + base_type; + typedef PoissonLogLikelihoodWithLinearModelForMeanAndProjData> SingleFrameObjFunc; VectorWithOffset _single_frame_obj_funcs; - public: - + +public: //! Name which will be used when parsing a GeneralisedObjectiveFunction object - static const char * const registered_name; + static const char* const registered_name; PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData(); @@ -76,42 +74,32 @@ public RegisteredParsingObject - get_exam_info_uptr_for_target() const; - protected: - virtual double - actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num); - - virtual Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr); + virtual TargetT* construct_target_ptr() const; + virtual void compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, const TargetT& current_estimate, + const int subset_num); + + virtual std::unique_ptr get_exam_info_uptr_for_target() const; + +protected: + virtual double actual_compute_objective_function_without_penalty(const TargetT& current_estimate, const int subset_num); + + virtual Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr); //! Add subset sensitivity to existing data /*! \todo Current implementation does NOT add to the subset sensitivity, but overwrites */ - virtual void - add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const; + virtual void add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const; - virtual Succeeded - actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const; + virtual Succeeded actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, const TargetT& input, + const int subset_num) const; - virtual Succeeded - actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT &output, - const TargetT ¤t_image_estimate, - const TargetT &input, - const int subset_num) const; + virtual Succeeded actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, + const TargetT& current_image_estimate, + const TargetT& input, const int subset_num) const; - public: +public: /*! \name Functions to get parameters - \warning Be careful with changing shared pointers. If you modify the objects in + \warning Be careful with changing shared pointers. If you modify the objects in one place, all objects that use the shared pointer will be affected. */ //@{ @@ -130,7 +118,7 @@ public RegisteredParsingObject&); virtual void set_additive_proj_data_sptr(const shared_ptr&); - virtual void set_input_data(const shared_ptr &); + virtual void set_input_data(const shared_ptr&); virtual const DynamicProjData& get_input_data() const; //@} - protected: +protected: //! Filename with input projection data std::string _input_filename; @@ -161,7 +149,7 @@ public RegisteredParsingObject _additive_dyn_proj_data_sptr; /*! the normalisation or/and attenuation data */ @@ -178,14 +166,13 @@ public RegisteredParsingObject -#include +#include // For the Patlak Plot Modelling #include "stir/modelling/ModelMatrix.h" #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h" #ifndef NDEBUG -#include "stir/IO/write_to_file.h" +# include "stir/IO/write_to_file.h" #endif START_NAMESPACE_STIR -template -const char * const -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -registered_name = -"PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData"; +template +const char* const PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::registered_name = + "PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData"; -template +template void -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -set_defaults() -{ +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::set_defaults() { base_type::set_defaults(); - this->_input_filename=""; - this->_max_segment_num_to_process=-1; // use all segments - //num_views_to_add=1; // KT 20/06/2001 disabled + this->_input_filename = ""; + this->_max_segment_num_to_process = -1; // use all segments + // num_views_to_add=1; // KT 20/06/2001 disabled this->_dyn_proj_data_sptr.reset(); this->_zero_seg0_end_planes = 0; @@ -87,13 +83,12 @@ set_defaults() shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingRayTracing()); shared_ptr back_projector_ptr(new BackProjectorByBinUsingInterpolation()); #else - shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); - shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); - shared_ptr back_projector_ptr(new BackProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr back_projector_ptr(new BackProjectorByBinUsingProjMatrixByBin(PM)); #endif - this->_projector_pair_ptr. - reset(new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); + this->_projector_pair_ptr.reset(new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); this->_normalisation_sptr.reset(new TrivialBinNormalisation); this->target_parameter_parser.set_defaults(); @@ -102,15 +97,13 @@ set_defaults() this->_patlak_plot_sptr.reset(); } -template +template void -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -initialise_keymap() -{ +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData Parameters"); this->parser.add_stop_key("End PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData Parameters"); - this->parser.add_key("input file",&this->_input_filename); + this->parser.add_key("input file", &this->_input_filename); // parser.add_key("mash x views", &num_views_to_add); // KT 20/06/2001 disabled this->parser.add_key("maximum absolute segment number to process", &this->_max_segment_num_to_process); @@ -120,7 +113,7 @@ initialise_keymap() this->parser.add_parsing_key("Projector pair type", &this->_projector_pair_ptr); // Scatter correction - this->parser.add_key("additive sinograms",&this->_additive_dyn_proj_data_filename); + this->parser.add_key("additive sinograms", &this->_additive_dyn_proj_data_filename); // normalisation (and attenuation correction) this->parser.add_parsing_key("Bin Normalisation type", &this->_normalisation_sptr); @@ -132,220 +125,200 @@ initialise_keymap() // this->parser.add_parsing_key("prior type", &this->_prior_sptr); } -template +template bool -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -post_processing() -{ +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::post_processing() { if (base_type::post_processing() == true) return true; - if (this->_input_filename.length() == 0) - { warning("You need to specify an input filename"); return true; } - + if (this->_input_filename.length() == 0) { + warning("You need to specify an input filename"); + return true; + } + #if 0 // KT 20/06/2001 disabled as not functional yet if (num_views_to_add!=1 && (num_views_to_add<=0 || num_views_to_add%2 != 0)) { warning("The 'mash x views' key has an invalid value (must be 1 or even number)"); return true; } #endif - + this->_dyn_proj_data_sptr = DynamicProjData::read_from_file(_input_filename); - if (is_null_ptr(this->_dyn_proj_data_sptr)) - { warning("Error reading input file %s", _input_filename.c_str()); return true; } + if (is_null_ptr(this->_dyn_proj_data_sptr)) { + warning("Error reading input file %s", _input_filename.c_str()); + return true; + } this->target_parameter_parser.check_values(); - if (this->_additive_dyn_proj_data_filename != "0") - { - info(boost::format("Reading additive projdata data %1%") % this->_additive_dyn_proj_data_filename); - this->_additive_dyn_proj_data_sptr = DynamicProjData::read_from_file(this->_additive_dyn_proj_data_filename); - if (is_null_ptr(this->_additive_dyn_proj_data_sptr)) - { warning("Error reading additive input file %s", _additive_dyn_proj_data_filename.c_str()); return true; } - + if (this->_additive_dyn_proj_data_filename != "0") { + info(boost::format("Reading additive projdata data %1%") % this->_additive_dyn_proj_data_filename); + this->_additive_dyn_proj_data_sptr = DynamicProjData::read_from_file(this->_additive_dyn_proj_data_filename); + if (is_null_ptr(this->_additive_dyn_proj_data_sptr)) { + warning("Error reading additive input file %s", _additive_dyn_proj_data_filename.c_str()); + return true; } + } return false; } template -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData() -{ +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData< + TargetT>::PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData() { this->set_defaults(); } template -TargetT * -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -construct_target_ptr() const -{ - return - this->target_parameter_parser.create(this->get_input_data()); +TargetT* +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::construct_target_ptr() const { + return this->target_parameter_parser.create(this->get_input_data()); } -template - std::unique_ptr - PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: - get_exam_info_uptr_for_target() const -{ - auto exam_info_uptr = this->get_exam_info_uptr_for_target(); - if (auto norm_ptr = dynamic_cast(get_normalisation_sptr().get())) - { - exam_info_uptr->set_calibration_factor(norm_ptr->get_calibration_factor()); - // somehow tell the image that it's calibrated (do we have a way?) - } - else - { - exam_info_uptr->set_calibration_factor(1.F); - // somehow tell the image that it's not calibrated (do we have a way?) - } - return exam_info_uptr; +template +std::unique_ptr +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_exam_info_uptr_for_target() const { + auto exam_info_uptr = this->get_exam_info_uptr_for_target(); + if (auto norm_ptr = dynamic_cast(get_normalisation_sptr().get())) { + exam_info_uptr->set_calibration_factor(norm_ptr->get_calibration_factor()); + // somehow tell the image that it's calibrated (do we have a way?) + } else { + exam_info_uptr->set_calibration_factor(1.F); + // somehow tell the image that it's not calibrated (do we have a way?) + } + return exam_info_uptr; } /*************************************************************** subset balancing ***************************************************************/ -template +template bool -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -actual_subsets_are_approximately_balanced(std::string& warning_message) const -{ // call actual_subsets_are_approximately_balanced( for first single_frame_obj_func +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::actual_subsets_are_approximately_balanced( + std::string& warning_message) const { // call actual_subsets_are_approximately_balanced( for first single_frame_obj_func if (this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames() == 0 || this->_single_frame_obj_funcs.size() == 0) error("PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:\n" "actual_subsets_are_approximately_balanced called but not frames yet.\n"); - else if(this->_single_frame_obj_funcs.size() != 0) - { - bool frames_are_balanced=true; - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame();frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames();++frame_num) - frames_are_balanced &= this->_single_frame_obj_funcs[frame_num].subsets_are_approximately_balanced(warning_message); - return frames_are_balanced; - } - else + else if (this->_single_frame_obj_funcs.size() != 0) { + bool frames_are_balanced = true; + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) + frames_are_balanced &= this->_single_frame_obj_funcs[frame_num].subsets_are_approximately_balanced(warning_message); + return frames_are_balanced; + } else error("Something strange happened in PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:\n" - "actual_subsets_are_approximately_balanced called before setup()?\n"); - return - false; + "actual_subsets_are_approximately_balanced called before setup()?\n"); + return false; } /*************************************************************** get_ functions ***************************************************************/ template -const DynamicProjData& -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_dyn_proj_data() const -{ return *this->_dyn_proj_data_sptr; } +const DynamicProjData& +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_dyn_proj_data() const { + return *this->_dyn_proj_data_sptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_dyn_proj_data_sptr() const -{ return this->_dyn_proj_data_sptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_dyn_proj_data_sptr() const { + return this->_dyn_proj_data_sptr; +} template -const int -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_max_segment_num_to_process() const -{ return this->_max_segment_num_to_process; } +const int +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_max_segment_num_to_process() const { + return this->_max_segment_num_to_process; +} template -const bool -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_zero_seg0_end_planes() const -{ return this->_zero_seg0_end_planes; } +const bool +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_zero_seg0_end_planes() const { + return this->_zero_seg0_end_planes; +} template -const DynamicProjData& -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_additive_dyn_proj_data() const -{ return *this->_additive_dyn_proj_data_sptr; } +const DynamicProjData& +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_additive_dyn_proj_data() const { + return *this->_additive_dyn_proj_data_sptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_additive_dyn_proj_data_sptr() const -{ return this->_additive_dyn_proj_data_sptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_additive_dyn_proj_data_sptr() const { + return this->_additive_dyn_proj_data_sptr; +} template -const ProjectorByBinPair& -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_projector_pair() const -{ return *this->_projector_pair_ptr; } +const ProjectorByBinPair& +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_projector_pair() const { + return *this->_projector_pair_ptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_projector_pair_sptr() const -{ return this->_projector_pair_ptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_projector_pair_sptr() const { + return this->_projector_pair_ptr; +} template -const BinNormalisation& -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_normalisation() const -{ return *this->_normalisation_sptr; } +const BinNormalisation& +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_normalisation() const { + return *this->_normalisation_sptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_normalisation_sptr() const -{ return this->_normalisation_sptr; } - +const shared_ptr& +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_normalisation_sptr() const { + return this->_normalisation_sptr; +} /*************************************************************** set_ functions ***************************************************************/ -template +template int -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -set_num_subsets(const int num_subsets) -{ - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame();frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames();++frame_num) - { - if(this->_single_frame_obj_funcs.size() != 0) - if(this->_single_frame_obj_funcs[frame_num].set_num_subsets(num_subsets) != num_subsets) - error("set_num_subsets didn't work"); - } - this->num_subsets=num_subsets; +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::set_num_subsets(const int num_subsets) { + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) { + if (this->_single_frame_obj_funcs.size() != 0) + if (this->_single_frame_obj_funcs[frame_num].set_num_subsets(num_subsets) != num_subsets) + error("set_num_subsets didn't work"); + } + this->num_subsets = num_subsets; return this->num_subsets; } /*************************************************************** set_up() ***************************************************************/ -template -Succeeded -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -set_up_before_sensitivity(shared_ptr const& target_sptr) -{ - if (this->_max_segment_num_to_process==-1) - this->_max_segment_num_to_process = - (this->_dyn_proj_data_sptr)->get_proj_data_sptr(1)->get_max_segment_num(); - - if (this->_max_segment_num_to_process > (this->_dyn_proj_data_sptr)->get_proj_data_sptr(1)->get_max_segment_num()) - { - warning("_max_segment_num_to_process (%d) is too large", - this->_max_segment_num_to_process); - return Succeeded::no; - } +template +Succeeded +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::set_up_before_sensitivity( + shared_ptr const& target_sptr) { + if (this->_max_segment_num_to_process == -1) + this->_max_segment_num_to_process = (this->_dyn_proj_data_sptr)->get_proj_data_sptr(1)->get_max_segment_num(); + + if (this->_max_segment_num_to_process > (this->_dyn_proj_data_sptr)->get_proj_data_sptr(1)->get_max_segment_num()) { + warning("_max_segment_num_to_process (%d) is too large", this->_max_segment_num_to_process); + return Succeeded::no; + } const shared_ptr proj_data_info_sptr( - (this->_dyn_proj_data_sptr->get_proj_data_sptr(1))->get_proj_data_info_sptr()->clone()); - proj_data_info_sptr-> - reduce_segment_range(-this->_max_segment_num_to_process, - +this->_max_segment_num_to_process); - - if (is_null_ptr(this->_projector_pair_ptr)) - { warning("You need to specify a projector pair"); return Succeeded::no; } - - if (this->num_subsets <= 0) - { - warning("Number of subsets %d should be larger than 0.", - this->num_subsets); - return Succeeded::no; - } + (this->_dyn_proj_data_sptr->get_proj_data_sptr(1))->get_proj_data_info_sptr()->clone()); + proj_data_info_sptr->reduce_segment_range(-this->_max_segment_num_to_process, +this->_max_segment_num_to_process); - if (is_null_ptr(this->_normalisation_sptr)) - { - warning("Invalid normalisation object"); - return Succeeded::no; - } + if (is_null_ptr(this->_projector_pair_ptr)) { + warning("You need to specify a projector pair"); + return Succeeded::no; + } + + if (this->num_subsets <= 0) { + warning("Number of subsets %d should be larger than 0.", this->num_subsets); + return Succeeded::no; + } + + if (is_null_ptr(this->_normalisation_sptr)) { + warning("Invalid normalisation object"); + return Succeeded::no; + } if (this->_normalisation_sptr->set_up(this->_dyn_proj_data_sptr->get_exam_info_sptr(), proj_data_info_sptr) == Succeeded::no) return Succeeded::no; @@ -353,279 +326,247 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) if (this->_patlak_plot_sptr->set_up() == Succeeded::no) return Succeeded::no; - if (this->_patlak_plot_sptr->get_starting_frame()<=0 || this->_patlak_plot_sptr->get_starting_frame()>this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames()) - { - warning("Starting frame is %d. Generally, it should be a late frame,\nbut in any case it should be less than the number of frames %d\nand at least 1.",this->_patlak_plot_sptr->get_starting_frame(), this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames()); - return Succeeded::no; - } + if (this->_patlak_plot_sptr->get_starting_frame() <= 0 || + this->_patlak_plot_sptr->get_starting_frame() > this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames()) { + warning("Starting frame is %d. Generally, it should be a late frame,\nbut in any case it should be less than the number of " + "frames %d\nand at least 1.", + this->_patlak_plot_sptr->get_starting_frame(), + this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames()); + return Succeeded::no; + } { - const shared_ptr > - density_template_sptr((target_sptr->construct_single_density(1)).get_empty_copy()); + const shared_ptr> density_template_sptr( + (target_sptr->construct_single_density(1)).get_empty_copy()); const shared_ptr scanner_sptr(new Scanner(*proj_data_info_sptr->get_scanner_ptr())); - this->_dyn_image_template= - DynamicDiscretisedDensity(this->_patlak_plot_sptr->get_time_frame_definitions(), - this->_dyn_proj_data_sptr->get_start_time_in_secs_since_1970(), - scanner_sptr, - density_template_sptr); + this->_dyn_image_template = DynamicDiscretisedDensity(this->_patlak_plot_sptr->get_time_frame_definitions(), + this->_dyn_proj_data_sptr->get_start_time_in_secs_since_1970(), + scanner_sptr, density_template_sptr); // construct _single_frame_obj_funcs - this->_single_frame_obj_funcs.resize(this->_patlak_plot_sptr->get_starting_frame(),this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames()); - - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame();frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames();++frame_num) - { - this->_single_frame_obj_funcs[frame_num].set_projector_pair_sptr(this->_projector_pair_ptr); - this->_single_frame_obj_funcs[frame_num].set_proj_data_sptr(this->_dyn_proj_data_sptr->get_proj_data_sptr(frame_num)); - this->_single_frame_obj_funcs[frame_num].set_max_segment_num_to_process(this->_max_segment_num_to_process); - this->_single_frame_obj_funcs[frame_num].set_zero_seg0_end_planes(this->_zero_seg0_end_planes!=0); - if(!is_null_ptr(this->_additive_dyn_proj_data_sptr)) - this->_single_frame_obj_funcs[frame_num].set_additive_proj_data_sptr(this->_additive_dyn_proj_data_sptr->get_proj_data_sptr(frame_num)); - this->_single_frame_obj_funcs[frame_num].set_num_subsets(this->num_subsets); - this->_single_frame_obj_funcs[frame_num].set_frame_num(frame_num); - this->_single_frame_obj_funcs[frame_num].set_frame_definitions(this->_patlak_plot_sptr->get_time_frame_definitions()); - this->_single_frame_obj_funcs[frame_num].set_normalisation_sptr(this->_normalisation_sptr); - this->_single_frame_obj_funcs[frame_num].set_recompute_sensitivity(this->get_recompute_sensitivity()); - this->_single_frame_obj_funcs[frame_num].set_use_subset_sensitivities(this->get_use_subset_sensitivities()); - if(this->_single_frame_obj_funcs[frame_num].set_up(density_template_sptr) != Succeeded::yes) - error("Single frame objective functions is not set correctly!"); - } - }//_single_frame_obj_funcs[frame_num] + this->_single_frame_obj_funcs.resize(this->_patlak_plot_sptr->get_starting_frame(), + this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames()); + + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) { + this->_single_frame_obj_funcs[frame_num].set_projector_pair_sptr(this->_projector_pair_ptr); + this->_single_frame_obj_funcs[frame_num].set_proj_data_sptr(this->_dyn_proj_data_sptr->get_proj_data_sptr(frame_num)); + this->_single_frame_obj_funcs[frame_num].set_max_segment_num_to_process(this->_max_segment_num_to_process); + this->_single_frame_obj_funcs[frame_num].set_zero_seg0_end_planes(this->_zero_seg0_end_planes != 0); + if (!is_null_ptr(this->_additive_dyn_proj_data_sptr)) + this->_single_frame_obj_funcs[frame_num].set_additive_proj_data_sptr( + this->_additive_dyn_proj_data_sptr->get_proj_data_sptr(frame_num)); + this->_single_frame_obj_funcs[frame_num].set_num_subsets(this->num_subsets); + this->_single_frame_obj_funcs[frame_num].set_frame_num(frame_num); + this->_single_frame_obj_funcs[frame_num].set_frame_definitions(this->_patlak_plot_sptr->get_time_frame_definitions()); + this->_single_frame_obj_funcs[frame_num].set_normalisation_sptr(this->_normalisation_sptr); + this->_single_frame_obj_funcs[frame_num].set_recompute_sensitivity(this->get_recompute_sensitivity()); + this->_single_frame_obj_funcs[frame_num].set_use_subset_sensitivities(this->get_use_subset_sensitivities()); + if (this->_single_frame_obj_funcs[frame_num].set_up(density_template_sptr) != Succeeded::yes) + error("Single frame objective functions is not set correctly!"); + } + } //_single_frame_obj_funcs[frame_num] return Succeeded::yes; } -template +template void -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -set_input_data(const shared_ptr & arg) -{ - this->_dyn_proj_data_sptr = dynamic_pointer_cast(arg); +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::set_input_data(const shared_ptr& arg) { + this->_dyn_proj_data_sptr = dynamic_pointer_cast(arg); } -template +template const DynamicProjData& -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -get_input_data() const -{ +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::get_input_data() const { return *this->_dyn_proj_data_sptr; } -template +template void -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -set_additive_proj_data_sptr(const shared_ptr &arg) -{ - this->_additive_dyn_proj_data_sptr = dynamic_pointer_cast(arg); +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::set_additive_proj_data_sptr( + const shared_ptr& arg) { + this->_additive_dyn_proj_data_sptr = dynamic_pointer_cast(arg); } -template +template void -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -set_normalisation_sptr(const shared_ptr& arg) -{ -// this->normalisation_sptr = arg; - error("Not implemeted yet"); +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::set_normalisation_sptr( + const shared_ptr& arg) { + // this->normalisation_sptr = arg; + error("Not implemeted yet"); } - /************************************************************************* functions that compute the value/gradient of the objective function etc *************************************************************************/ -template +template void -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) -{ - if (subset_num<0 || subset_num>=this->get_num_subsets()) +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData< + TargetT>::compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, const TargetT& current_estimate, + const int subset_num) { + if (subset_num < 0 || subset_num >= this->get_num_subsets()) error("compute_sub_gradient_without_penalty subset_num out-of-range error"); - DynamicDiscretisedDensity dyn_gradient=this->_dyn_image_template; - DynamicDiscretisedDensity dyn_image_estimate=this->_dyn_image_template; + DynamicDiscretisedDensity dyn_gradient = this->_dyn_image_template; + DynamicDiscretisedDensity dyn_image_estimate = this->_dyn_image_template; - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame();frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames();++frame_num) - std::fill(dyn_image_estimate[frame_num].begin_all(), - dyn_image_estimate[frame_num].end_all(), - 1.F); + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) + std::fill(dyn_image_estimate[frame_num].begin_all(), dyn_image_estimate[frame_num].end_all(), 1.F); - this->_patlak_plot_sptr->get_dynamic_image_from_parametric_image(dyn_image_estimate,current_estimate) ; - - // loop over single_frame and use model_matrix - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame();frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames();++frame_num) - { - std::fill(dyn_gradient[frame_num].begin_all(), - dyn_gradient[frame_num].end_all(), - 1.F); + this->_patlak_plot_sptr->get_dynamic_image_from_parametric_image(dyn_image_estimate, current_estimate); + // loop over single_frame and use model_matrix + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) { + std::fill(dyn_gradient[frame_num].begin_all(), dyn_gradient[frame_num].end_all(), 1.F); - this->_single_frame_obj_funcs[frame_num]. - compute_sub_gradient_without_penalty_plus_sensitivity(dyn_gradient[frame_num], - dyn_image_estimate[frame_num], - subset_num); - } + this->_single_frame_obj_funcs[frame_num].compute_sub_gradient_without_penalty_plus_sensitivity( + dyn_gradient[frame_num], dyn_image_estimate[frame_num], subset_num); + } - this->_patlak_plot_sptr->multiply_dynamic_image_with_model_gradient(gradient, - dyn_gradient) ; + this->_patlak_plot_sptr->multiply_dynamic_image_with_model_gradient(gradient, dyn_gradient); } -template +template double -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num) -{ - assert(subset_num>=0); - assert(subset_numnum_subsets); +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::actual_compute_objective_function_without_penalty( + const TargetT& current_estimate, const int subset_num) { + assert(subset_num >= 0); + assert(subset_num < this->num_subsets); double result = 0.; - DynamicDiscretisedDensity dyn_image_estimate=this->_dyn_image_template; + DynamicDiscretisedDensity dyn_image_estimate = this->_dyn_image_template; // TODO why fill with 1? - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame();frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames();++frame_num) - std::fill(dyn_image_estimate[frame_num].begin_all(), - dyn_image_estimate[frame_num].end_all(), - 1.F); - this->_patlak_plot_sptr->get_dynamic_image_from_parametric_image(dyn_image_estimate,current_estimate) ; - + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) + std::fill(dyn_image_estimate[frame_num].begin_all(), dyn_image_estimate[frame_num].end_all(), 1.F); + this->_patlak_plot_sptr->get_dynamic_image_from_parametric_image(dyn_image_estimate, current_estimate); + // loop over single_frame - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame(); - frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); - ++frame_num) - { - result += - this->_single_frame_obj_funcs[frame_num]. - compute_objective_function_without_penalty(dyn_image_estimate[frame_num], - subset_num); - } + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) { + result += this->_single_frame_obj_funcs[frame_num].compute_objective_function_without_penalty(dyn_image_estimate[frame_num], + subset_num); + } return result; } -template +template void -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const -{ - DynamicDiscretisedDensity dyn_sensitivity=this->_dyn_image_template; +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::add_subset_sensitivity(TargetT& sensitivity, + const int subset_num) const { + DynamicDiscretisedDensity dyn_sensitivity = this->_dyn_image_template; // loop over single_frame and use model_matrix - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame();frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames();++frame_num) - { - dyn_sensitivity[frame_num]=this->_single_frame_obj_funcs[frame_num].get_subset_sensitivity(subset_num); - // add_subset_sensitivity(dyn_sensitivity[frame_num],subset_num); - } + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) { + dyn_sensitivity[frame_num] = this->_single_frame_obj_funcs[frame_num].get_subset_sensitivity(subset_num); + // add_subset_sensitivity(dyn_sensitivity[frame_num],subset_num); + } - this->_patlak_plot_sptr->multiply_dynamic_image_with_model_gradient_and_add_to_input(sensitivity, - dyn_sensitivity) ; + this->_patlak_plot_sptr->multiply_dynamic_image_with_model_gradient_and_add_to_input(sensitivity, dyn_sensitivity); } -template +template Succeeded -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const -{ +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData< + TargetT>::actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, const TargetT& input, + const int subset_num) const { { std::string explanation; - if (!input.has_same_characteristics(this->get_sensitivity(), - explanation)) - { - warning("PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:\n" - "sensitivity and input for add_multiplication_with_approximate_Hessian_without_penalty\n" - "should have the same characteristics.\n%s", - explanation.c_str()); - return Succeeded::no; - } - } + if (!input.has_same_characteristics(this->get_sensitivity(), explanation)) { + warning("PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:\n" + "sensitivity and input for add_multiplication_with_approximate_Hessian_without_penalty\n" + "should have the same characteristics.\n%s", + explanation.c_str()); + return Succeeded::no; + } + } #ifndef NDEBUG - info(boost::format("INPUT max: (%1% , %2%)") % input.construct_single_density(1).find_max() % input.construct_single_density(2).find_max()); -#endif //NDEBUG - DynamicDiscretisedDensity dyn_input=this->_dyn_image_template; - DynamicDiscretisedDensity dyn_output=this->_dyn_image_template; - this->_patlak_plot_sptr->get_dynamic_image_from_parametric_image(dyn_input,input) ; - - VectorWithOffset scale_factor(this->_patlak_plot_sptr->get_starting_frame(),this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames()); - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame(); - frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); - ++frame_num) - { - assert(dyn_input[frame_num].find_max()==dyn_input[frame_num].find_min()); - if (dyn_input[frame_num].find_max()==dyn_input[frame_num].find_min() && dyn_input[frame_num].find_min()>0.F) - scale_factor[frame_num]=dyn_input[frame_num].find_max(); - else - error("The input image should be uniform even after multiplying with the Patlak Plot.\n"); - -/*! /note This is used to avoid higher values than these set in the precompute_denominator_of_conditioner_without_penalty() function. -/sa for more information see the recon_array_functions.cxx and the value of the max_quotient (originaly set to 10000.F) -*/ - dyn_input[frame_num]/=scale_factor[frame_num]; + info(boost::format("INPUT max: (%1% , %2%)") % input.construct_single_density(1).find_max() % + input.construct_single_density(2).find_max()); +#endif // NDEBUG + DynamicDiscretisedDensity dyn_input = this->_dyn_image_template; + DynamicDiscretisedDensity dyn_output = this->_dyn_image_template; + this->_patlak_plot_sptr->get_dynamic_image_from_parametric_image(dyn_input, input); + + VectorWithOffset scale_factor(this->_patlak_plot_sptr->get_starting_frame(), + this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames()); + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) { + assert(dyn_input[frame_num].find_max() == dyn_input[frame_num].find_min()); + if (dyn_input[frame_num].find_max() == dyn_input[frame_num].find_min() && dyn_input[frame_num].find_min() > 0.F) + scale_factor[frame_num] = dyn_input[frame_num].find_max(); + else + error("The input image should be uniform even after multiplying with the Patlak Plot.\n"); + + /*! /note This is used to avoid higher values than these set in the precompute_denominator_of_conditioner_without_penalty() + function. /sa for more information see the recon_array_functions.cxx and the value of the max_quotient (originaly set to + 10000.F) + */ + dyn_input[frame_num] /= scale_factor[frame_num]; #ifndef NDEBUG - info(boost::format("scale factor[%1%]: %2%") % frame_num % scale_factor[frame_num]); - info(boost::format("dyn_input[%1%] max after scale: %2%") % frame_num % dyn_input[frame_num].find_max()); -#endif //NDEBUG - this->_single_frame_obj_funcs[frame_num]. - add_multiplication_with_approximate_sub_Hessian_without_penalty(dyn_output[frame_num], - dyn_input[frame_num], - subset_num); + info(boost::format("scale factor[%1%]: %2%") % frame_num % scale_factor[frame_num]); + info(boost::format("dyn_input[%1%] max after scale: %2%") % frame_num % dyn_input[frame_num].find_max()); +#endif // NDEBUG + this->_single_frame_obj_funcs[frame_num].add_multiplication_with_approximate_sub_Hessian_without_penalty( + dyn_output[frame_num], dyn_input[frame_num], subset_num); #ifndef NDEBUG - info(boost::format("dyn_output[%1%] max before scale: %2%") % frame_num % dyn_output[frame_num].find_max()); -#endif //NDEBUG - dyn_output[frame_num]*=scale_factor[frame_num]; + info(boost::format("dyn_output[%1%] max before scale: %2%") % frame_num % dyn_output[frame_num].find_max()); +#endif // NDEBUG + dyn_output[frame_num] *= scale_factor[frame_num]; #ifndef NDEBUG - info(boost::format("dyn_output[%1%] max after scale: %2%") % frame_num % dyn_output[frame_num].find_max()); -#endif //NDEBUG - } // end of loop over frames + info(boost::format("dyn_output[%1%] max after scale: %2%") % frame_num % dyn_output[frame_num].find_max()); +#endif // NDEBUG + } // end of loop over frames shared_ptr unnormalised_temp(output.get_empty_copy()); shared_ptr temp(output.get_empty_copy()); - this->_patlak_plot_sptr->multiply_dynamic_image_with_model_gradient(*unnormalised_temp, - dyn_output) ; - // Trick to use a better step size for the two parameters. - (this->_patlak_plot_sptr->get_model_matrix()).normalise_parametric_image_with_model_sum(*temp,*unnormalised_temp) ; + this->_patlak_plot_sptr->multiply_dynamic_image_with_model_gradient(*unnormalised_temp, dyn_output); + // Trick to use a better step size for the two parameters. + (this->_patlak_plot_sptr->get_model_matrix()).normalise_parametric_image_with_model_sum(*temp, *unnormalised_temp); #ifndef NDEBUG - info(boost::format("TEMP max: (%1% , %2%)") % temp->construct_single_density(1).find_max() % temp->construct_single_density(2).find_max()); + info(boost::format("TEMP max: (%1% , %2%)") % temp->construct_single_density(1).find_max() % + temp->construct_single_density(2).find_max()); // Writing images write_to_file("all_params_one_input.img", input); write_to_file("temp_denominator.img", *temp); dyn_input.write_to_ecat7("dynamic_input_from_all_params_one.img"); dyn_output.write_to_ecat7("dynamic_precomputed_denominator.img"); DynamicProjData temp_projdata = this->get_dyn_proj_data(); - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame(); - frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); - ++frame_num) - temp_projdata.set_proj_data_sptr(this->_single_frame_obj_funcs[frame_num].get_proj_data_sptr(),frame_num); - + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) + temp_projdata.set_proj_data_sptr(this->_single_frame_obj_funcs[frame_num].get_proj_data_sptr(), frame_num); + temp_projdata.write_to_ecat7("DynamicProjections.S"); #endif // NDEBUG // output += temp typename TargetT::full_iterator out_iter = output.begin_all(); typename TargetT::full_iterator out_end = output.end_all(); typename TargetT::const_full_iterator temp_iter = temp->begin_all_const(); - while (out_iter != out_end) - { - *out_iter += *temp_iter; - ++out_iter; ++temp_iter; - } + while (out_iter != out_end) { + *out_iter += *temp_iter; + ++out_iter; + ++temp_iter; + } #ifndef NDEBUG - info(boost::format("OUTPUT max: (%1% , %2%)") % output.construct_single_density(1).find_max() % output.construct_single_density(2).find_max()); + info(boost::format("OUTPUT max: (%1% , %2%)") % output.construct_single_density(1).find_max() % + output.construct_single_density(2).find_max()); #endif // NDEBUG - return Succeeded::yes; } -template +template Succeeded -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input, - const int subset_num) const -{ +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData< + TargetT>::actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, const TargetT& current_image_estimate, + const TargetT& input, const int subset_num) const { { // check argument characteristics std::string explanation; - if (!input.has_same_characteristics(this->get_sensitivity(), explanation)) - { + if (!input.has_same_characteristics(this->get_sensitivity(), explanation)) { warning("PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:\n" "sensitivity and input for actual_accumulate_sub_Hessian_times_input_without_penalty\n" "should have the same characteristics.\n%s", @@ -633,74 +574,65 @@ actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, return Succeeded::no; } - if (!current_image_estimate.has_same_characteristics(this->get_sensitivity(), explanation)) - { + if (!current_image_estimate.has_same_characteristics(this->get_sensitivity(), explanation)) { warning("PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:\n" "sensitivity and current_image_estimate for actual_accumulate_sub_Hessian_times_input_without_penalty\n" "should have the same characteristics.\n%s", explanation.c_str()); return Succeeded::no; } - } #ifndef NDEBUG - info(boost::format("INPUT max: (%1% , %2%)") % input.construct_single_density(1).find_max() % input.construct_single_density(2).find_max()); -#endif //NDEBUG - DynamicDiscretisedDensity dyn_input=this->_dyn_image_template; - DynamicDiscretisedDensity dyn_current_image_estimate=this->_dyn_image_template; - DynamicDiscretisedDensity dyn_output=this->_dyn_image_template; + info(boost::format("INPUT max: (%1% , %2%)") % input.construct_single_density(1).find_max() % + input.construct_single_density(2).find_max()); +#endif // NDEBUG + DynamicDiscretisedDensity dyn_input = this->_dyn_image_template; + DynamicDiscretisedDensity dyn_current_image_estimate = this->_dyn_image_template; + DynamicDiscretisedDensity dyn_output = this->_dyn_image_template; this->_patlak_plot_sptr->get_dynamic_image_from_parametric_image(dyn_input, input); this->_patlak_plot_sptr->get_dynamic_image_from_parametric_image(dyn_current_image_estimate, current_image_estimate); - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame(); - frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); - ++frame_num) - { - assert(dyn_input[frame_num].find_max()==dyn_input[frame_num].find_min()); - this->_single_frame_obj_funcs[frame_num]. - accumulate_sub_Hessian_times_input_without_penalty(dyn_output[frame_num], - dyn_current_image_estimate[frame_num], - dyn_input[frame_num], - subset_num); + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) { + assert(dyn_input[frame_num].find_max() == dyn_input[frame_num].find_min()); + this->_single_frame_obj_funcs[frame_num].accumulate_sub_Hessian_times_input_without_penalty( + dyn_output[frame_num], dyn_current_image_estimate[frame_num], dyn_input[frame_num], subset_num); } // end of loop over frames shared_ptr unnormalised_temp(output.get_empty_copy()); shared_ptr temp(output.get_empty_copy()); - this->_patlak_plot_sptr->multiply_dynamic_image_with_model_gradient(*unnormalised_temp, - dyn_output) ; + this->_patlak_plot_sptr->multiply_dynamic_image_with_model_gradient(*unnormalised_temp, dyn_output); // Trick to use a better step size for the two parameters. - (this->_patlak_plot_sptr->get_model_matrix()).normalise_parametric_image_with_model_sum(*temp,*unnormalised_temp) ; + (this->_patlak_plot_sptr->get_model_matrix()).normalise_parametric_image_with_model_sum(*temp, *unnormalised_temp); #ifndef NDEBUG - info(boost::format("TEMP max: (%1% , %2%)") % temp->construct_single_density(1).find_max() % temp->construct_single_density(2).find_max()); -// Writing images -write_to_file("all_params_one_input.img", input); -write_to_file("temp_denominator.img", *temp); -dyn_input.write_to_ecat7("dynamic_input_from_all_params_one.img"); -dyn_output.write_to_ecat7("dynamic_precomputed_denominator.img"); -DynamicProjData temp_projdata = this->get_dyn_proj_data(); -for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame(); - frame_num<=this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); - ++frame_num) -temp_projdata.set_proj_data_sptr(this->_single_frame_obj_funcs[frame_num].get_proj_data_sptr(),frame_num); - -temp_projdata.write_to_ecat7("DynamicProjections.S"); + info(boost::format("TEMP max: (%1% , %2%)") % temp->construct_single_density(1).find_max() % + temp->construct_single_density(2).find_max()); + // Writing images + write_to_file("all_params_one_input.img", input); + write_to_file("temp_denominator.img", *temp); + dyn_input.write_to_ecat7("dynamic_input_from_all_params_one.img"); + dyn_output.write_to_ecat7("dynamic_precomputed_denominator.img"); + DynamicProjData temp_projdata = this->get_dyn_proj_data(); + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_time_frame_definitions().get_num_frames(); ++frame_num) + temp_projdata.set_proj_data_sptr(this->_single_frame_obj_funcs[frame_num].get_proj_data_sptr(), frame_num); + + temp_projdata.write_to_ecat7("DynamicProjections.S"); #endif // NDEBUG // output += temp typename TargetT::full_iterator out_iter = output.begin_all(); typename TargetT::full_iterator out_end = output.end_all(); typename TargetT::const_full_iterator temp_iter = temp->begin_all_const(); - while (out_iter != out_end) - { + while (out_iter != out_end) { *out_iter += *temp_iter; - ++out_iter; ++temp_iter; + ++out_iter; + ++temp_iter; } #ifndef NDEBUG - info(boost::format("OUTPUT max: (%1% , %2%)") % output.construct_single_density(1).find_max() % output.construct_single_density(2).find_max()); + info(boost::format("OUTPUT max: (%1% , %2%)") % output.construct_single_density(1).find_max() % + output.construct_single_density(2).find_max()); #endif // NDEBUG - return Succeeded::yes; } END_NAMESPACE_STIR - - diff --git a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.h b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.h index a42e2ba0df..16ffcb0128 100644 --- a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.h +++ b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.h @@ -30,24 +30,23 @@ START_NAMESPACE_STIR - /*! \ingroup GeneralisedObjectiveFunction - \brief a base class for LogLikelihood of independent Poisson variables + \brief a base class for LogLikelihood of independent Poisson variables where the mean values are linear combinations of the parameters. Suppose the measured data \f$y\f$ are statistically independent and - Poisson distributed with mean \f$\bar y\f$. The log likelihood is then + Poisson distributed with mean \f$\bar y\f$. The log likelihood is then given by \f[ L(y\;\bar y) = \sum_b y_b log \bar y_b - \mathrm{log} y_b! - \bar y_b \f] - + If the means are modeled by some functions of some parameters - \f$Y(\lambda)\f$, the gradient w.r.t. those parameters follows + \f$Y(\lambda)\f$, the gradient w.r.t. those parameters follows immediately as \f[ {\partial L \over \partial \lambda_v} = - \sum_b \left( {y_b \over Y_b} - 1 \right) + \sum_b \left( {y_b \over Y_b} - 1 \right) {\partial Y_b \over \partial \lambda_v } \f] @@ -65,8 +64,8 @@ START_NAMESPACE_STIR \f[ {\partial L \over \partial \lambda_v} = \sum_b P_{bv} {y_b \over Y_b} - P_v \f] - where - \f[ + where + \f[ P_v = \sum_b P_{bv} \f] where the sum is over all possible bins (not only those where @@ -75,14 +74,14 @@ START_NAMESPACE_STIR probability of detecting a count (in any bin) originating from \f$v\f$. This class computes the gradient as a sum of these two terms. The - sensitivity has to be computed by the virtual function + sensitivity has to be computed by the virtual function \c add_subset_sensitivity(). The sum is computed by \c compute_sub_gradient_without_penalty_plus_sensitivity(). The reason for this is that the sensitivity is data-independent, and can be computed only once. See also PoissonLogLikelihoodWithLinearModelForMeanAndListModeData. - + \par Relation with Kullback-Leibler distance Note that up to terms independent of \f$\bar y\f$, the log likelihood @@ -91,14 +90,14 @@ START_NAMESPACE_STIR \f[ \mathrm{KL}(y,\bar y) = \sum_b y_b \mathrm{log}(y_b/\bar y_b) + \bar y_b - y_b \f] - which has the nice property that \f$\mathrm{KL}(y,\bar y)=0\f$ implies that + which has the nice property that \f$\mathrm{KL}(y,\bar y)=0\f$ implies that \f$y=\bar y\f$. \par Parameters for parsing Defaults are indicated below \verbatim - ; specifies if we keep separate sensitivity images (which is more accurate and is - ; recommended) or if we assume the subsets are exactly balanced + ; specifies if we keep separate sensitivity images (which is more accurate and is + ; recommended) or if we assume the subsets are exactly balanced ; and hence compute the subset-senstivity as sensitivity/num_subsets (this uses less memory). use_subset_sensitivities := 1 ; for recomputing sensitivity, even if a filename is specified @@ -114,25 +113,22 @@ START_NAMESPACE_STIR \endverbatim \par Terminology - We currently use \c sub_gradient for the gradient of the likelihood of the subset (not + We currently use \c sub_gradient for the gradient of the likelihood of the subset (not the mathematical subgradient). */ template -class PoissonLogLikelihoodWithLinearModelForMean: -public GeneralisedObjectiveFunction -{ - private: +class PoissonLogLikelihoodWithLinearModelForMean : public GeneralisedObjectiveFunction { +private: typedef GeneralisedObjectiveFunction base_type; - public: - - //PoissonLogLikelihoodWithLinearModelForMean(); +public: + // PoissonLogLikelihoodWithLinearModelForMean(); //! Implementation in terms of compute_sub_gradient_without_penalty_plus_sensitivity() - /*! \warning If separate subsensitivities are not used, we just subtract the total + /*! \warning If separate subsensitivities are not used, we just subtract the total sensitivity divided by the number of subsets. - This is fine for some algorithms as the sum over all the subsets is - equal to gradient of the objective function (without prior). + This is fine for some algorithms as the sum over all the subsets is + equal to gradient of the objective function (without prior). Other algorithms do not behave very stable under this approximation however. So, currently setup() will return an error if !subsets_are_approximately_balanced() and subset sensitivities @@ -140,13 +136,10 @@ public GeneralisedObjectiveFunction \see get_use_subset_sensitivities() */ - virtual void - compute_sub_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num); + virtual void compute_sub_gradient_without_penalty(TargetT& gradient, const TargetT& current_estimate, const int subset_num); //! This should compute the gradient of the (unregularised) objective function plus the (sub)sensitivity - /*! + /*! This function is used for instance by OSMAPOSL. This computes @@ -156,14 +149,12 @@ public GeneralisedObjectiveFunction (see the class general documentation). The sum will however be restricted to a subset. */ - virtual void - compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) =0; + virtual void compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, const TargetT& current_estimate, + const int subset_num) = 0; //! set-up sensitivity etc if possible /*! If \c recompute_sensitivity is \c false, we will try to - read it from either \c subset_sensitivity_filenames or \c sensitivity_filename, + read it from either \c subset_sensitivity_filenames or \c sensitivity_filename, depending on the setting of get_use_subset_sensitivities(). If \c sensitivity_filename is equal @@ -174,7 +165,7 @@ public GeneralisedObjectiveFunction Calls set_up_before_sensitivity(). */ - virtual Succeeded set_up(shared_ptr const& target_sptr); + virtual Succeeded set_up(shared_ptr const& target_sptr); //! Get a const reference to the total sensitivity const TargetT& get_sensitivity() const; @@ -182,12 +173,11 @@ public GeneralisedObjectiveFunction const TargetT& get_subset_sensitivity(const int subset_num) const; //! Add subset sensitivity to existing data - virtual void - add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const = 0; + virtual void add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const = 0; //! find out if subset_sensitivities are used /*! If \c true, the sub_gradient and subset_sensitivity functions use the sensitivity - for the given subset, otherwise, we use the total sensitivity divided by the number + for the given subset, otherwise, we use the total sensitivity divided by the number of subsets. The latter uses less memory, but is less stable for most (all?) algorithms. */ bool get_use_subset_sensitivities() const; @@ -208,7 +198,7 @@ public GeneralisedObjectiveFunction /*! \name Functions to set parameters This can be used as alternative to the parsing mechanism. \warning After using any of these, you have to call set_up(). - \warning Be careful with setting shared pointers. If you modify the objects in + \warning Be careful with setting shared pointers. If you modify the objects in one place, all objects that use the shared pointer will be affected. */ //@{ @@ -234,24 +224,21 @@ public GeneralisedObjectiveFunction /*! The implementation checks if the sensitivity of a voxel is zero. If so, it will the target voxel will be assigned the desired value. */ - void - fill_nonidentifiable_target_parameters(TargetT& target, const float value ) const; - - private: + void fill_nonidentifiable_target_parameters(TargetT& target, const float value) const; +private: std::string sensitivity_filename; std::string subsensitivity_filenames; bool recompute_sensitivity; bool use_subset_sensitivities; - VectorWithOffset > subsensitivity_sptrs; + VectorWithOffset> subsensitivity_sptrs; shared_ptr sensitivity_sptr; //! Get the subset sensitivity sptr - shared_ptr - get_subset_sensitivity_sptr(const int subset_num) const; + shared_ptr get_subset_sensitivity_sptr(const int subset_num) const; //! compute total from subsensitivity or vice versa - /*! This function will be called by set_up() after reading new images, and/or + /*! This function will be called by set_up() after reading new images, and/or by compute_sensitivities(). if get_use_subset_sensitivities() is true, the total sensitivity is computed @@ -261,25 +248,23 @@ public GeneralisedObjectiveFunction void set_total_or_subset_sensitivities(); protected: - //! set-up specifics for the derived class - virtual Succeeded - set_up_before_sensitivity(shared_ptr const& target_sptr) = 0; + //! set-up specifics for the derived class + virtual Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr) = 0; //! compute subset and total sensitivity /*! This function fills in the sensitivity data by calling add_subset_sensitivity() - for all subsets. It assumes that the subsensitivity for the 1st subset has been + for all subsets. It assumes that the subsensitivity for the 1st subset has been allocated already (and is the correct size). */ void compute_sensitivities(); - //! Sets defaults for parsing + //! Sets defaults for parsing /*! Resets \c sensitivity_filename, \c subset_sensitivity_filenames to empty, \c recompute_sensitivity to \c false, and \c use_subset_sensitivities to false. */ virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h index 0df1484168..3066284043 100644 --- a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h +++ b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h @@ -7,12 +7,12 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! @@ -43,40 +43,37 @@ START_NAMESPACE_STIR /*! \ingroup GeneralisedObjectiveFunction - \brief a base class for LogLikelihood of independent Poisson variables + \brief a base class for LogLikelihood of independent Poisson variables where the mean values are linear combinations of the gated images. \f[ \begin{array}{lcl} - \Lambda_{\nu}^{(s+1)}&&=\Lambda_{\nu}^{(s)} \frac{1}{ \sum\limits_{b\in S_{l}, g} \sum\limits_{\nu'} \hat{W}^{-1} _{\nu'g\rightarrow \nu}P_{\nu' b}A_{bg}+\beta \nabla_{\Lambda_{\nu}} E_{\nu}^{(s)}}\\ - &&\times \sum\limits_{b\in S_{l}, g} \sum\limits_{\nu'}\left(\hat{W}^{-1} _{\nu'g\rightarrow \nu}P_{\nu' b}\frac{Y_{bg}}{\sum\limits_{\tilde{\nu}}P_{b\tilde{\nu}}\sum\limits_{\tilde{\nu}'}\hat{W} _{\tilde{\nu}'\rightarrow \tilde{\nu}g}\Lambda_{\tilde{\nu}'}^{(s)}+\frac{B_{bg}}{A_{bg}}}\right) - \end{array} -\f] - \par Parameters for parsing - + \Lambda_{\nu}^{(s+1)}&&=\Lambda_{\nu}^{(s)} \frac{1}{ \sum\limits_{b\in S_{l}, g} \sum\limits_{\nu'} \hat{W}^{-1} +_{\nu'g\rightarrow \nu}P_{\nu' b}A_{bg}+\beta \nabla_{\Lambda_{\nu}} E_{\nu}^{(s)}}\\ + &&\times \sum\limits_{b\in S_{l}, g} \sum\limits_{\nu'}\left(\hat{W}^{-1} _{\nu'g\rightarrow \nu}P_{\nu' +b}\frac{Y_{bg}}{\sum\limits_{\tilde{\nu}}P_{b\tilde{\nu}}\sum\limits_{\tilde{\nu}'}\hat{W} _{\tilde{\nu}'\rightarrow +\tilde{\nu}g}\Lambda_{\tilde{\nu}'}^{(s)}+\frac{B_{bg}}{A_{bg}}}\right) \end{array} \f] \par Parameters for parsing + For more information: Tsoumpas et al (2013) Physics in Medicine and Biology */ template -class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion: -public RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > -{ - private: - typedef RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > base_type; - typedef PoissonLogLikelihoodWithLinearModelForMeanAndProjData > SingleGateObjFunc ; +class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion + : public RegisteredParsingObject, + GeneralisedObjectiveFunction, PoissonLogLikelihoodWithLinearModelForMean> { +private: + typedef RegisteredParsingObject, + GeneralisedObjectiveFunction, PoissonLogLikelihoodWithLinearModelForMean> + base_type; + typedef PoissonLogLikelihoodWithLinearModelForMeanAndProjData> SingleGateObjFunc; VectorWithOffset _single_gate_obj_funcs; TimeGateDefinitions _time_gate_definitions; - public: - +public: //! Name which will be used when parsing a GeneralisedObjectiveFunction object - static const char * const registered_name; + static const char* const registered_name; PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion(); @@ -84,38 +81,28 @@ public RegisteredParsingObject const& target_sptr); + virtual Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr); //! Add subset sensitivity to existing data - virtual void - add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const; + virtual void add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const; - virtual Succeeded - actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const; - virtual Succeeded - actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT &output, - const TargetT ¤t_image_estimate, - const TargetT &input, - const int subset_num) const; + virtual Succeeded actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, const TargetT& input, + const int subset_num) const; + virtual Succeeded actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, + const TargetT& current_image_estimate, + const TargetT& input, const int subset_num) const; - void set_time_gate_definitions(const TimeGateDefinitions & time_gate_definitions); + void set_time_gate_definitions(const TimeGateDefinitions& time_gate_definitions); /*! \name Functions to get parameters - \warning Be careful with changing shared pointers. If you modify the objects in + \warning Be careful with changing shared pointers. If you modify the objects in one place, all objects that use the shared pointer will be affected. */ //@{ @@ -134,7 +121,7 @@ public RegisteredParsingObject&); virtual void set_additive_proj_data_sptr(const shared_ptr&); - virtual void set_input_data(const shared_ptr &); + virtual void set_input_data(const shared_ptr&); virtual const GatedProjData& get_input_data() const; //@} - protected: +protected: //! Filename with input projection data std::string _input_filename; std::string _motion_vectors_filename_prefix; @@ -162,8 +149,7 @@ public RegisteredParsingObject target_parameter_parser; @@ -185,7 +171,8 @@ public RegisteredParsingObject -#include +#include // For Motion #include "stir/spatial_transformation/GatedSpatialTransformation.h" #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h" @@ -54,65 +54,53 @@ START_NAMESPACE_STIR -template -const char * const -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -registered_name = -"PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion"; +template +const char* const PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::registered_name = + "PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion"; -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_defaults() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_defaults() { base_type::set_defaults(); - this->_input_filename=""; - this->_max_segment_num_to_process=-1; // use all segments - //num_views_to_add=1; // KT 20/06/2001 disabled + this->_input_filename = ""; + this->_max_segment_num_to_process = -1; // use all segments + // num_views_to_add=1; // KT 20/06/2001 disabled - this->_gated_proj_data_sptr.reset(); + this->_gated_proj_data_sptr.reset(); this->_zero_seg0_end_planes = 0; - this->_reverse_motion_vectors_filename_prefix="0"; - this->_normalisation_gated_proj_data_filename="1"; + this->_reverse_motion_vectors_filename_prefix = "0"; + this->_normalisation_gated_proj_data_filename = "1"; this->_normalisation_gated_proj_data_sptr.reset(); // this->_reverse_motion_vectors_sptr=NULL; - this->_motion_vectors_filename_prefix="0"; + this->_motion_vectors_filename_prefix = "0"; // this->_motion_vectors_sptr=NULL; - this->_gate_definitions_filename="0"; + this->_gate_definitions_filename = "0"; // this->_time_gate_definitions_sptr=NULL; this->_additive_gated_proj_data_filename = "0"; this->_additive_gated_proj_data_sptr.reset(); #ifndef USE_PMRT // set default for _projector_pair_ptr - shared_ptr forward_projector_ptr - (new ForwardProjectorByBinUsingRayTracing()); - shared_ptr back_projector_ptr - (new BackProjectorByBinUsingInterpolation()); + shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingRayTracing()); + shared_ptr back_projector_ptr(new BackProjectorByBinUsingInterpolation()); #else - shared_ptr PM - (new ProjMatrixByBinUsingRayTracing()); - shared_ptr forward_projector_ptr - (new ForwardProjectorByBinUsingProjMatrixByBin(PM)); - shared_ptr back_projector_ptr - (new BackProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr back_projector_ptr(new BackProjectorByBinUsingProjMatrixByBin(PM)); #endif - this->_projector_pair_ptr.reset( - new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); + this->_projector_pair_ptr.reset(new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); this->target_parameter_parser.set_defaults(); } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -initialise_keymap() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion Parameters"); this->parser.add_stop_key("End PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion Parameters"); - this->parser.add_key("input filename",&this->_input_filename); + this->parser.add_key("input filename", &this->_input_filename); // parser.add_key("mash x views", &num_views_to_add); // KT 20/06/2001 disabled this->parser.add_key("maximum absolute segment number to process", &this->_max_segment_num_to_process); @@ -122,44 +110,40 @@ initialise_keymap() this->parser.add_parsing_key("Projector pair type", &this->_projector_pair_ptr); // Scatter correction - this->parser.add_key("additive sinograms",&this->_additive_gated_proj_data_filename); + this->parser.add_key("additive sinograms", &this->_additive_gated_proj_data_filename); // normalisation (and attenuation correction) this->parser.add_key("normalisation sinograms", &this->_normalisation_gated_proj_data_filename); - + // Motion Information this->parser.add_key("Gate Definitions filename", &this->_gate_definitions_filename); this->parser.add_key("Motion Vectors filename prefix", &this->_motion_vectors_filename_prefix); - this->parser.add_key("Reverse Motion Vectors filename prefix", &this->_reverse_motion_vectors_filename_prefix); + this->parser.add_key("Reverse Motion Vectors filename prefix", &this->_reverse_motion_vectors_filename_prefix); } -template +template bool -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -post_processing() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::post_processing() { if (base_type::post_processing() == true) return true; - if (this->_input_filename.length() == 0) - { warning("You need to specify an input filename"); return true; } - + if (this->_input_filename.length() == 0) { + warning("You need to specify an input filename"); + return true; + } + this->_gated_proj_data_sptr = GatedProjData::read_from_file(this->_input_filename); - + // image stuff this->target_parameter_parser.check_values(); - if (this->_additive_gated_proj_data_filename != "0") - { - info(boost::format("Reading additive projdata data %1%") % this->_additive_gated_proj_data_filename); - this->_additive_gated_proj_data_sptr = - GatedProjData::read_from_file(this->_additive_gated_proj_data_filename); - } - if (this->_normalisation_gated_proj_data_filename != "1") - { - info(boost::format("Reading normalisation projdata data %1%") % this->_normalisation_gated_proj_data_filename); - this->_normalisation_gated_proj_data_sptr = - GatedProjData::read_from_file(this->_normalisation_gated_proj_data_filename); - } + if (this->_additive_gated_proj_data_filename != "0") { + info(boost::format("Reading additive projdata data %1%") % this->_additive_gated_proj_data_filename); + this->_additive_gated_proj_data_sptr = GatedProjData::read_from_file(this->_additive_gated_proj_data_filename); + } + if (this->_normalisation_gated_proj_data_filename != "1") { + info(boost::format("Reading normalisation projdata data %1%") % this->_normalisation_gated_proj_data_filename); + this->_normalisation_gated_proj_data_sptr = GatedProjData::read_from_file(this->_normalisation_gated_proj_data_filename); + } this->_time_gate_definitions.read_gdef_file(this->_gate_definitions_filename); @@ -171,248 +155,226 @@ post_processing() } template -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion< + TargetT>::PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion() { this->set_defaults(); } template -TargetT * -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -construct_target_ptr() const -{ - return - this->target_parameter_parser.create(this->get_input_data()); +TargetT* +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::construct_target_ptr() const { + return this->target_parameter_parser.create(this->get_input_data()); } /*************************************************************** subset balancing ***************************************************************/ -template +template bool -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -actual_subsets_are_approximately_balanced(std::string& warning_message) const -{ // call actual_subsets_are_approximately_balanced() for first single_gate_obj_func +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::actual_subsets_are_approximately_balanced( + std::string& warning_message) const { // call actual_subsets_are_approximately_balanced() for first single_gate_obj_func if (this->get_time_gate_definitions().get_num_gates() == 0 || this->_single_gate_obj_funcs.size() == 0) error("PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:\n" - "actual_subsets_are_approximately_balanced called but no gates yet."); - else if(this->_single_gate_obj_funcs.size() != 0) - { - bool gates_are_balanced=true; - for(unsigned int gate_num=1;gate_num<=this->get_time_gate_definitions().get_num_gates();++gate_num) - gates_are_balanced &= this->_single_gate_obj_funcs[gate_num].subsets_are_approximately_balanced(warning_message); - return gates_are_balanced; - } - else + "actual_subsets_are_approximately_balanced called but no gates yet."); + else if (this->_single_gate_obj_funcs.size() != 0) { + bool gates_are_balanced = true; + for (unsigned int gate_num = 1; gate_num <= this->get_time_gate_definitions().get_num_gates(); ++gate_num) + gates_are_balanced &= this->_single_gate_obj_funcs[gate_num].subsets_are_approximately_balanced(warning_message); + return gates_are_balanced; + } else error("Something strange happened in PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:\n" - "actual_subsets_are_approximately_balanced called before setup()?"); - return - false; + "actual_subsets_are_approximately_balanced called before setup()?"); + return false; } /*************************************************************** get_ functions ***************************************************************/ template -const TimeGateDefinitions & -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_time_gate_definitions() const -{ return this->_time_gate_definitions; } +const TimeGateDefinitions& +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_time_gate_definitions() const { + return this->_time_gate_definitions; +} template -const GatedProjData& -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_gated_proj_data() const -{ return *this->_gated_proj_data_sptr; } +const GatedProjData& +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_gated_proj_data() const { + return *this->_gated_proj_data_sptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_gated_proj_data_sptr() const -{ return this->_gated_proj_data_sptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_gated_proj_data_sptr() const { + return this->_gated_proj_data_sptr; +} template -const int -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_max_segment_num_to_process() const -{ return this->_max_segment_num_to_process; } +const int +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_max_segment_num_to_process() const { + return this->_max_segment_num_to_process; +} template -const bool -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_zero_seg0_end_planes() const -{ return this->_zero_seg0_end_planes; } +const bool +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_zero_seg0_end_planes() const { + return this->_zero_seg0_end_planes; +} template -const GatedProjData& -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_additive_gated_proj_data() const -{ return *this->_additive_gated_proj_data_sptr; } +const GatedProjData& +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_additive_gated_proj_data() const { + return *this->_additive_gated_proj_data_sptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_additive_gated_proj_data_sptr() const -{ return this->_additive_gated_proj_data_sptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_additive_gated_proj_data_sptr() const { + return this->_additive_gated_proj_data_sptr; +} template -const GatedProjData& -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_normalisation_gated_proj_data() const -{ return *this->_normalisation_gated_proj_data_sptr; } +const GatedProjData& +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_normalisation_gated_proj_data() const { + return *this->_normalisation_gated_proj_data_sptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_normalisation_gated_proj_data_sptr() const -{ return this->_normalisation_gated_proj_data_sptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_normalisation_gated_proj_data_sptr() const { + return this->_normalisation_gated_proj_data_sptr; +} template -const ProjectorByBinPair& -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_projector_pair() const -{ return *this->_projector_pair_ptr; } +const ProjectorByBinPair& +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_projector_pair() const { + return *this->_projector_pair_ptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_projector_pair_sptr() const -{ return this->_projector_pair_ptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_projector_pair_sptr() const { + return this->_projector_pair_ptr; +} /*************************************************************** set_ functions ***************************************************************/ -template +template int -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_num_subsets(const int num_subsets) -{ - for(unsigned int gate_num=1;gate_num<=this->get_time_gate_definitions().get_num_gates();++gate_num) - { - if(this->_single_gate_obj_funcs.size() != 0) - if(this->_single_gate_obj_funcs[gate_num].set_num_subsets(num_subsets) != num_subsets) - error("set_num_subsets didn't work"); - } - this->num_subsets=num_subsets; +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_num_subsets(const int num_subsets) { + for (unsigned int gate_num = 1; gate_num <= this->get_time_gate_definitions().get_num_gates(); ++gate_num) { + if (this->_single_gate_obj_funcs.size() != 0) + if (this->_single_gate_obj_funcs[gate_num].set_num_subsets(num_subsets) != num_subsets) + error("set_num_subsets didn't work"); + } + this->num_subsets = num_subsets; return this->num_subsets; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_time_gate_definitions(const TimeGateDefinitions & time_gate_definitions) -{ this->_time_gate_definitions=time_gate_definitions; } +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_time_gate_definitions( + const TimeGateDefinitions& time_gate_definitions) { + this->_time_gate_definitions = time_gate_definitions; +} -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_input_data(const shared_ptr & arg) -{ - this->_gated_proj_data_sptr = dynamic_pointer_cast(arg); +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_input_data(const shared_ptr& arg) { + this->_gated_proj_data_sptr = dynamic_pointer_cast(arg); } -template +template const GatedProjData& -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -get_input_data() const -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::get_input_data() const { return *this->_gated_proj_data_sptr; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_additive_proj_data_sptr(const shared_ptr &arg) -{ - this->_additive_gated_proj_data_sptr = dynamic_pointer_cast(arg); +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_additive_proj_data_sptr( + const shared_ptr& arg) { + this->_additive_gated_proj_data_sptr = dynamic_pointer_cast(arg); } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_normalisation_sptr(const shared_ptr& arg) -{ -// this->normalisation_sptr = arg; - error("Not implemeted yet"); +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_normalisation_sptr( + const shared_ptr& arg) { + // this->normalisation_sptr = arg; + error("Not implemeted yet"); } /*************************************************************** set_up() ***************************************************************/ -template -Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_up_before_sensitivity(shared_ptr const& target_sptr) -{ - /*!todo define in the PoissonLogLikelihoodWithLinearModelForMean class to return Succeeded::yes +template +Succeeded +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_up_before_sensitivity( + shared_ptr const& target_sptr) { + /*!todo define in the PoissonLogLikelihoodWithLinearModelForMean class to return Succeeded::yes if (base_type::set_up_before_sensitivity(target_sptr) != Succeeded::yes) return Succeeded::no; */ - if (this->_max_segment_num_to_process==-1) - this->_max_segment_num_to_process = - (this->_gated_proj_data_sptr)->get_proj_data_sptr(1)->get_max_segment_num(); - - if (this->_max_segment_num_to_process > (this->_gated_proj_data_sptr)->get_proj_data_sptr(1)->get_max_segment_num()) - { - warning("_max_segment_num_to_process (%d) is too large", - this->_max_segment_num_to_process); - return Succeeded::no; - } + if (this->_max_segment_num_to_process == -1) + this->_max_segment_num_to_process = (this->_gated_proj_data_sptr)->get_proj_data_sptr(1)->get_max_segment_num(); + + if (this->_max_segment_num_to_process > (this->_gated_proj_data_sptr)->get_proj_data_sptr(1)->get_max_segment_num()) { + warning("_max_segment_num_to_process (%d) is too large", this->_max_segment_num_to_process); + return Succeeded::no; + } shared_ptr proj_data_info_sptr( - (this->_gated_proj_data_sptr->get_proj_data_sptr(1))->get_proj_data_info_sptr()->clone()); - proj_data_info_sptr-> - reduce_segment_range(-this->_max_segment_num_to_process, - +this->_max_segment_num_to_process); - - if (is_null_ptr(this->_projector_pair_ptr)) - { warning("You need to specify a projector pair"); return Succeeded::no; } - - if (this->num_subsets <= 0) - { - warning("Number of subsets %d should be larger than 0.", - this->num_subsets); - return Succeeded::no; - } + (this->_gated_proj_data_sptr->get_proj_data_sptr(1))->get_proj_data_info_sptr()->clone()); + proj_data_info_sptr->reduce_segment_range(-this->_max_segment_num_to_process, +this->_max_segment_num_to_process); + + if (is_null_ptr(this->_projector_pair_ptr)) { + warning("You need to specify a projector pair"); + return Succeeded::no; + } + + if (this->num_subsets <= 0) { + warning("Number of subsets %d should be larger than 0.", this->num_subsets); + return Succeeded::no; + } { - const shared_ptr > density_template_sptr(target_sptr->get_empty_copy()); // target_sptr appears not to be set up correctly + const shared_ptr> density_template_sptr( + target_sptr->get_empty_copy()); // target_sptr appears not to be set up correctly const shared_ptr scanner_sptr(new Scanner(*proj_data_info_sptr->get_scanner_ptr())); - this->_gated_image_template=GatedDiscretisedDensity(this->get_time_gate_definitions(), density_template_sptr); + this->_gated_image_template = GatedDiscretisedDensity(this->get_time_gate_definitions(), density_template_sptr); // construct _single_gate_obj_funcs - this->_single_gate_obj_funcs.resize(1,this->get_time_gate_definitions().get_num_gates()); - - for(unsigned int gate_num=1;gate_num<=this->get_time_gate_definitions().get_num_gates();++gate_num) - { - info(boost::format("Objective Function for Gate Number: %1%") % gate_num); - this->_single_gate_obj_funcs[gate_num].set_projector_pair_sptr(this->_projector_pair_ptr); - this->_single_gate_obj_funcs[gate_num].set_proj_data_sptr(this->_gated_proj_data_sptr->get_proj_data_sptr(gate_num)); - this->_single_gate_obj_funcs[gate_num].set_max_segment_num_to_process(this->_max_segment_num_to_process); - this->_single_gate_obj_funcs[gate_num].set_zero_seg0_end_planes(this->_zero_seg0_end_planes!=0); - if(!is_null_ptr(this->_additive_gated_proj_data_sptr)) - this->_single_gate_obj_funcs[gate_num].set_additive_proj_data_sptr(this->_additive_gated_proj_data_sptr->get_proj_data_sptr(gate_num)); - this->_single_gate_obj_funcs[gate_num].set_num_subsets(this->num_subsets); - this->_single_gate_obj_funcs[gate_num].set_frame_num(1);//This should be gate... - std::vector > frame_times(1, std::pair(0,1)); - this->_single_gate_obj_funcs[gate_num].set_frame_definitions(TimeFrameDefinitions(frame_times)); - - shared_ptr current_gate_norm_factors_sptr; - if (is_null_ptr(this->_normalisation_gated_proj_data_sptr)) - current_gate_norm_factors_sptr.reset(new TrivialBinNormalisation); - else { - shared_ptr norm_data_sptr(this->_normalisation_gated_proj_data_sptr->get_proj_data_sptr(gate_num)); - current_gate_norm_factors_sptr.reset( - new BinNormalisationFromProjData(norm_data_sptr)); - } - this->_single_gate_obj_funcs[gate_num].set_normalisation_sptr(current_gate_norm_factors_sptr); - this->_single_gate_obj_funcs[gate_num].set_recompute_sensitivity(this->get_recompute_sensitivity()); - this->_single_gate_obj_funcs[gate_num].set_use_subset_sensitivities(this->get_use_subset_sensitivities()); - - if(this->_single_gate_obj_funcs[gate_num].set_up(density_template_sptr) != Succeeded::yes) - error("Single gate objective functions is not set correctly!"); + this->_single_gate_obj_funcs.resize(1, this->get_time_gate_definitions().get_num_gates()); + + for (unsigned int gate_num = 1; gate_num <= this->get_time_gate_definitions().get_num_gates(); ++gate_num) { + info(boost::format("Objective Function for Gate Number: %1%") % gate_num); + this->_single_gate_obj_funcs[gate_num].set_projector_pair_sptr(this->_projector_pair_ptr); + this->_single_gate_obj_funcs[gate_num].set_proj_data_sptr(this->_gated_proj_data_sptr->get_proj_data_sptr(gate_num)); + this->_single_gate_obj_funcs[gate_num].set_max_segment_num_to_process(this->_max_segment_num_to_process); + this->_single_gate_obj_funcs[gate_num].set_zero_seg0_end_planes(this->_zero_seg0_end_planes != 0); + if (!is_null_ptr(this->_additive_gated_proj_data_sptr)) + this->_single_gate_obj_funcs[gate_num].set_additive_proj_data_sptr( + this->_additive_gated_proj_data_sptr->get_proj_data_sptr(gate_num)); + this->_single_gate_obj_funcs[gate_num].set_num_subsets(this->num_subsets); + this->_single_gate_obj_funcs[gate_num].set_frame_num(1); // This should be gate... + std::vector> frame_times(1, std::pair(0, 1)); + this->_single_gate_obj_funcs[gate_num].set_frame_definitions(TimeFrameDefinitions(frame_times)); + + shared_ptr current_gate_norm_factors_sptr; + if (is_null_ptr(this->_normalisation_gated_proj_data_sptr)) + current_gate_norm_factors_sptr.reset(new TrivialBinNormalisation); + else { + shared_ptr norm_data_sptr(this->_normalisation_gated_proj_data_sptr->get_proj_data_sptr(gate_num)); + current_gate_norm_factors_sptr.reset(new BinNormalisationFromProjData(norm_data_sptr)); } - }//_single_gate_obj_funcs[gate_num] + this->_single_gate_obj_funcs[gate_num].set_normalisation_sptr(current_gate_norm_factors_sptr); + this->_single_gate_obj_funcs[gate_num].set_recompute_sensitivity(this->get_recompute_sensitivity()); + this->_single_gate_obj_funcs[gate_num].set_use_subset_sensitivities(this->get_use_subset_sensitivities()); + + if (this->_single_gate_obj_funcs[gate_num].set_up(density_template_sptr) != Succeeded::yes) + error("Single gate objective functions is not set correctly!"); + } + } //_single_gate_obj_funcs[gate_num] return Succeeded::yes; } @@ -420,143 +382,117 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) functions that compute the value/gradient of the objective function etc *************************************************************************/ -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) -{ - assert(subset_num>=0); - assert(subset_numnum_subsets); - - GatedDiscretisedDensity gated_gradient=this->_gated_image_template; - GatedDiscretisedDensity gated_image_estimate=this->_gated_image_template; +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion< + TargetT>::compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, const TargetT& current_estimate, + const int subset_num) { + assert(subset_num >= 0); + assert(subset_num < this->num_subsets); + + GatedDiscretisedDensity gated_gradient = this->_gated_image_template; + GatedDiscretisedDensity gated_image_estimate = this->_gated_image_template; // The following initialization doesn't stabilize reconstruction. - for(unsigned int gate_num=1;gate_num<=this->get_time_gate_definitions().get_num_gates();++gate_num) - std::fill(gated_image_estimate[gate_num].begin_all(), - gated_image_estimate[gate_num].end_all(), - 0.F); - this->_motion_vectors.warp_image(gated_image_estimate,current_estimate); - for(unsigned int gate_num=1;gate_num<=this->get_time_gate_definitions().get_num_gates();++gate_num) { - std::fill(gated_gradient[gate_num].begin_all(), - gated_gradient[gate_num].end_all(), - 0.F); - this->_single_gate_obj_funcs[gate_num]. - compute_sub_gradient_without_penalty_plus_sensitivity(gated_gradient[gate_num], - gated_image_estimate[gate_num], - subset_num); - } + for (unsigned int gate_num = 1; gate_num <= this->get_time_gate_definitions().get_num_gates(); ++gate_num) + std::fill(gated_image_estimate[gate_num].begin_all(), gated_image_estimate[gate_num].end_all(), 0.F); + this->_motion_vectors.warp_image(gated_image_estimate, current_estimate); + for (unsigned int gate_num = 1; gate_num <= this->get_time_gate_definitions().get_num_gates(); ++gate_num) { + std::fill(gated_gradient[gate_num].begin_all(), gated_gradient[gate_num].end_all(), 0.F); + this->_single_gate_obj_funcs[gate_num].compute_sub_gradient_without_penalty_plus_sensitivity( + gated_gradient[gate_num], gated_image_estimate[gate_num], subset_num); + } // if(this->_motion_correction_type==-1) - this->_reverse_motion_vectors.warp_image(gradient,gated_gradient) ; + this->_reverse_motion_vectors.warp_image(gradient, gated_gradient); // else - // this->_motion_vectors.warp_image(gradient,gated_gradient) ; + // this->_motion_vectors.warp_image(gradient,gated_gradient) ; } -template +template double -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num) -{ - assert(subset_num>=0); - assert(subset_numnum_subsets); +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::actual_compute_objective_function_without_penalty( + const TargetT& current_estimate, const int subset_num) { + assert(subset_num >= 0); + assert(subset_num < this->num_subsets); double result = 0.; - GatedDiscretisedDensity gated_image_estimate=this->_gated_image_template; + GatedDiscretisedDensity gated_image_estimate = this->_gated_image_template; // The following initialization doesn't stabilize reconstruction. - for(unsigned int gate_num=1; gate_num<=this->get_time_gate_definitions().get_num_gates(); ++gate_num) - std::fill(gated_image_estimate[gate_num].begin_all(), - gated_image_estimate[gate_num].end_all(), - 0.F); - this->_motion_vectors.warp_image(gated_image_estimate,current_estimate) ; + for (unsigned int gate_num = 1; gate_num <= this->get_time_gate_definitions().get_num_gates(); ++gate_num) + std::fill(gated_image_estimate[gate_num].begin_all(), gated_image_estimate[gate_num].end_all(), 0.F); + this->_motion_vectors.warp_image(gated_image_estimate, current_estimate); // loop over single_gate - for(unsigned int gate_num=1 ; - gate_num<=this->get_time_gate_definitions().get_num_gates(); - ++gate_num) - { - result += this->_single_gate_obj_funcs[gate_num]. - compute_objective_function_without_penalty(gated_image_estimate[gate_num], - subset_num); - } + for (unsigned int gate_num = 1; gate_num <= this->get_time_gate_definitions().get_num_gates(); ++gate_num) { + result += this->_single_gate_obj_funcs[gate_num].compute_objective_function_without_penalty(gated_image_estimate[gate_num], + subset_num); + } return result; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const -{ - GatedDiscretisedDensity gated_subset_sensitivity=this->_gated_image_template; +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::add_subset_sensitivity( + TargetT& sensitivity, const int subset_num) const { + GatedDiscretisedDensity gated_subset_sensitivity = this->_gated_image_template; // loop over single_gate to get original subset sensitivity - for(unsigned int gate_num=1;gate_num<=this->get_time_gate_definitions().get_num_gates();++gate_num) - { - const shared_ptr > single_gate_subsensitivity_sptr( - this->_single_gate_obj_funcs[gate_num].get_subset_sensitivity(subset_num).clone()); - gated_subset_sensitivity.set_density_sptr(single_gate_subsensitivity_sptr,gate_num); - } + for (unsigned int gate_num = 1; gate_num <= this->get_time_gate_definitions().get_num_gates(); ++gate_num) { + const shared_ptr> single_gate_subsensitivity_sptr( + this->_single_gate_obj_funcs[gate_num].get_subset_sensitivity(subset_num).clone()); + gated_subset_sensitivity.set_density_sptr(single_gate_subsensitivity_sptr, gate_num); + } // perform warp - this->_reverse_motion_vectors.accumulate_warp_image(sensitivity,gated_subset_sensitivity) ; + this->_reverse_motion_vectors.accumulate_warp_image(sensitivity, gated_subset_sensitivity); } -//! /todo The PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::actual_add_multiplication_with_approximate_sub_Hessian_without_penalty is not validated and at the moment OSSPS does not converge with motion correction. -template +//! /todo The +//! PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::actual_add_multiplication_with_approximate_sub_Hessian_without_penalty +//! is not validated and at the moment OSSPS does not converge with motion correction. +template Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion< + TargetT>::actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, const TargetT& input, + const int subset_num) const { // TODO this does not add but replace { std::string explanation; - if (!input.has_same_characteristics(this->get_subset_sensitivity(0), //////////////////// - explanation)) - { - warning("PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:\n" - "sensitivity and input for add_multiplication_with_approximate_Hessian_without_penalty\n" - "should have the same characteristics.\n%s", - explanation.c_str()); - return Succeeded::no; - } - } - GatedDiscretisedDensity gated_input=this->_gated_image_template; - GatedDiscretisedDensity gated_output=this->_gated_image_template; - this->_motion_vectors.warp_image(gated_input,input) ; - - VectorWithOffset scale_factor(1,this->get_time_gate_definitions().get_num_gates()); - for(unsigned int gate_num=1; - gate_num<=this->get_time_gate_definitions().get_num_gates(); - ++gate_num) - { - scale_factor[gate_num]=gated_input[gate_num].find_max(); - /*! /note This is used to avoid higher values than these set in the precompute_denominator_of_conditioner_without_penalty() function. - /sa for more information see the recon_array_functions.cxx and the value of the max_quotient (originaly set to 10000.F) */ - gated_input[gate_num]/=scale_factor[gate_num]; - this->_single_gate_obj_funcs[gate_num]. - add_multiplication_with_approximate_sub_Hessian_without_penalty(gated_output[gate_num], - gated_input[gate_num], - subset_num); - gated_output[gate_num]*=scale_factor[gate_num]; - } // end of loop over gates - this->_reverse_motion_vectors.warp_image(output,gated_output); - output/=static_cast(this->get_time_gate_definitions().get_num_gates()); //Normalizing to get the average value to test if OSSPS works. + if (!input.has_same_characteristics(this->get_subset_sensitivity(0), //////////////////// + explanation)) { + warning("PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:\n" + "sensitivity and input for add_multiplication_with_approximate_Hessian_without_penalty\n" + "should have the same characteristics.\n%s", + explanation.c_str()); + return Succeeded::no; + } + } + GatedDiscretisedDensity gated_input = this->_gated_image_template; + GatedDiscretisedDensity gated_output = this->_gated_image_template; + this->_motion_vectors.warp_image(gated_input, input); + + VectorWithOffset scale_factor(1, this->get_time_gate_definitions().get_num_gates()); + for (unsigned int gate_num = 1; gate_num <= this->get_time_gate_definitions().get_num_gates(); ++gate_num) { + scale_factor[gate_num] = gated_input[gate_num].find_max(); + /*! /note This is used to avoid higher values than these set in the precompute_denominator_of_conditioner_without_penalty() + function. /sa for more information see the recon_array_functions.cxx and the value of the max_quotient (originaly set to + 10000.F) */ + gated_input[gate_num] /= scale_factor[gate_num]; + this->_single_gate_obj_funcs[gate_num].add_multiplication_with_approximate_sub_Hessian_without_penalty( + gated_output[gate_num], gated_input[gate_num], subset_num); + gated_output[gate_num] *= scale_factor[gate_num]; + } // end of loop over gates + this->_reverse_motion_vectors.warp_image(output, gated_output); + output /= static_cast( + this->get_time_gate_definitions().get_num_gates()); // Normalizing to get the average value to test if OSSPS works. return Succeeded::yes; } -template +template Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input, - const int subset_num) const -{ +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion< + TargetT>::actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, const TargetT& current_image_estimate, + const TargetT& input, const int subset_num) const { { // check argument characteristics std::string explanation; - if (!input.has_same_characteristics(this->get_subset_sensitivity(0), explanation)) - { + if (!input.has_same_characteristics(this->get_subset_sensitivity(0), explanation)) { warning("PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:\n" "sensitivity and input for actual_accumulate_sub_Hessian_times_input_without_penalty\n" "should have the same characteristics.\n%s", @@ -564,8 +500,7 @@ actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, return Succeeded::no; } - if (!current_image_estimate.has_same_characteristics(this->get_subset_sensitivity(0), explanation)) - { + if (!current_image_estimate.has_same_characteristics(this->get_subset_sensitivity(0), explanation)) { warning("PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:\n" "sensitivity and current_image_estimate for actual_accumulate_sub_Hessian_times_input_without_penalty\n" "should have the same characteristics.\n%s", @@ -574,26 +509,20 @@ actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, } } - GatedDiscretisedDensity gated_input=this->_gated_image_template; - GatedDiscretisedDensity gated_current_image_estimate=this->_gated_image_template; - GatedDiscretisedDensity gated_output=this->_gated_image_template; - this->_motion_vectors.warp_image(gated_input,input); + GatedDiscretisedDensity gated_input = this->_gated_image_template; + GatedDiscretisedDensity gated_current_image_estimate = this->_gated_image_template; + GatedDiscretisedDensity gated_output = this->_gated_image_template; + this->_motion_vectors.warp_image(gated_input, input); this->_motion_vectors.warp_image(gated_current_image_estimate, current_image_estimate); - for(unsigned int gate_num=1; - gate_num<=this->get_time_gate_definitions().get_num_gates(); - ++gate_num) - { - this->_single_gate_obj_funcs[gate_num]. - accumulate_sub_Hessian_times_input_without_penalty(gated_output[gate_num], - gated_current_image_estimate[gate_num], - gated_input[gate_num], - subset_num); + for (unsigned int gate_num = 1; gate_num <= this->get_time_gate_definitions().get_num_gates(); ++gate_num) { + this->_single_gate_obj_funcs[gate_num].accumulate_sub_Hessian_times_input_without_penalty( + gated_output[gate_num], gated_current_image_estimate[gate_num], gated_input[gate_num], subset_num); } // end of loop over gates this->_reverse_motion_vectors.warp_image(output, gated_output); - output/=static_cast(this->get_time_gate_definitions().get_num_gates()); //Normalizing to get the average value to test if OSSPS works. + output /= static_cast( + this->get_time_gate_definitions().get_num_gates()); // Normalizing to get the average value to test if OSSPS works. return Succeeded::yes; } - END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h index ec82354276..d69b04ac6a 100644 --- a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h +++ b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h @@ -20,7 +20,7 @@ /*! \file \ingroup GeneralisedObjectiveFunction - \brief Declaration of class + \brief Declaration of class stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeData \author Kris Thielemans @@ -31,7 +31,6 @@ #ifndef __stir_recon_buildblock_PoissonLogLikelihoodWithLinearModelForMeanAndListModeData_H__ #define __stir_recon_buildblock_PoissonLogLikelihoodWithLinearModelForMeanAndListModeData_H__ - //#include "stir/RegisteredParsingObject.h" #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.h" #include "stir/listmode/ListModeData.h" @@ -46,7 +45,7 @@ START_NAMESPACE_STIR The statistics for list mode data is slightly different from having a set of counts, see the paper - H. H. Barrett, L. Parra, and T. White, + H. H. Barrett, L. Parra, and T. White, List-mode likelihood, J. Optical Soc. Amer. A, vol. 14, no. 11, 1997. However, it is intuitive that the list mode likelihood can be @@ -69,41 +68,34 @@ START_NAMESPACE_STIR */ template -class PoissonLogLikelihoodWithLinearModelForMeanAndListModeData: -public PoissonLogLikelihoodWithLinearModelForMean -{ -private: - +class PoissonLogLikelihoodWithLinearModelForMeanAndListModeData : public PoissonLogLikelihoodWithLinearModelForMean { +private: typedef PoissonLogLikelihoodWithLinearModelForMean base_type; -public: - - - PoissonLogLikelihoodWithLinearModelForMeanAndListModeData(); - - //virtual TargetT * construct_target_ptr(); - - virtual Succeeded - set_up(shared_ptr const& target_sptr); - - virtual - void compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num)=0; +public: + PoissonLogLikelihoodWithLinearModelForMeanAndListModeData(); + + // virtual TargetT * construct_target_ptr(); + + virtual Succeeded set_up(shared_ptr const& target_sptr); + + virtual void compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, const TargetT& current_estimate, + const int subset_num) = 0; //! time frame definitions - /*! \todo This is currently used to be able to compute the gradient for + /*! \todo This is currently used to be able to compute the gradient for one time frame. However, it probably does not belong here. For instance when fitting kinetic model parameters from list mode data, time frames are in principle irrelevant. So, we will probably shift this to the derived class. */ - TimeFrameDefinitions frame_defs; + TimeFrameDefinitions frame_defs; - virtual void set_normalisation_sptr(const shared_ptr&); - virtual void set_additive_proj_data_sptr(const shared_ptr&); + virtual void set_normalisation_sptr(const shared_ptr&); + virtual void set_additive_proj_data_sptr(const shared_ptr&); + + virtual void set_input_data(const shared_ptr&); + virtual const ListModeData& get_input_data() const; - virtual void set_input_data(const shared_ptr &); - virtual const ListModeData& get_input_data() const; protected: std::string frame_defs_filename; @@ -113,31 +105,31 @@ public PoissonLogLikelihoodWithLinearModelForMean shared_ptr additive_proj_data_sptr; shared_ptr normalisation_sptr; - + //! Listmode pointer shared_ptr list_mode_data_sptr; - + unsigned int current_frame_num; //! This is part of some functionality I transfer from LmToProjData. long int num_events_to_use; - //! Reconstruct based on time frames - bool do_time_frame; - + //! Reconstruct based on time frames + bool do_time_frame; + //! sets any default values /*! Has to be called by set_defaults in the leaf-class */ virtual void set_defaults(); //! sets keys /*! Has to be called by initialise_keymap in the leaf-class */ - virtual void initialise_keymap(); + virtual void initialise_keymap(); - virtual bool post_processing(); + virtual bool post_processing(); - //! will be called when a new time frame starts - /*! The frame numbers start from 1. */ - virtual void start_new_time_frame(const unsigned int new_frame_num); + //! will be called when a new time frame starts + /*! The frame numbers start from 1. */ + virtual void start_new_time_frame(const unsigned int new_frame_num); - ParseAndCreateFrom target_parameter_parser; + ParseAndCreateFrom target_parameter_parser; }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h index 85b398417d..65302975a4 100644 --- a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h +++ b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h @@ -19,7 +19,7 @@ /*! \file \ingroup GeneralisedObjectiveFunction - \brief Declaration of class + \brief Declaration of class stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin \author Nikos Efthimiou @@ -30,22 +30,21 @@ #ifndef __stir_recon_buildblock_PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin_H__ #define __stir_recon_buildblock_PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h" -#include "stir/recon_buildblock/ProjMatrixByBin.h" +#include "stir/recon_buildblock/ProjMatrixByBin.h" #include "stir/ProjDataInMemory.h" #include "stir/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.h" #include "stir/ExamInfo.h" -START_NAMESPACE_STIR +START_NAMESPACE_STIR /*! \ingroup GeneralisedObjectiveFunction \brief Class for PET list mode data from static images for a scanner with discrete detectors. If the scanner has discrete (and stationary) detectors, it can be modeled via ProjMatrixByBin and BinNormalisation. - + \see PoissonLogLikelihoodWithLinearModelForMeanAndProjData If the list mode data is binned (with LmToProjData) without merging @@ -54,70 +53,67 @@ START_NAMESPACE_STIR */ template -class PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin: -public RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMeanAndListModeData > +class PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin + : public RegisteredParsingObject, + GeneralisedObjectiveFunction, + PoissonLogLikelihoodWithLinearModelForMeanAndListModeData> { private: -typedef RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMeanAndListModeData > - base_type; + typedef RegisteredParsingObject, + GeneralisedObjectiveFunction, + PoissonLogLikelihoodWithLinearModelForMeanAndListModeData> + base_type; public: - - //! Name which will be used when parsing a GeneralisedObjectiveFunction object - static const char * const registered_name; - - PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin(); + //! Name which will be d when parsing a GeneralisedObjectiveFunction object + static const char* const registered_name; + + PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin(); //! This should compute the gradient of the objective function at the \a current_estimate overwriting \a gradient - virtual - void compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num); - virtual TargetT * construct_target_ptr() const; + virtual void compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, const TargetT& current_estimate, + const int subset_num); + virtual TargetT* construct_target_ptr() const; int set_num_subsets(const int new_num_subsets); - - const shared_ptr & - get_normalisation_sptr() const - { return this->normalisation_sptr; } - + + const shared_ptr& get_normalisation_sptr() const { return this->normalisation_sptr; } + virtual unique_ptr get_exam_info_uptr_for_target() const; - + protected: - virtual double - actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num) - { // TODO + virtual double actual_compute_objective_function_without_penalty(const TargetT& current_estimate, + const int subset_num) { // TODO error("compute_objective_function_without_penalty Not implemented yet"); - return 0; + return 0; } - virtual Succeeded - set_up_before_sensitivity(shared_ptr const& target_sptr); - - virtual void - add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const; - + virtual Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr); + + virtual void add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const; + //! Maximum ring difference to take into account /*! \todo Might be removed */ - int max_ring_difference_num_to_process; + int max_ring_difference_num_to_process; + + //! Triggers calculation of sensitivity using time-of-flight + bool use_tofsens; //! Stores the projectors that are used for the computations shared_ptr PM_sptr; //! Stores the projectors that are used for the computations - shared_ptr projector_pair_sptr; + shared_ptr projector_pair_sptr; + + //! Backprojector used for sensitivity computation + shared_ptr sens_backprojector_sptr; //! points to the additive projection data shared_ptr additive_proj_data_sptr; - - std::string additive_projection_data_filename ; + + std::string additive_projection_data_filename; //! ProjDataInfo shared_ptr proj_data_info_sptr; @@ -131,8 +127,7 @@ typedef RegisteredParsingObjectnot \f$r\f$). @@ -109,9 +107,9 @@ class DistributedCachingInformation; ; see ProjectorByBinPair hierarchy for possible values Projector pair type := - + ; reserved value: 0 means none - ; see PoissonLogLikelihoodWithLinearModelForMeanAndProjData + ; see PoissonLogLikelihoodWithLinearModelForMeanAndProjData ; class documentation additive sinogram := @@ -128,33 +126,29 @@ class DistributedCachingInformation; \endverbatim */ template -class PoissonLogLikelihoodWithLinearModelForMeanAndProjData: -public RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > -{ - private: +class PoissonLogLikelihoodWithLinearModelForMeanAndProjData + : public RegisteredParsingObject, + GeneralisedObjectiveFunction, PoissonLogLikelihoodWithLinearModelForMean> { +private: typedef RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > - base_type; + GeneralisedObjectiveFunction, PoissonLogLikelihoodWithLinearModelForMean> + base_type; public: - //! Name which will be used when parsing a GeneralisedObjectiveFunction object - static const char * const registered_name; + static const char* const registered_name; // /*! \name Variables for STIR_MPI - Only used when STIR_MPI is enabled. + Only used when STIR_MPI is enabled. \todo move to protected area */ //@{ //! points to the information object needed to support distributed caching - DistributedCachingInformation * caching_info_ptr; + DistributedCachingInformation* caching_info_ptr; //#ifdef STIR_MPI - //!enable/disable key for distributed caching + //! enable/disable key for distributed caching bool distributed_cache_enabled; bool distributed_tests_enabled; bool message_timings_enabled; @@ -163,7 +157,6 @@ public RegisteredParsingObject& get_proj_data_sptr() const; const int get_max_segment_num_to_process() const; + const int get_max_timing_pos_num_to_process() const; const bool get_zero_seg0_end_planes() const; const ProjData& get_additive_proj_data() const; const shared_ptr& get_additive_proj_data_sptr() const; @@ -200,7 +193,7 @@ public RegisteredParsingObject&); void set_max_segment_num_to_process(const int); + void set_max_timing_pos_num_to_process(const int); void set_zero_seg0_end_planes(const bool); - //N.E. Changed to ExamData + // N.E. Changed to ExamData virtual void set_additive_proj_data_sptr(const shared_ptr&); - void set_projector_pair_sptr(const shared_ptr&) ; + void set_projector_pair_sptr(const shared_ptr&); void set_frame_num(const int); void set_frame_definitions(const TimeFrameDefinitions&); virtual void set_normalisation_sptr(const shared_ptr&); - virtual void set_input_data(const shared_ptr &); + virtual void set_input_data(const shared_ptr&); virtual const ProjData& get_input_data() const; -//@} - - virtual void - compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num); - - virtual std::unique_ptr - get_exam_info_uptr_for_target() const; + //@} + + virtual void compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, const TargetT& current_estimate, + const int subset_num); + + virtual std::unique_ptr get_exam_info_uptr_for_target() const; #if 0 // currently not used float sum_projection_data() const; #endif - virtual void - add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const; + virtual void add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const; - protected: - virtual Succeeded - set_up_before_sensitivity(shared_ptr const& target_sptr); +protected: + virtual Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr); - virtual double - actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num); + virtual double actual_compute_objective_function_without_penalty(const TargetT& current_estimate, const int subset_num); /*! The Hessian (without penalty) is approximately given by: @@ -254,15 +241,15 @@ public RegisteredParsingObject target_parameter_parser; + ParseAndCreateFrom target_parameter_parser; /********************************/ - //! Stores the projectors that are used for the computations shared_ptr projector_pair_ptr; + //! Backprojector used for sensitivity computation + shared_ptr sens_backprojector_sptr; + //! signals whether to zero the data in the end planes of the projection data bool zero_seg0_end_planes; + //! Triggers calculation of sensitivity using time-of-flight + bool use_tofsens; + //! name of file in which additive projection data are stored std::string additive_projection_data_filename; - shared_ptr additive_proj_data_sptr; shared_ptr normalisation_sptr; - // TODO doc + // TODO doc int frame_num; std::string frame_definition_filename; TimeFrameDefinitions frame_defs; -//Loglikelihood computation parameters - // TODO rename and move higher up in the hierarchy + // Loglikelihood computation parameters + // TODO rename and move higher up in the hierarchy //! subiteration interval at which the loglikelihood function is evaluated int loglikelihood_computation_interval; @@ -348,17 +339,18 @@ public RegisteredParsingObject symmetries_sptr; #if 0 void @@ -367,7 +359,7 @@ public RegisteredParsingObject class Viewgram; -template class DataProcessor; +template +class Viewgram; +template +class DataProcessor; /*! \brief A very preliminary class that first smooths the image, then back projects. \warning. It assumes that the DataProcessor does not change the size of the image. */ -class PostsmoothingBackProjectorByBin : - public - RegisteredParsingObject -{ +class PostsmoothingBackProjectorByBin : public RegisteredParsingObject { #ifdef SWIG // work-around swig problem. It gets confused when using a private (or protected) // typedef in a definition of a public typedef/member public: #else - private: +private: #endif typedef BackProjectorByBin base_type; + public: //! Name which will be used when parsing a PostsmoothingBackProjectorByBin object - static const char * const registered_name; + static const char* const registered_name; //! Default constructor (calls set_defaults()) PostsmoothingBackProjectorByBin(); - ~ PostsmoothingBackProjectorByBin(); + ~PostsmoothingBackProjectorByBin(); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); - - PostsmoothingBackProjectorByBin( - const shared_ptr& original_back_projector_ptr, - const shared_ptr > >&); + PostsmoothingBackProjectorByBin(const shared_ptr& original_back_projector_ptr, + const shared_ptr>>&); // Informs on which symmetries the projector handles // It should get data related by at least those symmetries. // Otherwise, a run-time error will occur (unless the derived // class has other behaviour). - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const; + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const; -private: + void update_filtered_density_image(DiscretisedDensity<3, float>&); + + void init_filtered_density_image(DiscretisedDensity<3, float>&); + BackProjectorByBin* get_original_back_projector_ptr() const; + + PostsmoothingBackProjectorByBin* clone() const; + +private: shared_ptr original_back_projector_ptr; #ifdef STIR_PROJECTORS_AS_V3 - void actual_back_project(DiscretisedDensity<3,float>&, - const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + void actual_back_project(DiscretisedDensity<3, float>&, const RelatedViewgrams&, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num); #endif - void actual_back_project(const RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, + void actual_back_project(const RelatedViewgrams&, const int min_axial_pos_num, const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num); + void actual_back_project(DiscretisedDensity<3, float>& density, const Bin& bin); + + shared_ptr> filtered_density_sptr; virtual void set_defaults(); virtual void initialise_keymap(); diff --git a/src/include/stir/recon_buildblock/PresmoothingForwardProjectorByBin.h b/src/include/stir/recon_buildblock/PresmoothingForwardProjectorByBin.h index 3003e2cd45..a4767474a8 100644 --- a/src/include/stir/recon_buildblock/PresmoothingForwardProjectorByBin.h +++ b/src/include/stir/recon_buildblock/PresmoothingForwardProjectorByBin.h @@ -33,72 +33,70 @@ #include "stir/recon_buildblock/ForwardProjectorByBin.h" #include "stir/shared_ptr.h" - START_NAMESPACE_STIR -template class Viewgram; -template class DataProcessor; +template +class Viewgram; +template +class DataProcessor; /*! \brief A very preliminary class that first smooths the image, then forward projects. \warning. It assumes that the DataProcessor does not change the size of the image. */ -class PresmoothingForwardProjectorByBin : - public - RegisteredParsingObject -{ +class PresmoothingForwardProjectorByBin + : public RegisteredParsingObject { #ifdef SWIG // work-around swig problem. It gets confused when using a private (or protected) // typedef in a definition of a public typedef/member public: #else - private: +private: #endif typedef ForwardProjectorByBin base_type; + public: //! Name which will be used when parsing a PresmoothingForwardProjectorByBin object - static const char * const registered_name; + static const char* const registered_name; //! Default constructor (calls set_defaults()) PresmoothingForwardProjectorByBin(); - ~ PresmoothingForwardProjectorByBin(); + ~PresmoothingForwardProjectorByBin(); + + // void update_filtered_density_image(const DiscretisedDensity<3,float>&); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); - - PresmoothingForwardProjectorByBin( - const shared_ptr& original_forward_projector_ptr, - const shared_ptr > >&); + PresmoothingForwardProjectorByBin(const shared_ptr& original_forward_projector_ptr, + const shared_ptr>>&); // Informs on which symmetries the projector handles // It should get data related by at least those symmetries. // Otherwise, a run-time error will occur (unless the derived // class has other behaviour). - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const; + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const; private: - shared_ptr original_forward_projector_ptr; #ifdef STIR_PROJECTORS_AS_V3 - void actual_forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + void actual_forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>&, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num); #endif - void actual_forward_project(RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, + void actual_forward_project(RelatedViewgrams&, const int min_axial_pos_num, const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num); +#if 0 // disabled as currently not used. needs to be written in the new style anyway + void actual_forward_project(Bin&, + const DiscretisedDensity<3,float>&); +#endif virtual void set_defaults(); virtual void initialise_keymap(); diff --git a/src/include/stir/recon_buildblock/PriorWithParabolicSurrogate.h b/src/include/stir/recon_buildblock/PriorWithParabolicSurrogate.h index 8786db6c3f..ac88e4bfbe 100644 --- a/src/include/stir/recon_buildblock/PriorWithParabolicSurrogate.h +++ b/src/include/stir/recon_buildblock/PriorWithParabolicSurrogate.h @@ -5,7 +5,7 @@ \ingroup priors \brief Declaration of class stir::PriorWithParabolicSurrogate - \author Sanida Mustafovic + \author Sanida Mustafovic \author Kris Thielemans */ @@ -26,7 +26,6 @@ See STIR/LICENSE.txt for details */ - #ifndef __stir_recon_buildblock_PriorWithParabolicSurrogate_H__ #define __stir_recon_buildblock_PriorWithParabolicSurrogate_H__ @@ -39,28 +38,21 @@ START_NAMESPACE_STIR \ingroup priors \brief this class implements priors with a parabolic surrogate curvature - + See for example Erdogan and Fessler, Ordered subsets algorithms for transmission tomography, PMB, 44 (1999) 2835. - + */ template -class PriorWithParabolicSurrogate: - public GeneralisedPrior -{ +class PriorWithParabolicSurrogate : public GeneralisedPrior { public: - - //!this should calculate the parabolic surrogate curvature - virtual void - parabolic_surrogate_curvature(TargetT& parabolic_surrogate_curvature, - const TargetT ¤t_estimate) = 0; + //! this should calculate the parabolic surrogate curvature + virtual void parabolic_surrogate_curvature(TargetT& parabolic_surrogate_curvature, const TargetT& current_estimate) = 0; //! A function that allows skipping some computations if the curvature is independent of the \c current_estimate /*! Defaults to return \c true, but can be overloaded by the derived class. */ - virtual bool - parabolic_surrogate_curvature_depends_on_argument() const - { return true; } + virtual bool parabolic_surrogate_curvature_depends_on_argument() const { return true; } #if 0 // TODO this does not work for arbitrary TargetT, but only 3-dimensional things // maybe we could have a TargetT::index_type or so @@ -69,10 +61,8 @@ class PriorWithParabolicSurrogate: const BasicCoordinate<3,int>& coords, const TargetT ¤t_estimate) =0; #endif - }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir/recon_buildblock/ProjDataRebinning.h b/src/include/stir/recon_buildblock/ProjDataRebinning.h index ae717fc838..104b545f73 100644 --- a/src/include/stir/recon_buildblock/ProjDataRebinning.h +++ b/src/include/stir/recon_buildblock/ProjDataRebinning.h @@ -19,17 +19,16 @@ #ifndef __stir_recon_buildblock_ProjDataRebinning_H__ #define __stir_recon_buildblock_ProjDataRebinning_H__ /*! - \file + \file \ingroup recon_buildblock - + \brief declares the stir::ProjDataRebinning class \author Kris Thielemans */ /* Modification history -*/ - + */ #include "stir/RegisteredObject.h" #include "stir/TimedObject.h" @@ -40,7 +39,6 @@ START_NAMESPACE_STIR - class Succeeded; /*! @@ -54,8 +52,8 @@ class Succeeded; The utility rebin_projdata provides the user interface to this class. What follows is for developers. - Parameters need to be initialised somehow. This is usually done using the - parse() member functions (see ParsingObject). + Parameters need to be initialised somehow. This is usually done using the + parse() member functions (see ParsingObject). For some parameters, set_some_parameter() methods are provided. @@ -71,33 +69,28 @@ class Succeeded; \par Info for developers - For convenience, the class is derived from TimedObject. It is the + For convenience, the class is derived from TimedObject. It is the responsibility of the derived class to run these timers though. \todo there should be a method to rebin the data without writing the result to disk */ - -class ProjDataRebinning : - public TimedObject, - public RegisteredObject -{ +class ProjDataRebinning : public TimedObject, public RegisteredObject { public: //! virtual destructor virtual ~ProjDataRebinning(); - + //! gives method information virtual std::string method_info() const = 0; - + //! executes the rebinning /*! At the end of the rebinning, the final 2D projection data are saved to file as given in output_filename_prefix. \return Succeeded::yes if everything was alright. - */ - virtual Succeeded - rebin()=0; - + */ + virtual Succeeded rebin() = 0; + /*! \name get/set the number of segments to process \see max_segment_num_to_process @@ -119,19 +112,18 @@ class ProjDataRebinning : // KTTODO I'm not enthousiastic about the next function // why would you need this? shared_ptr get_proj_data_sptr(); - + // TODO needed at all? // KTTODO: yes, and change parameters //! operations prior to the rebinning virtual Succeeded set_up(); // parameters - protected: - +protected: //! file name for output projdata (should be without extension) - std::string output_filename_prefix; + std::string output_filename_prefix; //! file name for input projdata - std::string input_filename; + std::string input_filename; //! the maximum absolute segment number to use in the reconstruction /*! convention: if -1, use get_max_segment_num()*/ int max_segment_num_to_process; @@ -152,17 +144,14 @@ class ProjDataRebinning : #endif //! used to check acceptable parameter ranges, etc... - virtual bool post_processing(); + virtual bool post_processing(); virtual void set_defaults(); virtual void initialise_keymap(); - protected: // members - +protected: // members shared_ptr proj_data_sptr; }; END_NAMESPACE_STIR - #endif - diff --git a/src/include/stir/recon_buildblock/ProjMatrixByBin.h b/src/include/stir/recon_buildblock/ProjMatrixByBin.h index d2ca21b1da..54922c2d76 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBin.h +++ b/src/include/stir/recon_buildblock/ProjMatrixByBin.h @@ -4,9 +4,10 @@ /*! \file - \ingroup projection + \ingroup projection \brief declaration of stir::ProjMatrixByBin and its helpers classes - + + \author Nikos Efthimiou \author Mustapha Sadki \author Kris Thielemans \author PARAPET project @@ -15,6 +16,7 @@ Copyright (C) 2000 PARAPET partners Copyright (C) 2000-2009, Hammersmith Imanet Ltd Copyright (C) 2013, 2015 University College London + Copyright (C) 2016, University of Hull This file is part of STIR. @@ -38,40 +40,41 @@ #include "stir/shared_ptr.h" #include "stir/VectorWithOffset.h" #include "stir/TimedObject.h" +#include "stir/VoxelsOnCartesianGrid.h" #include //#include #include #ifdef STIR_OPENMP -#include +# include #endif // define a local preprocessor symbol to keep code relatively clean #ifdef STIR_NO_MUTABLE -#define STIR_MUTABLE_CONST +# define STIR_MUTABLE_CONST #else -#define STIR_MUTABLE_CONST const +# define STIR_MUTABLE_CONST const #endif START_NAMESPACE_STIR -/* TODO +/* TODO class ProjMatrixElemsForOneViewgram; class SubsetInfo; */ - -class Bin; - + +class Bin; + /*! \ingroup projection -\brief - This is the (abstract) base class for all projection matrices +\brief + This is the (abstract) base class for all projection matrices which are organised by 'bin'. - This class provides essentially only 2 public members: a method to get a - 'row' of the matrix, and a method to get information on the symmetries. + This class provides essentially only 2 public members: a method to get a + 'row' of the matrix, and a method to get information on the symmetries. Currently, the class provides for some (basic) caching. - This functionality will probably be moved to a new class + This functionality will probably be moved to a new class ProjMatrixByBinWithCache. (TODO) \par Parsing parameters @@ -82,47 +85,44 @@ class Bin; store only basic bins in cache := true \endverbatim The 2nd option allows to cache the whole matrix. This results in the fastest - behaviour IF your system does not start swapping. The default choice caches + behaviour IF your system does not start swapping. The default choice caches only the 'basic' bins, and computes symmetry related bins from the 'basic' ones. */ -class ProjMatrixByBin : - public RegisteredObject, - public TimedObject -{ +class ProjMatrixByBin : public RegisteredObject, public TimedObject { public: - virtual ~ProjMatrixByBin() {} //! To be called before any calculation is performed /*! Note that get_proj_matrix_elems_for_one_bin() will expect objects of compatible sizes and other info. - \warning: Any implementation of set_up in a derived class has to + \warning: Any implementation of set_up in a derived class has to call ProjMatrixByBin::set_up first. */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) = 0; + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) = 0; + + virtual ProjMatrixByBin* clone() const = 0; //! get a pointer to an object encoding all symmetries that are used by this ProjMatrixByBin - inline const DataSymmetriesForBins* get_symmetries_ptr() const; + inline const DataSymmetriesForBins* get_symmetries_ptr() const; //! get a shared_ptr to an object encoding all symmetries that are used by this ProjMatrixByBin inline const shared_ptr get_symmetries_sptr() const; - + //! The main method for getting a row of the matrix. - /*! + /*! The ProjMatrixElemsForOneBin argument will be overwritten (i.e. data is NOT appended). - + The implementation is inline as it just gets it in - terms of the cached_proj_matrix_elems_for_one_bin or - calculate_proj_matrix_elems_for_one_bin.*/ - inline void - get_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&, - const Bin&) STIR_MUTABLE_CONST; - + terms of the cached_proj_matrix_elems_for_one_bin or + calculate_proj_matrix_elems_for_one_bin. + + N.E: Updated to accomondate TOF information. +*/ + inline void get_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&, const Bin&) STIR_MUTABLE_CONST; + #if 0 // TODO /*! \brief Facility to write the 'independent' part of the matrix to file. @@ -132,19 +132,19 @@ class ProjMatrixByBin : */ virtual void write_to_file_by_bin( const char * const file_name_without_extension) const; -#endif +#endif // TODO implement this one at some point ? /* virtual void write_to_file_by_voxel( const char * const file_name_without_extension); */ - - //void set_maximum_cache_size(const unsigned long size){;} + + // void set_maximum_cache_size(const unsigned long size){;} /* TODO void set_subset_usage(const SubsetInfo&, const int num_access_times); */ void enable_cache(const bool v = true); - void store_only_basic_bins_in_cache(const bool v = true) ; + void store_only_basic_bins_in_cache(const bool v = true); bool is_cache_enabled() const; bool does_cache_store_only_basic_bins() const; @@ -153,30 +153,26 @@ class ProjMatrixByBin : //! Remove all elements from the cache void clear_cache() STIR_MUTABLE_CONST; - protected: shared_ptr symmetries_sptr; - + //! default ctor (calls set_defaults()) - /*! Note that due to the C++ definition (and some good reasons), + /*! Note that due to the C++ definition (and some good reasons), ProjMatrixByBin::set_defaults() is called, even though this is a virtual function. */ - ProjMatrixByBin(); - + ProjMatrixByBin(); + /*! \brief This method needs to be implemented in the derived class. - + bin-coordinates are obtained via the ProjMatrixElemsForOneBin::get_bin() method. Note that 'calculate' could just as well mean 'get from file' */ - virtual void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& - ) const = 0; + virtual void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const = 0; /////////////////////////////// parsing stuff ////////////////////// - + //! sets value for caching configuration (enables caching, but for 'basic' bins only) /*! Has to be called by set_defaults in the leaf-class */ virtual void set_defaults(); @@ -186,55 +182,79 @@ class ProjMatrixByBin : //! Checks if parameters have sensible values /*! Has to be called by post_processing in the leaf-class */ virtual bool post_processing(); - + /////////////////////////////// caching stuff ////////////////////// - bool cache_disabled; + bool cache_disabled; bool cache_stores_only_basic_bins; + //! If activated TOF reconstruction will be performed. + bool tof_enabled; /*! \brief The method that tries to get data from the cache. - + If it succeeds, it overwrites the ProjMatrixElemsForOneBin parameter and returns Succeeded::yes, otherwise it does not touch the ProjMatrixElemsForOneBin and returns Succeeded::false. */ - Succeeded get_cached_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& - ) const; - + Succeeded get_cached_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const; + + //! We need a local copy of the discretised density in order to find the + //! cartesian coordinates of each voxel. + shared_ptr> image_info_sptr; + + //! We need a local copy of the proj_data_info to get the integration boundaries and RayTracing + shared_ptr proj_data_info_sptr; + //! The method to store data in the cache. - void cache_proj_matrix_elems_for_one_bin( const ProjMatrixElemsForOneBin&) - STIR_MUTABLE_CONST; + void cache_proj_matrix_elems_for_one_bin(const ProjMatrixElemsForOneBin&) STIR_MUTABLE_CONST; private: - typedef boost::uint32_t CacheKey; - // typedef std::map MapProjMatrixElemsForOneBin; - typedef boost::unordered_map MapProjMatrixElemsForOneBin; + // typedef std::map MapProjMatrixElemsForOneBin; + typedef boost::unordered_map MapProjMatrixElemsForOneBin; typedef MapProjMatrixElemsForOneBin::iterator MapProjMatrixElemsForOneBinIterator; typedef MapProjMatrixElemsForOneBin::const_iterator const_MapProjMatrixElemsForOneBinIterator; - - //! collection of ProjMatrixElemsForOneBin (internal cache ) + + //! collection of ProjMatrixElemsForOneBin (internal cache ) #ifndef STIR_NO_MUTABLE mutable #endif - VectorWithOffset > cache_collection; + VectorWithOffset> + cache_collection; #ifdef STIR_OPENMP -#ifndef STIR_NO_MUTABLE +# ifndef STIR_NO_MUTABLE mutable -#endif - VectorWithOffset > cache_locks; +# endif + VectorWithOffset> + cache_locks; #endif //! create the key for caching // KT 15/05/2002 not static anymore as it uses cache_stores_only_basic_bins CacheKey cache_key(const Bin& bin) const; - -}; + //! Activates the application of the timing kernel to the LOR + //! and performs initial set_up(). + //! \warning Must be called after set_up() + void enable_tof(const shared_ptr& proj_data_info_sptr, const bool v = true); + + //! A local copy of the scanner's time resolution in mm. + float gauss_sigma_in_mm; + //! 1/(2*sigma_in_mm) + float r_sqrt2_gauss_sigma; + Array<1, float> cache_erf; + //! The function which actually applies the TOF kernel on the LOR. + inline void apply_tof_kernel_and_symm_transformation(ProjMatrixElemsForOneBin& probabilities, + const CartesianCoordinate3D& point1, + const CartesianCoordinate3D& point2, + const unique_ptr& symm_ptr) STIR_MUTABLE_CONST; + + //! Get the interal value erf(m - v_j) - erf(m -v_j) + inline void get_tof_value(const float d1, const float d2, float& val) const; +}; END_NAMESPACE_STIR @@ -243,6 +263,3 @@ END_NAMESPACE_STIR #undef STIR_MUTABLE_CONST #endif // __ProjMatrixByBin_H__ - - - diff --git a/src/include/stir/recon_buildblock/ProjMatrixByBin.inl b/src/include/stir/recon_buildblock/ProjMatrixByBin.inl index 1c358553cd..f6cd98055f 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBin.inl +++ b/src/include/stir/recon_buildblock/ProjMatrixByBin.inl @@ -7,7 +7,8 @@ \brief Implementations of inline functions for class stir::ProjMatrixByBin - \author Mustapha Sadki + \author Nikos Efthimiou + \author Mustapha Sadki \author Kris Thielemans \author PARAPET project @@ -15,6 +16,7 @@ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2013, Hammersmith Imanet Ltd + Copyright (C) 2016, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -31,72 +33,65 @@ */ #include "stir/Succeeded.h" #include "stir/recon_buildblock/SymmetryOperation.h" +#include "stir/geometry/line_distances.h" START_NAMESPACE_STIR const DataSymmetriesForBins* -ProjMatrixByBin:: get_symmetries_ptr() const -{ - return symmetries_sptr.get(); +ProjMatrixByBin::get_symmetries_ptr() const { + return symmetries_sptr.get(); } const shared_ptr -ProjMatrixByBin:: get_symmetries_sptr() const -{ - return symmetries_sptr; +ProjMatrixByBin::get_symmetries_sptr() const { + return symmetries_sptr; } -inline void -ProjMatrixByBin:: -get_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& probabilities, - const Bin& bin) STIR_MUTABLE_CONST -{ +inline void +ProjMatrixByBin::get_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& probabilities, const Bin& bin) STIR_MUTABLE_CONST { // start_timers(); TODO, can't do this in a const member // set to empty probabilities.erase(); - - if (cache_stores_only_basic_bins) - { + + if (cache_stores_only_basic_bins) { // find basic bin - Bin basic_bin = bin; - unique_ptr symm_ptr = - symmetries_sptr->find_symmetry_operation_from_basic_bin(basic_bin); - + Bin basic_bin = bin; + unique_ptr symm_ptr = symmetries_sptr->find_symmetry_operation_from_basic_bin(basic_bin); + probabilities.set_bin(basic_bin); - // check if basic bin is in cache - if (get_cached_proj_matrix_elems_for_one_bin(probabilities) == - Succeeded::no) - { + // check if basic bin is in cache + if (get_cached_proj_matrix_elems_for_one_bin(probabilities) == Succeeded::no) { // call 'calculate' just for the basic bin calculate_proj_matrix_elems_for_one_bin(probabilities); #ifndef NDEBUG probabilities.check_state(); #endif - cache_proj_matrix_elems_for_one_bin(probabilities); + cache_proj_matrix_elems_for_one_bin(probabilities); } - - // now transform to original bin - symm_ptr->transform_proj_matrix_elems_for_one_bin(probabilities); - } - else // !cache_stores_only_basic_bins + if (proj_data_info_sptr->is_tof_data() && this->tof_enabled) { + LORInAxialAndNoArcCorrSinogramCoordinates lor; + proj_data_info_sptr->get_LOR(lor, bin); + LORAs2Points lor2(lor); + probabilities.set_bin(bin); + // now apply TOF kernel and transform to original bin + apply_tof_kernel_and_symm_transformation(probabilities, lor2.p1(), lor2.p2(), symm_ptr); + } else { + // now transform to original bin + symm_ptr->transform_proj_matrix_elems_for_one_bin(probabilities); + } + } else // !cache_stores_only_basic_bins { probabilities.set_bin(bin); - // check if in cache - if (get_cached_proj_matrix_elems_for_one_bin(probabilities) == - Succeeded::no) - { + // check if in cache + if (get_cached_proj_matrix_elems_for_one_bin(probabilities) == Succeeded::no) { // find basic bin - Bin basic_bin = bin; - unique_ptr symm_ptr = - symmetries_sptr->find_symmetry_operation_from_basic_bin(basic_bin); + Bin basic_bin = bin; + unique_ptr symm_ptr = symmetries_sptr->find_symmetry_operation_from_basic_bin(basic_bin); probabilities.set_bin(basic_bin); // check if basic bin is in cache - if (get_cached_proj_matrix_elems_for_one_bin(probabilities) == - Succeeded::no) - { + if (get_cached_proj_matrix_elems_for_one_bin(probabilities) == Succeeded::no) { // call 'calculate' just for the basic bin calculate_proj_matrix_elems_for_one_bin(probabilities); #ifndef NDEBUG @@ -104,11 +99,73 @@ get_proj_matrix_elems_for_one_bin( #endif cache_proj_matrix_elems_for_one_bin(probabilities); } - symm_ptr->transform_proj_matrix_elems_for_one_bin(probabilities); - cache_proj_matrix_elems_for_one_bin(probabilities); + if (proj_data_info_sptr->is_tof_data() && this->tof_enabled) { + LORInAxialAndNoArcCorrSinogramCoordinates lor; + proj_data_info_sptr->get_LOR(lor, bin); + LORAs2Points lor2(lor); + probabilities.set_bin(bin); + // now apply TOF kernel and transform to original bin + apply_tof_kernel_and_symm_transformation(probabilities, lor2.p1(), lor2.p2(), symm_ptr); + + } else { + // now transform to original bin + symm_ptr->transform_proj_matrix_elems_for_one_bin(probabilities); + } + cache_proj_matrix_elems_for_one_bin(probabilities); } - } + } // stop_timers(); TODO, can't do this in a const member } +void +ProjMatrixByBin::apply_tof_kernel_and_symm_transformation(ProjMatrixElemsForOneBin& probabilities, + const CartesianCoordinate3D& point1, + const CartesianCoordinate3D& point2, + const unique_ptr& symm_ptr) STIR_MUTABLE_CONST { + + CartesianCoordinate3D voxel_center; + float new_value = 0.f; + float low_dist = 0.f; + float high_dist = 0.f; + + // The direction can be from 1 -> 2 depending on the bin sign. + const CartesianCoordinate3D middle = (point1 + point2) * 0.5f; + const CartesianCoordinate3D diff = point2 - middle; + + const float lor_length = 1.f / (std::sqrt(diff.x() * diff.x() + diff.y() * diff.y() + diff.z() * diff.z())); + + for (ProjMatrixElemsForOneBin::iterator element_ptr = probabilities.begin(); element_ptr != probabilities.end(); + ++element_ptr) { + Coordinate3D c(element_ptr->get_coords()); + symm_ptr->transform_image_coordinates(c); + + voxel_center = image_info_sptr->get_physical_coordinates_for_indices(c); + + project_point_on_a_line(point1, point2, voxel_center); + + const CartesianCoordinate3D x = voxel_center - middle; + + const float d2 = -inner_product(x, diff) * lor_length; + + low_dist = ((proj_data_info_sptr->tof_bin_boundaries_mm[probabilities.get_bin_ptr()->timing_pos_num()].low_lim - d2) * + r_sqrt2_gauss_sigma); + high_dist = ((proj_data_info_sptr->tof_bin_boundaries_mm[probabilities.get_bin_ptr()->timing_pos_num()].high_lim - d2) * + r_sqrt2_gauss_sigma); + + if ((low_dist >= 4.f && high_dist >= 4.f) || (low_dist <= -4.f && high_dist <= -4.f)) { + *element_ptr = ProjMatrixElemsForOneBin::value_type(c, 0.0f); + continue; + } + + get_tof_value(low_dist, high_dist, new_value); + new_value *= element_ptr->get_value(); + *element_ptr = ProjMatrixElemsForOneBin::value_type(c, new_value); + } +} + +void +ProjMatrixByBin::get_tof_value(const float d1, const float d2, float& val) const { + val = 0.5f * (erf(d2) - erf(d1)); +} + END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/ProjMatrixByBinFromFile.h b/src/include/stir/recon_buildblock/ProjMatrixByBinFromFile.h index f54102d602..d9b88fefb8 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBinFromFile.h +++ b/src/include/stir/recon_buildblock/ProjMatrixByBinFromFile.h @@ -20,7 +20,7 @@ \file \ingroup projection - \brief stir::ProjMatrixByBinFromFile's definition + \brief stir::ProjMatrixByBinFromFile's definition \author Kris Thielemans @@ -36,21 +36,20 @@ #include "stir/shared_ptr.h" #include - - START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; class Bin; /*! \ingroup projection \brief Reads/writes a projection matrix from/to file The only supported file format consists of an Interfile-type header - and a binary file which stores the 'basic' elements in a sparse form, + and a binary file which stores the 'basic' elements in a sparse form, i.e. only the elements that cannot by constructed via symmetries. - \todo this class currently only works with VoxelsOnCartesianGrid. + \todo this class currently only works with VoxelsOnCartesianGrid. To fix this, we would need a DiscretisedDensityInfo class, and be able to have constructed the appropriate symmetries object by parsing the .par file @@ -61,60 +60,52 @@ class Bin; Version := 1.0 symmetries type := PET_CartesianGrid PET_CartesianGrid symmetries parameters:= - do_symmetry_90degrees_min_phi:= - do_symmetry_180degrees_min_phi:= - do_symmetry_swap_segment:= - do_symmetry_swap_s:= - do_symmetry_shift_z:= - End PET_CartesianGrid symmetries parameters:= + do_symmetry_90degrees_min_phi:= + do_symmetry_180degrees_min_phi:= + do_symmetry_swap_segment:= + do_symmetry_swap_s:= + do_symmetry_shift_z:= + End PET_CartesianGrid symmetries parameters:= ; example projection data of the same dimensions as used when constructing the matrix template proj data filename:= ; example image of the same dimensions as used when constructing the matrix template density filename:= ; binary data with projection matrix elements - data_filename:= + data_filename:= End ProjMatrixByBinFromFile Parameters:= \endverbatim */ -class ProjMatrixByBinFromFile : - public RegisteredParsingObject< - ProjMatrixByBinFromFile, - ProjMatrixByBin, - ProjMatrixByBin - > -{ -public : +class ProjMatrixByBinFromFile : public RegisteredParsingObject { +public: //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; - + static const char* const registered_name; + //! Writes a projection matrix to file in a format such that this class can read it back /*! Currently this will write an interfile-type header, a file with the binary data, a template image and template sinogram. You will need all 4 to be able to read the matrix back in. */ -static Succeeded - write_to_file(const std::string& output_filename_prefix, - const ProjMatrixByBin& proj_matrix, - const shared_ptr& proj_data_info_sptr, - const DiscretisedDensity<3,float>& template_density); - + static Succeeded write_to_file(const std::string& output_filename_prefix, const ProjMatrixByBin& proj_matrix, + const shared_ptr& proj_data_info_sptr, + const DiscretisedDensity<3, float>& template_density); + //! Default constructor (calls set_defaults()) ProjMatrixByBinFromFile(); //! Checks all necessary geometric info - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); -private: + virtual ProjMatrixByBinFromFile* clone() const; +private: std::string parsed_version; std::string template_density_filename; std::string template_proj_data_filename; std::string data_filename; - + std::string symmetries_type; // should be in symmetries bool do_symmetry_90degrees_min_phi; @@ -126,28 +117,20 @@ static Succeeded // TODO this only works as long as we only have VoxelsOnCartesianGrid // explicitly list necessary members for image details (should use an Info object instead) CartesianCoordinate3D voxel_size; - CartesianCoordinate3D origin; + CartesianCoordinate3D origin; IndexRange<3> densel_range; - shared_ptr proj_data_info_ptr; - - virtual void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const; + virtual void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); Succeeded read_data(); - }; END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir/recon_buildblock/ProjMatrixByBinSPECTUB.h b/src/include/stir/recon_buildblock/ProjMatrixByBinSPECTUB.h index aa4f42ea7c..afad02495a 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBinSPECTUB.h +++ b/src/include/stir/recon_buildblock/ProjMatrixByBinSPECTUB.h @@ -19,7 +19,7 @@ \file \ingroup projection - \brief stir::ProjMatrixByBinSPECTUB's definition + \brief stir::ProjMatrixByBinSPECTUB's definition \author Berta Marti Fuster \author Kris Thielemans @@ -35,28 +35,28 @@ #include "stir/shared_ptr.h" #include - #include "stir/recon_buildblock/SPECTUB_Tools.h" START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; class Bin; /*! \ingroup projection \brief generates projection matrix for SPECT studies This functionality is described in - Berta Marti Fuster, Carles Falcon, Charalampos Tsoumpas, Lefteris Livieratos, Pablo Aguiar, Albert Cot, Domenec Ros and Kris Thielemans, - Integration of advanced 3D SPECT modeling into the open-source STIR framework, - Med. Phys. 40, 092502 (2013); http://dx.doi.org/10.1118/1.4816676 + Berta Marti Fuster, Carles Falcon, Charalampos Tsoumpas, Lefteris Livieratos, Pablo Aguiar, Albert Cot, Domenec Ros and Kris +Thielemans, Integration of advanced 3D SPECT modeling into the open-source STIR framework, Med. Phys. 40, 092502 (2013); +http://dx.doi.org/10.1118/1.4816676 - \warning this class currently only works with VoxelsOnCartesianGrid. + \warning this class currently only works with VoxelsOnCartesianGrid. \par Sample parameter file \verbatim - Projection Matrix By Bin SPECT UB Parameters:= + Projection Matrix By Bin SPECT UB Parameters:= ; width of PSF maximum number of sigmas:= 2.0 @@ -69,8 +69,8 @@ class Bin; collimator sigma 0(cm) := 0.1466 ;Attenuation correction { Simple // Full // No } - attenuation type := Simple - ;Values in attenuation map in cm-1 + attenuation type := Simple + ;Values in attenuation map in cm-1 attenuation map := attMapRec.hv ;Mask properties { Cylinder // Attenuation Map // Explicit Mask // No} @@ -84,17 +84,11 @@ End Projection Matrix By Bin SPECT UB Parameters:= \endverbatim */ -class ProjMatrixByBinSPECTUB : - public RegisteredParsingObject< - ProjMatrixByBinSPECTUB, - ProjMatrixByBin, - ProjMatrixByBin - > -{ - public : +class ProjMatrixByBinSPECTUB : public RegisteredParsingObject { +public: //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor (calls set_defaults()) ProjMatrixByBinSPECTUB(); @@ -102,10 +96,9 @@ class ProjMatrixByBinSPECTUB : ~ProjMatrixByBinSPECTUB(); //! Checks all necessary geometric info - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); bool get_keep_all_views_in_cache() const; //! Enable keeping the matrix in memory @@ -122,8 +115,7 @@ class ProjMatrixByBinSPECTUB : You have to call set_up() after this (unless the value didn't change). */ void set_attenuation_type(const std::string& value); - shared_ptr > - get_attenuation_image_sptr() const; + shared_ptr> get_attenuation_image_sptr() const; //! Sets attenuation image /*! The image has to have same characteristics as the emission image currently. @@ -132,10 +124,8 @@ class ProjMatrixByBinSPECTUB : You have to call set_up() after this. */ - void - set_attenuation_image_sptr(const shared_ptr > value); - void - set_attenuation_image_sptr(const std::string& value); + void set_attenuation_image_sptr(const shared_ptr> value); + void set_attenuation_image_sptr(const std::string& value); //! Set the parameters for the depth-dependent resolution model /*! The detector and collimator blurring is modelled as a Gaussian with sigma dependent on the @@ -152,13 +142,15 @@ class ProjMatrixByBinSPECTUB : You have to call set_up() after this. */ - void - set_resolution_model(const float collimator_sigma_0_in_mm, const float collimator_slope_in_mm, const bool full_3D = true); + void set_resolution_model(const float collimator_sigma_0_in_mm, const float collimator_slope_in_mm, const bool full_3D = true); - private: + // Alex + // Fix to compile, missing function definition in header + ProjMatrixByBinSPECTUB* clone() const; +private: // parameters that will be parsed - + float minimum_weight; float maximum_number_of_sigmas; float spatial_resolution_PSF; @@ -173,47 +165,43 @@ class ProjMatrixByBinSPECTUB : // explicitly list necessary members for image details (should use an Info object instead) CartesianCoordinate3D voxel_size; - CartesianCoordinate3D origin; + CartesianCoordinate3D origin; IndexRange<3> densel_range; shared_ptr proj_data_info_ptr; bool already_setup; - - virtual void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const; + virtual void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - shared_ptr > attenuation_image_sptr; + shared_ptr> attenuation_image_sptr; // wm_SPECT starts here --------------------------------------------------------------------------------------------- - bool *msk_3d; //!< voxels to be included in matrix (no weight calculated outside the mask) - bool *msk_2d; //!< 2d collapse of msk_3d. + bool* msk_3d; //!< voxels to be included in matrix (no weight calculated outside the mask) + bool* msk_2d; //!< 2d collapse of msk_3d. //... variables for estimated sizes of arrays to allocate ................................ - int **NITEMS; //!< number of non-zero elements for each weight matrix row + int** NITEMS; //!< number of non-zero elements for each weight matrix row //... user defined structures (types defined in SPECTUB_Tools.h) ..................................... - SPECTUB::volume_type vol; //!< structure with volume (image) information - SPECTUB::proj_type prj; //!< structure with projection information + SPECTUB::volume_type vol; //!< structure with volume (image) information + SPECTUB::proj_type prj; //!< structure with projection information - SPECTUB::voxel_type vox; //!< structure with voxel information - SPECTUB::bin_type bin; //!< structure with bin information + SPECTUB::voxel_type vox; //!< structure with voxel information + SPECTUB::bin_type bin; //!< structure with bin information - SPECTUB::angle_type * ang; //!< structure with angle indices, values, ratios and voxel projections - float *attmap; //!< attenuation map (copied as float array) + SPECTUB::angle_type* ang; //!< structure with angle indices, values, ratios and voxel projections + float* attmap; //!< attenuation map (copied as float array) - SPECTUB::discrf_type gaussdens; //!< structure with gaussian density function + SPECTUB::discrf_type gaussdens; //!< structure with gaussian density function int maxszb; - void compute_one_subset(const int kOS) const; void delete_UB_SPECT_arrays(); mutable std::vector subset_already_processed; @@ -222,6 +210,3 @@ class ProjMatrixByBinSPECTUB : END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir/recon_buildblock/ProjMatrixByBinUsingInterpolation.h b/src/include/stir/recon_buildblock/ProjMatrixByBinUsingInterpolation.h index 3b96754fc0..5f9aa3d6ba 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBinUsingInterpolation.h +++ b/src/include/stir/recon_buildblock/ProjMatrixByBinUsingInterpolation.h @@ -20,7 +20,7 @@ \file \ingroup projection - \brief stir::ProjMatrixByBinUsingInterpolation's definition + \brief stir::ProjMatrixByBinUsingInterpolation's definition \author Kris Thielemans @@ -34,49 +34,44 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/shared_ptr.h" - - START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; class Bin; /*! \ingroup projection \brief Computes projection matrix elements for VoxelsOnCartesianGrid images - by using an interpolation model. + by using an interpolation model. This class implements a projection model that interpolates in projection space. - When used for back-projection, it should give the same results as + When used for back-projection, it should give the same results as BackProjectorByByUsingInterpolation, but is probably much slower. The current implementation uses some quite generic code to handle symmetries, but - is very very slow to compute the elements. Once they are cached, performance is + is very very slow to compute the elements. Once they are cached, performance is as usual of course. \warning Preliminary code, not tested to usual STIR standards. */ -class ProjMatrixByBinUsingInterpolation : - public RegisteredParsingObject< - ProjMatrixByBinUsingInterpolation, - ProjMatrixByBin, - ProjMatrixByBin - > -{ -public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; +class ProjMatrixByBinUsingInterpolation + : public RegisteredParsingObject { +public: + //! Name which will be used when parsing a ProjMatrixByBin object + static const char* const registered_name; //! Default constructor (calls set_defaults()) ProjMatrixByBinUsingInterpolation(); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); + + virtual ProjMatrixByBinUsingInterpolation* clone() const; private: bool do_symmetry_90degrees_min_phi; @@ -87,97 +82,80 @@ public : // explicitly list necessary members for image details (should use an Info object instead) CartesianCoordinate3D voxel_size; - CartesianCoordinate3D origin; + CartesianCoordinate3D origin; IndexRange<3> densel_range; - shared_ptr proj_data_info_ptr; // for Jacobian - const ProjDataInfoCylindrical& - proj_data_info_cyl() const - { return static_cast(*proj_data_info_ptr); } -/*! - \brief - The next class is used - to take geometric things - into account. It also includes some normalisation. (internal use only). - - \internal - - Use as follows: - TODO incorrect (also in original) - \code - const JacobianForIntBP jacobian(*(segment.scanner)); - jacobian(segment.get_average_delta(), s+ 0.5); - \endcode - */ - - -class JacobianForIntBP -{ -private: - // store some scanner related data to avoid recomputation - float R2; - float ring_spacing2; - bool arccor; - // total normalisation of backprojection, 3 factors: - // (_Pi/scanner.num_views) for discretisation of integral over phi - // scanner.ring_spacing for discretisation of integral over delta - // normalisation of projection space integral: 1/(2 Pi) - - float backprojection_normalisation; - - bool use_exact_Jacobian_now; - -public: - // default constructor needed as now member of projector class (better to make set_up) - JacobianForIntBP() {} - explicit JacobianForIntBP(const ProjDataInfoCylindrical* proj_data_info_ptr, bool exact); - // s in mm here! - float operator()(const float delta, const float s) const - { - float tmp; - if (use_exact_Jacobian_now) - tmp = 4*(R2 - s*s); - else - tmp = 4*R2; - if (!arccor) - tmp *= sqrt(tmp); - return - (arccor ? tmp : pow(tmp,1.5F)) / - pow(tmp + ring_spacing2*delta*delta, 1.5F)* backprojection_normalisation; - } -}; - + const ProjDataInfoCylindrical& proj_data_info_cyl() const { + return static_cast(*proj_data_info_ptr); + } + /*! + \brief + The next class is used + to take geometric things + into account. It also includes some normalisation. (internal use only). + + \internal + + Use as follows: + TODO incorrect (also in original) + \code + const JacobianForIntBP jacobian(*(segment.scanner)); + jacobian(segment.get_average_delta(), s+ 0.5); + \endcode + */ + + class JacobianForIntBP { + private: + // store some scanner related data to avoid recomputation + float R2; + float ring_spacing2; + bool arccor; + // total normalisation of backprojection, 3 factors: + // (_Pi/scanner.num_views) for discretisation of integral over phi + // scanner.ring_spacing for discretisation of integral over delta + // normalisation of projection space integral: 1/(2 Pi) + + float backprojection_normalisation; + + bool use_exact_Jacobian_now; + + public: + // default constructor needed as now member of projector class (better to make set_up) + JacobianForIntBP() {} + explicit JacobianForIntBP(const ProjDataInfoCylindrical* proj_data_info_ptr, bool exact); + // s in mm here! + float operator()(const float delta, const float s) const { + float tmp; + if (use_exact_Jacobian_now) + tmp = 4 * (R2 - s * s); + else + tmp = 4 * R2; + if (!arccor) + tmp *= sqrt(tmp); + return (arccor ? tmp : pow(tmp, 1.5F)) / pow(tmp + ring_spacing2 * delta * delta, 1.5F) * backprojection_normalisation; + } + }; JacobianForIntBP jacobian; bool use_piecewise_linear_interpolation_now; bool use_exact_Jacobian_now; - virtual void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const; + virtual void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - float - get_element(const Bin& bin, - const CartesianCoordinate3D& densel_ctr) const; - private: - void - find_tang_ax_pos_diff(float& tang_pos_diff, - float& ax_pos_diff, - const Bin& bin, - const CartesianCoordinate3D& point) const; - + float get_element(const Bin& bin, const CartesianCoordinate3D& densel_ctr) const; + +private: + void find_tang_ax_pos_diff(float& tang_pos_diff, float& ax_pos_diff, const Bin& bin, + const CartesianCoordinate3D& point) const; }; END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h b/src/include/stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h index 54906f67d5..22c3ec446d 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h +++ b/src/include/stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h @@ -2,7 +2,7 @@ \file \ingroup projection - \brief stir::ProjMatrixByBinUsingRayTracing's definition + \brief stir::ProjMatrixByBinUsingRayTracing's definition \author Kris Thielemans \author Mustapha Sadki @@ -34,20 +34,19 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/shared_ptr.h" - - START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; class ProjDataInfo; /*! \ingroup projection \brief Computes projection matrix elements for VoxelsOnCartesianGrid images - by using a Length of Intersection (LOI) model. + by using a Length of Intersection (LOI) model. Currently, the LOIs are divided by voxel_size.x(), unless NEWSCALE is - #defined during compilation time of ProjMatrixByBinUsingRayTracing.cxx. + #defined during compilation time of ProjMatrixByBinUsingRayTracing.cxx. It is possible to use multiple LORs in tangential direction. The result will then be the average of the various contributions. Currently all these @@ -58,16 +57,16 @@ class ProjDataInfo; 2 or 3 LORs are used, to avoid missing voxels. (TODOdoc describe how). If use_actual_detector_boundaries is set (currently only possible - for non-arccorrected data, without mashing and/or axial compression), - the detectors are assumed to be on a cylinder. If only a single LOR - in tangential direction is used for ray tracing, + for non-arccorrected data, without mashing and/or axial compression), + the detectors are assumed to be on a cylinder. If only a single LOR + in tangential direction is used for ray tracing, the centre of those detectors is used, which is slightly different from the 'usual' LOR (due to interleaving of the sinogram). When multiple LORs are used, the actual detector sizes are used, such that the resulting strip is twice as wide. It is possible to use a cylindrical or cuboid FOV (in the latter case it - is going to be square in transaxial direction). In both cases, the FOV is + is going to be square in transaxial direction). In both cases, the FOV is slightly 'inside' the image (i.e. it is about 1 voxel at each side smaller than the maximum possible). @@ -81,7 +80,7 @@ class ProjDataInfo; Enabling more symmetries (from DataSymmetriesForBins_PET_CartesianGrid) means that less memory is needed to store the matrix (when caching), less time to compute it, but using the matrix might be slightly slower. By default, as many symmetries as possible are enabled. - + \par Parsing parameters The following parameters can be set (default values are indicated): @@ -98,7 +97,7 @@ class ProjDataInfo; do_symmetry_shift_z := 1 End Ray Tracing Matrix Parameters := \endverbatim - + \par Implementation details The implementation uses RayTraceVoxelsOnCartesianGrid(). @@ -108,37 +107,33 @@ class ProjDataInfo; \warning Only appropriate for VoxelsOnCartesianGrid type of images (otherwise error() will be called). - - \warning Care should be taken to select the number of rays in tangential direction + + \warning Care should be taken to select the number of rays in tangential direction such that the sampling is at least as small as the x,y voxel sizes. \warning Current implementation assumes that z voxel size is either smaller than or exactly twice the sampling in axial direction of the segments. - \bug Currently, strange things happen if the z voxel size is not exactly equal to half + \bug Currently, strange things happen if the z voxel size is not exactly equal to half the ring spacing of the scanner. */ -class ProjMatrixByBinUsingRayTracing : - public RegisteredParsingObject< - ProjMatrixByBinUsingRayTracing, - ProjMatrixByBin, - ProjMatrixByBin - > -{ -public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; +class ProjMatrixByBinUsingRayTracing + : public RegisteredParsingObject { +public: + //! Name which will be used when parsing a ProjMatrixByBin object + static const char* const registered_name; //! Default constructor (calls set_defaults()) ProjMatrixByBinUsingRayTracing(); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); + + virtual ProjMatrixByBinUsingRayTracing* clone() const; //! \name If a cylindrical FOV or the whole image will be handled //!@{ @@ -195,26 +190,19 @@ public : // explicitly list necessary members for image details (should use an Info object instead) CartesianCoordinate3D voxel_size; - CartesianCoordinate3D origin; + CartesianCoordinate3D origin; CartesianCoordinate3D min_index; CartesianCoordinate3D max_index; shared_ptr proj_data_info_ptr; + virtual void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const; - virtual void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const; - - virtual void set_defaults(); - virtual void initialise_keymap(); - virtual bool post_processing(); - + virtual void set_defaults(); + virtual void initialise_keymap(); + virtual bool post_processing(); }; END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.h b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.h index a869a966c9..5fc484dc00 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.h +++ b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.h @@ -8,17 +8,19 @@ \file \ingroup projection - + \brief Declaration of class stir::ProjMatrixElemsForOneBin - + + \author Nikos Efthimiou \author Mustapha Sadki \author Kris Thielemans \author PARAPET project - + */ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2009, Hammersmith Imanet Ltd + Copyright (C) 2016, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -34,8 +36,6 @@ See STIR/LICENSE.txt for details */ - - #include "stir/recon_buildblock/ProjMatrixElemsForOneBinValue.h" #include "stir/Bin.h" #include @@ -44,10 +44,8 @@ START_NAMESPACE_STIR class Succeeded; class RelatedBins; -template class DiscretisedDensity; - - - +template +class DiscretisedDensity; /*! \brief This stores the non-zero projection matrix elements @@ -63,22 +61,21 @@ template class DiscretisedDensity; \todo It might be useful to template this class in terms of the - element-type as well. That way, we could have 'compact' + element-type as well. That way, we could have 'compact' elements, efficient elements, etc. However, doing this will probably only be useful if all ProjMatrixByBin classes are then templated as well, which would be a pain. */ -/* +/* it might be a bit faster to derive this (privately) from std::vector as opposed to having a member of that type. TODO: check */ -class ProjMatrixElemsForOneBin -{ +class ProjMatrixElemsForOneBin { public: - /*! \brief Recommended way to call the type of the elements, instead of + /*! \brief Recommended way to call the type of the elements, instead of referring to the actual classname. Think about this name as 'the type of the value of a ProjMatrixElemsForOneBin::iterator *'. @@ -86,14 +83,15 @@ class ProjMatrixElemsForOneBin This typedef is also required for 'standard' iterators. */ typedef ProjMatrixElemsForOneBinValue value_type; + private: //! shorthand to keep typedefs below concise typedef std::vector Element_vector; -public: +public: //! typedefs for iterator support - typedef Element_vector::iterator iterator; - typedef Element_vector::const_iterator const_iterator; + typedef Element_vector::iterator iterator; + typedef Element_vector::const_iterator const_iterator; typedef Element_vector::size_type size_type; typedef Element_vector::difference_type difference_type; typedef std::random_access_iterator_tag iterator_category; @@ -101,59 +99,60 @@ class ProjMatrixElemsForOneBin typedef value_type& reference; typedef const value_type& const_reference; - //! constructor /*! \param bin effectively calls set_bin(bin) \param default_capacity effectively calls reserve(default_capacity) */ - explicit ProjMatrixElemsForOneBin(const Bin& bin= Bin(), const int default_capacity = 0); - - /* rely on compiler-generated versions + explicit ProjMatrixElemsForOneBin(const Bin& bin = Bin(), const int default_capacity = 0); + + /* rely on compiler-generated versions ProjMatrixElemsForOneBin( const ProjMatrixElemsForOneBin&); ProjMatrixElemsForOneBin& operator=(const ProjMatrixElemsForOneBin&) ; */ //! check if each voxel occurs only once Succeeded check_state() const; - + //! get the bin coordinates corresponding to this row inline Bin get_bin() const; //! and set the bin coordinates inline void set_bin(const Bin&); + //! get a ref to the bin + inline Bin* get_bin_ptr(); //! functions for allowing iterator access - inline iterator begin() ; - inline const_iterator begin() const; + inline iterator begin(); + inline const_iterator begin() const; inline iterator end(); inline const_iterator end() const; //! reset lor to 0 length void erase(); //! add a new value_type object at the end - /*! - \warning For future compatibility, it is required - (but not checked) that the elements are added such + /*! + \warning For future compatibility, it is required + (but not checked) that the elements are added such that calling sort() after the push_back() would not change the order of the elements. Otherwise, schemes for 'incremental' storing of coordinates would require too much overhead. */ - inline void push_back( const value_type&); + inline void push_back(const value_type&); //! reserve enough space for max_number elements (but don't fill them in) void reserve(size_type max_number); //! number of non-zero elements - inline size_type size() const; + inline size_type size() const; //! number of allocated elements size_type capacity() const; //! Multiplies all values with a constant - ProjMatrixElemsForOneBin& operator*=(const float d); + ProjMatrixElemsForOneBin& operator*=(const float d); //! Divides all values with a constant - ProjMatrixElemsForOneBin& operator/=(const float d); - + ProjMatrixElemsForOneBin& operator/=(const float d); + //! Sort the elements on coordinates of the voxels /*! Uses value_type::coordinates_less as ordering function. - */ + */ void sort(); //! merge 2nd lor into current object @@ -161,7 +160,7 @@ class ProjMatrixElemsForOneBin \warning This currently modifies the argument \c lor. */ // TODO make sure we can have a const argument - void merge(ProjMatrixElemsForOneBin &lor ); + void merge(ProjMatrixElemsForOneBin& lor); //! Compare 2 lors to see if they are equal /*! \warning Compares element by element. Does not sort first or so. @@ -170,15 +169,13 @@ class ProjMatrixElemsForOneBin \warning this is a fairly CPU intensive operation. */ bool operator==(const ProjMatrixElemsForOneBin&) const; - //! Compare 2 lors + //! Compare 2 lors bool operator!=(const ProjMatrixElemsForOneBin&) const; - #if 0 void write(std::fstream&fst) const; void read(std::fstream&fst ); #endif - //! Return sum of squares of all values /*! \warning This sums over all elements in the LOR, irrespective if they @@ -188,31 +185,24 @@ class ProjMatrixElemsForOneBin //******************** projection operations ********************// - //! back project a single bin - void back_project(DiscretisedDensity<3,float>&, - const Bin&) const; + //! back project a single bin + void back_project(DiscretisedDensity<3, float>&, const Bin&) const; //! forward project into a single bin - void forward_project(Bin&, - const DiscretisedDensity<3,float>&) const; - //! back project related bins - void back_project(DiscretisedDensity<3,float>&, - const RelatedBins&) const; + void forward_project(Bin&, const DiscretisedDensity<3, float>&) const; + //! back project related bins + void back_project(DiscretisedDensity<3, float>&, const RelatedBins&) const; //! forward project related bins - void forward_project(RelatedBins&, - const DiscretisedDensity<3,float>&) const; + void forward_project(RelatedBins&, const DiscretisedDensity<3, float>&) const; - private: - std::vector elements; + std::vector elements; Bin bin; - //! remove a single value_type inline iterator erase(iterator it); }; - END_NAMESPACE_STIR #include "stir/recon_buildblock/ProjMatrixElemsForOneBin.inl" diff --git a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.inl b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.inl index 4fac67243c..9a7afbd632 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.inl +++ b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.inl @@ -33,57 +33,55 @@ START_NAMESPACE_STIR -Bin -ProjMatrixElemsForOneBin:: -get_bin() const -{ +Bin +ProjMatrixElemsForOneBin::get_bin() const { return bin; } +Bin* +ProjMatrixElemsForOneBin::get_bin_ptr() { + return &bin; +} + void -ProjMatrixElemsForOneBin:: -set_bin(const Bin& new_bin) -{ +ProjMatrixElemsForOneBin::set_bin(const Bin& new_bin) { bin = new_bin; } -void ProjMatrixElemsForOneBin::push_back( const ProjMatrixElemsForOneBin::value_type& el) -{ - elements.push_back(el); +void +ProjMatrixElemsForOneBin::push_back(const ProjMatrixElemsForOneBin::value_type& el) { + elements.push_back(el); } - -ProjMatrixElemsForOneBin::size_type -ProjMatrixElemsForOneBin:: -size() const -{ +ProjMatrixElemsForOneBin::size_type +ProjMatrixElemsForOneBin::size() const { return elements.size(); } -ProjMatrixElemsForOneBin::iterator -ProjMatrixElemsForOneBin::begin() - { return elements.begin(); } - -ProjMatrixElemsForOneBin::const_iterator -ProjMatrixElemsForOneBin:: -begin() const - { return elements.begin(); }; - -ProjMatrixElemsForOneBin::iterator -ProjMatrixElemsForOneBin:: -end() - { return elements.end(); }; - -ProjMatrixElemsForOneBin::const_iterator -ProjMatrixElemsForOneBin:: -end() const - { return elements.end(); }; - -ProjMatrixElemsForOneBin::iterator -ProjMatrixElemsForOneBin:: -erase(iterator it){ - return elements.erase(it); - } +ProjMatrixElemsForOneBin::iterator +ProjMatrixElemsForOneBin::begin() { + return elements.begin(); +} + +ProjMatrixElemsForOneBin::const_iterator +ProjMatrixElemsForOneBin::begin() const { + return elements.begin(); +}; + +ProjMatrixElemsForOneBin::iterator +ProjMatrixElemsForOneBin::end() { + return elements.end(); +}; + +ProjMatrixElemsForOneBin::const_iterator +ProjMatrixElemsForOneBin::end() const { + return elements.end(); +}; + +ProjMatrixElemsForOneBin::iterator +ProjMatrixElemsForOneBin::erase(iterator it) { + return elements.erase(it); +} #if 0 unsigned int ProjMatrixElemsForOneBin::make_key(int X,int Y,int Z) diff --git a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBinValue.h b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBinValue.h index b21cf3a65a..b1116cc002 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBinValue.h +++ b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBinValue.h @@ -3,13 +3,13 @@ /*! \file \ingroup projection - + \brief Declaration of class stir::ProjMatrixElemsForOneBinValue - + \author Kris Thielemans \author Mustapha Sadki \author PARAPET project - + */ /* Copyright (C) 2000 PARAPET partners @@ -32,17 +32,17 @@ #ifndef __ProjMatrixElemsForOneBinValue_H__ #define __ProjMatrixElemsForOneBinValue_H__ - #include "stir/common.h" START_NAMESPACE_STIR -template class BasicCoordinate; +template +class BasicCoordinate; /*! \ingroup projection - \brief Stores voxel coordinates and the value of the matrix element. - + \brief Stores voxel coordinates and the value of the matrix element. + (Probably) only useful in class ProjMatrixElemsForOneBin. \warning It is recommended never to use this class name directly, but @@ -51,18 +51,14 @@ template class BasicCoordinate; \warning Voxel coordinates are currently stored as shorts for saving memory. */ -class ProjMatrixElemsForOneBinValue -{ +class ProjMatrixElemsForOneBinValue { public: - explicit inline - ProjMatrixElemsForOneBinValue(const BasicCoordinate<3,int>& coords, - const float ivalue=0); + explicit inline ProjMatrixElemsForOneBinValue(const BasicCoordinate<3, int>& coords, const float ivalue = 0); inline ProjMatrixElemsForOneBinValue(); - //! get the coordinates - inline BasicCoordinate<3,int> get_coords() const; + inline BasicCoordinate<3, int> get_coords() const; //! In effect the same as get_coords()[1] (but faster) inline int coord1() const; @@ -78,12 +74,11 @@ class ProjMatrixElemsForOneBinValue inline ProjMatrixElemsForOneBinValue& operator+=(const ProjMatrixElemsForOneBinValue& el2); //! Multiplies the value of with a float inline ProjMatrixElemsForOneBinValue& operator*=(const float d); - //! Adds a float to the value + //! Adds a float to the value inline ProjMatrixElemsForOneBinValue& operator+=(const float d); //! Divides the value of with a float inline ProjMatrixElemsForOneBinValue& operator/=(const float d); - //////// comparison functions //! Checks if the coordinates are equal @@ -94,20 +89,18 @@ class ProjMatrixElemsForOneBinValue //! Checks lexicographical order of the coordinates static inline bool coordinates_less(const ProjMatrixElemsForOneBinValue& el1, const ProjMatrixElemsForOneBinValue& el2); - + //! Checks coordinates and value are equal friend inline bool operator==(const ProjMatrixElemsForOneBinValue& el1, const ProjMatrixElemsForOneBinValue& el2); - + //! Checks lexicographical order of the coordinates and the value friend inline bool operator<(const ProjMatrixElemsForOneBinValue& el1, const ProjMatrixElemsForOneBinValue& el2); - + private: - short c3,c2,c1; + short c3, c2, c1; float value; - }; - END_NAMESPACE_STIR #include "stir/recon_buildblock/ProjMatrixElemsForOneBinValue.inl" diff --git a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBinValue.inl b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBinValue.inl index 6fd22eb4c3..6cb1dd8210 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBinValue.inl +++ b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBinValue.inl @@ -3,13 +3,13 @@ /*! \file \ingroup projection - + \brief Inline implementations for class stir::ProjMatrixElemsForOneBinValue - + \author Kris Thielemans \author Mustapha Sadki \author PARAPET project - + */ /* Copyright (C) 2000 PARAPET partners @@ -31,133 +31,97 @@ #include "stir/Coordinate3D.h" -//for SHRT_MAX etc +// for SHRT_MAX etc #ifndef NDEBUG -#include +# include #endif START_NAMESPACE_STIR -ProjMatrixElemsForOneBinValue:: -ProjMatrixElemsForOneBinValue(const BasicCoordinate<3,int>& coords, - const float ivalue) - : c3(static_cast(coords[3])), - c2(static_cast(coords[2])), - c1(static_cast(coords[1])), - value(ivalue) -{ +ProjMatrixElemsForOneBinValue::ProjMatrixElemsForOneBinValue(const BasicCoordinate<3, int>& coords, const float ivalue) + : c3(static_cast(coords[3])), c2(static_cast(coords[2])), c1(static_cast(coords[1])), value(ivalue) { assert(coords[3] <= SHRT_MAX); assert(coords[3] >= SHRT_MIN); assert(coords[2] <= SHRT_MAX); assert(coords[2] >= SHRT_MIN); assert(coords[1] <= SHRT_MAX); assert(coords[1] >= SHRT_MIN); -} - -ProjMatrixElemsForOneBinValue:: -ProjMatrixElemsForOneBinValue() - : c3(0), - c2(0), - c1(0), - value(0) -{} - -BasicCoordinate<3,int> -ProjMatrixElemsForOneBinValue:: -get_coords() const -{ - return Coordinate3D(c1,c2,c3); } -int -ProjMatrixElemsForOneBinValue:: -coord1() const -{ return static_cast(c1); } - -int -ProjMatrixElemsForOneBinValue:: -coord2() const -{ return static_cast(c2); } - -int -ProjMatrixElemsForOneBinValue:: -coord3() const -{ return static_cast(c3); } - -float -ProjMatrixElemsForOneBinValue:: -get_value() const -{ return value; } - - -ProjMatrixElemsForOneBinValue& -ProjMatrixElemsForOneBinValue:: -operator+=(const ProjMatrixElemsForOneBinValue& el2) -{ +ProjMatrixElemsForOneBinValue::ProjMatrixElemsForOneBinValue() : c3(0), c2(0), c1(0), value(0) {} + +BasicCoordinate<3, int> +ProjMatrixElemsForOneBinValue::get_coords() const { + return Coordinate3D(c1, c2, c3); +} + +int +ProjMatrixElemsForOneBinValue::coord1() const { + return static_cast(c1); +} + +int +ProjMatrixElemsForOneBinValue::coord2() const { + return static_cast(c2); +} + +int +ProjMatrixElemsForOneBinValue::coord3() const { + return static_cast(c3); +} + +float +ProjMatrixElemsForOneBinValue::get_value() const { + return value; +} + +ProjMatrixElemsForOneBinValue& +ProjMatrixElemsForOneBinValue::operator+=(const ProjMatrixElemsForOneBinValue& el2) { assert(get_coords() == el2.get_coords()); value += el2.value; return *this; } -ProjMatrixElemsForOneBinValue& -ProjMatrixElemsForOneBinValue:: -operator+=(const float d) -{ +ProjMatrixElemsForOneBinValue& +ProjMatrixElemsForOneBinValue::operator+=(const float d) { value += d; return *this; } -ProjMatrixElemsForOneBinValue& -ProjMatrixElemsForOneBinValue:: -operator*=(const float d) -{ +ProjMatrixElemsForOneBinValue& +ProjMatrixElemsForOneBinValue::operator*=(const float d) { value *= d; return *this; } -ProjMatrixElemsForOneBinValue& -ProjMatrixElemsForOneBinValue:: -operator/=(const float d) -{ +ProjMatrixElemsForOneBinValue& +ProjMatrixElemsForOneBinValue::operator/=(const float d) { value /= d; return *this; } -bool -ProjMatrixElemsForOneBinValue:: -coordinates_equal(const ProjMatrixElemsForOneBinValue& el1, const ProjMatrixElemsForOneBinValue& el2) -{ - return el1.c3==el2.c3 && el1.c2==el2.c2 && el1.c1==el2.c1; +bool +ProjMatrixElemsForOneBinValue::coordinates_equal(const ProjMatrixElemsForOneBinValue& el1, + const ProjMatrixElemsForOneBinValue& el2) { + return el1.c3 == el2.c3 && el1.c2 == el2.c2 && el1.c1 == el2.c1; } -bool -ProjMatrixElemsForOneBinValue:: -coordinates_less(const ProjMatrixElemsForOneBinValue& el1, const ProjMatrixElemsForOneBinValue& el2) -{ - return el1.c1 - START_NAMESPACE_STIR class RelatedDensels; -template class DiscretisedDensity; +template +class DiscretisedDensity; class Succeeded; - - /*! \ingroup projection \brief This stores the non-zero projection matrix elements for every 'voxel'. @@ -56,22 +52,21 @@ class Succeeded; base class, templated in the type of element (TODO). It might be useful to template this class in terms of the - element-type as well. That way, we could have 'compact' + element-type as well. That way, we could have 'compact' elements, efficient elements, etc. However, doing this will probably only be useful if all ProjMatrixByDensel classes are then templated as well (TODO?). */ -/* +/* it might be a bit faster to derive this (privately) from std::vector as opposed to having a member of that type. TODO: check */ -class ProjMatrixElemsForOneDensel -{ +class ProjMatrixElemsForOneDensel { public: - /*! \brief Recommended way to call the type of the elements, instead of + /*! \brief Recommended way to call the type of the elements, instead of referring to the actual classname. Think about this name as 'the type of the value of a ProjMatrixElemsForOneDensel::iterator *'. @@ -79,14 +74,15 @@ class ProjMatrixElemsForOneDensel This typedef is also required for 'standard' iterators. */ typedef ProjMatrixElemsForOneDenselValue value_type; + private: //! shorthand to keep typedefs below concise typedef std::vector Element_vector; -public: +public: //! typedefs for iterator support - typedef Element_vector::iterator iterator; - typedef Element_vector::const_iterator const_iterator; + typedef Element_vector::iterator iterator; + typedef Element_vector::const_iterator const_iterator; typedef Element_vector::size_type size_type; typedef Element_vector::difference_type difference_type; typedef std::random_access_iterator_tag iterator_category; @@ -94,59 +90,58 @@ class ProjMatrixElemsForOneDensel typedef value_type& reference; typedef const value_type& const_reference; - //! constructor - ProjMatrixElemsForOneDensel(); + ProjMatrixElemsForOneDensel(); /*! \param Densel effectively calls set_densel(Densel) \param default_capacity effectively calls reserve(default_capacity) */ - explicit ProjMatrixElemsForOneDensel(const Densel& Densel, const int default_capacity = 300); - - /* rely on compiler-generated versions + explicit ProjMatrixElemsForOneDensel(const Densel& Densel, const int default_capacity = 300); + + /* rely on compiler-generated versions ProjMatrixElemsForOneDensel( const ProjMatrixElemsForOneDensel&); ProjMatrixElemsForOneDensel& operator=(const ProjMatrixElemsForOneDensel&) ; */ //! check if each voxel occurs only once Succeeded check_state() const; - + //! get the Densel coordinates corresponding to this row inline Densel get_densel() const; //! and set the Densel coordinates inline void set_densel(const Densel&); //! functions for allowing iterator access - inline iterator begin() ; - inline const_iterator begin() const; + inline iterator begin(); + inline const_iterator begin() const; inline iterator end(); inline const_iterator end() const; //! reset lor to 0 length void erase(); //! add a new value_type object at the end - /*! - \warning For future compatibility, it is required - (but not checked) that the elements are added such + /*! + \warning For future compatibility, it is required + (but not checked) that the elements are added such that calling sort() after the push_back() would not change the order of the elements. Otherwise, schemes for 'incremental' storing of coordinates would require too much overhead. */ - inline void push_back( const value_type&); + inline void push_back(const value_type&); //! reserve enough space for max_number elements (but don't fill them in) void reserve(size_type max_number); //! number of non-zero elements - inline size_type size() const; + inline size_type size() const; //! Multiplies all values with a constant - ProjMatrixElemsForOneDensel& operator*=(const float d); + ProjMatrixElemsForOneDensel& operator*=(const float d); //! Divides all values with a constant - ProjMatrixElemsForOneDensel& operator/=(const float d); - + ProjMatrixElemsForOneDensel& operator/=(const float d); + //! Sort the elements on coordinates of the voxels /*! Uses value_type::coordinates_less as ordering function. - */ + */ void sort(); //! merge 2nd lor into current object @@ -154,13 +149,12 @@ class ProjMatrixElemsForOneDensel \warning This currently modifies the argument \c lor. */ // TODO make sure we can have a const argument - void merge(ProjMatrixElemsForOneDensel &lor ); + void merge(ProjMatrixElemsForOneDensel& lor); #if 0 void write(fstream&fst) const; void read(fstream&fst ); #endif - //! Return sum of squares of all values /*! \warning This sums over all elements in the LOR, irrespective if they @@ -185,17 +179,15 @@ class ProjMatrixElemsForOneDensel const DiscretisedDensity<3,float>&) const; #endif - + private: - std::vector elements; + std::vector elements; Densel densel; - //! remove a single value_type inline iterator erase(iterator it); }; - END_NAMESPACE_STIR #include "stir/recon_buildblock/ProjMatrixElemsForOneDensel.inl" diff --git a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDensel.inl b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDensel.inl index 8ce19fc05c..a795ae8673 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDensel.inl +++ b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDensel.inl @@ -30,57 +30,49 @@ START_NAMESPACE_STIR -Densel -ProjMatrixElemsForOneDensel:: -get_densel() const -{ +Densel +ProjMatrixElemsForOneDensel::get_densel() const { return densel; } void -ProjMatrixElemsForOneDensel:: -set_densel(const Densel& new_densel) -{ +ProjMatrixElemsForOneDensel::set_densel(const Densel& new_densel) { densel = new_densel; } -void ProjMatrixElemsForOneDensel::push_back( const ProjMatrixElemsForOneDensel::value_type& el) -{ - elements.push_back(el); +void +ProjMatrixElemsForOneDensel::push_back(const ProjMatrixElemsForOneDensel::value_type& el) { + elements.push_back(el); } - -ProjMatrixElemsForOneDensel::size_type -ProjMatrixElemsForOneDensel:: -size() const -{ +ProjMatrixElemsForOneDensel::size_type +ProjMatrixElemsForOneDensel::size() const { return elements.size(); } -ProjMatrixElemsForOneDensel::iterator -ProjMatrixElemsForOneDensel::begin() - { return elements.begin(); } - -ProjMatrixElemsForOneDensel::const_iterator -ProjMatrixElemsForOneDensel:: -begin() const - { return elements.begin(); }; +ProjMatrixElemsForOneDensel::iterator +ProjMatrixElemsForOneDensel::begin() { + return elements.begin(); +} -ProjMatrixElemsForOneDensel::iterator -ProjMatrixElemsForOneDensel:: -end() - { return elements.end(); }; +ProjMatrixElemsForOneDensel::const_iterator +ProjMatrixElemsForOneDensel::begin() const { + return elements.begin(); +}; -ProjMatrixElemsForOneDensel::const_iterator -ProjMatrixElemsForOneDensel:: -end() const - { return elements.end(); }; +ProjMatrixElemsForOneDensel::iterator +ProjMatrixElemsForOneDensel::end() { + return elements.end(); +}; -ProjMatrixElemsForOneDensel::iterator -ProjMatrixElemsForOneDensel:: -erase(iterator it){ - return elements.erase(it); - } +ProjMatrixElemsForOneDensel::const_iterator +ProjMatrixElemsForOneDensel::end() const { + return elements.end(); +}; +ProjMatrixElemsForOneDensel::iterator +ProjMatrixElemsForOneDensel::erase(iterator it) { + return elements.erase(it); +} END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDenselValue.h b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDenselValue.h index 6448711c96..804a8eca99 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDenselValue.h +++ b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDenselValue.h @@ -3,11 +3,11 @@ /*! \file \ingroup projection - + \brief Declaration of class stir::ProjMatrixElemsForOneDenselValue - + \author Kris Thielemans - + */ /* Copyright (C) 2000- 2009, Hammersmith Imanet Ltd @@ -33,11 +33,10 @@ START_NAMESPACE_STIR - /*! \ingroup projection - \brief Stores voxel coordinates and the value of the matrix element. - + \brief Stores voxel coordinates and the value of the matrix element. + (Probably) only useful in class ProjMatrixElemsForOneDensel. \warning It is recommended never to use this class name directly, but @@ -47,11 +46,9 @@ START_NAMESPACE_STIR \todo Simply derived from Bin for now. */ - class ProjMatrixElemsForOneDenselValue : public Bin -{ +class ProjMatrixElemsForOneDenselValue : public Bin { public: - explicit inline - ProjMatrixElemsForOneDenselValue(const Bin&); + explicit inline ProjMatrixElemsForOneDenselValue(const Bin&); inline ProjMatrixElemsForOneDenselValue(); @@ -59,15 +56,15 @@ START_NAMESPACE_STIR inline ProjMatrixElemsForOneDenselValue& operator+=(const ProjMatrixElemsForOneDenselValue& el2); //! Multiplies the value of with a float inline ProjMatrixElemsForOneDenselValue& operator*=(const float d); - //! Adds a float to the value + //! Adds a float to the value inline ProjMatrixElemsForOneDenselValue& operator+=(const float d); //! Divides the value of with a float inline ProjMatrixElemsForOneDenselValue& operator/=(const float d); // TODO inline float get_value() const { return get_bin_value(); } - inline void set_value(const float v) { set_bin_value(v); } - + inline void set_value(const float v) { set_bin_value(v); } + //////// comparison functions //! Checks if the coordinates are equal @@ -78,17 +75,14 @@ START_NAMESPACE_STIR //! Checks lexicographical order of the coordinates static inline bool coordinates_less(const ProjMatrixElemsForOneDenselValue& el1, const ProjMatrixElemsForOneDenselValue& el2); - + //! Checks coordinates and value are equal friend inline bool operator==(const ProjMatrixElemsForOneDenselValue& el1, const ProjMatrixElemsForOneDenselValue& el2); - + //! Checks lexicographical order of the coordinates and the value friend inline bool operator<(const ProjMatrixElemsForOneDenselValue& el1, const ProjMatrixElemsForOneDenselValue& el2); - - }; - END_NAMESPACE_STIR #include "stir/recon_buildblock/ProjMatrixElemsForOneDenselValue.inl" diff --git a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDenselValue.inl b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDenselValue.inl index d13ca2c919..8b4796db99 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDenselValue.inl +++ b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDenselValue.inl @@ -3,11 +3,11 @@ /*! \file \ingroup projection - + \brief Inline implementations for class stir::ProjMatrixElemsForOneDenselValue - + \author Kris Thielemans - + */ /* Copyright (C) 2000- 2009, Hammersmith Imanet Ltd @@ -26,105 +26,71 @@ See STIR/LICENSE.txt for details */ - START_NAMESPACE_STIR -ProjMatrixElemsForOneDenselValue:: -ProjMatrixElemsForOneDenselValue(const Bin& bin) -: Bin(bin) -{ -} - -ProjMatrixElemsForOneDenselValue:: -ProjMatrixElemsForOneDenselValue() - : Bin() -{} +ProjMatrixElemsForOneDenselValue::ProjMatrixElemsForOneDenselValue(const Bin& bin) : Bin(bin) {} +ProjMatrixElemsForOneDenselValue::ProjMatrixElemsForOneDenselValue() : Bin() {} - -ProjMatrixElemsForOneDenselValue& -ProjMatrixElemsForOneDenselValue:: -operator+=(const ProjMatrixElemsForOneDenselValue& el2) -{ - //TODO assert(get_coords() == el2.get_coords()); +ProjMatrixElemsForOneDenselValue& +ProjMatrixElemsForOneDenselValue::operator+=(const ProjMatrixElemsForOneDenselValue& el2) { + // TODO assert(get_coords() == el2.get_coords()); //*this += static_cast(el2); set_bin_value(get_bin_value() + el2.get_bin_value()); return *this; } -ProjMatrixElemsForOneDenselValue& -ProjMatrixElemsForOneDenselValue:: -operator+=(const float d) -{ +ProjMatrixElemsForOneDenselValue& +ProjMatrixElemsForOneDenselValue::operator+=(const float d) { static_cast(*this) += d; return *this; } -ProjMatrixElemsForOneDenselValue& -ProjMatrixElemsForOneDenselValue:: -operator*=(const float d) -{ +ProjMatrixElemsForOneDenselValue& +ProjMatrixElemsForOneDenselValue::operator*=(const float d) { set_bin_value(get_bin_value() * d); return *this; } -ProjMatrixElemsForOneDenselValue& -ProjMatrixElemsForOneDenselValue:: -operator/=(const float d) -{ +ProjMatrixElemsForOneDenselValue& +ProjMatrixElemsForOneDenselValue::operator/=(const float d) { set_bin_value(get_bin_value() / d); return *this; } -bool -ProjMatrixElemsForOneDenselValue:: -coordinates_equal(const ProjMatrixElemsForOneDenselValue& el1, const ProjMatrixElemsForOneDenselValue& el2) -{ - return - el1.segment_num() == el2.segment_num() && - el1.view_num() == el2.view_num() && - el1.axial_pos_num() == el2.axial_pos_num() && - el1.tangential_pos_num() == el2.tangential_pos_num(); +bool +ProjMatrixElemsForOneDenselValue::coordinates_equal(const ProjMatrixElemsForOneDenselValue& el1, + const ProjMatrixElemsForOneDenselValue& el2) { + return el1.segment_num() == el2.segment_num() && el1.view_num() == el2.view_num() && + el1.axial_pos_num() == el2.axial_pos_num() && el1.tangential_pos_num() == el2.tangential_pos_num(); } -bool -ProjMatrixElemsForOneDenselValue:: -coordinates_less(const ProjMatrixElemsForOneDenselValue& el1, const ProjMatrixElemsForOneDenselValue& el2) -{ - return - el1.segment_num() < el2.segment_num() || - (el1.segment_num() == el2.segment_num() && - (el1.view_num() < el2.view_num() || - (el1.view_num() == el2.view_num() && - (el1.axial_pos_num() < el2.axial_pos_num() || - (el1.axial_pos_num() == el2.axial_pos_num() && - el1.tangential_pos_num() < el2.tangential_pos_num()))))); +bool +ProjMatrixElemsForOneDenselValue::coordinates_less(const ProjMatrixElemsForOneDenselValue& el1, + const ProjMatrixElemsForOneDenselValue& el2) { + return el1.segment_num() < el2.segment_num() || + (el1.segment_num() == el2.segment_num() && + (el1.view_num() < el2.view_num() || + (el1.view_num() == el2.view_num() && + (el1.axial_pos_num() < el2.axial_pos_num() || + (el1.axial_pos_num() == el2.axial_pos_num() && el1.tangential_pos_num() < el2.tangential_pos_num()))))); } - - -bool -operator==(const ProjMatrixElemsForOneDenselValue& el1, - const ProjMatrixElemsForOneDenselValue& el2) -{ +bool +operator==(const ProjMatrixElemsForOneDenselValue& el1, const ProjMatrixElemsForOneDenselValue& el2) { return static_cast(el1) == static_cast(el2); } - -bool -operator<(const ProjMatrixElemsForOneDenselValue& el1, - const ProjMatrixElemsForOneDenselValue& el2) -{ - return - el1.segment_num() < el2.segment_num() || - (el1.segment_num() == el2.segment_num() && - (el1.view_num() < el2.view_num() || - (el1.view_num() == el2.view_num() && - (el1.axial_pos_num() < el2.axial_pos_num() || +bool +operator<(const ProjMatrixElemsForOneDenselValue& el1, const ProjMatrixElemsForOneDenselValue& el2) { + return el1.segment_num() < el2.segment_num() || + (el1.segment_num() == el2.segment_num() && + (el1.view_num() < el2.view_num() || + (el1.view_num() == el2.view_num() && + (el1.axial_pos_num() < el2.axial_pos_num() || (el1.axial_pos_num() == el2.axial_pos_num() && (el1.tangential_pos_num() < el2.tangential_pos_num() || - (el1.tangential_pos_num() < el2.tangential_pos_num() && - el1.get_bin_value() class DiscretisedDensity; +template +class DiscretisedDensity; class ProjDataInfo; - /*! \ingroup projection \brief Abstract base class for all projector pairs - This class is useful for all algorithms which need both a forward - and back projector. It's only purpose in that case is to provide the - parsing mechanisms, such that the projectors can be defined in a .par + This class is useful for all algorithms which need both a forward + and back projector. It's only purpose in that case is to provide the + parsing mechanisms, such that the projectors can be defined in a .par file. */ -class ProjectorByBinPair : -public RegisteredObject -{ +class ProjectorByBinPair : public RegisteredObject { public: - - //! Default constructor + //! Default constructor ProjectorByBinPair(); virtual ~ProjectorByBinPair() {} //! Stores all necessary geometric info - /*! + /*! If necessary, set_up() can be called more than once. Derived classes can assume that the projectors will be called - with input corresponding to the arguments of the last call to set_up(). + with input corresponding to the arguments of the last call to set_up(). \warning Derived classes have to call set_up from the base class. */ - virtual Succeeded - set_up( - const shared_ptr&, - const shared_ptr >& // TODO should be Info only - ); - + virtual Succeeded set_up(const shared_ptr&, + const shared_ptr>& // TODO should be Info only + ); - //ForwardProjectorByBin const * - const shared_ptr - get_forward_projector_sptr() const; + // ForwardProjectorByBin const * + const shared_ptr get_forward_projector_sptr() const; - //BackProjectorByBin const * - const shared_ptr - get_back_projector_sptr() const; - + // BackProjectorByBin const * + const shared_ptr get_back_projector_sptr() const; //! Provide access to the (minimal) symmetries used by the projectors /*! It is expected that the forward and back projector can handle the same @@ -91,13 +83,11 @@ public RegisteredObject the symmetries returned by the back projector. \todo determine set of minimal symmetries */ - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const - { - return get_back_projector_sptr()->get_symmetries_used(); - } + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const { + return get_back_projector_sptr()->get_symmetries_used(); + } protected: - shared_ptr forward_projector_sptr; shared_ptr back_projector_sptr; @@ -106,17 +96,16 @@ public RegisteredObject If overriding this function in a derived class, you need to call this one. */ - virtual void check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3,float>& density_info) const; + virtual void check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3, float>& density_info) const; bool _already_set_up; - private: +private: shared_ptr _proj_data_info_sptr; //! The density ptr set with set_up() /*! \todo it is wasteful to have to store the whole image as this uses memory that we don't need. */ - shared_ptr > _density_info_sptr; + shared_ptr> _density_info_sptr; }; END_NAMESPACE_STIR - #endif // __stir_recon_buildblock_ProjectorByBinPair_h_ diff --git a/src/include/stir/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.h b/src/include/stir/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.h index 063faf64fc..93cbc31535 100644 --- a/src/include/stir/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.h +++ b/src/include/stir/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.h @@ -39,22 +39,16 @@ class Succeeded; \ingroup projection \brief A projector pair based on a single matrix */ -class ProjectorByBinPairUsingProjMatrixByBin : - public RegisteredParsingObject -{ - private: - typedef - RegisteredParsingObject - base_type; +class ProjectorByBinPairUsingProjMatrixByBin + : public RegisteredParsingObject { +private: + typedef RegisteredParsingObject base_type; + public: //! Name which will be used when parsing a ProjectorByBinPair object - static const char * const registered_name; + static const char* const registered_name; - //! Default constructor + //! Default constructor ProjectorByBinPairUsingProjMatrixByBin(); //! Constructor that sets the projection matrix @@ -62,20 +56,17 @@ class ProjectorByBinPairUsingProjMatrixByBin : //! Stores all necessary geometric info /*! First constructs forward and back projectors and then calls base_type::setup */ - virtual Succeeded set_up( - const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_info_sptr // TODO should be Info only - ); + virtual Succeeded set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& density_info_sptr // TODO should be Info only + ); - ProjMatrixByBin const * - get_proj_matrix_ptr() const; + ProjMatrixByBin const* get_proj_matrix_ptr() const; shared_ptr get_proj_matrix_sptr() const; void set_proj_matrix_sptr(const shared_ptr& sptr); private: - shared_ptr proj_matrix_sptr; void set_defaults(); void initialise_keymap(); @@ -84,5 +75,4 @@ class ProjectorByBinPairUsingProjMatrixByBin : END_NAMESPACE_STIR - #endif // __stir_recon_buildblock_ProjectorByBinPairUsingProjMatrixByBin_h_ diff --git a/src/include/stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h b/src/include/stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h index f8bf5b8df6..ff267f4a5b 100644 --- a/src/include/stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h +++ b/src/include/stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h @@ -33,36 +33,27 @@ START_NAMESPACE_STIR - /*! \ingroup projection \brief A projector pair based on a single matrix */ -class ProjectorByBinPairUsingSeparateProjectors : - public RegisteredParsingObject -{ - private: - typedef - RegisteredParsingObject - base_type; +class ProjectorByBinPairUsingSeparateProjectors + : public RegisteredParsingObject { +private: + typedef RegisteredParsingObject base_type; + public: //! Name which will be used when parsing a ProjectorByBinPair object - static const char * const registered_name; + static const char* const registered_name; - //! Default constructor + //! Default constructor ProjectorByBinPairUsingSeparateProjectors(); - //! Constructor that sets the pair + //! Constructor that sets the pair ProjectorByBinPairUsingSeparateProjectors(const shared_ptr& forward_projector_sptr, const shared_ptr& back_projector_sptr); - private: - void set_defaults(); void initialise_keymap(); bool post_processing(); @@ -70,5 +61,4 @@ class ProjectorByBinPairUsingSeparateProjectors : END_NAMESPACE_STIR - #endif // __stir_recon_buildblock_ProjectorByBinPairUsingSeparateProjectors_h_ diff --git a/src/include/stir/recon_buildblock/QuadraticPrior.h b/src/include/stir/recon_buildblock/QuadraticPrior.h index 0f0262e227..fea3230e25 100644 --- a/src/include/stir/recon_buildblock/QuadraticPrior.h +++ b/src/include/stir/recon_buildblock/QuadraticPrior.h @@ -26,11 +26,9 @@ */ - #ifndef __stir_recon_buildblock_QuadraticPrior_H__ #define __stir_recon_buildblock_QuadraticPrior_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/recon_buildblock/PriorWithParabolicSurrogate.h" #include "stir/Array.h" @@ -40,33 +38,32 @@ START_NAMESPACE_STIR - /*! \ingroup priors \brief A class in the GeneralisedPrior hierarchy. This implements a quadratic Gibbs prior. The gradient of the prior is computed as follows: - + \f[ g_r = \sum_dr w_{dr} (\lambda_r - \lambda_{r+dr}) * \kappa_r * \kappa_{r+dr} \f] where \f$\lambda\f$ is the image and \f$r\f$ and \f$dr\f$ are indices and the sum is over the neighbourhood where the weights \f$w_{dr}\f$ are non-zero. - The \f$\kappa\f$ image can be used to have spatially-varying penalties such as in + The \f$\kappa\f$ image can be used to have spatially-varying penalties such as in Jeff Fessler's papers. It should have identical dimensions to the image for which the penalty is computed. If \f$\kappa\f$ is not set, this class will effectively use 1 for all \f$\kappa\f$'s. - By default, a 3x3 or 3x3x3 neigbourhood is used where the weights are set to + By default, a 3x3 or 3x3x3 neigbourhood is used where the weights are set to x-voxel_size divided by the Euclidean distance between the points. - + \par Parsing These are the keywords that can be used in addition to the ones in GeneralPrior. \verbatim Quadratic Prior Parameters:= - ; next defaults to 0, set to 1 for 2D inverse Euclidean weights, 0 for 3D + ; next defaults to 0, set to 1 for 2D inverse Euclidean weights, 0 for 3D only 2D:= 0 ; next can be used to set weights explicitly. Needs to be a 3D array (of floats). ' value of only_2D is ignored @@ -77,120 +74,107 @@ START_NAMESPACE_STIR ; kappa filename:= ; use next parameter to get gradient images at every subiteration ; see class documentation - gradient filename prefix:= + gradient filename prefix:= END Quadratic Prior Parameters:= \endverbatim */ template -class QuadraticPrior: public - RegisteredParsingObject< QuadraticPrior, - GeneralisedPrior >, - PriorWithParabolicSurrogate > - > -{ - private: - typedef - RegisteredParsingObject< QuadraticPrior, - GeneralisedPrior >, - PriorWithParabolicSurrogate > > - base_type; - - public: +class QuadraticPrior : public RegisteredParsingObject, GeneralisedPrior>, + PriorWithParabolicSurrogate>> { +private: + typedef RegisteredParsingObject, GeneralisedPrior>, + PriorWithParabolicSurrogate>> + base_type; + +public: //! Name which will be used when parsing a GeneralisedPrior object - static const char * const registered_name; + static const char* const registered_name; - //! Default constructor + //! Default constructor QuadraticPrior(); //! Constructs it explicitly QuadraticPrior(const bool only_2D, float penalization_factor); - - virtual bool - parabolic_surrogate_curvature_depends_on_argument() const - { return false; } + + virtual bool parabolic_surrogate_curvature_depends_on_argument() const { return false; } //! compute the value of the function - double - compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate); + double compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate); - //! compute gradient - void compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate); + //! compute gradient + void compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, const DiscretisedDensity<3, elemT>& current_image_estimate); //! compute the parabolic surrogate for the prior /*! in the case of quadratic priors this will just be the sum of weighting coefficients*/ - void parabolic_surrogate_curvature(DiscretisedDensity<3,elemT>& parabolic_surrogate_curvature, - const DiscretisedDensity<3,elemT> ¤t_image_estimate); + void parabolic_surrogate_curvature(DiscretisedDensity<3, elemT>& parabolic_surrogate_curvature, + const DiscretisedDensity<3, elemT>& current_image_estimate); - //! compute Hessian - void compute_Hessian(DiscretisedDensity<3,elemT>& prior_Hessian_for_single_densel, - const BasicCoordinate<3,int>& coords, - const DiscretisedDensity<3,elemT> ¤t_image_estimate); + //! compute Hessian + void compute_Hessian(DiscretisedDensity<3, elemT>& prior_Hessian_for_single_densel, const BasicCoordinate<3, int>& coords, + const DiscretisedDensity<3, elemT>& current_image_estimate); //! Call accumulate_Hessian_times_input - virtual Succeeded - add_multiplication_with_approximate_Hessian(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& input) const; + virtual Succeeded add_multiplication_with_approximate_Hessian(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& input) const; //! Compute the multiplication of the hessian of the prior multiplied by the input. //! For the quadratic function, the hessian of the prior is 1. //! Therefore this will return the weights multiplied by the input. - virtual Succeeded accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& current_estimate, - const DiscretisedDensity<3,elemT>& input) const; + virtual Succeeded accumulate_Hessian_times_input(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& current_estimate, + const DiscretisedDensity<3, elemT>& input) const; //! get penalty weights for the neighbourhood - Array<3,float> get_weights() const; + Array<3, float> get_weights() const; //! set penalty weights for the neighbourhood - void set_weights(const Array<3,float>&); + void set_weights(const Array<3, float>&); //! get current kappa image /*! \warning As this function returns a shared_ptr, this is dangerous. You should not modify the image by manipulating the image refered to by this pointer. Unpredictable results will occur. */ - shared_ptr > get_kappa_sptr() const; + shared_ptr> get_kappa_sptr() const; //! set kappa image - void set_kappa_sptr(const shared_ptr >&); + void set_kappa_sptr(const shared_ptr>&); //! Has to be called before using this object - virtual Succeeded set_up(shared_ptr > const& target_sptr); - + virtual Succeeded set_up(shared_ptr> const& target_sptr); + protected: //! can be set during parsing to restrict the weights to the 2D case bool only_2D; //! filename prefix for outputing the gradient whenever compute_gradient() is called. /*! An internal counter is used to keep track of the number of times the - gradient is computed. The filename will be constructed by concatenating + gradient is computed. The filename will be constructed by concatenating gradient_filename_prefix and the counter. */ std::string gradient_filename_prefix; //! penalty weights - /*! + /*! \todo This member is mutable at present because some const functions initialise it. That initialisation should be moved to a new set_up() function. */ - mutable Array<3,float> weights; + mutable Array<3, float> weights; //! Filename for the \f$\kappa\f$ image that will be read by post_processing() std::string kappa_filename; //! Check that the prior is ready to be used - virtual void check(DiscretisedDensity<3,elemT> const& current_image_estimate) const; + virtual void check(DiscretisedDensity<3, elemT> const& current_image_estimate) const; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - private: - shared_ptr > kappa_ptr; -}; +private: + shared_ptr> kappa_ptr; +}; END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/recon_buildblock/RayTraceVoxelsOnCartesianGrid.h b/src/include/stir/recon_buildblock/RayTraceVoxelsOnCartesianGrid.h index f2528d6ae5..69b656b01d 100644 --- a/src/include/stir/recon_buildblock/RayTraceVoxelsOnCartesianGrid.h +++ b/src/include/stir/recon_buildblock/RayTraceVoxelsOnCartesianGrid.h @@ -32,10 +32,11 @@ START_NAMESPACE_STIR class ProjMatrixElemsForOneBin; -template class CartesianCoordinate3D; +template +class CartesianCoordinate3D; /*! \ingroup recon_buildblock - + \brief RayTraceVoxelsOnCartesianGrid finds the Length of Intersections (LOIs) of an LOR with a grid of voxels and appends them to the ProjMatrixElemsForOneBin object. @@ -48,7 +49,7 @@ template class CartesianCoordinate3D; start_point and end_point have to be given in 'voxel grid units' (i.e. voxels are spaced 1 unit apart). The centre - of the voxels are assumed to be at integer coordinates + of the voxels are assumed to be at integer coordinates (e.g. (0,0,0) is the centre of a voxel). For the start voxel, the intersection length of the LOR with the @@ -60,7 +61,7 @@ template class CartesianCoordinate3D; RayTraceVoxelsOnCartesianGrid is based on Siddon's algorithm. - Siddon's algorithm works by looking at intersections of the + Siddon's algorithm works by looking at intersections of the 'intra-voxel' planes with the LOR. The LORs is parametrised as @@ -73,11 +74,8 @@ template class CartesianCoordinate3D; as this determines which plane the LOR intersects at this point. */ -void -RayTraceVoxelsOnCartesianGrid(ProjMatrixElemsForOneBin& lor, - const CartesianCoordinate3D& start_point, - const CartesianCoordinate3D& end_point, - const CartesianCoordinate3D& voxel_size, - const float normalisation_constant = 1.F); +void RayTraceVoxelsOnCartesianGrid(ProjMatrixElemsForOneBin& lor, const CartesianCoordinate3D& start_point, + const CartesianCoordinate3D& end_point, const CartesianCoordinate3D& voxel_size, + const float normalisation_constant = 1.F); END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/Reconstruction.h b/src/include/stir/recon_buildblock/Reconstruction.h index 8620afda93..b55a790b08 100644 --- a/src/include/stir/recon_buildblock/Reconstruction.h +++ b/src/include/stir/recon_buildblock/Reconstruction.h @@ -21,9 +21,9 @@ #ifndef __stir_recon_buildblock_Reconstruction_H__ #define __stir_recon_buildblock_Reconstruction_H__ /*! - \file + \file \ingroup recon_buildblock - + \brief declares the stir::Reconstruction class \author Kris Thielemans @@ -45,7 +45,6 @@ START_NAMESPACE_STIR - class Succeeded; /*! @@ -55,7 +54,7 @@ class Succeeded; this base class is rather basic. It essentially takes care of constructing a target image, calls the virtual reconstruct() function, and writes the result to file. - For convenience, the class is derived from TimedObject. It is the + For convenience, the class is derived from TimedObject. It is the responsibility of the derived class to run these timers though. \par Parsing parameters @@ -66,7 +65,7 @@ class Succeeded; post-filter type := ; output file(s) will be written with the following file name - output filename prefix := + output filename prefix := ; output file(s) will use the following file format ; see OutputFileFormat output file format := @@ -75,30 +74,26 @@ class Succeeded; */ template -class Reconstruction : - public RegisteredObject >, - public TimedObject -{ +class Reconstruction : public RegisteredObject>, public TimedObject { public: //! default constructor (calls set_defaults()) Reconstruction(); //! virtual destructor - virtual ~Reconstruction() {}; - + virtual ~Reconstruction(){}; + //! gives method information virtual std::string method_info() const = 0; - + //! executes the reconstruction /*! \return Succeeded::yes if everything was alright. - */ - virtual Succeeded - reconstruct() = 0; + */ + virtual Succeeded reconstruct() = 0; //! executes the reconstruction storing result in \c target_image_sptr /*! - \param target_image_sptr The result of the reconstruction is stored in + \param target_image_sptr The result of the reconstruction is stored in \c *target_image_sptr. \return Succeeded::yes if everything was alright. @@ -108,12 +103,11 @@ class Reconstruction : in a derived class, will hide the other. So you have to overload both. \warning you need to call set_up() first. - */ - virtual Succeeded - reconstruct(shared_ptr const& target_image_sptr) = 0; + */ + virtual Succeeded reconstruct(shared_ptr const& target_image_sptr) = 0; //! operations prior to the reconstruction - /*! Will do various consistency checks and return Succeeded::no + /*! Will do various consistency checks and return Succeeded::no if something is wrong. \todo Currently, set_up() is called by reconstruct(). This is in @@ -121,23 +115,23 @@ class Reconstruction : has to be called before any actual processing. Maybe this should be made consistent. */ - virtual Succeeded set_up(shared_ptr const& target_data_sptr); + virtual Succeeded set_up(shared_ptr const& target_data_sptr); /*! \name Functions to set parameters This can be used as alternative to the parsing mechanism. - \warning Be careful with setting shared pointers. If you modify the objects in + \warning Be careful with setting shared pointers. If you modify the objects in one place, all objects that use the shared pointer will be affected. */ //@{ //! file name for output reconstructed images - void set_output_filename_prefix(const std::string&); + void set_output_filename_prefix(const std::string&); //! defines the format of the output files - void set_output_file_format_ptr(const shared_ptr >&); + void set_output_file_format_ptr(const shared_ptr>&); //! post-filter - void set_post_processor_sptr(const shared_ptr > &); + void set_post_processor_sptr(const shared_ptr>&); //! \brief set input data virtual void set_input_data(const shared_ptr&) = 0; @@ -167,19 +161,18 @@ class Reconstruction : //! \author Nikos Efthimiou //! \return //! - shared_ptr get_target_image(); + shared_ptr get_target_image(); // parameters - protected: - +protected: //! file name for output reconstructed images - std::string output_filename_prefix; + std::string output_filename_prefix; //! defines the format of the output files - shared_ptr > output_file_format_ptr; + shared_ptr> output_file_format_ptr; //! post-filter - shared_ptr > post_filter_sptr; + shared_ptr> post_filter_sptr; protected: //! do consistency checks @@ -190,12 +183,12 @@ class Reconstruction : virtual void check(TargetT const& target_data) const; bool _already_set_up; - /*! - \brief - This function initialises all parameters, either via parsing, + /*! + \brief + This function initialises all parameters, either via parsing, or by calling ask_parameters() (when parameter_filename is the empty string). - It should be called in the constructor of the last class in the + It should be called in the constructor of the last class in the hierarchy. At that time, all Interfile keys will have been initialised, and ask_parameters() will be the appropriate virtual function, such that questions are asked for all parameters. @@ -204,19 +197,19 @@ class Reconstruction : return Succeeded (or throw an exception). */ void initialise(const std::string& parameter_filename); - + virtual void set_defaults(); virtual void initialise_keymap(); //! used to check acceptable parameters after parsing /*! - The function should be used to set members that have + The function should be used to set members that have are not set directly by the parsing. For example, parsing might set \c input_filename, and \c post_processing() - might then read in the data and set the corresponding + might then read in the data and set the corresponding Reconstruction parameter. Consistency checks mostly belong in \c set_up(). The reason for this - is that for instance a GUI might not use the parsing mechanism and + is that for instance a GUI might not use the parsing mechanism and set parameters by calling various \c set_ functions (such as \c set_post_processor_sptr() ). */ @@ -225,7 +218,7 @@ class Reconstruction : //! //! \brief target_data_sptr //! - shared_ptr target_data_sptr; + shared_ptr target_data_sptr; //! //! \brief _disable_output @@ -235,14 +228,10 @@ class Reconstruction : //! from within some other code and want to use directly the output image. bool _disable_output; - /// Verbosity level int _verbosity; - - }; END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/recon_buildblock/RelatedBins.h b/src/include/stir/recon_buildblock/RelatedBins.h index 899c60fda2..6ad36d5ad2 100644 --- a/src/include/stir/recon_buildblock/RelatedBins.h +++ b/src/include/stir/recon_buildblock/RelatedBins.h @@ -38,19 +38,17 @@ START_NAMESPACE_STIR class ProjData; class Bin; class DataSymmetriesForBins; -/*! +/*! \ingroup recon_buildblock - \brief This class contains all information about a set of bins related + \brief This class contains all information about a set of bins related by symmetry. */ -class RelatedBins -{ +class RelatedBins { public: - //! typedefs for iterator support - + //! typedefs for iterator support - typedef std::random_access_iterator_tag iterator_category; + typedef std::random_access_iterator_tag iterator_category; typedef Bin value_type; typedef value_type& reference; typedef const value_type& const_reference; @@ -65,8 +63,8 @@ class RelatedBins typedef vector::iterator iterator; typedef vector::const_iterator const_iterator; #endif - //!Default constructor: creates no bins, no symmetries - inline RelatedBins(); + //! Default constructor: creates no bins, no symmetries + inline RelatedBins(); //! get the number of related bins inline int get_num_related_bins() const; @@ -74,36 +72,31 @@ class RelatedBins //! get 'basic' bin coordinates inline Bin get_basic_bin() const; - // get the pointer to a ProjDataInfo class + // get the pointer to a ProjDataInfo class // inline const ProjDataInfo * get_proj_data_info_sptr() const; //! return the symmetries used - inline const DataSymmetriesForBins* get_symmetries_ptr() const ; - + inline const DataSymmetriesForBins* get_symmetries_ptr() const; + //! get an empty copy RelatedBins get_empty_copy() const; - // basic iterator support + // basic iterator support //! use to initialise an iterator to the first element of the vector - inline iterator begin(); - //! iterator 'past' the last element of the vector - inline iterator end(); - //! use to initialise an iterator to the first element of the (const) vector - inline const_iterator begin() const; - //! iterator 'past' the last element of the (const) vector - inline const_iterator end() const; - - + inline iterator begin(); + //! iterator 'past' the last element of the vector + inline iterator end(); + //! use to initialise an iterator to the first element of the (const) vector + inline const_iterator begin() const; + //! iterator 'past' the last element of the (const) vector + inline const_iterator end() const; private: - std::vector related_bins; - shared_ptr symmetries; - //! a private constructor which sets the members - inline RelatedBins(const std::vector& related_bins, - const shared_ptr& symmetries_used); - - + std::vector related_bins; + shared_ptr symmetries; + //! a private constructor which sets the members + inline RelatedBins(const std::vector& related_bins, const shared_ptr& symmetries_used); }; END_NAMESPACE_STIR @@ -111,5 +104,3 @@ END_NAMESPACE_STIR #include "stir/recon_buildblock/RelatedBins.inl" #endif //__RelatedBins_H__ - - diff --git a/src/include/stir/recon_buildblock/RelatedBins.inl b/src/include/stir/recon_buildblock/RelatedBins.inl index 3ef79b682f..c8f91ef5b1 100644 --- a/src/include/stir/recon_buildblock/RelatedBins.inl +++ b/src/include/stir/recon_buildblock/RelatedBins.inl @@ -34,31 +34,22 @@ START_NAMESPACE_STIR +RelatedBins::RelatedBins() : related_bins(), symmetries() {} - -RelatedBins::RelatedBins() -:related_bins(),symmetries() -{} - -RelatedBins::RelatedBins(const std::vector< Bin>& related_bins_v, - const shared_ptr& symmetries_used) -:related_bins(related_bins_v),symmetries(symmetries_used) -{} +RelatedBins::RelatedBins(const std::vector& related_bins_v, const shared_ptr& symmetries_used) + : related_bins(related_bins_v), symmetries(symmetries_used) {} int -RelatedBins::get_num_related_bins() const -{ +RelatedBins::get_num_related_bins() const { return static_cast(related_bins.size()); } Bin -RelatedBins::get_basic_bin() const -{ +RelatedBins::get_basic_bin() const { assert(related_bins.size() != 0); return related_bins[0]; } - #if 0 const ProjDataInfo * RelatedBins:: get_proj_data_info_sptr() const @@ -68,30 +59,29 @@ RelatedBins:: get_proj_data_info_sptr() const } #endif - const DataSymmetriesForBins* -RelatedBins::get_symmetries_ptr() const -{ +RelatedBins::get_symmetries_ptr() const { return symmetries.get(); } - -RelatedBins::iterator -RelatedBins::begin() -{ return related_bins.begin();} - RelatedBins::iterator -RelatedBins::end() -{return related_bins.end();} +RelatedBins::begin() { + return related_bins.begin(); +} -RelatedBins::const_iterator -RelatedBins::begin() const -{return related_bins.begin();} +RelatedBins::iterator +RelatedBins::end() { + return related_bins.end(); +} -RelatedBins::const_iterator -RelatedBins::end() const -{return related_bins.end();} +RelatedBins::const_iterator +RelatedBins::begin() const { + return related_bins.begin(); +} +RelatedBins::const_iterator +RelatedBins::end() const { + return related_bins.end(); +} END_NAMESPACE_STIR - diff --git a/src/include/stir/recon_buildblock/RelatedDensels.h b/src/include/stir/recon_buildblock/RelatedDensels.h index 58b467551c..0c8262566e 100644 --- a/src/include/stir/recon_buildblock/RelatedDensels.h +++ b/src/include/stir/recon_buildblock/RelatedDensels.h @@ -40,18 +40,16 @@ START_NAMESPACE_STIR class DataSymmetriesForDensels; -/*! +/*! \ingroup symmetries - \brief This class contains all information about a set of densels related + \brief This class contains all information about a set of densels related by symmetry. */ -class RelatedDensels -{ +class RelatedDensels { public: - //! typedefs for iterator support - + //! typedefs for iterator support - typedef std::random_access_iterator_tag iterator_category; + typedef std::random_access_iterator_tag iterator_category; typedef Densel value_type; typedef value_type& reference; typedef const value_type& const_reference; @@ -66,8 +64,8 @@ class RelatedDensels typedef vector::iterator iterator; typedef vector::const_iterator const_iterator; #endif - //!Default constructor: creates no densels, no symmetries - inline RelatedDensels(); + //! Default constructor: creates no densels, no symmetries + inline RelatedDensels(); //! get the number of related densels inline int get_num_related_densels() const; @@ -75,36 +73,31 @@ class RelatedDensels //! get 'basic' densel coordinates inline Densel get_basic_densel() const; - // get the pointer to a ProjDataInfo class + // get the pointer to a ProjDataInfo class // inline const ProjDataInfo * get_proj_data_info_sptr() const; //! return the symmetries used - inline const DataSymmetriesForDensels* get_symmetries_ptr() const ; - + inline const DataSymmetriesForDensels* get_symmetries_ptr() const; + //! get an empty copy RelatedDensels get_empty_copy() const; - // basic iterator support + // basic iterator support //! use to initialise an iterator to the first element of the vector - inline iterator begin(); - //! iterator 'past' the last element of the vector - inline iterator end(); - //! use to initialise an iterator to the first element of the (const) vector - inline const_iterator begin() const; - //! iterator 'past' the last element of the (const) vector - inline const_iterator end() const; - - + inline iterator begin(); + //! iterator 'past' the last element of the vector + inline iterator end(); + //! use to initialise an iterator to the first element of the (const) vector + inline const_iterator begin() const; + //! iterator 'past' the last element of the (const) vector + inline const_iterator end() const; private: - std::vector related_densels; - shared_ptr symmetries; - //! a private constructor which sets the members - inline RelatedDensels(const std::vector& related_densels, - const shared_ptr& symmetries_used); - - + std::vector related_densels; + shared_ptr symmetries; + //! a private constructor which sets the members + inline RelatedDensels(const std::vector& related_densels, const shared_ptr& symmetries_used); }; END_NAMESPACE_STIR @@ -112,5 +105,3 @@ END_NAMESPACE_STIR #include "stir/recon_buildblock/RelatedDensels.inl" #endif //__RelatedDensels_H__ - - diff --git a/src/include/stir/recon_buildblock/RelatedDensels.inl b/src/include/stir/recon_buildblock/RelatedDensels.inl index 7d8f640225..e46180a67f 100644 --- a/src/include/stir/recon_buildblock/RelatedDensels.inl +++ b/src/include/stir/recon_buildblock/RelatedDensels.inl @@ -34,31 +34,23 @@ START_NAMESPACE_STIR +RelatedDensels::RelatedDensels() : related_densels(), symmetries() {} - -RelatedDensels::RelatedDensels() -:related_densels(),symmetries() -{} - -RelatedDensels::RelatedDensels(const std::vector< Densel>& related_densels_v, - const shared_ptr& symmetries_used) -:related_densels(related_densels_v),symmetries(symmetries_used) -{} +RelatedDensels::RelatedDensels(const std::vector& related_densels_v, + const shared_ptr& symmetries_used) + : related_densels(related_densels_v), symmetries(symmetries_used) {} int -RelatedDensels::get_num_related_densels() const -{ +RelatedDensels::get_num_related_densels() const { return related_densels.size(); } Densel -RelatedDensels::get_basic_densel() const -{ +RelatedDensels::get_basic_densel() const { assert(related_densels.size() != 0); return related_densels[0]; } - #if 0 const ProjDataInfo * RelatedDensels:: get_proj_data_info_sptr() const @@ -68,30 +60,29 @@ RelatedDensels:: get_proj_data_info_sptr() const } #endif - const DataSymmetriesForDensels* -RelatedDensels::get_symmetries_ptr() const -{ +RelatedDensels::get_symmetries_ptr() const { return symmetries.get(); } - -RelatedDensels::iterator -RelatedDensels::begin() -{ return related_densels.begin();} - RelatedDensels::iterator -RelatedDensels::end() -{return related_densels.end();} +RelatedDensels::begin() { + return related_densels.begin(); +} -RelatedDensels::const_iterator -RelatedDensels::begin() const -{return related_densels.begin();} +RelatedDensels::iterator +RelatedDensels::end() { + return related_densels.end(); +} -RelatedDensels::const_iterator -RelatedDensels::end() const -{return related_densels.end();} +RelatedDensels::const_iterator +RelatedDensels::begin() const { + return related_densels.begin(); +} +RelatedDensels::const_iterator +RelatedDensels::end() const { + return related_densels.end(); +} END_NAMESPACE_STIR - diff --git a/src/include/stir/recon_buildblock/RelativeDifferencePrior.h b/src/include/stir/recon_buildblock/RelativeDifferencePrior.h index ad755df09b..84228a069f 100644 --- a/src/include/stir/recon_buildblock/RelativeDifferencePrior.h +++ b/src/include/stir/recon_buildblock/RelativeDifferencePrior.h @@ -28,11 +28,9 @@ */ - #ifndef __stir_recon_buildblock_RelativeDifferencePrior_H__ #define __stir_recon_buildblock_RelativeDifferencePrior_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/recon_buildblock/GeneralisedPrior.h" #include "stir/Array.h" @@ -42,7 +40,6 @@ START_NAMESPACE_STIR - /*! \ingroup priors \brief @@ -52,7 +49,8 @@ START_NAMESPACE_STIR \f[ g_r = \sum_{dr} w_{dr} * - \frac{\left(\lambda_{j}-\lambda_{k}\right)\left(\gamma\left|\lambda_{j}-\lambda_{k}\right|+\lambda_{j}+3 \lambda_{k} + 2 \epsilon \right)} + \frac{\left(\lambda_{j}-\lambda_{k}\right)\left(\gamma\left|\lambda_{j}-\lambda_{k}\right|+\lambda_{j}+3 \lambda_{k} + 2 +\epsilon \right)} {\left(\lambda_{j}+\lambda_{k}+\gamma\left|\lambda_{j}-\lambda_{k}\right| + \epsilon \right)^{2}} * \kappa_r * \kappa_{r+dr} \f] @@ -65,7 +63,7 @@ START_NAMESPACE_STIR “A Concave Prior Penalizing Relative Differences for Maximum-a-Posteriori Reconstruction in Emission Tomography,” vol. 49, no. 1, pp. 56–60, 2002. - The \f$\kappa\f$ image can be used to have spatially-varying penalties such as in + The \f$\kappa\f$ image can be used to have spatially-varying penalties such as in Jeff Fessler's papers. It should have identical dimensions to the image for which the penalty is computed. If \f$\kappa\f$ is not set, this class will effectively use 1 for all \f$\kappa\f$'s. @@ -77,7 +75,7 @@ START_NAMESPACE_STIR These are the keywords that can be used in addition to the ones in GeneralPrior. \verbatim Relative Difference Prior Parameters:= - ; next defaults to 0, set to 1 for 2D inverse Euclidean weights, 0 for 3D + ; next defaults to 0, set to 1 for 2D inverse Euclidean weights, 0 for 3D only 2D:= 0 ; next can be used to set weights explicitly. Needs to be a 3D array (of floats). ' value of only_2D is ignored @@ -90,53 +88,41 @@ START_NAMESPACE_STIR ; kappa filename:= ; use next parameter to get gradient images at every subiteration ; see class documentation - gradient filename prefix:= + gradient filename prefix:= END Relative Difference Prior Parameters:= \endverbatim */ template -class RelativeDifferencePrior: public - RegisteredParsingObject< RelativeDifferencePrior, - GeneralisedPrior >, - GeneralisedPrior > - > -{ - private: - typedef - RegisteredParsingObject< RelativeDifferencePrior, - GeneralisedPrior >, - GeneralisedPrior > - > - base_type; - - public: +class RelativeDifferencePrior + : public RegisteredParsingObject, GeneralisedPrior>, + GeneralisedPrior>> { +private: + typedef RegisteredParsingObject, GeneralisedPrior>, + GeneralisedPrior>> + base_type; + +public: //! Name which will be used when parsing a GeneralisedPrior object - static const char * const registered_name; + static const char* const registered_name; //! Default constructor RelativeDifferencePrior(); //! Constructs it explicitly RelativeDifferencePrior(const bool only_2D, float penalization_factor, float gamma, float epsilon); - - virtual bool - parabolic_surrogate_curvature_depends_on_argument() const - { return false; } - //! compute the value of the function - double - compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate); + virtual bool parabolic_surrogate_curvature_depends_on_argument() const { return false; } - //! compute gradient - void compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate); + //! compute the value of the function + double compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate); + //! compute gradient + void compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, const DiscretisedDensity<3, elemT>& current_image_estimate); - virtual Succeeded - add_multiplication_with_approximate_Hessian(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& input) const; + virtual Succeeded add_multiplication_with_approximate_Hessian(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& input) const; //! get the gamma value used in RDP float get_gamma() const; @@ -148,26 +134,25 @@ class RelativeDifferencePrior: public //! set the epsilon value used in the RDP void set_epsilon(float e); - //! get penalty weights for the neigbourhood - Array<3,float> get_weights() const; + Array<3, float> get_weights() const; //! set penalty weights for the neigbourhood - void set_weights(const Array<3,float>&); + void set_weights(const Array<3, float>&); //! get current kappa image /*! \warning As this function returns a shared_ptr, this is dangerous. You should not modify the image by manipulating the image refered to by this pointer. Unpredictable results will occur. */ - shared_ptr > get_kappa_sptr() const; + shared_ptr> get_kappa_sptr() const; //! set kappa image - void set_kappa_sptr(const shared_ptr >&); + void set_kappa_sptr(const shared_ptr>&); //! Has to be called before using this object - virtual Succeeded set_up(shared_ptr > const& target_sptr); - + virtual Succeeded set_up(shared_ptr> const& target_sptr); + protected: //! Create variable gamma for Relative Difference Penalty float gamma; @@ -179,32 +164,31 @@ class RelativeDifferencePrior: public bool only_2D; //! filename prefix for outputing the gradient whenever compute_gradient() is called. /*! An internal counter is used to keep track of the number of times the - gradient is computed. The filename will be constructed by concatenating + gradient is computed. The filename will be constructed by concatenating gradient_filename_prefix and the counter. */ std::string gradient_filename_prefix; //! penalty weights - /*! + /*! \todo This member is mutable at present because some const functions initialise it. That initialisation should be moved to a new set_up() function. */ - mutable Array<3,float> weights; + mutable Array<3, float> weights; //! Filename for the \f$\kappa\f$ image that will be read by post_processing() std::string kappa_filename; //! Check that the prior is ready to be used - virtual void check(DiscretisedDensity<3,elemT> const& current_image_estimate) const; + virtual void check(DiscretisedDensity<3, elemT> const& current_image_estimate) const; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - private: - shared_ptr > kappa_ptr; -}; +private: + shared_ptr> kappa_ptr; +}; END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/recon_buildblock/SPECTUB_Tools.h b/src/include/stir/recon_buildblock/SPECTUB_Tools.h index 13e686e81f..4735b2b340 100644 --- a/src/include/stir/recon_buildblock/SPECTUB_Tools.h +++ b/src/include/stir/recon_buildblock/SPECTUB_Tools.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Biomedical Image Group (GIB), Universitat de Barcelona, Barcelona, Spain. + Copyright (c) 2013, Biomedical Image Group (GIB), Universitat de Barcelona, Barcelona, Spain. Copyright (c) 2013, University College London This file is part of STIR. @@ -31,355 +31,333 @@ namespace SPECTUB { //::: srtuctures :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //! collimator parameters structure -typedef struct -{ - int num; // number of collimator (see weight_64.cpp for options) - bool do_fb; // true: fanbeam collimator || false: parallel collimator - - //... parallel collimator parameters ..................... - - float A; // linear factor for dependency of sigma on distance: sigma=A*dist+B (parallel, fanbeam-vertical) - float B; // independent factor for dependency of sigma on distance: sigma=A*dist+B (parallel, fanbeam-vertical) - - //... fanbeam collimator parameters ...................... - - float F; // Focal length (fanbeam) - float L; // collimator to detector distance (?) (fanbeam) - float A_h; // linear factor for dependency of sigma on distance (fanbeam horizontal) - float A_v; // linear factor for dependency of sigma on distance (fanbeam horizontal) - float D; // collimator thicknes?? (fanbeam) - float w; // collimator thickness (?) (fanbeam) - float insgm; // intrinsic sigma (cristal resolution) (fanbeam) - +typedef struct { + int num; // number of collimator (see weight_64.cpp for options) + bool do_fb; // true: fanbeam collimator || false: parallel collimator + + //... parallel collimator parameters ..................... + + float A; // linear factor for dependency of sigma on distance: sigma=A*dist+B (parallel, fanbeam-vertical) + float B; // independent factor for dependency of sigma on distance: sigma=A*dist+B (parallel, fanbeam-vertical) + + //... fanbeam collimator parameters ...................... + + float F; // Focal length (fanbeam) + float L; // collimator to detector distance (?) (fanbeam) + float A_h; // linear factor for dependency of sigma on distance (fanbeam horizontal) + float A_v; // linear factor for dependency of sigma on distance (fanbeam horizontal) + float D; // collimator thicknes?? (fanbeam) + float w; // collimator thickness (?) (fanbeam) + float insgm; // intrinsic sigma (cristal resolution) (fanbeam) + } collim_type; //! structure for bin information -typedef struct -{ - int Nrow; // number of rows - int Ncol; // number of columns - int Nsli; // number of slices - int Npix; // number of pixels (axial planes) - int Nvox; // number of voxels (the whole volume) - - int first_sl; // first slice to reconstruct (0->Nslic-1) - int last_sl; // last slice to reconstruct + 1 (end of the 'for' loop) (1->Nslic) - - float Nrowd2; // half of Nrow - float Ncold2; // half of Ncol - float Nslid2; // half of Nsli - - float Xcmd2; // Half of the size of the volume, dimension x (cm); - float Ycmd2; // Half of the size of the volume, dimension y (cm); - float Zcmd2; // Half of the size of the volume, dimension z (cm); - - float szcm; // voxel size (side length in cm) - float thcm; // voxel thickness (cm) - - float x0; // x coordinate (cm, ref center of volume) of the first voxel - float y0; // y coordinate (cm, ref center of volume) of the first voxel - float z0; // z coordinate (cm, ref center of volume) of the first voxel - - float *val; // array of values - -} volume_type; +typedef struct { + int Nrow; // number of rows + int Ncol; // number of columns + int Nsli; // number of slices + int Npix; // number of pixels (axial planes) + int Nvox; // number of voxels (the whole volume) + + int first_sl; // first slice to reconstruct (0->Nslic-1) + int last_sl; // last slice to reconstruct + 1 (end of the 'for' loop) (1->Nslic) + float Nrowd2; // half of Nrow + float Ncold2; // half of Ncol + float Nslid2; // half of Nsli + + float Xcmd2; // Half of the size of the volume, dimension x (cm); + float Ycmd2; // Half of the size of the volume, dimension y (cm); + float Zcmd2; // Half of the size of the volume, dimension z (cm); + + float szcm; // voxel size (side length in cm) + float thcm; // voxel thickness (cm) + + float x0; // x coordinate (cm, ref center of volume) of the first voxel + float y0; // y coordinate (cm, ref center of volume) of the first voxel + float z0; // z coordinate (cm, ref center of volume) of the first voxel + + float* val; // array of values + +} volume_type; //! structure for projection information -typedef struct -{ - int Nbin; // length of the detection line in bins (number of bins per line) - float lngcm; // length of the detection line in cm. - float szcm; // bin size in cm - - int Nsli; // number of slices - float thcm; // slice thickness in cm - - int Nang; // number of projection angles - float ang0; // initial projection angle. degrees from upper detection plane (parallel to table). Negative for CW rotacions (see manual) - float incr; // angle increment between two consecutive projection angles. Degrees. Negative for CW, Positive for CCW - - int NOS; // number of subsets in which to split the matrix - int NangOS; // Number of angles in each subset = Nang/NOS - int Nbp; // number of bins in a 2D projection=lng*Nsli - int Nbt; // total number of bins= Nbp*Nang - int NbOS; // total number of bins per subset= Nbp*NangOS = Nbt/NOS - int *order; // order of the angles of projection (array formed by indexs of angles belonging to consecutive subsets) - - float Nbind2; // length of the detection line (in bins) divided by 2 - float lngcmd2; // length of the detection line in cm divided by 2 - float Nslid2; // number of slices divided by 2 - +typedef struct { + int Nbin; // length of the detection line in bins (number of bins per line) + float lngcm; // length of the detection line in cm. + float szcm; // bin size in cm + + int Nsli; // number of slices + float thcm; // slice thickness in cm + + int Nang; // number of projection angles + float ang0; // initial projection angle. degrees from upper detection plane (parallel to table). Negative for CW rotacions (see + // manual) + float incr; // angle increment between two consecutive projection angles. Degrees. Negative for CW, Positive for CCW + + int NOS; // number of subsets in which to split the matrix + int NangOS; // Number of angles in each subset = Nang/NOS + int Nbp; // number of bins in a 2D projection=lng*Nsli + int Nbt; // total number of bins= Nbp*Nang + int NbOS; // total number of bins per subset= Nbp*NangOS = Nbt/NOS + int* order; // order of the angles of projection (array formed by indexs of angles belonging to consecutive subsets) + + float Nbind2; // length of the detection line (in bins) divided by 2 + float lngcmd2; // length of the detection line in cm divided by 2 + float Nslid2; // number of slices divided by 2 + } proj_type; //! complementary information (matrix header) -typedef struct -{ - int subset_ind; // subset index of this matrix (-1: all subsets in a single file) - int *index; // included angles into this subset (index. Multiply by increm to get corresponding angles in degrees) - - float *Rrad; // Rotation radius (one value for each projection angle) - float min_w; // minimum weight to be taken into account - float psfres; // spatial resolution of continous distributions in PSF calculation - float maxsigm; // maximum number of sigmas in PSF calculation - - bool fixed_Rrad; // true: fixed radius of projection || false: variable radius of projection - bool do_psf; // true: to correct for PSF || false: do not correct for PSF - bool do_psf_3d; // true: 3d correction for PSF || false: 2d correction for PSF - bool predef_col; // true: predefined collimator || false: user defined PSF parametres - bool do_att; // true: to correct for attenuation || false: do not correct for attenuation - bool do_full_att; // true: diff att for each PSF bin || false: the whole PSF has the same att. factor (central line) - bool do_msk; // true: weights just inside msk || false: weights for the whole FOV - bool do_msk_slc; // true: weights for several slices || false: weights for all slices - bool do_msk_cyl; // true: to use cylinder as a mask || false: not to use cylinder as a mask - bool do_msk_att; // true: to use att map as a mask || false: not to use att map as a mask - bool do_msk_file; // true: explicit mask || false: not to use explicit mask - - std::string att_fn; // attenuation map filename - std::string msk_fn; // explicit mask filename - std::string col_fn; // collimator parameters filename - std::string Rrad_fn; // rotation radius file name - - volume_type vol; // - proj_type prj; // - collim_type COL; // collimator structure (see weight3d_64b.cpp for options) - +typedef struct { + int subset_ind; // subset index of this matrix (-1: all subsets in a single file) + int* index; // included angles into this subset (index. Multiply by increm to get corresponding angles in degrees) + + float* Rrad; // Rotation radius (one value for each projection angle) + float min_w; // minimum weight to be taken into account + float psfres; // spatial resolution of continous distributions in PSF calculation + float maxsigm; // maximum number of sigmas in PSF calculation + + bool fixed_Rrad; // true: fixed radius of projection || false: variable radius of projection + bool do_psf; // true: to correct for PSF || false: do not correct for PSF + bool do_psf_3d; // true: 3d correction for PSF || false: 2d correction for PSF + bool predef_col; // true: predefined collimator || false: user defined PSF parametres + bool do_att; // true: to correct for attenuation || false: do not correct for attenuation + bool do_full_att; // true: diff att for each PSF bin || false: the whole PSF has the same att. factor (central line) + bool do_msk; // true: weights just inside msk || false: weights for the whole FOV + bool do_msk_slc; // true: weights for several slices || false: weights for all slices + bool do_msk_cyl; // true: to use cylinder as a mask || false: not to use cylinder as a mask + bool do_msk_att; // true: to use att map as a mask || false: not to use att map as a mask + bool do_msk_file; // true: explicit mask || false: not to use explicit mask + + std::string att_fn; // attenuation map filename + std::string msk_fn; // explicit mask filename + std::string col_fn; // collimator parameters filename + std::string Rrad_fn; // rotation radius file name + + volume_type vol; // + proj_type prj; // + collim_type COL; // collimator structure (see weight3d_64b.cpp for options) + } wmh_type; //! weight_mat structure definition. Structure for reading weight matrix -typedef struct -{ - //weight matrix dimensions - - int ne; //nonzero elements - int NbOS; //dimension 1 (rows) of the weight matrix (NbOS or NBt) - int Nvox; //dimension 2 (columns) of the weight matrix (Nvox) - - //weight matrix values - - float *ar; //array of nonzero elements of weight matrix (by rows) - int *ja; //array of the column index of the above elements - int *ia; //array containing the indexes of the previous vector where a row change happens - - bool do_save_wmh; //to save or not to save weight_mat header info into weight_mat file +typedef struct { + // weight matrix dimensions + + int ne; // nonzero elements + int NbOS; // dimension 1 (rows) of the weight matrix (NbOS or NBt) + int Nvox; // dimension 2 (columns) of the weight matrix (Nvox) + + // weight matrix values + + float* ar; // array of nonzero elements of weight matrix (by rows) + int* ja; // array of the column index of the above elements + int* ia; // array containing the indexes of the previous vector where a row change happens + + bool do_save_wmh; // to save or not to save weight_mat header info into weight_mat file } wm_type; //! weight_mat_da structure definition. Structure for generating weight matrix -typedef struct -{ - int NbOS; // dimension 1 (rows) of the weight matrix (NbOS or NBt) - int Nvox; // dimension 2 (columns) of the weight matrix (Nvox) - float **val; // double array to store weights (index of the projection element, number of weight for that element) - int **col; // double array to store column indexs of the above element (index of the projection element, number of weight for that element) - int *ne; // array indicating how many elements has been stored for each element of projection - - //... filename ............................................. - - std::string fn; // matrix base name (filename without extension index) - std::string OSfn; // matrix filename - std::string fn_hdr; // matrix header file name - - //... indexs for STIR format ............................... - - int *na, *nb, *ns; //indexs for projection elements (angle, bin, slice respec.) - short int *nx, *ny, *nz; //indexs for image elements (x,y,z) - - //... format ............................................... - - bool do_save_wmh; // to save or not to save weight_mat header info into weight_mat file - bool do_save_STIR; // to save weight matrix with STIR format - +typedef struct { + int NbOS; // dimension 1 (rows) of the weight matrix (NbOS or NBt) + int Nvox; // dimension 2 (columns) of the weight matrix (Nvox) + float** val; // double array to store weights (index of the projection element, number of weight for that element) + int** col; // double array to store column indexs of the above element (index of the projection element, number of weight for + // that element) + int* ne; // array indicating how many elements has been stored for each element of projection + + //... filename ............................................. + + std::string fn; // matrix base name (filename without extension index) + std::string OSfn; // matrix filename + std::string fn_hdr; // matrix header file name + + //... indexs for STIR format ............................... + + int *na, *nb, *ns; // indexs for projection elements (angle, bin, slice respec.) + short int *nx, *ny, *nz; // indexs for image elements (x,y,z) + + //... format ............................................... + + bool do_save_wmh; // to save or not to save weight_mat header info into weight_mat file + bool do_save_STIR; // to save weight matrix with STIR format + } wm_da_type; //! structure for distribution function information -typedef struct -{ - int lng; // length (in discretization intervals) (odd number) - int lngd2; // half of the length (in discretization intervals) (lng-1)/2 - float res; // spatial resolution of distfunc (discretization interval) - float *val; // array of values - float *acu; // distribution function values (cumulative sum) +typedef struct { + int lng; // length (in discretization intervals) (odd number) + int lngd2; // half of the length (in discretization intervals) (lng-1)/2 + float res; // spatial resolution of distfunc (discretization interval) + float* val; // array of values + float* acu; // distribution function values (cumulative sum) } discrf_type; //! structure for PSF information -typedef struct -{ - int maxszb; // maximum size in bins (for allocation purposes) - - int di; // discretization interval (to reduce spatial resolution to bin resolution). (int: #points) - int *ind; // projection indexs for the bins of the PSF (horizontal) - int Nib; // actual number of bins forming the PSF (length of PSF in bins) - - float sgmcm; // sigma of the PSF in cm - float lngcm; // length of PSF (in cm) - float lngcmd2; // half of the length of PSF (in cm) - float *val; // array of values - float efres; // effective resolution (psfres rescaled to real psf length) - +typedef struct { + int maxszb; // maximum size in bins (for allocation purposes) + + int di; // discretization interval (to reduce spatial resolution to bin resolution). (int: #points) + int* ind; // projection indexs for the bins of the PSF (horizontal) + int Nib; // actual number of bins forming the PSF (length of PSF in bins) + + float sgmcm; // sigma of the PSF in cm + float lngcm; // length of PSF (in cm) + float lngcmd2; // half of the length of PSF (in cm) + float* val; // array of values + float efres; // effective resolution (psfres rescaled to real psf length) + } psf1d_type; //! structure for distribution function information -typedef struct -{ - int maxszb_h; // maximum size in bins horizontal (for allocation purposes) - int maxszb_v; // maximum size in bins vertical (for allocation purposes) - int maxszb_t; // maximum size in bins total (for allocation purposes) - - int *ib; // projection indexs for the bins of the PSF (horizontal) - int *jb; // projection indexs for the bins of the PSF (vertical) - int Nib; // actual number of bins forming the PSF (length of PSF in bins) - - float *val; // array of values - +typedef struct { + int maxszb_h; // maximum size in bins horizontal (for allocation purposes) + int maxszb_v; // maximum size in bins vertical (for allocation purposes) + int maxszb_t; // maximum size in bins total (for allocation purposes) + + int* ib; // projection indexs for the bins of the PSF (horizontal) + int* jb; // projection indexs for the bins of the PSF (vertical) + int Nib; // actual number of bins forming the PSF (length of PSF in bins) + + float* val; // array of values + } psf2da_type; //! structure to store angles values, indices and ratios -typedef struct -{ - int ind; // index of angle considering the whole set of projections (sequential order: 0->Nang-1) - int indOS; // index of angle considering the subjet - int iOS_proj; // index of the first bin for this angle (in subset of projections) - - float cos; // coninus of the angle - float sin; // sinus of the angle - - // parametres for describng the trapezoidal projection of a square voxel - - float p; // plateau higness - float m; // slope of the trapezoid - float n; // independent term of the slope - int N1; // index of the first vertice (end of plateau) in DX units - int N2; // index of the second vertice (end of the slope) in DX units - discrf_type vxprj; // projection of a square voxel in this direction (for no PSF) - - // variable rotation radius - - float Rrad ; // rotation radius for this angle - - // first bin position and increments - - float xbin0; // x coordinate for the first bin of the detection line corresponding to this angle - float ybin0; // y coordinate for the first bin of the detection line corresponding to this angle - float incx; // increment in x to the following bin in detection line - float incy; // increment in y to the following bin in detection line - -} angle_type; +typedef struct { + int ind; // index of angle considering the whole set of projections (sequential order: 0->Nang-1) + int indOS; // index of angle considering the subjet + int iOS_proj; // index of the first bin for this angle (in subset of projections) + float cos; // coninus of the angle + float sin; // sinus of the angle -//! structure for voxel information -typedef struct -{ - float szcm; // voxel size (side length in cm) - float thcm; // voxel thickness (cm) - - int irow; // row index - int icol; // column index - int islc; // slice index - int ip; // in plane index (considering the slice as an array) of the voxel - int iv; // volume index (considering the volume as an array) of the voxel - - float x; // x coordinate (cm, ref center of volume) - float y; // y coordinate (cm, ref center of volume) - float z; // z coordinate (cm, ref center of volume) - float x1; // x coordinade in rotated framework - - float dv2dp; // distance from voxel to detection plane - float costhe; // cosinus of theta (angle between focal-voxel line and line perpendicular to detection plane) (fanbeam) - float xdc; // distance (cm over detection line) from projected voxel to the center of the detection line - float xd0; // distance (cm over detection line) from projected voxel to the begin of the detection line - float zd0; // distance (cm) to the lowest plane of the volume - -} voxel_type; + // parametres for describng the trapezoidal projection of a square voxel -//! structure for bin information -typedef struct -{ - float szcm; // bin size (cm) - float szcmd2; // half of the above value - float thcm; // bin thickness (cm) - float thcmd2; // bin thickness (cm) - - float x; // x coordinate (cm, ref center of volume) - float y; // y coordinate (cm, ref center of volume) - float z; // z coordinate (cm, ref center of volume) - - float szdx; // bin size in resolution units - float thdx; // bin thickness in resolution units - -} bin_type; + float p; // plateau higness + float m; // slope of the trapezoid + float n; // independent term of the slope + int N1; // index of the first vertice (end of plateau) in DX units + int N2; // index of the second vertice (end of the slope) in DX units + discrf_type vxprj; // projection of a square voxel in this direction (for no PSF) -//! structure for attenuation calculus -typedef struct -{ - float *dl; // distance of attenuation path on each crossed voxel of the attenuation map - int *iv; // in-plane index (considering slices of attmap as an array) of any crossed voxel of the attenuation map - int lng; // number of elements in the attenuation path - int maxlng; // maximum number of elements in the attenuation path (for allocation) - -} attpth_type; + // variable rotation radius + float Rrad; // rotation radius for this angle -//::: functions ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + // first bin position and increments + float xbin0; // x coordinate for the first bin of the detection line corresponding to this angle + float ybin0; // y coordinate for the first bin of the detection line corresponding to this angle + float incx; // increment in x to the following bin in detection line + float incy; // increment in y to the following bin in detection line -//... functions from wmtools_SPECT.cpp ......................................... +} angle_type; +//! structure for voxel information +typedef struct { + float szcm; // voxel size (side length in cm) + float thcm; // voxel thickness (cm) + + int irow; // row index + int icol; // column index + int islc; // slice index + int ip; // in plane index (considering the slice as an array) of the voxel + int iv; // volume index (considering the volume as an array) of the voxel + + float x; // x coordinate (cm, ref center of volume) + float y; // y coordinate (cm, ref center of volume) + float z; // z coordinate (cm, ref center of volume) + float x1; // x coordinade in rotated framework + + float dv2dp; // distance from voxel to detection plane + float costhe; // cosinus of theta (angle between focal-voxel line and line perpendicular to detection plane) (fanbeam) + float xdc; // distance (cm over detection line) from projected voxel to the center of the detection line + float xd0; // distance (cm over detection line) from projected voxel to the begin of the detection line + float zd0; // distance (cm) to the lowest plane of the volume -void write_wm_FC (); // to write double array weight matrix +} voxel_type; -void write_wm_hdr (); // to write header of a matrix +//! structure for bin information +typedef struct { + float szcm; // bin size (cm) + float szcmd2; // half of the above value + float thcm; // bin thickness (cm) + float thcmd2; // bin thickness (cm) -void write_wm_STIR (); // to write matrix in STIR format + float x; // x coordinate (cm, ref center of volume) + float y; // y coordinate (cm, ref center of volume) + float z; // z coordinate (cm, ref center of volume) + float szdx; // bin size in resolution units + float thdx; // bin thickness in resolution units -void index_calc ( int *indexs ); // to calculate projection index order in subsets +} bin_type; -void read_Rrad (); // to read variable rotation radius from a text file (1 radius per line) +//! structure for attenuation calculus +typedef struct { + float* dl; // distance of attenuation path on each crossed voxel of the attenuation map + int* iv; // in-plane index (considering slices of attmap as an array) of any crossed voxel of the attenuation map + int lng; // number of elements in the attenuation path + int maxlng; // maximum number of elements in the attenuation path (for allocation) -// -//void col_params ( collim_type *COL ); // to fill collimator structure -// -//void read_col_params ( collim_type *COL); // to read collimator parameters from a file +} attpth_type; + +//::: functions ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +//... functions from wmtools_SPECT.cpp ......................................... -void fill_ang ( angle_type *ang ); // to fill angle structure +void write_wm_FC(); // to write double array weight matrix -void generate_msk ( bool *msk_3d, bool *msk_2d, float *att, volume_type *vol); // to create a boolean mask for wm (no weights outside the msk) +void write_wm_hdr(); // to write header of a matrix -void read_msk_file ( bool * msk ); // to read mask from a file +void write_wm_STIR(); // to write matrix in STIR format +void index_calc(int* indexs); // to calculate projection index order in subsets -void read_att_map ( float *attmap ); // to read attenuation map from a file +void read_Rrad(); // to read variable rotation radius from a text file (1 radius per line) + +// +// void col_params ( collim_type *COL ); // to fill collimator structure +// +// void read_col_params ( collim_type *COL); // to read collimator parameters from a file +void fill_ang(angle_type* ang); // to fill angle structure -int max_psf_szb ( angle_type *ang ); +void generate_msk(bool* msk_3d, bool* msk_2d, float* att, + volume_type* vol); // to create a boolean mask for wm (no weights outside the msk) -float calc_sigma_h ( voxel_type vox, collim_type COL); +void read_msk_file(bool* msk); // to read mask from a file -float calc_sigma_v ( voxel_type vox, collim_type COL); +void read_att_map(float* attmap); // to read attenuation map from a file +int max_psf_szb(angle_type* ang); -char *itoa ( int n, char *s); // to conver integer to ascii +float calc_sigma_h(voxel_type vox, collim_type COL); -void free_wm ( wm_type *f ); // to free weight_mat +float calc_sigma_v(voxel_type vox, collim_type COL); -void free_wm_da ( wm_da_type *f ); // to free weight_mat_da +char* itoa(int n, char* s); // to conver integer to ascii +void free_wm(wm_type* f); // to free weight_mat -void error_wmtools_SPECT(int nerr, std::string txt); // error messages in wm_SPECT +void free_wm_da(wm_da_type* f); // to free weight_mat_da +void error_wmtools_SPECT(int nerr, std::string txt); // error messages in wm_SPECT //... functions from wm_SPECT.2.0............................ -//int wm_SPECT( std::string inputFile); +// int wm_SPECT( std::string inputFile); // void error_wm_SPECT( int nerr, std::string txt); //list of error messages ////void wm_inputs( std::string fileName, proj_type * prj, volume_type *vol, voxel_type *vox, bin_type *bin ); -//void wm_inputs(char **argv, -// int argc, +// void wm_inputs(char **argv, +// int argc, // proj_type *prj, // volume_type *vol, // voxel_type *vox, @@ -387,17 +365,17 @@ void error_wmtools_SPECT(int nerr, std::string txt); // error messages in wm_ // // ////void read_inputs( std::string param, proj_type * prj, volume_type *vol, voxel_type *vox, bin_type *bin ); -//void read_inputs(vector param, +// void read_inputs(vector param, // proj_type *prj, // volume_type *vol, // voxel_type *vox, //// bin_type *bin); // -//extern wmh_type wmh; // weight matrix header. Global variable +// extern wmh_type wmh; // weight matrix header. Global variable // -//extern wm_da_type wm; // double array weight matrix structure. Global variable +// extern wm_da_type wm; // double array weight matrix structure. Global variable // -//extern float * Rrad; // variable projection radius (in acquisition order) +// extern float * Rrad; // variable projection radius (in acquisition order) } // namespace SPECTUB diff --git a/src/include/stir/recon_buildblock/SPECTUB_Weight3d.h b/src/include/stir/recon_buildblock/SPECTUB_Weight3d.h index 3595256d44..a33678ae2a 100644 --- a/src/include/stir/recon_buildblock/SPECTUB_Weight3d.h +++ b/src/include/stir/recon_buildblock/SPECTUB_Weight3d.h @@ -1,21 +1,21 @@ - /* - Copyright (c) 2013, Biomedical Image Group (GIB), Universitat de Barcelona, Barcelona, Spain. - Copyright (c) 2013, University College London - This file is part of STIR. +/* + Copyright (c) 2013, Biomedical Image Group (GIB), Universitat de Barcelona, Barcelona, Spain. + Copyright (c) 2013, University College London + This file is part of STIR. - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - See STIR/LICENSE.txt for details + See STIR/LICENSE.txt for details - \author Carles Falcon + \author Carles Falcon */ @@ -28,9 +28,9 @@ This namespace encompasses function to construct a projection matrix suitable for SPECT. The integration of this library into STIR is described in - Berta Marti Fuster, Carles Falcon, Charalampos Tsoumpas, Lefteris Livieratos, Pablo Aguiar, Albert Cot, Domenec Ros and Kris Thielemans, - Integration of advanced 3D SPECT modeling into the open-source STIR framework, - Med. Phys. 40, 092502 (2013); http://dx.doi.org/10.1118/1.4816676 + Berta Marti Fuster, Carles Falcon, Charalampos Tsoumpas, Lefteris Livieratos, Pablo Aguiar, Albert Cot, Domenec Ros and Kris + Thielemans, Integration of advanced 3D SPECT modeling into the open-source STIR framework, Med. Phys. 40, 092502 (2013); + http://dx.doi.org/10.1118/1.4816676 \todo Variables wm, wmh and Rrad are currently global variables. This means that this code would be very dangerous in a parallel setting. @@ -38,79 +38,55 @@ namespace SPECTUB { -/* Global variables: the matrix etc TODO +/* Global variables: the matrix etc TODO Need to be defined elsewhere A lot of the functions below modify these variables. */ - extern wm_da_type wm; //! weight (or probability) matrix - extern wmh_type wmh; //! information to construct wm - extern float * Rrad; //! radii per view - - -void wm_calculation( const int kOS, - const angle_type *const ang, - voxel_type vox, - bin_type bin, - const volume_type& vol, - const proj_type& prj, - const float *attmap, - const bool *msk_3d, - const bool *msk_2d, - const int maxszb, - const discrf_type *const gaussdens, - const int *const NITEMS - ); - -void wm_size_estimation (int kOS, - const angle_type * const ang, - voxel_type vox, - bin_type bin, - const volume_type& vol, - const proj_type& prj, - const bool * const msk_3d, - const bool *const msk_2d, - const int maxszb, - const discrf_type * const gaussdens, - int *NITEMS); +extern wm_da_type wm; //! weight (or probability) matrix +extern wmh_type wmh; //! information to construct wm +extern float* Rrad; //! radii per view +void wm_calculation(const int kOS, const angle_type* const ang, voxel_type vox, bin_type bin, const volume_type& vol, + const proj_type& prj, const float* attmap, const bool* msk_3d, const bool* msk_2d, const int maxszb, + const discrf_type* const gaussdens, const int* const NITEMS); -//... geometric component ............................................ +void wm_size_estimation(int kOS, const angle_type* const ang, voxel_type vox, bin_type bin, const volume_type& vol, + const proj_type& prj, const bool* const msk_3d, const bool* const msk_2d, const int maxszb, + const discrf_type* const gaussdens, int* NITEMS); -void calc_gauss ( discrf_type *gaussdens ); +//... geometric component ............................................ -void calc_vxprj ( angle_type *ang ); +void calc_gauss(discrf_type* gaussdens); -void voxel_projection ( voxel_type *vox, float * eff, float lngcmd2 ); +void calc_vxprj(angle_type* ang); -void fill_psf_no( psf2da_type *psf, psf1d_type *psf1d_h, const voxel_type& vox, const angle_type * const ang, float szdx ); +void voxel_projection(voxel_type* vox, float* eff, float lngcmd2); -void fill_psf_2d( psf2da_type *psf, psf1d_type *psf1d_h, const voxel_type& vox, discrf_type const*const gaussdens, float szdx ); +void fill_psf_no(psf2da_type* psf, psf1d_type* psf1d_h, const voxel_type& vox, const angle_type* const ang, float szdx); -void fill_psf_3d(psf2da_type *psf, - psf1d_type *psf1d_h, - psf1d_type *psf1d_v, - const voxel_type& vox, discrf_type const * const gaussdens, float szdx, float thdx, float thcmd2 ); +void fill_psf_2d(psf2da_type* psf, psf1d_type* psf1d_h, const voxel_type& vox, discrf_type const* const gaussdens, float szdx); -void calc_psf_bin ( float center_psf, float binszcm, discrf_type const * const vxprj, psf1d_type *psf ); +void fill_psf_3d(psf2da_type* psf, psf1d_type* psf1d_h, psf1d_type* psf1d_v, const voxel_type& vox, + discrf_type const* const gaussdens, float szdx, float thdx, float thcmd2); +void calc_psf_bin(float center_psf, float binszcm, discrf_type const* const vxprj, psf1d_type* psf); //... attenuation................................................... // not used -//void size_attpth_simple( psf2da_type *psf, voxel_type vox, volume_type vol, float *att, angle_type *ang ); - -//void size_attpth_full( psf2da_type *psf, voxel_type vox, volume_type vol, float *att, angle_type *ang ); +// void size_attpth_simple( psf2da_type *psf, voxel_type vox, volume_type vol, float *att, angle_type *ang ); -void calc_att_path ( const bin_type& bin, const voxel_type& vox, const volume_type& vol, attpth_type *attpth ); +// void size_attpth_full( psf2da_type *psf, voxel_type vox, volume_type vol, float *att, angle_type *ang ); -float calc_att ( const attpth_type *const attpth, const float *const attmap, int islc ); +void calc_att_path(const bin_type& bin, const voxel_type& vox, const volume_type& vol, attpth_type* attpth); -int comp_dist ( float dx, float dy, float dz, float dlast ); +float calc_att(const attpth_type* const attpth, const float* const attmap, int islc); +int comp_dist(float dx, float dy, float dz, float dlast); -void error_weight3d ( int nerr, const std::string& txt); // error messages in weight3d_SPECT +void error_weight3d(int nerr, const std::string& txt); // error messages in weight3d_SPECT -} // napespace SPECTUB +} // namespace SPECTUB #endif diff --git a/src/include/stir/recon_buildblock/SqrtHessianRowSum.h b/src/include/stir/recon_buildblock/SqrtHessianRowSum.h index 5bd66c672f..300678f4ca 100644 --- a/src/include/stir/recon_buildblock/SqrtHessianRowSum.h +++ b/src/include/stir/recon_buildblock/SqrtHessianRowSum.h @@ -63,99 +63,96 @@ class Succeeded; https://doi.org/10.1109/TMI.2019.2913889 */ template -class SqrtHessianRowSum: - public ParsingObject -{ +class SqrtHessianRowSum : public ParsingObject { public: - //! Default constructor - /*! calls set_defaults().*/ - SqrtHessianRowSum(); - explicit SqrtHessianRowSum(const std::string&); - - //! sets default values - /*! Sets \c use_approximate_hessian to \c true and \c compute_with_penalty to \c false - */ - void set_defaults(); - - //! The main function to compute and save the sqrt of the Hessian row sum volume - /*! Different Hessian row sum methods can be used, see compute_Hessian_row_sum() and - compute_approximate_Hessian_row_sum().*/ - void process_data(); - - //! \name get and set methods for the objective function sptr - //@{ - GeneralisedObjectiveFunction const& get_objective_function_sptr(); - void set_objective_function_sptr(const shared_ptr > &obj_fun); - //@} - - //! \name get and set methods for the input image - //@{ - shared_ptr get_input_image_sptr(); - void set_input_image_sptr(shared_ptr const& image); - //@} - - //! get method for returning the sqrt row sum image - shared_ptr get_output_target_sptr(); - - void set_up(); - - //! \name get and set methods for use approximate hessian bool - //@{ - bool get_use_approximate_hessian() const; - void set_use_approximate_hessian(bool use_approximate); - //@} - - //! \name get and set methods for the compute with penalty bool - //@{ - bool get_compute_with_penalty() const; - void set_compute_with_penalty(bool with_penalty); - //@} - - //! Computes the objective function Hessian row sum at the current image estimate. - //! Can compute the penalty's Hessian if it exists for the selected prior. - void compute_Hessian_row_sum(); - - //! Computes the approximate Hessian of the objective function. - //! Cannot use penalty's approximate Hessian, see compute_with_penalty - void compute_approximate_Hessian_row_sum(); + //! Default constructor + /*! calls set_defaults().*/ + SqrtHessianRowSum(); + explicit SqrtHessianRowSum(const std::string&); + + //! sets default values + /*! Sets \c use_approximate_hessian to \c true and \c compute_with_penalty to \c false + */ + void set_defaults(); + + //! The main function to compute and save the sqrt of the Hessian row sum volume + /*! Different Hessian row sum methods can be used, see compute_Hessian_row_sum() and + compute_approximate_Hessian_row_sum().*/ + void process_data(); + + //! \name get and set methods for the objective function sptr + //@{ + GeneralisedObjectiveFunction const& get_objective_function_sptr(); + void set_objective_function_sptr(const shared_ptr>& obj_fun); + //@} + + //! \name get and set methods for the input image + //@{ + shared_ptr get_input_image_sptr(); + void set_input_image_sptr(shared_ptr const& image); + //@} + + //! get method for returning the sqrt row sum image + shared_ptr get_output_target_sptr(); + + void set_up(); + + //! \name get and set methods for use approximate hessian bool + //@{ + bool get_use_approximate_hessian() const; + void set_use_approximate_hessian(bool use_approximate); + //@} + + //! \name get and set methods for the compute with penalty bool + //@{ + bool get_compute_with_penalty() const; + void set_compute_with_penalty(bool with_penalty); + //@} + + //! Computes the objective function Hessian row sum at the current image estimate. + //! Can compute the penalty's Hessian if it exists for the selected prior. + void compute_Hessian_row_sum(); + + //! Computes the approximate Hessian of the objective function. + //! Cannot use penalty's approximate Hessian, see compute_with_penalty + void compute_approximate_Hessian_row_sum(); protected: - private: - bool _already_setup = false; + bool _already_setup = false; - //! Objective function object - shared_ptr > objective_function_sptr; + //! Objective function object + shared_ptr> objective_function_sptr; - //! The filename the for the output sqrt row sum image - std::string output_filename; + //! The filename the for the output sqrt row sum image + std::string output_filename; - //! Used to load an image as a template or current image estimate to compute sqrt row sum - std::string input_image_filename; + //! Used to load an image as a template or current image estimate to compute sqrt row sum + std::string input_image_filename; - //! The input image, can be template or current_image_estimate, dependant on which sqrt row sum method used - shared_ptr input_image_sptr; + //! The input image, can be template or current_image_estimate, dependant on which sqrt row sum method used + shared_ptr input_image_sptr; - //! The output image that the row sum computation methods will populate - shared_ptr output_target_sptr; + //! The output image that the row sum computation methods will populate + shared_ptr output_target_sptr; - //! Used to toggle which of the two row sum methods will be utilised. - //! This toggles the usage of input_image_sptr. - //! If true, input_image_sptr is only used as a template for the output back-projection, - //! else, input_image_sptr is used as the current_image_estimate - bool use_approximate_hessian; + //! Used to toggle which of the two row sum methods will be utilised. + //! This toggles the usage of input_image_sptr. + //! If true, input_image_sptr is only used as a template for the output back-projection, + //! else, input_image_sptr is used as the current_image_estimate + bool use_approximate_hessian; - //! When computing the hessian row sum of the objective function, include the penalty term or not. - //! Does not work with use_approximate_hessian as priors do not have an approximate method. - bool compute_with_penalty; + //! When computing the hessian row sum of the objective function, include the penalty term or not. + //! Does not work with use_approximate_hessian as priors do not have an approximate method. + bool compute_with_penalty; - //! File-format to save images - shared_ptr > output_file_format_sptr; + //! File-format to save images + shared_ptr> output_file_format_sptr; - //! used to check acceptable parameter ranges, etc... - bool post_processing(); - void initialise_keymap(); + //! used to check acceptable parameter ranges, etc... + bool post_processing(); + void initialise_keymap(); }; END_NAMESPACE_STIR -#endif //STIR_SQRTHESSIANROWSUM_H +#endif // STIR_SQRTHESSIANROWSUM_H diff --git a/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.h b/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.h index 0340a1080f..67316d2d76 100644 --- a/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.h +++ b/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.h @@ -28,7 +28,6 @@ #ifndef __stir_recon_buildblock_SumOfGeneralisedObjectiveFunctions_H__ #define __stir_recon_buildblock_SumOfGeneralisedObjectiveFunctions_H__ - #include "stir/shared_ptr.h" #include "stir/recon_buildblock/GeneralisedObjectiveFunction.h" #include @@ -39,33 +38,25 @@ START_NAMESPACE_STIR \ingroup recon_buildblock \brief A base class for sums of 'generalised' objective functions, i.e. objective - functions for which at least a 'gradient' is defined. + functions for which at least a 'gradient' is defined. \todo document why use of ParentT template \todo doc subsets */ -template > -class SumOfGeneralisedObjectiveFunctions : - public ParentT -{ +template > +class SumOfGeneralisedObjectiveFunctions : public ParentT { typedef ParentT base_type; typedef SumOfGeneralisedObjectiveFunctions self_type; + public: - - inline - SumOfGeneralisedObjectiveFunctions(); + inline SumOfGeneralisedObjectiveFunctions(); template - inline - SumOfGeneralisedObjectiveFunctions(IterT begin, IterT end); - - inline virtual - ~SumOfGeneralisedObjectiveFunctions(); + inline SumOfGeneralisedObjectiveFunctions(IterT begin, IterT end); + + inline virtual ~SumOfGeneralisedObjectiveFunctions(); template - inline - void set_functions(IterT begin, IterT end); + inline void set_functions(IterT begin, IterT end); #if 0 //! Creates a suitable target as determined by the parameters @@ -74,39 +65,29 @@ class SumOfGeneralisedObjectiveFunctions : */ inline virtual TargetT * - construct_target_ptr() const; + construct_target_ptr() const; #endif //! Has to be called before using this object /*! Will call set_up() for all terms in the sum, but will stop as soon as one set_up() fails. */ - inline virtual - Succeeded - set_up(shared_ptr const& target_sptr); + inline virtual Succeeded set_up(shared_ptr const& target_sptr); //! This computes the gradient of the unregularised objective function at the \a current_estimate /*! It is computed as the sum of the subgradients for each term, depending on the subset scheme. - */ - inline virtual - void - compute_sub_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num); + */ + inline virtual void compute_sub_gradient_without_penalty(TargetT& gradient, const TargetT& current_estimate, + const int subset_num); - inline virtual - double - actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num); + inline virtual double actual_compute_objective_function_without_penalty(const TargetT& current_estimate, const int subset_num); - //! Attempts to change the number of subsets. + //! Attempts to change the number of subsets. /*! \return The number of subsets that will be used later, which is not guaranteed to be what you asked for. */ - inline virtual - int set_num_subsets(const int num_subsets) ; + inline virtual int set_num_subsets(const int num_subsets); protected: - typedef std::vector _functions_type; typedef typename _functions_type::iterator _functions_iterator_type; typedef typename _functions_type::const_iterator _functions_const_iterator_type; @@ -115,8 +96,7 @@ class SumOfGeneralisedObjectiveFunctions : /*! \todo doc subset */ - inline virtual - bool actual_subsets_are_approximately_balanced(std::string& warning_message) const; + inline virtual bool actual_subsets_are_approximately_balanced(std::string& warning_message) const; }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.inl b/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.inl index 7b861ac022..f91ade321c 100644 --- a/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.inl +++ b/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.inl @@ -31,31 +31,22 @@ START_NAMESPACE_STIR template template void -SumOfGeneralisedObjectiveFunctions:: -set_functions(IterT begin, IterT end) -{ +SumOfGeneralisedObjectiveFunctions::set_functions(IterT begin, IterT end) { this->_functions.resize(0); std::copy(begin, end, this->_functions.begin()); } template -SumOfGeneralisedObjectiveFunctions:: -SumOfGeneralisedObjectiveFunctions() -{} +SumOfGeneralisedObjectiveFunctions::SumOfGeneralisedObjectiveFunctions() {} template template -SumOfGeneralisedObjectiveFunctions:: -SumOfGeneralisedObjectiveFunctions(IterT begin, IterT end) -{ +SumOfGeneralisedObjectiveFunctions::SumOfGeneralisedObjectiveFunctions(IterT begin, IterT end) { set_functions(begin, end); } template -SumOfGeneralisedObjectiveFunctions:: -~SumOfGeneralisedObjectiveFunctions() -{} - +SumOfGeneralisedObjectiveFunctions::~SumOfGeneralisedObjectiveFunctions() {} #if 0 // this fails, as _functions might only be balid after set_up @@ -72,95 +63,75 @@ construct_target_ptr() const #endif template -Succeeded -SumOfGeneralisedObjectiveFunctions:: -set_up(shared_ptr const& target_sptr) -{ +Succeeded +SumOfGeneralisedObjectiveFunctions::set_up(shared_ptr const& target_sptr) { if (base_type::set_up(target_sptr) != Succeeded::yes) return Succeeded::no; _functions_iterator_type iter = this->_functions.begin(); _functions_iterator_type end_iter = this->_functions.end(); - while (iter != end_iter) - { - if (iter->set_up(target_sptr) == Succeeded::no) - return Succeeded::no; - ++iter; - } + while (iter != end_iter) { + if (iter->set_up(target_sptr) == Succeeded::no) + return Succeeded::no; + ++iter; + } return Succeeded::yes; } - + template -void -SumOfGeneralisedObjectiveFunctions:: -compute_sub_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) -{ +void +SumOfGeneralisedObjectiveFunctions::compute_sub_gradient_without_penalty( + TargetT& gradient, const TargetT& current_estimate, const int subset_num) { _functions_iterator_type iter = this->_functions.begin(); _functions_iterator_type end_iter = this->_functions.end(); - while (iter != end_iter) - { - iter->compute_sub_gradient_without_penalty(gradient, - current_estimate, - subset_num); - - ++iter; - } + while (iter != end_iter) { + iter->compute_sub_gradient_without_penalty(gradient, current_estimate, subset_num); + + ++iter; + } } template double -SumOfGeneralisedObjectiveFunctions:: -actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num) -{ +SumOfGeneralisedObjectiveFunctions::actual_compute_objective_function_without_penalty( + const TargetT& current_estimate, const int subset_num) { _functions_iterator_type iter = this->_functions.begin(); _functions_iterator_type end_iter = this->_functions.end(); double result = 0; - while (iter != end_iter) - { - result += - iter->compute_objective_function_without_penalty(current_estimate, - subset_num); - - ++iter; - } + while (iter != end_iter) { + result += iter->compute_objective_function_without_penalty(current_estimate, subset_num); + + ++iter; + } return result; } - template int -SumOfGeneralisedObjectiveFunctions:: -set_num_subsets(const int new_num_subsets) -{ +SumOfGeneralisedObjectiveFunctions::set_num_subsets(const int new_num_subsets) { this->num_subsets = new_num_subsets; _functions_iterator_type iter = this->_functions.begin(); _functions_iterator_type end_iter = this->_functions.end(); - while (iter != end_iter) - { - // we could check if they all return the same num_subsets, but cannot be bothered now - if (iter->set_num_subsets(this->num_subsets) != this->num_subsets) - error("set_num_subsets failed to set to %d subsets", this->num_subsets); - ++iter; - } + while (iter != end_iter) { + // we could check if they all return the same num_subsets, but cannot be bothered now + if (iter->set_num_subsets(this->num_subsets) != this->num_subsets) + error("set_num_subsets failed to set to %d subsets", this->num_subsets); + ++iter; + } return this->num_subsets; } template bool -SumOfGeneralisedObjectiveFunctions:: -actual_subsets_are_approximately_balanced(std::string& warning_message) const -{ +SumOfGeneralisedObjectiveFunctions::actual_subsets_are_approximately_balanced( + std::string& warning_message) const { _functions_const_iterator_type iter = this->_functions.begin(); _functions_const_iterator_type end_iter = this->_functions.end(); - while (iter != end_iter) - { - if (!iter->subsets_are_approximately_balanced(warning_message)) - return false; - ++iter; - } + while (iter != end_iter) { + if (!iter->subsets_are_approximately_balanced(warning_message)) + return false; + ++iter; + } return true; } diff --git a/src/include/stir/recon_buildblock/SymmetryOperation.h b/src/include/stir/recon_buildblock/SymmetryOperation.h index 7e2424262e..61917b152c 100644 --- a/src/include/stir/recon_buildblock/SymmetryOperation.h +++ b/src/include/stir/recon_buildblock/SymmetryOperation.h @@ -32,24 +32,23 @@ #include "stir/common.h" - START_NAMESPACE_STIR -template class BasicCoordinate; +template +class BasicCoordinate; class ViewSegmentNumbers; class ProjMatrixElemsForOneBin; class ProjMatrixElemsForOneDensel; class Bin; - /*! \ingroup buildblock \brief Encodes symmetry operation on image coordinates and projection data coordinates This class is mainly (only?) useful for ProjMatrix classes and their - 'users'. Together with DataSymmetriesForBins, it provides the basic - way to be able to write generic code without knowing which + 'users'. Together with DataSymmetriesForBins, it provides the basic + way to be able to write generic code without knowing which particular symmetries the data have. Ideally, there would be no reference here to ProjMatrixElemsForOneBin, @@ -57,7 +56,7 @@ class Bin; will allow the compiler to inline the symmetry operations, resulting in a dramatic speed-up. - Price to pay (aside from some tedious repetition in the derived classes): + Price to pay (aside from some tedious repetition in the derived classes): the need for a SymmetryOperation::transform_proj_matrix_elems_for_one_bin member, and hence knowledge of the ProjMatrixElemsForOneBin class @@ -67,60 +66,40 @@ class Bin; See recon_buildblock/SymmetryOperations_PET_CartesianGrid.cxx for some more info. */ -class SymmetryOperation -{ +class SymmetryOperation { public: virtual inline ~SymmetryOperation() {} - virtual inline bool is_trivial() const { return false;} - virtual void - transform_bin_coordinates(Bin&) const = 0; - virtual void - transform_view_segment_indices(ViewSegmentNumbers&) const = 0; - virtual void - transform_image_coordinates(BasicCoordinate<3,int>&) const = 0; + virtual inline bool is_trivial() const { return false; } + virtual void transform_bin_coordinates(Bin&) const = 0; + virtual void transform_view_segment_indices(ViewSegmentNumbers&) const = 0; + virtual void transform_image_coordinates(BasicCoordinate<3, int>&) const = 0; #if 0 // would be useful at some point virtual void transform_incremental_image_coordinates(BasicCoordinate<3,int>&) const = 0; #endif - virtual void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; - - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; }; - - /*! \ingroup symmetries \brief A class implementing the trivial case where the symmetry operation does nothing at all. */ -class TrivialSymmetryOperation : public SymmetryOperation -{ +class TrivialSymmetryOperation : public SymmetryOperation { public: - inline bool is_trivial() const { return true;} - inline void - transform_bin_coordinates(Bin& b) const {} - inline void - transform_view_segment_indices(ViewSegmentNumbers& n) const {} - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const {} - inline void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const {} + inline bool is_trivial() const { return true; } + inline void transform_bin_coordinates(Bin& b) const {} + inline void transform_view_segment_indices(ViewSegmentNumbers& n) const {} + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const {} + inline void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const {} - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const {} + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const {} }; - END_NAMESPACE_STIR //#include "stir/recon_buildblock/SymmetryOperation.inl" diff --git a/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.h b/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.h index ff5d96a123..a9901cf283 100644 --- a/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.h +++ b/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.h @@ -4,30 +4,30 @@ \file \ingroup symmetries - + \brief Declaration of all symmetry classes for PET (cylindrical) scanners and cartesian images \see class stir::DataSymmetriesForBins_PET_CartesianGrid - - \warning These classes should only be used by the + + \warning These classes should only be used by the stir::DataSymmetriesForBins_PET_CartesianGrid class. \warning It is strongly recommended not to derive from any of these - classes. If you do, you have to reimplement the + classes. If you do, you have to reimplement the transform_proj_matrix_elems_for_one_bin() member, or the wrong implementations will be called. All these classes have transform_proj_matrix_elems_for_one_bin() - members which essentially repeats just the default + members which essentially repeats just the default implementation. This is for efficiency. See - recon_buildblock/SymmetryOperations_PET_CartesianGrid.cxx for + recon_buildblock/SymmetryOperations_PET_CartesianGrid.cxx for more info. - + \author Kris Thielemans \author PARAPET project - -*/ + +*/ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2009, Hammersmith Imanet Ltd @@ -46,7 +46,6 @@ See STIR/LICENSE.txt for details */ - #ifndef __SymmetryOperations_PET_CartesianGrid_H__ #define __SymmetryOperations_PET_CartesianGrid_H__ @@ -54,59 +53,42 @@ START_NAMESPACE_STIR -class SymmetryOperation_PET_CartesianGrid_z_shift : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_z_shift : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_z_shift self; + public: SymmetryOperation_PET_CartesianGrid_z_shift(const int axial_pos_shift, const int z_shift) - : axial_pos_shift(axial_pos_shift), z_shift(z_shift) - {} + : axial_pos_shift(axial_pos_shift), z_shift(z_shift) {} - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& ) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int axial_pos_shift; int z_shift; }; -class SymmetryOperation_PET_CartesianGrid_swap_xmx_zq : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xmx_zq : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xmx_zq self; + public: SymmetryOperation_PET_CartesianGrid_swap_xmx_zq(const int num_views, const int axial_pos_shift, const int z_shift, const int q) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) - {} - - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -115,33 +97,24 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmx_zq : public SymmetryOperation int q; }; - /////////////////////////////////////// -class SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq self; -public: - SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq(const int num_views, const int axial_pos_shift, const int z_shift, const int q) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) - {} - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; +public: + SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq(const int num_views, const int axial_pos_shift, const int z_shift, + const int q) + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -150,31 +123,22 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq : public SymmetryOperat int q; }; - -class SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq self; -public: - SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq(const int num_views, const int axial_pos_shift, const int z_shift, const int q) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) - {} - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; +public: + SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq(const int num_views, const int axial_pos_shift, const int z_shift, + const int q) + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -183,30 +147,21 @@ class SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq : public SymmetryOperati int q; }; -class SymmetryOperation_PET_CartesianGrid_swap_xmy_yx : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xmy_yx : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xmy_yx self; + public: SymmetryOperation_PET_CartesianGrid_swap_xmy_yx(const int num_views, const int axial_pos_shift, const int z_shift) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) - {} - - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -214,31 +169,21 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmy_yx : public SymmetryOperation int z_shift; }; - -class SymmetryOperation_PET_CartesianGrid_swap_xy_yx : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xy_yx : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xy_yx self; -public: - SymmetryOperation_PET_CartesianGrid_swap_xy_yx(const int num_views, const int axial_pos_shift, const int z_shift) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) - {} - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; +public: + SymmetryOperation_PET_CartesianGrid_swap_xy_yx(const int num_views, const int axial_pos_shift, const int z_shift) + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -246,32 +191,21 @@ class SymmetryOperation_PET_CartesianGrid_swap_xy_yx : public SymmetryOperation int z_shift; }; - - -class SymmetryOperation_PET_CartesianGrid_swap_xmx : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xmx : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xmx self; + public: SymmetryOperation_PET_CartesianGrid_swap_xmx(const int num_views, const int axial_pos_shift, const int z_shift) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) - {} + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) {} - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -279,61 +213,43 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmx : public SymmetryOperation int z_shift; }; -class SymmetryOperation_PET_CartesianGrid_swap_ymy : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_ymy : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_ymy self; + public: SymmetryOperation_PET_CartesianGrid_swap_ymy(const int num_views, const int axial_pos_shift, const int z_shift) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) - {} - - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; int axial_pos_shift; int z_shift; - }; +}; -class SymmetryOperation_PET_CartesianGrid_swap_zq : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_zq : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_zq self; + public: SymmetryOperation_PET_CartesianGrid_swap_zq(const int num_views, const int axial_pos_shift, const int z_shift, const int q) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) - {} - - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -342,30 +258,22 @@ class SymmetryOperation_PET_CartesianGrid_swap_zq : public SymmetryOperation int q; }; -class SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq self; -public: - SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq(const int num_views, const int axial_pos_shift, const int z_shift, const int q) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) - {} - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; +public: + SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq(const int num_views, const int axial_pos_shift, const int z_shift, + const int q) + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -374,30 +282,22 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq : public SymmetryOpera int q; }; -class SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq self; -public: - SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq(const int num_views, const int axial_pos_shift, const int z_shift, const int q) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) - {} - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; +public: + SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq(const int num_views, const int axial_pos_shift, const int z_shift, + const int q) + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -406,30 +306,21 @@ class SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq : public SymmetryOperat int q; }; -class SymmetryOperation_PET_CartesianGrid_swap_xy_ymx : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xy_ymx : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xy_ymx self; + public: SymmetryOperation_PET_CartesianGrid_swap_xy_ymx(const int num_views, const int axial_pos_shift, const int z_shift) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) - {} - - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -437,30 +328,21 @@ class SymmetryOperation_PET_CartesianGrid_swap_xy_ymx : public SymmetryOperation int z_shift; }; -class SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx self; + public: SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(const int num_views, const int axial_pos_shift, const int z_shift) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) - {} - - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -468,30 +350,21 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx : public SymmetryOperatio int z_shift; }; -class SymmetryOperation_PET_CartesianGrid_swap_ymy_zq : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_ymy_zq : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_ymy_zq self; + public: SymmetryOperation_PET_CartesianGrid_swap_ymy_zq(const int num_views, const int axial_pos_shift, const int z_shift, const int q) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) - {} + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) {} - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -500,30 +373,21 @@ class SymmetryOperation_PET_CartesianGrid_swap_ymy_zq : public SymmetryOperation int q; }; -class SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy self; + public: SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy(const int num_views, const int axial_pos_shift, const int z_shift) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) - {} - - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -531,30 +395,22 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy : public SymmetryOperatio int z_shift; }; -class SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq : public SymmetryOperation -{ +class SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq : public SymmetryOperation { private: typedef SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq self; -public: - SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq(const int num_views, const int axial_pos_shift, const int z_shift, const int q) - : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) - {} - inline void - transform_bin_coordinates(Bin&) const; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const; +public: + SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq(const int num_views, const int axial_pos_shift, const int z_shift, + const int q) + : view180(num_views), axial_pos_shift(axial_pos_shift), z_shift(z_shift), q(q) {} - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const; + inline void transform_bin_coordinates(Bin&) const; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const; - virtual void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const; + virtual void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; private: int view180; @@ -563,11 +419,8 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq : public SymmetryOpera int q; }; - - END_NAMESPACE_STIR #include "stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.inl" - #endif diff --git a/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.inl b/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.inl index 5bcccd1213..eb08a20931 100644 --- a/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.inl +++ b/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.inl @@ -42,77 +42,62 @@ START_NAMESPACE_STIR -void -SymmetryOperation_PET_CartesianGrid_z_shift:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_z_shift::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; } -void -SymmetryOperation_PET_CartesianGrid_z_shift:: - transform_view_segment_indices(ViewSegmentNumbers& vs) const -{ -} - -void SymmetryOperation_PET_CartesianGrid_z_shift::transform_image_coordinates(BasicCoordinate<3,int>&c) const -{ +void +SymmetryOperation_PET_CartesianGrid_z_shift::transform_view_segment_indices(ViewSegmentNumbers& vs) const {} + +void +SymmetryOperation_PET_CartesianGrid_z_shift::transform_image_coordinates(BasicCoordinate<3, int>& c) const { c[1] += z_shift; } ////////////////////////////////////////// -void -SymmetryOperation_PET_CartesianGrid_swap_xmx_zq:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_zq::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; b.view_num() = view180 - b.view_num(); - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ - c[3] = -c[3]; + +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_zq::transform_image_coordinates(BasicCoordinate<3, int>& c) const { + c[3] = -c[3]; c[1] = q - c[1] + z_shift; } ////////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; b.segment_num() *= -1; - b.view_num() += view180/2; - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq::transform_image_coordinates(BasicCoordinate<3, int>& c) const { const int tmp = c[3]; c[3] = -c[2]; c[2] = tmp; @@ -121,27 +106,22 @@ void SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq::transform_image_coordin /////////////////////////////////////// -void -SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; - b.view_num() = view180/2 - b.view_num(); - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ + b.view_num() = view180 / 2 - b.view_num(); + assert(0 <= b.view_num()); + assert(b.view_num() < view180); +} +void +SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq::transform_view_segment_indices(ViewSegmentNumbers& vs) const { + vs.view_num() = view180 / 2 - vs.view_num(); + assert(0 <= vs.view_num()); + assert(vs.view_num() < view180); +} + +void +SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq::transform_image_coordinates(BasicCoordinate<3, int>& c) const { const int tmp = c[3]; c[3] = c[2]; c[2] = tmp; @@ -150,45 +130,34 @@ void SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq::transform_image_coordina /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_xmy_yx:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_yx::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; - if (b.view_num() < view180/2) - { - b.view_num() += view180/2; - } - else - { + if (b.view_num() < view180 / 2) { + b.view_num() += view180 / 2; + } else { b.segment_num() *= -1; - b.view_num() -= view180/2; + b.view_num() -= view180 / 2; b.tangential_pos_num() *= -1; } - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ + +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_yx::transform_image_coordinates(BasicCoordinate<3, int>& c) const { const int tmp = c[3]; c[3] = -c[2]; c[2] = tmp; @@ -196,415 +165,316 @@ void SymmetryOperation_PET_CartesianGrid_swap_xmy_yx::transform_image_coordinate } /////////////////////////////////////// -void -SymmetryOperation_PET_CartesianGrid_swap_xy_yx:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xy_yx::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; - if (b.view_num() <= view180/2) - { + if (b.view_num() <= view180 / 2) { b.segment_num() *= -1; - b.view_num() = view180/2 - b.view_num(); - } - else - { - b.view_num() = 3*view180/2 - b.view_num(); + b.view_num() = view180 / 2 - b.view_num(); + } else { + b.view_num() = 3 * view180 / 2 - b.view_num(); b.tangential_pos_num() *= -1; } - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xy_yx::transform_image_coordinates(BasicCoordinate<3, int>& c) const { const int tmp = c[3]; c[3] = c[2]; - c[2] = tmp; + c[2] = tmp; c[1] += z_shift; } /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_xmx:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmx::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; - if (b.view_num()!=0) - { + if (b.view_num() != 0) { b.segment_num() *= -1; b.view_num() = view180 - b.view_num(); - } - else - { + } else { b.tangential_pos_num() *= -1; } - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ - c[3] = -c[3]; +void +SymmetryOperation_PET_CartesianGrid_swap_xmx::transform_image_coordinates(BasicCoordinate<3, int>& c) const { + c[3] = -c[3]; c[1] += z_shift; -} +} /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_ymy:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_ymy::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; - if (b.view_num()!=0) - { + if (b.view_num() != 0) { b.view_num() = view180 - b.view_num(); b.tangential_pos_num() *= -1; - } - else - { + } else { b.segment_num() *= -1; } - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_ymy::transform_image_coordinates(BasicCoordinate<3, int>& c) const { c[2] = -c[2]; c[1] += z_shift; -} +} /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_zq:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_zq::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; b.segment_num() *= -1; } -void -SymmetryOperation_PET_CartesianGrid_swap_zq:: - transform_view_segment_indices(ViewSegmentNumbers& vs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_zq::transform_view_segment_indices(ViewSegmentNumbers& vs) const { vs.segment_num() *= -1; } - -void SymmetryOperation_PET_CartesianGrid_swap_zq::transform_image_coordinates(BasicCoordinate<3,int>&c) const -{ - c[1] = q - c[1] + z_shift; +void +SymmetryOperation_PET_CartesianGrid_swap_zq::transform_image_coordinates(BasicCoordinate<3, int>& c) const { + c[1] = q - c[1] + z_shift; } /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; b.tangential_pos_num() *= -1; } -void -SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq:: - transform_view_segment_indices(ViewSegmentNumbers& vs) const -{ - -} - +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq::transform_view_segment_indices(ViewSegmentNumbers& vs) const {} -void SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq::transform_image_coordinates(BasicCoordinate<3,int>&c) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq::transform_image_coordinates(BasicCoordinate<3, int>& c) const { c[3] = -c[3]; - c[2] = -c[2]; - c[1] = q - c[1] + z_shift; + c[2] = -c[2]; + c[1] = q - c[1] + z_shift; } /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; - if (b.view_num() < view180/2) - { - b.view_num() += view180/2; + if (b.view_num() < view180 / 2) { + b.view_num() += view180 / 2; b.tangential_pos_num() *= -1; - } - else - { + } else { b.segment_num() *= -1; - b.view_num() -= view180/2; + b.view_num() -= view180 / 2; } - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq::transform_image_coordinates(BasicCoordinate<3, int>& c) const { const int tmp = c[3]; c[3] = c[2]; - c[2] = -tmp; - c[1] = q - c[1] + z_shift; + c[2] = -tmp; + c[1] = q - c[1] + z_shift; } /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_xy_ymx:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xy_ymx::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; - if (b.view_num() < view180/2) - { + if (b.view_num() < view180 / 2) { b.segment_num() *= -1; - b.view_num() += view180/2; + b.view_num() += view180 / 2; b.tangential_pos_num() *= -1; + } else { + b.view_num() -= view180 / 2; } - else - { - b.view_num() -= view180/2; - } - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ + +void +SymmetryOperation_PET_CartesianGrid_swap_xy_ymx::transform_image_coordinates(BasicCoordinate<3, int>& c) const { const int tmp = c[3]; - c[3] = c[2]; - c[2] = -tmp; + c[3] = c[2]; + c[2] = -tmp; c[1] += z_shift; } /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; - if (b.view_num() <= view180/2) - { - b.view_num() = view180/2 - b.view_num(); + if (b.view_num() <= view180 / 2) { + b.view_num() = view180 / 2 - b.view_num(); b.tangential_pos_num() *= -1; - } - else - { + } else { b.segment_num() *= -1; - b.view_num() = 3*view180/2 - b.view_num(); + b.view_num() = 3 * view180 / 2 - b.view_num(); } - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ + +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx::transform_image_coordinates(BasicCoordinate<3, int>& c) const { const int tmp = c[3]; - c[3] = -c[2]; - c[2] = -tmp; + c[3] = -c[2]; + c[2] = -tmp; c[1] += z_shift; } /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_ymy_zq:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_ymy_zq::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; b.segment_num() *= -1; b.view_num() = view180 - b.view_num(); b.tangential_pos_num() *= -1; - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ - c[2] = -c[2]; - c[1] = q - c[1] + z_shift; +void +SymmetryOperation_PET_CartesianGrid_swap_ymy_zq::transform_image_coordinates(BasicCoordinate<3, int>& c) const { + c[2] = -c[2]; + c[1] = q - c[1] + z_shift; } /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; b.segment_num() *= -1; b.tangential_pos_num() *= -1; } -void -SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy:: - transform_view_segment_indices(ViewSegmentNumbers& vs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy::transform_view_segment_indices(ViewSegmentNumbers& vs) const { vs.segment_num() *= -1; } - -void SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy::transform_image_coordinates(BasicCoordinate<3,int>&c) const -{ - c[3] = -c[3]; - c[2] = -c[2]; + +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy::transform_image_coordinates(BasicCoordinate<3, int>& c) const { + c[3] = -c[3]; + c[2] = -c[2]; c[1] += z_shift; } /////////////////////////////////////// - -void -SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq:: - transform_bin_coordinates(Bin& b) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq::transform_bin_coordinates(Bin& b) const { b.axial_pos_num() += axial_pos_shift; b.segment_num() *= -1; - b.view_num() = view180/2 - b.view_num(); + b.view_num() = view180 / 2 - b.view_num(); b.tangential_pos_num() *= -1; - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ + +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq::transform_image_coordinates(BasicCoordinate<3, int>& c) const { const int tmp = c[3]; c[3] = -c[2]; - c[2] = -tmp; + c[2] = -tmp; c[1] = q - c[1] + z_shift; } diff --git a/src/include/stir/recon_buildblock/TrivialBinNormalisation.h b/src/include/stir/recon_buildblock/TrivialBinNormalisation.h index 663cc10712..3eea603ac1 100644 --- a/src/include/stir/recon_buildblock/TrivialBinNormalisation.h +++ b/src/include/stir/recon_buildblock/TrivialBinNormalisation.h @@ -39,24 +39,21 @@ START_NAMESPACE_STIR \todo Make sure that the keyword value \c None corresponds to this class. */ -class TrivialBinNormalisation : - public RegisteredParsingObject -{ +class TrivialBinNormalisation : public RegisteredParsingObject { public: //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; + static const char* const registered_name; - virtual inline void apply(RelatedViewgrams&,const double start_time, const double end_time) const {} - virtual inline void undo(RelatedViewgrams&,const double start_time, const double end_time) const {} - - virtual inline float get_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const { return 1;} + virtual inline void apply(RelatedViewgrams&, const double start_time, const double end_time) const {} + virtual inline void undo(RelatedViewgrams&, const double start_time, const double end_time) const {} - virtual inline bool is_trivial() const { return true;} + virtual inline float get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { return 1; } + + virtual inline bool is_trivial() const { return true; } private: virtual inline void set_defaults() {} virtual inline void initialise_keymap() {} - }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/TrivialDataSymmetriesForBins.h b/src/include/stir/recon_buildblock/TrivialDataSymmetriesForBins.h index 497593c5c1..c9ecd957e0 100644 --- a/src/include/stir/recon_buildblock/TrivialDataSymmetriesForBins.h +++ b/src/include/stir/recon_buildblock/TrivialDataSymmetriesForBins.h @@ -33,65 +33,52 @@ START_NAMESPACE_STIR - /*! \ingroup symmetries \brief A class derived from DataSymmetriesForBins that says that there are no symmetries at all. */ -class TrivialDataSymmetriesForBins : public DataSymmetriesForBins -{ +class TrivialDataSymmetriesForBins : public DataSymmetriesForBins { public: TrivialDataSymmetriesForBins(const shared_ptr& proj_data_info_ptr); - virtual + virtual #ifndef STIR_NO_COVARIANT_RETURN_TYPES - TrivialDataSymmetriesForBins + TrivialDataSymmetriesForBins #else - DataSymmetriesForViewSegmentNumbers + DataSymmetriesForViewSegmentNumbers #endif - * clone() const; + * + clone() const; - virtual void - get_related_bins(std::vector&, const Bin& b, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; + virtual void get_related_bins(std::vector&, const Bin& b, const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num, + const int min_timing_pos_num = 0, const int max_timing_pos_num = 0) const; - virtual void - get_related_bins_factorised(std::vector&, const Bin& b, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; + virtual void get_related_bins_factorised(std::vector&, const Bin& b, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) const; - virtual int - num_related_bins(const Bin& b) const; + virtual int num_related_bins(const Bin& b) const; - virtual unique_ptr - find_symmetry_operation_from_basic_bin(Bin&) const; + virtual unique_ptr find_symmetry_operation_from_basic_bin(Bin&) const; - virtual bool - find_basic_bin(Bin& b) const; + virtual bool find_basic_bin(Bin& b) const; - virtual bool - is_basic(const Bin& v_s) const; + virtual bool is_basic(const Bin& v_s) const; - virtual unique_ptr - find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers&) const; + virtual unique_ptr find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers&) const; - virtual void - get_related_view_segment_numbers(std::vector&, const ViewSegmentNumbers&) const; + virtual void get_related_view_segment_numbers(std::vector&, const ViewSegmentNumbers&) const; - virtual int - num_related_view_segment_numbers(const ViewSegmentNumbers&) const; - virtual bool - find_basic_view_segment_numbers(ViewSegmentNumbers&) const; + virtual int num_related_view_segment_numbers(const ViewSegmentNumbers&) const; + virtual bool find_basic_view_segment_numbers(ViewSegmentNumbers&) const; private: - virtual bool blindly_equals(const root_type * const) const; + virtual bool blindly_equals(const root_type* const) const; }; END_NAMESPACE_STIR - #endif - diff --git a/src/include/stir/recon_buildblock/distributable.h b/src/include/stir/recon_buildblock/distributable.h index b8d87cf7c8..e61b046d15 100644 --- a/src/include/stir/recon_buildblock/distributable.h +++ b/src/include/stir/recon_buildblock/distributable.h @@ -36,8 +36,10 @@ START_NAMESPACE_STIR -template class RelatedViewgrams; -template class DiscretisedDensity; +template +class RelatedViewgrams; +template +class DiscretisedDensity; class BinNormalisation; class ProjData; class ProjDataInfo; @@ -48,37 +50,34 @@ class BackProjectorByBin; class ProjectorByBinPair; class DistributedCachingInformation; - //! \name Task-ids currently understood by stir::DistributedWorker /*! \ingroup distributable */ //!@{ -const int task_stop_processing=0; -const int task_setup_distributable_computation=200; -const int task_do_distributable_gradient_computation=42; -const int task_do_distributable_loglikelihood_computation=43; -const int task_do_distributable_sensitivity_computation=44; +const int task_stop_processing = 0; +const int task_setup_distributable_computation = 200; +const int task_do_distributable_gradient_computation = 42; +const int task_do_distributable_loglikelihood_computation = 43; +const int task_do_distributable_sensitivity_computation = 44; //!@} //! set-up parameters before calling distributable_computation() /*! \ingroup distributable - Empty unless STIR_MPI is defined, in which case it sends parameters to the + Empty unless STIR_MPI is defined, in which case it sends parameters to the slaves (see stir::DistributedWorker). \todo currently uses some global variables for configuration in the distributed namespace. This needs to be converted to a class, e.g. \c DistributedMaster */ -void setup_distributable_computation( - const shared_ptr& proj_pair_sptr, +void setup_distributable_computation(const shared_ptr& proj_pair_sptr, const shared_ptr& exam_info_sptr, const shared_ptr proj_data_info_sptr, - const shared_ptr >& target_sptr, - const bool zero_seg0_end_planes, - const bool distributed_cache_enabled); + const shared_ptr>& target_sptr, + const bool zero_seg0_end_planes, const bool distributed_cache_enabled); //! clean-up after a sequence of computations /*! \ingroup distributable - Empty unless STIR_MPI is defined, in which case it sends the "stop" task to + Empty unless STIR_MPI is defined, in which case it sends the "stop" task to the slaves (see stir::DistributedWorker) */ void end_distributable_computation(); @@ -90,16 +89,15 @@ void end_distributable_computation(); \a count and \a count2 are normally incremental counters that accumulate over the loop in distributable_computation(). - \warning The data in *measured_viewgrams_ptr are allowed to be overwritten, but the new data - will not be used. + \warning The data in *measured_viewgrams_ptr are allowed to be overwritten, but the new data + will not be used. */ -typedef void RPC_process_related_viewgrams_type ( - const shared_ptr& forward_projector_sptr, - const shared_ptr& back_projector_sptr, - RelatedViewgrams* measured_viewgrams_ptr, - int& count, int& count2, double* log_likelihood_ptr, - const RelatedViewgrams* additive_binwise_correction_ptr, - const RelatedViewgrams* mult_viewgrams_ptr); +typedef void RPC_process_related_viewgrams_type(const shared_ptr& forward_projector_sptr, + const shared_ptr& back_projector_sptr, + RelatedViewgrams* measured_viewgrams_ptr, int& count, int& count2, + double* log_likelihood_ptr, + const RelatedViewgrams* additive_binwise_correction_ptr, + const RelatedViewgrams* mult_viewgrams_ptr); /*! \brief This function essentially implements a loop over segments and all views in the current subset. @@ -111,8 +109,8 @@ typedef void RPC_process_related_viewgrams_type ( If STIR_MPI is defined, this function distributes the computation over the slaves. - Subsets are currently defined on views. A particular \a subset_num contains all views which are symmetry related to - \code + Subsets are currently defined on views. A particular \a subset_num contains all views which are symmetry related to + \code proj_data_ptr->min_view_num()+subset_num + n*num_subsets \endcode for n=0,1,,.. \c and for which the above view_num is 'basic' (for some segment_num in the range). @@ -123,15 +121,15 @@ typedef void RPC_process_related_viewgrams_type ( You first need to call setup_distributable_computation(), then you can do multiple calls to distributable_computation() with different images (but the same projection data, as - this is potentially cached). If you want to change the image characteristics (e.g. + this is potentially cached). If you want to change the image characteristics (e.g. size, or origin so), you have to call setup_distributable_computation() again. Finally, end the sequence of computations by a call to end_distributable_computation(). \param output_image_ptr will store the output image if non-zero. \param input_image_ptr input when non-zero. \param proj_data_ptr input projection data - \param read_from_proj_data if true, the \a measured_viewgrams_ptr argument of the call_back function - will be constructed using ProjData::get_related_viewgrams, otherwise + \param read_from_proj_data if true, the \a measured_viewgrams_ptr argument of the call_back function + will be constructed using ProjData::get_related_viewgrams, otherwise ProjData::get_empty_related_viewgrams is used. \param subset_num the number of the current subset (see above). Should be between 0 and num_subsets-1. \param num_subsets the number of subsets to consider. 1 will process all data. @@ -147,60 +145,48 @@ typedef void RPC_process_related_viewgrams_type ( \param start_time_of_frame is passed to normalise_sptr \param end_time_of_frame is passed to normalise_sptr \param RPC_process_related_viewgrams function that does the actual work. - \param caching_info_ptr ignored unless STIR_MPI=1, in which case it enables caching of viewgrams at the slave side + \param caching_info_ptr ignored unless STIR_MPI=1, in which case it enables caching of viewgrams at the slave side \warning There is NO check that the resulting subsets are balanced. \warning The function assumes that \a min_segment_num, \a max_segment_num are such that - symmetries map this range onto itself (i.e. no segment_num is obtained outside the range). - This usually means that \a min_segment_num = -\a max_segment_num. This assumption is checked with + symmetries map this range onto itself (i.e. no segment_num is obtained outside the range). + This usually means that \a min_segment_num = -\a max_segment_num. This assumption is checked with assert(). \todo The subset-scheme should be moved somewhere else (a Subset class?). - \warning If STIR_MPI is defined, there can only be one set_up active, as the + \warning If STIR_MPI is defined, there can only be one set_up active, as the slaves use only one set of variabiles to store projectors etc. \see DistributedWorker for how the slaves perform the computation if STIR_MPI is defined. */ void distributable_computation( - const shared_ptr& forward_projector_sptr, - const shared_ptr& back_projector_sptr, - const shared_ptr& symmetries_sptr, - DiscretisedDensity<3,float>* output_image_ptr, - const DiscretisedDensity<3,float>* input_image_ptr, - const shared_ptr& proj_data_ptr, - const bool read_from_proj_data, - int subset_num, int num_subsets, - int min_segment_num, int max_segment_num, - bool zero_seg0_end_planes, - double* double_out_ptr, - const shared_ptr& additive_binwise_correction, - const shared_ptr normalise_sptr, - const double start_time_of_frame, - const double end_time_of_frame, - RPC_process_related_viewgrams_type * RPC_process_related_viewgrams, - DistributedCachingInformation* caching_info_ptr); - - - /*! \name Tag-names currently used by stir::distributable_computation and related functions0 - \ingroup distributable - */ - //!@{ - const int AVAILABLE_NOTIFICATION_TAG=2; - const int END_ITERATION_TAG=3; - const int END_RECONSTRUCTION_TAG=4; - const int END_NOTIFICATION_TAG=5; - const int BINWISE_CORRECTION_TAG=6; - const int BINWISE_MULT_TAG=66; - const int REUSE_VIEWGRAM_TAG=10; - const int NEW_VIEWGRAM_TAG=11; - const int USE_DOUBLE_ARG_TAG=70; - const int USE_OUTPUT_IMAGE_ARG_TAG=71; - - //!@} + const shared_ptr& forward_projector_sptr, const shared_ptr& back_projector_sptr, + const shared_ptr& symmetries_sptr, DiscretisedDensity<3, float>* output_image_ptr, + const DiscretisedDensity<3, float>* input_image_ptr, const shared_ptr& proj_data_ptr, + const bool read_from_proj_data, int subset_num, int num_subsets, int min_segment_num, int max_segment_num, + bool zero_seg0_end_planes, double* double_out_ptr, const shared_ptr& additive_binwise_correction, + const shared_ptr normalise_sptr, const double start_time_of_frame, const double end_time_of_frame, + RPC_process_related_viewgrams_type* RPC_process_related_viewgrams, DistributedCachingInformation* caching_info_ptr, + int min_timing_pos_num = 0, int max_timing_pos_num = 0); + +/*! \name Tag-names currently used by stir::distributable_computation and related functions0 + \ingroup distributable +*/ +//!@{ +const int AVAILABLE_NOTIFICATION_TAG = 2; +const int END_ITERATION_TAG = 3; +const int END_RECONSTRUCTION_TAG = 4; +const int END_NOTIFICATION_TAG = 5; +const int BINWISE_CORRECTION_TAG = 6; +const int BINWISE_MULT_TAG = 66; +const int REUSE_VIEWGRAM_TAG = 10; +const int NEW_VIEWGRAM_TAG = 11; +const int USE_DOUBLE_ARG_TAG = 70; +const int USE_OUTPUT_IMAGE_ARG_TAG = 71; +//!@} END_NAMESPACE_STIR #endif // __stir_recon_buildblock_DISTRIBUTABLE_H__ - diff --git a/src/include/stir/recon_buildblock/distributableMPICacheEnabled.h b/src/include/stir/recon_buildblock/distributableMPICacheEnabled.h index fc0ecd046b..ea2382dde1 100644 --- a/src/include/stir/recon_buildblock/distributableMPICacheEnabled.h +++ b/src/include/stir/recon_buildblock/distributableMPICacheEnabled.h @@ -40,11 +40,9 @@ START_NAMESPACE_STIR class DistributedCachingInformation; - //!@{ //! \ingroup distributable - /*! \brief This function essentially implements a loop over segments and all views in the current subset in the parallel case @@ -57,30 +55,18 @@ class DistributedCachingInformation; \internal */ void distributable_computation_cache_enabled( - const shared_ptr& forward_projector_ptr, - const shared_ptr& back_projector_ptr, - const shared_ptr& symmetries_ptr, - DiscretisedDensity<3,float>* output_image_ptr, - const DiscretisedDensity<3,float>* input_image_ptr, - const shared_ptr& proj_data_sptr, - const bool read_from_proj_data, - int subset_num, int num_subsets, - int min_segment_num, int max_segment_num, - bool zero_seg0_end_planes, - double* double_out_ptr, - const shared_ptr& additive_binwise_correction, - const shared_ptr normalise_sptr, - const double start_time_of_frame, - const double end_time_of_frame, - RPC_process_related_viewgrams_type * RPC_process_related_viewgrams, - DistributedCachingInformation* caching_info_ptr - ); - - -void test_image_estimate(shared_ptr > input_image_ptr); + const shared_ptr& forward_projector_ptr, const shared_ptr& back_projector_ptr, + const shared_ptr& symmetries_ptr, DiscretisedDensity<3, float>* output_image_ptr, + const DiscretisedDensity<3, float>* input_image_ptr, const shared_ptr& proj_data_sptr, + const bool read_from_proj_data, int subset_num, int num_subsets, int min_segment_num, int max_segment_num, + bool zero_seg0_end_planes, double* double_out_ptr, const shared_ptr& additive_binwise_correction, + const shared_ptr normalise_sptr, const double start_time_of_frame, const double end_time_of_frame, + RPC_process_related_viewgrams_type* RPC_process_related_viewgrams, DistributedCachingInformation* caching_info_ptr, + int min_timing_pos_num = 0, int max_timing_pos_num = 0); + +void test_image_estimate(shared_ptr> input_image_ptr); //!@} END_NAMESPACE_STIR #endif // __stir_recon_buildblock_DISTRIBUTABLEMPI_H__ - diff --git a/src/include/stir/recon_buildblock/distributable_main.h b/src/include/stir/recon_buildblock/distributable_main.h index a190a4d7b8..87760fdfd7 100644 --- a/src/include/stir/recon_buildblock/distributable_main.h +++ b/src/include/stir/recon_buildblock/distributable_main.h @@ -39,12 +39,12 @@ START_NAMESPACE_STIR //! main function that starts processing on the master or slave as appropriate /*! This function should be implemented by the application, replacing the usual ::main(). - + DistributedWorker.cxx provides a ::main() function that will set-up everything for - parallel processing (as appropriate on the master and slaves), and then calls + parallel processing (as appropriate on the master and slaves), and then calls distributable_main() on the master (passing any arguments along). - If STIR_MPI is not defined, ::main() will simply call distributable_main(). + If STIR_MPI is not defined, ::main() will simply call distributable_main(). Skeleton of a program that uses this module: \code @@ -57,11 +57,10 @@ START_NAMESPACE_STIR \endcode */ -int distributable_main(int argc, char **argv); +int distributable_main(int argc, char** argv); //!@} END_NAMESPACE_STIR #endif // __stir_recon_buildblock_DISTRIBUTABLE_main_H__ - diff --git a/src/include/stir/recon_buildblock/distributed_functions.h b/src/include/stir/recon_buildblock/distributed_functions.h index ea2a65ee9f..fa301538b2 100644 --- a/src/include/stir/recon_buildblock/distributed_functions.h +++ b/src/include/stir/recon_buildblock/distributed_functions.h @@ -20,9 +20,9 @@ #define __stir_recon_buildblock_DistributedFunctions_h__ /*! - \file + \file \ingroup distributable - + \brief Declaration of functions in the distributed namespace \author Tobias Beisel @@ -33,11 +33,11 @@ \namespace distributed \brief Namespace for distributed computation with MPI - This is a collection of functions to send and receive objects and data - needed for distributed computation with MPI. They all come in a separate + This is a collection of functions to send and receive objects and data + needed for distributed computation with MPI. They all come in a separate namespace "distributed". There was no need to have an object providing this functionality as that would have been more costly. - + Note that every send function has a corresponding receive function. \see STIR_MPI @@ -47,8 +47,8 @@ */ #ifdef DOXYGEN_SKIP // need to define the following to get the documentation -#define STIR_MPI -#define STIR_MPI_TIMINGS +# define STIR_MPI +# define STIR_MPI_TIMINGS #endif /*! \def STIR_MPI @@ -62,16 +62,16 @@ measurements included which print times from start to end of a single Send or Receive command. This will uncover some maybe unnecessary long waiting times. It was actually used while developing the parallel version to check whether some code - rearrangements would lead to faster computation. + rearrangements would lead to faster computation. To enable these timings, compile the MPI-Version with the preprocessor variable STIR_MPI_TIMINGS defined. - + If compiled with STIR_MPI_TIMINGS defined, you still have the possibility to enable/disable the timings by using the parsing parameter (for stir::stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData). \verbatim enable message timings := 1 \endverbatim - To give the printed times a threshold use + To give the printed times a threshold use \verbatim message timings threshold := 0.1 \endverbatim @@ -87,356 +87,337 @@ #include "stir/ProjDataInfo.h" namespace stir { - class ExamInfo; +class ExamInfo; } -namespace distributed -{ - /*! \name Global variables used for STIR_MPI - */ - //@{ - //!the number of processes used for distributed computation - extern int num_processors; - - //!some stuff in distributable_computation needs to be done only in the first iteration - extern bool first_iteration; - - //!enable/disable tests - extern bool test; - - //for timings - extern bool rpc_time; //!enable timings for PRC_process_related_viewgrams_gradient() computation - extern bool test_send_receive_times; //!enable timings for every single send/receive operation - - extern double total_rpc_time; //!adding up the time used for PRC_process_related_viewgrams_gradient() computation at all slaves - extern double total_rpc_time_2; //!adding up the time used for PRC_process_related_viewgrams_gradient() computation at a single slave - extern double total_rpc_time_slaves; //!value to reduce the total_rpc_time values - extern double min_threshold; //!threshold for displaying send/receive times, initially set to 0.1 seconds - - - //----------------------Send operations---------------------------------- - - /*! \brief sends or broadcasts an integer value - * \param value the int value to be sent - * \param destination the process id where to send the interger value. If set to -1 a Broadcast will be done - */ - void send_int_value(int value, int destination); - - - /*! \brief sends or broadcasts a string - * \param str the string to be sent - * \param tag identifier to associate messages - * \param destination the process id where to send the string. If set to -1 a Broadcast will be done - */ - void send_string(const std::string& str, int tag, int destination); - - - /*! \brief send or broadcast a bool value - * \param value the bool value to be sent - * \param tag identifier to associate messages. If the tag is -1 a Broadcast will be done - * \param destination the process id where to send the bool value. If set to -1 a Broadcast will be done - * - * This function actually sends an integer value (0 or 1) as there is no bool datatype in MPI - */ - void send_bool_value(bool value, int tag, int destination); - - - /*! \brief sends or broadcasts some integer values - * \param values pointer to integer values to be sent - * \param count the count of integer values to be sent - * \param tag identifier to associate messages - * \param destination the process id where to send the int values. If set to -1 a Broadcast will be done - */ - void send_int_values(int * values, int count, int tag, int destination); - - - /*! \brief send or broadcast double values - * \param values pointer to the double values to be sent - * \param count the count of double values to be sent - * \param tag identifier to associate messages - * \param destination the process id where to send the double values. If set to -1 a Broadcast will be done - */ - void send_double_values(double * values, int count, int tag, int destination); - - /*! \brief send or broadcast ViewSegmentNumbers object - * \param vs_num value to be sent - * \param tag identifier to associate messages - * \param destination the process id where to send the double values. If set to -1 a Broadcast will be done - */ - void send_view_segment_numbers(const stir::ViewSegmentNumbers& vs_num, int tag, int destination); - - /*! \brief send or broadcast a projector-pair object - * \param proj_pair_sptr value to be sent - * \param destination the process id where to send the double values. If set to -1 a Broadcast will be done - * - * \warning This function works by sending the parameter_info. Therefore, if file-names are used (e.g. for - * a projection matrix on disk) this will only work on systems with shared file systems. - */ - void send_projectors(const stir::shared_ptr &proj_pair_sptr, int destination); - - /*! \brief sends or broadcasts the parameters of a DiscretisedDensity object - * \param input_image_ptr the image_ptr to be sent - * \param tag identifier to associate messages - * \param destination the process id where to send the image parameters. If set to -1 a Broadcast will be done - * - * This function sends all parameters needed to construct a corresponding image object at the - * slave. The image values are sent separately. This is done, as sending the parameters is not - * needed everytime the values are sent. The slave needs to receive the current_image_estimate - * every iteration, but he already knows the parameters. - * - * The actual parameters sent are the image dimensions, the origin and the grid_spacing - */ - void send_image_parameters(const stir::DiscretisedDensity<3,float>* input_image_ptr, int tag, int destination); - - - /*! \brief sends or broadcasts the values of a DiscretisedDensity object - * \param input_image_ptr the image_ptr to be sent - * \param destination the process id where to send the image values. If set to -1 a Broadcast will be done - * - * This function sends the values of an image. The values are serialized to a one-dimensional array - * as MPI only sends that kind of data structures. - */ - void send_image_estimate(const stir::DiscretisedDensity<3,float>* input_image_ptr, int destination); - - - /*! \brief sends or broadcasts the information from ExamInfo and ProjDataInfo - * \param exam_info the ExamInfo pointer to be sent - * \param proj_data_info the ProjDataInfo pointer to be sent - * \param destination the process id where to send the values. If set to -1 a Broadcast will be done - * - * For sending the objects a rather "dirty trick" is used: - * Instead of sending all needed data for constructing the objects, - * the information is temporarily stored as ProjDataInterfile and then buffered - * as text from the file. Afterwards, that is sent to the slave. - * - * Doing this, the slave is able to construct the objects by using the received information. - * The sent char-array is used as stream-input to the parse() function of InterfileHeader. - * - * \warning Creates a temporary Interfile header in the local working directory. - */ - void send_exam_and_proj_data_info(const stir::ExamInfo& exam_info, const stir::ProjDataInfo& proj_data_info, int destination); - - - /*! \brief sends a RelatedViegrams object - * \param viewgrams the viewgrams to be sent - * \param destination the process id where to send the related viewgrams - * - * This function iterates through the relatedviewgrams object and calls \c send_viewgram() - * for each comprised viewgram. - * The only value sent is the count of viewgrams contained within the related_viewgrams object - * to make sure that the worker knows how many viewgrams he has to receive. - */ - void send_related_viewgrams(stir::RelatedViewgrams* viewgrams, int destination); - - - /*! \brief sends a Viewgram object - * \param viewgram the viewgrams to be sent - * \param destination the process id where to send the viewgram - * - * This function sends all parameters needed for the construction of the viewgram at the worker, - * as well as the actual values of the viewgram. That would mean that 2 Messages are sent: - * 1. The dimensions of the viewgram and the vs_num - * 2. The values detwermined by iterating through the viewgram and serializing it to a one-dimensional array - */ - void send_viewgram(const stir::Viewgram& viewgram, int destination); - - - //----------------------Receive operations---------------------------------- - - - /*! \brief receives a single integer value - * \param source the process id from which to receive the interger value. If set to -1 the receive will be done from broadcast - * \returns the received int value - */ - int receive_int_value(int source); - - - /*! \brief receives a string - * \param tag unique identifier to associate messages - * \param source the process id from which to receive the string - * \returns the received string - */ - std::string receive_string(int tag, int source); - - - /*! \brief receives all needed information to subsequently construct a ProjectorByBinPair object - * \param projector_pair_ptr address pointer of the new ProjectorByBinPair pointer - * \param source the process id from which to receive the ProjectorByBinPair - * - * First the registered_name string of the ProjectorByBinPair is received. - * Then the parameter_info() of the masters ProjectorByBinPair is received. - * Using the registered_name and the parameter_info() as stream, both can be used as - * input to the read_registered_object function, which then constructs the new ProjectorByBinPair pointer. - * - * The passed address pointer parameter will then be redirected to the address of ProjectorByBinPair created - * using the received parameters. - */ - void receive_and_initialize_projectors(stir::shared_ptr &projector_pair_ptr, int source); - - - /*! \brief receives a bool value - * \param tag unique identifier to associate messages - * \param source the process id from which to receive the bool value - * \returns the received bool value - * - * This function actually receives an integer value (0 or 1) - * as there is no bool datatype in MPI, but it will return a bool value - */ - bool receive_bool_value(int tag, int source); - - - /*! \brief receives some integer values - * \param values pointer to the receive buffer - * \param count the count of integer values to be received - * \param tag identifier to associate messages - * \returns MPI_Status object to query the source of the message - * - * The tag needs to be set to ARBITRARY_TAG (=8) if MPI_ANY_TAG shall be used - */ - MPI_Status receive_int_values(int * values, int count, int tag); - - - /*! \brief receives some double values - * \param values pointer to the receive buffer - * \param count the count of double values to be received - * \param tag identifier to associate messages - * \returns MPI_Status object to query the source of the message - * - * The tag needs to be set to ARBITRARY_TAG (=8) if MPI_ANY_TAG shall be used - */ - MPI_Status receive_double_values(double* values, int count, int tag); - - /*! \brief receive a ViewSegmentNumbers object - * \param[out] vs_num value that will be set - * \param tag identifier to associate messages - * \returns MPI_Status object to query the source of the message - * - * The tag needs to be set to ARBITRARY_TAG (=8) if MPI_ANY_TAG shall be used - */ - MPI_Status receive_view_segment_numbers(stir::ViewSegmentNumbers& vs_num, int tag); - - /*! \brief receives the parameters of a DiscretisedDensity object - * \param image_ptr address pointer of the new DiscretisedDensity - * \param buffer saves the image buffer size to be reused when receiving the image values - * \param tag identifier to associate messages. If set to -1 a Broadcast will be done - * \param source the process id from which to receive the image parameters. - * - * This function receives all parameters needed to construct an image object at the - * slave. The image values are sent separately. - * - * The actual parameters received are the image dimensions, the origin and the grid_spacing - * - * The function currently only supports VoxelsOnCartesianGrid - */ - void receive_and_set_image_parameters(stir::shared_ptr > &image_ptr, int &buffer, int tag, int source); - - - /*! \brief receives the values of a DiscretisedDensity object - * \param image_ptr the image_ptr to be sent - * \param buffer_size gives the needed size of the receive buffer - * \param source the process id from which to receive the image values. - * \returns MPI_Status object to query the source of the message - * - * The image_ptr is filled by iterating through the target pointer and copying - * the single values from the receive buffer. - * - * The buffer_size is used again to reduce the image values - */ - MPI_Status receive_image_values_and_fill_image_ptr(stir::shared_ptr > &image_ptr, int buffer_size, int source); - - - /*! \brief receives information of ExamInfo and ProjDataInfo objects and constructs new ones from it - * \param exam_info_sptr the new ExamInfo pointer to be set up - * \param proj_data_info_sptr the new ProjDataInfo pointer to be set up - * \param source the process id from which to receive from - * - * The parameter info is received as a Interfile Header string. That way the slave is able - * to construct a ProjDataInfo within a InterfilePDFSHeader using the received - * char-array as stream-input to the parse() function of InterfilePDFSHeader. - */ - void receive_and_construct_exam_and_proj_data_info_ptr(stir::shared_ptr& exam_info_sptr, - stir::shared_ptr& proj_data_info_sptr, - int source); - - - /*! \brief receives and constructs a RelatedViewgrams object - * \param viewgrams object that will be filled with the data - * \param proj_data_info_ptr the ProjDataInfo pointer describing the data - * \param symmetries_sptr the symmetries pointer constructed when setting up the projectors - * \param source the process id from which to receive the ProjDataInfo - * - * First of all it is important to notice, that this function is not independent. To construct - * a new RelatedViegrams object, the symmetries_ptr must be available. That would mean, - * that the slave has to call \c receive_and_initialize_projectors() to set up the symmetries_ptr - * before the related_vewgrams can be received. - * Additionally the ProjDataInfo-pointer must be available for receiving a single viewgrams. - * That implies calling \c receive_and_construct_proj_data_info_ptr() before. - * To make this function independent, both of these objects have to be sent here. On the other hand - * that would lead to the overhead of sending it everytime a related_viewgram is sent, - * which is really expensive. - * - * This function receives the count of viewgrams to be received and calls - * \c receive_and_construct_viewgram that often. Every received viewgram is pushed back - * to a viewgram vector, which afterwards is used with the symmetries to construct - * a RelatedViewgrams object. - */ - void receive_and_construct_related_viewgrams(stir::RelatedViewgrams*& viewgrams, - const stir::shared_ptr& proj_data_info_ptr, - const stir::shared_ptr symmetries_sptr, - int source); - - /*! \brief receives a Viewgram object - * \param viewgram the viewgrams to be constructed - * \param proj_data_info_ptr the ProjDataInfo pointer describing the data - * \param source the process id from which to receive the ProjDataInfo - * - * This function received all parameters needed for the construction of the viewgram at the worker, - * as well as the actual values of the viewgram. That would mean that 2 Messages are received: - * 1. The dimensions of the viewgram and the vs_num - * 2. The values of the viewgram - * - * The buffer_size needed to receive the values is calculated from the dimensions received. - * The viewgram is filled by iterating througn it and copying the values of the received values. - */ - void receive_and_construct_viewgram(stir::Viewgram*& viewgram, - const stir::shared_ptr& proj_data_info_ptr, - int source); - - //-----------------------reduce operations------------------------------------- - - /*! \brief the function called by the master to reduce the output image - * \param output_image_ptr the image pointer where the reduced image is saved - * \param destination the process id where the output_image is reduced - */ - void reduce_received_output_image(stir::DiscretisedDensity<3,float>* output_image_ptr, int destination); - - /*! \brief the function called by the slaves to reduce the output image - * \param output_image_ptr the image pointer where the reduced image is saved - * \param image_buffer_size the buffer size needed for the image - * \param my_rank rank of the slave, only used for screen output - * \param destination the process id where the output_image is reduced - * - * The buffer size was calculated in \c receive_image_values_and_fill_image_ptr(). - * Alternatively it can be calculated by the image parameters. - */ - void reduce_output_image(stir::shared_ptr > &output_image_ptr, int image_buffer_size, int my_rank, int destination); - - /*! \name Tag-names currently used by functions in the distributed namespace - */ - //!@{ - const int INT_TAG=7; - const int ARBITRARY_TAG=8; //!< special tag, equivalent to MPI_ANY_TAG in some functions - const int STIR_MPI_CONF_TAG=9; - const int IMAGE_ESTIMATE_TAG=23; - const int IMAGE_PARAMETER_TAG=24; - const int VIEWGRAM_DIMENSIONS_TAG=27; - const int VIEWGRAM_TAG=28; - const int VIEWGRAM_COUNT_TAG=29; - const int PROJECTION_DATA_INFO_TAG=30; - const int PARAMETER_INFO_TAG=21; - const int REGISTERED_NAME_TAG=25; - //!@} -} +namespace distributed { +/*! \name Global variables used for STIR_MPI + */ +//@{ +//! the number of processes used for distributed computation +extern int num_processors; -#endif +//! some stuff in distributable_computation needs to be done only in the first iteration +extern bool first_iteration; + +//! enable/disable tests +extern bool test; + +// for timings +extern bool rpc_time; //! enable timings for PRC_process_related_viewgrams_gradient() computation +extern bool test_send_receive_times; //! enable timings for every single send/receive operation + +extern double total_rpc_time; //! adding up the time used for PRC_process_related_viewgrams_gradient() computation at all slaves +extern double + total_rpc_time_2; //! adding up the time used for PRC_process_related_viewgrams_gradient() computation at a single slave +extern double total_rpc_time_slaves; //! value to reduce the total_rpc_time values +extern double min_threshold; //! threshold for displaying send/receive times, initially set to 0.1 seconds + +//----------------------Send operations---------------------------------- + +/*! \brief sends or broadcasts an integer value + * \param value the int value to be sent + * \param destination the process id where to send the interger value. If set to -1 a Broadcast will be done + */ +void send_int_value(int value, int destination); + +/*! \brief sends or broadcasts a string + * \param str the string to be sent + * \param tag identifier to associate messages + * \param destination the process id where to send the string. If set to -1 a Broadcast will be done + */ +void send_string(const std::string& str, int tag, int destination); + +/*! \brief send or broadcast a bool value + * \param value the bool value to be sent + * \param tag identifier to associate messages. If the tag is -1 a Broadcast will be done + * \param destination the process id where to send the bool value. If set to -1 a Broadcast will be done + * + * This function actually sends an integer value (0 or 1) as there is no bool datatype in MPI + */ +void send_bool_value(bool value, int tag, int destination); + +/*! \brief sends or broadcasts some integer values + * \param values pointer to integer values to be sent + * \param count the count of integer values to be sent + * \param tag identifier to associate messages + * \param destination the process id where to send the int values. If set to -1 a Broadcast will be done + */ +void send_int_values(int* values, int count, int tag, int destination); + +/*! \brief send or broadcast double values + * \param values pointer to the double values to be sent + * \param count the count of double values to be sent + * \param tag identifier to associate messages + * \param destination the process id where to send the double values. If set to -1 a Broadcast will be done + */ +void send_double_values(double* values, int count, int tag, int destination); + +/*! \brief send or broadcast ViewSegmentNumbers object + * \param vs_num value to be sent + * \param tag identifier to associate messages + * \param destination the process id where to send the double values. If set to -1 a Broadcast will be done + */ +void send_view_segment_numbers(const stir::ViewSegmentNumbers& vs_num, int tag, int destination); + +/*! \brief send or broadcast a projector-pair object + * \param proj_pair_sptr value to be sent + * \param destination the process id where to send the double values. If set to -1 a Broadcast will be done + * + * \warning This function works by sending the parameter_info. Therefore, if file-names are used (e.g. for + * a projection matrix on disk) this will only work on systems with shared file systems. + */ +void send_projectors(const stir::shared_ptr& proj_pair_sptr, int destination); + +/*! \brief sends or broadcasts the parameters of a DiscretisedDensity object + * \param input_image_ptr the image_ptr to be sent + * \param tag identifier to associate messages + * \param destination the process id where to send the image parameters. If set to -1 a Broadcast will be done + * + * This function sends all parameters needed to construct a corresponding image object at the + * slave. The image values are sent separately. This is done, as sending the parameters is not + * needed everytime the values are sent. The slave needs to receive the current_image_estimate + * every iteration, but he already knows the parameters. + * + * The actual parameters sent are the image dimensions, the origin and the grid_spacing + */ +void send_image_parameters(const stir::DiscretisedDensity<3, float>* input_image_ptr, int tag, int destination); + +/*! \brief sends or broadcasts the values of a DiscretisedDensity object + * \param input_image_ptr the image_ptr to be sent + * \param destination the process id where to send the image values. If set to -1 a Broadcast will be done + * + * This function sends the values of an image. The values are serialized to a one-dimensional array + * as MPI only sends that kind of data structures. + */ +void send_image_estimate(const stir::DiscretisedDensity<3, float>* input_image_ptr, int destination); + +/*! \brief sends or broadcasts the information from ExamInfo and ProjDataInfo + * \param exam_info the ExamInfo pointer to be sent + * \param proj_data_info the ProjDataInfo pointer to be sent + * \param destination the process id where to send the values. If set to -1 a Broadcast will be done + * + * For sending the objects a rather "dirty trick" is used: + * Instead of sending all needed data for constructing the objects, + * the information is temporarily stored as ProjDataInterfile and then buffered + * as text from the file. Afterwards, that is sent to the slave. + * + * Doing this, the slave is able to construct the objects by using the received information. + * The sent char-array is used as stream-input to the parse() function of InterfileHeader. + * + * \warning Creates a temporary Interfile header in the local working directory. + */ +void send_exam_and_proj_data_info(const stir::ExamInfo& exam_info, const stir::ProjDataInfo& proj_data_info, int destination); + +/*! \brief sends a RelatedViegrams object + * \param viewgrams the viewgrams to be sent + * \param destination the process id where to send the related viewgrams + * + * This function iterates through the relatedviewgrams object and calls \c send_viewgram() + * for each comprised viewgram. + * The only value sent is the count of viewgrams contained within the related_viewgrams object + * to make sure that the worker knows how many viewgrams he has to receive. + */ +void send_related_viewgrams(stir::RelatedViewgrams* viewgrams, int destination); +/*! \brief sends a Viewgram object + * \param viewgram the viewgrams to be sent + * \param destination the process id where to send the viewgram + * + * This function sends all parameters needed for the construction of the viewgram at the worker, + * as well as the actual values of the viewgram. That would mean that 2 Messages are sent: + * 1. The dimensions of the viewgram and the vs_num + * 2. The values detwermined by iterating through the viewgram and serializing it to a one-dimensional array + */ +void send_viewgram(const stir::Viewgram& viewgram, int destination); + +//----------------------Receive operations---------------------------------- + +/*! \brief receives a single integer value + * \param source the process id from which to receive the interger value. If set to -1 the receive will be done from broadcast + * \returns the received int value + */ +int receive_int_value(int source); + +/*! \brief receives a string + * \param tag unique identifier to associate messages + * \param source the process id from which to receive the string + * \returns the received string + */ +std::string receive_string(int tag, int source); + +/*! \brief receives all needed information to subsequently construct a ProjectorByBinPair object + * \param projector_pair_ptr address pointer of the new ProjectorByBinPair pointer + * \param source the process id from which to receive the ProjectorByBinPair + * + * First the registered_name string of the ProjectorByBinPair is received. + * Then the parameter_info() of the masters ProjectorByBinPair is received. + * Using the registered_name and the parameter_info() as stream, both can be used as + * input to the read_registered_object function, which then constructs the new ProjectorByBinPair pointer. + * + * The passed address pointer parameter will then be redirected to the address of ProjectorByBinPair created + * using the received parameters. + */ +void receive_and_initialize_projectors(stir::shared_ptr& projector_pair_ptr, int source); + +/*! \brief receives a bool value + * \param tag unique identifier to associate messages + * \param source the process id from which to receive the bool value + * \returns the received bool value + * + * This function actually receives an integer value (0 or 1) + * as there is no bool datatype in MPI, but it will return a bool value + */ +bool receive_bool_value(int tag, int source); + +/*! \brief receives some integer values + * \param values pointer to the receive buffer + * \param count the count of integer values to be received + * \param tag identifier to associate messages + * \returns MPI_Status object to query the source of the message + * + * The tag needs to be set to ARBITRARY_TAG (=8) if MPI_ANY_TAG shall be used + */ +MPI_Status receive_int_values(int* values, int count, int tag); + +/*! \brief receives some double values + * \param values pointer to the receive buffer + * \param count the count of double values to be received + * \param tag identifier to associate messages + * \returns MPI_Status object to query the source of the message + * + * The tag needs to be set to ARBITRARY_TAG (=8) if MPI_ANY_TAG shall be used + */ +MPI_Status receive_double_values(double* values, int count, int tag); + +/*! \brief receive a ViewSegmentNumbers object + * \param[out] vs_num value that will be set + * \param tag identifier to associate messages + * \returns MPI_Status object to query the source of the message + * + * The tag needs to be set to ARBITRARY_TAG (=8) if MPI_ANY_TAG shall be used + */ +MPI_Status receive_view_segment_numbers(stir::ViewSegmentNumbers& vs_num, int tag); + +/*! \brief receives the parameters of a DiscretisedDensity object + * \param image_ptr address pointer of the new DiscretisedDensity + * \param buffer saves the image buffer size to be reused when receiving the image values + * \param tag identifier to associate messages. If set to -1 a Broadcast will be done + * \param source the process id from which to receive the image parameters. + * + * This function receives all parameters needed to construct an image object at the + * slave. The image values are sent separately. + * + * The actual parameters received are the image dimensions, the origin and the grid_spacing + * + * The function currently only supports VoxelsOnCartesianGrid + */ +void receive_and_set_image_parameters(stir::shared_ptr>& image_ptr, int& buffer, int tag, + int source); + +/*! \brief receives the values of a DiscretisedDensity object + * \param image_ptr the image_ptr to be sent + * \param buffer_size gives the needed size of the receive buffer + * \param source the process id from which to receive the image values. + * \returns MPI_Status object to query the source of the message + * + * The image_ptr is filled by iterating through the target pointer and copying + * the single values from the receive buffer. + * + * The buffer_size is used again to reduce the image values + */ +MPI_Status receive_image_values_and_fill_image_ptr(stir::shared_ptr>& image_ptr, + int buffer_size, int source); + +/*! \brief receives information of ExamInfo and ProjDataInfo objects and constructs new ones from it + * \param exam_info_sptr the new ExamInfo pointer to be set up + * \param proj_data_info_sptr the new ProjDataInfo pointer to be set up + * \param source the process id from which to receive from + * + * The parameter info is received as a Interfile Header string. That way the slave is able + * to construct a ProjDataInfo within a InterfilePDFSHeader using the received + * char-array as stream-input to the parse() function of InterfilePDFSHeader. + */ +void receive_and_construct_exam_and_proj_data_info_ptr(stir::shared_ptr& exam_info_sptr, + stir::shared_ptr& proj_data_info_sptr, int source); + +/*! \brief receives and constructs a RelatedViewgrams object + * \param viewgrams object that will be filled with the data + * \param proj_data_info_ptr the ProjDataInfo pointer describing the data + * \param symmetries_sptr the symmetries pointer constructed when setting up the projectors + * \param source the process id from which to receive the ProjDataInfo + * + * First of all it is important to notice, that this function is not independent. To construct + * a new RelatedViegrams object, the symmetries_ptr must be available. That would mean, + * that the slave has to call \c receive_and_initialize_projectors() to set up the symmetries_ptr + * before the related_vewgrams can be received. + * Additionally the ProjDataInfo-pointer must be available for receiving a single viewgrams. + * That implies calling \c receive_and_construct_proj_data_info_ptr() before. + * To make this function independent, both of these objects have to be sent here. On the other hand + * that would lead to the overhead of sending it everytime a related_viewgram is sent, + * which is really expensive. + * + * This function receives the count of viewgrams to be received and calls + * \c receive_and_construct_viewgram that often. Every received viewgram is pushed back + * to a viewgram vector, which afterwards is used with the symmetries to construct + * a RelatedViewgrams object. + */ +void receive_and_construct_related_viewgrams(stir::RelatedViewgrams*& viewgrams, + const stir::shared_ptr& proj_data_info_ptr, + const stir::shared_ptr symmetries_sptr, + int source); + +/*! \brief receives a Viewgram object + * \param viewgram the viewgrams to be constructed + * \param proj_data_info_ptr the ProjDataInfo pointer describing the data + * \param source the process id from which to receive the ProjDataInfo + * + * This function received all parameters needed for the construction of the viewgram at the worker, + * as well as the actual values of the viewgram. That would mean that 2 Messages are received: + * 1. The dimensions of the viewgram and the vs_num + * 2. The values of the viewgram + * + * The buffer_size needed to receive the values is calculated from the dimensions received. + * The viewgram is filled by iterating througn it and copying the values of the received values. + */ +void receive_and_construct_viewgram(stir::Viewgram*& viewgram, + const stir::shared_ptr& proj_data_info_ptr, int source); + +//-----------------------reduce operations------------------------------------- + +/*! \brief the function called by the master to reduce the output image + * \param output_image_ptr the image pointer where the reduced image is saved + * \param destination the process id where the output_image is reduced + */ +void reduce_received_output_image(stir::DiscretisedDensity<3, float>* output_image_ptr, int destination); + +/*! \brief the function called by the slaves to reduce the output image + * \param output_image_ptr the image pointer where the reduced image is saved + * \param image_buffer_size the buffer size needed for the image + * \param my_rank rank of the slave, only used for screen output + * \param destination the process id where the output_image is reduced + * + * The buffer size was calculated in \c receive_image_values_and_fill_image_ptr(). + * Alternatively it can be calculated by the image parameters. + */ +void reduce_output_image(stir::shared_ptr>& output_image_ptr, int image_buffer_size, + int my_rank, int destination); + +/*! \name Tag-names currently used by functions in the distributed namespace + */ +//!@{ +const int INT_TAG = 7; +const int ARBITRARY_TAG = 8; //!< special tag, equivalent to MPI_ANY_TAG in some functions +const int STIR_MPI_CONF_TAG = 9; +const int IMAGE_ESTIMATE_TAG = 23; +const int IMAGE_PARAMETER_TAG = 24; +const int VIEWGRAM_DIMENSIONS_TAG = 27; +const int VIEWGRAM_TAG = 28; +const int VIEWGRAM_COUNT_TAG = 29; +const int PROJECTION_DATA_INFO_TAG = 30; +const int PARAMETER_INFO_TAG = 21; +const int REGISTERED_NAME_TAG = 25; +//!@} +} // namespace distributed + +#endif diff --git a/src/include/stir/recon_buildblock/distributed_test_functions.h b/src/include/stir/recon_buildblock/distributed_test_functions.h index dc1c74de2e..764da11169 100644 --- a/src/include/stir/recon_buildblock/distributed_test_functions.h +++ b/src/include/stir/recon_buildblock/distributed_test_functions.h @@ -21,36 +21,35 @@ #define __stir_recon_buildblock_DistributedTestFunctions_h__ /*! - \file + \file \ingroup distributable - + \brief Declaration of test functions for the distributed namespace - This is a collection of functions to test the function implemented - in DistributedFunction.cxx . Each of the possible tests consists of a + This is a collection of functions to test the function implemented + in DistributedFunction.cxx . Each of the possible tests consists of a master and a slave function to be called by different processes. Note that every master function has a corresponding slave function. - + \todo Currently no independent test functions are implemented. The tests are used - by embedding them into the reconstruction functions and calling them once. - - This is only done in debug mode and can be enabled/disabled with the following - parsing parameter: + by embedding them into the reconstruction functions and calling them once. + + This is only done in debug mode and can be enabled/disabled with the following + parsing parameter: \verbatim enable distributed tests := 1 \endverbatim The default value is 0. - + This obviously not a good way to do testing, so there is a need to write independent test functions. The problem with that is, that all needed objects have to be set up. - The function headers give an idea of what would have to be constructed. - + The function headers give an idea of what would have to be constructed. + \author Tobias Beisel */ - #include "mpi.h" #include "stir/shared_ptr.h" #include "stir/DataSymmetriesForViewSegmentNumbers.h" @@ -61,43 +60,39 @@ #include #include -namespace distributed -{ - //-----------------------test functions------------------------------------------ - - - void test_viewgram_slave(const stir::shared_ptr& proj_data_info_ptr); - - void test_viewgram_master(stir::Viewgram viewgram, const stir::shared_ptr& proj_data_info_ptr); - - void test_image_estimate_master(const stir::DiscretisedDensity<3,float>* input_image_ptr, int slave); - - void test_image_estimate_slave(); - - void test_related_viewgrams_master(const stir::shared_ptr& proj_data_info_ptr, - const stir::shared_ptr symmetries_sptr, - stir::RelatedViewgrams* y, int slave); - - void test_related_viewgrams_slave(const stir::shared_ptr& proj_data_info_ptr, - const stir::shared_ptr symmetries_sptr - ); - - void test_parameter_info_master(const std::string str, int slave, char const * const text); - - void test_parameter_info_slave(const std::string str); - - void test_bool_value_master(bool value, int slave); - - void test_bool_value_slave(); - - void test_int_value_master(int value, int slave); - - void test_int_value_slave(); - - void test_int_values_master(int slave); - - void test_int_values_slave(); -} +namespace distributed { +//-----------------------test functions------------------------------------------ -#endif +void test_viewgram_slave(const stir::shared_ptr& proj_data_info_ptr); + +void test_viewgram_master(stir::Viewgram viewgram, const stir::shared_ptr& proj_data_info_ptr); + +void test_image_estimate_master(const stir::DiscretisedDensity<3, float>* input_image_ptr, int slave); + +void test_image_estimate_slave(); + +void test_related_viewgrams_master(const stir::shared_ptr& proj_data_info_ptr, + const stir::shared_ptr symmetries_sptr, + stir::RelatedViewgrams* y, int slave); +void test_related_viewgrams_slave(const stir::shared_ptr& proj_data_info_ptr, + const stir::shared_ptr symmetries_sptr); + +void test_parameter_info_master(const std::string str, int slave, char const* const text); + +void test_parameter_info_slave(const std::string str); + +void test_bool_value_master(bool value, int slave); + +void test_bool_value_slave(); + +void test_int_value_master(int value, int slave); + +void test_int_value_slave(); + +void test_int_values_master(int slave); + +void test_int_values_slave(); +} // namespace distributed + +#endif diff --git a/src/include/stir/recon_buildblock/find_basic_vs_nums_in_subsets.h b/src/include/stir/recon_buildblock/find_basic_vs_nums_in_subsets.h index ebd80ecf7d..5a63d14c12 100644 --- a/src/include/stir/recon_buildblock/find_basic_vs_nums_in_subsets.h +++ b/src/include/stir/recon_buildblock/find_basic_vs_nums_in_subsets.h @@ -26,7 +26,6 @@ \author Kris Thielemans */ - #include "stir/ViewSegmentNumbers.h" #include @@ -35,23 +34,21 @@ START_NAMESPACE_STIR class ProjDataInfo; class DataSymmetriesForViewSegmentNumbers; -namespace detail -{ +namespace detail { - /*! - \brief a helper function to find which view/segments are in a subset - \ingroup recon_buildblock +/*! + \brief a helper function to find which view/segments are in a subset + \ingroup recon_buildblock - This function is used by projectors and distributable_computation etc - to construct a list of view/segments that are in a subset, and which are - "basic" w.r.t the symmetries. - */ - std::vector - find_basic_vs_nums_in_subset(const ProjDataInfo& proj_data_info, - const DataSymmetriesForViewSegmentNumbers& symmetries, - const int min_segment_num, const int max_segment_num, - const int subset_num, const int num_subsets); + This function is used by projectors and distributable_computation etc + to construct a list of view/segments that are in a subset, and which are + "basic" w.r.t the symmetries. +*/ +std::vector find_basic_vs_nums_in_subset(const ProjDataInfo& proj_data_info, + const DataSymmetriesForViewSegmentNumbers& symmetries, + const int min_segment_num, const int max_segment_num, + const int subset_num, const int num_subsets); -} +} // namespace detail END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/test/PoissonLLReconstructionTests.h b/src/include/stir/recon_buildblock/test/PoissonLLReconstructionTests.h index c49c2fbea2..e86e2ef4e0 100644 --- a/src/include/stir/recon_buildblock/test/PoissonLLReconstructionTests.h +++ b/src/include/stir/recon_buildblock/test/PoissonLLReconstructionTests.h @@ -31,39 +31,35 @@ START_NAMESPACE_STIR PoissonLogLikelihoodWithLinearModelForMeanAndProjData */ template -class PoissonLLReconstructionTests : public ReconstructionTests -{ +class PoissonLLReconstructionTests : public ReconstructionTests { private: typedef ReconstructionTests base_type; + public: //! Constructor that can take some input data to run the test with - explicit inline - PoissonLLReconstructionTests(const std::string &proj_data_filename = "", - const std::string & density_filename = "") - : base_type(proj_data_filename, density_filename) - {} + explicit inline PoissonLLReconstructionTests(const std::string& proj_data_filename = "", + const std::string& density_filename = "") + : base_type(proj_data_filename, density_filename) {} //! creates Poisson log likelihood /*! sets \c _proj_data_sptr and uses \c _input_density_sptr for set_up. - */ + */ virtual inline void construct_log_likelihood(); protected: - shared_ptr > _objective_function_sptr; + shared_ptr> _objective_function_sptr; }; template void -PoissonLLReconstructionTests:: -construct_log_likelihood() -{ +PoissonLLReconstructionTests::construct_log_likelihood() { this->_objective_function_sptr.reset(new PoissonLogLikelihoodWithLinearModelForMeanAndProjData); PoissonLogLikelihoodWithLinearModelForMeanAndProjData& objective_function = - reinterpret_cast< PoissonLogLikelihoodWithLinearModelForMeanAndProjData& >(*this->_objective_function_sptr); + reinterpret_cast&>(*this->_objective_function_sptr); objective_function.set_proj_data_sptr(this->_proj_data_sptr); shared_ptr proj_matrix_sptr(new ProjMatrixByBinUsingRayTracing()); shared_ptr proj_pair_sptr(new ProjectorByBinPairUsingProjMatrixByBin(proj_matrix_sptr)); - objective_function.set_projector_pair_sptr(proj_pair_sptr) ; + objective_function.set_projector_pair_sptr(proj_pair_sptr); /*objective_function.set_normalisation_sptr(bin_norm_sptr); objective_function.set_additive_proj_data_sptr(add_proj_data_sptr); */ diff --git a/src/include/stir/recon_buildblock/test/ReconstructionTests.h b/src/include/stir/recon_buildblock/test/ReconstructionTests.h index 5d2dca120a..2fc6f63b16 100644 --- a/src/include/stir/recon_buildblock/test/ReconstructionTests.h +++ b/src/include/stir/recon_buildblock/test/ReconstructionTests.h @@ -37,13 +37,10 @@ START_NAMESPACE_STIR \brief Base class for simple test on reconstruction */ template -class ReconstructionTests : public RunTests -{ +class ReconstructionTests : public RunTests { public: //! Constructor that can take some input data to run the test with - explicit inline - ReconstructionTests(const std::string &proj_data_filename = "", - const std::string & density_filename = ""); + explicit inline ReconstructionTests(const std::string& proj_data_filename = "", const std::string& density_filename = ""); virtual ~ReconstructionTests() {} @@ -71,86 +68,64 @@ class ReconstructionTests : public RunTests std::string _input_density_filename; shared_ptr _proj_data_sptr; shared_ptr _input_density_sptr; - shared_ptr > _recon_sptr; + shared_ptr> _recon_sptr; }; template -ReconstructionTests:: -ReconstructionTests(const std::string &proj_data_filename, - const std::string & density_filename) : - _proj_data_filename(proj_data_filename), - _input_density_filename(density_filename) -{ -} - +ReconstructionTests::ReconstructionTests(const std::string& proj_data_filename, const std::string& density_filename) + : _proj_data_filename(proj_data_filename), _input_density_filename(density_filename) {} template void -ReconstructionTests:: -construct_input_data() -{ +ReconstructionTests::construct_input_data() { Verbosity::set(1); - if (this->_proj_data_filename.empty()) - { - // construct a small scanner and sinogram - shared_ptr scanner_sptr(new Scanner(Scanner::E953)); - scanner_sptr->set_num_rings(5); - shared_ptr proj_data_info_sptr( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/3, - /*max_delta=*/4, - /*num_views=*/128, - /*num_tang_poss=*/128)); - shared_ptr exam_info_sptr(new ExamInfo); - exam_info_sptr->imaging_modality = ImagingModality::PT; - _proj_data_sptr.reset(new ProjDataInMemory (exam_info_sptr, proj_data_info_sptr)); - std::cerr << "Will run tests with projection data with the following settings:\n" - << proj_data_info_sptr->parameter_info(); - } - else - { - shared_ptr proj_data_sptr = - ProjData::read_from_file(this->_proj_data_filename); - _proj_data_sptr.reset(new ProjDataInMemory (*proj_data_sptr)); - } - - if (this->_input_density_filename.empty()) - { - CartesianCoordinate3D origin (0,0,0); - const float zoom=.7F; - - shared_ptr > - vox_sptr(new VoxelsOnCartesianGrid(this->_proj_data_sptr->get_exam_info_sptr(), - *this->_proj_data_sptr->get_proj_data_info_sptr(), - zoom,origin)); - - // create very long cylinder, such that we don't have to think about origin - EllipsoidalCylinder cylinder(/*length_z*/1000.F, - /*radius_y*/100.F, - /*radius_x*/90.F, - CartesianCoordinate3D(0.F,0.F,0.F)); - cylinder.construct_volume(*vox_sptr, CartesianCoordinate3D(2,2,2)); - - // filter it a bit to avoid too high frequency stuff creating trouble in the comparison - SeparableGaussianImageFilter filter; - filter.set_fwhms(make_coordinate(10.F,10.F,10.F)); - filter.set_up(*vox_sptr); - filter.apply(*vox_sptr); - this->_input_density_sptr = vox_sptr; - } - else - { - shared_ptr aptr(read_from_file(this->_input_density_filename)); - this->_input_density_sptr = aptr; - } + if (this->_proj_data_filename.empty()) { + // construct a small scanner and sinogram + shared_ptr scanner_sptr(new Scanner(Scanner::E953)); + scanner_sptr->set_num_rings(5); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/3, + /*max_delta=*/4, + /*num_views=*/128, + /*num_tang_poss=*/128)); + shared_ptr exam_info_sptr(new ExamInfo); + exam_info_sptr->imaging_modality = ImagingModality::PT; + _proj_data_sptr.reset(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr)); + std::cerr << "Will run tests with projection data with the following settings:\n" << proj_data_info_sptr->parameter_info(); + } else { + shared_ptr proj_data_sptr = ProjData::read_from_file(this->_proj_data_filename); + _proj_data_sptr.reset(new ProjDataInMemory(*proj_data_sptr)); + } + + if (this->_input_density_filename.empty()) { + CartesianCoordinate3D origin(0, 0, 0); + const float zoom = .7F; + + shared_ptr> vox_sptr(new VoxelsOnCartesianGrid( + this->_proj_data_sptr->get_exam_info_sptr(), *this->_proj_data_sptr->get_proj_data_info_sptr(), zoom, origin)); + + // create very long cylinder, such that we don't have to think about origin + EllipsoidalCylinder cylinder(/*length_z*/ 1000.F, + /*radius_y*/ 100.F, + /*radius_x*/ 90.F, CartesianCoordinate3D(0.F, 0.F, 0.F)); + cylinder.construct_volume(*vox_sptr, CartesianCoordinate3D(2, 2, 2)); + + // filter it a bit to avoid too high frequency stuff creating trouble in the comparison + SeparableGaussianImageFilter filter; + filter.set_fwhms(make_coordinate(10.F, 10.F, 10.F)); + filter.set_up(*vox_sptr); + filter.apply(*vox_sptr); + this->_input_density_sptr = vox_sptr; + } else { + shared_ptr aptr(read_from_file(this->_input_density_filename)); + this->_input_density_sptr = aptr; + } // forward project { - shared_ptr PM_sptr(new ProjMatrixByBinUsingRayTracing); - shared_ptr fwd_proj_sptr = - MAKE_SHARED(PM_sptr); - fwd_proj_sptr->set_up(this->_proj_data_sptr->get_proj_data_info_sptr(), - this->_input_density_sptr); + shared_ptr PM_sptr(new ProjMatrixByBinUsingRayTracing); + shared_ptr fwd_proj_sptr = MAKE_SHARED(PM_sptr); + fwd_proj_sptr->set_up(this->_proj_data_sptr->get_proj_data_info_sptr(), this->_input_density_sptr); fwd_proj_sptr->set_input(*this->_input_density_sptr); fwd_proj_sptr->forward_project(*this->_proj_data_sptr); } @@ -158,31 +133,24 @@ construct_input_data() template void -ReconstructionTests:: -reconstruct(shared_ptr target_sptr) -{ +ReconstructionTests::reconstruct(shared_ptr target_sptr) { this->_recon_sptr->set_input_data(this->_proj_data_sptr); this->_recon_sptr->set_disable_output(true); // set a prefix anyway, as some reconstruction algorithms write some files even with disabled output this->_recon_sptr->set_output_filename_prefix("test_recon_" + this->_recon_sptr->method_info()); - if (this->_recon_sptr->set_up(target_sptr)==Succeeded::no) + if (this->_recon_sptr->set_up(target_sptr) == Succeeded::no) error("recon::set_up() failed"); - - if (this->_recon_sptr->reconstruct(target_sptr)==Succeeded::no) + + if (this->_recon_sptr->reconstruct(target_sptr) == Succeeded::no) error("recon::reconstruct() failed"); - std::cerr << "\n================================\nReconstruction " - << this->_recon_sptr->method_info() - << " finished!\n\n"; + std::cerr << "\n================================\nReconstruction " << this->_recon_sptr->method_info() << " finished!\n\n"; } template void -ReconstructionTests:: -compare(const shared_ptr output_sptr) -{ - if (!check(this->_input_density_sptr->has_same_characteristics(*output_sptr), - "output image has wrong characteristics")) +ReconstructionTests::compare(const shared_ptr output_sptr) { + if (!check(this->_input_density_sptr->has_same_characteristics(*output_sptr), "output image has wrong characteristics")) return; shared_ptr diff_sptr(output_sptr->clone()); @@ -191,19 +159,18 @@ compare(const shared_ptr output_sptr) const float diff_max = diff_sptr->find_max(); const float max_input = this->_input_density_sptr->find_max(); in_place_abs(*diff_sptr); - const float mean_abs_error=diff_sptr->sum() / this->_input_density_sptr->size_all(); + const float mean_abs_error = diff_sptr->sum() / this->_input_density_sptr->size_all(); std::cerr << "Reconstruction diff relative range: " - << "[" << diff_min/max_input << ", " << diff_max/max_input << "]\n" - << "mean abs diff normalised was " << mean_abs_error/max_input << "\n"; - if (!check_if_less(-0.3F, diff_min/max_input, "relative diff min") || - !check_if_less(diff_max/max_input, .3F, "relative diff max") || - !check_if_less(mean_abs_error/max_input, .01F, "relative mean abs diff")) - { - const std::string prefix = "test_recon_" + this->_recon_sptr->method_info(); - write_to_file(prefix + "_output.hv", *output_sptr); - write_to_file(prefix + "_original.hv", *this->_input_density_sptr); - write_to_file(prefix + "_diff.hv", *diff_sptr); - } + << "[" << diff_min / max_input << ", " << diff_max / max_input << "]\n" + << "mean abs diff normalised was " << mean_abs_error / max_input << "\n"; + if (!check_if_less(-0.3F, diff_min / max_input, "relative diff min") || + !check_if_less(diff_max / max_input, .3F, "relative diff max") || + !check_if_less(mean_abs_error / max_input, .01F, "relative mean abs diff")) { + const std::string prefix = "test_recon_" + this->_recon_sptr->method_info(); + write_to_file(prefix + "_output.hv", *output_sptr); + write_to_file(prefix + "_original.hv", *this->_input_density_sptr); + write_to_file(prefix + "_diff.hv", *diff_sptr); + } } END_NAMESPACE_STIR diff --git a/src/include/stir/round.h b/src/include/stir/round.h index c3e9c44c53..247d27499b 100644 --- a/src/include/stir/round.h +++ b/src/include/stir/round.h @@ -21,12 +21,12 @@ /*! \file \ingroup buildblock - + \brief Declaration of the stir::round functions - + \author Kris Thielemans \author Charalampos Tsoumpas - + */ #include "stir/BasicCoordinate.h" @@ -35,26 +35,26 @@ START_NAMESPACE_STIR \ingroup buildblock \name Functions for rounding floating point numbers */ - //@{ +//@{ //! Implements rounding of floating point numbers /*! - - round() has the property that + + round() has the property that \code round(x) == -round(-x) \endcode - The usual (int)(x+.5) has machine dependent behaviour for + The usual (int)(x+.5) has machine dependent behaviour for negative numbers. .5 is rounded to 1 (and hence -.5 to -1). - \warning There is no check on overflow (i.e. if \a x is too + \warning There is no check on overflow (i.e. if \a x is too large to fit in an \c int). */ inline int round(const float x); //! Implements rounding of double numbers -/*! +/*! \see round(const float) */ inline int round(const double x); @@ -64,9 +64,7 @@ inline int round(const double x); \see round(const float) */ template -inline BasicCoordinate -round(const BasicCoordinate& x); - +inline BasicCoordinate round(const BasicCoordinate& x); //! Implements rounding of floating point numbers to other integer types /*! @@ -80,16 +78,13 @@ round(const BasicCoordinate& x); \todo add code to check that \c integerT is really an integer type at compilation time */ template -inline void -round_to(integerT& result, const float x); +inline void round_to(integerT& result, const float x); //! Implements rounding of a BasicCoordinate object to other integer types /*! \see round_to(integerT, float) */ template -inline void -round_to(BasicCoordinate& result, - const BasicCoordinate& x); +inline void round_to(BasicCoordinate& result, const BasicCoordinate& x); //@} diff --git a/src/include/stir/round.inl b/src/include/stir/round.inl index 7a7da9f5ed..a7a391aac5 100644 --- a/src/include/stir/round.inl +++ b/src/include/stir/round.inl @@ -3,12 +3,12 @@ /*! \file \ingroup buildblock - + \brief Implementation of the stir::round functions - + \author Kris Thielemans \author Charalampos Tsoumpas - + */ /* Copyright (C) 2000- 2010, Hammersmith Imanet Ltd @@ -31,73 +31,64 @@ START_NAMESPACE_STIR template inline void -round_to(integerT& result, const float x) -{ - if (x>=0) - result = static_cast(x+0.5F); +round_to(integerT& result, const float x) { + if (x >= 0) + result = static_cast(x + 0.5F); else - result = -static_cast(-x+0.5F); + result = -static_cast(-x + 0.5F); } - template inline void -round_to(integerT& result, const double x) -{ - if (x>=0) - result = static_cast(x+0.5); +round_to(integerT& result, const double x) { + if (x >= 0) + result = static_cast(x + 0.5); else - result = -static_cast(-x+0.5); + result = -static_cast(-x + 0.5); } /* next 2 are just to avoid compiler warnings about using - on an unsigned type */ inline void -round_to(unsigned& result, const double x) -{ - result = static_cast(x+0.5); +round_to(unsigned& result, const double x) { + result = static_cast(x + 0.5); } inline void -round_to(unsigned long& result, const double x) -{ - result = static_cast(x+0.5); +round_to(unsigned long& result, const double x) { + result = static_cast(x + 0.5); } /* could be implemented in terms of the above */ -int round(const float x) -{ - if (x>=0) - return static_cast(x+0.5F); +int +round(const float x) { + if (x >= 0) + return static_cast(x + 0.5F); else - return -static_cast(-x+0.5F); + return -static_cast(-x + 0.5F); } -int round(const double x) -{ - if (x>=0) - return static_cast(x+0.5); +int +round(const double x) { + if (x >= 0) + return static_cast(x + 0.5); else - return -static_cast(-x+0.5); + return -static_cast(-x + 0.5); } template -BasicCoordinate -round(const BasicCoordinate& x) -{ - BasicCoordinate rnd_x; - for(int i=1;i<=num_dimensions;++i) - rnd_x[i]=round(x[i]); - return rnd_x; +BasicCoordinate +round(const BasicCoordinate& x) { + BasicCoordinate rnd_x; + for (int i = 1; i <= num_dimensions; ++i) + rnd_x[i] = round(x[i]); + return rnd_x; } template -inline void -round_to(BasicCoordinate& result, - const BasicCoordinate& x) -{ - for(int i=1;i<=num_dimensions;++i) - round_to(result[i], x[i]); +inline void +round_to(BasicCoordinate& result, const BasicCoordinate& x) { + for (int i = 1; i <= num_dimensions; ++i) + round_to(result[i], x[i]); } END_NAMESPACE_STIR - diff --git a/src/include/stir/scale_sinograms.h b/src/include/stir/scale_sinograms.h index 1f8a772fbb..2c1a517151 100644 --- a/src/include/stir/scale_sinograms.h +++ b/src/include/stir/scale_sinograms.h @@ -20,7 +20,7 @@ \file \ingroup projdata \brief declaration of stir::scale_sinograms and stir::get_scale_factors_per_sinogram - + \author Charalampos Tsoumpas \author Kris Thielemans @@ -39,9 +39,8 @@ class Succeeded; corresponds to segments, the second to axial positions. \return indicates if writing failed or not */ -Succeeded scale_sinograms(ProjData& output_proj_data, - const ProjData& input_proj_data, - const Array<2,float> scale_factors_per_sinogram); +Succeeded scale_sinograms(ProjData& output_proj_data, const ProjData& input_proj_data, + const Array<2, float> scale_factors_per_sinogram); //! find scale factors between two different sinograms /*! \ingroup projdata @@ -59,9 +58,7 @@ Succeeded scale_sinograms(ProjData& output_proj_data, Currently this function sets the scale factor or a sinogram to 1 (and calls warning()) when the denominator gets too small. */ -Array<2,float> - get_scale_factors_per_sinogram(const ProjData& numerator_proj_data, - const ProjData& denominator_proj_data, - const ProjData& weights_proj_data); +Array<2, float> get_scale_factors_per_sinogram(const ProjData& numerator_proj_data, const ProjData& denominator_proj_data, + const ProjData& weights_proj_data); END_NAMESPACE_STIR diff --git a/src/include/stir/scatter/CreateTailMaskFromACFs.h b/src/include/stir/scatter/CreateTailMaskFromACFs.h index 323c898d73..5bca595108 100644 --- a/src/include/stir/scatter/CreateTailMaskFromACFs.h +++ b/src/include/stir/scatter/CreateTailMaskFromACFs.h @@ -51,7 +51,6 @@ #include "stir/Succeeded.h" #include "stir/is_null_ptr.h" - #include "stir/ParsingObject.h" #include "stir/ProjDataInMemory.h" @@ -63,65 +62,64 @@ START_NAMESPACE_STIR //! \details This class implements the functionality of the executable. //! It was nessesary in order to be able to perform this calculations from //! the ScatterEstimationByBin. -class CreateTailMaskFromACFs : public ParsingObject -{ +class CreateTailMaskFromACFs : public ParsingObject { public: - CreateTailMaskFromACFs(); + CreateTailMaskFromACFs(); - virtual Succeeded process_data(); + virtual Succeeded process_data(); - void set_input_projdata_sptr(shared_ptr &); + void set_input_projdata_sptr(shared_ptr&); - void set_input_projdata(std::string&); + void set_input_projdata(std::string&); - void set_output_projdata_sptr(shared_ptr&); + void set_output_projdata_sptr(shared_ptr&); - void set_output_projdata(std::string&); + void set_output_projdata(std::string&); - //! - //! \brief get_output_projdata - //! \return - //! \details Use this function to return the output - //! projdata. - shared_ptr get_output_projdata_sptr(); + //! + //! \brief get_output_projdata + //! \return + //! \details Use this function to return the output + //! projdata. + shared_ptr get_output_projdata_sptr(); - //! - //! \brief ACF_threshold - //! \warning ACF-threshold defaults to 1.1 (should be larger than 1) - float ACF_threshold; + //! + //! \brief ACF_threshold + //! \warning ACF-threshold defaults to 1.1 (should be larger than 1) + float ACF_threshold; - //! - //! \brief safety_margin - //! - int safety_margin; + //! + //! \brief safety_margin + //! + int safety_margin; protected: - void initialise_keymap(); - bool post_processing(); - void set_defaults(); + void initialise_keymap(); + bool post_processing(); + void set_defaults(); private: - //! - //! \brief ACF_sptr - //! \details Input projdata - shared_ptr ACF_sptr; - - //! - //! \brief mask_proj_data - //! \details Output projdata - shared_ptr mask_proj_data; - - //! - //! \brief _input_filename - //! \details The input filename can be omitted in the par file - //! but has to be set, later, using the set_input_projdata(). - std::string _input_filename; - - //! - //! \brief _output_filename - //! \details This is the output filename. - //! It can be omited, if an output is not nessesary. - std::string _output_filename; + //! + //! \brief ACF_sptr + //! \details Input projdata + shared_ptr ACF_sptr; + + //! + //! \brief mask_proj_data + //! \details Output projdata + shared_ptr mask_proj_data; + + //! + //! \brief _input_filename + //! \details The input filename can be omitted in the par file + //! but has to be set, later, using the set_input_projdata(). + std::string _input_filename; + + //! + //! \brief _output_filename + //! \details This is the output filename. + //! It can be omited, if an output is not nessesary. + std::string _output_filename; }; END_NAMESPACE_STIR diff --git a/src/include/stir/scatter/ScatterEstimation.h b/src/include/stir/scatter/ScatterEstimation.h index 6a16eeff15..5eed3c3999 100644 --- a/src/include/stir/scatter/ScatterEstimation.h +++ b/src/include/stir/scatter/ScatterEstimation.h @@ -23,7 +23,7 @@ \file \ingroup scatter \brief Definition of class stir::ScatterEstimation. - + \author Nikos Efthimiou \author Kris Thielemans */ @@ -46,17 +46,17 @@ START_NAMESPACE_STIR -template class PostFiltering; +template +class PostFiltering; class BinNormalisation; //! A struct to hold the parameters for image masking. -struct MaskingParameters -{ +struct MaskingParameters { float min_threshold; //! filter parameter file to be used in mask calculation std::string filter_filename; //! filter to apply before thresholding - shared_ptr > > filter_sptr; + shared_ptr>> filter_sptr; }; /*! @@ -85,298 +85,284 @@ struct MaskingParameters (Ensuring backwards compatibility was not so easy, so the code might look confusing.) */ -class ScatterEstimation: public ParsingObject -{ +class ScatterEstimation : public ParsingObject { public: - //! upsample coarse scatter estimate and fit it to tails of the emission data - /*! Current procedure: - 1. interpolate segment 0 of \a scatter_proj_data to size of segment 0 of \a emission_proj_data - 2. inverseSSRB to create oblique segments - 3. undo normalisation (as measured data is not normalised) - 4. find scale factors with get_scale_factors_per_sinogram() - 5. apply thresholds - 6. filter scale-factors in axial direction (independently for every segment) - 7. apply scale factors using scale_sinograms() - */ - static void - upsample_and_fit_scatter_estimate(ProjData& scaled_scatter_proj_data, - const ProjData& emission_proj_data, - const ProjData& scatter_proj_data, - BinNormalisation& scatter_normalisation, - const ProjData& weights_proj_data, - const float min_scale_factor, - const float max_scale_factor, - const unsigned half_filter_width, - BSpline::BSplineType spline_type, - const bool remove_interleaving = true); - - - //! Default constructor (calls set_defaults()) - ScatterEstimation(); - //! Overloaded constructor with parameter file and initialisation - explicit ScatterEstimation(const std::string& parameter_filename); - - //! Full process_data which performs set_up() before beginning - virtual Succeeded process_data(); - - //! Get current scatter estimate - shared_ptr get_output() const; - - //! - //! \brief set_up - //! \return - //! \details This function will take care most of the initialisation needed: - //!
      - //!
    • Procedure: - //!
        - //!
      1. Check if debug mode and activate all export flags. - //!
      2. Load the input_projdata_3d_sptr and perform SSRB - //!
      3. Initialise (partially for the moment) the reconstruction method: - //!
      4. Load Normalisation data and perform SSRB - //!
      5. Load the background data (randoms) and do normalisation (to get the additive data) - //!
      - //!
    - virtual Succeeded set_up(); - - // Set functions - //! Set the input projdata. - inline void set_input_proj_data_sptr(const shared_ptr); - //! Set the input projdata - /*! Using same name as Reconstruction */ + //! upsample coarse scatter estimate and fit it to tails of the emission data + /*! Current procedure: + 1. interpolate segment 0 of \a scatter_proj_data to size of segment 0 of \a emission_proj_data + 2. inverseSSRB to create oblique segments + 3. undo normalisation (as measured data is not normalised) + 4. find scale factors with get_scale_factors_per_sinogram() + 5. apply thresholds + 6. filter scale-factors in axial direction (independently for every segment) + 7. apply scale factors using scale_sinograms() +*/ + static void upsample_and_fit_scatter_estimate(ProjData& scaled_scatter_proj_data, const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, BinNormalisation& scatter_normalisation, + const ProjData& weights_proj_data, const float min_scale_factor, + const float max_scale_factor, const unsigned half_filter_width, + BSpline::BSplineType spline_type, const bool remove_interleaving = true); + + //! Default constructor (calls set_defaults()) + ScatterEstimation(); + //! Overloaded constructor with parameter file and initialisation + explicit ScatterEstimation(const std::string& parameter_filename); + + //! Full process_data which performs set_up() before beginning + virtual Succeeded process_data(); + + //! Get current scatter estimate + shared_ptr get_output() const; + + //! + //! \brief set_up + //! \return + //! \details This function will take care most of the initialisation needed: + //!
      + //!
    • Procedure: + //!
        + //!
      1. Check if debug mode and activate all export flags. + //!
      2. Load the input_projdata_3d_sptr and perform SSRB + //!
      3. Initialise (partially for the moment) the reconstruction method: + //!
      4. Load Normalisation data and perform SSRB + //!
      5. Load the background data (randoms) and do normalisation (to get the additive data) + //!
      + //!
    + virtual Succeeded set_up(); + + // Set functions + //! Set the input projdata. + inline void set_input_proj_data_sptr(const shared_ptr); + //! Set the input projdata + /*! Using same name as Reconstruction */ #if STIR_VERSION < 050000 - void set_input_data(const shared_ptr& data); + void set_input_data(const shared_ptr& data); #else - void set_input_data(const shared_ptr& data); + void set_input_data(const shared_ptr& data); #endif - shared_ptr get_input_data() const; - - //! Set the reconstruction method for the scatter estimation - inline void set_reconstruction_method_sptr(const shared_ptr > >); - //! Set the full resolution attenuation image. - inline void set_attenuation_image_sptr(const shared_ptr > ); - //! set projection data that contains the attenuation correction factors - void set_attenuation_correction_proj_data_sptr(const shared_ptr); - //! set normalisation object (excluding attenuation) - void set_normalisation_sptr(const shared_ptr); - //! - inline void set_background_proj_data_sptr(const shared_ptr); - //! - inline void set_initial_activity_image_sptr(const shared_ptr >); - - inline void set_mask_image_sptr(const shared_ptr >); - //! set mask for tail-fitting - /*! \c arg will not be modified */ - inline void set_mask_proj_data_sptr(const shared_ptr arg); - - inline void set_scatter_simulation_method_sptr(const shared_ptr); - - inline void set_num_iterations(int); - - void set_output_scatter_estimate_prefix(const std::string&); - void set_export_scatter_estimates_of_each_iteration(bool); - - //! Set the zoom factor in the XY plane for the downsampling of the activity and attenuation image. - inline void set_zoom_xy(float); - //! Set the zoom factor in the Z axis for the downsampling of the activity and attenuation image. - inline void set_zoom_z(float); - - - // Get functions - //! Get the number of iterations for the scatter estimation - /*! \deprecated Use get_num_iterations() */ - int get_iterations_num() const; - - //! Get the number of iterations for the scatter estimation - int get_num_iterations() const; - - //! Get the (low resolution) estimate of the activity image - shared_ptr > get_estimated_activity_image_sptr() const; - - //! allows checking if we have called set_up() - virtual bool already_setup() const; - - protected: - //! All recomputes_** will default true - virtual void set_defaults(); - virtual void initialise_keymap(); - virtual bool post_processing(); - - //! Recompute or load the mask image. - bool recompute_mask_image; - //! If set the mask projdata will be recomputed - bool recompute_mask_projdata; - //! If set to 1 the attenuation coefficients are going to - //! be recalculated. - bool recompute_atten_projdata; - - //! This is the reconstruction object which is going to be used for the scatter estimation - //! and the calculation of the initial activity image (if recompute set). It can be defined in the same - //! parameters file as the scatter parameters or in an external defined in the - //! reconstruction_template_par_filename - shared_ptr < Reconstruction < DiscretisedDensity < 3, float > > > - reconstruction_template_sptr; - //! The current activity estimate. - shared_ptr > current_activity_image_sptr; - //! Image with attenuation values. - shared_ptr > atten_image_sptr; - //! normalisation components in 3D (without atten) - shared_ptr norm_3d_sptr; - //! Mask proj_data - shared_ptr mask_projdata_sptr; - //! The full 3D projdata are used for the calculation of the 2D - //! and later for the upsampling back to 3D. - shared_ptr input_projdata_sptr; - //! The 2D projdata are used for the scatter estimation. - shared_ptr input_projdata_2d_sptr; - //! Additive projection data after SSRB -- Randoms - shared_ptr add_projdata_2d_sptr; - //! Prompts - randoms - shared_ptr data_to_fit_projdata_sptr; - - shared_ptr add_projdata_sptr; - //! (Additive + Scatter Estimate) * Mult in 2D - shared_ptr back_projdata_2d_sptr; - //! Initially this points to the un-normalised randoms. - shared_ptr back_projdata_sptr; - //! Filename of mask image - std::string mask_image_filename; - //! Filename of mask's projdata - std::string mask_projdata_filename; - //! Filename of background projdata - std::string back_projdata_filename; - //! Optional parameter file for the tail fitting. - /*! If not provided, sensible defaults are used */ - std::string tail_mask_par_filename; - //! Filename of the measured emission 3D data. - std::string input_projdata_filename; - //! This is the image file name with the anatomic information. - std::string atten_image_filename; - //! The filename for the parameters file of the reconstruction method. - std::string recon_template_par_filename; - //! The file name for the attenuation coefficients. - //! If they are to be recalculated they will be stored here, if set. - std::string atten_coeff_filename; - - //! \details the set of parameters to obtain a mask from the attenuation image - /*! The attenuation image will be thresholded to find a plausible mask for where there - can be emission data. This mask will be then forward projected to find the tails in the projection data. - - This is a simple strategy that can fail due to motion etc, so the attenuation image is first blurred, - and the default threshold is low. - - Note that there is currently no attempt to eliminate the bed from the attenuation image first. - Tails are therefore going to be too small, which could create trouble. - - By default, a Gaussian filter of FWHM (15,20,20) will be applied before thresholding with a value 0.003 cm^-1 - */ - MaskingParameters masking_parameters; - //! \details The number of iterations the scatter estimation will perform. - //! Default = 5. - int num_scatter_iterations; - //! Output file name prefix - std::string output_scatter_estimate_prefix; - - std::string output_additive_estimate_prefix; + shared_ptr get_input_data() const; + + //! Set the reconstruction method for the scatter estimation + inline void set_reconstruction_method_sptr(const shared_ptr>>); + //! Set the full resolution attenuation image. + inline void set_attenuation_image_sptr(const shared_ptr>); + //! set projection data that contains the attenuation correction factors + void set_attenuation_correction_proj_data_sptr(const shared_ptr); + //! set normalisation object (excluding attenuation) + void set_normalisation_sptr(const shared_ptr); + //! + inline void set_background_proj_data_sptr(const shared_ptr); + //! + inline void set_initial_activity_image_sptr(const shared_ptr>); + + inline void set_mask_image_sptr(const shared_ptr>); + //! set mask for tail-fitting + /*! \c arg will not be modified */ + inline void set_mask_proj_data_sptr(const shared_ptr arg); + + inline void set_scatter_simulation_method_sptr(const shared_ptr); + + inline void set_num_iterations(int); + + void set_output_scatter_estimate_prefix(const std::string&); + void set_export_scatter_estimates_of_each_iteration(bool); + + //! Set the zoom factor in the XY plane for the downsampling of the activity and attenuation image. + inline void set_zoom_xy(float); + //! Set the zoom factor in the Z axis for the downsampling of the activity and attenuation image. + inline void set_zoom_z(float); + + // Get functions + //! Get the number of iterations for the scatter estimation + /*! \deprecated Use get_num_iterations() */ + int get_iterations_num() const; + + //! Get the number of iterations for the scatter estimation + int get_num_iterations() const; + + //! Get the (low resolution) estimate of the activity image + shared_ptr> get_estimated_activity_image_sptr() const; + + //! allows checking if we have called set_up() + virtual bool already_setup() const; + +protected: + //! All recomputes_** will default true + virtual void set_defaults(); + virtual void initialise_keymap(); + virtual bool post_processing(); + + //! Recompute or load the mask image. + bool recompute_mask_image; + //! If set the mask projdata will be recomputed + bool recompute_mask_projdata; + //! If set to 1 the attenuation coefficients are going to + //! be recalculated. + bool recompute_atten_projdata; + + //! This is the reconstruction object which is going to be used for the scatter estimation + //! and the calculation of the initial activity image (if recompute set). It can be defined in the same + //! parameters file as the scatter parameters or in an external defined in the + //! reconstruction_template_par_filename + shared_ptr>> reconstruction_template_sptr; + //! The current activity estimate. + shared_ptr> current_activity_image_sptr; + //! Image with attenuation values. + shared_ptr> atten_image_sptr; + //! normalisation components in 3D (without atten) + shared_ptr norm_3d_sptr; + //! Mask proj_data + shared_ptr mask_projdata_sptr; + //! The full 3D projdata are used for the calculation of the 2D + //! and later for the upsampling back to 3D. + shared_ptr input_projdata_sptr; + //! The 2D projdata are used for the scatter estimation. + shared_ptr input_projdata_2d_sptr; + //! Additive projection data after SSRB -- Randoms + shared_ptr add_projdata_2d_sptr; + //! Prompts - randoms + shared_ptr data_to_fit_projdata_sptr; + + shared_ptr add_projdata_sptr; + //! (Additive + Scatter Estimate) * Mult in 2D + shared_ptr back_projdata_2d_sptr; + //! Initially this points to the un-normalised randoms. + shared_ptr back_projdata_sptr; + //! Filename of mask image + std::string mask_image_filename; + //! Filename of mask's projdata + std::string mask_projdata_filename; + //! Filename of background projdata + std::string back_projdata_filename; + //! Optional parameter file for the tail fitting. + /*! If not provided, sensible defaults are used */ + std::string tail_mask_par_filename; + //! Filename of the measured emission 3D data. + std::string input_projdata_filename; + //! This is the image file name with the anatomic information. + std::string atten_image_filename; + //! The filename for the parameters file of the reconstruction method. + std::string recon_template_par_filename; + //! The file name for the attenuation coefficients. + //! If they are to be recalculated they will be stored here, if set. + std::string atten_coeff_filename; + + //! \details the set of parameters to obtain a mask from the attenuation image + /*! The attenuation image will be thresholded to find a plausible mask for where there + can be emission data. This mask will be then forward projected to find the tails in the projection data. + + This is a simple strategy that can fail due to motion etc, so the attenuation image is first blurred, + and the default threshold is low. + + Note that there is currently no attempt to eliminate the bed from the attenuation image first. + Tails are therefore going to be too small, which could create trouble. + + By default, a Gaussian filter of FWHM (15,20,20) will be applied before thresholding with a value 0.003 cm^-1 + */ + MaskingParameters masking_parameters; + //! \details The number of iterations the scatter estimation will perform. + //! Default = 5. + int num_scatter_iterations; + //! Output file name prefix + std::string output_scatter_estimate_prefix; + + std::string output_additive_estimate_prefix; private: - //! variable to check if we have called set_up() - bool _already_setup; - - //! attenuation in 3D - shared_ptr atten_norm_3d_sptr; - - //! ((1/SSRB(1/norm3D)) * SSRB(atten)). - /*! Created such that the first term is the norm and second the atten */ - shared_ptr multiplicative_binnorm_2d_sptr; - - //! (norm * atten) in 3D. - /*! Created such that the first term is the norm and second the atten */ - shared_ptr multiplicative_binnorm_sptr; - - //! variable for storing current scatter estimate - shared_ptr scatter_estimate_sptr; - - //! variable storing the mask image - shared_ptr < const DiscretisedDensity < 3, float > > mask_image_sptr; - - //! \brief set_up iterative reconstruction - Succeeded set_up_iterative(shared_ptr > > arg); - - //! \brief set_up analytic reconstruction - Succeeded set_up_analytic(); - - //! \details A helper function to reduce the size of set_up(). - Succeeded project_mask_image(); - - //! reconstruct image with current scatter estimate (iteratively) - /*! \a scat_iter is used for determining the filename for saving */ - void reconstruct_iterative(int scat_iter, shared_ptr >& output_sptr); - - //! reconstruct image with current scatter estimate (analytic reconstruction) - /*! \a scat_iter is used for determining the filename for saving */ - void reconstruct_analytic(int scat_iter, shared_ptr > & output_sptr); - - //! \details Find a mask by thresholding etc - static void apply_mask_in_place(DiscretisedDensity<3, float> &, - const MaskingParameters&); - - void add_proj_data(ProjData&, const ProjData&); - - void subtract_proj_data(ProjData&, const ProjData&); - - void apply_to_proj_data(ProjData& , const pow_times_add&); - - //! Create combined norm from norm and atten - void create_multiplicative_binnorm_sptr(); - - //! extract the normalisation component of a combined norm - shared_ptr - get_normalisation_object_sptr(const shared_ptr& combined_norm_sptr) const; - - //! extract the attenuation factors from a combined norm - shared_ptr - get_attenuation_correction_factors_sptr(const shared_ptr& combined_norm_sptr) const; - - //! Returns a shared pointer to a new ProjData. If we run in run_debug_mode and - //! the extras_path has been set, then it will be a ProjDataInterfile, otherwise it will be a ProjDataInMemory. - shared_ptr create_new_proj_data(const std::string& filename, - const shared_ptr exam_info_sptr, - const shared_ptr proj_data_info_sptr) const; - - //! \details Average the two first activity images 0 and 1 (defaults to \c true) - bool do_average_at_2; - //! for upsampling (defaults to \c true) - bool remove_interleaving; - //! Save all scatter simulated sinograms - bool export_scatter_estimates_of_each_iteration; - //! Run the process in 2D by SSRB the 3D sinograms - bool run_in_2d_projdata; - //! This bool will allow the ScatterEstimation to override the value of - //! the density image set in ScatterSimulation par file (defaults to \c true) - bool override_density_image; - //! This will over-ride the scanner template in scatter sinogram simulation (defaults to \c true) - bool override_scanner_template; - //! In debug mode a lot of extra files are going to be saved in the disk. - bool run_debug_mode; - //! Parameter file for scatter simulation - //! \warning Values in this file could be overridden. - std::string scatter_sim_par_filename; - //! \details Class which will implement the scatter simulation. - shared_ptr < ScatterSimulation > scatter_simulation_sptr; - //! This path is used in the debug mode to store all the intermediate files, as they are many. - FilePath extras_path; - - //! Default value = 100 - float max_scale_value; - //! Default value = 0.4 - float min_scale_value; - - bool downsample_scanner_bool; - //! - unsigned int half_filter_width; - - //! \details internal variable set to \c true when using iterative reconstruction - bool iterative_method; + //! variable to check if we have called set_up() + bool _already_setup; + + //! attenuation in 3D + shared_ptr atten_norm_3d_sptr; + + //! ((1/SSRB(1/norm3D)) * SSRB(atten)). + /*! Created such that the first term is the norm and second the atten */ + shared_ptr multiplicative_binnorm_2d_sptr; + + //! (norm * atten) in 3D. + /*! Created such that the first term is the norm and second the atten */ + shared_ptr multiplicative_binnorm_sptr; + + //! variable for storing current scatter estimate + shared_ptr scatter_estimate_sptr; + + //! variable storing the mask image + shared_ptr> mask_image_sptr; + + //! \brief set_up iterative reconstruction + Succeeded set_up_iterative(shared_ptr>> arg); + + //! \brief set_up analytic reconstruction + Succeeded set_up_analytic(); + + //! \details A helper function to reduce the size of set_up(). + Succeeded project_mask_image(); + + //! reconstruct image with current scatter estimate (iteratively) + /*! \a scat_iter is used for determining the filename for saving */ + void reconstruct_iterative(int scat_iter, shared_ptr>& output_sptr); + + //! reconstruct image with current scatter estimate (analytic reconstruction) + /*! \a scat_iter is used for determining the filename for saving */ + void reconstruct_analytic(int scat_iter, shared_ptr>& output_sptr); + + //! \details Find a mask by thresholding etc + static void apply_mask_in_place(DiscretisedDensity<3, float>&, const MaskingParameters&); + + void add_proj_data(ProjData&, const ProjData&); + + void subtract_proj_data(ProjData&, const ProjData&); + + void apply_to_proj_data(ProjData&, const pow_times_add&); + + //! Create combined norm from norm and atten + void create_multiplicative_binnorm_sptr(); + + //! extract the normalisation component of a combined norm + shared_ptr get_normalisation_object_sptr(const shared_ptr& combined_norm_sptr) const; + + //! extract the attenuation factors from a combined norm + shared_ptr get_attenuation_correction_factors_sptr(const shared_ptr& combined_norm_sptr) const; + + //! Returns a shared pointer to a new ProjData. If we run in run_debug_mode and + //! the extras_path has been set, then it will be a ProjDataInterfile, otherwise it will be a ProjDataInMemory. + shared_ptr create_new_proj_data(const std::string& filename, const shared_ptr exam_info_sptr, + const shared_ptr proj_data_info_sptr) const; + + //! \details Average the two first activity images 0 and 1 (defaults to \c true) + bool do_average_at_2; + //! for upsampling (defaults to \c true) + bool remove_interleaving; + //! Save all scatter simulated sinograms + bool export_scatter_estimates_of_each_iteration; + //! Run the process in 2D by SSRB the 3D sinograms + bool run_in_2d_projdata; + //! This bool will allow the ScatterEstimation to override the value of + //! the density image set in ScatterSimulation par file (defaults to \c true) + bool override_density_image; + //! This will over-ride the scanner template in scatter sinogram simulation (defaults to \c true) + bool override_scanner_template; + //! In debug mode a lot of extra files are going to be saved in the disk. + bool run_debug_mode; + //! Parameter file for scatter simulation + //! \warning Values in this file could be overridden. + std::string scatter_sim_par_filename; + //! \details Class which will implement the scatter simulation. + shared_ptr scatter_simulation_sptr; + //! This path is used in the debug mode to store all the intermediate files, as they are many. + FilePath extras_path; + + //! Default value = 100 + float max_scale_value; + //! Default value = 0.4 + float min_scale_value; + + bool downsample_scanner_bool; + //! + unsigned int half_filter_width; + + //! \details internal variable set to \c true when using iterative reconstruction + bool iterative_method; }; END_NAMESPACE_STIR diff --git a/src/include/stir/scatter/ScatterEstimation.inl b/src/include/stir/scatter/ScatterEstimation.inl index ef1260bcf5..e9c788b395 100644 --- a/src/include/stir/scatter/ScatterEstimation.inl +++ b/src/include/stir/scatter/ScatterEstimation.inl @@ -3,73 +3,55 @@ START_NAMESPACE_STIR void -ScatterEstimation:: -set_input_proj_data_sptr(const shared_ptr arg) -{ +ScatterEstimation::set_input_proj_data_sptr(const shared_ptr arg) { this->_already_setup = false; - this->input_projdata_sptr = arg; + this->input_projdata_sptr = arg; } void -ScatterEstimation:: -set_reconstruction_method_sptr(const shared_ptr > > arg) -{ +ScatterEstimation::set_reconstruction_method_sptr(const shared_ptr>> arg) { this->_already_setup = false; - this->reconstruction_template_sptr = arg; + this->reconstruction_template_sptr = arg; } void -ScatterEstimation:: -set_attenuation_image_sptr(const shared_ptr > arg) -{ +ScatterEstimation::set_attenuation_image_sptr(const shared_ptr> arg) { this->_already_setup = false; - this->atten_image_sptr = arg; + this->atten_image_sptr = arg; } void -ScatterEstimation:: -set_background_proj_data_sptr(const shared_ptr arg) -{ +ScatterEstimation::set_background_proj_data_sptr(const shared_ptr arg) { this->_already_setup = false; - this->back_projdata_sptr = arg; + this->back_projdata_sptr = arg; } void -ScatterEstimation:: -set_initial_activity_image_sptr(const shared_ptr > arg) -{ +ScatterEstimation::set_initial_activity_image_sptr(const shared_ptr> arg) { this->_already_setup = false; - this->current_activity_image_sptr.reset(arg->clone()); + this->current_activity_image_sptr.reset(arg->clone()); } void -ScatterEstimation:: -set_mask_image_sptr(const shared_ptr > arg) -{ +ScatterEstimation::set_mask_image_sptr(const shared_ptr> arg) { this->_already_setup = false; - this->mask_image_sptr = arg; + this->mask_image_sptr = arg; } void -ScatterEstimation:: -set_mask_proj_data_sptr(const shared_ptr arg) -{ +ScatterEstimation::set_mask_proj_data_sptr(const shared_ptr arg) { this->_already_setup = false; - this->mask_projdata_sptr = arg; + this->mask_projdata_sptr = arg; } void -ScatterEstimation:: -set_scatter_simulation_method_sptr(const shared_ptr arg) -{ +ScatterEstimation::set_scatter_simulation_method_sptr(const shared_ptr arg) { this->_already_setup = false; - this->scatter_simulation_sptr = arg; + this->scatter_simulation_sptr = arg; } void -ScatterEstimation:: -set_num_iterations(int arg) -{ +ScatterEstimation::set_num_iterations(int arg) { this->num_scatter_iterations = arg; } diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 9b0d215e31..8ad2a1c612 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -87,349 +87,297 @@ START_NAMESPACE_STIR */ -class ScatterSimulation : public RegisteredObject -{ +class ScatterSimulation : public RegisteredObject { public: + //! Default constructor + ScatterSimulation(); + + virtual ~ScatterSimulation(); + + virtual Succeeded process_data(); + //! gives method information + virtual std::string method_info() const = 0; + //! prompts the user to enter parameter values manually + virtual void ask_parameters(); + //! \name check functions + //@{ + inline bool has_template_proj_data_info() const { return !stir::is_null_ptr(proj_data_info_cyl_noarc_cor_sptr); } + //! Returns true if template_exam_info_sptr has been set. + inline bool has_exam_info() const { return !stir::is_null_ptr(template_exam_info_sptr); } + //@} - //! Default constructor - ScatterSimulation(); - - virtual ~ScatterSimulation(); - - virtual Succeeded process_data(); - //! gives method information - virtual std::string method_info() const = 0; - //! prompts the user to enter parameter values manually - virtual void ask_parameters(); - //! \name check functions - //@{ - inline bool has_template_proj_data_info() const - { return !stir::is_null_ptr(proj_data_info_cyl_noarc_cor_sptr); } - //! Returns true if template_exam_info_sptr has been set. - inline bool has_exam_info() const - { return !stir::is_null_ptr(template_exam_info_sptr);} - //@} - - //! \name get functions - //@{ - shared_ptr - get_output_proj_data_sptr() const; - - inline int get_num_scatter_points() const - { return static_cast(this->scatt_points_vector.size());} - //! Get the template ProjDataInfo - shared_ptr get_template_proj_data_info_sptr() const; - //! Get the ExamInfo - shared_ptr get_exam_info_sptr() const; - - const DiscretisedDensity<3,float>& get_activity_image() const; - const DiscretisedDensity<3,float>& get_attenuation_image() const; - const DiscretisedDensity<3,float>& get_attenuation_image_for_scatter_points() const; - //! \deprecated - shared_ptr > get_density_image_for_scatter_points_sptr() const; - //@} - - //! \name set functions - //@{ - - void set_template_proj_data_info(const std::string&); - - void set_template_proj_data_info(const ProjDataInfo&); - - void set_activity_image_sptr(const shared_ptr >); - - void set_activity_image(const std::string& filename); - //! \details Since July 2016, the information for the energy window and energy - //! resolution are stored in ExamInfo. - void set_exam_info(const ExamInfo&); - void set_exam_info_sptr(const shared_ptr); - - void set_output_proj_data_sptr(shared_ptr); - - void set_density_image_sptr(const shared_ptr >); - - void set_density_image(const std::string&); - //! This function depends on the ProjDataInfo of the scanner. - //! You first have to set that. - void set_output_proj_data(const std::string&); - - void - set_output_proj_data_sptr(const shared_ptr, - const shared_ptr, - const std::string &); - - void set_density_image_for_scatter_points_sptr(shared_ptr >); - - void set_image_downsample_factors(float factor_xy = 1.f, float factor_z = 1.f, - int _size_zoom_xy = -1, int _size_zoom_z = -1); - //! set_density_image_for_scatter_points - void set_density_image_for_scatter_points(const std::string&); - //! set the attenuation threshold - void set_attenuation_threshold(const float); - //! The scattering point in the voxel will be chosen randomly, instead of choosing the centre. - /*! This was first recommended by Watson. It is recommended to leave this on, as otherwise - discretisation errors are more obvious. - - Note that the random generator is seeded via date/time, so re-running the scatter - simulation will give a slightly different result if this boolean is on. - */ - void set_randomly_place_scatter_points(const bool); - - void set_cache_enabled(const bool); - - //@} - - //! This function is a less powerfull tool than directly zooming the image. - //! However it will check that the downsampling is done in manner compatible with the - //! ScatterSimulation. - void downsample_density_image_for_scatter_points(float _zoom_xy, float _zoom_z, - int _size_xy = -1, int _size_z = -1); - - //! Downsample the scanner keeping the total axial length the same. - /*! If \c new_num_rings<=0, use rings of approximately 2 cm thickness. - If \c new_num_dets <=0, use the default set (currently set in set_defaults()) - */ - Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); - //! Downsamples activity and attenuation images to voxel sizes appropriate for the (downsampled) scanner. - /*! This step is not necessary but could result in a speed-up in computing the line integrals. - It also avoids problems with too high resolution images compared to the downsampled scanner. - - Another way to resolve that is to smooth the images before the scatter simulation. - This is currently not implemented in this class. - \warning This function should be called after having set all data. - */ - Succeeded downsample_images_to_scanner_size(); - - //! \name Compton scatter cross sections - //@{ - static - inline float - dif_Compton_cross_section(const float cos_theta, float energy); - - static - inline float - total_Compton_cross_section(float energy); - - static - inline float - photon_energy_after_Compton_scatter(const float cos_theta, const float energy); - - static - inline float - photon_energy_after_Compton_scatter_511keV(const float cos_theta); - - static - inline float - total_Compton_cross_section_relative_to_511keV(const float energy); - //@} - - virtual Succeeded set_up(); - - //! Output the log of the process. - virtual void write_log(const double simulation_time, const float total_scatter); - + //! \name get functions + //@{ + shared_ptr get_output_proj_data_sptr() const; -protected: + inline int get_num_scatter_points() const { return static_cast(this->scatt_points_vector.size()); } + //! Get the template ProjDataInfo + shared_ptr get_template_proj_data_info_sptr() const; + //! Get the ExamInfo + shared_ptr get_exam_info_sptr() const; + + const DiscretisedDensity<3, float>& get_activity_image() const; + const DiscretisedDensity<3, float>& get_attenuation_image() const; + const DiscretisedDensity<3, float>& get_attenuation_image_for_scatter_points() const; + //! \deprecated + shared_ptr> get_density_image_for_scatter_points_sptr() const; + //@} + + //! \name set functions + //@{ + + void set_template_proj_data_info(const std::string&); + + void set_template_proj_data_info(const ProjDataInfo&); + + void set_activity_image_sptr(const shared_ptr>); + + void set_activity_image(const std::string& filename); + //! \details Since July 2016, the information for the energy window and energy + //! resolution are stored in ExamInfo. + void set_exam_info(const ExamInfo&); + void set_exam_info_sptr(const shared_ptr); + + void set_output_proj_data_sptr(shared_ptr); + + void set_density_image_sptr(const shared_ptr>); + + void set_density_image(const std::string&); + //! This function depends on the ProjDataInfo of the scanner. + //! You first have to set that. + void set_output_proj_data(const std::string&); + + void set_output_proj_data_sptr(const shared_ptr, const shared_ptr, const std::string&); - //! computes scatter for one viewgram - /*! \return total scatter estimated for this viewgram */ - virtual double - process_data_for_view_segment_num(const ViewSegmentNumbers& vs_num); + void set_density_image_for_scatter_points_sptr(shared_ptr>); - float - compute_emis_to_det_points_solid_angle_factor(const CartesianCoordinate3D& emis_point, - const CartesianCoordinate3D& detector_coord); + void set_image_downsample_factors(float factor_xy = 1.f, float factor_z = 1.f, int _size_zoom_xy = -1, int _size_zoom_z = -1); + //! set_density_image_for_scatter_points + void set_density_image_for_scatter_points(const std::string&); + //! set the attenuation threshold + void set_attenuation_threshold(const float); + //! The scattering point in the voxel will be chosen randomly, instead of choosing the centre. + /*! This was first recommended by Watson. It is recommended to leave this on, as otherwise + discretisation errors are more obvious. + Note that the random generator is seeded via date/time, so re-running the scatter + simulation will give a slightly different result if this boolean is on. + */ + void set_randomly_place_scatter_points(const bool); + void set_cache_enabled(const bool); - virtual void set_defaults(); - virtual void initialise_keymap(); - //! \warning post_processing will set everything that has a file name in - //! the par file. The corresponding set functions should be used either - //! for files that are not stored in the drive. - virtual bool post_processing(); + //@} - enum image_type{act_image_type, att_image_type}; - struct ScatterPoint - { - CartesianCoordinate3D coord; - float mu_value; - }; + //! This function is a less powerfull tool than directly zooming the image. + //! However it will check that the downsampling is done in manner compatible with the + //! ScatterSimulation. + void downsample_density_image_for_scatter_points(float _zoom_xy, float _zoom_z, int _size_xy = -1, int _size_z = -1); - std::vector< ScatterPoint> scatt_points_vector; + //! Downsample the scanner keeping the total axial length the same. + /*! If \c new_num_rings<=0, use rings of approximately 2 cm thickness. + If \c new_num_dets <=0, use the default set (currently set in set_defaults()) + */ + Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); + //! Downsamples activity and attenuation images to voxel sizes appropriate for the (downsampled) scanner. + /*! This step is not necessary but could result in a speed-up in computing the line integrals. + It also avoids problems with too high resolution images compared to the downsampled scanner. - float scatter_volume; + Another way to resolve that is to smooth the images before the scatter simulation. + This is currently not implemented in this class. + \warning This function should be called after having set all data. + */ + Succeeded downsample_images_to_scanner_size(); - //! find scatter points - /*! This function sets scatt_points_vector and scatter_volume. It will also - remove any cached integrals as they would be incorrect otherwise. - */ - void - sample_scatter_points(); + //! \name Compton scatter cross sections + //@{ + static inline float dif_Compton_cross_section(const float cos_theta, float energy); - //! remove cached attenuation integrals - /*! should be used before recalculating scatter for a new attenuation image or - when changing the sampling of the detector etc */ - virtual void remove_cache_for_integrals_over_attenuation(); + static inline float total_Compton_cross_section(float energy); - //! reset cached activity integrals - /*! should be used before recalculating scatter for a new activity image or - when changing the sampling of the detector etc */ - virtual void remove_cache_for_integrals_over_activity(); + static inline float photon_energy_after_Compton_scatter(const float cos_theta, const float energy); - /** \name detection related functions - * - * @{ - */ + static inline float photon_energy_after_Compton_scatter_511keV(const float cos_theta); - float detection_efficiency(const float energy) const; + static inline float total_Compton_cross_section_relative_to_511keV(const float energy); + //@} + virtual Succeeded set_up(); - //! maximum angle to consider above which detection after Compton scatter is considered too small - static - float - max_cos_angle(const float low, const float approx, const float resolution_at_511keV); + //! Output the log of the process. + virtual void write_log(const double simulation_time, const float total_scatter); - //! mimumum energy to consider above which detection after Compton scatter is considered too small - static - float - energy_lower_limit(const float low, const float approx, const float resolution_at_511keV); +protected: + //! computes scatter for one viewgram + /*! \return total scatter estimated for this viewgram */ + virtual double process_data_for_view_segment_num(const ViewSegmentNumbers& vs_num); + + float compute_emis_to_det_points_solid_angle_factor(const CartesianCoordinate3D& emis_point, + const CartesianCoordinate3D& detector_coord); + + virtual void set_defaults(); + virtual void initialise_keymap(); + //! \warning post_processing will set everything that has a file name in + //! the par file. The corresponding set functions should be used either + //! for files that are not stored in the drive. + virtual bool post_processing(); + + enum image_type { act_image_type, att_image_type }; + struct ScatterPoint { + CartesianCoordinate3D coord; + float mu_value; + }; + + std::vector scatt_points_vector; + + float scatter_volume; - virtual - void - find_detectors(unsigned& det_num_A, unsigned& det_num_B, const Bin& bin) const; + //! find scatter points + /*! This function sets scatt_points_vector and scatter_volume. It will also + remove any cached integrals as they would be incorrect otherwise. + */ + void sample_scatter_points(); - unsigned - find_in_detection_points_vector(const CartesianCoordinate3D& coord) const; + //! remove cached attenuation integrals + /*! should be used before recalculating scatter for a new attenuation image or + when changing the sampling of the detector etc */ + virtual void remove_cache_for_integrals_over_attenuation(); - CartesianCoordinate3D shift_detector_coordinates_to_origin; + //! reset cached activity integrals + /*! should be used before recalculating scatter for a new activity image or + when changing the sampling of the detector etc */ + virtual void remove_cache_for_integrals_over_activity(); - //! average detection efficiency of unscattered counts - double - detection_efficiency_no_scatter(const unsigned det_num_A, - const unsigned det_num_B) const; + /** \name detection related functions + * + * @{ + */ - // next needs to be mutable because find_in_detection_points_vector is const - mutable std::vector > detection_points_vector; + float detection_efficiency(const float energy) const; - //!@} + //! maximum angle to consider above which detection after Compton scatter is considered too small + static float max_cos_angle(const float low, const float approx, const float resolution_at_511keV); - //! virtual function that computes the scatter for one (downsampled) bin - virtual double - scatter_estimate(const Bin& bin) = 0; + //! mimumum energy to consider above which detection after Compton scatter is considered too small + static float energy_lower_limit(const float low, const float approx, const float resolution_at_511keV); - //! \name integrating functions - //@{ - static - float - integral_between_2_points(const DiscretisedDensity<3,float>& density, - const CartesianCoordinate3D& point1, - const CartesianCoordinate3D& point2); + virtual void find_detectors(unsigned& det_num_A, unsigned& det_num_B, const Bin& bin) const; - float - exp_integral_over_attenuation_image_between_scattpoint_det (const CartesianCoordinate3D& scatter_point, - const CartesianCoordinate3D& detector_coord); + unsigned find_in_detection_points_vector(const CartesianCoordinate3D& coord) const; + CartesianCoordinate3D shift_detector_coordinates_to_origin; + //! average detection efficiency of unscattered counts + double detection_efficiency_no_scatter(const unsigned det_num_A, const unsigned det_num_B) const; - float - integral_over_activity_image_between_scattpoint_det (const CartesianCoordinate3D& scatter_point, - const CartesianCoordinate3D& detector_coord); + // next needs to be mutable because find_in_detection_points_vector is const + mutable std::vector> detection_points_vector; + //!@} + //! virtual function that computes the scatter for one (downsampled) bin + virtual double scatter_estimate(const Bin& bin) = 0; - float - cached_integral_over_activity_image_between_scattpoint_det(const unsigned scatter_point_num, - const unsigned det_num); + //! \name integrating functions + //@{ + static float integral_between_2_points(const DiscretisedDensity<3, float>& density, const CartesianCoordinate3D& point1, + const CartesianCoordinate3D& point2); - float - cached_exp_integral_over_attenuation_image_between_scattpoint_det(const unsigned scatter_point_num, - const unsigned det_num); - //@} + float exp_integral_over_attenuation_image_between_scattpoint_det(const CartesianCoordinate3D& scatter_point, + const CartesianCoordinate3D& detector_coord); - std::string template_proj_data_filename; + float integral_over_activity_image_between_scattpoint_det(const CartesianCoordinate3D& scatter_point, + const CartesianCoordinate3D& detector_coord); - shared_ptr proj_data_info_cyl_noarc_cor_sptr; + float cached_integral_over_activity_image_between_scattpoint_det(const unsigned scatter_point_num, const unsigned det_num); - //! \details Exam info extracted from the scanner template - shared_ptr template_exam_info_sptr; + float cached_exp_integral_over_attenuation_image_between_scattpoint_det(const unsigned scatter_point_num, + const unsigned det_num); + //@} - std::string density_image_filename; + std::string template_proj_data_filename; - std::string density_image_for_scatter_points_filename; + shared_ptr proj_data_info_cyl_noarc_cor_sptr; - std::string density_image_for_scatter_points_output_filename; + //! \details Exam info extracted from the scanner template + shared_ptr template_exam_info_sptr; - shared_ptr< const DiscretisedDensity<3, float> > density_image_sptr; + std::string density_image_filename; - //! Pointer to hold the current activity estimation - shared_ptr > activity_image_sptr; + std::string density_image_for_scatter_points_filename; - //! set-up cache for attenuation integrals - /*! \warning This will not remove existing cached data (if the sizes match). If you need this, - call remove_cache_for_scattpoint_det_integrals_over_attenuation() first. - */ - void initialise_cache_for_scattpoint_det_integrals_over_attenuation(); - //! set-up cache for activity integrals - /*! \warning This will not remove existing cached data (if the sizes match). If you need this, - call remove_cache_for_scattpoint_det_integrals_over_activity() first. - */ - void initialise_cache_for_scattpoint_det_integrals_over_activity(); + std::string density_image_for_scatter_points_output_filename; - //! Output proj_data fileanme prefix - std::string output_proj_data_filename; - //! Shared ptr to hold the simulated data. - shared_ptr output_proj_data_sptr; + shared_ptr> density_image_sptr; - //! threshold below which a voxel in the attenuation image will not be considered as a candidate scatter point - float attenuation_threshold; + //! Pointer to hold the current activity estimation + shared_ptr> activity_image_sptr; - //! boolean to see if we need to move the scatter point randomly within in its voxel - bool randomly_place_scatter_points; - //! boolean to see if we need to cache the integrals - /*! By default, we cache the integrals over the emission and attenuation image. If you run out - of memory, you can switch this off, but performance will suffer dramatically. - */ - bool use_cache; - //! Filename for the initial activity estimate. - std::string activity_image_filename; - //! Zoom factor on plane XY. Defaults on 1.f. - float zoom_xy; - //! Zoom factor on Z axis. Defaults on 1.f. - float zoom_z; - //! Zoomed image size on plane XY. Defaults on -1. - int zoom_size_xy; - //! Zoomed image size on Z axis. Defaults on -1. - int zoom_size_z; - //! Number of rings of downsampled scanner - int downsample_scanner_rings; - //! Number of detectors per ring of downsampled scanner - int downsample_scanner_dets; + //! set-up cache for attenuation integrals + /*! \warning This will not remove existing cached data (if the sizes match). If you need this, + call remove_cache_for_scattpoint_det_integrals_over_attenuation() first. + */ + void initialise_cache_for_scattpoint_det_integrals_over_attenuation(); + //! set-up cache for activity integrals + /*! \warning This will not remove existing cached data (if the sizes match). If you need this, + call remove_cache_for_scattpoint_det_integrals_over_activity() first. + */ + void initialise_cache_for_scattpoint_det_integrals_over_activity(); - bool downsample_scanner_bool; + //! Output proj_data fileanme prefix + std::string output_proj_data_filename; + //! Shared ptr to hold the simulated data. + shared_ptr output_proj_data_sptr; - private: - int total_detectors; + //! threshold below which a voxel in the attenuation image will not be considered as a candidate scatter point + float attenuation_threshold; - Array<2,float> cached_activity_integral_scattpoint_det; - Array<2,float> cached_attenuation_integral_scattpoint_det; - shared_ptr< DiscretisedDensity<3, float> > density_image_for_scatter_points_sptr; + //! boolean to see if we need to move the scatter point randomly within in its voxel + bool randomly_place_scatter_points; + //! boolean to see if we need to cache the integrals + /*! By default, we cache the integrals over the emission and attenuation image. If you run out + of memory, you can switch this off, but performance will suffer dramatically. + */ + bool use_cache; + //! Filename for the initial activity estimate. + std::string activity_image_filename; + //! Zoom factor on plane XY. Defaults on 1.f. + float zoom_xy; + //! Zoom factor on Z axis. Defaults on 1.f. + float zoom_z; + //! Zoomed image size on plane XY. Defaults on -1. + int zoom_size_xy; + //! Zoomed image size on Z axis. Defaults on -1. + int zoom_size_z; + //! Number of rings of downsampled scanner + int downsample_scanner_rings; + //! Number of detectors per ring of downsampled scanner + int downsample_scanner_dets; - // numbers that we don't want to recompute all the time - mutable float detector_efficiency_no_scatter; + bool downsample_scanner_bool; - bool _already_set_up; +private: + int total_detectors; - //! a function that checks if image sizes are ok - /*! It will call \c error() if not. + Array<2, float> cached_activity_integral_scattpoint_det; + Array<2, float> cached_attenuation_integral_scattpoint_det; + shared_ptr> density_image_for_scatter_points_sptr; - Currently, STIR shifts the middle of the image to the middle of the scanner. This - is dangerous when using image zooming. - This function currently checks if \a _image is consistent with the \c activity_image_sptr. + // numbers that we don't want to recompute all the time + mutable float detector_efficiency_no_scatter; - See https://github.com/UCL/STIR/issues/495 for more information. - */ - void check_z_to_middle_consistent(const DiscretisedDensity<3,float>& _image, const std::string& name) const; + bool _already_set_up; + + //! a function that checks if image sizes are ok + /*! It will call \c error() if not. + + Currently, STIR shifts the middle of the image to the middle of the scanner. This + is dangerous when using image zooming. + This function currently checks if \a _image is consistent with the \c activity_image_sptr. + + See https://github.com/UCL/STIR/issues/495 for more information. + */ + void check_z_to_middle_consistent(const DiscretisedDensity<3, float>& _image, const std::string& name) const; }; END_NAMESPACE_STIR @@ -437,5 +385,3 @@ END_NAMESPACE_STIR #include "stir/scatter/ScatterSimulation.inl" #endif - - diff --git a/src/include/stir/scatter/ScatterSimulation.inl b/src/include/stir/scatter/ScatterSimulation.inl index cf572f1eeb..03d2c722bb 100644 --- a/src/include/stir/scatter/ScatterSimulation.inl +++ b/src/include/stir/scatter/ScatterSimulation.inl @@ -38,53 +38,43 @@ START_NAMESPACE_STIR /**************** Functions to set images ****************/ float -ScatterSimulation:: -dif_Compton_cross_section(const float cos_theta, float energy) -{ - const double Re = 2.818E-13; // aktina peristrofis electroniou gia to atomo tou H - const double sin_theta_2= 1-cos_theta*cos_theta ; - const double P= 1.0/(1.0+(energy/511.0)*(1.0-cos_theta)); - return static_cast( (Re*Re/2) * P * (1 - P * sin_theta_2 + P * P)); +ScatterSimulation::dif_Compton_cross_section(const float cos_theta, float energy) { + const double Re = 2.818E-13; // aktina peristrofis electroniou gia to atomo tou H + const double sin_theta_2 = 1 - cos_theta * cos_theta; + const double P = 1.0 / (1.0 + (energy / 511.0) * (1.0 - cos_theta)); + return static_cast((Re * Re / 2) * P * (1 - P * sin_theta_2 + P * P)); } float -ScatterSimulation:: -photon_energy_after_Compton_scatter(const float cos_theta, const float energy) -{ - return static_cast(energy/(1+(energy/511.0f)*(1-cos_theta))); // For an arbitrary energy +ScatterSimulation::photon_energy_after_Compton_scatter(const float cos_theta, const float energy) { + return static_cast(energy / (1 + (energy / 511.0f) * (1 - cos_theta))); // For an arbitrary energy } float -ScatterSimulation:: -photon_energy_after_Compton_scatter_511keV(const float cos_theta) -{ - return 511.f/(2.f-cos_theta); // for a given energy, energy := 511 keV +ScatterSimulation::photon_energy_after_Compton_scatter_511keV(const float cos_theta) { + return 511.f / (2.f - cos_theta); // for a given energy, energy := 511 keV } float -ScatterSimulation:: -total_Compton_cross_section(const float energy) -{ - const double a= energy/511.0; - const double l= log(1.0+2.0*a); - const double sigma0= 6.65E-25; // sigma0=8*pi*a*a/(3*m*m) - return static_cast( 0.75*sigma0 * ( (1.0+a)/(a*a)*( 2.0*(1.0+a)/(1.0+2.0*a)- l/a ) + l/(2.0*a) - (1.0+3.0*a)/(1.0+2.0*a)/(1.0+2.0*a) ) ); // Klein - Nishina formula = sigma / sigma0 +ScatterSimulation::total_Compton_cross_section(const float energy) { + const double a = energy / 511.0; + const double l = log(1.0 + 2.0 * a); + const double sigma0 = 6.65E-25; // sigma0=8*pi*a*a/(3*m*m) + return static_cast(0.75 * sigma0 * + ((1.0 + a) / (a * a) * (2.0 * (1.0 + a) / (1.0 + 2.0 * a) - l / a) + l / (2.0 * a) - + (1.0 + 3.0 * a) / (1.0 + 2.0 * a) / (1.0 + 2.0 * a))); // Klein - Nishina formula = sigma / sigma0 } - float -ScatterSimulation:: -total_Compton_cross_section_relative_to_511keV(const float energy) -{ - const double a= energy/511.0; - static const double prefactor = 9.0/(-40 + 27*log(3.)); //Klein-Nishina formula for a=1 & devided with 0.75 == (40 - 27*log(3)) / 9 +ScatterSimulation::total_Compton_cross_section_relative_to_511keV(const float energy) { + const double a = energy / 511.0; + static const double prefactor = + 9.0 / (-40 + 27 * log(3.)); // Klein-Nishina formula for a=1 & devided with 0.75 == (40 - 27*log(3)) / 9 - return //checked this in Mathematica - static_cast - (prefactor* - (((-4 - a*(16 + a*(18 + 2*a)))/square(1 + 2*a) + - ((2 + (2 - a)*a)*log(1 + 2*a))/a)/square(a) - )); + return // checked this in Mathematica + static_cast( + prefactor * + (((-4 - a * (16 + a * (18 + 2 * a))) / square(1 + 2 * a) + ((2 + (2 - a) * a) * log(1 + 2 * a)) / a) / square(a))); } END_NAMESPACE_STIR diff --git a/src/include/stir/scatter/SingleScatterSimulation.h b/src/include/stir/scatter/SingleScatterSimulation.h index 70e4914416..6e3096c29a 100644 --- a/src/include/stir/scatter/SingleScatterSimulation.h +++ b/src/include/stir/scatter/SingleScatterSimulation.h @@ -29,7 +29,6 @@ #include "stir/scatter/ScatterSimulation.h" #include "stir/RegisteredParsingObject.h" - START_NAMESPACE_STIR /*! @@ -38,71 +37,54 @@ START_NAMESPACE_STIR \todo The class is specific to PET so should be renamed accordingly. */ -class SingleScatterSimulation : public - RegisteredParsingObject< - SingleScatterSimulation, - ScatterSimulation, - ScatterSimulation > -{ +class SingleScatterSimulation : public RegisteredParsingObject { private: - typedef RegisteredParsingObject< - SingleScatterSimulation, - ScatterSimulation, - ScatterSimulation > base_type; + typedef RegisteredParsingObject base_type; + public: + //! Name which will be used when parsing a ScatterSimulation object + static const char* const registered_name; - //! Name which will be used when parsing a ScatterSimulation object - static const char * const registered_name; + //! Default constructor + SingleScatterSimulation(); - //! Default constructor - SingleScatterSimulation(); + //! Constructor with initialisation from parameter file + explicit SingleScatterSimulation(const std::string& parameter_filename); - //! Constructor with initialisation from parameter file - explicit - SingleScatterSimulation(const std::string& parameter_filename); + virtual ~SingleScatterSimulation(); - virtual ~SingleScatterSimulation(); + virtual Succeeded process_data(); + //! gives method information + virtual std::string method_info() const; + //! prompts the user to enter parameter values manually + virtual void ask_parameters(); + //! Perform checks and intialisations + virtual Succeeded set_up(); - virtual Succeeded process_data(); - //! gives method information - virtual std::string method_info() const; - //! prompts the user to enter parameter values manually - virtual void ask_parameters(); - //! Perform checks and intialisations - virtual Succeeded set_up(); protected: + void initialise(const std::string& parameter_filename); - void initialise(const std::string& parameter_filename); - - virtual void set_defaults(); - virtual void initialise_keymap(); + virtual void set_defaults(); + virtual void initialise_keymap(); - //! used to check acceptable parameter ranges, etc... - virtual bool post_processing(); + //! used to check acceptable parameter ranges, etc... + virtual bool post_processing(); + //! + //! \brief simulate_for_one_scatter_point + //! \param scatter_point_num + //! \param det_num_A + //! \param det_num_B + //! \return + float simulate_for_one_scatter_point(const std::size_t scatter_point_num, const unsigned det_num_A, const unsigned det_num_B); - //! - //! \brief simulate_for_one_scatter_point - //! \param scatter_point_num - //! \param det_num_A - //! \param det_num_B - //! \return - float - simulate_for_one_scatter_point(const std::size_t scatter_point_num, - const unsigned det_num_A, - const unsigned det_num_B); + virtual double scatter_estimate(const Bin& bin); - virtual double - scatter_estimate(const Bin& bin); + virtual void actual_scatter_estimate(double& scatter_ratio_singles, const unsigned det_num_A, const unsigned det_num_B); - virtual void - actual_scatter_estimate(double& scatter_ratio_singles, - const unsigned det_num_A, - const unsigned det_num_B); - - private: - //! larger angles will be ignored - float max_single_scatter_cos_angle; +private: + //! larger angles will be ignored + float max_single_scatter_cos_angle; }; END_NAMESPACE_STIR diff --git a/src/include/stir/shared_ptr.h b/src/include/stir/shared_ptr.h index 7de2b9bd13..1eb18eba3b 100644 --- a/src/include/stir/shared_ptr.h +++ b/src/include/stir/shared_ptr.h @@ -3,12 +3,12 @@ /*! \file \ingroup buildblock - + \brief Import of std::shared_ptr, std::dynamic_pointer_cast and - std::static_pointer_cast (or corresponding boost versions if - STIR_USE_BOOST_SHARED_PTR is set, i.e. normally when std::shared_ptr doesn't exist) - into the stir namespace. -*/ + std::static_pointer_cast (or corresponding boost versions if + STIR_USE_BOOST_SHARED_PTR is set, i.e. normally when std::shared_ptr doesn't exist) + into the stir namespace. +*/ /* Copyright (C) 2011-07-01 - 2012, Kris Thielemans This file is part of STIR. @@ -31,25 +31,25 @@ #include "stir/common.h" #if defined(STIR_USE_BOOST_SHARED_PTR) -#include "boost/shared_ptr.hpp" -#include "boost/make_shared.hpp" -#include "boost/pointer_cast.hpp" +# include "boost/shared_ptr.hpp" +# include "boost/make_shared.hpp" +# include "boost/pointer_cast.hpp" namespace stir { - using boost::shared_ptr; - using boost::dynamic_pointer_cast; - using boost::static_pointer_cast; - //! work-around for using std::make_shared on old compilers -#define MAKE_SHARED boost::make_shared -} +using boost::shared_ptr; +using boost::dynamic_pointer_cast; +using boost::static_pointer_cast; +//! work-around for using std::make_shared on old compilers +# define MAKE_SHARED boost::make_shared +} // namespace stir #else -#include +# include namespace stir { - using std::shared_ptr; - using std::dynamic_pointer_cast; - using std::static_pointer_cast; - //! work-around for using std::make_shared on old compilers -#define MAKE_SHARED std::make_shared -} +using std::shared_ptr; +using std::dynamic_pointer_cast; +using std::static_pointer_cast; +//! work-around for using std::make_shared on old compilers +# define MAKE_SHARED std::make_shared +} // namespace stir #endif #endif diff --git a/src/include/stir/spatial_transformation/GatedSpatialTransformation.h b/src/include/stir/spatial_transformation/GatedSpatialTransformation.h index c6e6c3419b..f8b9e2df1a 100644 --- a/src/include/stir/spatial_transformation/GatedSpatialTransformation.h +++ b/src/include/stir/spatial_transformation/GatedSpatialTransformation.h @@ -2,25 +2,25 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup spatial_transformation \brief Declaration of class stir::GatedSpatialTransformation \author Charalampos Tsoumpas - + */ #ifndef __stir_spatial_transformation_GatedSpatialTransformation_H__ @@ -41,53 +41,43 @@ START_NAMESPACE_STIR /*! \ingroup spatial_transformation */ -class GatedSpatialTransformation: public RegisteredParsingObject -{ - public: - static const char * const registered_name; +class GatedSpatialTransformation : public RegisteredParsingObject { +public: + static const char* const registered_name; - GatedSpatialTransformation(); //!< default constructor + GatedSpatialTransformation(); //!< default constructor ~GatedSpatialTransformation(); //!< default destructor //! Construct an empty GatedSpatialTransformation based on a shared_ptr > GatedSpatialTransformation(const TimeGateDefinitions& time_gate_definitions, - const shared_ptr >& density_sptr); + const shared_ptr>& density_sptr); void read_from_files(const std::string input_string); - void write_to_files(const std::string output_string); + void write_to_files(const std::string output_string); //! \name Functions to get parameters @{ GatedDiscretisedDensity get_spatial_transformation_z() const; GatedDiscretisedDensity get_spatial_transformation_y() const; GatedDiscretisedDensity get_spatial_transformation_x() const; - const TimeGateDefinitions & get_time_gate_definitions() const; + const TimeGateDefinitions& get_time_gate_definitions() const; //!@} //! \name Functions to set parameters @{ - void set_spatial_transformations(const GatedDiscretisedDensity & motion_z, - const GatedDiscretisedDensity & motion_y, - const GatedDiscretisedDensity & motion_x); - void set_gate_defs(const TimeGateDefinitions & gate_defs); + void set_spatial_transformations(const GatedDiscretisedDensity& motion_z, const GatedDiscretisedDensity& motion_y, + const GatedDiscretisedDensity& motion_x); + void set_gate_defs(const TimeGateDefinitions& gate_defs); //!@} //! Warping functions from to gated images. @{ - void - warp_image(GatedDiscretisedDensity & new_gated_image, - const GatedDiscretisedDensity & gated_image) const ; - void - warp_image(DiscretisedDensity<3, float> & new_reference_image, - const GatedDiscretisedDensity & gated_image) const ; - void - warp_image(GatedDiscretisedDensity & gated_image, - const DiscretisedDensity<3, float> & reference_image) const; - void - accumulate_warp_image(DiscretisedDensity<3, float> & new_reference_image, - const GatedDiscretisedDensity & gated_image) const ; + void warp_image(GatedDiscretisedDensity& new_gated_image, const GatedDiscretisedDensity& gated_image) const; + void warp_image(DiscretisedDensity<3, float>& new_reference_image, const GatedDiscretisedDensity& gated_image) const; + void warp_image(GatedDiscretisedDensity& gated_image, const DiscretisedDensity<3, float>& reference_image) const; + void accumulate_warp_image(DiscretisedDensity<3, float>& new_reference_image, const GatedDiscretisedDensity& gated_image) const; void set_defaults(); - Succeeded set_up(); + Succeeded set_up(); //@} - private: - typedef RegisteredParsingObject base_type; +private: + typedef RegisteredParsingObject base_type; void initialise_keymap(); - bool post_processing(); + bool post_processing(); std::string _transformation_filename_prefix; GatedDiscretisedDensity _spatial_transformation_z; GatedDiscretisedDensity _spatial_transformation_y; diff --git a/src/include/stir/spatial_transformation/InvertAxis.h b/src/include/stir/spatial_transformation/InvertAxis.h index 7f14030349..be03267548 100644 --- a/src/include/stir/spatial_transformation/InvertAxis.h +++ b/src/include/stir/spatial_transformation/InvertAxis.h @@ -2,23 +2,23 @@ /* Copyright (C) 2019 National Physical Laboratory This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup spatial_transformation - + \brief This invert the selected image axis. \author Daniel Deidda */ @@ -30,28 +30,22 @@ START_NAMESPACE_STIR -/*! +/*! \ingroup spatial_transformation - + \brief a utility class to "invert" an axis \warning this will reorder the voxel values without adjusting the geometric information. */ -class InvertAxis{ +class InvertAxis { public: - //! transform the image /*! \a axis_name has to be x, y, z. Otherwise error() will be called. */ -void -invert_axis(DiscretisedDensity<3, float> &inverted_image, - const DiscretisedDensity<3, float> &input_image, - const std::string & axis_name); - -int -invert_axis_index(const int input_index, - const int size, - const std::string & axis_name); + void invert_axis(DiscretisedDensity<3, float>& inverted_image, const DiscretisedDensity<3, float>& input_image, + const std::string& axis_name); + + int invert_axis_index(const int input_index, const int size, const std::string& axis_name); }; END_NAMESPACE_STIR diff --git a/src/include/stir/spatial_transformation/SpatialTransformation.h b/src/include/stir/spatial_transformation/SpatialTransformation.h index 377c3b88c4..eaca5c4285 100644 --- a/src/include/stir/spatial_transformation/SpatialTransformation.h +++ b/src/include/stir/spatial_transformation/SpatialTransformation.h @@ -2,25 +2,25 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup spatial_transformation \brief Definition of class stir::SpatialTransformation \author Charalampos Tsoumpas - + */ #ifndef __stir_spatial_transformation_SpatialTransformation_H__ @@ -31,15 +31,14 @@ START_NAMESPACE_STIR -/*! +/*! \brief base class for any type of motion fields \ingroup spatial_transformation At present very basic. It just provides the parsing mechanism. */ -class SpatialTransformation: public RegisteredObject -{ - public: - static const char * const registered_name ; +class SpatialTransformation : public RegisteredObject { +public: + static const char* const registered_name; //! default constructor SpatialTransformation(); diff --git a/src/include/stir/spatial_transformation/warp_image.h b/src/include/stir/spatial_transformation/warp_image.h index 28dd2ca621..6b777f2c9b 100644 --- a/src/include/stir/spatial_transformation/warp_image.h +++ b/src/include/stir/spatial_transformation/warp_image.h @@ -2,23 +2,23 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup spatial_transformation - + \brief This warps an image. \author Charalampos Tsoumpas */ @@ -31,12 +31,11 @@ START_NAMESPACE_STIR -VoxelsOnCartesianGrid -warp_image(const shared_ptr > & density_sptr, - const shared_ptr > & motion_x_sptr, - const shared_ptr > & motion_y_sptr, - const shared_ptr > & motion_z_sptr, - const BSpline::BSplineType spline_type, const bool extend_borders); +VoxelsOnCartesianGrid warp_image(const shared_ptr>& density_sptr, + const shared_ptr>& motion_x_sptr, + const shared_ptr>& motion_y_sptr, + const shared_ptr>& motion_z_sptr, + const BSpline::BSplineType spline_type, const bool extend_borders); END_NAMESPACE_STIR diff --git a/src/include/stir/stir_math.h b/src/include/stir/stir_math.h index a5f611a5be..d3aa6bba01 100644 --- a/src/include/stir/stir_math.h +++ b/src/include/stir/stir_math.h @@ -1,17 +1,17 @@ /* Copyright (C) 2016, UCL This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ @@ -37,20 +37,17 @@ USING_NAMESPACE_STIR // places in the code. // a function object that takes a power of a float, and then multiplies with a float, and finally adds a float -class pow_times_add: public unary_function -{ +class pow_times_add : public unary_function { public: - pow_times_add(const float add_scalar, const float mult_scalar, const float power, - const float min_threshold, const float max_threshold) - : add(add_scalar), mult(mult_scalar), power(power), - min_threshold(min_threshold), max_threshold(max_threshold) - {} - - float operator()(float const arg) const - { + pow_times_add(const float add_scalar, const float mult_scalar, const float power, const float min_threshold, + const float max_threshold) + : add(add_scalar), mult(mult_scalar), power(power), min_threshold(min_threshold), max_threshold(max_threshold) {} + + float operator()(float const arg) const { const float value = min(max(arg, min_threshold), max_threshold); - return add+mult*(power==1?value : pow(value,power)); + return add + mult * (power == 1 ? value : pow(value, power)); } + private: const float add; const float mult; @@ -60,4 +57,3 @@ class pow_times_add: public unary_function }; #endif - diff --git a/src/include/stir/stream.h b/src/include/stir/stream.h index 54b7fad6f2..4fabf71af5 100644 --- a/src/include/stir/stream.h +++ b/src/include/stir/stream.h @@ -42,78 +42,68 @@ START_NAMESPACE_STIR /*! \brief Outputs a VectorWithOffset to a stream. - Output is of the form + Output is of the form \verbatim {1, 2, 3} \endverbatim - with an endl at the end. - - This can be used for higher dimensional arrays as well, where each 1D subobject + with an endl at the end. + + This can be used for higher dimensional arrays as well, where each 1D subobject will be on its own line. */ - template -inline -std::ostream& -operator<<(std::ostream& str, const VectorWithOffset& v); +inline std::ostream& operator<<(std::ostream& str, const VectorWithOffset& v); /*! \brief Outputs a BasicCoordinate to a stream. - Output is of the form + Output is of the form \verbatim {1, 2, 3} \endverbatim - with no endl at the end. + with no endl at the end. */ template -inline -std::ostream& -operator<<(std::ostream& str, const BasicCoordinate& v); - +inline std::ostream& operator<<(std::ostream& str, const BasicCoordinate& v); /*! \brief Outputs a vector to a stream. - Output is of the form + Output is of the form \verbatim {1, 2, 3} \endverbatim - with an endl at the end. - + with an endl at the end. + For each element of the vector std::ostream::operator<<() will be called. */ template -inline -std::ostream& -operator<<(std::ostream& str, const std::vector& v); +inline std::ostream& operator<<(std::ostream& str, const std::vector& v); /*! \brief Inputs a vector from a stream. - Input is of the form + Input is of the form \verbatim {1, 2, 3} \endverbatim - - Input is stopped when either the beginning '{', an intermediate ',' or the - trailing '}' is not found. The size of the vector will be the number of + + Input is stopped when either the beginning '{', an intermediate ',' or the + trailing '}' is not found. The size of the vector will be the number of correctly read elemT elements. - + For each element of the vector std::istream::operator>>(element) will be called. elemT needs to have a default constructor. */ template -inline -std::istream& -operator>>(std::istream& str, std::vector& v); +inline std::istream& operator>>(std::istream& str, std::vector& v); /*! \brief Inputs a VectorWithOffset from a stream. - Input is of the form + Input is of the form \verbatim {1, 2, 3} \endverbatim @@ -122,12 +112,12 @@ operator>>(std::istream& str, std::vector& v); \verbatim {{1,2}, {2,4,5}, {5}} \endverbatim - - - Input is stopped when either the beginning '{', an intermediate ',' or the - trailing '}' is not found. The size of the vector will be the number of + + + Input is stopped when either the beginning '{', an intermediate ',' or the + trailing '}' is not found. The size of the vector will be the number of correctly read elemT elements. - + v.get_min_index() will be 0 at the end of the call. For each element of the vector std::istream::operator>>(element) will be called. @@ -135,34 +125,29 @@ operator>>(std::istream& str, std::vector& v); elemT needs to have a default constructor. */ template -inline -std::istream& -operator>>(std::istream& str, VectorWithOffset& v); +inline std::istream& operator>>(std::istream& str, VectorWithOffset& v); /*! \brief Inputs a coordinate from a stream. - Input is of the form + Input is of the form \verbatim {1, 2, 3} \endverbatim - - Input is stopped when either the beginning '{', an intermediate ',' or the + + Input is stopped when either the beginning '{', an intermediate ',' or the trailing '}' is not found. If the number of correctly read elements is not \a num_dimensions, the last few will have undefined values. - + For each element of the vector std::istream::operator>>(element) will be called. elemT needs to have a default constructor. */ template -inline -std::istream& -operator>>(std::istream& str, BasicCoordinate& v); +inline std::istream& operator>>(std::istream& str, BasicCoordinate& v); END_NAMESPACE_STIR #include "stir/stream.inl" #endif - diff --git a/src/include/stir/stream.inl b/src/include/stir/stream.inl index 058e62c064..e441a2db9f 100644 --- a/src/include/stir/stream.inl +++ b/src/include/stir/stream.inl @@ -39,95 +39,82 @@ START_NAMESPACE_STIR template -std::ostream& -operator<<(std::ostream& str, const VectorWithOffset& v) -{ - str << '{'; - for (int i=v.get_min_index(); i0) - str << v[v.get_max_index()]; - str << '}' << std::endl; - return str; +std::ostream& +operator<<(std::ostream& str, const VectorWithOffset& v) { + str << '{'; + for (int i = v.get_min_index(); i < v.get_max_index(); i++) + str << v[i] << ", "; + + if (v.get_length() > 0) + str << v[v.get_max_index()]; + str << '}' << std::endl; + return str; } template -std::ostream& -operator<<(std::ostream& str, const BasicCoordinate& v) -{ - str << '{'; - for (int i=1; i0) - str << v[num_dimensions]; - str << '}'; - return str; +std::ostream& +operator<<(std::ostream& str, const BasicCoordinate& v) { + str << '{'; + for (int i = 1; i < num_dimensions; i++) + str << v[i] << ", "; + + if (num_dimensions > 0) + str << v[num_dimensions]; + str << '}'; + return str; } - template -std::ostream& -operator<<(std::ostream& str, const std::vector& v) -{ - str << '{'; - // slightly different from above because vector::size() is unsigned - // so 0-1 == 0xFFFFFFFF (and not -1) - if (v.size()>0) - { - for (unsigned int i=0; i& v) { + str << '{'; + // slightly different from above because vector::size() is unsigned + // so 0-1 == 0xFFFFFFFF (and not -1) + if (v.size() > 0) { + for (unsigned int i = 0; i < v.size() - 1; i++) + str << v[i] << ", "; + str << v[v.size() - 1]; + } + str << '}' << std::endl; + return str; } template -std::istream& -operator>>(std::istream& str, std::vector& v) -{ +std::istream& +operator>>(std::istream& str, std::vector& v) { v.resize(0); char c; str >> std::ws >> c; if (!str || c != '{') return str; - + elemT t; - do - { + do { str >> t; - if (!str.fail()) - { + if (!str.fail()) { v.push_back(t); str >> std::ws >> c; - } - else + } else break; - } - while (str && c == ','); + } while (str && c == ','); - if (str.fail()) - { + if (str.fail()) { str.clear(); str >> std::ws >> c; } - if (!str) - { + if (!str) { warning("\nreading a vector, expected closing }, but found EOF or worse. Length of vector returned is %ud\n", v.size()); return str; } - - if (c!= '}') + + if (c != '}') warning("\nreading a vector, expected closing }, found %c instead. Length of vector returned is %u\n", c, v.size()); return str; } template -std::istream& -operator>>(std::istream& str, VectorWithOffset& v) -{ +std::istream& +operator>>(std::istream& str, VectorWithOffset& v) { std::vector vv; str >> vv; v = VectorWithOffset(static_cast(vv.size())); @@ -136,36 +123,32 @@ operator>>(std::istream& str, VectorWithOffset& v) } template -std::istream& -operator>>(std::istream& str, BasicCoordinate& v) -{ +std::istream& +operator>>(std::istream& str, BasicCoordinate& v) { char c = '\0'; str >> std::ws >> c; - if (!str || c != '{') - { + if (!str || c != '{') { warning("reading a coordinate of dimension %d, expected opening {, found %c instead.\n" - "Elements will be undefined", num_dimensions, c); + "Elements will be undefined", + num_dimensions, c); return str; } - for (int i=1; i<=num_dimensions; i++) - { + for (int i = 1; i <= num_dimensions; i++) { c = '\0'; str >> v[i]; str >> std::ws >> c; - if (i
  • \c forw_iterT is a forward iterator
  • \c elemT must be assignable to *forw_iterT @@ -50,54 +50,44 @@ START_NAMESPACE_STIR */ template inline void -threshold_upper_lower(forw_iterT begin, forw_iterT end, - const elemT new_min, const elemT new_max) -{ - for (forw_iterT iter = begin; iter != end; ++iter) - { - if (*iter > new_max) - *iter = new_max; - else - if (new_min > *iter) - *iter = new_min; - } +threshold_upper_lower(forw_iterT begin, forw_iterT end, const elemT new_min, const elemT new_max) { + for (forw_iterT iter = begin; iter != end; ++iter) { + if (*iter > new_max) + *iter = new_max; + else if (new_min > *iter) + *iter = new_min; + } } //! Threshold a sequence from above -/*! +/*! \see threshold_upper_lower for type requirements */ template inline void -threshold_upper(forw_iterT begin, forw_iterT end, - const elemT new_max) -{ - for (forw_iterT iter = begin; iter != end; ++iter) - { - if (*iter > new_max) - *iter = new_max; - } +threshold_upper(forw_iterT begin, forw_iterT end, const elemT new_max) { + for (forw_iterT iter = begin; iter != end; ++iter) { + if (*iter > new_max) + *iter = new_max; + } } //! Threshold a sequence from below -/*! +/*! \see threshold_upper_lower for type requirements */ template inline void -threshold_lower(forw_iterT begin, forw_iterT end, - const elemT new_min) -{ - for (forw_iterT iter = begin; iter != end; ++iter) - { - if (new_min > *iter) - *iter = new_min; - } +threshold_lower(forw_iterT begin, forw_iterT end, const elemT new_min) { + for (forw_iterT iter = begin; iter != end; ++iter) { + if (new_min > *iter) + *iter = new_min; + } } //! sets non-positive values in the sequence to small positive ones /*! - Thresholds the sequence from below to + Thresholds the sequence from below to *min_positive_element()*small_number. - However, if all values are less than or equal to 0, they are + However, if all values are less than or equal to 0, they are set to \a small_number. \param begin start of the sequence. Usually object.begin(). @@ -107,17 +97,14 @@ threshold_lower(forw_iterT begin, forw_iterT end, The iterator type has to satisfy the requirements of a forward iterator, and its value_type has to be comparable using < and <=. -*/ +*/ template void -threshold_min_to_small_positive_value(ForwardIter_t begin, ForwardIter_t end, - const elemT& small_number) -{ - const ForwardIter_t smallest_positive_element_iter = - min_positive_element(begin, end); - - if (smallest_positive_element_iter!= end) - threshold_lower(begin, end, (*smallest_positive_element_iter)*small_number); +threshold_min_to_small_positive_value(ForwardIter_t begin, ForwardIter_t end, const elemT& small_number) { + const ForwardIter_t smallest_positive_element_iter = min_positive_element(begin, end); + + if (smallest_positive_element_iter != end) + threshold_lower(begin, end, (*smallest_positive_element_iter) * small_number); else std::fill(begin, end, small_number); } @@ -127,4 +114,3 @@ threshold_min_to_small_positive_value(ForwardIter_t begin, ForwardIter_t end, END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/unique_ptr.h b/src/include/stir/unique_ptr.h index a3d2bb8731..38068bc755 100644 --- a/src/include/stir/unique_ptr.h +++ b/src/include/stir/unique_ptr.h @@ -1,8 +1,8 @@ /*! \file \ingroup buildblock - - \brief Import of std::unique_ptr into the stir namespace, together with + + \brief Import of std::unique_ptr into the stir namespace, together with work-arounds for other compilers. If std::unique doesn't exist, we will define unique_ptr to auto_ptr. This is @@ -10,7 +10,7 @@ (normally by adding the -std=c++11 flag) \author Kris Thielemans -*/ +*/ /* Copyright (C) 2016, University College London This file is part of STIR. @@ -37,7 +37,7 @@ #if !defined(STIR_NO_UNIQUE_PTR) // simply use std::unique_ptr namespace stir { - using std::unique_ptr; +using std::unique_ptr; } #else // we need to replace it with something else @@ -46,16 +46,16 @@ namespace stir { // std::unique_ptr but even for Cxx03 compilers. However, end 2016 this still generated errors on OSX Sierra // with CLang (it could not return a unique_ptr). // So, this is attempt is now disabled. -#if 0 -#include -#if (BOOST_VERSION >= 105700) +# if 0 +# include +# if (BOOST_VERSION >= 105700) // Boost is recent enough to have a drop-in replacement -#include +# include namespace stir { using boost::movelib::unique_ptr; } -#endif -#endif +# endif +# endif // desperate measures. We will use a #define to auto_ptr. // Caveat: @@ -67,21 +67,21 @@ namespace stir { // We first include a bunch of system files which use std::unique_ptr such that we don't have a conflict. // You might have to add a few more... -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include -#define unique_ptr auto_ptr +# define unique_ptr auto_ptr using std::auto_ptr; #endif diff --git a/src/include/stir/utilities.h b/src/include/stir/utilities.h index d7d2dd94e8..522eca375c 100644 --- a/src/include/stir/utilities.h +++ b/src/include/stir/utilities.h @@ -16,9 +16,9 @@ See STIR/LICENSE.txt for details */ #ifndef __stir_UTILITIES_H__ -#define __stir_UTILITIES_H__ +#define __stir_UTILITIES_H__ /*! - \file + \file \ingroup buildblock \brief This file declares various utility functions. @@ -32,42 +32,34 @@ START_NAMESPACE_STIR - /******************************************************/ /*! \ingroup buildblock \name Functions for user input */ //@{ -//! A function to ask a number from the user +//! A function to ask a number from the user template -inline NUMBER -ask_num (const std::string& prompt, - NUMBER minimum_value, - NUMBER maximum_value, - NUMBER default_value); +inline NUMBER ask_num(const std::string& prompt, NUMBER minimum_value, NUMBER maximum_value, NUMBER default_value); -//! A function to ask a string from the user -std::string -ask_string(const std::string& prompt, const std::string& default_value = ""); +//! A function to ask a string from the user +std::string ask_string(const std::string& prompt, const std::string& default_value = ""); -/*! +/*! \brief A function to ask a yes/no question from the user - + \param prompt a text string which is supposed to be a question \param default_value When set to \c true , the default is Yes. The question is currently presented as \verbatim - prompt [Y/N D:default_value]: + prompt [Y/N D:default_value]: \endverbatim - Simply pressing 'enter' will select the default value. Otherwise, - the first charachter of the response will be checked against + Simply pressing 'enter' will select the default value. Otherwise, + the first charachter of the response will be checked against y/Y/n/N to determine the return value. If it is none of these, the question will be asked again. */ -bool -ask (const std::string& prompt, bool default_value); - +bool ask(const std::string& prompt, bool default_value); /***** filename functions ****/ @@ -83,16 +75,13 @@ ask (const std::string& prompt, bool default_value); char filename[max_filename_length]; ask_filename_with_extension(filename, "Input file name ?", ".img"); \endcode - \warning \a file_in_directory_name has to be preallocated + \warning \a file_in_directory_name has to be preallocated (with size \c max_filename_length) \warning starting or ending spaces are NOT stripped. */ -char * -ask_filename_with_extension(char *file_in_directory_name, - const std::string& prompt, - const std::string& default_extension); +char* ask_filename_with_extension(char* file_in_directory_name, const std::string& prompt, const std::string& default_extension); -/*! +/*! \brief Asks for a filename (appending an extension if none is provided). @@ -103,14 +92,12 @@ ask_filename_with_extension(char *file_in_directory_name, \endcode \warning starting or ending spaces are NOT stripped. */ -std::string -ask_filename_with_extension(const std::string& prompt, - const std::string& default_extension); +std::string ask_filename_with_extension(const std::string& prompt, const std::string& default_extension); /*! \brief Asks for a filename (with default extension) and opens the stream \a s - with \a mode giving the specifics. + with \a mode giving the specifics. Example: open a binary input file, aborting if it is not found \code @@ -123,22 +110,13 @@ ask_filename_with_extension(const std::string& prompt, // Implementation note: gcc 2.8.1 seems to have problems with default // values when templates are around, so I overload the function template -void -ask_filename_and_open(FSTREAM& s, - const std::string& prompt, - const std::string& default_extension, - std::ios::openmode mode, - bool abort_if_failed); +void ask_filename_and_open(FSTREAM& s, const std::string& prompt, const std::string& default_extension, std::ios::openmode mode, + bool abort_if_failed); //! as above, but with default \c abort_if_failed = true template -void -inline -ask_filename_and_open(FSTREAM& s, - const std::string& prompt, - const std::string& default_extension, - std::ios::openmode mode) -{ +void inline ask_filename_and_open(FSTREAM& s, const std::string& prompt, const std::string& default_extension, + std::ios::openmode mode) { ask_filename_and_open(s, prompt, default_extension, mode, true); } @@ -149,65 +127,60 @@ ask_filename_and_open(FSTREAM& s, \name Functions for stream/file manipulations */ //@{ -/*! +/*! \brief reads data into memory, returning a pointer to the memory If the file_size parameter is zero, the stream is read till EOF - and 'file_size' is set to the number of bytes in the file. + and 'file_size' is set to the number of bytes in the file. Otherwise 'file_size' bytes are read. The data is read from the current position in the stream. - At the end of this function, the 'input' stream will be positioned + At the end of this function, the 'input' stream will be positioned at original_position + file_size. */ -void * read_stream_in_memory(std::istream& input, std::streamsize& file_size); +void* read_stream_in_memory(std::istream& input, std::streamsize& file_size); -/*! +/*! \brief Find number of remaining characters in the stream - At the end of this function, the 'input' stream will be positioned + At the end of this function, the 'input' stream will be positioned at the original_position. \warning Works only properly for binary streams. */ -std::streamsize find_remaining_size (std::istream& input); +std::streamsize find_remaining_size(std::istream& input); //! opens a stream for reading binary data. Calls error() when it does not succeed. /*! \warning probably does not work if you are not in the C-locale */ template -inline IFSTREAM& open_read_binary(IFSTREAM& s, - const std::string& name); +inline IFSTREAM& open_read_binary(IFSTREAM& s, const std::string& name); //! opens a FILE for reading binary data. Calls error() when it does not succeed. /*! \warning probably does not work if you are not in the C-locale*/ -FILE*& open_read_binary(FILE*& fptr, - const std::string& name); +FILE*& open_read_binary(FILE*& fptr, const std::string& name); //! opens a stream for writing binary data. Calls error() when it does not succeed. -/*! +/*! Templated such that it works on std::ofstream and std::fstream. \warning probably does not work if you are not in the C-locale */ template -inline OFSTREAM& open_write_binary(OFSTREAM& s, - const std::string& name); +inline OFSTREAM& open_write_binary(OFSTREAM& s, const std::string& name); //! opens a FILE for writing binary data. Calls error() when it does not succeed. /*! \warning probably does not work if you are not in the C-locale*/ -FILE*& open_write_binary(FILE*& fptr, - const std::string& name); - +FILE*& open_write_binary(FILE*& fptr, const std::string& name); //! closes a stream without error checking. -/*! +/*! Templated such that it works on std::ofstream, std::ifstream and std::fstream. - This function is only provided in case you need to write code that works with + This function is only provided in case you need to write code that works with both std::fstream and stdio FILE. */ template inline void close_file(FSTREAM& s); //! closes a FILE without error checking. -/*! - This function is only provided in case you need to write code that works with +/*! + This function is only provided in case you need to write code that works with both std::fstream and stdio FILE. */ void close_file(FILE*& fptr); @@ -215,7 +188,7 @@ void close_file(FILE*& fptr); //@} /*! \brief - some large value to say how long filenames can be in + some large value to say how long filenames can be in the (deprecated) function ask_filename_with_extension(char *,const std::string&, const std::string&) \ingroup buildblock @@ -226,7 +199,7 @@ const int max_filename_length = 1000; /*! \ingroup buildblock \name Functions for filename manipulations - These functions work on different platforms, i.e. Unix, VAX, Windows. Also on + These functions work on different platforms, i.e. Unix, VAX, Windows. Also on older MacOS versions. \warning Functions that work on char* might be removed at some point. @@ -234,7 +207,7 @@ const int max_filename_length = 1000; //@{ //! return a pointer to the start of the filename (i.e. after directory specifications) -/*! The returned pointer is between filename_with_directory and +/*! The returned pointer is between filename_with_directory and (filename_with_directory+strlen(filename_with_directory)+1). This highest value is used when it looks like a directory name. @@ -242,8 +215,7 @@ const int max_filename_length = 1000; \warning This function works only with string manipulations. There is no check if the 'filename' part actually corresponds to a directory on disk. */ -extern const char * -find_filename(const char * const filename_with_directory); +extern const char* find_filename(const char* const filename_with_directory); //! return the position of the start of the filename (i.e. after directory specifications) /*! The returned number is between 0 and filename_with_directory.size()+1. This @@ -251,18 +223,16 @@ find_filename(const char * const filename_with_directory); \warning This function works only with string manipulations. There is no check if the 'filename' part actually corresponds to a directory on disk. */ -std::string::size_type -find_pos_of_filename(const std::string& filename_with_directory); +std::string::size_type find_pos_of_filename(const std::string& filename_with_directory); //! return a std::string containing only the filename (i.e. after directory specifications) /*! \warning This function works only with string manipulations. There is no check if the 'filename' part actually corresponds to a directory on disk. */ -std::string -get_filename(const std::string& filename_with_directory); +std::string get_filename(const std::string& filename_with_directory); -/*! +/*! \brief Copies the directory part from 'filename_with_directory' into 'directory_name' and returns the 'directory_name' pointer. @@ -272,9 +242,7 @@ get_filename(const std::string& filename_with_directory); \warning assumes that directory_name points to enough allocated space \deprecated Use get_directory_name(const std::string&) */ -char * -get_directory_name(char *directory_name, - const char * const filename_with_directory); +char* get_directory_name(char* directory_name, const char* const filename_with_directory); //! Returns a string with the directory part from 'filename_with_directory'. /*! @@ -284,27 +252,23 @@ get_directory_name(char *directory_name, \warning This function works only with string manipulations. There is no check if the 'filename' part actually corresponds to a directory on disk. */ -std::string -get_directory_name(const std::string& filename_with_directory); +std::string get_directory_name(const std::string& filename_with_directory); -/*! +/*! \brief Checks if the filename points to an absolute location, or is a relative (e.g. to current directory) pathname. */ -extern bool -is_absolute_pathname(const std::string& filename_with_directory); +extern bool is_absolute_pathname(const std::string& filename_with_directory); -/*! +/*! \brief Checks if the filename points to an absolute location, or is a relative (e.g. to current directory) pathname. */ -extern bool -is_absolute_pathname(const char * const filename_with_directory); +extern bool is_absolute_pathname(const char* const filename_with_directory); - -/*! +/*! \brief Prepend directory_name to the filename, but only if !is_absolute_pathname(filename_with_directory) @@ -312,20 +276,17 @@ is_absolute_pathname(const char * const filename_with_directory); If necessary, a directory separator is inserted. If 'directory_name' == 0, nothing happens. \return a pointer to the start of the new filename - \warning this function assumes that filename_with_directory + \warning this function assumes that filename_with_directory points to sufficient allocated space to contain the new string. */ -extern char * -prepend_directory_name(char * filename_with_directory, - const char * const directory_name); +extern char* prepend_directory_name(char* filename_with_directory, const char* const directory_name); //! find the position of the '.' of the extension -/*! +/*! If no '.' is found in the filename part (i.e. ignoring the directory name), the function returns \c std::string::npos */ -std::string::size_type -find_pos_of_extension(const std::string& file_in_directory_name); +std::string::size_type find_pos_of_extension(const std::string& file_in_directory_name); #if 0 // terribly dangerous for memory overrun. @@ -351,9 +312,7 @@ add_extension(char * file_in_directory_name, #endif //! Append extension if none present -std::string& -add_extension(std::string& file_in_directory_name, - const std::string& extension); +std::string& add_extension(std::string& file_in_directory_name, const std::string& extension); #if 0 // disabled because possible memory overrun @@ -380,10 +339,7 @@ replace_extension(char *file_in_directory_name, #endif //! Replace extension (or append if none present) -std::string& -replace_extension(std::string& file_in_directory_name, - const std::string& extension); - +std::string& replace_extension(std::string& file_in_directory_name, const std::string& extension); //@} @@ -394,10 +350,10 @@ replace_extension(std::string& file_in_directory_name, //! make C-string uppercase /*! \ingroup buildblock -*/ -inline char *strupr(char * const str); + */ +inline char* strupr(char* const str); #else -#define strupr _strupr +# define strupr _strupr #endif END_NAMESPACE_STIR diff --git a/src/include/stir/utilities.inl b/src/include/stir/utilities.inl index 84ddedd578..07f446937e 100644 --- a/src/include/stir/utilities.inl +++ b/src/include/stir/utilities.inl @@ -1,6 +1,6 @@ /*! - \file - \ingroup buildblock + \file + \ingroup buildblock \brief inline implementations for utility.h \author Kris Thielemans @@ -25,95 +25,85 @@ */ #include #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif START_NAMESPACE_STIR /*! The question is currently presented as \verbatim - str_text : [minimum_value, maximum_value, D: default_value]: + str_text : [minimum_value, maximum_value, D: default_value]: \endverbatim - Simply pressing 'enter' will select the default value. Otherwise, range + Simply pressing 'enter' will select the default value. Otherwise, range checking is performed, and the question asked again if necessary. */ template -inline NUMBER -ask_num (const std::string& str, - NUMBER minimum_value, - NUMBER maximum_value, - NUMBER default_value) -{ - - while(1) - { +inline NUMBER +ask_num(const std::string& str, NUMBER minimum_value, NUMBER maximum_value, NUMBER default_value) { + + while (1) { std::string input; - std::cerr << "\n" << str - << "[" << minimum_value << "," << maximum_value - << " D:" << default_value << "]: "; + std::cerr << "\n" << str << "[" << minimum_value << "," << maximum_value << " D:" << default_value << "]: "; std::getline(std::cin, input); #ifdef BOOST_NO_STRINGSTREAM istrstream ss(input.c_str()); #else std::istringstream ss(input.c_str()); #endif - + NUMBER value = default_value; ss >> value; - if ((value>=minimum_value) && (maximum_value>=value)) + if ((value >= minimum_value) && (maximum_value >= value)) return value; std::cerr << "\nOut of bounds. Try again."; } } - - template -inline IFSTREAM& open_read_binary(IFSTREAM& s, - const std::string& name) -{ +inline IFSTREAM& +open_read_binary(IFSTREAM& s, const std::string& name) { #if 0 //KT 30/07/98 The next lines are only necessary (in VC 5.0) when importing // . We use now, so they are disabled. // Visual C++ does not complain when opening a nonexisting file for reading, // unless using std::ios::nocreate - s.open(name.c_str(), std::ios::in | std::ios::binary | std::ios::nocreate); + s.open(name.c_str(), std::ios::in | std::ios::binary | std::ios::nocreate); #else - s.open(name.c_str(), std::ios::in | std::ios::binary); + s.open(name.c_str(), std::ios::in | std::ios::binary); #endif // KT 14/01/2000 added name of file in error message - if (s.fail() || s.bad()) - { error("Error opening file %s\n", name.c_str()); } + if (s.fail() || s.bad()) { + error("Error opening file %s\n", name.c_str()); + } return s; } template -inline OFSTREAM& open_write_binary(OFSTREAM& s, - const std::string& name) -{ - s.open(name.c_str(), std::ios::out | std::ios::binary); - // KT 14/01/2000 added name of file in error message - if (s.fail() || s.bad()) - { error("Error opening file %s\n", name.c_str()); } - return s; +inline OFSTREAM& +open_write_binary(OFSTREAM& s, const std::string& name) { + s.open(name.c_str(), std::ios::out | std::ios::binary); + // KT 14/01/2000 added name of file in error message + if (s.fail() || s.bad()) { + error("Error opening file %s\n", name.c_str()); + } + return s; } template -inline void close_file(FSTREAM& s) -{ +inline void +close_file(FSTREAM& s) { s.close(); } - #ifndef _MSC_VER -char *strupr(char * const str) -{ - for (char *a = str; *a; a++) - { - if ((*a >= 'a')&&(*a <= 'z')) *a += 'A'-'a'; +char* +strupr(char* const str) { + for (char* a = str; *a; a++) { + if ((*a >= 'a') && (*a <= 'z')) + *a += 'A' - 'a'; }; return str; } diff --git a/src/include/stir/warning.h b/src/include/stir/warning.h index 81aaba9985..68006b9a01 100644 --- a/src/include/stir/warning.h +++ b/src/include/stir/warning.h @@ -43,9 +43,7 @@ START_NAMESPACE_STIR \deprecated (use 1 argument version instead) */ -void -warning(const char *const s, ...); - +void warning(const char* const s, ...); //! Use this function for writing warning messages /*! \ingroup buildblock @@ -54,7 +52,7 @@ warning(const char *const s, ...); std::ostream::operator\<\< would work. This function currently first writes a newline, then \c WARNING:, then \c string - and then another newline to std::cerr. + and then another newline to std::cerr. \todo At a later stage, it will also write to a log-file. @@ -70,11 +68,8 @@ warning(const char *const s, ...); template inline void -warning(const STRING& string) -{ - std::cerr << "\nWARNING: " - << string - << std::endl; +warning(const STRING& string) { + std::cerr << "\nWARNING: " << string << std::endl; } END_NAMESPACE_STIR #endif diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index 4e25da9182..e38892311a 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -17,11 +17,11 @@ See STIR/LICENSE.txt for details */ #ifndef __stir_ZOOM_H__ -#define __stir_ZOOM_H__ +#define __stir_ZOOM_H__ /*! - \file - + \file + \brief This file declares various zooming functions. \ingroup buildblock \author Kris Thielemans @@ -32,15 +32,15 @@ These functions can be used for zooming of projection data or image data. - Zooming requires interpolation. Currently, this is done using + Zooming requires interpolation. Currently, this is done using stir::overlap_interpolate. - + The first set of functions allows zooming and translation in transaxial planes only. These parameters are the same for projection data or image data. That is, zoomed projection data are (approximately) the forward projections of zoomed images with the same parameters. These functions have the following parameters: - + \param zoom scales the projection bins (zoom larger than 1 means more detail, so smaller pixels) \param x_offset_in_mm x-coordinate of new origin (in mm) \param y_offset_in_mm y-coordinate of new origin (in mm) @@ -50,13 +50,13 @@ This allows 2-dimensional zooming and translation on arccorrected data, here translation means a translation in 'image' space which gives a \c sin shift of origin in the \c s - coordinate in - projection space. + projection space. The new range of \c s coordinates is given by - \param min_tang_pos_num [for projection data only] the minimum tangential position number in the new + \param min_tang_pos_num [for projection data only] the minimum tangential position number in the new projection line - \param max_tang_pos_num [for projection data only] the maximum tangential position number in the new + \param max_tang_pos_num [for projection data only] the maximum tangential position number in the new projection line - Note that the (projection of the) centre of the scanner axis is supposed to be + Note that the (projection of the) centre of the scanner axis is supposed to be at \a tang_pos_num = 0. \par images @@ -65,27 +65,27 @@ zooming and translation. Parameters are derived either from stir::CartesianCoordinate3D objects, or from the information in the \a in and \a out images. - + In the case that the offsets are 0, the following holds:
    • If \c size is equal to \c zoom*old_size, the same amount of data is represented.
    • If it is less, data are truncated.
    • If it is larger, the outer ends are filled with 0.
    - - + + \warning Because overlap_interpolate is used, the zooming is 'count-preserving', i.e. when the output range is large enough, the in.sum() == out.sum(). \warning In STIR 1.x, origins were taken relative to the centre of the coordinate range: -\code - x_in_mm = (x_index - x_ctr_index) * voxel_size.x() + origin.x() +\code + x_in_mm = (x_index - x_ctr_index) * voxel_size.x() + origin.x() \endcode - where -\code + where +\code x_ctr_index = (x_max_index + x_min_index)/2 \endcode - This is no longer true. Instead we use + This is no longer true. Instead we use DiscretisedDensity\<3,float\>::get_physical_coordinates_for_indices. */ @@ -94,12 +94,18 @@ START_NAMESPACE_STIR -template class Viewgram; -template class RelatedViewgrams; -template class VoxelsOnCartesianGrid; -template class PixelsOnCartesianGrid; -template class CartesianCoordinate3D; -template class BasicCoordinate; +template +class Viewgram; +template +class RelatedViewgrams; +template +class VoxelsOnCartesianGrid; +template +class PixelsOnCartesianGrid; +template +class CartesianCoordinate3D; +template +class BasicCoordinate; /*! \ingroup buildblock @@ -111,34 +117,24 @@ template class BasicCoordinate; \brief zoom a RelatedViewgrams object, replacing it with the new data \see zoom.h for parameter info */ -void -zoom_viewgrams (RelatedViewgrams& viewgrams, - const float zoom, - const int min_tang_pos_num, const int max_tang_pos_num, - const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); +void zoom_viewgrams(RelatedViewgrams& viewgrams, const float zoom, const int min_tang_pos_num, const int max_tang_pos_num, + const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); /*! \brief zoom \a viewgram, replacing it with the new data \see zoom.h for parameter info */ -void -zoom_viewgram (Viewgram& viewgram, - const float zoom, - const int min_tang_pos_num, const int max_tang_pos_num, - const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); +void zoom_viewgram(Viewgram& viewgram, const float zoom, const int min_tang_pos_num, const int max_tang_pos_num, + const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); /*! \brief zoom \a in_viewgram, replacing \a out_viewgram with the new data - - This version of zoom_viewgram gets the info on the new sizes, sampling etc. + + This version of zoom_viewgram gets the info on the new sizes, sampling etc. from \a out_viewgram. \see zoom.h for parameter info */ -void -zoom_viewgram (Viewgram& out_viewgram, - const Viewgram& in_viewgram, - const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); - - +void zoom_viewgram(Viewgram& out_viewgram, const Viewgram& in_viewgram, const float x_offset_in_mm = 0, + const float y_offset_in_mm = 0); /*! \brief zoom \a image, returning the new image @@ -146,21 +142,18 @@ zoom_viewgram (Viewgram& out_viewgram, \see zoom_image_in_place */ -VoxelsOnCartesianGrid -zoom_image(const VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& offsets_in_mm, - const BasicCoordinate<3,int>& new_sizes, - const ZoomOptions = ZoomOptions::preserve_sum); - -/*! - \brief - zoom \a image, replacing the first argument with the new data. - Full 3D shifts and zooms. +VoxelsOnCartesianGrid zoom_image(const VoxelsOnCartesianGrid& image, const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& offsets_in_mm, + const BasicCoordinate<3, int>& new_sizes, const ZoomOptions = ZoomOptions::preserve_sum); + +/*! + \brief + zoom \a image, replacing the first argument with the new data. + Full 3D shifts and zooms. \see zoom.h for parameter info. Zooming is done such that the physical coordinates of a point - (as returned by + (as returned by DiscretisedDensity\<3,float\>::get_physical_coordinates_for_indices) remain the same. @@ -177,19 +170,16 @@ zoom_image(const VoxelsOnCartesianGrid &image, \warning: For even-sized images, this convention can lead to somewhat non-intuitive results (half-pixel shifts etc). */ -void -zoom_image_in_place(VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& offsets_in_mm, - const BasicCoordinate<3,int>& new_sizes, - const ZoomOptions = ZoomOptions::preserve_sum); +void zoom_image_in_place(VoxelsOnCartesianGrid& image, const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& offsets_in_mm, const BasicCoordinate<3, int>& new_sizes, + const ZoomOptions = ZoomOptions::preserve_sum); /*! \brief zoom \a image_in according to dimensions, origin and voxel_size of \a image_out. \see zoom.h for parameter info Zooming is done such that the physical coordinates of a point - (as returned by + (as returned by DiscretisedDensity\<3,float\>::get_physical_coordinates_for_indices) remain the same. @@ -198,49 +188,37 @@ zoom_image_in_place(VoxelsOnCartesianGrid &image, (ii) preserving the image projectors: should be used when zooming an activity image (iii) preserving the image sum: default */ -void -zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, - const ZoomOptions = ZoomOptions::preserve_sum); +void zoom_image(VoxelsOnCartesianGrid& image_out, const VoxelsOnCartesianGrid& image_in, + const ZoomOptions = ZoomOptions::preserve_sum); //------------------ 2D zooms--------------------- -/*! -\brief -zoom \a image2D_in according to dimensions, origin and pixel_size of +/*! +\brief +zoom \a image2D_in according to dimensions, origin and pixel_size of \a image2D_out. \see zoom.h for parameter info */ -void -zoom_image(PixelsOnCartesianGrid &image2D_out, - const PixelsOnCartesianGrid &image2D_in, - const ZoomOptions = ZoomOptions::preserve_sum); +void zoom_image(PixelsOnCartesianGrid& image2D_out, const PixelsOnCartesianGrid& image2D_in, + const ZoomOptions = ZoomOptions::preserve_sum); /*! \brief zoom \a image, replacing the first argument with the new data \see zoom.h for parameter info */ -VoxelsOnCartesianGrid -zoom_image(const VoxelsOnCartesianGrid &image, - const float zoom, - const float x_offset_in_mm, const float y_offset_in_mm, - const int new_size, - const ZoomOptions = ZoomOptions::preserve_sum); +VoxelsOnCartesianGrid zoom_image(const VoxelsOnCartesianGrid& image, const float zoom, const float x_offset_in_mm, + const float y_offset_in_mm, const int new_size, + const ZoomOptions = ZoomOptions::preserve_sum); /*! \brief zoom \a image, replacing the first argument with the new data \see zoom.h for parameter info */ -void -zoom_image_in_place(VoxelsOnCartesianGrid &image, - const float zoom, - const float x_offset_in_mm, const float y_offset_in_mm, - const int new_size, - const ZoomOptions = ZoomOptions::preserve_sum); +void zoom_image_in_place(VoxelsOnCartesianGrid& image, const float zoom, const float x_offset_in_mm, + const float y_offset_in_mm, const int new_size, const ZoomOptions = ZoomOptions::preserve_sum); //@} END_NAMESPACE_STIR #endif - diff --git a/src/include/stir_experimental/AbsTimeInterval.h b/src/include/stir_experimental/AbsTimeInterval.h index 8d4ad0e2d7..ec98cccfaf 100644 --- a/src/include/stir_experimental/AbsTimeInterval.h +++ b/src/include/stir_experimental/AbsTimeInterval.h @@ -27,35 +27,22 @@ START_NAMESPACE_STIR Absolute time means at present 'secs since midnight 1/1/1970 UTC' */ -class AbsTimeInterval: public RegisteredObject -{ +class AbsTimeInterval : public RegisteredObject { public: virtual ~AbsTimeInterval() {} - AbsTimeInterval() - : - _start_time_in_secs_since_1970(0), - _end_time_in_secs_since_1970(0) - {} - AbsTimeInterval( double start_time_in_secs_since_1970, - double end_time_in_secs_since_1970) - : - _start_time_in_secs_since_1970(start_time_in_secs_since_1970), - _end_time_in_secs_since_1970(end_time_in_secs_since_1970) - {} - - - double get_start_time_in_secs_since_1970() const - { return _start_time_in_secs_since_1970; } - double get_end_time_in_secs_since_1970() const - { return _end_time_in_secs_since_1970; } - double get_duration_in_secs() const - { return _end_time_in_secs_since_1970 - _start_time_in_secs_since_1970; } - - protected: + AbsTimeInterval() : _start_time_in_secs_since_1970(0), _end_time_in_secs_since_1970(0) {} + AbsTimeInterval(double start_time_in_secs_since_1970, double end_time_in_secs_since_1970) + : _start_time_in_secs_since_1970(start_time_in_secs_since_1970), _end_time_in_secs_since_1970(end_time_in_secs_since_1970) { + } + + double get_start_time_in_secs_since_1970() const { return _start_time_in_secs_since_1970; } + double get_end_time_in_secs_since_1970() const { return _end_time_in_secs_since_1970; } + double get_duration_in_secs() const { return _end_time_in_secs_since_1970 - _start_time_in_secs_since_1970; } + +protected: double _start_time_in_secs_since_1970; double _end_time_in_secs_since_1970; - }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/AbsTimeIntervalFromDynamicData.h b/src/include/stir_experimental/AbsTimeIntervalFromDynamicData.h index 11ff451c99..570ccd0d34 100644 --- a/src/include/stir_experimental/AbsTimeIntervalFromDynamicData.h +++ b/src/include/stir_experimental/AbsTimeIntervalFromDynamicData.h @@ -29,7 +29,7 @@ class Succeeded; The dynamic scan can be either a sinogram of an image. It is read via DynamicProjData or DynamicDiscretisedDensity. - + \par Example .par file \verbatim ; example keyword in some .par file @@ -43,27 +43,23 @@ class Succeeded; */ class AbsTimeIntervalFromDynamicData -: public RegisteredParsingObject -{ + : public RegisteredParsingObject { public: - //! Name which will be used when parsing a AbsTimeInterval object - static const char * const registered_name; + //! Name which will be used when parsing a AbsTimeInterval object + static const char* const registered_name; virtual ~AbsTimeIntervalFromDynamicData() {} //! default constructor gives ill-defined values AbsTimeIntervalFromDynamicData(); //! read info from file /*! will call error() if something goes wrong */ - AbsTimeIntervalFromDynamicData(const std::string& filename, - const unsigned int start_time_frame_num, + AbsTimeIntervalFromDynamicData(const std::string& filename, const unsigned int start_time_frame_num, const unsigned int end_time_frame_num); - - private: - std::string _filename; - //TimeFrameDefinitions _time_frame_defs; + +private: + std::string _filename; + // TimeFrameDefinitions _time_frame_defs; double _scan_start_time_in_secs_since_1970; // start of scan, not the time-interval unsigned int _start_time_frame_num; unsigned int _end_time_frame_num; @@ -72,9 +68,7 @@ class AbsTimeIntervalFromDynamicData virtual void initialise_keymap(); virtual bool post_processing(); - Succeeded set_times(); - }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/AbsTimeIntervalFromECAT7ACF.h b/src/include/stir_experimental/AbsTimeIntervalFromECAT7ACF.h index 7693defa86..b0853ac73e 100644 --- a/src/include/stir_experimental/AbsTimeIntervalFromECAT7ACF.h +++ b/src/include/stir_experimental/AbsTimeIntervalFromECAT7ACF.h @@ -27,30 +27,26 @@ class Succeeded; \brief class for specifying a time interval via an ECAT7 .a file The ECAT7 header for a .a file does not record the scan duration, but only - the start time of the transmission scan. So, we have to explicitly ask for + the start time of the transmission scan. So, we have to explicitly ask for the duration. - + */ class AbsTimeIntervalFromECAT7ACF -: public RegisteredParsingObject -{ + : public RegisteredParsingObject { public: - //! Name which will be used when parsing a AbsTimeInterval object - static const char * const registered_name; + //! Name which will be used when parsing a AbsTimeInterval object + static const char* const registered_name; virtual ~AbsTimeIntervalFromECAT7ACF() {} //! default constructor sets duration to -1 (i.e. ill-defined) AbsTimeIntervalFromECAT7ACF(); //! read info from ECAT7 file /*! will call error() if something goes wrong */ - AbsTimeIntervalFromECAT7ACF(const std::string& filename, - const double duration_in_secs); - - private: - std::string _attenuation_filename; + AbsTimeIntervalFromECAT7ACF(const std::string& filename, const double duration_in_secs); + +private: + std::string _attenuation_filename; double _transmission_duration; virtual void set_defaults(); @@ -58,7 +54,6 @@ class AbsTimeIntervalFromECAT7ACF virtual bool post_processing(); Succeeded set_times(); - }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/AbsTimeIntervalWithParsing.h b/src/include/stir_experimental/AbsTimeIntervalWithParsing.h index dae449bd51..88ff94b55b 100644 --- a/src/include/stir_experimental/AbsTimeIntervalWithParsing.h +++ b/src/include/stir_experimental/AbsTimeIntervalWithParsing.h @@ -29,28 +29,22 @@ class Succeeded; start and end times from a file. This functionality could potentially be put in AbsTimeInterval, but that would give an overlap/conflict with keywords of other derived classes. - + */ -class AbsTimeIntervalWithParsing -: public RegisteredParsingObject -{ +class AbsTimeIntervalWithParsing : public RegisteredParsingObject { public: - //! Name which will be used when parsing a AbsTimeInterval object - static const char * const registered_name; + //! Name which will be used when parsing a AbsTimeInterval object + static const char* const registered_name; virtual ~AbsTimeIntervalWithParsing() {} //! default constructor sets times to invalid values AbsTimeIntervalWithParsing(); - - private: +private: virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/DAVArrayFilter3D.h b/src/include/stir_experimental/DAVArrayFilter3D.h index 489050f659..917e18f38d 100644 --- a/src/include/stir_experimental/DAVArrayFilter3D.h +++ b/src/include/stir_experimental/DAVArrayFilter3D.h @@ -4,13 +4,13 @@ \file - \brief + \brief \author Sanida Mustafovic \author Kris Thielemans - Warning: - At the moment it is essential to have + Warning: + At the moment it is essential to have mask_radius_x = mask_radius_y =mask_radius_z = odd. */ @@ -19,39 +19,32 @@ See STIR/LICENSE.txt for details */ - #ifndef __stir_DAVArrayFilter3D_H__ #define __stir_DAVArrayFilter3D_H__ #include "stir/ArrayFunctionObject_2ArgumentImplementation.h" - START_NAMESPACE_STIR -template class Coordinate3D; - +template +class Coordinate3D; template -class DAVArrayFilter3D: public ArrayFunctionObject_2ArgumentImplementation<3,elemT> -{ +class DAVArrayFilter3D : public ArrayFunctionObject_2ArgumentImplementation<3, elemT> { public: - DAVArrayFilter3D (const Coordinate3D& mask_radius = Coordinate3D()); + DAVArrayFilter3D(const Coordinate3D& mask_radius = Coordinate3D()); bool is_trivial() const; private: - int mask_radius_x; - int mask_radius_y; - int mask_radius_z; - - virtual void do_it (Array<3,elemT>& out_array, const Array<3,elemT>& in_array) const; + int mask_radius_x; + int mask_radius_y; + int mask_radius_z; - void extract_neighbours_and_average(elemT& out_elem, const Array<3,elemT>& in_array,const Coordinate3D& c_pixel) const; + virtual void do_it(Array<3, elemT>& out_array, const Array<3, elemT>& in_array) const; + void extract_neighbours_and_average(elemT& out_elem, const Array<3, elemT>& in_array, const Coordinate3D& c_pixel) const; }; END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir_experimental/DAVImageFilter3D.h b/src/include/stir_experimental/DAVImageFilter3D.h index 3c841dfcc1..9c5b758ca6 100644 --- a/src/include/stir_experimental/DAVImageFilter3D.h +++ b/src/include/stir_experimental/DAVImageFilter3D.h @@ -24,13 +24,12 @@ \author Sanida Mustafovic \author Kris Thielemans - + */ #ifndef __stir_DAVImageFilter3D_H__ #define __stir_DAVImageFilter3D_H__ - #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" #include "stir_experimental/DAVArrayFilter3D.h" @@ -39,42 +38,35 @@ START_NAMESPACE_STIR -template class CartesianCoordinate3D; +template +class CartesianCoordinate3D; template -class DAVImageFilter3D: - public - RegisteredParsingObject< - DAVImageFilter3D, - DataProcessor >, - DataProcessor > - > +class DAVImageFilter3D : public RegisteredParsingObject, DataProcessor>, + DataProcessor>> { public: - static const char * const registered_name; + static const char* const registered_name; DAVImageFilter3D(); - DAVImageFilter3D(const CartesianCoordinate3D& mask_radius); - + DAVImageFilter3D(const CartesianCoordinate3D& mask_radius); + private: DAVArrayFilter3D dav_filter; int mask_radius_x; int mask_radius_y; int mask_radius_z; - virtual void set_defaults(); virtual void initialise_keymap(); - Succeeded virtual_set_up (const DiscretisedDensity< 3,elemT>& density); - void virtual_apply(DiscretisedDensity<3,elemT>& density, const DiscretisedDensity<3,elemT>& in_density) const; - void virtual_apply(DiscretisedDensity<3,elemT>& density) const; + Succeeded virtual_set_up(const DiscretisedDensity<3, elemT>& density); + void virtual_apply(DiscretisedDensity<3, elemT>& density, const DiscretisedDensity<3, elemT>& in_density) const; + void virtual_apply(DiscretisedDensity<3, elemT>& density) const; }; - END_NAMESPACE_STIR - -#endif // DAVImageFilter3D +#endif // DAVImageFilter3D diff --git a/src/include/stir_experimental/Filter.h b/src/include/stir_experimental/Filter.h index 13d1263343..c38a1cd905 100644 --- a/src/include/stir_experimental/Filter.h +++ b/src/include/stir_experimental/Filter.h @@ -1,8 +1,8 @@ // // -/*! - \file +/*! + \file \brief Filter classes (filter defined in Fourier space) \author Kris Thielemans \author Claire LABBE @@ -14,9 +14,8 @@ See STIR/LICENSE.txt for details */ - #ifndef __FILTER_H__ -#define __FILTER_H__ +#define __FILTER_H__ #include "stir/TimedObject.h" #include "stir/Array.h" @@ -25,8 +24,8 @@ START_NAMESPACE_STIR -template class Array; - +template +class Array; /*! \brief Preliminary class for 1D filtering using FFTs @@ -34,112 +33,107 @@ template class Array; \warning The filtering will be performed using the convlvC() function. See warnings in its documentation. \todo apply() members can't be const as they call TimedObject::start_timers() */ -template class Filter1D : public TimedObject - { - // AZ public, as need to access length for parallel FBP3DRP code (TODO) -// protected: - public: - //! Stores the filter in frequency space (will be private sometime) - Array<1,float> filter; - public: - Filter1D(const int length_v) - : filter(1,length_v) - {} - Filter1D(const Array<1,T> &filter) - : filter(filter) - {} - virtual ~Filter1D() {} - - //! Filters data (which has to be in the 'spatial' domain - /*! data will be padded with zeroes to the same length as the stored filter before - filtering. This is done on a local copy of the data, such that the index range of - \a data is not modified. - */ - inline void apply(Array<1,T> &data); - //! Applies the filter on each 1D subarray - inline void apply(Array<2,T> &data); - //! Applies the filter on each 1D subarray - inline void apply(Array<3,T> &data); - - - virtual std::string parameter_info() const = 0; +template +class Filter1D : public TimedObject { + // AZ public, as need to access length for parallel FBP3DRP code (TODO) + // protected: +public: + //! Stores the filter in frequency space (will be private sometime) + Array<1, float> filter; + +public: + Filter1D(const int length_v) : filter(1, length_v) {} + Filter1D(const Array<1, T>& filter) : filter(filter) {} + virtual ~Filter1D() {} + + //! Filters data (which has to be in the 'spatial' domain + /*! data will be padded with zeroes to the same length as the stored filter before + filtering. This is done on a local copy of the data, such that the index range of + \a data is not modified. + */ + inline void apply(Array<1, T>& data); + //! Applies the filter on each 1D subarray + inline void apply(Array<2, T>& data); + //! Applies the filter on each 1D subarray + inline void apply(Array<3, T>& data); + + virtual std::string parameter_info() const = 0; }; // TODO can't be const due to start_timers() -template void Filter1D ::apply(Array<1,T> &data) //const +template +void +Filter1D::apply(Array<1, T>& data) // const { start_timers(); const int length = filter.get_length(); - if (length==0) + if (length == 0) return; - assert(length>0); + assert(length > 0); - Array<1,T> Padded = data; + Array<1, T> Padded = data; Padded.set_offset(1); - Padded.grow(1,length); - convlvC(Padded, filter,length); + Padded.grow(1, length); + convlvC(Padded, filter, length); Padded.set_offset(data.get_min_index()); - for (int j=data.get_min_index();j<=data.get_max_index();j++) - data[j]= Padded[j]; + for (int j = data.get_min_index(); j <= data.get_max_index(); j++) + data[j] = Padded[j]; stop_timers(); } -template void Filter1D ::apply(Array<2,T> &data)// const +template +void +Filter1D::apply(Array<2, T>& data) // const { - for (int i= data.get_min_index(); i <= data.get_max_index(); i++) - apply(data[i]); + for (int i = data.get_min_index(); i <= data.get_max_index(); i++) + apply(data[i]); } -template void Filter1D ::apply(Array<3,T> &data)// const +template +void +Filter1D::apply(Array<3, T>& data) // const { - for (int i= data.get_min_index(); i <= data.get_max_index(); i++) - apply(data[i]); + for (int i = data.get_min_index(); i <= data.get_max_index(); i++) + apply(data[i]); } - - /*! \brief 2-dimensional filters (filtering done by FFTs) */ -template class Filter2D : public TimedObject -{ +template +class Filter2D : public TimedObject { public: - Filter2D(int height_v, int width_v) - : height(height_v), width(width_v), filter(1,width_v*height_v) - {} + Filter2D(int height_v, int width_v) : height(height_v), width(width_v), filter(1, width_v * height_v) {} - virtual ~Filter2D() {} - inline void apply(Array<1,T> &data) const; + virtual ~Filter2D() {} + inline void apply(Array<1, T>& data) const; // TODO ??? void padd_scale_filter(int height_proj, int width_proj); - + virtual std::string parameter_info() const = 0; protected: - int height; - int width; + int height; + int width; //! Stores the filter in the 'funny' but efficient Numerical Recipes format - Array<1,T> filter; - + Array<1, T> filter; }; +template +void +Filter2D::apply(Array<1, T>& data) const { - - -template void Filter2D::apply(Array<1,T> &data) const -{ - - assert(data.get_length() == 2*height*width); + assert(data.get_length() == 2 * height * width); assert(data.get_min_index() == 1); - int j,k; + int j, k; /*TODO copy lines from Filter_proj_Colsher for this convertion, and call apply with a Array<2,T> Array<1,T> data(1, 2*height*width); @@ -148,24 +142,21 @@ template void Filter2D::apply(Array<1,T> &data) const data[j++] = data2d[h][w]; } */ - - Array<1,int> nn(1,2); + + Array<1, int> nn(1, 2); nn[1] = height; nn[2] = width; fourn(data, nn, 2, 1); - for (j = 1, k = 1; j < width * height + 1; j++) - { + for (j = 1, k = 1; j < width * height + 1; j++) { // KT 11/04/2000 normalise with total length // divide by width*height to take Num Recipes convention into account that the // 'inverse' Fourier transform needs scaling by the total number of data points. - data[k++] *= filter[j]/(width * height); - data[k++] *= filter[j]/(width * height); + data[k++] *= filter[j] / (width * height); + data[k++] *= filter[j] / (width * height); } fourn(data, nn, 2, -1); - }; END_NAMESPACE_STIR #endif - diff --git a/src/include/stir_experimental/ModifiedInverseAveragingImageFilterAll.h b/src/include/stir_experimental/ModifiedInverseAveragingImageFilterAll.h index 046e11e2d6..d4bb8cdaf7 100644 --- a/src/include/stir_experimental/ModifiedInverseAveragingImageFilterAll.h +++ b/src/include/stir_experimental/ModifiedInverseAveragingImageFilterAll.h @@ -3,15 +3,15 @@ /*! \file - \ingroup buildblock - \brief This is a messy, first, attempt to design spatially varying filter - Given the kernel which in this case is a lospass filter with a DC gain 1 the filter + \ingroup buildblock + \brief This is a messy, first, attempt to design spatially varying filter + Given the kernel which in this case is a lospass filter with a DC gain 1 the filter is design such that the output kernel varies depending on the k0 and k1 ( for more details on these factors look at Fessler) - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2007, Hammersmith Imanet @@ -21,8 +21,6 @@ #ifndef __stir_ModifiedInverseAveragingImageFilterAll_H__ #define __stir_ModifiedInverseAveragingImageFilterAll_H__ - - #include "stir_experimental/ModifiedInverseAverigingArrayFilter.h" #include "stir/DiscretisedDensity.h" #include "stir/DataProcessor.h" @@ -34,106 +32,91 @@ #include "stir/shared_ptr.h" - - - START_NAMESPACE_STIR // TODO!! remove define #define num_dimensions 3 - template -class ModifiedInverseAveragingImageFilterAll: -public - RegisteredParsingObject< - ModifiedInverseAveragingImageFilterAll, - DataProcessor >, - DataProcessor > - > -{ - private: - typedef - RegisteredParsingObject< - ModifiedInverseAveragingImageFilterAll, - DataProcessor >, - DataProcessor > - > - base_type; -public: - static const char * const registered_name; +class ModifiedInverseAveragingImageFilterAll + : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { +private: + typedef RegisteredParsingObject, + DataProcessor>, + DataProcessor>> + base_type; + +public: + static const char* const registered_name; //! Default constructor - ModifiedInverseAveragingImageFilterAll(); - - ModifiedInverseAveragingImageFilterAll(string proj_data_filename, - string attenuation_proj_data_filename, - const VectorWithOffset& filter_coefficients, - shared_ptr proj_data_ptr, - shared_ptr attenuation_proj_data_ptr, - DiscretisedDensity<3,float>* initial_image, - DiscretisedDensity<3,float>* sensitivity_image, - DiscretisedDensity<3,float>* precomputed_coefficients_image, - DiscretisedDensity<3,float>* normalised_bck_image, - int mask_size, - int num_dim); - - - -private: + ModifiedInverseAveragingImageFilterAll(); + ModifiedInverseAveragingImageFilterAll(string proj_data_filename, string attenuation_proj_data_filename, + const VectorWithOffset& filter_coefficients, shared_ptr proj_data_ptr, + shared_ptr attenuation_proj_data_ptr, + DiscretisedDensity<3, float>* initial_image, + DiscretisedDensity<3, float>* sensitivity_image, + DiscretisedDensity<3, float>* precomputed_coefficients_image, + DiscretisedDensity<3, float>* normalised_bck_image, int mask_size, int num_dim); + +private: int mask_size; vector filter_coefficients_for_parsing; VectorWithOffset filter_coefficients; - + shared_ptr proj_data_ptr; string proj_data_filename; shared_ptr attenuation_proj_data_ptr; string attenuation_proj_data_filename; - DiscretisedDensity<3,float>* initial_image; + DiscretisedDensity<3, float>* initial_image; string initial_image_filename; - - DiscretisedDensity<3,float>* sensitivity_image; + + DiscretisedDensity<3, float>* sensitivity_image; string sensitivity_image_filename; - DiscretisedDensity<3,float>* precomputed_coefficients_image ; + DiscretisedDensity<3, float>* precomputed_coefficients_image; string precomputed_coefficients_filename; - DiscretisedDensity<3,float>* normalised_bck_image ; + DiscretisedDensity<3, float>* normalised_bck_image; string normalised_bck_filename; int num_dim; - Succeeded virtual_set_up(const DiscretisedDensity& density); - // new - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const; - void virtual_apply(DiscretisedDensity& density) const; - void precalculate_filter_coefficients (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const; - - void precalculate_filter_coefficients_2D (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const; - - void precalculate_filter_coefficients_separable(VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const; - + Succeeded virtual_set_up(const DiscretisedDensity& density); + // new + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const; + void virtual_apply(DiscretisedDensity& density) const; + void precalculate_filter_coefficients( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const; + + void precalculate_filter_coefficients_2D( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const; + + void precalculate_filter_coefficients_separable( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - mutable - ModifiedInverseAverigingArrayFilter inverse_filter; + mutable ModifiedInverseAverigingArrayFilter inverse_filter; }; - #undef num_dimensions END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir_experimental/ModifiedInverseAverigingArrayFilter.h b/src/include/stir_experimental/ModifiedInverseAverigingArrayFilter.h index a9fd5d23e4..e995bcec5b 100644 --- a/src/include/stir_experimental/ModifiedInverseAverigingArrayFilter.h +++ b/src/include/stir_experimental/ModifiedInverseAverigingArrayFilter.h @@ -1,22 +1,22 @@ // -// $Id: +// $Id: // /*! \file - \ingroup buildblock - \brief - This is a messy first attempt to design spatially varying filter - Given the kernel which in this case is a lospass filter with a DC gain 1 the filter + \ingroup buildblock + \brief + This is a messy first attempt to design spatially varying filter + Given the kernel which in this case is a lospass filter with a DC gain 1 the filter is design such that the output kernel varies depending on the k0 and k1 ( for more details on these factors look at Fessler) - + \author Sanida Mustafovic \author Kris Thielemans - - $Date: - $Revision: + + $Date: + $Revision: */ /* Copyright (C) 2000- 2001, IRSL @@ -32,48 +32,39 @@ #include "stir/Array.h" #include "stir/IndexRange.h" - START_NAMESPACE_STIR -class FFT_routines -{ - public: - void find_fft_filter(Array<1,float>& filter_coefficients); - void find_fft_unity(Array<1,float>& unity); - private: - Array<1,float> filter_coefficients; - Array<1,float> unity; - +class FFT_routines { +public: + void find_fft_filter(Array<1, float>& filter_coefficients); + void find_fft_unity(Array<1, float>& unity); +private: + Array<1, float> filter_coefficients; + Array<1, float> unity; }; - template -class ModifiedInverseAverigingArrayFilter: public SeparableLowPassArrayFilter2 -//public SeparableArrayFunctionObject +class ModifiedInverseAverigingArrayFilter : public SeparableLowPassArrayFilter2 +// public SeparableArrayFunctionObject { -public: - +public: //! Default constructor ModifiedInverseAverigingArrayFilter(); - - //ModifiedInverseAverigingArrayFilter(const float kapa0_over_kapa1); - - ModifiedInverseAverigingArrayFilter(const VectorWithOffset& filter_coefficients, - const float kapa0_over_kapa1); - + + // ModifiedInverseAverigingArrayFilter(const float kapa0_over_kapa1); + + ModifiedInverseAverigingArrayFilter(const VectorWithOffset& filter_coefficients, const float kapa0_over_kapa1); + // temporary (?) member - IndexRange get_kernel_index_range() const - { return kernel_index_range; } + IndexRange get_kernel_index_range() const { return kernel_index_range; } private: - VectorWithOffset filter_coefficients; - IndexRange kernel_index_range; - float kapa0_over_kapa1; - + VectorWithOffset filter_coefficients; + IndexRange kernel_index_range; + float kapa0_over_kapa1; }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir_experimental/ModifiedInverseAverigingImageFilter.h b/src/include/stir_experimental/ModifiedInverseAverigingImageFilter.h index 239f8624ca..7cc5c15ab1 100644 --- a/src/include/stir_experimental/ModifiedInverseAverigingImageFilter.h +++ b/src/include/stir_experimental/ModifiedInverseAverigingImageFilter.h @@ -3,15 +3,15 @@ /*! \file - \ingroup buildblock - \brief This is a messy, first, attempt to design spatially varying filter - Given the kernel which in this case is a lospass filter with a DC gain 1 the filter + \ingroup buildblock + \brief This is a messy, first, attempt to design spatially varying filter + Given the kernel which in this case is a lospass filter with a DC gain 1 the filter is design such that the output kernel varies depending on the k0 and k1 ( for more details on these factors look at Fessler) - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2007, Hammersmith Imanet @@ -21,7 +21,6 @@ #ifndef __stir_ModifiedInverseAverigingImageFilter_H__ #define __stir_ModifiedInverseAverigingImageFilter_H__ - #include "stir_experimental/ModifiedInverseAverigingArrayFilter.h" #include "stir/DiscretisedDensity.h" #include "stir/DataProcessor.h" @@ -30,89 +29,68 @@ #include "stir/ProjData.h" #include "stir_experimental/ArrayFilter3DUsingConvolution.h" - - - START_NAMESPACE_STIR // TODO!! remove define #define num_dimensions 3 - template -class ModifiedInverseAverigingImageFilter: -public - RegisteredParsingObject< - ModifiedInverseAverigingImageFilter, - DataProcessor >, - DataProcessor > - > -{ - private: - typedef - RegisteredParsingObject< - ModifiedInverseAverigingImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; -public: - static const char * const registered_name; +class ModifiedInverseAverigingImageFilter + : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { +private: + typedef RegisteredParsingObject, + DataProcessor>, + DataProcessor>> + base_type; + +public: + static const char* const registered_name; //! Default constructor - ModifiedInverseAverigingImageFilter(); - - ModifiedInverseAverigingImageFilter(string proj_data_filename, - string attenuation_proj_data_filename, - const VectorWithOffset& filter_coefficients, - shared_ptr proj_data_ptr, - shared_ptr attenuation_proj_data_ptr, - DiscretisedDensity<3,float>* initial_image, - DiscretisedDensity<3,float>* sensitivity_image, - int mask_size, bool z_direction_trivial); - - - -private: + ModifiedInverseAverigingImageFilter(); + ModifiedInverseAverigingImageFilter(string proj_data_filename, string attenuation_proj_data_filename, + const VectorWithOffset& filter_coefficients, shared_ptr proj_data_ptr, + shared_ptr attenuation_proj_data_ptr, DiscretisedDensity<3, float>* initial_image, + DiscretisedDensity<3, float>* sensitivity_image, int mask_size, bool z_direction_trivial); + +private: int mask_size; vector filter_coefficients_for_parsing; VectorWithOffset filter_coefficients; - + shared_ptr proj_data_ptr; string proj_data_filename; shared_ptr attenuation_proj_data_ptr; string attenuation_proj_data_filename; - DiscretisedDensity<3,float>* initial_image; + DiscretisedDensity<3, float>* initial_image; string initial_image_filename; - - DiscretisedDensity<3,float>* sensitivity_image; + + DiscretisedDensity<3, float>* sensitivity_image; string sensitivity_image_filename; bool z_direction_trivial; + Succeeded virtual_set_up(const DiscretisedDensity& density); + // new + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const; + void virtual_apply(DiscretisedDensity& density) const; + void precalculate_filter_coefficients( + VectorWithOffset>>>>& all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const; - - - Succeeded virtual_set_up(const DiscretisedDensity& density); - // new - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const; - void virtual_apply(DiscretisedDensity& density) const; - void precalculate_filter_coefficients (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const; - - virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - }; - #undef num_dimensions END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/NonseparableSpatiallyVaryingFilters.h b/src/include/stir_experimental/NonseparableSpatiallyVaryingFilters.h index 1e60a343f8..65dcbf8326 100644 --- a/src/include/stir_experimental/NonseparableSpatiallyVaryingFilters.h +++ b/src/include/stir_experimental/NonseparableSpatiallyVaryingFilters.h @@ -3,15 +3,15 @@ /*! \file - \ingroup buildblock - \brief This is a messy, first, attempt to design spatially varying filter - Given the kernel which in this case is a lospass filter with a DC gain 1 the filter + \ingroup buildblock + \brief This is a messy, first, attempt to design spatially varying filter + Given the kernel which in this case is a lospass filter with a DC gain 1 the filter is design such that the output kernel varies depending on the k0 and k1 ( for more details on these factors look at Fessler) - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2007, Hammersmith Imanet @@ -21,8 +21,6 @@ #ifndef __stir_NonseparableSpatiallyVaryingFilters_H__ #define __stir_NonseparableSpatiallyVaryingFilters_H__ - - #include "stir_experimental/ModifiedInverseAverigingArrayFilter.h" #include "stir/DiscretisedDensity.h" #include "stir/DataProcessor.h" @@ -34,101 +32,79 @@ #include "stir/shared_ptr.h" - - - START_NAMESPACE_STIR // TODO!! remove define #define num_dimensions 3 - template -class NonseparableSpatiallyVaryingFilters: -public - RegisteredParsingObject< - NonseparableSpatiallyVaryingFilters, - DataProcessor >, - DataProcessor > - > -{ - private: - typedef - RegisteredParsingObject< - NonseparableSpatiallyVaryingFilters, - DataProcessor >, - DataProcessor > - > - base_type; -public: - static const char * const registered_name; +class NonseparableSpatiallyVaryingFilters + : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { +private: + typedef RegisteredParsingObject, + DataProcessor>, + DataProcessor>> + base_type; + +public: + static const char* const registered_name; //! Default constructor - NonseparableSpatiallyVaryingFilters(); - - NonseparableSpatiallyVaryingFilters(string proj_data_filename, - string attenuation_proj_data_filename, - const Array<2,float>& filter_coefficients, - shared_ptr proj_data_ptr, - shared_ptr attenuation_proj_data_ptr, - DiscretisedDensity<3,float>* initial_image, - DiscretisedDensity<3,float>* sensitivity_image, - DiscretisedDensity<3,float>* precomputed_coefficients_image, - DiscretisedDensity<3,float>* normalised_bck_image, - int mask_size, - int num_dim); - - - -private: + NonseparableSpatiallyVaryingFilters(); + NonseparableSpatiallyVaryingFilters(string proj_data_filename, string attenuation_proj_data_filename, + const Array<2, float>& filter_coefficients, shared_ptr proj_data_ptr, + shared_ptr attenuation_proj_data_ptr, DiscretisedDensity<3, float>* initial_image, + DiscretisedDensity<3, float>* sensitivity_image, + DiscretisedDensity<3, float>* precomputed_coefficients_image, + DiscretisedDensity<3, float>* normalised_bck_image, int mask_size, int num_dim); + +private: int mask_size; - Array<2,float> filter_coefficients_for_parsing; - mutable Array<2,float> filter_coefficients; - + Array<2, float> filter_coefficients_for_parsing; + mutable Array<2, float> filter_coefficients; + shared_ptr proj_data_ptr; string proj_data_filename; shared_ptr attenuation_proj_data_ptr; string attenuation_proj_data_filename; - DiscretisedDensity<3,float>* initial_image; + DiscretisedDensity<3, float>* initial_image; string initial_image_filename; - - DiscretisedDensity<3,float>* sensitivity_image; + + DiscretisedDensity<3, float>* sensitivity_image; string sensitivity_image_filename; - DiscretisedDensity<3,float>* precomputed_coefficients_image ; + DiscretisedDensity<3, float>* precomputed_coefficients_image; string precomputed_coefficients_filename; - DiscretisedDensity<3,float>* normalised_bck_image ; + DiscretisedDensity<3, float>* normalised_bck_image; string normalised_bck_filename; int num_dim; int number_of_coefficients_before_padding; - Succeeded virtual_set_up(const DiscretisedDensity& density); - // new - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const; - void virtual_apply(DiscretisedDensity& density) const; - void precalculate_filter_coefficients_2D (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const; - - - - - virtual void set_defaults(); - virtual void initialise_keymap(); - - virtual bool post_processing(); - -}; + Succeeded virtual_set_up(const DiscretisedDensity& density); + // new + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const; + void virtual_apply(DiscretisedDensity& density) const; + void precalculate_filter_coefficients_2D( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const; + virtual void set_defaults(); + virtual void initialise_keymap(); + + virtual bool post_processing(); +}; #undef num_dimensions END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir_experimental/NonseparableSpatiallyVaryingFilters3D.h b/src/include/stir_experimental/NonseparableSpatiallyVaryingFilters3D.h index 29a3538c5e..ad2db8063a 100644 --- a/src/include/stir_experimental/NonseparableSpatiallyVaryingFilters3D.h +++ b/src/include/stir_experimental/NonseparableSpatiallyVaryingFilters3D.h @@ -2,15 +2,15 @@ /*! \file - \ingroup buildblock - \brief This is a messy, first, attempt to design spatially varying filter - Given the kernel which in this case is a lospass filter with a DC gain 1 the filter + \ingroup buildblock + \brief This is a messy, first, attempt to design spatially varying filter + Given the kernel which in this case is a lospass filter with a DC gain 1 the filter is design such that the output kernel varies depending on the k0 and k1 ( for more details on these factors look at Fessler) - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2007, Hammersmith Imanet @@ -20,8 +20,6 @@ #ifndef __stir_NonseparableSpatiallyVaryingFilters3D_H__ #define __stir_NonseparableSpatiallyVaryingFilters3D_H__ - - #include "stir_experimental/ModifiedInverseAverigingArrayFilter.h" #include "stir/DiscretisedDensity.h" #include "stir/DataProcessor.h" @@ -33,101 +31,83 @@ #include "stir/shared_ptr.h" - - - START_NAMESPACE_STIR // TODO!! remove define #define num_dimensions 3 - template -class NonseparableSpatiallyVaryingFilters3D: -public - RegisteredParsingObject< - NonseparableSpatiallyVaryingFilters3D, - DataProcessor >, - DataProcessor > - > -{ - private: - typedef - RegisteredParsingObject< - NonseparableSpatiallyVaryingFilters3D, - DataProcessor >, - DataProcessor > - > - base_type; -public: - static const char * const registered_name; +class NonseparableSpatiallyVaryingFilters3D + : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { +private: + typedef RegisteredParsingObject, + DataProcessor>, + DataProcessor>> + base_type; + +public: + static const char* const registered_name; //! Default constructor - NonseparableSpatiallyVaryingFilters3D(); - - NonseparableSpatiallyVaryingFilters3D(string proj_data_filename, - string attenuation_proj_data_filename, - const Array<3,float>& filter_coefficients, - shared_ptr proj_data_ptr, - shared_ptr attenuation_proj_data_ptr, - DiscretisedDensity<3,float>* initial_image, - DiscretisedDensity<3,float>* sensitivity_image, - DiscretisedDensity<3,float>* precomputed_coefficients_image, - DiscretisedDensity<3,float>* normalised_bck_image, - int mask_size, - float rescaling_coefficient); - - -private: - + NonseparableSpatiallyVaryingFilters3D(); + + NonseparableSpatiallyVaryingFilters3D(string proj_data_filename, string attenuation_proj_data_filename, + const Array<3, float>& filter_coefficients, shared_ptr proj_data_ptr, + shared_ptr attenuation_proj_data_ptr, + DiscretisedDensity<3, float>* initial_image, + DiscretisedDensity<3, float>* sensitivity_image, + DiscretisedDensity<3, float>* precomputed_coefficients_image, + DiscretisedDensity<3, float>* normalised_bck_image, int mask_size, + float rescaling_coefficient); + +private: int mask_size; - Array<3,float> filter_coefficients_for_parsing; - mutable Array<3,float> filter_coefficients; - + Array<3, float> filter_coefficients_for_parsing; + mutable Array<3, float> filter_coefficients; + shared_ptr proj_data_ptr; string proj_data_filename; shared_ptr attenuation_proj_data_ptr; string attenuation_proj_data_filename; - DiscretisedDensity<3,float>* initial_image; + DiscretisedDensity<3, float>* initial_image; string initial_image_filename; - - DiscretisedDensity<3,float>* sensitivity_image; + + DiscretisedDensity<3, float>* sensitivity_image; string sensitivity_image_filename; - mutable DiscretisedDensity<3,float>* precomputed_coefficients_image ; + mutable DiscretisedDensity<3, float>* precomputed_coefficients_image; string precomputed_coefficients_filename; - DiscretisedDensity<3,float>* normalised_bck_image ; + DiscretisedDensity<3, float>* normalised_bck_image; string normalised_bck_filename; float rescaling_coefficient; mutable float k_interval; int recompute_every_num_subiterations; int recompute_from_subiteration_num; - Succeeded virtual_set_up(const DiscretisedDensity& density); - // new - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const; - void virtual_apply(DiscretisedDensity& density) const; - void precalculate_filter_coefficients_3D (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const; - - - - - virtual void set_defaults(); - virtual void initialise_keymap(); - - virtual bool post_processing(); - -}; + Succeeded virtual_set_up(const DiscretisedDensity& density); + // new + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const; + void virtual_apply(DiscretisedDensity& density) const; + void precalculate_filter_coefficients_3D( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const; + virtual void set_defaults(); + virtual void initialise_keymap(); + + virtual bool post_processing(); +}; #undef num_dimensions END_NAMESPACE_STIR #endif - diff --git a/src/include/stir_experimental/Quaternion.h b/src/include/stir_experimental/Quaternion.h index ac240c5c1c..a463d33492 100644 --- a/src/include/stir_experimental/Quaternion.h +++ b/src/include/stir_experimental/Quaternion.h @@ -14,8 +14,6 @@ \author Kris Thielemans */ - - #ifndef __stir_Quaternion_H__ #define __stir_Quaternion_H__ @@ -24,41 +22,39 @@ START_NAMESPACE_STIR template -class Quaternion : public BasicCoordinate<4, coordT> // TODO kris wants private inheritance +class Quaternion : public BasicCoordinate<4, coordT> // TODO kris wants private inheritance { protected: typedef BasicCoordinate<4, coordT> base_type; public: - - Quaternion(); - Quaternion(const coordT&, const coordT&, const coordT&, const coordT&); - Quaternion(const base_type& q); - - /*coordT component_1() const; - coordT component_2() const; - coordT component_3() const; - coordT component_4() const;*/ - - // Overload multiplication - inline Quaternion & operator*= (const coordT& a); - inline Quaternion & operator*= (const Quaternion& q); - inline Quaternion operator* (const Quaternion& q) const; - inline Quaternion operator* (const coordT& a) const; - // Overload division - inline Quaternion & operator/= (const coordT& a); - inline Quaternion & operator/= (const Quaternion& q); - inline Quaternion operator/ (const Quaternion& q) const; - inline Quaternion operator/ (const coordT& a) const; - - inline void neg_quaternion(); - inline void conjugate(); - inline void normalise(); - inline void inverse(); - inline static coordT dot_product (const Quaternion&, const Quaternion&); + Quaternion(); + Quaternion(const coordT&, const coordT&, const coordT&, const coordT&); + Quaternion(const base_type& q); + + /*coordT component_1() const; + coordT component_2() const; + coordT component_3() const; + coordT component_4() const;*/ + + // Overload multiplication + inline Quaternion& operator*=(const coordT& a); + inline Quaternion& operator*=(const Quaternion& q); + inline Quaternion operator*(const Quaternion& q) const; + inline Quaternion operator*(const coordT& a) const; + // Overload division + inline Quaternion& operator/=(const coordT& a); + inline Quaternion& operator/=(const Quaternion& q); + inline Quaternion operator/(const Quaternion& q) const; + inline Quaternion operator/(const coordT& a) const; + + inline void neg_quaternion(); + inline void conjugate(); + inline void normalise(); + inline void inverse(); + inline static coordT dot_product(const Quaternion&, const Quaternion&); private: - }; template diff --git a/src/include/stir_experimental/Quaternion.inl b/src/include/stir_experimental/Quaternion.inl index b943d7db0c..3cbabeb03e 100644 --- a/src/include/stir_experimental/Quaternion.inl +++ b/src/include/stir_experimental/Quaternion.inl @@ -14,59 +14,49 @@ \author Kris Thielemans */ - - START_NAMESPACE_STIR - template -coordT norm_squared(const Quaternion& q) -{ - return square(q[1]) + square(q[2]) +square(q[3])+ square(q[4]); +coordT +norm_squared(const Quaternion& q) { + return square(q[1]) + square(q[2]) + square(q[3]) + square(q[4]); } template -coordT norm(const Quaternion& q) -{ +coordT +norm(const Quaternion& q) { return sqrt(norm_squared(q)); } template -coordT -Quaternion::dot_product (const Quaternion& q1, const Quaternion& q2) -{ - return((q1[1]*q2[1])+(q1[2]*q2[2])+(q1[3]*q2[3])+(q1[4]*q2[4])); +coordT +Quaternion::dot_product(const Quaternion& q1, const Quaternion& q2) { + return ((q1[1] * q2[1]) + (q1[2] * q2[2]) + (q1[3] * q2[3]) + (q1[4] * q2[4])); } template -Quaternion& -Quaternion:: -operator*=(const Quaternion& q) -{ - const Quaternion tmp (*this); - (*this)[1] = tmp[1]*q[1]-tmp[2]*q[2]-tmp[3]*q[3]-tmp[4]*q[4]; - (*this)[2] = tmp[1]*q[2]+tmp[2]*q[1]+tmp[3]*q[4]-tmp[4]*q[3]; - (*this)[3] = tmp[1]*q[3]+tmp[3]*q[1]+tmp[4]*q[2]-tmp[2]*q[4]; - (*this)[4] = tmp[1]*q[4]+tmp[4]*q[1]+tmp[2]*q[3]-tmp[3]*q[2]; +Quaternion& +Quaternion::operator*=(const Quaternion& q) { + const Quaternion tmp(*this); + (*this)[1] = tmp[1] * q[1] - tmp[2] * q[2] - tmp[3] * q[3] - tmp[4] * q[4]; + (*this)[2] = tmp[1] * q[2] + tmp[2] * q[1] + tmp[3] * q[4] - tmp[4] * q[3]; + (*this)[3] = tmp[1] * q[3] + tmp[3] * q[1] + tmp[4] * q[2] - tmp[2] * q[4]; + (*this)[4] = tmp[1] * q[4] + tmp[4] * q[1] + tmp[2] * q[3] - tmp[3] * q[2]; return *this; - } template -Quaternion& -Quaternion::operator*= (const coordT& a) -{ - for (int i=1; i<=4; i++) +Quaternion& +Quaternion::operator*=(const coordT& a) { + for (int i = 1; i <= 4; i++) (*this)[i] *= a; return *this; - } template -Quaternion -Quaternion::operator* (const Quaternion& q) const -{ +Quaternion +Quaternion::operator*(const Quaternion& q) const { Quaternion tmp(*this); tmp *= q; @@ -74,29 +64,25 @@ Quaternion::operator* (const Quaternion& q) const } template -Quaternion -Quaternion::operator* (const coordT& a) const -{ +Quaternion +Quaternion::operator*(const coordT& a) const { Quaternion tmp(*this); tmp *= a; return tmp; } template -Quaternion& -Quaternion:: operator/= (const coordT& a) -{ - for (int i=1; i<=4; i++) +Quaternion& +Quaternion::operator/=(const coordT& a) { + for (int i = 1; i <= 4; i++) (*this)[i] /= a; return *this; - } template -Quaternion& -Quaternion::operator/= (const Quaternion& q) -{ - const Quaternion con_q(q[1],-q[2],-q[3],-q[4]); - const coordT norm_squared =(square(q[1])+square(q[2])+square(q[3])+square(q[4])); +Quaternion& +Quaternion::operator/=(const Quaternion& q) { + const Quaternion con_q(q[1], -q[2], -q[3], -q[4]); + const coordT norm_squared = (square(q[1]) + square(q[2]) + square(q[3]) + square(q[4])); *this *= con_q; *this /= norm_squared; @@ -104,81 +90,70 @@ Quaternion::operator/= (const Quaternion& q) } template -Quaternion -Quaternion::operator/(const Quaternion& q) const -{ +Quaternion +Quaternion::operator/(const Quaternion& q) const { Quaternion tmp(*this); - tmp/=q; + tmp /= q; return tmp; } template -Quaternion -Quaternion::operator/ (const coordT& a) const -{ +Quaternion +Quaternion::operator/(const coordT& a) const { Quaternion tmp(*this); tmp /= a; return tmp; - } template -void -Quaternion:: neg_quaternion () -{ - (*this)[1] =-(*this)[1]; - (*this)[2] =-(*this)[2]; - (*this)[3] =-(*this)[3]; - (*this)[4] =-(*this)[4]; - +void +Quaternion::neg_quaternion() { + (*this)[1] = -(*this)[1]; + (*this)[2] = -(*this)[2]; + (*this)[3] = -(*this)[3]; + (*this)[4] = -(*this)[4]; } - - template -void -Quaternion:: conjugate() -{ -// (*this)[1] =(*this)[1]; - (*this)[2] =-(*this)[2]; - (*this)[3] =-(*this)[3]; - (*this)[4] =-(*this)[4]; +void +Quaternion::conjugate() { + // (*this)[1] =(*this)[1]; + (*this)[2] = -(*this)[2]; + (*this)[3] = -(*this)[3]; + (*this)[4] = -(*this)[4]; } template -void -Quaternion:: normalise() -{ +void +Quaternion::normalise() { const coordT n = norm(*this); - (*this)[1] /=n; - (*this)[2] /=n; - (*this)[3] /=n; - (*this)[4] /=n; + (*this)[1] /= n; + (*this)[2] /= n; + (*this)[3] /= n; + (*this)[4] /= n; } template -void -Quaternion::inverse() -{ +void +Quaternion::inverse() { const coordT dp = norm_squared(*this); - (*this)[1] = (*this)[1]/dp; - (*this)[2] = -(*this)[2]/dp; - (*this)[3] = -(*this)[3]/dp; - (*this)[4] = -(*this)[4]/dp; + (*this)[1] = (*this)[1] / dp; + (*this)[2] = -(*this)[2] / dp; + (*this)[3] = -(*this)[3] / dp; + (*this)[4] = -(*this)[4] / dp; } - template -Quaternion conjugate(const Quaternion& q) -{ +Quaternion +conjugate(const Quaternion& q) { Quaternion tmp = q; tmp.conjugate(); return tmp; } template -Quaternion inverse(const Quaternion& q) -{ +Quaternion +inverse(const Quaternion& q) { Quaternion tmp = q; tmp.inverse(); return tmp; diff --git a/src/include/stir_experimental/SeparableGaussianArrayFilter.h b/src/include/stir_experimental/SeparableGaussianArrayFilter.h index 582a970b77..03b0eae969 100644 --- a/src/include/stir_experimental/SeparableGaussianArrayFilter.h +++ b/src/include/stir_experimental/SeparableGaussianArrayFilter.h @@ -1,18 +1,18 @@ // -// $Id: +// $Id: // /*! \file - \ingroup local/buildblock - \brief - - + \ingroup local/buildblock + \brief + + \author Sanida Mustafovic \author Kris Thielemans - - $Date: - $Revision: + + $Date: + $Revision: */ /* Copyright (C) 2000- 2002, IRSL @@ -30,30 +30,21 @@ START_NAMESPACE_STIR - template -class SeparableGaussianArrayFilter: - public SeparableArrayFunctionObject -{ -public: - +class SeparableGaussianArrayFilter : public SeparableArrayFunctionObject { +public: //! Default constructor - SeparableGaussianArrayFilter(); - - SeparableGaussianArrayFilter(const float standard_deviation, - const int number_of_coefficients); - - + SeparableGaussianArrayFilter(); + + SeparableGaussianArrayFilter(const float standard_deviation, const int number_of_coefficients); + private: - void calculate_coefficients(VectorWithOffset& filter_coefficients, - const int number_of_coefficients, - const float standard_deviation); - float standard_deviation; + void calculate_coefficients(VectorWithOffset& filter_coefficients, const int number_of_coefficients, + const float standard_deviation); + float standard_deviation; int number_of_coefficients; - }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir_experimental/SeparableGaussianImageFilter.h b/src/include/stir_experimental/SeparableGaussianImageFilter.h index 9e3438d0a6..634fa5127e 100644 --- a/src/include/stir_experimental/SeparableGaussianImageFilter.h +++ b/src/include/stir_experimental/SeparableGaussianImageFilter.h @@ -3,12 +3,12 @@ /*! \file - \ingroup buildblock + \ingroup buildblock \brief Declaration of class SeparableGaussianImageFilter - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2007, Hammersmith Imanet @@ -18,13 +18,11 @@ #ifndef __stir_SeparableGaussianImageFilter_H__ #define __stir_SeparableGaussianImageFilter_H__ - #include "stir_experimental/SeparableGaussianArrayFilter.h" #include "stir/RegisteredParsingObject.h" #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" - START_NAMESPACE_STIR // TODO!! remove define @@ -32,46 +30,37 @@ START_NAMESPACE_STIR #define num_dimensions 3 template -class SeparableGaussianImageFilter : - public - RegisteredParsingObject< - SeparableGaussianImageFilter, - DataProcessor >, - DataProcessor > - > -{ - private: - typedef - RegisteredParsingObject< - SeparableGaussianImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; +class SeparableGaussianImageFilter : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { +private: + typedef RegisteredParsingObject, DataProcessor>, + DataProcessor>> + base_type; + public: - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor SeparableGaussianImageFilter(); float get_standard_deviation(); - - + private: float standard_deviation; int number_of_coefficients; - - SeparableGaussianArrayFilter gaussian_filter; + + SeparableGaussianArrayFilter gaussian_filter; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - - Succeeded virtual_set_up(const DiscretisedDensity& image); + + Succeeded virtual_set_up(const DiscretisedDensity& image); // new - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const; - void virtual_apply(DiscretisedDensity& density) const ; - + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const; + void virtual_apply(DiscretisedDensity& density) const; }; #undef num_dimensions @@ -79,5 +68,3 @@ class SeparableGaussianImageFilter : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir_experimental/SeparableLowPassArrayFilter.h b/src/include/stir_experimental/SeparableLowPassArrayFilter.h index 6628c58d0c..35253d2bbf 100644 --- a/src/include/stir_experimental/SeparableLowPassArrayFilter.h +++ b/src/include/stir_experimental/SeparableLowPassArrayFilter.h @@ -1,18 +1,18 @@ // -// $Id: +// $Id: // /*! \file - \ingroup buildblock - \brief - - + \ingroup buildblock + \brief + + \author Sanida Mustafovic \author Kris Thielemans - - $Date: - $Revision: + + $Date: + $Revision: */ /* Copyright (C) 2000- 2002, IRSL @@ -28,24 +28,19 @@ START_NAMESPACE_STIR - template -class SeparableLowPassArrayFilter: - public SeparableArrayFunctionObject -{ -public: - +class SeparableLowPassArrayFilter : public SeparableArrayFunctionObject { +public: //! Default constructor - SeparableLowPassArrayFilter(); - + SeparableLowPassArrayFilter(); + SeparableLowPassArrayFilter(const VectorWithOffset& filter_coefficients, int z_trivial); - + private: - VectorWithOffset filter_coefficients; - int z_trivial; + VectorWithOffset filter_coefficients; + int z_trivial; }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir_experimental/SeparableLowPassArrayFilter2.h b/src/include/stir_experimental/SeparableLowPassArrayFilter2.h index b3b4da69b3..eea173388f 100644 --- a/src/include/stir_experimental/SeparableLowPassArrayFilter2.h +++ b/src/include/stir_experimental/SeparableLowPassArrayFilter2.h @@ -3,7 +3,7 @@ /*! \file \ingroup test - \brief + \brief \author Kris Thielemans */ @@ -32,127 +32,94 @@ START_NAMESPACE_STIR is separable. 'Separable' means that its operation consists of \c n 1D operations, one on each - index of the \c n -dimensional array. + index of the \c n -dimensional array. \see in_place_apply_array_functions_on_each_index() TODO - + */ // TODO don't use 2Argument, but do 1arg explicitly as well template -class SeparableArrayFunctionObject2 : - public ArrayFunctionObject_2ArgumentImplementation -{ +class SeparableArrayFunctionObject2 : public ArrayFunctionObject_2ArgumentImplementation { public: - SeparableArrayFunctionObject2 (); - SeparableArrayFunctionObject2 (const VectorWithOffset< shared_ptr > >&); + SeparableArrayFunctionObject2(); + SeparableArrayFunctionObject2(const VectorWithOffset>>&); bool is_trivial() const; // TODO reimplement get_*indices protected: - - VectorWithOffset< shared_ptr > > all_1d_array_filters; - virtual void do_it(Array& out_array, const Array& in_array) const; - + VectorWithOffset>> all_1d_array_filters; + virtual void do_it(Array& out_array, const Array& in_array) const; }; - template -SeparableArrayFunctionObject2:: -SeparableArrayFunctionObject2() -: all_1d_array_filters(VectorWithOffset< shared_ptr > >(num_dim)) -{} - +SeparableArrayFunctionObject2::SeparableArrayFunctionObject2() + : all_1d_array_filters(VectorWithOffset>>(num_dim)) {} template -SeparableArrayFunctionObject2:: -SeparableArrayFunctionObject2(const VectorWithOffset< shared_ptr > >& array_filters) -: all_1d_array_filters(array_filters) -{ +SeparableArrayFunctionObject2::SeparableArrayFunctionObject2( + const VectorWithOffset>>& array_filters) + : all_1d_array_filters(array_filters) { assert(all_1d_array_filters.get_length() == num_dim); } template -void -SeparableArrayFunctionObject2:: -do_it(Array& out_array, const Array& in_array) const -{ - - //if (!is_trivial()) - apply_array_functions_on_each_index(out_array, in_array, - all_1d_array_filters.begin(), - all_1d_array_filters.end()); - //else somehow copy in_array into out_array but keeping index ranges - //TODO - +void +SeparableArrayFunctionObject2::do_it(Array& out_array, + const Array& in_array) const { + + // if (!is_trivial()) + apply_array_functions_on_each_index(out_array, in_array, all_1d_array_filters.begin(), all_1d_array_filters.end()); + // else somehow copy in_array into out_array but keeping index ranges + // TODO } template -bool -SeparableArrayFunctionObject2:: -is_trivial() const -{ - for (typename VectorWithOffset< shared_ptr > >::const_iterator iter=all_1d_array_filters.begin(); - iter!=all_1d_array_filters.end();++iter) - { - // TODO insert condition on is_null_ptr here (see SeparableArrayFunctionObject) - if (!(*iter)->is_trivial()) - return false; - } - return true; +bool +SeparableArrayFunctionObject2::is_trivial() const { + for (typename VectorWithOffset>>::const_iterator iter = all_1d_array_filters.begin(); + iter != all_1d_array_filters.end(); ++iter) { + // TODO insert condition on is_null_ptr here (see SeparableArrayFunctionObject) + if (!(*iter)->is_trivial()) + return false; + } + return true; } //---------------------------------------------- template -class SeparableLowPassArrayFilter2: - public SeparableArrayFunctionObject2 -{ -public: - +class SeparableLowPassArrayFilter2 : public SeparableArrayFunctionObject2 { +public: //! Default constructor - SeparableLowPassArrayFilter2(); - + SeparableLowPassArrayFilter2(); + SeparableLowPassArrayFilter2(const VectorWithOffset& filter_coefficients); - + private: - VectorWithOffset filter_coefficients; - + VectorWithOffset filter_coefficients; }; - template -SeparableLowPassArrayFilter2:: -SeparableLowPassArrayFilter2() -{ - for (int i=1;i<=num_dimensions;i++) - { - all_1d_array_filters[i-1] = - new ArrayFilter1DUsingConvolution(); +SeparableLowPassArrayFilter2::SeparableLowPassArrayFilter2() { + for (int i = 1; i <= num_dimensions; i++) { + all_1d_array_filters[i - 1] = new ArrayFilter1DUsingConvolution(); } } - -template -SeparableLowPassArrayFilter2:: -SeparableLowPassArrayFilter2(const VectorWithOffset& filter_coefficients_v) -:filter_coefficients(filter_coefficients_v) -{ - assert(num_dimensions==3); +template +SeparableLowPassArrayFilter2::SeparableLowPassArrayFilter2( + const VectorWithOffset& filter_coefficients_v) + : filter_coefficients(filter_coefficients_v) { + assert(num_dimensions == 3); std::cerr << "Printing filter coefficients" << endl; - for (int i =filter_coefficients_v.get_min_index();i<=filter_coefficients_v.get_max_index();i++) - std::cerr << i<<" "<< filter_coefficients_v[i] <<" " << endl; - + for (int i = filter_coefficients_v.get_min_index(); i <= filter_coefficients_v.get_max_index(); i++) + std::cerr << i << " " << filter_coefficients_v[i] << " " << endl; - all_1d_array_filters[2] = - new ArrayFilter1DUsingConvolution(filter_coefficients_v); + all_1d_array_filters[2] = new ArrayFilter1DUsingConvolution(filter_coefficients_v); - all_1d_array_filters[0] = - new ArrayFilter1DUsingConvolution(); - all_1d_array_filters[1] = - new ArrayFilter1DUsingConvolution(filter_coefficients_v); - - + all_1d_array_filters[0] = new ArrayFilter1DUsingConvolution(); + all_1d_array_filters[1] = new ArrayFilter1DUsingConvolution(filter_coefficients_v); } END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/SeparableLowPassImageFilter.h b/src/include/stir_experimental/SeparableLowPassImageFilter.h index 6de6e234a7..9aa877611f 100644 --- a/src/include/stir_experimental/SeparableLowPassImageFilter.h +++ b/src/include/stir_experimental/SeparableLowPassImageFilter.h @@ -3,12 +3,12 @@ /*! \file - \ingroup buildblock + \ingroup buildblock \brief Declaration of class SeparableLowPassImageFilter - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2007, IRSL @@ -18,13 +18,11 @@ #ifndef __stir_SeparableLowPassImageFilter_H__ #define __stir_SeparableLowPassImageFilter_H__ - #include "stir_experimental/SeparableLowPassArrayFilter.h" #include "stir/RegisteredParsingObject.h" #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" - START_NAMESPACE_STIR // TODO!! remove define @@ -32,49 +30,38 @@ START_NAMESPACE_STIR #define num_dimensions 3 template -class SeparableLowPassImageFilter : - public - RegisteredParsingObject< - SeparableLowPassImageFilter, - DataProcessor >, - DataProcessor > - > -{ - private: - typedef - RegisteredParsingObject< - SeparableLowPassImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; +class SeparableLowPassImageFilter + : public RegisteredParsingObject, DataProcessor>, + DataProcessor>> { +private: + typedef RegisteredParsingObject, DataProcessor>, + DataProcessor>> + base_type; + public: - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor SeparableLowPassImageFilter(); VectorWithOffset get_filter_coefficients(); - - + private: vector filter_coefficients_for_parsing; VectorWithOffset filter_coefficients; - int z_trivial ; - - - - SeparableLowPassArrayFilter lowpass_filter; + int z_trivial; + + SeparableLowPassArrayFilter lowpass_filter; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - - Succeeded virtual_set_up(const DiscretisedDensity& image); + + Succeeded virtual_set_up(const DiscretisedDensity& image); // new - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const; - void virtual_apply(DiscretisedDensity& density) const ; - + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const; + void virtual_apply(DiscretisedDensity& density) const; }; #undef num_dimensions @@ -82,5 +69,3 @@ class SeparableLowPassImageFilter : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir_experimental/fft.h b/src/include/stir_experimental/fft.h index f760ac76b6..8f52831aaf 100644 --- a/src/include/stir_experimental/fft.h +++ b/src/include/stir_experimental/fft.h @@ -29,47 +29,48 @@ START_NAMESPACE_STIR -template class Array; +template +class Array; //! 1-dimensional FFT /*! Replaces data by its discrete Fourier transform, if isign is input - as 1; or replaces data by nn times its inverse discrete Fourier transform, - if isign is input as -1. data is a complex array of length nn, input as a - real array data[1..2*nn]. nn MUST be an integer power of 2 ( this is not + as 1; or replaces data by nn times its inverse discrete Fourier transform, + if isign is input as -1. data is a complex array of length nn, input as a + real array data[1..2*nn]. nn MUST be an integer power of 2 ( this is not checked for !). */ -void four1(Array<1,float> &data, int nn, int isign); +void four1(Array<1, float>& data, int nn, int isign); //! n-dimensional FFT /*! - Replaces data by its ndim-dimensional discrete Fourier transform, - if isign is input as 1. nn[1..ndim] is an integer array containing the + Replaces data by its ndim-dimensional discrete Fourier transform, + if isign is input as 1. nn[1..ndim] is an integer array containing the lengths of each dimension (number of complex values), which MUST all be powers of 2. data is a real array of length twice the product of - thes lengths, in which the data are stored as in a multidimensional - complex array: real and imaginary parts of each element are in - consecutive locations , and the rightmost index of the array - increases most rapidly as one proceeds along data. For a - two-dimensional array, this is equivalent to storing the - array by rows . If isign is in input as -1 , data is replaced by + thes lengths, in which the data are stored as in a multidimensional + complex array: real and imaginary parts of each element are in + consecutive locations , and the rightmost index of the array + increases most rapidly as one proceeds along data. For a + two-dimensional array, this is equivalent to storing the + array by rows . If isign is in input as -1 , data is replaced by its inverse transform time the product of the lengths of all dimensions. */ -void fourn (Array<1,float> &data, Array<1,int> &nn, int ndim, int isign); -//void convlv (Array<1,float> &data, const Array<1,float> &filter, int n); +void fourn(Array<1, float>& data, Array<1, int>& nn, int ndim, int isign); +// void convlv (Array<1,float> &data, const Array<1,float> &filter, int n); //! Convolve data with a filter which is given in frequency space /*! \param data has to have a min_index == 1 - \param filter has to in the format produced by realft. + \param filter has to in the format produced by realft. \param n has to be equal to th elength of \a data \warning Currently, only the real elements of the filter will be used. (Historical reason?) - So, the result will be incorrect of the filter has complex components (i.e. its + So, the result will be incorrect of the filter has complex components (i.e. its spatial kernel is not symmetric). */ -void convlvC (Array<1,float> &data, const Array<1,float> &filter, int n); +void convlvC(Array<1, float>& data, const Array<1, float>& filter, int n); //! 3D FFT of real numbers -void rlft3(Array<3,float> &data, Array<2,float> &speq, int nn1, int nn2, int nn3, int isign); +void rlft3(Array<3, float>& data, Array<2, float>& speq, int nn1, int nn2, int nn3, int isign); //! Calculates the Fourier Transform of a set of 2n real-valued data points. /*! Replaces this data ( which is stored in array data[1..2n]) by the positive @@ -80,9 +81,8 @@ void rlft3(Array<3,float> &data, Array<2,float> &speq, int nn1, int nn2, int nn3 data. (Result in this case must be multiplied by 1/n.) */ -void realft ( Array<1,float> &data, int n, int isign); +void realft(Array<1, float>& data, int n, int isign); END_NAMESPACE_STIR #endif - diff --git a/src/include/stir_experimental/fwd_and_bck_manipulation_for_SAF.h b/src/include/stir_experimental/fwd_and_bck_manipulation_for_SAF.h index 9fd606e1f2..50d470fde8 100644 --- a/src/include/stir_experimental/fwd_and_bck_manipulation_for_SAF.h +++ b/src/include/stir_experimental/fwd_and_bck_manipulation_for_SAF.h @@ -5,49 +5,23 @@ #include "stir/SegmentByView.h" #include "stir_experimental/recon_buildblock/ProjMatrixByDensel.h" - - START_NAMESPACE_STIR -void -fwd_project(ProjData& proj_data,VoxelsOnCartesianGrid* vox_image_ptr, - const int start_segment_num, const int end_segment_num, - const int start_axial_pos_num, const int end_axial_pos_num, - const int start_view, const int end_view, - const int start_tang_pos_num,const int end_tang_pos_num); - - - -void -do_segments_densels_fwd(const VoxelsOnCartesianGrid& image, - ProjData& proj_data, - VectorWithOffset *>& all_segments, - const int min_z, const int max_z, - const int min_y, const int max_y, - const int min_x, const int max_x, - ProjMatrixByDensel& proj_matrix); - - -void -fwd_densels_all(VectorWithOffset *>& all_segments, - shared_ptr proj_matrix_ptr, - shared_ptr proj_data_ptr, - const int min_z, const int max_z, - const int min_y, const int max_y, - const int min_x, const int max_x, - const DiscretisedDensity<3,float>& in_density); - -void -find_inverse_and_bck_densels(DiscretisedDensity<3,float>& image, - VectorWithOffset *>& all_segments, - VectorWithOffset *>& attenuation_segmnets, - const int min_z, const int max_z, - const int min_y, const int max_y, - const int min_x, const int max_x, - ProjMatrixByDensel& proj_matrix, - bool do_attenuation, - const float threshold, bool normalize_result); - - - +void fwd_project(ProjData& proj_data, VoxelsOnCartesianGrid* vox_image_ptr, const int start_segment_num, + const int end_segment_num, const int start_axial_pos_num, const int end_axial_pos_num, const int start_view, + const int end_view, const int start_tang_pos_num, const int end_tang_pos_num); + +void do_segments_densels_fwd(const VoxelsOnCartesianGrid& image, ProjData& proj_data, + VectorWithOffset*>& all_segments, const int min_z, const int max_z, + const int min_y, const int max_y, const int min_x, const int max_x, ProjMatrixByDensel& proj_matrix); + +void fwd_densels_all(VectorWithOffset*>& all_segments, shared_ptr proj_matrix_ptr, + shared_ptr proj_data_ptr, const int min_z, const int max_z, const int min_y, const int max_y, + const int min_x, const int max_x, const DiscretisedDensity<3, float>& in_density); + +void find_inverse_and_bck_densels(DiscretisedDensity<3, float>& image, VectorWithOffset*>& all_segments, + VectorWithOffset*>& attenuation_segmnets, const int min_z, const int max_z, + const int min_y, const int max_y, const int min_x, const int max_x, + ProjMatrixByDensel& proj_matrix, bool do_attenuation, const float threshold, + bool normalize_result); END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/listmode/CListModeDataLMF.h b/src/include/stir_experimental/listmode/CListModeDataLMF.h index 2419dc8497..92a03e7d22 100644 --- a/src/include/stir_experimental/listmode/CListModeDataLMF.h +++ b/src/include/stir_experimental/listmode/CListModeDataLMF.h @@ -4,14 +4,14 @@ \file \ingroup ClearPET_utilities \brief Declaration of class stir::CListModeDataLMF - + \author Kris Thielemans - + */ /* Copyright (C) 2003- 2004, Hammersmith Imanet Ltd - This software is distributed under the terms + This software is distributed under the terms of the GNU Lesser General Public Licence (LGPL) See STIR/LICENSE.txt for details */ @@ -23,7 +23,7 @@ #include "stir/shared_ptr.h" #include "LMF/lmf.h" // TODO adjust location //#include "LMF/LMF_ClearPET.h" // TODO don't know which is needed -//#include "LMF/LMF_Interfile.h" +//#include "LMF/LMF_Interfile.h" #include #include @@ -31,53 +31,39 @@ START_NAMESPACE_STIR - //! A class that reads the listmode data from an LMF file -class CListModeDataLMF : public CListModeData -{ +class CListModeDataLMF : public CListModeData { public: - //! Constructor taking a filename CListModeDataLMF(const std::string& listmode_filename); // Destructor closes the file and destroys various structures ~CListModeDataLMF(); - virtual std::time_t - get_scan_start_time_in_secs_since_1970() const - { return std::time_t(-1); } // TODO - - virtual - shared_ptr get_empty_record_sptr() const; + virtual std::time_t get_scan_start_time_in_secs_since_1970() const { return std::time_t(-1); } // TODO + virtual shared_ptr get_empty_record_sptr() const; //! LMF listmode data stores delayed events as well (as opposed to prompts) - virtual bool has_delayeds() const - { return true; } // TODO always? + virtual bool has_delayeds() const { return true; } // TODO always? - virtual - Succeeded get_next_record(CListRecord& event) const; + virtual Succeeded get_next_record(CListRecord& event) const; - virtual - Succeeded reset(); + virtual Succeeded reset(); - virtual - SavedPosition save_get_position(); + virtual SavedPosition save_get_position(); - virtual - Succeeded set_get_position(const SavedPosition&); + virtual Succeeded set_get_position(const SavedPosition&); private: - string listmode_filename; // TODO we really want to make this a shared_ptr I think to avoid memory leaks when throwing exceptions - struct LMF_ccs_encodingHeader *pEncoH; - FILE *pfCCS; + struct LMF_ccs_encodingHeader* pEncoH; + FILE* pfCCS; // possibly use this from LMF2Projection // SCANNER_CHECK_LIST scanCheckList; std::vector saved_get_positions; - }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/listmode/CListRecordLMF.h b/src/include/stir_experimental/listmode/CListRecordLMF.h index ced054ad59..648188664a 100644 --- a/src/include/stir_experimental/listmode/CListRecordLMF.h +++ b/src/include/stir_experimental/listmode/CListRecordLMF.h @@ -3,15 +3,15 @@ /*! \file \ingroup ClearPET_utilities - \brief Preliminary code to handle listmode events - + \brief Preliminary code to handle listmode events + \author Kris Thielemans - + */ /* Copyright (C) 2003- 2011, Hammersmith Imanet Ltd - This software is distributed under the terms + This software is distributed under the terms of the GNU Lesser General Public Licence (LGPL) See STIR/LICENSE.txt for details */ @@ -31,27 +31,22 @@ class CListModeDataLMF; //! Class for storing and using a coincidence event from a listmode file /*! \ingroup ClearPET_utilities */ -class CListEventDataLMF -{ - public: - inline bool is_prompt() const { return true; } // TODO +class CListEventDataLMF { +public: + inline bool is_prompt() const { return true; } // TODO inline Succeeded set_prompt(const bool prompt = true) // TODO - { return Succeeded::no; } - - inline LORAs2Points get_LOR() const - { return this->lor; } - - - CartesianCoordinate3D pos1() const - { return lor.p1(); } - CartesianCoordinate3D& pos1() - { return lor.p1(); } - CartesianCoordinate3D pos2() const - { return lor.p2(); } - CartesianCoordinate3D& pos2() - { return lor.p1(); } - - private: + { + return Succeeded::no; + } + + inline LORAs2Points get_LOR() const { return this->lor; } + + CartesianCoordinate3D pos1() const { return lor.p1(); } + CartesianCoordinate3D& pos1() { return lor.p1(); } + CartesianCoordinate3D pos2() const { return lor.p2(); } + CartesianCoordinate3D& pos2() { return lor.p1(); } + +private: LORAs2Points lor; }; /*-coincidence event*/ @@ -60,18 +55,18 @@ class CListRecordLMF; //! A class for storing and using a timing 'event' from a listmode file /*! \ingroup ClearPET_utilities */ -class CListTimeDataLMF -{ - public: - inline unsigned long get_time_in_millisecs() const - { return time; }// TODO - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs)//TODO - { return Succeeded::no; } +class CListTimeDataLMF { +public: + inline unsigned long get_time_in_millisecs() const { return time; } // TODO + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) // TODO + { + return Succeeded::no; + } + private: unsigned long time; // in millisecs TODO }; - //! A class for a general element of a listmode file /*! \ingroup ClearPET_utilities @@ -80,57 +75,40 @@ I store both time and CListEvent info in one CListRecordLMF. That's obviously not necessary nor desirable. */ -class CListRecordLMF : public CListRecord, public ListTime, public CListEvent -{ +class CListRecordLMF : public CListRecord, public ListTime, public CListEvent { public: - - CListRecordLMF& operator=(const CListEventDataLMF& event) - { - is_time_flag=false; - event_data = event; - } - bool is_time() const - { return is_time_flag == true; } - bool is_event() const - { return is_time_flag == false; } - virtual CListEvent& event() - { return *this; } - virtual const CListEvent& event() const - { return *this; } - virtual ListTime& time() - { return *this; } - virtual const ListTime& time() const - { return *this; } + CListRecordLMF& operator=(const CListEventDataLMF& event) { + is_time_flag = false; + event_data = event; + } + bool is_time() const { return is_time_flag == true; } + bool is_event() const { return is_time_flag == false; } + virtual CListEvent& event() { return *this; } + virtual const CListEvent& event() const { return *this; } + virtual ListTime& time() { return *this; } + virtual const ListTime& time() const { return *this; } bool operator==(const CListRecord& e2) const; - // time - inline double get_time_in_secs() const - { return time_data.get_time_in_secs(); } - inline Succeeded set_time_in_secs(const double time_in_secs) - { return time_data.set_time_in_secs(time_in_secs); } - inline unsigned int get_gating() const - { return time_data.get_gating(); } - inline Succeeded set_gating(unsigned int g) - { return time_data.set_gating(g); } + // time + inline double get_time_in_secs() const { return time_data.get_time_in_secs(); } + inline Succeeded set_time_in_secs(const double time_in_secs) { return time_data.set_time_in_secs(time_in_secs); } + inline unsigned int get_gating() const { return time_data.get_gating(); } + inline Succeeded set_gating(unsigned int g) { return time_data.set_gating(g); } // event inline bool is_prompt() const { return event_data.is_prompt(); } - inline Succeeded set_prompt(const bool prompt = true) - { return event_data.set_prompt(prompt); } - + inline Succeeded set_prompt(const bool prompt = true) { return event_data.set_prompt(prompt); } - private: +private: friend class CListModeDataLMF; - CListEventDataLMF event_data; - CListTimeDataLMF time_data; + CListEventDataLMF event_data; + CListTimeDataLMF time_data; bool is_time_flag; }; - - END_NAMESPACE_STIR #endif diff --git a/src/include/stir_experimental/listmode/LmToProjDataWithMC.h b/src/include/stir_experimental/listmode/LmToProjDataWithMC.h index 5361319ae9..4176ac3fa3 100644 --- a/src/include/stir_experimental/listmode/LmToProjDataWithMC.h +++ b/src/include/stir_experimental/listmode/LmToProjDataWithMC.h @@ -9,16 +9,15 @@ \ingroup listmode \brief Declaration of class stir::LmToProjDataWithMC - + \author Sanida Mustafovic \author Kris Thielemans - + */ #ifndef __stir_listmode_LmToProjDataWithMC_H__ #define __stir_listmode_LmToProjDataWithMC_H__ - #include "stir/listmode/LmToProjData.h" #include "stir/CartesianCoordinate3D.h" #include "stir_experimental/AbsTimeInterval.h" @@ -32,39 +31,33 @@ START_NAMESPACE_STIR Implements LOR repositioning during bining of list mode data into sinograms. */ -class LmToProjDataWithMC : public LmToProjData -{ +class LmToProjDataWithMC : public LmToProjData { public: - - LmToProjDataWithMC(const char * const par_filename); + LmToProjDataWithMC(const char* const par_filename); virtual void get_bin_from_event(Bin& bin, const CListEvent&) const; virtual void process_new_time_event(const ListTime& time_event); -protected: +protected: //! motion information shared_ptr ro3d_ptr; //! switch between constant reference position, or one for each frame bool reference_position_is_average_position_in_frame; //! constant reference position (if used) - shared_ptr _reference_abs_time_sptr; + shared_ptr _reference_abs_time_sptr; virtual void start_new_time_frame(const unsigned int new_frame_num); - virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); private: - RigidObject3DTransformation _transformation_to_reference_position; RigidObject3DTransformation ro3dtrans; // actual motion for current_time - }; END_NAMESPACE_STIR - #endif diff --git a/src/include/stir_experimental/local_helping_functions.h b/src/include/stir_experimental/local_helping_functions.h index ff8c04677a..f6f6ff2714 100644 --- a/src/include/stir_experimental/local_helping_functions.h +++ b/src/include/stir_experimental/local_helping_functions.h @@ -1,58 +1,44 @@ - - #include "stir/Array.h" #include "stir/VoxelsOnCartesianGrid.h" - - /* Here there are helping function used locally in ModifiedInverseAverigingImageFilter.cxx */ - START_NAMESPACE_STIR // Complex multiplication -void mulitply_complex_arrays(Array<1,float>& out_array, const Array<1,float>& array_nom, - const Array<1,float>& array_denom); +void mulitply_complex_arrays(Array<1, float>& out_array, const Array<1, float>& array_nom, const Array<1, float>& array_denom); -// Complex division -void divide_complex_arrays( Array<1,float>& out_array, const Array<1,float>& array_nom, - const Array<1,float>& array_denom); +// Complex division +void divide_complex_arrays(Array<1, float>& out_array, const Array<1, float>& array_nom, const Array<1, float>& array_denom); // two argument implementation -void mulitply_complex_arrays(Array<1,float>& array_nom, - const Array<1,float>& array_denom); -void divide_complex_arrays( Array<1,float>& array_nom, - const Array<1,float>& array_denom); +void mulitply_complex_arrays(Array<1, float>& array_nom, const Array<1, float>& array_denom); +void divide_complex_arrays(Array<1, float>& array_nom, const Array<1, float>& array_denom); // convert 3D arra into 1D array -void convert_array_3D_into_1D_array ( Array<1,float>& out_array,const Array<3,float>& in_array); -// convert 1d array into 3d array -void convert_array_1D_into_3D_array( Array<3,float>& out_array,const Array<1,float>& in_array); +void convert_array_3D_into_1D_array(Array<1, float>& out_array, const Array<3, float>& in_array); +// convert 1d array into 3d array +void convert_array_1D_into_3D_array(Array<3, float>& out_array, const Array<1, float>& in_array); // create 3d kernel -void create_kernel_3d ( Array<3,float>& kernel_3d, const VectorWithOffset < float>& kernel_1d); -void create_kernel_2d ( Array<2, float> & kernel_2d, const VectorWithOffset < float>& kernel_1d); +void create_kernel_3d(Array<3, float>& kernel_3d, const VectorWithOffset& kernel_1d); +void create_kernel_2d(Array<2, float>& kernel_2d, const VectorWithOffset& kernel_1d); // padd filter coefficients and make them symmetric -void padd_filter_coefficients_3D_and_make_them_symmetric(VectorWithOffset < VectorWithOffset < VectorWithOffset < float> > > &padded_filter_coefficients_3D, - VectorWithOffset < VectorWithOffset < VectorWithOffset < float> > > &filter_coefficients); +void padd_filter_coefficients_3D_and_make_them_symmetric( + VectorWithOffset>>& padded_filter_coefficients_3D, + VectorWithOffset>>& filter_coefficients); +void convert_array_2D_into_1D_array(Array<1, float>& out_array, Array<2, float>& in_array); -void convert_array_2D_into_1D_array( Array<1,float>& out_array,Array<2,float>& in_array); - -void convert_array_1D_into_2D_array( Array<2,float>& out_array,Array<1,float>& in_array); - +void convert_array_1D_into_2D_array(Array<2, float>& out_array, Array<1, float>& in_array); void precompute_filter_coefficients_for_second_apporach(VoxelsOnCartesianGrid& precomputed_coefficients, - const VoxelsOnCartesianGrid& input_image, - VoxelsOnCartesianGrid& sensitivity_image, - VoxelsOnCartesianGrid& normalised_bck); - - - - + const VoxelsOnCartesianGrid& input_image, + VoxelsOnCartesianGrid& sensitivity_image, + VoxelsOnCartesianGrid& normalised_bck); END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/modelling/BloodFrame.h b/src/include/stir_experimental/modelling/BloodFrame.h index 20bee8e500..0ab1d1483c 100644 --- a/src/include/stir_experimental/modelling/BloodFrame.h +++ b/src/include/stir_experimental/modelling/BloodFrame.h @@ -23,7 +23,7 @@ \brief Declaration of class stir::PlasmaData \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_BloodFrame_H__ @@ -35,42 +35,39 @@ START_NAMESPACE_STIR -class BloodFrame -{ +class BloodFrame { public: - //! default constructor + //! default constructor inline BloodFrame(); - - //! constructor of a frame, and its blood_counts_in_kBq, based on the acquired image. + + //! constructor of a frame, and its blood_counts_in_kBq, based on the acquired image. inline BloodFrame(const unsigned int frame_num, const float blood_counts); - //! constructor, mean time of a frame in seconds, and its blood_counts_in_kBq, based on the acquired image. - inline BloodFrame(const unsigned int frame_num, - const float frame_start_time_in_s, - const float frame_end_time_in_s, - const float blood_counts); + //! constructor, mean time of a frame in seconds, and its blood_counts_in_kBq, based on the acquired image. + inline BloodFrame(const unsigned int frame_num, const float frame_start_time_in_s, const float frame_end_time_in_s, + const float blood_counts); //! default destructor inline ~BloodFrame(); - - //! set the time of the sample - inline void set_frame_start_time_in_s( const float frame_start_time_in_s ); - //! set the time of the sample - inline void set_frame_end_time_in_s( const float frame_end_time_in_s ); - //! get the time of the sample - inline float get_frame_start_time_in_s() const; - //! get the time of the sample - inline float get_frame_end_time_in_s() const; - //! set the frame number of the sample, if the plasma is based on the acquired image. - inline void set_frame_num( const unsigned int frame_num ); - //! get the frame number of the sample, if the plasma is based on the acquired image. + + //! set the time of the sample + inline void set_frame_start_time_in_s(const float frame_start_time_in_s); + //! set the time of the sample + inline void set_frame_end_time_in_s(const float frame_end_time_in_s); + //! get the time of the sample + inline float get_frame_start_time_in_s() const; + //! get the time of the sample + inline float get_frame_end_time_in_s() const; + //! set the frame number of the sample, if the plasma is based on the acquired image. + inline void set_frame_num(const unsigned int frame_num); + //! get the frame number of the sample, if the plasma is based on the acquired image. inline unsigned int get_frame_num() const; - //! set the blood counts of the sample - inline void set_blood_counts_in_kBq( const float blood_counts ); - //! get the blood counts of the sample - inline float get_blood_counts_in_kBq() const; - -private : + //! set the blood counts of the sample + inline void set_blood_counts_in_kBq(const float blood_counts); + //! get the blood counts of the sample + inline float get_blood_counts_in_kBq() const; + +private: float _blood_counts; float _frame_start_time_in_s; float _frame_end_time_in_s; diff --git a/src/include/stir_experimental/modelling/BloodFrame.inl b/src/include/stir_experimental/modelling/BloodFrame.inl index a31ed7edb0..28f06ef1ee 100644 --- a/src/include/stir_experimental/modelling/BloodFrame.inl +++ b/src/include/stir_experimental/modelling/BloodFrame.inl @@ -27,61 +27,72 @@ START_NAMESPACE_STIR - //! default constructor -BloodFrame::BloodFrame() -{ } - //! constructor, time in s -BloodFrame::BloodFrame(const unsigned int frame_num, const float frame_start_time_in_s, const float frame_end_time_in_s, const float blood_counts) -{ - BloodFrame::set_frame_num( frame_num ); - BloodFrame::set_frame_start_time_in_s( frame_start_time_in_s ); - BloodFrame::set_frame_end_time_in_s( frame_end_time_in_s ); - BloodFrame::set_blood_counts_in_kBq( blood_counts ); +//! default constructor +BloodFrame::BloodFrame() {} +//! constructor, time in s +BloodFrame::BloodFrame(const unsigned int frame_num, const float frame_start_time_in_s, const float frame_end_time_in_s, + const float blood_counts) { + BloodFrame::set_frame_num(frame_num); + BloodFrame::set_frame_start_time_in_s(frame_start_time_in_s); + BloodFrame::set_frame_end_time_in_s(frame_end_time_in_s); + BloodFrame::set_blood_counts_in_kBq(blood_counts); } - //! constructor, frame number, if the plasma is based on the acquired image. -BloodFrame::BloodFrame(const unsigned int frame_num, const float blood_sample_counts) -{ - BloodFrame::set_frame_num( frame_num ); - BloodFrame::set_blood_counts_in_kBq( blood_sample_counts ); +//! constructor, frame number, if the plasma is based on the acquired image. +BloodFrame::BloodFrame(const unsigned int frame_num, const float blood_sample_counts) { + BloodFrame::set_frame_num(frame_num); + BloodFrame::set_blood_counts_in_kBq(blood_sample_counts); } - //! default destructor -BloodFrame::~BloodFrame() -{ } - - //! set the start_time of the sample -void BloodFrame::set_frame_start_time_in_s( const float frame_start_time_in_s ) -{ BloodFrame::_frame_start_time_in_s=frame_start_time_in_s ; } +//! default destructor +BloodFrame::~BloodFrame() {} - //! get the start_time of the sample -float BloodFrame::get_frame_start_time_in_s() const -{ return BloodFrame::_frame_start_time_in_s ; } - - //! set the start_time of the sample -void BloodFrame::set_frame_end_time_in_s( const float frame_end_time_in_s ) -{ BloodFrame::_frame_end_time_in_s=frame_end_time_in_s ; } +//! set the start_time of the sample +void +BloodFrame::set_frame_start_time_in_s(const float frame_start_time_in_s) { + BloodFrame::_frame_start_time_in_s = frame_start_time_in_s; +} - //! get the start_time of the sample -float BloodFrame::get_frame_end_time_in_s() const -{ return BloodFrame::_frame_end_time_in_s ; } +//! get the start_time of the sample +float +BloodFrame::get_frame_start_time_in_s() const { + return BloodFrame::_frame_start_time_in_s; +} - //! set the frame number of the sample, if the plasma is based on the acquired image. -void BloodFrame::set_frame_num( const unsigned int frame_num ) -{ BloodFrame::_frame_num=frame_num ; } +//! set the start_time of the sample +void +BloodFrame::set_frame_end_time_in_s(const float frame_end_time_in_s) { + BloodFrame::_frame_end_time_in_s = frame_end_time_in_s; +} - //! get the frame number of the sample, if the plasma is based on the acquired image. -unsigned int BloodFrame::get_frame_num() const -{ return BloodFrame::_frame_num ; } +//! get the start_time of the sample +float +BloodFrame::get_frame_end_time_in_s() const { + return BloodFrame::_frame_end_time_in_s; +} - //! set the blood counts of the sample -void BloodFrame::set_blood_counts_in_kBq( const float blood_counts ) -{ BloodFrame::_blood_counts=blood_counts ; } +//! set the frame number of the sample, if the plasma is based on the acquired image. +void +BloodFrame::set_frame_num(const unsigned int frame_num) { + BloodFrame::_frame_num = frame_num; +} - //! get the blood counts of the sample -float BloodFrame::get_blood_counts_in_kBq() const -{ return BloodFrame::_blood_counts ; } +//! get the frame number of the sample, if the plasma is based on the acquired image. +unsigned int +BloodFrame::get_frame_num() const { + return BloodFrame::_frame_num; +} +//! set the blood counts of the sample +void +BloodFrame::set_blood_counts_in_kBq(const float blood_counts) { + BloodFrame::_blood_counts = blood_counts; +} +//! get the blood counts of the sample +float +BloodFrame::get_blood_counts_in_kBq() const { + return BloodFrame::_blood_counts; +} END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/modelling/BloodFrameData.h b/src/include/stir_experimental/modelling/BloodFrameData.h index 20f05f12f1..15fab18f0d 100644 --- a/src/include/stir_experimental/modelling/BloodFrameData.h +++ b/src/include/stir_experimental/modelling/BloodFrameData.h @@ -23,7 +23,7 @@ \brief Declaration of class stir::BloodFrameData \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_BloodFrameData_H__ @@ -35,86 +35,81 @@ START_NAMESPACE_STIR - -/*! +/*! \ingroup modelling \brief A class for storing plasma samples of a single study. */ -class BloodFrameData -{ - typedef std::vector plot_type; - - public: - - typedef plot_type::const_iterator const_iterator; - /* enum VolumeUnits - { ml , litre }; - enum SamplingTimeUnits - { seconds , minutes }; - enum RadioactivityUnits - { counts_per_sec , counts_per_min , kBq }; - - inline void set_input_units(const SamplingTimeUnits input_sampling_time_units, - const VolumeUnits input_volume_units, - const RadioactivityUnits input_radioactivity_units ) ; - - */ +class BloodFrameData { + typedef std::vector plot_type; + +public: + typedef plot_type::const_iterator const_iterator; + /* enum VolumeUnits + { ml , litre }; + enum SamplingTimeUnits + { seconds , minutes }; + enum RadioactivityUnits + { counts_per_sec , counts_per_min , kBq }; + + inline void set_input_units(const SamplingTimeUnits input_sampling_time_units, + const VolumeUnits input_volume_units, + const RadioactivityUnits input_radioactivity_units ) ; + + */ //! Implementation to read the input function from ONLY a 2-columns frame data (FrameNumber-InputFunctionRadioactivity). - inline void read_blood_frame_data(const std::string input_string) ; - inline void set_plot(const std::vector & blood_plot) ; + inline void read_blood_frame_data(const std::string input_string); + inline void set_plot(const std::vector& blood_plot); //! Implementation to set the input units not currently used. Always, it assumed to use kBq, seconds, ml. - //!Function to shift the time data + //! Function to shift the time data inline void shift_time(const float time_shift); - //!Function to get the time data + //! Function to get the time data inline float get_time_shift(); - //!Function to set the isotope halflife + //! Function to set the isotope halflife inline void set_isotope_halflife(const float isotope_halflife); - //!Function to set _is_decay_corrected boolean true ar false + //! Function to set _is_decay_corrected boolean true ar false inline void set_if_decay_corrected(const bool is_decay_corrected); - //!Function to set _is_decay_corrected boolean true ar false + //! Function to set _is_decay_corrected boolean true ar false inline bool get_if_decay_corrected(); - //!Function to decay correct the data + //! Function to decay correct the data inline void decay_correct_BloodFrameData(); //! default constructor inline BloodFrameData(); //! constructor giving a vector //ChT::ToDO: Better to use iterators - inline BloodFrameData(const std::vector & blood_plot); + inline BloodFrameData(const std::vector& blood_plot); //! default constructor inline ~BloodFrameData(); //! void begin() and end() iterators for the plasma curve ; -inline const_iterator begin() const ; -inline const_iterator end() const ; - inline unsigned int size() const ; - // non const_iterator should be defined if the plasma data needs to be changed -//inline iterator begin() ; -//inline iterator end() ; - - private: - /* VolumeUnits _input_volume_units ; - SamplingTimeUnits _input_sampling_time_units ; - RadioactivityUnits _input_radioactivity_units ;*/ - bool _is_decay_corrected ; + inline const_iterator begin() const; + inline const_iterator end() const; + inline unsigned int size() const; + // non const_iterator should be defined if the plasma data needs to be changed + // inline iterator begin() ; + // inline iterator end() ; + +private: + /* VolumeUnits _input_volume_units ; + SamplingTimeUnits _input_sampling_time_units ; + RadioactivityUnits _input_radioactivity_units ;*/ + bool _is_decay_corrected; float _isotope_halflife; - std::vector _blood_plot ; + std::vector _blood_plot; int _num_frames; - float _time_shift ; + float _time_shift; }; - END_NAMESPACE_STIR - #include "stir_experimental/modelling/BloodFrameData.inl" #endif //__stir_modelling_BloodFrameData_H__ diff --git a/src/include/stir_experimental/modelling/BloodFrameData.inl b/src/include/stir_experimental/modelling/BloodFrameData.inl index 21e4ccc4b0..57b996c9de 100644 --- a/src/include/stir_experimental/modelling/BloodFrameData.inl +++ b/src/include/stir_experimental/modelling/BloodFrameData.inl @@ -28,115 +28,114 @@ START_NAMESPACE_STIR //! default constructor -BloodFrameData::BloodFrameData() -{ } +BloodFrameData::BloodFrameData() {} //! constructor giving a vector //ChT::ToDO: Better to use iterators -BloodFrameData::BloodFrameData(const std::vector & blood_plot) -{this->_blood_plot=blood_plot;} +BloodFrameData::BloodFrameData(const std::vector& blood_plot) { this->_blood_plot = blood_plot; } //! default destructor -BloodFrameData::~BloodFrameData() -{ } +BloodFrameData::~BloodFrameData() {} //! Implementation to read the input function from ONLY a 2-columns frame data (FrameNumber-InputFunctionRadioactivity). -void BloodFrameData::read_blood_frame_data(const std::string input_string) -{ - std::ifstream data_stream(input_string.c_str()); - if(!data_stream) - error("cannot read blood frame data from file.\n"); - else - { - data_stream >> _num_frames ; - while(true) - { - unsigned int frame_num=0; - float blood_sample_radioactivity=0.F; - data_stream >> frame_num ; - data_stream >> blood_sample_radioactivity ; - if(!data_stream) - break; - const BloodFrame current_sample(frame_num,blood_sample_radioactivity); - (this->_blood_plot).push_back(current_sample); - } - } +void +BloodFrameData::read_blood_frame_data(const std::string input_string) { + std::ifstream data_stream(input_string.c_str()); + if (!data_stream) + error("cannot read blood frame data from file.\n"); + else { + data_stream >> _num_frames; + while (true) { + unsigned int frame_num = 0; + float blood_sample_radioactivity = 0.F; + data_stream >> frame_num; + data_stream >> blood_sample_radioactivity; + if (!data_stream) + break; + const BloodFrame current_sample(frame_num, blood_sample_radioactivity); + (this->_blood_plot).push_back(current_sample); + } + } } //! Implementation to set the input units not currently used. /* void -BloodFrameData::set_input_units( SamplingTimeUnits input_sampling_time_units, - VolumeUnits input_volume_units, - RadioactivityUnits input_radioactivity_units ) +BloodFrameData::set_input_units( SamplingTimeUnits input_sampling_time_units, + VolumeUnits input_volume_units, + RadioactivityUnits input_radioactivity_units ) { _input_sampling_time_units=input_sampling_time_units ; _input_volume_units=input_volume_units ; _input_radioactivity_units=input_radioactivity_units ; -} +} */ -//!Function to shift the time data -void BloodFrameData::shift_time(const float time_shift) -{ - _time_shift=time_shift; - for(std::vector::iterator cur_iter=this->_blood_plot.begin() ; - cur_iter!=this->_blood_plot.end() ; ++cur_iter) - { - cur_iter->set_frame_start_time_in_s(cur_iter->get_frame_start_time_in_s()+time_shift); - cur_iter->set_frame_end_time_in_s(cur_iter->get_frame_end_time_in_s()+time_shift); - } +//! Function to shift the time data +void +BloodFrameData::shift_time(const float time_shift) { + _time_shift = time_shift; + for (std::vector::iterator cur_iter = this->_blood_plot.begin(); cur_iter != this->_blood_plot.end(); ++cur_iter) { + cur_iter->set_frame_start_time_in_s(cur_iter->get_frame_start_time_in_s() + time_shift); + cur_iter->set_frame_end_time_in_s(cur_iter->get_frame_end_time_in_s() + time_shift); + } +} +//! Function to get the time data +float +BloodFrameData::get_time_shift() { + return BloodFrameData::_time_shift; } -//!Function to get the time data -float BloodFrameData::get_time_shift() -{ return BloodFrameData::_time_shift ; } -void BloodFrameData::set_isotope_halflife(const float isotope_halflife) -{ _isotope_halflife=isotope_halflife; } +void +BloodFrameData::set_isotope_halflife(const float isotope_halflife) { + _isotope_halflife = isotope_halflife; +} -void BloodFrameData:: -set_if_decay_corrected(const bool is_decay_corrected) -{ this->_is_decay_corrected=is_decay_corrected; } +void +BloodFrameData::set_if_decay_corrected(const bool is_decay_corrected) { + this->_is_decay_corrected = is_decay_corrected; +} -bool BloodFrameData:: -get_if_decay_corrected() -{ return this->_is_decay_corrected; } +bool +BloodFrameData::get_if_decay_corrected() { + return this->_is_decay_corrected; +} -void BloodFrameData:: -decay_correct_BloodFrameData() -{ - if (BloodFrameData::_is_decay_corrected==true) +void +BloodFrameData::decay_correct_BloodFrameData() { + if (BloodFrameData::_is_decay_corrected == true) warning("BloodFrameData are already decay corrected"); - else - { - for(std::vector::iterator cur_iter=this->_blood_plot.begin() ; - cur_iter!=this->_blood_plot.end() ; ++cur_iter) - cur_iter->set_blood_counts_in_kBq(cur_iter->get_blood_counts_in_kBq() - *decay_correct_factor(_isotope_halflife,cur_iter->get_frame_start_time_in_s(),cur_iter->get_frame_end_time_in_s())); - BloodFrameData::set_if_decay_corrected(true); - } + else { + for (std::vector::iterator cur_iter = this->_blood_plot.begin(); cur_iter != this->_blood_plot.end(); ++cur_iter) + cur_iter->set_blood_counts_in_kBq( + cur_iter->get_blood_counts_in_kBq() * + decay_correct_factor(_isotope_halflife, cur_iter->get_frame_start_time_in_s(), cur_iter->get_frame_end_time_in_s())); + BloodFrameData::set_if_decay_corrected(true); + } } +void +BloodFrameData::set_plot(const std::vector& blood_plot) { + this->_blood_plot = blood_plot; +} -void BloodFrameData::set_plot(const std::vector & blood_plot) -{this->_blood_plot=blood_plot;} - - -//BloodFrameData begin() and end() of the BloodFrameData ; +// BloodFrameData begin() and end() of the BloodFrameData ; BloodFrameData::const_iterator -BloodFrameData::begin() const -{ return this->_blood_plot.begin() ; } +BloodFrameData::begin() const { + return this->_blood_plot.begin(); +} BloodFrameData::const_iterator -BloodFrameData::end() const -{ return this->_blood_plot.end() ; } +BloodFrameData::end() const { + return this->_blood_plot.end(); +} unsigned int -BloodFrameData::size() const -{ return this->_blood_plot.size() ; } +BloodFrameData::size() const { + return this->_blood_plot.size(); +} /* //BloodFrameData begin() and end() of the BloodFrameData ; BloodFrameData::iterator -BloodFrameData::begin() +BloodFrameData::begin() { return this->_blood_plot.begin() ; } BloodFrameData::iterator BloodFrameData::end() { return this->_blood_plot.end() ; } */ - END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/modelling/OneParamModel.h b/src/include/stir_experimental/modelling/OneParamModel.h index 753dce753b..6db2bd5582 100644 --- a/src/include/stir_experimental/modelling/OneParamModel.h +++ b/src/include/stir_experimental/modelling/OneParamModel.h @@ -32,23 +32,21 @@ START_NAMESPACE_STIR -class OneParamModel -{ - public: - +class OneParamModel { +public: //! default constructor inline OneParamModel(); //! constructor inline OneParamModel(const int starting_frame, const int last_frame); - //! Create a unit model matrix for a single frame and single parameter + //! Create a unit model matrix for a single frame and single parameter inline ModelMatrix<1> get_unit_matrix(const int starting_frame, const int last_frame); //! default destructor inline ~OneParamModel(); - private: +private: ModelMatrix<1> _unit_matrix; int _starting_frame; int _last_frame; diff --git a/src/include/stir_experimental/modelling/OneParamModel.inl b/src/include/stir_experimental/modelling/OneParamModel.inl index fbea5c5773..7f7b4b7ea7 100644 --- a/src/include/stir_experimental/modelling/OneParamModel.inl +++ b/src/include/stir_experimental/modelling/OneParamModel.inl @@ -28,43 +28,39 @@ START_NAMESPACE_STIR //! default constructor -OneParamModel::OneParamModel() -{ _matrix_is_stored=false; } +OneParamModel::OneParamModel() { _matrix_is_stored = false; } -OneParamModel::OneParamModel(const int starting_frame, const int last_frame) -{ - this->_matrix_is_stored=false; - this->_starting_frame=starting_frame; - this->_last_frame=last_frame; +OneParamModel::OneParamModel(const int starting_frame, const int last_frame) { + this->_matrix_is_stored = false; + this->_starting_frame = starting_frame; + this->_last_frame = last_frame; } //! default destructor -OneParamModel::~OneParamModel() -{ } +OneParamModel::~OneParamModel() {} -//! Create a unit model matrix for a single frame and single parameter -ModelMatrix<1> -OneParamModel:: -get_unit_matrix(const int starting_frame, const int last_frame) -{ - if(_matrix_is_stored==false) - { - this->_starting_frame=starting_frame; - this->_last_frame=last_frame; - BasicCoordinate<2,int> min_range; - BasicCoordinate<2,int> max_range; - min_range[1]=1; min_range[2]=this->_starting_frame; - max_range[1]=1; max_range[2]=this->_last_frame; - IndexRange<2> data_range(min_range,max_range); - Array<2,float> unit_array(data_range); - - for(int frame_num=this->_starting_frame ; frame_num<=this->_last_frame; ++frame_num) - unit_array[1][frame_num]=1.F; +//! Create a unit model matrix for a single frame and single parameter +ModelMatrix<1> +OneParamModel::get_unit_matrix(const int starting_frame, const int last_frame) { + if (_matrix_is_stored == false) { + this->_starting_frame = starting_frame; + this->_last_frame = last_frame; + BasicCoordinate<2, int> min_range; + BasicCoordinate<2, int> max_range; + min_range[1] = 1; + min_range[2] = this->_starting_frame; + max_range[1] = 1; + max_range[2] = this->_last_frame; + IndexRange<2> data_range(min_range, max_range); + Array<2, float> unit_array(data_range); - _unit_matrix.set_model_array(unit_array); - _matrix_is_stored=true; - } - return _unit_matrix ; + for (int frame_num = this->_starting_frame; frame_num <= this->_last_frame; ++frame_num) + unit_array[1][frame_num] = 1.F; + + _unit_matrix.set_model_array(unit_array); + _matrix_is_stored = true; + } + return _unit_matrix; } END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/MatchTrackerAndScanner.h b/src/include/stir_experimental/motion/MatchTrackerAndScanner.h index a8d1474233..0f4ba04cbe 100644 --- a/src/include/stir_experimental/motion/MatchTrackerAndScanner.h +++ b/src/include/stir_experimental/motion/MatchTrackerAndScanner.h @@ -14,7 +14,7 @@ \author Kris Thielemans - + */ #include "stir_experimental/motion/RigidObject3DTransformation.h" #include "stir/TimeFrameDefinitions.h" @@ -32,13 +32,13 @@ START_NAMESPACE_STIR You need to have performed a scan where the '0' marker of the tracker is filled with some radioactive material, and the marker is then moved to various stationary positions inside - the scanner, while performing a (list-mode) scan, while the tracker is running. - Remember: discrete movements. - + the scanner, while performing a (list-mode) scan, while the tracker is running. + Remember: discrete movements. + Then you need to make a frame-definition file where all non-stationary parts are skipped. Then you sort the list mode data into sinograms, and reconstruct images (preferably with large zoom) for each of these discrete positions. - + \par What does it do? This implements Horn's method, as discussed in detail in Roger Fulton's thesis. Briefly: @@ -46,7 +46,7 @@ START_NAMESPACE_STIR a threshold) in the image as the location of the point source. - for each tracker-sample in the time frame, we find where the tracker says that the 0 marker moved to. - - All the data for all time frames is then put through + - All the data for all time frames is then put through RigidObject3DTransformation::find_closest_transformation to find a least-squares fit between the 2 sets of coordinates. - The class writes various diagnostics to stdout, including the value of the fit. @@ -59,9 +59,9 @@ START_NAMESPACE_STIR MoveImage Parameters:= ; see TimeFrameDefinitions time frame_definition filename := frame_definition_filename - + ; next parameter is optional (and not normally necessary) - ; it can be used if the frame definitions are relative to another scan as what + ; it can be used if the frame definitions are relative to another scan as what ; is used to for the rigid object motion (i.e. currently the list mode data used ; for the Polaris synchronisation) ; scan_start_time_secs_since_1970_UTC @@ -70,7 +70,7 @@ START_NAMESPACE_STIR ; specify motion, see stir::RigidObject3DMotion Rigid Object 3D Motion Type := type - ; optional field to determine relative threshold to apply to + ; optional field to determine relative threshold to apply to ; the image before taking the centre of gravity ; it is relative to the maximum in each image (i.e. .5 would be at half the maximum) ; default is .1 @@ -84,44 +84,37 @@ START_NAMESPACE_STIR \warning Currently the motion object needs to be defined using a transformation_from_scanner_coords file. However, the value of the transformation is completely ignored by the current class. -*/ -class MatchTrackerAndScanner : public ParsingObject -{ +*/ +class MatchTrackerAndScanner : public ParsingObject { public: - MatchTrackerAndScanner(const char * const par_filename); + MatchTrackerAndScanner(const char* const par_filename); //! finds the match when all parameters have been set /*! will store the transformation as part of this object, but also write it to stdout */ Succeeded run(); - const TimeFrameDefinitions& - get_time_frame_defs() const; + const TimeFrameDefinitions& get_time_frame_defs() const; - double get_frame_start_time(unsigned frame_num) const - { return frame_defs.get_start_time(frame_num) + scan_start_time; } + double get_frame_start_time(unsigned frame_num) const { return frame_defs.get_start_time(frame_num) + scan_start_time; } - double get_frame_end_time(unsigned frame_num) const - { return frame_defs.get_end_time(frame_num) + scan_start_time; } + double get_frame_end_time(unsigned frame_num) const { return frame_defs.get_end_time(frame_num) + scan_start_time; } - const string& get_image_filename_prefix() const - { return _image_filename_prefix; } - - const RigidObject3DMotion& get_motion() const - { return *_ro3d_sptr; } + const string& get_image_filename_prefix() const { return _image_filename_prefix; } - const RigidObject3DTransformation& - get_transformation_from_scanner_coords() const - { return _transformation_from_scanner_coords; } + const RigidObject3DMotion& get_motion() const { return *_ro3d_sptr; } -protected: + const RigidObject3DTransformation& get_transformation_from_scanner_coords() const { + return _transformation_from_scanner_coords; + } +protected: // all of these really should be in a AbsTimeFrameDefinitions class or so TimeFrameDefinitions frame_defs; int scan_start_time_secs_since_1970_UTC; double _current_frame_end_time; double _current_frame_start_time; - + //! parsing functions virtual void set_defaults(); virtual void initialise_keymap(); @@ -135,11 +128,12 @@ class MatchTrackerAndScanner : public ParsingObject string _image_filename_prefix; float relative_threshold; + private: shared_ptr _ro3d_sptr; // will be set to new value - RigidObject3DTransformation _transformation_from_scanner_coords; + RigidObject3DTransformation _transformation_from_scanner_coords; }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/NonRigidObjectTransformationUsingBSplines.h b/src/include/stir_experimental/motion/NonRigidObjectTransformationUsingBSplines.h index e0f7e1843e..204f977941 100644 --- a/src/include/stir_experimental/motion/NonRigidObjectTransformationUsingBSplines.h +++ b/src/include/stir_experimental/motion/NonRigidObjectTransformationUsingBSplines.h @@ -16,7 +16,6 @@ #ifndef __stir_motion_NonRigidObjectTransformationUsingBSplines_H__ #define __stir_motion_NonRigidObjectTransformationUsingBSplines_H__ - #include "stir_experimental/motion/ObjectTransformation.h" #include "stir/CartesianCoordinate3D.h" #include "stir/numerics/BSplines.h" @@ -29,13 +28,11 @@ START_NAMESPACE_STIR class Succeeded; template - class DeformationFieldOnCartesianGrid : - public BasicCoordinate > +class DeformationFieldOnCartesianGrid : public BasicCoordinate> // public DiscretisedDensityOnCartesianGrid > { - public: +public: DeformationFieldOnCartesianGrid() {} - }; /*! \ingroup motion @@ -44,46 +41,42 @@ template */ template class NonRigidObjectTransformationUsingBSplines - : - public - RegisteredParsingObject, - ObjectTransformation, - ObjectTransformation > -{ + : public RegisteredParsingObject, + ObjectTransformation, ObjectTransformation> { public: - static const char * const registered_name; + static const char* const registered_name; // Default constructor NonRigidObjectTransformationUsingBSplines(); /// Give x, y and z components of the deformation field images separately. /// N.B., this will only work if the three components are in STIR orientation. - NonRigidObjectTransformationUsingBSplines(const std::string &filename_x, const std::string &filename_y, const std::string &filename_z, const int bspline_order); + NonRigidObjectTransformationUsingBSplines(const std::string& filename_x, const std::string& filename_y, + const std::string& filename_z, const int bspline_order); /// Give x, y and z components of the deformation field images together (e.g., multicomponent nifti) NonRigidObjectTransformationUsingBSplines(const std::string& filename, const int bspline_order); - //! Transform point - virtual - BasicCoordinate - transform_point(const BasicCoordinate& point) const; + //! Transform point + virtual BasicCoordinate transform_point(const BasicCoordinate& point) const; - float jacobian(const BasicCoordinate& point) const; + float jacobian(const BasicCoordinate& point) const; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); virtual void set_key_values(); + private: - BasicCoordinate > interpolator; - //BasicCoordinate _grid_spacing; - //BasicCoordinate _origin; + BasicCoordinate> interpolator; + // BasicCoordinate _grid_spacing; + // BasicCoordinate _origin; CartesianCoordinate3D _grid_spacing; CartesianCoordinate3D _origin; BSpline::BSplineType _bspline_type; // use for parsing only - shared_ptr< DeformationFieldOnCartesianGrid > deformation_field_sptr; + shared_ptr> deformation_field_sptr; int _bspline_order; // for NCAT only std::string _deformation_field_from_NCAT_file; @@ -110,7 +103,6 @@ operator>>(std::istream& , NonRigidObjectTransformationUsingBSplines& rigid_object_transformation); #endif - END_NAMESPACE_STIR #endif diff --git a/src/include/stir_experimental/motion/ObjectTransformation.h b/src/include/stir_experimental/motion/ObjectTransformation.h index 49df86751b..22c6cfea30 100644 --- a/src/include/stir_experimental/motion/ObjectTransformation.h +++ b/src/include/stir_experimental/motion/ObjectTransformation.h @@ -16,7 +16,6 @@ #ifndef __stir_motion_ObjectTransformation_H__ #define __stir_motion_ObjectTransformation_H__ - #include "stir/BasicCoordinate.h" #include "stir/RegisteredObject.h" #include "stir/ParsingObject.h" @@ -24,26 +23,22 @@ START_NAMESPACE_STIR /*! \ingroup motion - \brief Base-class for performing (potentially non-rigid) object transformations + \brief Base-class for performing (potentially non-rigid) object transformations */ template -class ObjectTransformation : - public RegisteredObject > -{ +class ObjectTransformation : public RegisteredObject> { public: //! typedef used by read_from_file typedef ObjectTransformation hierarchy_base_type; virtual ~ObjectTransformation() {} - //! Transform point + //! Transform point /* \todo should be CartesianCoordinate, but we don't have that class yet*/ - virtual BasicCoordinate - transform_point(const BasicCoordinate& point) const = 0; + virtual BasicCoordinate transform_point(const BasicCoordinate& point) const = 0; //! Returns the determinant of the Jacobian matrix /*! This is related to the volume-element change due to the transformation. */ - virtual float - jacobian(const BasicCoordinate& point) const = 0; + virtual float jacobian(const BasicCoordinate& point) const = 0; }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h b/src/include/stir_experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h index 98c9f9be7c..c0349f2d66 100644 --- a/src/include/stir_experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h +++ b/src/include/stir_experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h @@ -28,7 +28,6 @@ #ifndef __stir_recon_buildblock_PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion_H__ #define __stir_recon_buildblock_PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" #include "stir/GatedProjData.h" @@ -46,38 +45,29 @@ class GatedProjData; \brief */ template -class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion -: public RegisteredParsingObject - , - GeneralisedObjectiveFunction, - SumOfGeneralisedObjectiveFunctions, - TargetT, - PoissonLogLikelihoodWithLinearModelForMean > -> -{ - private: - typedef - RegisteredParsingObject - , - GeneralisedObjectiveFunction, - SumOfGeneralisedObjectiveFunctions, - TargetT, - PoissonLogLikelihoodWithLinearModelForMean > - > - base_type; +class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion + : public RegisteredParsingObject< + PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion, GeneralisedObjectiveFunction, + SumOfGeneralisedObjectiveFunctions, TargetT, + PoissonLogLikelihoodWithLinearModelForMean>> { +private: + typedef RegisteredParsingObject< + PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion, GeneralisedObjectiveFunction, + SumOfGeneralisedObjectiveFunctions, TargetT, + PoissonLogLikelihoodWithLinearModelForMean>> + base_type; public: - //! Name which will be used when parsing a GeneralisedObjectiveFunction object - static const char * const registered_name; + static const char* const registered_name; //! Default constructor calls set_defaults() PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion(); - + /*! \name Functions to set parameters This can be used as alternative to the parsing mechanism. \warning After using any of these, you have to call set_up(). - \warning Be careful with setting shared pointers. If you modify the objects in + \warning Be careful with setting shared pointers. If you modify the objects in one place, all objects that use the shared pointer will be affected. */ @@ -86,28 +76,20 @@ class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion void set_max_segment_num_to_process(const int); void set_zero_seg0_end_planes(const bool); void set_additive_proj_data_sptr(const shared_ptr&); - void set_projector_pair_sptr(const shared_ptr&) ; + void set_projector_pair_sptr(const shared_ptr&); void set_frame_num(const int); void set_frame_definitions(const TimeFrameDefinitions&); //@} - virtual - TargetT * - construct_target_ptr() const; + virtual TargetT* construct_target_ptr() const; - virtual - void - compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT& target, - const int subset_num); -protected: + virtual void compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, const TargetT& target, + const int subset_num); - virtual - Succeeded - set_up_before_sensitivity(shared_ptr const& target_sptr); +protected: + virtual Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr); - virtual void - add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const; + virtual void add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const; //! Filename with input projection data std::string _input_filename; @@ -121,12 +103,12 @@ class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion // TODO to be replaced with single class or so (TargetT obviously) //! the output image size in x and y direction /*! convention: if -1, use a size such that the whole FOV is covered - */ + */ int output_image_size_xy; // KT 10122001 appended _xy //! the output image size in z direction /*! convention: if -1, use default as provided by VoxelsOnCartesianGrid constructor - */ + */ int output_image_size_z; // KT 10122001 new //! the zoom factor @@ -143,7 +125,6 @@ class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion double Zoffset; /********************************/ - //! Stores the projectors that are used for the computations shared_ptr projector_pair_ptr; @@ -153,13 +134,13 @@ class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion //! name of file in which loglikelihood measurements are stored std::string _additive_projection_data_filename; - // TODO doc + // TODO doc int frame_num; std::string frame_definition_filename; TimeFrameDefinitions frame_defs; - VectorWithOffset > _normalisation_sptrs; + VectorWithOffset> _normalisation_sptrs; - private: +private: virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); @@ -169,7 +150,7 @@ class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion shared_ptr symmetries_sptr; - VectorWithOffset > > _forward_transformations; + VectorWithOffset>> _forward_transformations; }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/Polaris_MT_File.h b/src/include/stir_experimental/motion/Polaris_MT_File.h index 1b57460daf..adfbd703b5 100644 --- a/src/include/stir_experimental/motion/Polaris_MT_File.h +++ b/src/include/stir_experimental/motion/Polaris_MT_File.h @@ -25,11 +25,14 @@ #include #include -# ifdef BOOST_NO_STDC_NAMESPACE -namespace std { using ::time_t; using ::tm; using ::localtime; } +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::time_t; +using ::tm; +using ::localtime; +} // namespace std #endif - START_NAMESPACE_STIR /*!\ingroup motion @@ -49,7 +52,7 @@ START_NAMESPACE_STIR Tool Number (as a character) Q0, Qx, Qy, Qz Tx, Ty, Tz - RMS Error + RMS Error \endverbatim or something like \verbatim @@ -59,55 +62,54 @@ START_NAMESPACE_STIR \warning All times are in local time, and are hence subject to the settings of your TZ environment variable. This means that if the - data is processed in a different time zone, you will run into + data is processed in a different time zone, you will run into trouble. */ -class Polaris_MT_File -{ +class Polaris_MT_File { public: - struct Record - { - double sample_time; - unsigned int frame_num; - unsigned int rand_num; - char total_num; - Quaternion quat; - CartesianCoordinate3D trans; - float rms ; - unsigned int out_of_FOV; - }; + struct Record { + double sample_time; + unsigned int frame_num; + unsigned int rand_num; + char total_num; + Quaternion quat; + CartesianCoordinate3D trans; + float rms; + unsigned int out_of_FOV; + }; typedef std::vector::const_iterator const_iterator; - ~Polaris_MT_File () {}; - Polaris_MT_File(const std::string& filename); - - //! get the \a n-th complete record - /*! \warning This skips the 'missing data' records*/ - Record operator[](unsigned int n) const; - - //! iterators that go through complete records - const_iterator begin() const { return vector_of_records.begin();} - const_iterator end() const { return vector_of_records.end();} - unsigned long num_samples() const { return vector_of_records.size(); } - - //! iterators that go through all tags recorded by the Polaris - const_iterator begin_all_tags() const { return vector_of_tags.begin();} - const_iterator end_all_tags() const { return vector_of_tags.end();} - unsigned long num_tags() const { return vector_of_tags.size(); } - - //! start of acquisition as would have been returned by std::time() - std::time_t get_start_time_in_secs_since_1970(); + ~Polaris_MT_File(){}; + Polaris_MT_File(const std::string& filename); + + //! get the \a n-th complete record + /*! \warning This skips the 'missing data' records*/ + Record operator[](unsigned int n) const; + + //! iterators that go through complete records + const_iterator begin() const { return vector_of_records.begin(); } + const_iterator end() const { return vector_of_records.end(); } + unsigned long num_samples() const { return vector_of_records.size(); } + + //! iterators that go through all tags recorded by the Polaris + const_iterator begin_all_tags() const { return vector_of_tags.begin(); } + const_iterator end_all_tags() const { return vector_of_tags.end(); } + unsigned long num_tags() const { return vector_of_tags.size(); } + + //! start of acquisition as would have been returned by std::time() + std::time_t get_start_time_in_secs_since_1970(); + private: - std::time_t start_time_in_secs_since_1970; + std::time_t start_time_in_secs_since_1970; - std::vector vector_of_records; - // this contains all tags and times (even those with 'missing data') - std::vector vector_of_tags; + std::vector vector_of_records; + // this contains all tags and times (even those with 'missing data') + std::vector vector_of_tags; - void read_Peter_Bloomfield_mt_file(const std::string& mt_filename, std::istream& mt_stream, const char * const first_line); - void read_NDI_Toolviewer_mt_file(const std::string& mt_filename, std::istream& mt_stream, const char * const first_line); + void read_Peter_Bloomfield_mt_file(const std::string& mt_filename, std::istream& mt_stream, const char* const first_line); + void read_NDI_Toolviewer_mt_file(const std::string& mt_filename, std::istream& mt_stream, const char* const first_line); }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/RigidObject3DMotion.h b/src/include/stir_experimental/motion/RigidObject3DMotion.h index 328d83e1b5..bd5dd891d9 100644 --- a/src/include/stir_experimental/motion/RigidObject3DMotion.h +++ b/src/include/stir_experimental/motion/RigidObject3DMotion.h @@ -29,51 +29,42 @@ class AbsTimeInterval; \brief Base class for 3D rigid motion - This is really a class for encoding motion of an object in a scanner. So, there is + This is really a class for encoding motion of an object in a scanner. So, there is some stuff in here to go from tracker coordinates to scanner coordinates etc. Preliminary. Things that need to be worked out: - - time issues. Relative time is supposed to be relative to the scan start, but - this is really dependent on the derived class. It would be far - better to stick to secs_since_1970 in the class hierarchy, and use have a "set_reference_time" + - time issues. Relative time is supposed to be relative to the scan start, but + this is really dependent on the derived class. It would be far + better to stick to secs_since_1970 in the class hierarchy, and use have a "set_reference_time" member here or so. - - synchronisation: this is supposed to synchornise the tracker clock to a master clock. Again, that behaviour + - synchronisation: this is supposed to synchornise the tracker clock to a master clock. Again, that behaviour is completely dependent on what the derived class does. - + */ -class RigidObject3DMotion: public RegisteredObject -{ +class RigidObject3DMotion : public RegisteredObject { public: virtual ~RigidObject3DMotion() {} - //! get motion in tracker coordinates - virtual - RigidObject3DTransformation - get_motion_in_tracker_coords_rel_time(const double time) const =0; + //! get motion in tracker coordinates + virtual RigidObject3DTransformation get_motion_in_tracker_coords_rel_time(const double time) const = 0; //! get motion in scanner coordinates - virtual - RigidObject3DTransformation - get_motion_in_scanner_coords_rel_time(const double time) const; + virtual RigidObject3DTransformation get_motion_in_scanner_coords_rel_time(const double time) const; //! \name Average motion for a time interval //@{ - virtual - RigidObject3DTransformation - compute_average_motion_in_tracker_coords(const AbsTimeInterval&) const; + virtual RigidObject3DTransformation compute_average_motion_in_tracker_coords(const AbsTimeInterval&) const; - virtual - RigidObject3DTransformation - compute_average_motion_in_scanner_coords(const AbsTimeInterval&) const; + virtual RigidObject3DTransformation compute_average_motion_in_scanner_coords(const AbsTimeInterval&) const; - virtual RigidObject3DTransformation - compute_average_motion_in_tracker_coords_rel_time(const double start_time, const double end_time)const = 0; + virtual RigidObject3DTransformation compute_average_motion_in_tracker_coords_rel_time(const double start_time, + const double end_time) const = 0; - virtual RigidObject3DTransformation - compute_average_motion_in_scanner_coords_rel_time(const double start_time, const double end_time)const; + virtual RigidObject3DTransformation compute_average_motion_in_scanner_coords_rel_time(const double start_time, + const double end_time) const; //@} @@ -86,19 +77,16 @@ class RigidObject3DMotion: public RegisteredObject a lot of sense. So, it probably should be moved to a derived class \c SampledRigidObject3DMotion or so. */ - virtual std::vector - get_rel_time_of_samples(const double start_time, const double end_time)const = 0; + virtual std::vector get_rel_time_of_samples(const double start_time, const double end_time) const = 0; //! Has to be called and will be used to synchronise the target-system time and motion tracking time /*! In practice, this should make sure that a 'rel_time' of 0 corresponds to the start of the scan */ - virtual Succeeded synchronise() =0; - + virtual Succeeded synchronise() = 0; virtual double secs_since_1970_to_rel_time(std::time_t) const = 0; - - protected: +protected: #if 0 //! Option to set time offset manually in case synchronisation cannot be performed void @@ -108,21 +96,17 @@ class RigidObject3DMotion: public RegisteredObject #endif //! Temporary (?) function to allow base class to see if synchronised was called or not virtual bool is_synchronised() const = 0; - public: - virtual const RigidObject3DTransformation& - get_transformation_to_scanner_coords() const = 0; - virtual const RigidObject3DTransformation& - get_transformation_from_scanner_coords() const = 0; +public: + virtual const RigidObject3DTransformation& get_transformation_to_scanner_coords() const = 0; + virtual const RigidObject3DTransformation& get_transformation_from_scanner_coords() const = 0; - virtual void - set_transformation_from_scanner_coords(const RigidObject3DTransformation&) = 0; + virtual void set_transformation_from_scanner_coords(const RigidObject3DTransformation&) = 0; protected: virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/RigidObject3DMotionFromPolaris.h b/src/include/stir_experimental/motion/RigidObject3DMotionFromPolaris.h index 62506c8036..ac2246f434 100644 --- a/src/include/stir_experimental/motion/RigidObject3DMotionFromPolaris.h +++ b/src/include/stir_experimental/motion/RigidObject3DMotionFromPolaris.h @@ -47,36 +47,27 @@ START_NAMESPACE_STIR \todo move synchronisation out of this class */ -class RigidObject3DMotionFromPolaris: - public - RegisteredParsingObject< RigidObject3DMotionFromPolaris, - RigidObject3DMotion, - RigidObject3DMotion> - +class RigidObject3DMotionFromPolaris + : public RegisteredParsingObject + { public: - //! Name which will be used when parsing a MotionTracking object - static const char * const registered_name; + //! Name which will be used when parsing a MotionTracking object + static const char* const registered_name; //! Convert from Polaris transformation to STIR conventions /* see more info in .cxx file */ - static - RigidObject3DTransformation - make_transformation_from_polaris_data(Polaris_MT_File::Record const& record); - + static RigidObject3DTransformation make_transformation_from_polaris_data(Polaris_MT_File::Record const& record); // only need this to enable LmToProjDataWithMC(const char * const par_filename) function RigidObject3DMotionFromPolaris(); - virtual RigidObject3DTransformation - compute_average_motion_in_tracker_coords_rel_time(const double start_time, const double end_time) const; + virtual RigidObject3DTransformation compute_average_motion_in_tracker_coords_rel_time(const double start_time, + const double end_time) const; - virtual - RigidObject3DTransformation - get_motion_in_tracker_coords_rel_time(const double time) const; + virtual RigidObject3DTransformation get_motion_in_tracker_coords_rel_time(const double time) const; - virtual std::vector - get_rel_time_of_samples(const double start_time, const double end_time) const; + virtual std::vector get_rel_time_of_samples(const double start_time, const double end_time) const; //! set mask to be able to ignore one or more channels in the listmode gating data void set_mask_for_tags(const unsigned int mask_for_tags); @@ -85,12 +76,9 @@ class RigidObject3DMotionFromPolaris: virtual Succeeded synchronise(); virtual double secs_since_1970_to_rel_time(std::time_t) const; - virtual const RigidObject3DTransformation& - get_transformation_to_scanner_coords() const; - virtual const RigidObject3DTransformation& - get_transformation_from_scanner_coords() const; - virtual void - set_transformation_from_scanner_coords(const RigidObject3DTransformation&); + virtual const RigidObject3DTransformation& get_transformation_to_scanner_coords() const; + virtual const RigidObject3DTransformation& get_transformation_from_scanner_coords() const; + virtual void set_transformation_from_scanner_coords(const RigidObject3DTransformation&); Succeeded set_mt_file(const std::string& mt_filename); Succeeded set_list_mode_data_file(const std::string& lm_filename); @@ -100,38 +88,29 @@ class RigidObject3DMotionFromPolaris: //! Gets boundaries to determine when the time offset is out of bounds //*! Currently, the time offset is compared to the start of the listmode scan.*/ - double get_max_time_offset_deviation() const - { return max_time_offset_deviation; } + double get_max_time_offset_deviation() const { return max_time_offset_deviation; } //! Sets boundaries to determine when the time offset is out of bounds - void set_max_time_offset_deviation(const double v) - { max_time_offset_deviation = v; } + void set_max_time_offset_deviation(const double v) { max_time_offset_deviation = v; } //! Gets boundaries to determine when the time drift is too large /*! deviation is measured as fabs(time_drift-1) */ - double get_max_time_drift_deviation() const - { return max_time_drift_deviation; } + double get_max_time_drift_deviation() const { return max_time_drift_deviation; } //! Sets boundaries to determine when the time drift is too large - void set_max_time_drift_deviation(const double v) - { max_time_drift_deviation = v; } - -private: + void set_max_time_drift_deviation(const double v) { max_time_drift_deviation = v; } +private: void do_synchronisation(CListModeData& listmode_data); virtual bool is_synchronised() const; double rel_time_to_polaris_time(const double time) const; double polaris_time_to_rel_time(const double time) const; - RigidObject3DTransformation - compute_average_motion_polaris_time(const double start_time, const double end_time)const; - + RigidObject3DTransformation compute_average_motion_polaris_time(const double start_time, const double end_time) const; shared_ptr mt_file_ptr; - std::string mt_filename; + std::string mt_filename; std::string list_mode_filename; - - - private: +private: //! allow masking out certain bits of the tags in case a cable is not connected unsigned int _mask_for_tags; @@ -153,6 +132,5 @@ class RigidObject3DMotionFromPolaris: std::time_t listmode_data_start_time_in_secs; }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir_experimental/motion/RigidObject3DTransformation.h b/src/include/stir_experimental/motion/RigidObject3DTransformation.h index c3432a83b9..115a47750e 100644 --- a/src/include/stir_experimental/motion/RigidObject3DTransformation.h +++ b/src/include/stir_experimental/motion/RigidObject3DTransformation.h @@ -16,7 +16,6 @@ #ifndef __stir_motion_RigidObject3DTransformation_H__ #define __stir_motion_RigidObject3DTransformation_H__ - #include "stir_experimental/motion/ObjectTransformation.h" #include "stir/RegisteredParsingObject.h" #include "stir_experimental/Quaternion.h" @@ -35,11 +34,11 @@ class Succeeded; Supported transformations include rotations and translations. Rotations are encoded using quaternions. The convention used is described in
    - B.K. Horn, Closed-form solution of absolute orientation using + B.K. Horn, Closed-form solution of absolute orientation using unit quaternions, J. Opt. Soc. Am. A Vol.4 No. 6, (1987) p.629. - \warning STIR uses a left-handed coordinate-system. + \warning STIR uses a left-handed coordinate-system. The transformation that is applied is as follows \f[ r' = \mathrm{conj}(q)(r-t)q \f] @@ -62,16 +61,11 @@ class Succeeded; \warning The Euler angles are probably different from the ones used in the Shape3D hierarchy. \todo define Euler angles (the code is derived from the Polaris manual) */ -class RigidObject3DTransformation - : - public - RegisteredParsingObject, - ObjectTransformation<3,float> > -{ +class RigidObject3DTransformation : public RegisteredParsingObject, + ObjectTransformation<3, float>> { public: - static const char * const registered_name; - /*! + static const char* const registered_name; + /*! \brief Find the rigid transformation that gives the closest match between 2 sets of points. Minimises the Mean Square Error, i.e. the sum of @@ -80,7 +74,7 @@ class RigidObject3DTransformation \endcode The implementation uses Horn's algorithm. - + Horn's method needs to compute the maximum eigenvector of a matrix, which is done here using the Power method (see max_eigenvector_using_power_method()). @@ -90,35 +84,28 @@ class RigidObject3DTransformation choice would correspond to another eigenvector of the matrix (giving a very bad match). */ template - static - Succeeded - find_closest_transformation(RigidObject3DTransformation& result, - Iter1T start_orig_points, - Iter1T end_orig_points, - Iter2T start_transformed_points, - const Quaternion& initial_rotation = Quaternion(1.F,0.F,0.F,0.F)); + static Succeeded find_closest_transformation(RigidObject3DTransformation& result, Iter1T start_orig_points, + Iter1T end_orig_points, Iter2T start_transformed_points, + const Quaternion& initial_rotation = Quaternion(1.F, 0.F, 0.F, 0.F)); /*! \brief Compute Root Mean Square Error for 2 sets of points */ template - static double - RMSE(const RigidObject3DTransformation& transformation, - Iter1T start_orig_points, - Iter1T end_orig_points, - Iter2T start_transformed_points); + static double RMSE(const RigidObject3DTransformation& transformation, Iter1T start_orig_points, Iter1T end_orig_points, + Iter2T start_transformed_points); - RigidObject3DTransformation (); + RigidObject3DTransformation(); //! Constructor taking quaternion and translation info /*! \see RigidObject3DTransformation class documentation for conventions */ - RigidObject3DTransformation (const Quaternion& quat, const CartesianCoordinate3D& translation); - + RigidObject3DTransformation(const Quaternion& quat, const CartesianCoordinate3D& translation); + //! Compute the inverse transformation RigidObject3DTransformation inverse() const; //! Get quaternion Quaternion get_quaternion() const; - + //! Get translation CartesianCoordinate3D get_translation() const; @@ -130,25 +117,21 @@ class RigidObject3DTransformation Succeeded set_euler_angles(); #endif - //! Transform point + //! Transform point // can't return CartesianCoordinate3D anymore because virtual function - virtual - BasicCoordinate<3,float> - transform_point(const BasicCoordinate<3,float>& point) const; + virtual BasicCoordinate<3, float> transform_point(const BasicCoordinate<3, float>& point) const; //! Computes the jacobian for the transformation (which is always 1) - float jacobian(const BasicCoordinate<3,float>& point) const - { return 1; } + float jacobian(const BasicCoordinate<3, float>& point) const { return 1; } //! Transform bin from some projection data /*! Finds 'closest' (in some sense) bin to the transformed LOR. - if NEW_ROT is not #defined at compilation time, + if NEW_ROT is not #defined at compilation time, it will throw an exception when arc-corrected data is used.*/ - void transform_bin(Bin& bin,const ProjDataInfo& out_proj_data_info, - const ProjDataInfo& in_proj_data_info) const; + void transform_bin(Bin& bin, const ProjDataInfo& out_proj_data_info, const ProjDataInfo& in_proj_data_info) const; //! Get relative transformation (not implemented at present) - void get_relative_transformation(RigidObject3DTransformation& output, const RigidObject3DTransformation& reference); + void get_relative_transformation(RigidObject3DTransformation& output, const RigidObject3DTransformation& reference); #if 0 //! \name conversion to other conventions for rotations /*! \warning Currently disabled Code probably only works when FIRSTROT is defined. @@ -166,24 +149,20 @@ class RigidObject3DTransformation private: Quaternion quat; CartesianCoordinate3D translation; - friend RigidObject3DTransformation compose ( const RigidObject3DTransformation& apply_last, - const RigidObject3DTransformation& apply_first); + friend RigidObject3DTransformation compose(const RigidObject3DTransformation& apply_last, + const RigidObject3DTransformation& apply_first); }; //! Output to (text) stream /*! \ingroup motion Will be written as \verbatim { quaternion, translation } \endverbatim */ -std::ostream& -operator<<(std::ostream& out, - const RigidObject3DTransformation& rigid_object_transformation); +std::ostream& operator<<(std::ostream& out, const RigidObject3DTransformation& rigid_object_transformation); //! Input from (text) stream /*! \ingroup motion Should have format \verbatim { quaternion, translation } \endverbatim */ -std::istream& -operator>>(std::istream& , - RigidObject3DTransformation& rigid_object_transformation); +std::istream& operator>>(std::istream&, RigidObject3DTransformation& rigid_object_transformation); //! Composition of 2 transformations /*! \ingroup motion @@ -199,9 +178,8 @@ operator>>(std::istream& , \endcode */ -RigidObject3DTransformation -compose (const RigidObject3DTransformation& apply_last, - const RigidObject3DTransformation& apply_first); +RigidObject3DTransformation compose(const RigidObject3DTransformation& apply_last, + const RigidObject3DTransformation& apply_first); END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/TimeFrameMotion.h b/src/include/stir_experimental/motion/TimeFrameMotion.h index d233663db8..204a942098 100644 --- a/src/include/stir_experimental/motion/TimeFrameMotion.h +++ b/src/include/stir_experimental/motion/TimeFrameMotion.h @@ -23,7 +23,7 @@ #include "stir/ParsingObject.h" START_NAMESPACE_STIR -/***********************************************************/ +/***********************************************************/ /*! \ingroup motion \brief A class for encoding average motion in the frames. @@ -36,9 +36,9 @@ START_NAMESPACE_STIR ; see stir::TimeFrameDefinitions time frame_definition filename := frame_definition_filename - + ; next parameter is optional (and not normally necessary) - ; it can be used if the frame definitions are relative to another scan as what + ; it can be used if the frame definitions are relative to another scan as what ; is used to for the rigid object motion (i.e. currently the list mode data used ; for the Polaris synchronisation) ; scan_start_time_secs_since_1970_UTC @@ -57,9 +57,8 @@ START_NAMESPACE_STIR END := \endverbatim -*/ -class TimeFrameMotion : public ParsingObject -{ +*/ +class TimeFrameMotion : public ParsingObject { public: /* don't have this constructor, as it would need to be repeated by all derived classes anyway. @@ -74,40 +73,31 @@ class TimeFrameMotion : public ParsingObject int get_frame_num_to_process() const; //! get transformation from (or to) reference for current frame - /*! This is computed using + /*! This is computed using RigidObject3DTransformation::compute_average_motion_in_scanner_coords for the current frame. */ - const RigidObject3DTransformation& - get_current_rigid_object_transformation() const; + const RigidObject3DTransformation& get_current_rigid_object_transformation() const; //! Get the transformation to the reference as returned by the RigidObject3DMotion object - const RigidObject3DTransformation& - get_rigid_object_transformation_to_reference() const - { return _transformation_to_reference_position; } + const RigidObject3DTransformation& get_rigid_object_transformation_to_reference() const { + return _transformation_to_reference_position; + } - const TimeFrameDefinitions& - get_time_frame_defs() const; + const TimeFrameDefinitions& get_time_frame_defs() const; - double get_frame_start_time(unsigned frame_num) const - { return _frame_defs.get_start_time(frame_num) + _scan_start_time; } + double get_frame_start_time(unsigned frame_num) const { return _frame_defs.get_start_time(frame_num) + _scan_start_time; } - double get_frame_end_time(unsigned frame_num) const - { return _frame_defs.get_end_time(frame_num) + _scan_start_time; } - - const RigidObject3DMotion& get_motion() const - { return *_ro3d_sptr; } - -protected: + double get_frame_end_time(unsigned frame_num) const { return _frame_defs.get_end_time(frame_num) + _scan_start_time; } + const RigidObject3DMotion& get_motion() const { return *_ro3d_sptr; } - +protected: //! parsing functions virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - private: std::string _frame_definition_filename; bool _do_move_to_reference; @@ -116,13 +106,13 @@ class TimeFrameMotion : public ParsingObject shared_ptr _ro3d_sptr; shared_ptr _reference_abs_time_sptr; RigidObject3DTransformation _current_rigid_object_transformation; - + RigidObject3DTransformation _transformation_to_reference_position; int _scan_start_time_secs_since_1970_UTC; double _scan_start_time; - int _frame_num_to_process; + int _frame_num_to_process; }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/Transform3DObjectImageProcessor.h b/src/include/stir_experimental/motion/Transform3DObjectImageProcessor.h index 759b34936a..4a3d3c5f35 100644 --- a/src/include/stir_experimental/motion/Transform3DObjectImageProcessor.h +++ b/src/include/stir_experimental/motion/Transform3DObjectImageProcessor.h @@ -6,11 +6,11 @@ /*! \file - \ingroup ImageProcessor + \ingroup ImageProcessor \ingroup motion \brief Declaration of class stir::Transform3DObjectImageProcessor \author Kris Thielemans - + */ #ifndef __stir_motion_Transform3DObjectImageProcessor_H__ @@ -23,7 +23,6 @@ // next is currently needed to get Array> to compile (definition of assign() in there) #include "stir_experimental/motion/transform_3d_object.h" - START_NAMESPACE_STIR // TODO!! remove define @@ -31,29 +30,25 @@ START_NAMESPACE_STIR #define num_dimensions 3 /*! - \ingroup ImageProcessor + \ingroup ImageProcessor \brief A class in the ImageProcessor hierarchy that performs movement by reinterpolation - \warning This class is currently restricted to 3d. + \warning This class is currently restricted to 3d. */ template -class Transform3DObjectImageProcessor : - public - RegisteredParsingObject< - Transform3DObjectImageProcessor, - DataProcessor >, - DataProcessor > - > -{ - typedef DataProcessor > base_type; +class Transform3DObjectImageProcessor + : public RegisteredParsingObject, DataProcessor>, + DataProcessor>> { + typedef DataProcessor> base_type; + public: - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor - //Transform3DObjectImageProcessor(); + // Transform3DObjectImageProcessor(); //! Constructor that set the transformation - explicit - Transform3DObjectImageProcessor(const shared_ptr > = shared_ptr >()); + explicit Transform3DObjectImageProcessor( + const shared_ptr> = shared_ptr>()); bool get_do_transpose() const; void set_do_transpose(const bool); @@ -63,23 +58,23 @@ class Transform3DObjectImageProcessor : void set_do_cache(const bool); private: - //motion - shared_ptr > transformation_sptr; + // motion + shared_ptr> transformation_sptr; bool _do_transpose; - bool _do_jacobian; + bool _do_jacobian; bool _cache_transformed_coords; - Array<3, BasicCoordinate<3,elemT> > _transformed_coords; - Array<3, std::pair, elemT> > _transformed_coords_and_jacobian; + Array<3, BasicCoordinate<3, elemT>> _transformed_coords; + Array<3, std::pair, elemT>> _transformed_coords_and_jacobian; virtual void set_defaults(); virtual void initialise_keymap(); - virtual bool post_processing(); - - Succeeded virtual_set_up(const DiscretisedDensity& image); - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const; - void virtual_apply(DiscretisedDensity& density) const ; - + virtual bool post_processing(); + + Succeeded virtual_set_up(const DiscretisedDensity& image); + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const; + void virtual_apply(DiscretisedDensity& density) const; }; #undef num_dimensions @@ -87,5 +82,3 @@ class Transform3DObjectImageProcessor : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir_experimental/motion/bin_interpolate.h b/src/include/stir_experimental/motion/bin_interpolate.h index 3e7a894a01..30f99b3c67 100644 --- a/src/include/stir_experimental/motion/bin_interpolate.h +++ b/src/include/stir_experimental/motion/bin_interpolate.h @@ -25,13 +25,9 @@ START_NAMESPACE_STIR -static -Succeeded -get_transformed_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& out_lor, - const RigidObject3DTransformation& transformation, - const Bin& bin, - const ProjDataInfo& in_proj_data_info) -{ +static Succeeded +get_transformed_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& out_lor, const RigidObject3DTransformation& transformation, + const Bin& bin, const ProjDataInfo& in_proj_data_info) { LORInAxialAndNoArcCorrSinogramCoordinates lor; in_proj_data_info.get_LOR(lor, bin); LORAs2Points lor_as_points; @@ -39,40 +35,34 @@ get_transformed_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& out_lor, // TODO origin // currently, the origin used for proj_data_info is in the centre of the scanner, // while for standard images it is in the centre of the first ring. - // This is pretty horrible though, as the transform_point function has no clue + // This is pretty horrible though, as the transform_point function has no clue // where the origin is - // Note that the present shift will make this version compatible with the + // Note that the present shift will make this version compatible with the // version above, as find_bin_given_cartesian_coordinates_of_detection // also uses an origin in the centre of the first ring - const float z_shift = - (in_proj_data_info.get_scanner_ptr()->get_num_rings()-1)/2.F * - in_proj_data_info.get_scanner_ptr()->get_ring_spacing(); + const float z_shift = + (in_proj_data_info.get_scanner_ptr()->get_num_rings() - 1) / 2.F * in_proj_data_info.get_scanner_ptr()->get_ring_spacing(); lor_as_points.p1().z() += z_shift; lor_as_points.p2().z() += z_shift; - LORAs2Points - transformed_lor_as_points(transformation.transform_point(lor_as_points.p1()), - transformation.transform_point(lor_as_points.p2())); + LORAs2Points transformed_lor_as_points(transformation.transform_point(lor_as_points.p1()), + transformation.transform_point(lor_as_points.p2())); transformed_lor_as_points.p1().z() -= z_shift; transformed_lor_as_points.p2().z() -= z_shift; return transformed_lor_as_points.change_representation(out_lor, lor.radius()); } -static -Coordinate4D -lor_to_coords(const LORInAxialAndNoArcCorrSinogramCoordinates& lor) -{ +static Coordinate4D +lor_to_coords(const LORInAxialAndNoArcCorrSinogramCoordinates& lor) { Coordinate4D coord; - coord[1] = lor.z2()-lor.z1(); - coord[2] = (lor.z2()+lor.z1())/2; + coord[1] = lor.z2() - lor.z1(); + coord[2] = (lor.z2() + lor.z1()) / 2; coord[3] = lor.phi(); coord[4] = lor.beta(); return coord; } -static -Coordinate4D -bin_to_coords(const Bin& bin) -{ +static Coordinate4D +bin_to_coords(const Bin& bin) { Coordinate4D coord; coord[1] = bin.segment_num(); coord[2] = bin.axial_pos_num(); @@ -81,11 +71,8 @@ bin_to_coords(const Bin& bin) return coord; } - -static -Bin -coords_to_bin(const Coordinate4D& coord) -{ +static Bin +coords_to_bin(const Coordinate4D& coord) { Bin bin; bin.segment_num() = coord[1]; bin.axial_pos_num() = coord[2]; @@ -94,127 +81,102 @@ coords_to_bin(const Coordinate4D& coord) return bin; } -inline int sign(float x) -{ return x>=0 ? 1 : -1; } +inline int +sign(float x) { + return x >= 0 ? 1 : -1; +} -inline -Coordinate4D sign (const Coordinate4D& c) -{ - return Coordinate4D (sign(c[1]),sign(c[2]),sign(c[3]),sign(c[4])); +inline Coordinate4D +sign(const Coordinate4D& c) { + return Coordinate4D(sign(c[1]), sign(c[2]), sign(c[3]), sign(c[4])); } -inline -Coordinate4D abs (const Coordinate4D& c) -{ - return Coordinate4D (fabs(c[1]),fabs(c[2]),fabs(c[3]),fabs(c[4])); +inline Coordinate4D +abs(const Coordinate4D& c) { + return Coordinate4D(fabs(c[1]), fabs(c[2]), fabs(c[3]), fabs(c[4])); } -inline -void add_to_bin(VectorWithOffset > > & segments, - const Bin& bin, - const float value) -{ - (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += - value; +inline void +add_to_bin(VectorWithOffset>>& segments, const Bin& bin, const float value) { + (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += value; } -static -bool -is_in_range(const Bin& bin, const ProjDataInfo& proj_data_info) -{ - if (bin.segment_num()>= proj_data_info.get_min_segment_num() - && bin.segment_num()<= proj_data_info.get_max_segment_num() - && bin.tangential_pos_num()>= proj_data_info.get_min_tangential_pos_num() - && bin.tangential_pos_num()<= proj_data_info.get_max_tangential_pos_num() - && bin.axial_pos_num()>=proj_data_info.get_min_axial_pos_num(bin.segment_num()) - && bin.axial_pos_num()<=proj_data_info.get_max_axial_pos_num(bin.segment_num()) - ) - { - assert(bin.view_num()>=proj_data_info.get_min_view_num()); - assert(bin.view_num()<=proj_data_info.get_max_view_num()); - return true; - } - else +static bool +is_in_range(const Bin& bin, const ProjDataInfo& proj_data_info) { + if (bin.segment_num() >= proj_data_info.get_min_segment_num() && bin.segment_num() <= proj_data_info.get_max_segment_num() && + bin.tangential_pos_num() >= proj_data_info.get_min_tangential_pos_num() && + bin.tangential_pos_num() <= proj_data_info.get_max_tangential_pos_num() && + bin.axial_pos_num() >= proj_data_info.get_min_axial_pos_num(bin.segment_num()) && + bin.axial_pos_num() <= proj_data_info.get_max_axial_pos_num(bin.segment_num())) { + assert(bin.view_num() >= proj_data_info.get_min_view_num()); + assert(bin.view_num() <= proj_data_info.get_max_view_num()); + return true; + } else return false; } -static -Bin -standardise(const Bin& in_bin, const ProjDataInfo& proj_data_info) -{ +static Bin +standardise(const Bin& in_bin, const ProjDataInfo& proj_data_info) { Bin bin = in_bin; bool swap_direction = false; - if (bin.view_num()< proj_data_info.get_min_view_num()) - { - swap_direction = true; - bin.view_num()+=proj_data_info.get_num_views(); - } - else if (bin.view_num() > proj_data_info.get_max_view_num()) - { - swap_direction = true; - bin.view_num()-=proj_data_info.get_num_views(); - } - assert(bin.view_num()>=proj_data_info.get_min_view_num()); - assert(bin.view_num()<=proj_data_info.get_max_view_num()); - - if (swap_direction) - { + if (bin.view_num() < proj_data_info.get_min_view_num()) { + swap_direction = true; + bin.view_num() += proj_data_info.get_num_views(); + } else if (bin.view_num() > proj_data_info.get_max_view_num()) { + swap_direction = true; + bin.view_num() -= proj_data_info.get_num_views(); + } + assert(bin.view_num() >= proj_data_info.get_min_view_num()); + assert(bin.view_num() <= proj_data_info.get_max_view_num()); + + if (swap_direction) { bin.tangential_pos_num() *= -1; bin.segment_num() *= -1; - } + } return bin; } - -static -Succeeded -find_sampling(Coordinate4D& sampling, const Bin& bin, const ProjDataInfo& proj_data_info) -{ +static Succeeded +find_sampling(Coordinate4D& sampling, const Bin& bin, const ProjDataInfo& proj_data_info) { LORInAxialAndNoArcCorrSinogramCoordinates tmp_lor; LORInAxialAndNoArcCorrSinogramCoordinates lor; proj_data_info.get_LOR(lor, bin); - for (int d=1; d<=4; ++d) - { - Coordinate4D neighbour_coords = bin_to_coords(bin); - neighbour_coords[d]+=1; - const Bin neighbour = standardise(coords_to_bin(neighbour_coords), - proj_data_info); - if (!is_in_range(neighbour, proj_data_info)) - return Succeeded::no; - proj_data_info.get_LOR(tmp_lor, neighbour); - sampling[d] = (lor_to_coords(tmp_lor) - lor_to_coords(lor))[d]; - } + for (int d = 1; d <= 4; ++d) { + Coordinate4D neighbour_coords = bin_to_coords(bin); + neighbour_coords[d] += 1; + const Bin neighbour = standardise(coords_to_bin(neighbour_coords), proj_data_info); + if (!is_in_range(neighbour, proj_data_info)) + return Succeeded::no; + proj_data_info.get_LOR(tmp_lor, neighbour); + sampling[d] = (lor_to_coords(tmp_lor) - lor_to_coords(lor))[d]; + } return Succeeded::yes; } -static -void -bin_interpolate(VectorWithOffset > > & seg_ptr, - const LORInAxialAndNoArcCorrSinogramCoordinates& lor, - const ProjDataInfo& out_proj_data_info, - const ProjDataInfo& proj_data_info, - const float value) -{ +static void +bin_interpolate(VectorWithOffset>>& seg_ptr, + const LORInAxialAndNoArcCorrSinogramCoordinates& lor, const ProjDataInfo& out_proj_data_info, + const ProjDataInfo& proj_data_info, const float value) { Coordinate4D sampling; - //warning assuming uniform sampling to avoid problem of neighbour dropping of at the edge - if (find_sampling(sampling, Bin(0,0,0,0), proj_data_info)!= Succeeded::yes) + // warning assuming uniform sampling to avoid problem of neighbour dropping of at the edge + if (find_sampling(sampling, Bin(0, 0, 0, 0), proj_data_info) != Succeeded::yes) error("error in finding sampling"); const Bin central_bin = proj_data_info.get_bin(lor); - if (central_bin.get_bin_value()<0) + if (central_bin.get_bin_value() < 0) return; LORInAxialAndNoArcCorrSinogramCoordinates central_lor; proj_data_info.get_LOR(central_lor, central_bin); const Coordinate4D central_lor_coords = lor_to_coords(central_lor); const Coordinate4D lor_coords = lor_to_coords(lor); const Coordinate4D central_bin_coords = bin_to_coords(central_bin); - const Coordinate4D diff = (lor_coords - central_lor_coords)/ sampling; - assert(diff[1]<=1.001 && diff[1]>=-1.001); - assert(diff[2]<=.5001 && diff[2]>=-.5001); - assert(diff[3]<=.5001 && diff[3]>=-.5001); - assert(diff[4]<=.5001 && diff[4]>=-.5001); + const Coordinate4D diff = (lor_coords - central_lor_coords) / sampling; + assert(diff[1] <= 1.001 && diff[1] >= -1.001); + assert(diff[2] <= .5001 && diff[2] >= -.5001); + assert(diff[3] <= .5001 && diff[3] >= -.5001); + assert(diff[4] <= .5001 && diff[4] >= -.5001); const Coordinate4D bin_inc = sign(sampling); - assert(bin_inc == Coordinate4D(1,1,1,1)); + assert(bin_inc == Coordinate4D(1, 1, 1, 1)); const Coordinate4D inc = sign(diff); Coordinate4D offset; @@ -222,74 +184,67 @@ bin_interpolate(VectorWithOffset > > & seg_ptr, for (offset[1]=0; offset[1]!=2*inc[1]; offset[1]+=inc[1]) for (offset[2]=0; offset[2]!=2*inc[2]; offset[2]+=inc[2]) for (offset[3]=0; offset[3]!=2*inc[3]; offset[3]+=inc[3]) - for (offset[4]=0; offset[4]!=2*inc[4]; offset[4]+=inc[4]) + for (offset[4]=0; offset[4]!=2*inc[4]; offset[4]+=inc[4]) #else - for (offset[1]=-1; offset[1]!=2; offset[1]++) - for (offset[2]=-1; offset[2]!=2; offset[2]++) - for (offset[3]=-1; offset[3]!=2; offset[3]++) - for (offset[4]=-1; offset[4]!=2; offset[4]++) + for (offset[1] = -1; offset[1] != 2; offset[1]++) + for (offset[2] = -1; offset[2] != 2; offset[2]++) + for (offset[3] = -1; offset[3] != 2; offset[3]++) + for (offset[4] = -1; offset[4] != 2; offset[4]++) #endif - { - const Bin target_bin = - standardise(coords_to_bin(central_bin_coords + offset), proj_data_info); - if (is_in_range(target_bin, proj_data_info)) - { - - //const BasicCoordinate<4,float> float_offset(offset); - //Coordinate4D weights = abs(diff - float_offset); - + { + const Bin target_bin = standardise(coords_to_bin(central_bin_coords + offset), proj_data_info); + if (is_in_range(target_bin, proj_data_info)) { + + // const BasicCoordinate<4,float> float_offset(offset); + // Coordinate4D weights = abs(diff - float_offset); + + LORInAxialAndNoArcCorrSinogramCoordinates new_lor; + proj_data_info.get_LOR(new_lor, target_bin); + Coordinate4D new_lor_coords = lor_to_coords(new_lor); + Coordinate4D new_diff = (lor_coords - new_lor_coords) / sampling; + if (fabs(new_diff[3]) > 2) { + new_lor_coords[1] *= -1; + new_lor_coords[3] += _PI * sign(new_diff[3]); + new_lor_coords[4] *= -1; + new_diff = (lor_coords - new_lor_coords) / sampling; + } - LORInAxialAndNoArcCorrSinogramCoordinates new_lor; - proj_data_info.get_LOR(new_lor, target_bin); - Coordinate4D new_lor_coords = lor_to_coords(new_lor); - Coordinate4D new_diff = (lor_coords - new_lor_coords)/ sampling; - if (fabs(new_diff[3])>2) - { - new_lor_coords[1] *= -1; - new_lor_coords[3] += _PI*sign(new_diff[3]); - new_lor_coords[4]*=-1; - new_diff = (lor_coords - new_lor_coords)/ sampling; - } - #if 0 assert(new_diff[1]<=1.001 && new_diff[1]>=-1.001); assert(new_diff[2]<=1.101 && new_diff[2]>=-1.101); assert(new_diff[3]<=1.001 && new_diff[3]>=-1.001); assert(new_diff[4]<=1.001 && new_diff[4]>=-1.001); #endif - // assert(norm(new_diff - (diff - float_offset))<.001); - Coordinate4D weights = abs(new_diff); - if (weights[4]>1 || weights[3]>1 || weights[2]>1 || weights[1]>1) - continue; - const float weight = (1-weights[1])*(1-weights[2])*(1-weights[3])*(1-weights[4]); - if (weight<0.001) - continue; + // assert(norm(new_diff - (diff - float_offset))<.001); + Coordinate4D weights = abs(new_diff); + if (weights[4] > 1 || weights[3] > 1 || weights[2] > 1 || weights[1] > 1) + continue; + const float weight = (1 - weights[1]) * (1 - weights[2]) * (1 - weights[3]) * (1 - weights[4]); + if (weight < 0.001) + continue; #if 0 const Bin out_bin = target_bin; #else -#if 0 +# if 0 const Bin out_bin = out_proj_data_info.get_bin(new_lor); if (out_bin.get_bin_value()<0) continue; -#else - DetectionPositionPair<> detection_positions; - dynamic_cast - (proj_data_info). - get_det_pos_pair_for_bin(detection_positions, target_bin); - Bin out_bin; - if (dynamic_cast - (out_proj_data_info). - get_bin_for_det_pos_pair(out_bin, detection_positions) == Succeeded::no) - continue; - if (!is_in_range(out_bin, out_proj_data_info)) - continue; -#endif +# else + DetectionPositionPair<> detection_positions; + dynamic_cast(proj_data_info) + .get_det_pos_pair_for_bin(detection_positions, target_bin); + Bin out_bin; + if (dynamic_cast(out_proj_data_info) + .get_bin_for_det_pos_pair(out_bin, detection_positions) == Succeeded::no) + continue; + if (!is_in_range(out_bin, out_proj_data_info)) + continue; +# endif #endif - add_to_bin(seg_ptr, out_bin, value*weight); - } - - } + add_to_bin(seg_ptr, out_bin, value * weight); + } + } } END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/transform_3d_object.h b/src/include/stir_experimental/motion/transform_3d_object.h index ddf2ad78b8..2328b1ddc9 100644 --- a/src/include/stir_experimental/motion/transform_3d_object.h +++ b/src/include/stir_experimental/motion/transform_3d_object.h @@ -10,7 +10,7 @@ \file \ingroup motion - \brief Declaration of functions to re-interpolate an image or projection data + \brief Declaration of functions to re-interpolate an image or projection data to a new coordinate system. \author Kris Thielemans @@ -29,14 +29,13 @@ START_NAMESPACE_STIR class RigidObject3DTransformation; template - class ObjectTransformation; +class ObjectTransformation; -template - class DiscretisedDensity; +template +class DiscretisedDensity; class ProjData; class Succeeded; - //! transform image data /*! \ingroup motion \brief the interpolator has to push values from the input into the output image @@ -48,13 +47,10 @@ class Succeeded; This function is inline to avoid template instantiation problems. */ template -inline -Succeeded -transform_3d_object_push_interpolation(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const ObjectTransformationT& transformation_in_to_out, - const PushInterpolatorT& interpolator, - const bool do_jacobian); +inline Succeeded transform_3d_object_push_interpolation(DiscretisedDensity<3, float>& out_density, + const DiscretisedDensity<3, float>& in_density, + const ObjectTransformationT& transformation_in_to_out, + const PushInterpolatorT& interpolator, const bool do_jacobian); //! transform image data /*! \ingroup motion @@ -67,13 +63,10 @@ transform_3d_object_push_interpolation(DiscretisedDensity<3,float>& out_density, This function is inline to avoid template instantiation problems. */ template -inline -Succeeded -transform_3d_object_pull_interpolation(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const ObjectTransformationT& transformation_out_to_in, - const PullInterpolatorT& interpolator, - const bool do_jacobian); +inline Succeeded transform_3d_object_pull_interpolation(DiscretisedDensity<3, float>& out_density, + const DiscretisedDensity<3, float>& in_density, + const ObjectTransformationT& transformation_out_to_in, + const PullInterpolatorT& interpolator, const bool do_jacobian); //! transform image data /*! \ingroup motion @@ -82,69 +75,59 @@ transform_3d_object_pull_interpolation(DiscretisedDensity<3,float>& out_density, \todo cannot use ObjectTransformation yet as it needs the inverse transformation */ -Succeeded -transform_3d_object(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const RigidObject3DTransformation& transformation_in_to_out); - // const ObjectTransformation<3,float>& transformation_in_to_out); - +Succeeded transform_3d_object(DiscretisedDensity<3, float>& out_density, const DiscretisedDensity<3, float>& in_density, + const RigidObject3DTransformation& transformation_in_to_out); +// const ObjectTransformation<3,float>& transformation_in_to_out); // ugly functions for storing transformed points. // TODO clean up at some point -Array<3, BasicCoordinate<3,float> > -find_grid_coords_of_transformed_centres(const DiscretisedDensity<3,float>& source_density, - const DiscretisedDensity<3,float>& target_density, - const ObjectTransformation<3,float>& transformation_source_to_target); +Array<3, BasicCoordinate<3, float>> +find_grid_coords_of_transformed_centres(const DiscretisedDensity<3, float>& source_density, + const DiscretisedDensity<3, float>& target_density, + const ObjectTransformation<3, float>& transformation_source_to_target); // TODO need this for now to get Array> to work template - inline - void assign(std::pair, float>& x, T2 y) -{ - BasicCoordinate<3,float> tmp; - assign(tmp,y); - x = std::make_pair(tmp,float(y)); +inline void +assign(std::pair, float>& x, T2 y) { + BasicCoordinate<3, float> tmp; + assign(tmp, y); + x = std::make_pair(tmp, float(y)); } -Array<3, std::pair, float> > -find_grid_coords_of_transformed_centres_and_jacobian(const DiscretisedDensity<3,float>& source_density, - const DiscretisedDensity<3,float>& target_density, - const ObjectTransformation<3,float>& transformation_source_to_target); +Array<3, std::pair, float>> +find_grid_coords_of_transformed_centres_and_jacobian(const DiscretisedDensity<3, float>& source_density, + const DiscretisedDensity<3, float>& target_density, + const ObjectTransformation<3, float>& transformation_source_to_target); //! transform projection data /*! \ingroup motion Currently only supports non-arccorrected data. - + Uses all available input segments */ -Succeeded -transform_3d_object(ProjData& out_proj_data, - const ProjData& in_proj_data, - const RigidObject3DTransformation& object_transformation); +Succeeded transform_3d_object(ProjData& out_proj_data, const ProjData& in_proj_data, + const RigidObject3DTransformation& object_transformation); //! transform image data using transposed matrix /*! \ingroup motion - Implements the transpose (not the inverse) of + Implements the transpose (not the inverse) of transform_3d_object(DiscretisedDensity<3,float>&, const DiscretisedDensity<3,float>&,const RigidObject3DTransformation&) \todo cannot use ObjectTransformation yet as it needs the inverse transformation */ -Succeeded -transpose_of_transform_3d_object(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const RigidObject3DTransformation& transformation_in_to_out); +Succeeded transpose_of_transform_3d_object(DiscretisedDensity<3, float>& out_density, + const DiscretisedDensity<3, float>& in_density, + const RigidObject3DTransformation& transformation_in_to_out); // const ObjectTransformation<3,float>& transformation_in_to_out); //! transform projection data /*! \ingroup motion Currently only supports non-arccorrected data. */ -Succeeded -transform_3d_object(ProjData& out_proj_data, - const ProjData& in_proj_data, - const RigidObject3DTransformation& rigid_object_transformation, - const int min_in_segment_num_to_process, - const int max_in_segment_num_to_process); +Succeeded transform_3d_object(ProjData& out_proj_data, const ProjData& in_proj_data, + const RigidObject3DTransformation& rigid_object_transformation, + const int min_in_segment_num_to_process, const int max_in_segment_num_to_process); END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/transform_3d_object.inl b/src/include/stir_experimental/motion/transform_3d_object.inl index ddc0848bc6..ff66968329 100644 --- a/src/include/stir_experimental/motion/transform_3d_object.inl +++ b/src/include/stir_experimental/motion/transform_3d_object.inl @@ -7,7 +7,7 @@ /*! \file \ingroup motion - \brief Functions to re-interpolate an image + \brief Functions to re-interpolate an image \author Kris Thielemans @@ -19,80 +19,57 @@ START_NAMESPACE_STIR template -Succeeded -transform_3d_object_push_interpolation(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const ObjectTransformationT& transformation_in_to_out, - const PushInterpolatorT& interpolator, - const bool do_jacobian) -{ +Succeeded +transform_3d_object_push_interpolation(DiscretisedDensity<3, float>& out_density, const DiscretisedDensity<3, float>& in_density, + const ObjectTransformationT& transformation_in_to_out, + const PushInterpolatorT& interpolator, const bool do_jacobian) { - const VoxelsOnCartesianGrid& in_image = - dynamic_cast const&>(in_density); - VoxelsOnCartesianGrid& out_image = - dynamic_cast&>(out_density); + const VoxelsOnCartesianGrid& in_image = dynamic_cast const&>(in_density); + VoxelsOnCartesianGrid& out_image = dynamic_cast&>(out_density); interpolator.set_output(out_image); - for (int z= in_image.get_min_index(); z<= in_image.get_max_index(); ++z) - for (int y= in_image[z].get_min_index(); y<= in_image[z].get_max_index(); ++y) - for (int x= in_image[z][y].get_min_index(); x<= in_image[z][y].get_max_index(); ++x) - { + for (int z = in_image.get_min_index(); z <= in_image.get_max_index(); ++z) + for (int y = in_image[z].get_min_index(); y <= in_image[z].get_max_index(); ++y) + for (int x = in_image[z][y].get_min_index(); x <= in_image[z][y].get_max_index(); ++x) { const CartesianCoordinate3D current_point = - CartesianCoordinate3D(z,y,x) * in_image.get_voxel_size() + - in_image.get_origin(); - const CartesianCoordinate3D new_point = - transformation_in_to_out.transform_point(current_point); + CartesianCoordinate3D(z, y, x) * in_image.get_voxel_size() + in_image.get_origin(); + const CartesianCoordinate3D new_point = transformation_in_to_out.transform_point(current_point); const CartesianCoordinate3D new_point_in_image_coords = - (new_point - out_image.get_origin()) / out_image.get_voxel_size(); - const float jacobian = - do_jacobian - ? transformation_in_to_out.jacobian(current_point) - : 1; - interpolator.add_to(new_point_in_image_coords, in_image[z][y][x]*jacobian); + (new_point - out_image.get_origin()) / out_image.get_voxel_size(); + const float jacobian = do_jacobian ? transformation_in_to_out.jacobian(current_point) : 1; + interpolator.add_to(new_point_in_image_coords, in_image[z][y][x] * jacobian); } return Succeeded::yes; } template -Succeeded -transform_3d_object_pull_interpolation(DiscretisedDensity<3,float>& out_density, - const DiscretisedDensity<3,float>& in_density, - const ObjectTransformationT& transformation_out_to_in, - const PullInterpolatorT& interpolator, - const bool do_jacobian) -{ +Succeeded +transform_3d_object_pull_interpolation(DiscretisedDensity<3, float>& out_density, const DiscretisedDensity<3, float>& in_density, + const ObjectTransformationT& transformation_out_to_in, + const PullInterpolatorT& interpolator, const bool do_jacobian) { - const VoxelsOnCartesianGrid& in_image = - dynamic_cast const&>(in_density); - VoxelsOnCartesianGrid& out_image = - dynamic_cast&>(out_density); + const VoxelsOnCartesianGrid& in_image = dynamic_cast const&>(in_density); + VoxelsOnCartesianGrid& out_image = dynamic_cast&>(out_density); interpolator.set_input(in_density); - for (int z= out_image.get_min_index(); z<= out_image.get_max_index(); ++z) - for (int y= out_image[z].get_min_index(); y<= out_image[z].get_max_index(); ++y) - for (int x= out_image[z][y].get_min_index(); x<= out_image[z][y].get_max_index(); ++x) - { + for (int z = out_image.get_min_index(); z <= out_image.get_max_index(); ++z) + for (int y = out_image[z].get_min_index(); y <= out_image[z].get_max_index(); ++y) + for (int x = out_image[z][y].get_min_index(); x <= out_image[z][y].get_max_index(); ++x) { const CartesianCoordinate3D current_point = - CartesianCoordinate3D(static_cast(z), - static_cast(y), - static_cast(x)) * - out_image.get_voxel_size() + - out_image.get_origin(); - const CartesianCoordinate3D new_point = - transformation_out_to_in.transform_point(current_point); + CartesianCoordinate3D(static_cast(z), static_cast(y), static_cast(x)) * + out_image.get_voxel_size() + + out_image.get_origin(); + const CartesianCoordinate3D new_point = transformation_out_to_in.transform_point(current_point); const CartesianCoordinate3D new_point_in_image_coords = - (new_point - in_image.get_origin()) / in_image.get_voxel_size(); - out_image[z][y][x] = - interpolator(new_point_in_image_coords); - if (do_jacobian) - out_image[z][y][x] *= transformation_out_to_in.jacobian(current_point); - + (new_point - in_image.get_origin()) / in_image.get_voxel_size(); + out_image[z][y][x] = interpolator(new_point_in_image_coords); + if (do_jacobian) + out_image[z][y][x] *= transformation_out_to_in.jacobian(current_point); } return Succeeded::yes; } - END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/multiply_plane_scale_factorsImageProcessor.h b/src/include/stir_experimental/multiply_plane_scale_factorsImageProcessor.h index fbe5c26a2a..91cf70152b 100644 --- a/src/include/stir_experimental/multiply_plane_scale_factorsImageProcessor.h +++ b/src/include/stir_experimental/multiply_plane_scale_factorsImageProcessor.h @@ -3,11 +3,11 @@ /*! \file - \ingroup ImageProcessor + \ingroup ImageProcessor \brief Declaration of class multiply_plane_scale_factorsImageProcessor - + \author Kris Thielemans - + */ /* Copyright (C) 2003- 2007, Hammersmith Imanet @@ -17,7 +17,6 @@ #ifndef __stir_multiply_plane_scale_factorsImageProcessor_H__ #define __stir_multiply_plane_scale_factorsImageProcessor_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" @@ -25,51 +24,40 @@ START_NAMESPACE_STIR -template class VectorWithOffset; +template +class VectorWithOffset; /*! \brief Simply multiplies each plane in an image with a scale factor. */ template -class multiply_plane_scale_factorsImageProcessor : - public - RegisteredParsingObject< - multiply_plane_scale_factorsImageProcessor, - DataProcessor >, - DataProcessor > - > -{ +class multiply_plane_scale_factorsImageProcessor + : public RegisteredParsingObject, + DataProcessor>, DataProcessor>> { private: - typedef - RegisteredParsingObject< - multiply_plane_scale_factorsImageProcessor, - DataProcessor >, - DataProcessor > - > - base_type; + typedef RegisteredParsingObject, DataProcessor>, + DataProcessor>> + base_type; + public: - static const char * const registered_name; + static const char* const registered_name; multiply_plane_scale_factorsImageProcessor(); - multiply_plane_scale_factorsImageProcessor(const VectorWithOffset& plane_scale_factors); - multiply_plane_scale_factorsImageProcessor(const std::vector& plane_scale_factors); - - + multiply_plane_scale_factorsImageProcessor(const VectorWithOffset& plane_scale_factors); + multiply_plane_scale_factorsImageProcessor(const std::vector& plane_scale_factors); + private: - std::vector plane_scale_factors; + std::vector plane_scale_factors; virtual void set_defaults(); virtual void initialise_keymap(); - - Succeeded virtual_set_up(const DiscretisedDensity<3,elemT>& image); - void virtual_apply(DiscretisedDensity<3,elemT>& out_density, const DiscretisedDensity<3,elemT>& in_density) const; - void virtual_apply(DiscretisedDensity<3,elemT>& density) const ; - + Succeeded virtual_set_up(const DiscretisedDensity<3, elemT>& image); + + void virtual_apply(DiscretisedDensity<3, elemT>& out_density, const DiscretisedDensity<3, elemT>& in_density) const; + void virtual_apply(DiscretisedDensity<3, elemT>& density) const; }; END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir_experimental/numerics/linear_extrapolation.h b/src/include/stir_experimental/numerics/linear_extrapolation.h index 17b1ddcead..78bfa118d8 100644 --- a/src/include/stir_experimental/numerics/linear_extrapolation.h +++ b/src/include/stir_experimental/numerics/linear_extrapolation.h @@ -17,7 +17,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics \brief stir::linear_extrapolation @@ -25,17 +25,14 @@ */ - #include "stir/common.h" START_NAMESPACE_STIR - - template - inline void - linear_extrapolation(std::vector &input_vector) - { - input_vector.push_back(*(input_vector.end()-1)*2 - *(input_vector.end()-2)); - input_vector.insert(input_vector.begin(), *input_vector.begin()*2 - *(input_vector.begin()+1)); - } +template +inline void +linear_extrapolation(std::vector& input_vector) { + input_vector.push_back(*(input_vector.end() - 1) * 2 - *(input_vector.end() - 2)); + input_vector.insert(input_vector.begin(), *input_vector.begin() * 2 - *(input_vector.begin() + 1)); +} END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/numerics/more_interpolators.h b/src/include/stir_experimental/numerics/more_interpolators.h index 9be43b2001..30e2801ef2 100644 --- a/src/include/stir_experimental/numerics/more_interpolators.h +++ b/src/include/stir_experimental/numerics/more_interpolators.h @@ -19,7 +19,6 @@ #include "stir/BasicCoordinate.h" #include "stir/Array.h" - START_NAMESPACE_STIR /*! \ingroup numerics @@ -28,9 +27,7 @@ START_NAMESPACE_STIR Adds \a value to the grid point nearest to \a point_in_output_coords */ template -elemT -pull_nearest_neighbour_interpolate(const Array<3, elemT>& in, - const BasicCoordinate<3, positionT>& point_in_input_coords); +elemT pull_nearest_neighbour_interpolate(const Array<3, elemT>& in, const BasicCoordinate<3, positionT>& point_in_input_coords); /*! \ingroup numerics \brief Push \a value into the output array using nearest neigbour interpolation. @@ -38,28 +35,21 @@ pull_nearest_neighbour_interpolate(const Array<3, elemT>& in, Adds \a value to the grid point nearest to \a point_in_output_coords */ template -void -push_nearest_neighbour_interpolate(Array& out, - const BasicCoordinate& point_in_output_coords, - valueT value); - +void push_nearest_neighbour_interpolate(Array& out, + const BasicCoordinate& point_in_output_coords, valueT value); /*! \ingroup numerics \brief Returns an interpolated value according to \a point_in_input_coords. */ template -elemT -pull_linear_interpolate(const Array<3, elemT>& in, - const BasicCoordinate<3, positionT>& point_in_input_coords); +elemT pull_linear_interpolate(const Array<3, elemT>& in, const BasicCoordinate<3, positionT>& point_in_input_coords); /*! \ingroup numerics \brief Push \a value into the output array using the transpose of linear interpolation. */ template -void -push_transpose_linear_interpolate(Array<3, elemT>& out, - const BasicCoordinate<3, positionT>& point_in_output_coords, - valueT value); +void push_transpose_linear_interpolate(Array<3, elemT>& out, const BasicCoordinate<3, positionT>& point_in_output_coords, + valueT value); /*! \ingroup numerics \brief A function object to pull interpolated values from the input array into the grid points of the output array. @@ -67,68 +57,48 @@ push_transpose_linear_interpolate(Array<3, elemT>& out, \todo preliminary. We might want to derive this from a class or so. */ template -class -PullLinearInterpolator -{ +class PullLinearInterpolator { public: - PullLinearInterpolator() - : _input_ptr(0) - {} + PullLinearInterpolator() : _input_ptr(0) {} - void set_input(const Array<3, elemT>& input) const - { - this->_input_ptr = &input; - } + void set_input(const Array<3, elemT>& input) const { this->_input_ptr = &input; } template - elemT operator()(const BasicCoordinate<3, positionT>& point_in_input_coords) const - { - return - pull_linear_interpolate(*(this->_input_ptr), - point_in_input_coords); + elemT operator()(const BasicCoordinate<3, positionT>& point_in_input_coords) const { + return pull_linear_interpolate(*(this->_input_ptr), point_in_input_coords); } + private: // todo terribly dangerous // we have it such that we can have a default constructor without any arguments // this means we cannot use a reference // we could use a shared_ptr, but then we can only interpolate data for which we have a shared_ptr - mutable const Array<3, elemT> * _input_ptr; + mutable const Array<3, elemT>* _input_ptr; }; - - /*! \ingroup numerics - \brief A function object to push values at the grid of the input array into the output array + \brief A function object to push values at the grid of the input array into the output array \todo preliminary. We might want to derive this from a class or so. */ template -class -PushTransposeLinearInterpolator -{ +class PushTransposeLinearInterpolator { public: - PushTransposeLinearInterpolator() - :_output_ptr(0) - {} + PushTransposeLinearInterpolator() : _output_ptr(0) {} - void set_output(Array<3, elemT>& output) const - { - this->_output_ptr = &output; - } + void set_output(Array<3, elemT>& output) const { this->_output_ptr = &output; } template - void add_to(const BasicCoordinate<3, positionT>& point_in_output_coords, const valueT value) const - { - push_transpose_linear_interpolate(*(this->_output_ptr), - point_in_output_coords, - value); + void add_to(const BasicCoordinate<3, positionT>& point_in_output_coords, const valueT value) const { + push_transpose_linear_interpolate(*(this->_output_ptr), point_in_output_coords, value); } + private: // todo terribly dangerous // we have it such that we can have a default constructor without any arguments // this means we cannot use a reference // we could use a shared_ptr, but then we can only interpolate data for which we have a shared_ptr - mutable Array<3, elemT> * _output_ptr; + mutable Array<3, elemT>* _output_ptr; }; /*! \ingroup numerics @@ -137,68 +107,48 @@ PushTransposeLinearInterpolator \todo preliminary. We might want to derive this from a class or so. */ template -class -PullNearestNeighbourInterpolator -{ +class PullNearestNeighbourInterpolator { public: - PullNearestNeighbourInterpolator() - : _input_ptr(0) - {} + PullNearestNeighbourInterpolator() : _input_ptr(0) {} - void set_input(const Array<3, elemT>& input) const - { - this->_input_ptr = &input; - } + void set_input(const Array<3, elemT>& input) const { this->_input_ptr = &input; } template - elemT operator()(const BasicCoordinate<3, positionT>& point_in_input_coords) const - { - return - pull_nearest_neighbour_interpolate(*(this->_input_ptr), - point_in_input_coords); + elemT operator()(const BasicCoordinate<3, positionT>& point_in_input_coords) const { + return pull_nearest_neighbour_interpolate(*(this->_input_ptr), point_in_input_coords); } + private: // todo terribly dangerous // we have it such that we can have a default constructor without any arguments // this means we cannot use a reference // we could use a shared_ptr, but then we can only interpolate data for which we have a shared_ptr - mutable const Array<3, elemT> * _input_ptr; + mutable const Array<3, elemT>* _input_ptr; }; - - /*! \ingroup numerics - \brief A function object to push values at the grid of the input array into the output array + \brief A function object to push values at the grid of the input array into the output array \todo preliminary. We might want to derive this from a class or so. */ template -class -PushNearestNeighbourInterpolator -{ +class PushNearestNeighbourInterpolator { public: - PushNearestNeighbourInterpolator() - :_output_ptr(0) - {} + PushNearestNeighbourInterpolator() : _output_ptr(0) {} - void set_output(Array<3, elemT>& output) const - { - this->_output_ptr = &output; - } + void set_output(Array<3, elemT>& output) const { this->_output_ptr = &output; } template - void add_to(const BasicCoordinate<3, positionT>& point_in_output_coords, const valueT value) const - { - push_nearest_neighbour_interpolate(*(this->_output_ptr), - point_in_output_coords, - value); + void add_to(const BasicCoordinate<3, positionT>& point_in_output_coords, const valueT value) const { + push_nearest_neighbour_interpolate(*(this->_output_ptr), point_in_output_coords, value); } + private: // todo terribly dangerous // we have it such that we can have a default constructor without any arguments // this means we cannot use a reference // we could use a shared_ptr, but then we can only interpolate data for which we have a shared_ptr - mutable Array<3, elemT> * _output_ptr; + mutable Array<3, elemT>* _output_ptr; }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/numerics/more_interpolators.inl b/src/include/stir_experimental/numerics/more_interpolators.inl index c04de3c1d6..a9c959586a 100644 --- a/src/include/stir_experimental/numerics/more_interpolators.inl +++ b/src/include/stir_experimental/numerics/more_interpolators.inl @@ -17,145 +17,108 @@ #include "stir/round.h" #include - START_NAMESPACE_STIR template elemT -pull_nearest_neighbour_interpolate(const Array<3, elemT>& in, - const BasicCoordinate<3, positionT>& point_in_input_coords) -{ - // find nearest neighbour - const Coordinate3D - nearest_neighbour = round(point_in_input_coords); +pull_nearest_neighbour_interpolate(const Array<3, elemT>& in, const BasicCoordinate<3, positionT>& point_in_input_coords) { + // find nearest neighbour + const Coordinate3D nearest_neighbour = round(point_in_input_coords); - if (nearest_neighbour[1] <= in.get_max_index() && - nearest_neighbour[1] >= in.get_min_index() && + if (nearest_neighbour[1] <= in.get_max_index() && nearest_neighbour[1] >= in.get_min_index() && nearest_neighbour[2] <= in[nearest_neighbour[1]].get_max_index() && nearest_neighbour[2] >= in[nearest_neighbour[1]].get_min_index() && nearest_neighbour[3] <= in[nearest_neighbour[1]][nearest_neighbour[2]].get_max_index() && - nearest_neighbour[3] >= in[nearest_neighbour[1]][nearest_neighbour[2]].get_min_index()) - { - return in[nearest_neighbour]; - } - else + nearest_neighbour[3] >= in[nearest_neighbour[1]][nearest_neighbour[2]].get_min_index()) { + return in[nearest_neighbour]; + } else return 0; } template void -push_nearest_neighbour_interpolate(Array& out, - const BasicCoordinate& point_in_output_coords, - valueT value) -{ - if (value==0) - return; - const BasicCoordinate nearest_neighbour = - round(point_in_output_coords); - - if (nearest_neighbour[1] <= out.get_max_index() && - nearest_neighbour[1] >= out.get_min_index() && +push_nearest_neighbour_interpolate(Array& out, + const BasicCoordinate& point_in_output_coords, valueT value) { + if (value == 0) + return; + const BasicCoordinate nearest_neighbour = round(point_in_output_coords); + + if (nearest_neighbour[1] <= out.get_max_index() && nearest_neighbour[1] >= out.get_min_index() && nearest_neighbour[2] <= out[nearest_neighbour[1]].get_max_index() && nearest_neighbour[2] >= out[nearest_neighbour[1]].get_min_index() && nearest_neighbour[3] <= out[nearest_neighbour[1]][nearest_neighbour[2]].get_max_index() && nearest_neighbour[3] >= out[nearest_neighbour[1]][nearest_neighbour[2]].get_min_index()) - out[nearest_neighbour] += - static_cast(value); + out[nearest_neighbour] += static_cast(value); } - - template elemT -pull_linear_interpolate(const Array<3, elemT>& in, - const BasicCoordinate<3, positionT>& point_in_input_coords) -{ - // find left neighbour - const Coordinate3D - left_neighbour(round(std::floor(point_in_input_coords[1])), - round(std::floor(point_in_input_coords[2])), - round(std::floor(point_in_input_coords[3]))); +pull_linear_interpolate(const Array<3, elemT>& in, const BasicCoordinate<3, positionT>& point_in_input_coords) { + // find left neighbour + const Coordinate3D left_neighbour(round(std::floor(point_in_input_coords[1])), round(std::floor(point_in_input_coords[2])), + round(std::floor(point_in_input_coords[3]))); // TODO handle boundary conditions - if (left_neighbour[1] < in.get_max_index() && - left_neighbour[1] >= in.get_min_index() && - left_neighbour[2] < in[left_neighbour[1]].get_max_index() && - left_neighbour[2] >= in[left_neighbour[1]].get_min_index() && + if (left_neighbour[1] < in.get_max_index() && left_neighbour[1] >= in.get_min_index() && + left_neighbour[2] < in[left_neighbour[1]].get_max_index() && left_neighbour[2] >= in[left_neighbour[1]].get_min_index() && left_neighbour[3] < in[left_neighbour[1]][left_neighbour[2]].get_max_index() && - left_neighbour[3] >= in[left_neighbour[1]][left_neighbour[2]].get_min_index()) - { - const int x1=left_neighbour[3]; - const int y1=left_neighbour[2]; - const int z1=left_neighbour[1]; - const int x2=left_neighbour[3]+1; - const int y2=left_neighbour[2]+1; - const int z2=left_neighbour[1]+1; - const positionT ix = point_in_input_coords[3]-x1; - const positionT iy = point_in_input_coords[2]-y1; - const positionT iz = point_in_input_coords[1]-z1; - const positionT ixc = 1 - ix; - const positionT iyc = 1 - iy; - const positionT izc = 1 - iz; - return - static_cast - ( - ixc * (iyc * (izc * in[z1][y1][x1] - + iz * in[z2][y1][x1]) - + iy * (izc * in[z1][y2][x1] - + iz * in[z2][y2][x1])) - + ix * (iyc * (izc * in[z1][y1][x2] - + iz * in[z2][y1][x2]) - + iy * (izc * in[z1][y2][x2] - + iz * in[z2][y2][x2])) - ); - } - else + left_neighbour[3] >= in[left_neighbour[1]][left_neighbour[2]].get_min_index()) { + const int x1 = left_neighbour[3]; + const int y1 = left_neighbour[2]; + const int z1 = left_neighbour[1]; + const int x2 = left_neighbour[3] + 1; + const int y2 = left_neighbour[2] + 1; + const int z2 = left_neighbour[1] + 1; + const positionT ix = point_in_input_coords[3] - x1; + const positionT iy = point_in_input_coords[2] - y1; + const positionT iz = point_in_input_coords[1] - z1; + const positionT ixc = 1 - ix; + const positionT iyc = 1 - iy; + const positionT izc = 1 - iz; + return static_cast( + ixc * (iyc * (izc * in[z1][y1][x1] + iz * in[z2][y1][x1]) + iy * (izc * in[z1][y2][x1] + iz * in[z2][y2][x1])) + + ix * (iyc * (izc * in[z1][y1][x2] + iz * in[z2][y1][x2]) + iy * (izc * in[z1][y2][x2] + iz * in[z2][y2][x2]))); + } else return 0; } template void -push_transpose_linear_interpolate(Array<3, elemT>& out, - const BasicCoordinate<3, positionT>& point_in_output_coords, - valueT value) -{ - if (value==0) - return; +push_transpose_linear_interpolate(Array<3, elemT>& out, const BasicCoordinate<3, positionT>& point_in_output_coords, + valueT value) { + if (value == 0) + return; // find left neighbour - const Coordinate3D - left_neighbour(round(std::floor(point_in_output_coords[1])), - round(std::floor(point_in_output_coords[2])), - round(std::floor(point_in_output_coords[3]))); + const Coordinate3D left_neighbour(round(std::floor(point_in_output_coords[1])), + round(std::floor(point_in_output_coords[2])), + round(std::floor(point_in_output_coords[3]))); // TODO handle boundary conditions - if (left_neighbour[1] < out.get_max_index() && - left_neighbour[1] >= out.get_min_index() && - left_neighbour[2] < out[left_neighbour[1]].get_max_index() && - left_neighbour[2] >= out[left_neighbour[1]].get_min_index() && + if (left_neighbour[1] < out.get_max_index() && left_neighbour[1] >= out.get_min_index() && + left_neighbour[2] < out[left_neighbour[1]].get_max_index() && left_neighbour[2] >= out[left_neighbour[1]].get_min_index() && left_neighbour[3] < out[left_neighbour[1]][left_neighbour[2]].get_max_index() && - left_neighbour[3] >= out[left_neighbour[1]][left_neighbour[2]].get_min_index()) - { - const int x1=left_neighbour[3]; - const int y1=left_neighbour[2]; - const int z1=left_neighbour[1]; - const int x2=left_neighbour[3]+1; - const int y2=left_neighbour[2]+1; - const int z2=left_neighbour[1]+1; - const float ix = point_in_output_coords[3]-x1; - const float iy = point_in_output_coords[2]-y1; - const float iz = point_in_output_coords[1]-z1; - const float ixc = 1 - ix; - const float iyc = 1 - iy; - const float izc = 1 - iz; - out[z1][y1][x1] += ixc * iyc * izc * value; - out[z2][y1][x1] += ixc * iyc * iz * value; - out[z1][y2][x1] += ixc * iy * izc * value; - out[z2][y2][x1] += ixc * iy * iz * value; - out[z1][y1][x2] += ix * iyc * izc * value; - out[z2][y1][x2] += ix * iyc * iz * value; - out[z1][y2][x2] += ix * iy * izc * value; - out[z2][y2][x2] += ix * iy * iz * value; - } + left_neighbour[3] >= out[left_neighbour[1]][left_neighbour[2]].get_min_index()) { + const int x1 = left_neighbour[3]; + const int y1 = left_neighbour[2]; + const int z1 = left_neighbour[1]; + const int x2 = left_neighbour[3] + 1; + const int y2 = left_neighbour[2] + 1; + const int z2 = left_neighbour[1] + 1; + const float ix = point_in_output_coords[3] - x1; + const float iy = point_in_output_coords[2] - y1; + const float iz = point_in_output_coords[1] - z1; + const float ixc = 1 - ix; + const float iyc = 1 - iy; + const float izc = 1 - iz; + out[z1][y1][x1] += ixc * iyc * izc * value; + out[z2][y1][x1] += ixc * iyc * iz * value; + out[z1][y2][x1] += ixc * iy * izc * value; + out[z2][y2][x1] += ixc * iy * iz * value; + out[z1][y1][x2] += ix * iyc * izc * value; + out[z2][y1][x2] += ix * iyc * iz * value; + out[z1][y2][x2] += ix * iy * izc * value; + out[z2][y2][x2] += ix * iy * iz * value; + } } END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/phantoms/CylindersWithLineSource.h b/src/include/stir_experimental/phantoms/CylindersWithLineSource.h index 29ac08cc0d..da4acf4c18 100644 --- a/src/include/stir_experimental/phantoms/CylindersWithLineSource.h +++ b/src/include/stir_experimental/phantoms/CylindersWithLineSource.h @@ -6,153 +6,122 @@ #include "stir_experimental/Shape/EllipsoidalCylinder.h" #include "stir_experimental/Shape/CombinedShape3D.h" - - - START_NAMESPACE_STIR -class LineSource_phantom -{ +class LineSource_phantom { public: - inline LineSource_phantom(); - - inline const shared_ptr& get_A_ptr() const - { return A_ptr; } - + + inline const shared_ptr& get_A_ptr() const { return A_ptr; } + inline shared_ptr make_union_ptr(const float fraction) const; - + inline void translate(const CartesianCoordinate3D& direction); inline void scale(const CartesianCoordinate3D& scale3D); -private: +private: shared_ptr A_ptr; - }; - -LineSource_phantom::LineSource_phantom() -{ - A_ptr = new EllipsoidalCylinder (150,0,0, - CartesianCoordinate3D(0,0,0), - 0,0,0); +LineSource_phantom::LineSource_phantom() { + A_ptr = new EllipsoidalCylinder(150, 0, 0, CartesianCoordinate3D(0, 0, 0), 0, 0, 0); } -void -LineSource_phantom::translate(const CartesianCoordinate3D& direction) -{ - A_ptr->translate(direction); +void +LineSource_phantom::translate(const CartesianCoordinate3D& direction) { + A_ptr->translate(direction); } -void -LineSource_phantom::scale(const CartesianCoordinate3D& scale3D) -{ - //check this!!! +void +LineSource_phantom::scale(const CartesianCoordinate3D& scale3D) { + // check this!!! A_ptr->scale_around_origin(scale3D); } shared_ptr -LineSource_phantom::make_union_ptr(const float fraction) const -{ - shared_ptr full_A = get_A_ptr()->clone(); - - return full_A ; - +LineSource_phantom::make_union_ptr(const float fraction) const { + shared_ptr full_A = get_A_ptr()->clone(); + return full_A; } -class CylindersWithLineSource_phantom -{ +class CylindersWithLineSource_phantom { public: - inline CylindersWithLineSource_phantom(); - - //inline const shared_ptr& get_A_ptr() const + + // inline const shared_ptr& get_A_ptr() const //{ return A_ptr; } - - inline const shared_ptr& get_B_ptr() const - { return B_ptr; } - inline const shared_ptr& get_C_ptr() const - { return C_ptr; } + inline const shared_ptr& get_B_ptr() const { return B_ptr; } + + inline const shared_ptr& get_C_ptr() const { return C_ptr; } - //inline const shared_ptr& get_B1_ptr() const + // inline const shared_ptr& get_B1_ptr() const //{ return B1_ptr; } - //inline const shared_ptr& get_C1_ptr() const + // inline const shared_ptr& get_C1_ptr() const //{ return C1_ptr; } - inline shared_ptr make_union_ptr(const float fraction) const; - + inline void translate(const CartesianCoordinate3D& direction); inline void scale(const CartesianCoordinate3D& scale3D); -private: - //shared_ptr A_ptr; +private: + // shared_ptr A_ptr; shared_ptr B_ptr; shared_ptr C_ptr; - //shared_ptr B1_ptr; - //shared_ptr C1_ptr; - + // shared_ptr B1_ptr; + // shared_ptr C1_ptr; }; - -CylindersWithLineSource_phantom::CylindersWithLineSource_phantom() -{ +CylindersWithLineSource_phantom::CylindersWithLineSource_phantom() { // A_ptr = new EllipsoidalCylinder (150,19,19, - //CartesianCoordinate3D(0,0,0), - //0,0,0); + // CartesianCoordinate3D(0,0,0), + // 0,0,0); // for 966 - //B_ptr = new EllipsoidalCylinder (500,60,60, - // CartesianCoordinate3D(0,0,0), + // B_ptr = new EllipsoidalCylinder (500,60,60, + // CartesianCoordinate3D(0,0,0), // 0,0,0); - - // two planes only - /* B_ptr = new EllipsoidalCylinder (1,6,6, - CartesianCoordinate3D(0,-14,0), - 0,0,0); - - C_ptr = new EllipsoidalCylinder (1,6,6, - CartesianCoordinate3D(0,14,0), - 0,0,0);*/ + /* B_ptr = new EllipsoidalCylinder (1,6,6, + CartesianCoordinate3D(0,-14,0), + 0,0,0); + + C_ptr = new EllipsoidalCylinder (1,6,6, + CartesianCoordinate3D(0,14,0), + 0,0,0);*/ // off centre // this is to check the bloody arthifacts in new filters /*B_ptr = new EllipsoidalCylinder (1,6,6, - CartesianCoordinate3D(0,-13,4), + CartesianCoordinate3D(0,-13,4), 0,0,0); - + C_ptr = new EllipsoidalCylinder (1,6,6, CartesianCoordinate3D(0,13,4), 0,0,0);*/ - // these are the ones noramly used - B_ptr = new EllipsoidalCylinder (1,8,8, - CartesianCoordinate3D(0,-14,5), - 0,0,0); - - C_ptr = new EllipsoidalCylinder (1,8,8, - CartesianCoordinate3D(0,14,5), - 0,0,0); + B_ptr = new EllipsoidalCylinder(1, 8, 8, CartesianCoordinate3D(0, -14, 5), 0, 0, 0); - // the one that I use for resolution - /* B_ptr = new EllipsoidalCylinder (100,8,8, - CartesianCoordinate3D(0,-14,0), - 0,0,0); - - C_ptr = new EllipsoidalCylinder (100,8,8, - CartesianCoordinate3D(0,14,0), - 0,0,0);*/ + C_ptr = new EllipsoidalCylinder(1, 8, 8, CartesianCoordinate3D(0, 14, 5), 0, 0, 0); + + // the one that I use for resolution + /* B_ptr = new EllipsoidalCylinder (100,8,8, + CartesianCoordinate3D(0,-14,0), + 0,0,0); + + C_ptr = new EllipsoidalCylinder (100,8,8, + CartesianCoordinate3D(0,14,0), + 0,0,0);*/ - // the one that I use for resolution + // the one that I use for resolution /* B1_ptr = new EllipsoidalCylinder (1,6,6, - CartesianCoordinate3D(0,0,-14), + CartesianCoordinate3D(0,0,-14), 0,0,0); C1_ptr = new EllipsoidalCylinder (1,6,6, @@ -161,72 +130,56 @@ CylindersWithLineSource_phantom::CylindersWithLineSource_phantom() // off centre /*B1_ptr = new EllipsoidalCylinder (1,6,6, - CartesianCoordinate3D(0,-2,-14), + CartesianCoordinate3D(0,-2,-14), 0,0,0); C1_ptr = new EllipsoidalCylinder (1,6,6, CartesianCoordinate3D(0,-2,14), 0,0,0);*/ - } -void -CylindersWithLineSource_phantom::translate(const CartesianCoordinate3D& direction) -{ -// A_ptr->translate(direction); - B_ptr->translate(direction); - C_ptr->translate(direction); -// B1_ptr->translate(direction); -// C1_ptr->translate(direction); +void +CylindersWithLineSource_phantom::translate(const CartesianCoordinate3D& direction) { + // A_ptr->translate(direction); + B_ptr->translate(direction); + C_ptr->translate(direction); + // B1_ptr->translate(direction); + // C1_ptr->translate(direction); } -void -CylindersWithLineSource_phantom::scale(const CartesianCoordinate3D& scale3D) -{ - //check this!!! - //A_ptr->scale_around_origin(scale3D); +void +CylindersWithLineSource_phantom::scale(const CartesianCoordinate3D& scale3D) { + // check this!!! + // A_ptr->scale_around_origin(scale3D); B_ptr->scale_around_origin(scale3D); C_ptr->scale_around_origin(scale3D); - //B1_ptr->scale_around_origin(scale3D); - //C1_ptr->scale_around_origin(scale3D); - - - + // B1_ptr->scale_around_origin(scale3D); + // C1_ptr->scale_around_origin(scale3D); } shared_ptr -CylindersWithLineSource_phantom::make_union_ptr(const float fraction) const -{ - //shared_ptr full_A = get_A_ptr()->clone(); - shared_ptr full_B = get_B_ptr()->clone(); - shared_ptr full_C = get_C_ptr()->clone(); - - //shared_ptr full_B1 = get_B1_ptr()->clone(); - //shared_ptr full_C1 = get_C1_ptr()->clone(); - - shared_ptr AB_union = - new CombinedShape3D >( full_C,full_B); - - //shared_ptr AB1_union = - //new CombinedShape3D >( full_C1,full_B1); - - //shared_ptr AB1_AB_union = - //new CombinedShape3D >( AB_union, AB1_union); - - // shared_ptr ABC_union = - // new CombinedShape3D >( AB_union,full_C); - - //return AB1_AB_union; - return AB_union; - //return full_B; - - -} +CylindersWithLineSource_phantom::make_union_ptr(const float fraction) const { + // shared_ptr full_A = get_A_ptr()->clone(); + shared_ptr full_B = get_B_ptr()->clone(); + shared_ptr full_C = get_C_ptr()->clone(); + // shared_ptr full_B1 = get_B1_ptr()->clone(); + // shared_ptr full_C1 = get_C1_ptr()->clone(); + shared_ptr AB_union = new CombinedShape3D>(full_C, full_B); + // shared_ptr AB1_union = + // new CombinedShape3D >( full_C1,full_B1); + // shared_ptr AB1_AB_union = + // new CombinedShape3D >( AB_union, AB1_union); + // shared_ptr ABC_union = + // new CombinedShape3D >( AB_union,full_C); + // return AB1_AB_union; + return AB_union; + // return full_B; +} // OLD #if 0 diff --git a/src/include/stir_experimental/phantoms/Utah.h b/src/include/stir_experimental/phantoms/Utah.h index aa6d07d9bf..1cc2e34d22 100644 --- a/src/include/stir_experimental/phantoms/Utah.h +++ b/src/include/stir_experimental/phantoms/Utah.h @@ -19,7 +19,7 @@ #ifndef __stir_phantoms_Utah_H__ #define __stir_phantoms_Utah_H__ /*! - \file + \file \ingroup Shape \brief inline implementations for stir::Utah_phantom. @@ -33,54 +33,46 @@ #include "stir/CombinedShape3D.h" START_NAMESPACE_STIR - + /*! \brief A class that represents a Utah phantom. \todo dims here are wrong A: cylinder, 20cm diam, 10cm height B: cylinder, 18cm diam, 15cm height - C: outer annulus, 20cm extern.diam, + C: outer annulus, 20cm extern.diam, 2cm thick, 15cm height D: cylinder in B, 4.5cm diam, 18cm??? height - E: shorter cylinder in B, 4.5cm diam, + E: shorter cylinder in B, 4.5cm diam, 5.5cm height */ -class Utah_phantom -{ +class Utah_phantom { public: - /*! + /*! \brief Construct a Utah phantom. It is oriented along z, with edge between A and B at z=0. */ inline Utah_phantom(); - - inline const shared_ptr& get_A_ptr() const - { return A_ptr; } - - inline const shared_ptr& get_B_ptr() const - { return B_ptr; } - + + inline const shared_ptr& get_A_ptr() const { return A_ptr; } + + inline const shared_ptr& get_B_ptr() const { return B_ptr; } + //! get B without holes - inline const shared_ptr& get_full_B_ptr() const - { return full_B_ptr; } + inline const shared_ptr& get_full_B_ptr() const { return full_B_ptr; } + + inline const shared_ptr& get_C_ptr() const { return C_ptr; } - inline const shared_ptr& get_C_ptr() const - { return C_ptr; } - //! get C without hole - inline const shared_ptr& get_full_C_ptr() const - { return full_C_ptr; } + inline const shared_ptr& get_full_C_ptr() const { return full_C_ptr; } + + inline const shared_ptr& get_D_ptr() const { return D_ptr; } - inline const shared_ptr& get_D_ptr() const - { return D_ptr; } - - inline const shared_ptr& get_E_ptr() const - { return E_ptr; } + inline const shared_ptr& get_E_ptr() const { return E_ptr; } - /*! + /*! \brief make a region inside B when \c fraction<1. The region has a smaller outer cylinder (scaled with fraction) @@ -88,7 +80,7 @@ class Utah_phantom */ inline shared_ptr make_inside_B_ptr(const float fraction) const; - /*! + /*! \brief make a region inside C when \c fraction<1. The region has a smaller outer cylinder (scaled with fraction) @@ -109,67 +101,52 @@ class Utah_phantom shared_ptr E_ptr; }; -Utah_phantom::Utah_phantom() -{ -//EllipsoidalCylinder (Lcyl,Rcyl_a,Rcyl_b, -// CartesianCoordinate3D(zc,yc,xc), -// alpha,beta,gamma) - - - A_ptr = new EllipsoidalCylinder (100,100,100, - CartesianCoordinate3D(-50,0,0)); - full_B_ptr = new EllipsoidalCylinder (150,80,80, - CartesianCoordinate3D(75,0,0)); - full_C_ptr = new EllipsoidalCylinder (150,100,100, - CartesianCoordinate3D(75,0,0)); - D_ptr = new EllipsoidalCylinder (105,22.5,22.5, - CartesianCoordinate3D(52.5,0,-47.5)); - E_ptr = new EllipsoidalCylinder (55,22.5,22.5, - CartesianCoordinate3D(27.5,0,47.5)); - - //CombinedShape3D< logical_and_not > C( &FullC,&FullB); - C_ptr = new CombinedShape3D< logical_and_not > ( full_C_ptr,full_B_ptr); - shared_ptr full_B_notD_ptr = - new CombinedShape3D< logical_and_not > ( full_B_ptr,D_ptr); - B_ptr = new CombinedShape3D< logical_and_not > ( full_B_notD_ptr,E_ptr); +Utah_phantom::Utah_phantom() { + // EllipsoidalCylinder (Lcyl,Rcyl_a,Rcyl_b, + // CartesianCoordinate3D(zc,yc,xc), + // alpha,beta,gamma) + + A_ptr = new EllipsoidalCylinder(100, 100, 100, CartesianCoordinate3D(-50, 0, 0)); + full_B_ptr = new EllipsoidalCylinder(150, 80, 80, CartesianCoordinate3D(75, 0, 0)); + full_C_ptr = new EllipsoidalCylinder(150, 100, 100, CartesianCoordinate3D(75, 0, 0)); + D_ptr = new EllipsoidalCylinder(105, 22.5, 22.5, CartesianCoordinate3D(52.5, 0, -47.5)); + E_ptr = new EllipsoidalCylinder(55, 22.5, 22.5, CartesianCoordinate3D(27.5, 0, 47.5)); + + // CombinedShape3D< logical_and_not > C( &FullC,&FullB); + C_ptr = new CombinedShape3D>(full_C_ptr, full_B_ptr); + shared_ptr full_B_notD_ptr = new CombinedShape3D>(full_B_ptr, D_ptr); + B_ptr = new CombinedShape3D>(full_B_notD_ptr, E_ptr); } -shared_ptr -Utah_phantom::make_inside_B_ptr(const float fraction) const -{ +shared_ptr +Utah_phantom::make_inside_B_ptr(const float fraction) const { // first get a new copy of full_B shared_ptr small_full_B_ptr = get_full_B_ptr()->clone(); - // make it smaller - small_full_B_ptr ->scale_around_origin(CartesianCoordinate3D(1.F,fraction,fraction)); + // make it smaller + small_full_B_ptr->scale_around_origin(CartesianCoordinate3D(1.F, fraction, fraction)); // the same for D shared_ptr large_D_ptr = get_D_ptr()->clone(); - large_D_ptr ->scale_around_origin(CartesianCoordinate3D(1.F,1/fraction,1/fraction)); + large_D_ptr->scale_around_origin(CartesianCoordinate3D(1.F, 1 / fraction, 1 / fraction)); // and E shared_ptr large_E_ptr = get_E_ptr()->clone(); - large_E_ptr ->scale_around_origin(CartesianCoordinate3D(1.F,1/fraction,1/fraction)); - + large_E_ptr->scale_around_origin(CartesianCoordinate3D(1.F, 1 / fraction, 1 / fraction)); + // combine the whole thing - shared_ptr small_full_B_notD_ptr = - new CombinedShape3D< logical_and_not > ( small_full_B_ptr,large_D_ptr); - return - new CombinedShape3D< logical_and_not > ( small_full_B_notD_ptr,large_E_ptr); + shared_ptr small_full_B_notD_ptr = new CombinedShape3D>(small_full_B_ptr, large_D_ptr); + return new CombinedShape3D>(small_full_B_notD_ptr, large_E_ptr); } - -shared_ptr -Utah_phantom::make_inside_C_ptr(const float fraction) const -{ +shared_ptr +Utah_phantom::make_inside_C_ptr(const float fraction) const { shared_ptr small_full_C_ptr = get_full_C_ptr()->clone(); - small_full_C_ptr ->scale_around_origin(CartesianCoordinate3D(1.F,fraction,fraction)); + small_full_C_ptr->scale_around_origin(CartesianCoordinate3D(1.F, fraction, fraction)); shared_ptr large_full_B_ptr = get_full_B_ptr()->clone(); - large_full_B_ptr ->scale_around_origin(CartesianCoordinate3D(1.F,1/fraction,1/fraction)); - return - new CombinedShape3D< logical_and_not > ( small_full_C_ptr,large_full_B_ptr); + large_full_B_ptr->scale_around_origin(CartesianCoordinate3D(1.F, 1 / fraction, 1 / fraction)); + return new CombinedShape3D>(small_full_C_ptr, large_full_B_ptr); } -void -Utah_phantom::translate(const CartesianCoordinate3D& direction) -{ +void +Utah_phantom::translate(const CartesianCoordinate3D& direction) { A_ptr->translate(direction); B_ptr->translate(direction); full_B_ptr->translate(direction); @@ -179,9 +156,8 @@ Utah_phantom::translate(const CartesianCoordinate3D& direction) E_ptr->translate(direction); } -void -Utah_phantom::scale(const CartesianCoordinate3D& scale3D) -{ +void +Utah_phantom::scale(const CartesianCoordinate3D& scale3D) { A_ptr->scale(scale3D); B_ptr->scale(scale3D); full_B_ptr->scale(scale3D); diff --git a/src/include/stir_experimental/recon_buildblock/BinNormalisationFromML2D.h b/src/include/stir_experimental/recon_buildblock/BinNormalisationFromML2D.h index 62ff47dd24..71a8492443 100644 --- a/src/include/stir_experimental/recon_buildblock/BinNormalisationFromML2D.h +++ b/src/include/stir_experimental/recon_buildblock/BinNormalisationFromML2D.h @@ -42,7 +42,7 @@ START_NAMESPACE_STIR \brief A BinNormalisation class that gets the normalisation factors from the files output by find_ML_normfactors. - \warning the ProjData object has to be 2D, no mashing, no span, no arc-correction. + \warning the ProjData object has to be 2D, no mashing, no span, no arc-correction. I'm not sure if this is properly checked at run-time. \par Parsing details @@ -62,16 +62,14 @@ START_NAMESPACE_STIR */ -class BinNormalisationFromML2D : - public RegisteredParsingObject -{ +class BinNormalisationFromML2D : public RegisteredParsingObject { public: //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor - /*! - \warning You should not call any member functions for any object just + /*! + \warning You should not call any member functions for any object just constructed with this constructor. Initialise the object properly first by parsing. */ @@ -81,16 +79,16 @@ class BinNormalisationFromML2D : virtual Succeeded set_up(const shared_ptr&); //! Normalise some data - /*! - This means \c multiply with the data in the projdata object - passed in the constructor. + /*! + This means \c multiply with the data in the projdata object + passed in the constructor. */ virtual void apply(RelatedViewgrams& viewgrams) const; //! Undo the normalisation of some data - /*! - This means \c divide with the data in the projdata object - passed in the constructor. + /*! + This means \c divide with the data in the projdata object + passed in the constructor. */ virtual void undo(RelatedViewgrams& viewgrams) const; @@ -109,7 +107,6 @@ class BinNormalisationFromML2D : shared_ptr norm_factors_ptr; }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir_experimental/recon_buildblock/BinNormalisationSinogramRescaling.h b/src/include/stir_experimental/recon_buildblock/BinNormalisationSinogramRescaling.h index 499bfae83b..a863638a2a 100644 --- a/src/include/stir_experimental/recon_buildblock/BinNormalisationSinogramRescaling.h +++ b/src/include/stir_experimental/recon_buildblock/BinNormalisationSinogramRescaling.h @@ -13,8 +13,6 @@ \author Sanida Mustafovic */ - - #ifndef __stir_recon_buildblock_BinNormalisationSinogramRescaling_H__ #define __stir_recon_buildblock_BinNormalisationSinogramRescaling_H__ @@ -29,23 +27,20 @@ START_NAMESPACE_STIR - /*! \ingroup recon_buildblock - \brief The BinNormalisationSinogramRescaling class gets normaliastion factors by dividing + \brief The BinNormalisationSinogramRescaling class gets normaliastion factors by dividing forward projection of the fitted cyl. to the precorrecred data - + */ -class BinNormalisationSinogramRescaling : - public RegisteredParsingObject -{ +class BinNormalisationSinogramRescaling : public RegisteredParsingObject { public: //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; - + static const char* const registered_name; + //! Default constructor - /*! - \warning You should not call any member functions for any object just + /*! + \warning You should not call any member functions for any object just constructed with this constructor. Initialise the object properly first by parsing. */ @@ -58,13 +53,13 @@ class BinNormalisationSinogramRescaling : float get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const; //! Normalise some data - /*! + /*! This means \c multiply with the data in the scale factors file. */ - virtual void apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; //! Undo the normalisation of some data - /*! + /*! This means \c divide with the data in th scale factors file. */ virtual void undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; @@ -73,7 +68,7 @@ class BinNormalisationSinogramRescaling : // the proj data info used for obtaining axial position num, segment num // will be set by set_up() shared_ptr proj_data_info_sptr; - Array<3,float> rescaling_factors; + Array<3, float> rescaling_factors; // parsing stuff virtual void set_defaults(); @@ -83,7 +78,6 @@ class BinNormalisationSinogramRescaling : std::string sinogram_rescaling_factors_filename; }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir_experimental/recon_buildblock/BinNormalisationUsingProfile.h b/src/include/stir_experimental/recon_buildblock/BinNormalisationUsingProfile.h index 27340036c5..b2bf68b1b6 100644 --- a/src/include/stir_experimental/recon_buildblock/BinNormalisationUsingProfile.h +++ b/src/include/stir_experimental/recon_buildblock/BinNormalisationUsingProfile.h @@ -24,25 +24,23 @@ START_NAMESPACE_STIR -class BinNormalisationUsingProfile : - public RegisteredParsingObject -{ +class BinNormalisationUsingProfile : public RegisteredParsingObject { public: //! Name which will be used when parsing a BinNormalisation object - static const char * const registered_name; + static const char* const registered_name; BinNormalisationUsingProfile(); BinNormalisationUsingProfile(const std::string& filename); - virtual void apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; - virtual void undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const; + virtual void undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const; + + virtual float get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { return 1; } - virtual float get_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const { return 1;} - private: - mutable Array<1,float> profile; + mutable Array<1, float> profile; std::string profile_filename; virtual void set_defaults(); @@ -53,4 +51,3 @@ class BinNormalisationUsingProfile : END_NAMESPACE_STIR #endif - diff --git a/src/include/stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.h b/src/include/stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.h index 6ad81f9ec0..e5fe4e8aee 100644 --- a/src/include/stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.h +++ b/src/include/stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.h @@ -24,12 +24,11 @@ \brief Declaration of class stir::DataSymmetriesForDensels_PET_CartesianGrid \author Kris Thielemans - + */ #ifndef __stir_recon_buildblock_DataSymmetriesForDensels_PET_CartesianGrid_H__ #define __stir_recon_buildblock_DataSymmetriesForDensels_PET_CartesianGrid_H__ - #include "stir/recon_buildblock/DataSymmetriesForDensels.h" #include "stir/ProjDataInfo.h" //#include "stir/SymmetryOperations_PET_CartesianGrid.h" @@ -40,38 +39,37 @@ START_NAMESPACE_STIR -template class DiscretisedDensity; -template class DiscretisedDensityOnCartesianGrid; +template +class DiscretisedDensity; +template +class DiscretisedDensityOnCartesianGrid; /*! \ingroup recon_buildblock - \brief Symmetries appropriate for a (cylindrical) PET scanner, and + \brief Symmetries appropriate for a (cylindrical) PET scanner, and a discretised density on a Cartesian grid. All operations (except the constructor) are inline as timing of the methods of this class is critical. */ -class DataSymmetriesForDensels_PET_CartesianGrid : public DataSymmetriesForDensels -{ +class DataSymmetriesForDensels_PET_CartesianGrid : public DataSymmetriesForDensels { private: typedef DataSymmetriesForDensels base_type; typedef DataSymmetriesForDensels_PET_CartesianGrid self_type; -public: +public: DataSymmetriesForDensels_PET_CartesianGrid(const shared_ptr& proj_data_info_ptr, - const shared_ptr >& image_info_ptr); - + const shared_ptr>& image_info_ptr); - virtual + virtual #ifndef STIR_NO_COVARIANT_RETURN_TYPES - DataSymmetriesForDensels_PET_CartesianGrid * + DataSymmetriesForDensels_PET_CartesianGrid* #else - DataSymmetriesForDensels * + DataSymmetriesForDensels* #endif - clone() const; + clone() const; - bool - operator ==(const DataSymmetriesForDensels_PET_CartesianGrid&) const; + bool operator==(const DataSymmetriesForDensels_PET_CartesianGrid&) const; #if 0 TODO! @@ -80,33 +78,26 @@ class DataSymmetriesForDensels_PET_CartesianGrid : public DataSymmetriesForDense get_basic_densel_index_range() const; #endif - inline void - get_related_densels(vector&, const Densel& b) const; + inline void get_related_densels(vector&, const Densel& b) const; - inline int - num_related_densels(const Densel& b) const; + inline int num_related_densels(const Densel& b) const; - inline unique_ptr - find_symmetry_operation_from_basic_densel(Densel&) const; + inline unique_ptr find_symmetry_operation_from_basic_densel(Densel&) const; - inline bool - find_basic_densel(Densel& b) const; - + inline bool find_basic_densel(Densel& b) const; //! find out how many image planes there are for every scanner ring inline float get_num_planes_per_scanner_ring() const; - - //! find correspondence between axial_pos_num and image coordinates /*! z = num_planes_per_axial_pos * axial_pos_num + axial_pos_to_z_offset - - compute the offset by matching up the centre of the scanner + + compute the offset by matching up the centre of the scanner in the 2 coordinate systems */ inline float get_num_planes_per_axial_pos(const int segment_num) const; inline float get_axial_pos_to_z_offset(const int segment_num) const; - + private: const shared_ptr& proj_data_info_ptr; int num_planes; @@ -129,11 +120,9 @@ class DataSymmetriesForDensels_PET_CartesianGrid : public DataSymmetriesForDense cartesian_grid_info_ptr() const; #endif - virtual bool blindly_equals(const root_type * const) const; - - inline SymmetryOperation* - find_sym_op_general_densel( const int z, const int y, const int x) const; - + virtual bool blindly_equals(const root_type* const) const; + + inline SymmetryOperation* find_sym_op_general_densel(const int z, const int y, const int x) const; }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.inl b/src/include/stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.inl index 80ebe1f829..afa559195c 100644 --- a/src/include/stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.inl +++ b/src/include/stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.inl @@ -31,97 +31,78 @@ cartesian_grid_info_ptr() const #endif float -DataSymmetriesForDensels_PET_CartesianGrid:: -get_num_planes_per_axial_pos(const int segment_num) const -{ +DataSymmetriesForDensels_PET_CartesianGrid::get_num_planes_per_axial_pos(const int segment_num) const { return static_cast(num_planes_per_axial_pos[segment_num]); } float -DataSymmetriesForDensels_PET_CartesianGrid:: -get_num_planes_per_scanner_ring() const -{ +DataSymmetriesForDensels_PET_CartesianGrid::get_num_planes_per_scanner_ring() const { return static_cast(num_planes_per_scanner_ring); } -float -DataSymmetriesForDensels_PET_CartesianGrid:: -get_axial_pos_to_z_offset(const int segment_num) const -{ +float +DataSymmetriesForDensels_PET_CartesianGrid::get_axial_pos_to_z_offset(const int segment_num) const { return axial_pos_to_z_offset[segment_num]; -} - - +} -SymmetryOperation* -DataSymmetriesForDensels_PET_CartesianGrid:: -find_sym_op_general_densel(const int z, const int y, const int x) const -{ - const int z_shift = z - (z%num_independent_planes); +SymmetryOperation* +DataSymmetriesForDensels_PET_CartesianGrid::find_sym_op_general_densel(const int z, const int y, const int x) const { + const int z_shift = z - (z % num_independent_planes); // TODO next shift might depend on the segment. // Solving this will require removing the axial_pos_num_shift argument from the symmetry operations - const int axial_pos_num_shift = z_shift/num_independent_planes; + const int axial_pos_num_shift = z_shift / num_independent_planes; const int view180 = num_views; - - if (x>=y && y>=0) // [0,45] - { - if (z_shift==0) - return new TrivialSymmetryOperation(); - else - return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num_shift, z_shift); - } - else if ( x>=0 && y>x) // [ 45, 90] + + if (x >= y && y >= 0) // [0,45] + { + if (z_shift == 0) + return new TrivialSymmetryOperation(); + else + return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num_shift, z_shift); + } else if (x >= 0 && y > x) // [ 45, 90] return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx(view180, axial_pos_num_shift, z_shift); - else if (x<0 && y>-x) //[90, 135 ] + else if (x < 0 && y > -x) //[90, 135 ] return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx(view180, axial_pos_num_shift, z_shift); - else if ( x<0 && y>=0) // [ 135, 180] - { - assert(y<=-x); - return new SymmetryOperation_PET_CartesianGrid_swap_xmx(view180, axial_pos_num_shift, z_shift); - } - else if ( x<0 && y<=0 && -y<=-x ) // [ 180, 225] + else if (x < 0 && y >= 0) // [ 135, 180] + { + assert(y <= -x); + return new SymmetryOperation_PET_CartesianGrid_swap_xmx(view180, axial_pos_num_shift, z_shift); + } else if (x < 0 && y <= 0 && -y <= -x) // [ 180, 225] return new SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy(view180, axial_pos_num_shift, z_shift); - else if ( x<=0 && y<0) // [ 225, 270] - { - assert(-y>-x); - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(view180, axial_pos_num_shift, z_shift); - } - else if ( x>0 && -y>x) // [ 270, 315] + else if (x <= 0 && y < 0) // [ 225, 270] + { + assert(-y > -x); + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(view180, axial_pos_num_shift, z_shift); + } else if (x > 0 && -y > x) // [ 270, 315] return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx(view180, axial_pos_num_shift, z_shift); else // [ 315, 360] - { - assert(x>0 && y<0 && -y<=x); - return new SymmetryOperation_PET_CartesianGrid_swap_ymy(view180, axial_pos_num_shift, z_shift); - } + { + assert(x > 0 && y < 0 && -y <= x); + return new SymmetryOperation_PET_CartesianGrid_swap_ymy(view180, axial_pos_num_shift, z_shift); + } } - -bool -DataSymmetriesForDensels_PET_CartesianGrid:: -find_basic_densel(Densel& c) const -{ +bool +DataSymmetriesForDensels_PET_CartesianGrid::find_basic_densel(Densel& c) const { int& z = c[1]; int& y = c[2]; int& x = c[3]; - if (z==z%num_independent_planes && x>=0 && y>=0 && y<=x) + if (z == z % num_independent_planes && x >= 0 && y >= 0 && y <= x) return false; - z = z%num_independent_planes; - if (x<0) x = -x; - if (y<0) y = -y; - if (y>x) std::swap(x,y); + z = z % num_independent_planes; + if (x < 0) + x = -x; + if (y < 0) + y = -y; + if (y > x) + std::swap(x, y); return true; } - // TODO, optimise unique_ptr -DataSymmetriesForDensels_PET_CartesianGrid:: - find_symmetry_operation_from_basic_densel(Densel& c) const -{ - unique_ptr - sym_op( - find_sym_op_general_densel(c[1], c[2], c[3]) - ); +DataSymmetriesForDensels_PET_CartesianGrid::find_symmetry_operation_from_basic_densel(Densel& c) const { + unique_ptr sym_op(find_sym_op_general_densel(c[1], c[2], c[3])); #ifndef NDEBUG const Densel copy_original = c; #endif @@ -129,32 +110,27 @@ DataSymmetriesForDensels_PET_CartesianGrid:: #ifndef NDEBUG Densel copy = c; sym_op->transform_image_coordinates(copy); - assert(copy_original==copy); + assert(copy_original == copy); #endif return sym_op; } - int -DataSymmetriesForDensels_PET_CartesianGrid:: -num_related_densels(const Densel& b) const -{ +DataSymmetriesForDensels_PET_CartesianGrid::num_related_densels(const Densel& b) const { int num = 1; - if (b[3]!=0) + if (b[3] != 0) num *= 2; - if (b[2]!=0) + if (b[2] != 0) num *= 2; - if (abs(b[3])!=abs(b[2])) + if (abs(b[3]) != abs(b[2])) num *= 2; - num *= static_cast(ceil(static_cast(num_planes)/num_independent_planes)); + num *= static_cast(ceil(static_cast(num_planes) / num_independent_planes)); return num; } void -DataSymmetriesForDensels_PET_CartesianGrid:: -get_related_densels(vector& v, const Densel& d) const -{ +DataSymmetriesForDensels_PET_CartesianGrid::get_related_densels(vector& v, const Densel& d) const { #ifndef NDEBUG { Densel dcopy = d; @@ -163,54 +139,46 @@ get_related_densels(vector& v, const Densel& d) const #endif v.reserve(num_related_densels(d)); v.resize(0); - + const int x = d[3]; const int y = d[2]; - const int basic_z =d[1]; + const int basic_z = d[1]; { - for (int z=basic_z; z0) - { - for (int z=basic_z; z 0) { + for (int z = basic_z; z < num_planes; z += num_independent_planes) v.push_back(Densel(z, y, -x)); } - if (y>0) - { - for (int z=basic_z; z 0) { + for (int z = basic_z; z < num_planes; z += num_independent_planes) v.push_back(Densel(z, -y, x)); } - if (x>0 && y>0) - { - for (int z=basic_z; z 0 && y > 0) { + for (int z = basic_z; z < num_planes; z += num_independent_planes) v.push_back(Densel(z, -y, -x)); } - if (x!=y) + if (x != y) { { - { - for (int z=basic_z; z0) - { - for (int z=basic_z; z0) - { - for (int z=basic_z; z0 && y>0) - { - for (int z=basic_z; z 0) { + for (int z = basic_z; z < num_planes; z += num_independent_planes) + v.push_back(Densel(z, x, -y)); + } + if (y > 0) { + for (int z = basic_z; z < num_planes; z += num_independent_planes) + v.push_back(Densel(z, -x, y)); + } + if (x > 0 && y > 0) { + for (int z = basic_z; z < num_planes; z += num_independent_planes) + v.push_back(Densel(z, -x, -y)); + } + } assert(v.size() == static_cast(num_related_densels(d))); - } - + END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/recon_buildblock/ParametricQuadraticPrior.h b/src/include/stir_experimental/recon_buildblock/ParametricQuadraticPrior.h index f8bd610650..ad171f3245 100644 --- a/src/include/stir_experimental/recon_buildblock/ParametricQuadraticPrior.h +++ b/src/include/stir_experimental/recon_buildblock/ParametricQuadraticPrior.h @@ -27,11 +27,9 @@ */ - #ifndef __stir_recon_buildblock_ParametricQuadraticPrior_H__ #define __stir_recon_buildblock_ParametricQuadraticPrior_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/recon_buildblock/QuadraticPrior.h" #include "stir/recon_buildblock/PriorWithParabolicSurrogate.h" @@ -51,26 +49,26 @@ START_NAMESPACE_STIR A class in the GeneralisedPrior hierarchy. This implements a quadratic Gibbs prior. The gradient of the prior is computed as follows: - + \f[ g_r = \sum_dr w_{dr} (\lambda_r - \lambda_{r+dr}) * \kappa_r * \kappa_{r+dr} \f] where \f$\lambda\f$ is the image and \f$r\f$ and \f$dr\f$ are indices and the sum is over the neighbourhood where the weights \f$w_{dr}\f$ are non-zero. - The \f$\kappa\f$ image can be used to have spatially-varying penalties such as in + The \f$\kappa\f$ image can be used to have spatially-varying penalties such as in Jeff Fessler's papers. It should have identical dimensions to the image for which the penalty is computed. If \f$\kappa\f$ is not set, this class will effectively use 1 for all \f$\kappa\f$'s. - By default, a 3x3 or 3x3x3 neigbourhood is used where the weights are set to + By default, a 3x3 or 3x3x3 neigbourhood is used where the weights are set to x-voxel_size divided by the Euclidean distance between the points. - + \par Parsing These are the keywords that can be used in addition to the ones in GeneralPrior. \verbatim Quadratic Prior Parameters:= - ; next defaults to 0, set to 1 for 2D inverse Euclidean weights, 0 for 3D + ; next defaults to 0, set to 1 for 2D inverse Euclidean weights, 0 for 3D only 2D:= 0 ; next can be used to set weights explicitly. Needs to be a 3D array (of floats). ' value of only_2D is ignored @@ -81,54 +79,43 @@ START_NAMESPACE_STIR ; kappa filename:= ; use next parameter to get gradient images at every subiteration ; see class documentation - gradient filename prefix:= + gradient filename prefix:= END Quadratic Prior Parameters:= \endverbatim */ template -class ParametricQuadraticPrior: public - RegisteredParsingObject< ParametricQuadraticPrior, - GeneralisedPrior, - PriorWithParabolicSurrogate - > -{ - private: - typedef - RegisteredParsingObject< ParametricQuadraticPrior, - GeneralisedPrior, - PriorWithParabolicSurrogate > - base_type; - shared_ptr kappa_ptr; - VectorWithOffset > _single_quadratic_priors; - - public: +class ParametricQuadraticPrior : public RegisteredParsingObject, GeneralisedPrior, + PriorWithParabolicSurrogate> { +private: + typedef RegisteredParsingObject, GeneralisedPrior, + PriorWithParabolicSurrogate> + base_type; + shared_ptr kappa_ptr; + VectorWithOffset> _single_quadratic_priors; + +public: //! Name which will be used when parsing a GeneralisedPrior object - static const char * const registered_name; + static const char* const registered_name; - //! Default constructor + //! Default constructor ParametricQuadraticPrior(); //! Constructs it explicitly ParametricQuadraticPrior(const bool only_2D, float penalization_factor); - virtual bool - parabolic_surrogate_curvature_depends_on_argument() const - { return false; } - + virtual bool parabolic_surrogate_curvature_depends_on_argument() const { return false; } + //! compute the value of the function - double - compute_value(const TargetT ¤t_image_estimate); + double compute_value(const TargetT& current_image_estimate); - //! compute gradient - void compute_gradient(TargetT& prior_gradient, - const TargetT ¤t_image_estimate); + //! compute gradient + void compute_gradient(TargetT& prior_gradient, const TargetT& current_image_estimate); //! compute the parabolic surrogate for the prior /*! in the case of quadratic priors this will just be the sum of weighting coefficients*/ - void parabolic_surrogate_curvature(TargetT& parabolic_surrogate_curvature, - const TargetT ¤t_image_estimate); + void parabolic_surrogate_curvature(TargetT& parabolic_surrogate_curvature, const TargetT& current_image_estimate); #if 0 //! compute Hessian void compute_Hessian(TargetT& prior_Hessian_for_single_densel, @@ -136,59 +123,55 @@ class ParametricQuadraticPrior: public const TargetT ¤t_image_estimate); #endif - virtual Succeeded - add_multiplication_with_approximate_Hessian(TargetT& output, - const TargetT& input) const; + virtual Succeeded add_multiplication_with_approximate_Hessian(TargetT& output, const TargetT& input) const; //! get penalty weights for the neigbourhood - Array<3,float> get_weights() const; + Array<3, float> get_weights() const; //! set penalty weights for the neigbourhood - void set_weights(const Array<3,float>&); + void set_weights(const Array<3, float>&); //! get current kappa image /*! \warning As this function returns a shared_ptr, this is dangerous. You should not modify the image by manipulating the image refered to by this pointer. Unpredictable results will occur. */ - shared_ptr get_kappa_sptr() const; + shared_ptr get_kappa_sptr() const; //! set kappa image - void set_kappa_sptr(const shared_ptr&); + void set_kappa_sptr(const shared_ptr&); //! Has to be called before using this object - virtual Succeeded set_up(shared_ptr > const& target_sptr); - + virtual Succeeded set_up(shared_ptr> const& target_sptr); + protected: //! can be set during parsing to restrict the weights to the 2D case bool only_2D; //! filename prefix for outputing the gradient whenever compute_gradient() is called. /*! An internal counter is used to keep track of the number of times the - gradient is computed. The filename will be constructed by concatenating + gradient is computed. The filename will be constructed by concatenating gradient_filename_prefix and the counter. */ string gradient_filename_prefix; //! penalty weights - /*! + /*! \todo This member is mutable at present because some const functions initialise it. That initialisation should be moved to a new set_up() function. */ - mutable Array<3,float> weights; + mutable Array<3, float> weights; //! Filename for the \f$\kappa\f$ image that will be read by post_processing() - std::string kappa_filename; //CHECK IF THERE IS A CONFILCT WHEN GIVING A KAPPA FILE...// THINK IF IT IS BETTER TO ESTIMATE KAPPA FILE IN THE CODE... + std::string kappa_filename; // CHECK IF THERE IS A CONFILCT WHEN GIVING A KAPPA FILE...// THINK IF IT IS BETTER TO ESTIMATE + // KAPPA FILE IN THE CODE... //! Check that the prior is ready to be used - virtual void check(DiscretisedDensity<3,elemT> const& current_image_estimate) const; + virtual void check(DiscretisedDensity<3, elemT> const& current_image_estimate) const; virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - }; - END_NAMESPACE_STIR #endif - diff --git a/src/include/stir_experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.h b/src/include/stir_experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.h index 15cca6baf6..0fe93ebcbc 100644 --- a/src/include/stir_experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.h +++ b/src/include/stir_experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.h @@ -35,11 +35,11 @@ #include "stir/DynamicDiscretisedDensity.h" START_NAMESPACE_STIR -// ChT::ToDo: If this class appears to be useful I have to define some of the functions that are not specifically defined, yet. +// ChT::ToDo: If this class appears to be useful I have to define some of the functions that are not specifically defined, yet. /*! \ingroup GeneralisedObjectiveFunction - \brief a base class for LogLikelihood of independent Poisson variables + \brief a base class for LogLikelihood of independent Poisson variables where the mean values are linear combinations of the frames. \par Parameters for parsing @@ -47,22 +47,20 @@ START_NAMESPACE_STIR */ template -class PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData: -public RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > -{ - private: - typedef RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > base_type; - typedef PoissonLogLikelihoodWithLinearModelForMeanAndProjData > SingleFrameObjFunc ; +class PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData + : public RegisteredParsingObject, + GeneralisedObjectiveFunction, PoissonLogLikelihoodWithLinearModelForMean> { +private: + typedef RegisteredParsingObject, + GeneralisedObjectiveFunction, PoissonLogLikelihoodWithLinearModelForMean> + base_type; + typedef PoissonLogLikelihoodWithLinearModelForMeanAndProjData> SingleFrameObjFunc; VectorWithOffset _single_frame_obj_funcs; - public: - + +public: //! Name which will be used when parsing a GeneralisedObjectiveFunction object - static const char * const registered_name; -#if 0 // ChT::ToDo + static const char* const registered_name; +#if 0 // ChT::ToDo PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData(); //! Returns a pointer to a newly allocated target object (with 0 data). @@ -100,7 +98,7 @@ public RegisteredParsingObject _additive_dyn_proj_data_sptr; /*! the normalisation or/and attenuation data */ @@ -154,14 +152,13 @@ public RegisteredParsingObject class Viewgram; +template +class Viewgram; /*! \brief A very preliminary class that first forward projects, and then smooths the viewgrams */ -class PostsmoothingForwardProjectorByBin : - public - RegisteredParsingObject -{ +class PostsmoothingForwardProjectorByBin + : public RegisteredParsingObject { public: //! Name which will be used when parsing a PostsmoothingForwardProjectorByBin object - static const char * const registered_name; + static const char* const registered_name; //! Default constructor (calls set_defaults()) PostsmoothingForwardProjectorByBin(); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); - - PostsmoothingForwardProjectorByBin( - const shared_ptr& original_forward_projector_ptr, - const VectorWithOffset& tangential_kernel, - const VectorWithOffset& axial_kernel, - const bool smooth_segment_0_axially = false); + PostsmoothingForwardProjectorByBin(const shared_ptr& original_forward_projector_ptr, + const VectorWithOffset& tangential_kernel, + const VectorWithOffset& axial_kernel, const bool smooth_segment_0_axially = false); // Informs on which symmetries the projector handles // It should get data related by at least those symmetries. // Otherwise, a run-time error will occur (unless the derived // class has other behaviour). - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const; - + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const; private: - shared_ptr original_forward_projector_ptr; VectorWithOffset tang_kernel; VectorWithOffset ax_kernel; @@ -77,19 +69,14 @@ class PostsmoothingForwardProjectorByBin : std::vector ax_kernel_double; #ifdef STIR_PROJECTORS_AS_V3 - void actual_forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); + void actual_forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>&, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num); #endif /// Actual forward project where input has already been set. - void actual_forward_project(RelatedViewgrams&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num); - void smooth(Viewgram&, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const; - + void actual_forward_project(RelatedViewgrams&, const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num); + void smooth(Viewgram&, const int min_axial_pos_num, const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) const; virtual void set_defaults(); virtual void initialise_keymap(); diff --git a/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.h b/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.h index 9da5fc078d..f19a6946a0 100644 --- a/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.h +++ b/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.h @@ -4,9 +4,9 @@ \file \ingroup recon_buildblock - \brief ProjMatrixByBinSinglePhoton's definition + \brief ProjMatrixByBinSinglePhoton's definition - \author Kris + \author Kris */ /* @@ -22,15 +22,14 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/shared_ptr.h" - - START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; /*! \ingroup recon_buildblock - \brief a 'projection matrix' to implement a model for a single + \brief a 'projection matrix' to implement a model for a single photon acquisition in terms of the detector efficiencies. \todo This is a horrible work-around for the fact that STIR currently @@ -38,49 +37,35 @@ template class DiscretisedDensity; */ -class ProjMatrixByBinSinglePhoton : - public RegisteredParsingObject< - ProjMatrixByBinSinglePhoton, - ProjMatrixByBin, - ProjMatrixByBin - > -{ -public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; +class ProjMatrixByBinSinglePhoton + : public RegisteredParsingObject { +public: + //! Name which will be used when parsing a ProjMatrixByBin object + static const char* const registered_name; //! Default constructor (calls set_defaults()) ProjMatrixByBinSinglePhoton(); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); private: - // explicitly list necessary members for image details (should use an Info object instead) CartesianCoordinate3D min_index; CartesianCoordinate3D max_index; shared_ptr proj_data_info_ptr; + virtual void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const; - virtual void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const; - - virtual void set_defaults(); - virtual void initialise_keymap(); - + virtual void set_defaults(); + virtual void initialise_keymap(); }; END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.h b/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.h index 1973f1637c..0259b21305 100644 --- a/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.h +++ b/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.h @@ -4,9 +4,9 @@ \file \ingroup recon_buildblock - \brief ProjMatrixByBinUsingSolidAngle's definition + \brief ProjMatrixByBinUsingSolidAngle's definition - \author Kris + \author Kris */ /* @@ -22,65 +22,50 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/shared_ptr.h" - - START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; /*! \ingroup recon_buildblock \brief Computes projection matrix elements for VoxelsOnCartesianGrid images - by using a Solid Angle model. + by using a Solid Angle model. */ -class ProjMatrixByBinUsingSolidAngle : - public RegisteredParsingObject< - ProjMatrixByBinUsingSolidAngle, - ProjMatrixByBin, - ProjMatrixByBin - > -{ -public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; +class ProjMatrixByBinUsingSolidAngle + : public RegisteredParsingObject { +public: + //! Name which will be used when parsing a ProjMatrixByBin object + static const char* const registered_name; //! Default constructor (calls set_defaults()) ProjMatrixByBinUsingSolidAngle(); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); private: - // explicitly list necessary members for image details (should use an Info object instead) // ideally these should be const, but I have some trouble initialising them in that case CartesianCoordinate3D voxel_size; - CartesianCoordinate3D origin; + CartesianCoordinate3D origin; CartesianCoordinate3D min_index; CartesianCoordinate3D max_index; shared_ptr proj_data_info_ptr; + virtual void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const; - virtual void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const; - - virtual void set_defaults(); - virtual void initialise_keymap(); - + virtual void set_defaults(); + virtual void initialise_keymap(); }; END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.h b/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.h index 7e76eb2dcd..999573b7b5 100644 --- a/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.h +++ b/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.h @@ -4,9 +4,9 @@ \file \ingroup recon_buildblock - \brief ProjMatrixByBinWithPositronRange's definition + \brief ProjMatrixByBinWithPositronRange's definition - \author Kris + \author Kris */ /* @@ -22,47 +22,39 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/shared_ptr.h" - - START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; /*! \ingroup recon_buildblock \brief Computes projection matrix elements for VoxelsOnCartesianGrid images - by using a Solid Angle model. + by using a Solid Angle model. */ -class ProjMatrixByBinWithPositronRange : - public RegisteredParsingObject< - ProjMatrixByBinWithPositronRange, - ProjMatrixByBin, - ProjMatrixByBin - > -{ -public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; +class ProjMatrixByBinWithPositronRange + : public RegisteredParsingObject { +public: + //! Name which will be used when parsing a ProjMatrixByBin object + static const char* const registered_name; //! Default constructor (calls set_defaults()) ProjMatrixByBinWithPositronRange(); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); private: - // explicitly list necessary members for image details (should use an Info object instead) // ideally these should be const, but I have some trouble initialising them in that case CartesianCoordinate3D voxel_size; - CartesianCoordinate3D origin; + CartesianCoordinate3D origin; CartesianCoordinate3D min_index; CartesianCoordinate3D max_index; @@ -73,23 +65,15 @@ public : int positron_range_zoom; int positron_num_samples; - shared_ptr proj_data_info_ptr; + virtual void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const; - virtual void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const; - - virtual void set_defaults(); - virtual void initialise_keymap(); - virtual bool post_processing(); - + virtual void set_defaults(); + virtual void initialise_keymap(); + virtual bool post_processing(); }; END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.h b/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.h index a8328383a5..15150f02ae 100644 --- a/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.h +++ b/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.h @@ -7,19 +7,17 @@ /*! \file - \ingroup recon_buildblock + \ingroup recon_buildblock \brief declaration of ProjMatrixByDensel and its helpers classes - + \author Kris Thielemans - + */ /* Copyright (C) 2000- 2011, Hammersmith Imanet Ltd See STIR/LICENSE.txt for details */ - - #include "stir/RegisteredObject.h" #include "stir/recon_buildblock/ProjMatrixElemsForOneDensel.h" #include "stir/recon_buildblock/DataSymmetriesForDensels.h" @@ -30,61 +28,55 @@ // define a local preprocessor symbol to keep code relatively clean #ifdef STIR_NO_MUTABLE -#define STIR_MUTABLE_CONST +# define STIR_MUTABLE_CONST #else -#define STIR_MUTABLE_CONST const +# define STIR_MUTABLE_CONST const #endif START_NAMESPACE_STIR - -//template class RelatedViewgrams; -//class Densel; -template class DiscretisedDensity; + +// template class RelatedViewgrams; +// class Densel; +template +class DiscretisedDensity; /*! \ingroup recon_buildblock -\brief - This is the (abstract) base class for all projection matrices +\brief + This is the (abstract) base class for all projection matrices which are organised by 'Densel'. - This class provides essentially only 2 public members: a method to get a - 'row' of the matrix, and a method to get information on the symmetries. + This class provides essentially only 2 public members: a method to get a + 'row' of the matrix, and a method to get information on the symmetries. Currently, the class provides for some (basic) caching. - This functionality will probably be moved to a new class + This functionality will probably be moved to a new class ProjMatrixByDenselWithCache. (TODO) */ -class ProjMatrixByDensel : public RegisteredObject -{ +class ProjMatrixByDensel : public RegisteredObject { public: - virtual ~ProjMatrixByDensel() {} //! To be called before any calculation is performed /*! Note that get_proj_matrix_elems_for_one_Densel() will expect objects of compatible sizes and other info. */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) = 0; + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) = 0; //! get a pointer to an object encoding all symmetries that are used by this ProjMatrixByDensel virtual const DataSymmetriesForDensels* get_symmetries_ptr() const = 0; - - + //! The main method for getting a column of the matrix. - /*! + /*! The ProjMatrixElemsForOneDensel argument will be overwritten (i.e. data is NOT appended). - + The implementation is inline as it just gets it in - terms of the cached__proj_matrix_elems_for_one_densel or + terms of the cached__proj_matrix_elems_for_one_densel or calculate_proj_matrix_elems_for_one_densel.*/ - inline void - get_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&, - const Densel&) STIR_MUTABLE_CONST; - + inline void get_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&, const Densel&) STIR_MUTABLE_CONST; + #if 0 // TODO /*! \brief Facility to write the 'independent' part of the matrix to file. @@ -94,82 +86,67 @@ class ProjMatrixByDensel : public RegisteredObject */ virtual void write_to_file_by_densel( const char * const file_name_without_extension) const; -#endif +#endif // TODO implement this one at some point ? /* virtual void write_to_file_by_bin( const char * const file_name_without_extension); */ - - //void set_maximum_cache_size(const unsigned long size){;} - void enable_cache(bool v){cache_disabled = !v;} + + // void set_maximum_cache_size(const unsigned long size){;} + void enable_cache(bool v) { cache_disabled = !v; } /* TODO void set_subset_usage(const SubsetInfo&, const int num_access_times); */ - - - -protected: - +protected: //! default ctor (enables caching) - ProjMatrixByDensel(); - + ProjMatrixByDensel(); + /*! \brief This method needs to be implemented in the derived class. - + Densel-coordinates are obtained via the ProjMatrixElemsForOneDensel::get_Densel() method. Note that 'calculate' could just as well mean 'get from file' */ - virtual void - calculate_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& - ) const = 0; - + virtual void calculate_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const = 0; + /////////////////////////////// caching stuff ////////////////////// - bool cache_disabled; + bool cache_disabled; /*! \brief The method that tries to get data from the cache. - + If it succeeds, it overwrites the ProjMatrixElemsForOneDensel parameter and returns Succeeded::yes, otherwise it does not touch the ProjMatrixElemsForOneDensel and returns Succeeded::false. */ - Succeeded get_cached_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& - ) const; - + Succeeded get_cached_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; + //! The method to store data in the cache. - inline void cache_proj_matrix_elems_for_one_densel( const ProjMatrixElemsForOneDensel&) - STIR_MUTABLE_CONST; + inline void cache_proj_matrix_elems_for_one_densel(const ProjMatrixElemsForOneDensel&) STIR_MUTABLE_CONST; private: - typedef unsigned int CacheKey; #ifndef STIR_NO_NAMESPACES - typedef std::map MapProjMatrixElemsForOneDensel; + typedef std::map MapProjMatrixElemsForOneDensel; #else - typedef map MapProjMatrixElemsForOneDensel; - #endif + typedef map MapProjMatrixElemsForOneDensel; +#endif typedef MapProjMatrixElemsForOneDensel::iterator MapProjMatrixElemsForOneDenselIterator; typedef MapProjMatrixElemsForOneDensel::const_iterator const_MapProjMatrixElemsForOneDenselIterator; - - //! collection of ProjMatrixElemsForOneDensel (internal cache ) + + //! collection of ProjMatrixElemsForOneDensel (internal cache ) #ifndef STIR_NO_MUTABLE mutable #endif - MapProjMatrixElemsForOneDensel cache_collection; - + MapProjMatrixElemsForOneDensel cache_collection; + //! create the key for caching inline static CacheKey cache_key(const Densel& Densel); - - }; - - END_NAMESPACE_STIR #include "stir_experimental/recon_buildblock/ProjMatrixByDensel.inl" @@ -177,6 +154,3 @@ END_NAMESPACE_STIR #undef STIR_MUTABLE_CONST #endif // __ProjMatrixByDensel_H__ - - - diff --git a/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.inl b/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.inl index 8a94893542..e2281f6dd5 100644 --- a/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.inl +++ b/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.inl @@ -20,79 +20,64 @@ START_NAMESPACE_STIR -void ProjMatrixByDensel:: -get_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probabilities, - const Densel& densel) STIR_MUTABLE_CONST -{ +void +ProjMatrixByDensel::get_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel& probabilities, + const Densel& densel) STIR_MUTABLE_CONST { // set to empty probabilities.erase(); - // find basic densel Densel basic_densel = densel; - - unique_ptr symm_ptr = - get_symmetries_ptr()->find_symmetry_operation_from_basic_densel(basic_densel); - + + unique_ptr symm_ptr = get_symmetries_ptr()->find_symmetry_operation_from_basic_densel(basic_densel); + probabilities.set_densel(basic_densel); - // check if in cache - if (get_cached_proj_matrix_elems_for_one_densel(probabilities) == - Succeeded::no) - + // check if in cache + if (get_cached_proj_matrix_elems_for_one_densel(probabilities) == Succeeded::no) + { // call 'calculate' just for the basic densel calculate_proj_matrix_elems_for_one_densel(probabilities); #ifndef NDEBUG probabilities.check_state(); #endif - cache_proj_matrix_elems_for_one_densel(probabilities); - } - + cache_proj_matrix_elems_for_one_densel(probabilities); + } + // now transform to original densel - symm_ptr->transform_proj_matrix_elems_for_one_densel(probabilities); - + symm_ptr->transform_proj_matrix_elems_for_one_densel(probabilities); } /*! -\warning Preconditions: +\warning Preconditions:
    • all coordinates non-negative
    • segment_num coded in 8 bits
    • view coded in 10 bits
    • axial_pos_num in 6 bits -
    • tangential_pos_num in 8 bits +
    • tangential_pos_num in 8 bits
    */ ProjMatrixByDensel::CacheKey -ProjMatrixByDensel::cache_key(const Densel& densel) -{ +ProjMatrixByDensel::cache_key(const Densel& densel) { assert(densel[1] >= 0); - assert(densel[1] < (1<<10)); + assert(densel[1] < (1 << 10)); assert(densel[2] >= 0); - assert(densel[2] < (1<<10)); + assert(densel[2] < (1 << 10)); assert(densel[3] >= 0); - assert(densel[3] < (1<<10)); - return (CacheKey)( - (static_cast(densel[1])<< 20) - | (static_cast(densel[2]) << 10) - | (static_cast(densel[3])) ); -} - - - -//! insert matrix elements for one densel into the cache collection -void -ProjMatrixByDensel:: -cache_proj_matrix_elems_for_one_densel( - const ProjMatrixElemsForOneDensel& probabilities) STIR_MUTABLE_CONST -{ - if ( cache_disabled ) return; - - // insert probabilities into the collection - cache_collection.insert(MapProjMatrixElemsForOneDensel::value_type( cache_key(probabilities.get_densel()), probabilities)); - + assert(densel[3] < (1 << 10)); + return (CacheKey)((static_cast(densel[1]) << 20) | (static_cast(densel[2]) << 10) | + (static_cast(densel[3]))); } +//! insert matrix elements for one densel into the cache collection +void +ProjMatrixByDensel::cache_proj_matrix_elems_for_one_densel(const ProjMatrixElemsForOneDensel& probabilities) STIR_MUTABLE_CONST { + if (cache_disabled) + return; + + // insert probabilities into the collection + cache_collection.insert(MapProjMatrixElemsForOneDensel::value_type(cache_key(probabilities.get_densel()), probabilities)); +} END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/recon_buildblock/ProjMatrixByDenselOnCartesianGridUsingElement.h b/src/include/stir_experimental/recon_buildblock/ProjMatrixByDenselOnCartesianGridUsingElement.h index 47baf865db..f17347df35 100644 --- a/src/include/stir_experimental/recon_buildblock/ProjMatrixByDenselOnCartesianGridUsingElement.h +++ b/src/include/stir_experimental/recon_buildblock/ProjMatrixByDenselOnCartesianGridUsingElement.h @@ -4,7 +4,7 @@ \file \ingroup recon_buildblock - \brief ProjMatrixByDenselOnCartesianGridUsingElement's definition + \brief ProjMatrixByDenselOnCartesianGridUsingElement's definition \author Kris Thielemans @@ -21,54 +21,49 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/shared_ptr.h" - - START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; /*! \ingroup recon_buildblock \brief Computes projection matrix elements for VoxelsOnCartesianGrid images - by using a Length of Intersection (LOI) model. + by using a Length of Intersection (LOI) model. Currently, the LOIs are divided by voxel_size.x(), unless NEWSCALE is - #defined during compilation time of ProjMatrixByDenselOnCartesianGridUsingElement.cxx. + #defined during compilation time of ProjMatrixByDenselOnCartesianGridUsingElement.cxx. If the z voxel size is exactly twice the sampling in axial direction, multiple LORs are used, to avoid missing voxels. (TODOdoc describe how). - Currently, a FOV is used which is circular, and is slightly 'inside' the + Currently, a FOV is used which is circular, and is slightly 'inside' the image (i.e. the radius is about 1 voxel smaller than the maximum possible). The implementation uses RayTraceVoxelsOnCartesianGrid(). \warning Only appropriate for VoxelsOnCartesianGrid type of images (otherwise a run-time error occurs). - - \warning Current implementation assumes that x,y voxel sizes are at least as + + \warning Current implementation assumes that x,y voxel sizes are at least as large as the sampling in tangential direction, and that z voxel size is either smaller than or exactly twice the sampling in axial direction of the segments. */ -class ProjMatrixByDenselOnCartesianGridUsingElement : - public ProjMatrixByDensel -{ -public : - +class ProjMatrixByDenselOnCartesianGridUsingElement : public ProjMatrixByDensel { +public: //! Stores necessary geometric info /*! This function \c hsd to be called by any derived class. - Note that the density_info_ptr is not stored in this object. It's only + Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. Currently, the proj_data_info_ptr argument is not used. */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); //! this member computes a single element of the projection matrix /*! \param bin The bin-coordinates specifying the row of the projection matrix @@ -78,39 +73,33 @@ public : Ideally, get_element should be implemented such that tiny elements are truncated to 0, to avoid storing (and using) elements that not really contribute to the result. - + \warning Currently, the densel_ctr has to be in mm and w.r.t. the centre of the scanner. This is a bad idea (it should use dicrete coordinates) and so will change in the future. It's there now for the RT projector to avoid recomputing the coordinates per mm fo revery bin. */ - virtual float - get_element(const Bin& bin, - const CartesianCoordinate3D& densel_ctr) const = 0; + virtual float get_element(const Bin& bin, const CartesianCoordinate3D& densel_ctr) const = 0; + protected: shared_ptr proj_data_info_ptr; // explicitly list necessary members for image details (should use an Info object instead) CartesianCoordinate3D grid_spacing; - CartesianCoordinate3D origin; + CartesianCoordinate3D origin; float min_z_index; float max_z_index; //! Calculates all non-zero elements for a particular densel /*! This implementation uses the get_element() member. It uses a generic - way of finding non-zero elements, which is slow but makes only a + way of finding non-zero elements, which is slow but makes only a few assumptions. TODO more doc. */ - void calculate_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel &) const; - - + void calculate_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const; }; END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir_experimental/recon_buildblock/ProjMatrixByDenselUsingRayTracing.h b/src/include/stir_experimental/recon_buildblock/ProjMatrixByDenselUsingRayTracing.h index e3bb0adef7..4e7f11c777 100644 --- a/src/include/stir_experimental/recon_buildblock/ProjMatrixByDenselUsingRayTracing.h +++ b/src/include/stir_experimental/recon_buildblock/ProjMatrixByDenselUsingRayTracing.h @@ -4,7 +4,7 @@ \file \ingroup recon_buildblock - \brief ProjMatrixByDenselUsingRayTracing's definition + \brief ProjMatrixByDenselUsingRayTracing's definition \author Kris Thielemans @@ -20,64 +20,58 @@ #include "stir_experimental/recon_buildblock/ProjMatrixByDenselOnCartesianGridUsingElement.h" #include "stir/CartesianCoordinate3D.h" - - START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; class DataSymmetriesForDensels_PET_CartesianGrid; /*! \ingroup recon_buildblock \brief Computes projection matrix elements for VoxelsOnCartesianGrid images - by using a Length of Intersection (LOI) model. + by using a Length of Intersection (LOI) model. Currently, the LOIs are divided by voxel_size.x(), unless NEWSCALE is - #defined during compilation time of ProjMatrixByDenselUsingRayTracing.cxx. + #defined during compilation time of ProjMatrixByDenselUsingRayTracing.cxx. If the z voxel size is exactly twice the sampling in axial direction, multiple LORs are used, to avoid missing voxels. (TODOdoc describe how). - Currently, a FOV is used which is circular, and is slightly 'inside' the + Currently, a FOV is used which is circular, and is slightly 'inside' the image (i.e. the radius is about 1 voxel smaller than the maximum possible). The implementation uses RayTraceVoxelsOnCartesianGrid(). \warning Only appropriate for VoxelsOnCartesianGrid type of images (otherwise a run-time error occurs). - - \warning Current implementation assumes that x,y voxel sizes are at least as + + \warning Current implementation assumes that x,y voxel sizes are at least as large as the sampling in tangential direction, and that z voxel size is either smaller than or exactly twice the sampling in axial direction of the segments. */ -class ProjMatrixByDenselUsingRayTracing : - public RegisteredParsingObject< - ProjMatrixByDenselUsingRayTracing, - ProjMatrixByDenselOnCartesianGridUsingElement - > -{ +class ProjMatrixByDenselUsingRayTracing + : public RegisteredParsingObject { typedef ProjMatrixByDenselOnCartesianGridUsingElement base_type; -public : - //! Name which will be used when parsing a ProjMatrixByDensel object - static const char * const registered_name; + +public: + //! Name which will be used when parsing a ProjMatrixByDensel object + static const char* const registered_name; //! Default constructor (calls set_defaults()) ProjMatrixByDenselUsingRayTracing(); //! Stores all necessary geometric info /*! Note that the density_info_ptr is not stored in this object. It's only used to get some info on sizes etc. - */ - virtual void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ); + */ + virtual void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ); - virtual const DataSymmetriesForDensels* get_symmetries_ptr() const; + virtual const DataSymmetriesForDensels* get_symmetries_ptr() const; - virtual float - get_element(const Bin&, const CartesianCoordinate3D&) const; + virtual float get_element(const Bin&, const CartesianCoordinate3D&) const; private: shared_ptr symmetries_ptr; @@ -88,12 +82,12 @@ public : //! variable that determines how many rays will be traced in tangential direction for one bin int num_tangential_LORs; //! variable that determines if interleaved sinogram coordinates are used or not. - bool use_actual_detector_boundaries; + bool use_actual_detector_boundaries; // explicitly list necessary members for image details (should use an Info object instead) // ideally these should be const, but I have some trouble initialising them in that case CartesianCoordinate3D voxel_size; - CartesianCoordinate3D origin; + CartesianCoordinate3D origin; CartesianCoordinate3D min_index; CartesianCoordinate3D max_index; @@ -101,17 +95,11 @@ public : float yhalfsize; float zhalfsize; - - - virtual void set_defaults(); - virtual void initialise_keymap(); - virtual bool post_processing(); - + virtual void set_defaults(); + virtual void initialise_keymap(); + virtual bool post_processing(); }; END_NAMESPACE_STIR #endif - - - diff --git a/src/iterative/KOSMAPOSL/KOSMAPOSL.cxx b/src/iterative/KOSMAPOSL/KOSMAPOSL.cxx index 930e8f8cba..299d6ec231 100644 --- a/src/iterative/KOSMAPOSL/KOSMAPOSL.cxx +++ b/src/iterative/KOSMAPOSL/KOSMAPOSL.cxx @@ -44,9 +44,11 @@ using std::cout; using std::endl; #ifdef STIR_MPI -int stir::distributable_main(int argc, char **argv) +int +stir::distributable_main(int argc, char** argv) #else -int main(int argc, char **argv) +int +main(int argc, char** argv) #endif { @@ -55,23 +57,17 @@ int main(int argc, char **argv) HighResWallClockTimer t; t.reset(); t.start(); - - KOSMAPOSLReconstruction > - reconstruction_object(argc>1?argv[1]:""); - - //return reconstruction_object.reconstruct() == Succeeded::yes ? - // EXIT_SUCCESS : EXIT_FAILURE; - if (reconstruction_object.reconstruct() == Succeeded::yes) - { - t.stop(); - cout << "Total Wall clock time: " << t.value() << " seconds" << endl; - return EXIT_SUCCESS; - } - else - { - t.stop(); - return EXIT_FAILURE; - } - + KOSMAPOSLReconstruction> reconstruction_object(argc > 1 ? argv[1] : ""); + + // return reconstruction_object.reconstruct() == Succeeded::yes ? + // EXIT_SUCCESS : EXIT_FAILURE; + if (reconstruction_object.reconstruct() == Succeeded::yes) { + t.stop(); + cout << "Total Wall clock time: " << t.value() << " seconds" << endl; + return EXIT_SUCCESS; + } else { + t.stop(); + return EXIT_FAILURE; + } } diff --git a/src/iterative/KOSMAPOSL/KOSMAPOSLReconstruction.cxx b/src/iterative/KOSMAPOSL/KOSMAPOSLReconstruction.cxx index 5b5ce610e8..7870691c90 100644 --- a/src/iterative/KOSMAPOSL/KOSMAPOSLReconstruction.cxx +++ b/src/iterative/KOSMAPOSL/KOSMAPOSLReconstruction.cxx @@ -31,7 +31,7 @@ \author Ashley Gillman \author Palak Wadhwa \author Kris Thielemans - + */ #include "stir/KOSMAPOSL/KOSMAPOSLReconstruction.h" @@ -61,14 +61,14 @@ #include #ifdef STIR_OPENMP -#include +# include #endif #include "stir/num_threads.h" #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif #include "stir/unique_ptr.h" @@ -85,26 +85,21 @@ using std::endl; START_NAMESPACE_STIR - // worker functions - namespace { // priave namespace for internal functions -inline unsigned int ravel_index(int x, int y, int z, - int min_x, int min_y, int min_z, - int max_x, int max_y, int max_z) { - unsigned int ravelled_index= - (z-min_z)*(max_x-min_x +1)*(max_y-min_y +1) - + (y-min_y)*(max_x-min_x +1) - + (x-min_x); - return ravelled_index; - } - +inline unsigned int +ravel_index(int x, int y, int z, int min_x, int min_y, int min_z, int max_x, int max_y, int max_z) { + unsigned int ravelled_index = + (z - min_z) * (max_x - min_x + 1) * (max_y - min_y + 1) + (y - min_y) * (max_x - min_x + 1) + (x - min_x); + return ravelled_index; +} -inline double gaussian_kernel_already_sq(double distance_sq) { +inline double +gaussian_kernel_already_sq(double distance_sq) { // std::cout << "gaussian_kernel(" << distance_sq << ", " << sigma << ")" << std::endl; - return exp(-distance_sq ); + return exp(-distance_sq); } inline void @@ -114,225 +109,190 @@ precalculate_patch_euclidean_distances(Array<3, float>& distance, int num_neighb if (only_2D) { min_dz = max_dz = 0; + } else { + min_dz = -(num_neighbours - 1) / 2; + max_dz = (num_neighbours - 1) / 2; } - else { - min_dz = -(num_neighbours-1)/2; - max_dz = (num_neighbours-1)/2; - } - min_dy = -(num_neighbours-1)/2; - max_dy = (num_neighbours-1)/2; - min_dx = -(num_neighbours-1)/2; - max_dx = (num_neighbours-1)/2; + min_dy = -(num_neighbours - 1) / 2; + max_dy = (num_neighbours - 1) / 2; + min_dx = -(num_neighbours - 1) / 2; + max_dx = (num_neighbours - 1) / 2; - distance = - Array<3,float>(IndexRange3D(min_dz, max_dz, min_dy, max_dy, min_dx, max_dx)); + distance = Array<3, float>(IndexRange3D(min_dz, max_dz, min_dy, max_dy, min_dx, max_dx)); - for (int z=min_dz; z<=max_dz; ++z) { - for (int y=min_dy; y<=max_dy; ++y) { - for (int x=min_dx; x<=max_dx; ++x) { + for (int z = min_dz; z <= max_dz; ++z) { + for (int y = min_dy; y <= max_dy; ++y) { + for (int x = min_dx; x <= max_dx; ++x) { distance[z][y][x] = - sqrt(square(x * grid_spacing.x()) - + square(y * grid_spacing.y()) - + square(z * grid_spacing.z()))/grid_spacing.x(); + sqrt(square(x * grid_spacing.x()) + square(y * grid_spacing.y()) + square(z * grid_spacing.z())) / grid_spacing.x(); } } } -}} +} +} // namespace template -const char * const -KOSMAPOSLReconstruction ::registered_name = - "KOSMAPOSL"; +const char* const KOSMAPOSLReconstruction::registered_name = "KOSMAPOSL"; //*********** parameters *********** template void -KOSMAPOSLReconstruction:: -set_defaults() -{ +KOSMAPOSLReconstruction::set_defaults() { base_type::set_defaults(); this->sigma_m.clear(); this->anatomical_image_filenames.clear(); this->anatomical_prior_sptrs.clear(); - - this->num_neighbours=3; - this->num_non_zero_feat=1; -// this->sigma_m.push_back(1); -// this->anatomical_image_filenames.push_back(""); - this->sigma_p=1; - this->sigma_dp=1; - this->sigma_dm=1; + + this->num_neighbours = 3; + this->num_non_zero_feat = 1; + // this->sigma_m.push_back(1); + // this->anatomical_image_filenames.push_back(""); + this->sigma_p = 1; + this->sigma_dp = 1; + this->sigma_dm = 1; this->only_2D = 0; - this->kernelised_output_filename_prefix=""; - this->hybrid=0; + this->kernelised_output_filename_prefix = ""; + this->hybrid = 0; } template void -KOSMAPOSLReconstruction:: -initialise_keymap() -{ +KOSMAPOSLReconstruction::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("KOSMAPOSLParameters"); this->parser.add_stop_key("End KOSMAPOSLParameters"); -// this->parser.add_key("anatomical image filename",&this->anatomical_image_filenames); - this->parser.add_key("number of neighbours",&this->num_neighbours); - this->parser.add_key("number of non-zero feature elements",&this->num_non_zero_feat); - this->parser.add_key("sigma_m",&this->sigma_m); - this->parser.add_key("sigma_p",&this->sigma_p); - this->parser.add_key("sigma_dp",&this->sigma_dp); - this->parser.add_key("sigma_dm",&this->sigma_dm); - this->parser.add_key("only_2D",&this->only_2D); - this->parser.add_key("hybrid",&this->hybrid); + // this->parser.add_key("anatomical image filename",&this->anatomical_image_filenames); + this->parser.add_key("number of neighbours", &this->num_neighbours); + this->parser.add_key("number of non-zero feature elements", &this->num_non_zero_feat); + this->parser.add_key("sigma_m", &this->sigma_m); + this->parser.add_key("sigma_p", &this->sigma_p); + this->parser.add_key("sigma_dp", &this->sigma_dp); + this->parser.add_key("sigma_dm", &this->sigma_dm); + this->parser.add_key("only_2D", &this->only_2D); + this->parser.add_key("hybrid", &this->hybrid); this->parser.add_key("anatomical image filenames", &anatomical_image_filenames); - this->parser.add_key("kernelised output filename prefix",&this->kernelised_output_filename_prefix); + this->parser.add_key("kernelised output filename prefix", &this->kernelised_output_filename_prefix); } - template -void KOSMAPOSLReconstruction:: -ask_parameters() -{ - OSMAPOSLReconstruction::ask_parameters(); - - +void +KOSMAPOSLReconstruction::ask_parameters() { + OSMAPOSLReconstruction::ask_parameters(); } - template -bool KOSMAPOSLReconstruction:: -post_processing() -{ +bool +KOSMAPOSLReconstruction::post_processing() { if (base_type::post_processing()) return true; - - if (this->anatomical_image_filenames.size()!=sigma_m.size()){ - error("The number of sigma_m parameters must be the same as the number of anatomical image filenames"); - return false; + + if (this->anatomical_image_filenames.size() != sigma_m.size()) { + error("The number of sigma_m parameters must be the same as the number of anatomical image filenames"); + return false; } - for(unsigned int i = 0; i < this->anatomical_image_filenames.size(); i++) - { - info(boost::format("Reading anatomical data '%1%'") - % anatomical_image_filenames[i] ); - set_anatomical_prior_sptr (shared_ptr(read_from_file(anatomical_image_filenames[i])),i); - - if (is_null_ptr(this->anatomical_prior_sptrs[i])) - { - error("Failed to read anatomical file %s", anatomical_image_filenames[i].c_str()); - return false; - } + for (unsigned int i = 0; i < this->anatomical_image_filenames.size(); i++) { + info(boost::format("Reading anatomical data '%1%'") % anatomical_image_filenames[i]); + set_anatomical_prior_sptr(shared_ptr(read_from_file(anatomical_image_filenames[i])), i); + + if (is_null_ptr(this->anatomical_prior_sptrs[i])) { + error("Failed to read anatomical file %s", anatomical_image_filenames[i].c_str()); + return false; } + } return false; } //*********** other functions *********** - - template -KOSMAPOSLReconstruction:: -KOSMAPOSLReconstruction() -{ +KOSMAPOSLReconstruction::KOSMAPOSLReconstruction() { set_defaults(); } template -KOSMAPOSLReconstruction:: -KOSMAPOSLReconstruction(const std::string& parameter_filename) -{ +KOSMAPOSLReconstruction::KOSMAPOSLReconstruction(const std::string& parameter_filename) { this->initialise(parameter_filename); info(this->parameter_info()); } - template -Succeeded -KOSMAPOSLReconstruction:: -set_up(shared_ptr const& target_image_sptr) -{ - - if (base_type::set_up(target_image_sptr) == Succeeded::no) - error("KOSMAPOSL::set_up(): Error setting-up underlying OSMAPOSLReconstruction object"); - - if ((this->anatomical_prior_sptrs.size()==0) && - (this->hybrid==0)) - error("KOSMAPOSL::set_up(): anatomical image has not been set"); - - this->subiteration_counter=0; - - if (this->anatomical_prior_sptrs.size()!=sigma_m.size()){ - error("The number of sigma_m parameters must be the same as the number of anatomical images"); - } - - for(unsigned int i = 0; i < this->anatomical_prior_sptrs.size(); i++) - { - if (is_null_ptr(anatomical_prior_sptrs[i])) - error("Not all the anatomical prior images have been set"); - } - if(!this->only_2D){ - this->num_elem_neighbourhood=this->num_neighbours*this->num_neighbours*this->num_neighbours ;} - else{ - this->num_elem_neighbourhood=this->num_neighbours*this->num_neighbours ; - } - - (*target_image_sptr).get_regular_range(min_ind, max_ind); - const int min_z = min_ind[1]; - const int max_z = max_ind[1]; - this->dimz = max_z -min_z+1; - const int min_y = min_ind[2]; - const int max_y = max_ind[2]; - this->dimy = max_y -min_y+1; - const int min_x = min_ind[3]; - const int max_x = max_ind[3]; - this->dimx = max_x -min_x +1; - this->num_voxels = dimz*dimy*dimx; - - if(this->anatomical_prior_sptrs.size()!=0){ - estimate_stand_dev_for_anatomical_image(this->anatomical_sd); - info(boost::format("Kernel from anatomical image calculated "));} - else - info(boost::format("Kernel will be calculated only from functional image ")); - - for(unsigned int i = 0; i < this->anatomical_prior_sptrs.size(); i++) - { - info(boost::format("SDs from anatomical images calculated = '%1%'") - % this->anatomical_sd[i]); - } - - const DiscretisedDensityOnCartesianGrid<3,float>* current_anatomical_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,float> *> - (target_image_sptr.get()); - - // TODO - which spacing to use? Need both? - const CartesianCoordinate3D& grid_spacing = - current_anatomical_cast->get_grid_spacing(); - precalculate_patch_euclidean_distances(distance,num_neighbours, only_2D, grid_spacing); - - if(num_non_zero_feat>1){ - this->kmnorm_sptrs.resize(anatomical_sd.size()); - for(unsigned int i = 0; i < this->anatomical_prior_sptrs.size(); i++){ - this->kmnorm_sptrs[i].reset(target_image_sptr->get_empty_copy ()); - this->kmnorm_sptrs[i]->resize(IndexRange3D(0,0,0,this->num_voxels-1,0,this->num_elem_neighbourhood-1)); - } - - this->kpnorm_sptr= shared_ptr(target_image_sptr->get_empty_copy ()); - this->kpnorm_sptr->resize(IndexRange3D(0,0,0,this->num_voxels-1,0,this->num_elem_neighbourhood-1)); - - int dimf_col = this->num_non_zero_feat-1; - int dimf_row=this->num_voxels; - - if (this->anatomical_prior_sptrs.size()!=0){ - calculate_norm_const_matrix(this->kmnorm_sptrs, - dimf_row, - dimf_col); - } - } +Succeeded +KOSMAPOSLReconstruction::set_up(shared_ptr const& target_image_sptr) { + + if (base_type::set_up(target_image_sptr) == Succeeded::no) + error("KOSMAPOSL::set_up(): Error setting-up underlying OSMAPOSLReconstruction object"); + + if ((this->anatomical_prior_sptrs.size() == 0) && (this->hybrid == 0)) + error("KOSMAPOSL::set_up(): anatomical image has not been set"); + + this->subiteration_counter = 0; + + if (this->anatomical_prior_sptrs.size() != sigma_m.size()) { + error("The number of sigma_m parameters must be the same as the number of anatomical images"); + } + + for (unsigned int i = 0; i < this->anatomical_prior_sptrs.size(); i++) { + if (is_null_ptr(anatomical_prior_sptrs[i])) + error("Not all the anatomical prior images have been set"); + } + if (!this->only_2D) { + this->num_elem_neighbourhood = this->num_neighbours * this->num_neighbours * this->num_neighbours; + } else { + this->num_elem_neighbourhood = this->num_neighbours * this->num_neighbours; + } + + (*target_image_sptr).get_regular_range(min_ind, max_ind); + const int min_z = min_ind[1]; + const int max_z = max_ind[1]; + this->dimz = max_z - min_z + 1; + const int min_y = min_ind[2]; + const int max_y = max_ind[2]; + this->dimy = max_y - min_y + 1; + const int min_x = min_ind[3]; + const int max_x = max_ind[3]; + this->dimx = max_x - min_x + 1; + this->num_voxels = dimz * dimy * dimx; + + if (this->anatomical_prior_sptrs.size() != 0) { + estimate_stand_dev_for_anatomical_image(this->anatomical_sd); + info(boost::format("Kernel from anatomical image calculated ")); + } else + info(boost::format("Kernel will be calculated only from functional image ")); + + for (unsigned int i = 0; i < this->anatomical_prior_sptrs.size(); i++) { + info(boost::format("SDs from anatomical images calculated = '%1%'") % this->anatomical_sd[i]); + } + + const DiscretisedDensityOnCartesianGrid<3, float>* current_anatomical_cast = + dynamic_cast*>(target_image_sptr.get()); + + // TODO - which spacing to use? Need both? + const CartesianCoordinate3D& grid_spacing = current_anatomical_cast->get_grid_spacing(); + precalculate_patch_euclidean_distances(distance, num_neighbours, only_2D, grid_spacing); + + if (num_non_zero_feat > 1) { + this->kmnorm_sptrs.resize(anatomical_sd.size()); + for (unsigned int i = 0; i < this->anatomical_prior_sptrs.size(); i++) { + this->kmnorm_sptrs[i].reset(target_image_sptr->get_empty_copy()); + this->kmnorm_sptrs[i]->resize(IndexRange3D(0, 0, 0, this->num_voxels - 1, 0, this->num_elem_neighbourhood - 1)); + } + + this->kpnorm_sptr = shared_ptr(target_image_sptr->get_empty_copy()); + this->kpnorm_sptr->resize(IndexRange3D(0, 0, 0, this->num_voxels - 1, 0, this->num_elem_neighbourhood - 1)); + + int dimf_col = this->num_non_zero_feat - 1; + int dimf_row = this->num_voxels; + + if (this->anatomical_prior_sptrs.size() != 0) { + calculate_norm_const_matrix(this->kmnorm_sptrs, dimf_row, dimf_col); + } + } this->_already_set_up = true; - + return Succeeded::yes; } @@ -342,194 +302,167 @@ set_up(shared_ptr const& target_image_sptr) template const std::vector -KOSMAPOSLReconstruction:: -get_anatomical_image_filenames() const -{ return this->anatomical_image_filenames; } +KOSMAPOSLReconstruction::get_anatomical_image_filenames() const { + return this->anatomical_image_filenames; +} template const int -KOSMAPOSLReconstruction:: -get_num_neighbours() const -{ return this->num_neighbours; } +KOSMAPOSLReconstruction::get_num_neighbours() const { + return this->num_neighbours; +} template const int -KOSMAPOSLReconstruction:: -get_num_non_zero_feat() const -{ return this->num_non_zero_feat; } +KOSMAPOSLReconstruction::get_num_non_zero_feat() const { + return this->num_non_zero_feat; +} template const std::vector -KOSMAPOSLReconstruction:: -get_sigma_m() const -{ return this->sigma_m; } +KOSMAPOSLReconstruction::get_sigma_m() const { + return this->sigma_m; +} template const double -KOSMAPOSLReconstruction:: -get_sigma_p() const -{ return this->sigma_p; } +KOSMAPOSLReconstruction::get_sigma_p() const { + return this->sigma_p; +} template const double -KOSMAPOSLReconstruction:: -get_sigma_dp() const -{ return this->sigma_dp; } +KOSMAPOSLReconstruction::get_sigma_dp() const { + return this->sigma_dp; +} template const double -KOSMAPOSLReconstruction:: -get_sigma_dm() const -{ return this->sigma_dm; } +KOSMAPOSLReconstruction::get_sigma_dm() const { + return this->sigma_dm; +} template const bool -KOSMAPOSLReconstruction:: -get_only_2D() const -{ return this->only_2D; } +KOSMAPOSLReconstruction::get_only_2D() const { + return this->only_2D; +} template const bool -KOSMAPOSLReconstruction:: -get_hybrid() const -{ return this->hybrid; } +KOSMAPOSLReconstruction::get_hybrid() const { + return this->hybrid; +} template -std::vector > KOSMAPOSLReconstruction::get_anatomical_prior_sptrs() -{ return this->anatomical_prior_sptrs; } - +std::vector> +KOSMAPOSLReconstruction::get_anatomical_prior_sptrs() { + return this->anatomical_prior_sptrs; +} /*************************************************************** set_ functions ***************************************************************/ - -template +template void -KOSMAPOSLReconstruction:: -set_anatomical_prior_sptr (shared_ptr arg, int index) -{ +KOSMAPOSLReconstruction::set_anatomical_prior_sptr(shared_ptr arg, int index) { this->_already_set_up = false; if (index < this->anatomical_prior_sptrs.size()) - this->anatomical_prior_sptrs.at(index) = arg; - else - this->anatomical_prior_sptrs.push_back(arg); + this->anatomical_prior_sptrs.at(index) = arg; + else + this->anatomical_prior_sptrs.push_back(arg); } -template +template void -KOSMAPOSLReconstruction:: -set_anatomical_prior_sptr (shared_ptr arg) -{ +KOSMAPOSLReconstruction::set_anatomical_prior_sptr(shared_ptr arg) { this->_already_set_up = false; - this->anatomical_prior_sptrs.resize(1); - this->anatomical_prior_sptrs[0] = arg; + this->anatomical_prior_sptrs.resize(1); + this->anatomical_prior_sptrs[0] = arg; } template void -KOSMAPOSLReconstruction:: -set_anatomical_image_filename(const std::string &arg, const int index) -{ +KOSMAPOSLReconstruction::set_anatomical_image_filename(const std::string& arg, const int index) { this->_already_set_up = false; if (static_cast(index) < this->anatomical_image_filenames.size()) - this->anatomical_image_filenames.at(index) = arg; - else - this->anatomical_image_filenames.push_back(arg); - + this->anatomical_image_filenames.at(index) = arg; + else + this->anatomical_image_filenames.push_back(arg); } template void -KOSMAPOSLReconstruction:: -set_anatomical_image_filename(const std::string &arg) -{ +KOSMAPOSLReconstruction::set_anatomical_image_filename(const std::string& arg) { this->_already_set_up = false; - this->anatomical_image_filenames[0] = arg; + this->anatomical_image_filenames[0] = arg; } template void -KOSMAPOSLReconstruction:: -set_num_neighbours(const int arg) -{ +KOSMAPOSLReconstruction::set_num_neighbours(const int arg) { this->_already_set_up = false; this->num_neighbours = arg; } template void -KOSMAPOSLReconstruction:: -set_num_non_zero_feat(const int arg) -{ +KOSMAPOSLReconstruction::set_num_non_zero_feat(const int arg) { this->_already_set_up = false; this->num_non_zero_feat = arg; } template void -KOSMAPOSLReconstruction:: -set_sigma_m(const double arg, const int index) -{ - this->_already_set_up = false; - if (static_cast(index) < this->sigma_m.size()) - this->sigma_m.at(index) = arg; - else - this->sigma_m.push_back(arg); +KOSMAPOSLReconstruction::set_sigma_m(const double arg, const int index) { + this->_already_set_up = false; + if (static_cast(index) < this->sigma_m.size()) + this->sigma_m.at(index) = arg; + else + this->sigma_m.push_back(arg); } template void -KOSMAPOSLReconstruction:: -set_sigma_m(const double arg) -{ - this->_already_set_up = false; - this->sigma_m.resize(1); - this->sigma_m[0] = arg; +KOSMAPOSLReconstruction::set_sigma_m(const double arg) { + this->_already_set_up = false; + this->sigma_m.resize(1); + this->sigma_m[0] = arg; } template void -KOSMAPOSLReconstruction:: -set_sigma_p(const double arg) -{ - this->_already_set_up = false; - this->sigma_p = arg; +KOSMAPOSLReconstruction::set_sigma_p(const double arg) { + this->_already_set_up = false; + this->sigma_p = arg; } template void -KOSMAPOSLReconstruction:: -set_sigma_dp(const double arg) -{ +KOSMAPOSLReconstruction::set_sigma_dp(const double arg) { this->_already_set_up = false; this->sigma_dp = arg; } template void -KOSMAPOSLReconstruction:: -set_sigma_dm(const double arg) -{ +KOSMAPOSLReconstruction::set_sigma_dm(const double arg) { this->_already_set_up = false; this->sigma_dm = arg; } template void -KOSMAPOSLReconstruction:: -set_only_2D(const bool arg) -{ +KOSMAPOSLReconstruction::set_only_2D(const bool arg) { this->_already_set_up = false; this->only_2D = arg; } template void -KOSMAPOSLReconstruction:: -set_hybrid(const bool arg) -{ +KOSMAPOSLReconstruction::set_hybrid(const bool arg) { this->_already_set_up = false; this->hybrid = arg; } @@ -538,20 +471,17 @@ set_hybrid(const bool arg) // Here start the definition of few functions that calculate the SD of the anatomical image, a norm matrix and // finally the Kernelised image -template -void KOSMAPOSLReconstruction:: -calculate_norm_matrix(TargetT &normp, - const int dimf_row, - const int dimf_col, - const TargetT& emission) -{ -// The following is the 2D matrix containing the feature vector for each voxel of the image "emission" - Array<2,float> fp; -// The following are the indexes obtained when reshaping a 3D matrix to a 1D vector and they depend -// on x y and z, and dx dy and dz respectively -// int l=0,m=0; - - fp = Array<2,float>(IndexRange2D(0,dimf_row,0,dimf_col)); +template +void +KOSMAPOSLReconstruction::calculate_norm_matrix(TargetT& normp, const int dimf_row, const int dimf_col, + const TargetT& emission) { + // The following is the 2D matrix containing the feature vector for each voxel of the image "emission" + Array<2, float> fp; + // The following are the indexes obtained when reshaping a 3D matrix to a 1D vector and they depend + // on x y and z, and dx dy and dz respectively + // int l=0,m=0; + + fp = Array<2, float>(IndexRange2D(0, dimf_row, 0, dimf_col)); const int min_z = min_ind[1]; const int max_z = max_ind[1]; @@ -561,595 +491,471 @@ calculate_norm_matrix(TargetT &normp, const int max_x = max_ind[3]; #ifdef STIR_OPENMP -# if _OPENMP <201107 - #pragma omp parallel for +# if _OPENMP < 201107 +# pragma omp parallel for # else - #pragma omp parallel for collapse(3) schedule(dynamic) +# pragma omp parallel for collapse(3) schedule(dynamic) # endif #endif -//The following loop extracts the feature vector related to each voxel in the "emission" image and save it in "fp" - for (int z=min_z; z<=max_z; z++) - { - for (int y=min_y;y<= max_y;y++) - { - for (int x=min_x;x<= max_x;x++) - { - const int min_dz = max(distance.get_min_index(), min_z-z); - const int max_dz = min(distance.get_max_index(), max_z-z); - const int min_dy = max(distance[0].get_min_index(), min_y-y); - const int max_dy = min(distance[0].get_max_index(), max_y-y); - - const int min_dx = max(distance[0][0].get_min_index(), min_x-x); - const int max_dx = min(distance[0][0].get_max_index(), max_x-x); - - - int l = (z-min_z)*(max_x-min_x +1)*(max_y-min_y +1) - + (y-min_y)*(max_x-min_x +1) + (x-min_x); - - //here a matrix with the feature vectors is created - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { - int m = (dz)*(max_dx-min_dx +1)*(max_dy-min_dy +1) - + (dy)*(max_dx-min_dx +1) - + (dx); - int c = m; - - if(m<0){ - c = m+this->num_elem_neighbourhood ; - } else { - c=m; - } - - if ( z+dz > max_z || y+dy> max_y || x+dx > max_x - || z+dz < min_z || y+dy< min_y || x+dx < min_x - || m > this->num_non_zero_feat-1 || m <0) { - continue; - } - else{ - fp[l][c] = (emission[z+dz][y+dy][x+dx]) ; - } - } + // The following loop extracts the feature vector related to each voxel in the "emission" image and save it in "fp" + for (int z = min_z; z <= max_z; z++) { + for (int y = min_y; y <= max_y; y++) { + for (int x = min_x; x <= max_x; x++) { + const int min_dz = max(distance.get_min_index(), min_z - z); + const int max_dz = min(distance.get_max_index(), max_z - z); + const int min_dy = max(distance[0].get_min_index(), min_y - y); + const int max_dy = min(distance[0].get_max_index(), max_y - y); + + const int min_dx = max(distance[0][0].get_min_index(), min_x - x); + const int max_dx = min(distance[0][0].get_max_index(), max_x - x); + + int l = (z - min_z) * (max_x - min_x + 1) * (max_y - min_y + 1) + (y - min_y) * (max_x - min_x + 1) + (x - min_x); + + // here a matrix with the feature vectors is created + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { + int m = (dz) * (max_dx - min_dx + 1) * (max_dy - min_dy + 1) + (dy) * (max_dx - min_dx + 1) + (dx); + int c = m; + + if (m < 0) { + c = m + this->num_elem_neighbourhood; + } else { + c = m; + } + + if (z + dz > max_z || y + dy > max_y || x + dx > max_x || z + dz < min_z || y + dy < min_y || x + dx < min_x || + m > this->num_non_zero_feat - 1 || m < 0) { + continue; + } else { + fp[l][c] = (emission[z + dz][y + dy][x + dx]); + } } - } } + } + } // the norms of the difference between feature vectors related to the // same neighbourhood are calculated now #ifdef STIR_OPENMP -# if _OPENMP <201107 - #pragma omp parallel for +# if _OPENMP < 201107 +# pragma omp parallel for # else - #pragma omp parallel for collapse(3) schedule(dynamic) +# pragma omp parallel for collapse(3) schedule(dynamic) # endif #endif - for (int q=0; q<=dimf_row-1; ++q){ - for (int n=-(this->num_neighbours-1)/2*(!this->only_2D); - n<=(this->num_neighbours-1)/2*(!this->only_2D); - ++n) - for (int k=-(this->num_neighbours-1)/2; - k<=(this->num_neighbours-1)/2; - ++k) - for (int j=-(this->num_neighbours-1)/2; - j<=(this->num_neighbours-1)/2; - ++j) - for (int i=0; i<=dimf_col; ++i) - { - - int p = j - + k*(this->num_neighbours) - + n*(this->num_neighbours)*(this->num_neighbours) - + (this->num_elem_neighbourhood-1)/2; - int o; - - if (q%dimx==0 && (j+k*this->dimx+n*dimx*dimy)>=(dimx-1)) - { - if (j+k*this->dimx+n*dimx*dimy - >= dimx+(this->num_neighbours-1)/2) { - continue; - } - - o=q+j+k*this->dimx+n*dimx*dimy+1; - } - - else{ - o=q+j+k*this->dimx+n*dimx*dimy; - } - - if(o>=dimf_row-1 || o<0 || i<0|| i>this->num_non_zero_feat-1 - || q>=dimf_row-1 || q<0){ + for (int q = 0; q <= dimf_row - 1; ++q) { + for (int n = -(this->num_neighbours - 1) / 2 * (!this->only_2D); n <= (this->num_neighbours - 1) / 2 * (!this->only_2D); ++n) + for (int k = -(this->num_neighbours - 1) / 2; k <= (this->num_neighbours - 1) / 2; ++k) + for (int j = -(this->num_neighbours - 1) / 2; j <= (this->num_neighbours - 1) / 2; ++j) + for (int i = 0; i <= dimf_col; ++i) { + + int p = j + k * (this->num_neighbours) + n * (this->num_neighbours) * (this->num_neighbours) + + (this->num_elem_neighbourhood - 1) / 2; + int o; + + if (q % dimx == 0 && (j + k * this->dimx + n * dimx * dimy) >= (dimx - 1)) { + if (j + k * this->dimx + n * dimx * dimy >= dimx + (this->num_neighbours - 1) / 2) { continue; } - normp[0][q][p] += square(fp[q][i]-fp[o][i]); - } - } -} -template -void KOSMAPOSLReconstruction:: -calculate_norm_const_matrix(std::vector > &normm, - const int dimf_row, - const int dimf_col) -{ - for(unsigned int i=0; i < this->anatomical_prior_sptrs.size();i++){ - calculate_norm_matrix(*normm[i],dimf_row,dimf_col,*(this->anatomical_prior_sptrs[i])); - } + o = q + j + k * this->dimx + n * dimx * dimy + 1; + } + else { + o = q + j + k * this->dimx + n * dimx * dimy; + } + if (o >= dimf_row - 1 || o < 0 || i < 0 || i > this->num_non_zero_feat - 1 || q >= dimf_row - 1 || q < 0) { + continue; + } + normp[0][q][p] += square(fp[q][i] - fp[o][i]); + } + } +} +template +void +KOSMAPOSLReconstruction::calculate_norm_const_matrix(std::vector>& normm, const int dimf_row, + const int dimf_col) { + for (unsigned int i = 0; i < this->anatomical_prior_sptrs.size(); i++) { + calculate_norm_matrix(*normm[i], dimf_row, dimf_col, *(this->anatomical_prior_sptrs[i])); + } } -template -void KOSMAPOSLReconstruction::estimate_stand_dev_for_anatomical_image(std::vector &SD) -{ - SD.resize(this->anatomical_prior_sptrs.size()); - for(unsigned int i=0; i < this->anatomical_prior_sptrs.size();i++){ - - double kmean=0; - double kStand_dev=0; - int nv=0; - - const int min_z = min_ind[1]; - const int max_z = max_ind[1]; - const int min_y = min_ind[2]; - const int max_y = max_ind[2]; - const int min_x = min_ind[3]; - const int max_x = max_ind[3]; +template +void +KOSMAPOSLReconstruction::estimate_stand_dev_for_anatomical_image(std::vector& SD) { + SD.resize(this->anatomical_prior_sptrs.size()); + for (unsigned int i = 0; i < this->anatomical_prior_sptrs.size(); i++) { + + double kmean = 0; + double kStand_dev = 0; + int nv = 0; + + const int min_z = min_ind[1]; + const int max_z = max_ind[1]; + const int min_y = min_ind[2]; + const int max_y = max_ind[2]; + const int min_x = min_ind[3]; + const int max_x = max_ind[3]; #ifdef STIR_OPENMP -# if _OPENMP <201107 - #pragma omp parallel for +# if _OPENMP < 201107 +# pragma omp parallel for # else - #pragma omp parallel for collapse(3) reduction(+:kmean,nv) +# pragma omp parallel for collapse(3) reduction(+ : kmean, nv) # endif #endif - for (int z=min_z; z<=max_z; z++) - { - for (int y=min_y;y<= max_y;y++) - { - for (int x=min_x;x<= max_x;x++) - {// no break allowed inside a parallel for - if(!((*anatomical_prior_sptrs[i])[z][y][x]>=0 && (*anatomical_prior_sptrs[i])[z][y][x]<=1000000)) - warning("The anatomical image might contain nan, negatives or infinitive. You might get all-zero image!"); - - kmean += (*anatomical_prior_sptrs[i])[z][y][x]; - nv+=1; - } - } - } - kmean=kmean / nv; + for (int z = min_z; z <= max_z; z++) { + for (int y = min_y; y <= max_y; y++) { + for (int x = min_x; x <= max_x; x++) { // no break allowed inside a parallel for + if (!((*anatomical_prior_sptrs[i])[z][y][x] >= 0 && (*anatomical_prior_sptrs[i])[z][y][x] <= 1000000)) + warning("The anatomical image might contain nan, negatives or infinitive. You might get all-zero image!"); + + kmean += (*anatomical_prior_sptrs[i])[z][y][x]; + nv += 1; + } + } + } + kmean = kmean / nv; #ifdef STIR_OPENMP -# if _OPENMP <201107 - #pragma omp parallel for +# if _OPENMP < 201107 +# pragma omp parallel for # else - #pragma omp parallel for collapse(3) reduction(+:kStand_dev) +# pragma omp parallel for collapse(3) reduction(+ : kStand_dev) # endif #endif - for (int z=min_z; z<=max_z; z++) - { - for (int y=min_y;y<= max_y;y++) - { - for (int x=min_x;x<= max_x;x++) - { - kStand_dev += square((*anatomical_prior_sptrs[i])[z][y][x] - kmean); - } - } - } - SD[i] = ((double)sqrt(kStand_dev/(nv-1) )); + for (int z = min_z; z <= max_z; z++) { + for (int y = min_y; y <= max_y; y++) { + for (int x = min_x; x <= max_x; x++) { + kStand_dev += square((*anatomical_prior_sptrs[i])[z][y][x] - kmean); + } + } } + SD[i] = ((double)sqrt(kStand_dev / (nv - 1))); + } } -template -void KOSMAPOSLReconstruction::compute_kernelised_image( - TargetT& kernelised_image_out, - const TargetT& image_to_kernelise, - const TargetT& current_alpha_estimate) -{ - - for(unsigned int i=0; i < this->anatomical_prior_sptrs.size();i++){ - if(!current_alpha_estimate.has_same_characteristics(*this->anatomical_prior_sptrs[i])) - error("anatomical and emission image have different sizes! Make sure they are the same"); - } - - bool use_compact_implementation = this->num_non_zero_feat == 1; +template +void +KOSMAPOSLReconstruction::compute_kernelised_image(TargetT& kernelised_image_out, const TargetT& image_to_kernelise, + const TargetT& current_alpha_estimate) { - // Something very weird happens here if I do not get_empty_copy() - // KImage elements will be all nan + for (unsigned int i = 0; i < this->anatomical_prior_sptrs.size(); i++) { + if (!current_alpha_estimate.has_same_characteristics(*this->anatomical_prior_sptrs[i])) + error("anatomical and emission image have different sizes! Make sure they are the same"); + } - unique_ptr kImage_uptr(current_alpha_estimate.get_empty_copy()); + bool use_compact_implementation = this->num_non_zero_feat == 1; - if (!use_compact_implementation && this->get_hybrid()) { - // Going to need the full emission regional normalised differences - int dimf_row = this->num_voxels; - int dimf_col = this->num_non_zero_feat-1; - calculate_norm_matrix(*this->kpnorm_sptr, dimf_row, dimf_col, - current_alpha_estimate); - } + // Something very weird happens here if I do not get_empty_copy() + // KImage elements will be all nan + unique_ptr kImage_uptr(current_alpha_estimate.get_empty_copy()); - // calculate kernelised image - int min_z, max_z, min_y, max_y, min_x, max_x; + if (!use_compact_implementation && this->get_hybrid()) { + // Going to need the full emission regional normalised differences + int dimf_row = this->num_voxels; + int dimf_col = this->num_non_zero_feat - 1; + calculate_norm_matrix(*this->kpnorm_sptr, dimf_row, dimf_col, current_alpha_estimate); + } - min_z = current_alpha_estimate.get_min_index(); - max_z = current_alpha_estimate.get_max_index(); - min_y = current_alpha_estimate[min_z].get_min_index(); - max_y = current_alpha_estimate[min_z].get_max_index(); - min_x = current_alpha_estimate[min_z][min_y].get_min_index(); - max_x = current_alpha_estimate[min_z][min_y].get_max_index(); + // calculate kernelised image + int min_z, max_z, min_y, max_y, min_x, max_x; - // Iterate over the image + min_z = current_alpha_estimate.get_min_index(); + max_z = current_alpha_estimate.get_max_index(); + min_y = current_alpha_estimate[min_z].get_min_index(); + max_y = current_alpha_estimate[min_z].get_max_index(); + min_x = current_alpha_estimate[min_z][min_y].get_min_index(); + max_x = current_alpha_estimate[min_z][min_y].get_max_index(); + // Iterate over the image #ifdef STIR_OPENMP -# if _OPENMP <201107 - #pragma omp parallel for +# if _OPENMP < 201107 +# pragma omp parallel for # else - #pragma omp parallel for collapse(3) schedule(dynamic) +# pragma omp parallel for collapse(3) schedule(dynamic) # endif #endif - for (int z=min_z; z<=max_z; z++) { - for (int y=min_y; y<= max_y; y++) { - for (int x=min_x; x<= max_x; x++) { - const int min_dz = max(distance.get_min_index(), min_z-z); - const int max_dz = min(distance.get_max_index(), max_z-z); - const int min_dy = max(distance[0].get_min_index(), min_y-y); - const int max_dy = min(distance[0].get_max_index(), max_y-y); - const int min_dx = max(distance[0][0].get_min_index(), min_x-x); - const int max_dx = min(distance[0][0].get_max_index(), max_x-x); - - // Iterate over the kernel patch, centered at the current voxel - - double kernel_sum = 0; - - for (int dz=min_dz; dz<=max_dz; ++dz) { - for (int dy=min_dy; dy<=max_dy; ++dy) { - for (int dx=min_dx; dx<=max_dx; ++dx) { - - const int current_ravelled_idx - = ravel_index(x, y, z, min_x, min_y, min_z, max_x, max_y, max_z); - const int delta_ravelled_idx - = ravel_index(dx, dy, dz, min_dx, min_dy, min_dz, max_dx, max_dy, max_dz); - -// std::cout << "d " <anatomical_prior_sptrs.size();i++){ - anatomical_kernel = anatomical_kernel * calc_anatomical_kernel((*anatomical_prior_sptrs[i])[z][y][x], - (*anatomical_prior_sptrs[i])[z+dz][y+dy][x+dx], - distance[dz][dy][dx], - use_compact_implementation, - current_ravelled_idx, - delta_ravelled_idx, - i); - } - - const double kernel = anatomical_kernel * emission_kernel; - - kernelised_image_out[z][y][x] - += kernel * image_to_kernelise[z+dz][y+dy][x+dx]; - kernel_sum += kernel; - } - } - } - - if (current_alpha_estimate[z][y][x] == 0) { - continue; + for (int z = min_z; z <= max_z; z++) { + for (int y = min_y; y <= max_y; y++) { + for (int x = min_x; x <= max_x; x++) { + const int min_dz = max(distance.get_min_index(), min_z - z); + const int max_dz = min(distance.get_max_index(), max_z - z); + const int min_dy = max(distance[0].get_min_index(), min_y - y); + const int max_dy = min(distance[0].get_max_index(), max_y - y); + const int min_dx = max(distance[0][0].get_min_index(), min_x - x); + const int max_dx = min(distance[0][0].get_max_index(), max_x - x); + + // Iterate over the kernel patch, centered at the current voxel + + double kernel_sum = 0; + + for (int dz = min_dz; dz <= max_dz; ++dz) { + for (int dy = min_dy; dy <= max_dy; ++dy) { + for (int dx = min_dx; dx <= max_dx; ++dx) { + + const int current_ravelled_idx = ravel_index(x, y, z, min_x, min_y, min_z, max_x, max_y, max_z); + const int delta_ravelled_idx = ravel_index(dx, dy, dz, min_dx, min_dy, min_dz, max_dx, max_dy, max_dz); + + // std::cout << "d " <anatomical_prior_sptrs.size(); i++) { + anatomical_kernel = + anatomical_kernel * calc_anatomical_kernel((*anatomical_prior_sptrs[i])[z][y][x], + (*anatomical_prior_sptrs[i])[z + dz][y + dy][x + dx], + distance[dz][dy][dx], use_compact_implementation, + current_ravelled_idx, delta_ravelled_idx, i); } + const double kernel = anatomical_kernel * emission_kernel; - kernelised_image_out[z][y][x] /= kernel_sum; - } - } - } + kernelised_image_out[z][y][x] += kernel * image_to_kernelise[z + dz][y + dy][x + dx]; + kernel_sum += kernel; + } + } + } + + if (current_alpha_estimate[z][y][x] == 0) { + continue; + } + + kernelised_image_out[z][y][x] /= kernel_sum; + } } + } +} template double -KOSMAPOSLReconstruction:: -calc_emission_kernel(const double current_alpha_estimate_zyx, - const double current_alpha_estimate_zyx_dr, - const double distance_dzdydx, - const bool use_compact_implementation, - const int l, - const int m) { +KOSMAPOSLReconstruction::calc_emission_kernel(const double current_alpha_estimate_zyx, + const double current_alpha_estimate_zyx_dr, const double distance_dzdydx, + const bool use_compact_implementation, const int l, const int m) { const double emission_kernel = - use_compact_implementation - ? calc_kernel_compact(current_alpha_estimate_zyx- - current_alpha_estimate_zyx_dr, - sigma_p*sigma_p, - sigma_dp*sigma_dp, - distance_dzdydx*distance_dzdydx, - current_alpha_estimate_zyx*current_alpha_estimate_zyx) - : calc_kernel_from_precalculated((*kpnorm_sptr)[0][l][m], - sigma_p*sigma_p, - sigma_dp*sigma_dp, - distance_dzdydx*distance_dzdydx, - current_alpha_estimate_zyx*current_alpha_estimate_zyx); - - return emission_kernel; + use_compact_implementation ? calc_kernel_compact(current_alpha_estimate_zyx - current_alpha_estimate_zyx_dr, + sigma_p * sigma_p, sigma_dp * sigma_dp, distance_dzdydx * distance_dzdydx, + current_alpha_estimate_zyx * current_alpha_estimate_zyx) + : calc_kernel_from_precalculated((*kpnorm_sptr)[0][l][m], sigma_p * sigma_p, sigma_dp * sigma_dp, + distance_dzdydx * distance_dzdydx, + current_alpha_estimate_zyx * current_alpha_estimate_zyx); + + return emission_kernel; } template double -KOSMAPOSLReconstruction:: -calc_kernel_from_precalculated(const double precalculated_norm_zxy, - const double sq_sigma_int, - const double sq_sigma_dist, - const double sq_distance_dzdydx, - const double sq_precalc_denom) { +KOSMAPOSLReconstruction::calc_kernel_from_precalculated(const double precalculated_norm_zxy, const double sq_sigma_int, + const double sq_sigma_dist, const double sq_distance_dzdydx, + const double sq_precalc_denom) { - const double norm_distance_sq - = precalculated_norm_zxy/ sq_precalc_denom/sq_sigma_int+ - sq_distance_dzdydx/sq_sigma_dist/2; + const double norm_distance_sq = + precalculated_norm_zxy / sq_precalc_denom / sq_sigma_int + sq_distance_dzdydx / sq_sigma_dist / 2; return gaussian_kernel_already_sq(norm_distance_sq); } template double -KOSMAPOSLReconstruction:: -calc_anatomical_kernel(const double anatomical_prior_zyx, - const double anatomical_prior_zyx_dr, - const double distance_dzdydx, - const bool use_compact_implementation, - const int l, - const int m, - const int index) { +KOSMAPOSLReconstruction::calc_anatomical_kernel(const double anatomical_prior_zyx, const double anatomical_prior_zyx_dr, + const double distance_dzdydx, const bool use_compact_implementation, + const int l, const int m, const int index) { const double anatomical_kernel = - use_compact_implementation - ? calc_kernel_compact(anatomical_prior_zyx- - anatomical_prior_zyx_dr, - sigma_m[index]*sigma_m[index], - sigma_dm*sigma_dm, - distance_dzdydx*distance_dzdydx, - anatomical_sd[index]*anatomical_sd[index]) - : calc_kernel_from_precalculated((*kmnorm_sptrs[index])[0][l][m], - sigma_m[index]*sigma_m[index], - sigma_dm*sigma_dm, - distance_dzdydx*distance_dzdydx, - anatomical_sd[index]*anatomical_sd[index]); + use_compact_implementation + ? calc_kernel_compact(anatomical_prior_zyx - anatomical_prior_zyx_dr, sigma_m[index] * sigma_m[index], + sigma_dm * sigma_dm, distance_dzdydx * distance_dzdydx, + anatomical_sd[index] * anatomical_sd[index]) + : calc_kernel_from_precalculated((*kmnorm_sptrs[index])[0][l][m], sigma_m[index] * sigma_m[index], sigma_dm * sigma_dm, + distance_dzdydx * distance_dzdydx, anatomical_sd[index] * anatomical_sd[index]); return anatomical_kernel; } template double -KOSMAPOSLReconstruction:: -calc_kernel_compact(const double prior_image_zyx_diff, - const double sq_sigma_int, - const double sq_sigma_dist, - const double sq_distance_dzdydx, - const double sq_precalc_denom) { - - const double norm_distance_sq - = ((prior_image_zyx_diff)/sq_precalc_denom/sq_sigma_int)* - ((prior_image_zyx_diff)/2)+ - sq_distance_dzdydx/sq_sigma_dist/2; - - return gaussian_kernel_already_sq(norm_distance_sq); +KOSMAPOSLReconstruction::calc_kernel_compact(const double prior_image_zyx_diff, const double sq_sigma_int, + const double sq_sigma_dist, const double sq_distance_dzdydx, + const double sq_precalc_denom) { + + const double norm_distance_sq = ((prior_image_zyx_diff) / sq_precalc_denom / sq_sigma_int) * ((prior_image_zyx_diff) / 2) + + sq_distance_dzdydx / sq_sigma_dist / 2; + + return gaussian_kernel_already_sq(norm_distance_sq); } template -void -KOSMAPOSLReconstruction:: -update_estimate(TargetT ¤t_alpha_coefficent_image) -{ +void +KOSMAPOSLReconstruction::update_estimate(TargetT& current_alpha_coefficent_image) { this->check(current_alpha_coefficent_image); - // TODO should use something like iterator_traits to figure out the + // TODO should use something like iterator_traits to figure out the // type instead of hard-wiring float static const float small_num = 0.000001F; #ifndef PARALLEL - //CPUTimer subset_timer; - //subset_timer.start(); -#else // PARALLEL + // CPUTimer subset_timer; + // subset_timer.start(); +#else // PARALLEL PTimer timerSubset; timerSubset.Start(); #endif // PARALLEL - + // TODO make member parameter to avoid reallocation all the time - unique_ptr< TargetT > multiplicative_update_image_ptr - (current_alpha_coefficent_image.get_empty_copy()); + unique_ptr multiplicative_update_image_ptr(current_alpha_coefficent_image.get_empty_copy()); - const int subset_num=this->get_subset_num(); + const int subset_num = this->get_subset_num(); info(boost::format("Now processing subset #: %1%") % subset_num); - unique_ptr< TargetT > current_update_image_ptr(current_alpha_coefficent_image.get_empty_copy()); - compute_kernelised_image (*current_update_image_ptr, current_alpha_coefficent_image, current_alpha_coefficent_image); + unique_ptr current_update_image_ptr(current_alpha_coefficent_image.get_empty_copy()); + compute_kernelised_image(*current_update_image_ptr, current_alpha_coefficent_image, current_alpha_coefficent_image); + base_type::compute_sub_gradient_without_penalty_plus_sensitivity(*multiplicative_update_image_ptr, *current_update_image_ptr, + subset_num); + unique_ptr kmultiplicative_update_ptr((*multiplicative_update_image_ptr).get_empty_copy()); + const TargetT& sensitivity = base_type::get_subset_sensitivity(subset_num); - base_type::compute_sub_gradient_without_penalty_plus_sensitivity (*multiplicative_update_image_ptr, - *current_update_image_ptr, - subset_num); - unique_ptr< TargetT > kmultiplicative_update_ptr((*multiplicative_update_image_ptr).get_empty_copy()); + unique_ptr ksens_ptr(sensitivity.get_empty_copy()); - const TargetT& sensitivity = - base_type::get_subset_sensitivity(subset_num); + // apply kernel to the multiplicative update + compute_kernelised_image(*kmultiplicative_update_ptr, *multiplicative_update_image_ptr, current_alpha_coefficent_image); -unique_ptr< TargetT > ksens_ptr(sensitivity.get_empty_copy()); + // divide by subset sensitivity + compute_kernelised_image(*ksens_ptr, sensitivity, current_alpha_coefficent_image); - //apply kernel to the multiplicative update - compute_kernelised_image (*kmultiplicative_update_ptr, *multiplicative_update_image_ptr, current_alpha_coefficent_image); + int count = 0; - // divide by subset sensitivity - compute_kernelised_image (*ksens_ptr, sensitivity, current_alpha_coefficent_image); + // std::cerr <MAP_model << std::endl; - int count = 0; - - //std::cerr <MAP_model << std::endl; - - if (this->objective_function_sptr->prior_is_zero()) - { - divide(kmultiplicative_update_ptr->begin_all(), - kmultiplicative_update_ptr->end_all(), - (*ksens_ptr).begin_all(), - small_num); - - } - else - { - unique_ptr< TargetT > denominator_ptr - (current_alpha_coefficent_image.get_empty_copy()); - - - this->objective_function_sptr-> - get_prior_ptr()->compute_gradient(*denominator_ptr, current_alpha_coefficent_image); - - typename TargetT::full_iterator denominator_iter = denominator_ptr->begin_all(); - const typename TargetT::full_iterator denominator_end = denominator_ptr->end_all(); - typename TargetT::const_full_iterator sensitivity_iter = (*ksens_ptr).begin_all(); - - if(this->MAP_model =="additive" ) - { - // lambda_new = lambda / (p_v + beta*prior_gradient/ num_subsets) * + if (this->objective_function_sptr->prior_is_zero()) { + divide(kmultiplicative_update_ptr->begin_all(), kmultiplicative_update_ptr->end_all(), (*ksens_ptr).begin_all(), small_num); + + } else { + unique_ptr denominator_ptr(current_alpha_coefficent_image.get_empty_copy()); + + this->objective_function_sptr->get_prior_ptr()->compute_gradient(*denominator_ptr, current_alpha_coefficent_image); + + typename TargetT::full_iterator denominator_iter = denominator_ptr->begin_all(); + const typename TargetT::full_iterator denominator_end = denominator_ptr->end_all(); + typename TargetT::const_full_iterator sensitivity_iter = (*ksens_ptr).begin_all(); + + if (this->MAP_model == "additive") { + // lambda_new = lambda / (p_v + beta*prior_gradient/ num_subsets) * + // sum_subset backproj(measured/forwproj(lambda)) + // with p_v = sum_{b in subset} p_bv + // actually, we restrict 1 + beta*prior_gradient/num_subsets/p_v between .1 and 10 + while (denominator_iter != denominator_end) { + *denominator_iter = *denominator_iter / this->get_num_subsets() + (*sensitivity_iter); + // bound denominator between (*sensitivity_iter)/10 and (*sensitivity_iter)*10 + *denominator_iter = std::max(std::min(*denominator_iter, (*sensitivity_iter) * 10), (*sensitivity_iter) / 10); + ++denominator_iter; + ++sensitivity_iter; + } + } else { + if (this->MAP_model == "multiplicative") { + // multiplicative form + // lambda_new = lambda / (p_v*(1 + beta*prior_gradient)) * // sum_subset backproj(measured/forwproj(lambda)) // with p_v = sum_{b in subset} p_bv - // actually, we restrict 1 + beta*prior_gradient/num_subsets/p_v between .1 and 10 - while (denominator_iter != denominator_end) - { - *denominator_iter = *denominator_iter/this->get_num_subsets() + (*sensitivity_iter); - // bound denominator between (*sensitivity_iter)/10 and (*sensitivity_iter)*10 - *denominator_iter = - std::max(std::min(*denominator_iter, (*sensitivity_iter)*10),(*sensitivity_iter)/10); - ++denominator_iter; - ++sensitivity_iter; - } - } - else - { - if(this->MAP_model =="multiplicative" ) - { - // multiplicative form - // lambda_new = lambda / (p_v*(1 + beta*prior_gradient)) * - // sum_subset backproj(measured/forwproj(lambda)) - // with p_v = sum_{b in subset} p_bv - // actually, we restrict 1 + beta*prior_gradient between .1 and 10 - while (denominator_iter != denominator_end) - { - *denominator_iter += 1; - // bound denominator between 1/10 and 1*10 - // TODO code will fail if *denominator_iter is not a float - *denominator_iter = - std::max(std::min(*denominator_iter, 10.F),1/10.F); - *denominator_iter *= (*sensitivity_iter); - ++denominator_iter; - ++sensitivity_iter; - } + // actually, we restrict 1 + beta*prior_gradient between .1 and 10 + while (denominator_iter != denominator_end) { + *denominator_iter += 1; + // bound denominator between 1/10 and 1*10 + // TODO code will fail if *denominator_iter is not a float + *denominator_iter = std::max(std::min(*denominator_iter, 10.F), 1 / 10.F); + *denominator_iter *= (*sensitivity_iter); + ++denominator_iter; + ++sensitivity_iter; } - } - divide(kmultiplicative_update_ptr->begin_all(), - kmultiplicative_update_ptr->end_all(), - denominator_ptr->begin_all(), - small_num); + } } - - info(boost::format("Number of (cancelled) singularities in Sensitivity division: %1%") % count); - - - - if(this->inter_update_filter_interval>0 && - !is_null_ptr(this->inter_update_filter_ptr) && - !(this->subiteration_num%this->inter_update_filter_interval)) - { + divide(kmultiplicative_update_ptr->begin_all(), kmultiplicative_update_ptr->end_all(), denominator_ptr->begin_all(), + small_num); + } + + info(boost::format("Number of (cancelled) singularities in Sensitivity division: %1%") % count); + + if (this->inter_update_filter_interval > 0 && !is_null_ptr(this->inter_update_filter_ptr) && + !(this->subiteration_num % this->inter_update_filter_interval)) { info("Applying inter-update filter"); this->inter_update_filter_ptr->apply(current_alpha_coefficent_image); } - + // KT 17/08/2000 limit update // TODO move below thresholding? - if (this->write_update_image && !this->_disable_output) - { + if (this->write_update_image && !this->_disable_output) { // allocate space for the filename assuming that // we never have more than 10^49 subiterations ... - char * fname = new char[this->output_filename_prefix.size() + 60]; + char* fname = new char[this->output_filename_prefix.size() + 60]; sprintf(fname, "%s_update_%d", this->output_filename_prefix.c_str(), this->subiteration_num); - + // Write it to file - this->output_file_format_ptr-> - write_to_file(fname, *kmultiplicative_update_ptr); + this->output_file_format_ptr->write_to_file(fname, *kmultiplicative_update_ptr); delete[] fname; } - - if (this->subiteration_num != 1) - { - const float current_min = - *std::min_element(kmultiplicative_update_ptr->begin_all(), - kmultiplicative_update_ptr->end_all()); - const float current_max = - *std::max_element(kmultiplicative_update_ptr->begin_all(), - kmultiplicative_update_ptr->end_all()); - const float new_min = - static_cast(this->minimum_relative_change); - const float new_max = - static_cast(this->maximum_relative_change); - info(boost::format("Update image old min,max: %1%, %2%, new min,max %3%, %4%") % current_min % current_max % (min(current_min, new_min)) % (max(current_max, new_max))); - - threshold_upper_lower(kmultiplicative_update_ptr->begin_all(), - kmultiplicative_update_ptr->end_all(), - new_min, new_max); - } - - //current_alpha_coefficent_image *= *kmultiplicative_update_ptr; + + if (this->subiteration_num != 1) { + const float current_min = *std::min_element(kmultiplicative_update_ptr->begin_all(), kmultiplicative_update_ptr->end_all()); + const float current_max = *std::max_element(kmultiplicative_update_ptr->begin_all(), kmultiplicative_update_ptr->end_all()); + const float new_min = static_cast(this->minimum_relative_change); + const float new_max = static_cast(this->maximum_relative_change); + info(boost::format("Update image old min,max: %1%, %2%, new min,max %3%, %4%") % current_min % current_max % + (min(current_min, new_min)) % (max(current_max, new_max))); + + threshold_upper_lower(kmultiplicative_update_ptr->begin_all(), kmultiplicative_update_ptr->end_all(), new_min, new_max); + } + + // current_alpha_coefficent_image *= *kmultiplicative_update_ptr; { typename TargetT::const_full_iterator multiplicative_update_image_iter = kmultiplicative_update_ptr->begin_all_const(); - const typename TargetT::const_full_iterator end_multiplicative_update_image_iter = kmultiplicative_update_ptr->end_all_const(); + const typename TargetT::const_full_iterator end_multiplicative_update_image_iter = + kmultiplicative_update_ptr->end_all_const(); typename TargetT::full_iterator current_alpha_coefficent_image_iter = current_alpha_coefficent_image.begin_all(); - while (multiplicative_update_image_iter!=end_multiplicative_update_image_iter) - { - *current_alpha_coefficent_image_iter *= (*multiplicative_update_image_iter); - ++current_alpha_coefficent_image_iter; ++multiplicative_update_image_iter; - } - + while (multiplicative_update_image_iter != end_multiplicative_update_image_iter) { + *current_alpha_coefficent_image_iter *= (*multiplicative_update_image_iter); + ++current_alpha_coefficent_image_iter; + ++multiplicative_update_image_iter; + } unique_ptr kcurrent_ptr(current_alpha_coefficent_image.get_empty_copy()); // compute the emission image from the alpha coefficient image - compute_kernelised_image (*kcurrent_ptr, current_alpha_coefficent_image,current_alpha_coefficent_image); + compute_kernelised_image(*kcurrent_ptr, current_alpha_coefficent_image, current_alpha_coefficent_image); - //Write the emission image estimate: - if(!(this->subiteration_num % this->save_interval) || // every save_interval'th + // Write the emission image estimate: + if (!(this->subiteration_num % this->save_interval) || // every save_interval'th this->subiteration_num == this->num_subiterations) { // or on last iteration - this->current_kimage_filename = this->make_filename_prefix_subiteration_num( - this->kernelised_output_filename_prefix); - write_to_file(this->current_kimage_filename, *kcurrent_ptr); + this->current_kimage_filename = this->make_filename_prefix_subiteration_num(this->kernelised_output_filename_prefix); + write_to_file(this->current_kimage_filename, *kcurrent_ptr); } } - + #ifndef PARALLEL - //cerr << "Subset : " << subset_timer.value() << "secs " < >; -//template class KOSMAPOSLReconstruction; - +template class KOSMAPOSLReconstruction>; +// template class KOSMAPOSLReconstruction; END_NAMESPACE_STIR - - diff --git a/src/iterative/OSMAPOSL/OSMAPOSL.cxx b/src/iterative/OSMAPOSL/OSMAPOSL.cxx index 13ff863f15..cabfa8b3b5 100644 --- a/src/iterative/OSMAPOSL/OSMAPOSL.cxx +++ b/src/iterative/OSMAPOSL/OSMAPOSL.cxx @@ -39,9 +39,11 @@ using std::cout; using std::endl; #ifdef STIR_MPI -int stir::distributable_main(int argc, char **argv) +int +stir::distributable_main(int argc, char** argv) #else -int main(int argc, char **argv) +int +main(int argc, char** argv) #endif { @@ -50,23 +52,17 @@ int main(int argc, char **argv) HighResWallClockTimer t; t.reset(); t.start(); - - OSMAPOSLReconstruction > - reconstruction_object(argc>1?argv[1]:""); - - //return reconstruction_object.reconstruct() == Succeeded::yes ? - // EXIT_SUCCESS : EXIT_FAILURE; - if (reconstruction_object.reconstruct() == Succeeded::yes) - { - t.stop(); - cout << "Total Wall clock time: " << t.value() << " seconds" << endl; - return EXIT_SUCCESS; - } - else - { - t.stop(); - return EXIT_FAILURE; - } - + OSMAPOSLReconstruction> reconstruction_object(argc > 1 ? argv[1] : ""); + + // return reconstruction_object.reconstruct() == Succeeded::yes ? + // EXIT_SUCCESS : EXIT_FAILURE; + if (reconstruction_object.reconstruct() == Succeeded::yes) { + t.stop(); + cout << "Total Wall clock time: " << t.value() << " seconds" << endl; + return EXIT_SUCCESS; + } else { + t.stop(); + return EXIT_FAILURE; + } } diff --git a/src/iterative/OSMAPOSL/OSMAPOSLReconstruction.cxx b/src/iterative/OSMAPOSL/OSMAPOSLReconstruction.cxx index b42a6942b9..1bce5dc1d2 100644 --- a/src/iterative/OSMAPOSL/OSMAPOSLReconstruction.cxx +++ b/src/iterative/OSMAPOSL/OSMAPOSLReconstruction.cxx @@ -59,9 +59,9 @@ #include #include #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif #include "stir/unique_ptr.h" @@ -73,39 +73,26 @@ using std::cerr; using std::endl; #endif - START_NAMESPACE_STIR template -const char * const -OSMAPOSLReconstruction ::registered_name = - "OSMAPOSL"; +const char* const OSMAPOSLReconstruction::registered_name = "OSMAPOSL"; template -PoissonLogLikelihoodWithLinearModelForMean& -OSMAPOSLReconstruction:: -objective_function() -{ - return - static_cast&> - (*this->objective_function_sptr); +PoissonLogLikelihoodWithLinearModelForMean& +OSMAPOSLReconstruction::objective_function() { + return static_cast&>(*this->objective_function_sptr); } template -PoissonLogLikelihoodWithLinearModelForMean const& -OSMAPOSLReconstruction:: -objective_function() const -{ - return - static_cast&> - (*this->objective_function_sptr); +PoissonLogLikelihoodWithLinearModelForMean const& +OSMAPOSLReconstruction::objective_function() const { + return static_cast&>(*this->objective_function_sptr); } template -PoissonLogLikelihoodWithLinearModelForMean const& -OSMAPOSLReconstruction:: -get_objective_function() const -{ +PoissonLogLikelihoodWithLinearModelForMean const& +OSMAPOSLReconstruction::get_objective_function() const { // just use the above (private) function return this->objective_function(); } @@ -113,10 +100,8 @@ get_objective_function() const //*********** parameters *********** template -void -OSMAPOSLReconstruction:: -set_defaults() -{ +void +OSMAPOSLReconstruction::set_defaults() { base_type::set_defaults(); enforce_initial_positivity = true; maximum_relative_change = NumericInfo().max_value(); @@ -124,82 +109,65 @@ set_defaults() write_update_image = 0; inter_update_filter_interval = 0; inter_update_filter_ptr.reset(); - MAP_model="additive"; + MAP_model = "additive"; } template void -OSMAPOSLReconstruction:: -initialise_keymap() -{ +OSMAPOSLReconstruction::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("OSMAPOSLParameters"); this->parser.add_stop_key("End"); this->parser.add_stop_key("End OSMAPOSLParameters"); - this->parser.add_key("enforce initial positivity condition",&this->enforce_initial_positivity); - this->parser.add_key("inter-update filter subiteration interval",&this->inter_update_filter_interval); + this->parser.add_key("enforce initial positivity condition", &this->enforce_initial_positivity); + this->parser.add_key("inter-update filter subiteration interval", &this->inter_update_filter_interval); this->parser.add_parsing_key("inter-update filter type", &this->inter_update_filter_ptr); this->parser.add_key("MAP_model", &this->MAP_model); this->parser.add_key("maximum relative change", &this->maximum_relative_change); - this->parser.add_key("minimum relative change",&this->minimum_relative_change); - this->parser.add_key("write update image",&this->write_update_image); + this->parser.add_key("minimum relative change", &this->minimum_relative_change); + this->parser.add_key("write update image", &this->write_update_image); } - template -void OSMAPOSLReconstruction:: -ask_parameters() -{ +void +OSMAPOSLReconstruction::ask_parameters() { base_type::ask_parameters(); - enforce_initial_positivity= - ask("Enforce initial positivity condition?",true); - - inter_update_filter_interval= - ask_num("Do inter-update filtering at sub-iteration intervals of: ", - 0, this->num_subiterations, 0); - - if(inter_update_filter_interval>0) - { - - cerr<::list_registered_names(cerr); - + enforce_initial_positivity = ask("Enforce initial positivity condition?", true); + + inter_update_filter_interval = + ask_num("Do inter-update filtering at sub-iteration intervals of: ", 0, this->num_subiterations, 0); + + if (inter_update_filter_interval > 0) { + + cerr << endl << "Supply inter-update filter type:\nPossible values:\n"; + DataProcessor::list_registered_names(cerr); + const std::string inter_update_filter_type = ask_string(""); - - inter_update_filter_ptr.reset(DataProcessor::read_registered_object(0, inter_update_filter_type)); - - } + + inter_update_filter_ptr.reset(DataProcessor::read_registered_object(0, inter_update_filter_type)); + } if (!this->objective_function_sptr->prior_is_zero()) - MAP_model = - ask_string("Use additive or multiplicative form of MAP-OSL ('additive' or 'multiplicative')","additive"); - + MAP_model = ask_string("Use additive or multiplicative form of MAP-OSL ('additive' or 'multiplicative')", "additive"); + // KT 17/08/2000 3 new parameters const double max_in_double = static_cast(NumericInfo().max_value()); - maximum_relative_change = ask_num("maximum relative change", - 1.,max_in_double,max_in_double); - minimum_relative_change = ask_num("minimum relative change", - 0.,1.,0.); - - write_update_image = ask_num("write update image", 0,1,0); + maximum_relative_change = ask_num("maximum relative change", 1., max_in_double, max_in_double); + minimum_relative_change = ask_num("minimum relative change", 0., 1., 0.); + write_update_image = ask_num("write update image", 0, 1, 0); } - - - template -bool OSMAPOSLReconstruction:: -post_processing() -{ +bool +OSMAPOSLReconstruction::post_processing() { if (base_type::post_processing()) return true; - if (!this->objective_function_sptr->prior_is_zero()) - { + if (!this->objective_function_sptr->prior_is_zero()) { // TODO MAP_model really should be an ASCIIlist, without automatic checking on values // let set_MAP_model do the checking this->set_MAP_model(this->MAP_model); @@ -210,79 +178,58 @@ post_processing() //*********** set_ functions *********** template void -OSMAPOSLReconstruction:: -set_inter_update_filter_interval(const int arg) -{ - this->inter_update_filter_interval = arg; +OSMAPOSLReconstruction::set_inter_update_filter_interval(const int arg) { + this->inter_update_filter_interval = arg; } template void -OSMAPOSLReconstruction:: -set_inter_update_filter_ptr(const shared_ptr > & arg) -{ - this->inter_update_filter_ptr = arg; +OSMAPOSLReconstruction::set_inter_update_filter_ptr(const shared_ptr>& arg) { + this->inter_update_filter_ptr = arg; } template void -OSMAPOSLReconstruction:: -set_maximum_relative_change(const double arg) -{ - this->maximum_relative_change = arg; +OSMAPOSLReconstruction::set_maximum_relative_change(const double arg) { + this->maximum_relative_change = arg; } template void -OSMAPOSLReconstruction:: -set_minimum_relative_change(const double arg) -{ - this->minimum_relative_change = arg; +OSMAPOSLReconstruction::set_minimum_relative_change(const double arg) { + this->minimum_relative_change = arg; } - + template void -OSMAPOSLReconstruction:: -set_write_update_image(const int arg) -{ - this->write_update_image = arg; +OSMAPOSLReconstruction::set_write_update_image(const int arg) { + this->write_update_image = arg; } template void -OSMAPOSLReconstruction:: -set_MAP_model(const std::string& arg) -{ - this->MAP_model = arg; +OSMAPOSLReconstruction::set_MAP_model(const std::string& arg) { + this->MAP_model = arg; if (MAP_model != "additive" && MAP_model != "multiplicative") - error(boost::format("MAP model should have as value 'additive' or 'multiplicative', while it is '%s'") % - MAP_model); + error(boost::format("MAP model should have as value 'additive' or 'multiplicative', while it is '%s'") % MAP_model); } //*********** other functions *********** - - template -OSMAPOSLReconstruction:: -OSMAPOSLReconstruction() -{ +OSMAPOSLReconstruction::OSMAPOSLReconstruction() { set_defaults(); } template -OSMAPOSLReconstruction:: -OSMAPOSLReconstruction(const std::string& parameter_filename) -{ +OSMAPOSLReconstruction::OSMAPOSLReconstruction(const std::string& parameter_filename) { this->initialise(parameter_filename); info(this->parameter_info()); } template -std::string -OSMAPOSLReconstruction:: -method_info() const -{ +std::string +OSMAPOSLReconstruction::method_info() const { // TODO add prior name? @@ -294,97 +241,80 @@ method_info() const std::ostringstream s; #endif - if(this->inter_update_filter_interval>0) s<<"IUF-"; - if(this->num_subsets>1) s<<"OS"; + if (this->inter_update_filter_interval > 0) + s << "IUF-"; + if (this->num_subsets > 1) + s << "OS"; if (this->objective_function_sptr->prior_is_zero()) - s<<"EM"; + s << "EM"; else s << "MAPOSL"; - if(this->inter_iteration_filter_interval>0) s<<"S"; + if (this->inter_iteration_filter_interval > 0) + s << "S"; return s.str(); - } template -Succeeded -OSMAPOSLReconstruction:: -set_up(shared_ptr const& target_image_ptr) -{ - // TODO should use something like iterator_traits to figure out the +Succeeded +OSMAPOSLReconstruction::set_up(shared_ptr const& target_image_ptr) { + // TODO should use something like iterator_traits to figure out the // type instead of hard-wiring float static const float small_num = 0.000001F; if (base_type::set_up(target_image_ptr) == Succeeded::no) return Succeeded::no; - if (is_null_ptr(dynamic_cast const *> - (this->objective_function_sptr.get()))) - { error("OSMAPOSL can only work with an objective function of type PoissonLogLikelihoodWithLinearModelForMean"); return Succeeded::no; } + if (is_null_ptr( + dynamic_cast const*>(this->objective_function_sptr.get()))) { + error("OSMAPOSL can only work with an objective function of type PoissonLogLikelihoodWithLinearModelForMean"); + return Succeeded::no; + } // check subset balancing { std::string warning_message = "OSMAPOSL\n"; - if (!this->objective_function().subsets_are_approximately_balanced(warning_message)) - { - error("%s\nOSMAPOSL cannot handle this.", - warning_message.c_str()); - return Succeeded::no; - } + if (!this->objective_function().subsets_are_approximately_balanced(warning_message)) { + error("%s\nOSMAPOSL cannot handle this.", warning_message.c_str()); + return Succeeded::no; + } } // end check balancing + if (this->enforce_initial_positivity) + threshold_min_to_small_positive_value(target_image_ptr->begin_all(), target_image_ptr->end_all(), small_num); - if(this->enforce_initial_positivity) - threshold_min_to_small_positive_value(target_image_ptr->begin_all(), - target_image_ptr->end_all(), - small_num); - - if (this->inter_update_filter_interval<0) - { error("Range error in inter-update filter interval"); return Succeeded::no; } - - if(this->inter_update_filter_interval>0 && - !is_null_ptr(this->inter_update_filter_ptr)) - { - // ensure that the result image of the filter is positive - shared_ptr > - thresholding_sptr(new ThresholdMinToSmallPositiveValueDataProcessor); - this->inter_update_filter_ptr.reset( - new ChainedDataProcessor( - this->inter_update_filter_ptr, - thresholding_sptr)); - // KT 04/06/2003 moved set_up after chaining the filter. Otherwise it would be - // called again later on anyway. - // Note however that at present, - info("Building inter-update filter kernel"); - if (this->inter_update_filter_ptr->set_up(*target_image_ptr) - == Succeeded::no) - { - error("Error building inter-update filter"); - return Succeeded::no; - } + if (this->inter_update_filter_interval < 0) { + error("Range error in inter-update filter interval"); + return Succeeded::no; + } + if (this->inter_update_filter_interval > 0 && !is_null_ptr(this->inter_update_filter_ptr)) { + // ensure that the result image of the filter is positive + shared_ptr> thresholding_sptr( + new ThresholdMinToSmallPositiveValueDataProcessor); + this->inter_update_filter_ptr.reset(new ChainedDataProcessor(this->inter_update_filter_ptr, thresholding_sptr)); + // KT 04/06/2003 moved set_up after chaining the filter. Otherwise it would be + // called again later on anyway. + // Note however that at present, + info("Building inter-update filter kernel"); + if (this->inter_update_filter_ptr->set_up(*target_image_ptr) == Succeeded::no) { + error("Error building inter-update filter"); + return Succeeded::no; } - if (this->inter_iteration_filter_interval>0 && - !is_null_ptr(this->inter_iteration_filter_ptr)) - { - // ensure that the result image of the filter is positive - shared_ptr > - thresholding_sptr(new ThresholdMinToSmallPositiveValueDataProcessor); - this->inter_iteration_filter_ptr.reset( - new ChainedDataProcessor( - this->inter_iteration_filter_ptr, - thresholding_sptr - )); - // KT 04/06/2003 moved set_up after chaining the filter (and removed it from IterativeReconstruction) - info("Building inter-iteration filter kernel"); - if (this->inter_iteration_filter_ptr->set_up(*target_image_ptr) - == Succeeded::no) - { - error("Error building inter iteration filter"); - return Succeeded::no; - } - + } + if (this->inter_iteration_filter_interval > 0 && !is_null_ptr(this->inter_iteration_filter_ptr)) { + // ensure that the result image of the filter is positive + shared_ptr> thresholding_sptr( + new ThresholdMinToSmallPositiveValueDataProcessor); + this->inter_iteration_filter_ptr.reset( + new ChainedDataProcessor(this->inter_iteration_filter_ptr, thresholding_sptr)); + // KT 04/06/2003 moved set_up after chaining the filter (and removed it from IterativeReconstruction) + info("Building inter-iteration filter kernel"); + if (this->inter_iteration_filter_ptr->set_up(*target_image_ptr) == Succeeded::no) { + error("Error building inter iteration filter"); + return Succeeded::no; } + } // initialise mutliplicative update to zeros multiplicative_update_image_ptr = unique_ptr(target_image_ptr->get_empty_copy()); @@ -392,190 +322,148 @@ set_up(shared_ptr const& target_image_ptr) return Succeeded::yes; } - template void -OSMAPOSLReconstruction:: -compute_sub_gradient_without_penalty_plus_sensitivity( - TargetT& gradient, const TargetT& current_estimate, const int subset_num) -{ - this->objective_function().compute_sub_gradient_without_penalty_plus_sensitivity( - gradient, current_estimate, subset_num); +OSMAPOSLReconstruction::compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, + const TargetT& current_estimate, + const int subset_num) { + this->objective_function().compute_sub_gradient_without_penalty_plus_sensitivity(gradient, current_estimate, subset_num); }; - template const TargetT& -OSMAPOSLReconstruction::get_subset_sensitivity(const int subset_num) -{ +OSMAPOSLReconstruction::get_subset_sensitivity(const int subset_num) { return this->objective_function().get_subset_sensitivity(subset_num); }; - template void -OSMAPOSLReconstruction::apply_multiplicative_update( - TargetT& current_image_estimate, const TargetT& multiplicative_update_image) -{ +OSMAPOSLReconstruction::apply_multiplicative_update(TargetT& current_image_estimate, + const TargetT& multiplicative_update_image) { this->check(current_image_estimate); - typename TargetT::const_full_iterator multiplicative_update_image_iter = - multiplicative_update_image.begin_all_const(); - const typename TargetT::const_full_iterator end_multiplicative_update_image_iter = - multiplicative_update_image.end_all_const(); - typename TargetT::full_iterator current_image_estimate_iter = - current_image_estimate.begin_all(); - while (multiplicative_update_image_iter != end_multiplicative_update_image_iter) - { + typename TargetT::const_full_iterator multiplicative_update_image_iter = multiplicative_update_image.begin_all_const(); + const typename TargetT::const_full_iterator end_multiplicative_update_image_iter = multiplicative_update_image.end_all_const(); + typename TargetT::full_iterator current_image_estimate_iter = current_image_estimate.begin_all(); + while (multiplicative_update_image_iter != end_multiplicative_update_image_iter) { *current_image_estimate_iter *= (*multiplicative_update_image_iter); ++current_image_estimate_iter; ++multiplicative_update_image_iter; } } - template -void -OSMAPOSLReconstruction:: -update_estimate(TargetT ¤t_image_estimate) -{ +void +OSMAPOSLReconstruction::update_estimate(TargetT& current_image_estimate) { this->check(current_image_estimate); - // TODO should use something like iterator_traits to figure out the + // TODO should use something like iterator_traits to figure out the // type instead of hard-wiring float static const float small_num = 0.000001F; - + #ifndef PARALLEL - //CPUTimer subset_timer; - //subset_timer.start(); -#else // PARALLEL + // CPUTimer subset_timer; + // subset_timer.start(); +#else // PARALLEL PTimer timerSubset; timerSubset.Start(); #endif // PARALLEL - const int subset_num=this->get_subset_num(); + const int subset_num = this->get_subset_num(); info(boost::format("Now processing subset #: %1%") % subset_num); - this->compute_sub_gradient_without_penalty_plus_sensitivity( - *multiplicative_update_image_ptr, current_image_estimate, subset_num); + this->compute_sub_gradient_without_penalty_plus_sensitivity(*multiplicative_update_image_ptr, current_image_estimate, + subset_num); // divide by subset sensitivity { const TargetT& sensitivity = this->get_subset_sensitivity(subset_num); int count = 0; - - //std::cerr <MAP_model << std::endl; - - if (this->objective_function_sptr->prior_is_zero()) - { - divide(multiplicative_update_image_ptr->begin_all(), - multiplicative_update_image_ptr->end_all(), - sensitivity.begin_all(), + + // std::cerr <MAP_model << std::endl; + + if (this->objective_function_sptr->prior_is_zero()) { + divide(multiplicative_update_image_ptr->begin_all(), multiplicative_update_image_ptr->end_all(), sensitivity.begin_all(), small_num); - } - else - { - unique_ptr< TargetT > denominator_ptr - (current_image_estimate.get_empty_copy()); - - - this->objective_function_sptr-> - get_prior_ptr()->compute_gradient(*denominator_ptr, current_image_estimate); - + } else { + unique_ptr denominator_ptr(current_image_estimate.get_empty_copy()); + + this->objective_function_sptr->get_prior_ptr()->compute_gradient(*denominator_ptr, current_image_estimate); + typename TargetT::full_iterator denominator_iter = denominator_ptr->begin_all(); const typename TargetT::full_iterator denominator_end = denominator_ptr->end_all(); typename TargetT::const_full_iterator sensitivity_iter = sensitivity.begin_all(); - if(this->MAP_model =="additive" ) - { + if (this->MAP_model == "additive") { // lambda_new = lambda / (p_v + beta*prior_gradient/ num_subsets) * // sum_subset backproj(measured/forwproj(lambda)) // with p_v = sum_{b in subset} p_bv // actually, we restrict 1 + beta*prior_gradient/num_subsets/p_v between .1 and 10 - while (denominator_iter != denominator_end) - { - *denominator_iter = *denominator_iter/this->get_num_subsets() + (*sensitivity_iter); - // bound denominator between (*sensitivity_iter)/10 and (*sensitivity_iter)*10 - *denominator_iter = - std::max(std::min(*denominator_iter, (*sensitivity_iter)*10),(*sensitivity_iter)/10); - ++denominator_iter; - ++sensitivity_iter; - } - } - else - { - if(this->MAP_model =="multiplicative" ) - { + while (denominator_iter != denominator_end) { + *denominator_iter = *denominator_iter / this->get_num_subsets() + (*sensitivity_iter); + // bound denominator between (*sensitivity_iter)/10 and (*sensitivity_iter)*10 + *denominator_iter = std::max(std::min(*denominator_iter, (*sensitivity_iter) * 10), (*sensitivity_iter) / 10); + ++denominator_iter; + ++sensitivity_iter; + } + } else { + if (this->MAP_model == "multiplicative") { // multiplicative form // lambda_new = lambda / (p_v*(1 + beta*prior_gradient)) * // sum_subset backproj(measured/forwproj(lambda)) // with p_v = sum_{b in subset} p_bv // actually, we restrict 1 + beta*prior_gradient between .1 and 10 - while (denominator_iter != denominator_end) - { + while (denominator_iter != denominator_end) { *denominator_iter += 1; // bound denominator between 1/10 and 1*10 // TODO code will fail if *denominator_iter is not a float - *denominator_iter = - std::max(std::min(*denominator_iter, 10.F),1/10.F); + *denominator_iter = std::max(std::min(*denominator_iter, 10.F), 1 / 10.F); *denominator_iter *= (*sensitivity_iter); ++denominator_iter; ++sensitivity_iter; } } - } - divide(multiplicative_update_image_ptr->begin_all(), - multiplicative_update_image_ptr->end_all(), - denominator_ptr->begin_all(), - small_num); + } + divide(multiplicative_update_image_ptr->begin_all(), multiplicative_update_image_ptr->end_all(), + denominator_ptr->begin_all(), small_num); } - + info(boost::format("Number of (cancelled) singularities in Sensitivity division: %1%") % count); } - - - if(this->inter_update_filter_interval>0 && - !is_null_ptr(this->inter_update_filter_ptr) && - !(this->subiteration_num%this->inter_update_filter_interval)) - { + + if (this->inter_update_filter_interval > 0 && !is_null_ptr(this->inter_update_filter_ptr) && + !(this->subiteration_num % this->inter_update_filter_interval)) { info("Applying inter-update filter"); - this->inter_update_filter_ptr->apply(current_image_estimate); + this->inter_update_filter_ptr->apply(current_image_estimate); } - + // KT 17/08/2000 limit update // TODO move below thresholding? - if (this->write_update_image && !this->_disable_output) - { + if (this->write_update_image && !this->_disable_output) { // allocate space for the filename assuming that // we never have more than 10^49 subiterations ... - char * fname = new char[this->output_filename_prefix.size() + 60]; + char* fname = new char[this->output_filename_prefix.size() + 60]; sprintf(fname, "%s_update_%d", this->output_filename_prefix.c_str(), this->subiteration_num); - + // Write it to file - this->output_file_format_ptr-> - write_to_file(fname, *multiplicative_update_image_ptr); + this->output_file_format_ptr->write_to_file(fname, *multiplicative_update_image_ptr); delete[] fname; } - - if (this->subiteration_num != 1) - { - const float current_min = - *std::min_element(multiplicative_update_image_ptr->begin_all(), - multiplicative_update_image_ptr->end_all()); - const float current_max = - *std::max_element(multiplicative_update_image_ptr->begin_all(), - multiplicative_update_image_ptr->end_all()); - const float new_min = - static_cast(this->minimum_relative_change); - const float new_max = - static_cast(this->maximum_relative_change); - info(boost::format("Update image old min,max: %1%, %2%, new min,max %3%, %4%") % current_min % current_max % (min(current_min, new_min)) % (max(current_max, new_max))); - - threshold_upper_lower(multiplicative_update_image_ptr->begin_all(), - multiplicative_update_image_ptr->end_all(), - new_min, new_max); - } - //current_image_estimate *= *multiplicative_update_image_ptr; + if (this->subiteration_num != 1) { + const float current_min = + *std::min_element(multiplicative_update_image_ptr->begin_all(), multiplicative_update_image_ptr->end_all()); + const float current_max = + *std::max_element(multiplicative_update_image_ptr->begin_all(), multiplicative_update_image_ptr->end_all()); + const float new_min = static_cast(this->minimum_relative_change); + const float new_max = static_cast(this->maximum_relative_change); + info(boost::format("Update image old min,max: %1%, %2%, new min,max %3%, %4%") % current_min % current_max % + (min(current_min, new_min)) % (max(current_max, new_max))); + + threshold_upper_lower(multiplicative_update_image_ptr->begin_all(), multiplicative_update_image_ptr->end_all(), new_min, + new_max); + } + + // current_image_estimate *= *multiplicative_update_image_ptr; apply_multiplicative_update(current_image_estimate, *multiplicative_update_image_ptr); #ifdef PARALLEL @@ -584,7 +472,7 @@ update_estimate(TargetT ¤t_image_estimate) #endif } -template class OSMAPOSLReconstruction >; -template class OSMAPOSLReconstruction; +template class OSMAPOSLReconstruction>; +template class OSMAPOSLReconstruction; END_NAMESPACE_STIR diff --git a/src/iterative/OSSPS/OSSPS.cxx b/src/iterative/OSSPS/OSSPS.cxx index 54f4968eb5..49cf83e956 100644 --- a/src/iterative/OSSPS/OSSPS.cxx +++ b/src/iterative/OSSPS/OSSPS.cxx @@ -23,7 +23,7 @@ \author Sanida Mustafovic \author Kris Thielemans - + */ #include "stir/OSSPS/OSSPSReconstruction.h" #include "stir/DiscretisedDensity.h" @@ -33,18 +33,15 @@ USING_NAMESPACE_STIR #ifdef STIR_MPI -int stir::distributable_main(int argc, char **argv) +int +stir::distributable_main(int argc, char** argv) #else -int main(int argc, char **argv) +int +main(int argc, char** argv) #endif { - OSSPSReconstruction > reconstruction_object(argc>1?argv[1]:""); - - - return reconstruction_object.reconstruct() == Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; - + OSSPSReconstruction> reconstruction_object(argc > 1 ? argv[1] : ""); + return reconstruction_object.reconstruct() == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } - diff --git a/src/iterative/OSSPS/OSSPSReconstruction.cxx b/src/iterative/OSSPS/OSSPSReconstruction.cxx index c549ec12ce..e5e0e95106 100644 --- a/src/iterative/OSSPS/OSSPSReconstruction.cxx +++ b/src/iterative/OSSPS/OSSPSReconstruction.cxx @@ -18,13 +18,13 @@ */ /*! \file -\ingroup OSSPS +\ingroup OSSPS \ingroup reconstructors -\brief implementation of the stir::OSSPSReconstruction class +\brief implementation of the stir::OSSPSReconstruction class \author Sanida Mustafovic \author Kris Thielemans - + */ #include "stir/OSSPS/OSSPSReconstruction.h" @@ -45,9 +45,9 @@ #include #include #ifdef BOOST_NO_STRINGSTREAM -#include +# include #else -#include +# include #endif #include #include "boost/lambda/lambda.hpp" @@ -60,50 +60,42 @@ using boost::lambda::_1; using boost::lambda::_2; #endif - START_NAMESPACE_STIR //*************** parameters ************* template -const char * const -OSSPSReconstruction ::registered_name = - "OSSPS"; +const char* const OSSPSReconstruction::registered_name = "OSSPS"; template -void -OSSPSReconstruction:: -set_defaults() -{ +void +OSSPSReconstruction::set_defaults() { base_type::set_defaults(); enforce_initial_positivity = 0; upper_bound = NumericInfo().max_value(); write_update_image = 0; precomputed_denominator_filename = ""; - //MAP_model="additive"; + // MAP_model="additive"; relaxation_parameter = 1; relaxation_gamma = 0.1F; #if 0 this->do_line_search = false; #endif - } template -void -OSSPSReconstruction:: -initialise_keymap() -{ +void +OSSPSReconstruction::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("OSSPSParameters"); this->parser.add_stop_key("End"); - - this->parser.add_key("enforce initial positivity condition",&enforce_initial_positivity); - //this->parser.add_key("MAP_model", &MAP_model); + + this->parser.add_key("enforce initial positivity condition", &enforce_initial_positivity); + // this->parser.add_key("MAP_model", &MAP_model); this->parser.add_key("upper bound", &upper_bound); - this->parser.add_key("write update image",&write_update_image); + this->parser.add_key("write update image", &write_update_image); this->parser.add_key("precomputed denominator", &precomputed_denominator_filename); this->parser.add_key("relaxation parameter", &relaxation_parameter); @@ -113,57 +105,45 @@ initialise_keymap() #endif } - template -void -OSSPSReconstruction:: -ask_parameters() -{ +void +OSSPSReconstruction::ask_parameters() { error("Currently incomplete code. Use a parameter file. Sorry."); base_type::ask_parameters(); - + // KT 05/07/2000 made enforce_initial_positivity int - enforce_initial_positivity= - ask("Enforce initial positivity condition?",true) ? 1 : 0; - + enforce_initial_positivity = ask("Enforce initial positivity condition?", true) ? 1 : 0; + char precomputed_denominator_filename_char[max_filename_length]; - - ask_filename_with_extension(precomputed_denominator_filename_char,"Enter file name of precomputed denominator (1 = 1's): ", ""); - - precomputed_denominator_filename=precomputed_denominator_filename_char; - + ask_filename_with_extension(precomputed_denominator_filename_char, + "Enter file name of precomputed denominator (1 = 1's): ", ""); + + precomputed_denominator_filename = precomputed_denominator_filename_char; - { - - cerr<::list_registered_names(cerr); + { + + cerr << endl << "Supply objective function type:\nPossible values:\n"; + GeneralisedObjectiveFunction::list_registered_names(cerr); const std::string objective_function_type = ask_string(""); - - this->objective_function_sptr. - reset(GeneralisedObjectiveFunction::read_registered_object(0, objective_function_type)); - - } - + + this->objective_function_sptr.reset( + GeneralisedObjectiveFunction::read_registered_object(0, objective_function_type)); + } + // KT 17/08/2000 3 new parameters const double max_in_double = static_cast(NumericInfo().max_value()); - upper_bound = ask_num("upper bound", - 1.,max_in_double,max_in_double); - - write_update_image = ask_num("write update image", 0,1,0); + upper_bound = ask_num("upper bound", 1., max_in_double, max_in_double); + + write_update_image = ask_num("write update image", 0, 1, 0); // TODO some more parameters here (relaxation et al) } - - - template -bool -OSSPSReconstruction:: -post_processing() -{ +bool +OSSPSReconstruction::post_processing() { if (base_type::post_processing()) return true; return false; @@ -172,52 +152,45 @@ post_processing() //*************** other functions ************* template -OSSPSReconstruction:: -OSSPSReconstruction() -{ +OSSPSReconstruction::OSSPSReconstruction() { set_defaults(); } template -OSSPSReconstruction:: -OSSPSReconstruction(const std::string& parameter_filename) -{ +OSSPSReconstruction::OSSPSReconstruction(const std::string& parameter_filename) { this->initialise(parameter_filename); info(this->parameter_info()); } template -std::string -OSSPSReconstruction:: -method_info() const -{ - +std::string +OSSPSReconstruction::method_info() const { + // TODO add prior name? - + #ifdef BOOST_NO_STRINGSTREAM char str[10000]; ostrstream s(str, 10000); #else std::ostringstream s; #endif - + // if(inter_update_filter_interval>0) s<<"IUF-"; if (!this->objective_function_sptr->prior_is_zero()) s << "MAP-"; - if(this->num_subsets>1) - s<<"OS-"; + if (this->num_subsets > 1) + s << "OS-"; s << "SPS"; - if(this->inter_iteration_filter_interval>0) s<<"S"; + if (this->inter_iteration_filter_interval > 0) + s << "S"; return s.str(); } template -Succeeded -OSSPSReconstruction:: -precompute_denominator_of_conditioner_without_penalty() -{ - +Succeeded +OSSPSReconstruction::precompute_denominator_of_conditioner_without_penalty() { + CPUTimer timer; timer.reset(); timer.start(); @@ -225,265 +198,204 @@ precompute_denominator_of_conditioner_without_penalty() assert(*std::max_element(precomputed_denominator_ptr->begin_all(), precomputed_denominator_ptr->end_all()) == 0); assert(*std::min_element(precomputed_denominator_ptr->begin_all(), precomputed_denominator_ptr->end_all()) == 0); - unique_ptr data_full_of_ones_aptr - ( precomputed_denominator_ptr->clone()); - std::fill(data_full_of_ones_aptr->begin_all(), - data_full_of_ones_aptr->end_all(), - 1.F); + unique_ptr data_full_of_ones_aptr(precomputed_denominator_ptr->clone()); + std::fill(data_full_of_ones_aptr->begin_all(), data_full_of_ones_aptr->end_all(), 1.F); - this->objective_function_sptr-> - add_multiplication_with_approximate_Hessian_without_penalty( - *precomputed_denominator_ptr, - *data_full_of_ones_aptr); + this->objective_function_sptr->add_multiplication_with_approximate_Hessian_without_penalty(*precomputed_denominator_ptr, + *data_full_of_ones_aptr); timer.stop(); info(boost::format("Precomputing denominator took %1% s CPU time") % timer.value()); - info(boost::format("min and max in precomputed denominator %1%, %2%") % *std::min_element(precomputed_denominator_ptr->begin_all(), precomputed_denominator_ptr->end_all()) % *std::max_element(precomputed_denominator_ptr->begin_all(), precomputed_denominator_ptr->end_all())); + info(boost::format("min and max in precomputed denominator %1%, %2%") % + *std::min_element(precomputed_denominator_ptr->begin_all(), precomputed_denominator_ptr->end_all()) % + *std::max_element(precomputed_denominator_ptr->begin_all(), precomputed_denominator_ptr->end_all())); // Write it to file { - std::string fname = - this->output_filename_prefix + - "_precomputed_denominator"; - - info(boost::format(" - Saving %1%") % fname); - this->output_file_format_ptr-> - write_to_file(fname, *precomputed_denominator_ptr); + std::string fname = this->output_filename_prefix + "_precomputed_denominator"; + + info(boost::format(" - Saving %1%") % fname); + this->output_file_format_ptr->write_to_file(fname, *precomputed_denominator_ptr); } return Succeeded::yes; } template -Succeeded -OSSPSReconstruction:: -set_up(shared_ptr const& target_image_ptr) -{ +Succeeded +OSSPSReconstruction::set_up(shared_ptr const& target_image_ptr) { if (base_type::set_up(target_image_ptr) == Succeeded::no) return Succeeded::no; - if (this->relaxation_parameter<=0) - { - warning("OSSPS: relaxation parameter should be positive but is %g", - this->relaxation_parameter); - return Succeeded::no; - } - if (this->relaxation_gamma<0) - { - warning("OSSPS: relaxation_gamma parameter should be non-negative but is %g", - this->relaxation_gamma); - return Succeeded::no; - } + if (this->relaxation_parameter <= 0) { + warning("OSSPS: relaxation parameter should be positive but is %g", this->relaxation_parameter); + return Succeeded::no; + } + if (this->relaxation_gamma < 0) { + warning("OSSPS: relaxation_gamma parameter should be non-negative but is %g", this->relaxation_gamma); + return Succeeded::no; + } - if (!is_null_ptr(this->get_prior_ptr())&& - dynamic_cast*>(this->get_prior_ptr())==0) - { + if (!is_null_ptr(this->get_prior_ptr()) && dynamic_cast*>(this->get_prior_ptr()) == 0) { warning("OSSPS: Prior must be of a type derived from PriorWithParabolicSurrogate\n"); return Succeeded::no; } - if(enforce_initial_positivity) - threshold_min_to_small_positive_value(target_image_ptr->begin_all(), - target_image_ptr->end_all(), - 10.E-6F); - - if(this->precomputed_denominator_filename=="") - { + if (enforce_initial_positivity) + threshold_min_to_small_positive_value(target_image_ptr->begin_all(), target_image_ptr->end_all(), 10.E-6F); + + if (this->precomputed_denominator_filename == "") { precomputed_denominator_ptr.reset(target_image_ptr->get_empty_copy()); precompute_denominator_of_conditioner_without_penalty(); - } - else if(this->precomputed_denominator_filename=="1") - { + } else if (this->precomputed_denominator_filename == "1") { precomputed_denominator_ptr.reset(target_image_ptr->get_empty_copy()); std::fill(precomputed_denominator_ptr->begin_all(), precomputed_denominator_ptr->end_all(), 1.F); - } - else - { - precomputed_denominator_ptr = - read_from_file(this->precomputed_denominator_filename); + } else { + precomputed_denominator_ptr = read_from_file(this->precomputed_denominator_filename); { std::string explanation; - if (!precomputed_denominator_ptr->has_same_characteristics(*target_image_ptr, explanation)) - { - warning("OSSPS: precomputed_denominator should have same characteristics as target image: %s", - explanation.c_str()); - return Succeeded::no; - } + if (!precomputed_denominator_ptr->has_same_characteristics(*target_image_ptr, explanation)) { + warning("OSSPS: precomputed_denominator should have same characteristics as target image: %s", explanation.c_str()); + return Succeeded::no; + } } - } + } return Succeeded::yes; } - - /*! \brief OSSPS additive update at every subiteration \warning This modifies *precomputed_denominator_ptr. So, you have to call set_up() before running a new reconstruction. */ template -void -OSSPSReconstruction:: -update_estimate(TargetT ¤t_image_estimate) -{ +void +OSSPSReconstruction::update_estimate(TargetT& current_image_estimate) { this->check(current_image_estimate); - if (this->get_subiteration_num() == this->get_start_subiteration_num()) - { - // set all voxels to 0 that cannot be estimated. - this->objective_function_sptr-> - fill_nonidentifiable_target_parameters(current_image_estimate, 0); - } + if (this->get_subiteration_num() == this->get_start_subiteration_num()) { + // set all voxels to 0 that cannot be estimated. + this->objective_function_sptr->fill_nonidentifiable_target_parameters(current_image_estimate, 0); + } // Check if we need to recompute the penalty term in the denominator during iterations . // For the quadratic prior, this is independent of the image (only on kappa's) // And of course, it's also independent when there is no prior // TODO by default, this should be off probably (to save time). const bool recompute_penalty_term_in_denominator = - !this->objective_function_sptr->prior_is_zero() && - static_cast const&>(*this->get_prior_ptr()). - parabolic_surrogate_curvature_depends_on_argument(); + !this->objective_function_sptr->prior_is_zero() && + static_cast const&>(*this->get_prior_ptr()) + .parabolic_surrogate_curvature_depends_on_argument(); #ifndef PARALLEL - //CPUTimer subset_timer; - //subset_timer.start(); -#else // PARALLEL + // CPUTimer subset_timer; + // subset_timer.start(); +#else // PARALLEL PTimer timerSubset; timerSubset.Start(); #endif // PARALLEL - - const int subset_num=this->get_subset_num(); + + const int subset_num = this->get_subset_num(); info(boost::format("Now processing subset #: %1%") % subset_num); - + // TODO make member or static parameter to avoid reallocation all the time - unique_ptr< TargetT > numerator_ptr - (current_image_estimate.get_empty_copy()); + unique_ptr numerator_ptr(current_image_estimate.get_empty_copy()); this->objective_function_sptr->compute_sub_gradient(*numerator_ptr, current_image_estimate, subset_num); //*numerator_ptr *= this->num_subsets; - std::transform(numerator_ptr->begin_all(), numerator_ptr->end_all(), - numerator_ptr->begin_all(), - _1 * this->num_subsets); + std::transform(numerator_ptr->begin_all(), numerator_ptr->end_all(), numerator_ptr->begin_all(), _1 * this->num_subsets); info(boost::format("num subsets %1%") % this->num_subsets); - info(boost::format("this->num_subsets*subgradient : max %1%, min %2%") % *std::max_element(numerator_ptr->begin_all(), numerator_ptr->end_all()) % *std::min_element(numerator_ptr->begin_all(), numerator_ptr->end_all())); + info(boost::format("this->num_subsets*subgradient : max %1%, min %2%") % + *std::max_element(numerator_ptr->begin_all(), numerator_ptr->end_all()) % + *std::min_element(numerator_ptr->begin_all(), numerator_ptr->end_all())); // now divide by denominator - if (recompute_penalty_term_in_denominator || - (this->get_subiteration_num() == this->get_start_subiteration_num())) - { - unique_ptr< TargetT > work_image_ptr - (current_image_estimate.get_empty_copy()); - - // avoid work (or crash) when penalty is 0 - if (!this->objective_function_sptr->prior_is_zero()) - { - static_cast&>(*get_prior_ptr()). - parabolic_surrogate_curvature(*work_image_ptr, current_image_estimate); - //*work_image_ptr *= 2; - //*work_image_ptr += *precomputed_denominator_ptr ; - std::transform(work_image_ptr->begin_all(), work_image_ptr->end_all(), - precomputed_denominator_ptr->begin_all(), - work_image_ptr->begin_all(), - _1 * 2 + _2); - } - else - *work_image_ptr = *precomputed_denominator_ptr ; - - // KT 09/12/2002 new - // avoid division by 0 by thresholding the denominator to be strictly positive - threshold_min_to_small_positive_value(work_image_ptr->begin_all(), - work_image_ptr->end_all(), - 10.E-6F); - info(boost::format(" denominator max %1%, min %2%") % *std::max_element(work_image_ptr->begin_all(), work_image_ptr->end_all()) % *std::min_element(work_image_ptr->begin_all(), work_image_ptr->end_all())); - - if (!recompute_penalty_term_in_denominator) - { - // store for future use - *precomputed_denominator_ptr = *work_image_ptr; - } - - //*numerator_ptr /= *work_image_ptr; - std::transform(numerator_ptr->begin_all(), numerator_ptr->end_all(), - work_image_ptr->begin_all(), - numerator_ptr->begin_all(), - _1 / _2); - + if (recompute_penalty_term_in_denominator || (this->get_subiteration_num() == this->get_start_subiteration_num())) { + unique_ptr work_image_ptr(current_image_estimate.get_empty_copy()); + + // avoid work (or crash) when penalty is 0 + if (!this->objective_function_sptr->prior_is_zero()) { + static_cast&>(*get_prior_ptr()) + .parabolic_surrogate_curvature(*work_image_ptr, current_image_estimate); + //*work_image_ptr *= 2; + //*work_image_ptr += *precomputed_denominator_ptr ; + std::transform(work_image_ptr->begin_all(), work_image_ptr->end_all(), precomputed_denominator_ptr->begin_all(), + work_image_ptr->begin_all(), _1 * 2 + _2); + } else + *work_image_ptr = *precomputed_denominator_ptr; + + // KT 09/12/2002 new + // avoid division by 0 by thresholding the denominator to be strictly positive + threshold_min_to_small_positive_value(work_image_ptr->begin_all(), work_image_ptr->end_all(), 10.E-6F); + info(boost::format(" denominator max %1%, min %2%") % + *std::max_element(work_image_ptr->begin_all(), work_image_ptr->end_all()) % + *std::min_element(work_image_ptr->begin_all(), work_image_ptr->end_all())); + + if (!recompute_penalty_term_in_denominator) { + // store for future use + *precomputed_denominator_ptr = *work_image_ptr; } - else - { - // we have computed the denominator already - //*numerator_ptr /= *precomputed_denominator_ptr; - std::transform(numerator_ptr->begin_all(), numerator_ptr->end_all(), - precomputed_denominator_ptr->begin_all(), - numerator_ptr->begin_all(), - _1 / _2); - } + //*numerator_ptr /= *work_image_ptr; + std::transform(numerator_ptr->begin_all(), numerator_ptr->end_all(), work_image_ptr->begin_all(), numerator_ptr->begin_all(), + _1 / _2); - //relaxation_parameter ~1/(1+n) where n is iteration number - const float relaxation_parameter = this->relaxation_parameter/ - (1+this->relaxation_gamma*(this->subiteration_num/this->num_subsets)); + } else { + // we have computed the denominator already + //*numerator_ptr /= *precomputed_denominator_ptr; + std::transform(numerator_ptr->begin_all(), numerator_ptr->end_all(), precomputed_denominator_ptr->begin_all(), + numerator_ptr->begin_all(), _1 / _2); + } + // relaxation_parameter ~1/(1+n) where n is iteration number + const float relaxation_parameter = + this->relaxation_parameter / (1 + this->relaxation_gamma * (this->subiteration_num / this->num_subsets)); info(boost::format("relaxation parameter = %1%") % relaxation_parameter); - const float alpha = 1.F; // line_search(current_image_estimate, *numerator_ptr); - // *numerator_ptr *= relaxation_parameter * alpha; - std::transform(numerator_ptr->begin_all(), numerator_ptr->end_all(), - numerator_ptr->begin_all(), - _1 * relaxation_parameter * alpha); + const float alpha = 1.F; // line_search(current_image_estimate, *numerator_ptr); + // *numerator_ptr *= relaxation_parameter * alpha; + std::transform(numerator_ptr->begin_all(), numerator_ptr->end_all(), numerator_ptr->begin_all(), + _1 * relaxation_parameter * alpha); - - if (write_update_image) - { - // Write it to file - const std::string fname = - this->make_filename_prefix_subiteration_num(this->output_filename_prefix + "_update"); - this->output_file_format_ptr-> - write_to_file(fname, *numerator_ptr); - } - - { - info(boost::format("additive update image min,max: %1%, %2%") % *std::min_element(numerator_ptr->begin_all(), numerator_ptr->end_all()) % *std::max_element(numerator_ptr->begin_all(), numerator_ptr->end_all())); + if (write_update_image) { + // Write it to file + const std::string fname = this->make_filename_prefix_subiteration_num(this->output_filename_prefix + "_update"); + this->output_file_format_ptr->write_to_file(fname, *numerator_ptr); + } - } - current_image_estimate += *numerator_ptr; + { + info(boost::format("additive update image min,max: %1%, %2%") % + *std::min_element(numerator_ptr->begin_all(), numerator_ptr->end_all()) % + *std::max_element(numerator_ptr->begin_all(), numerator_ptr->end_all())); + } + current_image_estimate += *numerator_ptr; // now threshold image { - const float current_min = - *std::min_element(current_image_estimate.begin_all(), - current_image_estimate.end_all()); - const float current_max = - *std::max_element(current_image_estimate.begin_all(), - current_image_estimate.end_all()); + const float current_min = *std::min_element(current_image_estimate.begin_all(), current_image_estimate.end_all()); + const float current_max = *std::max_element(current_image_estimate.begin_all(), current_image_estimate.end_all()); const float new_min = 0.F; - const float new_max = - static_cast(upper_bound); - info(boost::format("current image old min,max: %1%, %2%, new min,max %3%, %4%") % current_min % current_max % std::max(current_min, new_min) % std::min(current_max, new_max)); - - threshold_upper_lower(current_image_estimate.begin_all(), - current_image_estimate.end_all(), - new_min, new_max); - } + const float new_max = static_cast(upper_bound); + info(boost::format("current image old min,max: %1%, %2%, new min,max %3%, %4%") % current_min % current_max % + std::max(current_min, new_min) % std::min(current_max, new_max)); + + threshold_upper_lower(current_image_estimate.begin_all(), current_image_estimate.end_all(), new_min, new_max); + } #ifndef PARALLEL - //cerr << "Subset : " << subset_timer.value() << "secs " < >; -template class OSSPSReconstruction; +template class OSSPSReconstruction>; +template class OSSPSReconstruction; END_NAMESPACE_STIR - - diff --git a/src/iterative/POSMAPOSL/POSMAPOSL.cxx b/src/iterative/POSMAPOSL/POSMAPOSL.cxx index 2a6911f6e8..a8048f8d77 100644 --- a/src/iterative/POSMAPOSL/POSMAPOSL.cxx +++ b/src/iterative/POSMAPOSL/POSMAPOSL.cxx @@ -26,22 +26,17 @@ #include "stir/modelling/ParametricDiscretisedDensity.h" #include "stir/recon_buildblock/distributable_main.h" - - #ifdef STIR_MPI -int stir::distributable_main(int argc, char **argv) +int +stir::distributable_main(int argc, char** argv) #else -int main(int argc, char **argv) +int +main(int argc, char** argv) #endif { using namespace stir; - OSMAPOSLReconstruction - reconstruction_object(argc>1?argv[1]:""); - - return reconstruction_object.reconstruct() == Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; - + OSMAPOSLReconstruction reconstruction_object(argc > 1 ? argv[1] : ""); + return reconstruction_object.reconstruct() == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } - diff --git a/src/iterative/POSSPS/POSSPS.cxx b/src/iterative/POSSPS/POSSPS.cxx index 36b0d3d6b2..4b65e6db23 100644 --- a/src/iterative/POSSPS/POSSPS.cxx +++ b/src/iterative/POSSPS/POSSPS.cxx @@ -29,17 +29,16 @@ #include "stir/Succeeded.h" #include "stir/recon_buildblock/distributable_main.h" - - #ifdef STIR_MPI -int stir::distributable_main(int argc, char **argv) +int +stir::distributable_main(int argc, char** argv) #else -int main(int argc, char **argv) +int +main(int argc, char** argv) #endif { using namespace stir; - OSSPSReconstruction reconstruction_object(argc>1?argv[1]:""); + OSSPSReconstruction reconstruction_object(argc > 1 ? argv[1] : ""); - return reconstruction_object.reconstruct() == Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; + return reconstruction_object.reconstruct() == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/listmode_buildblock/CListEvent.cxx b/src/listmode_buildblock/CListEvent.cxx index db96917b8d..a8577d3ee0 100644 --- a/src/listmode_buildblock/CListEvent.cxx +++ b/src/listmode_buildblock/CListEvent.cxx @@ -4,9 +4,9 @@ \file \ingroup listmode \brief Implementations of class stir::CListEvent. - + \author Kris Thielemans - + */ /* Copyright (C) 2003- 2011, Hammersmith Imanet Ltd @@ -25,7 +25,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/listmode/CListRecord.h" #include "stir/ProjDataInfo.h" #include "stir/Bin.h" @@ -34,11 +33,9 @@ START_NAMESPACE_STIR -Succeeded -CListEvent:: -set_prompt(const bool) -{ - return Succeeded::no; +Succeeded +CListEvent::set_prompt(const bool) { + return Succeeded::no; } END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/CListModeDataECAT.cxx b/src/listmode_buildblock/CListModeDataECAT.cxx index fd137427ca..a9150e5446 100644 --- a/src/listmode_buildblock/CListModeDataECAT.cxx +++ b/src/listmode_buildblock/CListModeDataECAT.cxx @@ -17,22 +17,21 @@ */ /*! \file - \ingroup listmode + \ingroup listmode \brief Implementation of class stir::CListModeDataECAT - + \author Kris Thielemans */ - #include "stir/listmode/CListModeDataECAT.h" #include "stir/listmode/CListRecordECAT966.h" #include "stir/listmode/CListRecordECAT962.h" #include "stir/info.h" #include #ifdef HAVE_LLN_MATRIX -#include "stir/IO/stir_ecat7.h" +# include "stir/IO/stir_ecat7.h" #else -#error Need HAVE_LLN_MATRIX +# error Need HAVE_LLN_MATRIX #endif #include "boost/static_assert.hpp" #ifndef STIR_NO_NAMESPACES @@ -49,231 +48,199 @@ START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 // compile time asserts -BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT966)==4); -BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT966)==4); -BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT962)==4); -BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT962)==4); +BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT966) == 4); +BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT966) == 4); +BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT962) == 4); +BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT962) == 4); template -CListModeDataECAT:: -CListModeDataECAT(const std::string& listmode_filename_prefix) - : listmode_filename_prefix(listmode_filename_prefix) -{ +CListModeDataECAT::CListModeDataECAT(const std::string& listmode_filename_prefix) + : listmode_filename_prefix(listmode_filename_prefix) { // initialise scanner_ptr before calling open_lm_file, as it is used in that function - shared_ptr scanner_sptr; - shared_ptr exam_info_sptr(new ExamInfo); - exam_info_sptr->imaging_modality = ImagingModality::PT; + shared_ptr scanner_sptr; + shared_ptr exam_info_sptr(new ExamInfo); + exam_info_sptr->imaging_modality = ImagingModality::PT; // attempt to read the .sgl file { const std::string singles_filename = listmode_filename_prefix + "_1.sgl"; ifstream singles_file(singles_filename.c_str(), ios::binary); char buffer[sizeof(Main_header)]; - if (!singles_file) - { - warning("CListModeDataECAT: Couldn't read main_header from %s. We forge ahead anyway (assuming this is ECAT 962 data).", singles_filename.c_str()); - // This should have been handled by the projdatainfo. - scanner_sptr.reset(new Scanner(Scanner::E962)); - - // TODO invalidate other fields in singles header - } - else - { - Main_header singles_main_header; - singles_file.read(buffer, - sizeof(singles_main_header)); - unmap_main_header(buffer, &singles_main_header); - // This should have been handled by the projdatainfo. - ecat::ecat7::find_scanner(scanner_sptr, singles_main_header); - - exam_info_sptr->start_time_in_secs_since_1970 = double(singles_main_header.scan_start_time); - - switch(singles_main_header.patient_orientation) - { - case FeetFirstProne: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFP); break; - case HeadFirstProne: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFP); break; - case FeetFirstSupine: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFS); break; - case HeadFirstSupine: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFS); break; - case FeetFirstRight: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFDR); break; - case HeadFirstRight: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFDR); break; - case FeetFirstLeft: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFDL); break; - case HeadFirstLeft: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFDL); break; - case UnknownOrientation: - default: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::unknown_position); break; - } + if (!singles_file) { + warning("CListModeDataECAT: Couldn't read main_header from %s. We forge ahead anyway (assuming this is ECAT 962 data).", + singles_filename.c_str()); + // This should have been handled by the projdatainfo. + scanner_sptr.reset(new Scanner(Scanner::E962)); + + // TODO invalidate other fields in singles header + } else { + Main_header singles_main_header; + singles_file.read(buffer, sizeof(singles_main_header)); + unmap_main_header(buffer, &singles_main_header); + // This should have been handled by the projdatainfo. + ecat::ecat7::find_scanner(scanner_sptr, singles_main_header); + + exam_info_sptr->start_time_in_secs_since_1970 = double(singles_main_header.scan_start_time); + + switch (singles_main_header.patient_orientation) { + case FeetFirstProne: + exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFP); + break; + case HeadFirstProne: + exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFP); + break; + case FeetFirstSupine: + exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFS); + break; + case HeadFirstSupine: + exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFS); + break; + case FeetFirstRight: + exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFDR); + break; + case HeadFirstRight: + exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFDR); + break; + case FeetFirstLeft: + exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFDL); + break; + case HeadFirstLeft: + exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFDL); + break; + case UnknownOrientation: + default: + exam_info_sptr->patient_position = PatientPosition(PatientPosition::unknown_position); + break; } + } } this->set_exam_info(*exam_info_sptr); - shared_ptr tmp(ProjDataInfo::construct_proj_data_info(scanner_sptr, - 1, - scanner_sptr->get_num_rings() - 1, - scanner_sptr->get_max_num_views(), - scanner_sptr->get_max_num_non_arccorrected_bins(), - /* arc_correction*/false)); - this->set_proj_data_info_sptr( tmp ); - - if ((get_proj_data_info_sptr()->get_scanner_ptr()->get_type() == Scanner::E966 && typeid(CListRecordT) != typeid(CListRecordECAT966)) || - (get_proj_data_info_sptr()->get_scanner_ptr()->get_type() == Scanner::E962 && typeid(CListRecordT) != typeid(CListRecordECAT962))) - { - error("Data in %s is from a %s scanner, but reading with wrong type of CListModeData", - listmode_filename_prefix.c_str(), get_proj_data_info_sptr()->get_scanner_ptr()->get_name().c_str()); - } - else if (get_proj_data_info_sptr()->get_scanner_ptr()->get_type() != Scanner::E966 && get_proj_data_info_sptr()->get_scanner_ptr()->get_type() != Scanner::E962) - { - error("CListModeDataECAT: Unsupported scanner in %s", listmode_filename_prefix.c_str()); - } + shared_ptr tmp(ProjDataInfo::construct_proj_data_info(scanner_sptr, 1, scanner_sptr->get_num_rings() - 1, + scanner_sptr->get_max_num_views(), + scanner_sptr->get_max_num_non_arccorrected_bins(), + /* arc_correction*/ false)); + this->set_proj_data_info_sptr(tmp); + + if ((get_proj_data_info_sptr()->get_scanner_ptr()->get_type() == Scanner::E966 && + typeid(CListRecordT) != typeid(CListRecordECAT966)) || + (get_proj_data_info_sptr()->get_scanner_ptr()->get_type() == Scanner::E962 && + typeid(CListRecordT) != typeid(CListRecordECAT962))) { + error("Data in %s is from a %s scanner, but reading with wrong type of CListModeData", listmode_filename_prefix.c_str(), + get_proj_data_info_sptr()->get_scanner_ptr()->get_name().c_str()); + } else if (get_proj_data_info_sptr()->get_scanner_ptr()->get_type() != Scanner::E966 && + get_proj_data_info_sptr()->get_scanner_ptr()->get_type() != Scanner::E962) { + error("CListModeDataECAT: Unsupported scanner in %s", listmode_filename_prefix.c_str()); + } if (open_lm_file(1) == Succeeded::no) - error("CListModeDataECAT: error opening the first listmode file for filename %s\n", - listmode_filename_prefix.c_str()); + error("CListModeDataECAT: error opening the first listmode file for filename %s\n", listmode_filename_prefix.c_str()); } template std::string -CListModeDataECAT:: -get_name() const -{ +CListModeDataECAT::get_name() const { return listmode_filename_prefix + "_1.sgl"; } - template -shared_ptr -CListModeDataECAT:: -get_empty_record_sptr() const -{ +shared_ptr +CListModeDataECAT::get_empty_record_sptr() const { shared_ptr sptr(new CListRecordT); return sptr; } template Succeeded -CListModeDataECAT:: -open_lm_file(unsigned int new_lm_file) const -{ +CListModeDataECAT::open_lm_file(unsigned int new_lm_file) const { // current_lm_file and new_lm_file are 1-based - assert(new_lm_file>0); - - if (is_null_ptr(current_lm_data_ptr) || new_lm_file != current_lm_file) - { - // first store saved_get_positions - if (!is_null_ptr(current_lm_data_ptr)) - { - assert(current_lm_file>0); - if (current_lm_file>=saved_get_positions_for_each_lm_data.size()) - saved_get_positions_for_each_lm_data.resize(current_lm_file); - - saved_get_positions_for_each_lm_data[current_lm_file-1] = - current_lm_data_ptr->get_saved_get_positions(); - } - - // now open new file - std::string filename = listmode_filename_prefix; - char rest[50]; - sprintf(rest, "_%d.lm", new_lm_file); - filename += rest; - info(boost::format("CListModeDataECAT: opening file %1%") % filename); - shared_ptr stream_ptr(new fstream(filename.c_str(), ios::in | ios::binary)); - if (!(*stream_ptr)) - { - warning("CListModeDataECAT: cannot open file %s (probably this is perfectly ok)\n ", filename.c_str()); - return Succeeded::no; - } - current_lm_data_ptr.reset( - new InputStreamWithRecords(stream_ptr, - sizeof(CListTimeDataECAT966), - sizeof(CListTimeDataECAT966), - ByteOrder::big_endian != ByteOrder::get_native_order())); - current_lm_file = new_lm_file; + assert(new_lm_file > 0); - // now restore saved_get_positions for this file - if (!is_null_ptr(current_lm_data_ptr) && - current_lm_file - set_saved_get_positions(saved_get_positions_for_each_lm_data[current_lm_file-1]); + if (is_null_ptr(current_lm_data_ptr) || new_lm_file != current_lm_file) { + // first store saved_get_positions + if (!is_null_ptr(current_lm_data_ptr)) { + assert(current_lm_file > 0); + if (current_lm_file >= saved_get_positions_for_each_lm_data.size()) + saved_get_positions_for_each_lm_data.resize(current_lm_file); - return Succeeded::yes; + saved_get_positions_for_each_lm_data[current_lm_file - 1] = current_lm_data_ptr->get_saved_get_positions(); } - else + + // now open new file + std::string filename = listmode_filename_prefix; + char rest[50]; + sprintf(rest, "_%d.lm", new_lm_file); + filename += rest; + info(boost::format("CListModeDataECAT: opening file %1%") % filename); + shared_ptr stream_ptr(new fstream(filename.c_str(), ios::in | ios::binary)); + if (!(*stream_ptr)) { + warning("CListModeDataECAT: cannot open file %s (probably this is perfectly ok)\n ", filename.c_str()); + return Succeeded::no; + } + current_lm_data_ptr.reset( + new InputStreamWithRecords(stream_ptr, sizeof(CListTimeDataECAT966), sizeof(CListTimeDataECAT966), + ByteOrder::big_endian != ByteOrder::get_native_order())); + current_lm_file = new_lm_file; + + // now restore saved_get_positions for this file + if (!is_null_ptr(current_lm_data_ptr) && current_lm_file < saved_get_positions_for_each_lm_data.size()) + current_lm_data_ptr->set_saved_get_positions(saved_get_positions_for_each_lm_data[current_lm_file - 1]); + + return Succeeded::yes; + } else return current_lm_data_ptr->reset(); } -/*! \todo Currently switches over to the next .lm file whenever +/*! \todo Currently switches over to the next .lm file whenever get_next_record() on the current file fails. This even happens when it failed not because of EOF, or if the listmode file is shorter than 2 GB. */ template Succeeded -CListModeDataECAT:: -get_next_record(CListRecord& record_of_general_type) const -{ +CListModeDataECAT::get_next_record(CListRecord& record_of_general_type) const { CListRecordT& record = static_cast(record_of_general_type); if (current_lm_data_ptr->get_next_record(record) == Succeeded::yes) return Succeeded::yes; - else - { + else { // warning: do not modify current_lm_file here. This is done by open_lm_file // open_lm_file uses current_lm_file as well - if (open_lm_file(current_lm_file+1) == Succeeded::yes) + if (open_lm_file(current_lm_file + 1) == Succeeded::yes) return current_lm_data_ptr->get_next_record(record); else return Succeeded::no; } } - - template Succeeded -CListModeDataECAT:: -reset() -{ +CListModeDataECAT::reset() { // current_lm_file and new_lm_file are 1-based - assert(current_lm_file>0); - if (current_lm_file!=1) - { - return open_lm_file(1); - } - else - { - return current_lm_data_ptr->reset(); - } + assert(current_lm_file > 0); + if (current_lm_file != 1) { + return open_lm_file(1); + } else { + return current_lm_data_ptr->reset(); + } } - template CListModeData::SavedPosition -CListModeDataECAT:: -save_get_position() -{ +CListModeDataECAT::save_get_position() { GetPosition current_pos; - current_pos.first = current_lm_file; + current_pos.first = current_lm_file; current_pos.second = current_lm_data_ptr->save_get_position(); saved_get_positions.push_back(current_pos); - return saved_get_positions.size()-1; -} + return saved_get_positions.size() - 1; +} template Succeeded -CListModeDataECAT:: -set_get_position(const typename CListModeDataECAT::SavedPosition& pos) -{ +CListModeDataECAT::set_get_position(const typename CListModeDataECAT::SavedPosition& pos) { assert(pos < saved_get_positions.size()); if (open_lm_file(saved_get_positions[pos].first) == Succeeded::no) return Succeeded::no; - return - current_lm_data_ptr->set_get_position(saved_get_positions[pos].second); + return current_lm_data_ptr->set_get_position(saved_get_positions[pos].second); } #if 0 template @@ -334,6 +301,12 @@ get_num_records() const #endif +template +shared_ptr +CListModeDataECAT::get_proj_data_info_sptr() const { + assert(!is_null_ptr(proj_data_info_sptr)); + return proj_data_info_sptr; +} // instantiations template class CListModeDataECAT; diff --git a/src/listmode_buildblock/CListModeDataECAT8_32bit.cxx b/src/listmode_buildblock/CListModeDataECAT8_32bit.cxx index b44e193365..ba85e6dbbe 100644 --- a/src/listmode_buildblock/CListModeDataECAT8_32bit.cxx +++ b/src/listmode_buildblock/CListModeDataECAT8_32bit.cxx @@ -17,13 +17,12 @@ */ /*! \file - \ingroup listmode + \ingroup listmode \brief Implementation of class stir::CListModeDataECAT8_32bit \author Kris Thielemans */ - #include "stir/listmode/CListModeDataECAT8_32bit.h" #include "stir/listmode/CListRecordECAT8_32bit.h" #include "stir/Succeeded.h" @@ -32,108 +31,79 @@ #include "stir/error.h" #include - START_NAMESPACE_STIR namespace ecat { -CListModeDataECAT8_32bit:: -CListModeDataECAT8_32bit(const std::string& listmode_filename) - : listmode_filename(listmode_filename) -{ - this->interfile_parser.parse(listmode_filename.c_str());// , false /* no warnings about unrecognised keywords */); +CListModeDataECAT8_32bit::CListModeDataECAT8_32bit(const std::string& listmode_filename) : listmode_filename(listmode_filename) { + this->interfile_parser.parse(listmode_filename.c_str()); // , false /* no warnings about unrecognised keywords */); this->exam_info_sptr.reset(new ExamInfo(interfile_parser.get_exam_info())); const std::string originating_system(this->interfile_parser.get_exam_info().originating_system); shared_ptr this_scanner_sptr(Scanner::get_scanner_from_name(originating_system)); if (this_scanner_sptr->get_type() == Scanner::Unknown_scanner) - error(boost::format("Unknown value for originating_system keyword: '%s") % originating_system ); + error(boost::format("Unknown value for originating_system keyword: '%s") % originating_system); this->set_proj_data_info_sptr(interfile_parser.data_info_ptr->create_shared_clone()); if (this->open_lm_file() == Succeeded::no) - error("CListModeDataECAT8_32bit: error opening the first listmode file for filename %s\n", - listmode_filename.c_str()); + error("CListModeDataECAT8_32bit: error opening the first listmode file for filename %s\n", listmode_filename.c_str()); } std::string -CListModeDataECAT8_32bit:: -get_name() const -{ +CListModeDataECAT8_32bit::get_name() const { return listmode_filename; } - -shared_ptr -CListModeDataECAT8_32bit:: -get_empty_record_sptr() const -{ +shared_ptr +CListModeDataECAT8_32bit::get_empty_record_sptr() const { shared_ptr sptr(new CListRecordT(this->get_proj_data_info_sptr())); return sptr; } - Succeeded -CListModeDataECAT8_32bit:: -open_lm_file() -{ - //const std::string filename = interfile_parser.data_file_name; - std::string filename = interfile_parser.data_file_name; - - char directory_name[max_filename_length]; - get_directory_name(directory_name, listmode_filename.c_str()); - char full_data_file_name[max_filename_length]; - strcpy(full_data_file_name, filename.c_str()); - prepend_directory_name(full_data_file_name, directory_name); - filename = std::string(full_data_file_name); - - info(boost::format("CListModeDataECAT8_32bit: opening file %1%") % filename); +CListModeDataECAT8_32bit::open_lm_file() { + // const std::string filename = interfile_parser.data_file_name; + std::string filename = interfile_parser.data_file_name; + + char directory_name[max_filename_length]; + get_directory_name(directory_name, listmode_filename.c_str()); + char full_data_file_name[max_filename_length]; + strcpy(full_data_file_name, filename.c_str()); + prepend_directory_name(full_data_file_name, directory_name); + filename = std::string(full_data_file_name); + + info(boost::format("CListModeDataECAT8_32bit: opening file %1%") % filename); shared_ptr stream_ptr(new std::fstream(filename.c_str(), std::ios::in | std::ios::binary)); - if (!(*stream_ptr)) - { - warning("CListModeDataECAT8_32bit: cannot open file '%s'", filename.c_str()); - return Succeeded::no; - } - current_lm_data_ptr.reset( - new InputStreamWithRecords(stream_ptr, 4, 4, - ByteOrder::little_endian != ByteOrder::get_native_order())); + if (!(*stream_ptr)) { + warning("CListModeDataECAT8_32bit: cannot open file '%s'", filename.c_str()); + return Succeeded::no; + } + current_lm_data_ptr.reset(new InputStreamWithRecords( + stream_ptr, 4, 4, ByteOrder::little_endian != ByteOrder::get_native_order())); return Succeeded::yes; } - - Succeeded -CListModeDataECAT8_32bit:: -get_next_record(CListRecord& record_of_general_type) const -{ +CListModeDataECAT8_32bit::get_next_record(CListRecord& record_of_general_type) const { CListRecordT& record = static_cast(record_of_general_type); return current_lm_data_ptr->get_next_record(record); - } - +} Succeeded -CListModeDataECAT8_32bit:: -reset() -{ +CListModeDataECAT8_32bit::reset() { return current_lm_data_ptr->reset(); } - CListModeData::SavedPosition -CListModeDataECAT8_32bit:: -save_get_position() -{ +CListModeDataECAT8_32bit::save_get_position() { return static_cast(current_lm_data_ptr->save_get_position()); -} - +} Succeeded -CListModeDataECAT8_32bit:: -set_get_position(const CListModeDataECAT8_32bit::SavedPosition& pos) -{ - return - current_lm_data_ptr->set_get_position(pos); +CListModeDataECAT8_32bit::set_get_position(const CListModeDataECAT8_32bit::SavedPosition& pos) { + return current_lm_data_ptr->set_get_position(pos); } } // namespace ecat diff --git a/src/listmode_buildblock/CListModeDataGEHDF5.cxx b/src/listmode_buildblock/CListModeDataGEHDF5.cxx index 0728e5ce7c..88d72c97a0 100644 --- a/src/listmode_buildblock/CListModeDataGEHDF5.cxx +++ b/src/listmode_buildblock/CListModeDataGEHDF5.cxx @@ -16,10 +16,10 @@ \author Palak Wadhwa */ - #include "stir/listmode/CListModeDataGEHDF5.h" #include "stir/Succeeded.h" #include "stir/ExamInfo.h" +#include "stir/ProjDataInfo.h" #include "stir/info.h" #include "stir/is_null_ptr.h" #include "stir/IO/GEHDF5Wrapper.h" @@ -33,110 +33,79 @@ START_NAMESPACE_STIR namespace GE { namespace RDF_HDF5 { -CListModeDataGEHDF5:: -CListModeDataGEHDF5(const std::string& listmode_filename) - : listmode_filename(listmode_filename) -{ +CListModeDataGEHDF5::CListModeDataGEHDF5(const std::string& listmode_filename) : listmode_filename(listmode_filename) { if (open_lm_file() == Succeeded::no) - error(boost::format("CListModeDataGEHDF5: error opening the listmode file for filename %s") % - listmode_filename); + error(boost::format("CListModeDataGEHDF5: error opening the listmode file for filename %s") % listmode_filename); } std::string -CListModeDataGEHDF5:: -get_name() const -{ +CListModeDataGEHDF5::get_name() const { return listmode_filename; } std::time_t -CListModeDataGEHDF5:: -get_scan_start_time_in_secs_since_1970() const -{ +CListModeDataGEHDF5::get_scan_start_time_in_secs_since_1970() const { return this->get_exam_info().start_time_in_secs_since_1970; } - -shared_ptr -CListModeDataGEHDF5:: -get_empty_record_sptr() const -{ +shared_ptr +CListModeDataGEHDF5::get_empty_record_sptr() const { if (is_null_ptr(this->get_proj_data_info_sptr())) error("listmode file needs to be opened before calling get_empty_record_sptr()"); - shared_ptr sptr(new CListRecordT(this->get_proj_data_info_sptr()->get_scanner_sptr(), - this->first_time_stamp)); + shared_ptr sptr(new CListRecordT(this->get_proj_data_info_sptr(), this->first_time_stamp)); return sptr; } Succeeded -CListModeDataGEHDF5:: -open_lm_file() -{ +CListModeDataGEHDF5::open_lm_file() { info(boost::format("CListModeDataGEHDF5: opening file %1%") % listmode_filename); - if(!GEHDF5Wrapper::check_GE_signature(listmode_filename)) - { - //! \todo N.E:Write a msg - return Succeeded::no; + if (!GEHDF5Wrapper::check_GE_signature(listmode_filename)) { + //! \todo N.E:Write a msg + return Succeeded::no; } -// input_sptr.reset( new GEHDF5Wrapper(listmode_filename)); + // input_sptr.reset( new GEHDF5Wrapper(listmode_filename)); GEHDF5Wrapper inputFile(listmode_filename); this->set_proj_data_info_sptr(inputFile.get_proj_data_info_sptr()->create_shared_clone()); this->set_exam_info(*inputFile.get_exam_info_sptr()); - this->first_time_stamp = - inputFile.read_dataset_uint32("/HeaderData/ListHeader/firstTmAbsTimeStamp"); - const std::uint32_t last_time_stamp = - inputFile.read_dataset_uint32("/HeaderData/ListHeader/lastTmAbsTimeStamp"); + this->first_time_stamp = inputFile.read_dataset_uint32("/HeaderData/ListHeader/firstTmAbsTimeStamp"); + const std::uint32_t last_time_stamp = inputFile.read_dataset_uint32("/HeaderData/ListHeader/lastTmAbsTimeStamp"); this->lm_duration_in_millisecs = last_time_stamp - this->first_time_stamp; - info(boost::format("First/last time-stamp: %1%/%2%. Duration %3% ms.") - % this->first_time_stamp % last_time_stamp % this->lm_duration_in_millisecs, + info(boost::format("First/last time-stamp: %1%/%2%. Duration %3% ms.") % this->first_time_stamp % last_time_stamp % + this->lm_duration_in_millisecs, 2); //! \todo N.E: Remove hard-coded sizes; (they're stored in GEHDF5Wrapper) - current_lm_data_ptr. - reset( - new InputStreamWithRecordsFromHDF5(listmode_filename, - 6, 16)); + + current_lm_data_ptr.reset(new InputStreamWithRecordsFromHDF5(listmode_filename, 6, 16)); return Succeeded::yes; } Succeeded -CListModeDataGEHDF5:: -get_next_record(CListRecord& record_of_general_type) const -{ +CListModeDataGEHDF5::get_next_record(CListRecord& record_of_general_type) const { CListRecordT& record = static_cast(record_of_general_type); return current_lm_data_ptr->get_next_record(record); } - - Succeeded -CListModeDataGEHDF5:: -reset() -{ +CListModeDataGEHDF5::reset() { return current_lm_data_ptr->reset(); } - CListModeData::SavedPosition -CListModeDataGEHDF5:: -save_get_position() -{ +CListModeDataGEHDF5::save_get_position() { return static_cast(current_lm_data_ptr->save_get_position()); } Succeeded -CListModeDataGEHDF5:: -set_get_position(const CListModeDataGEHDF5::SavedPosition& pos) -{ - return - current_lm_data_ptr->set_get_position(pos); +CListModeDataGEHDF5::set_get_position(const CListModeDataGEHDF5::SavedPosition& pos) { + return current_lm_data_ptr->set_get_position(pos); } -} // namespace -} +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index 6bd87b0dce..ad40c73b16 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -1,5 +1,6 @@ /* Copyright (C) 2015, 2016 University of Leeds + Copyright (C) 2017, 2018 University of Hull Copyright (C) 2016, 2017, 2020 University College London Copyright (C) 2018 University of Hull This file is part of STIR. @@ -38,328 +39,295 @@ START_NAMESPACE_STIR -CListModeDataROOT:: -CListModeDataROOT(const std::string& hroot_filename) - : hroot_filename(hroot_filename) -{ - set_defaults(); - std::string error_str; - int num_virtual_axial_crystals_per_block = -1; // -1 means: use scanner default - int num_virtual_transaxial_crystals_per_block = -1; // -1 means: use scanner default - - this->parser.add_start_key("ROOT header"); - this->parser.add_stop_key("End ROOT header"); - - // Scanner related & Physical dimensions. - this->parser.add_key("originating system", &this->originating_system); - - this->parser.add_key("Number of rings", &this->num_rings); - this->parser.add_key("Number of detectors per ring", &this->num_detectors_per_ring); - this->parser.add_key("Inner ring diameter (cm)", &this->inner_ring_diameter); - this->parser.add_key("Average depth of interaction (cm)", &this->average_depth_of_interaction); - this->parser.add_key("Distance between rings (cm)", &this->ring_spacing); - this->parser.add_key("Default bin size (cm)", &this->bin_size); - this->parser.add_key("View offset (degrees)", &this->view_offset); - this->parser.add_key("Maximum number of non-arc-corrected bins", &this->max_num_non_arccorrected_bins); - this->parser.add_key("Default number of arc-corrected bins", &this->default_num_arccorrected_bins); - this->parser.add_key("Number of virtual axial crystals per block", &num_virtual_axial_crystals_per_block); - this->parser.add_key("Number of virtual transaxial crystals per block", &num_virtual_transaxial_crystals_per_block); - // end Scanner and physical dimensions. - - // ROOT related - this->parser.add_parsing_key("GATE scanner type", &this->root_file_sptr); - if(!this->parser.parse(hroot_filename.c_str())) - error("CListModeDataROOT: error parsing '%s'", hroot_filename.c_str()); - - FilePath f(hroot_filename); - if (root_file_sptr->set_up( f.get_path_only()) == Succeeded::no) - error("CListModeDataROOT: Unable to set_up() from the input Header file (.hroot)."); - - // ExamInfo initialisation - shared_ptr _exam_info_sptr(new ExamInfo); - - // Only PET scanners supported - _exam_info_sptr->imaging_modality = ImagingModality::PT; - _exam_info_sptr->originating_system = this->originating_system; - _exam_info_sptr->set_low_energy_thres(this->root_file_sptr->get_low_energy_thres()); - _exam_info_sptr->set_high_energy_thres(this->root_file_sptr->get_up_energy_thres()); - - this->exam_info_sptr = _exam_info_sptr; - - shared_ptr this_scanner_sptr; - - // If the user set Scanner::User_defined_scanner then the local geometry valiables must be set. - bool give_it_a_try = false; - if (this->originating_system != "User_defined_scanner") // - { - this_scanner_sptr.reset(Scanner::get_scanner_from_name(this->originating_system)); - if (this_scanner_sptr->get_type() == Scanner::Unknown_scanner) - { - warning(boost::format("CListModeDataROOT: Unknown value for originating_system keyword: '%s.\n WIll try to " - "figure out the scanner's geometry from the parameters") % originating_system ); - give_it_a_try = true; - } - else - warning("CListModeDataROOT: I've set the scanner from STIR settings and ignored values in the hroot header."); +CListModeDataROOT::CListModeDataROOT(const std::string& hroot_filename) : hroot_filename(hroot_filename) { + set_defaults(); + std::string error_str; + int num_virtual_axial_crystals_per_block = -1; // -1 means: use scanner default + int num_virtual_transaxial_crystals_per_block = -1; // -1 means: use scanner default + + this->parser.add_start_key("ROOT header"); + this->parser.add_stop_key("End ROOT header"); + + // Scanner related & Physical dimensions. + this->parser.add_key("originating system", &this->originating_system); + + this->parser.add_key("Number of rings", &this->num_rings); + this->parser.add_key("Number of detectors per ring", &this->num_detectors_per_ring); + this->parser.add_key("Inner ring diameter (cm)", &this->inner_ring_diameter); + this->parser.add_key("Average depth of interaction (cm)", &this->average_depth_of_interaction); + this->parser.add_key("Distance between rings (cm)", &this->ring_spacing); + this->parser.add_key("Default bin size (cm)", &this->bin_size); + this->parser.add_key("View offset (degrees)", &this->view_offset); + this->parser.add_key("Maximum number of non-arc-corrected bins", &this->max_num_non_arccorrected_bins); + this->parser.add_key("Default number of arc-corrected bins", &this->default_num_arccorrected_bins); + this->parser.add_key("Number of virtual axial crystals per block", &num_virtual_axial_crystals_per_block); + this->parser.add_key("Number of virtual transaxial crystals per block", &num_virtual_transaxial_crystals_per_block); + // end Scanner and physical dimensions. + + this->parser.add_key("energy resolution", &this->energy_resolution); + this->parser.add_key("reference energy", &this->reference_energy); + + this->parser.add_key("number of TOF time bins", &this->max_num_timing_bins); + this->parser.add_key("Size of timing bin (ps)", &this->size_timing_bin); + this->parser.add_key("Timing resolution (ps)", &this->timing_resolution); + + this->parser.add_key("%TOF mashing factor", &this->tof_mash_factor); + // + + // ROOT related + this->parser.add_parsing_key("GATE scanner type", &this->root_file_sptr); + if (!this->parser.parse(hroot_filename.c_str())) + error("CListModeDataROOT: error parsing '%s'", hroot_filename.c_str()); + + FilePath f(hroot_filename); + if (root_file_sptr->set_up(f.get_path_only()) == Succeeded::no) + error("CListModeDataROOT: Unable to set_up() from the input Header file (.hroot)."); + + // ExamInfo initialisation + shared_ptr _exam_info_sptr(new ExamInfo); + + // Only PET scanners supported + _exam_info_sptr->imaging_modality = ImagingModality::PT; + _exam_info_sptr->originating_system = this->originating_system; + _exam_info_sptr->set_low_energy_thres(this->root_file_sptr->get_low_energy_thres()); + _exam_info_sptr->set_high_energy_thres(this->root_file_sptr->get_up_energy_thres()); + + this->exam_info_sptr = _exam_info_sptr; + + shared_ptr this_scanner_sptr; + + // If the user set Scanner::User_defined_scanner then the local geometry valiables must be set. + bool give_it_a_try = false; + if (this->originating_system != "User_defined_scanner") // + { + this_scanner_sptr.reset(Scanner::get_scanner_from_name(this->originating_system)); + if (this_scanner_sptr->get_type() == Scanner::Unknown_scanner) { + warning(boost::format("CListModeDataROOT: Unknown value for originating_system keyword: '%s.\n WIll try to " + "figure out the scanner's geometry from the parameters") % + originating_system); + give_it_a_try = true; + } else + warning("CListModeDataROOT: I've set the scanner from STIR settings and ignored values in the hroot header."); + } + // If the user provide a Scanner name then, the local variables will be ignored and the Scanner + // will be the selected. + else if (this->originating_system == "User_defined_scanner" || give_it_a_try) { + warning("CListModeDataROOT: Trying to figure out the scanner geometry from the information " + "given in the ROOT header file."); + + if (check_scanner_definition(error_str) == Succeeded::no) { + error(error_str.c_str()); } - // If the user provide a Scanner name then, the local variables will be ignored and the Scanner - // will be the selected. - else if (this->originating_system == "User_defined_scanner" || - give_it_a_try) - { - warning("CListModeDataROOT: Trying to figure out the scanner geometry from the information " - "given in the ROOT header file."); - - if (check_scanner_definition(error_str) == Succeeded::no) - { - error(error_str.c_str()); - } - if (default_num_arccorrected_bins == -1) - { - default_num_arccorrected_bins = max_num_non_arccorrected_bins; - } - - this_scanner_sptr.reset(new Scanner(Scanner::User_defined_scanner, - std::string ("ROOT_defined_scanner"), - /* num dets per ring */ - this->num_detectors_per_ring, - /* num of rings */ - this->num_rings, - /* number of non arccor bins */ - this->max_num_non_arccorrected_bins, - /* number of maximum arccor bins */ - this->default_num_arccorrected_bins, - /* inner ring radius */ - this->inner_ring_diameter/0.2f, - /* doi */ this->average_depth_of_interaction * 10.f, - /* ring spacing */ - this->ring_spacing * 10.f, - this->bin_size * 10.f, - /* offset*/ - this->view_offset * _PI /180, - /*num_axial_blocks_per_bucket_v */ - this->root_file_sptr->get_num_axial_blocks_per_bucket_v(), - /*num_transaxial_blocks_per_bucket_v*/ - this->root_file_sptr->get_num_transaxial_blocks_per_bucket_v(), - /*num_axial_crystals_per_block_v*/ - this->root_file_sptr->get_num_axial_crystals_per_block_v(), - /*num_transaxial_crystals_per_block_v*/ - this->root_file_sptr->get_num_transaxial_crystals_per_block_v(), - /*num_axial_crystals_per_singles_unit_v*/ - this->root_file_sptr->get_num_axial_crystals_per_singles_unit(), - /*num_transaxial_crystals_per_singles_unit_v*/ - this->root_file_sptr->get_num_trans_crystals_per_singles_unit(), - /*num_detector_layers_v*/ 1 )); - } - // have to do this here currently as these variables cannot be set via the constructor - if (num_virtual_axial_crystals_per_block>=0) - this_scanner_sptr->set_num_virtual_axial_crystals_per_block(num_virtual_axial_crystals_per_block); - if (num_virtual_transaxial_crystals_per_block>=0) - this_scanner_sptr->set_num_virtual_transaxial_crystals_per_block(num_virtual_transaxial_crystals_per_block); - // put virtual block info in root_file_sptr - this->root_file_sptr->set_num_virtual_axial_crystals_per_block(this_scanner_sptr->get_num_virtual_axial_crystals_per_block()); - this->root_file_sptr->set_num_virtual_transaxial_crystals_per_block(this_scanner_sptr->get_num_virtual_transaxial_crystals_per_block()); - - // Compare with InputStreamFromROOTFile scanner generated geometry and throw error if wrong. - if (check_scanner_match_geometry(error_str, this_scanner_sptr) == Succeeded::no) - { - error(error_str.c_str()); + if (default_num_arccorrected_bins == -1) { + default_num_arccorrected_bins = max_num_non_arccorrected_bins; } - shared_ptr tmp( ProjDataInfo::construct_proj_data_info(this_scanner_sptr, - 1, - this_scanner_sptr->get_num_rings()-1, - this_scanner_sptr->get_num_detectors_per_ring()/2, - this_scanner_sptr->get_max_num_non_arccorrected_bins(), - /* arc_correction*/false)); - this->set_proj_data_info_sptr(tmp); - - if (this->open_lm_file() == Succeeded::no) - error("CListModeDataROOT: error opening ROOT file for filename '%s'", - hroot_filename.c_str()); + this_scanner_sptr.reset(new Scanner(Scanner::User_defined_scanner, std::string("ROOT_defined_scanner"), + /* num dets per ring */ + this->num_detectors_per_ring, + /* num of rings */ + this->num_rings, + /* number of non arccor bins */ + this->max_num_non_arccorrected_bins, + /* number of maximum arccor bins */ + this->default_num_arccorrected_bins, + /* inner ring radius */ + this->inner_ring_diameter / 0.2f, + /* doi */ this->average_depth_of_interaction * 10.f, + /* ring spacing */ + this->ring_spacing * 10.f, this->bin_size * 10.f, + /* offset*/ + this->view_offset * _PI / 180, + /*num_axial_blocks_per_bucket_v */ + this->root_file_sptr->get_num_axial_blocks_per_bucket_v(), + /*num_transaxial_blocks_per_bucket_v*/ + this->root_file_sptr->get_num_transaxial_blocks_per_bucket_v(), + /*num_axial_crystals_per_block_v*/ + this->root_file_sptr->get_num_axial_crystals_per_block_v(), + /*num_transaxial_crystals_per_block_v*/ + this->root_file_sptr->get_num_transaxial_crystals_per_block_v(), + /*num_axial_crystals_per_singles_unit_v*/ + this->root_file_sptr->get_num_axial_crystals_per_singles_unit(), + /*num_transaxial_crystals_per_singles_unit_v*/ + this->root_file_sptr->get_num_trans_crystals_per_singles_unit(), + /*num_detector_layers_v*/ 1, this->energy_resolution, this->reference_energy, + /* maximum number of timing bins */ + max_num_timing_bins, + /* size of basic TOF bin */ + size_timing_bin, + /* Scanner's timing resolution */ + timing_resolution)); + } + // have to do this here currently as these variables cannot be set via the constructor + if (num_virtual_axial_crystals_per_block >= 0) + this_scanner_sptr->set_num_virtual_axial_crystals_per_block(num_virtual_axial_crystals_per_block); + if (num_virtual_transaxial_crystals_per_block >= 0) + this_scanner_sptr->set_num_virtual_transaxial_crystals_per_block(num_virtual_transaxial_crystals_per_block); + // put virtual block info in root_file_sptr + this->root_file_sptr->set_num_virtual_axial_crystals_per_block(this_scanner_sptr->get_num_virtual_axial_crystals_per_block()); + this->root_file_sptr->set_num_virtual_transaxial_crystals_per_block( + this_scanner_sptr->get_num_virtual_transaxial_crystals_per_block()); + + // Compare with InputStreamFromROOTFile scanner generated geometry and throw error if wrong. + if (check_scanner_match_geometry(error_str, this_scanner_sptr) == Succeeded::no) { + error(error_str.c_str()); + } + + proj_data_info_sptr = std::const_pointer_cast( + ProjDataInfo::construct_proj_data_info(this_scanner_sptr, 1, this_scanner_sptr->get_num_rings() - 1, + this_scanner_sptr->get_num_detectors_per_ring() / 2, + this_scanner_sptr->get_max_num_non_arccorrected_bins(), + /* arc_correction*/ false, tof_mash_factor) + ->create_shared_clone()); + // this->set_proj_data_info_sptr(tmp); + + if (this->open_lm_file() == Succeeded::no) + error("CListModeDataROOT: error opening ROOT file for filename '%s'", hroot_filename.c_str()); } std::string -CListModeDataROOT:: -get_name() const -{ - return hroot_filename; +CListModeDataROOT::get_name() const { + return hroot_filename; } -shared_ptr -CListModeDataROOT:: -get_empty_record_sptr() const -{ - shared_ptr sptr(new CListRecordROOT(this->get_proj_data_info_sptr()->get_scanner_sptr())); - return sptr; +shared_ptr +CListModeDataROOT::get_empty_record_sptr() const { + shared_ptr sptr(new CListRecordROOT(this->get_proj_data_info_sptr())); + return sptr; } Succeeded -CListModeDataROOT:: -open_lm_file() -{ - info(boost::format("CListModeDataROOT: used ROOT file %s") % - this->root_file_sptr->get_ROOT_filename()); - return Succeeded::yes; +CListModeDataROOT::open_lm_file() { + info(boost::format("CListModeDataROOT: used ROOT file %s") % this->root_file_sptr->get_ROOT_filename()); + return Succeeded::yes; } - - Succeeded -CListModeDataROOT:: -get_next_record(CListRecord& record_of_general_type) const -{ - CListRecordROOT& record = dynamic_cast(record_of_general_type); - return root_file_sptr->get_next_record(record); +CListModeDataROOT::get_next_record(CListRecord& record_of_general_type) const { + CListRecordROOT& record = dynamic_cast(record_of_general_type); + return root_file_sptr->get_next_record(record); } Succeeded -CListModeDataROOT:: -reset() -{ - return root_file_sptr->reset(); +CListModeDataROOT::reset() { + return root_file_sptr->reset(); } -unsigned long CListModeDataROOT::get_total_number_of_events() const -{ - return root_file_sptr->get_total_number_of_events(); +unsigned long +CListModeDataROOT::get_total_number_of_events() const { + return root_file_sptr->get_total_number_of_events(); } CListModeData::SavedPosition -CListModeDataROOT:: -save_get_position() -{ - return static_cast(root_file_sptr->save_get_position()); +CListModeDataROOT::save_get_position() { + return static_cast(root_file_sptr->save_get_position()); } Succeeded -CListModeDataROOT:: -set_get_position(const CListModeDataROOT::SavedPosition& pos) -{ - return root_file_sptr->set_get_position(pos); +CListModeDataROOT::set_get_position(const CListModeDataROOT::SavedPosition& pos) { + return root_file_sptr->set_get_position(pos); } void -CListModeDataROOT:: -set_defaults() -{ - num_rings = -1; - num_detectors_per_ring = -1; - max_num_non_arccorrected_bins = -1; - default_num_arccorrected_bins = -1; - inner_ring_diameter = -1.f; - average_depth_of_interaction = -1.f; - ring_spacing = -.1f; - bin_size = -1.f; - view_offset = 0.f; +CListModeDataROOT::set_defaults() { + num_rings = -1; + num_detectors_per_ring = -1; + max_num_non_arccorrected_bins = -1; + default_num_arccorrected_bins = -1; + inner_ring_diameter = -1.f; + average_depth_of_interaction = -1.f; + ring_spacing = -.1f; + bin_size = -1.f; + view_offset = 0.f; } Succeeded -CListModeDataROOT:: -check_scanner_match_geometry(std::string& ret, const shared_ptr& scanner_sptr) -{ - std::ostringstream stream("CListModeDataROOT: The Scanner does not match the GATE geometry. Check: "); - bool ok = true; - - if (scanner_sptr->get_num_rings() != root_file_sptr->get_num_rings()) - { - stream << "the number of rings, "; - ok = false; - } - - if (scanner_sptr->get_num_detectors_per_ring() != root_file_sptr->get_num_dets_per_ring()) - { - stream << "the number of detector per ring, "; - ok = false; - } - - if (scanner_sptr->get_num_axial_blocks_per_bucket() != root_file_sptr->get_num_axial_blocks_per_bucket_v()) - { - stream << "the number of axial blocks per bucket, "; - ok = false; - } - - if(scanner_sptr->get_num_transaxial_blocks_per_bucket() != root_file_sptr->get_num_transaxial_blocks_per_bucket_v()) - { - stream << "the number of transaxial blocks per bucket, "; - ok = false; - } - - if(scanner_sptr->get_num_axial_crystals_per_block() != root_file_sptr->get_num_axial_crystals_per_block_v()) - { - stream << "the number of axial crystals per block, "; - ok = false; - } - - if(scanner_sptr->get_num_transaxial_crystals_per_block() != root_file_sptr->get_num_transaxial_crystals_per_block_v()) - { - stream << "the number of transaxial crystals per block, "; - ok = false; - } - - if(scanner_sptr->get_num_axial_crystals_per_singles_unit() != root_file_sptr->get_num_axial_crystals_per_singles_unit()) - { - stream << "the number of axial crystals per singles unit, "; - ok = false; - } - - if(scanner_sptr->get_num_transaxial_crystals_per_singles_unit() != root_file_sptr->get_num_trans_crystals_per_singles_unit()) - { - stream << "the number of transaxial crystals per singles unit, "; - ok = false; - } - - if (!ok) - { - ret = stream.str(); - return Succeeded::no; - } - - return Succeeded::yes; +CListModeDataROOT::check_scanner_match_geometry(std::string& ret, const shared_ptr& scanner_sptr) { + std::ostringstream stream("CListModeDataROOT: The Scanner does not match the GATE geometry. Check: "); + bool ok = true; + + if (scanner_sptr->get_num_rings() != root_file_sptr->get_num_rings()) { + stream << "the number of rings, "; + ok = false; + } + + if (scanner_sptr->get_num_detectors_per_ring() != root_file_sptr->get_num_dets_per_ring()) { + stream << "the number of detector per ring, "; + ok = false; + } + + if (scanner_sptr->get_num_axial_blocks_per_bucket() != root_file_sptr->get_num_axial_blocks_per_bucket_v()) { + stream << "the number of axial blocks per bucket, "; + ok = false; + } + + if (scanner_sptr->get_num_transaxial_blocks_per_bucket() != root_file_sptr->get_num_transaxial_blocks_per_bucket_v()) { + stream << "the number of transaxial blocks per bucket, "; + ok = false; + } + + if (scanner_sptr->get_num_axial_crystals_per_block() != root_file_sptr->get_num_axial_crystals_per_block_v()) { + stream << "the number of axial crystals per block, "; + ok = false; + } + + if (scanner_sptr->get_num_transaxial_crystals_per_block() != root_file_sptr->get_num_transaxial_crystals_per_block_v()) { + stream << "the number of transaxial crystals per block, "; + ok = false; + } + + if (scanner_sptr->get_num_axial_crystals_per_singles_unit() != root_file_sptr->get_num_axial_crystals_per_singles_unit()) { + stream << "the number of axial crystals per singles unit, "; + ok = false; + } + + if (scanner_sptr->get_num_transaxial_crystals_per_singles_unit() != root_file_sptr->get_num_trans_crystals_per_singles_unit()) { + stream << "the number of transaxial crystals per singles unit, "; + ok = false; + } + + if (!ok) { + ret = stream.str(); + return Succeeded::no; + } + + return Succeeded::yes; } Succeeded -CListModeDataROOT:: -check_scanner_definition(std::string& ret) -{ - if ( num_rings == -1 || - num_detectors_per_ring == -1 || - max_num_non_arccorrected_bins == -1 || - inner_ring_diameter == -1.f || - average_depth_of_interaction == -1.f || - ring_spacing == -.1f || - bin_size == -1.f ) - { - std::ostringstream stream("CListModeDataROOT: The User_defined_scanner has not been fully described.\nPlease include in the hroot:\n"); +CListModeDataROOT::check_scanner_definition(std::string& ret) { + if (num_rings == -1 || num_detectors_per_ring == -1 || max_num_non_arccorrected_bins == -1 || inner_ring_diameter == -1.f || + average_depth_of_interaction == -1.f || ring_spacing == -.1f || bin_size == -1.f) { + std::ostringstream stream( + "CListModeDataROOT: The User_defined_scanner has not been fully described.\nPlease include in the hroot:\n"); - if (num_rings == -1) - stream << "Number of rings := \n"; + if (num_rings == -1) + stream << "Number of rings := \n"; - if (num_detectors_per_ring == -1) - stream << "Number of detectors per ring := \n"; + if (num_detectors_per_ring == -1) + stream << "Number of detectors per ring := \n"; - if (max_num_non_arccorrected_bins == -1) - stream << "Maximum number of non-arc-corrected bins := \n"; + if (max_num_non_arccorrected_bins == -1) + stream << "Maximum number of non-arc-corrected bins := \n"; - if (inner_ring_diameter == -1) - stream << "Inner ring diameter (cm) := \n"; + if (inner_ring_diameter == -1) + stream << "Inner ring diameter (cm) := \n"; - if (average_depth_of_interaction == -1) - stream << "Average depth of interaction (cm) := \n"; + if (average_depth_of_interaction == -1) + stream << "Average depth of interaction (cm) := \n"; - if (ring_spacing == -1) - stream << "Distance between rings (cm) := \n"; + if (ring_spacing == -1) + stream << "Distance between rings (cm) := \n"; - if (bin_size == -1) - stream << "Default bin size (cm) := \n"; + if (bin_size == -1) + stream << "Default bin size (cm) := \n"; - ret = stream.str(); + ret = stream.str(); - return Succeeded::no; - } + return Succeeded::no; + } - return Succeeded::yes; + return Succeeded::yes; } - END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/CListModeDataSAFIR.cxx b/src/listmode_buildblock/CListModeDataSAFIR.cxx index 4baf4382a7..541d7eef2a 100644 --- a/src/listmode_buildblock/CListModeDataSAFIR.cxx +++ b/src/listmode_buildblock/CListModeDataSAFIR.cxx @@ -2,20 +2,20 @@ Coincidence LM Data Class for SAFIR: Implementation - Copyright 2015 ETH Zurich, Institute of Particle Physics - Copyright 2020 Positrigo AG, Zurich + Copyright 2015 ETH Zurich, Institute of Particle Physics + Copyright 2020 Positrigo AG, Zurich - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ #include @@ -40,86 +40,70 @@ using std::istream; START_NAMESPACE_STIR; - template -CListModeDataSAFIR:: -CListModeDataSAFIR(const std::string& listmode_filename, const std::string& crystal_map_filename, const std::string& template_proj_data_filename, const double lor_randomization_sigma) - : listmode_filename(listmode_filename), map(MAKE_SHARED(crystal_map_filename, lor_randomization_sigma)) -{ - this->exam_info_sptr.reset(new ExamInfo); - - // Here we are reading the scanner data from the template projdata - shared_ptr template_proj_data_sptr = - ProjData::read_from_file(template_proj_data_filename); - this->set_proj_data_info_sptr(template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone()); - - if( open_lm_file() == Succeeded::no ) - { - error("CListModeDataSAFIR: Could not open listmode file " +listmode_filename + "\n"); - } +CListModeDataSAFIR::CListModeDataSAFIR(const std::string& listmode_filename, + const std::string& crystal_map_filename, + const std::string& template_proj_data_filename, + const double lor_randomization_sigma) + : listmode_filename(listmode_filename), + map(MAKE_SHARED(crystal_map_filename, lor_randomization_sigma)) { + this->exam_info_sptr.reset(new ExamInfo); + + // Here we are reading the scanner data from the template projdata + shared_ptr template_proj_data_sptr = ProjData::read_from_file(template_proj_data_filename); + this->set_proj_data_info_sptr(template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone()); + + if (open_lm_file() == Succeeded::no) { + error("CListModeDataSAFIR: Could not open listmode file " + listmode_filename + "\n"); + } } - template std::string -CListModeDataSAFIR:: -get_name() const -{ - return listmode_filename; +CListModeDataSAFIR::get_name() const { + return listmode_filename; } template -shared_ptr -CListModeDataSAFIR:: -get_empty_record_sptr() const -{ - shared_ptr sptr(new CListRecordSAFIR); - sptr->event_SAFIR().set_map(map); - return static_pointer_cast(sptr); +shared_ptr +CListModeDataSAFIR::get_empty_record_sptr() const { + shared_ptr sptr(new CListRecordSAFIR); + sptr->event_SAFIR().set_map(map); + return static_pointer_cast(sptr); } template Succeeded -CListModeDataSAFIR:: -get_next_record(CListRecord& record_of_general_type) const -{ - CListRecordT& record = static_cast(record_of_general_type); - Succeeded status = current_lm_data_ptr->get_next_record(record); - if( status == Succeeded::yes ) record.event_SAFIR().set_map(map); - return status; - +CListModeDataSAFIR::get_next_record(CListRecord& record_of_general_type) const { + CListRecordT& record = static_cast(record_of_general_type); + Succeeded status = current_lm_data_ptr->get_next_record(record); + if (status == Succeeded::yes) + record.event_SAFIR().set_map(map); + return status; } template Succeeded -CListModeDataSAFIR:: -reset() -{ - return current_lm_data_ptr->reset(); +CListModeDataSAFIR::reset() { + return current_lm_data_ptr->reset(); } template Succeeded -CListModeDataSAFIR:: -open_lm_file() const -{ - cerr << "CListModeDataSAFIR: opening file " << listmode_filename << endl; - shared_ptr stream_ptr(new fstream(listmode_filename.c_str(), ios::in | ios::binary )); - if(!(*stream_ptr)) - { - warning("CListModeDataSAFIR: cannot open file " + listmode_filename + "\n"); - return Succeeded::no; - } - stream_ptr->seekg((std::streamoff)32); - current_lm_data_ptr.reset( - new InputStreamWithRecords - ( stream_ptr, sizeof(CListTimeDataSAFIR), - sizeof(CListTimeDataSAFIR), - ByteOrder::little_endian !=ByteOrder::get_native_order())); - return Succeeded::yes; +CListModeDataSAFIR::open_lm_file() const { + cerr << "CListModeDataSAFIR: opening file " << listmode_filename << endl; + shared_ptr stream_ptr(new fstream(listmode_filename.c_str(), ios::in | ios::binary)); + if (!(*stream_ptr)) { + warning("CListModeDataSAFIR: cannot open file " + listmode_filename + "\n"); + return Succeeded::no; + } + stream_ptr->seekg((std::streamoff)32); + current_lm_data_ptr.reset( + new InputStreamWithRecords(stream_ptr, sizeof(CListTimeDataSAFIR), sizeof(CListTimeDataSAFIR), + ByteOrder::little_endian != ByteOrder::get_native_order())); + return Succeeded::yes; } - + template class CListModeDataSAFIR; END_NAMESPACE_STIR - diff --git a/src/listmode_buildblock/CListRecordECAT8_32bit.cxx b/src/listmode_buildblock/CListRecordECAT8_32bit.cxx index 693caf53dc..b5306f922f 100644 --- a/src/listmode_buildblock/CListRecordECAT8_32bit.cxx +++ b/src/listmode_buildblock/CListRecordECAT8_32bit.cxx @@ -17,9 +17,9 @@ /*! \file \ingroup listmode - \brief Implementation of classes stir::ecat::CListEventECAT8_32bit and stir::ecat::CListRecordECAT8_32bit + \brief Implementation of classes stir::ecat::CListEventECAT8_32bit and stir::ecat::CListRecordECAT8_32bit for listmode events for the ECAT8 32bit listmode file format. - + \author Kris Thielemans */ @@ -34,64 +34,54 @@ START_NAMESPACE_STIR namespace ecat { -CListEventECAT8_32bit:: -CListEventECAT8_32bit(const shared_ptr& proj_data_info_sptr) : - CListEventCylindricalScannerWithDiscreteDetectors(shared_ptr(new Scanner(*proj_data_info_sptr->get_scanner_ptr()))) -{ - const ProjDataInfoCylindricalNoArcCorr * const proj_data_info_ptr = - dynamic_cast(proj_data_info_sptr.get()); +CListEventECAT8_32bit::CListEventECAT8_32bit(const shared_ptr& proj_data_info_sptr) + : CListEventCylindricalScannerWithDiscreteDetectors(proj_data_info_sptr) { + const ProjDataInfoCylindricalNoArcCorr* const proj_data_info_ptr = + dynamic_cast(proj_data_info_sptr.get()); if (proj_data_info_ptr == 0) error("CListEventECAT8_32bit can only be initialised with cylindrical projection data without arc-correction"); - if (proj_data_info_ptr->get_max_ring_difference(0) != proj_data_info_ptr->get_min_ring_difference(0)) - error("CListEventECAT8_32bit can only handle axial compression==1"); + if (proj_data_info_ptr->get_max_ring_difference(0) != proj_data_info_ptr->get_min_ring_difference(0)) + error(boost::format( + "CListEventECAT8_32bit can only handle axial compression==1, got segment 0 min/max RD: %s,%s") + % proj_data_info_ptr->get_max_ring_difference(0) % proj_data_info_ptr->get_min_ring_difference(0)); - this->segment_sequence = ecat::find_segment_sequence(*proj_data_info_ptr); - this->sizes.resize(this->segment_sequence.size()); - for (std::size_t s=0U; s < this->segment_sequence.size(); ++s) - this->sizes[s]=proj_data_info_ptr->get_num_axial_poss(segment_sequence[s]); + this->segment_sequence = ecat::find_segment_sequence(*proj_data_info_ptr); + this->sizes.resize(this->segment_sequence.size()); + for (std::size_t s = 0U; s < this->segment_sequence.size(); ++s) + this->sizes[s] = proj_data_info_ptr->get_num_axial_poss(segment_sequence[s]); } void -CListEventECAT8_32bit:: -get_detection_position(DetectionPositionPair<>& det_pos) const -{ +CListEventECAT8_32bit::get_detection_position(DetectionPositionPair<>& det_pos) const { /* data is organised by segment, axial coordinate, view, tangential */ - const int num_tangential_poss = this->scanner_sptr->get_default_num_arccorrected_bins(); - const int num_views = this->scanner_sptr->get_num_detectors_per_ring()/2; + const int num_tangential_poss = this->uncompressed_proj_data_info_sptr->get_scanner_ptr()->get_default_num_arccorrected_bins(); + const int num_views = this->uncompressed_proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring() / 2; - const int tang_pos_num = this->data.offset % num_tangential_poss;//(this->num_sinograms * this-> num_views); + const int tang_pos_num = this->data.offset % num_tangential_poss; //(this->num_sinograms * this-> num_views); const int rest = this->data.offset / num_tangential_poss; const int view_num = rest % num_views; int z = rest / num_views; int axial_pos_num = 0; int segment_num = 0; - for (std::size_t i=0; isegment_sequence.size();++i) - { - if (z< this->sizes[i]) - { - axial_pos_num = z; - segment_num = this->segment_sequence[i]; - break; - } - else - { - z -= this->sizes[i]; - } + for (std::size_t i = 0; i < this->segment_sequence.size(); ++i) { + if (z < this->sizes[i]) { + axial_pos_num = z; + segment_num = this->segment_sequence[i]; + break; + } else { + z -= this->sizes[i]; } + } // this is actually a compressed bin for many Siemens scanners. would have to go to det_pos somehow, or overload get_bin - const Bin uncompressed_bin(segment_num, view_num, axial_pos_num,tang_pos_num - (num_tangential_poss/2)); - this->get_uncompressed_proj_data_info_sptr()->get_det_pos_pair_for_bin(det_pos,uncompressed_bin); + const Bin uncompressed_bin(segment_num, view_num, axial_pos_num, tang_pos_num - (num_tangential_poss / 2)); + this->get_uncompressed_proj_data_info_sptr()->get_det_pos_pair_for_bin(det_pos, uncompressed_bin); } void -CListEventECAT8_32bit:: -set_detection_position(const DetectionPositionPair<>&) -{ +CListEventECAT8_32bit::set_detection_position(const DetectionPositionPair<>&) { error("cannot set events yet"); } - - } // namespace ecat END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/CListRecordECAT962.cxx b/src/listmode_buildblock/CListRecordECAT962.cxx index ce4fcda683..7e06f82cf2 100644 --- a/src/listmode_buildblock/CListRecordECAT962.cxx +++ b/src/listmode_buildblock/CListRecordECAT962.cxx @@ -21,9 +21,9 @@ \ingroup listmode \brief Implementation of classes CListEventECAT962 and CListRecordECAT962 for listmode events for the ECAT 962 (aka Exact HR+). - + \author Kris Thielemans - + */ #include "stir/listmode/CListRecordECAT962.h" @@ -35,57 +35,48 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 - /* Global Definitions */ -static const int MAXPROJBIN = 512; +static const int MAXPROJBIN = 512; /* data for the 962 scanner */ static const int CRYSTALRINGSPERDETECTOR = 8; -//TODO NK check +// TODO NK check void -CListEventDataECAT962:: -get_sinogram_and_ring_coordinates( - int& view_num, int& tangential_pos_num, unsigned int& ring_a, unsigned int& ring_b) const -{ +CListEventDataECAT962::get_sinogram_and_ring_coordinates(int& view_num, int& tangential_pos_num, unsigned int& ring_a, + unsigned int& ring_b) const { const int NumProjBins = MAXPROJBIN; const int NumProjBinsBy2 = MAXPROJBIN / 2; view_num = view; tangential_pos_num = bin; /* KT 31/05/98 use >= in comparison now */ - if ( tangential_pos_num >= NumProjBinsBy2 ) - tangential_pos_num -= NumProjBins ; + if (tangential_pos_num >= NumProjBinsBy2) + tangential_pos_num -= NumProjBins; - ring_a = ( (block_A_ring_bit0 + 2*block_A_ring_bit1) - * CRYSTALRINGSPERDETECTOR ) + block_A_detector ; - ring_b = ( (block_B_ring_bit0 + 2*block_B_ring_bit1) - * CRYSTALRINGSPERDETECTOR ) + block_B_detector ; + ring_a = ((block_A_ring_bit0 + 2 * block_A_ring_bit1) * CRYSTALRINGSPERDETECTOR) + block_A_detector; + ring_b = ((block_B_ring_bit0 + 2 * block_B_ring_bit1) * CRYSTALRINGSPERDETECTOR) + block_B_detector; } -void -CListEventDataECAT962:: -set_sinogram_and_ring_coordinates( - const int view_num, const int tangential_pos_num, - const unsigned int ring_a, const unsigned int ring_b) -{ +void +CListEventDataECAT962::set_sinogram_and_ring_coordinates(const int view_num, const int tangential_pos_num, + const unsigned int ring_a, const unsigned int ring_b) { const int NumProjBins = MAXPROJBIN; type = 0; - const unsigned int block_A_ring = ring_a / CRYSTALRINGSPERDETECTOR; + const unsigned int block_A_ring = ring_a / CRYSTALRINGSPERDETECTOR; block_A_detector = ring_a % CRYSTALRINGSPERDETECTOR; - const unsigned int block_B_ring = ring_b / CRYSTALRINGSPERDETECTOR; + const unsigned int block_B_ring = ring_b / CRYSTALRINGSPERDETECTOR; block_B_detector = ring_b % CRYSTALRINGSPERDETECTOR; - assert(block_A_ring<4); + assert(block_A_ring < 4); block_A_ring_bit0 = block_A_ring | 0x1; - block_A_ring_bit1 = block_A_ring/2; - assert(block_B_ring<4); + block_A_ring_bit1 = block_A_ring / 2; + assert(block_B_ring < 4); block_B_ring_bit0 = block_B_ring | 0x1; - block_B_ring_bit1 = block_B_ring/2; - + block_B_ring_bit1 = block_B_ring / 2; + bin = tangential_pos_num < 0 ? tangential_pos_num + NumProjBins : tangential_pos_num; view = view_num; } - END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/CListRecordECAT966.cxx b/src/listmode_buildblock/CListRecordECAT966.cxx index 84fb644433..9dd7978897 100644 --- a/src/listmode_buildblock/CListRecordECAT966.cxx +++ b/src/listmode_buildblock/CListRecordECAT966.cxx @@ -19,11 +19,11 @@ /*! \file \ingroup listmode - \brief Implementation of classes CListEventECAT966 and CListRecordECAT966 + \brief Implementation of classes CListEventECAT966 and CListRecordECAT966 for listmode events for the ECAT 966 (aka Exact 3d). - + \author Kris Thielemans - + */ #include "stir/listmode/CListRecordECAT966.h" @@ -39,47 +39,40 @@ START_NAMESPACE_ECAT7 // static members /* Global Definitions */ -static const int MAXPROJBIN = 512; +static const int MAXPROJBIN = 512; /* data for the 966 scanner */ static const int CRYSTALRINGSPERDETECTOR = 8; void -CListEventDataECAT966:: -get_sinogram_and_ring_coordinates( - int& view_num, int& tangential_pos_num, unsigned int& ring_a, unsigned int& ring_b) const -{ +CListEventDataECAT966::get_sinogram_and_ring_coordinates(int& view_num, int& tangential_pos_num, unsigned int& ring_a, + unsigned int& ring_b) const { const int NumProjBins = MAXPROJBIN; const int NumProjBinsBy2 = MAXPROJBIN / 2; view_num = view; tangential_pos_num = bin; /* KT 31/05/98 use >= in comparison now */ - if ( tangential_pos_num >= NumProjBinsBy2 ) - tangential_pos_num -= NumProjBins ; + if (tangential_pos_num >= NumProjBinsBy2) + tangential_pos_num -= NumProjBins; - ring_a = ( block_A_ring * CRYSTALRINGSPERDETECTOR ) + block_A_detector ; - ring_b = ( block_B_ring * CRYSTALRINGSPERDETECTOR ) + block_B_detector ; + ring_a = (block_A_ring * CRYSTALRINGSPERDETECTOR) + block_A_detector; + ring_b = (block_B_ring * CRYSTALRINGSPERDETECTOR) + block_B_detector; } -void -CListEventDataECAT966:: -set_sinogram_and_ring_coordinates( - const int view_num, const int tangential_pos_num, - const int ring_a, const int ring_b) -{ +void +CListEventDataECAT966::set_sinogram_and_ring_coordinates(const int view_num, const int tangential_pos_num, const int ring_a, + const int ring_b) { const int NumProjBins = MAXPROJBIN; type = 0; - block_A_ring = ring_a / CRYSTALRINGSPERDETECTOR; + block_A_ring = ring_a / CRYSTALRINGSPERDETECTOR; block_A_detector = ring_a % CRYSTALRINGSPERDETECTOR; - block_B_ring = ring_b / CRYSTALRINGSPERDETECTOR; + block_B_ring = ring_b / CRYSTALRINGSPERDETECTOR; block_B_detector = ring_b % CRYSTALRINGSPERDETECTOR; bin = tangential_pos_num < 0 ? tangential_pos_num + NumProjBins : tangential_pos_num; view = view_num; } - - END_NAMESPACE_ECAT7 END_NAMESPACE_ECAT END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/CListRecordROOT.cxx b/src/listmode_buildblock/CListRecordROOT.cxx index 872656ff5d..bd7df2ed49 100644 --- a/src/listmode_buildblock/CListRecordROOT.cxx +++ b/src/listmode_buildblock/CListRecordROOT.cxx @@ -1,6 +1,7 @@ /* Copyright (C) 2015-2016 University of Leeds Copyright (C) 2016 UCL + Copyright (C) 2017, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -29,12 +30,9 @@ START_NAMESPACE_STIR - -CListEventROOT:: -CListEventROOT(const shared_ptr& scanner_sptr) : - CListEventCylindricalScannerWithDiscreteDetectors(scanner_sptr) -{ - quarter_of_detectors = static_cast(scanner_sptr->get_num_detectors_per_ring()/4.f); +CListEventROOT::CListEventROOT(const shared_ptr& proj_data_info) + : CListEventCylindricalScannerWithDiscreteDetectors(proj_data_info) { + quarter_of_detectors = static_cast(proj_data_info->get_scanner_ptr()->get_num_detectors_per_ring() / 4.f); } //! @@ -42,58 +40,45 @@ CListEventROOT(const shared_ptr& scanner_sptr) : //! \param det_pos //! \author Nikos Efthimiou //! -void CListEventROOT::get_detection_position(DetectionPositionPair<>& _det_pos) const -{ +void +CListEventROOT::get_detection_position(DetectionPositionPair<>& _det_pos) const { - DetectionPosition<> det1(this->det1, this->ring1, 0); - DetectionPosition<> det2(this->det2, this->ring2, 0); + DetectionPosition<> det1(this->det1, this->ring1, 0); + DetectionPosition<> det2(this->det2, this->ring2, 0); - _det_pos.pos1() = det1; - _det_pos.pos2() = det2; + _det_pos.pos1() = det1; + _det_pos.pos2() = det2; + _det_pos.timing_pos() = this->get_uncompressed_proj_data_info_sptr()->get_tof_bin(delta_time); + // _det_pos.timing_pos() = this->get_uncompressed_proj_data_info_sptr()->get_unmashed_tof_bin(delta_time); } -void CListEventROOT::set_detection_position(const DetectionPositionPair<>&) -{ - error("Cannot set events in a ROOT file!"); +void +CListEventROOT::set_detection_position(const DetectionPositionPair<>&) { + error("Cannot set events in a ROOT file!"); } -void CListEventROOT::init_from_data(const int& _ring1, const int& _ring2, - const int& crystal1, const int& crystal2) -{ -// if (crystal1 < 0 ) -// det1 = scanner_sptr->get_num_detectors_per_ring() + crystal1; -// else if ( crystal1 >= scanner_sptr->get_num_detectors_per_ring()) -// det1 = crystal1 - scanner_sptr->get_num_detectors_per_ring(); -// else -// det1 = crystal1; - -// if (crystal2 < 0 ) -// det2 = scanner_sptr->get_num_detectors_per_ring() + crystal2; -// else if ( crystal2 >= scanner_sptr->get_num_detectors_per_ring()) -// det2 = crystal2 - scanner_sptr->get_num_detectors_per_ring(); -// else -// det2 = crystal2; - - // STIR assumes that 0 is on y whill GATE on the x axis - det1 = crystal1 + quarter_of_detectors; - det2 = crystal2 + quarter_of_detectors; - - if (det1 < 0 ) - det1 = scanner_sptr->get_num_detectors_per_ring() + det1; - else if ( det1 >= scanner_sptr->get_num_detectors_per_ring()) - det1 = det1 - scanner_sptr->get_num_detectors_per_ring(); - - if (det2 < 0 ) - det2 = scanner_sptr->get_num_detectors_per_ring() + det2; - else if ( det2 >= scanner_sptr->get_num_detectors_per_ring()) - det2 = det2 - scanner_sptr->get_num_detectors_per_ring(); - - ring1 = _ring1; - ring2 = _ring2; - #ifdef STIR_TOF - delta_time = _delta_time; - #endif - swapped = false; +void +CListEventROOT::init_from_data(const int& _ring1, const int& _ring2, const int& crystal1, const int& crystal2, + const double& _delta_time) { + + // STIR assumes that 0 is on y whill GATE on the x axis + det1 = crystal1 + quarter_of_detectors; + det2 = crystal2 + quarter_of_detectors; + + if (det1 < 0) + det1 = this->uncompressed_proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring() + det1; + else if (det1 >= this->uncompressed_proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring()) + det1 = det1 - this->uncompressed_proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring(); + + if (det2 < 0) + det2 = this->uncompressed_proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring() + det2; + else if (det2 >= this->uncompressed_proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring()) + det2 = det2 - this->uncompressed_proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring(); + + ring1 = _ring1; + ring2 = _ring2; + delta_time = _delta_time; + swapped = false; } END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/DetectorCoordinateMapFromFile.cxx b/src/listmode_buildblock/DetectorCoordinateMapFromFile.cxx index af06cff109..ef89bb7b5d 100644 --- a/src/listmode_buildblock/DetectorCoordinateMapFromFile.cxx +++ b/src/listmode_buildblock/DetectorCoordinateMapFromFile.cxx @@ -2,58 +2,62 @@ Read List-Mode Event Data using map from file: Implementation - Copyright 2015 ETH Zurich, Institute of Particle Physics + Copyright 2015 ETH Zurich, Institute of Particle Physics - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ #include "stir/error.h" #include "stir/listmode/DetectorCoordinateMapFromFile.h" START_NAMESPACE_STIR - -void DetectorCoordinateMapFromFile::read_detectormap_from_file( const std::string& filename ) -{ - std::ifstream myfile(filename.c_str()); - if( !myfile ) - { - error("Error opening file " + filename + ".\n"); - return; - } - -// char line[80]; - std::string line; - while( std::getline( myfile, line)) - { - if( line.size() && line[0] == '#' ) continue; - bool has_layer_index = false; - stir::CartesianCoordinate3D coord; - stir::DetectionPosition<> detpos; - std::vector col; - boost::split(col, line, boost::is_any_of("\t,")); - if( !col.size() ) break; - else if( col.size() == 5 ) has_layer_index = false; - else if( col.size() == 6 ) has_layer_index = true; - coord[1] = static_cast(atof(col[4+has_layer_index].c_str() )); - coord[2] = static_cast(atof(col[3+has_layer_index].c_str() )); - coord[3] = static_cast(atof(col[2+has_layer_index].c_str() )); - - if( !has_layer_index ) detpos.radial_coord() = 0; - else detpos.radial_coord() = atoi(col[2].c_str()); - detpos.axial_coord() = atoi(col[0].c_str()); - detpos.tangential_coord() = atoi(col[1].c_str()); - - coord_map[detpos] = coord; - } + +void +DetectorCoordinateMapFromFile::read_detectormap_from_file(const std::string& filename) { + std::ifstream myfile(filename.c_str()); + if (!myfile) { + error("Error opening file " + filename + ".\n"); + return; + } + + // char line[80]; + std::string line; + while (std::getline(myfile, line)) { + if (line.size() && line[0] == '#') + continue; + bool has_layer_index = false; + stir::CartesianCoordinate3D coord; + stir::DetectionPosition<> detpos; + std::vector col; + boost::split(col, line, boost::is_any_of("\t,")); + if (!col.size()) + break; + else if (col.size() == 5) + has_layer_index = false; + else if (col.size() == 6) + has_layer_index = true; + coord[1] = static_cast(atof(col[4 + has_layer_index].c_str())); + coord[2] = static_cast(atof(col[3 + has_layer_index].c_str())); + coord[3] = static_cast(atof(col[2 + has_layer_index].c_str())); + + if (!has_layer_index) + detpos.radial_coord() = 0; + else + detpos.radial_coord() = atoi(col[2].c_str()); + detpos.axial_coord() = atoi(col[0].c_str()); + detpos.tangential_coord() = atoi(col[1].c_str()); + + coord_map[detpos] = coord; + } } END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/ListEvent.cxx b/src/listmode_buildblock/ListEvent.cxx index b0d29651f9..c40bf48889 100644 --- a/src/listmode_buildblock/ListEvent.cxx +++ b/src/listmode_buildblock/ListEvent.cxx @@ -4,7 +4,7 @@ \file \ingroup listmode \brief Implementations of class stir::ListEvent. - + \author Daniel Deidda \author Kris Thielemans @@ -27,7 +27,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/listmode/ListRecord.h" #include "stir/ProjDataInfo.h" #include "stir/Bin.h" @@ -36,12 +35,9 @@ START_NAMESPACE_STIR -void -ListEvent:: -get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const -{ +void +ListEvent::get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const { bin = proj_data_info.get_bin(get_LOR()); } END_NAMESPACE_STIR - diff --git a/src/listmode_buildblock/ListModeData.cxx b/src/listmode_buildblock/ListModeData.cxx index e223c85eac..ac8fcd97bb 100644 --- a/src/listmode_buildblock/ListModeData.cxx +++ b/src/listmode_buildblock/ListModeData.cxx @@ -31,37 +31,27 @@ START_NAMESPACE_STIR -ListModeData:: -ListModeData() -{ -} +ListModeData::ListModeData() {} -ListModeData:: -~ListModeData() -{} +ListModeData::~ListModeData() {} -const Scanner* -ListModeData:: -get_scanner_ptr() const -{ - if(is_null_ptr(proj_data_info_sptr)) - error("ListModeData: ProjDataInfo has not been set."); - return proj_data_info_sptr->get_scanner_ptr(); +shared_ptr +ListModeData::get_scanner_ptr() const { + if (is_null_ptr(proj_data_info_sptr)) + error("ListModeData: ProjDataInfo has not been set."); + return proj_data_info_sptr->get_scanner_sptr(); } void -ListModeData:: -set_proj_data_info_sptr(shared_ptr new_proj_data_info_sptr) -{ - proj_data_info_sptr = new_proj_data_info_sptr; +ListModeData::set_proj_data_info_sptr(shared_ptr new_proj_data_info_sptr) { + proj_data_info_sptr = new_proj_data_info_sptr->create_shared_clone(); } shared_ptr -ListModeData::get_proj_data_info_sptr() const -{ - if(is_null_ptr(proj_data_info_sptr)) - error("ListModeData: ProjDataInfo has not been set."); - return proj_data_info_sptr; +ListModeData::get_proj_data_info_sptr() const { + if (is_null_ptr(proj_data_info_sptr)) + error("ListModeData: ProjDataInfo has not been set."); + return proj_data_info_sptr; } #if 0 diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 160d8d3b47..6ca365ed6d 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -1,15 +1,17 @@ /*! - \file + \file \ingroup listmode \brief Implementation of class stir::LmToProjData - + + \author Nikos Efthimiou \author Kris Thielemans \author Sanida Mustafovic */ /* Copyright (C) 2000 - 2011-12-31, Hammersmith Imanet Ltd Copyright (C) 2013, University College London + Copyright (C) 2017, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -26,8 +28,8 @@ */ /* Possible compilation switches: - -USE_SegmentByView + +USE_SegmentByView Currently our ProjData classes store segments as floats, which is a waste of memory and time for simple binning of listmode data. This should be remedied at some point by having member template functions to allow different @@ -39,7 +41,7 @@ USE_SegmentByView FRAME_BASED_DT_CORR: dead-time correction based on the frame, or on the time of the event -*/ +*/ // (Note: can currently NOT be disabled) #define USE_SegmentByView @@ -48,16 +50,15 @@ USE_SegmentByView // set elem_type to what you want to use for the sinogram elements // we need a signed type, as randoms can be subtracted. However, signed char could do. -#if defined(USE_SegmentByView) - typedef float elem_type; +#if defined(USE_SegmentByView) +typedef float elem_type; # define OUTPUTNumericType NumericType::FLOAT #else - #error currently problem with normalisation code! - typedef short elem_type; +# error currently problem with normalisation code! +typedef short elem_type; # define OUTPUTNumericType NumericType::SHORT #endif - #include "stir/utilities.h" #include "stir/listmode/LmToProjData.h" @@ -68,13 +69,13 @@ USE_SegmentByView #include "stir/Scanner.h" #ifdef USE_SegmentByView -#include "stir/ProjDataInterfile.h" -#include "stir/SegmentByView.h" +# include "stir/ProjDataInterfile.h" +# include "stir/SegmentByView.h" #else -#include "stir/ProjDataFromStream.h" -#include "stir/IO/interfile.h" -#include "stir/Array.h" -#include "stir/IndexRange3D.h" +# include "stir/ProjDataFromStream.h" +# include "stir/IO/interfile.h" +# include "stir/Array.h" +# include "stir/IndexRange3D.h" #endif #include "stir/IO/read_from_file.h" #include "stir/ParsingObject.h" @@ -109,245 +110,191 @@ START_NAMESPACE_STIR #ifdef USE_SegmentByView typedef SegmentByView segment_type; #else -#error does not work at the moment +# error does not work at the moment #endif /******************** Prototypes for local routines ************************/ +static void allocate_segments(VectorWithOffset>& segments, const int start_timing_pos_index, + const int end_timing_pos_index, const int start_segment_index, const int end_segment_index, + const shared_ptr proj_data_info_ptr); - -static void -allocate_segments(VectorWithOffset& segments, - const int start_segment_index, - const int end_segment_index, - const shared_ptr proj_data_info_sptr); - -// In the next 2 functions, the 'output' parameter needs to be passed +// In the next 2 functions, the 'output' parameter needs to be passed // because save_and_delete_segments needs it when we're not using SegmentByView /* last parameter only used if USE_SegmentByView first parameter only used when not USE_SegmentByView - */ -static void -save_and_delete_segments(shared_ptr& output, - VectorWithOffset& segments, - const int start_segment_index, - const int end_segment_index, - ProjData& proj_data); -static -shared_ptr -construct_proj_data(shared_ptr& output, - const string& output_filename, - const ExamInfo& exam_info, - const shared_ptr& proj_data_info_ptr); + */ +static void save_and_delete_segments(shared_ptr& output, VectorWithOffset>& segments, + const int start_timing_pos_index, const int end_timing_pos_index, + const int start_segment_index, const int end_segment_index, ProjData& proj_data); +static shared_ptr construct_proj_data(shared_ptr& output, const string& output_filename, + const ExamInfo& exam_info, + const shared_ptr& proj_data_info_ptr); /************************************************************** The 3 parsing functions ***************************************************************/ -void -LmToProjData:: -set_defaults() -{ +void +LmToProjData::set_defaults() { max_segment_num_to_process = -1; store_prompts = true; store_delayeds = true; - interactive=false; + interactive = false; num_segments_in_memory = -1; + num_timing_poss_in_memory = 1; normalisation_ptr.reset(new TrivialBinNormalisation); post_normalisation_ptr.reset(new TrivialBinNormalisation); - do_pre_normalisation =0; + do_pre_normalisation = 0; num_events_to_store = 0L; - do_time_frame = false; + do_time_frame = false; } -void -LmToProjData:: -initialise_keymap() -{ +void +LmToProjData::initialise_keymap() { parser.add_start_key("lm_to_projdata Parameters"); - parser.add_key("input file",&input_filename); + parser.add_key("input file", &input_filename); parser.add_key("template_projdata", &template_proj_data_name); - parser.add_key("frame_definition file",&frame_definition_filename); - parser.add_key("num_events_to_store",&num_events_to_store); - parser.add_key("output filename prefix",&output_filename_prefix); + parser.add_key("frame_definition file", &frame_definition_filename); + parser.add_key("num_events_to_store", &num_events_to_store); + parser.add_key("output filename prefix", &output_filename_prefix); parser.add_parsing_key("Bin Normalisation type for pre-normalisation", &normalisation_ptr); parser.add_parsing_key("Bin Normalisation type for post-normalisation", &post_normalisation_ptr); - parser.add_key("maximum absolute segment number to process", &max_segment_num_to_process); + parser.add_key("maximum absolute segment number to process", &max_segment_num_to_process); parser.add_key("do pre normalisation ", &do_pre_normalisation); + parser.add_key("num_TOF_bins_in_memory", &num_timing_poss_in_memory); parser.add_key("num_segments_in_memory", &num_segments_in_memory); - //if (lm_data_ptr->has_delayeds()) TODO we haven't read the ListModeData yet, so cannot access has_delayeds() yet + // if (lm_data_ptr->has_delayeds()) TODO we haven't read the ListModeData yet, so cannot access has_delayeds() yet // one could add the next 2 keywords as part of a callback function for the 'input file' keyword. // That's a bit too much trouble for now though... { - parser.add_key("Store prompts",&store_prompts); - parser.add_key("Store delayeds",&store_delayeds); - //parser.add_key("increment to use for 'delayeds'",&delayed_increment); + parser.add_key("Store prompts", &store_prompts); + parser.add_key("Store delayeds", &store_delayeds); + // parser.add_key("increment to use for 'delayeds'",&delayed_increment); } - parser.add_key("List event coordinates",&interactive); - parser.add_stop_key("END"); - + parser.add_key("List event coordinates", &interactive); + parser.add_stop_key("END"); } - bool -LmToProjData:: -post_processing() -{ +LmToProjData::post_processing() { - if (input_filename.size()==0) - { - warning("You have to specify an input_filename\n"); - return true; - } + if (input_filename.size() == 0) { + warning("You have to specify an input_filename\n"); + return true; + } - if (!interactive && output_filename_prefix.size()==0) - { - warning("You have to specify an output_filename_prefix\n"); - return true; - } + if (!interactive && output_filename_prefix.size() == 0) { + warning("You have to specify an output_filename_prefix\n"); + return true; + } lm_data_ptr = stir::read_from_file(input_filename); - if (template_proj_data_name.size()==0) - { - warning("You have to specify template_projdata\n"); - return true; - } - shared_ptr template_proj_data_ptr = - ProjData::read_from_file(template_proj_data_name); + if (template_proj_data_name.size() == 0) { + warning("You have to specify template_projdata\n"); + return true; + } + shared_ptr template_proj_data_ptr = ProjData::read_from_file(template_proj_data_name); template_proj_data_info_ptr.reset(template_proj_data_ptr->get_proj_data_info_sptr()->clone()); // propagate relevant metadata - template_proj_data_info_ptr->set_bed_position_horizontal - (lm_data_ptr->get_proj_data_info_sptr()->get_bed_position_horizontal()); - template_proj_data_info_ptr->set_bed_position_vertical - (lm_data_ptr->get_proj_data_info_sptr()->get_bed_position_vertical()); + template_proj_data_info_ptr->set_bed_position_horizontal(lm_data_ptr->get_proj_data_info_sptr()->get_bed_position_horizontal()); + template_proj_data_info_ptr->set_bed_position_vertical(lm_data_ptr->get_proj_data_info_sptr()->get_bed_position_vertical()); // initialise segment_num related variables - if (max_segment_num_to_process==-1) - max_segment_num_to_process = - template_proj_data_info_ptr->get_max_segment_num(); - else - { - max_segment_num_to_process = - min(max_segment_num_to_process, - template_proj_data_info_ptr->get_max_segment_num()); - template_proj_data_info_ptr-> - reduce_segment_range(-max_segment_num_to_process, - max_segment_num_to_process); - } + if (max_segment_num_to_process == -1) + max_segment_num_to_process = template_proj_data_info_ptr->get_max_segment_num(); + else { + max_segment_num_to_process = min(max_segment_num_to_process, template_proj_data_info_ptr->get_max_segment_num()); + template_proj_data_info_ptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); + } const int num_segments = template_proj_data_info_ptr->get_num_segments(); if (num_segments_in_memory == -1 || interactive) num_segments_in_memory = num_segments; else - num_segments_in_memory = - min(num_segments_in_memory, num_segments); - if (num_segments == 0) - { - warning("LmToProjData: num_segments_in_memory cannot be 0"); - return true; - } - + num_segments_in_memory = min(num_segments_in_memory, num_segments); + if (num_segments == 0) { + warning("LmToProjData: num_segments_in_memory cannot be 0"); + return true; + } + Scanner const* const scanner_ptr = template_proj_data_info_ptr->get_scanner_ptr(); - Scanner const * const scanner_ptr = - template_proj_data_info_ptr->get_scanner_ptr(); + if (*scanner_ptr != *lm_data_ptr->get_scanner_ptr()) { + warning("LmToProjData:\nScanner from list mode data (%s) is different from\n" + "scanner from template projdata (%s).\n" + "Full definition of scanner from list mode data:\n%s\n" + "Full definition of scanner from template:\n%s\n", + lm_data_ptr->get_scanner_ptr()->get_name().c_str(), scanner_ptr->get_name().c_str(), + lm_data_ptr->get_scanner_ptr()->parameter_info().c_str(), scanner_ptr->parameter_info().c_str()); + return true; + } - if (*scanner_ptr != *lm_data_ptr->get_scanner_ptr()) - { - warning("LmToProjData:\nScanner from list mode data (%s) is different from\n" - "scanner from template projdata (%s).\n" - "Full definition of scanner from list mode data:\n%s\n" - "Full definition of scanner from template:\n%s\n", - lm_data_ptr->get_scanner_ptr()->get_name().c_str(), - scanner_ptr->get_name().c_str(), - lm_data_ptr->get_scanner_ptr()->parameter_info().c_str(), - scanner_ptr->parameter_info().c_str()); - return true; - } - // handle store_prompts and store_delayeds - if (lm_data_ptr->has_delayeds()==false && store_delayeds==true) - { - warning("This list mode data does not seem to have delayed events.\n" - "Setting store_delayeds to false."); - store_delayeds=true; - } - - if (store_prompts) - { - if (store_delayeds) - delayed_increment = -1; - else - delayed_increment = 0; - } - else - { - if (store_delayeds) - delayed_increment = 1; - else - { - warning("At least one of store_prompts or store_delayeds should be true"); - return true; - } + if (lm_data_ptr->has_delayeds() == false && store_delayeds == true) { + warning("This list mode data does not seem to have delayed events.\n" + "Setting store_delayeds to false."); + store_delayeds = true; + } + + if (store_prompts) { + if (store_delayeds) + delayed_increment = -1; + else + delayed_increment = 0; + } else { + if (store_delayeds) + delayed_increment = 1; + else { + warning("At least one of store_prompts or store_delayeds should be true"); + return true; } + } // set up normalisation objects - if (is_null_ptr(normalisation_ptr)) - { - warning("Invalid pre-normalisation object\n"); - return true; - } - if (is_null_ptr(post_normalisation_ptr)) - { - warning("Invalid post-normalisation object\n"); - return true; - } + if (is_null_ptr(normalisation_ptr)) { + warning("Invalid pre-normalisation object\n"); + return true; + } + if (is_null_ptr(post_normalisation_ptr)) { + warning("Invalid post-normalisation object\n"); + return true; + } - if (do_pre_normalisation) - { - shared_ptr scanner_sptr(new Scanner(*scanner_ptr)); - // TODO this won't work for the HiDAC or so - proj_data_info_cyl_uncompressed_ptr. - reset(dynamic_cast( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - 1, scanner_ptr->get_num_rings()-1, - scanner_ptr->get_num_detectors_per_ring()/2, - scanner_ptr->get_default_num_arccorrected_bins(), - false))); - - if ( normalisation_ptr->set_up(lm_data_ptr->get_exam_info_sptr(), proj_data_info_cyl_uncompressed_ptr) - != Succeeded::yes) - error("LmToProjData: set-up of pre-normalisation failed\n"); - } - else - { - if ( post_normalisation_ptr->set_up(lm_data_ptr->get_exam_info_sptr(),template_proj_data_info_ptr) - != Succeeded::yes) - error("LmToProjData: set-up of post-normalisation failed\n"); - } + if (do_pre_normalisation) { + shared_ptr scanner_sptr(new Scanner(*scanner_ptr)); + // TODO this won't work for the HiDAC or so + // N.E: The following command used to do a dynamic cast which now I removed. + proj_data_info_cyl_uncompressed_ptr.reset(ProjDataInfo::ProjDataInfoCTI( + scanner_sptr, 1, scanner_ptr->get_num_rings() - 1, scanner_ptr->get_num_detectors_per_ring() / 2, + scanner_ptr->get_default_num_arccorrected_bins(), false, 1)); + + if (normalisation_ptr->set_up(lm_data_ptr->get_exam_info_sptr(), proj_data_info_cyl_uncompressed_ptr) != Succeeded::yes) + error("LmToProjData: set-up of pre-normalisation failed\n"); + } else { + if (post_normalisation_ptr->set_up(lm_data_ptr->get_exam_info_sptr(), template_proj_data_info_ptr) != Succeeded::yes) + error("LmToProjData: set-up of post-normalisation failed\n"); + } // handle time frame definitions etc // If num_events_to_store == 0 && frame_definition_filename.size == 0 - if(num_events_to_store==0 && frame_definition_filename.size() == 0) - do_time_frame = true; + if (num_events_to_store == 0 && frame_definition_filename.size() == 0) + do_time_frame = true; - if (frame_definition_filename.size()!=0) - { + if (frame_definition_filename.size() != 0) { frame_defs = TimeFrameDefinitions(frame_definition_filename); do_time_frame = true; + } else if (frame_defs.get_num_frames() < 1) { + // make a single frame starting from 0. End value will be ignored. + vector> frame_times(1, pair(0, 0)); + frame_defs = TimeFrameDefinitions(frame_times); } - else if (frame_defs.get_num_frames() < 1) - { - // make a single frame starting from 0. End value will be ignored. - vector > frame_times(1, pair(0,0)); - frame_defs = TimeFrameDefinitions(frame_times); - } #ifdef FRAME_BASED_DT_CORR cerr << "LmToProjData Using FRAME_BASED_DT_CORR\n"; @@ -362,22 +309,14 @@ post_processing() Constructors ***************************************************************/ -LmToProjData:: -LmToProjData() -{ - set_defaults(); -} +LmToProjData::LmToProjData() { set_defaults(); } -LmToProjData:: -LmToProjData(const char * const par_filename) -{ +LmToProjData::LmToProjData(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - { - if (parse(par_filename)==false) - error("Exiting\n"); - } - else + if (par_filename != 0) { + if (parse(par_filename) == false) + error("Exiting\n"); + } else ask_parameters(); } @@ -385,130 +324,99 @@ LmToProjData(const char * const par_filename) Here follows the implementation of get_bin_from_event this function is complicated because of the normalisation stuff. sorry + N.E: Get_bin_from_event became Get_bin_from_record ***************************************************************/ void -LmToProjData:: -get_bin_from_event(Bin& bin, const ListEvent& event) const -{ - if (do_pre_normalisation) - { - Bin uncompressed_bin; - event.get_bin(uncompressed_bin, *proj_data_info_cyl_uncompressed_ptr); - if (uncompressed_bin.get_bin_value()<=0) +LmToProjData::get_bin_from_event(Bin& bin, const ListEvent& event) const { + if (do_pre_normalisation) { + Bin uncompressed_bin; + event.get_bin(uncompressed_bin, *proj_data_info_cyl_uncompressed_ptr); + if (uncompressed_bin.get_bin_value() <= 0) return; // rejected for some strange reason - - // do_normalisation + // do_normalisation #ifndef FRAME_BASED_DT_CORR - const double start_time = current_time; - const double end_time = current_time; + const double start_time = current_time; + const double end_time = current_time; #else - const double start_time = frame_defs.get_start_time(current_frame_num); - const double end_time =frame_defs.get_end_time(current_frame_num); + const double start_time = frame_defs.get_start_time(current_frame_num); + const double end_time = frame_defs.get_end_time(current_frame_num); #endif - - const float bin_efficiency = - normalisation_ptr->get_bin_efficiency(uncompressed_bin,start_time,end_time); - // TODO remove arbitrary number. Supposes that these bin_efficiencies are around 1 - if (bin_efficiency < 1.E-10) - { - warning("\nBin_efficiency %g too low for uncompressed bin (s:%d,v:%d,ax_pos:%d,tang_pos:%d). Event ignored\n", - bin_efficiency, - uncompressed_bin.segment_num(), uncompressed_bin.view_num(), - uncompressed_bin.axial_pos_num(), uncompressed_bin.tangential_pos_num()); - bin.set_bin_value(-1); - return; - } - + + const float bin_efficiency = normalisation_ptr->get_bin_efficiency(uncompressed_bin, start_time, end_time); + // TODO remove arbitrary number. Supposes that these bin_efficiencies are around 1 + if (bin_efficiency < 1.E-10) { + warning("\nBin_efficiency %g too low for uncompressed bin (s:%d,v:%d,ax_pos:%d,tang_pos:%d). Event ignored\n", + bin_efficiency, uncompressed_bin.segment_num(), uncompressed_bin.view_num(), uncompressed_bin.axial_pos_num(), + uncompressed_bin.tangential_pos_num()); + bin.set_bin_value(-1.f); + return; + } + // now find 'compressed' bin, i.e. taking mashing, span etc into account // Also, adjust the normalisation factor according to the number of // uncompressed bins in a compressed bin - const float bin_value = 1/bin_efficiency; + const float bin_value = 1.f / bin_efficiency; // TODO wasteful: we decode the event twice. replace by something like // template_proj_data_info_ptr->get_bin_from_uncompressed(bin, uncompressed_bin); + event.get_bin(bin, *template_proj_data_info_ptr); - - if (bin.get_bin_value()>0) - { - bin.set_bin_value(bin_value); - } - } - else - { - event.get_bin(bin, *template_proj_data_info_ptr); - } + bin.set_bin_value(bin_value); -} + } else { + event.get_bin(bin, *template_proj_data_info_ptr); + } +} /************************************************************** - Here follows the post_normalisation related stuff. + Here follows the post_normalisation related stuff. ***************************************************************/ -void -LmToProjData:: -do_post_normalisation(Bin& bin) const -{ - if (bin.get_bin_value()>0) - { - if (do_pre_normalisation) - { - bin.set_bin_value(bin.get_bin_value()/get_compression_count(bin)); - } - else - { +void +LmToProjData::do_post_normalisation(Bin& bin) const { + if (bin.get_bin_value() > 0) { + if (do_pre_normalisation) { + bin.set_bin_value(bin.get_bin_value() / get_compression_count(bin)); + } else { #ifndef FRAME_BASED_DT_CORR - const double start_time = current_time; - const double end_time = current_time; + const double start_time = current_time; + const double end_time = current_time; #else - const double start_time = frame_defs.get_start_time(current_frame_num); - const double end_time =frame_defs.get_end_time(current_frame_num); + const double start_time = frame_defs.get_start_time(current_frame_num); + const double end_time = frame_defs.get_end_time(current_frame_num); #endif - const float bin_efficiency = post_normalisation_ptr->get_bin_efficiency(bin,start_time,end_time); - // TODO remove arbitrary number. Supposes that these bin_efficiencies are around 1 - if (bin_efficiency < 1.E-10) - { - warning("\nBin_efficiency %g too low for bin (s:%d,v:%d,ax_pos:%d,tang_pos:%d). Event ignored\n", - bin_efficiency, - bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num()); - bin.set_bin_value(-1); - } - else - { - bin.set_bin_value(bin.get_bin_value()/bin_efficiency); - } - } + const float bin_efficiency = post_normalisation_ptr->get_bin_efficiency(bin, start_time, end_time); + // TODO remove arbitrary number. Supposes that these bin_efficiencies are around 1 + if (bin_efficiency < 1.E-10) { + warning("\nBin_efficiency %g too low for bin (s:%d,v:%d,ax_pos:%d,tang_pos:%d). Event ignored\n", bin_efficiency, + bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num()); + bin.set_bin_value(-1); + } else { + bin.set_bin_value(bin.get_bin_value() / bin_efficiency); + } } + } } - int -LmToProjData:: -get_compression_count(const Bin& bin) const -{ +LmToProjData::get_compression_count(const Bin& bin) const { // TODO this currently works ONLY for cylindrical PET scanners - const ProjDataInfoCylindrical& proj_data_info = - dynamic_cast(*template_proj_data_info_ptr); - - return static_cast(proj_data_info.get_num_ring_pairs_for_segment_axial_pos_num(bin.segment_num(),bin.axial_pos_num()))* - proj_data_info.get_view_mashing_factor(); + const ProjDataInfoCylindrical& proj_data_info = dynamic_cast(*template_proj_data_info_ptr); + return static_cast(proj_data_info.get_num_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), bin.axial_pos_num())) * + proj_data_info.get_view_mashing_factor(); } /************************************************************** Empty functions for new time events and new time frames. ***************************************************************/ void -LmToProjData:: -process_new_time_event(const ListTime&) -{} - +LmToProjData::process_new_time_event(const ListTime&) {} void -LmToProjData:: -start_new_time_frame(const unsigned int) -{} +LmToProjData::start_new_time_frame(const unsigned int) {} /************************************************************** Here follows the actual rebinning code (finally). @@ -516,10 +424,9 @@ start_new_time_frame(const unsigned int) It's essentially simple, but is in fact complicated because of the facility to store only part of the segments in memory. ***************************************************************/ + void -LmToProjData:: -process_data() -{ +LmToProjData::process_data() { CPUTimer timer; timer.start(); @@ -530,304 +437,491 @@ process_data() double time_of_last_stored_event = 0; long num_stored_events = 0; - VectorWithOffset - segments (template_proj_data_info_ptr->get_min_segment_num(), - template_proj_data_info_ptr->get_max_segment_num()); - - VectorWithOffset - frame_start_positions(1, static_cast(frame_defs.get_num_frames())); - shared_ptr record_sptr = lm_data_ptr->get_empty_record_sptr(); + VectorWithOffset segments(template_proj_data_info_ptr->get_min_segment_num(), + template_proj_data_info_ptr->get_max_segment_num()); + + VectorWithOffset frame_start_positions(1, static_cast(frame_defs.get_num_frames())); + shared_ptr record_sptr = lm_data_ptr->get_empty_record_sptr(); ListRecord& record = *record_sptr; if (!record.event().is_valid_template(*template_proj_data_info_ptr)) - error("The scanner template is not valid for LmToProjData. This might be because of unsupported arc correction."); - + error("The scanner template is not valid for LmToProjData. This might be because of unsupported arc correction."); /* Here starts the main loop which will store the listmode data. */ - for (current_frame_num = 1; - current_frame_num<=frame_defs.get_num_frames(); - ++current_frame_num) + for (current_frame_num = 1; current_frame_num <= frame_defs.get_num_frames(); ++current_frame_num) { + start_new_time_frame(current_frame_num); + + // construct ExamInfo appropriate for a single projdata with this time frame + ExamInfo this_frame_exam_info(*lm_data_ptr->get_exam_info_sptr()); { - start_new_time_frame(current_frame_num); + TimeFrameDefinitions this_time_frame_defs(frame_defs, current_frame_num); + this_frame_exam_info.set_time_frame_definitions(this_time_frame_defs); + } - // construct ExamInfo appropriate for a single projdata with this time frame - ExamInfo this_frame_exam_info(lm_data_ptr->get_exam_info()); - { - TimeFrameDefinitions this_time_frame_defs(frame_defs, current_frame_num); - this_frame_exam_info.set_time_frame_definitions(this_time_frame_defs); - } + // *********** open output file + shared_ptr output; + shared_ptr proj_data_ptr; - // *********** open output file - shared_ptr output; - shared_ptr proj_data_sptr; - - { - char rest[50]; - sprintf(rest, "_f%dg1d0b0", current_frame_num); - const string output_filename = output_filename_prefix + rest; - - proj_data_sptr = - construct_proj_data(output, output_filename, this_frame_exam_info, template_proj_data_info_ptr); - } + { + char rest[50]; + sprintf(rest, "_f%dg1d0b0", current_frame_num); + const string output_filename = output_filename_prefix + rest; - long num_prompts_in_frame = 0; - long num_delayeds_in_frame = 0; + proj_data_ptr = construct_proj_data(output, output_filename, this_frame_exam_info, template_proj_data_info_ptr); + } - const double start_time = frame_defs.get_start_time(current_frame_num); - const double end_time = frame_defs.get_end_time(current_frame_num); + long num_prompts_in_frame = 0; + long num_delayeds_in_frame = 0; - /* - For each start_segment_index, we check which events occur in the - segments between start_segment_index and - start_segment_index+num_segments_in_memory. - */ - for (int start_segment_index = proj_data_sptr->get_min_segment_num(); - start_segment_index <= proj_data_sptr->get_max_segment_num(); - start_segment_index += num_segments_in_memory) - { - - const int end_segment_index = - min( proj_data_sptr->get_max_segment_num()+1, start_segment_index + num_segments_in_memory) - 1; - - if (!interactive) - allocate_segments(segments, start_segment_index, end_segment_index, proj_data_sptr->get_proj_data_info_sptr()); - - // the next variable is used to see if there are more events to store for the current segments - // num_events_to_store-more_events will be the number of allowed coincidence events currently seen in the file - // ('allowed' independent on the fact of we have its segment in memory or not) - // When do_time_frame=true, the number of events is irrelevant, so we - // just set more_events to 1, and never change it - long more_events = - do_time_frame? 1 : num_events_to_store; - - if (start_segment_index != proj_data_sptr->get_min_segment_num()) - { - // we're going once more through the data (for the next batch of segments) - cerr << "\nProcessing next batch of segments\n"; - // go to the beginning of the listmode data for this frame - lm_data_ptr->set_get_position(frame_start_positions[current_frame_num]); - current_time = start_time; - } - else - { - cerr << "\nProcessing time frame " << current_frame_num << '\n'; - - // Note: we already have current_time from previous frame, so don't - // need to set it. In fact, setting it to start_time would be wrong - // as we first might have to skip some events before we get to start_time. - // So, let's do that now. - while (current_time < start_time && - lm_data_ptr->get_next_record(record) == Succeeded::yes) - { - if (record.is_time()) - current_time = record.time().get_time_in_secs(); - } - // now save position such that we can go back - frame_start_positions[current_frame_num] = - lm_data_ptr->save_get_position(); - } - { - // loop over all events in the listmode file - while (more_events) - { - if (lm_data_ptr->get_next_record(record) == Succeeded::no) - { - // no more events in file for some reason - break; //get out of while loop - } - if (record.is_time() && end_time > 0.01) // Direct comparison within doubles is unsafe. - { - current_time = record.time().get_time_in_secs(); - if (do_time_frame && current_time >= end_time) - break; // get out of while loop - assert(current_time>=start_time); - process_new_time_event(record.time()); - } - // note: could do "else if" here if we would be sure that - // a record can never be both timing and coincidence event - // and there might be a scanner around that has them both combined. - if (record.is_event()) - { - assert(start_time <= current_time); - Bin bin; - // set value in case the event decoder doesn't touch it - // otherwise it would be 0 and all events will be ignored - bin.set_bin_value(1); - get_bin_from_event(bin, record.event()); - - // check if it's inside the range we want to store - if (bin.get_bin_value()>0 - && bin.tangential_pos_num()>= proj_data_sptr->get_min_tangential_pos_num() - && bin.tangential_pos_num()<= proj_data_sptr->get_max_tangential_pos_num() - && bin.axial_pos_num()>=proj_data_sptr->get_min_axial_pos_num(bin.segment_num()) - && bin.axial_pos_num()<=proj_data_sptr->get_max_axial_pos_num(bin.segment_num()) - ) - { - assert(bin.view_num()>=proj_data_sptr->get_min_view_num()); - assert(bin.view_num()<=proj_data_sptr->get_max_view_num()); - - // see if we increment or decrement the value in the sinogram - const int event_increment = - record.event().is_prompt() - ? ( store_prompts ? 1 : 0 ) // it's a prompt - : delayed_increment;//it is a delayed-coincidence event - - if (event_increment==0) - continue; - - if (!do_time_frame) - more_events-= event_increment; - - // now check if we have its segment in memory - if (bin.segment_num() >= start_segment_index && bin.segment_num()<=end_segment_index) - { - do_post_normalisation(bin); - - num_stored_events += event_increment; - if (record.event().is_prompt()) - ++num_prompts_in_frame; - else - ++num_delayeds_in_frame; - - if (num_stored_events%500000L==0) cout << "\r" << num_stored_events << " events stored" << flush; - - if (interactive) - printf("Seg %4d view %4d ax_pos %4d tang_pos %4d time %8g stored with incr %d \n", - bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num(), - current_time, event_increment); - else - (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += - bin.get_bin_value() * - event_increment; - } - } - else // event is rejected for some reason - { - if (interactive) - printf("Seg %4d view %4d ax_pos %4d tang_pos %4d time %8g ignored\n", - bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num(), current_time); - } - } // end of spatial event processing - } // end of while loop over all events - - time_of_last_stored_event = - max(time_of_last_stored_event,current_time); - } - - if (!interactive) - save_and_delete_segments(output, segments, - start_segment_index, end_segment_index, - *proj_data_sptr); - } // end of for loop for segment range - cerr << "\nNumber of prompts stored in this time period : " << num_prompts_in_frame - << "\nNumber of delayeds stored in this time period: " << num_delayeds_in_frame - << '\n'; - } // end of loop over frames - - timer.stop(); - - cerr << "Last stored event was recorded before time-tick at " << time_of_last_stored_event << " secs\n"; - if (!do_time_frame && - (num_stored_events<=0 || - /*static_cast*/(num_stored_events)> segments(template_proj_data_info_ptr->get_min_tof_pos_num(), + template_proj_data_info_ptr->get_max_tof_pos_num()); + for (int timing_pos_num = segments.get_min_index(); timing_pos_num <= segments.get_max_index(); ++timing_pos_num) { + segments[timing_pos_num].resize(template_proj_data_info_ptr->get_min_segment_num(), + template_proj_data_info_ptr->get_max_segment_num()); + } + for (int start_timing_pos_index = proj_data_ptr->get_min_tof_pos_num(); + start_timing_pos_index <= proj_data_ptr->get_max_tof_pos_num(); start_timing_pos_index += num_timing_poss_in_memory) { + const int end_timing_pos_index = + min(proj_data_ptr->get_max_tof_pos_num() + 1, start_timing_pos_index + num_timing_poss_in_memory) - 1; + /* + For each start_segment_index, we check which events occur in the + segments between start_segment_index and + start_segment_index+num_segments_in_memory. + */ + for (int start_segment_index = proj_data_ptr->get_min_segment_num(); + start_segment_index <= proj_data_ptr->get_max_segment_num(); start_segment_index += num_segments_in_memory) { + + const int end_segment_index = + min(proj_data_ptr->get_max_segment_num() + 1, start_segment_index + num_segments_in_memory) - 1; + + if (!interactive) + allocate_segments(segments, start_timing_pos_index, end_timing_pos_index, start_segment_index, end_segment_index, + proj_data_ptr->get_proj_data_info_sptr()); + + // the next variable is used to see if there are more events to store for the current segments + // num_events_to_store-more_events will be the number of allowed coincidence events currently seen in the file + // ('allowed' independent on the fact of we have its segment in memory or not) + // When do_time_frame=true, the number of events is irrelevant, so we + // just set more_events to 1, and never change it + unsigned long int more_events = do_time_frame ? 1 : num_events_to_store; + + if (start_segment_index != proj_data_ptr->get_min_segment_num() || + start_timing_pos_index > proj_data_ptr->get_min_tof_pos_num()) { + // we're going once more through the data (for the next batch of segments) + cerr << "\nProcessing next batch of segments for start TOF bin " << start_timing_pos_index << "\n"; + // go to the beginning of the listmode data for this frame + lm_data_ptr->set_get_position(frame_start_positions[current_frame_num]); + current_time = start_time; + } else { + cerr << "\nProcessing time frame " << current_frame_num << '\n'; + + // Note: we already have current_time from previous frame, so don't + // need to set it. In fact, setting it to start_time would be wrong + // as we first might have to skip some events before we get to start_time. + // So, let's do that now. + while (current_time < start_time && lm_data_ptr->get_next_record(record) == Succeeded::yes) { + if (record.is_time()) + current_time = record.time().get_time_in_secs(); + } + // now save position such that we can go back + frame_start_positions[current_frame_num] = lm_data_ptr->save_get_position(); + } + { + // loop over all events in the listmode file + while (more_events) { + if (lm_data_ptr->get_next_record(record) == Succeeded::no) { + // no more events in file for some reason + break; // get out of while loop + } + if (record.is_time() && end_time > 0.01) // Direct comparison within doubles is unsafe. + { + current_time = record.time().get_time_in_secs(); + if (do_time_frame && current_time >= end_time) + break; // get out of while loop + assert(current_time >= start_time); + process_new_time_event(record.time()); + } + // note: could do "else if" here if we would be sure that + // a record can never be both timing and coincidence event + // and there might be a scanner around that has them both combined. + if (record.is_event()) { + assert(start_time <= current_time); + Bin bin; + // set value in case the event decoder doesn't touch it + // otherwise it would be 0 and all events will be ignored + bin.set_bin_value(1.f); + + get_bin_from_event(bin, record.event()); + + // check if it's inside the range we want to store + if (bin.get_bin_value() > 0 && bin.tangential_pos_num() >= proj_data_ptr->get_min_tangential_pos_num() && + bin.tangential_pos_num() <= proj_data_ptr->get_max_tangential_pos_num() && + bin.axial_pos_num() >= proj_data_ptr->get_min_axial_pos_num(bin.segment_num()) && + bin.axial_pos_num() <= proj_data_ptr->get_max_axial_pos_num(bin.segment_num()) && + bin.timing_pos_num() >= proj_data_ptr->get_min_tof_pos_num() && + bin.timing_pos_num() <= proj_data_ptr->get_max_tof_pos_num()) { + assert(bin.view_num() >= proj_data_ptr->get_min_view_num()); + assert(bin.view_num() <= proj_data_ptr->get_max_view_num()); + + // see if we increment or decrement the value in the sinogram + const int event_increment = record.event().is_prompt() ? (store_prompts ? 1 : 0) // it's a prompt + : delayed_increment; // it is a delayed-coincidence event + + if (event_increment == 0) + continue; + + if (!do_time_frame) + more_events -= event_increment; + + // Check if the timing position of the bin is in the range + if (bin.timing_pos_num() >= start_timing_pos_index && bin.timing_pos_num() <= end_timing_pos_index) { + // now check if we have its segment in memory + if (bin.segment_num() >= start_segment_index && bin.segment_num() <= end_segment_index) { + do_post_normalisation(bin); + + num_stored_events += event_increment; + if (record.event().is_prompt()) + ++num_prompts_in_frame; + else + ++num_delayeds_in_frame; + + if (num_stored_events % 500000L == 0) + cout << "\r" << num_stored_events << " events stored" << flush; + + if (interactive) + printf("TOFbin %4d Seg %4d view %4d ax_pos %4d tang_pos %4d time %8g stored with incr %d \n", + bin.timing_pos_num(), bin.segment_num(), bin.view_num(), bin.axial_pos_num(), + bin.tangential_pos_num(), current_time, event_increment); + else + (*segments[bin.timing_pos_num()][bin.segment_num()])[bin.view_num()][bin.axial_pos_num()] + [bin.tangential_pos_num()] += + bin.get_bin_value() * event_increment; + } + } + } else // event is rejected for some reason + { + if (interactive) + printf("TOFbin %4d Seg %4d view %4d ax_pos %4d tang_pos %4d time %8g ignored\n", bin.timing_pos_num(), + bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num(), current_time); + } + } // end of spatial event processing + } // end of while loop over all events + + time_of_last_stored_event = max(time_of_last_stored_event, current_time); + } + + if (!interactive) + save_and_delete_segments(output, segments, start_timing_pos_index, end_timing_pos_index, start_segment_index, + end_segment_index, *proj_data_ptr); + } // end of for loop for segment range + + } // end of for loop for timing positions + cerr << "\nNumber of prompts stored in this time period : " << num_prompts_in_frame + << "\nNumber of delayeds stored in this time period: " << num_delayeds_in_frame << '\n'; + } // end of loop over frames + + timer.stop(); + + cerr << "Last stored event was recorded before time-tick at " << time_of_last_stored_event << " secs\n"; + if (!do_time_frame && (num_stored_events <= 0 || + /*static_cast*/ (num_stored_events) < num_events_to_store)) + cerr << "Early stop due to EOF. " << endl; + cerr << "Total number of counts (either prompts/trues/delayeds) stored: " << num_stored_events << endl; + + cerr << "\nThis took " << timer.value() << "s CPU time." << endl; } +void +LmToProjData::run_tof_test_function() { +#if 1 + error("TOF test function disabled"); +#else +<<<<<<< HEAD + VectorWithOffset> segments(template_proj_data_info_ptr->get_min_segment_num(), + template_proj_data_info_ptr->get_max_segment_num()); +======= + // construct ExamInfo appropriate for a single projdata with this time frame + ExamInfo this_frame_exam_info(lm_data_ptr->get_exam_info()); + { + TimeFrameDefinitions this_time_frame_defs(frame_defs, current_frame_num); + this_frame_exam_info.set_time_frame_definitions(this_time_frame_defs); + } -/************************* Local helper routines *************************/ + // *********** open output file + shared_ptr output; + shared_ptr proj_data_sptr; +>>>>>>> master + // *********** open output file + shared_ptr output; + shared_ptr proj_data_ptr; -void -allocate_segments( VectorWithOffset& segments, - const int start_segment_index, - const int end_segment_index, - const shared_ptr proj_data_info_sptr) -{ - - for (int seg=start_segment_index ; seg<=end_segment_index; seg++) + ExamInfo this_frame_exam_info(*lm_data_ptr->get_exam_info_ptr()); { -#ifdef USE_SegmentByView - segments[seg] = new SegmentByView( - proj_data_info_sptr->get_empty_segment_by_view (seg)); -#else - segments[seg] = - new Array<3,elem_type>(IndexRange3D(0, proj_data_info_ptr->get_num_views()-1, - 0, proj_data_info_ptr->get_num_axial_poss(seg)-1, - -(proj_data_info_ptr->get_num_tangential_poss()/2), - proj_data_info_ptr->get_num_tangential_poss()-(proj_data_info_ptr->get_num_tangential_poss()/2)-1)); -#endif + TimeFrameDefinitions this_time_frame_defs(frame_defs, current_frame_num); + this_frame_exam_info.set_time_frame_definitions(this_time_frame_defs); } -} -void -save_and_delete_segments(shared_ptr& output, - VectorWithOffset& segments, - const int start_segment_index, - const int end_segment_index, - ProjData& proj_data) -{ - - for (int seg=start_segment_index; seg<=end_segment_index; seg++) { + char rest[50]; + sprintf(rest, "_f%dg1d0b0", current_frame_num); + const string output_filename = output_filename_prefix + rest; +<<<<<<< HEAD + + proj_data_ptr = construct_proj_data(output, output_filename, this_frame_exam_info, template_proj_data_info_ptr); + } +======= + + proj_data_sptr = construct_proj_data(output, output_filename, this_frame_exam_info, template_proj_data_info_ptr); + } + + long num_prompts_in_frame = 0; + long num_delayeds_in_frame = 0; + + const double start_time = frame_defs.get_start_time(current_frame_num); + const double end_time = frame_defs.get_end_time(current_frame_num); + + /* + For each start_segment_index, we check which events occur in the + segments between start_segment_index and + start_segment_index+num_segments_in_memory. + */ + for (int start_segment_index = proj_data_sptr->get_min_segment_num(); + start_segment_index <= proj_data_sptr->get_max_segment_num(); start_segment_index += num_segments_in_memory) { + + const int end_segment_index = + min(proj_data_sptr->get_max_segment_num() + 1, start_segment_index + num_segments_in_memory) - 1; + + if (!interactive) + allocate_segments(segments, start_segment_index, end_segment_index, proj_data_sptr->get_proj_data_info_sptr()); + + // the next variable is used to see if there are more events to store for the current segments + // num_events_to_store-more_events will be the number of allowed coincidence events currently seen in the file + // ('allowed' independent on the fact of we have its segment in memory or not) + // When do_time_frame=true, the number of events is irrelevant, so we + // just set more_events to 1, and never change it + long more_events = do_time_frame ? 1 : num_events_to_store; + + if (start_segment_index != proj_data_sptr->get_min_segment_num()) { + // we're going once more through the data (for the next batch of segments) + cerr << "\nProcessing next batch of segments\n"; + // go to the beginning of the listmode data for this frame + lm_data_ptr->set_get_position(frame_start_positions[current_frame_num]); + current_time = start_time; + } else { + cerr << "\nProcessing time frame " << current_frame_num << '\n'; + + // Note: we already have current_time from previous frame, so don't + // need to set it. In fact, setting it to start_time would be wrong + // as we first might have to skip some events before we get to start_time. + // So, let's do that now. + while (current_time < start_time && lm_data_ptr->get_next_record(record) == Succeeded::yes) { + if (record.is_time()) + current_time = record.time().get_time_in_secs(); + } + // now save position such that we can go back + frame_start_positions[current_frame_num] = lm_data_ptr->save_get_position(); + } { + // loop over all events in the listmode file + while (more_events) { + if (lm_data_ptr->get_next_record(record) == Succeeded::no) { + // no more events in file for some reason + break; // get out of while loop + } + if (record.is_time() && end_time > 0.01) // Direct comparison within doubles is unsafe. + { + current_time = record.time().get_time_in_secs(); + if (do_time_frame && current_time >= end_time) + break; // get out of while loop + assert(current_time >= start_time); + process_new_time_event(record.time()); + } + // note: could do "else if" here if we would be sure that + // a record can never be both timing and coincidence event + // and there might be a scanner around that has them both combined. + if (record.is_event()) { + assert(start_time <= current_time); + Bin bin; + // set value in case the event decoder doesn't touch it + // otherwise it would be 0 and all events will be ignored + bin.set_bin_value(1); + get_bin_from_event(bin, record.event()); + + // check if it's inside the range we want to store + if (bin.get_bin_value() > 0 && bin.tangential_pos_num() >= proj_data_sptr->get_min_tangential_pos_num() && + bin.tangential_pos_num() <= proj_data_sptr->get_max_tangential_pos_num() && + bin.axial_pos_num() >= proj_data_sptr->get_min_axial_pos_num(bin.segment_num()) && + bin.axial_pos_num() <= proj_data_sptr->get_max_axial_pos_num(bin.segment_num())) { + assert(bin.view_num() >= proj_data_sptr->get_min_view_num()); + assert(bin.view_num() <= proj_data_sptr->get_max_view_num()); + + // see if we increment or decrement the value in the sinogram + const int event_increment = record.event().is_prompt() ? (store_prompts ? 1 : 0) // it's a prompt + : delayed_increment; // it is a delayed-coincidence event + + if (event_increment == 0) + continue; + + if (!do_time_frame) + more_events -= event_increment; + + // now check if we have its segment in memory + if (bin.segment_num() >= start_segment_index && bin.segment_num() <= end_segment_index) { + do_post_normalisation(bin); + + num_stored_events += event_increment; + if (record.event().is_prompt()) + ++num_prompts_in_frame; + else + ++num_delayeds_in_frame; + + if (num_stored_events % 500000L == 0) + cout << "\r" << num_stored_events << " events stored" << flush; + + if (interactive) + printf("Seg %4d view %4d ax_pos %4d tang_pos %4d time %8g stored with incr %d \n", bin.segment_num(), + bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num(), current_time, event_increment); + else + (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += + bin.get_bin_value() * event_increment; + } + } else // event is rejected for some reason + { + if (interactive) + printf("Seg %4d view %4d ax_pos %4d tang_pos %4d time %8g ignored\n", bin.segment_num(), bin.view_num(), + bin.axial_pos_num(), bin.tangential_pos_num(), current_time); + } + } // end of spatial event processing + } // end of while loop over all events + + time_of_last_stored_event = max(time_of_last_stored_event, current_time); + } + + if (!interactive) + save_and_delete_segments(output, segments, start_segment_index, end_segment_index, *proj_data_sptr); + } // end of for loop for segment range + cerr << "\nNumber of prompts stored in this time period : " << num_prompts_in_frame + << "\nNumber of delayeds stored in this time period: " << num_delayeds_in_frame << '\n'; +} // end of loop over frames + +timer.stop(); + +cerr << "Last stored event was recorded before time-tick at " << time_of_last_stored_event << " secs\n"; +if (!do_time_frame && (num_stored_events <= 0 || + /*static_cast*/ (num_stored_events) < num_events_to_store)) + cerr << "Early stop due to EOF. " << endl; +cerr << "Total number of counts (either prompts/trues/delayeds) stored: " << num_stored_events << endl; + +cerr << "\nThis took " << timer.value() << "s CPU time." << endl; +>>>>>>> master + + for (int current_timing_pos_index = proj_data_ptr->get_min_tof_pos_num(); + current_timing_pos_index <= proj_data_ptr->get_max_tof_pos_num(); current_timing_pos_index += 1) { + for (int start_segment_index = proj_data_ptr->get_min_segment_num(); + start_segment_index <= proj_data_ptr->get_max_segment_num(); start_segment_index += 1) { + + const int end_segment_index = + min(proj_data_ptr->get_max_segment_num() + 1, start_segment_index + num_segments_in_memory) - 1; + + if (!interactive) + allocate_segments(segments, start_segment_index, end_segment_index, start_timing_pos_index, end_timing_pos_index, + proj_data_ptr->get_proj_data_info_ptr(), current_timing_pos_index); + + for (int ax_num = proj_data_ptr->get_proj_data_info_ptr()->get_min_axial_pos_num(start_segment_index); + ax_num <= proj_data_ptr->get_proj_data_info_ptr()->get_max_axial_pos_num(start_segment_index); ++ax_num) { + for (int view_num = proj_data_ptr->get_proj_data_info_ptr()->get_min_view_num(); + view_num <= proj_data_ptr->get_proj_data_info_ptr()->get_max_view_num(); ++view_num) { + for (int tang_num = proj_data_ptr->get_proj_data_info_ptr()->get_min_tangential_pos_num(); + tang_num <= proj_data_ptr->get_proj_data_info_ptr()->get_max_tangential_pos_num(); ++tang_num) { + (*segments[start_segment_index])[view_num][ax_num][tang_num] = current_timing_pos_index; + } + } + } + + if (!interactive) + save_and_delete_segments(output, segments, start_segment_index, end_segment_index, *proj_data_ptr); + } // end of for loop for segment range + + } // end of for loop for timing positions +#endif +} + +/************************* Local helper routines *************************/ + +void +allocate_segments(VectorWithOffset>& segments, const int start_timing_pos_index, + const int end_timing_pos_index, const int start_segment_index, const int end_segment_index, + const shared_ptr proj_data_info_sptr) { + + for (int timing_pos_num = start_timing_pos_index; timing_pos_num <= end_timing_pos_index; timing_pos_num++) + for (int seg = start_segment_index; seg <= end_segment_index; seg++) { #ifdef USE_SegmentByView - proj_data.set_segment(*segments[seg]); + segments[timing_pos_num][seg] = + new SegmentByView(proj_data_info_sptr->get_empty_segment_by_view(seg, false, timing_pos_num)); #else - (*segments[seg]).write_data(*output); + segments[timing_pos_num][seg] = new Array<3, elem_type>(IndexRange3D( + 0, proj_data_info_sptr->get_num_views() - 1, 0, proj_data_info_sptr->get_num_axial_poss(seg) - 1, + -(proj_data_info_sptr->get_num_tangential_poss() / 2), + proj_data_info_sptr->get_num_tangential_poss() - (proj_data_info_sptr->get_num_tangential_poss() / 2) - 1)); #endif - delete segments[seg]; } - - } } +void +save_and_delete_segments(shared_ptr& output, VectorWithOffset>& segments, + const int start_timing_pos_index, const int end_timing_pos_index, const int start_segment_index, + const int end_segment_index, ProjData& proj_data) { + for (int timing_pos_num = start_timing_pos_index; timing_pos_num <= end_timing_pos_index; timing_pos_num++) + for (int seg = start_segment_index; seg <= end_segment_index; seg++) { +#ifdef USE_SegmentByView + proj_data.set_segment(*segments[timing_pos_num][seg]); +#else + (*segments[timing_pos_num][seg]).write_data(*output); +#endif + delete segments[timing_pos_num][seg]; + } +} - -static -shared_ptr -construct_proj_data(shared_ptr& output, - const string& output_filename, - const ExamInfo& exam_info, - const shared_ptr& proj_data_info_ptr) -{ +static shared_ptr +construct_proj_data(shared_ptr& output, const string& output_filename, const ExamInfo& exam_info, + const shared_ptr& proj_data_info_ptr) { shared_ptr exam_info_sptr(new ExamInfo(exam_info)); - + shared_ptr proj_data_sptr; #ifdef USE_SegmentByView // don't need output stream in this case - shared_ptr proj_data_sptr(new ProjDataInterfile(exam_info_sptr, - proj_data_info_ptr, output_filename, ios::out, - ProjDataFromStream::Segment_View_AxialPos_TangPos, - OUTPUTNumericType)); + if (!proj_data_info_ptr->is_tof_data()) + proj_data_sptr.reset(new ProjDataInterfile(exam_info_sptr, proj_data_info_ptr, output_filename, ios::out, + ProjDataFromStream::Segment_View_AxialPos_TangPos, OUTPUTNumericType)); + else + proj_data_sptr.reset(new ProjDataInterfile(exam_info_sptr, proj_data_info_ptr, output_filename, ios::out, + ProjDataFromStream::Timing_Segment_View_AxialPos_TangPos, OUTPUTNumericType)); + return proj_data_sptr; #else // this code would work for USE_SegmentByView as well, but the above is far simpler... vector segment_sequence_in_stream(proj_data_info_ptr->get_num_segments()); - { - std::vector::iterator current_segment_iter = - segment_sequence_in_stream.begin(); - for (int segment_num=proj_data_info_ptr->get_min_segment_num(); - segment_num<=proj_data_info_ptr->get_max_segment_num(); + { + std::vector::iterator current_segment_iter = segment_sequence_in_stream.begin(); + for (int segment_num = proj_data_info_ptr->get_min_segment_num(); segment_num <= proj_data_info_ptr->get_max_segment_num(); ++segment_num) *current_segment_iter++ = segment_num; } - output = new fstream (output_filename.c_str(), ios::out|ios::binary); + output = new fstream(output_filename.c_str(), ios::out | ios::binary); if (!*output) - error("Error opening output file %s\n",output_filename.c_str()); - shared_ptr proj_data_ptr( - new ProjDataFromStream(exam_info_sptr, proj_data_info_ptr, output, - /*offset=*/std::streamoff(0), - segment_sequence_in_stream, - ProjDataFromStream::Segment_View_AxialPos_TangPos, - OUTPUTNumericType)); + error("Error opening output file %s\n", output_filename.c_str()); + shared_ptr proj_data_ptr(new ProjDataFromStream(exam_info_sptr, proj_data_info_ptr, output, + /*offset=*/std::streamoff(0), segment_sequence_in_stream, + ProjDataFromStream::Segment_View_AxialPos_TangPos, + OUTPUTNumericType)); write_basic_interfile_PDFS_header(output_filename, *proj_data_ptr); - return proj_data_ptr; + return proj_data_ptr; #endif } - END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/LmToProjDataAbstract.cxx b/src/listmode_buildblock/LmToProjDataAbstract.cxx index a5271089e1..2f375ad384 100644 --- a/src/listmode_buildblock/LmToProjDataAbstract.cxx +++ b/src/listmode_buildblock/LmToProjDataAbstract.cxx @@ -1,9 +1,9 @@ /*! - \file + \file \ingroup listmode \brief Implementation of class stir::LmToProjDataAbstract - + \author Richard Brown */ /* @@ -27,5 +27,4 @@ START_NAMESPACE_STIR - END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/LmToProjDataBootstrap.cxx b/src/listmode_buildblock/LmToProjDataBootstrap.cxx index e660cd7ceb..2ba730da50 100644 --- a/src/listmode_buildblock/LmToProjDataBootstrap.cxx +++ b/src/listmode_buildblock/LmToProjDataBootstrap.cxx @@ -5,10 +5,10 @@ \file \ingroup listmode \brief Class stir::LmToProjDataBootstrap for rebinning listmode files with the bootstrap method - + \author Kris Thielemans \author Daniel Deidda - + */ /* Copyright (C) 2003- 2011, Hammersmith Imanet Ltd @@ -45,66 +45,53 @@ using std::endl; #include #include - - START_NAMESPACE_STIR template -void -LmToProjDataBootstrap::set_defaults() -{ +void +LmToProjDataBootstrap::set_defaults() { LmToProjData::set_defaults(); seed = 42; } template -void -LmToProjDataBootstrap::initialise_keymap() -{ +void +LmToProjDataBootstrap::initialise_keymap() { LmToProjData::initialise_keymap(); this->parser.add_start_key("LmToProjDataBootstrap Parameters"); - this->parser.add_key("seed", reinterpret_cast(&seed)); // TODO get rid of cast + this->parser.add_key("seed", reinterpret_cast(&seed)); // TODO get rid of cast } template -LmToProjDataBootstrap:: -LmToProjDataBootstrap(const char * const par_filename) -{ +LmToProjDataBootstrap::LmToProjDataBootstrap(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - this->parse(par_filename) ; + if (par_filename != 0) + this->parse(par_filename); else this->ask_parameters(); } template -LmToProjDataBootstrap:: -LmToProjDataBootstrap(const char * const par_filename, const unsigned int seed_v) -{ +LmToProjDataBootstrap::LmToProjDataBootstrap(const char* const par_filename, const unsigned int seed_v) { set_defaults(); seed = seed_v; - if (par_filename!=0) - { - this->parse(par_filename); - // make sure that seed_v parameter overrides whatever was in the par file - if (seed != seed_v) - { - warning("LmToProjDataBootstrap: parameter file %s contains seed (%u) which is\n" - "different from the seed value (%u) passed to me.\n" - "I will use the latter.\n", - par_filename, seed, seed_v); - seed = seed_v; - } + if (par_filename != 0) { + this->parse(par_filename); + // make sure that seed_v parameter overrides whatever was in the par file + if (seed != seed_v) { + warning("LmToProjDataBootstrap: parameter file %s contains seed (%u) which is\n" + "different from the seed value (%u) passed to me.\n" + "I will use the latter.\n", + par_filename, seed, seed_v); + seed = seed_v; } - else + } else this->ask_parameters(); } template bool -LmToProjDataBootstrap:: -post_processing() -{ +LmToProjDataBootstrap::post_processing() { if (LmToProjData::post_processing()) return true; @@ -114,13 +101,9 @@ post_processing() return false; } - - -template -void -LmToProjDataBootstrap:: -start_new_time_frame(const unsigned int new_frame_num) -{ +template +void +LmToProjDataBootstrap::start_new_time_frame(const unsigned int new_frame_num) { base_type::start_new_time_frame(new_frame_num); ListModeData::SavedPosition start_of_this_frame = this->lm_data_ptr->save_get_position(); @@ -129,133 +112,107 @@ start_new_time_frame(const unsigned int new_frame_num) const double start_time = this->frame_defs.get_start_time(new_frame_num); const double end_time = this->frame_defs.get_end_time(new_frame_num); - // When do_time_frame=true, the number of events is irrelevant, so we + // When do_time_frame=true, the number of events is irrelevant, so we // just set more_events to 1, and never change it - long more_events = - this->do_time_frame? 1 : this->num_events_to_store; + long more_events = this->do_time_frame ? 1 : this->num_events_to_store; unsigned int total_num_events_in_this_frame = 0; // loop over all events in the listmode file - shared_ptr record_sptr = this->lm_data_ptr->get_empty_record_sptr(); + shared_ptr record_sptr = this->lm_data_ptr->get_empty_record_sptr(); ListRecord& record = *record_sptr; info("Going through listmode file to find number of events in this frame"); double current_time = start_time; - while (more_events) - { - if (this->lm_data_ptr->get_next_record(record) == Succeeded::no) - { - // no more events in file for some reason - break; //get out of while loop - } - if (record.is_time()) - { - const double new_time = record.time().get_time_in_secs(); - if (this->do_time_frame && new_time >= end_time) - break; // get out of while loop - current_time = new_time; - } - if (record.is_event() && start_time <= current_time) - { - ++total_num_events_in_this_frame; - - if (!this->do_time_frame) - { - // painful business to decrement more_events - - // TODO optimisation possible: - // if we reject an event below, we could force its replication count to 0 - // That way, we will not call get_bin_from_event for it anymore. - - Bin bin; - // set value in case the event decoder doesn't touch it - // otherwise it would be 0 and all events will be ignored - bin.set_bin_value(1); - base_type::get_bin_from_event(bin, record.event()); - // check if it's inside the range we want to store - if (bin.get_bin_value()>0 - && bin.tangential_pos_num()>= this->template_proj_data_info_ptr->get_min_tangential_pos_num() - && bin.tangential_pos_num()<= this->template_proj_data_info_ptr->get_max_tangential_pos_num() - && bin.axial_pos_num()>=this->template_proj_data_info_ptr->get_min_axial_pos_num(bin.segment_num()) - && bin.axial_pos_num()<=this->template_proj_data_info_ptr->get_max_axial_pos_num(bin.segment_num()) - && bin.segment_num()>=this->template_proj_data_info_ptr->get_min_segment_num() - && bin.segment_num()<=this->template_proj_data_info_ptr->get_max_segment_num() - ) - { - assert(bin.view_num()>=this->template_proj_data_info_ptr->get_min_view_num()); - assert(bin.view_num()<=this->template_proj_data_info_ptr->get_max_view_num()); - - // see if we increment or decrement the value in the sinogram - const int event_increment = - record.event().is_prompt() - ? ( this->store_prompts ? 1 : 0 ) // it's a prompt - : this->delayed_increment;//it is a delayed-coincidence event - - if (event_increment==0) - continue; - - - more_events-= event_increment; - } - } // !do_time_frame - } // if (record.is_event()) - } // while (more_events) - - // now initialise num_times_to_replicate + while (more_events) { + if (this->lm_data_ptr->get_next_record(record) == Succeeded::no) { + // no more events in file for some reason + break; // get out of while loop + } + if (record.is_time()) { + const double new_time = record.time().get_time_in_secs(); + if (this->do_time_frame && new_time >= end_time) + break; // get out of while loop + current_time = new_time; + } + if (record.is_event() && start_time <= current_time) { + ++total_num_events_in_this_frame; + + if (!this->do_time_frame) { + // painful business to decrement more_events + + // TODO optimisation possible: + // if we reject an event below, we could force its replication count to 0 + // That way, we will not call get_bin_from_event for it anymore. + + Bin bin; + // set value in case the event decoder doesn't touch it + // otherwise it would be 0 and all events will be ignored + bin.set_bin_value(1); + base_type::get_bin_from_event(bin, record.event()); + // check if it's inside the range we want to store + if (bin.get_bin_value() > 0 && + bin.tangential_pos_num() >= this->template_proj_data_info_ptr->get_min_tangential_pos_num() && + bin.tangential_pos_num() <= this->template_proj_data_info_ptr->get_max_tangential_pos_num() && + bin.axial_pos_num() >= this->template_proj_data_info_ptr->get_min_axial_pos_num(bin.segment_num()) && + bin.axial_pos_num() <= this->template_proj_data_info_ptr->get_max_axial_pos_num(bin.segment_num()) && + bin.segment_num() >= this->template_proj_data_info_ptr->get_min_segment_num() && + bin.segment_num() <= this->template_proj_data_info_ptr->get_max_segment_num()) { + assert(bin.view_num() >= this->template_proj_data_info_ptr->get_min_view_num()); + assert(bin.view_num() <= this->template_proj_data_info_ptr->get_max_view_num()); + + // see if we increment or decrement the value in the sinogram + const int event_increment = record.event().is_prompt() ? (this->store_prompts ? 1 : 0) // it's a prompt + : this->delayed_increment; // it is a delayed-coincidence event + + if (event_increment == 0) + continue; + + more_events -= event_increment; + } + } // !do_time_frame + } // if (record.is_event()) + } // while (more_events) + + // now initialise num_times_to_replicate typedef boost::mt19937 base_generator_type; - base_generator_type generator; + base_generator_type generator; generator.seed(static_cast(seed)); - boost::uniform_int - uniform_int_distribution(0U, total_num_events_in_this_frame-1); - boost::variate_generator > - random_int(generator, - uniform_int_distribution); - + boost::uniform_int uniform_int_distribution(0U, total_num_events_in_this_frame - 1); + boost::variate_generator> random_int(generator, uniform_int_distribution); + num_times_to_replicate.resize(total_num_events_in_this_frame); - - std::fill( num_times_to_replicate.begin(), num_times_to_replicate.end(), - static_cast(0)); - for (unsigned int i=total_num_events_in_this_frame; i!=0; --i) - { - const unsigned int event_num = random_int(); - num_times_to_replicate[event_num] += 1; - // warning this did not check for overflow - } - assert(std::accumulate(num_times_to_replicate.begin(), - num_times_to_replicate.end(), - 0U) == - total_num_events_in_this_frame); - + std::fill(num_times_to_replicate.begin(), num_times_to_replicate.end(), static_cast(0)); + for (unsigned int i = total_num_events_in_this_frame; i != 0; --i) { + const unsigned int event_num = random_int(); + num_times_to_replicate[event_num] += 1; + // warning this did not check for overflow + } + + assert(std::accumulate(num_times_to_replicate.begin(), num_times_to_replicate.end(), 0U) == total_num_events_in_this_frame); + num_times_to_replicate_iter = num_times_to_replicate.begin(); - + info(boost::format("Filled in replication vector for %1% events.") % total_num_events_in_this_frame); this->lm_data_ptr->set_get_position(start_of_this_frame); } -template -void -LmToProjDataBootstrap:: -get_bin_from_event(Bin& bin, const ListEvent& event) const -{ +template +void +LmToProjDataBootstrap::get_bin_from_event(Bin& bin, const ListEvent& event) const { assert(num_times_to_replicate_iter != num_times_to_replicate.end()); - if (*num_times_to_replicate_iter > 0) - { - base_type::get_bin_from_event(bin, event); - bin.set_bin_value(bin.get_bin_value() * *num_times_to_replicate_iter); - } - else + if (*num_times_to_replicate_iter > 0) { + base_type::get_bin_from_event(bin, event); + bin.set_bin_value(bin.get_bin_value() * *num_times_to_replicate_iter); + } else bin.set_bin_value(-1); ++num_times_to_replicate_iter; } - // instantiation template class LmToProjDataBootstrap; - - END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/LmToProjDataWithRandomRejection.cxx b/src/listmode_buildblock/LmToProjDataWithRandomRejection.cxx index 892f744336..e91c423d5c 100644 --- a/src/listmode_buildblock/LmToProjDataWithRandomRejection.cxx +++ b/src/listmode_buildblock/LmToProjDataWithRandomRejection.cxx @@ -5,10 +5,10 @@ \file \ingroup listmode \brief Class stir::LmToProjDataWithRandomRejection for rebinning listmode files rejection some events randomly - + \author Kris Thielemans \author Daniel Deidda - + */ /* Copyright (C) 2003- 2012, Hammersmith Imanet Ltd @@ -35,129 +35,103 @@ #include #include - - START_NAMESPACE_STIR template -void -LmToProjDataWithRandomRejection::set_defaults() -{ +void +LmToProjDataWithRandomRejection::set_defaults() { LmToProjData::set_defaults(); this->seed = 42; this->reject_if_above = .5F; } template -void -LmToProjDataWithRandomRejection::initialise_keymap() -{ +void +LmToProjDataWithRandomRejection::initialise_keymap() { LmToProjData::initialise_keymap(); this->parser.add_start_key("LmToProjDataWithRandomRejection Parameters"); - this->parser.add_key("seed", reinterpret_cast(&seed)); // TODO get rid of cast + this->parser.add_key("seed", reinterpret_cast(&seed)); // TODO get rid of cast this->parser.add_key("reject_if_above", &reject_if_above); } template -LmToProjDataWithRandomRejection:: -LmToProjDataWithRandomRejection(const char * const par_filename) -{ +LmToProjDataWithRandomRejection::LmToProjDataWithRandomRejection(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - this->parse(par_filename) ; + if (par_filename != 0) + this->parse(par_filename); else this->ask_parameters(); } template -LmToProjDataWithRandomRejection:: -LmToProjDataWithRandomRejection(const char * const par_filename, const unsigned int seed_v) -{ +LmToProjDataWithRandomRejection::LmToProjDataWithRandomRejection(const char* const par_filename, + const unsigned int seed_v) { set_defaults(); seed = seed_v; - if (par_filename!=0) - { - this->parse(par_filename); - // make sure that seed_v parameter overrides whatever was in the par file - if (seed != seed_v) - { - warning("LmToProjDataWithRandomRejection: parameter file %s contains seed (%u) which is\n" - "different from the seed value (%u) passed to me.\n" - "I will use the latter.\n", - par_filename, seed, seed_v); - seed = seed_v; - } + if (par_filename != 0) { + this->parse(par_filename); + // make sure that seed_v parameter overrides whatever was in the par file + if (seed != seed_v) { + warning("LmToProjDataWithRandomRejection: parameter file %s contains seed (%u) which is\n" + "different from the seed value (%u) passed to me.\n" + "I will use the latter.\n", + par_filename, seed, seed_v); + seed = seed_v; } - else + } else this->ask_parameters(); } template bool -LmToProjDataWithRandomRejection:: -post_processing() -{ +LmToProjDataWithRandomRejection::post_processing() { if (LmToProjData::post_processing()) return true; - if (this->seed == 0) - { - warning("Seed needs to be non-zero"); return true; - } + if (this->seed == 0) { + warning("Seed needs to be non-zero"); + return true; + } - if (this->reject_if_above<0.F || this->reject_if_above>1.F) - { - warning("reject_if_above needs to be between 0 and 1"); return true; - } + if (this->reject_if_above < 0.F || this->reject_if_above > 1.F) { + warning("reject_if_above needs to be between 0 and 1"); + return true; + } return false; } -template +template float -LmToProjDataWithRandomRejection:: -set_reject_if_above(const float v) -{ +LmToProjDataWithRandomRejection::set_reject_if_above(const float v) { const float ret = this->reject_if_above; this->reject_if_above = v; return ret; } - - - -template -void -LmToProjDataWithRandomRejection:: -start_new_time_frame(const unsigned int new_frame_num) -{ +template +void +LmToProjDataWithRandomRejection::start_new_time_frame(const unsigned int new_frame_num) { base_type::start_new_time_frame(new_frame_num); this->random_generator.seed(static_cast(seed)); } -template -void -LmToProjDataWithRandomRejection:: -get_bin_from_event(Bin& bin, const ListEvent& event) const -{ +template +void +LmToProjDataWithRandomRejection::get_bin_from_event(Bin& bin, const ListEvent& event) const { static boost::uniform_01 random01(random_generator); - const double randnum=random01(); - //std::cout << randnum << '\n'; - if (randnum <= this->reject_if_above) - { - base_type::get_bin_from_event(bin, event); - } - else + const double randnum = random01(); + // std::cout << randnum << '\n'; + if (randnum <= this->reject_if_above) { + base_type::get_bin_from_event(bin, event); + } else bin.set_bin_value(-1); } - // instantiation template class LmToProjDataWithRandomRejection; - - END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/NiftyPET_listmode/LmToProjDataNiftyPET.cxx b/src/listmode_buildblock/NiftyPET_listmode/LmToProjDataNiftyPET.cxx index 34cc22a420..6c29b9c299 100644 --- a/src/listmode_buildblock/NiftyPET_listmode/LmToProjDataNiftyPET.cxx +++ b/src/listmode_buildblock/NiftyPET_listmode/LmToProjDataNiftyPET.cxx @@ -1,9 +1,9 @@ /*! - \file + \file \ingroup listmode \brief Implementation of class stir::LmToProjDataNiftyPET - + \author Richard Brown */ /* @@ -28,41 +28,38 @@ START_NAMESPACE_STIR -LmToProjDataNiftyPET::LmToProjDataNiftyPET() : - _span(11), _cuda_device(0), _cuda_verbosity(true), _start_time(-1), _stop_time(-1), _norm_binary_file("") -{ } +LmToProjDataNiftyPET::LmToProjDataNiftyPET() + : _span(11), _cuda_device(0), _cuda_verbosity(true), _start_time(-1), _stop_time(-1), _norm_binary_file("") {} -void LmToProjDataNiftyPET::check_input() const -{ - if (_listmode_binary_file.empty()) - throw std::runtime_error("LmToProjDataNiftyPET::process_data: listmode binary file not set."); +void +LmToProjDataNiftyPET::check_input() const { + if (_listmode_binary_file.empty()) + throw std::runtime_error("LmToProjDataNiftyPET::process_data: listmode binary file not set."); - if (_start_time < 0) - throw std::runtime_error("LmToProjDataNiftyPET::process_data: start time not set."); + if (_start_time < 0) + throw std::runtime_error("LmToProjDataNiftyPET::process_data: start time not set."); - if (_stop_time < 0) - throw std::runtime_error("LmToProjDataNiftyPET::process_data: stop time not set."); + if (_stop_time < 0) + throw std::runtime_error("LmToProjDataNiftyPET::process_data: stop time not set."); - // Check span - if (_span != 11) - throw std::runtime_error("LmToProjDataNiftyPET::process_data: currently only implemented for span 11."); + // Check span + if (_span != 11) + throw std::runtime_error("LmToProjDataNiftyPET::process_data: currently only implemented for span 11."); } -void LmToProjDataNiftyPET::process_data() -{ - // Set up the niftyPET binary helper - NiftyPETHelper helper; - helper.set_cuda_device_id ( _cuda_device ); - helper.set_span ( static_cast(_span) ); - helper.set_att(0); - helper.set_verbose(_cuda_verbosity); - helper.set_scanner_type(Scanner::Siemens_mMR); - helper.set_up(); +void +LmToProjDataNiftyPET::process_data() { + // Set up the niftyPET binary helper + NiftyPETHelper helper; + helper.set_cuda_device_id(_cuda_device); + helper.set_span(static_cast(_span)); + helper.set_att(0); + helper.set_verbose(_cuda_verbosity); + helper.set_scanner_type(Scanner::Siemens_mMR); + helper.set_up(); - helper.lm_to_proj_data(_prompts_sptr, _delayeds_sptr, - _randoms_sptr, _norm_sptr, - _start_time, _stop_time, - _listmode_binary_file , _norm_binary_file); + helper.lm_to_proj_data(_prompts_sptr, _delayeds_sptr, _randoms_sptr, _norm_sptr, _start_time, _stop_time, _listmode_binary_file, + _norm_binary_file); } END_NAMESPACE_STIR diff --git a/src/listmode_utilities/add_ecat7_header_to_sgl.cxx b/src/listmode_utilities/add_ecat7_header_to_sgl.cxx index 0c67f41353..c15528ef36 100644 --- a/src/listmode_utilities/add_ecat7_header_to_sgl.cxx +++ b/src/listmode_utilities/add_ecat7_header_to_sgl.cxx @@ -17,7 +17,7 @@ See STIR/LICENSE.txt for more details. */ -/*! +/*! \file \ingroup utilities \ingroup ECAT @@ -26,7 +26,6 @@ \author Nacer Kerrouche */ - #include "stir/IO/stir_ecat7.h" #include @@ -37,114 +36,94 @@ USING_NAMESPACE_STIR USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 -static void update_main_header(Main_header& mh, const bool is_3d_scan) - { - strcpy(mh.study_description, "listmode"); - mh.acquisition_type = DynamicEmission; - mh.septa_state = - is_3d_scan ? SeptaRetracted : SeptaExtended; - // we set this to a sinogram-type such that header_doc can display the data - mh.file_type = Short3dSinogram; - } - - -void print_usage_and_exit(const char * const program_name) - { - std::cerr<< "\nPrepend contents of ECAT7 header to a sgl file.\n" - << "Usage: \n" - << "\t" << program_name << " [--2d|--3d] output_sgl_name input_sgl_name input_ECAT7_name \n" - << "Defaults to 3D (is used to set septa_state)\n"; - exit(EXIT_FAILURE); - } +static void +update_main_header(Main_header& mh, const bool is_3d_scan) { + strcpy(mh.study_description, "listmode"); + mh.acquisition_type = DynamicEmission; + mh.septa_state = is_3d_scan ? SeptaRetracted : SeptaExtended; + // we set this to a sinogram-type such that header_doc can display the data + mh.file_type = Short3dSinogram; +} +void +print_usage_and_exit(const char* const program_name) { + std::cerr << "\nPrepend contents of ECAT7 header to a sgl file.\n" + << "Usage: \n" + << "\t" << program_name << " [--2d|--3d] output_sgl_name input_sgl_name input_ECAT7_name \n" + << "Defaults to 3D (is used to set septa_state)\n"; + exit(EXIT_FAILURE); +} -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { bool is_3d_scan = true; - const char * const program_name = argv[0]; - - if (argc >= 3 && argv[1][0] == '-') - { - if (strcmp(argv[1], "--2d") == 0) - { - is_3d_scan = false; - --argc; ++argv; - } - else if (strcmp(argv[1], "--3d") == 0) - { - is_3d_scan = true; - --argc; ++argv; - } - else - print_usage_and_exit(program_name); - } - if(argc!=4) + const char* const program_name = argv[0]; + + if (argc >= 3 && argv[1][0] == '-') { + if (strcmp(argv[1], "--2d") == 0) { + is_3d_scan = false; + --argc; + ++argv; + } else if (strcmp(argv[1], "--3d") == 0) { + is_3d_scan = true; + --argc; + ++argv; + } else + print_usage_and_exit(program_name); + } + if (argc != 4) print_usage_and_exit(program_name); const std::string output_name = argv[1]; const std::string input_name_sgl = argv[2]; const std::string input_name_ecat7 = argv[3]; - + + { + FILE* sgl_fptr = fopen(input_name_sgl.c_str(), "rb"); + if (!sgl_fptr) { + error("Error opening '%s' for reading: %s", input_name_sgl.c_str(), strerror(errno)); + } + FILE* out_fptr = fopen(output_name.c_str(), "wb"); + if (!out_fptr) { + error("Error opening '%s' for writing: %s", output_name.c_str(), strerror(errno)); + } + // get ECAT7 header + Main_header mh_in; { - FILE * sgl_fptr = fopen(input_name_sgl.c_str(), "rb"); - if (!sgl_fptr) - { - error("Error opening '%s' for reading: %s", - input_name_sgl.c_str(), strerror(errno)); - } - FILE * out_fptr = fopen(output_name.c_str(), "wb"); - if (!out_fptr) - { - error("Error opening '%s' for writing: %s", - output_name.c_str(), strerror(errno)); - } - // get ECAT7 header - Main_header mh_in; - { - FILE * ecat7_fptr = fopen(input_name_ecat7.c_str(), "rb"); - if (!ecat7_fptr) - { - error("Error opening '%s' for reading: %s", - input_name_ecat7.c_str(), strerror(errno)); - } - if (mat_read_main_header(ecat7_fptr, &mh_in)!=0) - error("Error reading main header from %s", input_name_ecat7.c_str()); - fclose(ecat7_fptr); + FILE* ecat7_fptr = fopen(input_name_ecat7.c_str(), "rb"); + if (!ecat7_fptr) { + error("Error opening '%s' for reading: %s", input_name_ecat7.c_str(), strerror(errno)); } + if (mat_read_main_header(ecat7_fptr, &mh_in) != 0) + error("Error reading main header from %s", input_name_ecat7.c_str()); + fclose(ecat7_fptr); + } - update_main_header(mh_in, is_3d_scan); - if (mat_write_main_header(out_fptr, &mh_in)) - error("Error writing main header to %s", output_name.c_str()); - // copy rest of sgl file into output - - char buffer[512]; - int success = EXIT_SUCCESS; - while (!feof(sgl_fptr)) - { - size_t num_read = - fread(buffer, 1, 512, sgl_fptr); - if (ferror(sgl_fptr)) - { - warning("Error reading '%s' : %s", - input_name_sgl.c_str(), strerror(errno)); - success = EXIT_FAILURE; - break; - } - size_t num_written = - fwrite(buffer, 1, num_read, out_fptr); - if (ferror(sgl_fptr) || num_read!=num_written) - { - warning("Error writing '%s' : %s", - output_name.c_str(), strerror(errno)); - success = EXIT_FAILURE; - break; - } + update_main_header(mh_in, is_3d_scan); + if (mat_write_main_header(out_fptr, &mh_in)) + error("Error writing main header to %s", output_name.c_str()); + // copy rest of sgl file into output + + char buffer[512]; + int success = EXIT_SUCCESS; + while (!feof(sgl_fptr)) { + size_t num_read = fread(buffer, 1, 512, sgl_fptr); + if (ferror(sgl_fptr)) { + warning("Error reading '%s' : %s", input_name_sgl.c_str(), strerror(errno)); + success = EXIT_FAILURE; + break; + } + size_t num_written = fwrite(buffer, 1, num_read, out_fptr); + if (ferror(sgl_fptr) || num_read != num_written) { + warning("Error writing '%s' : %s", output_name.c_str(), strerror(errno)); + success = EXIT_FAILURE; + break; } - - fclose(out_fptr); - fclose(sgl_fptr); - return success; } + fclose(out_fptr); + fclose(sgl_fptr); + return success; + } } diff --git a/src/listmode_utilities/conv_NiftyPET_stir.cxx b/src/listmode_utilities/conv_NiftyPET_stir.cxx old mode 100755 new mode 100644 index a30a9bd999..0a7c5d5915 --- a/src/listmode_utilities/conv_NiftyPET_stir.cxx +++ b/src/listmode_utilities/conv_NiftyPET_stir.cxx @@ -33,191 +33,189 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit( const char * const program_name, const int exit_status) -{ - std::cerr << "\n\nUsage : " << program_name << " [-h|--help] output_filename input_filename [--cuda_device ] [--stir_im_par ]\n\n"; - exit(exit_status); +static void +print_usage_and_exit(const char* const program_name, const int exit_status) { + std::cerr << "\n\nUsage : " << program_name + << " [-h|--help] output_filename input_filename [--cuda_device ] [--stir_im_par " + "]\n\n"; + exit(exit_status); } -static void save_disc_density(const DiscretisedDensity<3,float> &out_im_stir, const std::string &filename, const std::string &stir_im_par_fname) -{ - shared_ptr > > output_file_format_sptr; - // Use the default - if (stir_im_par_fname.empty()) - output_file_format_sptr = OutputFileFormat >::default_sptr(); - // If parameter file has been given, try to read it - else { - KeyParser parser; - parser.add_start_key("OutputFileFormat Parameters"); - parser.add_parsing_key("output file format type", &output_file_format_sptr); - parser.add_stop_key("END"); - std::ifstream in(stir_im_par_fname); - if (!parser.parse(in) || is_null_ptr(output_file_format_sptr)) - throw std::runtime_error("Failed to parse output format file (" + stir_im_par_fname + ")."); - } - output_file_format_sptr->write_to_file(filename, out_im_stir); +static void +save_disc_density(const DiscretisedDensity<3, float>& out_im_stir, const std::string& filename, + const std::string& stir_im_par_fname) { + shared_ptr>> output_file_format_sptr; + // Use the default + if (stir_im_par_fname.empty()) + output_file_format_sptr = OutputFileFormat>::default_sptr(); + // If parameter file has been given, try to read it + else { + KeyParser parser; + parser.add_start_key("OutputFileFormat Parameters"); + parser.add_parsing_key("output file format type", &output_file_format_sptr); + parser.add_stop_key("END"); + std::ifstream in(stir_im_par_fname); + if (!parser.parse(in) || is_null_ptr(output_file_format_sptr)) + throw std::runtime_error("Failed to parse output format file (" + stir_im_par_fname + ")."); + } + output_file_format_sptr->write_to_file(filename, out_im_stir); } -static shared_ptr > read_disc_density(const std::string &filename) -{ - // Read - shared_ptr > disc_sptr(read_from_file >(filename)); - // Check - if (is_null_ptr(disc_sptr)) - throw std::runtime_error("Failed to read file: " + filename + "."); +static shared_ptr> +read_disc_density(const std::string& filename) { + // Read + shared_ptr> disc_sptr(read_from_file>(filename)); + // Check + if (is_null_ptr(disc_sptr)) + throw std::runtime_error("Failed to read file: " + filename + "."); - return disc_sptr; + return disc_sptr; } -static void save_np_vec(const std::vector &vec, const std::string &filename) -{ - std::ofstream fout(filename, std::ios::out | std::ios::binary); - fout.write(reinterpret_cast(&vec[0]), vec.size()*sizeof(float)); - fout.close(); +static void +save_np_vec(const std::vector& vec, const std::string& filename) { + std::ofstream fout(filename, std::ios::out | std::ios::binary); + fout.write(reinterpret_cast(&vec[0]), vec.size() * sizeof(float)); + fout.close(); } template -static -std::vector -read_binary_file(const std::string &data_path) -{ - std::ifstream file(data_path, std::ios::in | std::ios::binary); - - // get its size: - file.seekg(0, std::ios::end); - long file_size = file.tellg(); - unsigned long num_elements = static_cast(file_size) / static_cast(sizeof(dataType)); - file.seekg(0, std::ios::beg); - - std::vector contents(num_elements); - file.read(reinterpret_cast(contents.data()), file_size); - - return contents; +static std::vector +read_binary_file(const std::string& data_path) { + std::ifstream file(data_path, std::ios::in | std::ios::binary); + + // get its size: + file.seekg(0, std::ios::end); + long file_size = file.tellg(); + unsigned long num_elements = static_cast(file_size) / static_cast(sizeof(dataType)); + file.seekg(0, std::ios::beg); + + std::vector contents(num_elements); + file.read(reinterpret_cast(contents.data()), file_size); + + return contents; } int -main(int argc, char **argv) -{ - try { - const char * const program_name = argv[0]; - - // Check for help request - for (int i=1; i0 && argv[0][0]=='-') { - if (strcmp(argv[0], "--cuda_device")==0) { - cuda_device = std::atoi(argv[1]); - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "--stir_im_par")==0) { - stir_im_par_fname = argv[1]; - argc-=2; argv+=2; - if (!(is_image && toSTIR)) { - std::cerr << "--stir_im_par can only be supplied when converting to a STIR image.\n"; - print_usage_and_exit(program_name, EXIT_FAILURE); - } - } - else { - std::cerr << "Unknown option '" << argv[0] <<"'\n"; - print_usage_and_exit(program_name, EXIT_FAILURE); - } - } +main(int argc, char** argv) { + try { + const char* const program_name = argv[0]; + + // Check for help request + for (int i = 1; i < argc; ++i) + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) + print_usage_and_exit(program_name, EXIT_SUCCESS); + + // Check for all compulsory arguments + if (argc < 5) + print_usage_and_exit(program_name, EXIT_FAILURE); + + // Get filenames + const std::string output_filename = argv[1]; + const std::string input_filename = argv[2]; + + // Am i dealing with images or sinograms? + bool is_image; + if (strcmp(argv[3], "image") == 0) + is_image = true; + else if (strcmp(argv[3], "sinogram") == 0) + is_image = false; + else { + std::cerr << "\nExpected \"image\" or \"sinogram\"\n, got: " << argv[3] << "\n"; + print_usage_and_exit(program_name, EXIT_FAILURE); + } + // to STIR or to NiftyPET? + bool toSTIR; + if (strcmp(argv[4], "toSTIR") == 0) + toSTIR = true; + else if (strcmp(argv[4], "toNP") == 0) + toSTIR = false; + else { + std::cerr << "\nExpected \"toSTIR\" or \"toNP\"\n, got: " << argv[3] << "\n"; + print_usage_and_exit(program_name, EXIT_FAILURE); + } - // Set up the niftyPET binary helper - typedef NiftyPETHelper Helper; - Helper helper; - helper.set_cuda_device_id ( cuda_device ); - helper.set_span ( 11 ); - helper.set_att(0); - helper.set_verbose(1); - helper.set_scanner_type(Scanner::Siemens_mMR); - helper.set_up(); - - // if image - if (is_image) { - // image NP -> STIR - if (toSTIR) { - std::vector input_im_np = read_binary_file(input_filename); - shared_ptr > out_im_stir_sptr = helper.create_stir_im(); - helper.convert_image_niftyPET_to_stir(*out_im_stir_sptr, input_im_np); - save_disc_density(*out_im_stir_sptr, output_filename, stir_im_par_fname); - } - // image STIR -> NP - else { - shared_ptr > input_im_stir_sptr = - read_disc_density(input_filename); - std::vector out_im_np = helper.create_niftyPET_image(); - helper.convert_image_stir_to_niftyPET(out_im_np, *input_im_stir_sptr); - save_np_vec(out_im_np, output_filename); - } - } - // if sinogram - else { - // sinogram NP -> STIR - if (toSTIR) { - std::vector input_sino_np = read_binary_file(input_filename); - shared_ptr output_sino_stir_sptr = Helper::create_stir_sino(); - helper.convert_proj_data_niftyPET_to_stir(*output_sino_stir_sptr, input_sino_np); - output_sino_stir_sptr->write_to_file(output_filename); - } - // sinogram STIR -> NP - else { - shared_ptr input_sino_stir_sptr = ProjDataInMemory::read_from_file(input_filename); - std::vector output_sino_np = helper.create_niftyPET_sinogram_with_gaps(); - helper.convert_proj_data_stir_to_niftyPET(output_sino_np,*input_sino_stir_sptr); - save_np_vec(output_sino_np, output_filename); - } + // skip past compulsory arguments + argc -= 5; + argv += 5; + + // Set default value for optional arguments + char cuda_device(0); + std::string stir_im_par_fname; + + // Loop over remaining input + while (argc > 0 && argv[0][0] == '-') { + if (strcmp(argv[0], "--cuda_device") == 0) { + cuda_device = std::atoi(argv[1]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--stir_im_par") == 0) { + stir_im_par_fname = argv[1]; + argc -= 2; + argv += 2; + if (!(is_image && toSTIR)) { + std::cerr << "--stir_im_par can only be supplied when converting to a STIR image.\n"; + print_usage_and_exit(program_name, EXIT_FAILURE); } + } else { + std::cerr << "Unknown option '" << argv[0] << "'\n"; + print_usage_and_exit(program_name, EXIT_FAILURE); + } } - // If there was an error - catch(const std::exception &error) { - std::cerr << "\nError encountered:\n\t" << error.what() << "\n\n"; - return EXIT_FAILURE; + // Set up the niftyPET binary helper + typedef NiftyPETHelper Helper; + Helper helper; + helper.set_cuda_device_id(cuda_device); + helper.set_span(11); + helper.set_att(0); + helper.set_verbose(1); + helper.set_scanner_type(Scanner::Siemens_mMR); + helper.set_up(); + + // if image + if (is_image) { + // image NP -> STIR + if (toSTIR) { + std::vector input_im_np = read_binary_file(input_filename); + shared_ptr> out_im_stir_sptr = helper.create_stir_im(); + helper.convert_image_niftyPET_to_stir(*out_im_stir_sptr, input_im_np); + save_disc_density(*out_im_stir_sptr, output_filename, stir_im_par_fname); + } + // image STIR -> NP + else { + shared_ptr> input_im_stir_sptr = read_disc_density(input_filename); + std::vector out_im_np = helper.create_niftyPET_image(); + helper.convert_image_stir_to_niftyPET(out_im_np, *input_im_stir_sptr); + save_np_vec(out_im_np, output_filename); + } } - catch(...) { - std::cerr << "\nError encountered.\n\n"; - return EXIT_FAILURE; + // if sinogram + else { + // sinogram NP -> STIR + if (toSTIR) { + std::vector input_sino_np = read_binary_file(input_filename); + shared_ptr output_sino_stir_sptr = Helper::create_stir_sino(); + helper.convert_proj_data_niftyPET_to_stir(*output_sino_stir_sptr, input_sino_np); + output_sino_stir_sptr->write_to_file(output_filename); + } + // sinogram STIR -> NP + else { + shared_ptr input_sino_stir_sptr = ProjDataInMemory::read_from_file(input_filename); + std::vector output_sino_np = helper.create_niftyPET_sinogram_with_gaps(); + helper.convert_proj_data_stir_to_niftyPET(output_sino_np, *input_sino_stir_sptr); + save_np_vec(output_sino_np, output_filename); + } } - return(EXIT_SUCCESS); + } + + // If there was an error + catch (const std::exception& error) { + std::cerr << "\nError encountered:\n\t" << error.what() << "\n\n"; + return EXIT_FAILURE; + } catch (...) { + std::cerr << "\nError encountered.\n\n"; + return EXIT_FAILURE; + } + return (EXIT_SUCCESS); } diff --git a/src/listmode_utilities/list_lm_countrates.cxx b/src/listmode_utilities/list_lm_countrates.cxx index 20ac9aaad0..dd75c7bdda 100644 --- a/src/listmode_utilities/list_lm_countrates.cxx +++ b/src/listmode_utilities/list_lm_countrates.cxx @@ -31,74 +31,60 @@ #include #include - USING_NAMESPACE_STIR -int main(int argc, char * argv[]) -{ - if (argc<3 || argc>4) { +int +main(int argc, char* argv[]) { + if (argc < 3 || argc > 4) { std::cerr << "Usage: " << argv[0] << " output_filename listmode_file [time_interval_in_secs]\n" - << "time_interval_in_secs defaults to 1\n" - << "Output is a file with the count-rates per time interval in CSV format as in\n" - << "start_time_in_secs , end_time_in_secs , num_prompts , num_delayeds\n"; + << "time_interval_in_secs defaults to 1\n" + << "Output is a file with the count-rates per time interval in CSV format as in\n" + << "start_time_in_secs , end_time_in_secs , num_prompts , num_delayeds\n"; exit(EXIT_FAILURE); } - shared_ptr lm_data_ptr - (read_from_file(argv[2])); + shared_ptr lm_data_ptr(read_from_file(argv[2])); const std::string hc_filename = argv[1]; std::ofstream headcurve(hc_filename.c_str()); - if (!headcurve) - { - warning("Error opening headcurve file %s\n", hc_filename.c_str()); - exit(EXIT_FAILURE); - } + if (!headcurve) { + warning("Error opening headcurve file %s\n", hc_filename.c_str()); + exit(EXIT_FAILURE); + } - const double interval = argc>3 ? atof(argv[3]) : 1; + const double interval = argc > 3 ? atof(argv[3]) : 1; - shared_ptr record_sptr = lm_data_ptr->get_empty_record_sptr(); + shared_ptr record_sptr = lm_data_ptr->get_empty_record_sptr(); ListRecord& record = *record_sptr; double current_time = 0; - bool first_timing_event_read=false; + bool first_timing_event_read = false; unsigned long num_prompts = 0UL; unsigned long num_delayeds = 0UL; - while (true) - { - if (lm_data_ptr->get_next_record(record) == Succeeded::no) - { - // no more events in file for some reason - break; //get out of while loop - } - if (record.is_time()) - { - const double new_time = record.time().get_time_in_secs(); - if (!first_timing_event_read) - { - current_time = new_time; - num_prompts=0UL; - num_delayeds=0UL; - first_timing_event_read = true; - } - else if (new_time >= current_time+interval) - { - headcurve << std::fixed << std::setprecision(3) - << current_time - << " , " << current_time+interval - << " , " << num_prompts - << " , " << num_delayeds - << '\n'; - num_prompts=0UL; - num_delayeds=0UL; - current_time += interval; - } - } - if (record.is_event()) - { - if (record.event() .is_prompt()) - ++num_prompts; - else - ++num_delayeds; - } + while (true) { + if (lm_data_ptr->get_next_record(record) == Succeeded::no) { + // no more events in file for some reason + break; // get out of while loop + } + if (record.is_time()) { + const double new_time = record.time().get_time_in_secs(); + if (!first_timing_event_read) { + current_time = new_time; + num_prompts = 0UL; + num_delayeds = 0UL; + first_timing_event_read = true; + } else if (new_time >= current_time + interval) { + headcurve << std::fixed << std::setprecision(3) << current_time << " , " << current_time + interval << " , " + << num_prompts << " , " << num_delayeds << '\n'; + num_prompts = 0UL; + num_delayeds = 0UL; + current_time += interval; + } + } + if (record.is_event()) { + if (record.event().is_prompt()) + ++num_prompts; + else + ++num_delayeds; + } } return EXIT_SUCCESS; } diff --git a/src/listmode_utilities/list_lm_events.cxx b/src/listmode_utilities/list_lm_events.cxx index 32721c97f2..3521a7e3d6 100644 --- a/src/listmode_utilities/list_lm_events.cxx +++ b/src/listmode_utilities/list_lm_events.cxx @@ -18,16 +18,15 @@ */ /*! - \file + \file \ingroup listmode_utilities \brief Program to show info about listmode data - + \author Kris Thielemans \author Daniel Deidda */ - #include "stir/listmode/ListRecord.h" #include "stir/listmode/ListEvent.h" #include "stir/listmode/ListTime.h" @@ -49,167 +48,127 @@ using std::endl; using std::vector; #endif - - USING_NAMESPACE_STIR -int main(int argc, char *argv[]) -{ - const char * const program_name = argv[0]; +int +main(int argc, char* argv[]) { + const char* const program_name = argv[0]; // skip program name --argc; ++argv; - bool list_time=true; - bool list_coincidence=false; - bool list_SPECT_event=false; - bool list_gating=true; - bool list_unknown=false; + bool list_time = true; + bool list_coincidence = false; + bool list_SPECT_event = false; + bool list_gating = true; + bool list_unknown = false; unsigned long num_events_to_list = 0; - while (argc>1 && argv[0][0]=='-') - { - if (strcmp(argv[0], "--num-events-to-list")==0) - { - num_events_to_list = atol(argv[1]); - } - else if (strcmp(argv[0], "--time")==0) - { - list_time = atoi(argv[1])!=0; - } - else if (strcmp(argv[0], "--gating")==0) - { - list_gating = atoi(argv[1])!=0; - } - else if (strcmp(argv[0], "--coincidence")==0) - { - list_coincidence = atoi(argv[1])!=0; - } - else if (strcmp(argv[0], "--SPECT-event")==0) - { - list_SPECT_event = atoi(argv[1])!=0; - } - else if (strcmp(argv[0], "--unknown")==0) - { - list_unknown = atoi(argv[1])!=0; - } - else - { - cerr << "Unrecognised option\n"; - return EXIT_FAILURE; - } - argc-=2; argv+=2; - } - - if (argc!=1) - { - cerr << "Usage: " << program_name << "[options] lm_filename\n" - << "Options:\n" - << "--time 0|1 : list time events or not (default: 1)\n" - << "--gating 0|1 : list gating events or not (default: 1)\n" - << "--coincidence 0|1 : list coincidence events or not (default: 0)\n" - << "--unknown 0|1 : list if event of unknown type encountered or not (default: 0)\n" - << "--num-events-to-list : limit number of events written to stdout\n"; + while (argc > 1 && argv[0][0] == '-') { + if (strcmp(argv[0], "--num-events-to-list") == 0) { + num_events_to_list = atol(argv[1]); + } else if (strcmp(argv[0], "--time") == 0) { + list_time = atoi(argv[1]) != 0; + } else if (strcmp(argv[0], "--gating") == 0) { + list_gating = atoi(argv[1]) != 0; + } else if (strcmp(argv[0], "--coincidence") == 0) { + list_coincidence = atoi(argv[1]) != 0; + } else if (strcmp(argv[0], "--SPECT-event") == 0) { + list_SPECT_event = atoi(argv[1]) != 0; + } else if (strcmp(argv[0], "--unknown") == 0) { + list_unknown = atoi(argv[1]) != 0; + } else { + cerr << "Unrecognised option\n"; return EXIT_FAILURE; } + argc -= 2; + argv += 2; + } + + if (argc != 1) { + cerr << "Usage: " << program_name << "[options] lm_filename\n" + << "Options:\n" + << "--time 0|1 : list time events or not (default: 1)\n" + << "--gating 0|1 : list gating events or not (default: 1)\n" + << "--coincidence 0|1 : list coincidence events or not (default: 0)\n" + << "--unknown 0|1 : list if event of unknown type encountered or not (default: 0)\n" + << "--num-events-to-list : limit number of events written to stdout\n"; + return EXIT_FAILURE; + } shared_ptr lm_data_ptr(read_from_file(argv[0])); cout << "Scanner: " << lm_data_ptr->get_scanner_ptr()->get_name() << endl; unsigned long num_listed_events = 0; - { + { // loop over all events in the listmode file - shared_ptr record_sptr = lm_data_ptr->get_empty_record_sptr(); + shared_ptr record_sptr = lm_data_ptr->get_empty_record_sptr(); ListRecord& record = *record_sptr; - while (num_events_to_list==0 || num_events_to_list!=num_listed_events) - { - bool recognised = false; - bool listed = false; -// std::cout<<"ciao"<get_next_record(record) == Succeeded::no) - { - // no more events in file for some reason - break; //get out of while loop + while (num_events_to_list == 0 || num_events_to_list != num_listed_events) { + bool recognised = false; + bool listed = false; + // std::cout<<"ciao"<get_next_record(record) == Succeeded::no) { + // no more events in file for some reason + break; // get out of while loop } - if (record.is_time()) - { - recognised=true; - if (list_time) - { - cout << "Time " << record.time().get_time_in_millisecs(); - listed = true; - } - } - { - ListRecordWithGatingInput * record_ptr = dynamic_cast(&record); - if (record_ptr!=0 && record_ptr->is_gating_input()) - { - recognised=true; - if (list_gating) - { - cout << "Gating " << std::hex << record_ptr->gating_input().get_gating() << std::dec; - listed = true; - } - } + if (record.is_time()) { + recognised = true; + if (list_time) { + cout << "Time " << record.time().get_time_in_millisecs(); + listed = true; } - if (record.is_event()) - { - recognised=true; - if (list_coincidence) - {CListEventCylindricalScannerWithDiscreteDetectors * event_ptr = - dynamic_cast(&record.event()); - if (event_ptr!=0) - { - DetectionPositionPair<> det_pos; - event_ptr->get_detection_position(det_pos); - cout << "Coincidence " << (event_ptr->is_prompt() ? "p " : "d ") - << "(c:" << det_pos.pos1().tangential_coord() - << ",r:" << det_pos.pos1().axial_coord() - << ",l:" << det_pos.pos1().radial_coord() - << ")-" - << "(c:" << det_pos.pos2().tangential_coord() - << ",r:" << det_pos.pos2().axial_coord() - << ",l:" << det_pos.pos2().radial_coord() - << ")"; - listed = true; - } - } - if (list_SPECT_event) - {ListEvent * event_ptr = - dynamic_cast(&record.event()); - if (event_ptr!=0) - { - LORAs2Points lor; - lor=event_ptr->get_LOR(); - cout << "Gamma event: LOR as two points " - << "(x1:" << lor.p1().x() - << ",y1:" << lor.p1().y() - << ",z1:" << lor.p1().z() - << ")-" - << "(x2:" << lor.p2().x() - << ",y2:" << lor.p2().y() - << ",z2:" << lor.p2().z() - << ")"; - listed = true; - } - } + } + { + ListRecordWithGatingInput* record_ptr = dynamic_cast(&record); + if (record_ptr != 0 && record_ptr->is_gating_input()) { + recognised = true; + if (list_gating) { + cout << "Gating " << std::hex << record_ptr->gating_input().get_gating() << std::dec; + listed = true; + } } - if (!recognised && list_unknown) - { - cout << "Unknown type"; - listed = true; + } + if (record.is_event()) { + recognised = true; + if (list_coincidence) { + CListEventCylindricalScannerWithDiscreteDetectors* event_ptr = + dynamic_cast(&record.event()); + if (event_ptr != 0) { + DetectionPositionPair<> det_pos; + event_ptr->get_detection_position(det_pos); + cout << "Coincidence " << (event_ptr->is_prompt() ? "p " : "d ") << "(c:" << det_pos.pos1().tangential_coord() + << ",r:" << det_pos.pos1().axial_coord() << ",l:" << det_pos.pos1().radial_coord() << ")-" + << "(c:" << det_pos.pos2().tangential_coord() << ",r:" << det_pos.pos2().axial_coord() + << ",l:" << det_pos.pos2().radial_coord() << ")"; + cout << " delta time: " << event_ptr->get_delta_time(); + listed = true; + } } - if (listed) - { - ++num_listed_events; - cout << '\n'; + if (list_SPECT_event) { + ListEvent* event_ptr = dynamic_cast(&record.event()); + if (event_ptr != 0) { + LORAs2Points lor; + lor = event_ptr->get_LOR(); + cout << "Gamma event: LOR as two points " + << "(x1:" << lor.p1().x() << ",y1:" << lor.p1().y() << ",z1:" << lor.p1().z() << ")-" + << "(x2:" << lor.p2().x() << ",y2:" << lor.p2().y() << ",z2:" << lor.p2().z() << ")"; + listed = true; } + } + } + if (!recognised && list_unknown) { + cout << "Unknown type"; + listed = true; + } + if (listed) { + ++num_listed_events; + cout << '\n'; } + } cout << '\n'; - } return EXIT_SUCCESS; } - diff --git a/src/listmode_utilities/list_lm_info.cxx b/src/listmode_utilities/list_lm_info.cxx index 4a240619d5..8e106d510d 100644 --- a/src/listmode_utilities/list_lm_info.cxx +++ b/src/listmode_utilities/list_lm_info.cxx @@ -36,22 +36,22 @@ #include "stir/ProjDataInfo.h" #include "stir/is_null_ptr.h" #include "stir/IO/read_from_file.h" -#include +#include #include USING_NAMESPACE_STIR -void print_usage_and_exit(const std::string& program_name) -{ - std::cerr<<"Usage: " << program_name << " [--all | --geom | --exam] listmode_file\n" - <<"\nAdd one or more options to print the exam/geometric information.\n" - <<"\nIf no option is specified, exam info is printed.\n"; +void +print_usage_and_exit(const std::string& program_name) { + std::cerr << "Usage: " << program_name << " [--all | --geom | --exam] listmode_file\n" + << "\nAdd one or more options to print the exam/geometric information.\n" + << "\nIf no option is specified, exam info is printed.\n"; exit(EXIT_FAILURE); } -int main(int argc, char *argv[]) -{ - const char * const program_name = argv[0]; +int +main(int argc, char* argv[]) { + const char* const program_name = argv[0]; // skip program name --argc; ++argv; @@ -62,32 +62,27 @@ int main(int argc, char *argv[]) bool no_options = true; // need this for default behaviour // first process command line options - while (argc>0 && argv[0][0]=='-' && argc>=2) - { - no_options=false; - if (strcmp(argv[0], "--all")==0) - { - print_geom = print_exam = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--geom")==0) - { - print_geom = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--exam")==0) - { - print_exam = true; - --argc; ++argv; - } - else - print_usage_and_exit(program_name); - } + while (argc > 0 && argv[0][0] == '-' && argc >= 2) { + no_options = false; + if (strcmp(argv[0], "--all") == 0) { + print_geom = print_exam = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--geom") == 0) { + print_geom = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--exam") == 0) { + print_exam = true; + --argc; + ++argv; + } else + print_usage_and_exit(program_name); + } if (no_options) print_exam = true; - if(argc!=1) - { + if (argc != 1) { print_usage_and_exit(program_name); } @@ -96,11 +91,10 @@ int main(int argc, char *argv[]) shared_ptr lm_data_sptr(read_from_file(filename)); - if (is_null_ptr(lm_data_sptr)) - { - warning("Could not read %s", filename.c_str()); - return EXIT_FAILURE; - } + if (is_null_ptr(lm_data_sptr)) { + warning("Could not read %s", filename.c_str()); + return EXIT_FAILURE; + } if (print_exam) std::cout << lm_data_sptr->get_exam_info_sptr()->parameter_info(); diff --git a/src/listmode_utilities/lm_fansums.cxx b/src/listmode_utilities/lm_fansums.cxx index b35ba2e011..a94fb3b9ba 100644 --- a/src/listmode_utilities/lm_fansums.cxx +++ b/src/listmode_utilities/lm_fansums.cxx @@ -1,13 +1,13 @@ // // /*! - \file + \file \ingroup listmode \brief Program to compute detector fansums directly from listmode data - + \author Kris Thielemans - + $Revision $ */ /* @@ -27,7 +27,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/utilities.h" #include "stir/shared_ptr.h" #include "stir/ParsingObject.h" @@ -62,12 +61,9 @@ using std::vector; START_NAMESPACE_STIR - -class LmFansums : public ParsingObject -{ +class LmFansums : public ParsingObject { public: - - LmFansums(const char * const par_filename); + LmFansums(const char* const par_filename); int max_segment_num_to_process; int fan_size; @@ -75,8 +71,8 @@ class LmFansums : public ParsingObject TimeFrameDefinitions frame_defs; void compute(); -private: +private: virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); @@ -88,193 +84,148 @@ class LmFansums : public ParsingObject bool interactive; - void write_fan_sums(const Array<2,float>& data_fan_sums, - const unsigned current_frame_num) const; + void write_fan_sums(const Array<2, float>& data_fan_sums, const unsigned current_frame_num) const; }; -void -LmFansums:: -set_defaults() -{ +void +LmFansums::set_defaults() { max_segment_num_to_process = -1; fan_size = -1; store_prompts = true; delayed_increment = -1; - interactive=false; + interactive = false; } -void -LmFansums:: -initialise_keymap() -{ +void +LmFansums::initialise_keymap() { parser.add_start_key("lm_fansums Parameters"); - parser.add_key("input file",&input_filename); - parser.add_key("frame_definition file",&frame_definition_filename); - parser.add_key("output filename prefix",&output_filename_prefix); + parser.add_key("input file", &input_filename); + parser.add_key("frame_definition file", &frame_definition_filename); + parser.add_key("output filename prefix", &output_filename_prefix); parser.add_key("tangential fan_size", &fan_size); - parser.add_key("maximum absolute segment number to process", &max_segment_num_to_process); + parser.add_key("maximum absolute segment number to process", &max_segment_num_to_process); // TODO can't do this yet // if (CListEvent::has_delayeds()) { - parser.add_key("Store 'prompts'",&store_prompts); - parser.add_key("increment to use for 'delayeds'",&delayed_increment); + parser.add_key("Store 'prompts'", &store_prompts); + parser.add_key("increment to use for 'delayeds'", &delayed_increment); } - parser.add_key("List event coordinates",&interactive); - parser.add_stop_key("END"); - + parser.add_key("List event coordinates", &interactive); + parser.add_stop_key("END"); } - bool -LmFansums:: -post_processing() -{ - lm_data_ptr = - read_from_file(input_filename); - - const int num_rings = - lm_data_ptr->get_scanner_ptr()->get_num_rings(); - if (max_segment_num_to_process==-1) - max_segment_num_to_process = num_rings-1; +LmFansums::post_processing() { + lm_data_ptr = read_from_file(input_filename); + + const int num_rings = lm_data_ptr->get_scanner_ptr()->get_num_rings(); + if (max_segment_num_to_process == -1) + max_segment_num_to_process = num_rings - 1; else - max_segment_num_to_process = - min(max_segment_num_to_process, num_rings-1); + max_segment_num_to_process = min(max_segment_num_to_process, num_rings - 1); - const int max_fan_size = - lm_data_ptr->get_scanner_ptr()->get_max_num_non_arccorrected_bins(); - if (fan_size==-1) + const int max_fan_size = lm_data_ptr->get_scanner_ptr()->get_max_num_non_arccorrected_bins(); + if (fan_size == -1) fan_size = max_fan_size; else - fan_size = - min(fan_size, max_fan_size); + fan_size = min(fan_size, max_fan_size); frame_defs = TimeFrameDefinitions(frame_definition_filename); return false; } -LmFansums:: -LmFansums(const char * const par_filename) -{ +LmFansums::LmFansums(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - parse(par_filename) ; + if (par_filename != 0) + parse(par_filename); else ask_parameters(); - } - void -LmFansums:: -compute() -{ +LmFansums::compute() { //*********** get Scanner details - const int num_rings = - lm_data_ptr->get_scanner_ptr()->get_num_rings(); - const int num_detectors_per_ring = - lm_data_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); - + const int num_rings = lm_data_ptr->get_scanner_ptr()->get_num_rings(); + const int num_detectors_per_ring = lm_data_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); //*********** Finally, do the real work - + CPUTimer timer; timer.start(); - + double time_of_last_stored_event = 0; long num_stored_events = 0; - Array<2,float> data_fan_sums(IndexRange2D(num_rings, num_detectors_per_ring)); - + Array<2, float> data_fan_sums(IndexRange2D(num_rings, num_detectors_per_ring)); + // go to the beginning of the binary data lm_data_ptr->reset(); - + unsigned int current_frame_num = 1; - { + { // loop over all events in the listmode file - shared_ptr record_sptr = - lm_data_ptr->get_empty_record_sptr(); + shared_ptr record_sptr = lm_data_ptr->get_empty_record_sptr(); ListRecord& record = *record_sptr; - bool first_event=true; + bool first_event = true; double current_time = 0; - while (true) - { - if (lm_data_ptr->get_next_record(record) == Succeeded::no) - { - // no more events in file for some reason - write_fan_sums(data_fan_sums, current_frame_num); - break; //get out of while loop + while (true) { + if (lm_data_ptr->get_next_record(record) == Succeeded::no) { + // no more events in file for some reason + write_fan_sums(data_fan_sums, current_frame_num); + break; // get out of while loop + } + if (record.is_time()) { + const double new_time = record.time().get_time_in_secs(); + if (new_time >= frame_defs.get_end_time(current_frame_num)) { + while (current_frame_num <= frame_defs.get_num_frames() && new_time >= frame_defs.get_end_time(current_frame_num)) { + write_fan_sums(data_fan_sums, current_frame_num++); + data_fan_sums.fill(0); + } + if (current_frame_num > frame_defs.get_num_frames()) + break; // get out of while loop } - if (record.is_time()) - { - const double new_time = record.time().get_time_in_secs(); - if (new_time >= frame_defs.get_end_time(current_frame_num)) - { - while (current_frame_num <= frame_defs.get_num_frames() && - new_time >= frame_defs.get_end_time(current_frame_num)) - { - write_fan_sums(data_fan_sums, current_frame_num++); - data_fan_sums.fill(0); - } - if (current_frame_num > frame_defs.get_num_frames()) - break; // get out of while loop + current_time = new_time; + } else if (record.is_event() && frame_defs.get_start_time(current_frame_num) <= current_time) { + // do a consistency check with dynamic_cast first + if (first_event && dynamic_cast(&record.event()) == 0) + error("Currently only works for scanners with discrete detectors."); + first_event = false; + + // see if we increment or decrement the value in the sinogram + const int event_increment = record.event().is_prompt() ? (store_prompts ? 1 : 0) // it's a prompt + : delayed_increment; // it is a delayed-coincidence event + + if (event_increment == 0) + continue; + + DetectionPositionPair<> det_pos; + // because of above consistency check, we can use static_cast here (saving a bit of time) + dynamic_cast(record.event()).get_detection_position(det_pos); + const int ra = det_pos.pos1().axial_coord(); + const int rb = det_pos.pos2().axial_coord(); + const int a = det_pos.pos1().tangential_coord(); + const int b = det_pos.pos2().tangential_coord(); + if (abs(ra - rb) <= max_segment_num_to_process) { + const int det_num_diff = (a - b + 3 * num_detectors_per_ring / 2) % num_detectors_per_ring; + if (det_num_diff <= fan_size / 2 || det_num_diff >= num_detectors_per_ring - fan_size / 2) { + data_fan_sums[ra][a] += event_increment; + data_fan_sums[rb][b] += event_increment; + num_stored_events += event_increment; + } else { } - current_time = new_time; + } else { } - else if (record.is_event() && frame_defs.get_start_time(current_frame_num) <= current_time) - { - // do a consistency check with dynamic_cast first - if (first_event && dynamic_cast(&record.event()) == 0) - error("Currently only works for scanners with discrete detectors."); - first_event=false; - - // see if we increment or decrement the value in the sinogram - const int event_increment = - record.event().is_prompt() - ? ( store_prompts ? 1 : 0 ) // it's a prompt - : delayed_increment;//it is a delayed-coincidence event - - if (event_increment==0) - continue; - - DetectionPositionPair<> det_pos; - // because of above consistency check, we can use static_cast here (saving a bit of time) - dynamic_cast(record.event()). - get_detection_position(det_pos); - const int ra = det_pos.pos1().axial_coord(); - const int rb = det_pos.pos2().axial_coord(); - const int a = det_pos.pos1().tangential_coord(); - const int b = det_pos.pos2().tangential_coord(); - if (abs(ra-rb)<=max_segment_num_to_process) - { - const int det_num_diff = - (a-b+3*num_detectors_per_ring/2)%num_detectors_per_ring; - if (det_num_diff<=fan_size/2 || - det_num_diff>=num_detectors_per_ring-fan_size/2) - { - data_fan_sums[ra][a] += event_increment; - data_fan_sums[rb][b] += event_increment; - num_stored_events += event_increment; - } - else - { - } - } - else - { - } - - } // end of spatial event processing - } // end of while loop over all events - - time_of_last_stored_event = - max(time_of_last_stored_event,current_time); - } + } // end of spatial event processing + } // end of while loop over all events + + time_of_last_stored_event = max(time_of_last_stored_event, current_time); + } timer.stop(); - + cerr << "Last stored event was recorded after time-tick at " << time_of_last_stored_event << " secs\n"; if (current_frame_num <= frame_defs.get_num_frames()) cerr << "Early stop due to EOF. " << endl; @@ -283,13 +234,9 @@ compute() cerr << "\nThis took " << timer.value() << "s CPU time." << endl; } - // write fan sums to file -void -LmFansums:: -write_fan_sums(const Array<2,float>& data_fan_sums, - const unsigned current_frame_num) const -{ +void +LmFansums::write_fan_sums(const Array<2, float>& data_fan_sums, const unsigned current_frame_num) const { char txt[50]; sprintf(txt, "_f%u.dat", current_frame_num); std::string filename = output_filename_prefix; @@ -301,28 +248,19 @@ write_fan_sums(const Array<2,float>& data_fan_sums, END_NAMESPACE_STIR - USING_NAMESPACE_STIR - - - - /************************ main ************************/ +int +main(int argc, char* argv[]) { -int main(int argc, char * argv[]) -{ - - if (argc!=1 && argc!=2) { + if (argc != 1 && argc != 2) { cerr << "Usage: " << argv[0] << " [par_file]\n"; exit(EXIT_FAILURE); } - LmFansums lm_fansums(argc==2 ? argv[1] : 0); + LmFansums lm_fansums(argc == 2 ? argv[1] : 0); lm_fansums.compute(); return EXIT_SUCCESS; } - - - diff --git a/src/listmode_utilities/lm_to_projdata.cxx b/src/listmode_utilities/lm_to_projdata.cxx index fc6e50e285..a531f8f7a7 100644 --- a/src/listmode_utilities/lm_to_projdata.cxx +++ b/src/listmode_utilities/lm_to_projdata.cxx @@ -1,7 +1,7 @@ // // /*! - \file + \file \ingroup listmode_utilities \brief Program to bin listmode data to 3d sinograms @@ -10,7 +10,7 @@ \author Kris Thielemans \author Sanida Mustafovic - + */ /* Copyright (C) 2000- 2009, Hammersmith Imanet Ltd @@ -39,31 +39,34 @@ using std::endl; USING_NAMESPACE_STIR - - -int main(int argc, char * argv[]) -{ - if (argc>1) - { - if (strcmp(argv[1], "--help") == 0 || - strcmp(argv[1], "-?") == 0) { - cerr << "\nUsage: " << argv[0] << " [par_file]\n" - << "Run "<::default_sptr()-> - list_registered_names(cerr); - exit(EXIT_SUCCESS); - } +int +main(int argc, char* argv[]) { + if (argc > 1) { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { + cerr << "\nUsage: " << argv[0] << " [par_file]\n" + << "Run " << argv[0] << " --input-formats to list the supported input formats\n"; + exit(EXIT_SUCCESS); } - LmToProjData application(argc==2 ? argv[1] : 0); + // Display the supported inputs, we need this in order to know + // which listmode files are supported + if (strcmp(argv[1], "--input-formats") == 0) { + cerr << endl << "Supported input file formats:\n"; + InputFileFormatRegistry::default_sptr()->list_registered_names(cerr); + exit(EXIT_SUCCESS); + } + if (strcmp(argv[1], "--test_timing_positions") == 0) { + cerr << "A test function for TOF data which I could not fit anywhere else right now:\n" + "It is going to fill every segment with the index number of the respective TOF position \n" + "and then stop.\n"; + std::cout << argc << std::endl; + std::cout << argv[0] << "\n" << argv[1] << "\n" << argv[2] << std::endl; + LmToProjData application(argc == 3 ? argv[2] : 0); + application.run_tof_test_function(); + exit(EXIT_SUCCESS); + } + } + LmToProjData application(argc == 2 ? argv[1] : 0); application.process_data(); return EXIT_SUCCESS; } - diff --git a/src/listmode_utilities/lm_to_projdata_NiftyPET.cxx b/src/listmode_utilities/lm_to_projdata_NiftyPET.cxx index 07f271d2da..760b2fa1e2 100644 --- a/src/listmode_utilities/lm_to_projdata_NiftyPET.cxx +++ b/src/listmode_utilities/lm_to_projdata_NiftyPET.cxx @@ -1,5 +1,5 @@ /*! - \file + \file \ingroup listmode_utilities \ingroup NiftyPET @@ -29,121 +29,123 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit( const char * const program_name, const int exit_status) -{ - std::cerr << "\n\nUsage : " << program_name << " [-h|--help] listmode_binary_file tstart tstop [-N|--norm_binary ] [-p|--prompts ] [-d|--delayeds ] [-r|--randoms ] [-n|--norm_sino ] [--cuda_device ] [-v|--verbose ]\n\n"; - exit(exit_status); +static void +print_usage_and_exit(const char* const program_name, const int exit_status) { + std::cerr + << "\n\nUsage : " << program_name + << " [-h|--help] listmode_binary_file tstart tstop [-N|--norm_binary ] [-p|--prompts ] [-d|--delayeds " + "] [-r|--randoms ] [-n|--norm_sino ] [--cuda_device ] [-v|--verbose ]\n\n"; + exit(exit_status); } -int main(int argc, char * argv[]) -{ - try { - const char * const program_name = argv[0]; - - // Check for help request - for (int i=1; i0 && argv[0][0]=='-') { - - if (strcmp(argv[0], "-p")==0 || strcmp(argv[0], "--prompts")==0) { - p_filename = argv[1]; - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "-d")==0 || strcmp(argv[0], "--delayeds")==0) { - d_filename = argv[1]; - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "-r")==0 || strcmp(argv[0], "--randoms")==0) { - r_filename = argv[1]; - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "-N")==0 || strcmp(argv[0], "--norm_binary")==0) { - input_norm_binary = argv[1]; - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "-n")==0 || strcmp(argv[0], "--norm_sino")==0) { - n_filename = argv[1]; - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "--cuda_device")==0) { - cuda_device = std::atoi(argv[1]); - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "-v")==0 || strcmp(argv[0], "--verbose")==0) { - verbose = std::atoi(argv[1]); - argc-=2; argv+=2; - } - else { - std::cerr << "Unknown option '" << argv[0] <<"'\n"; - print_usage_and_exit(program_name, EXIT_FAILURE); - } - } - if (p_filename.empty() && d_filename.empty() && r_filename.empty() && n_filename.empty()) { - std::cerr << "At least one output filename required.\n"; - print_usage_and_exit(program_name, EXIT_FAILURE); - } - if (input_norm_binary.empty() && !n_filename.empty()) { - std::cerr << "To extract norm sinogram, need to supply norm binary file.\n"; - print_usage_and_exit(program_name, EXIT_FAILURE); - } - - LmToProjDataNiftyPET lmNP; - lmNP.set_cuda_device(cuda_device); - lmNP.set_cuda_verbosity(verbose); - lmNP.set_listmode_binary_file(input_filename); - lmNP.set_norm_binary_file(input_norm_binary); - lmNP.set_start_time(tstart); - lmNP.set_stop_time(tstop); - lmNP.process_data(); - - // Save outputs - if (!p_filename.empty()) { - std::cout << "\n saving prompts sinogram to " << p_filename << "\n"; - lmNP.get_prompts_sptr()->write_to_file(p_filename); - } - if (!d_filename.empty()) { - std::cout << "\n saving delayeds sinogram to " << d_filename << "\n"; - lmNP.get_delayeds_sptr()->write_to_file(d_filename); - } - if (!r_filename.empty()) { - std::cout << "\n saving randoms sinogram to " << r_filename << "\n"; - lmNP.get_randoms_sptr()->write_to_file(r_filename); - } - if (!n_filename.empty()) { - std::cout << "\n saving norm sinogram to " << n_filename << "\n"; - lmNP.get_norm_sptr()->write_to_file(n_filename); - } +int +main(int argc, char* argv[]) { + try { + const char* const program_name = argv[0]; + + // Check for help request + for (int i = 1; i < argc; ++i) + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) + print_usage_and_exit(program_name, EXIT_SUCCESS); + + // Check for all compulsory arguments + if (argc < 4) + print_usage_and_exit(program_name, EXIT_FAILURE); + + // Get filenames + const std::string input_filename = argv[1]; + const int tstart = std::atoi(argv[2]); + const int tstop = std::atoi(argv[3]); + + // skip past compulsory arguments + argc -= 4; + argv += 4; + + // Set default value for optional arguments + std::string p_filename, d_filename, r_filename, input_norm_binary, n_filename; + char cuda_device(0); + bool verbose(true); + + // Loop over remaining input + while (argc > 0 && argv[0][0] == '-') { + + if (strcmp(argv[0], "-p") == 0 || strcmp(argv[0], "--prompts") == 0) { + p_filename = argv[1]; + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "-d") == 0 || strcmp(argv[0], "--delayeds") == 0) { + d_filename = argv[1]; + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "-r") == 0 || strcmp(argv[0], "--randoms") == 0) { + r_filename = argv[1]; + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "-N") == 0 || strcmp(argv[0], "--norm_binary") == 0) { + input_norm_binary = argv[1]; + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "-n") == 0 || strcmp(argv[0], "--norm_sino") == 0) { + n_filename = argv[1]; + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--cuda_device") == 0) { + cuda_device = std::atoi(argv[1]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "-v") == 0 || strcmp(argv[0], "--verbose") == 0) { + verbose = std::atoi(argv[1]); + argc -= 2; + argv += 2; + } else { + std::cerr << "Unknown option '" << argv[0] << "'\n"; + print_usage_and_exit(program_name, EXIT_FAILURE); + } + } + if (p_filename.empty() && d_filename.empty() && r_filename.empty() && n_filename.empty()) { + std::cerr << "At least one output filename required.\n"; + print_usage_and_exit(program_name, EXIT_FAILURE); + } + if (input_norm_binary.empty() && !n_filename.empty()) { + std::cerr << "To extract norm sinogram, need to supply norm binary file.\n"; + print_usage_and_exit(program_name, EXIT_FAILURE); } - // If there was an error - catch(const std::exception &error) { - std::cerr << "\nError encountered:\n\t" << error.what() << "\n\n"; - return EXIT_FAILURE; + LmToProjDataNiftyPET lmNP; + lmNP.set_cuda_device(cuda_device); + lmNP.set_cuda_verbosity(verbose); + lmNP.set_listmode_binary_file(input_filename); + lmNP.set_norm_binary_file(input_norm_binary); + lmNP.set_start_time(tstart); + lmNP.set_stop_time(tstop); + lmNP.process_data(); + + // Save outputs + if (!p_filename.empty()) { + std::cout << "\n saving prompts sinogram to " << p_filename << "\n"; + lmNP.get_prompts_sptr()->write_to_file(p_filename); + } + if (!d_filename.empty()) { + std::cout << "\n saving delayeds sinogram to " << d_filename << "\n"; + lmNP.get_delayeds_sptr()->write_to_file(d_filename); + } + if (!r_filename.empty()) { + std::cout << "\n saving randoms sinogram to " << r_filename << "\n"; + lmNP.get_randoms_sptr()->write_to_file(r_filename); } - catch(...) { - std::cerr << "\nError encountered.\n\n"; - return EXIT_FAILURE; + if (!n_filename.empty()) { + std::cout << "\n saving norm sinogram to " << n_filename << "\n"; + lmNP.get_norm_sptr()->write_to_file(n_filename); } - return(EXIT_SUCCESS); + } + + // If there was an error + catch (const std::exception& error) { + std::cerr << "\nError encountered:\n\t" << error.what() << "\n\n"; + return EXIT_FAILURE; + } catch (...) { + std::cerr << "\nError encountered.\n\n"; + return EXIT_FAILURE; + } + return (EXIT_SUCCESS); } diff --git a/src/listmode_utilities/lm_to_projdata_bootstrap.cxx b/src/listmode_utilities/lm_to_projdata_bootstrap.cxx index d85e8ead13..cdd512bac9 100644 --- a/src/listmode_utilities/lm_to_projdata_bootstrap.cxx +++ b/src/listmode_utilities/lm_to_projdata_bootstrap.cxx @@ -1,13 +1,13 @@ // // /*! - \file + \file \ingroup listmode \brief Program to bin listmode data to projection data using bootstrapping (uses stir::LmToProjDataBootstrap) - + \author Kris Thielemans - + $Revision $ */ /* @@ -31,30 +31,21 @@ USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) { - -int main(int argc, char * argv[]) -{ - - if (argc<1 && argc>3) { + if (argc < 1 && argc > 3) { std::cerr << "Usage: " << argv[0] << " [par_file [seed]]\n"; exit(EXIT_FAILURE); } // clumsy way of having extra argument - if (argc==3) - { - LmToProjDataBootstrap - application(argc>=2 ? argv[1] : 0, - atoi(argv[2])); - application.process_data(); - } - else - { - LmToProjDataBootstrap - application(argc==2 ? argv[1] : 0); - application.process_data(); - } + if (argc == 3) { + LmToProjDataBootstrap application(argc >= 2 ? argv[1] : 0, atoi(argv[2])); + application.process_data(); + } else { + LmToProjDataBootstrap application(argc == 2 ? argv[1] : 0); + application.process_data(); + } return EXIT_SUCCESS; } - diff --git a/src/listmode_utilities/lm_to_projdata_with_random_rejection.cxx b/src/listmode_utilities/lm_to_projdata_with_random_rejection.cxx index 28eec99034..18103619ae 100644 --- a/src/listmode_utilities/lm_to_projdata_with_random_rejection.cxx +++ b/src/listmode_utilities/lm_to_projdata_with_random_rejection.cxx @@ -1,13 +1,14 @@ // // /*! - \file + \file \ingroup listmode - \brief Program to bin listmode data to projection data using random rejection of counts (uses stir::LmToProjDataWithRandomRejection) - + \brief Program to bin listmode data to projection data using random rejection of counts (uses + stir::LmToProjDataWithRandomRejection) + \author Kris Thielemans - + */ /* Copyright (C) 2003- 2012, Hammersmith Imanet Ltd @@ -30,19 +31,16 @@ USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) { - -int main(int argc, char * argv[]) -{ - - if ((argc<1) || (argc>3)) { + if ((argc < 1) || (argc > 3)) { std::cerr << "Usage: " << argv[0] << " [par_file fraction_of_counts_to_keep]]\n"; exit(EXIT_FAILURE); } - LmToProjDataWithRandomRejection - application(argc>=2 ? argv[1] : 0); - if (argc==3) + LmToProjDataWithRandomRejection application(argc >= 2 ? argv[1] : 0); + if (argc == 3) application.set_reject_if_above(float(atof(argv[2]))); application.process_data(); return EXIT_SUCCESS; diff --git a/src/listmode_utilities/print_sgl_values.cxx b/src/listmode_utilities/print_sgl_values.cxx index c68fd12e27..dbc553627c 100644 --- a/src/listmode_utilities/print_sgl_values.cxx +++ b/src/listmode_utilities/print_sgl_values.cxx @@ -24,16 +24,13 @@ \author Tim Borgeaud */ - #include "stir/data/SinglesRatesFromSglFile.h" - #include #include #include #include - #ifndef STIR_NO_NAMESPACES using std::cout; using std::cerr; @@ -45,16 +42,12 @@ using std::vector; USING_NAMESPACE_STIR - - - -int -main (int argc, char **argv) -{ +int +main(int argc, char** argv) { vector columns; - // Check arguments. + // Check arguments. // Singles filename + optional bin indices. if (argc < 2) { cerr << "Program to print out values from a singles file.\n\n"; @@ -65,11 +58,10 @@ main (int argc, char **argv) const string sgl_filename = argv[1]; - for (int arg = 2 ; arg < argc ; ++arg) { + for (int arg = 2; arg < argc; ++arg) { columns.push_back(atoi(argv[arg])); - } - - + } + // Singles file object. ecat::ecat7::SinglesRatesFromSglFile singles_from_sgl; @@ -78,53 +70,45 @@ main (int argc, char **argv) const vector times = singles_from_sgl.get_times(); - - // Get total number of time slices. int num_time_slices = singles_from_sgl.get_num_time_slices(); // Get scanner details and, from these, the number of singles units. - const Scanner *scanner = singles_from_sgl.get_scanner_ptr(); + const Scanner* scanner = singles_from_sgl.get_scanner_ptr(); int total_singles_units = scanner->get_num_singles_units(); - - + // If no columns are set. Create a vector with all columns. - if ( columns.size() == 0 ) { - for (int singles_bin = 0 ; singles_bin < total_singles_units ; ++singles_bin) { - columns.push_back(singles_bin); + if (columns.size() == 0) { + for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { + columns.push_back(singles_bin); } } - // Print columns cout << "# Time "; - for (vector::iterator col = columns.begin() ; col < columns.end() ; ++col) { + for (vector::iterator col = columns.begin(); col < columns.end(); ++col) { cout << setw(9) << *col << " "; } cout << "\n"; - // Loop over all time slices. - for (int time_slice = 0 ; time_slice < num_time_slices ; ++time_slice) { + for (int time_slice = 0; time_slice < num_time_slices; ++time_slice) { // Output time. cout << setw(8) << times[time_slice] << " "; - - for (vector::iterator col = columns.begin() ; col < columns.end() ; ++col) { - if ( *col >= 0 && *col < total_singles_units ) { + for (vector::iterator col = columns.begin(); col < columns.end(); ++col) { + + if (*col >= 0 && *col < total_singles_units) { int val = singles_from_sgl.get_singles_rate(*col, time_slice); - + cout << setw(9) << val << " "; } } - + // Output the end of line. cout << "\n"; - } - - return EXIT_SUCCESS; } diff --git a/src/listmode_utilities/rebin_sgl_file.cxx b/src/listmode_utilities/rebin_sgl_file.cxx index 6994e7b385..3f781b329e 100644 --- a/src/listmode_utilities/rebin_sgl_file.cxx +++ b/src/listmode_utilities/rebin_sgl_file.cxx @@ -26,7 +26,6 @@ \author Tim Borgeaud */ - #include "stir/data/SinglesRatesFromSglFile.h" #include "stir/TimeFrameDefinitions.h" @@ -34,7 +33,6 @@ #include #include - #ifndef STIR_NO_NAMESPACES using std::cerr; using std::endl; @@ -44,114 +42,95 @@ using std::vector; USING_NAMESPACE_STIR - - void -usage(const char *progname) { +usage(const char* progname) { cerr << "A program to rebin an sgl file.\n\n"; - cerr << "There are two ways to use this program.\n"; - cerr << "1) " << progname - << " sgl_input_file sgl_output_file frame_end [frame_ends ...]\n\n"; - cerr << "2) " << progname - << " -f frame_definition_file sgl_input_file sgl_output_file\n\n"; + cerr << "There are two ways to use this program.\n"; + cerr << "1) " << progname << " sgl_input_file sgl_output_file frame_end [frame_ends ...]\n\n"; + cerr << "2) " << progname << " -f frame_definition_file sgl_input_file sgl_output_file\n\n"; cerr << "Frame end times are floating point numbers of seconds\n"; } +int +main(int argc, char** argv) { - -int -main(int argc, char **argv) -{ - - // Check arguments. + // Check arguments. // Singles filename + optional output filename - if (argc < 4 ) { + if (argc < 4) { usage(argv[0]); exit(EXIT_FAILURE); } - - string input_filename; string output_filename; - vector new_times; - - + vector new_times; // Check to see if -f was supplied as the first argument. - if ( argv[1][0] == '-' ) { + if (argv[1][0] == '-') { // Option supplied - + int arg_len = strlen(argv[1]); - if ( arg_len != 2 || argv[1][1] != 'f' ) { - - for (int i = 1 ; i < arg_len ; ++i ) { - if ( argv[1][i] != 'f' ) { + if (arg_len != 2 || argv[1][1] != 'f') { + + for (int i = 1; i < arg_len; ++i) { + if (argv[1][i] != 'f') { cerr << "Unknown option " << argv[1][i] << endl; } } - + usage(argv[0]); exit(EXIT_FAILURE); } - + const string fdef_filename = argv[2]; input_filename = argv[3]; output_filename = argv[4]; - TimeFrameDefinitions time_frames(fdef_filename); - + double last_end = 0.0; // Create the new ending times by looping over the frames. - for (unsigned int frame = 1 ; frame <= time_frames.get_num_frames() ; ++frame) { + for (unsigned int frame = 1; frame <= time_frames.get_num_frames(); ++frame) { double frame_start = time_frames.get_start_time(frame); double frame_end = time_frames.get_end_time(frame); - //cerr << "Start: " << frame_start << " End: " << frame_end << endl; - - if ( frame_start != last_end ) { - //cerr << "Added frame at: " << frame_start << endl; + // cerr << "Start: " << frame_start << " End: " << frame_end << endl; + + if (frame_start != last_end) { + // cerr << "Added frame at: " << frame_start << endl; // Add an additional frame that ends at the start of this frame. new_times.push_back(frame_start); } // Add the frame end. new_times.push_back(frame_end); - + last_end = frame_end; } - } else { - + input_filename = argv[1]; output_filename = argv[2]; - + // Set up vector of new ending times. new_times = vector(argc - 3); - + // Read frame end times - for(int arg = 3 ; arg < argc ; arg++) { + for (int arg = 3; arg < argc; arg++) { new_times[arg - 3] = atof(argv[arg]); } - } - - - // Singles file object. ecat::ecat7::SinglesRatesFromSglFile singles_from_sgl; // Read the singles file. singles_from_sgl.read_singles_from_sgl_file(input_filename); - - std::ofstream output; // If necessary, open the output file. @@ -161,13 +140,11 @@ main(int argc, char **argv) error("Error opening output file\n"); } - // rebin singles_from_sgl.rebin(new_times); - + // Output. singles_from_sgl.write(output); - - + return EXIT_SUCCESS; } diff --git a/src/listmode_utilities/scan_sgl_file.cxx b/src/listmode_utilities/scan_sgl_file.cxx index 30663c3338..54d5bed599 100644 --- a/src/listmode_utilities/scan_sgl_file.cxx +++ b/src/listmode_utilities/scan_sgl_file.cxx @@ -23,7 +23,6 @@ \author Tim Borgeaud */ - #include "stir/data/SinglesRatesFromSglFile.h" #include @@ -40,11 +39,8 @@ using std::vector; USING_NAMESPACE_STIR - - const int MAX_VALID_VALUE = 1000000; - // Minimum allowed fraction of previous value. const float MIN_PREVIOUS_FRACTION = 0.225; @@ -57,128 +53,103 @@ const float MIN_MEDIAN_FRACTION = 0.2; // Max allowed multiple of median of next set of values. const float MAX_MEDIAN_MULTIPLE = 3.5; - - // Tolerance between adjacent bins. const float ADJACENT_TOLERANCE = 0.75; const int MEDIAN_SIZE = 7; // Number of elements forward for which the median is calculated. - - // // Function to calculate the median of singles values from // start_index to end_index (inclusive). // -int -calcMedian(const ecat::ecat7::SinglesRatesFromSglFile& singles_rates, - int singles_bin_index, int start_slice, int end_slice) { - +int +calcMedian(const ecat::ecat7::SinglesRatesFromSglFile& singles_rates, int singles_bin_index, int start_slice, int end_slice) { + int num_elements = end_slice - start_slice + 1; - + // Create a new temporary vector. vector elements(num_elements); - + // Fill the temporary vector. - for(int index = 0 ; index < num_elements ; index++) { - elements[index] = singles_rates.get_singles_rate(singles_bin_index, - start_slice + index); + for (int index = 0; index < num_elements; index++) { + elements[index] = singles_rates.get_singles_rate(singles_bin_index, start_slice + index); } - + // Calculate which element, of the sorted set, will be the median. vector::iterator median = elements.begin() + (num_elements / 2); - + // Partially sort the elements. nth_element(elements.begin(), median, elements.end()); - + // Return the element at the median position. - return(*median); - + return (*median); } - - - - // // Function to calculate a median of up to MEDIAN_SIZE values // starting from start_slice. // int -getMedian(const ecat::ecat7::SinglesRatesFromSglFile& singles_rates, - int singles_bin_index, int start_slice) { +getMedian(const ecat::ecat7::SinglesRatesFromSglFile& singles_rates, int singles_bin_index, int start_slice) { int num_slices = singles_rates.get_num_time_slices(); int end_slice = start_slice + MEDIAN_SIZE - 1; - if ( end_slice >= num_slices ) { + if (end_slice >= num_slices) { end_slice = num_slices - 1; } - - return(calcMedian(singles_rates, singles_bin_index, start_slice, end_slice)); -} - + return (calcMedian(singles_rates, singles_bin_index, start_slice, end_slice)); +} bool -compareAdjacentBin(int value, int slice, int singles_bin_index, - const ecat::ecat7::SinglesRatesFromSglFile& singles_rates, +compareAdjacentBin(int value, int slice, int singles_bin_index, const ecat::ecat7::SinglesRatesFromSglFile& singles_rates, int transaxial_offset) { - const Scanner *scanner = singles_rates.get_scanner_ptr(); + const Scanner* scanner = singles_rates.get_scanner_ptr(); int axial = scanner->get_axial_singles_unit(singles_bin_index); int num_transaxial = scanner->get_num_transaxial_singles_units(); int transaxial = scanner->get_transaxial_singles_unit(singles_bin_index); - + transaxial = (transaxial + transaxial_offset) % num_transaxial; - if ( transaxial < 0 ) { + if (transaxial < 0) { transaxial += num_transaxial; } - - + int bin_index = scanner->get_singles_bin_index(axial, transaxial); int rate = singles_rates.get_singles_rate(bin_index, slice); - - if ( (value >= (1.0 - ADJACENT_TOLERANCE) * rate) && - (value <= (1.0 + ADJACENT_TOLERANCE) * rate) ) { - return(true); - } - - return(false); -} - + if ((value >= (1.0 - ADJACENT_TOLERANCE) * rate) && (value <= (1.0 + ADJACENT_TOLERANCE) * rate)) { + return (true); + } + return (false); +} // // Check a rate against transaxially adjacent bins. // -// Note that a single bucket controller encompasses a number of -// axial singles units, so checking bins with the same transaxial +// Note that a single bucket controller encompasses a number of +// axial singles units, so checking bins with the same transaxial // position may result checking bins from the same bucket. // bool -checkAdjacentBins(int value, int slice, int singles_bin_index, - const ecat::ecat7::SinglesRatesFromSglFile& singles_rates) { - - if ( compareAdjacentBin(value, slice, singles_bin_index, singles_rates, -1) ) { - if ( compareAdjacentBin(value, slice, singles_bin_index, singles_rates, -2) || - compareAdjacentBin(value, slice, singles_bin_index, singles_rates, 1)) { - return(true); +checkAdjacentBins(int value, int slice, int singles_bin_index, const ecat::ecat7::SinglesRatesFromSglFile& singles_rates) { + + if (compareAdjacentBin(value, slice, singles_bin_index, singles_rates, -1)) { + if (compareAdjacentBin(value, slice, singles_bin_index, singles_rates, -2) || + compareAdjacentBin(value, slice, singles_bin_index, singles_rates, 1)) { + return (true); } - } else if ( compareAdjacentBin(value, slice, singles_bin_index, singles_rates, 1) && - compareAdjacentBin(value, slice, singles_bin_index, singles_rates, 2) ) { - return(true); + } else if (compareAdjacentBin(value, slice, singles_bin_index, singles_rates, 1) && + compareAdjacentBin(value, slice, singles_bin_index, singles_rates, 2)) { + return (true); } - - return(false); -} - - - + return (false); +} // // Check that a value is either within a tolerance of the median @@ -186,214 +157,169 @@ checkAdjacentBins(int value, int slice, int singles_bin_index, // value and a supplied value. // // Returns true if the value is ok. -// +// bool -checkValue(int value, int slice, int singles_bin_index, - const ecat::ecat7::SinglesRatesFromSglFile& singles_rates, +checkValue(int value, int slice, int singles_bin_index, const ecat::ecat7::SinglesRatesFromSglFile& singles_rates, int previous_value) { - - // Check absolute range ( 0 <= Value <= MAX_VALID_VALUE ). - if ( value > 0 && value < MAX_VALID_VALUE ) { - + // Check absolute range ( 0 <= Value <= MAX_VALID_VALUE ). + if (value > 0 && value < MAX_VALID_VALUE) { + // Check against previous value. - if ( ((MIN_PREVIOUS_FRACTION * previous_value) - value) <= 0 && - ((MAX_PREVIOUS_MULTIPLE * previous_value) - value) >= 0 ) { + if (((MIN_PREVIOUS_FRACTION * previous_value) - value) <= 0 && ((MAX_PREVIOUS_MULTIPLE * previous_value) - value) >= 0) { // Value is good. - return(true); + return (true); } - // Check against values from adjacent (transaxial) bins. - if ( checkAdjacentBins(value, slice, singles_bin_index, singles_rates) ) { + if (checkAdjacentBins(value, slice, singles_bin_index, singles_rates)) { // Value is good. - return(true); + return (true); } - - // See if there are any further values to compare the current value with. int num_slices = singles_rates.get_num_time_slices(); - - if ( slice < num_slices - 1 ) { - + + if (slice < num_slices - 1) { + // Calculate the median (should work for only one value). int median = getMedian(singles_rates, singles_bin_index, slice + 1); - // Check against median value. Note that the first slice only needs be less than // median * MAX_MULTIPLE. - if ( (slice == 0 || ((MIN_MEDIAN_FRACTION * median - value)) <= 0) && - ((MAX_MEDIAN_MULTIPLE * median) - value) >= 0 ) { + if ((slice == 0 || ((MIN_MEDIAN_FRACTION * median - value)) <= 0) && ((MAX_MEDIAN_MULTIPLE * median) - value) >= 0) { // Value is good. - return(true); + return (true); } - // Check to see if the value lies between previous and median. - if ( ((previous_value > median) && (value >= median && value <= previous_value)) || - (value >= previous_value && value <= median) ) { + if (((previous_value > median) && (value >= median && value <= previous_value)) || + (value >= previous_value && value <= median)) { // Value is good. - return(true); + return (true); } } } - - return(false); -} - - - - - + return (false); +} // // Function to check and correct a particular value. // // Returns true if a value was corrected. bool -correctSinglesValue(int value, int slice, int singles_bin_index, - ecat::ecat7::SinglesRatesFromSglFile& singles_rates) { - - +correctSinglesValue(int value, int slice, int singles_bin_index, ecat::ecat7::SinglesRatesFromSglFile& singles_rates) { + // Previous value. Set to 0 for the first slice. int previous = 0; - - if ( slice > 0 ) { + if (slice > 0) { previous = singles_rates.get_singles_rate(singles_bin_index, slice - 1); } - - if ( checkValue(value, slice, singles_bin_index, singles_rates, previous) == true ) { - return(false); + if (checkValue(value, slice, singles_bin_index, singles_rates, previous) == true) { + return (false); } - // The value is not good. Therefore, correct the value using // the previous value (which must be good) and the next good value. int num_slices = singles_rates.get_num_time_slices(); int next_slice; int next_value; - - for(next_slice = slice + 1; next_slice < num_slices ; ++next_slice ) { + + for (next_slice = slice + 1; next_slice < num_slices; ++next_slice) { next_value = singles_rates.get_singles_rate(singles_bin_index, next_slice); - - if ( checkValue(next_value, next_slice, singles_bin_index, singles_rates, previous) ) { + + if (checkValue(next_value, next_slice, singles_bin_index, singles_rates, previous)) { break; } } - - if ( next_slice < num_slices ) { + + if (next_slice < num_slices) { // Correct using previous and next_slice. int next_sep = next_slice - slice; - + // Adjust value. - value = ((previous * next_sep) + next_value) / (1 + next_sep); - + value = ((previous * next_sep) + next_value) / (1 + next_sep); + singles_rates.set_singles_rate(singles_bin_index, slice, value); } - + // Value was bad so return true. - return(true); - + return (true); } - - - - - -// +// // check and correct all the singles values. Return true if any values were corrected. -// +// // bool -correctAllValues(ecat::ecat7::SinglesRatesFromSglFile& singles_rates, - std::ostream& output) { +correctAllValues(ecat::ecat7::SinglesRatesFromSglFile& singles_rates, std::ostream& output) { bool changed = false; // Get scanner details and, from these, the number of singles units. - const Scanner *scanner = singles_rates.get_scanner_ptr(); + const Scanner* scanner = singles_rates.get_scanner_ptr(); int total_singles_units = scanner->get_num_singles_units(); - + // Get total number of time slices. int num_slices = singles_rates.get_num_time_slices(); // Loop over all bins. - for(int singles_bin = 0 ; singles_bin < total_singles_units ; ++singles_bin) { - + for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { + // Loop over each time slice. - for(int slice = 0 ; slice < num_slices ; ++slice) { - + for (int slice = 0; slice < num_slices; ++slice) { + int value = singles_rates.get_singles_rate(singles_bin, slice); - - if ( correctSinglesValue(value, slice, singles_bin, singles_rates) ) { - + + if (correctSinglesValue(value, slice, singles_bin, singles_rates)) { + changed = true; int new_value = singles_rates.get_singles_rate(singles_bin, slice); // Print details of the change to the output. - output << "Bin " << singles_bin - << " Slice index: " << slice - << " Rate: " << value - << " New estimate: " << new_value + output << "Bin " << singles_bin << " Slice index: " << slice << " Rate: " << value << " New estimate: " << new_value << "\n"; } - } - } - - return(changed); - -} - - - - - + return (changed); +} -int -main (int argc, char **argv) -{ +int +main(int argc, char** argv) { - // Check arguments. + // Check arguments. // Singles filename + optional output filename if (argc > 3 || argc < 2) { - cerr << "Usage: " << argv[0] << " sgl_filename [output_filename]\n"; - exit(EXIT_FAILURE); + cerr << "Usage: " << argv[0] << " sgl_filename [output_filename]\n"; + exit(EXIT_FAILURE); } - const string sgl_filename = argv[1]; bool write_file = false; string output_filename = ""; - if ( argc == 3 ) { + if (argc == 3) { write_file = true; output_filename = argv[2]; - } - - + } + // Singles file object. ecat::ecat7::SinglesRatesFromSglFile singles_from_sgl; // Read the singles file. singles_from_sgl.read_singles_from_sgl_file(sgl_filename); - const vector times = singles_from_sgl.get_times(); - - std::ofstream output; // If necessary, open the output file. - if ( output_filename.length() ) { + if (output_filename.length()) { output.open(output_filename.c_str(), std::ios_base::out); @@ -401,13 +327,10 @@ main (int argc, char **argv) error("Error opening output file\n"); } - - - if ( correctAllValues(singles_from_sgl, cout) && write_file ) { + if (correctAllValues(singles_from_sgl, cout) && write_file) { // Write data to output file. singles_from_sgl.write(output); } - - + return EXIT_SUCCESS; } diff --git a/src/modelling_buildblock/KineticModel.cxx b/src/modelling_buildblock/KineticModel.cxx index 94c21f9e07..b4252a9dbd 100644 --- a/src/modelling_buildblock/KineticModel.cxx +++ b/src/modelling_buildblock/KineticModel.cxx @@ -22,22 +22,19 @@ \author Charalampos Tsoumpas - This is the most basic class for including kinetic models. + This is the most basic class for including kinetic models. */ - #include "stir/modelling/KineticModel.h" - START_NAMESPACE_STIR -const char * const -KineticModel::registered_name = "Kinetic Model Type"; +const char* const KineticModel::registered_name = "Kinetic Model Type"; -KineticModel::KineticModel() //!< default constructor -{ } -KineticModel::~KineticModel() //!< default destructor -{ } +KineticModel::KineticModel() //!< default constructor +{} +KineticModel::~KineticModel() //!< default destructor +{} END_NAMESPACE_STIR diff --git a/src/modelling_buildblock/ParametricDiscretisedDensity.cxx b/src/modelling_buildblock/ParametricDiscretisedDensity.cxx index 08603dd812..f638adfce3 100644 --- a/src/modelling_buildblock/ParametricDiscretisedDensity.cxx +++ b/src/modelling_buildblock/ParametricDiscretisedDensity.cxx @@ -25,7 +25,7 @@ \author Kris Thielemans \author Richard Brown - + */ #include "stir/modelling/ParametricDiscretisedDensity.h" @@ -45,9 +45,7 @@ START_NAMESPACE_STIR ///////////////////////////////////////////////////////////////////////////////////// TEMPLATE unsigned int -ParamDiscDensity:: -get_num_params() -{ +ParamDiscDensity::get_num_params() { // somewhat naughty trick to get elemT of DiscDensityT typedef typename DiscDensityT::full_value_type KinParsT; const KinParsT dummy; @@ -55,23 +53,16 @@ get_num_params() } TEMPLATE -ParamDiscDensity:: -ParametricDiscretisedDensity(const DynamicDiscretisedDensity& dyn_im) - : base_type(dyn_im.get_density(1).get_index_range(), - dyn_im.get_density(1).get_origin(), - dynamic_cast&>(dyn_im.get_density(1)).get_grid_spacing()) -{ - this->set_exam_info(dyn_im.get_exam_info()); +ParamDiscDensity::ParametricDiscretisedDensity(const DynamicDiscretisedDensity& dyn_im) + : base_type(dyn_im.get_density(1).get_index_range(), dyn_im.get_density(1).get_origin(), + dynamic_cast&>(dyn_im.get_density(1)).get_grid_spacing()) { + this->set_exam_info(dyn_im.get_exam_info()); } TEMPLATE -ParamDiscDensity:: -ParametricDiscretisedDensity(const SingleDiscretisedDensityType& im) - : base_type(im.get_index_range(), - im.get_origin(), - dynamic_cast&>(im).get_grid_spacing()) -{ - this->set_exam_info(im.get_exam_info()); +ParamDiscDensity::ParametricDiscretisedDensity(const SingleDiscretisedDensityType& im) + : base_type(im.get_index_range(), im.get_origin(), dynamic_cast&>(im).get_grid_spacing()) { + this->set_exam_info(im.get_exam_info()); } #if 0 @@ -95,11 +86,11 @@ ParametricDiscretisedDensity(const VectorWithOffsetget_num_params(); ++f) { -#if 1 +# if 1 // for some reason, the following gives a segmentation fault in gcc 4.1 optimised mode. // Maybe because we're calling a member function in the constructor? this->update_parametric_image(*densities[f], f); -#else +# else // alternative (untested) const SingleDiscretisedDensityType& current_density = dynamic_cast(*densities[f]); @@ -114,7 +105,7 @@ ParametricDiscretisedDensity(const VectorWithOffsetget_num_params()); +ParamDiscDensity::update_parametric_image(const SingleDiscretisedDensityType& single_density, const unsigned int param_num) { + assert(param_num <= this->get_num_params()); assert(single_density.get_index_range() == this->get_index_range()); - const unsigned int f=param_num; - typename SingleDiscretisedDensityType::const_full_iterator single_density_iter = - single_density.begin_all(); - const typename SingleDiscretisedDensityType::const_full_iterator end_single_density_iter = - single_density.end_all(); - typename ParamDiscDensity::full_densel_iterator parametric_density_iter = - this->begin_all_densel(); - while (single_density_iter!=end_single_density_iter) - { - if (parametric_density_iter == this->end_all_densel()) - error("update ITER"); - //(*parametric_density_iter)[f] = *single_density_iter; - const float tmp = *single_density_iter; - (*parametric_density_iter)[f] = tmp; - ++single_density_iter; ++parametric_density_iter; - } + const unsigned int f = param_num; + typename SingleDiscretisedDensityType::const_full_iterator single_density_iter = single_density.begin_all(); + const typename SingleDiscretisedDensityType::const_full_iterator end_single_density_iter = single_density.end_all(); + typename ParamDiscDensity::full_densel_iterator parametric_density_iter = this->begin_all_densel(); + while (single_density_iter != end_single_density_iter) { + if (parametric_density_iter == this->end_all_densel()) + error("update ITER"); + //(*parametric_density_iter)[f] = *single_density_iter; + const float tmp = *single_density_iter; + (*parametric_density_iter)[f] = tmp; + ++single_density_iter; + ++parametric_density_iter; + } // TODO Currently need this to avoid segmentation fault with 4.1... // std::cerr << " Done\n"; } TEMPLATE -ParamDiscDensity * -ParamDiscDensity:: -read_from_file(const std::string& filename) // The written image is read in respect to its center as origin!!! +ParamDiscDensity* +ParamDiscDensity::read_from_file(const std::string& filename) // The written image is read in respect to its center as origin!!! { - unique_ptr param_sptr - (stir::read_from_file(filename)); + unique_ptr param_sptr(stir::read_from_file(filename)); return param_sptr.release(); } TEMPLATE -ParamDiscDensity * -ParamDiscDensity:: -get_empty_copy() const -{ +ParamDiscDensity* +ParamDiscDensity::get_empty_copy() const { // TODO maybe this can be done smarter by using base_type::get_empty_copy. Doesn't matter too much though. - ParamDiscDensity * res = this->clone(); - typename ParamDiscDensity::iterator parametric_density_iter = - res->begin(); - while (parametric_density_iter!=res->end()) - { - assign(*parametric_density_iter++, 0); - } + ParamDiscDensity* res = this->clone(); + typename ParamDiscDensity::iterator parametric_density_iter = res->begin(); + while (parametric_density_iter != res->end()) { + assign(*parametric_density_iter++, 0); + } return res; } TEMPLATE -ParamDiscDensity * -ParamDiscDensity:: -clone() const -{ +ParamDiscDensity* +ParamDiscDensity::clone() const { return new ParamDiscDensity(*this); } TEMPLATE template -void -ParamDiscDensity:: -construct_single_density_using_function(typename ParamDiscDensity::SingleDiscretisedDensityType& density, KPFunctionObject f) const -{ - std::transform(this->begin_all_densel(), - this->end_all_densel(), - density.begin_all(), - f); +void +ParamDiscDensity::construct_single_density_using_function(typename ParamDiscDensity::SingleDiscretisedDensityType& density, + KPFunctionObject f) const { + std::transform(this->begin_all_densel(), this->end_all_densel(), density.begin_all(), f); } - TEMPLATE template const typename ParamDiscDensity::SingleDiscretisedDensityType -ParamDiscDensity:: -construct_single_density_using_function(KPFunctionObject f) const -{ +ParamDiscDensity::construct_single_density_using_function(KPFunctionObject f) const { // TODO this will only work for VoxelsOnCartesianGrid - SingleDiscretisedDensityType - density(this->get_exam_info_sptr(), - this->get_index_range(), - this->get_origin(), - this->get_grid_spacing()); + SingleDiscretisedDensityType density(this->get_exam_info_sptr(), this->get_index_range(), this->get_origin(), + this->get_grid_spacing()); this->construct_single_density_using_function(density, f); return density; } TEMPLATE -void -ParamDiscDensity:: -construct_single_density(typename ParamDiscDensity::SingleDiscretisedDensityType& density, const int index) const -{ +void +ParamDiscDensity::construct_single_density(typename ParamDiscDensity::SingleDiscretisedDensityType& density, + const int index) const { using namespace boost::lambda; // TODO this will only work for elemT==float this->construct_single_density_using_function(density, ret(_1[index])); } - TEMPLATE const typename ParamDiscDensity::SingleDiscretisedDensityType -ParamDiscDensity:: -construct_single_density(const int index) const -{ +ParamDiscDensity::construct_single_density(const int index) const { using namespace boost::lambda; // TODO this will only work for elemT==float return this->construct_single_density_using_function(ret(_1[index])); } /////////////////////////////// -#if 0 //!< Implementation of non-const functions - which should be able to update a single parameter of a parametric image. +#if 0 //!< Implementation of non-const functions - which should be able to update a single parameter of a parametric image. TEMPLATE template void @@ -306,16 +270,13 @@ construct_single_density(const int index) return this->construct_single_density_using_function(ret(_1[index])); } -#endif - +#endif #undef ParamDiscDensity #undef TEMPLATE // instantiations // template class ParametricDiscretisedDensity<3,KineticParameters >; - template class ParametricDiscretisedDensity; +template class ParametricDiscretisedDensity; END_NAMESPACE_STIR - - diff --git a/src/modelling_buildblock/PatlakPlot.cxx b/src/modelling_buildblock/PatlakPlot.cxx index dac08a8033..ed67018a9b 100644 --- a/src/modelling_buildblock/PatlakPlot.cxx +++ b/src/modelling_buildblock/PatlakPlot.cxx @@ -25,308 +25,284 @@ */ - #include "stir/modelling/PatlakPlot.h" #include "stir/linear_regression.h" START_NAMESPACE_STIR void -PatlakPlot:: -set_defaults() -{ +PatlakPlot::set_defaults() { base_type::set_defaults(); - this->_blood_data_filename=""; - this->_cal_factor=1.F; - this->_starting_frame=0; - this->_time_shift=0.; - this->_in_correct_scale=false; - this->_in_total_cnt=false; + this->_blood_data_filename = ""; + this->_cal_factor = 1.F; + this->_starting_frame = 0; + this->_time_shift = 0.; + this->_in_correct_scale = false; + this->_in_total_cnt = false; } -const char * const -PatlakPlot::registered_name = "Patlak Plot"; +const char* const PatlakPlot::registered_name = "Patlak Plot"; //! default constructor -PatlakPlot::PatlakPlot() -{ - this->_matrix_is_stored=false; +PatlakPlot::PatlakPlot() { + this->_matrix_is_stored = false; this->set_defaults(); } -PatlakPlot::~PatlakPlot() //!< default destructor -{ } +PatlakPlot::~PatlakPlot() //!< default destructor +{} - //! Simply get model matrix if it has been already stored +//! Simply get model matrix if it has been already stored ModelMatrix<2> -PatlakPlot:: -get_model_matrix() const -{ - if(_matrix_is_stored==false) +PatlakPlot::get_model_matrix() const { + if (_matrix_is_stored == false) error("It seems that ModelMatrix has not been set, yet. "); - return _model_matrix ; + return _model_matrix; } -//! Simply set model matrix -void PatlakPlot::set_model_matrix(ModelMatrix<2> model_matrix) -{ - this->_model_matrix=model_matrix; - this->_matrix_is_stored=true; +//! Simply set model matrix +void +PatlakPlot::set_model_matrix(ModelMatrix<2> model_matrix) { + this->_model_matrix = model_matrix; + this->_matrix_is_stored = true; } - //! Create model matrix from private members +//! Create model matrix from private members void -PatlakPlot:: -create_model_matrix() -{ - if(_matrix_is_stored==false) - { - // Create empty Model matrix. this is a [2 x frames] matrix, that contains Cp(t) and \int{Ct(t)} for each frame (Cp(t): radiotracer concentration on plasma) - - // NOTE: as we are working in time frames, and not discrete time points, Cp(t) is not a value of Cp at a given single time, t, but instead - // it is the integral of Cp on that time frame , \int_{t_start}^{t_end} Cp(t) dt, for each time frame. The same happens with \int{Cp(t)} - // All this is handled in the PlasmaData class, and it's not visible here. - - // BasicCoordinate just changes the indexing range (instead of 0-N, to some min to some max) - BasicCoordinate<2,int> min_range; - BasicCoordinate<2,int> max_range; - min_range[1]=1; min_range[2]=this->_starting_frame; - max_range[1]=2; max_range[2]=this->_plasma_frame_data.size(); - IndexRange<2> data_range(min_range,max_range); - Array<2,float> patlak_array(data_range); - VectorWithOffset time_vector(min_range[2],max_range[2]); - PlasmaData::const_iterator cur_iter=this->_plasma_frame_data.begin(); - - double sum_value=0.; - unsigned int sample_num; - // Compute the value of the integral of Cp(t) for frames before the one we want to start applying Patlak to. - // Remember that this code requires all frames, from t=0 to be included, otherwise this integral will be wrongly computed. - // TODO: do not require the dynamic images to exist to do this integral. - for(sample_num=1 ; sample_num_starting_frame; ++sample_num, ++cur_iter ) - sum_value+=cur_iter->get_plasma_counts_in_kBq()*this->_plasma_frame_data.get_time_frame_definitions().get_duration(sample_num); - - assert(cur_iter==this->_plasma_frame_data.begin()+this->_starting_frame-1); - // For each frame that we are interested in, fill the model matrix. - for(sample_num=this->_starting_frame ; cur_iter!=this->_plasma_frame_data.end() ; ++sample_num, ++cur_iter ) - { - sum_value+=cur_iter->get_plasma_counts_in_kBq()*this->_plasma_frame_data.get_time_frame_definitions().get_duration(sample_num); - // integral of Cp(t) - patlak_array[1][sample_num]= static_cast(sum_value); - // Cp(t) - patlak_array[2][sample_num]=cur_iter->get_plasma_counts_in_kBq(); - // As we will do the reconstruction in un-corrected data, if the plasma data is corrected, we need to undo that - if(this->_plasma_frame_data.get_is_decay_corrected()) - { - const float dec_fact= - static_cast(decay_correction_factor(this->_plasma_frame_data.get_isotope_halflife(),this->_plasma_frame_data.get_time_frame_definitions().get_start_time(sample_num), - this->_plasma_frame_data.get_time_frame_definitions().get_end_time(sample_num))); - patlak_array[1][sample_num]/=dec_fact; - patlak_array[2][sample_num]/=dec_fact; - time_vector[sample_num]= static_cast(0.5*(this->_frame_defs.get_end_time(sample_num)+this->_frame_defs.get_start_time(sample_num))); - } - } - if(this->_plasma_frame_data.get_is_decay_corrected()) - warning("Uncorrecting previous decay correction, while putting the plasma_data into the model_matrix."); - else - error("plasma_data have not been corrected during the process, which will create wrong results!!!"); - - assert(sample_num-1==this->_plasma_frame_data.size()); - this->_model_matrix.set_model_array(patlak_array); - this->_model_matrix.set_time_vector(time_vector); - // Uncalibrate the ModelMatrix instead of Calibrating all the Dynamic Images. This should make faster the computation. - // Supposes the images are not calibrated. - this->_model_matrix.uncalibrate(this->_cal_factor); - if(this->_in_total_cnt) - this->_model_matrix.convert_to_total_frame_counts(this->_frame_defs); - this->_model_matrix.set_is_in_correct_scale(this->_in_correct_scale); - this->_model_matrix.threshold_model_array(.000000001F); - this->_matrix_is_stored=true; +PatlakPlot::create_model_matrix() { + if (_matrix_is_stored == false) { + // Create empty Model matrix. this is a [2 x frames] matrix, that contains Cp(t) and \int{Ct(t)} for each frame (Cp(t): + // radiotracer concentration on plasma) + + // NOTE: as we are working in time frames, and not discrete time points, Cp(t) is not a value of Cp at a given single time, t, + // but instead + // it is the integral of Cp on that time frame , \int_{t_start}^{t_end} Cp(t) dt, for each time frame. The same happens + // with \int{Cp(t)} All this is handled in the PlasmaData class, and it's not visible here. + + // BasicCoordinate just changes the indexing range (instead of 0-N, to some min to some max) + BasicCoordinate<2, int> min_range; + BasicCoordinate<2, int> max_range; + min_range[1] = 1; + min_range[2] = this->_starting_frame; + max_range[1] = 2; + max_range[2] = this->_plasma_frame_data.size(); + IndexRange<2> data_range(min_range, max_range); + Array<2, float> patlak_array(data_range); + VectorWithOffset time_vector(min_range[2], max_range[2]); + PlasmaData::const_iterator cur_iter = this->_plasma_frame_data.begin(); + + double sum_value = 0.; + unsigned int sample_num; + // Compute the value of the integral of Cp(t) for frames before the one we want to start applying Patlak to. + // Remember that this code requires all frames, from t=0 to be included, otherwise this integral will be wrongly computed. + // TODO: do not require the dynamic images to exist to do this integral. + for (sample_num = 1; sample_num < this->_starting_frame; ++sample_num, ++cur_iter) + sum_value += + cur_iter->get_plasma_counts_in_kBq() * this->_plasma_frame_data.get_time_frame_definitions().get_duration(sample_num); + + assert(cur_iter == this->_plasma_frame_data.begin() + this->_starting_frame - 1); + // For each frame that we are interested in, fill the model matrix. + for (sample_num = this->_starting_frame; cur_iter != this->_plasma_frame_data.end(); ++sample_num, ++cur_iter) { + sum_value += + cur_iter->get_plasma_counts_in_kBq() * this->_plasma_frame_data.get_time_frame_definitions().get_duration(sample_num); + // integral of Cp(t) + patlak_array[1][sample_num] = static_cast(sum_value); + // Cp(t) + patlak_array[2][sample_num] = cur_iter->get_plasma_counts_in_kBq(); + // As we will do the reconstruction in un-corrected data, if the plasma data is corrected, we need to undo that + if (this->_plasma_frame_data.get_is_decay_corrected()) { + const float dec_fact = static_cast( + decay_correction_factor(this->_plasma_frame_data.get_isotope_halflife(), + this->_plasma_frame_data.get_time_frame_definitions().get_start_time(sample_num), + this->_plasma_frame_data.get_time_frame_definitions().get_end_time(sample_num))); + patlak_array[1][sample_num] /= dec_fact; + patlak_array[2][sample_num] /= dec_fact; + time_vector[sample_num] = + static_cast(0.5 * (this->_frame_defs.get_end_time(sample_num) + this->_frame_defs.get_start_time(sample_num))); + } } - else + if (this->_plasma_frame_data.get_is_decay_corrected()) + warning("Uncorrecting previous decay correction, while putting the plasma_data into the model_matrix."); + else + error("plasma_data have not been corrected during the process, which will create wrong results!!!"); + + assert(sample_num - 1 == this->_plasma_frame_data.size()); + this->_model_matrix.set_model_array(patlak_array); + this->_model_matrix.set_time_vector(time_vector); + // Uncalibrate the ModelMatrix instead of Calibrating all the Dynamic Images. This should make faster the computation. + // Supposes the images are not calibrated. + this->_model_matrix.uncalibrate(this->_cal_factor); + if (this->_in_total_cnt) + this->_model_matrix.convert_to_total_frame_counts(this->_frame_defs); + this->_model_matrix.set_is_in_correct_scale(this->_in_correct_scale); + this->_model_matrix.threshold_model_array(.000000001F); + this->_matrix_is_stored = true; + } else warning("ModelMatrix has been already created"); } -Succeeded -PatlakPlot::set_up() -{ +Succeeded +PatlakPlot::set_up() { // if (base_type::set_up() != Succeeded::yes) // return Succeeded::no; this->create_model_matrix(); - if (this->_matrix_is_stored==true) + if (this->_matrix_is_stored == true) return Succeeded::yes; else return Succeeded::no; } -void -PatlakPlot::apply_linear_regression(ParametricVoxelsOnCartesianGrid & par_image, const DynamicDiscretisedDensity & dyn_image) const -{ - if (!this->_in_correct_scale) - { +void +PatlakPlot::apply_linear_regression(ParametricVoxelsOnCartesianGrid& par_image, + const DynamicDiscretisedDensity& dyn_image) const { + if (!this->_in_correct_scale) { #ifndef NDEBUG - this->_model_matrix.write_to_file("patlak_matrix_not_in_correct_scale.txt"); -#endif //NDEBUG - const DiscretisedDensityOnCartesianGrid <3,float>* image_cartesian_ptr = - dynamic_cast< DiscretisedDensityOnCartesianGrid<3,float>* > (((dyn_image.get_densities())[0]).get()); - const BasicCoordinate<3,float> this_grid_spacing = image_cartesian_ptr->get_grid_spacing(); - if (dyn_image.get_scanner_default_bin_size()<=0) - error("PatlakPlot: The dynamic image currently needs to know the Scanner's default_bin_size. Did you set the 'originating system'?"); - this->_model_matrix.scale_model_matrix(this_grid_spacing[2]/dyn_image.get_scanner_default_bin_size()); + this->_model_matrix.write_to_file("patlak_matrix_not_in_correct_scale.txt"); +#endif // NDEBUG + const DiscretisedDensityOnCartesianGrid<3, float>* image_cartesian_ptr = + dynamic_cast*>(((dyn_image.get_densities())[0]).get()); + const BasicCoordinate<3, float> this_grid_spacing = image_cartesian_ptr->get_grid_spacing(); + if (dyn_image.get_scanner_default_bin_size() <= 0) + error("PatlakPlot: The dynamic image currently needs to know the Scanner's default_bin_size. Did you set the 'originating " + "system'?"); + this->_model_matrix.scale_model_matrix(this_grid_spacing[2] / dyn_image.get_scanner_default_bin_size()); #ifndef NDEBUG - this->_model_matrix.write_to_file("patlak_matrix_in_correct_scale.txt"); -#endif //NDEBUG - } + this->_model_matrix.write_to_file("patlak_matrix_in_correct_scale.txt"); +#endif // NDEBUG + } // const DynamicDiscretisedDensity & dyn_image=this->_dyn_image; // TODO check consistency of time-frame definitions - const unsigned int num_frames=(this->_frame_defs).get_num_frames(); + const unsigned int num_frames = (this->_frame_defs).get_num_frames(); unsigned int frame_num; - unsigned int starting_frame= this->_starting_frame; - Array<2,float> patlak_model_array=this->_model_matrix.get_model_array(); - VectorWithOffset patlak_x(starting_frame-1,num_frames-1); - VectorWithOffset patlak_y(starting_frame-1,num_frames-1); - VectorWithOffset weights(starting_frame-1,num_frames-1); + unsigned int starting_frame = this->_starting_frame; + Array<2, float> patlak_model_array = this->_model_matrix.get_model_array(); + VectorWithOffset patlak_x(starting_frame - 1, num_frames - 1); + VectorWithOffset patlak_y(starting_frame - 1, num_frames - 1); + VectorWithOffset weights(starting_frame - 1, num_frames - 1); // Patlak Linear regression is applied to the data in the format: // C(t)/Cp(t)=Ki*\int{Cp(t)}/Cp(t)+Vb // therefore our "x" value for the regression is \int{Cp(t)}/Cp(t) (which we know from the model) // - // NOTE: as we are working in time frames, and not discrete time points, Cp(t) is not a value of Cp at a given single time, t, but instead - // it is the integral of Cp on that time frame , \int_{t_start}^{t_end} Cp(t) dt, for each time frame. The same happens with \int{Cp(t)} - // All this is handled in the PlasmaData class, and it's not visible here. - for(unsigned int frame_num = starting_frame; - frame_num<=num_frames ; ++frame_num ) - { - patlak_x[frame_num-1]=patlak_model_array[1][frame_num]/patlak_model_array[2][frame_num]; - weights[frame_num-1]=1; - } - { // Do linear_regression for each voxel // for k j i - float slope=0.F; - float y_intersection=0.F; - float variance_of_slope=0.F; - float variance_of_y_intersection=0.F; - float covariance_of_y_intersection_with_slope=0.F; - float chi_square = 0.F; - - const int min_k_index = dyn_image[1].get_min_index(); + // NOTE: as we are working in time frames, and not discrete time points, Cp(t) is not a value of Cp at a given single time, t, + // but instead + // it is the integral of Cp on that time frame , \int_{t_start}^{t_end} Cp(t) dt, for each time frame. The same happens + // with \int{Cp(t)} All this is handled in the PlasmaData class, and it's not visible here. + for (unsigned int frame_num = starting_frame; frame_num <= num_frames; ++frame_num) { + patlak_x[frame_num - 1] = patlak_model_array[1][frame_num] / patlak_model_array[2][frame_num]; + weights[frame_num - 1] = 1; + } + { // Do linear_regression for each voxel // for k j i + float slope = 0.F; + float y_intersection = 0.F; + float variance_of_slope = 0.F; + float variance_of_y_intersection = 0.F; + float covariance_of_y_intersection_with_slope = 0.F; + float chi_square = 0.F; + + const int min_k_index = dyn_image[1].get_min_index(); const int max_k_index = dyn_image[1].get_max_index(); - for ( int k = min_k_index; k<= max_k_index; ++k) - { - const int min_j_index = dyn_image[1][k].get_min_index(); - const int max_j_index = dyn_image[1][k].get_max_index(); - for ( int j = min_j_index; j<= max_j_index; ++j) - { - const int min_i_index = dyn_image[1][k][j].get_min_index(); - const int max_i_index = dyn_image[1][k][j].get_max_index(); - for ( int i = min_i_index; i<= max_i_index; ++i) - { - // Patlak Linear regression is applied to the data in the format: - // C(t)/Cp(t)=Ki*\int{Cp(t)}/Cp(t)+Vb - // therefore our "y" value for the regression is C(t)/Cp(t). C(t) is the dynamic image value. - // (remember, these are integrals over the time frame, not single values at discrete t) - for ( frame_num = starting_frame; - frame_num<=num_frames ; ++frame_num ) - patlak_y[frame_num-1]=dyn_image[frame_num][k][j][i]/patlak_model_array[2][frame_num]; - // Apply the regression to this pixel - linear_regression(y_intersection, slope, - chi_square, - variance_of_y_intersection, - variance_of_slope, - covariance_of_y_intersection_with_slope, - patlak_y, - patlak_x, - weights); - par_image[k][j][i][2]=y_intersection; - par_image[k][j][i][1]=slope; - } - } - } + for (int k = min_k_index; k <= max_k_index; ++k) { + const int min_j_index = dyn_image[1][k].get_min_index(); + const int max_j_index = dyn_image[1][k].get_max_index(); + for (int j = min_j_index; j <= max_j_index; ++j) { + const int min_i_index = dyn_image[1][k][j].get_min_index(); + const int max_i_index = dyn_image[1][k][j].get_max_index(); + for (int i = min_i_index; i <= max_i_index; ++i) { + // Patlak Linear regression is applied to the data in the format: + // C(t)/Cp(t)=Ki*\int{Cp(t)}/Cp(t)+Vb + // therefore our "y" value for the regression is C(t)/Cp(t). C(t) is the dynamic image value. + // (remember, these are integrals over the time frame, not single values at discrete t) + for (frame_num = starting_frame; frame_num <= num_frames; ++frame_num) + patlak_y[frame_num - 1] = dyn_image[frame_num][k][j][i] / patlak_model_array[2][frame_num]; + // Apply the regression to this pixel + linear_regression(y_intersection, slope, chi_square, variance_of_y_intersection, variance_of_slope, + covariance_of_y_intersection_with_slope, patlak_y, patlak_x, weights); + par_image[k][j][i][2] = y_intersection; + par_image[k][j][i][1] = slope; + } + } + } } } void -PatlakPlot::multiply_dynamic_image_with_model_gradient(ParametricVoxelsOnCartesianGrid & par_image, - const DynamicDiscretisedDensity & dyn_image) const -{ - if (!this->_in_correct_scale) - { +PatlakPlot::multiply_dynamic_image_with_model_gradient(ParametricVoxelsOnCartesianGrid& par_image, + const DynamicDiscretisedDensity& dyn_image) const { + if (!this->_in_correct_scale) { #ifndef NDEBUG - this->_model_matrix.write_to_file("patlak_matrix_not_in_correct_scale.txt"); -#endif //NDEBUG - const DiscretisedDensityOnCartesianGrid <3,float>* image_cartesian_ptr = - dynamic_cast< DiscretisedDensityOnCartesianGrid<3,float>* > (((dyn_image.get_densities())[0]).get()); - const BasicCoordinate<3,float> this_grid_spacing = image_cartesian_ptr->get_grid_spacing(); - if (dyn_image.get_scanner_default_bin_size()<=0) - error("PatlakPlot: The dynamic image currently needs to know the Scanner's default_bin_size. Did you set the 'originating system'?"); - this->_model_matrix.scale_model_matrix(this_grid_spacing[2]/dyn_image.get_scanner_default_bin_size()); + this->_model_matrix.write_to_file("patlak_matrix_not_in_correct_scale.txt"); +#endif // NDEBUG + const DiscretisedDensityOnCartesianGrid<3, float>* image_cartesian_ptr = + dynamic_cast*>(((dyn_image.get_densities())[0]).get()); + const BasicCoordinate<3, float> this_grid_spacing = image_cartesian_ptr->get_grid_spacing(); + if (dyn_image.get_scanner_default_bin_size() <= 0) + error("PatlakPlot: The dynamic image currently needs to know the Scanner's default_bin_size. Did you set the 'originating " + "system'?"); + this->_model_matrix.scale_model_matrix(this_grid_spacing[2] / dyn_image.get_scanner_default_bin_size()); #ifndef NDEBUG - this->_model_matrix.write_to_file("patlak_matrix_in_correct_scale.txt"); -#endif //NDEBUG - } - this->_model_matrix.multiply_dynamic_image_with_model(par_image,dyn_image); + this->_model_matrix.write_to_file("patlak_matrix_in_correct_scale.txt"); +#endif // NDEBUG + } + this->_model_matrix.multiply_dynamic_image_with_model(par_image, dyn_image); } void -PatlakPlot::multiply_dynamic_image_with_model_gradient_and_add_to_input(ParametricVoxelsOnCartesianGrid & par_image, - const DynamicDiscretisedDensity & dyn_image) const -{ - if (!this->_in_correct_scale) - { +PatlakPlot::multiply_dynamic_image_with_model_gradient_and_add_to_input(ParametricVoxelsOnCartesianGrid& par_image, + const DynamicDiscretisedDensity& dyn_image) const { + if (!this->_in_correct_scale) { #ifndef NDEBUG - this->_model_matrix.write_to_file("patlak_matrix_not_in_correct_scale.txt"); -#endif //NDEBUG - const DiscretisedDensityOnCartesianGrid <3,float>* image_cartesian_ptr = - dynamic_cast< DiscretisedDensityOnCartesianGrid<3,float>* > (((dyn_image.get_densities())[0]).get()); - const BasicCoordinate<3,float> this_grid_spacing = image_cartesian_ptr->get_grid_spacing(); - if (dyn_image.get_scanner_default_bin_size()<=0) - error("PatlakPlot: The dynamic image currently needs to know the Scanner's default_bin_size. Did you set the 'originating system'?"); - this->_model_matrix.scale_model_matrix(this_grid_spacing[2]/dyn_image.get_scanner_default_bin_size()); + this->_model_matrix.write_to_file("patlak_matrix_not_in_correct_scale.txt"); +#endif // NDEBUG + const DiscretisedDensityOnCartesianGrid<3, float>* image_cartesian_ptr = + dynamic_cast*>(((dyn_image.get_densities())[0]).get()); + const BasicCoordinate<3, float> this_grid_spacing = image_cartesian_ptr->get_grid_spacing(); + if (dyn_image.get_scanner_default_bin_size() <= 0) + error("PatlakPlot: The dynamic image currently needs to know the Scanner's default_bin_size. Did you set the 'originating " + "system'?"); + this->_model_matrix.scale_model_matrix(this_grid_spacing[2] / dyn_image.get_scanner_default_bin_size()); #ifndef NDEBUG - this->_model_matrix.write_to_file("patlak_matrix_in_correct_scale.txt"); -#endif //NDEBUG - } - this->_model_matrix.multiply_dynamic_image_with_model_and_add_to_input(par_image,dyn_image); + this->_model_matrix.write_to_file("patlak_matrix_in_correct_scale.txt"); +#endif // NDEBUG + } + this->_model_matrix.multiply_dynamic_image_with_model_and_add_to_input(par_image, dyn_image); } // Should be a virtual function declared in the KineticModels or better to the LinearModels void -PatlakPlot::get_dynamic_image_from_parametric_image(DynamicDiscretisedDensity & dyn_image, - const ParametricVoxelsOnCartesianGrid & par_image) const -{ - if (!this->_in_correct_scale) - { +PatlakPlot::get_dynamic_image_from_parametric_image(DynamicDiscretisedDensity& dyn_image, + const ParametricVoxelsOnCartesianGrid& par_image) const { + if (!this->_in_correct_scale) { #ifndef NDEBUG - this->_model_matrix.write_to_file("patlak_matrix_not_in_correct_scale.txt"); -#endif //NDEBUG - const DiscretisedDensityOnCartesianGrid <3,float>* image_cartesian_ptr = - dynamic_cast< DiscretisedDensityOnCartesianGrid<3,float>* > (((dyn_image.get_densities())[0]).get()); - const BasicCoordinate<3,float> this_grid_spacing = image_cartesian_ptr->get_grid_spacing(); - if (dyn_image.get_scanner_default_bin_size()<=0) - error("PatlakPlot: The dynamic image currently needs to know the Scanner's default_bin_size. Did you set the 'originating system'?"); - this->_model_matrix.scale_model_matrix(this_grid_spacing[2]/dyn_image.get_scanner_default_bin_size()); + this->_model_matrix.write_to_file("patlak_matrix_not_in_correct_scale.txt"); +#endif // NDEBUG + const DiscretisedDensityOnCartesianGrid<3, float>* image_cartesian_ptr = + dynamic_cast*>(((dyn_image.get_densities())[0]).get()); + const BasicCoordinate<3, float> this_grid_spacing = image_cartesian_ptr->get_grid_spacing(); + if (dyn_image.get_scanner_default_bin_size() <= 0) + error("PatlakPlot: The dynamic image currently needs to know the Scanner's default_bin_size. Did you set the 'originating " + "system'?"); + this->_model_matrix.scale_model_matrix(this_grid_spacing[2] / dyn_image.get_scanner_default_bin_size()); #ifndef NDEBUG - this->_model_matrix.write_to_file("patlak_matrix_in_correct_scale.txt"); -#endif //NDEBUG - } + this->_model_matrix.write_to_file("patlak_matrix_in_correct_scale.txt"); +#endif // NDEBUG + } - this->_model_matrix.multiply_parametric_image_with_model(dyn_image,par_image); + this->_model_matrix.multiply_parametric_image_with_model(dyn_image, par_image); } unsigned int -PatlakPlot::get_starting_frame() const -{ +PatlakPlot::get_starting_frame() const { return this->_starting_frame; } -TimeFrameDefinitions -PatlakPlot::get_time_frame_definitions() const -{ +TimeFrameDefinitions +PatlakPlot::get_time_frame_definitions() const { return this->_frame_defs; } void -PatlakPlot:: -initialise_keymap() -{ +PatlakPlot::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Patlak Plot Parameters"); this->parser.add_key("Blood Data Filename", &this->_blood_data_filename); @@ -335,44 +311,38 @@ initialise_keymap() this->parser.add_key("Time Shift", &this->_time_shift); this->parser.add_key("In total counts", &this->_in_total_cnt); this->parser.add_key("In correct scale", &this->_in_correct_scale); - this->parser.add_key("Time Frame Definition Filename", &this->_time_frame_definition_filename); + this->parser.add_key("Time Frame Definition Filename", &this->_time_frame_definition_filename); this->parser.add_stop_key("end Patlak Plot Parameters"); } /*! \todo This currently hard-wired F-18 decay for the plasma data */ bool -PatlakPlot:: -post_processing() -{ +PatlakPlot::post_processing() { if (base_type::post_processing() == true) return true; - // read time frame def - if (this->_time_frame_definition_filename.size()!=0) - this->_frame_defs=TimeFrameDefinitions(this->_time_frame_definition_filename); - else - { - error("No Time Frames Definitions available!!!\n "); - return true; - } + // read time frame def + if (this->_time_frame_definition_filename.size() != 0) + this->_frame_defs = TimeFrameDefinitions(this->_time_frame_definition_filename); + else { + error("No Time Frames Definitions available!!!\n "); + return true; + } // Reading the input function - if(this->_blood_data_filename=="0") - { - warning("You need to specify a file for the input function."); - return true; - } - else - { - this->_if_cardiac=false; - PlasmaData plasma_data_temp; - plasma_data_temp.read_plasma_data(this->_blood_data_filename); // The implementation assumes three list file. - // TODO have parameter - warning("Assuming F-18 tracer for half-life!!!"); - plasma_data_temp.set_isotope_halflife(6586.2F); - plasma_data_temp.shift_time(this->_time_shift); - this->_plasma_frame_data=plasma_data_temp.get_sample_data_in_frames(this->_frame_defs); - } -return false; + if (this->_blood_data_filename == "0") { + warning("You need to specify a file for the input function."); + return true; + } else { + this->_if_cardiac = false; + PlasmaData plasma_data_temp; + plasma_data_temp.read_plasma_data(this->_blood_data_filename); // The implementation assumes three list file. + // TODO have parameter + warning("Assuming F-18 tracer for half-life!!!"); + plasma_data_temp.set_isotope_halflife(6586.2F); + plasma_data_temp.shift_time(this->_time_shift); + this->_plasma_frame_data = plasma_data_temp.get_sample_data_in_frames(this->_frame_defs); + } + return false; } //! Create model matrix from blood frame data diff --git a/src/modelling_buildblock/modelling_registries.cxx b/src/modelling_buildblock/modelling_registries.cxx index 26b4e4044b..1e44c64ba2 100644 --- a/src/modelling_buildblock/modelling_registries.cxx +++ b/src/modelling_buildblock/modelling_registries.cxx @@ -27,7 +27,7 @@ \brief File that registers all stir::RegisterObject children in modelling \author Charalampos Tsoumpas - + */ #include "stir/modelling/PatlakPlot.h" @@ -36,4 +36,3 @@ START_NAMESPACE_STIR static PatlakPlot::RegisterIt dummy113; END_NAMESPACE_STIR - diff --git a/src/modelling_utilities/apply_patlak_to_images.cxx b/src/modelling_utilities/apply_patlak_to_images.cxx index 8fbdeb9842..89e36931d9 100644 --- a/src/modelling_utilities/apply_patlak_to_images.cxx +++ b/src/modelling_utilities/apply_patlak_to_images.cxx @@ -24,20 +24,21 @@ \par Usage: - \code - apply_patlak_to_images output_parametric_image input_dynamic_image [par_file] + \code + apply_patlak_to_images output_parametric_image input_dynamic_image [par_file] \endcode - + \par - - The dynamic images will be calibrated only if the calibration factor is given. - - The \a if_total_cnt is set to true the Dynamic Image will have the total number of + - The dynamic images will be calibrated only if the calibration factor is given. + - The \a if_total_cnt is set to true the Dynamic Image will have the total number of counts while if set to false it will have the \a total_number_of_counts/get_duration(frame_num). - The dynamic images will always be in decaying counts. - The plasma data is assumed to be in decaying counts. - + \sa PatlakPlot.h for the \a par_file - \note This implementation does not use wighted least squares because for Patlak Plot only the last frames are used, which they usually have the same duration and similar number of counts. + \note This implementation does not use wighted least squares because for Patlak Plot only the last frames are used, which they + usually have the same duration and similar number of counts. \todo Reimplement the method for image-based input function. @@ -56,51 +57,48 @@ #include #include -int main(int argc, char *argv[]) -{ -USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) { + USING_NAMESPACE_STIR PatlakPlot indirect_patlak; - if (argc==4) - { - if (indirect_patlak.parse(argv[3]) == false) - return EXIT_FAILURE; - } - if (argc!=3 && argc!=4) - { - std::cerr << "Usage:" << argv[0] << " output_parametric_image input_dynamic_image [par_file] \n"; + if (argc == 4) { + if (indirect_patlak.parse(argv[3]) == false) return EXIT_FAILURE; - } - if (argc==3) + } + if (argc != 3 && argc != 4) { + std::cerr << "Usage:" << argv[0] << " output_parametric_image input_dynamic_image [par_file] \n"; + return EXIT_FAILURE; + } + if (argc == 3) indirect_patlak.ask_parameters(); CPUTimer timer; timer.start(); - if (indirect_patlak.set_up()==Succeeded::no) - return EXIT_FAILURE ; - else - { - // Create dynamic images object from input file - shared_ptr dyn_image_sptr(read_from_file(argv[2])); - const DynamicDiscretisedDensity & dyn_image= *dyn_image_sptr; - // Create parametric images from input file - shared_ptr par_image_sptr; - par_image_sptr = MAKE_SHARED(dyn_image); - - //ToDo: Assertion for the dyn-par images, sizes I have to create from one to the other image, so then it should be OK... - assert(indirect_patlak.get_time_frame_definitions().get_num_frames()==dyn_image.get_time_frame_definitions().get_num_frames()); - indirect_patlak.apply_linear_regression(*par_image_sptr,dyn_image); - - // Writing image - std::cerr << "Writing parametric-image in '"<< argv[1] << "'\n"; - const Succeeded writing_succeeded=OutputFileFormat::default_sptr()-> - write_to_file(argv[1], *par_image_sptr); - std::cerr << "Total time for Image-Based Patlak in sec: " << timer.value() <<"\n"; - timer.stop(); - - if(writing_succeeded==Succeeded::yes) - return EXIT_SUCCESS ; - else - return EXIT_FAILURE ; - } -} + if (indirect_patlak.set_up() == Succeeded::no) + return EXIT_FAILURE; + else { + // Create dynamic images object from input file + shared_ptr dyn_image_sptr(read_from_file(argv[2])); + const DynamicDiscretisedDensity& dyn_image = *dyn_image_sptr; + // Create parametric images from input file + shared_ptr par_image_sptr; + par_image_sptr = MAKE_SHARED(dyn_image); + + // ToDo: Assertion for the dyn-par images, sizes I have to create from one to the other image, so then it should be OK... + assert(indirect_patlak.get_time_frame_definitions().get_num_frames() == + dyn_image.get_time_frame_definitions().get_num_frames()); + indirect_patlak.apply_linear_regression(*par_image_sptr, dyn_image); + // Writing image + std::cerr << "Writing parametric-image in '" << argv[1] << "'\n"; + const Succeeded writing_succeeded = + OutputFileFormat::default_sptr()->write_to_file(argv[1], *par_image_sptr); + std::cerr << "Total time for Image-Based Patlak in sec: " << timer.value() << "\n"; + timer.stop(); + + if (writing_succeeded == Succeeded::yes) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; + } +} diff --git a/src/modelling_utilities/extract_single_images_from_parametric_image.cxx b/src/modelling_utilities/extract_single_images_from_parametric_image.cxx index 208b474135..c30f82f7e9 100644 --- a/src/modelling_utilities/extract_single_images_from_parametric_image.cxx +++ b/src/modelling_utilities/extract_single_images_from_parametric_image.cxx @@ -25,7 +25,7 @@ \author Kris Thielemans \par Usage: - \code + \code extract_single_images_from_parametric_image output_filename_pattern input_header_filename output_format_parameter_file The output filename should look something like this: param_im_%d_output.file_extension, @@ -52,79 +52,79 @@ #include "stir/IO/OutputFileFormat.h" #include "stir/Succeeded.h" -int main(int argc, char *argv[]) -{ - USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) { + USING_NAMESPACE_STIR + + if (argc != 3 && argc != 4) { + std::cerr << "\nUsage: extract_single_images_from_parametric_image output_filename_pattern input_header_filename " + "[output_format_parameter_file]\n\n"; + return EXIT_FAILURE; + } + + try { + + // Read images + auto param_im_sptr(read_from_file(argv[2])); + + // Check + if (is_null_ptr(param_im_sptr)) + throw std::runtime_error("Failed to read dynamic image (" + std::string(argv[2]) + ")."); + + // Set up the output type + shared_ptr>> output_file_format_sptr; + if (argc == 3) + output_file_format_sptr = OutputFileFormat>::default_sptr(); + else { + KeyParser parser; + parser.add_start_key("OutputFileFormat Parameters"); + parser.add_parsing_key("output file format type", &output_file_format_sptr); + parser.add_stop_key("END"); + std::ifstream in(argv[3]); + if (!parser.parse(in) || is_null_ptr(output_file_format_sptr)) + throw std::runtime_error("Failed to parse output format file (" + std::string(argv[3]) + ")."); + } - if (argc != 3 && argc != 4) { - std::cerr << "\nUsage: extract_single_images_from_parametric_image output_filename_pattern input_header_filename [output_format_parameter_file]\n\n"; + // Loop over each image + for (unsigned i = 1; i <= param_im_sptr->get_num_params(); ++i) { + + auto disc = param_im_sptr->construct_single_density(i); + { + // Get the time frame definition (from start of first frame to end of last) + ExamInfo exam_info = disc.get_exam_info(); + TimeFrameDefinitions tdefs = exam_info.get_time_frame_definitions(); + const double start = tdefs.get_start_time(1); + const double end = tdefs.get_end_time(tdefs.get_num_frames()); + tdefs.set_num_time_frames(1); + tdefs.set_time_frame(1, start, end); + exam_info.set_time_frame_definitions(tdefs); + disc.set_exam_info(exam_info); + } + + std::string current_filename; + try { + current_filename = boost::str(boost::format(argv[1]) % i); + } catch (std::exception& e) { + error(boost::format("Error using 'output_filename' pattern (which is set to '%1%'). " + "Check syntax for boost::format. Error is:\n%2%") % + argv[1] % e.what()); return EXIT_FAILURE; + } + + // Write to file + const Succeeded success = output_file_format_sptr->write_to_file(current_filename, disc); + if (success == Succeeded::no) + throw std::runtime_error("Failed writing."); } - try { - - // Read images - auto param_im_sptr(read_from_file(argv[2])); - - // Check - if (is_null_ptr(param_im_sptr)) - throw std::runtime_error("Failed to read dynamic image (" + std::string(argv[2]) + ")."); - - // Set up the output type - shared_ptr > > output_file_format_sptr; - if (argc == 3) - output_file_format_sptr = OutputFileFormat >::default_sptr(); - else { - KeyParser parser; - parser.add_start_key("OutputFileFormat Parameters"); - parser.add_parsing_key("output file format type", &output_file_format_sptr); - parser.add_stop_key("END"); - std::ifstream in(argv[3]); - if (!parser.parse(in) || is_null_ptr(output_file_format_sptr)) - throw std::runtime_error("Failed to parse output format file (" + std::string(argv[3]) + ")."); - } - - // Loop over each image - for (unsigned i=1; i<=param_im_sptr->get_num_params(); ++i) { - - auto disc = param_im_sptr->construct_single_density(i); - { - // Get the time frame definition (from start of first frame to end of last) - ExamInfo exam_info = disc.get_exam_info(); - TimeFrameDefinitions tdefs = exam_info.get_time_frame_definitions(); - const double start = tdefs.get_start_time(1); - const double end = tdefs.get_end_time(tdefs.get_num_frames()); - tdefs.set_num_time_frames(1); - tdefs.set_time_frame(1,start,end); - exam_info.set_time_frame_definitions(tdefs); - disc.set_exam_info(exam_info); - } - - std::string current_filename; - try { - current_filename = boost::str(boost::format(argv[1]) % i); - } catch (std::exception& e) { - error(boost::format("Error using 'output_filename' pattern (which is set to '%1%'). " - "Check syntax for boost::format. Error is:\n%2%") % argv[1] % e.what()); - return EXIT_FAILURE; - } - - // Write to file - const Succeeded success = output_file_format_sptr->write_to_file(current_filename,disc); - if (success == Succeeded::no) - throw std::runtime_error("Failed writing."); - } - - // If all is good, exit - return EXIT_SUCCESS; + // If all is good, exit + return EXIT_SUCCESS; // If there was an error - } catch(const std::exception &error) { - std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; - return EXIT_FAILURE; - } catch(...) { - return EXIT_FAILURE; - } + } catch (const std::exception& error) { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + return EXIT_FAILURE; + } catch (...) { + return EXIT_FAILURE; + } } - - diff --git a/src/modelling_utilities/get_dynamic_images_from_parametric_images.cxx b/src/modelling_utilities/get_dynamic_images_from_parametric_images.cxx index baed0afdd8..5a311b92c2 100644 --- a/src/modelling_utilities/get_dynamic_images_from_parametric_images.cxx +++ b/src/modelling_utilities/get_dynamic_images_from_parametric_images.cxx @@ -22,18 +22,18 @@ \file \ingroup utilities \brief Multiplies Parametric Images with the Model Matrix creating Dynamic Images - \author Charalampos Tsoumpas + \author Charalampos Tsoumpas \author Richard Brown \par Usage: - \code + \code get_dynamic_images_from_parametric_images output_parametric_image input_dynamic_image [par_file [output_format_par_file]] \endcode - + \par - - The dynamic images will be calibrated only if the calibration factor is given. + - The dynamic images will be calibrated only if the calibration factor is given. - The dynamic images will be in decaying counts if the plasma data are in decaying counts. - + An optional output file format parameter file can also be given. An example for this might be: output file format parameters := output file format type := Interfile @@ -42,7 +42,7 @@ number_of_bytes_per_pixel:=4 End Interfile Output File Format Parameters:= end := - + \sa PatlakPlot.h for the \a par_file \todo Add to the Doxygen documentation how exactly this utility works. @@ -63,110 +63,98 @@ USING_NAMESPACE_STIR -shared_ptr > set_up_output_format(int argc, char *argv[]) -{ - shared_ptr > output = - OutputFileFormat::default_sptr(); +shared_ptr> +set_up_output_format(int argc, char* argv[]) { + shared_ptr> output = OutputFileFormat::default_sptr(); - if (argc == 5) { + if (argc == 5) { - KeyParser parser; - parser.add_start_key("output file format parameters"); - parser.add_parsing_key("output file format type", &output); - parser.add_stop_key("END"); + KeyParser parser; + parser.add_start_key("output file format parameters"); + parser.add_parsing_key("output file format type", &output); + parser.add_stop_key("END"); - if (parser.parse(argv[4]) == false || is_null_ptr(output)) { - warning("Error parsing output file format. Using default format."); - output = OutputFileFormat::default_sptr(); - } + if (parser.parse(argv[4]) == false || is_null_ptr(output)) { + warning("Error parsing output file format. Using default format."); + output = OutputFileFormat::default_sptr(); } - return output; + } + return output; } -int main(int argc, char *argv[]) -{ -// Impelemented only for the linear Patlak Plot so far. -// In the future I should implement the KineticModels with the "linear" specification -// for patlak, logan etc... PatlakPlot patlak_plot; +int +main(int argc, char* argv[]) { + // Impelemented only for the linear Patlak Plot so far. + // In the future I should implement the KineticModels with the "linear" specification + // for patlak, logan etc... PatlakPlot patlak_plot; PatlakPlot patlak_plot; - if (argc>=4) - { - if (patlak_plot.parse(argv[3]) == false) - return EXIT_FAILURE; - } - if (argc!=3 && argc!=4 && argc!=5) - { - std::cerr << "Usage:" << argv[0] << " output_dynamic_image input_parametric_image [par_file [output_format_par_file]]\n"; + if (argc >= 4) { + if (patlak_plot.parse(argv[3]) == false) return EXIT_FAILURE; - } - if (argc==3) + } + if (argc != 3 && argc != 4 && argc != 5) { + std::cerr << "Usage:" << argv[0] << " output_dynamic_image input_parametric_image [par_file [output_format_par_file]]\n"; + return EXIT_FAILURE; + } + if (argc == 3) patlak_plot.ask_parameters(); - if (patlak_plot.set_up()==Succeeded::no) - return EXIT_FAILURE ; - else - { - shared_ptr - par_image_sptr(ParametricVoxelsOnCartesianGrid::read_from_file(argv[2])); - - DynamicDiscretisedDensity dyn_image; - - // If the output file already exists, use it as the template - std::ifstream file(argv[1]); - if (file) - { - std::cerr << "\nOutput image already exists, so using that as the template.\n"; + if (patlak_plot.set_up() == Succeeded::no) + return EXIT_FAILURE; + else { + shared_ptr par_image_sptr(ParametricVoxelsOnCartesianGrid::read_from_file(argv[2])); + + DynamicDiscretisedDensity dyn_image; + + // If the output file already exists, use it as the template + std::ifstream file(argv[1]); + if (file) { + std::cerr << "\nOutput image already exists, so using that as the template.\n"; #if 1 - shared_ptr - dyn_image_sptr(read_from_file(argv[1])); - dyn_image= *dyn_image_sptr; + shared_ptr dyn_image_sptr(read_from_file(argv[1])); + dyn_image = *dyn_image_sptr; #else // At the moment it is impossible to have the scanner information without extra prior information. - const shared_ptr > density_template_sptr((par_image_sptr->construct_single_density(1)).clone()); - DynamicDiscretisedDensity dyn_image=DynamicDiscretisedDensity(patlak_plot.get_time_frame_definitions(), scanner_sptr, density_template_sptr); + const shared_ptr> density_template_sptr((par_image_sptr->construct_single_density(1)).clone()); + DynamicDiscretisedDensity dyn_image = + DynamicDiscretisedDensity(patlak_plot.get_time_frame_definitions(), scanner_sptr, density_template_sptr); #endif - //ToDo: Assertion for the dyn-par images, sizes I have to create from one to the other image, so then it should be OK... - assert(patlak_plot.get_time_frame_definitions().get_num_frames()==dyn_image.get_time_frame_definitions().get_num_frames()); + // ToDo: Assertion for the dyn-par images, sizes I have to create from one to the other image, so then it should be OK... + assert(patlak_plot.get_time_frame_definitions().get_num_frames() == + dyn_image.get_time_frame_definitions().get_num_frames()); #ifndef NDEBUG - const DiscretisedDensityOnCartesianGrid <3,float>* cartesian_ptr = - dynamic_cast< DiscretisedDensityOnCartesianGrid<3,float>*> (&dyn_image[1]); - assert(par_image_sptr->get_voxel_size()==cartesian_ptr->get_grid_spacing()); + const DiscretisedDensityOnCartesianGrid<3, float>* cartesian_ptr = + dynamic_cast*>(&dyn_image[1]); + assert(par_image_sptr->get_voxel_size() == cartesian_ptr->get_grid_spacing()); #endif - } + } - // If the output file doesn't exist, get all the info we need - else - { - std::cerr << "\nOutput image does not exist, so getting relevant info from parametric image and Patlak plot.\n"; + // If the output file doesn't exist, get all the info we need + else { + std::cerr << "\nOutput image does not exist, so getting relevant info from parametric image and Patlak plot.\n"; - const ExamInfo exam_info = par_image_sptr->get_exam_info(); - const TimeFrameDefinitions tdefs = patlak_plot.get_time_frame_definitions(); - const double time_since_1970 = exam_info.start_time_in_secs_since_1970; - shared_ptr scanner_sptr(Scanner::get_scanner_from_name(par_image_sptr->get_exam_info().originating_system)); - shared_ptr > voxels_sptr(par_image_sptr->construct_single_density(1).clone()); + const ExamInfo exam_info = par_image_sptr->get_exam_info(); + const TimeFrameDefinitions tdefs = patlak_plot.get_time_frame_definitions(); + const double time_since_1970 = exam_info.start_time_in_secs_since_1970; + shared_ptr scanner_sptr(Scanner::get_scanner_from_name(par_image_sptr->get_exam_info().originating_system)); + shared_ptr> voxels_sptr(par_image_sptr->construct_single_density(1).clone()); - // Construct the dynamic image - dyn_image = DynamicDiscretisedDensity(tdefs, - time_since_1970, - scanner_sptr, - voxels_sptr); - } + // Construct the dynamic image + dyn_image = DynamicDiscretisedDensity(tdefs, time_since_1970, scanner_sptr, voxels_sptr); + } - patlak_plot.get_dynamic_image_from_parametric_image(dyn_image,*par_image_sptr); + patlak_plot.get_dynamic_image_from_parametric_image(dyn_image, *par_image_sptr); - // Writing image - std::cerr << "Writing dynamic-image in '"<< argv[1] << "'\n"; + // Writing image + std::cerr << "Writing dynamic-image in '" << argv[1] << "'\n"; - shared_ptr > output_file_format = - set_up_output_format(argc, argv); + shared_ptr> output_file_format = set_up_output_format(argc, argv); - Succeeded writing_succeeded = output_file_format->write_to_file(argv[1], dyn_image); + Succeeded writing_succeeded = output_file_format->write_to_file(argv[1], dyn_image); - if(writing_succeeded==Succeeded::yes) - return EXIT_SUCCESS ; - else - return EXIT_FAILURE ; - } + if (writing_succeeded == Succeeded::yes) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; + } } - - diff --git a/src/modelling_utilities/make_parametric_image_from_components.cxx b/src/modelling_utilities/make_parametric_image_from_components.cxx index 32415411b0..1e8602e934 100644 --- a/src/modelling_utilities/make_parametric_image_from_components.cxx +++ b/src/modelling_utilities/make_parametric_image_from_components.cxx @@ -24,7 +24,7 @@ \author Richard Brown \par Usage: - \code + \code make_parametric_image_from_components output_parametric_image slope intercept \endcode @@ -42,73 +42,72 @@ #include "stir/ProjDataInfo.h" -int main(int argc, char *argv[]) -{ - USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) { + USING_NAMESPACE_STIR - if (argc != 4) { - std::cerr << "\nUsage: make_parametric_image_from_components output_parametric_image param1 param2 param3...\n\n"; - std::cerr << "\tCurrently only implemented for 2 kinetic parameters. E.g., for Patlak, slope followed by intercept.\n"; - return EXIT_FAILURE; - } - - try { - - std::vector > params; + if (argc != 4) { + std::cerr << "\nUsage: make_parametric_image_from_components output_parametric_image param1 param2 param3...\n\n"; + std::cerr << "\tCurrently only implemented for 2 kinetic parameters. E.g., for Patlak, slope followed by intercept.\n"; + return EXIT_FAILURE; + } - // Loop over all parameters - for (int i=2; i<=argc; ++i) { + try { - // Read - shared_ptr > im(read_from_file >(argv[i])); - // Check - if (is_null_ptr(im)) throw std::runtime_error("Failed to read file: " + std::string(argv[i]) + "."); + std::vector> params; - // Convert to VoxelsOnCartesianGrid - if (is_null_ptr(dynamic_cast*>(im.get()))) - throw std::runtime_error("Failed to convert parameter to VoxelsOnCartesianGrid."); + // Loop over all parameters + for (int i = 2; i <= argc; ++i) { - VoxelsOnCartesianGrid *param = dynamic_cast*>(im.get()); + // Read + shared_ptr> im(read_from_file>(argv[i])); + // Check + if (is_null_ptr(im)) + throw std::runtime_error("Failed to read file: " + std::string(argv[i]) + "."); - params.push_back(*param); + // Convert to VoxelsOnCartesianGrid + if (is_null_ptr(dynamic_cast*>(im.get()))) + throw std::runtime_error("Failed to convert parameter to VoxelsOnCartesianGrid."); - // Check characteristics match (compare new with first) - std::string explanation; - if (!param->has_same_characteristics(params.at(0),explanation)) - throw std::runtime_error("Kinetic images do not have same characteristics (" + std::string(explanation) + ")."); - } + VoxelsOnCartesianGrid* param = dynamic_cast*>(im.get()); - // At the moment, only implemented for 2 parameters - if (params.size() == 2) { - // Construct the parametric image - ParametricVoxelsOnCartesianGridBaseType base_type(params[0].get_index_range(),params[0].get_origin(),params[0].get_grid_spacing()); - ParametricVoxelsOnCartesianGrid param_im(base_type); + params.push_back(*param); - // Set data - param_im.update_parametric_image(params[0],1); - param_im.update_parametric_image(params[1],2); - - // Write it to file - const Succeeded success = OutputFileFormat::default_sptr()->write_to_file(argv[1], param_im); - if (success == Succeeded::no) - throw std::runtime_error("Failed writing."); - } - else { - std::cerr << "\ncurrently only implemented for 2 kinetic parameters. Exiting...\n"; - return EXIT_FAILURE; - } + // Check characteristics match (compare new with first) + std::string explanation; + if (!param->has_same_characteristics(params.at(0), explanation)) + throw std::runtime_error("Kinetic images do not have same characteristics (" + std::string(explanation) + ")."); + } + // At the moment, only implemented for 2 parameters + if (params.size() == 2) { + // Construct the parametric image + ParametricVoxelsOnCartesianGridBaseType base_type(params[0].get_index_range(), params[0].get_origin(), + params[0].get_grid_spacing()); + ParametricVoxelsOnCartesianGrid param_im(base_type); + + // Set data + param_im.update_parametric_image(params[0], 1); + param_im.update_parametric_image(params[1], 2); + + // Write it to file + const Succeeded success = + OutputFileFormat::default_sptr()->write_to_file(argv[1], param_im); + if (success == Succeeded::no) + throw std::runtime_error("Failed writing."); + } else { + std::cerr << "\ncurrently only implemented for 2 kinetic parameters. Exiting...\n"; + return EXIT_FAILURE; + } - // If all is good, exit - return EXIT_SUCCESS; + // If all is good, exit + return EXIT_SUCCESS; // If there was an error - } catch(const std::exception &error) { - std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; - return EXIT_FAILURE; - } catch(...) { - return EXIT_FAILURE; - } + } catch (const std::exception& error) { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + return EXIT_FAILURE; + } catch (...) { + return EXIT_FAILURE; + } } - - diff --git a/src/modelling_utilities/mult_image_parameters.cxx b/src/modelling_utilities/mult_image_parameters.cxx index 5465690693..472570e537 100644 --- a/src/modelling_utilities/mult_image_parameters.cxx +++ b/src/modelling_utilities/mult_image_parameters.cxx @@ -25,14 +25,14 @@ \par Usage: \code - mult_image_parameters -o output_filename -i input_filename + mult_image_parameters -o output_filename -i input_filename \endcode \attention Assumes that only two parameters exist. \todo Make a generic utility which will multiply all the parameters together and store them in a multiple image file. \todo It might be possible to integrate it into the stir_math.cxx, in the future. - \note It is useful to estimate the covariance between the two parameters of the parametric images. + \note It is useful to estimate the covariance between the two parameters of the parametric images. */ #include "stir/Succeeded.h" @@ -43,74 +43,65 @@ #include "stir/getopt.h" #include -int main(int argc, char * argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR; - const char * output_filename = 0; - const char * input_filename = 0; + const char* output_filename = 0; + const char* input_filename = 0; - const char * const usage = "mult_image_parameters -o output_filename -i input_filename\n"; + const char* const usage = "mult_image_parameters -o output_filename -i input_filename\n"; opterr = 0; { char c; - while ((c = getopt (argc, argv, "i:o:p")) != -1) - switch (c) - { + while ((c = getopt(argc, argv, "i:o:p")) != -1) + switch (c) { case 'i': - input_filename = optarg; - break; + input_filename = optarg; + break; case 'o': - output_filename = optarg; - break; + output_filename = optarg; + break; case '?': - std::cerr << usage; - return EXIT_FAILURE; + std::cerr << usage; + return EXIT_FAILURE; default: - if (isprint (optopt)) - fprintf (stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf (stderr, - "Unknown option character `\\x%x'.\n", - optopt); - std::cerr << usage; - return EXIT_FAILURE; + if (isprint(optopt)) + fprintf(stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); + std::cerr << usage; + return EXIT_FAILURE; } } - if (output_filename==0 || input_filename==0) - { - std::cerr << usage; - return EXIT_FAILURE; - } + if (output_filename == 0 || input_filename == 0) { + std::cerr << usage; + return EXIT_FAILURE; + } - const shared_ptr - input_image_sptr(ParametricVoxelsOnCartesianGrid::read_from_file(input_filename)); - const ParametricVoxelsOnCartesianGrid & input_image = *input_image_sptr; + const shared_ptr input_image_sptr( + ParametricVoxelsOnCartesianGrid::read_from_file(input_filename)); + const ParametricVoxelsOnCartesianGrid& input_image = *input_image_sptr; - shared_ptr > - output_image_sptr((input_image_sptr->construct_single_density(1)).clone()); - DiscretisedDensity<3,float>& output_image = *output_image_sptr; + shared_ptr> output_image_sptr((input_image_sptr->construct_single_density(1)).clone()); + DiscretisedDensity<3, float>& output_image = *output_image_sptr; - const int min_k_index = output_image.get_min_index(); + const int min_k_index = output_image.get_min_index(); const int max_k_index = output_image.get_max_index(); - for ( int k = min_k_index; k<= max_k_index; ++k) - { - const int min_j_index = output_image[k].get_min_index(); - const int max_j_index = output_image[k].get_max_index(); - for ( int j = min_j_index; j<= max_j_index; ++j) - { - const int min_i_index = output_image[k][j].get_min_index(); - const int max_i_index = output_image[k][j].get_max_index(); - for ( int i = min_i_index; i<= max_i_index; ++i) - output_image[k][j][i]=input_image[k][j][i][1]*input_image[k][j][i][2]; - } + for (int k = min_k_index; k <= max_k_index; ++k) { + const int min_j_index = output_image[k].get_min_index(); + const int max_j_index = output_image[k].get_max_index(); + for (int j = min_j_index; j <= max_j_index; ++j) { + const int min_i_index = output_image[k][j].get_min_index(); + const int max_i_index = output_image[k][j].get_max_index(); + for (int i = min_i_index; i <= max_i_index; ++i) + output_image[k][j][i] = input_image[k][j][i][1] * input_image[k][j][i][2]; } + } Succeeded success = - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, *output_image_sptr); - - return success==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; -} + OutputFileFormat>::default_sptr()->write_to_file(output_filename, *output_image_sptr); + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/modelling_utilities/mult_model_with_dyn_images.cxx b/src/modelling_utilities/mult_model_with_dyn_images.cxx index 36b77f7642..e522ae3896 100644 --- a/src/modelling_utilities/mult_model_with_dyn_images.cxx +++ b/src/modelling_utilities/mult_model_with_dyn_images.cxx @@ -24,14 +24,14 @@ \author Charalampos Tsoumpas \par Usage: - \code - mult_model_with_dyn_images output_parametric_image input_dynamic_image [par_file] + \code + mult_model_with_dyn_images output_parametric_image input_dynamic_image [par_file] \endcode - + \par - - The dynamic images will be calibrated only if the calibration factor is given. + - The dynamic images will be calibrated only if the calibration factor is given. - The dynamic images and the plasma data must be both either in decaying counts or in decay-corrected counts. - + \sa PatlakPlot.h for the \a par_file \todo Add to the Doxygen documentation how exactly this utility works. @@ -48,52 +48,47 @@ #include #include -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR -// Impelemented only for the linear Patlak Plot so far. -// In the future I should implement the KineticModels with the "linear" specification -// for patlak, logan etc... + // Impelemented only for the linear Patlak Plot so far. + // In the future I should implement the KineticModels with the "linear" specification + // for patlak, logan etc... PatlakPlot patlak_plot; - if (argc==4) - { - if (patlak_plot.parse(argv[3]) == false) - { - std::cerr << "Usage:" << argv[0] << " output_parametric_image input_dynamic_image [par_file] \n"; - return EXIT_FAILURE; - } + if (argc == 4) { + if (patlak_plot.parse(argv[3]) == false) { + std::cerr << "Usage:" << argv[0] << " output_parametric_image input_dynamic_image [par_file] \n"; + return EXIT_FAILURE; } - if (argc!=3 && argc!=4) + } + if (argc != 3 && argc != 4) return EXIT_FAILURE; - if (argc==3) + if (argc == 3) patlak_plot.ask_parameters(); - if (patlak_plot.set_up()==Succeeded::no) - return EXIT_FAILURE ; - else - { - shared_ptr - par_image_sptr(ParametricVoxelsOnCartesianGrid::read_from_file(argv[1])); - ParametricVoxelsOnCartesianGrid par_image = *par_image_sptr; - - shared_ptr - dyn_image_sptr(read_from_file(argv[2])); - const DynamicDiscretisedDensity & dyn_image= *dyn_image_sptr; - - //NotToDo: Assertion for the dyn-par images, sizes should not be ncessary ONLY WHEN I will create from dyn_image the par_image... - assert(patlak_plot.get_time_frame_definitions().get_num_frames()==dyn_image.get_time_frame_definitions().get_num_frames()); - patlak_plot.multiply_dynamic_image_with_model_gradient(par_image,dyn_image); - - // Writing image - std::cerr << "Writing parametric-image in '"<< argv[1] << "'\n"; - const Succeeded writing_succeeded=OutputFileFormat::default_sptr()-> - write_to_file(argv[1], par_image); - - if(writing_succeeded==Succeeded::yes) - return EXIT_SUCCESS ; - else - return EXIT_FAILURE ; - } + if (patlak_plot.set_up() == Succeeded::no) + return EXIT_FAILURE; + else { + shared_ptr par_image_sptr(ParametricVoxelsOnCartesianGrid::read_from_file(argv[1])); + ParametricVoxelsOnCartesianGrid par_image = *par_image_sptr; + + shared_ptr dyn_image_sptr(read_from_file(argv[2])); + const DynamicDiscretisedDensity& dyn_image = *dyn_image_sptr; + + // NotToDo: Assertion for the dyn-par images, sizes should not be ncessary ONLY WHEN I will create from dyn_image the + // par_image... + assert(patlak_plot.get_time_frame_definitions().get_num_frames() == dyn_image.get_time_frame_definitions().get_num_frames()); + patlak_plot.multiply_dynamic_image_with_model_gradient(par_image, dyn_image); + + // Writing image + std::cerr << "Writing parametric-image in '" << argv[1] << "'\n"; + const Succeeded writing_succeeded = + OutputFileFormat::default_sptr()->write_to_file(argv[1], par_image); + + if (writing_succeeded == Succeeded::yes) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; + } } - diff --git a/src/modelling_utilities/write_patlak_matrix.cxx b/src/modelling_utilities/write_patlak_matrix.cxx index ff5210c0f5..2f332ad93c 100644 --- a/src/modelling_utilities/write_patlak_matrix.cxx +++ b/src/modelling_utilities/write_patlak_matrix.cxx @@ -25,8 +25,8 @@ \par Usage: - \code - write_patlak_matrix [par_file] + \code + write_patlak_matrix [par_file] \endcode \note It writes it always to the text file: "model_matrix.out" of the working directory @@ -40,37 +40,32 @@ #include #include -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR -// Impelemented only for the linear Patlak Plot so far. -// In the future I should implement the KineticModels with the "linear" specification -// for patlak, logan etc... + // Impelemented only for the linear Patlak Plot so far. + // In the future I should implement the KineticModels with the "linear" specification + // for patlak, logan etc... PatlakPlot patlak_plot; - if (argc==2) - { - if (patlak_plot.parse(argv[1]) == false) - return EXIT_FAILURE; - } - else + if (argc == 2) { + if (patlak_plot.parse(argv[1]) == false) + return EXIT_FAILURE; + } else patlak_plot.ask_parameters(); - if (patlak_plot.set_up()==Succeeded::no) - { - std::cerr << "Usage:" << argv[0] << " [par_file] \n"; - return EXIT_FAILURE ; - } - else - { - // Writing model matrix - std::cerr << "Writing Patlak Model Matrix in file 'model_matrix.out'" << "\n"; - Succeeded writing_succeeded=(patlak_plot.get_model_matrix().write_to_file("model_matrix.out")); + if (patlak_plot.set_up() == Succeeded::no) { + std::cerr << "Usage:" << argv[0] << " [par_file] \n"; + return EXIT_FAILURE; + } else { + // Writing model matrix + std::cerr << "Writing Patlak Model Matrix in file 'model_matrix.out'" + << "\n"; + Succeeded writing_succeeded = (patlak_plot.get_model_matrix().write_to_file("model_matrix.out")); - if(writing_succeeded==Succeeded::yes) - return EXIT_SUCCESS ; - else - return EXIT_FAILURE ; - } + if (writing_succeeded == Succeeded::yes) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; + } } - diff --git a/src/numerics_buildblock/determinant.cxx b/src/numerics_buildblock/determinant.cxx index 7f3212754d..976d0e6969 100644 --- a/src/numerics_buildblock/determinant.cxx +++ b/src/numerics_buildblock/determinant.cxx @@ -19,9 +19,9 @@ /*! \file \ingroup numerics - + \brief Implementation of stir::determinant() function for matrices - + \author Kris Thielemans */ @@ -32,50 +32,38 @@ START_NAMESPACE_STIR -namespace detail -{ +namespace detail { - template - static elemT - determinant_size3(const Array<2,elemT>& m) - { - const int i0 = m.get_min_index(); - const int j0 = m[i0].get_min_index(); - return - m[i0+0][j0+0]*m[i0+1][j0+1]*m[i0+2][j0+2] + - m[i0+0][j0+1]*m[i0+1][j0+2]*m[i0+2][j0+0] + - m[i0+0][j0+2]*m[i0+1][j0+0]*m[i0+2][j0+1] - - m[i0+0][j0+2]*m[i0+1][j0+1]*m[i0+2][j0+0] - - m[i0+0][j0+1]*m[i0+1][j0+0]*m[i0+2][j0+2] - - m[i0+0][j0+0]*m[i0+1][j0+2]*m[i0+2][j0+1]; - } +template +static elemT +determinant_size3(const Array<2, elemT>& m) { + const int i0 = m.get_min_index(); + const int j0 = m[i0].get_min_index(); + return m[i0 + 0][j0 + 0] * m[i0 + 1][j0 + 1] * m[i0 + 2][j0 + 2] + m[i0 + 0][j0 + 1] * m[i0 + 1][j0 + 2] * m[i0 + 2][j0 + 0] + + m[i0 + 0][j0 + 2] * m[i0 + 1][j0 + 0] * m[i0 + 2][j0 + 1] - m[i0 + 0][j0 + 2] * m[i0 + 1][j0 + 1] * m[i0 + 2][j0 + 0] - + m[i0 + 0][j0 + 1] * m[i0 + 1][j0 + 0] * m[i0 + 2][j0 + 2] - m[i0 + 0][j0 + 0] * m[i0 + 1][j0 + 2] * m[i0 + 2][j0 + 1]; +} - template - static elemT - determinant_size2(const Array<2,elemT>& m) - { - const int i0 = m.get_min_index(); - const int j0 = m[i0].get_min_index(); - return - m[i0+0][j0+0]*m[i0+1][j0+1] - - m[i0+0][j0+2]*m[i0+1][j0+1]; - } +template +static elemT +determinant_size2(const Array<2, elemT>& m) { + const int i0 = m.get_min_index(); + const int j0 = m[i0].get_min_index(); + return m[i0 + 0][j0 + 0] * m[i0 + 1][j0 + 1] - m[i0 + 0][j0 + 2] * m[i0 + 1][j0 + 1]; +} - template - static elemT - determinant_size1(const Array<2,elemT>& m) - { - const int i0 = m.get_min_index(); - const int j0 = m[i0].get_min_index(); - return - m[i0][j0]; - } +template +static elemT +determinant_size1(const Array<2, elemT>& m) { + const int i0 = m.get_min_index(); + const int j0 = m[i0].get_min_index(); + return m[i0][j0]; } +} // namespace detail template elemT -determinant(const Array<2,elemT>& m) -{ +determinant(const Array<2, elemT>& m) { assert(m.is_regular()); if (m.size() == 1) return detail::determinant_size1(m); @@ -83,8 +71,7 @@ determinant(const Array<2,elemT>& m) return detail::determinant_size2(m); if (m.size() == 3) return detail::determinant_size3(m); - error("determinant called for size larger than 3. Code in file %s needs work", - __FILE__); + error("determinant called for size larger than 3. Code in file %s needs work", __FILE__); // return to avoid compiler warning return 0; } @@ -92,8 +79,8 @@ determinant(const Array<2,elemT>& m) // // instantiations // -template float determinant(const Array<2,float>&); -template double determinant(const Array<2,double>&); -template std::complex determinant(const Array<2,std::complex >&); -template std::complex determinant(const Array<2,std::complex >&); +template float determinant(const Array<2, float>&); +template double determinant(const Array<2, double>&); +template std::complex determinant(const Array<2, std::complex>&); +template std::complex determinant(const Array<2, std::complex>&); END_NAMESPACE_STIR diff --git a/src/numerics_buildblock/fourier.cxx b/src/numerics_buildblock/fourier.cxx index 4fe4e6927c..a5ce6b4b80 100644 --- a/src/numerics_buildblock/fourier.cxx +++ b/src/numerics_buildblock/fourier.cxx @@ -1,5 +1,5 @@ /*! - \file + \file \ingroup DFT \brief Functions for computing discrete fourier transforms @@ -28,17 +28,16 @@ #include "stir/array_index_functions.h" START_NAMESPACE_STIR - template -static void bitreversal(VectorWithOffset& data) -{ - const int n=data.get_length(); - int j=1; - for (int i=0;i i) { - std::swap(data[j/2],data[i]); +static void +bitreversal(VectorWithOffset& data) { + const int n = data.get_length(); + int j = 1; + for (int i = 0; i < n; ++i) { + if (j / 2 > i) { + std::swap(data[j / 2], data[i]); } - int m=n; + int m = n; while (m >= 2 && j > m) { j -= m; m >>= 1; @@ -51,38 +50,37 @@ static void bitreversal(VectorWithOffset& data) call of the Fourier functions, and then stored in static arrays. */ // exparray[k][i] = exp(i*_PI/pow(2,k)) -typedef VectorWithOffset > > exparray_t; -static exparray_t exparray; +typedef VectorWithOffset>> exparray_t; +static exparray_t exparray; -static void init_exparray(const int k, const int pow2k) -{ - if (exparray.get_max_index() >= k && exparray[k].size()>0) +static void +init_exparray(const int k, const int pow2k) { + if (exparray.get_max_index() >= k && exparray[k].size() > 0) return; - if (exparray.get_max_index() (0, static_cast((i*_PI)/pow2k))); + exparray[k].grow(0, pow2k - 1); + for (int i = 0; i < pow2k; ++i) + exparray[k][i] = std::exp(std::complex(0, static_cast((i * _PI) / pow2k))); } // expminarray[k][i] = exp(-i*_PI/pow(2,k)) // obviously just the complex conjugate of exparray -static exparray_t expminarray; +static exparray_t expminarray; -static void init_expminarray(const int k, const int pow2k) -{ - if (expminarray.get_max_index() >= k && expminarray[k].size()>0) +static void +init_expminarray(const int k, const int pow2k) { + if (expminarray.get_max_index() >= k && expminarray[k].size() > 0) return; - if (expminarray.get_max_index() (0, static_cast(-(i*_PI)/pow2k))); + expminarray[k].grow(0, pow2k - 1); + for (int i = 0; i < pow2k; ++i) + expminarray[k][i] = std::exp(std::complex(0, static_cast(-(i * _PI) / pow2k))); } - /* First we define 1D fourier transforms of vectors with almost arbitrary element types. This is almost a straightforward 1D FFT implementation. The only tricky bit @@ -91,47 +89,45 @@ static void init_expminarray(const int k, const int pow2k) */ template -void fourier_1d(T& c, const int sign) -{ - if (c.size()==0) return; - assert(c.get_min_index()==0); - assert(sign==1 || sign ==-1); +void +fourier_1d(T& c, const int sign) { + if (c.size() == 0) + return; + assert(c.get_min_index() == 0); + assert(sign == 1 || sign == -1); bitreversal(c); // find 'nn' which is such that length==2^nn - const int nn=round(log(static_cast(c.size()))/log(2.)); - if (c.get_length()!= round(pow(2.,nn))) - error ("fourier_1d called with array length %d which is not 2^%d\n", c.size(), nn); - - int k=0; - int pow2k = 1; // will be updated to be round(pow(2,k)) - const int pow2nn=c.get_length(); // ==round(pow(2,nn)); - for (; k(c.size())) / log(2.)); + if (c.get_length() != round(pow(2., nn))) + error("fourier_1d called with array length %d which is not 2^%d\n", c.size(), nn); + + int k = 0; + int pow2k = 1; // will be updated to be round(pow(2,k)) + const int pow2nn = c.get_length(); // ==round(pow(2,nn)); + for (; k < nn; ++k, pow2k *= 2) { + if (sign == 1) + init_exparray(k, pow2k); else - init_expminarray(k,pow2k); - const exparray_t& cur_exparray = - sign==1? exparray : expminarray; - for (int j=0; j< pow2nn;j+= pow2k*2) - for (int i=0; i< pow2k; ++i) - { - typename T::reference c1= c[i + j]; - typename T::reference c2= c[i + j + pow2k]; - - typename T::value_type const t1 = c1; - /* here is what we have to do: - typename T::value_type const t2 = + init_expminarray(k, pow2k); + const exparray_t& cur_exparray = sign == 1 ? exparray : expminarray; + for (int j = 0; j < pow2nn; j += pow2k * 2) + for (int i = 0; i < pow2k; ++i) { + typename T::reference c1 = c[i + j]; + typename T::reference c2 = c[i + j + pow2k]; + + typename T::value_type const t1 = c1; + /* here is what we have to do: + typename T::value_type const t2 = c2*cur_exparray[k][i]; c1 = t1+t2; c2 = t1-t2; - however, this would create an unnecessary copy of t2, which is - potentially large. - So, we rewrite it without t2, and using operations that also - work when using multi-dim arrays. - Note that for multi-dimensional arrays, this code involves 4 - loops over the same data. - Using expression templates would speed this up. - */ + however, this would create an unnecessary copy of t2, which is + potentially large. + So, we rewrite it without t2, and using operations that also + work when using multi-dim arrays. + Note that for multi-dimensional arrays, this code involves 4 + loops over the same data. + Using expression templates would speed this up. + */ c2 *= cur_exparray[k][i]; c1 += c2; c2 *= -1; @@ -148,16 +144,11 @@ namespace detail { more powerful than function overloading. */ template -struct fourier_auxiliary -{ - static void - do_fourier(VectorWithOffset& c, const int sign) - { +struct fourier_auxiliary { + static void do_fourier(VectorWithOffset& c, const int sign) { fourier_1d(c, sign); const typename VectorWithOffset::iterator iter_end = c.end(); - for (typename VectorWithOffset::iterator iter = c.begin(); - iter != iter_end; - ++iter) + for (typename VectorWithOffset::iterator iter = c.begin(); iter != iter_end; ++iter) fourier(*iter, sign); } }; @@ -166,35 +157,19 @@ struct fourier_auxiliary #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template -struct fourier_auxiliary > -{ - static void - do_fourier(VectorWithOffset >& c, const int sign) - { - fourier_1d(c, sign); - } +struct fourier_auxiliary> { + static void do_fourier(VectorWithOffset>& c, const int sign) { fourier_1d(c, sign); } }; - -#else //no partial template specialisation +#else // no partial template specialisation // we just list float and double explicitly -struct fourier_auxiliary > -{ - static void - do_fourier(VectorWithOffset >& c, const int sign) - { - fourier_1d(c, sign); - } +struct fourier_auxiliary> { + static void do_fourier(VectorWithOffset>& c, const int sign) { fourier_1d(c, sign); } }; -struct fourier_auxiliary > -{ - static void - do_fourier(VectorWithOffset >& c, const int sign) - { - fourier_1d(c, sign); - } +struct fourier_auxiliary> { + static void do_fourier(VectorWithOffset>& c, const int sign) { fourier_1d(c, sign); } }; #endif @@ -202,90 +177,82 @@ struct fourier_auxiliary > // now the fourier function is easy to define in terms of the class above template -void -fourier(T& c, const int sign) -{ -#if !defined(_MSC_VER) || _MSC_VER>1200 - detail::fourier_auxiliary::do_fourier(c,sign); +void +fourier(T& c, const int sign) { +#if !defined(_MSC_VER) || _MSC_VER > 1200 + detail::fourier_auxiliary::do_fourier(c, sign); #else - detail::fourier_auxiliary::do_fourier(c,sign); + detail::fourier_auxiliary::do_fourier(c, sign); #endif } - /****************************************************************** DFT of real data *****************************************************************/ - - template -Array<1,std::complex > -fourier_1d_for_real_data(const Array<1,T>& v, const int sign) -//Array<1,std::complex > -//fourier_1d_for_real_data(const T& v, const int sign) +Array<1, std::complex> +fourier_1d_for_real_data(const Array<1, T>& v, const int sign) +// Array<1,std::complex > +// fourier_1d_for_real_data(const T& v, const int sign) { - //typedef std::complex complex_t; + // typedef std::complex complex_t; typedef std::complex complex_t; - if (v.size()==0) return Array<1,complex_t>(); - assert(v.get_min_index()==0); - assert(sign==1 || sign ==-1); - if (v.size()%2!=0) + if (v.size() == 0) + return Array<1, complex_t>(); + assert(v.get_min_index() == 0); + assert(sign == 1 || sign == -1); + if (v.size() % 2 != 0) error("fourier_1d_of_real can only handle arrays of even length.\n"); - Array<1,complex_t> c; - const unsigned int n = static_cast(v.size()/2); - // we reserve a range of 0,n here, such that + Array<1, complex_t> c; + const unsigned int n = static_cast(v.size() / 2); + // we reserve a range of 0,n here, such that // resize(n) later doesn't reallocate and copy - c.reserve(n+1); + c.reserve(n + 1); c.resize(n); // fill in complex numbers. // note: we need to divide by 2 in the final result. To save // some time, we do that already here. - for (int i=0; i(sign*(i*_PI)/n-_PI/2)))* - (c[i]-std::conj(c[n-i])); - - c[i] = (t1 + t2); - c[n-i] = std::conj(t1-t2); - } + // cout << "C: " << c; + c.resize(n + 1); + for (unsigned int i = 1; i <= n / 2; ++i) { + const complex_t t1 = (c[i] + std::conj(c[n - i])); + // TODO could get exp() from static exparray + // the nice thing about this code that it works even when the length is not a power of 2 + // (but of course, the call to fourier_1d would currently abort in that case) + const complex_t t2 = std::exp(complex_t(0, static_cast(sign * (i * _PI) / n - _PI / 2))) * (c[i] - std::conj(c[n - i])); + + c[i] = (t1 + t2); + c[n - i] = std::conj(t1 - t2); + } { const complex_t c0_copy = c[0]; - c[0]=(c0_copy.real() + c0_copy.imag())*2; - c[n]=(c0_copy.real() - c0_copy.imag())*2; + c[0] = (c0_copy.real() + c0_copy.imag()) * 2; + c[n] = (c0_copy.real() - c0_copy.imag()) * 2; } return c; } - template -Array<1,T> -inverse_fourier_1d_for_real_data_corrupting_input(Array<1,std::complex >& c, const int sign) -{ +Array<1, T> +inverse_fourier_1d_for_real_data_corrupting_input(Array<1, std::complex>& c, const int sign) { typedef std::complex complex_t; - if (c.size()==0) return Array<1,T>(); - assert(c.get_min_index()==0); - assert(sign==1 || sign ==-1); - const int n = c.get_length()-1; - if (n%2!=0) + if (c.size() == 0) + return Array<1, T>(); + assert(c.get_min_index() == 0); + assert(sign == 1 || sign == -1); + const int n = c.get_length() - 1; + if (n % 2 != 0) error("inverse_fourier_1d_of_real_data can only handle arrays of even length.\n"); /* Problematic asserts to check that the imaginary part of c[0] and c[n] is 0 - Trouble is that it could be only approximately 0 (e.g. when calling + Trouble is that it could be only approximately 0 (e.g. when calling inverse_fourier_real_data on multi-dimensional arrays). The version below tries to circumvent this problem by comparing with the norm of c. That fails however when c is zero (up to numerical precision). @@ -293,48 +260,38 @@ inverse_fourier_1d_for_real_data_corrupting_input(Array<1,std::complex >& c, we don't have that one to our disposal in this function. So, I disabled the asserts. */ - //assert(fabs(c[0].imag())<=.001*norm(c.begin_all(),c.end_all())/sqrt(n+1.)); // note divide by n+1 to avoid division by 0 - //assert(fabs(c[n].imag())<=.001*norm(c.begin_all(),c.end_all())/sqrt(n+1.)); - for (int i=1; i<=n/2; ++i) - { - const complex_t t1 = (c[i]+std::conj(c[n-i])); - // TODO could get exp() from static exparray - const complex_t t2 = - std::exp(complex_t(0, static_cast(-sign*(i*_PI)/n+_PI/2)))* - (c[i]-std::conj(c[n-i])); - - c[i] = (t1 + t2); - c[n-i] = std::conj(t1-t2); - } - { - c[0]=complex_t((c[0].real() + c[n].real()), - (c[0].real() - c[n].real()) - ); + // assert(fabs(c[0].imag())<=.001*norm(c.begin_all(),c.end_all())/sqrt(n+1.)); // note divide by n+1 to avoid division by 0 + // assert(fabs(c[n].imag())<=.001*norm(c.begin_all(),c.end_all())/sqrt(n+1.)); + for (int i = 1; i <= n / 2; ++i) { + const complex_t t1 = (c[i] + std::conj(c[n - i])); + // TODO could get exp() from static exparray + const complex_t t2 = std::exp(complex_t(0, static_cast(-sign * (i * _PI) / n + _PI / 2))) * (c[i] - std::conj(c[n - i])); + + c[i] = (t1 + t2); + c[n - i] = std::conj(t1 - t2); } + { c[0] = complex_t((c[0].real() + c[n].real()), (c[0].real() - c[n].real())); } - // now get rid of c[n] + // now get rid of c[n] c.resize(n); - //cout << "\nC: " << c/4; + // cout << "\nC: " << c/4; inverse_fourier(c, sign); // extract real numbers. - Array<1,T> v(2*n); - for (int i=0; i v(2 * n); + for (int i = 0; i < n; ++i) { + v[2 * i] = c[i].real() / 2; + v[2 * i + 1] = c[i].imag() / 2; + } return v; } template -Array<1,T> -inverse_fourier_1d_for_real_data(const Array<1,std::complex >& c, const int sign) -{ - Array<1,std::complex > tmp(c); +Array<1, T> +inverse_fourier_1d_for_real_data(const Array<1, std::complex>& c, const int sign) { + Array<1, std::complex> tmp(c); return inverse_fourier_1d_for_real_data_corrupting_input(tmp, sign); } - // multi-dimensional case namespace detail { @@ -344,40 +301,37 @@ namespace detail { more powerful than function overloading. */ template -struct fourier_for_real_data_auxiliary -{ - static Array > - do_fourier_for_real_data(const Array& c, const int sign) - { +struct fourier_for_real_data_auxiliary { + static Array> do_fourier_for_real_data(const Array& c, + const int sign) { // complicated business to get index range which is as follows: // outer_dimension = outer_dimension of c // all other dimensions are as small as possible (to avoid reallocations) BasicCoordinate min_index, max_index; - for (int d=2; d<=num_dimensions; ++d) + for (int d = 2; d <= num_dimensions; ++d) min_index[d] = max_index[d] = 0; min_index[1] = c.get_min_index(); max_index[1] = c.get_max_index(); - Array > array(IndexRange(min_index, max_index)); - for (int i=c.get_min_index(); i<=c.get_max_index(); ++i) + Array> array(IndexRange(min_index, max_index)); + for (int i = c.get_min_index(); i <= c.get_max_index(); ++i) array[i] = fourier_for_real_data(c[i], sign); fourier_1d(array, sign); return array; } - static Array - do_inverse_fourier_for_real_data_corrupting_input(Array >& c, const int sign) - { + static Array + do_inverse_fourier_for_real_data_corrupting_input(Array>& c, const int sign) { inverse_fourier_1d(c, sign); // complicated business to get index range which is as follows: // outer_dimension = outer_dimension of c // all other dimensions are as small as possible (to avoid reallocations) BasicCoordinate min_index, max_index; - for (int d=2; d<=num_dimensions; ++d) + for (int d = 2; d <= num_dimensions; ++d) min_index[d] = max_index[d] = 0; min_index[1] = c.get_min_index(); max_index[1] = c.get_max_index(); Array array(IndexRange(min_index, max_index)); - for (int i=c.get_min_index(); i<=c.get_max_index(); ++i) + for (int i = c.get_min_index(); i <= c.get_max_index(); ++i) array[i] = inverse_fourier_for_real_data_corrupting_input(c[i], sign); return array; } @@ -387,44 +341,29 @@ struct fourier_for_real_data_auxiliary #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template -struct fourier_for_real_data_auxiliary<1,elemT> -{ - static Array<1,std::complex > - do_fourier_for_real_data(const Array<1,elemT>& c, const int sign) - { - return - fourier_1d_for_real_data(c, sign); +struct fourier_for_real_data_auxiliary<1, elemT> { + static Array<1, std::complex> do_fourier_for_real_data(const Array<1, elemT>& c, const int sign) { + return fourier_1d_for_real_data(c, sign); } - static Array<1,elemT> - do_inverse_fourier_for_real_data_corrupting_input(Array<1,std::complex >& c, const int sign) - { - return - inverse_fourier_1d_for_real_data_corrupting_input(c, sign); + static Array<1, elemT> do_inverse_fourier_for_real_data_corrupting_input(Array<1, std::complex>& c, const int sign) { + return inverse_fourier_1d_for_real_data_corrupting_input(c, sign); } }; - -#else //no partial template specialisation +#else // no partial template specialisation // we just list float explicitly -struct fourier_for_real_data_auxiliary<1,float> -{ - static Array<1,std::complex > - do_fourier_for_real_data(const Array<1,float>& c, const int sign) - { - return - fourier_1d_for_real_data(c, sign); +struct fourier_for_real_data_auxiliary<1, float> { + static Array<1, std::complex> do_fourier_for_real_data(const Array<1, float>& c, const int sign) { + return fourier_1d_for_real_data(c, sign); } - static Array<1,float> - do_inverse_fourier_for_real_data_corrupting_input(Array<1,std::complex >& c, const int sign) - { - return - inverse_fourier_1d_for_real_data_corrupting_input(c, sign); + static Array<1, float> do_inverse_fourier_for_real_data_corrupting_input(Array<1, std::complex>& c, const int sign) { + return inverse_fourier_1d_for_real_data_corrupting_input(c, sign); } }; -#if 0 +# if 0 /* Disabled double for now. If you want to use double, you will probably have to make sure that Array<1,std::complex > is instantiated. @@ -445,108 +384,77 @@ struct fourier_for_real_data_auxiliary<1,double> inverse_fourier_1d_for_real_data_corrupting_input(c, sign); } }; -#endif // end of double +# endif // end of double #endif // end of BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION } // end of namespace detail - // now the fourier_for_real_data function is easy to define in terms of the class above template -Array > -fourier_for_real_data(const Array& c, const int sign) -{ - return - detail::fourier_for_real_data_auxiliary:: - do_fourier_for_real_data(c,sign); +Array> +fourier_for_real_data(const Array& c, const int sign) { + return detail::fourier_for_real_data_auxiliary::do_fourier_for_real_data(c, sign); } - template -Array -inverse_fourier_for_real_data_corrupting_input(Array >& c, const int sign) -{ - return - detail::fourier_for_real_data_auxiliary:: - do_inverse_fourier_for_real_data_corrupting_input(c,sign); +Array +inverse_fourier_for_real_data_corrupting_input(Array>& c, const int sign) { + return detail::fourier_for_real_data_auxiliary::do_inverse_fourier_for_real_data_corrupting_input(c, sign); } template -Array -inverse_fourier_for_real_data(const Array >& c, const int sign) -{ - Array > tmp(c); +Array +inverse_fourier_for_real_data(const Array>& c, const int sign) { + Array> tmp(c); return inverse_fourier_for_real_data_corrupting_input(tmp, sign); } template -Array > -pos_frequencies_to_all(const Array >& c) -{ +Array> +pos_frequencies_to_all(const Array>& c) { assert(c.is_regular()); BasicCoordinate min_index, max_index; c.get_regular_range(min_index, max_index); // check min_indices are 0 - assert(min_index == (min_index*0)); - max_index[num_dimensions]=max_index[num_dimensions]*2-1; - Array > result(IndexRange(min_index, max_index)); - + assert(min_index == (min_index * 0)); + max_index[num_dimensions] = max_index[num_dimensions] * 2 - 1; + Array> result(IndexRange(min_index, max_index)); + BasicCoordinate index = min_index; - const BasicCoordinate sizes = max_index+1; - do - { - result[index] = c[index]; - if (index[num_dimensions]>0) - { - const BasicCoordinate related_index = - modulo(sizes-index, sizes); - result[related_index] = std::conj(c[index]); - } + const BasicCoordinate sizes = max_index + 1; + do { + result[index] = c[index]; + if (index[num_dimensions] > 0) { + const BasicCoordinate related_index = modulo(sizes - index, sizes); + result[related_index] = std::conj(c[index]); } - while(next(index, c)); + } while (next(index, c)); return result; } - /***************************************************************** * INSTANTIATIONS * add any you need ******************************************************************/ -template -void -fourier<>(Array<3,std::complex >& c, const int sign); +template void fourier<>(Array<3, std::complex>& c, const int sign); -template -void -fourier<>(Array<2,std::complex >& c, const int sign); +template void fourier<>(Array<2, std::complex>& c, const int sign); -template -void -fourier<>(Array<1,std::complex >& c, const int sign); - -template -void -fourier<>(VectorWithOffset >& c, const int sign); - -#define INSTANTIATE(d,type) \ - template \ - Array > \ - fourier_for_real_data<>(const Array& v, const int sign); \ - template \ - Array \ - inverse_fourier_for_real_data_corrupting_input<>(Array >& c, const int sign); \ - template \ - Array \ - inverse_fourier_for_real_data<>(const Array >& c, const int sign); \ - template \ - Array > \ - pos_frequencies_to_all<>(const Array >& c); - -INSTANTIATE(1,float); -INSTANTIATE(2,float); -INSTANTIATE(3,float); +template void fourier<>(Array<1, std::complex>& c, const int sign); + +template void fourier<>(VectorWithOffset>& c, const int sign); + +#define INSTANTIATE(d, type) \ + template Array> fourier_for_real_data<>(const Array& v, const int sign); \ + template Array inverse_fourier_for_real_data_corrupting_input<>(Array> & c, const int sign); \ + template Array inverse_fourier_for_real_data<>(const Array>& c, const int sign); \ + template Array> pos_frequencies_to_all<>(const Array>& c); + +INSTANTIATE(1, float); +INSTANTIATE(2, float); +INSTANTIATE(3, float); #undef INSTANTIATE END_NAMESPACE_STIR diff --git a/src/recon_buildblock/AnalyticReconstruction.cxx b/src/recon_buildblock/AnalyticReconstruction.cxx index a5d4e50594..264d89cdce 100644 --- a/src/recon_buildblock/AnalyticReconstruction.cxx +++ b/src/recon_buildblock/AnalyticReconstruction.cxx @@ -1,33 +1,33 @@ /* Copyright (C) 2000 PARAPET partners - Copyright (C) 2000 - 2006, Hammersmith Imanet Ltd + Copyright (C) 2000 - 2006, Hammersmith Imanet Ltd Copyright (C) 2016, 2018 - 2020 University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! \file \ingroup recon_buildblock - - \brief implementation of the stir::AnalyticReconstruction class - + + \brief implementation of the stir::AnalyticReconstruction class + \author Kris Thielemans \author Matthew Jacobson \author Nikos Efthimiou \author PARAPET project - + */ #include "stir/recon_buildblock/AnalyticReconstruction.h" @@ -40,35 +40,29 @@ START_NAMESPACE_STIR - - // parameters -void -AnalyticReconstruction::set_defaults() -{ +void +AnalyticReconstruction::set_defaults() { base_type::set_defaults(); - input_filename=""; - max_segment_num_to_process=-1; - proj_data_ptr.reset(); + input_filename = ""; + max_segment_num_to_process = -1; + proj_data_ptr.reset(); target_parameter_parser.set_defaults(); } - -void -AnalyticReconstruction::initialise_keymap() -{ +void +AnalyticReconstruction::initialise_keymap() { base_type::initialise_keymap(); - parser.add_key("input file",&input_filename); + parser.add_key("input file", &input_filename); // KT 20/06/2001 disabled - //parser.add_key("mash x views", &num_views_to_add); + // parser.add_key("mash x views", &num_views_to_add); parser.add_key("maximum absolute segment number to process", &max_segment_num_to_process); this->target_parameter_parser.add_to_keymap(parser); -// parser.add_key("END", &KeyParser::stop_parsing); - + // parser.add_key("END", &KeyParser::stop_parsing); } #if 0 @@ -90,7 +84,7 @@ void AnalyticReconstruction::ask_parameters() max_segment_num_to_process= ask_num("Maximum absolute segment number to process: ", 0, proj_data_ptr->get_max_segment_num(), 0); -#if 0 +# if 0 // The angular compression consists of an average pairs of sinograms rows // in order to reduce the number of views by a factor of 2 // and therefore reduce the amount of data in a sinogram as well @@ -101,7 +95,7 @@ void AnalyticReconstruction::ask_parameters() // to have little effect near the center of the FOV. // However, it could cause loss of precision num_views_to_add= ask_num("Mashing views ? (1: No mashing, 2: By 2 , 4: By 4) : ",1,4,1); -#endif +# endif ask_filename_with_extension(output_filename_prefix_char,"Output filename prefix", ""); @@ -110,67 +104,54 @@ void AnalyticReconstruction::ask_parameters() } #endif // ask_parameters disabled - -bool AnalyticReconstruction::post_processing() -{ - if (base_type::post_processing()) - return true; - if (input_filename.length() == 0) - { warning("You need to specify an input file\n"); return true; } +bool +AnalyticReconstruction::post_processing() { + if (base_type::post_processing()) + return true; + if (input_filename.length() == 0) { + warning("You need to specify an input file\n"); + return true; + } // KT 20/06/2001 disabled as not functional yet #if 0 if (num_views_to_add!=1 && (num_views_to_add<=0 || num_views_to_add%2 != 0)) { warning("The 'mash x views' key has an invalid value (must be 1 or even number)\n"); return true; } #endif - - proj_data_ptr= ProjData::read_from_file(input_filename); + + proj_data_ptr = ProjData::read_from_file(input_filename); target_parameter_parser.check_values(); return false; } - //************* other functions ************* -DiscretisedDensity<3,float>* -AnalyticReconstruction:: -construct_target_image_ptr() const -{ - return - this->target_parameter_parser.create(this->get_input_data()); +DiscretisedDensity<3, float>* +AnalyticReconstruction::construct_target_image_ptr() const { + return this->target_parameter_parser.create(this->get_input_data()); } - - -Succeeded -AnalyticReconstruction:: -reconstruct() -{ +Succeeded +AnalyticReconstruction::reconstruct() { this->start_timers(); this->target_data_sptr.reset(this->construct_target_image_ptr()); - if (this->set_up(this->target_data_sptr) == Succeeded::no) - { - this->stop_timers(); - return Succeeded::no; - } + if (this->set_up(this->target_data_sptr) == Succeeded::no) { + this->stop_timers(); + return Succeeded::no; + } this->stop_timers(); const Succeeded success = this->reconstruct(this->target_data_sptr); - if (success == Succeeded::yes && !_disable_output) - { - this->output_file_format_ptr-> - write_to_file(this->output_filename_prefix, *this->target_data_sptr); + if (success == Succeeded::yes && !_disable_output) { + this->output_file_format_ptr->write_to_file(this->output_filename_prefix, *this->target_data_sptr); } return success; } - -Succeeded -AnalyticReconstruction:: -reconstruct(shared_ptr const& target_image_sptr) -{ +Succeeded +AnalyticReconstruction::reconstruct(shared_ptr const& target_image_sptr) { this->check(*target_data_sptr); #if 0 Succeeded success = this->set_up(target_image_sptr); @@ -179,32 +160,27 @@ reconstruct(shared_ptr const& target_image_sptr) #endif this->start_timers(); Succeeded success = this->actual_reconstruct(target_image_sptr); - if (success == Succeeded::yes) - { - if(!is_null_ptr(this->post_filter_sptr)) - { - info("Applying post-filter"); - this->post_filter_sptr->apply(*target_image_sptr); - - info(boost::format(" min and max after post-filtering %1% %2%") % target_image_sptr->find_min() % target_image_sptr->find_max()); - } + if (success == Succeeded::yes) { + if (!is_null_ptr(this->post_filter_sptr)) { + info("Applying post-filter"); + this->post_filter_sptr->apply(*target_image_sptr); + + info(boost::format(" min and max after post-filtering %1% %2%") % target_image_sptr->find_min() % + target_image_sptr->find_max()); + } } this->stop_timers(); return success; } void -AnalyticReconstruction:: -set_input_data(const shared_ptr &arg) -{ +AnalyticReconstruction::set_input_data(const shared_ptr& arg) { _already_set_up = false; - this->proj_data_ptr = dynamic_pointer_cast < ProjData >(arg); + this->proj_data_ptr = dynamic_pointer_cast(arg); } const ProjData& -AnalyticReconstruction:: -get_input_data() const -{ +AnalyticReconstruction::get_input_data() const { if (is_null_ptr(this->proj_data_ptr)) error("calling get_input_data but it hasn't been set yet"); return *this->proj_data_ptr; @@ -212,69 +188,58 @@ get_input_data() const // forwarding functions for ParseDiscretisedDensityParameters int -AnalyticReconstruction:: -get_output_image_size_xy() const -{ return target_parameter_parser.get_output_image_size_xy(); } +AnalyticReconstruction::get_output_image_size_xy() const { + return target_parameter_parser.get_output_image_size_xy(); +} void -AnalyticReconstruction:: -set_output_image_size_xy(int v) -{ +AnalyticReconstruction::set_output_image_size_xy(int v) { _already_set_up = false; target_parameter_parser.set_output_image_size_xy(v); } int -AnalyticReconstruction:: -get_output_image_size_z() const -{ return target_parameter_parser.get_output_image_size_z(); } +AnalyticReconstruction::get_output_image_size_z() const { + return target_parameter_parser.get_output_image_size_z(); +} void -AnalyticReconstruction:: -set_output_image_size_z(int v) -{ +AnalyticReconstruction::set_output_image_size_z(int v) { _already_set_up = false; target_parameter_parser.set_output_image_size_z(v); } float -AnalyticReconstruction:: -get_zoom_xy() const -{ return target_parameter_parser.get_zoom_xy(); } +AnalyticReconstruction::get_zoom_xy() const { + return target_parameter_parser.get_zoom_xy(); +} void -AnalyticReconstruction:: -set_zoom_xy(float v) -{ +AnalyticReconstruction::set_zoom_xy(float v) { _already_set_up = false; target_parameter_parser.set_zoom_xy(v); } float -AnalyticReconstruction:: -get_zoom_z() const -{ return target_parameter_parser.get_zoom_z(); } +AnalyticReconstruction::get_zoom_z() const { + return target_parameter_parser.get_zoom_z(); +} void -AnalyticReconstruction:: -set_zoom_z(float v) -{ +AnalyticReconstruction::set_zoom_z(float v) { _already_set_up = false; target_parameter_parser.set_zoom_z(v); } const CartesianCoordinate3D& -AnalyticReconstruction:: -get_offset() const -{ return target_parameter_parser.get_offset(); } +AnalyticReconstruction::get_offset() const { + return target_parameter_parser.get_offset(); +} void -AnalyticReconstruction:: -set_offset(const CartesianCoordinate3D& v) -{ +AnalyticReconstruction::set_offset(const CartesianCoordinate3D& v) { _already_set_up = false; target_parameter_parser.set_offset(v); } END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/BackProjectorByBin.cxx b/src/recon_buildblock/BackProjectorByBin.cxx index 2a228b80f8..9fdc6fddd5 100644 --- a/src/recon_buildblock/BackProjectorByBin.cxx +++ b/src/recon_buildblock/BackProjectorByBin.cxx @@ -9,7 +9,7 @@ \author Kris Thielemans \author PARAPET project \author Richard Brown - + */ /* Copyright (C) 2000 PARAPET partners @@ -30,7 +30,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/BackProjectorByBin.h" #include "stir/recon_buildblock/find_basic_vs_nums_in_subsets.h" #include "stir/RelatedViewgrams.h" @@ -41,120 +40,91 @@ #include "stir/DataProcessor.h" #include #ifdef STIR_OPENMP -#include "stir/is_null_ptr.h" -#include "stir/DiscretisedDensity.h" -#include +# include "stir/is_null_ptr.h" +# include "stir/DiscretisedDensity.h" +# include #endif #include START_NAMESPACE_STIR -BackProjectorByBin::BackProjectorByBin() - : _already_set_up(false) -{ - set_defaults(); -} +BackProjectorByBin::BackProjectorByBin() : _already_set_up(false) { set_defaults(); } -BackProjectorByBin::~BackProjectorByBin() -{ -} +BackProjectorByBin::~BackProjectorByBin() {} void -BackProjectorByBin:: -set_defaults() -{ +BackProjectorByBin::set_defaults() { _post_data_processor_sptr.reset(); } void -BackProjectorByBin:: -initialise_keymap() -{ +BackProjectorByBin::initialise_keymap() { parser.add_start_key("Back Projector Parameters"); parser.add_stop_key("End Back Projector Parameters"); parser.add_parsing_key("post data processor", &_post_data_processor_sptr); } void -BackProjectorByBin:: -set_up(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_info_sptr) -{ +BackProjectorByBin::set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& density_info_sptr) { _already_set_up = true; _proj_data_info_sptr = proj_data_info_sptr->create_shared_clone(); _density_sptr.reset(density_info_sptr->clone()); #ifdef STIR_OPENMP -#pragma omp parallel - { -#pragma omp single - _local_output_image_sptrs.resize(omp_get_num_threads(), shared_ptr >()); - } - for (int i=0; i(_local_output_image_sptrs.size()); ++i) - if(!is_null_ptr(_local_output_image_sptrs[i])) // already created in previous run - if (!_local_output_image_sptrs[i]->has_same_characteristics(*density_info_sptr)) - { - // previous run was with different sizes, so reallocate - _local_output_image_sptrs[i].reset(density_info_sptr->get_empty_copy()); - } +# pragma omp parallel + { +# pragma omp single + _local_output_image_sptrs.resize(omp_get_num_threads(), shared_ptr>()); + } + for (int i = 0; i < static_cast(_local_output_image_sptrs.size()); ++i) + if (!is_null_ptr(_local_output_image_sptrs[i])) // already created in previous run + if (!_local_output_image_sptrs[i]->has_same_characteristics(*density_info_sptr)) { + // previous run was with different sizes, so reallocate + _local_output_image_sptrs[i].reset(density_info_sptr->get_empty_copy()); + } #endif } void -BackProjectorByBin:: -check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3,float>& density_info) const -{ +BackProjectorByBin::check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3, float>& density_info) const { if (!this->_already_set_up) error("BackProjectorByBin method called without calling set_up first."); if (!(*this->_proj_data_info_sptr >= proj_data_info)) - error(boost::format("BackProjectorByBin set-up with different geometry for projection data.\nSet_up was with\n%1%\nCalled with\n%2%") - % this->_proj_data_info_sptr->parameter_info() % proj_data_info.parameter_info()); - if (! this->_density_sptr->has_same_characteristics(density_info)) + error(boost::format( + "BackProjectorByBin set-up with different geometry for projection data.\nSet_up was with\n%1%\nCalled with\n%2%") % + this->_proj_data_info_sptr->parameter_info() % proj_data_info.parameter_info()); + if (!this->_density_sptr->has_same_characteristics(density_info)) error("BackProjectorByBin set-up with different geometry for density or volume data."); } void -BackProjectorByBin::back_project(DiscretisedDensity<3,float>& image, -const ProjData& proj_data, int subset_num, int num_subsets) -{ +BackProjectorByBin::back_project(DiscretisedDensity<3, float>& image, const ProjData& proj_data, int subset_num, + int num_subsets) { start_accumulating_in_new_target(); back_project(proj_data, subset_num, num_subsets); get_output(image); } #ifdef STIR_PROJECTORS_AS_V3 void -BackProjectorByBin::back_project( DiscretisedDensity<3,float>& image, - const RelatedViewgrams& viewgrams) -{ - back_project(image,viewgrams, - viewgrams.get_min_axial_pos_num(), - viewgrams.get_max_axial_pos_num(), - viewgrams.get_min_tangential_pos_num(), - viewgrams.get_max_tangential_pos_num()); +BackProjectorByBin::back_project(DiscretisedDensity<3, float>& image, const RelatedViewgrams& viewgrams) { + back_project(image, viewgrams, viewgrams.get_min_axial_pos_num(), viewgrams.get_max_axial_pos_num(), + viewgrams.get_min_tangential_pos_num(), viewgrams.get_max_tangential_pos_num()); } -void BackProjectorByBin::back_project - (DiscretisedDensity<3,float>& image, - const RelatedViewgrams& viewgrams, - const int min_axial_pos_num, - const int max_axial_pos_num) -{ - back_project(image,viewgrams, - min_axial_pos_num, - max_axial_pos_num, - viewgrams.get_min_tangential_pos_num(), - viewgrams.get_max_tangential_pos_num()); +void +BackProjectorByBin::back_project(DiscretisedDensity<3, float>& image, const RelatedViewgrams& viewgrams, + const int min_axial_pos_num, const int max_axial_pos_num) { + back_project(image, viewgrams, min_axial_pos_num, max_axial_pos_num, viewgrams.get_min_tangential_pos_num(), + viewgrams.get_max_tangential_pos_num()); } void -BackProjectorByBin:: -back_project(DiscretisedDensity<3,float>& density, - const RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - if (viewgrams.get_num_viewgrams()==0) +BackProjectorByBin::back_project(DiscretisedDensity<3, float>& density, const RelatedViewgrams& viewgrams, + const int min_axial_pos_num, const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { + if (viewgrams.get_num_viewgrams() == 0) return; check(*viewgrams.get_proj_data_info_sptr(), density); @@ -165,111 +135,92 @@ back_project(DiscretisedDensity<3,float>& density, { const ViewSegmentNumbers basic_vs = viewgrams.get_basic_view_segment_num(); - if (get_symmetries_used()->num_related_view_segment_numbers(basic_vs) != - viewgrams.get_num_viewgrams()) + if (get_symmetries_used()->num_related_view_segment_numbers(basic_vs) != viewgrams.get_num_viewgrams()) error("BackProjectorByBin::back_project called with incorrect related_viewgrams. Problem with symmetries!\n"); - for (RelatedViewgrams::const_iterator iter = viewgrams.begin(); - iter != viewgrams.end(); - ++iter) - { - ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); - get_symmetries_used()->find_basic_view_segment_numbers(vs); - if (vs != basic_vs) - error("BackProjectorByBin::back_project called with incorrect related_viewgrams. Problem with symmetries!\n"); + for (RelatedViewgrams::const_iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); + get_symmetries_used()->find_basic_view_segment_numbers(vs); + if (vs != basic_vs) + error("BackProjectorByBin::back_project called with incorrect related_viewgrams. Problem with symmetries!\n"); } } - actual_back_project(density,viewgrams, - min_axial_pos_num, - max_axial_pos_num, - min_tangential_pos_num, - max_tangential_pos_num); + actual_back_project(density, viewgrams, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); stop_timers(); } #endif // -------------------------------------------------------------------------------------------------------------------- // -// The following are repetition of above, where the DiscretisedDensity has already been set with start_accumulating_in_new_target() +// The following are repetition of above, where the DiscretisedDensity has already been set with +// start_accumulating_in_new_target() // -------------------------------------------------------------------------------------------------------------------- // void -BackProjectorByBin::back_project(const ProjData& proj_data, int subset_num, int num_subsets) -{ +BackProjectorByBin::back_project(const ProjData& proj_data, int subset_num, int num_subsets) { #ifndef NDEBUG - assert(fabs(_density_sptr->sum()) < 1.e-7F); + assert(fabs(_density_sptr->sum()) < 1.e-7F); #endif check(*proj_data.get_proj_data_info_sptr(), *_density_sptr); - shared_ptr - symmetries_sptr(this->get_symmetries_used()->clone()); + shared_ptr symmetries_sptr(this->get_symmetries_used()->clone()); - const std::vector vs_nums_to_process = - detail::find_basic_vs_nums_in_subset(*proj_data.get_proj_data_info_sptr(), *symmetries_sptr, - proj_data.get_min_segment_num(), proj_data.get_max_segment_num(), - subset_num, num_subsets); + const std::vector vs_nums_to_process = detail::find_basic_vs_nums_in_subset( + *proj_data.get_proj_data_info_sptr(), *symmetries_sptr, proj_data.get_min_segment_num(), proj_data.get_max_segment_num(), + subset_num, num_subsets); #ifdef STIR_OPENMP -#pragma omp parallel shared(proj_data, symmetries_sptr) +# pragma omp parallel shared(proj_data, symmetries_sptr) #endif { #ifdef STIR_OPENMP -#pragma omp for schedule(runtime) +# pragma omp for schedule(runtime) #endif // note: older versions of openmp need an int as loop - for (int i=0; i(vs_nums_to_process.size()); ++i) - { - const ViewSegmentNumbers vs=vs_nums_to_process[i]; + for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++i) { + const ViewSegmentNumbers vs = vs_nums_to_process[i]; + + for (int k = proj_data.get_proj_data_info_sptr()->get_min_tof_pos_num(); + k <= proj_data.get_proj_data_info_sptr()->get_max_tof_pos_num(); ++k) { #ifdef STIR_OPENMP RelatedViewgrams viewgrams; -#pragma omp critical (BACKPROJECTORBYBIN_GETVIEWGRAMS) - viewgrams = proj_data.get_related_viewgrams(vs, symmetries_sptr); +# pragma omp critical(BACKPROJECTORBYBIN_GETVIEWGRAMS) + viewgrams = proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); #else - const RelatedViewgrams viewgrams = - proj_data.get_related_viewgrams(vs, symmetries_sptr); + const RelatedViewgrams viewgrams = proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); #endif info(boost::format("Processing view %1% of segment %2%") % vs.view_num() % vs.segment_num(), 2); back_project(viewgrams); } + } } #ifdef STIR_OPENMP // "reduce" data constructed by threads { - for (int i=0; i(_local_output_image_sptrs.size()); ++i) - if(!is_null_ptr(_local_output_image_sptrs[i])) // only accumulate if a thread filled something in + for (int i = 0; i < static_cast(_local_output_image_sptrs.size()); ++i) + if (!is_null_ptr(_local_output_image_sptrs[i])) // only accumulate if a thread filled something in (*_density_sptr) += *(_local_output_image_sptrs[i]); } #endif } void -BackProjectorByBin::back_project(const RelatedViewgrams& viewgrams) -{ - back_project(viewgrams, - viewgrams.get_min_axial_pos_num(), - viewgrams.get_max_axial_pos_num(), - viewgrams.get_min_tangential_pos_num(), - viewgrams.get_max_tangential_pos_num()); +BackProjectorByBin::back_project(const RelatedViewgrams& viewgrams) { + back_project(viewgrams, viewgrams.get_min_axial_pos_num(), viewgrams.get_max_axial_pos_num(), + viewgrams.get_min_tangential_pos_num(), viewgrams.get_max_tangential_pos_num()); } -void BackProjectorByBin::back_project - (const RelatedViewgrams& viewgrams, - const int min_axial_pos_num, - const int max_axial_pos_num) -{ - back_project(viewgrams, - min_axial_pos_num, - max_axial_pos_num, - viewgrams.get_min_tangential_pos_num(), - viewgrams.get_max_tangential_pos_num()); +void +BackProjectorByBin::back_project(const RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num) { + back_project(viewgrams, min_axial_pos_num, max_axial_pos_num, viewgrams.get_min_tangential_pos_num(), + viewgrams.get_max_tangential_pos_num()); } void -BackProjectorByBin:: -back_project(const RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - if (viewgrams.get_num_viewgrams()==0) +BackProjectorByBin::back_project(const RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { + if (viewgrams.get_num_viewgrams() == 0) return; check(*viewgrams.get_proj_data_info_sptr(), *_density_sptr); @@ -277,8 +228,8 @@ back_project(const RelatedViewgrams& viewgrams, start_timers(); #ifdef STIR_OPENMP - const int thread_num=omp_get_thread_num(); - if(is_null_ptr(_local_output_image_sptrs[thread_num])) + const int thread_num = omp_get_thread_num(); + if (is_null_ptr(_local_output_image_sptrs[thread_num])) _local_output_image_sptrs[thread_num].reset(_density_sptr->get_empty_copy()); #endif @@ -286,112 +237,90 @@ back_project(const RelatedViewgrams& viewgrams, { const ViewSegmentNumbers basic_vs = viewgrams.get_basic_view_segment_num(); - if (get_symmetries_used()->num_related_view_segment_numbers(basic_vs) != - viewgrams.get_num_viewgrams()) + if (get_symmetries_used()->num_related_view_segment_numbers(basic_vs) != viewgrams.get_num_viewgrams()) error("BackProjectorByBin::back_project called with incorrect related_viewgrams. Problem with symmetries!\n"); - for (RelatedViewgrams::const_iterator iter = viewgrams.begin(); - iter != viewgrams.end(); - ++iter) - { - ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); - get_symmetries_used()->find_basic_view_segment_numbers(vs); - if (vs != basic_vs) - error("BackProjectorByBin::back_project called with incorrect related_viewgrams. Problem with symmetries!\n"); + for (RelatedViewgrams::const_iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); + get_symmetries_used()->find_basic_view_segment_numbers(vs); + if (vs != basic_vs) + error("BackProjectorByBin::back_project called with incorrect related_viewgrams. Problem with symmetries!\n"); } } - actual_back_project( - viewgrams, - min_axial_pos_num, - max_axial_pos_num, - min_tangential_pos_num, - max_tangential_pos_num); + actual_back_project(viewgrams, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); stop_timers(); } void -BackProjectorByBin:: -start_accumulating_in_new_target() -{ +BackProjectorByBin::start_accumulating_in_new_target() { #ifdef STIR_OPENMP - if (omp_get_num_threads()!=1) - error("BackProjectorByBin::start_accumulating_in_new_target cannot be called inside a thread"); - - for (int i=0; i(_local_output_image_sptrs.size()); ++i) - if(!is_null_ptr(_local_output_image_sptrs[i])) // only reset to zero if a thread filled something in - { - if (!_local_output_image_sptrs.at(i)->has_same_characteristics(*_density_sptr)) - error("BackProjectorByBin implementation error: local images for openmp have wrong size"); - _local_output_image_sptrs.at(i)->fill(0.F); - } + if (omp_get_num_threads() != 1) + error("BackProjectorByBin::start_accumulating_in_new_target cannot be called inside a thread"); + + for (int i = 0; i < static_cast(_local_output_image_sptrs.size()); ++i) + if (!is_null_ptr(_local_output_image_sptrs[i])) // only reset to zero if a thread filled something in + { + if (!_local_output_image_sptrs.at(i)->has_same_characteristics(*_density_sptr)) + error("BackProjectorByBin implementation error: local images for openmp have wrong size"); + _local_output_image_sptrs.at(i)->fill(0.F); + } #endif - _density_sptr->fill(0.); + _density_sptr->fill(0.); } void -BackProjectorByBin:: -get_output(DiscretisedDensity<3,float> &density) const -{ - if (!density.has_same_characteristics(*_density_sptr)) - error("Images should have similar characteristics."); +BackProjectorByBin::get_output(DiscretisedDensity<3, float>& density) const { + if (!density.has_same_characteristics(*_density_sptr)) + error("Images should have similar characteristics."); #ifdef STIR_OPENMP - if (omp_get_num_threads()!=1) - error("BackProjectorByBin::get_output() cannot be called inside a thread"); + if (omp_get_num_threads() != 1) + error("BackProjectorByBin::get_output() cannot be called inside a thread"); // "reduce" data constructed by threads { density.fill(0.F); - for (int i=0; i(_local_output_image_sptrs.size()); ++i) { - if(!is_null_ptr(_local_output_image_sptrs[i]))// only accumulate if a thread filled something in - density += *(_local_output_image_sptrs[i]); + for (int i = 0; i < static_cast(_local_output_image_sptrs.size()); ++i) { + if (!is_null_ptr(_local_output_image_sptrs[i])) // only accumulate if a thread filled something in + density += *(_local_output_image_sptrs[i]); } } #else - std::copy(_density_sptr->begin_all(), _density_sptr->end_all(), density.begin_all()); + std::copy(_density_sptr->begin_all(), _density_sptr->end_all(), density.begin_all()); #endif - // If a post-back-projection data processor has been set, apply it. - if (!is_null_ptr(_post_data_processor_sptr)) { - Succeeded success = _post_data_processor_sptr->apply(density); - if (success != Succeeded::yes) - throw std::runtime_error("BackProjectorByBin::get_output(). Post-back-projection data processor failed."); - } + // If a post-back-projection data processor has been set, apply it. + if (!is_null_ptr(_post_data_processor_sptr)) { + Succeeded success = _post_data_processor_sptr->apply(density); + if (success != Succeeded::yes) + throw std::runtime_error("BackProjectorByBin::get_output(). Post-back-projection data processor failed."); + } } void -BackProjectorByBin:: -set_post_data_processor(shared_ptr > > post_data_processor_sptr) -{ - _post_data_processor_sptr = post_data_processor_sptr; +BackProjectorByBin::set_post_data_processor(shared_ptr>> post_data_processor_sptr) { + _post_data_processor_sptr = post_data_processor_sptr; } void -BackProjectorByBin:: -actual_back_project(DiscretisedDensity<3,float>&, - const RelatedViewgrams&, - const int, const int, - const int, const int) -{ - error("BackProjectorByBin::actual_forward_project() This is deprecated and should not be used."); +BackProjectorByBin::actual_back_project(DiscretisedDensity<3, float>&, const RelatedViewgrams&, const int, const int, + const int, const int) { + error("BackProjectorByBin::actual_forward_project() This is deprecated and should not be used."); } void -BackProjectorByBin:: -actual_back_project(const RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - shared_ptr > density_sptr = _density_sptr; +BackProjectorByBin::actual_back_project(const RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { + shared_ptr> density_sptr = _density_sptr; #ifdef STIR_OPENMP - const int thread_num=omp_get_thread_num(); - density_sptr = _local_output_image_sptrs[thread_num]; + const int thread_num = omp_get_thread_num(); + density_sptr = _local_output_image_sptrs[thread_num]; #endif - actual_back_project(*density_sptr, viewgrams, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); + actual_back_project(*density_sptr, viewgrams, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/BackProjectorByBinUsingInterpolation.cxx b/src/recon_buildblock/BackProjectorByBinUsingInterpolation.cxx index d0305410fb..af651552c8 100644 --- a/src/recon_buildblock/BackProjectorByBinUsingInterpolation.cxx +++ b/src/recon_buildblock/BackProjectorByBinUsingInterpolation.cxx @@ -27,7 +27,7 @@ \author Kris Thielemans \author Claire Labbe \author PARAPET project - + */ #include "stir/VoxelsOnCartesianGrid.h" @@ -49,26 +49,17 @@ using std::max; START_NAMESPACE_STIR -JacobianForIntBP:: -JacobianForIntBP(const shared_ptr proj_data_info_sptr, bool exact) - - : R2(square(proj_data_info_sptr->get_ring_radius())), - dxy2(square(proj_data_info_sptr->get_tangential_sampling())), - ring_spacing2 (square(proj_data_info_sptr->get_ring_spacing())), - backprojection_normalisation - (proj_data_info_sptr->get_ring_spacing()/2/proj_data_info_sptr->get_num_views()), - use_exact_Jacobian_now(exact) - {} +JacobianForIntBP::JacobianForIntBP(const shared_ptr proj_data_info_sptr, bool exact) -const char * const -BackProjectorByBinUsingInterpolation::registered_name = - "Interpolation"; + : R2(square(proj_data_info_sptr->get_ring_radius())), dxy2(square(proj_data_info_sptr->get_tangential_sampling())), + ring_spacing2(square(proj_data_info_sptr->get_ring_spacing())), + backprojection_normalisation(proj_data_info_sptr->get_ring_spacing() / 2 / proj_data_info_sptr->get_num_views()), + use_exact_Jacobian_now(exact) {} +const char* const BackProjectorByBinUsingInterpolation::registered_name = "Interpolation"; void -BackProjectorByBinUsingInterpolation:: -set_defaults() -{ +BackProjectorByBinUsingInterpolation::set_defaults() { use_piecewise_linear_interpolation_now = true; use_exact_Jacobian_now = true; @@ -80,17 +71,14 @@ set_defaults() // next 2 can be set to false but are ignored anyway do_symmetry_swap_s = true; do_symmetry_shift_z = true; - } void -BackProjectorByBinUsingInterpolation:: -initialise_keymap() -{ +BackProjectorByBinUsingInterpolation::initialise_keymap() { parser.add_start_key("Back Projector Using Interpolation Parameters"); parser.add_stop_key("End Back Projector Using Interpolation Parameters"); parser.add_key("use_piecewise_linear_interpolation", &use_piecewise_linear_interpolation_now); - parser.add_key("use_exact_Jacobian",&use_exact_Jacobian_now); + parser.add_key("use_exact_Jacobian", &use_exact_Jacobian_now); #ifdef STIR_DEVEL // see set_defaults() parser.add_key("do_symmetry_90degrees_min_phi", &do_symmetry_90degrees_min_phi); @@ -101,29 +89,24 @@ initialise_keymap() #endif } -const DataSymmetriesForViewSegmentNumbers * - BackProjectorByBinUsingInterpolation::get_symmetries_used() const -{ +const DataSymmetriesForViewSegmentNumbers* +BackProjectorByBinUsingInterpolation::get_symmetries_used() const { if (!this->_already_set_up) error("BackProjectorByBin method called without calling set_up first."); return symmetries_ptr.get(); } -BackProjectorByBinUsingInterpolation:: -BackProjectorByBinUsingInterpolation(const bool use_piecewise_linear_interpolation, - const bool use_exact_Jacobian) -{ +BackProjectorByBinUsingInterpolation::BackProjectorByBinUsingInterpolation(const bool use_piecewise_linear_interpolation, + const bool use_exact_Jacobian) { set_defaults(); use_piecewise_linear_interpolation_now = use_piecewise_linear_interpolation; use_exact_Jacobian_now = use_exact_Jacobian; } -BackProjectorByBinUsingInterpolation:: -BackProjectorByBinUsingInterpolation(shared_ptr const& proj_data_info_ptr, - shared_ptr > const& image_info_ptr, - const bool use_piecewise_linear_interpolation, - const bool use_exact_Jacobian) -{ +BackProjectorByBinUsingInterpolation::BackProjectorByBinUsingInterpolation( + shared_ptr const& proj_data_info_ptr, + shared_ptr> const& image_info_ptr, const bool use_piecewise_linear_interpolation, + const bool use_exact_Jacobian) { set_defaults(); use_piecewise_linear_interpolation_now = use_piecewise_linear_interpolation; use_exact_Jacobian_now = use_exact_Jacobian; @@ -132,21 +115,16 @@ BackProjectorByBinUsingInterpolation(shared_ptr const& proj_ void BackProjectorByBinUsingInterpolation::set_up(shared_ptr const& proj_data_info_ptr, - shared_ptr > const& image_info_ptr) -{ + shared_ptr> const& image_info_ptr) { BackProjectorByBin::set_up(proj_data_info_ptr, image_info_ptr); - this->symmetries_ptr. - reset(new DataSymmetriesForBins_PET_CartesianGrid(proj_data_info_ptr, image_info_ptr, - do_symmetry_90degrees_min_phi, - do_symmetry_180degrees_min_phi, - do_symmetry_swap_segment, - do_symmetry_swap_s, - do_symmetry_shift_z)); + this->symmetries_ptr.reset(new DataSymmetriesForBins_PET_CartesianGrid( + proj_data_info_ptr, image_info_ptr, do_symmetry_90degrees_min_phi, do_symmetry_180degrees_min_phi, do_symmetry_swap_segment, + do_symmetry_swap_s, do_symmetry_shift_z)); - // check if data are according to what we can handle + // check if data are according to what we can handle - const VoxelsOnCartesianGrid * vox_image_info_ptr = - dynamic_cast*> (image_info_ptr.get()); + const VoxelsOnCartesianGrid* vox_image_info_ptr = + dynamic_cast*>(image_info_ptr.get()); if (vox_image_info_ptr == NULL) error("BackProjectorByBinUsingInterpolation initialised with a wrong type of DiscretisedDensity\n"); @@ -154,8 +132,7 @@ BackProjectorByBinUsingInterpolation::set_up(shared_ptr cons const CartesianCoordinate3D voxel_size = vox_image_info_ptr->get_voxel_size(); // z_origin_in_planes should be an integer - const float z_origin_in_planes = - image_info_ptr->get_origin().z()/voxel_size.z(); + const float z_origin_in_planes = image_info_ptr->get_origin().z() / voxel_size.z(); if (fabs(round(z_origin_in_planes) - z_origin_in_planes) > 1.E-4) error("BackProjectorByBinUsingInterpolation: the shift in the " "z-direction of the origin (which is %g) should be a multiple of the plane " @@ -163,287 +140,221 @@ BackProjectorByBinUsingInterpolation::set_up(shared_ptr cons image_info_ptr->get_origin().z(), voxel_size.z()); // num_planes_per_axial_pos should currently be an integer - for (int segment_num = proj_data_info_ptr->get_min_segment_num(); - segment_num <= proj_data_info_ptr->get_max_segment_num(); - ++segment_num) - { - const float num_planes_per_axial_pos = - symmetries_ptr->get_num_planes_per_axial_pos(segment_num); + for (int segment_num = proj_data_info_ptr->get_min_segment_num(); segment_num <= proj_data_info_ptr->get_max_segment_num(); + ++segment_num) { + const float num_planes_per_axial_pos = symmetries_ptr->get_num_planes_per_axial_pos(segment_num); if (fabs(round(num_planes_per_axial_pos) - num_planes_per_axial_pos) > 1.E-4) error("BackProjectorByBinUsingInterpolation: the number of image planes " "per axial_pos (which is %g for segment %d) should be an integer\n", - num_planes_per_axial_pos, segment_num); + num_planes_per_axial_pos, segment_num); } - - } void -BackProjectorByBinUsingInterpolation:: -use_exact_Jacobian(const bool use_exact_Jacobian) -{ +BackProjectorByBinUsingInterpolation::use_exact_Jacobian(const bool use_exact_Jacobian) { use_exact_Jacobian_now = use_exact_Jacobian; } +BackProjectorByBinUsingInterpolation* +BackProjectorByBinUsingInterpolation::clone() const { + return new BackProjectorByBinUsingInterpolation(*this); +} void -BackProjectorByBinUsingInterpolation:: -use_piecewise_linear_interpolation(const bool use_piecewise_linear_interpolation) -{ +BackProjectorByBinUsingInterpolation::use_piecewise_linear_interpolation(const bool use_piecewise_linear_interpolation) { use_piecewise_linear_interpolation_now = use_piecewise_linear_interpolation; } -void BackProjectorByBinUsingInterpolation:: -actual_back_project(DiscretisedDensity<3,float>& density, - const RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) +void +BackProjectorByBinUsingInterpolation::actual_back_project(DiscretisedDensity<3, float>& density, + const RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { const shared_ptr proj_data_info_cyl_sptr = - dynamic_pointer_cast (viewgrams.get_proj_data_info_sptr()); - + dynamic_pointer_cast(viewgrams.get_proj_data_info_sptr()); - if (is_null_ptr(proj_data_info_cyl_sptr)) - { + if (is_null_ptr(proj_data_info_cyl_sptr)) { error("\nBackProjectorByBinUsingInterpolation:\n" - "can only handle arc-corrected data (cast to ProjDataInfoCylindricalArcCorr)!\n"); + "can only handle arc-corrected data (cast to ProjDataInfoCylindricalArcCorr)!\n"); } // this will throw an exception when the cast does not work - VoxelsOnCartesianGrid& image = - dynamic_cast&>(density); + VoxelsOnCartesianGrid& image = dynamic_cast&>(density); // TODO somehow check symmetry object in RelatedViewgrams - const float zoom = - proj_data_info_cyl_sptr->get_tangential_sampling()/ - image.get_voxel_size().x(); + const float zoom = proj_data_info_cyl_sptr->get_tangential_sampling() / image.get_voxel_size().x(); // zoom the viewgrams if necessary // if zoom==1 there's no need for allocation of a new // RelatedViewgrams object, so we do some trickery with a pointer const RelatedViewgrams* zoomed_viewgrams_ptr = 0; // to make it exception-proof we need to use an unique_ptr or shared_ptr - shared_ptr > zoomed_viewgrams_sptr; + shared_ptr> zoomed_viewgrams_sptr; int zoomed_min_tangential_pos_num; int zoomed_max_tangential_pos_num; // warning: this criterion has to be the same as the error-check in x,y voxel size // (see lines around warning message 'must be equal to'... which occurs more than once) - if (fabs(zoom-1) > 1E-4) - { - zoomed_min_tangential_pos_num = - static_cast(ceil(min_tangential_pos_num*zoom)); - zoomed_max_tangential_pos_num = - static_cast(ceil(max_tangential_pos_num*zoom)); - // store it in a shared_ptr, such that it gets cleaned up correctly - zoomed_viewgrams_sptr.reset(new RelatedViewgrams(viewgrams)); - zoomed_viewgrams_ptr = zoomed_viewgrams_sptr.get(); - - zoom_viewgrams(*zoomed_viewgrams_sptr, zoom, - zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); - } - else - { - zoomed_min_tangential_pos_num = - min_tangential_pos_num; - zoomed_max_tangential_pos_num = - max_tangential_pos_num; - // we cannot use the unique_ptr here, as that would try to free the - // viewgrams object - zoomed_viewgrams_ptr = &viewgrams; - } + if (fabs(zoom - 1) > 1E-4) { + zoomed_min_tangential_pos_num = static_cast(ceil(min_tangential_pos_num * zoom)); + zoomed_max_tangential_pos_num = static_cast(ceil(max_tangential_pos_num * zoom)); + // store it in a shared_ptr, such that it gets cleaned up correctly + zoomed_viewgrams_sptr.reset(new RelatedViewgrams(viewgrams)); + zoomed_viewgrams_ptr = zoomed_viewgrams_sptr.get(); + + zoom_viewgrams(*zoomed_viewgrams_sptr, zoom, zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); + } else { + zoomed_min_tangential_pos_num = min_tangential_pos_num; + zoomed_max_tangential_pos_num = max_tangential_pos_num; + // we cannot use the unique_ptr here, as that would try to free the + // viewgrams object + zoomed_viewgrams_ptr = &viewgrams; + } const int num_views = viewgrams.get_proj_data_info_sptr()->get_num_views(); RelatedViewgrams::const_iterator r_viewgrams_iter = zoomed_viewgrams_ptr->begin(); - if (zoomed_viewgrams_ptr->get_basic_segment_num() == 0) - { - // no segment symmetry - const Viewgram & pos_view =*r_viewgrams_iter; - const Viewgram neg_view = pos_view.get_empty_copy(); - - if (zoomed_viewgrams_ptr->get_num_viewgrams() == 1) - { - const Viewgram pos_plus90 = pos_view.get_empty_copy(); - const Viewgram& neg_plus90 = pos_plus90; - back_project_view_plus_90_and_delta( - image, - pos_view, neg_view, pos_plus90, neg_plus90, - min_axial_pos_num, max_axial_pos_num, - zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); - } - else - { - r_viewgrams_iter++; - if (zoomed_viewgrams_ptr->get_num_viewgrams() == 2) - { - if (r_viewgrams_iter->get_view_num() == pos_view.get_view_num() + num_views/2) - { - const Viewgram & pos_plus90 =*r_viewgrams_iter; - const Viewgram neg_plus90 = pos_plus90.get_empty_copy(); - assert(pos_plus90.get_view_num() == num_views / 2 + pos_view.get_view_num()); - back_project_view_plus_90_and_delta( - image, - pos_view, neg_view, pos_plus90, neg_plus90, - min_axial_pos_num, max_axial_pos_num, - zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); - } - else if (r_viewgrams_iter->get_view_num() == num_views-pos_view.get_view_num()) - { - assert(zoomed_viewgrams_ptr->get_basic_view_num() != 0); - const Viewgram & pos_min180 =*r_viewgrams_iter; - const Viewgram neg_min180 = pos_min180.get_empty_copy(); - const Viewgram& pos_plus90 =neg_min180;// anything 0 really - const Viewgram& neg_plus90 = pos_plus90; - const Viewgram& pos_min90 =neg_min180;// anything 0 really - const Viewgram& neg_min90 = pos_min90; - - assert(pos_min180.get_view_num() == num_views - pos_view.get_view_num()); - - back_project_all_symmetries( - image, - pos_view, neg_view, pos_plus90, neg_plus90, - pos_min180, neg_min180, pos_min90, neg_min90, - min_axial_pos_num, max_axial_pos_num, - zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); - } - else - { - error("BackProjectorByBinUsingInterpolation: back_project called with RelatedViewgrams with inconsistent views"); - } - } - else - { - assert(zoomed_viewgrams_ptr->get_basic_view_num() != 0); - assert(zoomed_viewgrams_ptr->get_basic_view_num() != num_views/4); - const Viewgram & pos_plus90 =*r_viewgrams_iter; - const Viewgram neg_plus90 = pos_plus90.get_empty_copy(); - r_viewgrams_iter++;//2 - const Viewgram & pos_min180 =*r_viewgrams_iter; - r_viewgrams_iter++;//3 - const Viewgram & pos_min90 =*r_viewgrams_iter; - const Viewgram& neg_min180 = neg_plus90;//pos_min180.get_empty_copy(); - const Viewgram& neg_min90 = neg_plus90;//pos_min90.get_empty_copy(); - - assert(pos_plus90.get_view_num() == num_views / 2 + pos_view.get_view_num()); - assert(pos_min90.get_view_num() == num_views / 2 - pos_view.get_view_num()); - assert(pos_min180.get_view_num() == num_views - pos_view.get_view_num()); - - back_project_all_symmetries( - image, - pos_view, neg_view, pos_plus90, neg_plus90, - pos_min180, neg_min180, pos_min90, neg_min90, - min_axial_pos_num, max_axial_pos_num, - zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); - } - } + if (zoomed_viewgrams_ptr->get_basic_segment_num() == 0) { + // no segment symmetry + const Viewgram& pos_view = *r_viewgrams_iter; + const Viewgram neg_view = pos_view.get_empty_copy(); + + if (zoomed_viewgrams_ptr->get_num_viewgrams() == 1) { + const Viewgram pos_plus90 = pos_view.get_empty_copy(); + const Viewgram& neg_plus90 = pos_plus90; + back_project_view_plus_90_and_delta(image, pos_view, neg_view, pos_plus90, neg_plus90, min_axial_pos_num, max_axial_pos_num, + zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); + } else { + r_viewgrams_iter++; + if (zoomed_viewgrams_ptr->get_num_viewgrams() == 2) { + if (r_viewgrams_iter->get_view_num() == pos_view.get_view_num() + num_views / 2) { + const Viewgram& pos_plus90 = *r_viewgrams_iter; + const Viewgram neg_plus90 = pos_plus90.get_empty_copy(); + assert(pos_plus90.get_view_num() == num_views / 2 + pos_view.get_view_num()); + back_project_view_plus_90_and_delta(image, pos_view, neg_view, pos_plus90, neg_plus90, min_axial_pos_num, + max_axial_pos_num, zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); + } else if (r_viewgrams_iter->get_view_num() == num_views - pos_view.get_view_num()) { + assert(zoomed_viewgrams_ptr->get_basic_view_num() != 0); + const Viewgram& pos_min180 = *r_viewgrams_iter; + const Viewgram neg_min180 = pos_min180.get_empty_copy(); + const Viewgram& pos_plus90 = neg_min180; // anything 0 really + const Viewgram& neg_plus90 = pos_plus90; + const Viewgram& pos_min90 = neg_min180; // anything 0 really + const Viewgram& neg_min90 = pos_min90; + + assert(pos_min180.get_view_num() == num_views - pos_view.get_view_num()); + + back_project_all_symmetries(image, pos_view, neg_view, pos_plus90, neg_plus90, pos_min180, neg_min180, pos_min90, + neg_min90, min_axial_pos_num, max_axial_pos_num, zoomed_min_tangential_pos_num, + zoomed_max_tangential_pos_num); + } else { + error("BackProjectorByBinUsingInterpolation: back_project called with RelatedViewgrams with inconsistent views"); + } + } else { + assert(zoomed_viewgrams_ptr->get_basic_view_num() != 0); + assert(zoomed_viewgrams_ptr->get_basic_view_num() != num_views / 4); + const Viewgram& pos_plus90 = *r_viewgrams_iter; + const Viewgram neg_plus90 = pos_plus90.get_empty_copy(); + r_viewgrams_iter++; // 2 + const Viewgram& pos_min180 = *r_viewgrams_iter; + r_viewgrams_iter++; // 3 + const Viewgram& pos_min90 = *r_viewgrams_iter; + const Viewgram& neg_min180 = neg_plus90; // pos_min180.get_empty_copy(); + const Viewgram& neg_min90 = neg_plus90; // pos_min90.get_empty_copy(); + + assert(pos_plus90.get_view_num() == num_views / 2 + pos_view.get_view_num()); + assert(pos_min90.get_view_num() == num_views / 2 - pos_view.get_view_num()); + assert(pos_min180.get_view_num() == num_views - pos_view.get_view_num()); + + back_project_all_symmetries(image, pos_view, neg_view, pos_plus90, neg_plus90, pos_min180, neg_min180, pos_min90, + neg_min90, min_axial_pos_num, max_axial_pos_num, zoomed_min_tangential_pos_num, + zoomed_max_tangential_pos_num); + } } - else - { - // segment symmetry + } else { + // segment symmetry + + if (zoomed_viewgrams_ptr->get_num_viewgrams() == 1) + error("BackProjectorByBinUsingInterpolation: back_project called with RelatedViewgrams with unexpect number of related " + "viewgrams"); + + const Viewgram& pos_view = *r_viewgrams_iter; // 0 + r_viewgrams_iter++; + const Viewgram& neg_view = *r_viewgrams_iter; // 1 + assert(neg_view.get_view_num() == pos_view.get_view_num()); + + if (zoomed_viewgrams_ptr->get_num_viewgrams() == 2) { + const Viewgram pos_plus90 = pos_view.get_empty_copy(); + const Viewgram& neg_plus90 = pos_plus90; + back_project_view_plus_90_and_delta(image, pos_view, neg_view, pos_plus90, neg_plus90, min_axial_pos_num, max_axial_pos_num, + zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); + } else if (zoomed_viewgrams_ptr->get_num_viewgrams() == 4) { + r_viewgrams_iter++; - if (zoomed_viewgrams_ptr->get_num_viewgrams() == 1) - error("BackProjectorByBinUsingInterpolation: back_project called with RelatedViewgrams with unexpect number of related viewgrams"); + if (r_viewgrams_iter->get_view_num() == pos_view.get_view_num() + num_views / 2) { + const Viewgram& pos_plus90 = *r_viewgrams_iter; // 2 + r_viewgrams_iter++; + const Viewgram& neg_plus90 = *r_viewgrams_iter; // 3 + + assert(pos_plus90.get_view_num() == num_views / 2 + pos_view.get_view_num()); + assert(neg_plus90.get_view_num() == num_views / 2 + pos_view.get_view_num()); + back_project_view_plus_90_and_delta(image, pos_view, neg_view, pos_plus90, neg_plus90, min_axial_pos_num, + max_axial_pos_num, zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); + } else if (r_viewgrams_iter->get_view_num() == num_views - pos_view.get_view_num()) { + assert(zoomed_viewgrams_ptr->get_basic_view_num() != 0); + const Viewgram& pos_min180 = *r_viewgrams_iter; // 2 + r_viewgrams_iter++; + const Viewgram& neg_min180 = *r_viewgrams_iter; // 3 + const Viewgram& pos_plus90 = pos_view.get_empty_copy(); // anything 0 really + const Viewgram& neg_plus90 = pos_plus90; + const Viewgram& pos_min90 = pos_plus90; + const Viewgram& neg_min90 = pos_plus90; + + assert(pos_min180.get_view_num() == num_views - pos_view.get_view_num()); + assert(neg_min180.get_view_num() == num_views - pos_view.get_view_num()); + + back_project_all_symmetries(image, pos_view, neg_view, pos_plus90, neg_plus90, pos_min180, neg_min180, pos_min90, + neg_min90, min_axial_pos_num, max_axial_pos_num, zoomed_min_tangential_pos_num, + zoomed_max_tangential_pos_num); + } else { + error("BackProjectorByBinUsingInterpolation: back_project called with RelatedViewgrams with inconsistent views"); + } - const Viewgram & pos_view = *r_viewgrams_iter;//0 + } else if (zoomed_viewgrams_ptr->get_num_viewgrams() == 8) { + assert(zoomed_viewgrams_ptr->get_basic_view_num() != 0); + assert(zoomed_viewgrams_ptr->get_basic_view_num() != num_views / 4); + r_viewgrams_iter++; + const Viewgram& pos_plus90 = *r_viewgrams_iter; // 2 r_viewgrams_iter++; - const Viewgram & neg_view = *r_viewgrams_iter;//1 + const Viewgram& neg_plus90 = *r_viewgrams_iter; // 3 + r_viewgrams_iter++; // 4 + const Viewgram& pos_min180 = *r_viewgrams_iter; + r_viewgrams_iter++; // 5 + const Viewgram& neg_min180 = *r_viewgrams_iter; + r_viewgrams_iter++; // 6 + const Viewgram& pos_min90 = *r_viewgrams_iter; + r_viewgrams_iter++; // 7 + const Viewgram& neg_min90 = *r_viewgrams_iter; + + assert(pos_plus90.get_view_num() == num_views / 2 + pos_view.get_view_num()); + assert(pos_min90.get_view_num() == num_views / 2 - pos_view.get_view_num()); + assert(pos_min180.get_view_num() == num_views - pos_view.get_view_num()); assert(neg_view.get_view_num() == pos_view.get_view_num()); - - if (zoomed_viewgrams_ptr->get_num_viewgrams() == 2) - { - const Viewgram pos_plus90 = pos_view.get_empty_copy(); - const Viewgram& neg_plus90 = pos_plus90; - back_project_view_plus_90_and_delta( - image, - pos_view, neg_view, pos_plus90, neg_plus90, - min_axial_pos_num, max_axial_pos_num, - zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); - } - else if (zoomed_viewgrams_ptr->get_num_viewgrams() == 4) - { - r_viewgrams_iter++; - - if (r_viewgrams_iter->get_view_num() == pos_view.get_view_num() + num_views/2) - { - const Viewgram & pos_plus90 =*r_viewgrams_iter;//2 - r_viewgrams_iter++; - const Viewgram & neg_plus90 =*r_viewgrams_iter;//3 - - assert(pos_plus90.get_view_num() == num_views / 2 + pos_view.get_view_num()); - assert(neg_plus90.get_view_num() == num_views / 2 + pos_view.get_view_num()); - back_project_view_plus_90_and_delta( - image, - pos_view, neg_view, pos_plus90, neg_plus90, - min_axial_pos_num, max_axial_pos_num, - zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); - } - else if (r_viewgrams_iter->get_view_num() == num_views-pos_view.get_view_num()) - { - assert(zoomed_viewgrams_ptr->get_basic_view_num() != 0); - const Viewgram & pos_min180 =*r_viewgrams_iter; //2 - r_viewgrams_iter++; - const Viewgram & neg_min180 =*r_viewgrams_iter;//3 - const Viewgram& pos_plus90 =pos_view.get_empty_copy();// anything 0 really - const Viewgram& neg_plus90 = pos_plus90; - const Viewgram& pos_min90 = pos_plus90; - const Viewgram& neg_min90 = pos_plus90; - - assert(pos_min180.get_view_num() == num_views - pos_view.get_view_num()); - assert(neg_min180.get_view_num() == num_views - pos_view.get_view_num()); - - back_project_all_symmetries( - image, - pos_view, neg_view, pos_plus90, neg_plus90, - pos_min180, neg_min180, pos_min90, neg_min90, - min_axial_pos_num, max_axial_pos_num, - zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); - } - else - { - error("BackProjectorByBinUsingInterpolation: back_project called with RelatedViewgrams with inconsistent views"); - } - - } - else if (zoomed_viewgrams_ptr->get_num_viewgrams() == 8) - { - assert(zoomed_viewgrams_ptr->get_basic_view_num() != 0); - assert(zoomed_viewgrams_ptr->get_basic_view_num() != num_views/4); - r_viewgrams_iter++; - const Viewgram & pos_plus90 =*r_viewgrams_iter;//2 - r_viewgrams_iter++; - const Viewgram & neg_plus90 =*r_viewgrams_iter;//3 - r_viewgrams_iter++;//4 - const Viewgram & pos_min180 =*r_viewgrams_iter; - r_viewgrams_iter++;//5 - const Viewgram & neg_min180 =*r_viewgrams_iter; - r_viewgrams_iter++;//6 - const Viewgram & pos_min90 =*r_viewgrams_iter; - r_viewgrams_iter++;//7 - const Viewgram & neg_min90 =*r_viewgrams_iter; - - assert(pos_plus90.get_view_num() == num_views / 2 + pos_view.get_view_num()); - assert(pos_min90.get_view_num() == num_views / 2 - pos_view.get_view_num()); - assert(pos_min180.get_view_num() == num_views - pos_view.get_view_num()); - assert(neg_view.get_view_num() == pos_view.get_view_num()); - assert(neg_plus90.get_view_num() == pos_plus90.get_view_num()); - assert(neg_min90.get_view_num() == pos_min90.get_view_num()); - assert(neg_min180.get_view_num() == pos_min180.get_view_num()); - - back_project_all_symmetries( - image, - pos_view, neg_view, pos_plus90, neg_plus90, - pos_min180, neg_min180, pos_min90, neg_min90, - min_axial_pos_num, max_axial_pos_num, - zoomed_min_tangential_pos_num, zoomed_max_tangential_pos_num); - - } - } + assert(neg_plus90.get_view_num() == pos_plus90.get_view_num()); + assert(neg_min90.get_view_num() == pos_min90.get_view_num()); + assert(neg_min180.get_view_num() == pos_min180.get_view_num()); + back_project_all_symmetries(image, pos_view, neg_view, pos_plus90, neg_plus90, pos_min180, neg_min180, pos_min90, neg_min90, + min_axial_pos_num, max_axial_pos_num, zoomed_min_tangential_pos_num, + zoomed_max_tangential_pos_num); + } + } } - - - +void +BackProjectorByBinUsingInterpolation::actual_back_project(DiscretisedDensity<3, float>&, const Bin&) { + error("BackProjectorByBinUsingInterpolation is not supported for list-mode reconstruction. Abort."); +} #if 0 /****************************************************************************** @@ -568,444 +479,363 @@ BackProjectorByBinUsingInterpolation:: #endif - - /**************************************************************************** real work ****************************************************************************/ - /* - The version which uses all possible symmetries. - Here 0<=view < num_views/4 (= 45 degrees) - */ +/* + The version which uses all possible symmetries. + Here 0<=view < num_views/4 (= 45 degrees) + */ -void +void BackProjectorByBinUsingInterpolation::back_project_all_symmetries( - VoxelsOnCartesianGrid& image, - const Viewgram & pos_view, - const Viewgram & neg_view, - const Viewgram & pos_plus90, - const Viewgram & neg_plus90, - const Viewgram & pos_min180, - const Viewgram & neg_min180, - const Viewgram & pos_min90, - const Viewgram & neg_min90, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ + VoxelsOnCartesianGrid& image, const Viewgram& pos_view, const Viewgram& neg_view, + const Viewgram& pos_plus90, const Viewgram& neg_plus90, const Viewgram& pos_min180, + const Viewgram& neg_min180, const Viewgram& pos_min90, const Viewgram& neg_min90, + const int min_axial_pos_num, const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { const shared_ptr proj_data_info_cyl_sptr = - dynamic_pointer_cast (pos_view.get_proj_data_info_sptr()); - + dynamic_pointer_cast(pos_view.get_proj_data_info_sptr()); - if (is_null_ptr(proj_data_info_cyl_sptr)) - { + if (is_null_ptr(proj_data_info_cyl_sptr)) { error("\nBackProjectorByBinUsingInterpolation:\n\ can only handle arc-corrected data (cast to ProjDataInfoCylindricalArcCorr)!\n"); } - assert(min_axial_pos_num >= pos_view. get_min_axial_pos_num()); - assert(max_axial_pos_num <= pos_view. get_max_axial_pos_num()); + assert(min_axial_pos_num >= pos_view.get_min_axial_pos_num()); + assert(max_axial_pos_num <= pos_view.get_max_axial_pos_num()); assert(min_tangential_pos_num >= pos_view.get_min_tangential_pos_num()); assert(max_tangential_pos_num <= pos_view.get_max_tangential_pos_num()); - //KTxxx not necessary anymore - //assert(min_tangential_pos_num == - max_tangential_pos_num); + // KTxxx not necessary anymore + // assert(min_tangential_pos_num == - max_tangential_pos_num); #ifndef NDEBUG - // This variable is only used in assert() at the moment, so avoid compiler + // This variable is only used in assert() at the moment, so avoid compiler // warning by defining it only when in debug mode const int segment_num = pos_view.get_segment_num(); #endif - - assert(proj_data_info_cyl_sptr ->get_average_ring_difference(segment_num) >= 0); + assert(proj_data_info_cyl_sptr->get_average_ring_difference(segment_num) >= 0); assert(pos_view.get_view_num() > 0); - assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views()/4 || - (!symmetries_ptr->using_symmetry_90degrees_min_phi() && - pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views()/2 && - pos_plus90.find_max()==0 && neg_plus90.find_max()==0 && - pos_min90.find_max()==0 && neg_min90.find_max()==0) ); + assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views() / 4 || + (!symmetries_ptr->using_symmetry_90degrees_min_phi() && + pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views() / 2 && pos_plus90.find_max() == 0 && + neg_plus90.find_max() == 0 && pos_min90.find_max() == 0 && neg_min90.find_max() == 0)); const int nviews = pos_view.get_proj_data_info_sptr()->get_num_views(); // warning: error check has to be the same as what is used for the criterion to do the zooming // (see lines concerning zoomed_viewgrams) - if(fabs(image.get_voxel_size().x()/proj_data_info_cyl_sptr->get_tangential_sampling() - 1) > 1E-4 - || fabs(image.get_voxel_size().y()/proj_data_info_cyl_sptr->get_tangential_sampling() - 1) > 1E-4) + if (fabs(image.get_voxel_size().x() / proj_data_info_cyl_sptr->get_tangential_sampling() - 1) > 1E-4 || + fabs(image.get_voxel_size().y() / proj_data_info_cyl_sptr->get_tangential_sampling() - 1) > 1E-4) error("BackProjectorByBinUsingInterpolation: x,y voxel size must be equal to bin size."); - + // KTxxx not necessary anymore - //assert(image.get_min_z() == 0); + // assert(image.get_min_z() == 0); - if (pos_view.get_view_num() == 0) - { - error("BackProjectorByBinUsingInterpolation: back_project_all_symmetries called with view 0 degrees.\n"); - } - if (symmetries_ptr->using_symmetry_90degrees_min_phi() && - pos_view.get_view_num() == nviews/4) - { - error("BackProjectorByBinUsingInterpolation: back_project_all_symmetries called with view 45 degrees.\n"); - } + if (pos_view.get_view_num() == 0) { + error("BackProjectorByBinUsingInterpolation: back_project_all_symmetries called with view 0 degrees.\n"); + } + if (symmetries_ptr->using_symmetry_90degrees_min_phi() && pos_view.get_view_num() == nviews / 4) { + error("BackProjectorByBinUsingInterpolation: back_project_all_symmetries called with view 45 degrees.\n"); + } // KT XXX - const float fovrad_in_mm = - min((min(image.get_max_x(), -image.get_min_x()))*image.get_voxel_size().x(), - (min(image.get_max_y(), -image.get_min_y()))*image.get_voxel_size().y()); - const int fovrad = round(fovrad_in_mm/image.get_voxel_size().x()); + const float fovrad_in_mm = min((min(image.get_max_x(), -image.get_min_x())) * image.get_voxel_size().x(), + (min(image.get_max_y(), -image.get_min_y())) * image.get_voxel_size().y()); + const int fovrad = round(fovrad_in_mm / image.get_voxel_size().x()); // TODO remove -2, it's there because otherwise find_start_values() goes crazy. - const int max_tang_pos_to_use = - min(max_tangential_pos_num, fovrad-2); - const int min_tang_pos_to_use = - max(min_tangential_pos_num, -(fovrad-2)); - - const int max_abs_tang_pos_to_use = - max(max_tang_pos_to_use, -min_tang_pos_to_use); - const int min_abs_tang_pos_to_use = - max_tang_pos_to_use<0 ? - -max_tang_pos_to_use - : (min_tang_pos_to_use>0 ? - min_tang_pos_to_use - : 0 ); + const int max_tang_pos_to_use = min(max_tangential_pos_num, fovrad - 2); + const int min_tang_pos_to_use = max(min_tangential_pos_num, -(fovrad - 2)); + const int max_abs_tang_pos_to_use = max(max_tang_pos_to_use, -min_tang_pos_to_use); + const int min_abs_tang_pos_to_use = + max_tang_pos_to_use < 0 ? -max_tang_pos_to_use : (min_tang_pos_to_use > 0 ? min_tang_pos_to_use : 0); start_timers(); const JacobianForIntBP jacobian(proj_data_info_cyl_sptr, use_exact_Jacobian_now); - Array<4, float > Proj2424(IndexRange4D(0, 1, 0, 3, 0, 1, 1, 4)); + Array<4, float> Proj2424(IndexRange4D(0, 1, 0, 3, 0, 1, 1, 4)); // a variable which will be used in the loops over s to get s_in_mm - Bin bin(pos_view.get_segment_num(), pos_view.get_view_num(),min_axial_pos_num,0); + Bin bin(pos_view.get_segment_num(), pos_view.get_view_num(), min_axial_pos_num, pos_view.get_timing_pos_num(), 0); - // KT 20/06/2001 rewrite using get_phi + // KT 20/06/2001 rewrite using get_phi const float cphi = cos(proj_data_info_cyl_sptr->get_phi(bin)); const float sphi = sin(proj_data_info_cyl_sptr->get_phi(bin)); - // Do a loop over all axial positions. However, because we use interpolation of // a 'beam', each step takes elements from ax_pos and ax_pos+1. So, data in // a ring influences beam ax_pos-1 and ax_pos. All this means that we // have to let ax_pos run from min_axial_pos_num-1 to max_axial_pos_num. - for (int ax_pos = min_axial_pos_num-1; ax_pos <= max_axial_pos_num; ax_pos++) - { - const int ax_pos_plus = ax_pos + 1; - - // We have to fill with 0, as not all elements are set in the lines below - if (ax_pos==min_axial_pos_num-1 || ax_pos==max_axial_pos_num) - Proj2424.fill(0); - - for (int s = min_abs_tang_pos_to_use; s <= max_abs_tang_pos_to_use; s++) { - const int splus = s + 1; - const int ms = -s; - const int msplus = -splus; - - // now I have to check if ax_pos is in allowable range - if (ax_pos >= min_axial_pos_num) - { - Proj2424[0][0][0][1] = s>max_tang_pos_to_use ? 0 : pos_view[ax_pos][s]; - Proj2424[0][0][0][2] = splus>max_tang_pos_to_use ? 0 : pos_view[ax_pos][splus]; - Proj2424[0][1][0][3] = s>max_tang_pos_to_use ? 0 : pos_min90[ax_pos][s]; - Proj2424[0][1][0][4] = splus>max_tang_pos_to_use ? 0 : pos_min90[ax_pos][splus]; - Proj2424[0][2][0][1] = s>max_tang_pos_to_use ? 0 : pos_plus90[ax_pos][s]; - Proj2424[0][2][0][2] = splus>max_tang_pos_to_use ? 0 : pos_plus90[ax_pos][splus]; - Proj2424[0][3][0][3] = s>max_tang_pos_to_use ? 0 : pos_min180[ax_pos][s]; - Proj2424[0][3][0][4] = splus>max_tang_pos_to_use ? 0 : pos_min180[ax_pos][splus]; - Proj2424[1][0][0][3] = s>max_tang_pos_to_use ? 0 : neg_view[ax_pos][s]; - Proj2424[1][0][0][4] = splus>max_tang_pos_to_use ? 0 : neg_view[ax_pos][splus]; - Proj2424[1][1][0][1] = s>max_tang_pos_to_use ? 0 : neg_min90[ax_pos][s]; - Proj2424[1][1][0][2] = splus>max_tang_pos_to_use ? 0 : neg_min90[ax_pos][splus]; - Proj2424[1][2][0][3] = s>max_tang_pos_to_use ? 0 : neg_plus90[ax_pos][s]; - Proj2424[1][2][0][4] = splus>max_tang_pos_to_use ? 0 : neg_plus90[ax_pos][splus]; - Proj2424[1][3][0][1] = s>max_tang_pos_to_use ? 0 : neg_min180[ax_pos][s]; - Proj2424[1][3][0][2] = splus>max_tang_pos_to_use ? 0 : neg_min180[ax_pos][splus]; - - Proj2424[0][0][1][3] = msmax_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][s]; - Proj2424[0][0][0][4] = splus>max_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][splus]; - Proj2424[0][1][0][1] = s>max_tang_pos_to_use ? 0 : pos_min90[ax_pos_plus][s]; - Proj2424[0][1][0][2] = splus>max_tang_pos_to_use ? 0 : pos_min90[ax_pos_plus][splus]; - Proj2424[0][2][0][3] = s>max_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][s]; - Proj2424[0][2][0][4] = splus>max_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][splus]; - Proj2424[0][3][0][1] = s>max_tang_pos_to_use ? 0 : pos_min180[ax_pos_plus][s]; - Proj2424[0][3][0][2] = splus>max_tang_pos_to_use ? 0 : pos_min180[ax_pos_plus][splus]; - Proj2424[1][0][0][1] = s>max_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][s]; - Proj2424[1][0][0][2] = splus>max_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][splus]; - Proj2424[1][1][0][3] = s>max_tang_pos_to_use ? 0 : neg_min90[ax_pos_plus][s]; - Proj2424[1][1][0][4] = splus>max_tang_pos_to_use ? 0 : neg_min90[ax_pos_plus][splus]; - Proj2424[1][2][0][1] = s>max_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][s]; - Proj2424[1][2][0][2] = splus>max_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][splus]; - Proj2424[1][3][0][3] = s>max_tang_pos_to_use ? 0 : neg_min180[ax_pos_plus][s]; - Proj2424[1][3][0][4] = splus>max_tang_pos_to_use ? 0 : neg_min180[ax_pos_plus][splus]; - - Proj2424[0][0][1][1] = msget_average_ring_difference(segment_num); - - // take s+.5 as average for the beam (it's slowly varying in s anyway) - Proj2424 *= jacobian(delta, s+ 0.5F); - - // find correspondence between ax_pos coordinates and image coordinates: - // z = num_planes_per_axial_pos * ring + axial_pos_to_z_offset - // KT 20/06/2001 rewrote using symmetries_ptr - const int num_planes_per_axial_pos = - round(symmetries_ptr->get_num_planes_per_axial_pos(segment_num)); - const float axial_pos_to_z_offset = - symmetries_ptr->get_axial_pos_to_z_offset(segment_num); - - if (use_piecewise_linear_interpolation_now && num_planes_per_axial_pos>1) - piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview - (Proj2424, - image, - proj_data_info_cyl_sptr, - delta, - cphi, sphi, s, ax_pos, - num_planes_per_axial_pos, - axial_pos_to_z_offset); - else - linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview - (Proj2424, - image, - proj_data_info_cyl_sptr, - delta, - cphi, sphi, s, ax_pos, - num_planes_per_axial_pos, - axial_pos_to_z_offset); + for (int ax_pos = min_axial_pos_num - 1; ax_pos <= max_axial_pos_num; ax_pos++) { + const int ax_pos_plus = ax_pos + 1; + + // We have to fill with 0, as not all elements are set in the lines below + if (ax_pos == min_axial_pos_num - 1 || ax_pos == max_axial_pos_num) + Proj2424.fill(0); + + for (int s = min_abs_tang_pos_to_use; s <= max_abs_tang_pos_to_use; s++) { + const int splus = s + 1; + const int ms = -s; + const int msplus = -splus; + + // now I have to check if ax_pos is in allowable range + if (ax_pos >= min_axial_pos_num) { + Proj2424[0][0][0][1] = s > max_tang_pos_to_use ? 0 : pos_view[ax_pos][s]; + Proj2424[0][0][0][2] = splus > max_tang_pos_to_use ? 0 : pos_view[ax_pos][splus]; + Proj2424[0][1][0][3] = s > max_tang_pos_to_use ? 0 : pos_min90[ax_pos][s]; + Proj2424[0][1][0][4] = splus > max_tang_pos_to_use ? 0 : pos_min90[ax_pos][splus]; + Proj2424[0][2][0][1] = s > max_tang_pos_to_use ? 0 : pos_plus90[ax_pos][s]; + Proj2424[0][2][0][2] = splus > max_tang_pos_to_use ? 0 : pos_plus90[ax_pos][splus]; + Proj2424[0][3][0][3] = s > max_tang_pos_to_use ? 0 : pos_min180[ax_pos][s]; + Proj2424[0][3][0][4] = splus > max_tang_pos_to_use ? 0 : pos_min180[ax_pos][splus]; + Proj2424[1][0][0][3] = s > max_tang_pos_to_use ? 0 : neg_view[ax_pos][s]; + Proj2424[1][0][0][4] = splus > max_tang_pos_to_use ? 0 : neg_view[ax_pos][splus]; + Proj2424[1][1][0][1] = s > max_tang_pos_to_use ? 0 : neg_min90[ax_pos][s]; + Proj2424[1][1][0][2] = splus > max_tang_pos_to_use ? 0 : neg_min90[ax_pos][splus]; + Proj2424[1][2][0][3] = s > max_tang_pos_to_use ? 0 : neg_plus90[ax_pos][s]; + Proj2424[1][2][0][4] = splus > max_tang_pos_to_use ? 0 : neg_plus90[ax_pos][splus]; + Proj2424[1][3][0][1] = s > max_tang_pos_to_use ? 0 : neg_min180[ax_pos][s]; + Proj2424[1][3][0][2] = splus > max_tang_pos_to_use ? 0 : neg_min180[ax_pos][splus]; + + Proj2424[0][0][1][3] = ms < min_tang_pos_to_use ? 0 : pos_view[ax_pos][ms]; + Proj2424[0][0][1][4] = msplus < min_tang_pos_to_use ? 0 : pos_view[ax_pos][msplus]; + Proj2424[0][1][1][1] = ms < min_tang_pos_to_use ? 0 : pos_min90[ax_pos][ms]; + Proj2424[0][1][1][2] = msplus < min_tang_pos_to_use ? 0 : pos_min90[ax_pos][msplus]; + Proj2424[0][2][1][3] = ms < min_tang_pos_to_use ? 0 : pos_plus90[ax_pos][ms]; + Proj2424[0][2][1][4] = msplus < min_tang_pos_to_use ? 0 : pos_plus90[ax_pos][msplus]; + Proj2424[0][3][1][1] = ms < min_tang_pos_to_use ? 0 : pos_min180[ax_pos][ms]; + Proj2424[0][3][1][2] = msplus < min_tang_pos_to_use ? 0 : pos_min180[ax_pos][msplus]; + Proj2424[1][0][1][1] = ms < min_tang_pos_to_use ? 0 : neg_view[ax_pos][ms]; + Proj2424[1][0][1][2] = msplus < min_tang_pos_to_use ? 0 : neg_view[ax_pos][msplus]; + Proj2424[1][1][1][3] = ms < min_tang_pos_to_use ? 0 : neg_min90[ax_pos][ms]; + Proj2424[1][1][1][4] = msplus < min_tang_pos_to_use ? 0 : neg_min90[ax_pos][msplus]; + Proj2424[1][2][1][1] = ms < min_tang_pos_to_use ? 0 : neg_plus90[ax_pos][ms]; + Proj2424[1][2][1][2] = msplus < min_tang_pos_to_use ? 0 : neg_plus90[ax_pos][msplus]; + Proj2424[1][3][1][3] = ms < min_tang_pos_to_use ? 0 : neg_min180[ax_pos][ms]; + Proj2424[1][3][1][4] = msplus < min_tang_pos_to_use ? 0 : neg_min180[ax_pos][msplus]; } + + if (ax_pos_plus <= max_axial_pos_num) { + Proj2424[0][0][0][3] = s > max_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][s]; + Proj2424[0][0][0][4] = splus > max_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][splus]; + Proj2424[0][1][0][1] = s > max_tang_pos_to_use ? 0 : pos_min90[ax_pos_plus][s]; + Proj2424[0][1][0][2] = splus > max_tang_pos_to_use ? 0 : pos_min90[ax_pos_plus][splus]; + Proj2424[0][2][0][3] = s > max_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][s]; + Proj2424[0][2][0][4] = splus > max_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][splus]; + Proj2424[0][3][0][1] = s > max_tang_pos_to_use ? 0 : pos_min180[ax_pos_plus][s]; + Proj2424[0][3][0][2] = splus > max_tang_pos_to_use ? 0 : pos_min180[ax_pos_plus][splus]; + Proj2424[1][0][0][1] = s > max_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][s]; + Proj2424[1][0][0][2] = splus > max_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][splus]; + Proj2424[1][1][0][3] = s > max_tang_pos_to_use ? 0 : neg_min90[ax_pos_plus][s]; + Proj2424[1][1][0][4] = splus > max_tang_pos_to_use ? 0 : neg_min90[ax_pos_plus][splus]; + Proj2424[1][2][0][1] = s > max_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][s]; + Proj2424[1][2][0][2] = splus > max_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][splus]; + Proj2424[1][3][0][3] = s > max_tang_pos_to_use ? 0 : neg_min180[ax_pos_plus][s]; + Proj2424[1][3][0][4] = splus > max_tang_pos_to_use ? 0 : neg_min180[ax_pos_plus][splus]; + + Proj2424[0][0][1][1] = ms < min_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][ms]; + Proj2424[0][0][1][2] = msplus < min_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][msplus]; + Proj2424[0][1][1][3] = ms < min_tang_pos_to_use ? 0 : pos_min90[ax_pos_plus][ms]; + Proj2424[0][1][1][4] = msplus < min_tang_pos_to_use ? 0 : pos_min90[ax_pos_plus][msplus]; + Proj2424[0][2][1][1] = ms < min_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][ms]; + Proj2424[0][2][1][2] = msplus < min_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][msplus]; + Proj2424[0][3][1][3] = ms < min_tang_pos_to_use ? 0 : pos_min180[ax_pos_plus][ms]; + Proj2424[0][3][1][4] = msplus < min_tang_pos_to_use ? 0 : pos_min180[ax_pos_plus][msplus]; + Proj2424[1][0][1][3] = ms < min_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][ms]; + Proj2424[1][0][1][4] = msplus < min_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][msplus]; + Proj2424[1][1][1][1] = ms < min_tang_pos_to_use ? 0 : neg_min90[ax_pos_plus][ms]; + Proj2424[1][1][1][2] = msplus < min_tang_pos_to_use ? 0 : neg_min90[ax_pos_plus][msplus]; + Proj2424[1][2][1][3] = ms < min_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][ms]; + Proj2424[1][2][1][4] = msplus < min_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][msplus]; + Proj2424[1][3][1][1] = ms < min_tang_pos_to_use ? 0 : neg_min180[ax_pos_plus][ms]; + Proj2424[1][3][1][2] = msplus < min_tang_pos_to_use ? 0 : neg_min180[ax_pos_plus][msplus]; + } + const int segment_num = pos_view.get_segment_num(); + + const float delta = proj_data_info_cyl_sptr->get_average_ring_difference(segment_num); + + // take s+.5 as average for the beam (it's slowly varying in s anyway) + Proj2424 *= jacobian(delta, s + 0.5F); + + // find correspondence between ax_pos coordinates and image coordinates: + // z = num_planes_per_axial_pos * ring + axial_pos_to_z_offset + // KT 20/06/2001 rewrote using symmetries_ptr + const int num_planes_per_axial_pos = round(symmetries_ptr->get_num_planes_per_axial_pos(segment_num)); + const float axial_pos_to_z_offset = symmetries_ptr->get_axial_pos_to_z_offset(segment_num); + + if (use_piecewise_linear_interpolation_now && num_planes_per_axial_pos > 1) + piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview( + Proj2424, image, proj_data_info_cyl_sptr, delta, cphi, sphi, s, ax_pos, num_planes_per_axial_pos, + axial_pos_to_z_offset); + else + linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview(Proj2424, image, proj_data_info_cyl_sptr, delta, + cphi, sphi, s, ax_pos, num_planes_per_axial_pos, + axial_pos_to_z_offset); } + } stop_timers(); } /* This function projects 4 viewgrams related by symmetry. -It will be used for view=0 or 45 degrees +It will be used for view=0 or 45 degrees (or others if the 90degrees_min_phi symmetry is not used). Here 0<=view < num_views/2 (= 90 degrees) */ -void -BackProjectorByBinUsingInterpolation:: -back_project_view_plus_90_and_delta( - VoxelsOnCartesianGrid& image, - const Viewgram & pos_view, - const Viewgram & neg_view, - const Viewgram & pos_plus90, - const Viewgram & neg_plus90, - const int min_axial_pos_num, - const int max_axial_pos_num, - const int min_tangential_pos_num, - const int max_tangential_pos_num) -{ +void +BackProjectorByBinUsingInterpolation::back_project_view_plus_90_and_delta( + VoxelsOnCartesianGrid& image, const Viewgram& pos_view, const Viewgram& neg_view, + const Viewgram& pos_plus90, const Viewgram& neg_plus90, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, const int max_tangential_pos_num) { const shared_ptr proj_data_info_cyl_sptr = - dynamic_pointer_cast (pos_view.get_proj_data_info_sptr()); + dynamic_pointer_cast(pos_view.get_proj_data_info_sptr()); - if (is_null_ptr(proj_data_info_cyl_sptr)) - { - error("\nBackProjectorByBinUsingInterpolation:,\n\ + if (is_null_ptr(proj_data_info_cyl_sptr)) { + error("\nBackProjectorByBinUsingInterpolation:,\n\ can only handle arc-corrected data (cast to ProjDataInfoCylindricalArcCorr)!\n"); - } + } - assert(min_axial_pos_num >= pos_view. get_min_axial_pos_num()); - assert(max_axial_pos_num <= pos_view. get_max_axial_pos_num()); + assert(min_axial_pos_num >= pos_view.get_min_axial_pos_num()); + assert(max_axial_pos_num <= pos_view.get_max_axial_pos_num()); assert(min_tangential_pos_num >= pos_view.get_min_tangential_pos_num()); assert(max_tangential_pos_num <= pos_view.get_max_tangential_pos_num()); // KTXXX not necessary anymore - //assert(min_tangential_pos_num == - max_tangential_pos_num); + // assert(min_tangential_pos_num == - max_tangential_pos_num); #ifndef NDEBUG - // These variables are only used in assert() at the moment, so avoid compiler + // These variables are only used in assert() at the moment, so avoid compiler // warning by defining it only when in debug mode const int segment_num = pos_view.get_segment_num(); #endif - assert(proj_data_info_cyl_sptr ->get_average_ring_difference(segment_num) >= 0); + assert(proj_data_info_cyl_sptr->get_average_ring_difference(segment_num) >= 0); - const int num_views = pos_view.get_proj_data_info_sptr()->get_num_views(); - - assert(pos_view.get_view_num()>=0); - assert(pos_view.get_view_num() get_num_views(); + assert(pos_view.get_view_num() >= 0); + assert(pos_view.get_view_num() < num_views / 2 || + (pos_view.get_view_num() < num_views && pos_plus90.find_max() == 0 && neg_plus90.find_max() == 0)); // warning: error check has to be the same as what is used for the criterion to do the zooming // (see lines concerning zoomed_viewgrams) - if(fabs(image.get_voxel_size().x()/proj_data_info_cyl_sptr->get_tangential_sampling() - 1) > 1E-4 - || fabs(image.get_voxel_size().y()/proj_data_info_cyl_sptr->get_tangential_sampling() - 1) > 1E-4) + if (fabs(image.get_voxel_size().x() / proj_data_info_cyl_sptr->get_tangential_sampling() - 1) > 1E-4 || + fabs(image.get_voxel_size().y() / proj_data_info_cyl_sptr->get_tangential_sampling() - 1) > 1E-4) error("BackProjectorByBinUsingInterpolation: x,y voxel size must be equal to bin size."); // KTXXX not necessary anymore - //assert(image.get_min_z() == 0); + // assert(image.get_min_z() == 0); start_timers(); const JacobianForIntBP jacobian(proj_data_info_cyl_sptr, use_exact_Jacobian_now); - Array<4, float > Proj2424(IndexRange4D(0, 1, 0, 3, 0, 1, 1, 4)); + Array<4, float> Proj2424(IndexRange4D(0, 1, 0, 3, 0, 1, 1, 4)); // a variable which will be used in the loops over s to get s_in_mm - Bin bin(pos_view.get_segment_num(), pos_view.get_view_num(),min_axial_pos_num,0); + Bin bin(pos_view.get_segment_num(), pos_view.get_view_num(), min_axial_pos_num, 0, pos_view.get_timing_pos_num()); // compute cos(phi) and sin(phi) /* KT included special cases for phi=0 and 90 degrees to try to avoid rounding problems This is because the current low-level code has problems with e.g. cos(phi) being a very small negative number.*/ - const float cphi = - bin.view_num()==0? 1 : - 2*bin.view_num()==num_views ? 0 : - cos(proj_data_info_cyl_sptr->get_phi(bin)); - const float sphi = - bin.view_num()==0? 0 : - 2*bin.view_num()==num_views ? 1 : - sin(proj_data_info_cyl_sptr->get_phi(bin)); - - assert(fabs(cphi-cos(proj_data_info_cyl_sptr->get_phi(bin)))<.001); - assert(fabs(sphi-sin(proj_data_info_cyl_sptr->get_phi(bin)))<.001); + const float cphi = bin.view_num() == 0 ? 1 : 2 * bin.view_num() == num_views ? 0 : cos(proj_data_info_cyl_sptr->get_phi(bin)); + const float sphi = bin.view_num() == 0 ? 0 : 2 * bin.view_num() == num_views ? 1 : sin(proj_data_info_cyl_sptr->get_phi(bin)); + + assert(fabs(cphi - cos(proj_data_info_cyl_sptr->get_phi(bin))) < .001); + assert(fabs(sphi - sin(proj_data_info_cyl_sptr->get_phi(bin))) < .001); // KT XXX - const float fovrad_in_mm = - min((min(image.get_max_x(), -image.get_min_x()))*image.get_voxel_size().x(), - (min(image.get_max_y(), -image.get_min_y()))*image.get_voxel_size().y()); - const int fovrad = round(fovrad_in_mm/image.get_voxel_size().x()); + const float fovrad_in_mm = min((min(image.get_max_x(), -image.get_min_x())) * image.get_voxel_size().x(), + (min(image.get_max_y(), -image.get_min_y())) * image.get_voxel_size().y()); + const int fovrad = round(fovrad_in_mm / image.get_voxel_size().x()); // TODO remove -2, it's there because otherwise find_start_values() goes crazy. - const int max_tang_pos_to_use = - min(max_tangential_pos_num, fovrad-2); - const int min_tang_pos_to_use = - max(min_tangential_pos_num, -(fovrad-2)); + const int max_tang_pos_to_use = min(max_tangential_pos_num, fovrad - 2); + const int min_tang_pos_to_use = max(min_tangential_pos_num, -(fovrad - 2)); - - const int max_abs_tang_pos_to_use = - max(max_tang_pos_to_use, -min_tang_pos_to_use); - const int min_abs_tang_pos_to_use = - max_tang_pos_to_use<0 ? - -max_tang_pos_to_use - : (min_tang_pos_to_use>0 ? - min_tang_pos_to_use - : 0 ); + const int max_abs_tang_pos_to_use = max(max_tang_pos_to_use, -min_tang_pos_to_use); + const int min_abs_tang_pos_to_use = + max_tang_pos_to_use < 0 ? -max_tang_pos_to_use : (min_tang_pos_to_use > 0 ? min_tang_pos_to_use : 0); // Do a loop over all axial positions. However, because we use interpolation of // a 'beam', each step takes elements from ax_pos and ax_pos+1. So, data at // ax_pos influences beam ax_pos-1 and ax_pos. All this means that we // have to let ax_pos run from min_axial_pos_num-1 to max_axial_pos_num. - for (int ax_pos = min_axial_pos_num-1; ax_pos <= max_axial_pos_num; ax_pos++) - { - const int ax_pos_plus = ax_pos + 1; - - // We have to fill with 0, as not all elements are set in the lines below - if (ax_pos==min_axial_pos_num-1 || ax_pos==max_axial_pos_num) - Proj2424.fill(0); - for (int s = min_abs_tang_pos_to_use; s <= max_abs_tang_pos_to_use; s++) { - const int splus = s + 1; - const int ms = -s; - const int msplus = -splus; - - // now I have to check if ax_pos is in allowable range - if (ax_pos >= min_axial_pos_num) - { - Proj2424[0][0][0][1] = s>max_tang_pos_to_use ? 0 : pos_view[ax_pos][s]; - Proj2424[0][0][0][2] = splus>max_tang_pos_to_use ? 0 : pos_view[ax_pos][splus]; - Proj2424[0][2][0][1] = s>max_tang_pos_to_use ? 0 : pos_plus90[ax_pos][s]; - Proj2424[0][2][0][2] = splus>max_tang_pos_to_use ? 0 : pos_plus90[ax_pos][splus]; - Proj2424[1][0][0][3] = s>max_tang_pos_to_use ? 0 : neg_view[ax_pos][s]; - Proj2424[1][0][0][4] = splus>max_tang_pos_to_use ? 0 : neg_view[ax_pos][splus]; - Proj2424[1][2][0][3] = s>max_tang_pos_to_use ? 0 : neg_plus90[ax_pos][s]; - Proj2424[1][2][0][4] = splus>max_tang_pos_to_use ? 0 : neg_plus90[ax_pos][splus]; - - Proj2424[0][0][1][3] = msmax_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][s]; - Proj2424[0][0][0][4] = splus>max_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][splus]; - Proj2424[0][2][0][3] = s>max_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][s]; - Proj2424[0][2][0][4] = splus>max_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][splus]; - Proj2424[1][0][0][1] = s>max_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][s]; - Proj2424[1][0][0][2] = splus>max_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][splus]; - Proj2424[1][2][0][1] = s>max_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][s]; - Proj2424[1][2][0][2] = splus>max_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][splus]; - - Proj2424[0][0][1][1] = msget_average_ring_difference(segment_num); - - // take s+.5 as average for the beam (it's slowly varying in s anyway) - Proj2424 *= jacobian(delta, s+ 0.5F); - - // find correspondence between ax_pos coordinates and image coordinates: - // z = num_planes_per_axial_pos * ring + axial_pos_to_z_offset - // KT 20/06/2001 rewrote using symmetries_ptr - const int num_planes_per_axial_pos = - round(symmetries_ptr->get_num_planes_per_axial_pos(segment_num)); - const float axial_pos_to_z_offset = - symmetries_ptr->get_axial_pos_to_z_offset(segment_num); - - if (use_piecewise_linear_interpolation_now && num_planes_per_axial_pos>1) - piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90( Proj2424, image, - proj_data_info_cyl_sptr, - delta, - cphi, sphi, s, ax_pos, - num_planes_per_axial_pos, - axial_pos_to_z_offset); - else - linear_interpolation_backproj3D_Cho_view_viewplus90( Proj2424, image, - proj_data_info_cyl_sptr, - delta, - cphi, sphi, s, ax_pos, - num_planes_per_axial_pos, - axial_pos_to_z_offset); + for (int ax_pos = min_axial_pos_num - 1; ax_pos <= max_axial_pos_num; ax_pos++) { + const int ax_pos_plus = ax_pos + 1; + + // We have to fill with 0, as not all elements are set in the lines below + if (ax_pos == min_axial_pos_num - 1 || ax_pos == max_axial_pos_num) + Proj2424.fill(0); + for (int s = min_abs_tang_pos_to_use; s <= max_abs_tang_pos_to_use; s++) { + const int splus = s + 1; + const int ms = -s; + const int msplus = -splus; + + // now I have to check if ax_pos is in allowable range + if (ax_pos >= min_axial_pos_num) { + Proj2424[0][0][0][1] = s > max_tang_pos_to_use ? 0 : pos_view[ax_pos][s]; + Proj2424[0][0][0][2] = splus > max_tang_pos_to_use ? 0 : pos_view[ax_pos][splus]; + Proj2424[0][2][0][1] = s > max_tang_pos_to_use ? 0 : pos_plus90[ax_pos][s]; + Proj2424[0][2][0][2] = splus > max_tang_pos_to_use ? 0 : pos_plus90[ax_pos][splus]; + Proj2424[1][0][0][3] = s > max_tang_pos_to_use ? 0 : neg_view[ax_pos][s]; + Proj2424[1][0][0][4] = splus > max_tang_pos_to_use ? 0 : neg_view[ax_pos][splus]; + Proj2424[1][2][0][3] = s > max_tang_pos_to_use ? 0 : neg_plus90[ax_pos][s]; + Proj2424[1][2][0][4] = splus > max_tang_pos_to_use ? 0 : neg_plus90[ax_pos][splus]; + + Proj2424[0][0][1][3] = ms < min_tang_pos_to_use ? 0 : pos_view[ax_pos][ms]; + Proj2424[0][0][1][4] = msplus < min_tang_pos_to_use ? 0 : pos_view[ax_pos][msplus]; + Proj2424[0][2][1][3] = ms < min_tang_pos_to_use ? 0 : pos_plus90[ax_pos][ms]; + Proj2424[0][2][1][4] = msplus < min_tang_pos_to_use ? 0 : pos_plus90[ax_pos][msplus]; + Proj2424[1][0][1][1] = ms < min_tang_pos_to_use ? 0 : neg_view[ax_pos][ms]; + Proj2424[1][0][1][2] = msplus < min_tang_pos_to_use ? 0 : neg_view[ax_pos][msplus]; + Proj2424[1][2][1][1] = ms < min_tang_pos_to_use ? 0 : neg_plus90[ax_pos][ms]; + Proj2424[1][2][1][2] = msplus < min_tang_pos_to_use ? 0 : neg_plus90[ax_pos][msplus]; + } + + if (ax_pos_plus <= max_axial_pos_num) { + Proj2424[0][0][0][3] = s > max_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][s]; + Proj2424[0][0][0][4] = splus > max_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][splus]; + Proj2424[0][2][0][3] = s > max_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][s]; + Proj2424[0][2][0][4] = splus > max_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][splus]; + Proj2424[1][0][0][1] = s > max_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][s]; + Proj2424[1][0][0][2] = splus > max_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][splus]; + Proj2424[1][2][0][1] = s > max_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][s]; + Proj2424[1][2][0][2] = splus > max_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][splus]; + + Proj2424[0][0][1][1] = ms < min_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][ms]; + Proj2424[0][0][1][2] = msplus < min_tang_pos_to_use ? 0 : pos_view[ax_pos_plus][msplus]; + Proj2424[0][2][1][1] = ms < min_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][ms]; + Proj2424[0][2][1][2] = msplus < min_tang_pos_to_use ? 0 : pos_plus90[ax_pos_plus][msplus]; + Proj2424[1][0][1][3] = ms < min_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][ms]; + Proj2424[1][0][1][4] = msplus < min_tang_pos_to_use ? 0 : neg_view[ax_pos_plus][msplus]; + Proj2424[1][2][1][3] = ms < min_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][ms]; + Proj2424[1][2][1][4] = msplus < min_tang_pos_to_use ? 0 : neg_plus90[ax_pos_plus][msplus]; } + + const int segment_num = pos_view.get_segment_num(); + const float delta = proj_data_info_cyl_sptr->get_average_ring_difference(segment_num); + + // take s+.5 as average for the beam (it's slowly varying in s anyway) + Proj2424 *= jacobian(delta, s + 0.5F); + + // find correspondence between ax_pos coordinates and image coordinates: + // z = num_planes_per_axial_pos * ring + axial_pos_to_z_offset + // KT 20/06/2001 rewrote using symmetries_ptr + const int num_planes_per_axial_pos = round(symmetries_ptr->get_num_planes_per_axial_pos(segment_num)); + const float axial_pos_to_z_offset = symmetries_ptr->get_axial_pos_to_z_offset(segment_num); + + if (use_piecewise_linear_interpolation_now && num_planes_per_axial_pos > 1) + piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90(Proj2424, image, proj_data_info_cyl_sptr, delta, cphi, sphi, + s, ax_pos, num_planes_per_axial_pos, axial_pos_to_z_offset); + else + linear_interpolation_backproj3D_Cho_view_viewplus90(Proj2424, image, proj_data_info_cyl_sptr, delta, cphi, sphi, s, + ax_pos, num_planes_per_axial_pos, axial_pos_to_z_offset); } + } stop_timers(); } - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/BackProjectorByBinUsingInterpolation_3DCho.cxx b/src/recon_buildblock/BackProjectorByBinUsingInterpolation_3DCho.cxx index 53af34a3ad..503f05656c 100644 --- a/src/recon_buildblock/BackProjectorByBinUsingInterpolation_3DCho.cxx +++ b/src/recon_buildblock/BackProjectorByBinUsingInterpolation_3DCho.cxx @@ -25,7 +25,7 @@ \brief This file defines two private static functions from stir::BackProjectorByBinUsingInterpolation. - \warning This file is #included by BackProjectorByBinUsingInterpolation_linear.cxx + \warning This file is #included by BackProjectorByBinUsingInterpolation_linear.cxx and BackProjectorByBinUsingInterpolation_piecewise_linear.cxx. It should NOT be added to a Makefile (or project). @@ -40,16 +40,16 @@ // enable this variable if you need to handle very oblique LORs #define MOREZ //#define ALTERNATIVE -/* +/* - These functions use a 3D version of Cho's algorithm for backprojecting + These functions use a 3D version of Cho's algorithm for backprojecting incrementally. See M. Egger's thesis for details. They use the following symmetries: - opposite ring difference - views : view, view+90 degrees, 180 degrees - view, 90 degrees - view - - s,-s symmetry (while being careful when s==0 to avoid self-symmetric + - s,-s symmetry (while being careful when s==0 to avoid self-symmetric cases) For historical reasons, 'axial_pos_num' is here called 'ring'. @@ -59,10 +59,10 @@ n : 1 : negative delta; 0 : positive delta f : 0 : view; 1 : pi/2-view; 2 : pi/2+view; 3: pi-view ms : 1 : negative s; 0 : positive s - b : 1 : r1,s; 2: r2,s+1; 3: r2,s 4: r1,s+1 + b : 1 : r1,s; 2: r2,s+1; 3: r2,s 4: r1,s+1 where r1=ring0, r2=ring0+1 when - (n==ms && f==0||2) || (n!=ms && f==1||3) - and the role of r1,r2 are reversed in the other cases + (n==ms && f==0||2) || (n!=ms && f==1||3) + and the role of r1,r2 are reversed in the other cases Naming conventions for the incremental variables: n==0 && ms==0: A'f' @@ -77,7 +77,6 @@ delta->-delta changes dz->1-dz, ds->ds */ - #include "stir/ProjDataInfo.h" #include "stir/VoxelsOnCartesianGrid.h" #include "stir/ProjDataInfoCylindricalArcCorr.h" @@ -94,62 +93,62 @@ using std::max; KT 22/05/98 drastic revision cosmetic changes: - - removed lots of local variables which were not used (or are not used + - removed lots of local variables which were not used (or are not used anymore) - - moved most declarations of variables to the place where they are + - moved most declarations of variables to the place where they are initialised, and add const when possible - - added grouping {} to make variables local + - added grouping {} to make variables local - translated German and Afrikaans comments and added new comments - reordered the main loop to avoid repeating the 'voxel-updating' code - - moved the initialisation code (common to all symmetry cases) into the + - moved the initialisation code (common to all symmetry cases) into the find_start_values() function bugs removed: - handle self-symmetric case at s==0 properly, this was only correct in - the 45 degrees case. This removed most of the bright spot in the + the 45 degrees case. This removed most of the bright spot in the central pixel. - - changed the condition to break out of the loop to avoid early stopping, + - changed the condition to break out of the loop to avoid early stopping, which gave artifacts at the border - attempt to take into account that calculations are done with finite precision There used to be 'random' misplacements of data into neighboring voxels, this happened in the central pixel and at 45 and 135 degrees. - * use double to prevent rounding errors, necessary for incremental + * use double to prevent rounding errors, necessary for incremental quantities - * change all comparisons with 0 to comparisons with a small number + * change all comparisons with 0 to comparisons with a small number 'epsilon' increased precision: - use double for invariants as well - (otherwise computations of incremental constants would mean promoting + (otherwise computations of incremental constants would mean promoting floats to doubles all the time) speed-up - all these changes resulted in an (unexpected) speed-up of about a factor 2 - - KT&CL 22/12/99 + + KT&CL 22/12/99 span works now by introducing offsets - - KT&SM + + KT&SM introduced MOREZ to handle very oblique segments. This handles the case where Z needs to be incremented more than once to find the next voxel in the beam KT 25/09/2001 make sure things are ok for any image size. The main change is -to let find_start_values return Succeeded::no if there's no voxel in +to let find_start_values return Succeeded::no if there's no voxel in the FOV for this partiuclar tube. If so, we'll just exit. -TODO: +TODO: solve remaining issues of rounding errors (see backproj2D) if we never parallelise 'beyond' viewgram level (that is, always execute the calling back_project() and these functions at the same processor), there is probably no point in using the Projptr parameter, and we could -use the viewgrams directly. -Indeed, each element in Projptr is accessed 2 (sometimes 3) times only. The -compiler probably optimises this to 1 (sometimes 2) accesses only. +use the viewgrams directly. +Indeed, each element in Projptr is accessed 2 (sometimes 3) times only. The +compiler probably optimises this to 1 (sometimes 2) accesses only. So, it could be more expensive to construct the Projptr and fill it in from the viewgrams, compared to use the viewgrams directly. */ @@ -158,8 +157,8 @@ START_NAMESPACE_STIR static const double epsilon = 1e-10; -/* - This declares a local function that finds the first voxel in the beam, and +/* + This declares a local function that finds the first voxel in the beam, and associated ds,dz etc. It is implemented at the end of the file. @@ -170,52 +169,40 @@ static const double epsilon = 1e-10; */ // KT 25/09/2001 changed return value -static Succeeded find_start_values(const shared_ptr proj_data_info_sptr, - const float delta, const double cphi, const double sphi, - const int s, const int ring0, - const float image_rad, - const double d_sl, - int&X1, int&Y1, int& Z1, - double& ds, double& dz, double& dzhor, double& dzvert, - const float num_planes_per_axial_pos, - const float axial_pos_to_z_offset); - - -inline void -check_values(const shared_ptr proj_data_info_sptr, - const float delta, const double cphi, const double sphi, - const int s, const int ring0, - const int X1, const int Y1, const int Z1, - const double ds, const double dz, - const float num_planes_per_axial_pos, - const float axial_pos_to_z_offset) -{ +static Succeeded find_start_values(const shared_ptr proj_data_info_sptr, const float delta, + const double cphi, const double sphi, const int s, const int ring0, const float image_rad, + const double d_sl, int& X1, int& Y1, int& Z1, double& ds, double& dz, double& dzhor, + double& dzvert, const float num_planes_per_axial_pos, const float axial_pos_to_z_offset); + +inline void +check_values(const shared_ptr proj_data_info_sptr, const float delta, const double cphi, + const double sphi, const int s, const int ring0, const int X1, const int Y1, const int Z1, const double ds, + const double dz, const float num_planes_per_axial_pos, const float axial_pos_to_z_offset) { #ifdef BPINT_CHECK const double d_xy = proj_data_info_sptr->get_tangential_sampling(); - - const double R2 =square(proj_data_info_sptr->get_ring_radius()); + + const double R2 = square(proj_data_info_sptr->get_ring_radius()); /* Radius of scanner squared in Pixel^2 */ const double R2p = R2 / d_xy / d_xy; // TODO remove assumption const int num_planes_per_physical_ring = 2; - const double t = s + 0.5; /* In a beam, not on a ray */ - //t=X1*cphi+Y1*sphi; - //ds=t-s; + const double t = s + 0.5; /* In a beam, not on a ray */ + // t=X1*cphi+Y1*sphi; + // ds=t-s; - const double new_ds=X1*cphi+Y1*sphi-s;// Eq 6.13 in Egger thsis - const double root=sqrt(R2p-t*t);//CL 26/10/98 Put it back the original formula as before it was root=sqrt(R2p-s*s) + const double new_ds = X1 * cphi + Y1 * sphi - s; // Eq 6.13 in Egger thsis + const double root = sqrt(R2p - t * t); // CL 26/10/98 Put it back the original formula as before it was root=sqrt(R2p-s*s) // Eq 6.15 from Egger Thesis - const double z=( Z1-num_planes_per_physical_ring*delta/2*( (-X1*sphi+Y1*cphi)/root + 1 ) - - axial_pos_to_z_offset)/num_planes_per_axial_pos; - const double new_dz=z-ring0; + const double z = + (Z1 - num_planes_per_physical_ring * delta / 2 * ((-X1 * sphi + Y1 * cphi) / root + 1) - axial_pos_to_z_offset) / + num_planes_per_axial_pos; + const double new_dz = z - ring0; - if (fabs(ds-new_ds)>.005 || fabs(dz - new_dz)>.005) - { - warning("Difference ds (%g,%g) dz (%g,%g) at X=%d,Y=%d,Z=%d\n", - ds,new_ds,dz,new_dz,X1,Y1,Z1); - } -#endif //BPINT_CHECK + if (fabs(ds - new_ds) > .005 || fabs(dz - new_dz) > .005) { + warning("Difference ds (%g,%g) dz (%g,%g) at X=%d,Y=%d,Z=%d\n", ds, new_ds, dz, new_dz, X1, Y1, Z1); + } +#endif // BPINT_CHECK } /**************************************************************************** @@ -225,392 +212,374 @@ check_values(const shared_ptr proj_data_in *****************************************************************************/ -// KT 22/05/98 new, but extracted from backproj3D_ChoView45 +// KT 22/05/98 new, but extracted from backproj3D_ChoView45 // (which used to be called Backproj_Cho_Symstheta_Phiplus90s0_P) void BackProjectorByBinUsingInterpolation:: #if PIECEWISE_INTERPOLATION -piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90 + piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90 #else -linear_interpolation_backproj3D_Cho_view_viewplus90 + linear_interpolation_backproj3D_Cho_view_viewplus90 #endif -(Array<4, float > const &Projptr, - VoxelsOnCartesianGrid& image, - const shared_ptr proj_data_info_sptr, - float delta, - const double cphi, const double sphi, int s, int ring0, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset) -{ + (Array<4, float> const& Projptr, VoxelsOnCartesianGrid& image, + const shared_ptr proj_data_info_sptr, float delta, const double cphi, + const double sphi, int s, int ring0, const int num_planes_per_axial_pos, const float axial_pos_to_z_offset) { // KT 04/05/2000 new check #if PIECEWISE_INTERPOLATION - if (num_planes_per_axial_pos==1 && delta !=0) + if (num_planes_per_axial_pos == 1 && delta != 0) error("This version of the backprojector cannot be used for span>1. \ -Recompile %s with PIECEWISE_INTERPOLATION=0", __FILE__); +Recompile %s with PIECEWISE_INTERPOLATION=0", + __FILE__); #else -#ifdef ALTERNATIVE +# ifdef ALTERNATIVE // TODO - if (num_planes_per_axial_pos==1 && delta !=0) + if (num_planes_per_axial_pos == 1 && delta != 0) error("This version of the backprojector cannot be used for span>1. \ -Recompile %s with ALTERNATIVE not #defined", __FILE__); -#endif +Recompile %s with ALTERNATIVE not #defined", + __FILE__); +# endif #endif #ifndef MOREZ - // below test was too conservative. We have to adjust it a bit -#error times sqrt(2)/iets met t + // below test was too conservative. We have to adjust it a bit +# error times sqrt(2)/iets met t /* Check if delta is not too large. If the condition below is violated, z might have to be incremented more than once to remain in the beam. To do this, the code would have to be modified with while() instead of if(). As this will slow it down, we just abort at the moment. */ - - - if (delta * proj_data_info_sptr_info_cyl_ptr->get_tangential_sampling() / proj_data_info_sptr_info_cyl_ptr->get_ring_radius() > 1) - { - error("This backprojector cannot handle such oblique segments: delta = %g. Sorry.\n",delta); + if (delta * proj_data_info_sptr_info_cyl_ptr->get_tangential_sampling() / proj_data_info_sptr_info_cyl_ptr->get_ring_radius() > + 1) { + error("This backprojector cannot handle such oblique segments: delta = %g. Sorry.\n", delta); } #endif // conditions on searching flow - assert(cphi>=0-.001); - assert(sphi>=0-.001); - assert(cphi+sphi>=1-.001); + assert(cphi >= 0 - .001); + assert(sphi >= 0 - .001); + assert(cphi + sphi >= 1 - .001); - double dzvert,dzhor,ds; - double dsdiag,dzdiag,dz; - int X,Y,Z,Q; + double dzvert, dzhor, ds; + double dsdiag, dzdiag, dz; + int X, Y, Z, Q; + + const float ring_unit = 1. / num_planes_per_axial_pos; - const float ring_unit = 1./num_planes_per_axial_pos; - // in our current coordinate system, the following constant is always 2 // TODO remove assumption const int num_planes_per_physical_ring = 2; - assert(fabs(image.get_voxel_size().z() * num_planes_per_physical_ring/ proj_data_info_sptr->get_ring_spacing() -1) < 10E-4); + assert(fabs(image.get_voxel_size().z() * num_planes_per_physical_ring / proj_data_info_sptr->get_ring_spacing() - 1) < 10E-4); /* FOV radius in voxel units */ // KT 20/06/2001 change calculation of FOV such that even sized image will work - const float fovrad_in_mm = - min((min(image.get_max_x(), -image.get_min_x()))*image.get_voxel_size().x(), - (min(image.get_max_y(), -image.get_min_y()))*image.get_voxel_size().y()); - const float image_rad = fovrad_in_mm/image.get_voxel_size().x() - 2; - //const int image_rad = (int)((image.get_x_size()-1)/2); - - //KT 20/06/2001 allow min_z!=0 in all comparisons below - const int minplane = image.get_min_z(); - const int maxplane = image.get_max_z(); - - - if (find_start_values(proj_data_info_sptr, - delta, cphi, sphi, s, ring0, - image_rad, image.get_voxel_size().z(), - X, Y, Z, - ds, dz, dzhor, dzvert, - num_planes_per_axial_pos, - axial_pos_to_z_offset) == Succeeded::no) - { - // no voxels in the beam - return; - } + const float fovrad_in_mm = min((min(image.get_max_x(), -image.get_min_x())) * image.get_voxel_size().x(), + (min(image.get_max_y(), -image.get_min_y())) * image.get_voxel_size().y()); + const float image_rad = fovrad_in_mm / image.get_voxel_size().x() - 2; + // const int image_rad = (int)((image.get_x_size()-1)/2); + + // KT 20/06/2001 allow min_z!=0 in all comparisons below + const int minplane = image.get_min_z(); + const int maxplane = image.get_max_z(); + + if (find_start_values(proj_data_info_sptr, delta, cphi, sphi, s, ring0, image_rad, image.get_voxel_size().z(), X, Y, Z, ds, dz, + dzhor, dzvert, num_planes_per_axial_pos, axial_pos_to_z_offset) == Succeeded::no) { + // no voxels in the beam + return; + } - /* - The formulas below give the values to update a pixel. - Things are then complicated by optimising this backprojection - by 'incrementalising' the formulas. - // linear (original) interpolation - double UpA0=Projptr[0][0][0][1]+ds*K1A0+dz*K2A0; - image[Z][Y][X]+= (UpA0+dsdz*K3A0); - - // new interpolation - double A0a0 = Projptr[0][0][0][1]+ds*K1A0; - double A0a1 = Projptr[0][0][0][3]+ds*(K1A0+K3A0); - double UpA0 = 2*(Projptr[0][0][0][1]+ds*K1A0+dz*K2A0) - (A0a0 + A0a1)/2; - image[Z][Y][X]+= (dz <= 0.25) ? A0a0 : UpA0+twodsdz*K3A0; - - incremental changes: - // original interpolation - UpA0inc=dsinc*K1A0+dzinc*K2A0; - // new interpolation - A0a0inc = dsinc*K1A0; - A0a1inc = dsinc*(K1A0+K3A0); - UpA0inc = A0a0inc - A0a1inc/2 +2*dzinc*K2A0 + /* + The formulas below give the values to update a pixel. + Things are then complicated by optimising this backprojection + by 'incrementalising' the formulas. + // linear (original) interpolation + double UpA0=Projptr[0][0][0][1]+ds*K1A0+dz*K2A0; + image[Z][Y][X]+= (UpA0+dsdz*K3A0); + + // new interpolation + double A0a0 = Projptr[0][0][0][1]+ds*K1A0; + double A0a1 = Projptr[0][0][0][3]+ds*(K1A0+K3A0); + double UpA0 = 2*(Projptr[0][0][0][1]+ds*K1A0+dz*K2A0) - (A0a0 + A0a1)/2; + image[Z][Y][X]+= (dz <= 0.25) ? A0a0 : UpA0+twodsdz*K3A0; + + incremental changes: + // original interpolation + UpA0inc=dsinc*K1A0+dzinc*K2A0; + // new interpolation + A0a0inc = dsinc*K1A0; + A0a1inc = dsinc*(K1A0+K3A0); + UpA0inc = A0a0inc - A0a1inc/2 +2*dzinc*K2A0 - */ +*/ // K1, K2, K3 invariants - const double K1A0=Projptr[0][0][0][2]-Projptr[0][0][0][1]; - const double K2A0=Projptr[0][0][0][3]-Projptr[0][0][0][1]; - const double K3A0=Projptr[0][0][0][4]-Projptr[0][0][0][2]-K2A0; - const double K1A2=Projptr[0][2][0][2]-Projptr[0][2][0][1]; - const double K2A2=Projptr[0][2][0][3]-Projptr[0][2][0][1]; - const double K3A2=Projptr[0][2][0][4]-Projptr[0][2][0][2]-K2A2; - - const double K1A0n=Projptr[1][0][0][2]-Projptr[1][0][0][1]; - const double K2A0n=Projptr[1][0][0][3]-Projptr[1][0][0][1]; - const double K3A0n=Projptr[1][0][0][4]-Projptr[1][0][0][2]-K2A0n; - const double K1A2n=Projptr[1][2][0][2]-Projptr[1][2][0][1]; - const double K2A2n=Projptr[1][2][0][3]-Projptr[1][2][0][1]; - const double K3A2n=Projptr[1][2][0][4]-Projptr[1][2][0][2]-K2A2n; - - const double K1P0=Projptr[0][0][1][2]-Projptr[0][0][1][1]; - const double K2P0=Projptr[0][0][1][3]-Projptr[0][0][1][1]; - const double K3P0=Projptr[0][0][1][4]-Projptr[0][0][1][2]-K2P0; - const double K1P2=Projptr[0][2][1][2]-Projptr[0][2][1][1]; - const double K2P2=Projptr[0][2][1][3]-Projptr[0][2][1][1]; - const double K3P2=Projptr[0][2][1][4]-Projptr[0][2][1][2]-K2P2; - - const double K1P0n=Projptr[1][0][1][2]-Projptr[1][0][1][1]; - const double K2P0n=Projptr[1][0][1][3]-Projptr[1][0][1][1]; - const double K3P0n=Projptr[1][0][1][4]-Projptr[1][0][1][2]-K2P0n; - const double K1P2n=Projptr[1][2][1][2]-Projptr[1][2][1][1]; - const double K2P2n=Projptr[1][2][1][3]-Projptr[1][2][1][1]; - const double K3P2n=Projptr[1][2][1][4]-Projptr[1][2][1][2]-K2P2n; - + const double K1A0 = Projptr[0][0][0][2] - Projptr[0][0][0][1]; + const double K2A0 = Projptr[0][0][0][3] - Projptr[0][0][0][1]; + const double K3A0 = Projptr[0][0][0][4] - Projptr[0][0][0][2] - K2A0; + const double K1A2 = Projptr[0][2][0][2] - Projptr[0][2][0][1]; + const double K2A2 = Projptr[0][2][0][3] - Projptr[0][2][0][1]; + const double K3A2 = Projptr[0][2][0][4] - Projptr[0][2][0][2] - K2A2; + + const double K1A0n = Projptr[1][0][0][2] - Projptr[1][0][0][1]; + const double K2A0n = Projptr[1][0][0][3] - Projptr[1][0][0][1]; + const double K3A0n = Projptr[1][0][0][4] - Projptr[1][0][0][2] - K2A0n; + const double K1A2n = Projptr[1][2][0][2] - Projptr[1][2][0][1]; + const double K2A2n = Projptr[1][2][0][3] - Projptr[1][2][0][1]; + const double K3A2n = Projptr[1][2][0][4] - Projptr[1][2][0][2] - K2A2n; + + const double K1P0 = Projptr[0][0][1][2] - Projptr[0][0][1][1]; + const double K2P0 = Projptr[0][0][1][3] - Projptr[0][0][1][1]; + const double K3P0 = Projptr[0][0][1][4] - Projptr[0][0][1][2] - K2P0; + const double K1P2 = Projptr[0][2][1][2] - Projptr[0][2][1][1]; + const double K2P2 = Projptr[0][2][1][3] - Projptr[0][2][1][1]; + const double K3P2 = Projptr[0][2][1][4] - Projptr[0][2][1][2] - K2P2; + + const double K1P0n = Projptr[1][0][1][2] - Projptr[1][0][1][1]; + const double K2P0n = Projptr[1][0][1][3] - Projptr[1][0][1][1]; + const double K3P0n = Projptr[1][0][1][4] - Projptr[1][0][1][2] - K2P0n; + const double K1P2n = Projptr[1][2][1][2] - Projptr[1][2][1][1]; + const double K2P2n = Projptr[1][2][1][3] - Projptr[1][2][1][1]; + const double K3P2n = Projptr[1][2][1][4] - Projptr[1][2][1][2] - K2P2n; #if !PIECEWISE_INTERPOLATION - const double ZplusKorrA0=ring_unit*K2A0; - const double ZplusKorrA2=ring_unit*K2A2; + const double ZplusKorrA0 = ring_unit * K2A0; + const double ZplusKorrA2 = ring_unit * K2A2; - const double ZplusKorrA0n=ring_unit*K2A0n; - const double ZplusKorrA2n=ring_unit*K2A2n; + const double ZplusKorrA0n = ring_unit * K2A0n; + const double ZplusKorrA2n = ring_unit * K2A2n; - const double ZplusKorrP0=ring_unit*K2P0; - const double ZplusKorrP2=ring_unit*K2P2; + const double ZplusKorrP0 = ring_unit * K2P0; + const double ZplusKorrP2 = ring_unit * K2P2; - const double ZplusKorrP0n=ring_unit*K2P0n; - const double ZplusKorrP2n=ring_unit*K2P2n; + const double ZplusKorrP0n = ring_unit * K2P0n; + const double ZplusKorrP2n = ring_unit * K2P2n; // V, H, D invariants - const double VA0=dzvert*K2A0+sphi*K1A0; - const double HA0=dzhor*K2A0-cphi*K1A0; - const double DA0=VA0+HA0; - const double VZA0=VA0+ring_unit*K2A0; - const double HZA0=HA0+ring_unit*K2A0; - const double DZA0=DA0+ring_unit*K2A0; - const double VA2=dzvert*K2A2+sphi*K1A2; - const double HA2=dzhor*K2A2-cphi*K1A2; - const double DA2=VA2+HA2; - const double VZA2=VA2+ring_unit*K2A2; - const double HZA2=HA2+ring_unit*K2A2; - const double DZA2=DA2+ring_unit*K2A2; - - const double VA0n=dzvert*K2A0n+sphi*K1A0n; - const double HA0n=dzhor*K2A0n-cphi*K1A0n; - const double DA0n=VA0n+HA0n; - const double VZA0n=VA0n+ring_unit*K2A0n; - const double HZA0n=HA0n+ring_unit*K2A0n; - const double DZA0n=DA0n+ring_unit*K2A0n; - const double VA2n=dzvert*K2A2n+sphi*K1A2n; - const double HA2n=dzhor*K2A2n-cphi*K1A2n; - const double DA2n=VA2n+HA2n; - const double VZA2n=VA2n+ring_unit*K2A2n; - const double HZA2n=HA2n+ring_unit*K2A2n; - const double DZA2n=DA2n+ring_unit*K2A2n; - - const double VP0=dzvert*K2P0+sphi*K1P0; - const double HP0=dzhor*K2P0-cphi*K1P0; - const double DP0=VP0+HP0; - const double VZP0=VP0+ring_unit*K2P0; - const double HZP0=HP0+ring_unit*K2P0; - const double DZP0=DP0+ring_unit*K2P0; - const double VP2=dzvert*K2P2+sphi*K1P2; - const double HP2=dzhor*K2P2-cphi*K1P2; - const double DP2=VP2+HP2; - const double VZP2=VP2+ring_unit*K2P2; - const double HZP2=HP2+ring_unit*K2P2; - const double DZP2=DP2+ring_unit*K2P2; - - const double VP0n=dzvert*K2P0n+sphi*K1P0n; - const double HP0n=dzhor*K2P0n-cphi*K1P0n; - const double DP0n=VP0n+HP0n; - const double VZP0n=VP0n+ring_unit*K2P0n; - const double HZP0n=HP0n+ring_unit*K2P0n; - const double DZP0n=DP0n+ring_unit*K2P0n; - const double VP2n=dzvert*K2P2n+sphi*K1P2n; - const double HP2n=dzhor*K2P2n-cphi*K1P2n; - const double DP2n=VP2n+HP2n; - const double VZP2n=VP2n+ring_unit*K2P2n; - const double HZP2n=HP2n+ring_unit*K2P2n; - const double DZP2n=DP2n+ring_unit*K2P2n; - + const double VA0 = dzvert * K2A0 + sphi * K1A0; + const double HA0 = dzhor * K2A0 - cphi * K1A0; + const double DA0 = VA0 + HA0; + const double VZA0 = VA0 + ring_unit * K2A0; + const double HZA0 = HA0 + ring_unit * K2A0; + const double DZA0 = DA0 + ring_unit * K2A0; + const double VA2 = dzvert * K2A2 + sphi * K1A2; + const double HA2 = dzhor * K2A2 - cphi * K1A2; + const double DA2 = VA2 + HA2; + const double VZA2 = VA2 + ring_unit * K2A2; + const double HZA2 = HA2 + ring_unit * K2A2; + const double DZA2 = DA2 + ring_unit * K2A2; + + const double VA0n = dzvert * K2A0n + sphi * K1A0n; + const double HA0n = dzhor * K2A0n - cphi * K1A0n; + const double DA0n = VA0n + HA0n; + const double VZA0n = VA0n + ring_unit * K2A0n; + const double HZA0n = HA0n + ring_unit * K2A0n; + const double DZA0n = DA0n + ring_unit * K2A0n; + const double VA2n = dzvert * K2A2n + sphi * K1A2n; + const double HA2n = dzhor * K2A2n - cphi * K1A2n; + const double DA2n = VA2n + HA2n; + const double VZA2n = VA2n + ring_unit * K2A2n; + const double HZA2n = HA2n + ring_unit * K2A2n; + const double DZA2n = DA2n + ring_unit * K2A2n; + + const double VP0 = dzvert * K2P0 + sphi * K1P0; + const double HP0 = dzhor * K2P0 - cphi * K1P0; + const double DP0 = VP0 + HP0; + const double VZP0 = VP0 + ring_unit * K2P0; + const double HZP0 = HP0 + ring_unit * K2P0; + const double DZP0 = DP0 + ring_unit * K2P0; + const double VP2 = dzvert * K2P2 + sphi * K1P2; + const double HP2 = dzhor * K2P2 - cphi * K1P2; + const double DP2 = VP2 + HP2; + const double VZP2 = VP2 + ring_unit * K2P2; + const double HZP2 = HP2 + ring_unit * K2P2; + const double DZP2 = DP2 + ring_unit * K2P2; + + const double VP0n = dzvert * K2P0n + sphi * K1P0n; + const double HP0n = dzhor * K2P0n - cphi * K1P0n; + const double DP0n = VP0n + HP0n; + const double VZP0n = VP0n + ring_unit * K2P0n; + const double HZP0n = HP0n + ring_unit * K2P0n; + const double DZP0n = DP0n + ring_unit * K2P0n; + const double VP2n = dzvert * K2P2n + sphi * K1P2n; + const double HP2n = dzhor * K2P2n - cphi * K1P2n; + const double DP2n = VP2n + HP2n; + const double VZP2n = VP2n + ring_unit * K2P2n; + const double HZP2n = HP2n + ring_unit * K2P2n; + const double DZP2n = DP2n + ring_unit * K2P2n; // Initial values of update values (Up) - double UpA0=Projptr[0][0][0][1]+ds*K1A0+dz*K2A0; - double UpA2=Projptr[0][2][0][1]+ds*K1A2+dz*K2A2; + double UpA0 = Projptr[0][0][0][1] + ds * K1A0 + dz * K2A0; + double UpA2 = Projptr[0][2][0][1] + ds * K1A2 + dz * K2A2; - double UpA0n=Projptr[1][0][0][1]+ds*K1A0n+dz*K2A0n; - double UpA2n=Projptr[1][2][0][1]+ds*K1A2n+dz*K2A2n; + double UpA0n = Projptr[1][0][0][1] + ds * K1A0n + dz * K2A0n; + double UpA2n = Projptr[1][2][0][1] + ds * K1A2n + dz * K2A2n; - double UpP0=Projptr[0][0][1][1]+ds*K1P0+dz*K2P0; - double UpP2=Projptr[0][2][1][1]+ds*K1P2+dz*K2P2; + double UpP0 = Projptr[0][0][1][1] + ds * K1P0 + dz * K2P0; + double UpP2 = Projptr[0][2][1][1] + ds * K1P2 + dz * K2P2; - double UpP0n=Projptr[1][0][1][1]+ds*K1P0n+dz*K2P0n; - double UpP2n=Projptr[1][2][1][1]+ds*K1P2n+dz*K2P2n; + double UpP0n = Projptr[1][0][1][1] + ds * K1P0n + dz * K2P0n; + double UpP2n = Projptr[1][2][1][1] + ds * K1P2n + dz * K2P2n; #else // PIECEWISE_INTERPOLATION - const double ZplusKorrA0=K2A0; - const double ZplusKorrA2=K2A2; + const double ZplusKorrA0 = K2A0; + const double ZplusKorrA2 = K2A2; - const double ZplusKorrA0n=K2A0n; - const double ZplusKorrA2n=K2A2n; + const double ZplusKorrA0n = K2A0n; + const double ZplusKorrA2n = K2A2n; - const double ZplusKorrP0=K2P0; - const double ZplusKorrP2=K2P2; + const double ZplusKorrP0 = K2P0; + const double ZplusKorrP2 = K2P2; - const double ZplusKorrP0n=K2P0n; - const double ZplusKorrP2n=K2P2n; + const double ZplusKorrP0n = K2P0n; + const double ZplusKorrP2n = K2P2n; // V, H, D invariants - const double VA0a0=+sphi*K1A0; - const double HA0a0=-cphi*K1A0; - const double DA0a0=VA0a0+HA0a0; - const double VA2a0=+sphi*K1A2; - const double HA2a0=-cphi*K1A2; - const double DA2a0=VA2a0+HA2a0; - - const double VA0na0=+sphi*K1A0n; - const double HA0na0=-cphi*K1A0n; - const double DA0na0=VA0na0+HA0na0; - const double VA2na0=+sphi*K1A2n; - const double HA2na0=-cphi*K1A2n; - const double DA2na0=VA2na0+HA2na0; - - const double VP0a0=+sphi*K1P0; - const double HP0a0=-cphi*K1P0; - const double DP0a0=VP0a0+HP0a0; - const double VP2a0=+sphi*K1P2; - const double HP2a0=-cphi*K1P2; - const double DP2a0=VP2a0+HP2a0; - - const double VP0na0=+sphi*K1P0n; - const double HP0na0=-cphi*K1P0n; - const double DP0na0=VP0na0+HP0na0; - const double VP2na0=+sphi*K1P2n; - const double HP2na0=-cphi*K1P2n; - const double DP2na0=VP2na0+HP2na0; - - - const double VA0a1=+sphi*(K1A0+K3A0); - const double HA0a1=-cphi*(K1A0+K3A0); - const double DA0a1=VA0a1+HA0a1; - const double VA2a1=+sphi*(K1A2+K3A2); - const double HA2a1=-cphi*(K1A2+K3A2); - const double DA2a1=VA2a1+HA2a1; - - const double VA0na1=+sphi*(K1A0n+K3A0n); - const double HA0na1=-cphi*(K1A0n+K3A0n); - const double DA0na1=VA0na1+HA0na1; - const double VA2na1=+sphi*(K1A2n+K3A2n); - const double HA2na1=-cphi*(K1A2n+K3A2n); - const double DA2na1=VA2na1+HA2na1; - - const double VP0a1=+sphi*(K1P0+K3P0); - const double HP0a1=-cphi*(K1P0+K3P0); - const double DP0a1=VP0a1+HP0a1; - const double VP2a1=+sphi*(K1P2+K3P2); - const double HP2a1=-cphi*(K1P2+K3P2); - const double DP2a1=VP2a1+HP2a1; - - const double VP0na1=+sphi*(K1P0n+K3P0n); - const double HP0na1=-cphi*(K1P0n+K3P0n); - const double DP0na1=VP0na1+HP0na1; - const double VP2na1=+sphi*(K1P2n+K3P2n); - const double HP2na1=-cphi*(K1P2n+K3P2n); - const double DP2na1=VP2na1+HP2na1; - - - const double VA0=VA0a0*1.5 - VA0a1/2 + 2*dzvert*K2A0; - const double HA0=HA0a0*1.5 - HA0a1/2 + 2*dzhor*K2A0; - const double DA0=VA0+HA0; - const double VZA0=VA0+K2A0; - const double HZA0=HA0+K2A0; - const double DZA0=DA0+K2A0; - const double VA2=VA2a0*1.5 - VA2a1/2 + 2*dzvert*K2A2; - const double HA2=HA2a0*1.5 - HA2a1/2 + 2*dzhor*K2A2; - const double DA2=VA2+HA2; - const double VZA2=VA2+K2A2; - const double HZA2=HA2+K2A2; - const double DZA2=DA2+K2A2; - - const double VA0n=VA0na0*1.5 - VA0na1/2 + 2*dzvert*K2A0n; - const double HA0n=HA0na0*1.5 - HA0na1/2 + 2*dzhor*K2A0n; - const double DA0n=VA0n+HA0n; - const double VZA0n=VA0n+K2A0n; - const double HZA0n=HA0n+K2A0n; - const double DZA0n=DA0n+K2A0n; - const double VA2n=VA2na0*1.5 - VA2na1/2 + 2*dzvert*K2A2n; - const double HA2n=HA2na0*1.5 - HA2na1/2 + 2*dzhor*K2A2n; - const double DA2n=VA2n+HA2n; - const double VZA2n=VA2n+K2A2n; - const double HZA2n=HA2n+K2A2n; - const double DZA2n=DA2n+K2A2n; - - const double VP0=VP0a0*1.5 - VP0a1/2 + 2*dzvert*K2P0; - const double HP0=HP0a0*1.5 - HP0a1/2 + 2*dzhor*K2P0; - const double DP0=VP0+HP0; - const double VZP0=VP0+K2P0; - const double HZP0=HP0+K2P0; - const double DZP0=DP0+K2P0; - const double VP2=VP2a0*1.5 - VP2a1/2 + 2*dzvert*K2P2; - const double HP2=HP2a0*1.5 - HP2a1/2 + 2*dzhor*K2P2; - const double DP2=VP2+HP2; - const double VZP2=VP2+K2P2; - const double HZP2=HP2+K2P2; - const double DZP2=DP2+K2P2; - - const double VP0n=VP0na0*1.5 - VP0na1/2 + 2*dzvert*K2P0n; - const double HP0n=HP0na0*1.5 - HP0na1/2 + 2*dzhor*K2P0n; - const double DP0n=VP0n+HP0n; - const double VZP0n=VP0n+K2P0n; - const double HZP0n=HP0n+K2P0n; - const double DZP0n=DP0n+K2P0n; - const double VP2n=VP2na0*1.5 - VP2na1/2 + 2*dzvert*K2P2n; - const double HP2n=HP2na0*1.5 - HP2na1/2 + 2*dzhor*K2P2n; - const double DP2n=VP2n+HP2n; - const double VZP2n=VP2n+K2P2n; - const double HZP2n=HP2n+K2P2n; - const double DZP2n=DP2n+K2P2n; + const double VA0a0 = +sphi * K1A0; + const double HA0a0 = -cphi * K1A0; + const double DA0a0 = VA0a0 + HA0a0; + const double VA2a0 = +sphi * K1A2; + const double HA2a0 = -cphi * K1A2; + const double DA2a0 = VA2a0 + HA2a0; + + const double VA0na0 = +sphi * K1A0n; + const double HA0na0 = -cphi * K1A0n; + const double DA0na0 = VA0na0 + HA0na0; + const double VA2na0 = +sphi * K1A2n; + const double HA2na0 = -cphi * K1A2n; + const double DA2na0 = VA2na0 + HA2na0; + + const double VP0a0 = +sphi * K1P0; + const double HP0a0 = -cphi * K1P0; + const double DP0a0 = VP0a0 + HP0a0; + const double VP2a0 = +sphi * K1P2; + const double HP2a0 = -cphi * K1P2; + const double DP2a0 = VP2a0 + HP2a0; + + const double VP0na0 = +sphi * K1P0n; + const double HP0na0 = -cphi * K1P0n; + const double DP0na0 = VP0na0 + HP0na0; + const double VP2na0 = +sphi * K1P2n; + const double HP2na0 = -cphi * K1P2n; + const double DP2na0 = VP2na0 + HP2na0; + + const double VA0a1 = +sphi * (K1A0 + K3A0); + const double HA0a1 = -cphi * (K1A0 + K3A0); + const double DA0a1 = VA0a1 + HA0a1; + const double VA2a1 = +sphi * (K1A2 + K3A2); + const double HA2a1 = -cphi * (K1A2 + K3A2); + const double DA2a1 = VA2a1 + HA2a1; + + const double VA0na1 = +sphi * (K1A0n + K3A0n); + const double HA0na1 = -cphi * (K1A0n + K3A0n); + const double DA0na1 = VA0na1 + HA0na1; + const double VA2na1 = +sphi * (K1A2n + K3A2n); + const double HA2na1 = -cphi * (K1A2n + K3A2n); + const double DA2na1 = VA2na1 + HA2na1; + + const double VP0a1 = +sphi * (K1P0 + K3P0); + const double HP0a1 = -cphi * (K1P0 + K3P0); + const double DP0a1 = VP0a1 + HP0a1; + const double VP2a1 = +sphi * (K1P2 + K3P2); + const double HP2a1 = -cphi * (K1P2 + K3P2); + const double DP2a1 = VP2a1 + HP2a1; + + const double VP0na1 = +sphi * (K1P0n + K3P0n); + const double HP0na1 = -cphi * (K1P0n + K3P0n); + const double DP0na1 = VP0na1 + HP0na1; + const double VP2na1 = +sphi * (K1P2n + K3P2n); + const double HP2na1 = -cphi * (K1P2n + K3P2n); + const double DP2na1 = VP2na1 + HP2na1; + + const double VA0 = VA0a0 * 1.5 - VA0a1 / 2 + 2 * dzvert * K2A0; + const double HA0 = HA0a0 * 1.5 - HA0a1 / 2 + 2 * dzhor * K2A0; + const double DA0 = VA0 + HA0; + const double VZA0 = VA0 + K2A0; + const double HZA0 = HA0 + K2A0; + const double DZA0 = DA0 + K2A0; + const double VA2 = VA2a0 * 1.5 - VA2a1 / 2 + 2 * dzvert * K2A2; + const double HA2 = HA2a0 * 1.5 - HA2a1 / 2 + 2 * dzhor * K2A2; + const double DA2 = VA2 + HA2; + const double VZA2 = VA2 + K2A2; + const double HZA2 = HA2 + K2A2; + const double DZA2 = DA2 + K2A2; + + const double VA0n = VA0na0 * 1.5 - VA0na1 / 2 + 2 * dzvert * K2A0n; + const double HA0n = HA0na0 * 1.5 - HA0na1 / 2 + 2 * dzhor * K2A0n; + const double DA0n = VA0n + HA0n; + const double VZA0n = VA0n + K2A0n; + const double HZA0n = HA0n + K2A0n; + const double DZA0n = DA0n + K2A0n; + const double VA2n = VA2na0 * 1.5 - VA2na1 / 2 + 2 * dzvert * K2A2n; + const double HA2n = HA2na0 * 1.5 - HA2na1 / 2 + 2 * dzhor * K2A2n; + const double DA2n = VA2n + HA2n; + const double VZA2n = VA2n + K2A2n; + const double HZA2n = HA2n + K2A2n; + const double DZA2n = DA2n + K2A2n; + + const double VP0 = VP0a0 * 1.5 - VP0a1 / 2 + 2 * dzvert * K2P0; + const double HP0 = HP0a0 * 1.5 - HP0a1 / 2 + 2 * dzhor * K2P0; + const double DP0 = VP0 + HP0; + const double VZP0 = VP0 + K2P0; + const double HZP0 = HP0 + K2P0; + const double DZP0 = DP0 + K2P0; + const double VP2 = VP2a0 * 1.5 - VP2a1 / 2 + 2 * dzvert * K2P2; + const double HP2 = HP2a0 * 1.5 - HP2a1 / 2 + 2 * dzhor * K2P2; + const double DP2 = VP2 + HP2; + const double VZP2 = VP2 + K2P2; + const double HZP2 = HP2 + K2P2; + const double DZP2 = DP2 + K2P2; + + const double VP0n = VP0na0 * 1.5 - VP0na1 / 2 + 2 * dzvert * K2P0n; + const double HP0n = HP0na0 * 1.5 - HP0na1 / 2 + 2 * dzhor * K2P0n; + const double DP0n = VP0n + HP0n; + const double VZP0n = VP0n + K2P0n; + const double HZP0n = HP0n + K2P0n; + const double DZP0n = DP0n + K2P0n; + const double VP2n = VP2na0 * 1.5 - VP2na1 / 2 + 2 * dzvert * K2P2n; + const double HP2n = HP2na0 * 1.5 - HP2na1 / 2 + 2 * dzhor * K2P2n; + const double DP2n = VP2n + HP2n; + const double VZP2n = VP2n + K2P2n; + const double HZP2n = HP2n + K2P2n; + const double DZP2n = DP2n + K2P2n; // Initial values of update values (Up) - double A0a0 = Projptr[0][0][0][1]+ds*K1A0; - double A0a1 = Projptr[0][0][0][3]+ds*(K1A0+K3A0); - double A2a0 = Projptr[0][2][0][1]+ds*K1A2; - double A2a1 = Projptr[0][2][0][3]+ds*(K1A2+K3A2); - - double P0na0 = Projptr[1][0][1][1]+ds*K1P0n; - double P0na1 = Projptr[1][0][1][3]+ds*(K1P0n+K3P0n); - double P2na0 = Projptr[1][2][1][1]+ds*K1P2n; - double P2na1 = Projptr[1][2][1][3]+ds*(K1P2n+K3P2n); + double A0a0 = Projptr[0][0][0][1] + ds * K1A0; + double A0a1 = Projptr[0][0][0][3] + ds * (K1A0 + K3A0); + double A2a0 = Projptr[0][2][0][1] + ds * K1A2; + double A2a1 = Projptr[0][2][0][3] + ds * (K1A2 + K3A2); - double A0na0 = Projptr[1][0][0][1]+ds*K1A0n; - double A0na1 = Projptr[1][0][0][3]+ds*(K1A0n+K3A0n); - double A2na0 = Projptr[1][2][0][1]+ds*K1A2n; - double A2na1 = Projptr[1][2][0][3]+ds*(K1A2n+K3A2n); + double P0na0 = Projptr[1][0][1][1] + ds * K1P0n; + double P0na1 = Projptr[1][0][1][3] + ds * (K1P0n + K3P0n); + double P2na0 = Projptr[1][2][1][1] + ds * K1P2n; + double P2na1 = Projptr[1][2][1][3] + ds * (K1P2n + K3P2n); - double P0a0 = Projptr[0][0][1][1]+ds*K1P0; - double P0a1 = Projptr[0][0][1][3]+ds*(K1P0+K3P0); - double P2a0 = Projptr[0][2][1][1]+ds*K1P2; - double P2a1 = Projptr[0][2][1][3]+ds*(K1P2+K3P2); + double A0na0 = Projptr[1][0][0][1] + ds * K1A0n; + double A0na1 = Projptr[1][0][0][3] + ds * (K1A0n + K3A0n); + double A2na0 = Projptr[1][2][0][1] + ds * K1A2n; + double A2na1 = Projptr[1][2][0][3] + ds * (K1A2n + K3A2n); + double P0a0 = Projptr[0][0][1][1] + ds * K1P0; + double P0a1 = Projptr[0][0][1][3] + ds * (K1P0 + K3P0); + double P2a0 = Projptr[0][2][1][1] + ds * K1P2; + double P2a1 = Projptr[0][2][1][3] + ds * (K1P2 + K3P2); - double UpA0 = 2*(Projptr[0][0][0][1]+ds*K1A0+dz*K2A0) - (A0a0 + A0a1)/2; - double UpA2 = 2*(Projptr[0][2][0][1]+ds*K1A2+dz*K2A2) - (A2a0 + A2a1)/2; + double UpA0 = 2 * (Projptr[0][0][0][1] + ds * K1A0 + dz * K2A0) - (A0a0 + A0a1) / 2; + double UpA2 = 2 * (Projptr[0][2][0][1] + ds * K1A2 + dz * K2A2) - (A2a0 + A2a1) / 2; - double UpA0n = 2*(Projptr[1][0][0][1]+ds*K1A0n+dz*K2A0n) - (A0na0 + A0na1)/2; - double UpA2n = 2*(Projptr[1][2][0][1]+ds*K1A2n+dz*K2A2n) - (A2na0 + A2na1)/2; + double UpA0n = 2 * (Projptr[1][0][0][1] + ds * K1A0n + dz * K2A0n) - (A0na0 + A0na1) / 2; + double UpA2n = 2 * (Projptr[1][2][0][1] + ds * K1A2n + dz * K2A2n) - (A2na0 + A2na1) / 2; - double UpP0 = 2*(Projptr[0][0][1][1]+ds*K1P0+dz*K2P0) - (P0a0 + P0a1)/2; - double UpP2 = 2*(Projptr[0][2][1][1]+ds*K1P2+dz*K2P2) - (P2a0 + P2a1)/2; + double UpP0 = 2 * (Projptr[0][0][1][1] + ds * K1P0 + dz * K2P0) - (P0a0 + P0a1) / 2; + double UpP2 = 2 * (Projptr[0][2][1][1] + ds * K1P2 + dz * K2P2) - (P2a0 + P2a1) / 2; - double UpP0n = 2*(Projptr[1][0][1][1]+ds*K1P0n+dz*K2P0n) - (P0na0 + P0na1)/2; - double UpP2n = 2*(Projptr[1][2][1][1]+ds*K1P2n+dz*K2P2n) - (P2na0 + P2na1)/2; + double UpP0n = 2 * (Projptr[1][0][1][1] + ds * K1P0n + dz * K2P0n) - (P0na0 + P0na1) / 2; + double UpP2n = 2 * (Projptr[1][2][1][1] + ds * K1P2n + dz * K2P2n) - (P2na0 + P2na1) / 2; #endif // PIECEWISE_INTERPOLATION @@ -623,20 +592,17 @@ Recompile %s with ALTERNATIVE not #defined", __FILE__); // CL&KT 21/12/99 added axial_pos_to_z_offset and num_planes_per_physical_ring { // first compute it as floating point (although it has to be an int really) - const float Qf = (2*num_planes_per_axial_pos*(ring0 + 0.5) - + num_planes_per_physical_ring*delta - + 2*axial_pos_to_z_offset - - Z); + const float Qf = + (2 * num_planes_per_axial_pos * (ring0 + 0.5) + num_planes_per_physical_ring * delta + 2 * axial_pos_to_z_offset - Z); // now use rounding to be safe Q = (int)floor(Qf + 0.5); - assert(fabs(Q-Qf) < 10E-4); + assert(fabs(Q - Qf) < 10E-4); } - dzdiag=dzvert+dzhor; - dsdiag=-cphi+sphi; - + dzdiag = dzvert + dzhor; + dsdiag = -cphi + sphi; - /* KT 13/05/98 changed loop condition, originally a combination of + /* KT 13/05/98 changed loop condition, originally a combination of while (X>X2||YY2||Z>Z2) @@ -647,428 +613,420 @@ Recompile %s with ALTERNATIVE not #defined", __FILE__); Now I break out of the while when the voxel goes out of the cylinder, which means I don't have to use X2,Y2,Z2 anymore */ - do - { - assert(ds >= 0); - assert(ds <= 1); - assert(dz >= 0); - assert(dz <= ring_unit+epsilon); - - // Update voxel values for this X,Y,Z - // For 1 given (X,Y)-position, there are always 2 voxels along the z-axis - // in this beam - const int Zplus=Z+1; - const int Qmin=Q-1; - -#if PIECEWISE_INTERPOLATION - //KT&MJ 07/08/98 new - - // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control - const bool do_s_symmetry = (s!=0 || fabs(ds) > epsilon); - const double twodsdz=2*ds*dz; - const double twodsdz2=2*ds*(dz+0.5); - - if (Z>=minplane&&Z<=maxplane) { - // original image[Z][Y][X]+=UpA0+dsdz*K3A0 - image[Z][Y][X]+= (dz <= 0.25) ? A0a0 : UpA0+twodsdz*K3A0; - image[Z][X][-Y]+=(dz <= 0.25) ? A2a0 : UpA2 +twodsdz*K3A2; - if (do_s_symmetry) { - image[Z][-Y][-X]+= (dz <= 0.25) ? P0na0 : UpP0n +twodsdz*K3P0n; - image[Z][-X][Y]+=(dz <= 0.25) ? P2na0 : UpP2n +twodsdz*K3P2n; - } + do { + assert(ds >= 0); + assert(ds <= 1); + assert(dz >= 0); + assert(dz <= ring_unit + epsilon); + + // Update voxel values for this X,Y,Z + // For 1 given (X,Y)-position, there are always 2 voxels along the z-axis + // in this beam + const int Zplus = Z + 1; + const int Qmin = Q - 1; +#if PIECEWISE_INTERPOLATION + // KT&MJ 07/08/98 new + + // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control + const bool do_s_symmetry = (s != 0 || fabs(ds) > epsilon); + const double twodsdz = 2 * ds * dz; + const double twodsdz2 = 2 * ds * (dz + 0.5); + + if (Z >= minplane && Z <= maxplane) { + // original image[Z][Y][X]+=UpA0+dsdz*K3A0 + image[Z][Y][X] += (dz <= 0.25) ? A0a0 : UpA0 + twodsdz * K3A0; + image[Z][X][-Y] += (dz <= 0.25) ? A2a0 : UpA2 + twodsdz * K3A2; + if (do_s_symmetry) { + image[Z][-Y][-X] += (dz <= 0.25) ? P0na0 : UpP0n + twodsdz * K3P0n; + image[Z][-X][Y] += (dz <= 0.25) ? P2na0 : UpP2n + twodsdz * K3P2n; } - if (Zplus>=minplane&&Zplus<=maxplane) { - image[Zplus][Y][X]+=(dz >= 0.25) ? A0a1 : UpA0+twodsdz2*K3A0 +ZplusKorrA0; - image[Zplus][X][-Y]+=(dz >= 0.25) ? A2a1 : UpA2+twodsdz2*K3A2 +ZplusKorrA2; - if (do_s_symmetry) { - image[Zplus][-Y][-X]+=(dz >= 0.25) ? P0na1 : UpP0n+twodsdz2*K3P0n +ZplusKorrP0n; - image[Zplus][-X][Y]+=(dz >= 0.25) ? P2na1 : UpP2n+twodsdz2*K3P2n +ZplusKorrP2n; - } - + } + if (Zplus >= minplane && Zplus <= maxplane) { + image[Zplus][Y][X] += (dz >= 0.25) ? A0a1 : UpA0 + twodsdz2 * K3A0 + ZplusKorrA0; + image[Zplus][X][-Y] += (dz >= 0.25) ? A2a1 : UpA2 + twodsdz2 * K3A2 + ZplusKorrA2; + if (do_s_symmetry) { + image[Zplus][-Y][-X] += (dz >= 0.25) ? P0na1 : UpP0n + twodsdz2 * K3P0n + ZplusKorrP0n; + image[Zplus][-X][Y] += (dz >= 0.25) ? P2na1 : UpP2n + twodsdz2 * K3P2n + ZplusKorrP2n; } - if (Q>=minplane&&Q<=maxplane) { - image[Q][Y][X]+=(dz <= 0.25) ? A0na0 : UpA0n +twodsdz*K3A0n; - image[Q][X][-Y]+=(dz <= 0.25) ? A2na0 : UpA2n +twodsdz*K3A2n; - if (do_s_symmetry) { - image[Q][-Y][-X]+=(dz <= 0.25) ? P0a0 : UpP0 +twodsdz*K3P0; - image[Q][-X][Y]+=(dz <= 0.25) ? P2a0 : UpP2 +twodsdz*K3P2; - } + } + if (Q >= minplane && Q <= maxplane) { + image[Q][Y][X] += (dz <= 0.25) ? A0na0 : UpA0n + twodsdz * K3A0n; + image[Q][X][-Y] += (dz <= 0.25) ? A2na0 : UpA2n + twodsdz * K3A2n; + if (do_s_symmetry) { + image[Q][-Y][-X] += (dz <= 0.25) ? P0a0 : UpP0 + twodsdz * K3P0; + image[Q][-X][Y] += (dz <= 0.25) ? P2a0 : UpP2 + twodsdz * K3P2; } - if (Qmin>=minplane&&Qmin<=maxplane) { - image[Qmin][Y][X]+=(dz >= 0.25) ? A0na1 : UpA0n+twodsdz2*K3A0n + ZplusKorrA0n; - image[Qmin][X][-Y]+=(dz >= 0.25) ? A2na1 : UpA2n+twodsdz2*K3A2n + ZplusKorrA2n; - if (do_s_symmetry) { - image[Qmin][-Y][-X]+=(dz >= 0.25) ? P0a1 : UpP0+twodsdz2*K3P0 + ZplusKorrP0; - image[Qmin][-X][Y]+=(dz >= 0.25) ? P2a1 : UpP2+twodsdz2*K3P2 + ZplusKorrP2; - } + } + if (Qmin >= minplane && Qmin <= maxplane) { + image[Qmin][Y][X] += (dz >= 0.25) ? A0na1 : UpA0n + twodsdz2 * K3A0n + ZplusKorrA0n; + image[Qmin][X][-Y] += (dz >= 0.25) ? A2na1 : UpA2n + twodsdz2 * K3A2n + ZplusKorrA2n; + if (do_s_symmetry) { + image[Qmin][-Y][-X] += (dz >= 0.25) ? P0a1 : UpP0 + twodsdz2 * K3P0 + ZplusKorrP0; + image[Qmin][-X][Y] += (dz >= 0.25) ? P2a1 : UpP2 + twodsdz2 * K3P2 + ZplusKorrP2; } + } #else // !PIECEWISE_INTERPOLATION -#ifdef ALTERNATIVE - // This code and the one after #else are equivalent. However, this version is - // shorter, while the other version looks 'more optimal'. - // TODO check which is faster. - // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control - const bool do_s_symmetry = (s!=0 || fabs(ds) > epsilon); - const double dsdz=ds*dz; - const double dsdz2=ds*(dz+ring_unit); - - if (Z>=minplane&&Z<=maxplane) { - image[Z][Y][X]+=UpA0+dsdz*K3A0; - image[Z][X][-Y]+=UpA2+dsdz*K3A2; - if (do_s_symmetry) { - image[Z][-Y][-X]+=UpP0n+dsdz*K3P0n; - image[Z][-X][Y]+=UpP2n+dsdz*K3P2n; - } - +# ifdef ALTERNATIVE + // This code and the one after #else are equivalent. However, this version is + // shorter, while the other version looks 'more optimal'. + // TODO check which is faster. + // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control + const bool do_s_symmetry = (s != 0 || fabs(ds) > epsilon); + const double dsdz = ds * dz; + const double dsdz2 = ds * (dz + ring_unit); + + if (Z >= minplane && Z <= maxplane) { + image[Z][Y][X] += UpA0 + dsdz * K3A0; + image[Z][X][-Y] += UpA2 + dsdz * K3A2; + if (do_s_symmetry) { + image[Z][-Y][-X] += UpP0n + dsdz * K3P0n; + image[Z][-X][Y] += UpP2n + dsdz * K3P2n; } - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) { - image[Zplus][Y][X]+=UpA0+dsdz2*K3A0+ZplusKorrA0; - image[Zplus][X][-Y]+=UpA2+dsdz2*K3A2+ZplusKorrA2; - if (do_s_symmetry) { - image[Zplus][-Y][-X]+=UpP0n+dsdz2*K3P0n+ZplusKorrP0n; - image[Zplus][-X][Y]+=UpP2n+dsdz2*K3P2n+ZplusKorrP2n; - } - + } + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) { + image[Zplus][Y][X] += UpA0 + dsdz2 * K3A0 + ZplusKorrA0; + image[Zplus][X][-Y] += UpA2 + dsdz2 * K3A2 + ZplusKorrA2; + if (do_s_symmetry) { + image[Zplus][-Y][-X] += UpP0n + dsdz2 * K3P0n + ZplusKorrP0n; + image[Zplus][-X][Y] += UpP2n + dsdz2 * K3P2n + ZplusKorrP2n; } - if (Q>=minplane&&Q<=maxplane) { - image[Q][Y][X]+=UpA0n+dsdz*K3A0n; - image[Q][X][-Y]+=UpA2n+dsdz*K3A2n; - if (do_s_symmetry) { - image[Q][-Y][-X]+=UpP0+dsdz*K3P0; - image[Q][-X][Y]+=UpP2+dsdz*K3P2; - } + } + if (Q >= minplane && Q <= maxplane) { + image[Q][Y][X] += UpA0n + dsdz * K3A0n; + image[Q][X][-Y] += UpA2n + dsdz * K3A2n; + if (do_s_symmetry) { + image[Q][-Y][-X] += UpP0 + dsdz * K3P0; + image[Q][-X][Y] += UpP2 + dsdz * K3P2; } - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) { - image[Qmin][Y][X]+=UpA0n+dsdz2*K3A0n+ZplusKorrA0n; - image[Qmin][X][-Y]+=UpA2n+dsdz2*K3A2n+ZplusKorrA2n; - if (do_s_symmetry) { - image[Qmin][-Y][-X]+=UpP0+dsdz2*K3P0+ZplusKorrP0; - image[Qmin][-X][Y]+=UpP2+dsdz2*K3P2+ZplusKorrP2; - } + } + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) { + image[Qmin][Y][X] += UpA0n + dsdz2 * K3A0n + ZplusKorrA0n; + image[Qmin][X][-Y] += UpA2n + dsdz2 * K3A2n + ZplusKorrA2n; + if (do_s_symmetry) { + image[Qmin][-Y][-X] += UpP0 + dsdz2 * K3P0 + ZplusKorrP0; + image[Qmin][-X][Y] += UpP2 + dsdz2 * K3P2 + ZplusKorrP2; } -#else // ALTERNATIVE - double TMP1,TMP2; + } +# else // ALTERNATIVE + double TMP1, TMP2; - // if(Z == maxplane || Q == maxplane || Zplus == maxplane || Qmin == maxplane) + // if(Z == maxplane || Q == maxplane || Zplus == maxplane || Qmin == maxplane) // cout << " " << ring0 ; - - TMP1=ds*K3A0; - TMP2=UpA0+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][Y][X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][Y][X]+=TMP2+ring_unit*TMP1+ZplusKorrA0; - TMP1=ds*K3A2; - TMP2=UpA2+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][X][-Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][X][-Y]+=TMP2+ring_unit*TMP1+ZplusKorrA2; - - TMP1=ds*K3A0n; - TMP2=UpA0n+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][Y][X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][Y][X]+=TMP2+ring_unit*TMP1+ZplusKorrA0n; - TMP1=ds*K3A2n; - TMP2=UpA2n+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][X][-Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][X][-Y]+=TMP2+ring_unit*TMP1+ZplusKorrA2n; - - // KT 14/05/98 changed X!=-Y to s!=0 || ds!=0 to make it work for view != view45 - // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control - if (s!=0 || fabs(ds) > epsilon) { - TMP1=ds*K3P0; - TMP2=UpP0+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][-Y][-X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][-Y][-X]+=TMP2+ring_unit*TMP1+ZplusKorrP0; - TMP1=ds*K3P2; - TMP2=UpP2+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][-X][Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][-X][Y]+=TMP2+ring_unit*TMP1+ZplusKorrP2; - - TMP1=ds*K3P0n; - TMP2=UpP0n+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][-Y][-X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][-Y][-X]+=TMP2+ring_unit*TMP1+ZplusKorrP0n; - TMP1=ds*K3P2n; - TMP2=UpP2n+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][-X][Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][-X][Y]+=TMP2+ring_unit*TMP1+ZplusKorrP2n; - } -#endif // ALTERNATIVE -#endif // PIECEWISE_INTERPOLATION - // Search for next pixel in the beam - - if (ds>=cphi) { - /* horizontal*/ - X-=1; - ds-=cphi; - dz+=dzhor; - if (dz= minplane && Z <= maxplane) + image[Z][Y][X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrA0; + TMP1 = ds * K3A2; + TMP2 = UpA2 + dz * TMP1; + if (Z >= minplane && Z <= maxplane) + image[Z][X][-Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA2; + + TMP1 = ds * K3A0n; + TMP2 = UpA0n + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][Y][X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrA0n; + TMP1 = ds * K3A2n; + TMP2 = UpA2n + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][X][-Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA2n; + + // KT 14/05/98 changed X!=-Y to s!=0 || ds!=0 to make it work for view != view45 + // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control + if (s != 0 || fabs(ds) > epsilon) { + TMP1 = ds * K3P0; + TMP2 = UpP0 + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][-Y][-X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][-Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrP0; + TMP1 = ds * K3P2; + TMP2 = UpP2 + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][-X][Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][-X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP2; + + TMP1 = ds * K3P0n; + TMP2 = UpP0n + dz * TMP1; + if (Z >= minplane && Z <= maxplane) + image[Z][-Y][-X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][-Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrP0n; + TMP1 = ds * K3P2n; + TMP2 = UpP2n + dz * TMP1; + if (Z >= minplane && Z <= maxplane) + image[Z][-X][Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][-X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP2n; + } +# endif // ALTERNATIVE +#endif // PIECEWISE_INTERPOLATION + + // Search for next pixel in the beam + + if (ds >= cphi) { + /* horizontal*/ + X -= 1; + ds -= cphi; + dz += dzhor; + if (dz < epsilon) { /* increment Z */ + Z++; + Q--; + dz += ring_unit; + UpA0 += HZA0; + UpA2 += HZA2; + UpA0n += HZA0n; + UpA2n += HZA2n; + UpP0 += HZP0; + UpP2 += HZP2; + UpP0n += HZP0n; + UpP2n += HZP2n; #ifdef MOREZ - while (dz=minplane)); - + check_values(proj_data_info_sptr, delta, cphi, sphi, s, ring0, X, Y, Z, ds, dz, num_planes_per_axial_pos, + axial_pos_to_z_offset); + } while ((X * X + Y * Y <= image_rad * image_rad) && (Z <= maxplane || Q >= minplane)); } /***************************************************************************** - backproj3D_Cho_view_viewplus90_180minview_90minview backprojects 8 beams + backproj3D_Cho_view_viewplus90_180minview_90minview backprojects 8 beams related by symmetry (see bckproj.h) The structure of this function is essentially the same as the previous one. Only we have more variables because we are handling 8 viewgrams here. *****************************************************************************/ - -// KT 22/05/98 new, but extracted from backproj3D_ChoViews + +// KT 22/05/98 new, but extracted from backproj3D_ChoViews // (which used to be called Backproj_Cho_Symsphitheta_P) -void +void BackProjectorByBinUsingInterpolation:: #if PIECEWISE_INTERPOLATION -piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview + piecewise_linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview #else -linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview + linear_interpolation_backproj3D_Cho_view_viewplus90_180minview_90minview #endif - (Array<4, float > const& Projptr, - VoxelsOnCartesianGrid& image, - const shared_ptr proj_data_info_sptr, - float delta, - const double cphi, const double sphi, - int s, int ring0, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset) -{ + (Array<4, float> const& Projptr, VoxelsOnCartesianGrid& image, + const shared_ptr proj_data_info_sptr, float delta, const double cphi, + const double sphi, int s, int ring0, const int num_planes_per_axial_pos, const float axial_pos_to_z_offset) { // KT 04/05/2000 new check #if PIECEWISE_INTERPOLATION - if (num_planes_per_axial_pos==1 && delta !=0) + if (num_planes_per_axial_pos == 1 && delta != 0) error("This version of the backprojector cannot be used for span>1. \ -Recompile %s with PIECEWISE_INTERPOLATION=0", __FILE__); +Recompile %s with PIECEWISE_INTERPOLATION=0", + __FILE__); #else -#ifdef ALTERNATIVE +# ifdef ALTERNATIVE // TODO - if (num_planes_per_axial_pos==1 && delta !=0) + if (num_planes_per_axial_pos == 1 && delta != 0) error("This version of the backprojector cannot be used for span>1. \ -Recompile %s with ALTERNATIVE not #defined", __FILE__); -#endif +Recompile %s with ALTERNATIVE not #defined", + __FILE__); +# endif #endif #ifndef MOREZ @@ -1079,548 +1037,532 @@ Recompile %s with ALTERNATIVE not #defined", __FILE__); As this will slow it down, we just abort at the moment. */ - - if (delta * proj_data_info_sptr_info_cyl_ptr->get_tangential_sampling() /proj_data_info_sptr_info_cyl_ptr->get_ring_radius() > 1) - { - error("This backprojector cannot handle such oblique segments: delta = %g. Sorry.\n",delta); + if (delta * proj_data_info_sptr_info_cyl_ptr->get_tangential_sampling() / proj_data_info_sptr_info_cyl_ptr->get_ring_radius() > + 1) { + error("This backprojector cannot handle such oblique segments: delta = %g. Sorry.\n", delta); } #endif // conditions on searching flow - assert(cphi>=0-.001); - assert(sphi>=0-.001); - assert(cphi+sphi>=1-.001); + assert(cphi >= 0 - .001); + assert(sphi >= 0 - .001); + assert(cphi + sphi >= 1 - .001); - const float ring_unit = 1./num_planes_per_axial_pos; + const float ring_unit = 1. / num_planes_per_axial_pos; // CL&KT 21/12/99 new // in our current coordinate system, the following constant is always 2 const int num_planes_per_physical_ring = 2; - assert(fabs(image.get_voxel_size().z() * num_planes_per_physical_ring/ proj_data_info_sptr->get_ring_spacing() -1) < 10E-4); + assert(fabs(image.get_voxel_size().z() * num_planes_per_physical_ring / proj_data_info_sptr->get_ring_spacing() - 1) < 10E-4); - double dzvert,dzhor,ds; - double dsdiag,dzdiag,dz; - int X,Y,Z,Q; + double dzvert, dzhor, ds; + double dsdiag, dzdiag, dz; + int X, Y, Z, Q; /* FOV radius in voxel units */ // KT 20/06/2001 change calculation of FOV such that even sized image will work - const float fovrad_in_mm = - min((min(image.get_max_x(), -image.get_min_x()))*image.get_voxel_size().x(), - (min(image.get_max_y(), -image.get_min_y()))*image.get_voxel_size().y()); - const float image_rad = fovrad_in_mm/image.get_voxel_size().x() - 2; - //const int image_rad = (int)((image.get_x_size()-1)/2); - //KT 20/06/2001 allow min_z!=0 in all comparisons below - const int minplane = image.get_min_z(); - const int maxplane = image.get_max_z(); - - - if(find_start_values(proj_data_info_sptr, - delta, cphi, sphi, s, ring0, - image_rad, image.get_voxel_size().z(), - X, Y, Z, - ds, dz, dzhor, dzvert, - num_planes_per_axial_pos, - axial_pos_to_z_offset) == Succeeded::no) - { - // no voxels in the beam - return; - } + const float fovrad_in_mm = min((min(image.get_max_x(), -image.get_min_x())) * image.get_voxel_size().x(), + (min(image.get_max_y(), -image.get_min_y())) * image.get_voxel_size().y()); + const float image_rad = fovrad_in_mm / image.get_voxel_size().x() - 2; + // const int image_rad = (int)((image.get_x_size()-1)/2); + // KT 20/06/2001 allow min_z!=0 in all comparisons below + const int minplane = image.get_min_z(); + const int maxplane = image.get_max_z(); + + if (find_start_values(proj_data_info_sptr, delta, cphi, sphi, s, ring0, image_rad, image.get_voxel_size().z(), X, Y, Z, ds, dz, + dzhor, dzvert, num_planes_per_axial_pos, axial_pos_to_z_offset) == Succeeded::no) { + // no voxels in the beam + return; + } // K1, K2, K3 invariants - const double K1A0=Projptr[0][0][0][2]-Projptr[0][0][0][1]; - const double K2A0=Projptr[0][0][0][3]-Projptr[0][0][0][1]; - const double K3A0=Projptr[0][0][0][4]-Projptr[0][0][0][2]-K2A0; - const double K1A1=Projptr[0][1][0][2]-Projptr[0][1][0][1]; - const double K2A1=Projptr[0][1][0][3]-Projptr[0][1][0][1]; - const double K3A1=Projptr[0][1][0][4]-Projptr[0][1][0][2]-K2A1; - const double K1A2=Projptr[0][2][0][2]-Projptr[0][2][0][1]; - const double K2A2=Projptr[0][2][0][3]-Projptr[0][2][0][1]; - const double K3A2=Projptr[0][2][0][4]-Projptr[0][2][0][2]-K2A2; - const double K1A3=Projptr[0][3][0][2]-Projptr[0][3][0][1]; - const double K2A3=Projptr[0][3][0][3]-Projptr[0][3][0][1]; - const double K3A3=Projptr[0][3][0][4]-Projptr[0][3][0][2]-K2A3; - - const double K1A0n=Projptr[1][0][0][2]-Projptr[1][0][0][1]; - const double K2A0n=Projptr[1][0][0][3]-Projptr[1][0][0][1]; - const double K3A0n=Projptr[1][0][0][4]-Projptr[1][0][0][2]-K2A0n; - const double K1A1n=Projptr[1][1][0][2]-Projptr[1][1][0][1]; - const double K2A1n=Projptr[1][1][0][3]-Projptr[1][1][0][1]; - const double K3A1n=Projptr[1][1][0][4]-Projptr[1][1][0][2]-K2A1n; - const double K1A2n=Projptr[1][2][0][2]-Projptr[1][2][0][1]; - const double K2A2n=Projptr[1][2][0][3]-Projptr[1][2][0][1]; - const double K3A2n=Projptr[1][2][0][4]-Projptr[1][2][0][2]-K2A2n; - const double K1A3n=Projptr[1][3][0][2]-Projptr[1][3][0][1]; - const double K2A3n=Projptr[1][3][0][3]-Projptr[1][3][0][1]; - const double K3A3n=Projptr[1][3][0][4]-Projptr[1][3][0][2]-K2A3n; - - const double K1P0=Projptr[0][0][1][2]-Projptr[0][0][1][1]; - const double K2P0=Projptr[0][0][1][3]-Projptr[0][0][1][1]; - const double K3P0=Projptr[0][0][1][4]-Projptr[0][0][1][2]-K2P0; - const double K1P1=Projptr[0][1][1][2]-Projptr[0][1][1][1]; - const double K2P1=Projptr[0][1][1][3]-Projptr[0][1][1][1]; - const double K3P1=Projptr[0][1][1][4]-Projptr[0][1][1][2]-K2P1; - const double K1P2=Projptr[0][2][1][2]-Projptr[0][2][1][1]; - const double K2P2=Projptr[0][2][1][3]-Projptr[0][2][1][1]; - const double K3P2=Projptr[0][2][1][4]-Projptr[0][2][1][2]-K2P2; - const double K1P3=Projptr[0][3][1][2]-Projptr[0][3][1][1]; - const double K2P3=Projptr[0][3][1][3]-Projptr[0][3][1][1]; - const double K3P3=Projptr[0][3][1][4]-Projptr[0][3][1][2]-K2P3; - - const double K1P0n=Projptr[1][0][1][2]-Projptr[1][0][1][1]; - const double K2P0n=Projptr[1][0][1][3]-Projptr[1][0][1][1]; - const double K3P0n=Projptr[1][0][1][4]-Projptr[1][0][1][2]-K2P0n; - const double K1P1n=Projptr[1][1][1][2]-Projptr[1][1][1][1]; - const double K2P1n=Projptr[1][1][1][3]-Projptr[1][1][1][1]; - const double K3P1n=Projptr[1][1][1][4]-Projptr[1][1][1][2]-K2P1n; - const double K1P2n=Projptr[1][2][1][2]-Projptr[1][2][1][1]; - const double K2P2n=Projptr[1][2][1][3]-Projptr[1][2][1][1]; - const double K3P2n=Projptr[1][2][1][4]-Projptr[1][2][1][2]-K2P2n; - const double K1P3n=Projptr[1][3][1][2]-Projptr[1][3][1][1]; - const double K2P3n=Projptr[1][3][1][3]-Projptr[1][3][1][1]; - const double K3P3n=Projptr[1][3][1][4]-Projptr[1][3][1][2]-K2P3n; + const double K1A0 = Projptr[0][0][0][2] - Projptr[0][0][0][1]; + const double K2A0 = Projptr[0][0][0][3] - Projptr[0][0][0][1]; + const double K3A0 = Projptr[0][0][0][4] - Projptr[0][0][0][2] - K2A0; + const double K1A1 = Projptr[0][1][0][2] - Projptr[0][1][0][1]; + const double K2A1 = Projptr[0][1][0][3] - Projptr[0][1][0][1]; + const double K3A1 = Projptr[0][1][0][4] - Projptr[0][1][0][2] - K2A1; + const double K1A2 = Projptr[0][2][0][2] - Projptr[0][2][0][1]; + const double K2A2 = Projptr[0][2][0][3] - Projptr[0][2][0][1]; + const double K3A2 = Projptr[0][2][0][4] - Projptr[0][2][0][2] - K2A2; + const double K1A3 = Projptr[0][3][0][2] - Projptr[0][3][0][1]; + const double K2A3 = Projptr[0][3][0][3] - Projptr[0][3][0][1]; + const double K3A3 = Projptr[0][3][0][4] - Projptr[0][3][0][2] - K2A3; + + const double K1A0n = Projptr[1][0][0][2] - Projptr[1][0][0][1]; + const double K2A0n = Projptr[1][0][0][3] - Projptr[1][0][0][1]; + const double K3A0n = Projptr[1][0][0][4] - Projptr[1][0][0][2] - K2A0n; + const double K1A1n = Projptr[1][1][0][2] - Projptr[1][1][0][1]; + const double K2A1n = Projptr[1][1][0][3] - Projptr[1][1][0][1]; + const double K3A1n = Projptr[1][1][0][4] - Projptr[1][1][0][2] - K2A1n; + const double K1A2n = Projptr[1][2][0][2] - Projptr[1][2][0][1]; + const double K2A2n = Projptr[1][2][0][3] - Projptr[1][2][0][1]; + const double K3A2n = Projptr[1][2][0][4] - Projptr[1][2][0][2] - K2A2n; + const double K1A3n = Projptr[1][3][0][2] - Projptr[1][3][0][1]; + const double K2A3n = Projptr[1][3][0][3] - Projptr[1][3][0][1]; + const double K3A3n = Projptr[1][3][0][4] - Projptr[1][3][0][2] - K2A3n; + + const double K1P0 = Projptr[0][0][1][2] - Projptr[0][0][1][1]; + const double K2P0 = Projptr[0][0][1][3] - Projptr[0][0][1][1]; + const double K3P0 = Projptr[0][0][1][4] - Projptr[0][0][1][2] - K2P0; + const double K1P1 = Projptr[0][1][1][2] - Projptr[0][1][1][1]; + const double K2P1 = Projptr[0][1][1][3] - Projptr[0][1][1][1]; + const double K3P1 = Projptr[0][1][1][4] - Projptr[0][1][1][2] - K2P1; + const double K1P2 = Projptr[0][2][1][2] - Projptr[0][2][1][1]; + const double K2P2 = Projptr[0][2][1][3] - Projptr[0][2][1][1]; + const double K3P2 = Projptr[0][2][1][4] - Projptr[0][2][1][2] - K2P2; + const double K1P3 = Projptr[0][3][1][2] - Projptr[0][3][1][1]; + const double K2P3 = Projptr[0][3][1][3] - Projptr[0][3][1][1]; + const double K3P3 = Projptr[0][3][1][4] - Projptr[0][3][1][2] - K2P3; + + const double K1P0n = Projptr[1][0][1][2] - Projptr[1][0][1][1]; + const double K2P0n = Projptr[1][0][1][3] - Projptr[1][0][1][1]; + const double K3P0n = Projptr[1][0][1][4] - Projptr[1][0][1][2] - K2P0n; + const double K1P1n = Projptr[1][1][1][2] - Projptr[1][1][1][1]; + const double K2P1n = Projptr[1][1][1][3] - Projptr[1][1][1][1]; + const double K3P1n = Projptr[1][1][1][4] - Projptr[1][1][1][2] - K2P1n; + const double K1P2n = Projptr[1][2][1][2] - Projptr[1][2][1][1]; + const double K2P2n = Projptr[1][2][1][3] - Projptr[1][2][1][1]; + const double K3P2n = Projptr[1][2][1][4] - Projptr[1][2][1][2] - K2P2n; + const double K1P3n = Projptr[1][3][1][2] - Projptr[1][3][1][1]; + const double K2P3n = Projptr[1][3][1][3] - Projptr[1][3][1][1]; + const double K3P3n = Projptr[1][3][1][4] - Projptr[1][3][1][2] - K2P3n; #if !PIECEWISE_INTERPOLATION + const double ZplusKorrA0 = ring_unit * K2A0; + const double ZplusKorrA1 = ring_unit * K2A1; + const double ZplusKorrA2 = ring_unit * K2A2; + const double ZplusKorrA3 = ring_unit * K2A3; - const double ZplusKorrA0=ring_unit*K2A0; - const double ZplusKorrA1=ring_unit*K2A1; - const double ZplusKorrA2=ring_unit*K2A2; - const double ZplusKorrA3=ring_unit*K2A3; + const double ZplusKorrA0n = ring_unit * K2A0n; + const double ZplusKorrA1n = ring_unit * K2A1n; + const double ZplusKorrA2n = ring_unit * K2A2n; + const double ZplusKorrA3n = ring_unit * K2A3n; - const double ZplusKorrA0n=ring_unit*K2A0n; - const double ZplusKorrA1n=ring_unit*K2A1n; - const double ZplusKorrA2n=ring_unit*K2A2n; - const double ZplusKorrA3n=ring_unit*K2A3n; + const double ZplusKorrP0 = ring_unit * K2P0; + const double ZplusKorrP1 = ring_unit * K2P1; + const double ZplusKorrP2 = ring_unit * K2P2; + const double ZplusKorrP3 = ring_unit * K2P3; - const double ZplusKorrP0=ring_unit*K2P0; - const double ZplusKorrP1=ring_unit*K2P1; - const double ZplusKorrP2=ring_unit*K2P2; - const double ZplusKorrP3=ring_unit*K2P3; - - const double ZplusKorrP0n=ring_unit*K2P0n; - const double ZplusKorrP1n=ring_unit*K2P1n; - const double ZplusKorrP2n=ring_unit*K2P2n; - const double ZplusKorrP3n=ring_unit*K2P3n; + const double ZplusKorrP0n = ring_unit * K2P0n; + const double ZplusKorrP1n = ring_unit * K2P1n; + const double ZplusKorrP2n = ring_unit * K2P2n; + const double ZplusKorrP3n = ring_unit * K2P3n; // V, H, D invariants - const double VA0=dzvert*K2A0+sphi*K1A0; - const double HA0=dzhor*K2A0-cphi*K1A0; - const double DA0=VA0+HA0; - const double VZA0=VA0+ring_unit*K2A0; - const double HZA0=HA0+ring_unit*K2A0; - const double DZA0=DA0+ring_unit*K2A0; - const double VA1=dzvert*K2A1+sphi*K1A1; - const double HA1=dzhor*K2A1-cphi*K1A1; - const double DA1=VA1+HA1; - const double VZA1=VA1+ring_unit*K2A1; - const double HZA1=HA1+ring_unit*K2A1; - const double DZA1=DA1+ring_unit*K2A1; - const double VA2=dzvert*K2A2+sphi*K1A2; - const double HA2=dzhor*K2A2-cphi*K1A2; - const double DA2=VA2+HA2; - const double VZA2=VA2+ring_unit*K2A2; - const double HZA2=HA2+ring_unit*K2A2; - const double DZA2=DA2+ring_unit*K2A2; - const double VA3=dzvert*K2A3+sphi*K1A3; - const double HA3=dzhor*K2A3-cphi*K1A3; - const double DA3=VA3+HA3; - const double VZA3=VA3+ring_unit*K2A3; - const double HZA3=HA3+ring_unit*K2A3; - const double DZA3=DA3+ring_unit*K2A3; - - const double VA0n=dzvert*K2A0n+sphi*K1A0n; - const double HA0n=dzhor*K2A0n-cphi*K1A0n; - const double DA0n=VA0n+HA0n; - const double VZA0n=VA0n+ring_unit*K2A0n; - const double HZA0n=HA0n+ring_unit*K2A0n; - const double DZA0n=DA0n+ring_unit*K2A0n; - const double VA1n=dzvert*K2A1n+sphi*K1A1n; - const double HA1n=dzhor*K2A1n-cphi*K1A1n; - const double DA1n=VA1n+HA1n; - const double VZA1n=VA1n+ring_unit*K2A1n; - const double HZA1n=HA1n+ring_unit*K2A1n; - const double DZA1n=DA1n+ring_unit*K2A1n; - const double VA2n=dzvert*K2A2n+sphi*K1A2n; - const double HA2n=dzhor*K2A2n-cphi*K1A2n; - const double DA2n=VA2n+HA2n; - const double VZA2n=VA2n+ring_unit*K2A2n; - const double HZA2n=HA2n+ring_unit*K2A2n; - const double DZA2n=DA2n+ring_unit*K2A2n; - const double VA3n=dzvert*K2A3n+sphi*K1A3n; - const double HA3n=dzhor*K2A3n-cphi*K1A3n; - const double DA3n=VA3n+HA3n; - const double VZA3n=VA3n+ring_unit*K2A3n; - const double HZA3n=HA3n+ring_unit*K2A3n; - const double DZA3n=DA3n+ring_unit*K2A3n; - - const double VP0=dzvert*K2P0+sphi*K1P0; - const double HP0=dzhor*K2P0-cphi*K1P0; - const double DP0=VP0+HP0; - const double VZP0=VP0+ring_unit*K2P0; - const double HZP0=HP0+ring_unit*K2P0; - const double DZP0=DP0+ring_unit*K2P0; - const double VP1=dzvert*K2P1+sphi*K1P1; - const double HP1=dzhor*K2P1-cphi*K1P1; - const double DP1=VP1+HP1; - const double VZP1=VP1+ring_unit*K2P1; - const double HZP1=HP1+ring_unit*K2P1; - const double DZP1=DP1+ring_unit*K2P1; - const double VP2=dzvert*K2P2+sphi*K1P2; - const double HP2=dzhor*K2P2-cphi*K1P2; - const double DP2=VP2+HP2; - const double VZP2=VP2+ring_unit*K2P2; - const double HZP2=HP2+ring_unit*K2P2; - const double DZP2=DP2+ring_unit*K2P2; - const double VP3=dzvert*K2P3+sphi*K1P3; - const double HP3=dzhor*K2P3-cphi*K1P3; - const double DP3=VP3+HP3; - const double VZP3=VP3+ring_unit*K2P3; - const double HZP3=HP3+ring_unit*K2P3; - const double DZP3=DP3+ring_unit*K2P3; - - const double VP0n=dzvert*K2P0n+sphi*K1P0n; - const double HP0n=dzhor*K2P0n-cphi*K1P0n; - const double DP0n=VP0n+HP0n; - const double VZP0n=VP0n+ring_unit*K2P0n; - const double HZP0n=HP0n+ring_unit*K2P0n; - const double DZP0n=DP0n+ring_unit*K2P0n; - const double VP1n=dzvert*K2P1n+sphi*K1P1n; - const double HP1n=dzhor*K2P1n-cphi*K1P1n; - const double DP1n=VP1n+HP1n; - const double VZP1n=VP1n+ring_unit*K2P1n; - const double HZP1n=HP1n+ring_unit*K2P1n; - const double DZP1n=DP1n+ring_unit*K2P1n; - const double VP2n=dzvert*K2P2n+sphi*K1P2n; - const double HP2n=dzhor*K2P2n-cphi*K1P2n; - const double DP2n=VP2n+HP2n; - const double VZP2n=VP2n+ring_unit*K2P2n; - const double HZP2n=HP2n+ring_unit*K2P2n; - const double DZP2n=DP2n+ring_unit*K2P2n; - const double VP3n=dzvert*K2P3n+sphi*K1P3n; - const double HP3n=dzhor*K2P3n-cphi*K1P3n; - const double DP3n=VP3n+HP3n; - const double VZP3n=VP3n+ring_unit*K2P3n; - const double HZP3n=HP3n+ring_unit*K2P3n; - const double DZP3n=DP3n+ring_unit*K2P3n; - - + const double VA0 = dzvert * K2A0 + sphi * K1A0; + const double HA0 = dzhor * K2A0 - cphi * K1A0; + const double DA0 = VA0 + HA0; + const double VZA0 = VA0 + ring_unit * K2A0; + const double HZA0 = HA0 + ring_unit * K2A0; + const double DZA0 = DA0 + ring_unit * K2A0; + const double VA1 = dzvert * K2A1 + sphi * K1A1; + const double HA1 = dzhor * K2A1 - cphi * K1A1; + const double DA1 = VA1 + HA1; + const double VZA1 = VA1 + ring_unit * K2A1; + const double HZA1 = HA1 + ring_unit * K2A1; + const double DZA1 = DA1 + ring_unit * K2A1; + const double VA2 = dzvert * K2A2 + sphi * K1A2; + const double HA2 = dzhor * K2A2 - cphi * K1A2; + const double DA2 = VA2 + HA2; + const double VZA2 = VA2 + ring_unit * K2A2; + const double HZA2 = HA2 + ring_unit * K2A2; + const double DZA2 = DA2 + ring_unit * K2A2; + const double VA3 = dzvert * K2A3 + sphi * K1A3; + const double HA3 = dzhor * K2A3 - cphi * K1A3; + const double DA3 = VA3 + HA3; + const double VZA3 = VA3 + ring_unit * K2A3; + const double HZA3 = HA3 + ring_unit * K2A3; + const double DZA3 = DA3 + ring_unit * K2A3; + + const double VA0n = dzvert * K2A0n + sphi * K1A0n; + const double HA0n = dzhor * K2A0n - cphi * K1A0n; + const double DA0n = VA0n + HA0n; + const double VZA0n = VA0n + ring_unit * K2A0n; + const double HZA0n = HA0n + ring_unit * K2A0n; + const double DZA0n = DA0n + ring_unit * K2A0n; + const double VA1n = dzvert * K2A1n + sphi * K1A1n; + const double HA1n = dzhor * K2A1n - cphi * K1A1n; + const double DA1n = VA1n + HA1n; + const double VZA1n = VA1n + ring_unit * K2A1n; + const double HZA1n = HA1n + ring_unit * K2A1n; + const double DZA1n = DA1n + ring_unit * K2A1n; + const double VA2n = dzvert * K2A2n + sphi * K1A2n; + const double HA2n = dzhor * K2A2n - cphi * K1A2n; + const double DA2n = VA2n + HA2n; + const double VZA2n = VA2n + ring_unit * K2A2n; + const double HZA2n = HA2n + ring_unit * K2A2n; + const double DZA2n = DA2n + ring_unit * K2A2n; + const double VA3n = dzvert * K2A3n + sphi * K1A3n; + const double HA3n = dzhor * K2A3n - cphi * K1A3n; + const double DA3n = VA3n + HA3n; + const double VZA3n = VA3n + ring_unit * K2A3n; + const double HZA3n = HA3n + ring_unit * K2A3n; + const double DZA3n = DA3n + ring_unit * K2A3n; + + const double VP0 = dzvert * K2P0 + sphi * K1P0; + const double HP0 = dzhor * K2P0 - cphi * K1P0; + const double DP0 = VP0 + HP0; + const double VZP0 = VP0 + ring_unit * K2P0; + const double HZP0 = HP0 + ring_unit * K2P0; + const double DZP0 = DP0 + ring_unit * K2P0; + const double VP1 = dzvert * K2P1 + sphi * K1P1; + const double HP1 = dzhor * K2P1 - cphi * K1P1; + const double DP1 = VP1 + HP1; + const double VZP1 = VP1 + ring_unit * K2P1; + const double HZP1 = HP1 + ring_unit * K2P1; + const double DZP1 = DP1 + ring_unit * K2P1; + const double VP2 = dzvert * K2P2 + sphi * K1P2; + const double HP2 = dzhor * K2P2 - cphi * K1P2; + const double DP2 = VP2 + HP2; + const double VZP2 = VP2 + ring_unit * K2P2; + const double HZP2 = HP2 + ring_unit * K2P2; + const double DZP2 = DP2 + ring_unit * K2P2; + const double VP3 = dzvert * K2P3 + sphi * K1P3; + const double HP3 = dzhor * K2P3 - cphi * K1P3; + const double DP3 = VP3 + HP3; + const double VZP3 = VP3 + ring_unit * K2P3; + const double HZP3 = HP3 + ring_unit * K2P3; + const double DZP3 = DP3 + ring_unit * K2P3; + + const double VP0n = dzvert * K2P0n + sphi * K1P0n; + const double HP0n = dzhor * K2P0n - cphi * K1P0n; + const double DP0n = VP0n + HP0n; + const double VZP0n = VP0n + ring_unit * K2P0n; + const double HZP0n = HP0n + ring_unit * K2P0n; + const double DZP0n = DP0n + ring_unit * K2P0n; + const double VP1n = dzvert * K2P1n + sphi * K1P1n; + const double HP1n = dzhor * K2P1n - cphi * K1P1n; + const double DP1n = VP1n + HP1n; + const double VZP1n = VP1n + ring_unit * K2P1n; + const double HZP1n = HP1n + ring_unit * K2P1n; + const double DZP1n = DP1n + ring_unit * K2P1n; + const double VP2n = dzvert * K2P2n + sphi * K1P2n; + const double HP2n = dzhor * K2P2n - cphi * K1P2n; + const double DP2n = VP2n + HP2n; + const double VZP2n = VP2n + ring_unit * K2P2n; + const double HZP2n = HP2n + ring_unit * K2P2n; + const double DZP2n = DP2n + ring_unit * K2P2n; + const double VP3n = dzvert * K2P3n + sphi * K1P3n; + const double HP3n = dzhor * K2P3n - cphi * K1P3n; + const double DP3n = VP3n + HP3n; + const double VZP3n = VP3n + ring_unit * K2P3n; + const double HZP3n = HP3n + ring_unit * K2P3n; + const double DZP3n = DP3n + ring_unit * K2P3n; + // Initial values of update values (Up) - double UpA0=Projptr[0][0][0][1]+ds*K1A0+dz*K2A0; - double UpA1=Projptr[0][1][0][1]+ds*K1A1+dz*K2A1; - double UpA2=Projptr[0][2][0][1]+ds*K1A2+dz*K2A2; - double UpA3=Projptr[0][3][0][1]+ds*K1A3+dz*K2A3; + double UpA0 = Projptr[0][0][0][1] + ds * K1A0 + dz * K2A0; + double UpA1 = Projptr[0][1][0][1] + ds * K1A1 + dz * K2A1; + double UpA2 = Projptr[0][2][0][1] + ds * K1A2 + dz * K2A2; + double UpA3 = Projptr[0][3][0][1] + ds * K1A3 + dz * K2A3; - double UpA0n=Projptr[1][0][0][1]+ds*K1A0n+dz*K2A0n; - double UpA1n=Projptr[1][1][0][1]+ds*K1A1n+dz*K2A1n; - double UpA2n=Projptr[1][2][0][1]+ds*K1A2n+dz*K2A2n; - double UpA3n=Projptr[1][3][0][1]+ds*K1A3n+dz*K2A3n; + double UpA0n = Projptr[1][0][0][1] + ds * K1A0n + dz * K2A0n; + double UpA1n = Projptr[1][1][0][1] + ds * K1A1n + dz * K2A1n; + double UpA2n = Projptr[1][2][0][1] + ds * K1A2n + dz * K2A2n; + double UpA3n = Projptr[1][3][0][1] + ds * K1A3n + dz * K2A3n; - double UpP0=Projptr[0][0][1][1]+ds*K1P0+dz*K2P0; - double UpP1=Projptr[0][1][1][1]+ds*K1P1+dz*K2P1; - double UpP2=Projptr[0][2][1][1]+ds*K1P2+dz*K2P2; - double UpP3=Projptr[0][3][1][1]+ds*K1P3+dz*K2P3; + double UpP0 = Projptr[0][0][1][1] + ds * K1P0 + dz * K2P0; + double UpP1 = Projptr[0][1][1][1] + ds * K1P1 + dz * K2P1; + double UpP2 = Projptr[0][2][1][1] + ds * K1P2 + dz * K2P2; + double UpP3 = Projptr[0][3][1][1] + ds * K1P3 + dz * K2P3; - double UpP0n=Projptr[1][0][1][1]+ds*K1P0n+dz*K2P0n; - double UpP1n=Projptr[1][1][1][1]+ds*K1P1n+dz*K2P1n; - double UpP2n=Projptr[1][2][1][1]+ds*K1P2n+dz*K2P2n; - double UpP3n=Projptr[1][3][1][1]+ds*K1P3n+dz*K2P3n; + double UpP0n = Projptr[1][0][1][1] + ds * K1P0n + dz * K2P0n; + double UpP1n = Projptr[1][1][1][1] + ds * K1P1n + dz * K2P1n; + double UpP2n = Projptr[1][2][1][1] + ds * K1P2n + dz * K2P2n; + double UpP3n = Projptr[1][3][1][1] + ds * K1P3n + dz * K2P3n; #else // PIECEWISE_INTERPOLATION + const double ZplusKorrA0 = K2A0; + const double ZplusKorrA1 = K2A1; + const double ZplusKorrA2 = K2A2; + const double ZplusKorrA3 = K2A3; - const double ZplusKorrA0=K2A0; - const double ZplusKorrA1=K2A1; - const double ZplusKorrA2=K2A2; - const double ZplusKorrA3=K2A3; + const double ZplusKorrA0n = K2A0n; + const double ZplusKorrA1n = K2A1n; + const double ZplusKorrA2n = K2A2n; + const double ZplusKorrA3n = K2A3n; - const double ZplusKorrA0n=K2A0n; - const double ZplusKorrA1n=K2A1n; - const double ZplusKorrA2n=K2A2n; - const double ZplusKorrA3n=K2A3n; + const double ZplusKorrP0 = K2P0; + const double ZplusKorrP1 = K2P1; + const double ZplusKorrP2 = K2P2; + const double ZplusKorrP3 = K2P3; - const double ZplusKorrP0=K2P0; - const double ZplusKorrP1=K2P1; - const double ZplusKorrP2=K2P2; - const double ZplusKorrP3=K2P3; - - const double ZplusKorrP0n=K2P0n; - const double ZplusKorrP1n=K2P1n; - const double ZplusKorrP2n=K2P2n; - const double ZplusKorrP3n=K2P3n; + const double ZplusKorrP0n = K2P0n; + const double ZplusKorrP1n = K2P1n; + const double ZplusKorrP2n = K2P2n; + const double ZplusKorrP3n = K2P3n; // V, H, D invariants - const double VA0a0=+sphi*K1A0; - const double HA0a0=-cphi*K1A0; - const double DA0a0=VA0a0+HA0a0; - const double VA1a0=+sphi*K1A1; - const double HA1a0=-cphi*K1A1; - const double DA1a0=VA1a0+HA1a0; - const double VA2a0=+sphi*K1A2; - const double HA2a0=-cphi*K1A2; - const double DA2a0=VA2a0+HA2a0; - const double VA3a0=+sphi*K1A3; - const double HA3a0=-cphi*K1A3; - const double DA3a0=VA3a0+HA3a0; - - const double VA0na0=+sphi*K1A0n; - const double HA0na0=-cphi*K1A0n; - const double DA0na0=VA0na0+HA0na0; - const double VA1na0=+sphi*K1A1n; - const double HA1na0=-cphi*K1A1n; - const double DA1na0=VA1na0+HA1na0; - const double VA2na0=+sphi*K1A2n; - const double HA2na0=-cphi*K1A2n; - const double DA2na0=VA2na0+HA2na0; - const double VA3na0=+sphi*K1A3n; - const double HA3na0=-cphi*K1A3n; - const double DA3na0=VA3na0+HA3na0; - - const double VP0a0=+sphi*K1P0; - const double HP0a0=-cphi*K1P0; - const double DP0a0=VP0a0+HP0a0; - const double VP1a0=+sphi*K1P1; - const double HP1a0=-cphi*K1P1; - const double DP1a0=VP1a0+HP1a0; - const double VP2a0=+sphi*K1P2; - const double HP2a0=-cphi*K1P2; - const double DP2a0=VP2a0+HP2a0; - const double VP3a0=+sphi*K1P3; - const double HP3a0=-cphi*K1P3; - const double DP3a0=VP3a0+HP3a0; - - const double VP0na0=+sphi*K1P0n; - const double HP0na0=-cphi*K1P0n; - const double DP0na0=VP0na0+HP0na0; - const double VP1na0=+sphi*K1P1n; - const double HP1na0=-cphi*K1P1n; - const double DP1na0=VP1na0+HP1na0; - const double VP2na0=+sphi*K1P2n; - const double HP2na0=-cphi*K1P2n; - const double DP2na0=VP2na0+HP2na0; - const double VP3na0=+sphi*K1P3n; - const double HP3na0=-cphi*K1P3n; - const double DP3na0=VP3na0+HP3na0; - - - - const double VA0a1=+sphi*(K1A0+K3A0); - const double HA0a1=-cphi*(K1A0+K3A0); - const double DA0a1=VA0a1+HA0a1; - const double VA1a1=+sphi*(K1A1+K3A1); - const double HA1a1=-cphi*(K1A1+K3A1); - const double DA1a1=VA1a1+HA1a1; - const double VA2a1=+sphi*(K1A2+K3A2); - const double HA2a1=-cphi*(K1A2+K3A2); - const double DA2a1=VA2a1+HA2a1; - const double VA3a1=+sphi*(K1A3+K3A3); - const double HA3a1=-cphi*(K1A3+K3A3); - const double DA3a1=VA3a1+HA3a1; - - const double VA0na1=+sphi*(K1A0n+K3A0n); - const double HA0na1=-cphi*(K1A0n+K3A0n); - const double DA0na1=VA0na1+HA0na1; - const double VA1na1=+sphi*(K1A1n+K3A1n); - const double HA1na1=-cphi*(K1A1n+K3A1n); - const double DA1na1=VA1na1+HA1na1; - const double VA2na1=+sphi*(K1A2n+K3A2n); - const double HA2na1=-cphi*(K1A2n+K3A2n); - const double DA2na1=VA2na1+HA2na1; - const double VA3na1=+sphi*(K1A3n+K3A3n); - const double HA3na1=-cphi*(K1A3n+K3A3n); - const double DA3na1=VA3na1+HA3na1; - - const double VP0a1=+sphi*(K1P0+K3P0); - const double HP0a1=-cphi*(K1P0+K3P0); - const double DP0a1=VP0a1+HP0a1; - const double VP1a1=+sphi*(K1P1+K3P1); - const double HP1a1=-cphi*(K1P1+K3P1); - const double DP1a1=VP1a1+HP1a1; - const double VP2a1=+sphi*(K1P2+K3P2); - const double HP2a1=-cphi*(K1P2+K3P2); - const double DP2a1=VP2a1+HP2a1; - const double VP3a1=+sphi*(K1P3+K3P3); - const double HP3a1=-cphi*(K1P3+K3P3); - const double DP3a1=VP3a1+HP3a1; - - const double VP0na1=+sphi*(K1P0n+K3P0n); - const double HP0na1=-cphi*(K1P0n+K3P0n); - const double DP0na1=VP0na1+HP0na1; - const double VP1na1=+sphi*(K1P1n+K3P1n); - const double HP1na1=-cphi*(K1P1n+K3P1n); - const double DP1na1=VP1na1+HP1na1; - const double VP2na1=+sphi*(K1P2n+K3P2n); - const double HP2na1=-cphi*(K1P2n+K3P2n); - const double DP2na1=VP2na1+HP2na1; - const double VP3na1=+sphi*(K1P3n+K3P3n); - const double HP3na1=-cphi*(K1P3n+K3P3n); - const double DP3na1=VP3na1+HP3na1; - - - const double VA0=VA0a0*1.5 - VA0a1/2 + 2*dzvert*K2A0; - const double HA0=HA0a0*1.5 - HA0a1/2 + 2*dzhor*K2A0; - const double DA0=VA0+HA0; - const double VZA0=VA0+K2A0; - const double HZA0=HA0+K2A0; - const double DZA0=DA0+K2A0; - const double VA1=VA1a0*1.5 - VA1a1/2 + 2*dzvert*K2A1; - const double HA1=HA1a0*1.5 - HA1a1/2 + 2*dzhor*K2A1; - const double DA1=VA1+HA1; - const double VZA1=VA1+K2A1; - const double HZA1=HA1+K2A1; - const double DZA1=DA1+K2A1; - const double VA2=VA2a0*1.5 - VA2a1/2 + 2*dzvert*K2A2; - const double HA2=HA2a0*1.5 - HA2a1/2 + 2*dzhor*K2A2; - const double DA2=VA2+HA2; - const double VZA2=VA2+K2A2; - const double HZA2=HA2+K2A2; - const double DZA2=DA2+K2A2; - const double VA3=VA3a0*1.5 - VA3a1/2 + 2*dzvert*K2A3; - const double HA3=HA3a0*1.5 - HA3a1/2 + 2*dzhor*K2A3; - const double DA3=VA3+HA3; - const double VZA3=VA3+K2A3; - const double HZA3=HA3+K2A3; - const double DZA3=DA3+K2A3; - - const double VA0n=VA0na0*1.5 - VA0na1/2 + 2*dzvert*K2A0n; - const double HA0n=HA0na0*1.5 - HA0na1/2 + 2*dzhor*K2A0n; - const double DA0n=VA0n+HA0n; - const double VZA0n=VA0n+K2A0n; - const double HZA0n=HA0n+K2A0n; - const double DZA0n=DA0n+K2A0n; - const double VA1n=VA1na0*1.5 - VA1na1/2 + 2*dzvert*K2A1n; - const double HA1n=HA1na0*1.5 - HA1na1/2 + 2*dzhor*K2A1n; - const double DA1n=VA1n+HA1n; - const double VZA1n=VA1n+K2A1n; - const double HZA1n=HA1n+K2A1n; - const double DZA1n=DA1n+K2A1n; - const double VA2n=VA2na0*1.5 - VA2na1/2 + 2*dzvert*K2A2n; - const double HA2n=HA2na0*1.5 - HA2na1/2 + 2*dzhor*K2A2n; - const double DA2n=VA2n+HA2n; - const double VZA2n=VA2n+K2A2n; - const double HZA2n=HA2n+K2A2n; - const double DZA2n=DA2n+K2A2n; - const double VA3n=VA3na0*1.5 - VA3na1/2 + 2*dzvert*K2A3n; - const double HA3n=HA3na0*1.5 - HA3na1/2 + 2*dzhor*K2A3n; - const double DA3n=VA3n+HA3n; - const double VZA3n=VA3n+K2A3n; - const double HZA3n=HA3n+K2A3n; - const double DZA3n=DA3n+K2A3n; - - const double VP0=VP0a0*1.5 - VP0a1/2 + 2*dzvert*K2P0; - const double HP0=HP0a0*1.5 - HP0a1/2 + 2*dzhor*K2P0; - const double DP0=VP0+HP0; - const double VZP0=VP0+K2P0; - const double HZP0=HP0+K2P0; - const double DZP0=DP0+K2P0; - const double VP1=VP1a0*1.5 - VP1a1/2 + 2*dzvert*K2P1; - const double HP1=HP1a0*1.5 - HP1a1/2 + 2*dzhor*K2P1; - const double DP1=VP1+HP1; - const double VZP1=VP1+K2P1; - const double HZP1=HP1+K2P1; - const double DZP1=DP1+K2P1; - const double VP2=VP2a0*1.5 - VP2a1/2 + 2*dzvert*K2P2; - const double HP2=HP2a0*1.5 - HP2a1/2 + 2*dzhor*K2P2; - const double DP2=VP2+HP2; - const double VZP2=VP2+K2P2; - const double HZP2=HP2+K2P2; - const double DZP2=DP2+K2P2; - const double VP3=VP3a0*1.5 - VP3a1/2 + 2*dzvert*K2P3; - const double HP3=HP3a0*1.5 - HP3a1/2 + 2*dzhor*K2P3; - const double DP3=VP3+HP3; - const double VZP3=VP3+K2P3; - const double HZP3=HP3+K2P3; - const double DZP3=DP3+K2P3; - - const double VP0n=VP0na0*1.5 - VP0na1/2 + 2*dzvert*K2P0n; - const double HP0n=HP0na0*1.5 - HP0na1/2 + 2*dzhor*K2P0n; - const double DP0n=VP0n+HP0n; - const double VZP0n=VP0n+K2P0n; - const double HZP0n=HP0n+K2P0n; - const double DZP0n=DP0n+K2P0n; - const double VP1n=VP1na0*1.5 - VP1na1/2 + 2*dzvert*K2P1n; - const double HP1n=HP1na0*1.5 - HP1na1/2 + 2*dzhor*K2P1n; - const double DP1n=VP1n+HP1n; - const double VZP1n=VP1n+K2P1n; - const double HZP1n=HP1n+K2P1n; - const double DZP1n=DP1n+K2P1n; - const double VP2n=VP2na0*1.5 - VP2na1/2 + 2*dzvert*K2P2n; - const double HP2n=HP2na0*1.5 - HP2na1/2 + 2*dzhor*K2P2n; - const double DP2n=VP2n+HP2n; - const double VZP2n=VP2n+K2P2n; - const double HZP2n=HP2n+K2P2n; - const double DZP2n=DP2n+K2P2n; - const double VP3n=VP3na0*1.5 - VP3na1/2 + 2*dzvert*K2P3n; - const double HP3n=HP3na0*1.5 - HP3na1/2 + 2*dzhor*K2P3n; - const double DP3n=VP3n+HP3n; - const double VZP3n=VP3n+K2P3n; - const double HZP3n=HP3n+K2P3n; - const double DZP3n=DP3n+K2P3n; - - + const double VA0a0 = +sphi * K1A0; + const double HA0a0 = -cphi * K1A0; + const double DA0a0 = VA0a0 + HA0a0; + const double VA1a0 = +sphi * K1A1; + const double HA1a0 = -cphi * K1A1; + const double DA1a0 = VA1a0 + HA1a0; + const double VA2a0 = +sphi * K1A2; + const double HA2a0 = -cphi * K1A2; + const double DA2a0 = VA2a0 + HA2a0; + const double VA3a0 = +sphi * K1A3; + const double HA3a0 = -cphi * K1A3; + const double DA3a0 = VA3a0 + HA3a0; + + const double VA0na0 = +sphi * K1A0n; + const double HA0na0 = -cphi * K1A0n; + const double DA0na0 = VA0na0 + HA0na0; + const double VA1na0 = +sphi * K1A1n; + const double HA1na0 = -cphi * K1A1n; + const double DA1na0 = VA1na0 + HA1na0; + const double VA2na0 = +sphi * K1A2n; + const double HA2na0 = -cphi * K1A2n; + const double DA2na0 = VA2na0 + HA2na0; + const double VA3na0 = +sphi * K1A3n; + const double HA3na0 = -cphi * K1A3n; + const double DA3na0 = VA3na0 + HA3na0; + + const double VP0a0 = +sphi * K1P0; + const double HP0a0 = -cphi * K1P0; + const double DP0a0 = VP0a0 + HP0a0; + const double VP1a0 = +sphi * K1P1; + const double HP1a0 = -cphi * K1P1; + const double DP1a0 = VP1a0 + HP1a0; + const double VP2a0 = +sphi * K1P2; + const double HP2a0 = -cphi * K1P2; + const double DP2a0 = VP2a0 + HP2a0; + const double VP3a0 = +sphi * K1P3; + const double HP3a0 = -cphi * K1P3; + const double DP3a0 = VP3a0 + HP3a0; + + const double VP0na0 = +sphi * K1P0n; + const double HP0na0 = -cphi * K1P0n; + const double DP0na0 = VP0na0 + HP0na0; + const double VP1na0 = +sphi * K1P1n; + const double HP1na0 = -cphi * K1P1n; + const double DP1na0 = VP1na0 + HP1na0; + const double VP2na0 = +sphi * K1P2n; + const double HP2na0 = -cphi * K1P2n; + const double DP2na0 = VP2na0 + HP2na0; + const double VP3na0 = +sphi * K1P3n; + const double HP3na0 = -cphi * K1P3n; + const double DP3na0 = VP3na0 + HP3na0; + + const double VA0a1 = +sphi * (K1A0 + K3A0); + const double HA0a1 = -cphi * (K1A0 + K3A0); + const double DA0a1 = VA0a1 + HA0a1; + const double VA1a1 = +sphi * (K1A1 + K3A1); + const double HA1a1 = -cphi * (K1A1 + K3A1); + const double DA1a1 = VA1a1 + HA1a1; + const double VA2a1 = +sphi * (K1A2 + K3A2); + const double HA2a1 = -cphi * (K1A2 + K3A2); + const double DA2a1 = VA2a1 + HA2a1; + const double VA3a1 = +sphi * (K1A3 + K3A3); + const double HA3a1 = -cphi * (K1A3 + K3A3); + const double DA3a1 = VA3a1 + HA3a1; + + const double VA0na1 = +sphi * (K1A0n + K3A0n); + const double HA0na1 = -cphi * (K1A0n + K3A0n); + const double DA0na1 = VA0na1 + HA0na1; + const double VA1na1 = +sphi * (K1A1n + K3A1n); + const double HA1na1 = -cphi * (K1A1n + K3A1n); + const double DA1na1 = VA1na1 + HA1na1; + const double VA2na1 = +sphi * (K1A2n + K3A2n); + const double HA2na1 = -cphi * (K1A2n + K3A2n); + const double DA2na1 = VA2na1 + HA2na1; + const double VA3na1 = +sphi * (K1A3n + K3A3n); + const double HA3na1 = -cphi * (K1A3n + K3A3n); + const double DA3na1 = VA3na1 + HA3na1; + + const double VP0a1 = +sphi * (K1P0 + K3P0); + const double HP0a1 = -cphi * (K1P0 + K3P0); + const double DP0a1 = VP0a1 + HP0a1; + const double VP1a1 = +sphi * (K1P1 + K3P1); + const double HP1a1 = -cphi * (K1P1 + K3P1); + const double DP1a1 = VP1a1 + HP1a1; + const double VP2a1 = +sphi * (K1P2 + K3P2); + const double HP2a1 = -cphi * (K1P2 + K3P2); + const double DP2a1 = VP2a1 + HP2a1; + const double VP3a1 = +sphi * (K1P3 + K3P3); + const double HP3a1 = -cphi * (K1P3 + K3P3); + const double DP3a1 = VP3a1 + HP3a1; + + const double VP0na1 = +sphi * (K1P0n + K3P0n); + const double HP0na1 = -cphi * (K1P0n + K3P0n); + const double DP0na1 = VP0na1 + HP0na1; + const double VP1na1 = +sphi * (K1P1n + K3P1n); + const double HP1na1 = -cphi * (K1P1n + K3P1n); + const double DP1na1 = VP1na1 + HP1na1; + const double VP2na1 = +sphi * (K1P2n + K3P2n); + const double HP2na1 = -cphi * (K1P2n + K3P2n); + const double DP2na1 = VP2na1 + HP2na1; + const double VP3na1 = +sphi * (K1P3n + K3P3n); + const double HP3na1 = -cphi * (K1P3n + K3P3n); + const double DP3na1 = VP3na1 + HP3na1; + + const double VA0 = VA0a0 * 1.5 - VA0a1 / 2 + 2 * dzvert * K2A0; + const double HA0 = HA0a0 * 1.5 - HA0a1 / 2 + 2 * dzhor * K2A0; + const double DA0 = VA0 + HA0; + const double VZA0 = VA0 + K2A0; + const double HZA0 = HA0 + K2A0; + const double DZA0 = DA0 + K2A0; + const double VA1 = VA1a0 * 1.5 - VA1a1 / 2 + 2 * dzvert * K2A1; + const double HA1 = HA1a0 * 1.5 - HA1a1 / 2 + 2 * dzhor * K2A1; + const double DA1 = VA1 + HA1; + const double VZA1 = VA1 + K2A1; + const double HZA1 = HA1 + K2A1; + const double DZA1 = DA1 + K2A1; + const double VA2 = VA2a0 * 1.5 - VA2a1 / 2 + 2 * dzvert * K2A2; + const double HA2 = HA2a0 * 1.5 - HA2a1 / 2 + 2 * dzhor * K2A2; + const double DA2 = VA2 + HA2; + const double VZA2 = VA2 + K2A2; + const double HZA2 = HA2 + K2A2; + const double DZA2 = DA2 + K2A2; + const double VA3 = VA3a0 * 1.5 - VA3a1 / 2 + 2 * dzvert * K2A3; + const double HA3 = HA3a0 * 1.5 - HA3a1 / 2 + 2 * dzhor * K2A3; + const double DA3 = VA3 + HA3; + const double VZA3 = VA3 + K2A3; + const double HZA3 = HA3 + K2A3; + const double DZA3 = DA3 + K2A3; + + const double VA0n = VA0na0 * 1.5 - VA0na1 / 2 + 2 * dzvert * K2A0n; + const double HA0n = HA0na0 * 1.5 - HA0na1 / 2 + 2 * dzhor * K2A0n; + const double DA0n = VA0n + HA0n; + const double VZA0n = VA0n + K2A0n; + const double HZA0n = HA0n + K2A0n; + const double DZA0n = DA0n + K2A0n; + const double VA1n = VA1na0 * 1.5 - VA1na1 / 2 + 2 * dzvert * K2A1n; + const double HA1n = HA1na0 * 1.5 - HA1na1 / 2 + 2 * dzhor * K2A1n; + const double DA1n = VA1n + HA1n; + const double VZA1n = VA1n + K2A1n; + const double HZA1n = HA1n + K2A1n; + const double DZA1n = DA1n + K2A1n; + const double VA2n = VA2na0 * 1.5 - VA2na1 / 2 + 2 * dzvert * K2A2n; + const double HA2n = HA2na0 * 1.5 - HA2na1 / 2 + 2 * dzhor * K2A2n; + const double DA2n = VA2n + HA2n; + const double VZA2n = VA2n + K2A2n; + const double HZA2n = HA2n + K2A2n; + const double DZA2n = DA2n + K2A2n; + const double VA3n = VA3na0 * 1.5 - VA3na1 / 2 + 2 * dzvert * K2A3n; + const double HA3n = HA3na0 * 1.5 - HA3na1 / 2 + 2 * dzhor * K2A3n; + const double DA3n = VA3n + HA3n; + const double VZA3n = VA3n + K2A3n; + const double HZA3n = HA3n + K2A3n; + const double DZA3n = DA3n + K2A3n; + + const double VP0 = VP0a0 * 1.5 - VP0a1 / 2 + 2 * dzvert * K2P0; + const double HP0 = HP0a0 * 1.5 - HP0a1 / 2 + 2 * dzhor * K2P0; + const double DP0 = VP0 + HP0; + const double VZP0 = VP0 + K2P0; + const double HZP0 = HP0 + K2P0; + const double DZP0 = DP0 + K2P0; + const double VP1 = VP1a0 * 1.5 - VP1a1 / 2 + 2 * dzvert * K2P1; + const double HP1 = HP1a0 * 1.5 - HP1a1 / 2 + 2 * dzhor * K2P1; + const double DP1 = VP1 + HP1; + const double VZP1 = VP1 + K2P1; + const double HZP1 = HP1 + K2P1; + const double DZP1 = DP1 + K2P1; + const double VP2 = VP2a0 * 1.5 - VP2a1 / 2 + 2 * dzvert * K2P2; + const double HP2 = HP2a0 * 1.5 - HP2a1 / 2 + 2 * dzhor * K2P2; + const double DP2 = VP2 + HP2; + const double VZP2 = VP2 + K2P2; + const double HZP2 = HP2 + K2P2; + const double DZP2 = DP2 + K2P2; + const double VP3 = VP3a0 * 1.5 - VP3a1 / 2 + 2 * dzvert * K2P3; + const double HP3 = HP3a0 * 1.5 - HP3a1 / 2 + 2 * dzhor * K2P3; + const double DP3 = VP3 + HP3; + const double VZP3 = VP3 + K2P3; + const double HZP3 = HP3 + K2P3; + const double DZP3 = DP3 + K2P3; + + const double VP0n = VP0na0 * 1.5 - VP0na1 / 2 + 2 * dzvert * K2P0n; + const double HP0n = HP0na0 * 1.5 - HP0na1 / 2 + 2 * dzhor * K2P0n; + const double DP0n = VP0n + HP0n; + const double VZP0n = VP0n + K2P0n; + const double HZP0n = HP0n + K2P0n; + const double DZP0n = DP0n + K2P0n; + const double VP1n = VP1na0 * 1.5 - VP1na1 / 2 + 2 * dzvert * K2P1n; + const double HP1n = HP1na0 * 1.5 - HP1na1 / 2 + 2 * dzhor * K2P1n; + const double DP1n = VP1n + HP1n; + const double VZP1n = VP1n + K2P1n; + const double HZP1n = HP1n + K2P1n; + const double DZP1n = DP1n + K2P1n; + const double VP2n = VP2na0 * 1.5 - VP2na1 / 2 + 2 * dzvert * K2P2n; + const double HP2n = HP2na0 * 1.5 - HP2na1 / 2 + 2 * dzhor * K2P2n; + const double DP2n = VP2n + HP2n; + const double VZP2n = VP2n + K2P2n; + const double HZP2n = HP2n + K2P2n; + const double DZP2n = DP2n + K2P2n; + const double VP3n = VP3na0 * 1.5 - VP3na1 / 2 + 2 * dzvert * K2P3n; + const double HP3n = HP3na0 * 1.5 - HP3na1 / 2 + 2 * dzhor * K2P3n; + const double DP3n = VP3n + HP3n; + const double VZP3n = VP3n + K2P3n; + const double HZP3n = HP3n + K2P3n; + const double DZP3n = DP3n + K2P3n; + // Initial values of update values (Up) - - double A0a0 = Projptr[0][0][0][1]+ds*K1A0; - double A0a1 = Projptr[0][0][0][3]+ds*(K1A0+K3A0); - double A2a0 = Projptr[0][2][0][1]+ds*K1A2; - double A2a1 = Projptr[0][2][0][3]+ds*(K1A2+K3A2); - - double P0na0 = Projptr[1][0][1][1]+ds*K1P0n; - double P0na1 = Projptr[1][0][1][3]+ds*(K1P0n+K3P0n); - double P2na0 = Projptr[1][2][1][1]+ds*K1P2n; - double P2na1 = Projptr[1][2][1][3]+ds*(K1P2n+K3P2n); - - double A0na0 = Projptr[1][0][0][1]+ds*K1A0n; - double A0na1 = Projptr[1][0][0][3]+ds*(K1A0n+K3A0n); - double A2na0 = Projptr[1][2][0][1]+ds*K1A2n; - double A2na1 = Projptr[1][2][0][3]+ds*(K1A2n+K3A2n); - - double P0a0 = Projptr[0][0][1][1]+ds*K1P0; - double P0a1 = Projptr[0][0][1][3]+ds*(K1P0+K3P0); - double P2a0 = Projptr[0][2][1][1]+ds*K1P2; - double P2a1 = Projptr[0][2][1][3]+ds*(K1P2+K3P2); - - double A1a0 = Projptr[0][1][0][1]+ds*K1A1; - double A1a1 = Projptr[0][1][0][3]+ds*(K1A1+K3A1); - double A3a0 = Projptr[0][3][0][1]+ds*K1A3; - double A3a1 = Projptr[0][3][0][3]+ds*(K1A3+K3A3); - - double P1na0 = Projptr[1][1][1][1]+ds*K1P1n; - double P1na1 = Projptr[1][1][1][3]+ds*(K1P1n+K3P1n); - double P3na0 = Projptr[1][3][1][1]+ds*K1P3n; - double P3na1 = Projptr[1][3][1][3]+ds*(K1P3n+K3P3n); - - double A1na0 = Projptr[1][1][0][1]+ds*K1A1n; - double A1na1 = Projptr[1][1][0][3]+ds*(K1A1n+K3A1n); - double A3na0 = Projptr[1][3][0][1]+ds*K1A3n; - double A3na1 = Projptr[1][3][0][3]+ds*(K1A3n+K3A3n); - - double P1a0 = Projptr[0][1][1][1]+ds*K1P1; - double P1a1 = Projptr[0][1][1][3]+ds*(K1P1+K3P1); - double P3a0 = Projptr[0][3][1][1]+ds*K1P3; - double P3a1 = Projptr[0][3][1][3]+ds*(K1P3+K3P3); - - double UpA0 = 2*(Projptr[0][0][0][1]+ds*K1A0+dz*K2A0) - (A0a0 + A0a1)/2; - double UpA1 = 2*(Projptr[0][1][0][1]+ds*K1A1+dz*K2A1) - (A1a0 + A1a1)/2; - double UpA2 = 2*(Projptr[0][2][0][1]+ds*K1A2+dz*K2A2) - (A2a0 + A2a1)/2; - double UpA3 = 2*(Projptr[0][3][0][1]+ds*K1A3+dz*K2A3) - (A3a0 + A3a1)/2; - - double UpA0n = 2*(Projptr[1][0][0][1]+ds*K1A0n+dz*K2A0n) - (A0na0 + A0na1)/2; - double UpA1n = 2*(Projptr[1][1][0][1]+ds*K1A1n+dz*K2A1n) - (A1na0 + A1na1)/2; - double UpA2n = 2*(Projptr[1][2][0][1]+ds*K1A2n+dz*K2A2n) - (A2na0 + A2na1)/2; - double UpA3n = 2*(Projptr[1][3][0][1]+ds*K1A3n+dz*K2A3n) - (A3na0 + A3na1)/2; - - double UpP0 = 2*(Projptr[0][0][1][1]+ds*K1P0+dz*K2P0) - (P0a0 + P0a1)/2; - double UpP1 = 2*(Projptr[0][1][1][1]+ds*K1P1+dz*K2P1) - (P1a0 + P1a1)/2; - double UpP2 = 2*(Projptr[0][2][1][1]+ds*K1P2+dz*K2P2) - (P2a0 + P2a1)/2; - double UpP3 = 2*(Projptr[0][3][1][1]+ds*K1P3+dz*K2P3) - (P3a0 + P3a1)/2; - - double UpP0n = 2*(Projptr[1][0][1][1]+ds*K1P0n+dz*K2P0n) - (P0na0 + P0na1)/2; - double UpP1n = 2*(Projptr[1][1][1][1]+ds*K1P1n+dz*K2P1n) - (P1na0 + P1na1)/2; - double UpP2n = 2*(Projptr[1][2][1][1]+ds*K1P2n+dz*K2P2n) - (P2na0 + P2na1)/2; - double UpP3n = 2*(Projptr[1][3][1][1]+ds*K1P3n+dz*K2P3n) - (P3na0 + P3na1)/2; + + double A0a0 = Projptr[0][0][0][1] + ds * K1A0; + double A0a1 = Projptr[0][0][0][3] + ds * (K1A0 + K3A0); + double A2a0 = Projptr[0][2][0][1] + ds * K1A2; + double A2a1 = Projptr[0][2][0][3] + ds * (K1A2 + K3A2); + + double P0na0 = Projptr[1][0][1][1] + ds * K1P0n; + double P0na1 = Projptr[1][0][1][3] + ds * (K1P0n + K3P0n); + double P2na0 = Projptr[1][2][1][1] + ds * K1P2n; + double P2na1 = Projptr[1][2][1][3] + ds * (K1P2n + K3P2n); + + double A0na0 = Projptr[1][0][0][1] + ds * K1A0n; + double A0na1 = Projptr[1][0][0][3] + ds * (K1A0n + K3A0n); + double A2na0 = Projptr[1][2][0][1] + ds * K1A2n; + double A2na1 = Projptr[1][2][0][3] + ds * (K1A2n + K3A2n); + + double P0a0 = Projptr[0][0][1][1] + ds * K1P0; + double P0a1 = Projptr[0][0][1][3] + ds * (K1P0 + K3P0); + double P2a0 = Projptr[0][2][1][1] + ds * K1P2; + double P2a1 = Projptr[0][2][1][3] + ds * (K1P2 + K3P2); + + double A1a0 = Projptr[0][1][0][1] + ds * K1A1; + double A1a1 = Projptr[0][1][0][3] + ds * (K1A1 + K3A1); + double A3a0 = Projptr[0][3][0][1] + ds * K1A3; + double A3a1 = Projptr[0][3][0][3] + ds * (K1A3 + K3A3); + + double P1na0 = Projptr[1][1][1][1] + ds * K1P1n; + double P1na1 = Projptr[1][1][1][3] + ds * (K1P1n + K3P1n); + double P3na0 = Projptr[1][3][1][1] + ds * K1P3n; + double P3na1 = Projptr[1][3][1][3] + ds * (K1P3n + K3P3n); + + double A1na0 = Projptr[1][1][0][1] + ds * K1A1n; + double A1na1 = Projptr[1][1][0][3] + ds * (K1A1n + K3A1n); + double A3na0 = Projptr[1][3][0][1] + ds * K1A3n; + double A3na1 = Projptr[1][3][0][3] + ds * (K1A3n + K3A3n); + + double P1a0 = Projptr[0][1][1][1] + ds * K1P1; + double P1a1 = Projptr[0][1][1][3] + ds * (K1P1 + K3P1); + double P3a0 = Projptr[0][3][1][1] + ds * K1P3; + double P3a1 = Projptr[0][3][1][3] + ds * (K1P3 + K3P3); + + double UpA0 = 2 * (Projptr[0][0][0][1] + ds * K1A0 + dz * K2A0) - (A0a0 + A0a1) / 2; + double UpA1 = 2 * (Projptr[0][1][0][1] + ds * K1A1 + dz * K2A1) - (A1a0 + A1a1) / 2; + double UpA2 = 2 * (Projptr[0][2][0][1] + ds * K1A2 + dz * K2A2) - (A2a0 + A2a1) / 2; + double UpA3 = 2 * (Projptr[0][3][0][1] + ds * K1A3 + dz * K2A3) - (A3a0 + A3a1) / 2; + + double UpA0n = 2 * (Projptr[1][0][0][1] + ds * K1A0n + dz * K2A0n) - (A0na0 + A0na1) / 2; + double UpA1n = 2 * (Projptr[1][1][0][1] + ds * K1A1n + dz * K2A1n) - (A1na0 + A1na1) / 2; + double UpA2n = 2 * (Projptr[1][2][0][1] + ds * K1A2n + dz * K2A2n) - (A2na0 + A2na1) / 2; + double UpA3n = 2 * (Projptr[1][3][0][1] + ds * K1A3n + dz * K2A3n) - (A3na0 + A3na1) / 2; + + double UpP0 = 2 * (Projptr[0][0][1][1] + ds * K1P0 + dz * K2P0) - (P0a0 + P0a1) / 2; + double UpP1 = 2 * (Projptr[0][1][1][1] + ds * K1P1 + dz * K2P1) - (P1a0 + P1a1) / 2; + double UpP2 = 2 * (Projptr[0][2][1][1] + ds * K1P2 + dz * K2P2) - (P2a0 + P2a1) / 2; + double UpP3 = 2 * (Projptr[0][3][1][1] + ds * K1P3 + dz * K2P3) - (P3a0 + P3a1) / 2; + + double UpP0n = 2 * (Projptr[1][0][1][1] + ds * K1P0n + dz * K2P0n) - (P0na0 + P0na1) / 2; + double UpP1n = 2 * (Projptr[1][1][1][1] + ds * K1P1n + dz * K2P1n) - (P1na0 + P1na1) / 2; + double UpP2n = 2 * (Projptr[1][2][1][1] + ds * K1P2n + dz * K2P2n) - (P2na0 + P2na1) / 2; + double UpP3n = 2 * (Projptr[1][3][1][1] + ds * K1P3n + dz * K2P3n) - (P3na0 + P3na1) / 2; #endif @@ -1633,20 +1575,17 @@ Recompile %s with ALTERNATIVE not #defined", __FILE__); // CL&KT 21/12/99 added axial_pos_to_z_offset and num_planes_per_physical_ring { // first compute it as floating point (although it has to be an int really) - const float Qf = (2*num_planes_per_axial_pos*(ring0 + 0.5) - + num_planes_per_physical_ring*delta - + 2*axial_pos_to_z_offset - - Z); + const float Qf = + (2 * num_planes_per_axial_pos * (ring0 + 0.5) + num_planes_per_physical_ring * delta + 2 * axial_pos_to_z_offset - Z); // now use rounding to be safe Q = (int)floor(Qf + 0.5); - assert(fabs(Q-Qf) < 10E-4); + assert(fabs(Q - Qf) < 10E-4); } - dzdiag=dzvert+dzhor; - dsdiag=-cphi+sphi; - + dzdiag = dzvert + dzhor; + dsdiag = -cphi + sphi; - /* KT 13/05/98 changed loop condition, originally a combination of + /* KT 13/05/98 changed loop condition, originally a combination of while (X>X2||YY2||Z>Z2) @@ -1657,694 +1596,669 @@ Recompile %s with ALTERNATIVE not #defined", __FILE__); Now I break out of the while when the voxel goes out of the cylinder, which means I don't have to use X2,Y2,Z2 anymore */ - do - { - assert(ds >= 0); - assert(ds <= 1); - assert(dz >= 0); - assert(dz <= ring_unit+epsilon); - - // Update voxel values for this X,Y,Z - // For 1 given (X,Y)-position, there are always 2 voxels along the z-axis - // in this beam. - const int Zplus=Z+1; - const int Qmin=Q-1; - - + do { + assert(ds >= 0); + assert(ds <= 1); + assert(dz >= 0); + assert(dz <= ring_unit + epsilon); + + // Update voxel values for this X,Y,Z + // For 1 given (X,Y)-position, there are always 2 voxels along the z-axis + // in this beam. + const int Zplus = Z + 1; + const int Qmin = Q - 1; + #if PIECEWISE_INTERPOLATION - - const double twodsdz=2*ds*dz; - const double twodsdz2=2*ds*(dz+0.5); - // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control - const bool do_s_symmetry = (s!=0 || fabs(ds) > epsilon); - - - if (Z>=minplane&&Z<=maxplane) { - image[Z][Y][X]+=(dz <= 0.25) ? A0a0 : UpA0 +twodsdz*K3A0; - image[Z][X][-Y]+=(dz <= 0.25) ? A2a0 : UpA2 +twodsdz*K3A2; - image[Z][X][Y]+=(dz <= 0.25) ? A1na0 : UpA1n +twodsdz*K3A1n; - image[Z][Y][-X]+=(dz <= 0.25) ? A3na0 : UpA3n +twodsdz*K3A3n; - if (do_s_symmetry) - { - image[Z][-X][-Y]+=(dz <= 0.25) ? P1a0 : UpP1 +twodsdz*K3P1; - image[Z][-Y][X]+=(dz <= 0.25) ? P3a0 : UpP3 +twodsdz*K3P3; - image[Z][-Y][-X]+=(dz <= 0.25) ? P0na0 : UpP0n +twodsdz*K3P0n; - image[Z][-X][Y]+=(dz <= 0.25) ? P2na0 : UpP2n +twodsdz*K3P2n; - } + + const double twodsdz = 2 * ds * dz; + const double twodsdz2 = 2 * ds * (dz + 0.5); + // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control + const bool do_s_symmetry = (s != 0 || fabs(ds) > epsilon); + + if (Z >= minplane && Z <= maxplane) { + image[Z][Y][X] += (dz <= 0.25) ? A0a0 : UpA0 + twodsdz * K3A0; + image[Z][X][-Y] += (dz <= 0.25) ? A2a0 : UpA2 + twodsdz * K3A2; + image[Z][X][Y] += (dz <= 0.25) ? A1na0 : UpA1n + twodsdz * K3A1n; + image[Z][Y][-X] += (dz <= 0.25) ? A3na0 : UpA3n + twodsdz * K3A3n; + if (do_s_symmetry) { + image[Z][-X][-Y] += (dz <= 0.25) ? P1a0 : UpP1 + twodsdz * K3P1; + image[Z][-Y][X] += (dz <= 0.25) ? P3a0 : UpP3 + twodsdz * K3P3; + image[Z][-Y][-X] += (dz <= 0.25) ? P0na0 : UpP0n + twodsdz * K3P0n; + image[Z][-X][Y] += (dz <= 0.25) ? P2na0 : UpP2n + twodsdz * K3P2n; } - if (Zplus>=minplane&&Zplus<=maxplane) { - image[Zplus][Y][X]+=(dz >= 0.25) ? A0a1 : UpA0 +twodsdz2*K3A0+ZplusKorrA0; - image[Zplus][X][-Y]+=(dz >= 0.25) ? A2a1 : UpA2 +twodsdz2*K3A2+ZplusKorrA2; - image[Zplus][X][Y]+=(dz >= 0.25) ? A1na1 : UpA1n +twodsdz2*K3A1n+ZplusKorrA1n; - image[Zplus][Y][-X]+=(dz >= 0.25) ? A3na1 : UpA3n +twodsdz2*K3A3n+ZplusKorrA3n; - if (do_s_symmetry) - { - image[Zplus][-X][-Y]+=(dz >= 0.25) ? P1a1 : UpP1 +twodsdz2*K3P1+ZplusKorrP1; - image[Zplus][-Y][X]+=(dz >= 0.25) ? P3a1 : UpP3 +twodsdz2*K3P3+ZplusKorrP3; - image[Zplus][-Y][-X]+=(dz >= 0.25) ? P0na1 : UpP0n +twodsdz2*K3P0n+ZplusKorrP0n; - image[Zplus][-X][Y]+=(dz >= 0.25) ? P2na1 : UpP2n +twodsdz2*K3P2n+ZplusKorrP2n; - } + } + if (Zplus >= minplane && Zplus <= maxplane) { + image[Zplus][Y][X] += (dz >= 0.25) ? A0a1 : UpA0 + twodsdz2 * K3A0 + ZplusKorrA0; + image[Zplus][X][-Y] += (dz >= 0.25) ? A2a1 : UpA2 + twodsdz2 * K3A2 + ZplusKorrA2; + image[Zplus][X][Y] += (dz >= 0.25) ? A1na1 : UpA1n + twodsdz2 * K3A1n + ZplusKorrA1n; + image[Zplus][Y][-X] += (dz >= 0.25) ? A3na1 : UpA3n + twodsdz2 * K3A3n + ZplusKorrA3n; + if (do_s_symmetry) { + image[Zplus][-X][-Y] += (dz >= 0.25) ? P1a1 : UpP1 + twodsdz2 * K3P1 + ZplusKorrP1; + image[Zplus][-Y][X] += (dz >= 0.25) ? P3a1 : UpP3 + twodsdz2 * K3P3 + ZplusKorrP3; + image[Zplus][-Y][-X] += (dz >= 0.25) ? P0na1 : UpP0n + twodsdz2 * K3P0n + ZplusKorrP0n; + image[Zplus][-X][Y] += (dz >= 0.25) ? P2na1 : UpP2n + twodsdz2 * K3P2n + ZplusKorrP2n; } - if (Q>=minplane&&Q<=maxplane) { - image[Q][Y][-X]+=(dz <= 0.25) ? A3a0 : UpA3 +twodsdz*K3A3; - image[Q][Y][X]+=(dz <= 0.25) ? A0na0 : UpA0n +twodsdz*K3A0n; - image[Q][X][-Y]+=(dz <= 0.25) ? A2na0 : UpA2n +twodsdz*K3A2n; - image[Q][X][Y]+=(dz <= 0.25) ? A1a0 : UpA1 +twodsdz*K3A1; - if (do_s_symmetry) - { - image[Q][-Y][-X]+=(dz <= 0.25) ? P0a0 : UpP0 +twodsdz*K3P0; - image[Q][-X][Y]+=(dz <= 0.25) ? P2a0 : UpP2 +twodsdz*K3P2; - image[Q][-X][-Y]+=(dz <= 0.25) ? P1na0 : UpP1n +twodsdz*K3P1n; - image[Q][-Y][X]+=(dz <= 0.25) ? P3na0 : UpP3n +twodsdz*K3P3n; - } + } + if (Q >= minplane && Q <= maxplane) { + image[Q][Y][-X] += (dz <= 0.25) ? A3a0 : UpA3 + twodsdz * K3A3; + image[Q][Y][X] += (dz <= 0.25) ? A0na0 : UpA0n + twodsdz * K3A0n; + image[Q][X][-Y] += (dz <= 0.25) ? A2na0 : UpA2n + twodsdz * K3A2n; + image[Q][X][Y] += (dz <= 0.25) ? A1a0 : UpA1 + twodsdz * K3A1; + if (do_s_symmetry) { + image[Q][-Y][-X] += (dz <= 0.25) ? P0a0 : UpP0 + twodsdz * K3P0; + image[Q][-X][Y] += (dz <= 0.25) ? P2a0 : UpP2 + twodsdz * K3P2; + image[Q][-X][-Y] += (dz <= 0.25) ? P1na0 : UpP1n + twodsdz * K3P1n; + image[Q][-Y][X] += (dz <= 0.25) ? P3na0 : UpP3n + twodsdz * K3P3n; } - if (Qmin>=minplane&&Qmin<=maxplane) { - image[Qmin][Y][-X]+=(dz >= 0.25) ? A3a1 : UpA3 +twodsdz2*K3A3+ZplusKorrA3; - image[Qmin][Y][X]+=(dz >= 0.25) ? A0na1 : UpA0n +twodsdz2*K3A0n+ZplusKorrA0n; - image[Qmin][X][-Y]+=(dz >= 0.25) ? A2na1 : UpA2n +twodsdz2*K3A2n+ZplusKorrA2n; - image[Qmin][X][Y]+=(dz >= 0.25) ? A1a1 : UpA1 +twodsdz2*K3A1+ZplusKorrA1; - if (do_s_symmetry) - { - image[Qmin][-Y][-X]+=(dz >= 0.25) ? P0a1 : UpP0 +twodsdz2*K3P0+ZplusKorrP0; - image[Qmin][-X][Y]+=(dz >= 0.25) ? P2a1 : UpP2 +twodsdz2*K3P2+ZplusKorrP2; - image[Qmin][-X][-Y]+=(dz >= 0.25) ? P1na1 : UpP1n +twodsdz2*K3P1n+ZplusKorrP1n; - image[Qmin][-Y][X]+=(dz >= 0.25) ? P3na1 : UpP3n +twodsdz2*K3P3n+ZplusKorrP3n; - } + } + if (Qmin >= minplane && Qmin <= maxplane) { + image[Qmin][Y][-X] += (dz >= 0.25) ? A3a1 : UpA3 + twodsdz2 * K3A3 + ZplusKorrA3; + image[Qmin][Y][X] += (dz >= 0.25) ? A0na1 : UpA0n + twodsdz2 * K3A0n + ZplusKorrA0n; + image[Qmin][X][-Y] += (dz >= 0.25) ? A2na1 : UpA2n + twodsdz2 * K3A2n + ZplusKorrA2n; + image[Qmin][X][Y] += (dz >= 0.25) ? A1a1 : UpA1 + twodsdz2 * K3A1 + ZplusKorrA1; + if (do_s_symmetry) { + image[Qmin][-Y][-X] += (dz >= 0.25) ? P0a1 : UpP0 + twodsdz2 * K3P0 + ZplusKorrP0; + image[Qmin][-X][Y] += (dz >= 0.25) ? P2a1 : UpP2 + twodsdz2 * K3P2 + ZplusKorrP2; + image[Qmin][-X][-Y] += (dz >= 0.25) ? P1na1 : UpP1n + twodsdz2 * K3P1n + ZplusKorrP1n; + image[Qmin][-Y][X] += (dz >= 0.25) ? P3na1 : UpP3n + twodsdz2 * K3P3n + ZplusKorrP3n; } + } #else // !PIECEWISE_INTERPOLATION -#ifdef ALTERNATIVE - const double dsdz=ds*dz; - const double dsdz2=ds*(dz+0.5); - // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control - const bool do_s_symmetry = (s!=0 || fabs(ds) > epsilon); - - if (Z>=minplane&&Z<=maxplane) { - image[Z][Y][X]+=UpA0+dsdz*K3A0; - image[Z][X][-Y]+=UpA2+dsdz*K3A2; - image[Z][X][Y]+=UpA1n+dsdz*K3A1n; - image[Z][Y][-X]+=UpA3n+dsdz*K3A3n; - if (do_s_symmetry) - { - image[Z][-X][-Y]+=UpP1+dsdz*K3P1; - image[Z][-Y][X]+=UpP3+dsdz*K3P3; - image[Z][-Y][-X]+=UpP0n+dsdz*K3P0n; - image[Z][-X][Y]+=UpP2n+dsdz*K3P2n; - } +# ifdef ALTERNATIVE + const double dsdz = ds * dz; + const double dsdz2 = ds * (dz + 0.5); + // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control + const bool do_s_symmetry = (s != 0 || fabs(ds) > epsilon); + + if (Z >= minplane && Z <= maxplane) { + image[Z][Y][X] += UpA0 + dsdz * K3A0; + image[Z][X][-Y] += UpA2 + dsdz * K3A2; + image[Z][X][Y] += UpA1n + dsdz * K3A1n; + image[Z][Y][-X] += UpA3n + dsdz * K3A3n; + if (do_s_symmetry) { + image[Z][-X][-Y] += UpP1 + dsdz * K3P1; + image[Z][-Y][X] += UpP3 + dsdz * K3P3; + image[Z][-Y][-X] += UpP0n + dsdz * K3P0n; + image[Z][-X][Y] += UpP2n + dsdz * K3P2n; } - if (Zplus>=minplane&&Zplus<=maxplane) { - image[Zplus][Y][X]+=UpA0+dsdz2*K3A0+ZplusKorrA0; - image[Zplus][X][-Y]+=UpA2+dsdz2*K3A2+ZplusKorrA2; - image[Zplus][X][Y]+=UpA1n+dsdz2*K3A1n+ZplusKorrA1n; - image[Zplus][Y][-X]+=UpA3n+dsdz2*K3A3n+ZplusKorrA3n; - if (do_s_symmetry) - { - image[Zplus][-X][-Y]+=UpP1+dsdz2*K3P1+ZplusKorrP1; - image[Zplus][-Y][X]+=UpP3+dsdz2*K3P3+ZplusKorrP3; - image[Zplus][-Y][-X]+=UpP0n+dsdz2*K3P0n+ZplusKorrP0n; - image[Zplus][-X][Y]+=UpP2n+dsdz2*K3P2n+ZplusKorrP2n; - } + } + if (Zplus >= minplane && Zplus <= maxplane) { + image[Zplus][Y][X] += UpA0 + dsdz2 * K3A0 + ZplusKorrA0; + image[Zplus][X][-Y] += UpA2 + dsdz2 * K3A2 + ZplusKorrA2; + image[Zplus][X][Y] += UpA1n + dsdz2 * K3A1n + ZplusKorrA1n; + image[Zplus][Y][-X] += UpA3n + dsdz2 * K3A3n + ZplusKorrA3n; + if (do_s_symmetry) { + image[Zplus][-X][-Y] += UpP1 + dsdz2 * K3P1 + ZplusKorrP1; + image[Zplus][-Y][X] += UpP3 + dsdz2 * K3P3 + ZplusKorrP3; + image[Zplus][-Y][-X] += UpP0n + dsdz2 * K3P0n + ZplusKorrP0n; + image[Zplus][-X][Y] += UpP2n + dsdz2 * K3P2n + ZplusKorrP2n; } - if (Q>=minplane&&Q<=maxplane) { - image[Q][Y][-X]+=UpA3+dsdz*K3A3; - image[Q][Y][X]+=UpA0n+dsdz*K3A0n; - image[Q][X][-Y]+=UpA2n+dsdz*K3A2n; - image[Q][X][Y]+=UpA1+dsdz*K3A1; - if (do_s_symmetry) - { - image[Q][-Y][-X]+=UpP0+dsdz*K3P0; - image[Q][-X][Y]+=UpP2+dsdz*K3P2; - image[Q][-X][-Y]+=UpP1n+dsdz*K3P1n; - image[Q][-Y][X]+=UpP3n+dsdz*K3P3n; - } + } + if (Q >= minplane && Q <= maxplane) { + image[Q][Y][-X] += UpA3 + dsdz * K3A3; + image[Q][Y][X] += UpA0n + dsdz * K3A0n; + image[Q][X][-Y] += UpA2n + dsdz * K3A2n; + image[Q][X][Y] += UpA1 + dsdz * K3A1; + if (do_s_symmetry) { + image[Q][-Y][-X] += UpP0 + dsdz * K3P0; + image[Q][-X][Y] += UpP2 + dsdz * K3P2; + image[Q][-X][-Y] += UpP1n + dsdz * K3P1n; + image[Q][-Y][X] += UpP3n + dsdz * K3P3n; } - if (Qmin>=minplane&&Qmin<=maxplane) { - image[Qmin][Y][-X]+=UpA3+dsdz2*K3A3+ZplusKorrA3; - image[Qmin][Y][X]+=UpA0n+dsdz2*K3A0n+ZplusKorrA0n; - image[Qmin][X][-Y]+=UpA2n+dsdz2*K3A2n+ZplusKorrA2n; - image[Qmin][X][Y]+=UpA1+dsdz2*K3A1+ZplusKorrA1; - if (do_s_symmetry) - { - image[Qmin][-Y][-X]+=UpP0+dsdz2*K3P0+ZplusKorrP0; - image[Qmin][-X][Y]+=UpP2+dsdz2*K3P2+ZplusKorrP2; - image[Qmin][-X][-Y]+=UpP1n+dsdz2*K3P1n+ZplusKorrP1n; - image[Qmin][-Y][X]+=UpP3n+dsdz2*K3P3n+ZplusKorrP3n; - } + } + if (Qmin >= minplane && Qmin <= maxplane) { + image[Qmin][Y][-X] += UpA3 + dsdz2 * K3A3 + ZplusKorrA3; + image[Qmin][Y][X] += UpA0n + dsdz2 * K3A0n + ZplusKorrA0n; + image[Qmin][X][-Y] += UpA2n + dsdz2 * K3A2n + ZplusKorrA2n; + image[Qmin][X][Y] += UpA1 + dsdz2 * K3A1 + ZplusKorrA1; + if (do_s_symmetry) { + image[Qmin][-Y][-X] += UpP0 + dsdz2 * K3P0 + ZplusKorrP0; + image[Qmin][-X][Y] += UpP2 + dsdz2 * K3P2 + ZplusKorrP2; + image[Qmin][-X][-Y] += UpP1n + dsdz2 * K3P1n + ZplusKorrP1n; + image[Qmin][-Y][X] += UpP3n + dsdz2 * K3P3n + ZplusKorrP3n; } - #else // ALTERNATIVE - double TMP1,TMP2; - TMP1=ds*K3A0; - TMP2=UpA0+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][Y][X]+=TMP2; - - - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][Y][X]+=TMP2+ring_unit*TMP1+ZplusKorrA0; - - TMP1=ds*K3A1; - TMP2=UpA1+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][X][Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][X][Y]+=TMP2+ring_unit*TMP1+ZplusKorrA1; - - - TMP1=ds*K3A2; - TMP2=UpA2+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][X][-Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][X][-Y]+=TMP2+ring_unit*TMP1+ZplusKorrA2; - TMP1=ds*K3A3; - TMP2=UpA3+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][Y][-X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][Y][-X]+=TMP2+ring_unit*TMP1+ZplusKorrA3; - - TMP1=ds*K3A0n; - TMP2=UpA0n+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][Y][X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][Y][X]+=TMP2+ring_unit*TMP1+ZplusKorrA0n; - TMP1=ds*K3A1n; - TMP2=UpA1n+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][X][Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][X][Y]+=TMP2+ring_unit*TMP1+ZplusKorrA1n; - TMP1=ds*K3A2n; - TMP2=UpA2n+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][X][-Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][X][-Y]+=TMP2+ring_unit*TMP1+ZplusKorrA2n; - TMP1=ds*K3A3n; - TMP2=UpA3n+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][Y][-X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][Y][-X]+=TMP2+ring_unit*TMP1+ZplusKorrA3n; - - // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control - if (s!=0 || fabs(ds) > epsilon) - { - TMP1=ds*K3P0; - TMP2=UpP0+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][-Y][-X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][-Y][-X]+=TMP2+ring_unit*TMP1+ZplusKorrP0; - TMP1=ds*K3P1; - TMP2=UpP1+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][-X][-Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][-X][-Y]+=TMP2+ring_unit*TMP1+ZplusKorrP1; - TMP1=ds*K3P2; - TMP2=UpP2+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][-X][Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][-X][Y]+=TMP2+ring_unit*TMP1+ZplusKorrP2; - TMP1=ds*K3P3; - TMP2=UpP3+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][-Y][X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][-Y][X]+=TMP2+ring_unit*TMP1+ZplusKorrP3; - - TMP1=ds*K3P0n; - TMP2=UpP0n+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][-Y][-X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][-Y][-X]+=TMP2+ring_unit*TMP1+ZplusKorrP0n; - TMP1=ds*K3P1n; - TMP2=UpP1n+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][-X][-Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][-X][-Y]+=TMP2+ring_unit*TMP1+ZplusKorrP1n; - TMP1=ds*K3P2n; - TMP2=UpP2n+dz*TMP1; - if (Z>=minplane&&Z<=maxplane) - image[Z][-X][Y]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Zplus>=minplane&&Zplus<=maxplane && ring_unit==0.5) - image[Zplus][-X][Y]+=TMP2+ring_unit*TMP1+ZplusKorrP2n; - TMP1=ds*K3P3n; - TMP2=UpP3n+dz*TMP1; - if (Q>=minplane&&Q<=maxplane) - image[Q][-Y][X]+=TMP2; - //CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data - //as there is only one voxel in the beam in slice unit - if (Qmin>=minplane&&Qmin<=maxplane && ring_unit==0.5) - image[Qmin][-Y][X]+=TMP2+ring_unit*TMP1+ZplusKorrP3n; - } - -#endif // ALTERNATIVE -#endif //PIECEWISE_INTERPOLATION - - // Search for next pixel in the beam - - if (ds>=cphi) { - /* horizontal*/ - X-=1; - ds-=cphi; - dz+=dzhor; - if (dz= minplane && Z <= maxplane) + image[Z][Y][X] += TMP2; + + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrA0; + + TMP1 = ds * K3A1; + TMP2 = UpA1 + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][X][Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA1; + + TMP1 = ds * K3A2; + TMP2 = UpA2 + dz * TMP1; + if (Z >= minplane && Z <= maxplane) + image[Z][X][-Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA2; + TMP1 = ds * K3A3; + TMP2 = UpA3 + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][Y][-X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrA3; + + TMP1 = ds * K3A0n; + TMP2 = UpA0n + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][Y][X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrA0n; + TMP1 = ds * K3A1n; + TMP2 = UpA1n + dz * TMP1; + if (Z >= minplane && Z <= maxplane) + image[Z][X][Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA1n; + TMP1 = ds * K3A2n; + TMP2 = UpA2n + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][X][-Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrA2n; + TMP1 = ds * K3A3n; + TMP2 = UpA3n + dz * TMP1; + if (Z >= minplane && Z <= maxplane) + image[Z][Y][-X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrA3n; + + // KT 16/06/98 changed check ds!=0 to fabs(ds)>epsilon for better rounding control + if (s != 0 || fabs(ds) > epsilon) { + TMP1 = ds * K3P0; + TMP2 = UpP0 + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][-Y][-X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][-Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrP0; + TMP1 = ds * K3P1; + TMP2 = UpP1 + dz * TMP1; + if (Z >= minplane && Z <= maxplane) + image[Z][-X][-Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][-X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP1; + TMP1 = ds * K3P2; + TMP2 = UpP2 + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][-X][Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][-X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP2; + TMP1 = ds * K3P3; + TMP2 = UpP3 + dz * TMP1; + if (Z >= minplane && Z <= maxplane) + image[Z][-Y][X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][-Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrP3; + + TMP1 = ds * K3P0n; + TMP2 = UpP0n + dz * TMP1; + if (Z >= minplane && Z <= maxplane) + image[Z][-Y][-X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][-Y][-X] += TMP2 + ring_unit * TMP1 + ZplusKorrP0n; + TMP1 = ds * K3P1n; + TMP2 = UpP1n + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][-X][-Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][-X][-Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP1n; + TMP1 = ds * K3P2n; + TMP2 = UpP2n + dz * TMP1; + if (Z >= minplane && Z <= maxplane) + image[Z][-X][Y] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Zplus >= minplane && Zplus <= maxplane && ring_unit == 0.5) + image[Zplus][-X][Y] += TMP2 + ring_unit * TMP1 + ZplusKorrP2n; + TMP1 = ds * K3P3n; + TMP2 = UpP3n + dz * TMP1; + if (Q >= minplane && Q <= maxplane) + image[Q][-Y][X] += TMP2; + // CL SPAN 15/09/98 Add one more condition in order to skip the statement in case of span data + // as there is only one voxel in the beam in slice unit + if (Qmin >= minplane && Qmin <= maxplane && ring_unit == 0.5) + image[Qmin][-Y][X] += TMP2 + ring_unit * TMP1 + ZplusKorrP3n; + } + +# endif // ALTERNATIVE +#endif // PIECEWISE_INTERPOLATION + + // Search for next pixel in the beam + + if (ds >= cphi) { + /* horizontal*/ + X -= 1; + ds -= cphi; + dz += dzhor; + if (dz < epsilon) { /* increment Z */ + Z++; + Q--; + dz += ring_unit; + UpA0 += HZA0; + UpA1 += HZA1; + UpA2 += HZA2; + UpA3 += HZA3; + UpA0n += HZA0n; + UpA1n += HZA1n; + UpA2n += HZA2n; + UpA3n += HZA3n; + UpP0 += HZP0; + UpP1 += HZP1; + UpP2 += HZP2; + UpP3 += HZP3; + UpP0n += HZP0n; + UpP1n += HZP1n; + UpP2n += HZP2n; + UpP3n += HZP3n; #ifdef MOREZ - while (dz=minplane)); + check_values(proj_data_info_sptr, delta, cphi, sphi, s, ring0, X, Y, Z, ds, dz, num_planes_per_axial_pos, + axial_pos_to_z_offset); + } while ((X * X + Y * Y <= image_rad * image_rad) && (Z <= maxplane || Q >= minplane)); } - /****************************************************************************************/ - static Succeeded -find_start_values(const shared_ptr proj_data_info_sptr, - const float delta, const double cphi, const double sphi, - const int s, const int ring0, - const float image_rad, const double d_sl, - int&X1, int&Y1, int& Z1, - double& ds, double& dz, double& dzhor, double& dzvert, - const float num_planes_per_axial_pos, - const float axial_pos_to_z_offset) -{ +find_start_values(const shared_ptr proj_data_info_sptr, const float delta, + const double cphi, const double sphi, const int s, const int ring0, const float image_rad, const double d_sl, + int& X1, int& Y1, int& Z1, double& ds, double& dz, double& dzhor, double& dzvert, + const float num_planes_per_axial_pos, const float axial_pos_to_z_offset) { // use notations from Egger's thesis - const double d_p = proj_data_info_sptr->get_tangential_sampling(); - // d_xy = image.get_voxel_size().x, but we can use the bin_size here as + // d_xy = image.get_voxel_size().x, but we can use the bin_size here as // the routines.work only when these 2 are equal const double d_xy = proj_data_info_sptr->get_tangential_sampling(); - - const double R2 =square(proj_data_info_sptr->get_ring_radius()); + + const double R2 = square(proj_data_info_sptr->get_ring_radius()); /* Radius of scanner squared in Pixel^2 */ const double R2p = R2 / d_xy / d_xy; - + // TODO REMOVE ASSUMPTION const int num_planes_per_physical_ring = 2; - assert(fabs(d_sl * num_planes_per_physical_ring/proj_data_info_sptr->get_ring_spacing() -1) < 10E-4); - - /* KT 16/06/98 + assert(fabs(d_sl * num_planes_per_physical_ring / proj_data_info_sptr->get_ring_spacing() - 1) < 10E-4); + + /* KT 16/06/98 This code should select a pixel inside the FOV. I tried to set rpix=image_rad, and X1 = (int)(X1f<0 ? ceil(X1f) : floor(X1f)); Y1 = (int)(Y1f<0 ? ceil(Y1f) : floor(Y1f)); - Up to this point it is fine. However, it would also require (messy?) + Up to this point it is fine. However, it would also require (messy?) modifications of the 'push back into beam' code, so I gave up. - + So, now we simply take rpix=image_rad-1. This means that sometimes a pixel close to the border is not selected. Not that anyone cares... */ - int rpix = round(image_rad-1); /* Radius of target image in voxel units */ + int rpix = round(image_rad - 1); /* Radius of target image in voxel units */ const double r2 = rpix * rpix * d_xy * d_xy; /* Radius squared of target image in mm^2 */ - - -//Formula in Eq 6.12 of Egger Matthias PhD + + // Formula in Eq 6.12 of Egger Matthias PhD // First compute X1, Y1 // KT 16/06/98 added const - const double t = s + 0.5; /* In a beam, not on a ray */ + const double t = s + 0.5; /* In a beam, not on a ray */ // KT 25/09/2001 replace assert() with return value // check if there is any pixel in the beam if (t > rpix) return Succeeded::no; - { - const double root = sqrt(rpix * rpix - t * t);// Eq 6.12 in EGger Thesis - const double X1f = t * cphi + sphi * root; /* Only valid if d_xy = d_p from Eq 6.12 in EGger Thesis */ - //const double X2f = t * cphi - sphi * root; - const double Y1f = t * sphi - cphi * root;// Eq 6.12 in EGger Thesis - //const double Y2f = t * sphi + cphi * root; + { + const double root = sqrt(rpix * rpix - t * t); // Eq 6.12 in EGger Thesis + const double X1f = t * cphi + sphi * root; /* Only valid if d_xy = d_p from Eq 6.12 in EGger Thesis */ + // const double X2f = t * cphi - sphi * root; + const double Y1f = t * sphi - cphi * root; // Eq 6.12 in EGger Thesis + // const double Y2f = t * sphi + cphi * root; // KTTODO when using even number of bins, this should be floor(X1f) + .5 - X1 = (int) floor(X1f + 0.5); - //X2 = (int) floor(X2f + 0.5); - Y1 = (int) floor(Y1f + 0.5); - //Y2 = (int) floor(Y2f + 0.5); + X1 = (int)floor(X1f + 0.5); + // X2 = (int) floor(X2f + 0.5); + Y1 = (int)floor(Y1f + 0.5); + // Y2 = (int) floor(Y2f + 0.5); } - // Compute ds = difference between s and s-projection of selected voxel // KT 22/05/98 we don't need t later on - //t=X1*cphi+Y1*sphi; - //ds=t-s; - ds=X1*cphi+Y1*sphi-s;// Eq 6.13 in Egger thsis + // t=X1*cphi+Y1*sphi; + // ds=t-s; + ds = X1 * cphi + Y1 * sphi - s; // Eq 6.13 in Egger thsis // Note that X1f*cphi+Y1f*sphi == t == s + 0.5, so // ds == (X1-X1f)*cphi + (Y1-Y1f)*sphi + 0.5, hence // -(cphi + sphi)/2 + 0.5 <= ds <= (cphi + sphi)/2 + 0.5 /* Push voxel back into beam */ - // KT 16/06/98 I now always use the cos(phi) case + // KT 16/06/98 I now always use the cos(phi) case // For example, when ds<0, adding sin(phi) is not guaranteed to make it positive // (where the most obvious example was phi==0, although I did treat that correctly). // On the other hand ds + cphi >= (cphi-sphi)/2 + 0.5, which is >=0.5 as // 0<=phi<=45 (in fact, it is still >=0 if 45epsilon) { @@ -2355,15 +2269,14 @@ find_start_values(const shared_ptr proj_da } else #endif - { - X1++; - //X2--; - //t+=cphi; - ds+=cphi; - // Now 0.5 <= (cphi-sphi)/2 + 0.5 <= ds < cphi+epsilon - } - } else if (ds>=1.) - { + { + X1++; + // X2--; + // t+=cphi; + ds += cphi; + // Now 0.5 <= (cphi-sphi)/2 + 0.5 <= ds < cphi+epsilon + } + } else if (ds >= 1.) { #if 0 if(sphi>epsilon) { @@ -2374,53 +2287,55 @@ find_start_values(const shared_ptr proj_da } else #endif - { - X1--; - //X2++; - //t-=cphi; - ds-=cphi; - // Now 0 <= 1-cphi<= ds <= -(cphi-sphi)/2 + 0.5 <= 0.5 - } - } + { + X1--; + // X2++; + // t-=cphi; + ds -= cphi; + // Now 0 <= 1-cphi<= ds <= -(cphi-sphi)/2 + 0.5 <= 0.5 + } + } // At the end of all this, 0 <= ds < 1 // Now find Z1 // Note that t=s+.5 { - const double t2dp2 = t * t * d_p * d_p;//Eq 6.12 in EGger thesis - //const double ttheta =(delta * d_sl / sqrt(R2 - t2dp2));//Equivalent to tan(theta) see Eq 6.10 in Egger thesis except that d_r/2 has been replaced to d_sl - + const double t2dp2 = t * t * d_p * d_p; // Eq 6.12 in EGger thesis + // const double ttheta =(delta * d_sl / sqrt(R2 - t2dp2));//Equivalent to tan(theta) see Eq 6.10 in Egger thesis except that + // d_r/2 has been replaced to d_sl + if (t2dp2 >= R2 || t2dp2 > r2) return Succeeded::no; const double root1 = sqrt(R2 - t2dp2); - const double root2 = sqrt(r2 - t2dp2); + const double root2 = sqrt(r2 - t2dp2); // Eq 6.12 in Egger's thesis - // const double Z1f = 2 * ring0 + 1 + (ttheta * (root1 - root2))/d_sl: + // const double Z1f = 2 * ring0 + 1 + (ttheta * (root1 - root2))/d_sl: // equivalent formula: // Z1f = 2 * ring0 + 1 + delta * (1 - root2/root1) - // We convert this to 'general' sizes of planes w.r.t. rings + // We convert this to 'general' sizes of planes w.r.t. rings // KT&CL 22/12/99 inserted offset - const double Z1f = - num_planes_per_axial_pos*(ring0 + 0.5) + axial_pos_to_z_offset - + num_planes_per_physical_ring*delta/2 * (1 - root2/root1); - //const double Z2f = (ring0 + 0.5)/ring_unit + (ttheta * (root1 + root2))/d_sl; + const double Z1f = num_planes_per_axial_pos * (ring0 + 0.5) + axial_pos_to_z_offset + + num_planes_per_physical_ring * delta / 2 * (1 - root2 / root1); + // const double Z2f = (ring0 + 0.5)/ring_unit + (ttheta * (root1 + root2))/d_sl; // TODO possible problem for negative Z1f, use floor() instead - Z1 = (int) floor(Z1f); + Z1 = (int)floor(Z1f); - //Z2 = (int) Z2f; + // Z2 = (int) Z2f; } { // Compute 'z' (formula 6.15 in Egger's thesis) which is the ring coordinate of the // projection of the voxel X1,Y1,Z1 - const double root=sqrt(R2p-t*t);//CL 26/10/98 Put it back the original formula as before it was root=sqrt(R2p-s*s) - //const double z=ring_unit*( Z1-delta*( (-X1*sphi+Y1*cphi)/root + 1 ) );// Eq 6.15 from Egger Thesis//CL SPAN 14/09/98 2*delta + const double root = sqrt(R2p - t * t); // CL 26/10/98 Put it back the original formula as before it was root=sqrt(R2p-s*s) + // const double z=ring_unit*( Z1-delta*( (-X1*sphi+Y1*cphi)/root + 1 ) );// Eq 6.15 from Egger Thesis//CL SPAN 14/09/98 + // 2*delta // KT&CL 22/12/99 inserted offset - const double z=( Z1-num_planes_per_physical_ring*delta/2*( (-X1*sphi+Y1*cphi)/root + 1 ) - - axial_pos_to_z_offset)/num_planes_per_axial_pos; - dz=z-ring0; + const double z = + (Z1 - num_planes_per_physical_ring * delta / 2 * ((-X1 * sphi + Y1 * cphi) / root + 1) - axial_pos_to_z_offset) / + num_planes_per_axial_pos; + dz = z - ring0; // Using the same formula (z=...) for X1f, Y1f, Z1f gives zf = ring0+ 0.5 // As the difference between X1f, Y1f, Z1f and X1,Y1,Y2 is at most 1 in every coordinate, // -1/2 - delta/root/2 <= z - zf <= delta/root/2, so @@ -2429,39 +2344,34 @@ find_start_values(const shared_ptr proj_da // For some scanners though (e.g. HiDAC) this is not true, so we keep on checking if // dz is in the appropriate range - /* Push voxel back into beam */ // KT 01/06/98 added 'else' here for the case when dz=1/num_planes_per_axial_pos, the first step puts it to 0, - // the 2nd step shouldn't do anything (dz<0), but because we compare with epsilon, + // the 2nd step shouldn't do anything (dz<0), but because we compare with epsilon, // it got back to .5 - + // MOREZ: if ->while - if (dz>=1./num_planes_per_axial_pos) + if (dz >= 1. / num_planes_per_axial_pos) { + while (dz >= 1. / num_planes_per_axial_pos) { + Z1--; + // z-=1/num_planes_per_axial_pos; + dz -= 1. / num_planes_per_axial_pos; + } + } else // if { - while (dz>=1./num_planes_per_axial_pos) - { - Z1--; - //z-=1/num_planes_per_axial_pos; - dz-=1./num_planes_per_axial_pos; - } - } - else //if - { - while (dzproj_matrix_ptr.reset(); BackProjectorByBin::set_defaults(); } void -BackProjectorByBinUsingProjMatrixByBin:: -initialise_keymap() -{ +BackProjectorByBinUsingProjMatrixByBin::initialise_keymap() { parser.add_start_key("Back Projector Using Matrix Parameters"); parser.add_stop_key("End Back Projector Using Matrix Parameters"); parser.add_parsing_key("matrix type", &proj_matrix_ptr); BackProjectorByBin::initialise_keymap(); } - bool -BackProjectorByBinUsingProjMatrixByBin:: -post_processing() -{ - //if (BackProjectorByBin::post_processing() == true) +BackProjectorByBinUsingProjMatrixByBin::post_processing() { + // if (BackProjectorByBin::post_processing() == true) // return true; - if (is_null_ptr(proj_matrix_ptr)) - { + if (is_null_ptr(proj_matrix_ptr)) { warning("BackProjectorByBinUsingProjMatrixByBin: matrix not set.\n"); return true; } return false; } -BackProjectorByBinUsingProjMatrixByBin:: -BackProjectorByBinUsingProjMatrixByBin() -{ - set_defaults(); -} +BackProjectorByBinUsingProjMatrixByBin::BackProjectorByBinUsingProjMatrixByBin() { set_defaults(); } -BackProjectorByBinUsingProjMatrixByBin:: -BackProjectorByBinUsingProjMatrixByBin( - const shared_ptr& proj_matrix_ptr - ) - : proj_matrix_ptr(proj_matrix_ptr) -{ +BackProjectorByBinUsingProjMatrixByBin::BackProjectorByBinUsingProjMatrixByBin(const shared_ptr& proj_matrix_ptr) + : proj_matrix_ptr(proj_matrix_ptr) { if (is_null_ptr(proj_matrix_ptr)) error("BackProjector initialised with zero projection matrix ptr"); } void -BackProjectorByBinUsingProjMatrixByBin:: -set_up(const shared_ptr& proj_data_info_ptr, - const shared_ptr >& image_info_ptr) +BackProjectorByBinUsingProjMatrixByBin::set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& image_info_ptr) { BackProjectorByBin::set_up(proj_data_info_ptr, image_info_ptr); proj_matrix_ptr->set_up(proj_data_info_ptr, image_info_ptr); } -const DataSymmetriesForViewSegmentNumbers * -BackProjectorByBinUsingProjMatrixByBin::get_symmetries_used() const -{ +const DataSymmetriesForViewSegmentNumbers* +BackProjectorByBinUsingProjMatrixByBin::get_symmetries_used() const { if (!this->_already_set_up) error("BackProjectorByBin method called without calling set_up first."); return proj_matrix_ptr->get_symmetries_ptr(); } -void -BackProjectorByBinUsingProjMatrixByBin:: -actual_back_project(DiscretisedDensity<3,float>& image, - const RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ +void +BackProjectorByBinUsingProjMatrixByBin::actual_back_project(DiscretisedDensity<3, float>& image, + const RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { if (proj_matrix_ptr->is_cache_enabled()/* && !proj_matrix_ptr->does_cache_store_only_basic_bins()*/) { - // straightforward version which relies on ProjMatrixByBin to sort out all - // symmetries - // would be slow if there's no caching at all, but is very fast if everything is cached - - ProjMatrixElemsForOneBin proj_matrix_row; - - RelatedViewgrams::const_iterator r_viewgrams_iter = viewgrams.begin(); - - while( r_viewgrams_iter!=viewgrams.end()) - { - const Viewgram& viewgram = *r_viewgrams_iter; - const int view_num = viewgram.get_view_num(); - const int segment_num = viewgram.get_segment_num(); - - for ( int tang_pos = min_tangential_pos_num ;tang_pos <= max_tangential_pos_num ;++tang_pos) - for ( int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num ;++ax_pos) - { - // KT 21/02/2002 added check on 0 - if (viewgram[ax_pos][tang_pos] == 0) - continue; - Bin bin(segment_num, view_num, ax_pos, tang_pos, viewgram[ax_pos][tang_pos]); - proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, bin); - proj_matrix_row.back_project(image, bin); - } - ++r_viewgrams_iter; - } - } - else - { - // complicated version which handles the symmetries explicitly - // faster when no caching is performed, about just as fast when there is caching - ProjMatrixElemsForOneBin proj_matrix_row; - ProjMatrixElemsForOneBin proj_matrix_row_copy; - const DataSymmetriesForBins* symmetries = proj_matrix_ptr->get_symmetries_ptr(); - - Array<2,int> - already_processed(IndexRange2D(min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num)); - - vector related_ax_tang_poss; - for ( int tang_pos = min_tangential_pos_num ;tang_pos <= max_tangential_pos_num ;++tang_pos) - for ( int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num ;++ax_pos) - { - if (already_processed[ax_pos][tang_pos]) - continue; - - Bin basic_bin(viewgrams.get_basic_segment_num(), - viewgrams.get_basic_view_num(), - ax_pos, - tang_pos); - symmetries->find_basic_bin(basic_bin); - - proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, basic_bin); - - related_ax_tang_poss.resize(0); - symmetries->get_related_bins_factorised(related_ax_tang_poss,basic_bin, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - - for ( + // straightforward version which relies on ProjMatrixByBin to sort out all + // symmetries + // would be slow if there's no caching at all, but is very fast if everything is cached + + ProjMatrixElemsForOneBin proj_matrix_row; + + RelatedViewgrams::const_iterator r_viewgrams_iter = viewgrams.begin(); + + while (r_viewgrams_iter != viewgrams.end()) { + const Viewgram& viewgram = *r_viewgrams_iter; + const int view_num = viewgram.get_view_num(); + const int segment_num = viewgram.get_segment_num(); + const int timing_num = viewgram.get_timing_pos_num(); + + for (int tang_pos = min_tangential_pos_num; tang_pos <= max_tangential_pos_num; ++tang_pos) + for (int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num; ++ax_pos) { + // KT 21/02/2002 added check on 0 + if (viewgram[ax_pos][tang_pos] == 0) + continue; + Bin bin(segment_num, view_num, ax_pos, tang_pos, timing_num, viewgram[ax_pos][tang_pos]); + proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, bin); + proj_matrix_row.back_project(image, bin); + } + ++r_viewgrams_iter; + } + } else { + // complicated version which handles the symmetries explicitly + // faster when no caching is performed, about just as fast when there is caching + ProjMatrixElemsForOneBin proj_matrix_row; + ProjMatrixElemsForOneBin proj_matrix_row_copy; + const DataSymmetriesForBins* symmetries = proj_matrix_ptr->get_symmetries_ptr(); + + Array<2, int> already_processed( + IndexRange2D(min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num)); + + vector related_ax_tang_poss; + for (int tang_pos = min_tangential_pos_num; tang_pos <= max_tangential_pos_num; ++tang_pos) + for (int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num; ++ax_pos) { + if (already_processed[ax_pos][tang_pos]) + continue; + + Bin basic_bin(viewgrams.get_basic_segment_num(), viewgrams.get_basic_view_num(), ax_pos, tang_pos, + viewgrams.get_basic_timing_pos_num()); + symmetries->find_basic_bin(basic_bin); + + proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, basic_bin); + + related_ax_tang_poss.resize(0); + symmetries->get_related_bins_factorised(related_ax_tang_poss, basic_bin, min_axial_pos_num, max_axial_pos_num, + min_tangential_pos_num, max_tangential_pos_num); + + for ( #ifndef STIR_NO_NAMESPACES - std:: + std:: #endif - vector::const_iterator r_ax_tang_poss_iter = related_ax_tang_poss.begin(); - r_ax_tang_poss_iter != related_ax_tang_poss.end(); - ++r_ax_tang_poss_iter) - { - const int axial_pos_tmp = (*r_ax_tang_poss_iter)[1]; - const int tang_pos_tmp = (*r_ax_tang_poss_iter)[2]; - - // symmetries might take the ranges out of what the user wants - if ( !(min_axial_pos_num <= axial_pos_tmp && axial_pos_tmp <= max_axial_pos_num && - min_tangential_pos_num <=tang_pos_tmp && tang_pos_tmp <= max_tangential_pos_num)) - continue; - - already_processed[axial_pos_tmp][tang_pos_tmp] = 1; - - - for (RelatedViewgrams::const_iterator viewgram_iter = viewgrams.begin(); - viewgram_iter != viewgrams.end(); - ++viewgram_iter) - { - // KT 21/02/2002 added check on 0 - if ((*viewgram_iter)[axial_pos_tmp][tang_pos_tmp] == 0) - continue; - proj_matrix_row_copy = proj_matrix_row; - Bin bin(viewgram_iter->get_segment_num(), - viewgram_iter->get_view_num(), - axial_pos_tmp, - tang_pos_tmp, - (*viewgram_iter)[axial_pos_tmp][tang_pos_tmp]); - - unique_ptr symm_op_ptr = - symmetries->find_symmetry_operation_from_basic_bin(bin); - // TODO replace with Bin::compare_coordinates or so - assert(bin.segment_num() == basic_bin.segment_num()); - assert(bin.view_num() == basic_bin.view_num()); - assert(bin.axial_pos_num() == basic_bin.axial_pos_num()); - assert(bin.tangential_pos_num() == basic_bin.tangential_pos_num()); - - symm_op_ptr->transform_proj_matrix_elems_for_one_bin(proj_matrix_row_copy); - proj_matrix_row_copy.back_project(image, bin); - } - } - } - assert(already_processed.sum() - == ( - (max_axial_pos_num - min_axial_pos_num + 1) * - (max_tangential_pos_num - min_tangential_pos_num + 1))); - } + vector::const_iterator r_ax_tang_poss_iter = related_ax_tang_poss.begin(); + r_ax_tang_poss_iter != related_ax_tang_poss.end(); ++r_ax_tang_poss_iter) { + const int axial_pos_tmp = (*r_ax_tang_poss_iter)[1]; + const int tang_pos_tmp = (*r_ax_tang_poss_iter)[2]; + + // symmetries might take the ranges out of what the user wants + if (!(min_axial_pos_num <= axial_pos_tmp && axial_pos_tmp <= max_axial_pos_num && + min_tangential_pos_num <= tang_pos_tmp && tang_pos_tmp <= max_tangential_pos_num)) + continue; + + already_processed[axial_pos_tmp][tang_pos_tmp] = 1; + + for (RelatedViewgrams::const_iterator viewgram_iter = viewgrams.begin(); viewgram_iter != viewgrams.end(); + ++viewgram_iter) { + // KT 21/02/2002 added check on 0 + if ((*viewgram_iter)[axial_pos_tmp][tang_pos_tmp] == 0) + continue; + proj_matrix_row_copy = proj_matrix_row; + Bin bin(viewgram_iter->get_segment_num(), viewgram_iter->get_view_num(), axial_pos_tmp, tang_pos_tmp, + viewgram_iter->get_timing_pos_num(), (*viewgram_iter)[axial_pos_tmp][tang_pos_tmp]); + + unique_ptr symm_op_ptr = symmetries->find_symmetry_operation_from_basic_bin(bin); + // TODO replace with Bin::compare_coordinates or so + assert(bin.segment_num() == basic_bin.segment_num()); + assert(bin.view_num() == basic_bin.view_num()); + assert(bin.axial_pos_num() == basic_bin.axial_pos_num()); + assert(bin.tangential_pos_num() == basic_bin.tangential_pos_num()); + assert(bin.timing_pos_num() == basic_bin.timing_pos_num()); + + symm_op_ptr->transform_proj_matrix_elems_for_one_bin(proj_matrix_row_copy); + proj_matrix_row_copy.back_project(image, bin); + } + } + } + assert(already_processed.sum() == + ((max_axial_pos_num - min_axial_pos_num + 1) * (max_tangential_pos_num - min_tangential_pos_num + 1))); + } } +void +BackProjectorByBinUsingProjMatrixByBin::actual_back_project(DiscretisedDensity<3, float>& image, const Bin& bin) { + if (proj_matrix_ptr->is_cache_enabled() /*&& !tof_enabled*/) { + ProjMatrixElemsForOneBin proj_matrix_row; + proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, bin); + proj_matrix_row.back_project(image, bin); + } else if (proj_matrix_ptr->is_cache_enabled() /* && tof_enabled*/) { + tof_row->back_project(image, bin); + } else + error("BackProjectorByBinUsingProjMatrixByBin: Symmetries should be handled by ProjMatrix. Abort. "); +} +void +BackProjectorByBinUsingProjMatrixByBin::enable_tof(ProjMatrixElemsForOneBin* for_row) { + tof_row = for_row; + // tof_enabled = true; +} + +BackProjectorByBinUsingProjMatrixByBin* +BackProjectorByBinUsingProjMatrixByBin::clone() const { + BackProjectorByBinUsingProjMatrixByBin* sptr(new BackProjectorByBinUsingProjMatrixByBin(*this)); + sptr->proj_matrix_ptr.reset(this->proj_matrix_ptr->clone()); + return sptr; +} END_NAMESPACE_STIR diff --git a/src/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.cxx b/src/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.cxx index 520eafbe24..28ad70a436 100644 --- a/src/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.cxx +++ b/src/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.cxx @@ -8,10 +8,10 @@ \ingroup recon_buildblock \brief non-inline implementations for stir::BackProjectorByBinUsingSquareProjMatrixByBin - + \author Sanida Mustafovic \author Kris Thielemans - + */ /* Copyright (C) 2000- 2011, Hammersmith Imanet Ltd @@ -30,7 +30,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.h" #include "stir/Viewgram.h" #include "stir/RelatedViewgrams.h" @@ -40,100 +39,79 @@ START_NAMESPACE_STIR -const char * const -BackProjectorByBinUsingSquareProjMatrixByBin::registered_name = - "Matrix Square"; - +const char* const BackProjectorByBinUsingSquareProjMatrixByBin::registered_name = "Matrix Square"; void -BackProjectorByBinUsingSquareProjMatrixByBin:: -set_defaults() -{ +BackProjectorByBinUsingSquareProjMatrixByBin::set_defaults() { this->proj_matrix_ptr.reset(); } +BackProjectorByBinUsingSquareProjMatrixByBin::BackProjectorByBinUsingSquareProjMatrixByBin( + const shared_ptr& proj_matrix_ptr) + : proj_matrix_ptr(proj_matrix_ptr) { + assert(!is_null_ptr(proj_matrix_ptr)); +} -BackProjectorByBinUsingSquareProjMatrixByBin:: -BackProjectorByBinUsingSquareProjMatrixByBin( - const shared_ptr& proj_matrix_ptr - ) - : proj_matrix_ptr(proj_matrix_ptr) - { - assert(!is_null_ptr(proj_matrix_ptr)); - - } - -const DataSymmetriesForViewSegmentNumbers * -BackProjectorByBinUsingSquareProjMatrixByBin::get_symmetries_used() const -{ +const DataSymmetriesForViewSegmentNumbers* +BackProjectorByBinUsingSquareProjMatrixByBin::get_symmetries_used() const { if (!this->_already_set_up) error("BackProjectorByBin method called without calling set_up first."); return proj_matrix_ptr->get_symmetries_ptr(); } -void -BackProjectorByBinUsingSquareProjMatrixByBin:: -actual_back_project(DiscretisedDensity<3,float>& image, - const RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ +void +BackProjectorByBinUsingSquareProjMatrixByBin::actual_back_project(DiscretisedDensity<3, float>& image, + const RelatedViewgrams& viewgrams, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) { ProjMatrixElemsForOneBin proj_matrix_row; - - + RelatedViewgrams::const_iterator r_viewgrams_iter = viewgrams.begin(); - - while( r_viewgrams_iter!=viewgrams.end()) - { + while (r_viewgrams_iter != viewgrams.end()) { const Viewgram& viewgram = *r_viewgrams_iter; const int view_num = viewgram.get_view_num(); const int segment_num = viewgram.get_segment_num(); - - for ( int tang_pos = min_tangential_pos_num ;tang_pos <= max_tangential_pos_num ;++tang_pos) - for ( int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num ;++ax_pos) - { - - Bin bin(segment_num, view_num, ax_pos, tang_pos, viewgram[ax_pos][tang_pos]); - proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, bin); - ProjMatrixElemsForOneBin::iterator element_ptr = - proj_matrix_row.begin(); - - // square matrix elements - while (element_ptr != proj_matrix_row.end()) - { - const float val=element_ptr->get_value(); - *element_ptr *=val; - element_ptr++; - } - - proj_matrix_row.back_project(image, bin); + const int timing_pos_num = viewgram.get_timing_pos_num(); + + for (int tang_pos = min_tangential_pos_num; tang_pos <= max_tangential_pos_num; ++tang_pos) + for (int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num; ++ax_pos) { + + Bin bin(segment_num, view_num, ax_pos, tang_pos, timing_pos_num, viewgram[ax_pos][tang_pos]); + proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, bin); + ProjMatrixElemsForOneBin::iterator element_ptr = proj_matrix_row.begin(); + + // square matrix elements + while (element_ptr != proj_matrix_row.end()) { + const float val = element_ptr->get_value(); + *element_ptr *= val; + element_ptr++; + } + + proj_matrix_row.back_project(image, bin); } - ++r_viewgrams_iter; + ++r_viewgrams_iter; } } +void +BackProjectorByBinUsingSquareProjMatrixByBin::actual_back_project(DiscretisedDensity<3, float>& image, const Bin& bin) { + error("BackProjectorByBinUsingSquareProjMatrixByBin is not supported for list-mode reconstruction. Abort."); +} void -BackProjectorByBinUsingSquareProjMatrixByBin:: -initialise_keymap() -{ +BackProjectorByBinUsingSquareProjMatrixByBin::initialise_keymap() { parser.add_start_key("Back Projector ( Square) Using Matrix Parameters"); parser.add_stop_key("End Back Projector ( Square) Using Matrix Parameters"); parser.add_parsing_key("matrix type", &proj_matrix_ptr); } -BackProjectorByBinUsingSquareProjMatrixByBin:: -BackProjectorByBinUsingSquareProjMatrixByBin() -{ - set_defaults(); -} - +BackProjectorByBinUsingSquareProjMatrixByBin::BackProjectorByBinUsingSquareProjMatrixByBin() { set_defaults(); } void -BackProjectorByBinUsingSquareProjMatrixByBin:: -set_up(const shared_ptr& proj_data_info_ptr, - const shared_ptr >& image_info_ptr) +BackProjectorByBinUsingSquareProjMatrixByBin::set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& image_info_ptr) { BackProjectorByBin::set_up(proj_data_info_ptr, image_info_ptr); diff --git a/src/recon_buildblock/BinNormalisation.cxx b/src/recon_buildblock/BinNormalisation.cxx index f52e57b2bf..6b338a3610 100644 --- a/src/recon_buildblock/BinNormalisation.cxx +++ b/src/recon_buildblock/BinNormalisation.cxx @@ -26,7 +26,6 @@ \author Kris Thielemans */ - #include "stir/recon_buildblock/BinNormalisation.h" #include "stir/recon_buildblock/TrivialDataSymmetriesForBins.h" #include "stir/recon_buildblock/find_basic_vs_nums_in_subsets.h" @@ -40,190 +39,152 @@ START_NAMESPACE_STIR -BinNormalisation:: -BinNormalisation() - : _already_set_up(false) -{ -} +BinNormalisation::BinNormalisation() : _already_set_up(false) {} -BinNormalisation:: -~BinNormalisation() -{} +BinNormalisation::~BinNormalisation() {} -void BinNormalisation:: -set_exam_info_sptr(const shared_ptr _exam_info_sptr) -{ - this->exam_info_sptr=_exam_info_sptr; +void +BinNormalisation::set_exam_info_sptr(const shared_ptr _exam_info_sptr) { + this->exam_info_sptr = _exam_info_sptr; } -shared_ptr BinNormalisation:: -get_exam_info_sptr() const -{ - return this->exam_info_sptr; +shared_ptr +BinNormalisation::get_exam_info_sptr() const { + return this->exam_info_sptr; } Succeeded -BinNormalisation:: -set_up(const shared_ptr& exam_info_sptr, const shared_ptr& proj_data_info_sptr ) -{ +BinNormalisation::set_up(const shared_ptr& exam_info_sptr, + const shared_ptr& proj_data_info_sptr) { _already_set_up = true; _proj_data_info_sptr = proj_data_info_sptr->create_shared_clone(); - this->exam_info_sptr=exam_info_sptr; - return Succeeded::yes; + this->exam_info_sptr = exam_info_sptr; + return Succeeded::yes; } void -BinNormalisation:: -check(const ProjDataInfo& proj_data_info) const -{ +BinNormalisation::check(const ProjDataInfo& proj_data_info) const { if (!this->_already_set_up) error("BinNormalisation method called without calling set_up first."); if (!(*this->_proj_data_info_sptr >= proj_data_info)) - error(boost::format("BinNormalisation set-up with different geometry for projection data.\nSet_up was with\n%1%\nCalled with\n%2%") - % this->_proj_data_info_sptr->parameter_info() % proj_data_info.parameter_info()); + error(boost::format( + "BinNormalisation set-up with different geometry for projection data.\nSet_up was with\n%1%\nCalled with\n%2%") % + this->_proj_data_info_sptr->parameter_info() % proj_data_info.parameter_info()); } void -BinNormalisation:: -check(const ExamInfo &exam_info) const -{ - if (!(*this->exam_info_sptr==exam_info)) - error(boost::format("BinNormalisation set-up with different ExamInfo.\n Set_up was with\n%1%\nCalled with\n%2%") - % this->exam_info_sptr->parameter_info() % exam_info.parameter_info()); +BinNormalisation::check(const ExamInfo& exam_info) const { + if (!(*this->exam_info_sptr == exam_info)) + error(boost::format("BinNormalisation set-up with different ExamInfo.\n Set_up was with\n%1%\nCalled with\n%2%") % + this->exam_info_sptr->parameter_info() % exam_info.parameter_info()); } - + // TODO remove duplication between apply and undo by just having 1 functino that does the loops -void -BinNormalisation::apply(RelatedViewgrams& viewgrams, - const double start_time, const double end_time) const -{ +void +BinNormalisation::apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const { this->check(*viewgrams.get_proj_data_info_sptr()); - for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) - { - Bin bin(iter->get_segment_num(),iter->get_view_num(), 0,0); - for (bin.axial_pos_num()= iter->get_min_axial_pos_num(); - bin.axial_pos_num()<=iter->get_max_axial_pos_num(); - ++bin.axial_pos_num()) - for (bin.tangential_pos_num()= iter->get_min_tangential_pos_num(); - bin.tangential_pos_num()<=iter->get_max_tangential_pos_num(); - ++bin.tangential_pos_num()) - (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] /= - std::max(1.E-20F, get_bin_efficiency(bin, start_time, end_time)); + for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + Bin bin(iter->get_segment_num(), iter->get_view_num(), 0, 0, iter->get_timing_pos_num()); + for (bin.axial_pos_num() = iter->get_min_axial_pos_num(); bin.axial_pos_num() <= iter->get_max_axial_pos_num(); + ++bin.axial_pos_num()) + for (bin.tangential_pos_num() = iter->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= iter->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] /= + std::max(1.E-20F, get_bin_efficiency(bin, start_time, end_time)); } } -void -BinNormalisation:: -undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +void +BinNormalisation::undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const { this->check(*viewgrams.get_proj_data_info_sptr()); - for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) - { - Bin bin(iter->get_segment_num(),iter->get_view_num(), 0,0); - for (bin.axial_pos_num()= iter->get_min_axial_pos_num(); - bin.axial_pos_num()<=iter->get_max_axial_pos_num(); - ++bin.axial_pos_num()) - for (bin.tangential_pos_num()= iter->get_min_tangential_pos_num(); - bin.tangential_pos_num()<=iter->get_max_tangential_pos_num(); - ++bin.tangential_pos_num()) - (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] *= - this->get_bin_efficiency(bin,start_time, end_time); + for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + Bin bin(iter->get_segment_num(), iter->get_view_num(), 0, 0, iter->get_timing_pos_num()); + for (bin.axial_pos_num() = iter->get_min_axial_pos_num(); bin.axial_pos_num() <= iter->get_max_axial_pos_num(); + ++bin.axial_pos_num()) + for (bin.tangential_pos_num() = iter->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= iter->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] *= this->get_bin_efficiency(bin, start_time, end_time); } - } -void -BinNormalisation:: -apply(ProjData& proj_data, - shared_ptr symmetries_sptr) const -{ - const float start_time=exam_info_sptr->get_time_frame_definitions().get_start_time(); - const float end_time=exam_info_sptr->get_time_frame_definitions().get_end_time(); +void +BinNormalisation::apply(ProjData& proj_data, shared_ptr symmetries_sptr) const { + const float start_time = exam_info_sptr->get_time_frame_definitions().get_start_time(); + const float end_time = exam_info_sptr->get_time_frame_definitions().get_end_time(); this->check(*proj_data.get_proj_data_info_sptr()); this->check(proj_data.get_exam_info()); if (is_null_ptr(symmetries_sptr)) symmetries_sptr.reset(new TrivialDataSymmetriesForBins(proj_data.get_proj_data_info_sptr()->create_shared_clone())); - const std::vector vs_nums_to_process = - detail::find_basic_vs_nums_in_subset(*proj_data.get_proj_data_info_sptr(), *symmetries_sptr, - proj_data.get_min_segment_num(), proj_data.get_max_segment_num(), - 0, 1/*subset_num, num_subsets*/); + const std::vector vs_nums_to_process = detail::find_basic_vs_nums_in_subset( + *proj_data.get_proj_data_info_sptr(), *symmetries_sptr, proj_data.get_min_segment_num(), proj_data.get_max_segment_num(), 0, + 1 /*subset_num, num_subsets*/); #ifdef STIR_OPENMP -#pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(runtime) +# pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(runtime) #endif - // note: older versions of openmp need an int as loop - for (int i=0; i(vs_nums_to_process.size()); ++i) - { - const ViewSegmentNumbers vs=vs_nums_to_process[i]; - + // note: older versions of openmp need an int as loop + for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++i) { + const ViewSegmentNumbers vs = vs_nums_to_process[i]; + + for (int k = proj_data.get_proj_data_info_sptr()->get_min_tof_pos_num(); + k <= proj_data.get_proj_data_info_sptr()->get_max_tof_pos_num(); ++k) { + RelatedViewgrams viewgrams; #ifdef STIR_OPENMP // reading/writing to streams is not safe in multi-threaded code // so protect with a critical section // note that the name of the section has to be same for the get/set // function as they're reading from/writing to the same stream -#pragma omp critical (BINNORMALISATION_APPLY__VIEWGRAMS) +# pragma omp critical(BINNORMALISATION_APPLY__VIEWGRAMS) #endif - { - viewgrams = - proj_data.get_related_viewgrams(vs, symmetries_sptr); - } + { viewgrams = proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); } this->apply(viewgrams, start_time, end_time); #ifdef STIR_OPENMP -#pragma omp critical (BINNORMALISATION_APPLY__VIEWGRAMS) +# pragma omp critical(BINNORMALISATION_APPLY__VIEWGRAMS) #endif - { - proj_data.set_related_viewgrams(viewgrams); - } + { proj_data.set_related_viewgrams(viewgrams); } } + } } -void -BinNormalisation:: -undo(ProjData& proj_data,const double start_time, const double end_time, - shared_ptr symmetries_sptr) const -{ +void +BinNormalisation::undo(ProjData& proj_data, const double start_time, const double end_time, + shared_ptr symmetries_sptr) const { this->check(*proj_data.get_proj_data_info_sptr()); if (is_null_ptr(symmetries_sptr)) symmetries_sptr.reset(new TrivialDataSymmetriesForBins(proj_data.get_proj_data_info_sptr()->create_shared_clone())); - const std::vector vs_nums_to_process = - detail::find_basic_vs_nums_in_subset(*proj_data.get_proj_data_info_sptr(), *symmetries_sptr, - proj_data.get_min_segment_num(), proj_data.get_max_segment_num(), - 0, 1/*subset_num, num_subsets*/); + const std::vector vs_nums_to_process = detail::find_basic_vs_nums_in_subset( + *proj_data.get_proj_data_info_sptr(), *symmetries_sptr, proj_data.get_min_segment_num(), proj_data.get_max_segment_num(), 0, + 1 /*subset_num, num_subsets*/); #ifdef STIR_OPENMP -#pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(runtime) +# pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(runtime) #endif - // note: older versions of openmp need an int as loop - for (int i=0; i(vs_nums_to_process.size()); ++i) - { - const ViewSegmentNumbers vs=vs_nums_to_process[i]; - + // note: older versions of openmp need an int as loop + for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++i) { + const ViewSegmentNumbers vs = vs_nums_to_process[i]; + + for (int k = proj_data.get_proj_data_info_sptr()->get_min_tof_pos_num(); + k <= proj_data.get_proj_data_info_sptr()->get_max_tof_pos_num(); ++k) { RelatedViewgrams viewgrams; #ifdef STIR_OPENMP -#pragma omp critical (BINNORMALISATION_UNDO__VIEWGRAMS) +# pragma omp critical(BINNORMALISATION_UNDO__VIEWGRAMS) #endif - { - viewgrams = - proj_data.get_related_viewgrams(vs, symmetries_sptr); - } + { viewgrams = proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); } this->undo(viewgrams, start_time, end_time); #ifdef STIR_OPENMP -#pragma omp critical (BINNORMALISATION_UNDO__VIEWGRAMS) +# pragma omp critical(BINNORMALISATION_UNDO__VIEWGRAMS) #endif - { - proj_data.set_related_viewgrams(viewgrams); - } + { proj_data.set_related_viewgrams(viewgrams); } } + } } - END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/BinNormalisationFromAttenuationImage.cxx b/src/recon_buildblock/BinNormalisationFromAttenuationImage.cxx index 0903c3cf08..af0c49e835 100644 --- a/src/recon_buildblock/BinNormalisationFromAttenuationImage.cxx +++ b/src/recon_buildblock/BinNormalisationFromAttenuationImage.cxx @@ -37,158 +37,127 @@ START_NAMESPACE_STIR -const char * const -BinNormalisationFromAttenuationImage::registered_name = - "From Attenuation Image"; +const char* const BinNormalisationFromAttenuationImage::registered_name = "From Attenuation Image"; - -void -BinNormalisationFromAttenuationImage::set_defaults() -{ +void +BinNormalisationFromAttenuationImage::set_defaults() { attenuation_image_ptr.reset(); forward_projector_ptr.reset(); attenuation_image_filename = ""; } -void -BinNormalisationFromAttenuationImage:: -initialise_keymap() -{ +void +BinNormalisationFromAttenuationImage::initialise_keymap() { parser.add_start_key("Bin Normalisation From Attenuation Image"); parser.add_key("attenuation_image_filename", &attenuation_image_filename); parser.add_parsing_key("forward projector type", &forward_projector_ptr); parser.add_stop_key("End Bin Normalisation From Attenuation Image"); } -bool -BinNormalisationFromAttenuationImage:: -post_processing() -{ +bool +BinNormalisationFromAttenuationImage::post_processing() { // read attenuation_image // we do this only when it isn't initialised yet, as this function can be called from a constructor if (is_null_ptr(attenuation_image_ptr)) - attenuation_image_ptr = read_from_file >(attenuation_image_filename); - if (is_null_ptr(attenuation_image_ptr)) - { - warning("BinNormalisationFromAttenuationImage could not read attenuation image %s\n", - attenuation_image_filename.c_str()); + attenuation_image_ptr = read_from_file>(attenuation_image_filename); + if (is_null_ptr(attenuation_image_ptr)) { + warning("BinNormalisationFromAttenuationImage could not read attenuation image %s\n", attenuation_image_filename.c_str()); return true; } if (is_null_ptr(forward_projector_ptr)) forward_projector_ptr.reset(new ForwardProjectorByBinUsingRayTracing()); - + { const float amax = attenuation_image_ptr->find_max(); if ((amax < .08F) || (amax > .2F)) warning(boost::format("BinNormalisationFromAttenuationImage:\n" "\tattenuation image data are supposed to be in units cm^-1\n" - "\tReference: water has mu .096 cm^-1\n" + "\tReference: water has mu .096 cm^-1\n" "\tMax in attenuation image: %1%\n" - "\tContinuing as you might know what you are doing.") % amax); + "\tContinuing as you might know what you are doing.") % + amax); } #ifndef NEWSCALE - /* - cerr << "WARNING: multiplying attenuation image by x-voxel size " - << " to correct for scale factor in forward projectors...\n"; - */ - // projectors work in pixel units, so convert attenuation data + /* + cerr << "WARNING: multiplying attenuation image by x-voxel size " + << " to correct for scale factor in forward projectors...\n"; +*/ + // projectors work in pixel units, so convert attenuation data // from cm^-1 to pixel_units^-1 - const float rescale = - dynamic_cast const &>(*attenuation_image_ptr). - get_grid_spacing()[3]/10; + const float rescale = + dynamic_cast const&>(*attenuation_image_ptr).get_grid_spacing()[3] / 10; #else - const float rescale = - 0.1F; + const float rescale = 0.1F; #endif - shared_ptr > new_sptr(attenuation_image_ptr->clone()); + shared_ptr> new_sptr(attenuation_image_ptr->clone()); *new_sptr *= rescale; attenuation_image_ptr = new_sptr; return false; } +BinNormalisationFromAttenuationImage::BinNormalisationFromAttenuationImage() { set_defaults(); } -BinNormalisationFromAttenuationImage:: -BinNormalisationFromAttenuationImage() -{ - set_defaults(); -} - -BinNormalisationFromAttenuationImage:: -BinNormalisationFromAttenuationImage(const std::string& filename, - shared_ptr const& forward_projector_ptr) - : forward_projector_ptr(forward_projector_ptr), - attenuation_image_filename(filename) -{ +BinNormalisationFromAttenuationImage::BinNormalisationFromAttenuationImage( + const std::string& filename, shared_ptr const& forward_projector_ptr) + : forward_projector_ptr(forward_projector_ptr), attenuation_image_filename(filename) { attenuation_image_ptr.reset(); post_processing(); } -BinNormalisationFromAttenuationImage:: -BinNormalisationFromAttenuationImage(shared_ptr > const& attenuation_image_ptr_v, - shared_ptr const& forward_projector_ptr) - : attenuation_image_ptr(attenuation_image_ptr_v->clone()), // need a clone as it guarantees we won't be affected by the caller, and vice versa - forward_projector_ptr(forward_projector_ptr) -{ +BinNormalisationFromAttenuationImage::BinNormalisationFromAttenuationImage( + shared_ptr> const& attenuation_image_ptr_v, + shared_ptr const& forward_projector_ptr) + : attenuation_image_ptr( + attenuation_image_ptr_v->clone()), // need a clone as it guarantees we won't be affected by the caller, and vice versa + forward_projector_ptr(forward_projector_ptr) { post_processing(); } -Succeeded -BinNormalisationFromAttenuationImage:: -set_up(const shared_ptr &exam_info_sptr, const shared_ptr& proj_data_info_ptr) -{ +Succeeded +BinNormalisationFromAttenuationImage::set_up(const shared_ptr& exam_info_sptr, + const shared_ptr& proj_data_info_ptr) { BinNormalisation::set_up(exam_info_sptr, proj_data_info_ptr); forward_projector_ptr->set_up(proj_data_info_ptr, attenuation_image_ptr); forward_projector_ptr->set_input(*attenuation_image_ptr); return Succeeded::yes; } - -void -BinNormalisationFromAttenuationImage::apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +void +BinNormalisationFromAttenuationImage::apply(RelatedViewgrams& viewgrams, const double start_time, + const double end_time) const { this->check(*viewgrams.get_proj_data_info_sptr()); RelatedViewgrams attenuation_viewgrams = viewgrams.get_empty_copy(); forward_projector_ptr->forward_project(attenuation_viewgrams); - + // TODO cannot use std::transform ? - for (RelatedViewgrams::iterator viewgrams_iter = - attenuation_viewgrams.begin(); - viewgrams_iter != attenuation_viewgrams.end(); - ++viewgrams_iter) - { + for (RelatedViewgrams::iterator viewgrams_iter = attenuation_viewgrams.begin(); + viewgrams_iter != attenuation_viewgrams.end(); ++viewgrams_iter) { in_place_exp(*viewgrams_iter); } viewgrams *= attenuation_viewgrams; } -void -BinNormalisationFromAttenuationImage:: -undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +void +BinNormalisationFromAttenuationImage::undo(RelatedViewgrams& viewgrams, const double start_time, + const double end_time) const { this->check(*viewgrams.get_proj_data_info_sptr()); RelatedViewgrams attenuation_viewgrams = viewgrams.get_empty_copy(); forward_projector_ptr->forward_project(attenuation_viewgrams); - + // TODO cannot use std::transform ? - for (RelatedViewgrams::iterator viewgrams_iter = - attenuation_viewgrams.begin(); - viewgrams_iter != attenuation_viewgrams.end(); - ++viewgrams_iter) - { + for (RelatedViewgrams::iterator viewgrams_iter = attenuation_viewgrams.begin(); + viewgrams_iter != attenuation_viewgrams.end(); ++viewgrams_iter) { in_place_exp(*viewgrams_iter); } viewgrams /= attenuation_viewgrams; } -float -BinNormalisationFromAttenuationImage::get_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const -{ - //TODO +float +BinNormalisationFromAttenuationImage::get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { + // TODO error("BinNormalisationFromAttenuationImage::get_bin_efficiency is not implemented"); return 1; } - END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/BinNormalisationFromECAT7.cxx b/src/recon_buildblock/BinNormalisationFromECAT7.cxx index 28cf93c81e..ca5efd1bc0 100644 --- a/src/recon_buildblock/BinNormalisationFromECAT7.cxx +++ b/src/recon_buildblock/BinNormalisationFromECAT7.cxx @@ -61,126 +61,92 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 - +const char* const BinNormalisationFromECAT7::registered_name = "From ECAT7"; -const char * const -BinNormalisationFromECAT7::registered_name = "From ECAT7"; - - -namespace detail -{ +namespace detail { // // helper functions used in this class. // -static -float +static float calc_geo_z_correction(const Bin& bin, int span) { - const int rtmp = abs(bin.segment_num() * span) ; - return( 1.0F + ( ( 0.007F - ( 0.000164F * rtmp ) ) * rtmp ) ); + const int rtmp = abs(bin.segment_num() * span); + return (1.0F + ((0.007F - (0.000164F * rtmp)) * rtmp)); } - - - -static -int -calc_ring1_plus_ring2(const Bin& bin, - const ProjDataInfoCylindricalNoArcCorr *proj_data_cyl) { +static int +calc_ring1_plus_ring2(const Bin& bin, const ProjDataInfoCylindricalNoArcCorr* proj_data_cyl) { int segment_num = bin.segment_num(); - + const int min_ring_diff = proj_data_cyl->get_min_ring_difference(segment_num); const int max_ring_diff = proj_data_cyl->get_max_ring_difference(segment_num); const int num_rings = proj_data_cyl->get_scanner_ptr()->get_num_rings(); - return( (2 * bin.axial_pos_num() - - (proj_data_cyl->get_min_axial_pos_num(segment_num) + - proj_data_cyl->get_max_axial_pos_num(segment_num)) - ) / (min_ring_diff != max_ring_diff ? 2 : 1) - + num_rings - 1 ); - + return ((2 * bin.axial_pos_num() - + (proj_data_cyl->get_min_axial_pos_num(segment_num) + proj_data_cyl->get_max_axial_pos_num(segment_num))) / + (min_ring_diff != max_ring_diff ? 2 : 1) + + num_rings - 1); } - - -static -void -set_detection_tangential_coords(shared_ptr proj_data_cyl_uncomp, - const Bin& uncomp_bin, +static void +set_detection_tangential_coords(shared_ptr proj_data_cyl_uncomp, const Bin& uncomp_bin, DetectionPositionPair<>& detection_position_pair) { - int det1_num=0; - int det2_num=0; - - proj_data_cyl_uncomp->get_det_num_pair_for_view_tangential_pos_num(det1_num, det2_num, - uncomp_bin.view_num(), + int det1_num = 0; + int det2_num = 0; + + proj_data_cyl_uncomp->get_det_num_pair_for_view_tangential_pos_num(det1_num, det2_num, uncomp_bin.view_num(), uncomp_bin.tangential_pos_num()); detection_position_pair.pos1().tangential_coord() = det1_num; detection_position_pair.pos2().tangential_coord() = det2_num; - } - - // Returns the sum of the two axial coordinates. Or -1 if the ring positions are // out of range. // sets axial_coord of detection_position_pair -static -int -set_detection_axial_coords(const ProjDataInfoCylindricalNoArcCorr *proj_data_info_cyl, - int ring1_plus_ring2, const Bin& uncomp_bin, - DetectionPositionPair<>& detection_position_pair) { - +static int +set_detection_axial_coords(const ProjDataInfoCylindricalNoArcCorr* proj_data_info_cyl, int ring1_plus_ring2, + const Bin& uncomp_bin, DetectionPositionPair<>& detection_position_pair) { + const int num_rings = proj_data_info_cyl->get_scanner_ptr()->get_num_rings(); const int ring_diff = uncomp_bin.segment_num(); - const int ring1 = (ring1_plus_ring2 - ring_diff)/2; - const int ring2 = (ring1_plus_ring2 + ring_diff)/2; - - if (ring1<0 || ring2 < 0 || ring1>=num_rings || ring2 >= num_rings) { - return(-1); + const int ring1 = (ring1_plus_ring2 - ring_diff) / 2; + const int ring2 = (ring1_plus_ring2 + ring_diff) / 2; + + if (ring1 < 0 || ring2 < 0 || ring1 >= num_rings || ring2 >= num_rings) { + return (-1); } - - assert((ring1_plus_ring2 + ring_diff)%2 == 0); - assert((ring1_plus_ring2 - ring_diff)%2 == 0); - + + assert((ring1_plus_ring2 + ring_diff) % 2 == 0); + assert((ring1_plus_ring2 - ring_diff) % 2 == 0); + detection_position_pair.pos1().axial_coord() = ring1; detection_position_pair.pos2().axial_coord() = ring2; - - return(ring1 + ring2); + return (ring1 + ring2); } - - } // end of namespace detail - - - // // Member functions // - - -void -BinNormalisationFromECAT7::set_defaults() -{ +void +BinNormalisationFromECAT7::set_defaults() { this->normalisation_ECAT7_filename = ""; this->_use_detector_efficiencies = true; this->_use_dead_time = true; this->_use_geometric_factors = true; - this->_use_crystal_interference_factors = true; + this->_use_crystal_interference_factors = true; } -void -BinNormalisationFromECAT7:: -initialise_keymap() -{ +void +BinNormalisationFromECAT7::initialise_keymap() { this->parser.add_start_key("Bin Normalisation From ECAT7"); // todo remove obsolete keyword this->parser.add_key("normalisation_ECAT7_filename", &this->normalisation_ECAT7_filename); @@ -193,197 +159,151 @@ initialise_keymap() this->parser.add_stop_key("End Bin Normalisation From ECAT7"); } -bool -BinNormalisationFromECAT7:: -post_processing() -{ +bool +BinNormalisationFromECAT7::post_processing() { read_norm_data(normalisation_ECAT7_filename); this->set_calibration_factor(1); return false; } +BinNormalisationFromECAT7::BinNormalisationFromECAT7() { set_defaults(); } -BinNormalisationFromECAT7:: -BinNormalisationFromECAT7() -{ - set_defaults(); -} - -BinNormalisationFromECAT7:: -BinNormalisationFromECAT7(const std::string& filename) -{ - read_norm_data(filename); -} +BinNormalisationFromECAT7::BinNormalisationFromECAT7(const std::string& filename) { read_norm_data(filename); } Succeeded -BinNormalisationFromECAT7:: -set_up(const shared_ptr& proj_data_info_ptr_v) -{ +BinNormalisationFromECAT7::set_up(const shared_ptr& proj_data_info_ptr_v) { BinNormalisation::set_up(proj_data_info_ptr_v); proj_data_info_ptr = proj_data_info_ptr_v; - proj_data_info_cyl_ptr = - dynamic_cast(proj_data_info_ptr.get()); - if (proj_data_info_cyl_ptr==0) - { + proj_data_info_cyl_ptr = dynamic_cast(proj_data_info_ptr.get()); + if (proj_data_info_cyl_ptr == 0) { warning("BinNormalisationFromECAT7 can only be used on non-arccorrected data\n"); return Succeeded::no; } - if (*proj_data_info_ptr->get_scanner_ptr() != *scanner_ptr) - { + if (*proj_data_info_ptr->get_scanner_ptr() != *scanner_ptr) { warning("BinNormalisationFromECAT7: scanner object from proj data is different from the one " - "from the normalisation file\n"); + "from the normalisation file\n"); return Succeeded::no; } - span = - proj_data_info_cyl_ptr->get_max_ring_difference(0) - - proj_data_info_cyl_ptr->get_min_ring_difference(0) + 1; + span = proj_data_info_cyl_ptr->get_max_ring_difference(0) - proj_data_info_cyl_ptr->get_min_ring_difference(0) + 1; // TODO insert check all other segments are the same - mash = scanner_ptr->get_num_detectors_per_ring()/2/proj_data_info_ptr->get_num_views(); + mash = scanner_ptr->get_num_detectors_per_ring() / 2 / proj_data_info_ptr->get_num_views(); return Succeeded::yes; } void -BinNormalisationFromECAT7:: -read_norm_data(const std::string& filename) -{ - - MatrixFile* mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, Norm3d); +BinNormalisationFromECAT7::read_norm_data(const std::string& filename) { + + MatrixFile* mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, Norm3d); if (mptr == 0) error("BinNormalisationFromECAT7: error opening %s\n", filename.c_str()); - scanner_ptr.reset( - find_scanner_from_ECAT_system_type(mptr->mhptr->system_type)); - - MatrixData* matrix = matrix_read( mptr, mat_numcod (1, 1, 1, 0, 0), - Norm3d /*= read data as well */); + scanner_ptr.reset(find_scanner_from_ECAT_system_type(mptr->mhptr->system_type)); + + MatrixData* matrix = matrix_read(mptr, mat_numcod(1, 1, 1, 0, 0), Norm3d /*= read data as well */); if (matrix == 0) error("BinNormalisationFromECAT7: error reading data in %s\n", filename.c_str()); - Norm3D_subheader * nrm_subheader_ptr = - reinterpret_cast(matrix->shptr); - - num_transaxial_crystals_per_block = nrm_subheader_ptr->num_transaxial_crystals ; + Norm3D_subheader* nrm_subheader_ptr = reinterpret_cast(matrix->shptr); + num_transaxial_crystals_per_block = nrm_subheader_ptr->num_transaxial_crystals; - // Calculate the number of axial blocks per singles unit and + // Calculate the number of axial blocks per singles unit and // total number of blocks per singles unit. - int axial_crystals_per_singles_unit = - scanner_ptr->get_num_axial_crystals_per_singles_unit(); - - int transaxial_crystals_per_singles_unit = - scanner_ptr->get_num_transaxial_crystals_per_singles_unit(); - - int axial_crystals_per_block = - scanner_ptr->get_num_axial_crystals_per_block(); - - int transaxial_crystals_per_block = - scanner_ptr->get_num_transaxial_crystals_per_block(); - + int axial_crystals_per_singles_unit = scanner_ptr->get_num_axial_crystals_per_singles_unit(); + + int transaxial_crystals_per_singles_unit = scanner_ptr->get_num_transaxial_crystals_per_singles_unit(); + + int axial_crystals_per_block = scanner_ptr->get_num_axial_crystals_per_block(); + + int transaxial_crystals_per_block = scanner_ptr->get_num_transaxial_crystals_per_block(); + // Axial blocks. - num_axial_blocks_per_singles_unit = - axial_crystals_per_singles_unit / axial_crystals_per_block; - - int transaxial_blocks_per_singles_unit = - transaxial_crystals_per_singles_unit / transaxial_crystals_per_block; - - // Total blocks. - num_blocks_per_singles_unit = - num_axial_blocks_per_singles_unit * transaxial_blocks_per_singles_unit; - + num_axial_blocks_per_singles_unit = axial_crystals_per_singles_unit / axial_crystals_per_block; + + int transaxial_blocks_per_singles_unit = transaxial_crystals_per_singles_unit / transaxial_crystals_per_block; + // Total blocks. + num_blocks_per_singles_unit = num_axial_blocks_per_singles_unit * transaxial_blocks_per_singles_unit; if (scanner_ptr->get_num_rings() != nrm_subheader_ptr->num_crystal_rings) error("BinNormalisationFromECAT7: " "number of rings determined from subheader is %d, while the scanner object says it is %d\n", - nrm_subheader_ptr->num_crystal_rings, scanner_ptr->get_num_rings()); + nrm_subheader_ptr->num_crystal_rings, scanner_ptr->get_num_rings()); if (scanner_ptr->get_num_detectors_per_ring() != nrm_subheader_ptr->crystals_per_ring) error("BinNormalisationFromECAT7: " "number of detectors per ring determined from subheader is %d, while the scanner object says it is %d\n", - nrm_subheader_ptr->crystals_per_ring, scanner_ptr->get_num_detectors_per_ring()); - - proj_data_info_cyl_uncompressed_ptr.reset( - dynamic_cast( - ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - /*span=*/1, scanner_ptr->get_num_rings()-1, - /*num_views,=*/scanner_ptr->get_num_detectors_per_ring()/2, - /*num_tangential_poss=*/nrm_subheader_ptr->num_r_elements, - /*arc_corrected =*/false) - )); - + nrm_subheader_ptr->crystals_per_ring, scanner_ptr->get_num_detectors_per_ring()); + + proj_data_info_cyl_uncompressed_ptr.reset(dynamic_cast( + ProjDataInfo::ProjDataInfoCTI(scanner_ptr, + /*span=*/1, scanner_ptr->get_num_rings() - 1, + /*num_views,=*/scanner_ptr->get_num_detectors_per_ring() / 2, + /*num_tangential_poss=*/nrm_subheader_ptr->num_r_elements, + /*arc_corrected =*/false))); + /* Extract geometrical & crystal interference, and crystal efficiencies from the - normalisation data. + normalisation data. */ // SM 13/02/2003 corrected number of min_tang_pos_num and max_tang_pos_num used get_max_num_non_arccorrected_bins() - // instead of get_num_detectors_per_ring() - //const int min_tang_pos_num = -(scanner_ptr->get_num_detectors_per_ring()/2); - //const int max_tang_pos_num = min_tang_pos_num + scanner_ptr->get_num_detectors_per_ring() - 1; + // instead of get_num_detectors_per_ring() + // const int min_tang_pos_num = -(scanner_ptr->get_num_detectors_per_ring()/2); + // const int max_tang_pos_num = min_tang_pos_num + scanner_ptr->get_num_detectors_per_ring() - 1; - const int min_tang_pos_num = -(scanner_ptr->get_max_num_non_arccorrected_bins())/2; - const int max_tang_pos_num = min_tang_pos_num +scanner_ptr->get_max_num_non_arccorrected_bins()- 1; + const int min_tang_pos_num = -(scanner_ptr->get_max_num_non_arccorrected_bins()) / 2; + const int max_tang_pos_num = min_tang_pos_num + scanner_ptr->get_max_num_non_arccorrected_bins() - 1; - /* The order of coefficients is as follows: + /* The order of coefficients is as follows: 1. geometric_factors (= number_of_corr_planes * number_of_bins) 2. crystal_interference_factors (num_transaxial_crystals_per_block * number_of_bins) 3. efficiency_factors (number_of_rings*number_of_crystals ) */ - geometric_factors = - Array<2,float>(IndexRange2D(0,nrm_subheader_ptr->num_geo_corr_planes-1, - min_tang_pos_num, max_tang_pos_num)); + geometric_factors = + Array<2, float>(IndexRange2D(0, nrm_subheader_ptr->num_geo_corr_planes - 1, min_tang_pos_num, max_tang_pos_num)); crystal_interference_factors = - Array<2,float>(IndexRange2D(min_tang_pos_num, max_tang_pos_num, - 0, num_transaxial_crystals_per_block-1)); - // SM 13/02/2003 + Array<2, float>(IndexRange2D(min_tang_pos_num, max_tang_pos_num, 0, num_transaxial_crystals_per_block - 1)); + // SM 13/02/2003 efficiency_factors = - Array<2,float>(IndexRange2D(0,scanner_ptr->get_num_rings()-1, - 0, scanner_ptr->get_num_detectors_per_ring()-1)); - + Array<2, float>(IndexRange2D(0, scanner_ptr->get_num_rings() - 1, 0, scanner_ptr->get_num_detectors_per_ring() - 1)); #if 0 int geom_test = nrm_subheader_ptr->num_geo_corr_planes * (max_tang_pos_num-min_tang_pos_num +1); int cry_inter = num_transaxial_crystals_per_block * (max_tang_pos_num-min_tang_pos_num +1); int eff_test = scanner_ptr->get_num_detectors_per_ring() * scanner_ptr->get_num_rings(); #endif - + { - float const* data_ptr = reinterpret_cast(matrix->data_ptr); - for (Array<2,float>::full_iterator iter = geometric_factors.begin_all(); - iter != geometric_factors.end_all(); - ) + float const* data_ptr = reinterpret_cast(matrix->data_ptr); + for (Array<2, float>::full_iterator iter = geometric_factors.begin_all(); iter != geometric_factors.end_all();) *iter++ = *data_ptr++; - for (Array<2,float>::full_iterator iter = crystal_interference_factors.begin_all(); - iter != crystal_interference_factors.end_all(); - ) + for (Array<2, float>::full_iterator iter = crystal_interference_factors.begin_all(); + iter != crystal_interference_factors.end_all();) *iter++ = *data_ptr++; - for (Array<2,float>::full_iterator iter = efficiency_factors.begin_all(); - iter != efficiency_factors.end_all(); - ) + for (Array<2, float>::full_iterator iter = efficiency_factors.begin_all(); iter != efficiency_factors.end_all();) *iter++ = *data_ptr++; } // TODO mvoe dead-time stuff to a separate function /* Set up equation parameters for dead_time correction */ - float *axial_t1 = nrm_subheader_ptr->ring_dtcor1 ; /* 'Paralyzing dead_times' for each axial Xstal */ - float *axial_t2 = nrm_subheader_ptr->ring_dtcor2 ; /* 'Non-paralyzing dead_times' for each axial Xstal */ + float* axial_t1 = nrm_subheader_ptr->ring_dtcor1; /* 'Paralyzing dead_times' for each axial Xstal */ + float* axial_t2 = nrm_subheader_ptr->ring_dtcor2; /* 'Non-paralyzing dead_times' for each axial Xstal */ /* for 966 24 entries for axial_t1 & axial_t2 Each entry accounts for 2 crystal rings 0 <= iRing <= 23 for ring 0 --> 47 */ - axial_t1_array = Array<1,float>(0,scanner_ptr->get_num_rings()/num_axial_blocks_per_singles_unit-1); - axial_t2_array = Array<1,float>(0,scanner_ptr->get_num_rings()/num_axial_blocks_per_singles_unit-1); + axial_t1_array = Array<1, float>(0, scanner_ptr->get_num_rings() / num_axial_blocks_per_singles_unit - 1); + axial_t2_array = Array<1, float>(0, scanner_ptr->get_num_rings() / num_axial_blocks_per_singles_unit - 1); - for (Array<1,float>::full_iterator iter = axial_t1_array.begin_all(); - iter != axial_t1_array.end_all();) - *iter++ = *axial_t1++; + for (Array<1, float>::full_iterator iter = axial_t1_array.begin_all(); iter != axial_t1_array.end_all();) + *iter++ = *axial_t1++; - for (Array<1,float>::full_iterator iter = axial_t2_array.begin_all(); - iter != axial_t2_array.end_all();) - *iter++ = *axial_t2++; + for (Array<1, float>::full_iterator iter = axial_t2_array.begin_all(); iter != axial_t2_array.end_all();) + *iter++ = *axial_t2++; #if 0 // this is currently not used by CTI and hence not by get_dead_time_efficiency float *trans_t1 = nrm_subheader_ptr->crystal_dtcor ; /* 'Non-paralyzing dead_times' for each transaxial Xstal in block */ @@ -393,7 +313,6 @@ read_norm_data(const std::string& filename) *iter++ = *trans_t1++; #endif - free_matrix_data(matrix); matrix_close(mptr); #if 0 @@ -444,39 +363,29 @@ read_norm_data(const std::string& filename) #endif } -bool -BinNormalisationFromECAT7:: -use_detector_efficiencies() const -{ +bool +BinNormalisationFromECAT7::use_detector_efficiencies() const { return this->_use_detector_efficiencies; } -bool -BinNormalisationFromECAT7:: -use_dead_time() const -{ +bool +BinNormalisationFromECAT7::use_dead_time() const { return this->_use_dead_time; } -bool -BinNormalisationFromECAT7:: -use_geometric_factors() const -{ +bool +BinNormalisationFromECAT7::use_geometric_factors() const { return this->_use_geometric_factors; } -bool -BinNormalisationFromECAT7:: -use_crystal_interference_factors() const -{ +bool +BinNormalisationFromECAT7::use_crystal_interference_factors() const { return this->_use_crystal_interference_factors; } #if 1 -float -BinNormalisationFromECAT7:: -get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { - +float +BinNormalisationFromECAT7::get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { // TODO disable when not HR+ or HR++ /* @@ -492,47 +401,37 @@ get_bin_efficiency(const Bin& bin, const double start_time, const double end_tim */ const float geo_Z_corr = detail::calc_geo_z_correction(bin, span); - - float total_efficiency = 0 ; - + float total_efficiency = 0; + /* Correct dead time */ - const int start_view = bin.view_num() * mash ; - //SM removed bin.view_num() + mash ; - const int end_view = start_view + mash ; - //start_view +mash; + const int start_view = bin.view_num() * mash; + // SM removed bin.view_num() + mash ; + const int end_view = start_view + mash; + // start_view +mash; const int min_ring_diff = proj_data_info_cyl_ptr->get_min_ring_difference(bin.segment_num()); const int max_ring_diff = proj_data_info_cyl_ptr->get_max_ring_difference(bin.segment_num()); - - /* - ring1_plus_ring2 is the same for any ring pair that contributes to + /* + ring1_plus_ring2 is the same for any ring pair that contributes to this particular bin.segment_num(), bin.axial_pos_num(). We determine it first here. See ProjDataInfoCylindrical for the relevant formulas */ - const int ring1_plus_ring2 = detail::calc_ring1_plus_ring2(bin, proj_data_info_cyl_ptr); - - + const int ring1_plus_ring2 = detail::calc_ring1_plus_ring2(bin, proj_data_info_cyl_ptr); DetectionPositionPair<> detection_position_pair; - Bin uncompressed_bin(0,0,0,bin.tangential_pos_num()); + Bin uncompressed_bin(0, 0, 0, bin.tangential_pos_num()); { float view_efficiency = 0.; + for (uncompressed_bin.view_num() = start_view; uncompressed_bin.view_num() < end_view; ++uncompressed_bin.view_num()) { - for(uncompressed_bin.view_num() = start_view; - uncompressed_bin.view_num() < end_view; - ++uncompressed_bin.view_num() ) { + detail::set_detection_tangential_coords(proj_data_info_cyl_uncompressed_ptr, uncompressed_bin, detection_position_pair); - detail::set_detection_tangential_coords(proj_data_info_cyl_uncompressed_ptr, - uncompressed_bin, detection_position_pair); + float lor_efficiency = 0.; - - - float lor_efficiency= 0.; - /* loop over ring differences that contribute to bin.segment_num() at the current bin.axial_pos_num(). @@ -547,118 +446,90 @@ get_bin_efficiency(const Bin& bin, const double start_time, const double end_tim == (2*min_ring_diff+ring1_plus_ring2)%2 == ring1_plus_ring2%2 */ - for(uncompressed_bin.segment_num() = min_ring_diff + (min_ring_diff+ring1_plus_ring2)%2; - uncompressed_bin.segment_num() <= max_ring_diff; - uncompressed_bin.segment_num()+=2 ) { - - - int geo_plane_num = - detail::set_detection_axial_coords(proj_data_info_cyl_ptr, - ring1_plus_ring2, uncompressed_bin, - detection_position_pair); - if ( geo_plane_num < 0 ) { + for (uncompressed_bin.segment_num() = min_ring_diff + (min_ring_diff + ring1_plus_ring2) % 2; + uncompressed_bin.segment_num() <= max_ring_diff; uncompressed_bin.segment_num() += 2) { + + int geo_plane_num = detail::set_detection_axial_coords(proj_data_info_cyl_ptr, ring1_plus_ring2, uncompressed_bin, + detection_position_pair); + if (geo_plane_num < 0) { // Ring numbers out of range. continue; } - -#ifndef NDEBUG +# ifndef NDEBUG Bin check_bin; check_bin.set_bin_value(bin.get_bin_value()); - assert(proj_data_info_cyl_ptr->get_bin_for_det_pos_pair(check_bin, - detection_position_pair) == - Succeeded::yes); + assert(proj_data_info_cyl_ptr->get_bin_for_det_pos_pair(check_bin, detection_position_pair) == Succeeded::yes); assert(check_bin == bin); -#endif - - const DetectionPosition<>& pos1 = detection_position_pair.pos1(); +# endif + + const DetectionPosition<>& pos1 = detection_position_pair.pos1(); const DetectionPosition<>& pos2 = detection_position_pair.pos2(); - float lor_efficiency_this_pair = 1.F; - if (this->use_detector_efficiencies()) - { - lor_efficiency_this_pair = - efficiency_factors[pos1.axial_coord()][pos1.tangential_coord()] * - efficiency_factors[pos2.axial_coord()][pos2.tangential_coord()]; - } - if (this->use_dead_time()) - { - lor_efficiency_this_pair *= - get_dead_time_efficiency(pos1, start_time, end_time) * - get_dead_time_efficiency(pos2, start_time, end_time); - } - if (this->use_geometric_factors()) - { - lor_efficiency_this_pair *= -#ifdef SAME_AS_PETER + float lor_efficiency_this_pair = 1.F; + if (this->use_detector_efficiencies()) { + lor_efficiency_this_pair = efficiency_factors[pos1.axial_coord()][pos1.tangential_coord()] * + efficiency_factors[pos2.axial_coord()][pos2.tangential_coord()]; + } + if (this->use_dead_time()) { + lor_efficiency_this_pair *= + get_dead_time_efficiency(pos1, start_time, end_time) * get_dead_time_efficiency(pos2, start_time, end_time); + } + if (this->use_geometric_factors()) { + lor_efficiency_this_pair *= +# ifdef SAME_AS_PETER 1.F; -#else // this is 3dbkproj (at the moment) - geometric_factors[geo_plane_num][uncompressed_bin.tangential_pos_num()]; -#endif - } - lor_efficiency += lor_efficiency_this_pair; +# else // this is 3dbkproj (at the moment) + geometric_factors[geo_plane_num][uncompressed_bin.tangential_pos_num()]; +# endif + } + lor_efficiency += lor_efficiency_this_pair; } - if (this->use_crystal_interference_factors()) - { - view_efficiency += lor_efficiency * - crystal_interference_factors[uncompressed_bin.tangential_pos_num()][uncompressed_bin.view_num()%num_transaxial_crystals_per_block] ; - } - else - { - view_efficiency += lor_efficiency; - } - } - - if (this->use_geometric_factors()) - { - /* z==bin.get_axial_pos_num() only when min_axial_pos_num()==0*/ - // for oblique plaanes use the single radial profile from segment 0 - -#ifdef SAME_AS_PETER - const int geo_plane_num = 0; - - total_efficiency += view_efficiency * - geometric_factors[geo_plane_num][uncompressed_bin.tangential_pos_num()] * - geo_Z_corr; -#else - total_efficiency += view_efficiency * geo_Z_corr; -#endif - } - else - { - total_efficiency += view_efficiency; + if (this->use_crystal_interference_factors()) { + view_efficiency += lor_efficiency * + crystal_interference_factors[uncompressed_bin.tangential_pos_num()] + [uncompressed_bin.view_num() % num_transaxial_crystals_per_block]; + } else { + view_efficiency += lor_efficiency; } + } + + if (this->use_geometric_factors()) { + /* z==bin.get_axial_pos_num() only when min_axial_pos_num()==0*/ + // for oblique plaanes use the single radial profile from segment 0 + +# ifdef SAME_AS_PETER + const int geo_plane_num = 0; + + total_efficiency += view_efficiency * geometric_factors[geo_plane_num][uncompressed_bin.tangential_pos_num()] * geo_Z_corr; +# else + total_efficiency += view_efficiency * geo_Z_corr; +# endif + } else { + total_efficiency += view_efficiency; + } } return total_efficiency; } #endif - -float -BinNormalisationFromECAT7::get_dead_time_efficiency (const DetectionPosition<>& det_pos, - const double start_time, - const double end_time) const -{ +float +BinNormalisationFromECAT7::get_dead_time_efficiency(const DetectionPosition<>& det_pos, const double start_time, + const double end_time) const { if (is_null_ptr(singles_rates_ptr)) { return 1; } // Get singles rate per block (rate per singles unit / blocks per singles unit). - const float rate = singles_rates_ptr->get_singles_rate(det_pos, start_time, end_time) / - num_blocks_per_singles_unit; - - return - ( 1.0F + axial_t1_array[ det_pos.axial_coord()/num_axial_blocks_per_singles_unit] * rate + - axial_t2_array[ det_pos.axial_coord()/num_axial_blocks_per_singles_unit] * rate * rate ); - - //* ( 1. + ( trans_t1_array[ det_pos.tangential_coord() % num_transaxial_crystals_per_block ] * rate ) ) ; - -} + const float rate = singles_rates_ptr->get_singles_rate(det_pos, start_time, end_time) / num_blocks_per_singles_unit; + return (1.0F + axial_t1_array[det_pos.axial_coord() / num_axial_blocks_per_singles_unit] * rate + + axial_t2_array[det_pos.axial_coord() / num_axial_blocks_per_singles_unit] * rate * rate); + //* ( 1. + ( trans_t1_array[ det_pos.tangential_coord() % num_transaxial_crystals_per_block ] * rate ) ) ; +} END_NAMESPACE_ECAT7 -END_NAMESPACE_ECAT +END_NAMESPACE_ECAT END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/BinNormalisationFromECAT8.cxx b/src/recon_buildblock/BinNormalisationFromECAT8.cxx index bd2960fde0..006336c81b 100644 --- a/src/recon_buildblock/BinNormalisationFromECAT8.cxx +++ b/src/recon_buildblock/BinNormalisationFromECAT8.cxx @@ -32,7 +32,6 @@ \author Sanida Mustafovic */ - #include "stir/recon_buildblock/BinNormalisationFromECAT8.h" #include "stir/DetectionPosition.h" #include "stir/DetectionPositionPair.h" @@ -60,118 +59,87 @@ using std::ios; START_NAMESPACE_STIR START_NAMESPACE_ECAT - - -const char * const -BinNormalisationFromECAT8::registered_name = "From ECAT8"; +const char* const BinNormalisationFromECAT8::registered_name = "From ECAT8"; - -namespace detail -{ +namespace detail { // // helper functions used in this class. // - -static -int -calc_ring1_plus_ring2(const Bin& bin, - const ProjDataInfoCylindricalNoArcCorr *proj_data_cyl) { +static int +calc_ring1_plus_ring2(const Bin& bin, const ProjDataInfoCylindricalNoArcCorr* proj_data_cyl) { int segment_num = bin.segment_num(); - + const int min_ring_diff = proj_data_cyl->get_min_ring_difference(segment_num); const int max_ring_diff = proj_data_cyl->get_max_ring_difference(segment_num); const int num_rings = proj_data_cyl->get_scanner_ptr()->get_num_rings(); - return( (2 * bin.axial_pos_num() - - (proj_data_cyl->get_min_axial_pos_num(segment_num) + - proj_data_cyl->get_max_axial_pos_num(segment_num)) - ) / (min_ring_diff != max_ring_diff ? 2 : 1) - + num_rings - 1 ); - + return ((2 * bin.axial_pos_num() - + (proj_data_cyl->get_min_axial_pos_num(segment_num) + proj_data_cyl->get_max_axial_pos_num(segment_num))) / + (min_ring_diff != max_ring_diff ? 2 : 1) + + num_rings - 1); } - - -static -void -set_detection_tangential_coords(shared_ptr proj_data_cyl_uncomp, - const Bin& uncomp_bin, +static void +set_detection_tangential_coords(shared_ptr proj_data_cyl_uncomp, const Bin& uncomp_bin, DetectionPositionPair<>& detection_position_pair) { - int det1_num=0; - int det2_num=0; - - proj_data_cyl_uncomp->get_det_num_pair_for_view_tangential_pos_num(det1_num, det2_num, - uncomp_bin.view_num(), + int det1_num = 0; + int det2_num = 0; + + proj_data_cyl_uncomp->get_det_num_pair_for_view_tangential_pos_num(det1_num, det2_num, uncomp_bin.view_num(), uncomp_bin.tangential_pos_num()); detection_position_pair.pos1().tangential_coord() = det1_num; detection_position_pair.pos2().tangential_coord() = det2_num; - } - - // Returns the sum of the two axial coordinates. Or -1 if the ring positions are // out of range. // sets axial_coord of detection_position_pair -static -int -set_detection_axial_coords(const ProjDataInfoCylindricalNoArcCorr *proj_data_info_cyl, - int ring1_plus_ring2, const Bin& uncomp_bin, - DetectionPositionPair<>& detection_position_pair) { - +static int +set_detection_axial_coords(const ProjDataInfoCylindricalNoArcCorr* proj_data_info_cyl, int ring1_plus_ring2, + const Bin& uncomp_bin, DetectionPositionPair<>& detection_position_pair) { + const int num_rings = proj_data_info_cyl->get_scanner_ptr()->get_num_rings(); const int ring_diff = uncomp_bin.segment_num(); - const int ring1 = (ring1_plus_ring2 - ring_diff)/2; - const int ring2 = (ring1_plus_ring2 + ring_diff)/2; - - if (ring1<0 || ring2 < 0 || ring1>=num_rings || ring2 >= num_rings) { - return(-1); + const int ring1 = (ring1_plus_ring2 - ring_diff) / 2; + const int ring2 = (ring1_plus_ring2 + ring_diff) / 2; + + if (ring1 < 0 || ring2 < 0 || ring1 >= num_rings || ring2 >= num_rings) { + return (-1); } - - assert((ring1_plus_ring2 + ring_diff)%2 == 0); - assert((ring1_plus_ring2 - ring_diff)%2 == 0); - + + assert((ring1_plus_ring2 + ring_diff) % 2 == 0); + assert((ring1_plus_ring2 - ring_diff) % 2 == 0); + detection_position_pair.pos1().axial_coord() = ring1; detection_position_pair.pos2().axial_coord() = ring2; - - return(ring1 + ring2); + return (ring1 + ring2); } - - } // end of namespace detail - - - // // Member functions // - - -void -BinNormalisationFromECAT8::set_defaults() -{ +void +BinNormalisationFromECAT8::set_defaults() { this->normalisation_ECAT8_filename = ""; this->_use_gaps = true; this->_use_detector_efficiencies = true; this->_use_dead_time = false; this->_use_geometric_factors = true; - this->_use_crystal_interference_factors = true; + this->_use_crystal_interference_factors = true; } -void -BinNormalisationFromECAT8:: -initialise_keymap() -{ +void +BinNormalisationFromECAT8::initialise_keymap() { this->parser.add_start_key("Bin Normalisation From ECAT8"); // todo remove obsolete keyword this->parser.add_key("normalisation_ECAT8_filename", &this->normalisation_ECAT8_filename); @@ -179,73 +147,57 @@ initialise_keymap() this->parser.add_parsing_key("singles rates", &this->singles_rates_ptr); this->parser.add_key("use_gaps", &this->_use_gaps); this->parser.add_key("use_detector_efficiencies", &this->_use_detector_efficiencies); - //this->parser.add_key("use_dead_time", &this->_use_dead_time); + // this->parser.add_key("use_dead_time", &this->_use_dead_time); this->parser.add_key("use_geometric_factors", &this->_use_geometric_factors); this->parser.add_key("use_crystal_interference_factors", &this->_use_crystal_interference_factors); this->parser.add_stop_key("End Bin Normalisation From ECAT8"); } -bool -BinNormalisationFromECAT8:: -post_processing() -{ +bool +BinNormalisationFromECAT8::post_processing() { read_norm_data(normalisation_ECAT8_filename); -// this->set_calibration_factor(cross_calib_factor*calib_factor); TODO understand if we need to use cross calib factor. Let's set 1 for now + // this->set_calibration_factor(cross_calib_factor*calib_factor); TODO understand if we need to use cross calib factor. Let's + // set 1 for now this->set_calibration_factor(1); return false; } +BinNormalisationFromECAT8::BinNormalisationFromECAT8() { set_defaults(); } -BinNormalisationFromECAT8:: -BinNormalisationFromECAT8() -{ - set_defaults(); -} - -BinNormalisationFromECAT8:: -BinNormalisationFromECAT8(const string& filename) -{ +BinNormalisationFromECAT8::BinNormalisationFromECAT8(const string& filename) { set_defaults(); read_norm_data(filename); } Succeeded -BinNormalisationFromECAT8:: -set_up(const shared_ptr &exam_info_sptr_v, const shared_ptr& proj_data_info_ptr_v) -{ +BinNormalisationFromECAT8::set_up(const shared_ptr& exam_info_sptr_v, + const shared_ptr& proj_data_info_ptr_v) { BinNormalisation::set_up(exam_info_sptr_v, proj_data_info_ptr_v); set_exam_info_sptr(exam_info_sptr_v); proj_data_info_ptr = proj_data_info_ptr_v; - proj_data_info_cyl_ptr = - dynamic_cast(proj_data_info_ptr.get()); - if (proj_data_info_cyl_ptr==0) - { + proj_data_info_cyl_ptr = dynamic_cast(proj_data_info_ptr.get()); + if (proj_data_info_cyl_ptr == 0) { warning("BinNormalisationFromECAT8 can only be used on non-arccorrected data\n"); return Succeeded::no; } - if (*proj_data_info_ptr->get_scanner_ptr() != *scanner_ptr) - { + if (*proj_data_info_ptr->get_scanner_ptr() != *scanner_ptr) { warning("BinNormalisationFromECAT8: scanner object from proj data is different from the one " - "from the normalisation file\n"); + "from the normalisation file\n"); return Succeeded::no; } - span = - proj_data_info_cyl_ptr->get_max_ring_difference(0) - - proj_data_info_cyl_ptr->get_min_ring_difference(0) + 1; + span = proj_data_info_cyl_ptr->get_max_ring_difference(0) - proj_data_info_cyl_ptr->get_min_ring_difference(0) + 1; // TODO insert check all other segments are the same - mash = scanner_ptr->get_num_detectors_per_ring()/2/proj_data_info_ptr->get_num_views(); + mash = scanner_ptr->get_num_detectors_per_ring() / 2 / proj_data_info_ptr->get_num_views(); return Succeeded::yes; } void -BinNormalisationFromECAT8:: -read_norm_data(const string& filename) -{ - +BinNormalisationFromECAT8::read_norm_data(const string& filename) { + #if 0 MatrixFile* mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, Norm3d); if (mptr == 0) @@ -275,62 +227,54 @@ MatrixFile* mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, Norm3d); parser.add_key("originating_system", &originating_system); parser.add_key("name_of_data_file", &data_file_name); parser.add_key("%number of buckets", &num_buckets); - parser.add_key("%scanner quantification factor (Bq*s/ECAT counts)",& calib_factor); - parser.add_key("%cross calibration factor",& cross_calib_factor); + parser.add_key("%scanner quantification factor (Bq*s/ECAT counts)", &calib_factor); + parser.add_key("%cross calibration factor", &cross_calib_factor); parser.parse(filename.c_str()); } #endif // remove trailing \r - std::string s=/*interfile_parser.*/originating_system; - s.erase( std::remove_if( s.begin(), s.end(), isspace ), s.end() ); - /*interfile_parser.*/originating_system=s; - s=/*interfile_parser.*/data_file_name; - s.erase( std::remove_if( s.begin(), s.end(), isspace ), s.end() ); - /*interfile_parser.*/data_file_name=s; - - this->scanner_ptr.reset(Scanner::get_scanner_from_name(/*interfile_parser.*/originating_system)); - switch(this->scanner_ptr->get_type()) - { - //case Scanner::E1080: - case Scanner::Siemens_mCT: - case Scanner::Siemens_mMR: - break; - default: - error(boost::format("Unknown originating_system '%s', when parsing file '%s'") % /*interfile_parser.*/originating_system % filename ); - } + std::string s = /*interfile_parser.*/ originating_system; + s.erase(std::remove_if(s.begin(), s.end(), isspace), s.end()); + /*interfile_parser.*/ originating_system = s; + s = /*interfile_parser.*/ data_file_name; + s.erase(std::remove_if(s.begin(), s.end(), isspace), s.end()); + /*interfile_parser.*/ data_file_name = s; + + this->scanner_ptr.reset(Scanner::get_scanner_from_name(/*interfile_parser.*/ originating_system)); + switch (this->scanner_ptr->get_type()) { + // case Scanner::E1080: + case Scanner::Siemens_mCT: + case Scanner::Siemens_mMR: + break; + default: + error(boost::format("Unknown originating_system '%s', when parsing file '%s'") % /*interfile_parser.*/ originating_system % + filename); + } - char directory_name[max_filename_length]; - get_directory_name(directory_name, filename.c_str()); - char full_data_file_name[max_filename_length]; - strcpy(full_data_file_name, data_file_name.c_str()); - prepend_directory_name(full_data_file_name, directory_name); + char directory_name[max_filename_length]; + get_directory_name(directory_name, filename.c_str()); + char full_data_file_name[max_filename_length]; + strcpy(full_data_file_name, data_file_name.c_str()); + prepend_directory_name(full_data_file_name, directory_name); num_transaxial_crystals_per_block = scanner_ptr->get_num_transaxial_crystals_per_block(); - // Calculate the number of axial blocks per singles unit and + // Calculate the number of axial blocks per singles unit and // total number of blocks per singles unit. - int axial_crystals_per_singles_unit = - scanner_ptr->get_num_axial_crystals_per_singles_unit(); - - int transaxial_crystals_per_singles_unit = - scanner_ptr->get_num_transaxial_crystals_per_singles_unit(); - - int axial_crystals_per_block = - scanner_ptr->get_num_axial_crystals_per_block(); + int axial_crystals_per_singles_unit = scanner_ptr->get_num_axial_crystals_per_singles_unit(); + + int transaxial_crystals_per_singles_unit = scanner_ptr->get_num_transaxial_crystals_per_singles_unit(); + + int axial_crystals_per_block = scanner_ptr->get_num_axial_crystals_per_block(); + + int transaxial_crystals_per_block = scanner_ptr->get_num_transaxial_crystals_per_block(); - int transaxial_crystals_per_block = - scanner_ptr->get_num_transaxial_crystals_per_block(); - // Axial blocks. - num_axial_blocks_per_singles_unit = - axial_crystals_per_singles_unit / axial_crystals_per_block; - - int transaxial_blocks_per_singles_unit = - transaxial_crystals_per_singles_unit / transaxial_crystals_per_block; - + num_axial_blocks_per_singles_unit = axial_crystals_per_singles_unit / axial_crystals_per_block; + + int transaxial_blocks_per_singles_unit = transaxial_crystals_per_singles_unit / transaxial_crystals_per_block; + // Total blocks. - num_blocks_per_singles_unit = - num_axial_blocks_per_singles_unit * transaxial_blocks_per_singles_unit; - + num_blocks_per_singles_unit = num_axial_blocks_per_singles_unit * transaxial_blocks_per_singles_unit; #if 0 if (scanner_ptr->get_num_rings() != nrm_subheader_ptr->num_crystal_rings) @@ -342,44 +286,39 @@ MatrixFile* mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, Norm3d); "number of detectors per ring determined from subheader is %d, while the scanner object says it is %d\n", nrm_subheader_ptr->crystals_per_ring, scanner_ptr->get_num_detectors_per_ring()); #endif - proj_data_info_cyl_uncompressed_ptr.reset( - dynamic_cast( - ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - /*span=*/1, scanner_ptr->get_num_rings()-1, - /*num_views,=*/scanner_ptr->get_num_detectors_per_ring()/2, - /*num_tangential_poss=*/scanner_ptr->get_max_num_non_arccorrected_bins(), //XXXnrm_subheader_ptr->num_r_elements, - /*arc_corrected =*/false) - )); - + proj_data_info_cyl_uncompressed_ptr.reset(dynamic_cast(ProjDataInfo::ProjDataInfoCTI( + scanner_ptr, + /*span=*/1, scanner_ptr->get_num_rings() - 1, + /*num_views,=*/scanner_ptr->get_num_detectors_per_ring() / 2, + /*num_tangential_poss=*/scanner_ptr->get_max_num_non_arccorrected_bins(), // XXXnrm_subheader_ptr->num_r_elements, + /*arc_corrected =*/false))); + /* Extract geometrical & crystal interference, and crystal efficiencies from the - normalisation data. + normalisation data. */ // SM 13/02/2003 corrected number of min_tang_pos_num and max_tang_pos_num used get_max_num_non_arccorrected_bins() - // instead of get_num_detectors_per_ring() - //const int min_tang_pos_num = -(scanner_ptr->get_num_detectors_per_ring()/2); - //const int max_tang_pos_num = min_tang_pos_num + scanner_ptr->get_num_detectors_per_ring() - 1; + // instead of get_num_detectors_per_ring() + // const int min_tang_pos_num = -(scanner_ptr->get_num_detectors_per_ring()/2); + // const int max_tang_pos_num = min_tang_pos_num + scanner_ptr->get_num_detectors_per_ring() - 1; - const int min_tang_pos_num = -(scanner_ptr->get_max_num_non_arccorrected_bins())/2; - const int max_tang_pos_num = min_tang_pos_num +scanner_ptr->get_max_num_non_arccorrected_bins()- 1; + const int min_tang_pos_num = -(scanner_ptr->get_max_num_non_arccorrected_bins()) / 2; + const int max_tang_pos_num = min_tang_pos_num + scanner_ptr->get_max_num_non_arccorrected_bins() - 1; - /* The order of coefficients is as follows: + /* The order of coefficients is as follows: 1. geometric_factors (= number_of_corr_planes * number_of_bins) 2. crystal_interference_factors (num_transaxial_crystals_per_block * number_of_bins) 3. efficiency_factors (number_of_rings*number_of_crystals ) */ - geometric_factors = - Array<2,float>(IndexRange2D(0,scanner_ptr->get_num_rings()*2-1-1, //XXXXnrm_subheader_ptr->num_geo_corr_planes-1, - min_tang_pos_num, max_tang_pos_num)); + geometric_factors = + Array<2, float>(IndexRange2D(0, scanner_ptr->get_num_rings() * 2 - 1 - 1, // XXXXnrm_subheader_ptr->num_geo_corr_planes-1, + min_tang_pos_num, max_tang_pos_num)); crystal_interference_factors = - Array<2,float>(IndexRange2D(min_tang_pos_num, max_tang_pos_num, - 0, num_transaxial_crystals_per_block-1)); - // SM 13/02/2003 + Array<2, float>(IndexRange2D(min_tang_pos_num, max_tang_pos_num, 0, num_transaxial_crystals_per_block - 1)); + // SM 13/02/2003 efficiency_factors = - Array<2,float>(IndexRange2D(0,scanner_ptr->get_num_rings()-1, - 0, scanner_ptr->get_num_detectors_per_ring()-1)); - + Array<2, float>(IndexRange2D(0, scanner_ptr->get_num_rings() - 1, 0, scanner_ptr->get_num_detectors_per_ring() - 1)); #if 0 int geom_test = nrm_subheader_ptr->num_geo_corr_planes * (max_tang_pos_num-min_tang_pos_num +1); @@ -395,49 +334,39 @@ MatrixFile* mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, Norm3d); if (read_data(binary_data, efficiency_factors, ByteOrder::little_endian) != Succeeded::yes) error("failed reading efficiency_factors from '%s'", full_data_file_name); - if (scanner_ptr->get_type() == Scanner::Siemens_mMR) - { + if (scanner_ptr->get_type() == Scanner::Siemens_mMR) { // for mMR, we need to shift the efficiencies for 1 crystal. This is probably because of where the gap is inserted // TODO we have no idea if this is necessary for other ECAT8 scanners. // The code below works for the mMR ONLY - for (int r=0; rget_num_rings(); ++r) - { - int c=scanner_ptr->get_num_detectors_per_ring()-1; - const float save_last_eff = efficiency_factors[r][c]; - for (; c>0; --c) - { - efficiency_factors[r][c]= efficiency_factors[r][c-1]; - } - efficiency_factors[r][c]= save_last_eff; + for (int r = 0; r < scanner_ptr->get_num_rings(); ++r) { + int c = scanner_ptr->get_num_detectors_per_ring() - 1; + const float save_last_eff = efficiency_factors[r][c]; + for (; c > 0; --c) { + efficiency_factors[r][c] = efficiency_factors[r][c - 1]; } + efficiency_factors[r][c] = save_last_eff; + } } - if (this->_use_gaps) - { - // TODO we really have no idea where the gaps are for every ECAT8 scanner. - // The code below works for the mMR - if (scanner_ptr->get_num_virtual_transaxial_crystals_per_block()>0) - { - for (int r=0; rget_num_rings(); ++r) - for (int c=0; cget_num_detectors_per_ring(); - c+=scanner_ptr->get_num_transaxial_crystals_per_block()) - for (int inc=0; incget_num_virtual_transaxial_crystals_per_block(); ++inc) - { - efficiency_factors[r][c+inc]=0.F; - } - } - if (scanner_ptr->get_num_virtual_axial_crystals_per_block()>0) - { - // axial gaps for mCT etc - for (int r=scanner_ptr->get_num_axial_crystals_per_block()-scanner_ptr->get_num_virtual_axial_crystals_per_block(); - rget_num_rings(); - r+=scanner_ptr->get_num_axial_crystals_per_block()) - for (int inc=0; incget_num_virtual_axial_crystals_per_block(); ++inc) - { - efficiency_factors[r+inc].fill(0.F); - } + if (this->_use_gaps) { + // TODO we really have no idea where the gaps are for every ECAT8 scanner. + // The code below works for the mMR + if (scanner_ptr->get_num_virtual_transaxial_crystals_per_block() > 0) { + for (int r = 0; r < scanner_ptr->get_num_rings(); ++r) + for (int c = 0; c < scanner_ptr->get_num_detectors_per_ring(); c += scanner_ptr->get_num_transaxial_crystals_per_block()) + for (int inc = 0; inc < scanner_ptr->get_num_virtual_transaxial_crystals_per_block(); ++inc) { + efficiency_factors[r][c + inc] = 0.F; + } + } + if (scanner_ptr->get_num_virtual_axial_crystals_per_block() > 0) { + // axial gaps for mCT etc + for (int r = scanner_ptr->get_num_axial_crystals_per_block() - scanner_ptr->get_num_virtual_axial_crystals_per_block(); + r < scanner_ptr->get_num_rings(); r += scanner_ptr->get_num_axial_crystals_per_block()) + for (int inc = 0; inc < scanner_ptr->get_num_virtual_axial_crystals_per_block(); ++inc) { + efficiency_factors[r + inc].fill(0.F); } } + } // TODO mvoe dead-time stuff to a separate function #if 0 @@ -459,53 +388,45 @@ MatrixFile* mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, Norm3d); for (Array<1,float>::full_iterator iter = axial_t2_array.begin_all(); iter != axial_t2_array.end_all();) *iter++ = *axial_t2++; -#if 0 +# if 0 // this is currently not used by CTI and hence not by get_dead_time_efficiency float *trans_t1 = nrm_subheader_ptr->crystal_dtcor ; /* 'Non-paralyzing dead_times' for each transaxial Xstal in block */ trans_t1_array = Array<1,float>(0,num_transaxial_crystals_per_block-1); for (Array<1,float>::full_iterator iter = trans_t1_array.begin_all(); iter != trans_t1_array.end_all();) *iter++ = *trans_t1++; -#endif +# endif #endif - #if 1 - // to test pipe the obtained values into file - ofstream out_geom; - ofstream out_inter; - ofstream out_eff; - out_geom.open("geom_out.txt",ios::out); - out_inter.open("inter_out.txt",ios::out); - out_eff.open("eff_out.txt",ios::out); - - for ( int i = geometric_factors.get_min_index(); i<=geometric_factors.get_max_index();i++) - { - for ( int j =geometric_factors[i].get_min_index(); j <=geometric_factors[i].get_max_index(); j++) - { - out_geom << geometric_factors[i][j] << " " ; - } - out_geom << std::endl; + // to test pipe the obtained values into file + ofstream out_geom; + ofstream out_inter; + ofstream out_eff; + out_geom.open("geom_out.txt", ios::out); + out_inter.open("inter_out.txt", ios::out); + out_eff.open("eff_out.txt", ios::out); + + for (int i = geometric_factors.get_min_index(); i <= geometric_factors.get_max_index(); i++) { + for (int j = geometric_factors[i].get_min_index(); j <= geometric_factors[i].get_max_index(); j++) { + out_geom << geometric_factors[i][j] << " "; } + out_geom << std::endl; + } + for (int i = crystal_interference_factors.get_min_index(); i <= crystal_interference_factors.get_max_index(); i++) { + for (int j = crystal_interference_factors[i].get_min_index(); j <= crystal_interference_factors[i].get_max_index(); j++) { + out_inter << crystal_interference_factors[i][j] << " "; + } + out_inter << std::endl; + } - for ( int i = crystal_interference_factors.get_min_index(); i<=crystal_interference_factors.get_max_index();i++) - { - for ( int j =crystal_interference_factors[i].get_min_index(); j <=crystal_interference_factors[i].get_max_index(); j++) - { - out_inter << crystal_interference_factors[i][j] << " " ; - } - out_inter << std::endl; - } - - for ( int i = efficiency_factors.get_min_index(); i<=efficiency_factors.get_max_index();i++) - { - for ( int j =efficiency_factors[i].get_min_index(); j <=efficiency_factors[i].get_max_index(); j++) - { - out_eff << efficiency_factors[i][j] << " " ; - } - out_eff << std::endl<< std::endl; - } + for (int i = efficiency_factors.get_min_index(); i <= efficiency_factors.get_max_index(); i++) { + for (int j = efficiency_factors[i].get_min_index(); j <= efficiency_factors[i].get_max_index(); j++) { + out_eff << efficiency_factors[i][j] << " "; + } + out_eff << std::endl << std::endl; + } #endif @@ -516,39 +437,29 @@ MatrixFile* mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, Norm3d); #endif } -bool -BinNormalisationFromECAT8:: -use_detector_efficiencies() const -{ +bool +BinNormalisationFromECAT8::use_detector_efficiencies() const { return this->_use_detector_efficiencies; } -bool -BinNormalisationFromECAT8:: -use_dead_time() const -{ +bool +BinNormalisationFromECAT8::use_dead_time() const { return this->_use_dead_time; } -bool -BinNormalisationFromECAT8:: -use_geometric_factors() const -{ +bool +BinNormalisationFromECAT8::use_geometric_factors() const { return this->_use_geometric_factors; } -bool -BinNormalisationFromECAT8:: -use_crystal_interference_factors() const -{ +bool +BinNormalisationFromECAT8::use_crystal_interference_factors() const { return this->_use_crystal_interference_factors; } #if 1 -float -BinNormalisationFromECAT8:: -get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { - +float +BinNormalisationFromECAT8::get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { // TODO disable when not HR+ or HR++ /* @@ -564,47 +475,37 @@ get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const d */ const float geo_Z_corr = 1; - - float total_efficiency = 0 ; - + float total_efficiency = 0; + /* Correct dead time */ - const int start_view = bin.view_num() * mash ; - //SM removed bin.view_num() + mash ; - const int end_view = start_view + mash ; - //start_view +mash; + const int start_view = bin.view_num() * mash; + // SM removed bin.view_num() + mash ; + const int end_view = start_view + mash; + // start_view +mash; const int min_ring_diff = proj_data_info_cyl_ptr->get_min_ring_difference(bin.segment_num()); const int max_ring_diff = proj_data_info_cyl_ptr->get_max_ring_difference(bin.segment_num()); - - /* - ring1_plus_ring2 is the same for any ring pair that contributes to + /* + ring1_plus_ring2 is the same for any ring pair that contributes to this particular bin.segment_num(), bin.axial_pos_num(). We determine it first here. See ProjDataInfoCylindrical for the relevant formulas */ - const int ring1_plus_ring2 = detail::calc_ring1_plus_ring2(bin, proj_data_info_cyl_ptr); - - + const int ring1_plus_ring2 = detail::calc_ring1_plus_ring2(bin, proj_data_info_cyl_ptr); DetectionPositionPair<> detection_position_pair; - Bin uncompressed_bin(0,0,0,bin.tangential_pos_num()); + Bin uncompressed_bin(0, 0, 0, bin.tangential_pos_num()); { float view_efficiency = 0.; + for (uncompressed_bin.view_num() = start_view; uncompressed_bin.view_num() < end_view; ++uncompressed_bin.view_num()) { - for(uncompressed_bin.view_num() = start_view; - uncompressed_bin.view_num() < end_view; - ++uncompressed_bin.view_num() ) { + detail::set_detection_tangential_coords(proj_data_info_cyl_uncompressed_ptr, uncompressed_bin, detection_position_pair); - detail::set_detection_tangential_coords(proj_data_info_cyl_uncompressed_ptr, - uncompressed_bin, detection_position_pair); + float lor_efficiency = 0.; - - - float lor_efficiency= 0.; - /* loop over ring differences that contribute to bin.segment_num() at the current bin.axial_pos_num(). @@ -619,117 +520,89 @@ get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const d == (2*min_ring_diff+ring1_plus_ring2)%2 == ring1_plus_ring2%2 */ - for(uncompressed_bin.segment_num() = min_ring_diff + (min_ring_diff+ring1_plus_ring2)%2; - uncompressed_bin.segment_num() <= max_ring_diff; - uncompressed_bin.segment_num()+=2 ) { - - - int geo_plane_num = - detail::set_detection_axial_coords(proj_data_info_cyl_ptr, - ring1_plus_ring2, uncompressed_bin, - detection_position_pair); - if ( geo_plane_num < 0 ) { + for (uncompressed_bin.segment_num() = min_ring_diff + (min_ring_diff + ring1_plus_ring2) % 2; + uncompressed_bin.segment_num() <= max_ring_diff; uncompressed_bin.segment_num() += 2) { + + int geo_plane_num = detail::set_detection_axial_coords(proj_data_info_cyl_ptr, ring1_plus_ring2, uncompressed_bin, + detection_position_pair); + if (geo_plane_num < 0) { // Ring numbers out of range. continue; } - -#ifndef NDEBUG +# ifndef NDEBUG Bin check_bin; check_bin.set_bin_value(bin.get_bin_value()); - assert(proj_data_info_cyl_ptr->get_bin_for_det_pos_pair(check_bin, - detection_position_pair) == - Succeeded::yes); + assert(proj_data_info_cyl_ptr->get_bin_for_det_pos_pair(check_bin, detection_position_pair) == Succeeded::yes); assert(check_bin == bin); -#endif - - const DetectionPosition<>& pos1 = detection_position_pair.pos1(); +# endif + + const DetectionPosition<>& pos1 = detection_position_pair.pos1(); const DetectionPosition<>& pos2 = detection_position_pair.pos2(); - float lor_efficiency_this_pair = 1.F; - if (this->use_detector_efficiencies()) - { - lor_efficiency_this_pair = - efficiency_factors[pos1.axial_coord()][pos1.tangential_coord()] * - efficiency_factors[pos2.axial_coord()][pos2.tangential_coord()]; - } - if (this->use_dead_time()) - { - lor_efficiency_this_pair *= - get_dead_time_efficiency(pos1, start_time, end_time) * - get_dead_time_efficiency(pos2, start_time, end_time); - } - if (this->use_geometric_factors()) - { - lor_efficiency_this_pair *= -#ifdef SAME_AS_PETER + float lor_efficiency_this_pair = 1.F; + if (this->use_detector_efficiencies()) { + lor_efficiency_this_pair = efficiency_factors[pos1.axial_coord()][pos1.tangential_coord()] * + efficiency_factors[pos2.axial_coord()][pos2.tangential_coord()]; + } + if (this->use_dead_time()) { + lor_efficiency_this_pair *= + get_dead_time_efficiency(pos1, start_time, end_time) * get_dead_time_efficiency(pos2, start_time, end_time); + } + if (this->use_geometric_factors()) { + lor_efficiency_this_pair *= +# ifdef SAME_AS_PETER 1.F; -#else // this is 3dbkproj (at the moment) - geometric_factors[geo_plane_num][uncompressed_bin.tangential_pos_num()]; -#endif - } - lor_efficiency += lor_efficiency_this_pair; +# else // this is 3dbkproj (at the moment) + geometric_factors[geo_plane_num][uncompressed_bin.tangential_pos_num()]; +# endif + } + lor_efficiency += lor_efficiency_this_pair; } - if (this->use_crystal_interference_factors()) - { - view_efficiency += lor_efficiency * - crystal_interference_factors[uncompressed_bin.tangential_pos_num()][uncompressed_bin.view_num()%num_transaxial_crystals_per_block] ; - } - else - { - view_efficiency += lor_efficiency; - } - } - - if (this->use_geometric_factors()) - { - /* z==bin.get_axial_pos_num() only when min_axial_pos_num()==0*/ - // for oblique plaanes use the single radial profile from segment 0 - -#ifdef SAME_AS_PETER - const int geo_plane_num = 0; - - total_efficiency += view_efficiency * - geometric_factors[geo_plane_num][uncompressed_bin.tangential_pos_num()] * - geo_Z_corr; -#else - total_efficiency += view_efficiency * geo_Z_corr; -#endif - } - else - { - total_efficiency += view_efficiency; + if (this->use_crystal_interference_factors()) { + view_efficiency += lor_efficiency * + crystal_interference_factors[uncompressed_bin.tangential_pos_num()] + [uncompressed_bin.view_num() % num_transaxial_crystals_per_block]; + } else { + view_efficiency += lor_efficiency; } + } + + if (this->use_geometric_factors()) { + /* z==bin.get_axial_pos_num() only when min_axial_pos_num()==0*/ + // for oblique plaanes use the single radial profile from segment 0 + +# ifdef SAME_AS_PETER + const int geo_plane_num = 0; + + total_efficiency += view_efficiency * geometric_factors[geo_plane_num][uncompressed_bin.tangential_pos_num()] * geo_Z_corr; +# else + total_efficiency += view_efficiency * geo_Z_corr; +# endif + } else { + total_efficiency += view_efficiency; + } } return total_efficiency; } #endif - -float -BinNormalisationFromECAT8::get_dead_time_efficiency (const DetectionPosition<>& det_pos, - const double start_time, - const double end_time) const -{ +float +BinNormalisationFromECAT8::get_dead_time_efficiency(const DetectionPosition<>& det_pos, const double start_time, + const double end_time) const { if (is_null_ptr(singles_rates_ptr)) { return 1; } // Get singles rate per block (rate per singles unit / blocks per singles unit). - const float rate = singles_rates_ptr->get_singles_rate(det_pos, start_time, end_time) / - num_blocks_per_singles_unit; - - return - ( 1.0F + axial_t1_array[ det_pos.axial_coord()/num_axial_blocks_per_singles_unit] * rate + - axial_t2_array[ det_pos.axial_coord()/num_axial_blocks_per_singles_unit] * rate * rate ); - - //* ( 1. + ( trans_t1_array[ det_pos.tangential_coord() % num_transaxial_crystals_per_block ] * rate ) ) ; - -} + const float rate = singles_rates_ptr->get_singles_rate(det_pos, start_time, end_time) / num_blocks_per_singles_unit; + return (1.0F + axial_t1_array[det_pos.axial_coord() / num_axial_blocks_per_singles_unit] * rate + + axial_t2_array[det_pos.axial_coord() / num_axial_blocks_per_singles_unit] * rate * rate); + //* ( 1. + ( trans_t1_array[ det_pos.tangential_coord() % num_transaxial_crystals_per_block ] * rate ) ) ; +} -END_NAMESPACE_ECAT +END_NAMESPACE_ECAT END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/BinNormalisationFromGEHDF5.cxx b/src/recon_buildblock/BinNormalisationFromGEHDF5.cxx index dad62a913e..40b6dc8c54 100644 --- a/src/recon_buildblock/BinNormalisationFromGEHDF5.cxx +++ b/src/recon_buildblock/BinNormalisationFromGEHDF5.cxx @@ -33,7 +33,6 @@ \author Palak Wadhwa */ - #include "stir/recon_buildblock/BinNormalisationFromGEHDF5.h" #include "stir/DetectionPosition.h" #include "stir/DetectionPositionPair.h" @@ -65,121 +64,93 @@ START_NAMESPACE_STIR namespace GE { namespace RDF_HDF5 { - - -const char * const -BinNormalisationFromGEHDF5::registered_name = "From GE HDF5"; - +const char* const BinNormalisationFromGEHDF5::registered_name = "From GE HDF5"; -namespace detail -{ +namespace detail { // // helper functions used in this class. // - -static -int -calc_ring1_plus_ring2(const Bin& bin, - const ProjDataInfoCylindricalNoArcCorr *proj_data_cyl) { +static int +calc_ring1_plus_ring2(const Bin& bin, const ProjDataInfoCylindricalNoArcCorr* proj_data_cyl) { int segment_num = bin.segment_num(); - + const int min_ring_diff = proj_data_cyl->get_min_ring_difference(segment_num); const int max_ring_diff = proj_data_cyl->get_max_ring_difference(segment_num); const int num_rings = proj_data_cyl->get_scanner_ptr()->get_num_rings(); - return( (2 * bin.axial_pos_num() - - (proj_data_cyl->get_min_axial_pos_num(segment_num) + - proj_data_cyl->get_max_axial_pos_num(segment_num)) - ) / (min_ring_diff != max_ring_diff ? 2 : 1) - + num_rings - 1 ); - + return ((2 * bin.axial_pos_num() - + (proj_data_cyl->get_min_axial_pos_num(segment_num) + proj_data_cyl->get_max_axial_pos_num(segment_num))) / + (min_ring_diff != max_ring_diff ? 2 : 1) + + num_rings - 1); } - - -static -void -set_detection_tangential_coords(shared_ptr proj_data_cyl_uncomp, - const Bin& uncomp_bin, +static void +set_detection_tangential_coords(shared_ptr proj_data_cyl_uncomp, const Bin& uncomp_bin, DetectionPositionPair<>& detection_position_pair) { - int det1_num=0; - int det2_num=0; - - proj_data_cyl_uncomp->get_det_num_pair_for_view_tangential_pos_num(det1_num, det2_num, - uncomp_bin.view_num(), + int det1_num = 0; + int det2_num = 0; + + proj_data_cyl_uncomp->get_det_num_pair_for_view_tangential_pos_num(det1_num, det2_num, uncomp_bin.view_num(), uncomp_bin.tangential_pos_num()); detection_position_pair.pos1().tangential_coord() = det1_num; detection_position_pair.pos2().tangential_coord() = det2_num; - } - - // Returns the sum of the two axial coordinates. Or -1 if the ring positions are // out of range. // sets axial_coord of detection_position_pair -static -int -set_detection_axial_coords(const ProjDataInfoCylindricalNoArcCorr *proj_data_info_cyl, - int ring1_plus_ring2, const Bin& uncomp_bin, - DetectionPositionPair<>& detection_position_pair) { - +static int +set_detection_axial_coords(const ProjDataInfoCylindricalNoArcCorr* proj_data_info_cyl, int ring1_plus_ring2, + const Bin& uncomp_bin, DetectionPositionPair<>& detection_position_pair) { + const int num_rings = proj_data_info_cyl->get_scanner_ptr()->get_num_rings(); const int ring_diff = uncomp_bin.segment_num(); - const int ring1 = (ring1_plus_ring2 - ring_diff)/2; - const int ring2 = (ring1_plus_ring2 + ring_diff)/2; - - if (ring1<0 || ring2 < 0 || ring1>=num_rings || ring2 >= num_rings) { - return(-1); + const int ring1 = (ring1_plus_ring2 - ring_diff) / 2; + const int ring2 = (ring1_plus_ring2 + ring_diff) / 2; + + if (ring1 < 0 || ring2 < 0 || ring1 >= num_rings || ring2 >= num_rings) { + return (-1); } - - assert((ring1_plus_ring2 + ring_diff)%2 == 0); - assert((ring1_plus_ring2 - ring_diff)%2 == 0); - + + assert((ring1_plus_ring2 + ring_diff) % 2 == 0); + assert((ring1_plus_ring2 - ring_diff) % 2 == 0); + detection_position_pair.pos1().axial_coord() = ring1; detection_position_pair.pos2().axial_coord() = ring2; - - return(ring1 + ring2); + return (ring1 + ring2); } // Returns a vetor with the segment sequence, as 0, 1, -1, 2, -2,... -static -std::vector // Prefered since C++11 -create_segment_sequence(shared_ptr const& proj_data_info_ptr) -{ +static std::vector // Prefered since C++11 +create_segment_sequence(shared_ptr const& proj_data_info_ptr) { std::vector segment_sequence; - segment_sequence.resize(2*proj_data_info_ptr->get_max_segment_num()+1); + segment_sequence.resize(2 * proj_data_info_ptr->get_max_segment_num() + 1); segment_sequence[0] = 0; // PW Flipped the segments, segment sequence is now as: 0,1,-1 and so on. - for (int segment_num = 1; segment_num<=proj_data_info_ptr->get_max_segment_num(); ++segment_num) - { - segment_sequence[2*segment_num-1] = segment_num; - segment_sequence[2*segment_num] = -segment_num; + for (int segment_num = 1; segment_num <= proj_data_info_ptr->get_max_segment_num(); ++segment_num) { + segment_sequence[2 * segment_num - 1] = segment_num; + segment_sequence[2 * segment_num] = -segment_num; } return segment_sequence; } // Returns the index in the segment sequence for a given segment number (e.g -1 returns 2) -static -unsigned int -find_segment_index_in_sequence(std::vector& segment_sequence, const int segment_num) -{ +static unsigned int +find_segment_index_in_sequence(std::vector& segment_sequence, const int segment_num) { std::vector::const_iterator iter = std::find(segment_sequence.begin(), segment_sequence.end(), segment_num); - assert(iter != segment_sequence.end()); + assert(iter != segment_sequence.end()); return static_cast(iter - segment_sequence.begin()); } -// Creates a vector that has the axial position offset for each segment. -static -std::vector // Prefered since C++11 -create_ax_pos_offset(shared_ptr const& proj_data_info_ptr, std::vector& segment_sequence) -{ +// Creates a vector that has the axial position offset for each segment. +static std::vector // Prefered since C++11 +create_ax_pos_offset(shared_ptr const& proj_data_info_ptr, std::vector& segment_sequence) { std::vector seg_ax_offset; seg_ax_offset.resize(proj_data_info_ptr->get_num_segments()); @@ -187,236 +158,205 @@ create_ax_pos_offset(shared_ptr const& proj_data_info_ptr, std::ve unsigned int previous_value = 0; - for (int i_seg = 1; i_seg < proj_data_info_ptr->get_num_segments(); ++i_seg) - { - const int segment_num = segment_sequence[i_seg-1]; + for (int i_seg = 1; i_seg < proj_data_info_ptr->get_num_segments(); ++i_seg) { + const int segment_num = segment_sequence[i_seg - 1]; - seg_ax_offset[i_seg] = static_cast(proj_data_info_ptr->get_num_axial_poss(segment_num)) + - previous_value; - previous_value = seg_ax_offset[i_seg]; + seg_ax_offset[i_seg] = static_cast(proj_data_info_ptr->get_num_axial_poss(segment_num)) + previous_value; + previous_value = seg_ax_offset[i_seg]; } return seg_ax_offset; } } // end of namespace detail - - - // // Member functions // - - -void -BinNormalisationFromGEHDF5::set_defaults() -{ +void +BinNormalisationFromGEHDF5::set_defaults() { this->normalisation_GEHDF5_filename = ""; - //this->_use_gaps = false; + // this->_use_gaps = false; this->_use_detector_efficiencies = true; this->_use_dead_time = false; this->_use_geometric_factors = true; } -void -BinNormalisationFromGEHDF5:: -initialise_keymap() -{ +void +BinNormalisationFromGEHDF5::initialise_keymap() { this->parser.add_start_key("Bin Normalisation From GE HDF5"); this->parser.add_key("normalisation_filename", &this->normalisation_GEHDF5_filename); - //this->parser.add_parsing_key("singles rates", &this->singles_rates_ptr); - //this->parser.add_key("use_gaps", &this->_use_gaps); + // this->parser.add_parsing_key("singles rates", &this->singles_rates_ptr); + // this->parser.add_key("use_gaps", &this->_use_gaps); this->parser.add_key("use_detector_efficiencies", &this->_use_detector_efficiencies); - //this->parser.add_key("use_dead_time", &this->_use_dead_time); + // this->parser.add_key("use_dead_time", &this->_use_dead_time); this->parser.add_key("use_geometric_factors", &this->_use_geometric_factors); this->parser.add_stop_key("End Bin Normalisation From GE HDF5"); } -bool -BinNormalisationFromGEHDF5:: -post_processing() -{ +bool +BinNormalisationFromGEHDF5::post_processing() { read_norm_data(normalisation_GEHDF5_filename); - this->set_calibration_factor(1); //TODO: read actual factor somewhere + this->set_calibration_factor(1); // TODO: read actual factor somewhere return false; } +BinNormalisationFromGEHDF5::BinNormalisationFromGEHDF5() { set_defaults(); } -BinNormalisationFromGEHDF5:: -BinNormalisationFromGEHDF5() -{ - set_defaults(); -} - -BinNormalisationFromGEHDF5:: -BinNormalisationFromGEHDF5(const string& filename) -{ - read_norm_data(filename); -} +BinNormalisationFromGEHDF5::BinNormalisationFromGEHDF5(const string& filename) { read_norm_data(filename); } Succeeded -BinNormalisationFromGEHDF5:: -set_up(const shared_ptr &exam_info_sptr, const shared_ptr& proj_data_info_ptr_v) -{ +BinNormalisationFromGEHDF5::set_up(const shared_ptr& exam_info_sptr, + const shared_ptr& proj_data_info_ptr_v) { BinNormalisation::set_up(exam_info_sptr, proj_data_info_ptr_v); proj_data_info_ptr = proj_data_info_ptr_v; - proj_data_info_cyl_ptr = - dynamic_cast(proj_data_info_ptr.get()); - if (proj_data_info_cyl_ptr==0) - { + proj_data_info_cyl_ptr = dynamic_cast(proj_data_info_ptr.get()); + if (proj_data_info_cyl_ptr == 0) { warning("BinNormalisationFromGEHDF5 can only be used on non-arccorrected data\n"); return Succeeded::no; } - if (*proj_data_info_ptr->get_scanner_ptr() != *scanner_ptr) - { + if (*proj_data_info_ptr->get_scanner_ptr() != *scanner_ptr) { warning("BinNormalisationFromGEHDF5: scanner object from proj data is different from the one " - "from the normalisation file\n"); + "from the normalisation file\n"); return Succeeded::no; } - mash = scanner_ptr->get_num_detectors_per_ring()/2/proj_data_info_ptr->get_num_views(); + mash = scanner_ptr->get_num_detectors_per_ring() / 2 / proj_data_info_ptr->get_num_views(); return Succeeded::yes; } // Load all data that is needed for corrections -// This function will take a filename, that can be either a GE norm file, or a GE geo file. If you wan to do geo and norm corrections -// then you want the norm file as input, and if you only want geo files, then just the geo file is enough. The function will read from these files and -// fill the atributes with a full sinogram of efficiency factors and geometry factors. +// This function will take a filename, that can be either a GE norm file, or a GE geo file. If you wan to do geo and norm +// corrections then you want the norm file as input, and if you only want geo files, then just the geo file is enough. The +// function will read from these files and fill the atributes with a full sinogram of efficiency factors and geometry factors. void -BinNormalisationFromGEHDF5:: -read_norm_data(const string& filename) -{ +BinNormalisationFromGEHDF5::read_norm_data(const string& filename) { // If we actually do not want any correction, forget loading the data - if(!this->use_detector_efficiencies() && !this->use_geometric_factors()) + if (!this->use_detector_efficiencies() && !this->use_geometric_factors()) return; - // Build the HDF5 wrapper. This opens the file and makes sure its the correct type, plus loads all information about the scanner. + // Build the HDF5 wrapper. This opens the file and makes sure its the correct type, plus loads all information about the + // scanner. m_input_hdf5_sptr.reset(new GEHDF5Wrapper(filename)); - // We need the norm file to correct for geometry and efficiecies (the geometric correcction is contained inside the norm file too!) - // But if we are not correcting for efficiencies, then we dont require the file to be a norm file, it can be geo. - if(this->use_detector_efficiencies() && !m_input_hdf5_sptr->is_norm_file()) + // We need the norm file to correct for geometry and efficiecies (the geometric correcction is contained inside the norm file + // too!) But if we are not correcting for efficiencies, then we dont require the file to be a norm file, it can be geo. + if (this->use_detector_efficiencies() && !m_input_hdf5_sptr->is_norm_file()) error("Norm file required, another one given (possibly geo file). Aborting"); this->scanner_ptr = m_input_hdf5_sptr->get_scanner_sptr(); - // Generate a Projection data Info from the uncompressed scan, - proj_data_info_cyl_uncompressed_ptr.reset( - dynamic_cast( + // Generate a Projection data Info from the uncompressed scan, + proj_data_info_cyl_uncompressed_ptr.reset(dynamic_cast( ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - /*span=*/1, - /*max_delta*/scanner_ptr->get_num_rings()-1, - /*num_views,=*/scanner_ptr->get_num_detectors_per_ring()/2, - /*num_tangential_poss=*/scanner_ptr->get_max_num_non_arccorrected_bins(), - /*arc_corrected =*/false) ) ); + /*span=*/1, + /*max_delta*/ scanner_ptr->get_num_rings() - 1, + /*num_views,=*/scanner_ptr->get_num_detectors_per_ring() / 2, + /*num_tangential_poss=*/scanner_ptr->get_max_num_non_arccorrected_bins(), + /*arc_corrected =*/false))); // // Read efficiency data from file // - if(this->use_detector_efficiencies()) - { + if (this->use_detector_efficiencies()) { // Allocate efficiency factor data from an "uncompressed scanner" (i.e. span = 1, all bins are physical bins in the scanner). efficiency_factors = - Array<2,float>(IndexRange2D(0,scanner_ptr->get_num_rings()-1, - 0, scanner_ptr->get_num_detectors_per_ring()-1)); - // Initialize the data reading. This internally checks the file and loads required variables fo further reading. + Array<2, float>(IndexRange2D(0, scanner_ptr->get_num_rings() - 1, 0, scanner_ptr->get_num_detectors_per_ring() - 1)); + // Initialize the data reading. This internally checks the file and loads required variables fo further reading. m_input_hdf5_sptr->initialise_efficiency_factors(); // Do the reading using a buffer. - unsigned int total_size = (scanner_ptr->get_num_rings()-1)*(scanner_ptr->get_num_detectors_per_ring()-1); - stir::Array<1, float> buffer(0, total_size-1); + unsigned int total_size = (scanner_ptr->get_num_rings() - 1) * (scanner_ptr->get_num_detectors_per_ring() - 1); + stir::Array<1, float> buffer(0, total_size - 1); m_input_hdf5_sptr->read_efficiency_factors(buffer); - // Aparently GE stores the normalization factor and not the "efficiency factor", so we just need to invert it. - // Lambda function, this just applies 1/buffer and stores it in efficiency_factors - std::transform(buffer.begin(), buffer.end(),efficiency_factors.begin_all(), [](const float f) { return 1/f;} ); + // Aparently GE stores the normalization factor and not the "efficiency factor", so we just need to invert it. + // Lambda function, this just applies 1/buffer and stores it in efficiency_factors + std::transform(buffer.begin(), buffer.end(), efficiency_factors.begin_all(), [](const float f) { return 1 / f; }); } // // Read geo data from file // - if(this->use_geometric_factors()) - { - // Construct a proper ProjDataInfo to initialize geometry factors array and use it to know the boudns of the iteratios to load it. - shared_ptr projInfo = ProjDataInfo::construct_proj_data_info(scanner_ptr, - /*span*/ 2, - /* max_delta*/ scanner_ptr->get_num_rings()-1, - /* num_views */ scanner_ptr->get_num_detectors_per_ring()/2, - /* num_tangential_poss */ scanner_ptr->get_max_num_non_arccorrected_bins(), - /* arc_corrected */ false - ); - geo_eff_factors_sptr.reset(new ProjDataInMemory(m_input_hdf5_sptr->get_exam_info_sptr(), - projInfo, - true)); // Initialize with zeroes (always true internally...) - - // TODO: remove all these loops and "duplication", and load the entire geometric factors file. Then modify the function get_geometric_factors() - // so that when accessed, re-indexes the bin number to the correct geometric factor. - // Doing this would save lots of RAM, as there are lots of symetries that are exploited in the geo file, but we are here undoing all that and duplicating data. - + if (this->use_geometric_factors()) { + // Construct a proper ProjDataInfo to initialize geometry factors array and use it to know the boudns of the iteratios to load + // it. + shared_ptr projInfo = + ProjDataInfo::construct_proj_data_info(scanner_ptr, + /*span*/ 2, + /* max_delta*/ scanner_ptr->get_num_rings() - 1, + /* num_views */ scanner_ptr->get_num_detectors_per_ring() / 2, + /* num_tangential_poss */ scanner_ptr->get_max_num_non_arccorrected_bins(), + /* arc_corrected */ false); + geo_eff_factors_sptr.reset(new ProjDataInMemory(m_input_hdf5_sptr->get_exam_info_sptr(), projInfo, + true)); // Initialize with zeroes (always true internally...) + + // TODO: remove all these loops and "duplication", and load the entire geometric factors file. Then modify the function + // get_geometric_factors() so that when accessed, re-indexes the bin number to the correct geometric factor. Doing this would + // save lots of RAM, as there are lots of symetries that are exploited in the geo file, but we are here undoing all that and + // duplicating data. + // These arrays will help us index the data to read. Just auxiliary variables. - std::vector segment_sequence = detail::create_segment_sequence(projInfo); - std::vector segment_axial_position_offset = detail::create_ax_pos_offset (projInfo, segment_sequence); - - int num_crystals_per_bucket=scanner_ptr->get_num_transaxial_crystals_per_bucket(); - // Geometric factors are related to geometry (ovbiously). This means that as the scanner has several geometric symetries itself, there is no need to - // store all of them in a big file. This is what GE does in RDF9 files. - // The following loops undo that. They go selecting different data pieces in the initialise_geo_factors() and reading different parts of - // it in read_geo_factors(), all to create a complete sinogram with all the geo factors loaded. - for (int i_seg = projInfo->get_min_segment_num(); i_seg <= projInfo->get_max_segment_num(); ++i_seg) - { - for(int i_view = 0; i_view < scanner_ptr->get_max_num_views(); ++i_view) - { - // Auxiliary single viewgram as a buffer - Viewgram viewgram = projInfo->get_empty_viewgram(projInfo->get_num_views()-1-i_view, i_seg); - // AB TODO This allocates the memory. I wish I knew how to do this without continous reallocation (by reusing) - viewgram.fill(0.0); - switch (m_input_hdf5_sptr->get_geo_dims()) - { - case 3: - { - m_input_hdf5_sptr->initialise_geo_factors_data(modulo(i_view,num_crystals_per_bucket)+1); - - // Define which chunk of the data we are reading from. - std::array offset = {segment_axial_position_offset[detail::find_segment_index_in_sequence(segment_sequence,i_seg)], 0}; - std::array count = {static_cast(projInfo->get_num_axial_poss(i_seg)), - static_cast(projInfo->get_num_tangential_poss())}; - // Initialize buffer to store temp variables - stir::Array<1, unsigned int> buffer(0, count[0]*count[1]-1); - // read geo chunk - m_input_hdf5_sptr->read_geometric_factors(buffer, offset, count); - // copy data back - // AB TODO: Hardcoded magic number, remove somehow (when magic is discovered) - std::transform(buffer.begin(), buffer.end(),viewgram.begin_all(), [](const float f) { return 1/(f*2.2110049e-4);} ); - break; - } - case 2: - { - m_input_hdf5_sptr->initialise_geo_factors_data(1); - - std::array offset = {static_cast(modulo(i_view,num_crystals_per_bucket)), 0}; - std::array count = {1, static_cast(projInfo->get_num_tangential_poss())}; - // Initialize buffer to store temp variables - stir::Array<1, unsigned int> buffer(0, count[1]-1); - // read geo chunk - m_input_hdf5_sptr->read_geometric_factors(buffer, offset, count); - std::vector repeat_buffer; - repeat_buffer.reserve(projInfo->get_num_axial_poss(i_seg)*count[1]-1); - // repeat the values - for (unsigned int i=0; iget_num_axial_poss(i_seg);i++) - repeat_buffer.insert(repeat_buffer.end(),buffer.begin(),buffer.end()); - // copy data back - // AB TODO: Hardcoded magic number, remove somehow (when magic is discovered) - std::transform(repeat_buffer.begin(), repeat_buffer.end(),viewgram.begin_all(), [](const float f) { return 1/(f*2.2110049e-4);} ); - break; - } - default: - error("BinNormalisationFromGEHDF5: Unexpected geometry type"); - } - - geo_eff_factors_sptr->set_viewgram(viewgram); - - }// end view for - }// end segment for -#if 0 // Use this to store loaded geo result in an interfile format. Useful for debugging purposes. + std::vector segment_sequence = detail::create_segment_sequence(projInfo); + std::vector segment_axial_position_offset = detail::create_ax_pos_offset(projInfo, segment_sequence); + + int num_crystals_per_bucket = scanner_ptr->get_num_transaxial_crystals_per_bucket(); + // Geometric factors are related to geometry (ovbiously). This means that as the scanner has several geometric symetries + // itself, there is no need to store all of them in a big file. This is what GE does in RDF9 files. The following loops undo + // that. They go selecting different data pieces in the initialise_geo_factors() and reading different parts of it in + // read_geo_factors(), all to create a complete sinogram with all the geo factors loaded. + for (int i_seg = projInfo->get_min_segment_num(); i_seg <= projInfo->get_max_segment_num(); ++i_seg) { + for (int i_view = 0; i_view < scanner_ptr->get_max_num_views(); ++i_view) { + // Auxiliary single viewgram as a buffer + Viewgram viewgram = projInfo->get_empty_viewgram(projInfo->get_num_views() - 1 - i_view, i_seg); + // AB TODO This allocates the memory. I wish I knew how to do this without continous reallocation (by reusing) + viewgram.fill(0.0); + switch (m_input_hdf5_sptr->get_geo_dims()) { + case 3: { + m_input_hdf5_sptr->initialise_geo_factors_data(modulo(i_view, num_crystals_per_bucket) + 1); + + // Define which chunk of the data we are reading from. + std::array offset = { + segment_axial_position_offset[detail::find_segment_index_in_sequence(segment_sequence, i_seg)], 0}; + std::array count = {static_cast(projInfo->get_num_axial_poss(i_seg)), + static_cast(projInfo->get_num_tangential_poss())}; + // Initialize buffer to store temp variables + stir::Array<1, unsigned int> buffer(0, count[0] * count[1] - 1); + // read geo chunk + m_input_hdf5_sptr->read_geometric_factors(buffer, offset, count); + // copy data back + // AB TODO: Hardcoded magic number, remove somehow (when magic is discovered) + std::transform(buffer.begin(), buffer.end(), viewgram.begin_all(), + [](const float f) { return 1 / (f * 2.2110049e-4); }); + break; + } + case 2: { + m_input_hdf5_sptr->initialise_geo_factors_data(1); + + std::array offset = {static_cast(modulo(i_view, num_crystals_per_bucket)), 0}; + std::array count = {1, static_cast(projInfo->get_num_tangential_poss())}; + // Initialize buffer to store temp variables + stir::Array<1, unsigned int> buffer(0, count[1] - 1); + // read geo chunk + m_input_hdf5_sptr->read_geometric_factors(buffer, offset, count); + std::vector repeat_buffer; + repeat_buffer.reserve(projInfo->get_num_axial_poss(i_seg) * count[1] - 1); + // repeat the values + for (unsigned int i = 0; i < projInfo->get_num_axial_poss(i_seg); i++) + repeat_buffer.insert(repeat_buffer.end(), buffer.begin(), buffer.end()); + // copy data back + // AB TODO: Hardcoded magic number, remove somehow (when magic is discovered) + std::transform(repeat_buffer.begin(), repeat_buffer.end(), viewgram.begin_all(), + [](const float f) { return 1 / (f * 2.2110049e-4); }); + break; + } + default: + error("BinNormalisationFromGEHDF5: Unexpected geometry type"); + } + + geo_eff_factors_sptr->set_viewgram(viewgram); + + } // end view for + } // end segment for +#if 0 // Use this to store loaded geo result in an interfile format. Useful for debugging purposes. shared_ptr output_projdata_ptr; const string filename="geo_debug.hs"; output_projdata_ptr.reset(new ProjDataInterfile(m_input_hdf5_sptr->get_exam_info_sptr(),projInfo,filename)); @@ -426,39 +366,32 @@ read_norm_data(const string& filename) output_projdata_ptr->set_viewgram(geo_eff_factors_sptr->get_viewgram(i_view,i_seg)); } #endif - }// end loading of geo factors + } // end loading of geo factors } -bool -BinNormalisationFromGEHDF5:: -use_detector_efficiencies() const -{ +bool +BinNormalisationFromGEHDF5::use_detector_efficiencies() const { return this->_use_detector_efficiencies; } -bool -BinNormalisationFromGEHDF5:: -use_dead_time() const -{ +bool +BinNormalisationFromGEHDF5::use_dead_time() const { return this->_use_dead_time; } -bool -BinNormalisationFromGEHDF5:: -use_geometric_factors() const -{ +bool +BinNormalisationFromGEHDF5::use_geometric_factors() const { return this->_use_geometric_factors; } -float -BinNormalisationFromGEHDF5:: -get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const -{ - float total_efficiency = 0 ; +float +BinNormalisationFromGEHDF5::get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, + const double end_time) const { + float total_efficiency = 0; /* TODO this loop does some complicated stuff with rings etc - It should be possible to replace this with + It should be possible to replace this with std::vector > det_pos_pairs; proj_data_info_cyl_ptr->get_all_det_pos_pairs_for_bin(det_pos_pairs, bin); @@ -467,79 +400,66 @@ get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const d ... } */ - + /* Correct dead time */ - const int start_view = bin.view_num() * mash ; - const int end_view = start_view + mash ; + const int start_view = bin.view_num() * mash; + const int end_view = start_view + mash; const int min_ring_diff = proj_data_info_cyl_ptr->get_min_ring_difference(bin.segment_num()); const int max_ring_diff = proj_data_info_cyl_ptr->get_max_ring_difference(bin.segment_num()); - - /* + /* ring1_plus_ring2 is the same for any ring pair that contributes to this particular bin.segment_num(), bin.axial_pos_num(). We determine it first here. See ProjDataInfoCylindrical for the relevant formulas */ - const int ring1_plus_ring2 = detail::calc_ring1_plus_ring2(bin, proj_data_info_cyl_ptr); - + const int ring1_plus_ring2 = detail::calc_ring1_plus_ring2(bin, proj_data_info_cyl_ptr); + DetectionPositionPair<> detection_position_pair; - Bin uncompressed_bin(0,0,0,bin.tangential_pos_num()); + Bin uncompressed_bin(0, 0, 0, bin.tangential_pos_num()); - float view_efficiency = 0.; - for(uncompressed_bin.view_num() = start_view; - uncompressed_bin.view_num() < end_view; - ++uncompressed_bin.view_num() ) - { - - detail::set_detection_tangential_coords(proj_data_info_cyl_uncompressed_ptr, - uncompressed_bin, detection_position_pair); - - float lor_efficiency= 0.; - + for (uncompressed_bin.view_num() = start_view; uncompressed_bin.view_num() < end_view; ++uncompressed_bin.view_num()) { + + detail::set_detection_tangential_coords(proj_data_info_cyl_uncompressed_ptr, uncompressed_bin, detection_position_pair); + + float lor_efficiency = 0.; + /* Loop over ring differences that contribute to bin.segment_num() at the current bin.axial_pos_num(). - The ring_difference increments with 2 as the other ring differences do not give a ring pair with this axial_position. - This is because: ring1_plus_ring2%2 == ring_diff%2 + The ring_difference increments with 2 as the other ring differences do not give a ring pair with this axial_position. + This is because: ring1_plus_ring2%2 == ring_diff%2 (which easily follows by plugging in ring1+ring2 and ring1-ring2). - The starting ring_diff is determined such that the above condition is satisfied. + The starting ring_diff is determined such that the above condition is satisfied. You can check it by noting that the start_ring_diff%2 == (min_ring_diff + (min_ring_diff+ring1_plus_ring2)%2)%2 == (2*min_ring_diff+ring1_plus_ring2)%2 == ring1_plus_ring2%2 */ - for(uncompressed_bin.segment_num() = min_ring_diff + (min_ring_diff+ring1_plus_ring2)%2; - uncompressed_bin.segment_num() <= max_ring_diff; - uncompressed_bin.segment_num()+=2 ) - { - - // Make sure we are within the range. Just some error checking. - int geo_plane_num = detail::set_detection_axial_coords(proj_data_info_cyl_ptr, - ring1_plus_ring2, uncompressed_bin, - detection_position_pair); - if ( geo_plane_num < 0 ) - { + for (uncompressed_bin.segment_num() = min_ring_diff + (min_ring_diff + ring1_plus_ring2) % 2; + uncompressed_bin.segment_num() <= max_ring_diff; uncompressed_bin.segment_num() += 2) { + + // Make sure we are within the range. Just some error checking. + int geo_plane_num = + detail::set_detection_axial_coords(proj_data_info_cyl_ptr, ring1_plus_ring2, uncompressed_bin, detection_position_pair); + if (geo_plane_num < 0) { // Ring numbers out of range. continue; } - - // Here is where the normalization is applied. Apply each of them if required. + + // Here is where the normalization is applied. Apply each of them if required. float lor_efficiency_this_pair = 1.F; - if (this->use_detector_efficiencies()) - { + if (this->use_detector_efficiencies()) { lor_efficiency_this_pair *= get_efficiency_factors(detection_position_pair); } - if (this->use_dead_time()) - { + if (this->use_dead_time()) { lor_efficiency_this_pair *= get_dead_time_efficiency(detection_position_pair, start_time, end_time); } - if (this->use_geometric_factors()) - { + if (this->use_geometric_factors()) { lor_efficiency_this_pair *= get_geometric_efficiency_factors(detection_position_pair); } lor_efficiency += lor_efficiency_this_pair; - }//endfor + } // endfor view_efficiency += lor_efficiency; total_efficiency += view_efficiency; @@ -548,42 +468,37 @@ get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const d return total_efficiency; } -float -BinNormalisationFromGEHDF5::get_dead_time_efficiency (const DetectionPositionPair<>& detection_position_pair, - const double start_time, - const double end_time) const -{ +float +BinNormalisationFromGEHDF5::get_dead_time_efficiency(const DetectionPositionPair<>& detection_position_pair, + const double start_time, const double end_time) const { if (is_null_ptr(singles_rates_ptr)) { return 1; } - return 1; + return 1; } -float -BinNormalisationFromGEHDF5::get_geometric_efficiency_factors (const DetectionPositionPair<>& detection_position_pair) const -{ +float +BinNormalisationFromGEHDF5::get_geometric_efficiency_factors(const DetectionPositionPair<>& detection_position_pair) const { if (is_null_ptr(geo_eff_factors_sptr)) return 1.F; Bin bin; - if (this->proj_data_info_cyl_ptr->get_bin_for_det_pos_pair(bin,detection_position_pair) == Succeeded::no) + if (this->proj_data_info_cyl_ptr->get_bin_for_det_pos_pair(bin, detection_position_pair) == Succeeded::no) error("BinNormalisationFromGEHDF5 internal error"); return this->geo_eff_factors_sptr->get_bin_value(bin); } -float -BinNormalisationFromGEHDF5::get_efficiency_factors (const DetectionPositionPair<>& detection_position_pair) const -{ - const DetectionPosition<>& pos1=detection_position_pair.pos1(); - const DetectionPosition<>& pos2=detection_position_pair.pos2(); +float +BinNormalisationFromGEHDF5::get_efficiency_factors(const DetectionPositionPair<>& detection_position_pair) const { + const DetectionPosition<>& pos1 = detection_position_pair.pos1(); + const DetectionPosition<>& pos2 = detection_position_pair.pos2(); return (this->efficiency_factors[pos1.axial_coord()][pos1.tangential_coord()] * - this->efficiency_factors[pos2.axial_coord()][pos2.tangential_coord()]); + this->efficiency_factors[pos2.axial_coord()][pos2.tangential_coord()]); } -} // namespace -} +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/BinNormalisationFromProjData.cxx b/src/recon_buildblock/BinNormalisationFromProjData.cxx index 77d1031788..62d5103513 100644 --- a/src/recon_buildblock/BinNormalisationFromProjData.cxx +++ b/src/recon_buildblock/BinNormalisationFromProjData.cxx @@ -37,145 +37,107 @@ START_NAMESPACE_STIR -const char * const -BinNormalisationFromProjData::registered_name = "From ProjData"; +const char* const BinNormalisationFromProjData::registered_name = "From ProjData"; - -void -BinNormalisationFromProjData::set_defaults() -{ +void +BinNormalisationFromProjData::set_defaults() { normalisation_projdata_filename = ""; } -void -BinNormalisationFromProjData:: -initialise_keymap() -{ +void +BinNormalisationFromProjData::initialise_keymap() { parser.add_start_key("Bin Normalisation From ProjData"); parser.add_key("normalisation_projdata_filename", &normalisation_projdata_filename); parser.add_stop_key("End Bin Normalisation From ProjData"); } -bool -BinNormalisationFromProjData:: -post_processing() -{ +bool +BinNormalisationFromProjData::post_processing() { norm_proj_data_ptr = ProjData::read_from_file(normalisation_projdata_filename); return false; } -BinNormalisationFromProjData:: -BinNormalisationFromProjData() -{ - set_defaults(); -} +BinNormalisationFromProjData::BinNormalisationFromProjData() { set_defaults(); } -BinNormalisationFromProjData:: -BinNormalisationFromProjData(const std::string& filename) - : norm_proj_data_ptr(ProjData::read_from_file(filename)) - {} +BinNormalisationFromProjData::BinNormalisationFromProjData(const std::string& filename) + : norm_proj_data_ptr(ProjData::read_from_file(filename)) {} -BinNormalisationFromProjData:: -BinNormalisationFromProjData(const shared_ptr& norm_proj_data_ptr) - : norm_proj_data_ptr(norm_proj_data_ptr) - {} +BinNormalisationFromProjData::BinNormalisationFromProjData(const shared_ptr& norm_proj_data_ptr) + : norm_proj_data_ptr(norm_proj_data_ptr) {} -Succeeded -BinNormalisationFromProjData:: -set_up(const shared_ptr& exam_info_sptr, const shared_ptr& proj_data_info_ptr) -{ +Succeeded +BinNormalisationFromProjData::set_up(const shared_ptr& exam_info_sptr, + const shared_ptr& proj_data_info_ptr) { BinNormalisation::set_up(exam_info_sptr, proj_data_info_ptr); if (*(norm_proj_data_ptr->get_proj_data_info_sptr()) == *proj_data_info_ptr) return Succeeded::yes; - else - { + else { const ProjDataInfo& norm_proj = *(norm_proj_data_ptr->get_proj_data_info_sptr()); const ProjDataInfo& proj = *proj_data_info_ptr; - bool ok = - (norm_proj >= proj) && - (norm_proj.get_min_tangential_pos_num() ==proj.get_min_tangential_pos_num())&& - (norm_proj.get_max_tangential_pos_num() ==proj.get_max_tangential_pos_num()); - - for (int segment_num=proj.get_min_segment_num(); - ok && segment_num<=proj.get_max_segment_num(); - ++segment_num) - { - ok = - norm_proj.get_min_axial_pos_num(segment_num) == proj.get_min_axial_pos_num(segment_num) && - norm_proj.get_max_axial_pos_num(segment_num) == proj.get_max_axial_pos_num(segment_num); - } + bool ok = (norm_proj >= proj) && (norm_proj.get_min_tangential_pos_num() == proj.get_min_tangential_pos_num()) && + (norm_proj.get_max_tangential_pos_num() == proj.get_max_tangential_pos_num()); + if (ok) return Succeeded::yes; - else - { - warning(boost::format("BinNormalisationFromProjData: incompatible projection data:\nNorm projdata info:\n%s\nEmission projdata info:\n%s\n--- (end of incompatible projection data info)---\n") - % norm_proj.parameter_info() - % proj.parameter_info()); - return Succeeded::no; - } + else { + warning(boost::format("BinNormalisationFromProjData: incompatible projection data:\nNorm projdata info:\n%s\nEmission " + "projdata info:\n%s\n--- (end of incompatible projection data info)---\n") % + norm_proj.parameter_info() % proj.parameter_info()); + return Succeeded::no; + } } } -bool -BinNormalisationFromProjData:: -is_trivial() const -{ - // check if all data is 1 (up to a tolerance of 1e-4) - for (int segment_num = this->norm_proj_data_ptr->get_min_segment_num(); - segment_num <= this->norm_proj_data_ptr->get_max_segment_num(); - ++segment_num) - { - for (int view_num = this->norm_proj_data_ptr->get_min_view_num(); - view_num <= this->norm_proj_data_ptr->get_max_view_num(); - ++view_num) - { - const Viewgram viewgram = - this->norm_proj_data_ptr->get_viewgram(view_num, segment_num); - if (fabs(viewgram.find_min()-1)>.0001 || fabs(viewgram.find_max()-1)>.0001) - return false; // return from function as we know not all data is 1 - } +bool +BinNormalisationFromProjData::is_trivial() const { + for (int tof_pos = this->norm_proj_data_ptr->get_min_tof_pos_num(); tof_pos <= this->norm_proj_data_ptr->get_max_tof_pos_num(); + ++tof_pos) { + // check if all data is 1 (up to a tolerance of 1e-4) + for (int segment_num = this->norm_proj_data_ptr->get_min_segment_num(); + segment_num <= this->norm_proj_data_ptr->get_max_segment_num(); ++segment_num) { + for (int view_num = this->norm_proj_data_ptr->get_min_view_num(); view_num <= this->norm_proj_data_ptr->get_max_view_num(); + ++view_num) { + const Viewgram viewgram = this->norm_proj_data_ptr->get_viewgram(view_num, segment_num, tof_pos); + if (fabs(viewgram.find_min() - 1) > .0001 || fabs(viewgram.find_max() - 1) > .0001) + return false; // return from function as we know not all data is 1 + } } + } // if we get here. they were all 1 return true; } -void -BinNormalisationFromProjData::apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const - { - this->check(*viewgrams.get_proj_data_info_sptr()); - const ViewSegmentNumbers vs_num=viewgrams.get_basic_view_segment_num(); - shared_ptr symmetries_sptr(viewgrams.get_symmetries_ptr()->clone()); - viewgrams *= - norm_proj_data_ptr->get_related_viewgrams(vs_num,symmetries_sptr, false); - } - -void -BinNormalisationFromProjData:: -undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const - { - this->check(*viewgrams.get_proj_data_info_sptr()); - const ViewSegmentNumbers vs_num=viewgrams.get_basic_view_segment_num(); - shared_ptr symmetries_sptr(viewgrams.get_symmetries_ptr()->clone()); - viewgrams /= - norm_proj_data_ptr->get_related_viewgrams(vs_num,symmetries_sptr, false); +void +BinNormalisationFromProjData::apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const { + this->check(*viewgrams.get_proj_data_info_sptr()); + const ViewSegmentNumbers vs_num = viewgrams.get_basic_view_segment_num(); + const int timing_pos_num = + norm_proj_data_ptr->get_proj_data_info_sptr()->is_tof_data() ? viewgrams.get_basic_timing_pos_num() : 0; + shared_ptr symmetries_sptr(viewgrams.get_symmetries_ptr()->clone()); + viewgrams *= norm_proj_data_ptr->get_related_viewgrams(vs_num, symmetries_sptr, false, timing_pos_num); +} - } +void +BinNormalisationFromProjData::undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const { + this->check(*viewgrams.get_proj_data_info_sptr()); + const ViewSegmentNumbers vs_num = viewgrams.get_basic_view_segment_num(); + const int timing_pos_num = + norm_proj_data_ptr->get_proj_data_info_sptr()->is_tof_data() ? viewgrams.get_basic_timing_pos_num() : 0; + shared_ptr symmetries_sptr(viewgrams.get_symmetries_ptr()->clone()); + viewgrams /= norm_proj_data_ptr->get_related_viewgrams(vs_num, symmetries_sptr, false, timing_pos_num); +} -float -BinNormalisationFromProjData::get_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const -{ - //TODO +float +BinNormalisationFromProjData::get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { + // TODO error("BinNormalisationFromProjData::get_bin_efficiency is not implemented"); return 1; - } shared_ptr -BinNormalisationFromProjData::get_norm_proj_data_sptr() const -{ +BinNormalisationFromProjData::get_norm_proj_data_sptr() const { return this->norm_proj_data_ptr; } - -END_NAMESPACE_STIR +END_NAMESPACE_STIR diff --git a/src/recon_buildblock/BinNormalisationSPECT.cxx b/src/recon_buildblock/BinNormalisationSPECT.cxx index 2bf0c31d2b..b45f071119 100644 --- a/src/recon_buildblock/BinNormalisationSPECT.cxx +++ b/src/recon_buildblock/BinNormalisationSPECT.cxx @@ -51,41 +51,33 @@ using std::fstream; START_NAMESPACE_STIR - -const char * const -BinNormalisationSPECT::registered_name = "SPECT"; +const char* const BinNormalisationSPECT::registered_name = "SPECT"; // // helper functions used in this class. // - - -void -BinNormalisationSPECT::set_defaults() -{ +void +BinNormalisationSPECT::set_defaults() { this->uniformity_filename = ""; this->_use_detector_efficiencies = false; this->_use_dead_time = false; this->_use_uniformity_factors = false; this->num_detector_heads = 3; - this->half_life = 6*60*60; //seconds - this->resampled=0; - this->measured_calibration_factor=-1.F; - + this->half_life = 6 * 60 * 60; // seconds + this->resampled = 0; + this->measured_calibration_factor = -1.F; } -void -BinNormalisationSPECT:: -initialise_keymap() -{ +void +BinNormalisationSPECT::initialise_keymap() { this->parser.add_start_key("Bin Normalisation SPECT"); this->parser.add_key("uniformity_filename", &this->uniformity_filename); this->parser.add_key("use_detector_efficiencies", &this->_use_detector_efficiencies); this->parser.add_key("use_uniformity_factors", &this->_use_uniformity_factors); this->parser.add_key("folder_prefix", &this->folder_prefix); this->parser.add_key("rel_angle", &this->rel_angle); - this->parser.add_key("half_life", &this->half_life); //TODO read this from the database according to isotope name + this->parser.add_key("half_life", &this->half_life); // TODO read this from the database according to isotope name this->parser.add_key("view_time_interval", &this->view_time_interval); this->parser.add_key("num detector heads", &this->num_detector_heads); this->parser.add_key("projdata filename", &this->projdata_filename); @@ -95,306 +87,259 @@ initialise_keymap() this->parser.add_stop_key("End Bin Normalisation SPECT"); } -bool -BinNormalisationSPECT:: -post_processing() -{ - if(use_uniformity_factors()){ - uniformity.resize(IndexRange3D(0,2,0,1023,0,1023)); - read_uniformity_table(uniformity);} - - norm_proj_data_info_ptr=ProjData::read_from_file(projdata_filename); - max_tang=norm_proj_data_info_ptr->get_max_tangential_pos_num(); - -// allow to set your own calibration factor - if(measured_calibration_factor>0) - set_calibration_factor(measured_calibration_factor); - else - set_calibration_factor(get_exam_info_sptr()->get_calibration_factor()); - -// read_norm_data(normalisation_spect_filename); - return false; -} +bool +BinNormalisationSPECT::post_processing() { + if (use_uniformity_factors()) { + uniformity.resize(IndexRange3D(0, 2, 0, 1023, 0, 1023)); + read_uniformity_table(uniformity); + } + + norm_proj_data_info_ptr = ProjData::read_from_file(projdata_filename); + max_tang = norm_proj_data_info_ptr->get_max_tangential_pos_num(); + // allow to set your own calibration factor + if (measured_calibration_factor > 0) + set_calibration_factor(measured_calibration_factor); + else + set_calibration_factor(get_exam_info_sptr()->get_calibration_factor()); -BinNormalisationSPECT:: -BinNormalisationSPECT() -{ - set_defaults(); + // read_norm_data(normalisation_spect_filename); + return false; } +BinNormalisationSPECT::BinNormalisationSPECT() { set_defaults(); } + Succeeded -BinNormalisationSPECT:: -set_up(const shared_ptr &exam_info_sptr, const shared_ptr& proj_data_info_ptr_v) -{ +BinNormalisationSPECT::set_up(const shared_ptr& exam_info_sptr, + const shared_ptr& proj_data_info_ptr_v) { return BinNormalisation::set_up(exam_info_sptr, proj_data_info_ptr_v); } -BinNormalisationSPECT:: -BinNormalisationSPECT(const std::string& filename) -{ - read_norm_data(filename); -} +BinNormalisationSPECT::BinNormalisationSPECT(const std::string& filename) { read_norm_data(filename); } void -BinNormalisationSPECT:: -read_norm_data(const std::string& filename) -{// to think about this - } +BinNormalisationSPECT::read_norm_data(const std::string& filename) { // to think about this +} -float BinNormalisationSPECT::get_uncalibrated_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const { - int zoom=1024/(2*(max_tang+1)); - double normalisation=1; +float +BinNormalisationSPECT::get_uncalibrated_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { + int zoom = 1024 / (2 * (max_tang + 1)); + double normalisation = 1; - if(zoom!=1 && !resampled && use_uniformity_factors()){ + if (zoom != 1 && !resampled && use_uniformity_factors()) { - resample_uniformity(//down_sampled_uniformity, - uniformity, - max_tang, - zoom); - } + resample_uniformity( // down_sampled_uniformity, + uniformity, max_tang, zoom); + } - if(bin.view_num()==0) + if (bin.view_num() == 0) set_num_views(norm_proj_data_info_ptr->get_num_views()); - int head_num=(int)bin.view_num()/(num_views/num_detector_heads); - double rel_time; - rel_time=(this->view_time_interval)* - (bin.view_num()+1-head_num* - (num_views/num_detector_heads)); - /*#################################################################################################### - *#################################### uniformity factors #########################################*/ - - if (use_uniformity_factors()){ - if(uniformity_filename=="") - error("You need to define the uniformity filename and the folder prefix"); - if(zoom!=1) - normalisation= - normalisation*down_sampled_uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num()+max_tang+1]; - else{ - normalisation= - normalisation*uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num()+max_tang+1];} - } - /*#################################################################################################### - *#################################### decay factors #########################################*/ - - if (use_decay_correction_factors()){ - normalisation= - normalisation/decay_correction_factor(half_life, rel_time); - } -//std::cout<<"value"<view_time_interval) * (bin.view_num() + 1 - head_num * (num_views / num_detector_heads)); + /*#################################################################################################### + *#################################### uniformity factors #########################################*/ + + if (use_uniformity_factors()) { + if (uniformity_filename == "") + error("You need to define the uniformity filename and the folder prefix"); + if (zoom != 1) + normalisation = + normalisation * down_sampled_uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num() + max_tang + 1]; + else { + normalisation = normalisation * uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num() + max_tang + 1]; + } + } + /*#################################################################################################### + *#################################### decay factors #########################################*/ + + if (use_decay_correction_factors()) { + normalisation = normalisation / decay_correction_factor(half_life, rel_time); + } + // std::cout<<"value"<& viewgrams,const double start_time, const double end_time) const{ +void +BinNormalisationSPECT::apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const { - this->check(*viewgrams.get_proj_data_info_sptr()); - int view_num=viewgrams.get_basic_view_num(); - int max_tang=viewgrams.get_max_tangential_pos_num(); - int zoom=1024/(2*(max_tang+1)); - double normalisation=1; + this->check(*viewgrams.get_proj_data_info_sptr()); + int view_num = viewgrams.get_basic_view_num(); + int max_tang = viewgrams.get_max_tangential_pos_num(); + int zoom = 1024 / (2 * (max_tang + 1)); + double normalisation = 1; - if(zoom!=1 && !resampled && use_uniformity_factors()){ + if (zoom != 1 && !resampled && use_uniformity_factors()) { - resample_uniformity(//down_sampled_uniformity, - uniformity, - max_tang, - zoom); - } + resample_uniformity( // down_sampled_uniformity, + uniformity, max_tang, zoom); + } - if(view_num==0) + if (view_num == 0) set_num_views(viewgrams.get_proj_data_info_sptr()->get_num_views()); - int head_num=(int)view_num/(num_views/num_detector_heads); - - double rel_time; - rel_time=(this->view_time_interval)* - (view_num+1-head_num* - (num_views/num_detector_heads)); - - for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) - { - Bin bin(iter->get_segment_num(),iter->get_view_num(), 0,0); - for (bin.axial_pos_num()= iter->get_min_axial_pos_num(); - bin.axial_pos_num()<=iter->get_max_axial_pos_num(); - ++bin.axial_pos_num()) - for (bin.tangential_pos_num()= iter->get_min_tangential_pos_num(); - bin.tangential_pos_num()<=iter->get_max_tangential_pos_num(); - ++bin.tangential_pos_num()){ - - /*#################################################################################################### - *#################################### uniformity factors #########################################*/ - - if (use_uniformity_factors()){ - if(uniformity_filename=="") - error("You need to define the uniformity filename and the folder prefix"); - if(zoom!=1) - normalisation=normalisation*down_sampled_uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num()+max_tang+1]; - else - normalisation=normalisation*uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num()+max_tang+1]; - } - /*#################################################################################################### - *#################################### decay factors #########################################*/ - - if (use_decay_correction_factors()){ - normalisation= - normalisation/decay_correction_factor(half_life, rel_time); - } - (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] /= - (std::max(1.E-20F, get_uncalibrated_bin_efficiency(bin, start_time, end_time))* - normalisation); - normalisation=1; + int head_num = (int)view_num / (num_views / num_detector_heads); + + double rel_time; + rel_time = (this->view_time_interval) * (view_num + 1 - head_num * (num_views / num_detector_heads)); + + for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + Bin bin(iter->get_segment_num(), iter->get_view_num(), 0, 0); + for (bin.axial_pos_num() = iter->get_min_axial_pos_num(); bin.axial_pos_num() <= iter->get_max_axial_pos_num(); + ++bin.axial_pos_num()) + for (bin.tangential_pos_num() = iter->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= iter->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) { + + /*#################################################################################################### + *#################################### uniformity factors #########################################*/ + + if (use_uniformity_factors()) { + if (uniformity_filename == "") + error("You need to define the uniformity filename and the folder prefix"); + if (zoom != 1) + normalisation = + normalisation * down_sampled_uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num() + max_tang + 1]; + else + normalisation = normalisation * uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num() + max_tang + 1]; } - } + /*#################################################################################################### + *#################################### decay factors #########################################*/ + + if (use_decay_correction_factors()) { + normalisation = normalisation / decay_correction_factor(half_life, rel_time); + } + (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] /= + (std::max(1.E-20F, get_uncalibrated_bin_efficiency(bin, start_time, end_time)) * normalisation); + normalisation = 1; + } + } } -void BinNormalisationSPECT::undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const{ +void +BinNormalisationSPECT::undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const { - this->check(*viewgrams.get_proj_data_info_sptr()); - int view_num=viewgrams.get_basic_view_num(); - int max_tang=viewgrams.get_max_tangential_pos_num(); - int zoom=1024/(2*(max_tang+1)); - double normalisation=1; + this->check(*viewgrams.get_proj_data_info_sptr()); + int view_num = viewgrams.get_basic_view_num(); + int max_tang = viewgrams.get_max_tangential_pos_num(); + int zoom = 1024 / (2 * (max_tang + 1)); + double normalisation = 1; -if(zoom!=1 && !resampled && use_uniformity_factors()){ + if (zoom != 1 && !resampled && use_uniformity_factors()) { - resample_uniformity(//down_sampled_uniformity, - uniformity, - max_tang, - zoom); -} + resample_uniformity( // down_sampled_uniformity, + uniformity, max_tang, zoom); + } - if(view_num==0) + if (view_num == 0) set_num_views(viewgrams.get_proj_data_info_sptr()->get_num_views()); - int head_num=(int)view_num/(num_views/num_detector_heads); - - double rel_time; - rel_time=(this->view_time_interval)* - (view_num+1-head_num* - (num_views/num_detector_heads)); - - for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) - { - Bin bin(iter->get_segment_num(),iter->get_view_num(), 0,0); - for (bin.axial_pos_num()= iter->get_min_axial_pos_num(); - bin.axial_pos_num()<=iter->get_max_axial_pos_num(); - ++bin.axial_pos_num()) - for (bin.tangential_pos_num()= iter->get_min_tangential_pos_num(); - bin.tangential_pos_num()<=iter->get_max_tangential_pos_num(); - ++bin.tangential_pos_num()){ - -/*#################################################################################################### - *#################################### uniformity factors #########################################*/ - - if (use_uniformity_factors()){ - if(uniformity_filename=="") - error("You need to define the uniformity filename and the folder prefix"); - if(zoom!=1) - normalisation=normalisation*down_sampled_uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num()+max_tang+1]; - else - normalisation=normalisation*uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num()+max_tang+1]; - } -/*#################################################################################################### - *#################################### decay factors #########################################*/ - - if (use_decay_correction_factors()){ - normalisation= - normalisation/decay_correction_factor(half_life, rel_time); - } - - - (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()]*= - (this->get_uncalibrated_bin_efficiency(bin,start_time, end_time)*normalisation); - normalisation=1; + int head_num = (int)view_num / (num_views / num_detector_heads); + + double rel_time; + rel_time = (this->view_time_interval) * (view_num + 1 - head_num * (num_views / num_detector_heads)); + + for (RelatedViewgrams::iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + Bin bin(iter->get_segment_num(), iter->get_view_num(), 0, 0); + for (bin.axial_pos_num() = iter->get_min_axial_pos_num(); bin.axial_pos_num() <= iter->get_max_axial_pos_num(); + ++bin.axial_pos_num()) + for (bin.tangential_pos_num() = iter->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= iter->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) { + + /*#################################################################################################### + *#################################### uniformity factors #########################################*/ + + if (use_uniformity_factors()) { + if (uniformity_filename == "") + error("You need to define the uniformity filename and the folder prefix"); + if (zoom != 1) + normalisation = + normalisation * down_sampled_uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num() + max_tang + 1]; + else + normalisation = normalisation * uniformity[head_num][bin.axial_pos_num()][bin.tangential_pos_num() + max_tang + 1]; + } + /*#################################################################################################### + *#################################### decay factors #########################################*/ + if (use_decay_correction_factors()) { + normalisation = normalisation / decay_correction_factor(half_life, rel_time); } - } + + (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] *= + (this->get_uncalibrated_bin_efficiency(bin, start_time, end_time) * normalisation); + normalisation = 1; + } + } } void -BinNormalisationSPECT:: -read_uniformity_table(Array<3,float>& uniformity) const -{//std::ofstream unif_table("uniformity.dat",std::ios::out); - for(int n=1; n<=num_detector_heads; n++ ){ - - const std::string n_string = boost::lexical_cast(n); - const std::string filename(this->folder_prefix+n_string+"/"+uniformity_filename); - - std::ifstream input(filename.c_str()); - - if (!input) - error("Could not open Uniformity correction table!"); - input.read(const_cast(reinterpret_cast(&map)), sizeof(map)); - input.close(); - for(int j=1;j<=1023;j++) - for(int i=1;i<=1023;i++){ - uniformity[n-1][j][i]=map[j+i*1024]; -// std::cout<<"value"<& uniformity) const { // std::ofstream unif_table("uniformity.dat",std::ios::out); + for (int n = 1; n <= num_detector_heads; n++) { + + const std::string n_string = boost::lexical_cast(n); + const std::string filename(this->folder_prefix + n_string + "/" + uniformity_filename); + + std::ifstream input(filename.c_str()); + + if (!input) + error("Could not open Uniformity correction table!"); + input.read(const_cast(reinterpret_cast(&map)), sizeof(map)); + input.close(); + for (int j = 1; j <= 1023; j++) + for (int i = 1; i <= 1023; i++) { + uniformity[n - 1][j][i] = map[j + i * 1024]; + // std::cout<<"value"<& down_sampled_uniformity, - Array<3,float> uniformity, - const int max_tang, - const int zoom) const -{ -down_sampled_uniformity.resize(IndexRange3D(0, 2, 0, 2*max_tang+1, 0, 2*max_tang+1)); -for(int n=0;n<=2;n++){ - for(int i=0;i<=2*max_tang+1;i++){ - for(int j=0;j<=2*max_tang+1;j++){ - for(int l=0;l<=zoom-1;l++){ - for(int k=0;k<=zoom-1;k++){// maybe resize uniformity - - down_sampled_uniformity[n][i][j]=down_sampled_uniformity[n][i][j] + - uniformity[n][zoom*i+l][zoom*j+k]/square(zoom); -// std::cout<<"uni"<& down_sampled_uniformity, + Array<3, float> uniformity, const int max_tang, const int zoom) const { + down_sampled_uniformity.resize(IndexRange3D(0, 2, 0, 2 * max_tang + 1, 0, 2 * max_tang + 1)); + for (int n = 0; n <= 2; n++) { + for (int i = 0; i <= 2 * max_tang + 1; i++) { + for (int j = 0; j <= 2 * max_tang + 1; j++) { + for (int l = 0; l <= zoom - 1; l++) { + for (int k = 0; k <= zoom - 1; k++) { // maybe resize uniformity + + down_sampled_uniformity[n][i][j] = + down_sampled_uniformity[n][i][j] + uniformity[n][zoom * i + l][zoom * j + k] / square(zoom); + // std::cout<<"uni"<_use_detector_efficiencies; } bool -BinNormalisationSPECT:: -use_decay_correction_factors() const -{ +BinNormalisationSPECT::use_decay_correction_factors() const { return this->_use_decay_correction; } -bool -BinNormalisationSPECT:: -use_dead_time() const -{ +bool +BinNormalisationSPECT::use_dead_time() const { return this->_use_dead_time; } -bool -BinNormalisationSPECT:: -use_uniformity_factors() const -{ +bool +BinNormalisationSPECT::use_uniformity_factors() const { return this->_use_uniformity_factors; } double -BinNormalisationSPECT:: -get_half_life() const -{ +BinNormalisationSPECT::get_half_life() const { return this->half_life; } diff --git a/src/recon_buildblock/BinNormalisationWithCalibration.cxx b/src/recon_buildblock/BinNormalisationWithCalibration.cxx index ad1eaa2c8d..7f2ebae31f 100644 --- a/src/recon_buildblock/BinNormalisationWithCalibration.cxx +++ b/src/recon_buildblock/BinNormalisationWithCalibration.cxx @@ -27,78 +27,60 @@ \author Kris Thielemans */ - #include "stir/recon_buildblock/BinNormalisationWithCalibration.h" START_NAMESPACE_STIR -void -BinNormalisationWithCalibration::set_defaults() -{ +void +BinNormalisationWithCalibration::set_defaults() { base_type::set_defaults(); - + this->calibration_factor = 1; - this->branching_ratio=1; + this->branching_ratio = 1; } -void -BinNormalisationWithCalibration:: -initialise_keymap() -{ - base_type::initialise_keymap();/* - this->parser.add_key("calibration_factor", &this->calibration_factor); - this->parser.add_key("branching_ratio", &this->branching_ratio);*/ +void +BinNormalisationWithCalibration::initialise_keymap() { + base_type::initialise_keymap(); /* + this->parser.add_key("calibration_factor", &this->calibration_factor); + this->parser.add_key("branching_ratio", &this->branching_ratio);*/ } -bool -BinNormalisationWithCalibration:: -post_processing() -{ +bool +BinNormalisationWithCalibration::post_processing() { return base_type::post_processing(); } +BinNormalisationWithCalibration::BinNormalisationWithCalibration() { set_defaults(); } -BinNormalisationWithCalibration:: -BinNormalisationWithCalibration() -{ - set_defaults(); -} - -float -BinNormalisationWithCalibration:: -get_calib_decay_branching_ratio_factor(const Bin&) const{ - return this->calibration_factor* this->branching_ratio; //TODO: multiply by branching factor and decay +float +BinNormalisationWithCalibration::get_calib_decay_branching_ratio_factor(const Bin&) const { + return this->calibration_factor * this->branching_ratio; // TODO: multiply by branching factor and decay } float -BinNormalisationWithCalibration:: -get_calibration_factor() const { - return this->calibration_factor; +BinNormalisationWithCalibration::get_calibration_factor() const { + return this->calibration_factor; } void -BinNormalisationWithCalibration:: -set_calibration_factor(const float calib){ - this->calibration_factor=calib; +BinNormalisationWithCalibration::set_calibration_factor(const float calib) { + this->calibration_factor = calib; } float -BinNormalisationWithCalibration:: -get_branching_ratio() const { - return this->branching_ratio; +BinNormalisationWithCalibration::get_branching_ratio() const { + return this->branching_ratio; } void -BinNormalisationWithCalibration:: -set_branching_ratio(const float br){ - this->branching_ratio=br; +BinNormalisationWithCalibration::set_branching_ratio(const float br) { + this->branching_ratio = br; } void -BinNormalisationWithCalibration:: -set_radionuclide(const std::string& rnuclide){ - this->radionuclide=rnuclide; +BinNormalisationWithCalibration::set_radionuclide(const std::string& rnuclide) { + this->radionuclide = rnuclide; } - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ChainedBinNormalisation.cxx b/src/recon_buildblock/ChainedBinNormalisation.cxx index 6bb60041e4..12bba0c9ca 100644 --- a/src/recon_buildblock/ChainedBinNormalisation.cxx +++ b/src/recon_buildblock/ChainedBinNormalisation.cxx @@ -25,84 +25,66 @@ \author Kris Thielemans */ - #include "stir/recon_buildblock/ChainedBinNormalisation.h" #include "stir/is_null_ptr.h" #include "stir/Succeeded.h" START_NAMESPACE_STIR -const char * const -ChainedBinNormalisation::registered_name = "Chained"; +const char* const ChainedBinNormalisation::registered_name = "Chained"; -void -ChainedBinNormalisation::set_defaults() -{ +void +ChainedBinNormalisation::set_defaults() { apply_first.reset(); apply_second.reset(); } -void -ChainedBinNormalisation:: -initialise_keymap() -{ +void +ChainedBinNormalisation::initialise_keymap() { parser.add_start_key("Chained Bin Normalisation Parameters"); parser.add_parsing_key("Bin Normalisation to apply first", &apply_first); parser.add_parsing_key("Bin Normalisation to apply second", &apply_second); - parser.add_stop_key("END Chained Bin Normalisation Parameters");} + parser.add_stop_key("END Chained Bin Normalisation Parameters"); +} -bool -ChainedBinNormalisation:: -post_processing() -{ - if ((apply_first->get_calibration_factor()>0.F) && (apply_second->get_calibration_factor()>0.F)) +bool +ChainedBinNormalisation::post_processing() { + if ((apply_first->get_calibration_factor() > 0.F) && (apply_second->get_calibration_factor() > 0.F)) error("ChainedBinNormalisation: both first and second have a calibration factor. The factor would be applied twice"); return false; } +ChainedBinNormalisation::ChainedBinNormalisation() { set_defaults(); } -ChainedBinNormalisation:: -ChainedBinNormalisation() -{ - set_defaults(); -} - -ChainedBinNormalisation:: -ChainedBinNormalisation(shared_ptr const& apply_first_v, - shared_ptr const& apply_second_v) - : apply_first(apply_first_v), - apply_second(apply_second_v) -{ +ChainedBinNormalisation::ChainedBinNormalisation(shared_ptr const& apply_first_v, + shared_ptr const& apply_second_v) + : apply_first(apply_first_v), apply_second(apply_second_v) { post_processing(); } Succeeded -ChainedBinNormalisation:: -set_up(const shared_ptr& exam_info_sptr, const shared_ptr& proj_data_info_ptr) -{ - BinNormalisation::set_up( exam_info_sptr,proj_data_info_ptr); +ChainedBinNormalisation::set_up(const shared_ptr& exam_info_sptr, + const shared_ptr& proj_data_info_ptr) { + BinNormalisation::set_up(exam_info_sptr, proj_data_info_ptr); if (!is_null_ptr(apply_first)) - if (apply_first->set_up(exam_info_sptr,proj_data_info_ptr ) == Succeeded::no) - return Succeeded::no; + if (apply_first->set_up(exam_info_sptr, proj_data_info_ptr) == Succeeded::no) + return Succeeded::no; if (!is_null_ptr(apply_second)) - return apply_second->set_up(exam_info_sptr,proj_data_info_ptr); + return apply_second->set_up(exam_info_sptr, proj_data_info_ptr); else - return Succeeded::yes; + return Succeeded::yes; } - -void -ChainedBinNormalisation::apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +void +ChainedBinNormalisation::apply(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const { if (!is_null_ptr(apply_first)) - apply_first->apply(viewgrams,start_time,end_time); + apply_first->apply(viewgrams, start_time, end_time); if (!is_null_ptr(apply_second)) - apply_second->apply(viewgrams,start_time,end_time); + apply_second->apply(viewgrams, start_time, end_time); } void -ChainedBinNormalisation::apply(ProjData& proj_data) const -{ +ChainedBinNormalisation::apply(ProjData& proj_data) const { if (!is_null_ptr(apply_first)) apply_first->apply(proj_data); if (!is_null_ptr(apply_second)) @@ -110,129 +92,105 @@ ChainedBinNormalisation::apply(ProjData& proj_data) const } void -ChainedBinNormalisation::apply_only_first(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +ChainedBinNormalisation::apply_only_first(RelatedViewgrams& viewgrams, const double start_time, + const double end_time) const { if (!is_null_ptr(apply_first)) - apply_first->apply(viewgrams,start_time,end_time); + apply_first->apply(viewgrams, start_time, end_time); } void -ChainedBinNormalisation::apply_only_first(ProjData& proj_data,const double start_time, const double end_time) const -{ +ChainedBinNormalisation::apply_only_first(ProjData& proj_data, const double start_time, const double end_time) const { if (!is_null_ptr(apply_first)) apply_first->apply(proj_data); } void -ChainedBinNormalisation::apply_only_second(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +ChainedBinNormalisation::apply_only_second(RelatedViewgrams& viewgrams, const double start_time, + const double end_time) const { if (!is_null_ptr(apply_second)) - apply_second->apply(viewgrams,start_time,end_time); + apply_second->apply(viewgrams, start_time, end_time); } void -ChainedBinNormalisation::apply_only_second(ProjData& proj_data,const double start_time, const double end_time) const -{ +ChainedBinNormalisation::apply_only_second(ProjData& proj_data, const double start_time, const double end_time) const { if (!is_null_ptr(apply_second)) apply_second->apply(proj_data); } -void -ChainedBinNormalisation:: -undo(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +void +ChainedBinNormalisation::undo(RelatedViewgrams& viewgrams, const double start_time, const double end_time) const { if (!is_null_ptr(apply_first)) - apply_first->undo(viewgrams,start_time,end_time); + apply_first->undo(viewgrams, start_time, end_time); if (!is_null_ptr(apply_second)) - apply_second->undo(viewgrams,start_time,end_time); + apply_second->undo(viewgrams, start_time, end_time); } void -ChainedBinNormalisation:: -undo(ProjData& proj_data,const double start_time, const double end_time) const -{ +ChainedBinNormalisation::undo(ProjData& proj_data, const double start_time, const double end_time) const { if (!is_null_ptr(apply_first)) - apply_first->undo(proj_data,start_time,end_time); + apply_first->undo(proj_data, start_time, end_time); if (!is_null_ptr(apply_second)) - apply_second->undo(proj_data,start_time,end_time); + apply_second->undo(proj_data, start_time, end_time); } void -ChainedBinNormalisation:: -undo_only_first(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +ChainedBinNormalisation::undo_only_first(RelatedViewgrams& viewgrams, const double start_time, + const double end_time) const { if (!is_null_ptr(apply_first)) - apply_first->undo(viewgrams,start_time,end_time); + apply_first->undo(viewgrams, start_time, end_time); } void -ChainedBinNormalisation:: -undo_only_first(ProjData& proj_data,const double start_time, const double end_time) const -{ +ChainedBinNormalisation::undo_only_first(ProjData& proj_data, const double start_time, const double end_time) const { if (!is_null_ptr(apply_first)) - apply_first->undo(proj_data,start_time,end_time); + apply_first->undo(proj_data, start_time, end_time); } void -ChainedBinNormalisation:: -undo_only_second(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const -{ +ChainedBinNormalisation::undo_only_second(RelatedViewgrams& viewgrams, const double start_time, + const double end_time) const { if (!is_null_ptr(apply_second)) - apply_second->undo(viewgrams,start_time,end_time); + apply_second->undo(viewgrams, start_time, end_time); } void -ChainedBinNormalisation:: -undo_only_second(ProjData& proj_data,const double start_time, const double end_time) const -{ +ChainedBinNormalisation::undo_only_second(ProjData& proj_data, const double start_time, const double end_time) const { if (!is_null_ptr(apply_second)) - apply_second->undo(proj_data,start_time,end_time); + apply_second->undo(proj_data, start_time, end_time); } float -ChainedBinNormalisation:: get_bin_efficiency(const Bin& bin,const double start_time, const double end_time) const -{ - return - (!is_null_ptr(apply_first) - ? apply_first->get_bin_efficiency(bin,start_time,end_time) - : 1) - * - (!is_null_ptr(apply_second) - ? apply_second->get_bin_efficiency(bin,start_time,end_time) - : 1); -} - +ChainedBinNormalisation::get_bin_efficiency(const Bin& bin, const double start_time, const double end_time) const { + return (!is_null_ptr(apply_first) ? apply_first->get_bin_efficiency(bin, start_time, end_time) : 1) * + (!is_null_ptr(apply_second) ? apply_second->get_bin_efficiency(bin, start_time, end_time) : 1); +} + bool -ChainedBinNormalisation::is_first_trivial() const -{ - if (is_null_ptr(apply_first)) - error("First Normalisation object has not been set."); - return apply_first->is_trivial(); +ChainedBinNormalisation::is_first_trivial() const { + if (is_null_ptr(apply_first)) + error("First Normalisation object has not been set."); + return apply_first->is_trivial(); } bool -ChainedBinNormalisation::is_second_trivial() const -{ - if (is_null_ptr(apply_second)) - error("Second Normalisation object has not been set."); - return apply_second->is_trivial(); +ChainedBinNormalisation::is_second_trivial() const { + if (is_null_ptr(apply_second)) + error("Second Normalisation object has not been set."); + return apply_second->is_trivial(); } shared_ptr -ChainedBinNormalisation::get_first_norm() const -{ - if (is_null_ptr(apply_first)) - error("First Normalisation object has not been set."); - return apply_first; +ChainedBinNormalisation::get_first_norm() const { + if (is_null_ptr(apply_first)) + error("First Normalisation object has not been set."); + return apply_first; } shared_ptr -ChainedBinNormalisation::get_second_norm() const -{ - if (is_null_ptr(apply_second)) - error("Second Normalisation object has not been set."); - return apply_second; +ChainedBinNormalisation::get_second_norm() const { + if (is_null_ptr(apply_second)) + error("Second Normalisation object has not been set."); + return apply_second; } - -END_NAMESPACE_STIR +END_NAMESPACE_STIR diff --git a/src/recon_buildblock/DataSymmetriesForBins.cxx b/src/recon_buildblock/DataSymmetriesForBins.cxx index 346745a8c8..ff1391d0d0 100644 --- a/src/recon_buildblock/DataSymmetriesForBins.cxx +++ b/src/recon_buildblock/DataSymmetriesForBins.cxx @@ -39,61 +39,46 @@ using std::vector; START_NAMESPACE_STIR -DataSymmetriesForBins:: -~DataSymmetriesForBins() -{} +DataSymmetriesForBins::~DataSymmetriesForBins() {} -DataSymmetriesForBins:: -DataSymmetriesForBins(const shared_ptr& proj_data_info_ptr) -: proj_data_info_ptr(proj_data_info_ptr) -{} +DataSymmetriesForBins::DataSymmetriesForBins(const shared_ptr& proj_data_info_ptr) + : proj_data_info_ptr(proj_data_info_ptr) {} bool -DataSymmetriesForBins:: -blindly_equals(const root_type * const sym_ptr) const -{ +DataSymmetriesForBins::blindly_equals(const root_type* const sym_ptr) const { if (!base_type::blindly_equals(sym_ptr)) return false; - return - *this->proj_data_info_ptr == - *static_cast(*sym_ptr).proj_data_info_ptr; + return *this->proj_data_info_ptr == *static_cast(*sym_ptr).proj_data_info_ptr; } - /*! default implementation in terms of get_related_bins, will be slow of course */ int -DataSymmetriesForBins::num_related_bins(const Bin& b) const -{ +DataSymmetriesForBins::num_related_bins(const Bin& b) const { vector rel_b; get_related_bins(rel_b, b); return static_cast(rel_b.size()); } /*! default implementation in terms of find_symmetry_operation_from_basic_bin */ -bool DataSymmetriesForBins::find_basic_bin(Bin& b) const -{ - unique_ptr sym_op = - find_symmetry_operation_from_basic_bin(b); +bool +DataSymmetriesForBins::find_basic_bin(Bin& b) const { + unique_ptr sym_op = find_symmetry_operation_from_basic_bin(b); return sym_op->is_trivial(); } - bool -DataSymmetriesForBins:: -is_basic(const Bin& b) const -{ +DataSymmetriesForBins::is_basic(const Bin& b) const { Bin copy = b; return !find_basic_bin(copy); } /*! default implementation in terms of get_related_bins_factorised */ void -DataSymmetriesForBins:: -get_related_bins(vector& rel_b, const Bin& b, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ +DataSymmetriesForBins::get_related_bins(vector& rel_b, const Bin& b, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num, const int min_timing_pos_num, + const int max_timing_pos_num) const { #ifndef NDEBUG Bin bin_copy = b; assert(!find_basic_bin(bin_copy)); @@ -102,9 +87,8 @@ get_related_bins(vector& rel_b, const Bin& b, vector vs; vector ax_tang_poss; - get_related_bins_factorised(ax_tang_poss, b, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); + get_related_bins_factorised(ax_tang_poss, b, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); get_related_view_segment_numbers(vs, ViewSegmentNumbers(b.view_num(), b.segment_num())); @@ -113,39 +97,34 @@ get_related_bins(vector& rel_b, const Bin& b, for ( #ifdef _MSC_VER - // VC bug work-around... - std:: + // VC bug work-around... + std:: #endif - vector::const_iterator view_seg_ptr = vs.begin(); - view_seg_ptr != vs.end(); - ++view_seg_ptr) - { + vector::const_iterator view_seg_ptr = vs.begin(); + view_seg_ptr != vs.end(); ++view_seg_ptr) { for ( #ifdef _MSC_VER - // VC bug work-around... - std:: + // VC bug work-around... + std:: #endif - vector::const_iterator ax_tang_pos_ptr = ax_tang_poss.begin(); - ax_tang_pos_ptr != ax_tang_poss.end(); - ++ax_tang_pos_ptr) - { - rel_b.push_back(Bin(view_seg_ptr->segment_num(), view_seg_ptr->view_num(), - (*ax_tang_pos_ptr)[1], (*ax_tang_pos_ptr)[2])); + vector::const_iterator ax_tang_pos_ptr = ax_tang_poss.begin(); + ax_tang_pos_ptr != ax_tang_poss.end(); ++ax_tang_pos_ptr) { + for (int k = min_timing_pos_num; k <= max_timing_pos_num; ++k) { + rel_b.push_back( + Bin(view_seg_ptr->segment_num(), view_seg_ptr->view_num(), (*ax_tang_pos_ptr)[1], (*ax_tang_pos_ptr)[2], k)); + } } } } unique_ptr -DataSymmetriesForBins:: -find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers& vs) const -{ - Bin bin(vs.segment_num(), vs.view_num(),0,0); +DataSymmetriesForBins::find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers& vs) const { + Bin bin(vs.segment_num(), vs.view_num(), 0, 0); #ifndef NDEBUG Bin bin_copy = bin; #endif - unique_ptr sym_op = - find_symmetry_operation_from_basic_bin(bin); + unique_ptr sym_op = find_symmetry_operation_from_basic_bin(bin); vs.segment_num() = bin.segment_num(); vs.view_num() = bin.view_num(); diff --git a/src/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.cxx b/src/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.cxx index c3bc24c18a..a6b7c22097 100644 --- a/src/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.cxx +++ b/src/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.cxx @@ -41,16 +41,15 @@ START_NAMESPACE_STIR //! find correspondence between axial_pos_num and image coordinates /*! z = num_planes_per_axial_pos * axial_pos_num + axial_pos_to_z_offset - compute the offset by matching up the centre of the scanner + compute the offset by matching up the centre of the scanner in the 2 coordinate systems */ -static void -find_relation_between_coordinate_systems(int& num_planes_per_scanner_ring, - VectorWithOffset& num_planes_per_axial_pos, +static void +find_relation_between_coordinate_systems(int& num_planes_per_scanner_ring, VectorWithOffset& num_planes_per_axial_pos, VectorWithOffset& axial_pos_to_z_offset, const ProjDataInfoCylindrical* proj_data_info_cyl_ptr, - const DiscretisedDensityOnCartesianGrid<3,float> * cartesian_grid_info_ptr) - + const DiscretisedDensityOnCartesianGrid<3, float>* cartesian_grid_info_ptr) + { const int min_segment_num = proj_data_info_cyl_ptr->get_min_segment_num(); @@ -59,102 +58,85 @@ find_relation_between_coordinate_systems(int& num_planes_per_scanner_ring, num_planes_per_axial_pos = VectorWithOffset(min_segment_num, max_segment_num); axial_pos_to_z_offset = VectorWithOffset(min_segment_num, max_segment_num); - // TODO and WARNING: get_grid_spacing()[1] is z() + // TODO and WARNING: get_grid_spacing()[1] is z() const float image_plane_spacing = cartesian_grid_info_ptr->get_grid_spacing()[1]; - - { - const float num_planes_per_scanner_ring_float = - proj_data_info_cyl_ptr->get_ring_spacing() / image_plane_spacing; - + + { + const float num_planes_per_scanner_ring_float = proj_data_info_cyl_ptr->get_ring_spacing() / image_plane_spacing; + num_planes_per_scanner_ring = round(num_planes_per_scanner_ring_float); - + if (fabs(num_planes_per_scanner_ring_float - num_planes_per_scanner_ring) > 1.E-2) - error(boost::format("DataSymmetriesForBins_PET_CartesianGrid can currently only support z-grid spacing " - "equal to the ring spacing of the scanner divided by an integer. Sorry. " - "(Image z-spacing is %1% and ring spacing is %2%)") % image_plane_spacing % proj_data_info_cyl_ptr->get_ring_spacing()); + error(boost::format("DataSymmetriesForBins_PET_CartesianGrid can currently only support z-grid spacing " + "equal to the ring spacing of the scanner divided by an integer. Sorry. " + "(Image z-spacing is %1% and ring spacing is %2%)") % + image_plane_spacing % proj_data_info_cyl_ptr->get_ring_spacing()); } - + /* disabled as we support this now if (fabs( cartesian_grid_info_ptr->get_origin().x()) > 1.E-2) error("DataSymmetriesForBins_PET_CartesianGrid can currently only support x-origin = 0 " - "Sorry\n"); + "Sorry\n"); if (fabs( cartesian_grid_info_ptr->get_origin().y()) > 1.E-2) error("DataSymmetriesForBins_PET_CartesianGrid can currently only support y-origin = 0 " - "Sorry\n"); + "Sorry\n"); */ - - for (int segment_num=min_segment_num; segment_num<=max_segment_num; ++segment_num) - { - { - const float - num_planes_per_axial_pos_float = - proj_data_info_cyl_ptr->get_axial_sampling(segment_num)/image_plane_spacing; - + + for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) { + { + const float num_planes_per_axial_pos_float = proj_data_info_cyl_ptr->get_axial_sampling(segment_num) / image_plane_spacing; + num_planes_per_axial_pos[segment_num] = round(num_planes_per_axial_pos_float); - + if (fabs(num_planes_per_axial_pos_float - num_planes_per_axial_pos[segment_num]) > 1.E-2) - error(boost::format("DataSymmetriesForBins_PET_CartesianGrid can currently only support z-grid spacing " - "equal to the sinogram spacing of the scanner divided by an integer. Sorry. " - "(Image z-spacing is %1% and axial sinogram spacing is %2% at segment %3%") - % image_plane_spacing % proj_data_info_cyl_ptr->get_axial_sampling(segment_num) % segment_num); - - } - + error(boost::format("DataSymmetriesForBins_PET_CartesianGrid can currently only support z-grid spacing " + "equal to the sinogram spacing of the scanner divided by an integer. Sorry. " + "(Image z-spacing is %1% and axial sinogram spacing is %2% at segment %3%") % + image_plane_spacing % proj_data_info_cyl_ptr->get_axial_sampling(segment_num) % segment_num); + } + const float delta = proj_data_info_cyl_ptr->get_average_ring_difference(segment_num); - + // KT 20/06/2001 take origin.z() into account - axial_pos_to_z_offset[segment_num] = - (cartesian_grid_info_ptr->get_max_index() + cartesian_grid_info_ptr->get_min_index())/2.F - - cartesian_grid_info_ptr->get_origin().z()/image_plane_spacing - - - (num_planes_per_axial_pos[segment_num] - *(proj_data_info_cyl_ptr->get_max_axial_pos_num(segment_num) - + proj_data_info_cyl_ptr->get_min_axial_pos_num(segment_num)) - + num_planes_per_scanner_ring*delta)/2; + axial_pos_to_z_offset[segment_num] = + (cartesian_grid_info_ptr->get_max_index() + cartesian_grid_info_ptr->get_min_index()) / 2.F - + cartesian_grid_info_ptr->get_origin().z() / image_plane_spacing - + (num_planes_per_axial_pos[segment_num] * (proj_data_info_cyl_ptr->get_max_axial_pos_num(segment_num) + + proj_data_info_cyl_ptr->get_min_axial_pos_num(segment_num)) + + num_planes_per_scanner_ring * delta) / + 2; } } -/*! The DiscretisedDensity pointer has to point to an object of +/*! The DiscretisedDensity pointer has to point to an object of type DiscretisedDensityOnCartesianGrid (or a derived type). - + We really need only the geometrical info from the image. At the moment we have to use the data itself as well. */ -DataSymmetriesForBins_PET_CartesianGrid:: -DataSymmetriesForBins_PET_CartesianGrid -( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& image_info_ptr, - const bool do_symmetry_90degrees_min_phi_v, - const bool do_symmetry_180degrees_min_phi_v, - const bool do_symmetry_swap_segment_v, - const bool do_symmetry_swap_s_v, - const bool do_symmetry_shift_z -) - : DataSymmetriesForBins(proj_data_info_ptr), - do_symmetry_90degrees_min_phi(do_symmetry_90degrees_min_phi_v), - do_symmetry_180degrees_min_phi(do_symmetry_90degrees_min_phi_v || do_symmetry_180degrees_min_phi_v), - do_symmetry_swap_segment(do_symmetry_swap_segment_v), - do_symmetry_swap_s(do_symmetry_swap_s_v), - do_symmetry_shift_z(do_symmetry_shift_z) -{ - if(is_null_ptr(dynamic_cast(proj_data_info_ptr.get()))) +DataSymmetriesForBins_PET_CartesianGrid::DataSymmetriesForBins_PET_CartesianGrid( + const shared_ptr& proj_data_info_ptr, + const shared_ptr>& image_info_ptr, const bool do_symmetry_90degrees_min_phi_v, + const bool do_symmetry_180degrees_min_phi_v, const bool do_symmetry_swap_segment_v, const bool do_symmetry_swap_s_v, + const bool do_symmetry_shift_z) + : DataSymmetriesForBins(proj_data_info_ptr), do_symmetry_90degrees_min_phi(do_symmetry_90degrees_min_phi_v), + do_symmetry_180degrees_min_phi(do_symmetry_90degrees_min_phi_v || do_symmetry_180degrees_min_phi_v), + do_symmetry_swap_segment(do_symmetry_swap_segment_v), do_symmetry_swap_s(do_symmetry_swap_s_v), + do_symmetry_shift_z(do_symmetry_shift_z) { + if (is_null_ptr(dynamic_cast(proj_data_info_ptr.get()))) error("DataSymmetriesForBins_PET_CartesianGrid constructed with wrong type of ProjDataInfo: %s\n" "(can only handle projection data corresponding to a cylinder)\n", - typeid(*proj_data_info_ptr).name()); + typeid(*proj_data_info_ptr).name()); + + const DiscretisedDensityOnCartesianGrid<3, float>* cartesian_grid_info_ptr = + dynamic_cast*>(image_info_ptr.get()); - const DiscretisedDensityOnCartesianGrid<3,float> * - cartesian_grid_info_ptr = - dynamic_cast *> - (image_info_ptr.get()); - if (is_null_ptr(cartesian_grid_info_ptr)) error("DataSymmetriesForBins_PET_CartesianGrid constructed with wrong type of image info: %s\n", - typeid(*image_info_ptr).name()); + typeid(*image_info_ptr).name()); // WARNING get_grid_spacing()[1] == z - const float z_origin_in_planes = - image_info_ptr->get_origin().z()/cartesian_grid_info_ptr->get_grid_spacing()[1]; + const float z_origin_in_planes = image_info_ptr->get_origin().z() / cartesian_grid_info_ptr->get_grid_spacing()[1]; // z_origin_in_planes should be an integer if (fabs(round(z_origin_in_planes) - z_origin_in_planes) > 1.E-3F) error("DataSymmetriesForBins_PET_CartesianGrid: the shift in the " @@ -162,104 +144,79 @@ DataSymmetriesForBins_PET_CartesianGrid "separation (%g)\n", image_info_ptr->get_origin().z(), cartesian_grid_info_ptr->get_grid_spacing()[1]); - // check if unequal voxel size in x,y, if so, use less symmetry - if (fabs(cartesian_grid_info_ptr->get_grid_spacing()[2]- - cartesian_grid_info_ptr->get_grid_spacing()[3])>2.E-3F) + if (fabs(cartesian_grid_info_ptr->get_grid_spacing()[2] - cartesian_grid_info_ptr->get_grid_spacing()[3]) > 2.E-3F) do_symmetry_90degrees_min_phi = false; - num_views= proj_data_info_ptr->get_num_views(); + num_views = proj_data_info_ptr->get_num_views(); - if (num_views%4!=0) + if (num_views % 4 != 0) do_symmetry_90degrees_min_phi = false; - if (num_views%2!=0) + if (num_views % 2 != 0) do_symmetry_180degrees_min_phi = false; // check on segment symmetry - if (fabs(proj_data_info_ptr->get_tantheta(Bin(0,0,0,0)))> 1.E-4F) + if (fabs(proj_data_info_ptr->get_tantheta(Bin(0, 0, 0, 0))) > 1.E-4F) error("DataSymmetriesForBins_PET_CartesianGrid can only handle projection data " - "with segment 0 corresponding to direct planes (i.e. theta==0)\n"); - - for (int segment_num=1; - segment_num<= min(proj_data_info_ptr->get_max_segment_num(), - -proj_data_info_ptr->get_min_segment_num()); - ++segment_num) - if (fabs(proj_data_info_ptr->get_tantheta(Bin(segment_num,0,0,0)) + - proj_data_info_ptr->get_tantheta(Bin(-segment_num,0,0,0))) > 1.E-4F) + "with segment 0 corresponding to direct planes (i.e. theta==0)\n"); + + for (int segment_num = 1; + segment_num <= min(proj_data_info_ptr->get_max_segment_num(), -proj_data_info_ptr->get_min_segment_num()); ++segment_num) + if (fabs(proj_data_info_ptr->get_tantheta(Bin(segment_num, 0, 0, 0)) + + proj_data_info_ptr->get_tantheta(Bin(-segment_num, 0, 0, 0))) > 1.E-4F) + error("DataSymmetriesForBins_PET_CartesianGrid can only handle projection data " + "with negative segment numbers corresponding to -theta of the positive segments. " + "This is not true for segment pair %d.\n", + segment_num); + + // feable check on s-symmetry + if (fabs(proj_data_info_ptr->get_s(Bin(0, 0, 0, 1)) + proj_data_info_ptr->get_s(Bin(0, 0, 0, -1))) > 1.E-4F) error("DataSymmetriesForBins_PET_CartesianGrid can only handle projection data " - "with negative segment numbers corresponding to -theta of the positive segments. " - "This is not true for segment pair %d.\n", - segment_num); - - //feable check on s-symmetry - if (fabs(proj_data_info_ptr->get_s(Bin(0,0,0,1)) + - proj_data_info_ptr->get_s(Bin(0,0,0,-1))) > 1.E-4F) - error("DataSymmetriesForBins_PET_CartesianGrid can only handle projection data " - "with tangential_pos_num s.t. get_s(...,tang_pos_num)==-get_s(...,-tang_pos_num)\n"); - - if (fabs(image_info_ptr->get_origin().x())>.01F || fabs(image_info_ptr->get_origin().y())>.01F) - { - // disable symmetries with shifted images - if (this->do_symmetry_90degrees_min_phi|| - this->do_symmetry_180degrees_min_phi|| - this->do_symmetry_swap_segment|| - this->do_symmetry_swap_s) - { - warning("Disabling symmetries in transaxial plane as image is shifted"); - this->do_symmetry_90degrees_min_phi = - this->do_symmetry_180degrees_min_phi = - this->do_symmetry_swap_segment = - this->do_symmetry_swap_s = false; - } + "with tangential_pos_num s.t. get_s(...,tang_pos_num)==-get_s(...,-tang_pos_num)\n"); + + if (fabs(image_info_ptr->get_origin().x()) > .01F || fabs(image_info_ptr->get_origin().y()) > .01F) { + // disable symmetries with shifted images + if (this->do_symmetry_90degrees_min_phi || this->do_symmetry_180degrees_min_phi || this->do_symmetry_swap_segment || + this->do_symmetry_swap_s) { + warning("Disabling symmetries in transaxial plane as image is shifted"); + this->do_symmetry_90degrees_min_phi = this->do_symmetry_180degrees_min_phi = this->do_symmetry_swap_segment = + this->do_symmetry_swap_s = false; } - - find_relation_between_coordinate_systems(num_planes_per_scanner_ring, - num_planes_per_axial_pos, - axial_pos_to_z_offset, - static_cast(proj_data_info_ptr.get()), - cartesian_grid_info_ptr); -} + } + find_relation_between_coordinate_systems(num_planes_per_scanner_ring, num_planes_per_axial_pos, axial_pos_to_z_offset, + static_cast(proj_data_info_ptr.get()), + cartesian_grid_info_ptr); +} #ifndef STIR_NO_COVARIANT_RETURN_TYPES - DataSymmetriesForBins_PET_CartesianGrid * +DataSymmetriesForBins_PET_CartesianGrid* #else - DataSymmetriesForViewSegmentNumbers * +DataSymmetriesForViewSegmentNumbers* #endif -DataSymmetriesForBins_PET_CartesianGrid:: -clone() const -{ +DataSymmetriesForBins_PET_CartesianGrid::clone() const { return new DataSymmetriesForBins_PET_CartesianGrid(*this); } - -bool -DataSymmetriesForBins_PET_CartesianGrid:: -operator==(const DataSymmetriesForBins_PET_CartesianGrid& sym) const -{ +bool +DataSymmetriesForBins_PET_CartesianGrid::operator==(const DataSymmetriesForBins_PET_CartesianGrid& sym) const { if (!base_type::operator==(sym)) return false; - return - this->do_symmetry_90degrees_min_phi == sym.do_symmetry_90degrees_min_phi && - this->do_symmetry_180degrees_min_phi == sym.do_symmetry_180degrees_min_phi && - this->do_symmetry_swap_segment == sym.do_symmetry_swap_segment && - this->do_symmetry_swap_s == sym.do_symmetry_swap_s && - this->do_symmetry_shift_z == sym.do_symmetry_shift_z && - this->num_views == sym.num_views && - this->num_planes_per_scanner_ring == sym.num_planes_per_scanner_ring && - this->num_planes_per_axial_pos == sym.num_planes_per_axial_pos && - this->axial_pos_to_z_offset == sym.axial_pos_to_z_offset; + return this->do_symmetry_90degrees_min_phi == sym.do_symmetry_90degrees_min_phi && + this->do_symmetry_180degrees_min_phi == sym.do_symmetry_180degrees_min_phi && + this->do_symmetry_swap_segment == sym.do_symmetry_swap_segment && this->do_symmetry_swap_s == sym.do_symmetry_swap_s && + this->do_symmetry_shift_z == sym.do_symmetry_shift_z && this->num_views == sym.num_views && + this->num_planes_per_scanner_ring == sym.num_planes_per_scanner_ring && + this->num_planes_per_axial_pos == sym.num_planes_per_axial_pos && + this->axial_pos_to_z_offset == sym.axial_pos_to_z_offset; } -bool -DataSymmetriesForBins_PET_CartesianGrid:: -blindly_equals(const root_type * const that_ptr) const -{ - assert(dynamic_cast(that_ptr) != 0); - return - this->operator==(static_cast(*that_ptr)); +bool +DataSymmetriesForBins_PET_CartesianGrid::blindly_equals(const root_type* const that_ptr) const { + assert(dynamic_cast(that_ptr) != 0); + return this->operator==(static_cast(*that_ptr)); } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/DataSymmetriesForDensels.cxx b/src/recon_buildblock/DataSymmetriesForDensels.cxx index a7111eee83..74f19baa67 100644 --- a/src/recon_buildblock/DataSymmetriesForDensels.cxx +++ b/src/recon_buildblock/DataSymmetriesForDensels.cxx @@ -39,51 +39,38 @@ using std::vector; START_NAMESPACE_STIR -DataSymmetriesForDensels:: -DataSymmetriesForDensels() -{} +DataSymmetriesForDensels::DataSymmetriesForDensels() {} /*! Default implementation always returns \c true. Needs to be overloaded. */ bool -DataSymmetriesForDensels:: -blindly_equals(const root_type * const) const -{ +DataSymmetriesForDensels::blindly_equals(const root_type* const) const { return true; } bool -DataSymmetriesForDensels:: -operator ==(const root_type& that) const -{ - return - typeid(*this) == typeid(that) && - this->blindly_equals(&that); +DataSymmetriesForDensels::operator==(const root_type& that) const { + return typeid(*this) == typeid(that) && this->blindly_equals(&that); } bool -DataSymmetriesForDensels:: -operator !=(const root_type& that) const -{ +DataSymmetriesForDensels::operator!=(const root_type& that) const { return !((*this) == that); } /*! default implementation in terms of get_related_densels, will be slow of course */ int -DataSymmetriesForDensels::num_related_densels(const Densel& b) const -{ +DataSymmetriesForDensels::num_related_densels(const Densel& b) const { vector rel_b; get_related_densels(rel_b, b); return static_cast(rel_b.size()); } /*! default implementation in terms of find_symmetry_operation_from_basic_densel */ -bool DataSymmetriesForDensels::find_basic_densel(Densel& b) const -{ - unique_ptr sym_op = - find_symmetry_operation_from_basic_densel(b); +bool +DataSymmetriesForDensels::find_basic_densel(Densel& b) const { + unique_ptr sym_op = find_symmetry_operation_from_basic_densel(b); return sym_op->is_trivial(); } - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/DistributedCachingInformation.cxx b/src/recon_buildblock/DistributedCachingInformation.cxx index f899d9bfbc..055104d064 100644 --- a/src/recon_buildblock/DistributedCachingInformation.cxx +++ b/src/recon_buildblock/DistributedCachingInformation.cxx @@ -23,162 +23,146 @@ \brief Implementation of class stir::DistributedCachingInformation - \author Tobias Beisel + \author Tobias Beisel \author Kris Thielemans */ - #include "stir/recon_buildblock/DistributedCachingInformation.h" #include "stir/recon_buildblock/distributed_functions.h" START_NAMESPACE_STIR -DistributedCachingInformation::DistributedCachingInformation(const int num_workers_v) - : num_workers(num_workers_v) -{ +DistributedCachingInformation::DistributedCachingInformation(const int num_workers_v) : num_workers(num_workers_v) { initialise(); } +DistributedCachingInformation::~DistributedCachingInformation() {} -DistributedCachingInformation::~DistributedCachingInformation() -{ -} - -void DistributedCachingInformation::initialise() -{ - //initialize vector sizes +void +DistributedCachingInformation::initialise() { + // initialize vector sizes this->proc_vs_nums.resize(this->num_workers); - for (int i=0; inum_workers; i++) + for (int i = 0; i < this->num_workers; i++) this->proc_vs_nums[i].resize(0); - + this->vs_nums_to_process.resize(0); this->initialise_new_subiteration(this->vs_nums_to_process); } -void DistributedCachingInformation::initialise_new_subiteration(const std::vector& vs_nums_to_process_v) -{ - this->vs_nums_to_process= vs_nums_to_process_v; +void +DistributedCachingInformation::initialise_new_subiteration(const std::vector& vs_nums_to_process_v) { + this->vs_nums_to_process = vs_nums_to_process_v; this->set_all_vs_num_unprocessed(); } -void DistributedCachingInformation::set_all_vs_num_unprocessed() -{ +void +DistributedCachingInformation::set_all_vs_num_unprocessed() { this->still_to_process.resize(this->vs_nums_to_process.size()); std::fill(this->still_to_process.begin(), this->still_to_process.end(), true); } -int DistributedCachingInformation::find_vs_num_position_in_list_to_process(const ViewSegmentNumbers& vs_num) const -{ - std::vector::const_iterator iter = - std::find(this->vs_nums_to_process.begin(), this->vs_nums_to_process.end(), vs_num); - if (iter== this->vs_nums_to_process.end()) +int +DistributedCachingInformation::find_vs_num_position_in_list_to_process(const ViewSegmentNumbers& vs_num) const { + std::vector::const_iterator iter = + std::find(this->vs_nums_to_process.begin(), this->vs_nums_to_process.end(), vs_num); + if (iter == this->vs_nums_to_process.end()) error("Internal error: asked for vs_num that is not in the list"); return iter - this->vs_nums_to_process.begin(); } -int DistributedCachingInformation::find_position_of_first_unprocessed() const -{ - std::vector::const_iterator iter = - std::find(this->still_to_process.begin(), this->still_to_process.end(), true); - if (iter== this->still_to_process.end()) +int +DistributedCachingInformation::find_position_of_first_unprocessed() const { + std::vector::const_iterator iter = std::find(this->still_to_process.begin(), this->still_to_process.end(), true); + if (iter == this->still_to_process.end()) error("Internal error: asked for unprocessed, but all done"); return iter - this->still_to_process.begin(); } -void DistributedCachingInformation::set_processed(const ViewSegmentNumbers& vs_num) -{ - this->still_to_process[this->find_vs_num_position_in_list_to_process(vs_num)]=false; +void +DistributedCachingInformation::set_processed(const ViewSegmentNumbers& vs_num) { + this->still_to_process[this->find_vs_num_position_in_list_to_process(vs_num)] = false; } -bool DistributedCachingInformation::is_still_to_be_processed(const ViewSegmentNumbers& vs_num) const -{ - std::vector::const_iterator iter = - std::find(this->vs_nums_to_process.begin(), this->vs_nums_to_process.end(), vs_num); - if (iter== this->vs_nums_to_process.end()) +bool +DistributedCachingInformation::is_still_to_be_processed(const ViewSegmentNumbers& vs_num) const { + std::vector::const_iterator iter = + std::find(this->vs_nums_to_process.begin(), this->vs_nums_to_process.end(), vs_num); + if (iter == this->vs_nums_to_process.end()) return false; else return this->still_to_process[iter - this->vs_nums_to_process.begin()]; } -void DistributedCachingInformation::add_vs_num_to_proc(int proc, const ViewSegmentNumbers& vs_num) -{ +void +DistributedCachingInformation::add_vs_num_to_proc(int proc, const ViewSegmentNumbers& vs_num) { this->proc_vs_nums[proc].push_back(vs_num); this->set_processed(vs_num); } -int DistributedCachingInformation::get_num_remaining_cached_data_to_process(int proc) const -{ +int +DistributedCachingInformation::get_num_remaining_cached_data_to_process(int proc) const { int cnt = 0; - for (std::vector::const_iterator iter=this->proc_vs_nums[proc].begin(); - iter!=this->proc_vs_nums[proc].end(); ++ iter) - { - if (this->is_still_to_be_processed(*iter)) - cnt++; - } + for (std::vector::const_iterator iter = this->proc_vs_nums[proc].begin(); + iter != this->proc_vs_nums[proc].end(); ++iter) { + if (this->is_still_to_be_processed(*iter)) + cnt++; + } return cnt; } -bool DistributedCachingInformation::get_oldest_unprocessed_vs_num(ViewSegmentNumbers& vs, int proc) const -{ - //find unprocessed vs_num - for (std::vector::const_iterator iter=this->proc_vs_nums[proc].begin(); - iter!=this->proc_vs_nums[proc].end(); ++ iter) - { - if (this->is_still_to_be_processed(*iter)) - { - vs=*iter; - return true; - } +bool +DistributedCachingInformation::get_oldest_unprocessed_vs_num(ViewSegmentNumbers& vs, int proc) const { + // find unprocessed vs_num + for (std::vector::const_iterator iter = this->proc_vs_nums[proc].begin(); + iter != this->proc_vs_nums[proc].end(); ++iter) { + if (this->is_still_to_be_processed(*iter)) { + vs = *iter; + return true; } - - return false; + } + + return false; } -bool DistributedCachingInformation::get_unprocessed_vs_num(ViewSegmentNumbers& vs, int proc) -{ +bool +DistributedCachingInformation::get_unprocessed_vs_num(ViewSegmentNumbers& vs, int proc) { const bool in_cache = this->get_oldest_unprocessed_vs_num(vs, proc); - if (!in_cache) - { - // no cached unprocessed data found - // get work from worker with most work left - vs = this->get_vs_num_of_proc_with_most_work_left(proc); - } - + if (!in_cache) { + // no cached unprocessed data found + // get work from worker with most work left + vs = this->get_vs_num_of_proc_with_most_work_left(proc); + } + this->add_vs_num_to_proc(proc, vs); - return !in_cache; + return !in_cache; } -ViewSegmentNumbers DistributedCachingInformation::get_vs_num_of_proc_with_most_work_left(int proc) const -{ - int proc_with_max_work=0; - int max_work=0; - - //find processor with most work left - for (int i=0; inum_workers;i++) - { - if (i==proc) continue; - const int cnt = this->get_num_remaining_cached_data_to_process(i); - if (cnt>max_work) - { - max_work=cnt; - proc_with_max_work = i; - } +ViewSegmentNumbers +DistributedCachingInformation::get_vs_num_of_proc_with_most_work_left(int proc) const { + int proc_with_max_work = 0; + int max_work = 0; + + // find processor with most work left + for (int i = 0; i < this->num_workers; i++) { + if (i == proc) + continue; + const int cnt = this->get_num_remaining_cached_data_to_process(i); + if (cnt > max_work) { + max_work = cnt; + proc_with_max_work = i; } + } ViewSegmentNumbers vs; - //get vs_number of the processor with most work left - if (max_work>0) - { - this->get_oldest_unprocessed_vs_num(vs, proc_with_max_work); - } - else - { - // just return first unprocessed - vs = this->vs_nums_to_process[this->find_position_of_first_unprocessed()]; - } - + // get vs_number of the processor with most work left + if (max_work > 0) { + this->get_oldest_unprocessed_vs_num(vs, proc_with_max_work); + } else { + // just return first unprocessed + vs = this->vs_nums_to_process[this->find_position_of_first_unprocessed()]; + } + return vs; } - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/DistributedWorker.cxx b/src/recon_buildblock/DistributedWorker.cxx index f227f67876..2358f3dd1e 100644 --- a/src/recon_buildblock/DistributedWorker.cxx +++ b/src/recon_buildblock/DistributedWorker.cxx @@ -22,7 +22,7 @@ \brief Implementation of stir::DistributedWorker() - \author Tobias Beisel + \author Tobias Beisel \author Kris Thielemans \author Alexey Zverovich (idea of using main() function) */ @@ -48,184 +48,161 @@ #include "stir/recon_buildblock/distributable_main.h" -int main(int argc, char **argv) -{ +int +main(int argc, char** argv) { int return_value = EXIT_FAILURE; - try - { -#ifndef STIR_MPI - return stir::distributable_main(argc, argv); + try { +#ifndef STIR_MPI + return stir::distributable_main(argc, argv); #else - //processor-id within parallel Communicator - int my_rank; - - //saves the name of a processor - char processor_name[MPI_MAX_PROCESSOR_NAME]; - //length of the processor-name - int namelength; - - MPI_Init(&argc, &argv) ; /*Initializes the start up for MPI*/ - MPI_Comm_rank(MPI_COMM_WORLD, &my_rank) ; /*Gets the rank of the Processor*/ - MPI_Comm_size(MPI_COMM_WORLD, &distributed::num_processors) ; /*Finds the number of processes being used*/ - MPI_Get_processor_name(processor_name, &namelength); - - stir::info(boost::format("Process %d of %d on %s") - % my_rank % distributed::num_processors % processor_name); - - //master - if (my_rank==0) - { - if (distributed::num_processors<2) - { - stir::error("STIR MPI processing needs more than 1 processor"); - return_value = EXIT_FAILURE; - } - else - { - return_value=stir::distributable_main(argc, argv); - if (distributed::total_rpc_time_slaves!=0) - stir::info(boost::format("Total time used for RPC-processing: %1%") % - distributed::total_rpc_time_slaves); - } - } - else //slaves - { - //create Slave Object - stir::DistributedWorker > worker; - - //start Slave Process: - worker.start(); - return_value = EXIT_SUCCESS; - } -#endif + // processor-id within parallel Communicator + int my_rank; - } - catch (std::string& error_string) - { - // don't print yet, as error() already does that at the moment - // std::cerr << error_string << std::endl; - return_value = EXIT_FAILURE; - } - catch (std::exception& e) + // saves the name of a processor + char processor_name[MPI_MAX_PROCESSOR_NAME]; + // length of the processor-name + int namelength; + + MPI_Init(&argc, &argv); /*Initializes the start up for MPI*/ + MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); /*Gets the rank of the Processor*/ + MPI_Comm_size(MPI_COMM_WORLD, &distributed::num_processors); /*Finds the number of processes being used*/ + MPI_Get_processor_name(processor_name, &namelength); + + stir::info(boost::format("Process %d of %d on %s") % my_rank % distributed::num_processors % processor_name); + + // master + if (my_rank == 0) { + if (distributed::num_processors < 2) { + stir::error("STIR MPI processing needs more than 1 processor"); + return_value = EXIT_FAILURE; + } else { + return_value = stir::distributable_main(argc, argv); + if (distributed::total_rpc_time_slaves != 0) + stir::info(boost::format("Total time used for RPC-processing: %1%") % distributed::total_rpc_time_slaves); + } + } else // slaves { - stir::warning(e.what()); - return_value = EXIT_FAILURE; + // create Slave Object + stir::DistributedWorker> worker; + + // start Slave Process: + worker.start(); + return_value = EXIT_SUCCESS; } +#endif + + } catch (std::string& error_string) { + // don't print yet, as error() already does that at the moment + // std::cerr << error_string << std::endl; + return_value = EXIT_FAILURE; + } catch (std::exception& e) { + stir::warning(e.what()); + return_value = EXIT_FAILURE; + } #ifdef STIR_MPI MPI_Finalize(); #endif return return_value; } - -namespace stir -{ - - template - DistributedWorker::DistributedWorker() - { - this->set_defaults(); - MPI_Comm_rank(MPI_COMM_WORLD, &this->my_rank) ; /*Gets the rank of the Processor*/ - } - - template - DistributedWorker::~DistributedWorker() - { - } +namespace stir { - template - void DistributedWorker::set_defaults() - { - log_likelihood_ptr=NULL; - zero_seg0_end_planes=false; - cache_enabled=false; - } - - template - void DistributedWorker::start() - { - - // keep-on waiting for new tasks - while (true) - { - //Receive task broadcasted by Master - const int task_id = distributed::receive_int_value(-1); - - switch(task_id) - { - case task_stop_processing: // done with processing - { - return; - } - - case task_setup_distributable_computation: - { - this->setup_distributable_computation(); - break; - } - - case task_do_distributable_gradient_computation: - { - this->distributable_computation(RPC_process_related_viewgrams_gradient); - break; - } - case task_do_distributable_loglikelihood_computation: - { - this->distributable_computation(RPC_process_related_viewgrams_accumulate_loglikelihood); - break; - } - case task_do_distributable_sensitivity_computation: - { - this->distributable_computation(RPC_process_related_viewgrams_sensitivity_computation); - break; - } +template +DistributedWorker::DistributedWorker() { + this->set_defaults(); + MPI_Comm_rank(MPI_COMM_WORLD, &this->my_rank); /*Gets the rank of the Processor*/ +} + +template +DistributedWorker::~DistributedWorker() {} + +template +void +DistributedWorker::set_defaults() { + log_likelihood_ptr = NULL; + zero_seg0_end_planes = false; + cache_enabled = false; +} + +template +void +DistributedWorker::start() { + + // keep-on waiting for new tasks + while (true) { + // Receive task broadcasted by Master + const int task_id = distributed::receive_int_value(-1); + + switch (task_id) { + case task_stop_processing: // done with processing + { + return; + } + + case task_setup_distributable_computation: { + this->setup_distributable_computation(); + break; + } + + case task_do_distributable_gradient_computation: { + this->distributable_computation(RPC_process_related_viewgrams_gradient); + break; + } + case task_do_distributable_loglikelihood_computation: { + this->distributable_computation(RPC_process_related_viewgrams_accumulate_loglikelihood); + break; + } + case task_do_distributable_sensitivity_computation: { + this->distributable_computation(RPC_process_related_viewgrams_sensitivity_computation); + break; + } /* - case task_do_distributable_sensitivity_computation;break; + case task_do_distributable_sensitivity_computation;break; */ - default: - { - error("Internal error: Slave %d received unknown task-id %d", this->my_rank, task_id); - } - } // end switch task_id - } // infinite loop - } - - template - void DistributedWorker::setup_distributable_computation() - { - //Receive zero_seg_end_planes - this->zero_seg0_end_planes = distributed::receive_bool_value(-1,-1); - - //receive target image pointer - distributed::receive_and_set_image_parameters(this->target_sptr, image_buffer_size, -1, 0); - - //Receive input_image values - MPI_Status status; - status = distributed::receive_image_values_and_fill_image_ptr(this->target_sptr, this->image_buffer_size, 0); - //construct exam_info_ptr and projection_data_info_ptr - distributed::receive_and_construct_exam_and_proj_data_info_ptr(this->exam_info_sptr, this->proj_data_info_sptr, 0); - - //initialize projectors and call set_up - distributed::receive_and_initialize_projectors(this->proj_pair_sptr, 0); - - proj_pair_sptr->set_up(this->proj_data_info_sptr, this->target_sptr); - - //some values to configure tests - int configurations[4]; - status=distributed::receive_int_values(configurations, 4, distributed::STIR_MPI_CONF_TAG); - - status=distributed::receive_double_values(&distributed::min_threshold, 1, distributed::STIR_MPI_CONF_TAG); - - (configurations[0]==1)?distributed::test=true:distributed::test=false; - (configurations[1]==1)?distributed::test_send_receive_times=true:distributed::test_send_receive_times=false; - (configurations[2]==1)?distributed::rpc_time=true:distributed::rpc_time=false; - (configurations[3]==1)?cache_enabled=true:cache_enabled=false; - + default: { + error("Internal error: Slave %d received unknown task-id %d", this->my_rank, task_id); + } + } // end switch task_id + } // infinite loop +} + +template +void +DistributedWorker::setup_distributable_computation() { + // Receive zero_seg_end_planes + this->zero_seg0_end_planes = distributed::receive_bool_value(-1, -1); + + // receive target image pointer + distributed::receive_and_set_image_parameters(this->target_sptr, image_buffer_size, -1, 0); + + // Receive input_image values + MPI_Status status; + status = distributed::receive_image_values_and_fill_image_ptr(this->target_sptr, this->image_buffer_size, 0); + // construct exam_info_ptr and projection_data_info_ptr + distributed::receive_and_construct_exam_and_proj_data_info_ptr(this->exam_info_sptr, this->proj_data_info_sptr, 0); + + // initialize projectors and call set_up + distributed::receive_and_initialize_projectors(this->proj_pair_sptr, 0); + + proj_pair_sptr->set_up(this->proj_data_info_sptr, this->target_sptr); + + // some values to configure tests + int configurations[4]; + status = distributed::receive_int_values(configurations, 4, distributed::STIR_MPI_CONF_TAG); + + status = distributed::receive_double_values(&distributed::min_threshold, 1, distributed::STIR_MPI_CONF_TAG); + + (configurations[0] == 1) ? distributed::test = true : distributed::test = false; + (configurations[1] == 1) ? distributed::test_send_receive_times = true : distributed::test_send_receive_times = false; + (configurations[2] == 1) ? distributed::rpc_time = true : distributed::rpc_time = false; + (configurations[3] == 1) ? cache_enabled = true : cache_enabled = false; + #ifndef NDEBUG - if (distributed::test && my_rank==1) distributed::test_parameter_info_slave(proj_pair_sptr->stir::ParsingObject::parameter_info()); + if (distributed::test && my_rank == 1) + distributed::test_parameter_info_slave(proj_pair_sptr->stir::ParsingObject::parameter_info()); #endif #if 0 @@ -237,208 +214,192 @@ namespace stir objective_function_ptr->set_zero_seg0_end_planes(zero_seg0_end_planes); objective_function_ptr->set_projector_pair_sptr(proj_pair_sptr); #endif - - // reset cache-stores, they will be initialised if we need them - this->proj_data_ptr.reset(); - this->binwise_correction.reset(); - this->mult_proj_data_sptr.reset(); - } // set_up - - template - void DistributedWorker:: - distributable_computation(RPC_process_related_viewgrams_type * RPC_process_related_viewgrams) - { - shared_ptr input_image_ptr = this->target_sptr; // use the target_sptr member as we don't need its values anyway - - shared_ptr - symmetries_sptr(this->proj_pair_sptr->get_symmetries_used()->clone()); - + + // reset cache-stores, they will be initialised if we need them + this->proj_data_ptr.reset(); + this->binwise_correction.reset(); + this->mult_proj_data_sptr.reset(); +} // set_up + +template +void +DistributedWorker::distributable_computation(RPC_process_related_viewgrams_type* RPC_process_related_viewgrams) { + shared_ptr input_image_ptr = this->target_sptr; // use the target_sptr member as we don't need its values anyway + + shared_ptr symmetries_sptr(this->proj_pair_sptr->get_symmetries_used()->clone()); + #ifndef NDEBUG - if (distributed::test && my_rank==1) + if (distributed::test && my_rank == 1) { + distributed::test_image_estimate_slave(); + distributed::test_parameter_info_slave(proj_data_info_sptr->parameter_info()); + distributed::test_bool_value_slave(); + distributed::test_int_value_slave(); + distributed::test_int_values_slave(); + distributed::test_viewgram_slave(proj_data_info_sptr); + } +#endif + + HighResWallClockTimer t; + + { + if (distributed::receive_bool_value(USE_DOUBLE_ARG_TAG, -1)) { + this->log_likelihood_ptr = new double; + *this->log_likelihood_ptr = 0.0; + } else { + this->log_likelihood_ptr = 0; + } + + // Receive input_image values + MPI_Status status = distributed::receive_image_values_and_fill_image_ptr(input_image_ptr, this->image_buffer_size, 0); + + shared_ptr output_image_ptr; + if (distributed::receive_bool_value(USE_OUTPUT_IMAGE_ARG_TAG, -1)) { + output_image_ptr.reset(this->target_sptr->get_empty_copy()); + // already set to zero + // output_image_ptr->fill(0.F); + } + + proj_pair_sptr->get_forward_projector_sptr()->set_input(*this->target_sptr); + if (!is_null_ptr(output_image_ptr)) + proj_pair_sptr->get_back_projector_sptr()->start_accumulating_in_new_target(); + + // loop to receive viewgrams until received END_ITERATION_TAG + while (true) { + // TODO, get rid of pointers somehow + RelatedViewgrams* viewgrams = NULL; + RelatedViewgrams* additive_binwise_correction_viewgrams = NULL; + RelatedViewgrams* mult_viewgrams_ptr = NULL; + int count = 0, count2 = 0; + + // receive vs_num values + ViewSegmentNumbers vs; + status = distributed::receive_view_segment_numbers(vs, MPI_ANY_TAG); + + /*check whether to + * - use a viewgram already received in previous iteration + * - receive a new viewgram + * - end the iteration + */ + if (status.MPI_TAG == REUSE_VIEWGRAM_TAG) // use a viewgram already available { - distributed::test_image_estimate_slave(); - distributed::test_parameter_info_slave(proj_data_info_sptr->parameter_info()); - distributed::test_bool_value_slave(); - distributed::test_int_value_slave(); - distributed::test_int_values_slave(); - distributed::test_viewgram_slave(proj_data_info_sptr); - } -#endif - - HighResWallClockTimer t; - + viewgrams = new RelatedViewgrams(proj_data_ptr->get_related_viewgrams(vs, symmetries_sptr)); + if (!is_null_ptr(binwise_correction)) + additive_binwise_correction_viewgrams = + new RelatedViewgrams(binwise_correction->get_related_viewgrams(vs, symmetries_sptr)); + if (!is_null_ptr(mult_proj_data_sptr)) + mult_viewgrams_ptr = new RelatedViewgrams(mult_proj_data_sptr->get_related_viewgrams(vs, symmetries_sptr)); + } else if (status.MPI_TAG == NEW_VIEWGRAM_TAG) // receive a message with a new viewgram { - if (distributed::receive_bool_value(USE_DOUBLE_ARG_TAG,-1)) - { - this->log_likelihood_ptr = new double; - *this->log_likelihood_ptr=0.0; - } - else - { - this->log_likelihood_ptr = 0; - } - - //Receive input_image values - MPI_Status status = distributed::receive_image_values_and_fill_image_ptr(input_image_ptr, this->image_buffer_size, 0); - - shared_ptr output_image_ptr; - if (distributed::receive_bool_value(USE_OUTPUT_IMAGE_ARG_TAG,-1)) - { - output_image_ptr.reset(this->target_sptr->get_empty_copy()); - // already set to zero - //output_image_ptr->fill(0.F); - } - - proj_pair_sptr->get_forward_projector_sptr()->set_input(*this->target_sptr); - if (!is_null_ptr(output_image_ptr)) - proj_pair_sptr->get_back_projector_sptr()->start_accumulating_in_new_target(); - - //loop to receive viewgrams until received END_ITERATION_TAG - while (true) - { - // TODO, get rid of pointers somehow - RelatedViewgrams* viewgrams = NULL; - RelatedViewgrams* additive_binwise_correction_viewgrams = NULL; - RelatedViewgrams* mult_viewgrams_ptr = NULL; - int count=0, count2=0; - - //receive vs_num values - ViewSegmentNumbers vs; - status = distributed::receive_view_segment_numbers(vs, MPI_ANY_TAG); - - /*check whether to - * - use a viewgram already received in previous iteration - * - receive a new viewgram - * - end the iteration - */ - if (status.MPI_TAG==REUSE_VIEWGRAM_TAG) //use a viewgram already available - { - viewgrams = new RelatedViewgrams(proj_data_ptr->get_related_viewgrams(vs, symmetries_sptr)); - if (!is_null_ptr(binwise_correction)) - additive_binwise_correction_viewgrams = - new RelatedViewgrams(binwise_correction->get_related_viewgrams(vs, symmetries_sptr)); - if (!is_null_ptr(mult_proj_data_sptr)) - mult_viewgrams_ptr = - new RelatedViewgrams(mult_proj_data_sptr->get_related_viewgrams(vs, symmetries_sptr)); - } - else if (status.MPI_TAG==NEW_VIEWGRAM_TAG) //receive a message with a new viewgram - { #ifndef NDEBUG - //run test for related viewgrams - if (distributed::test && my_rank==1 && distributed::first_iteration==true) distributed::test_related_viewgrams_slave(proj_data_info_sptr, symmetries_sptr); -#endif - //receive info if additive_binwise_correction_viewgrams are NULL - const bool add_bin_corr_viewgrams=distributed::receive_bool_value(BINWISE_CORRECTION_TAG, 0); - if (add_bin_corr_viewgrams) - { - distributed::receive_and_construct_related_viewgrams(additive_binwise_correction_viewgrams, proj_data_info_sptr, symmetries_sptr, 0); - } - - //receive info if mult_viewgrams_ptr are NULL - const bool mult_viewgrams=distributed::receive_bool_value(BINWISE_MULT_TAG, 0); - if (mult_viewgrams) - { - distributed::receive_and_construct_related_viewgrams(mult_viewgrams_ptr, proj_data_info_sptr, symmetries_sptr, 0); - } - - // measured viewgrams - distributed::receive_and_construct_related_viewgrams(viewgrams, proj_data_info_sptr, symmetries_sptr, 0); - - //save Viewgrams to ProjDataInMemory object - if(cache_enabled) - { - if (is_null_ptr(this->proj_data_ptr)) - this->proj_data_ptr.reset(new ProjDataInMemory(this->exam_info_sptr,this->proj_data_info_sptr, /*init_with_0*/ false)); - - if (proj_data_ptr->set_related_viewgrams(*viewgrams)==Succeeded::no) - error("Slave %i: Storing viewgrams failed!\n", my_rank); - - if (add_bin_corr_viewgrams) - { - if (is_null_ptr(binwise_correction)) - binwise_correction.reset(new ProjDataInMemory(this->exam_info_sptr,this->proj_data_info_sptr, /*init_with_0*/ false)); - - if (binwise_correction->set_related_viewgrams(*additive_binwise_correction_viewgrams)==Succeeded::no) - error("Slave %i: Storing additive_binwise_correction_viewgrams failed!\n", my_rank); - } - - if (mult_viewgrams) - { - if (is_null_ptr(mult_proj_data_sptr)) - mult_proj_data_sptr.reset(new ProjDataInMemory(this->exam_info_sptr,this->proj_data_info_sptr, /*init_with_0*/ false)); - - if (mult_proj_data_sptr->set_related_viewgrams(*mult_viewgrams_ptr)==Succeeded::no) - error("Slave %i: Storing mult_viewgrams_ptr failed!\n", my_rank); - } - } - } - else if (status.MPI_TAG==END_ITERATION_TAG) //the iteration is completed --> send results - { - //make reduction over computed output_images - distributed::first_iteration=false; - if (!is_null_ptr(output_image_ptr)) - { - proj_pair_sptr->get_back_projector_sptr()->get_output(*output_image_ptr); - distributed::reduce_output_image(output_image_ptr, image_buffer_size, my_rank, 0); - } - // and log_likelihood - if (!is_null_ptr(log_likelihood_ptr)) - { - double buffer = 0.0; - MPI_Reduce(log_likelihood_ptr, &buffer, /*size*/1, MPI_DOUBLE, MPI_SUM, /*destination*/ 0, MPI_COMM_WORLD); - delete log_likelihood_ptr; - } - - if(distributed::rpc_time) - { - double send = distributed::total_rpc_time; - double receive; - MPI_Reduce(&send, &receive, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); - distributed::total_rpc_time = 0.0; - } - // get out of infinite while loop - break; - } - else - error("Slave received unknown tag"); - - //measure time used for parallelized part - if (distributed::rpc_time) {t.reset(); t.start();} - - //call the actual calculation - RPC_process_related_viewgrams( - this->proj_pair_sptr->get_forward_projector_sptr(), - this->proj_pair_sptr->get_back_projector_sptr(), - viewgrams, - count, count2, - log_likelihood_ptr, - additive_binwise_correction_viewgrams, - mult_viewgrams_ptr); - - if (distributed::rpc_time) - { - t.stop(); - distributed::total_rpc_time=distributed::total_rpc_time + t.value(); - distributed::total_rpc_time_2=distributed::total_rpc_time_2 + t.value(); - } - - int int_values[2]; - int_values[0]=count; - int_values[1]=count2; - //send count,count2 and ask for new work - distributed::send_int_values(int_values, 2, AVAILABLE_NOTIFICATION_TAG, 0); - - if (viewgrams!=NULL) delete viewgrams; - if (additive_binwise_correction_viewgrams!=NULL) delete additive_binwise_correction_viewgrams; - if (mult_viewgrams_ptr!=NULL) delete mult_viewgrams_ptr; + // run test for related viewgrams + if (distributed::test && my_rank == 1 && distributed::first_iteration == true) + distributed::test_related_viewgrams_slave(proj_data_info_sptr, symmetries_sptr); +#endif + // receive info if additive_binwise_correction_viewgrams are NULL + const bool add_bin_corr_viewgrams = distributed::receive_bool_value(BINWISE_CORRECTION_TAG, 0); + if (add_bin_corr_viewgrams) { + distributed::receive_and_construct_related_viewgrams(additive_binwise_correction_viewgrams, proj_data_info_sptr, + symmetries_sptr, 0); + } + + // receive info if mult_viewgrams_ptr are NULL + const bool mult_viewgrams = distributed::receive_bool_value(BINWISE_MULT_TAG, 0); + if (mult_viewgrams) { + distributed::receive_and_construct_related_viewgrams(mult_viewgrams_ptr, proj_data_info_sptr, symmetries_sptr, 0); + } + + // measured viewgrams + distributed::receive_and_construct_related_viewgrams(viewgrams, proj_data_info_sptr, symmetries_sptr, 0); + + // save Viewgrams to ProjDataInMemory object + if (cache_enabled) { + if (is_null_ptr(this->proj_data_ptr)) + this->proj_data_ptr.reset( + new ProjDataInMemory(this->exam_info_sptr, this->proj_data_info_sptr, /*init_with_0*/ false)); + + if (proj_data_ptr->set_related_viewgrams(*viewgrams) == Succeeded::no) + error("Slave %i: Storing viewgrams failed!\n", my_rank); + + if (add_bin_corr_viewgrams) { + if (is_null_ptr(binwise_correction)) + binwise_correction.reset( + new ProjDataInMemory(this->exam_info_sptr, this->proj_data_info_sptr, /*init_with_0*/ false)); + + if (binwise_correction->set_related_viewgrams(*additive_binwise_correction_viewgrams) == Succeeded::no) + error("Slave %i: Storing additive_binwise_correction_viewgrams failed!\n", my_rank); } - if (distributed::rpc_time) - stir::info(boost::format("Slave %1% used %2% seconds for PRC-processing.") - % my_rank % distributed::total_rpc_time_2); - } + + if (mult_viewgrams) { + if (is_null_ptr(mult_proj_data_sptr)) + mult_proj_data_sptr.reset( + new ProjDataInMemory(this->exam_info_sptr, this->proj_data_info_sptr, /*init_with_0*/ false)); + + if (mult_proj_data_sptr->set_related_viewgrams(*mult_viewgrams_ptr) == Succeeded::no) + error("Slave %i: Storing mult_viewgrams_ptr failed!\n", my_rank); + } + } + } else if (status.MPI_TAG == END_ITERATION_TAG) // the iteration is completed --> send results + { + // make reduction over computed output_images + distributed::first_iteration = false; + if (!is_null_ptr(output_image_ptr)) { + proj_pair_sptr->get_back_projector_sptr()->get_output(*output_image_ptr); + distributed::reduce_output_image(output_image_ptr, image_buffer_size, my_rank, 0); + } + // and log_likelihood + if (!is_null_ptr(log_likelihood_ptr)) { + double buffer = 0.0; + MPI_Reduce(log_likelihood_ptr, &buffer, /*size*/ 1, MPI_DOUBLE, MPI_SUM, /*destination*/ 0, MPI_COMM_WORLD); + delete log_likelihood_ptr; + } + + if (distributed::rpc_time) { + double send = distributed::total_rpc_time; + double receive; + MPI_Reduce(&send, &receive, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + distributed::total_rpc_time = 0.0; + } + // get out of infinite while loop + break; + } else + error("Slave received unknown tag"); + + // measure time used for parallelized part + if (distributed::rpc_time) { + t.reset(); + t.start(); + } + + // call the actual calculation + RPC_process_related_viewgrams(this->proj_pair_sptr->get_forward_projector_sptr(), + this->proj_pair_sptr->get_back_projector_sptr(), viewgrams, count, count2, log_likelihood_ptr, + additive_binwise_correction_viewgrams, mult_viewgrams_ptr); + + if (distributed::rpc_time) { + t.stop(); + distributed::total_rpc_time = distributed::total_rpc_time + t.value(); + distributed::total_rpc_time_2 = distributed::total_rpc_time_2 + t.value(); + } + + int int_values[2]; + int_values[0] = count; + int_values[1] = count2; + // send count,count2 and ask for new work + distributed::send_int_values(int_values, 2, AVAILABLE_NOTIFICATION_TAG, 0); + + if (viewgrams != NULL) + delete viewgrams; + if (additive_binwise_correction_viewgrams != NULL) + delete additive_binwise_correction_viewgrams; + if (mult_viewgrams_ptr != NULL) + delete mult_viewgrams_ptr; + } + if (distributed::rpc_time) + stir::info(boost::format("Slave %1% used %2% seconds for PRC-processing.") % my_rank % distributed::total_rpc_time_2); } +} + +// instantiation +template class DistributedWorker>; - // instantiation - template class DistributedWorker >; - } // namespace stir diff --git a/src/recon_buildblock/FilterRootPrior.cxx b/src/recon_buildblock/FilterRootPrior.cxx index 97bb26499d..ee4dd1f5ba 100644 --- a/src/recon_buildblock/FilterRootPrior.cxx +++ b/src/recon_buildblock/FilterRootPrior.cxx @@ -19,10 +19,10 @@ /*! \file \ingroup priors - \brief implementation of the stir::FilterRootPrior class - + \brief implementation of the stir::FilterRootPrior class + \author Kris Thielemans - \author Sanida Mustafovic + \author Sanida Mustafovic */ #include "stir/recon_buildblock/FilterRootPrior.h" @@ -35,81 +35,66 @@ START_NAMESPACE_STIR template -FilterRootPrior::FilterRootPrior() -{ +FilterRootPrior::FilterRootPrior() { set_defaults(); } - template -FilterRootPrior:: -FilterRootPrior(shared_ptr >const& filter_sptr, float penalisation_factor_v) -: filter_ptr(filter_sptr) -{ +FilterRootPrior::FilterRootPrior(shared_ptr> const& filter_sptr, float penalisation_factor_v) + : filter_ptr(filter_sptr) { this->penalisation_factor = penalisation_factor_v; } - -template < class T> +template static inline int -sign (const T& x) -{ return x>=0 ? 1: -1;} +sign(const T& x) { + return x >= 0 ? 1 : -1; +} -template < class T> -static inline T // can't call this abs() as it overlaps with std::abs -my_abs(const T& x) -{ return x>=0 ? x: -x;} +template +static inline T // can't call this abs() as it overlaps with std::abs +my_abs(const T& x) { + return x >= 0 ? x : -x; +} /* A function that divides 2 floats while avoiding division by 0 by imposing an upper threshold - It essentially returns + It essentially returns sign(numerator)*sign(denominator)* min(my_abs(numerator/denominator), max) */ -template < class T> +template static inline T -quotient_with_max(const T numerator, const T denominator, const T max) -{ - assert(max>0); - return - my_abs(numerator)< max*my_abs(denominator) ? - numerator/denominator : - max * sign(numerator)*sign(denominator); +quotient_with_max(const T numerator, const T denominator, const T max) { + assert(max > 0); + return my_abs(numerator) < max * my_abs(denominator) ? numerator / denominator : max * sign(numerator) * sign(denominator); } template double -FilterRootPrior:: -compute_value(const DataT ¤t_estimate) -{ - static bool first_time=true; - if (first_time) - { - warning("FilterRootPrior:compute_value does not make sense. Just returning 0."); - first_time=false; - } +FilterRootPrior::compute_value(const DataT& current_estimate) { + static bool first_time = true; + if (first_time) { + warning("FilterRootPrior:compute_value does not make sense. Just returning 0."); + first_time = false; + } return 0.; } template -void -FilterRootPrior:: -compute_gradient(DataT& prior_gradient, - const DataT ¤t_image_estimate) -{ - assert( prior_gradient.get_index_range() == current_image_estimate.get_index_range()); - if (this->penalisation_factor==0 || is_null_ptr(filter_ptr)) - { +void +FilterRootPrior::compute_gradient(DataT& prior_gradient, const DataT& current_image_estimate) { + assert(prior_gradient.get_index_range() == current_image_estimate.get_index_range()); + if (this->penalisation_factor == 0 || is_null_ptr(filter_ptr)) { std::fill(prior_gradient.begin_all(), prior_gradient.end_all(), 0); return; } this->check(current_image_estimate); - // first store filtered image in prior_gradient - filter_ptr->apply(prior_gradient,current_image_estimate); + filter_ptr->apply(prior_gradient, current_image_estimate); - /* now set + /* now set prior_gradient = current_image_estimate/filtered_image - 1 = current_image_estimate/prior_gradient - 1 However, we need to avoid division by 0, as it might cause a NaN or an 'infinity'. @@ -118,79 +103,64 @@ compute_gradient(DataT& prior_gradient, So, instead we do prior_gradient = quotient_with_max(current_image_estimate,prior_gradient,1000) - 1 - The code below does this by using a full_iterator loop as we're missing expression templates + The code below does this by using a full_iterator loop as we're missing expression templates at the moment and I did not feel like making a function object just for this ... */ - typename DataT::full_iterator iter_through_prior_gradient = - prior_gradient.begin_all(); - typename DataT::const_full_iterator iter_through_current_image_estimate = - current_image_estimate.begin_all(); - while (iter_through_current_image_estimate!= current_image_estimate.end_all()) - { - *iter_through_prior_gradient= - this->penalisation_factor * - (quotient_with_max(*iter_through_current_image_estimate, - *iter_through_prior_gradient, - static_cast(1000)) - - 1); + typename DataT::full_iterator iter_through_prior_gradient = prior_gradient.begin_all(); + typename DataT::const_full_iterator iter_through_current_image_estimate = current_image_estimate.begin_all(); + while (iter_through_current_image_estimate != current_image_estimate.end_all()) { + *iter_through_prior_gradient = + this->penalisation_factor * (quotient_with_max(*iter_through_current_image_estimate, *iter_through_prior_gradient, + static_cast(1000)) - + 1); ++iter_through_prior_gradient; ++iter_through_current_image_estimate; } assert(iter_through_prior_gradient == prior_gradient.end_all()); } - - template -void -FilterRootPrior::initialise_keymap() -{ +void +FilterRootPrior::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("FilterRootPrior Parameters"); - this->parser.add_parsing_key("Filter type", &filter_ptr); + this->parser.add_parsing_key("Filter type", &filter_ptr); this->parser.add_stop_key("END FilterRootPrior Parameters"); } - template void -FilterRootPrior::set_defaults() -{ +FilterRootPrior::set_defaults() { base_type::set_defaults(); filter_ptr.reset(); } template Succeeded -FilterRootPrior::set_up (shared_ptr const& target_sptr) -{ +FilterRootPrior::set_up(shared_ptr const& target_sptr) { base_type::set_up(target_sptr); return Succeeded::yes; } template -void FilterRootPrior::check(DataT const& current_image_estimate) const -{ +void +FilterRootPrior::check(DataT const& current_image_estimate) const { // Do base-class check base_type::check(current_image_estimate); } template -const char * const -FilterRootPrior:: -registered_name = - "FilterRootPrior"; +const char* const FilterRootPrior::registered_name = "FilterRootPrior"; -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif - +# pragma warning(disable : 4660) +#endif -template class FilterRootPrior >; -template class FilterRootPrior; +template class FilterRootPrior>; +template class FilterRootPrior; END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ForwardProjectorByBin.cxx b/src/recon_buildblock/ForwardProjectorByBin.cxx index d92e4cb328..7202177453 100644 --- a/src/recon_buildblock/ForwardProjectorByBin.cxx +++ b/src/recon_buildblock/ForwardProjectorByBin.cxx @@ -49,97 +49,68 @@ START_NAMESPACE_STIR +ForwardProjectorByBin::ForwardProjectorByBin() : _already_set_up(false) { set_defaults(); } -ForwardProjectorByBin::ForwardProjectorByBin() - : _already_set_up(false) -{ - set_defaults(); -} - -ForwardProjectorByBin::~ForwardProjectorByBin() -{ -} +ForwardProjectorByBin::~ForwardProjectorByBin() {} void -ForwardProjectorByBin:: -set_defaults() -{ +ForwardProjectorByBin::set_defaults() { _pre_data_processor_sptr.reset(); } void -ForwardProjectorByBin:: -initialise_keymap() -{ +ForwardProjectorByBin::initialise_keymap() { parser.add_start_key("Forward Projector Parameters"); parser.add_stop_key("End Forward Projector Parameters"); parser.add_parsing_key("pre data processor", &_pre_data_processor_sptr); } void -ForwardProjectorByBin:: -set_up(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_info_sptr) -{ +ForwardProjectorByBin::set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& density_info_sptr) { _already_set_up = true; _proj_data_info_sptr = proj_data_info_sptr->create_shared_clone(); _density_sptr.reset(density_info_sptr->clone()); } void -ForwardProjectorByBin:: -check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3,float>& density_info) const -{ +ForwardProjectorByBin::check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3, float>& density_info) const { if (!this->_already_set_up) error("ForwardProjectorByBin method called without calling set_up first."); if (!(*this->_proj_data_info_sptr >= proj_data_info)) - error(boost::format("ForwardProjectorByBin set-up with different geometry for projection data.\nSet_up was with\n%1%\nCalled with\n%2%") - % this->_proj_data_info_sptr->parameter_info() % proj_data_info.parameter_info()); - if (! this->_density_sptr->has_same_characteristics(density_info)) + error( + boost::format( + "ForwardProjectorByBin set-up with different geometry for projection data.\nSet_up was with\n%1%\nCalled with\n%2%") % + this->_proj_data_info_sptr->parameter_info() % proj_data_info.parameter_info()); + if (!this->_density_sptr->has_same_characteristics(density_info)) error("ForwardProjectorByBin set-up with different geometry for density or volume data."); } void -ForwardProjectorByBin::forward_project(ProjData& proj_data, - const DiscretisedDensity<3,float>& image, - int subset_num, int num_subsets, bool zero) -{ +ForwardProjectorByBin::forward_project(ProjData& proj_data, const DiscretisedDensity<3, float>& image, int subset_num, + int num_subsets, bool zero) { set_input(image); - forward_project(proj_data,subset_num,num_subsets,zero); + forward_project(proj_data, subset_num, num_subsets, zero); } #ifdef STIR_PROJECTORS_AS_V3 void -ForwardProjectorByBin::forward_project(RelatedViewgrams& viewgrams, - const DiscretisedDensity<3,float>& image) -{ - forward_project(viewgrams, image, - viewgrams.get_min_axial_pos_num(), - viewgrams.get_max_axial_pos_num(), - viewgrams.get_min_tangential_pos_num(), - viewgrams.get_max_tangential_pos_num()); +ForwardProjectorByBin::forward_project(RelatedViewgrams& viewgrams, const DiscretisedDensity<3, float>& image) { + forward_project(viewgrams, image, viewgrams.get_min_axial_pos_num(), viewgrams.get_max_axial_pos_num(), + viewgrams.get_min_tangential_pos_num(), viewgrams.get_max_tangential_pos_num()); } -void ForwardProjectorByBin::forward_project - (RelatedViewgrams& viewgrams, - const DiscretisedDensity<3,float>& image, - const int min_axial_pos_num, - const int max_axial_pos_num) -{ - forward_project(viewgrams, image, - min_axial_pos_num, - max_axial_pos_num, - viewgrams.get_min_tangential_pos_num(), - viewgrams.get_max_tangential_pos_num()); +void +ForwardProjectorByBin::forward_project(RelatedViewgrams& viewgrams, const DiscretisedDensity<3, float>& image, + const int min_axial_pos_num, const int max_axial_pos_num) { + forward_project(viewgrams, image, min_axial_pos_num, max_axial_pos_num, viewgrams.get_min_tangential_pos_num(), + viewgrams.get_max_tangential_pos_num()); } void -ForwardProjectorByBin:: -forward_project(RelatedViewgrams& viewgrams, - const DiscretisedDensity<3,float>& density, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - if (viewgrams.get_num_viewgrams()==0) +ForwardProjectorByBin::forward_project(RelatedViewgrams& viewgrams, const DiscretisedDensity<3, float>& density, + const int min_axial_pos_num, const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { + if (viewgrams.get_num_viewgrams() == 0) return; check(*viewgrams.get_proj_data_info_sptr(), density); start_timers(); @@ -148,25 +119,18 @@ forward_project(RelatedViewgrams& viewgrams, { const ViewSegmentNumbers basic_vs = viewgrams.get_basic_view_segment_num(); - if (get_symmetries_used()->num_related_view_segment_numbers(basic_vs) != - viewgrams.get_num_viewgrams()) + if (get_symmetries_used()->num_related_view_segment_numbers(basic_vs) != viewgrams.get_num_viewgrams()) error("ForwardProjectByBin: forward_project called with incorrect related_viewgrams. Problem with symmetries!\n"); - for (RelatedViewgrams::const_iterator iter = viewgrams.begin(); - iter != viewgrams.end(); - ++iter) - { - ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); - get_symmetries_used()->find_basic_view_segment_numbers(vs); - if (vs != basic_vs) - error("ForwardProjectByBin: forward_project called with incorrect related_viewgrams. Problem with symmetries!\n"); + for (RelatedViewgrams::const_iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); + get_symmetries_used()->find_basic_view_segment_numbers(vs); + if (vs != basic_vs) + error("ForwardProjectByBin: forward_project called with incorrect related_viewgrams. Problem with symmetries!\n"); } } - actual_forward_project(viewgrams, density, - min_axial_pos_num, - max_axial_pos_num, - min_tangential_pos_num, - max_tangential_pos_num); + actual_forward_project(viewgrams, density, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); stop_timers(); } #endif @@ -174,87 +138,71 @@ forward_project(RelatedViewgrams& viewgrams, // The following are repetition of above, where the DiscretisedDensity has already been set with set_input() // -------------------------------------------------------------------------------------------------------------------- // void -ForwardProjectorByBin::forward_project(ProjData& proj_data, - int subset_num, int num_subsets, bool zero) -{ - if (_density_sptr->get_exam_info().imaging_modality.is_unknown() - || proj_data.get_exam_info().imaging_modality.is_unknown()) - warning("forward_project. Imaging modality unknown for either the image or the projection data or both.\n" - "Going ahead anyway."); - else if (_density_sptr->get_exam_info().imaging_modality != - proj_data.get_exam_info().imaging_modality) - error("forward_project: Imaging modality should be the same for the image and the projection data"); - if (subset_num < 0) - error(boost::format("forward_project: wrong subset number %1%") % subset_num); - if (subset_num > num_subsets - 1) - error(boost::format("forward_project: wrong subset number %1% (must be less than the number of subsets %2%)") - % subset_num % num_subsets); - if (zero && num_subsets > 1) - proj_data.fill(0.0); - // this->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), -// image_sptr); +ForwardProjectorByBin::forward_project(ProjData& proj_data, int subset_num, int num_subsets, bool zero) { + if (_density_sptr->get_exam_info().imaging_modality.is_unknown() || proj_data.get_exam_info().imaging_modality.is_unknown()) + warning("forward_project. Imaging modality unknown for either the image or the projection data or both.\n" + "Going ahead anyway."); + else if (_density_sptr->get_exam_info().imaging_modality != proj_data.get_exam_info().imaging_modality) + error("forward_project: Imaging modality should be the same for the image and the projection data"); + if (subset_num < 0) + error(boost::format("forward_project: wrong subset number %1%") % subset_num); + if (subset_num > num_subsets - 1) + error(boost::format("forward_project: wrong subset number %1% (must be less than the number of subsets %2%)") % subset_num % + num_subsets); + if (zero && num_subsets > 1) + proj_data.fill(0.0); + // this->set_up(proj_data_ptr->get_proj_data_info_sptr()->clone(), + // image_sptr); check(*proj_data.get_proj_data_info_sptr(), *_density_sptr); - shared_ptr - symmetries_sptr(this->get_symmetries_used()->clone()); + shared_ptr symmetries_sptr(this->get_symmetries_used()->clone()); - const std::vector vs_nums_to_process = - detail::find_basic_vs_nums_in_subset(*proj_data.get_proj_data_info_sptr(), *symmetries_sptr, - proj_data.get_min_segment_num(), proj_data.get_max_segment_num(), - subset_num, num_subsets); + const std::vector vs_nums_to_process = detail::find_basic_vs_nums_in_subset( + *proj_data.get_proj_data_info_sptr(), *symmetries_sptr, proj_data.get_min_segment_num(), proj_data.get_max_segment_num(), + subset_num, num_subsets); #ifdef STIR_OPENMP -#pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(runtime) +# pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(runtime) #endif - // note: older versions of openmp need an int as loop - for (int i=0; i(vs_nums_to_process.size()); ++i) - { - const ViewSegmentNumbers vs=vs_nums_to_process[i]; - - info(boost::format("Processing view %1% of segment %2%") % vs.view_num() % vs.segment_num(), 2); - - RelatedViewgrams viewgrams = - proj_data.get_empty_related_viewgrams(vs, symmetries_sptr); + // note: older versions of openmp need an int as loop + for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++i) { + const ViewSegmentNumbers vs = vs_nums_to_process[i]; + for (int k = proj_data.get_proj_data_info_sptr()->get_min_tof_pos_num(); + k <= proj_data.get_proj_data_info_sptr()->get_max_tof_pos_num(); ++k) { + if (proj_data.get_proj_data_info_sptr()->is_tof_data()) + info(boost::format("Processing view %1% of segment %2% of TOF bin %3%") % vs.view_num() % vs.segment_num() % k); + else + info(boost::format("Processing view %1% of segment %2%") % vs.view_num() % vs.segment_num()); + RelatedViewgrams viewgrams = proj_data.get_empty_related_viewgrams(vs, symmetries_sptr, false, k); forward_project(viewgrams); #ifdef STIR_OPENMP -#pragma omp critical (FORWARDPROJ_SETVIEWGRAMS) +# pragma omp critical(FORWARDPROJ_SETVIEWGRAMS) #endif { if (!(proj_data.set_related_viewgrams(viewgrams) == Succeeded::yes)) error("Error set_related_viewgrams in forward projecting"); } } - + } } void -ForwardProjectorByBin::forward_project(RelatedViewgrams& viewgrams) -{ - forward_project(viewgrams, - viewgrams.get_min_axial_pos_num(), - viewgrams.get_max_axial_pos_num(), - viewgrams.get_min_tangential_pos_num(), - viewgrams.get_max_tangential_pos_num()); +ForwardProjectorByBin::forward_project(RelatedViewgrams& viewgrams) { + forward_project(viewgrams, viewgrams.get_min_axial_pos_num(), viewgrams.get_max_axial_pos_num(), + viewgrams.get_min_tangential_pos_num(), viewgrams.get_max_tangential_pos_num()); } -void ForwardProjectorByBin::forward_project - (RelatedViewgrams& viewgrams, - const int min_axial_pos_num, - const int max_axial_pos_num) -{ - forward_project(viewgrams, - min_axial_pos_num, - max_axial_pos_num, - viewgrams.get_min_tangential_pos_num(), - viewgrams.get_max_tangential_pos_num()); +void +ForwardProjectorByBin::forward_project(RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num) { + forward_project(viewgrams, min_axial_pos_num, max_axial_pos_num, viewgrams.get_min_tangential_pos_num(), + viewgrams.get_max_tangential_pos_num()); } void -ForwardProjectorByBin:: -forward_project(RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - if (viewgrams.get_num_viewgrams()==0) +ForwardProjectorByBin::forward_project(RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { + if (viewgrams.get_num_viewgrams() == 0) return; check(*viewgrams.get_proj_data_info_sptr(), *_density_sptr); start_timers(); @@ -263,69 +211,49 @@ forward_project(RelatedViewgrams& viewgrams, { const ViewSegmentNumbers basic_vs = viewgrams.get_basic_view_segment_num(); - if (get_symmetries_used()->num_related_view_segment_numbers(basic_vs) != - viewgrams.get_num_viewgrams()) + if (get_symmetries_used()->num_related_view_segment_numbers(basic_vs) != viewgrams.get_num_viewgrams()) error("ForwardProjectByBin: forward_project called with incorrect related_viewgrams. Problem with symmetries!\n"); - for (RelatedViewgrams::const_iterator iter = viewgrams.begin(); - iter != viewgrams.end(); - ++iter) - { - ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); - get_symmetries_used()->find_basic_view_segment_numbers(vs); - if (vs != basic_vs) - error("ForwardProjectByBin: forward_project called with incorrect related_viewgrams. Problem with symmetries!\n"); + for (RelatedViewgrams::const_iterator iter = viewgrams.begin(); iter != viewgrams.end(); ++iter) { + ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); + get_symmetries_used()->find_basic_view_segment_numbers(vs); + if (vs != basic_vs) + error("ForwardProjectByBin: forward_project called with incorrect related_viewgrams. Problem with symmetries!\n"); } } - actual_forward_project(viewgrams, - min_axial_pos_num, - max_axial_pos_num, - min_tangential_pos_num, - max_tangential_pos_num); + actual_forward_project(viewgrams, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); stop_timers(); } void -ForwardProjectorByBin:: -actual_forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int, const int, - const int, const int) -{ - error("ForwardProjectorByBin::actual_forward_project() This is deprecated and should not be used."); +ForwardProjectorByBin::actual_forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>&, const int, const int, + const int, const int) { + error("ForwardProjectorByBin::actual_forward_project() This is deprecated and should not be used."); } void -ForwardProjectorByBin:: -actual_forward_project(RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - actual_forward_project(viewgrams,*_density_sptr, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); +ForwardProjectorByBin::actual_forward_project(RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { + actual_forward_project(viewgrams, *_density_sptr, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); } - void -ForwardProjectorByBin:: -set_input(const DiscretisedDensity<3,float> & density) -{ - _density_sptr.reset(density.clone()); - - // If a pre-forward-projection data processor has been set, apply it. - if (!is_null_ptr(_pre_data_processor_sptr)) { - Succeeded success = _pre_data_processor_sptr->apply(*_density_sptr); - if (success != Succeeded::yes) - throw std::runtime_error("ForwardProjectorByBin::set_input(). Pre-forward-projection data processor failed."); - } +ForwardProjectorByBin::set_input(const DiscretisedDensity<3, float>& density) { + _density_sptr.reset(density.clone()); + + // If a pre-forward-projection data processor has been set, apply it. + if (!is_null_ptr(_pre_data_processor_sptr)) { + Succeeded success = _pre_data_processor_sptr->apply(*_density_sptr); + if (success != Succeeded::yes) + throw std::runtime_error("ForwardProjectorByBin::set_input(). Pre-forward-projection data processor failed."); + } } void -ForwardProjectorByBin:: -set_pre_data_processor(shared_ptr > > pre_data_processor_sptr) -{ - _pre_data_processor_sptr = pre_data_processor_sptr; +ForwardProjectorByBin::set_pre_data_processor(shared_ptr>> pre_data_processor_sptr) { + _pre_data_processor_sptr = pre_data_processor_sptr; } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.cxx b/src/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.cxx index 4e9cd399ed..be9b04dcd2 100644 --- a/src/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.cxx +++ b/src/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.cxx @@ -5,8 +5,8 @@ \file \ingroup projection - \brief implementations for stir::ForwardProjectorByBinUsingProjMatrixByBin - + \brief implementations for stir::ForwardProjectorByBinUsingProjMatrixByBin + \author Kris Thielemans \author PARAPET project @@ -29,7 +29,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" #include "stir/Viewgram.h" #include "stir/RelatedViewgrams.h" @@ -48,23 +47,16 @@ using std::list; START_NAMESPACE_STIR ////////////////////////////////////////////////////////// -const char * const -ForwardProjectorByBinUsingProjMatrixByBin::registered_name = - "Matrix"; - +const char* const ForwardProjectorByBinUsingProjMatrixByBin::registered_name = "Matrix"; void -ForwardProjectorByBinUsingProjMatrixByBin:: -set_defaults() -{ +ForwardProjectorByBinUsingProjMatrixByBin::set_defaults() { this->proj_matrix_ptr.reset(); ForwardProjectorByBin::set_defaults(); } void -ForwardProjectorByBinUsingProjMatrixByBin:: -initialise_keymap() -{ +ForwardProjectorByBinUsingProjMatrixByBin::initialise_keymap() { parser.add_start_key("Forward Projector Using Matrix Parameters"); parser.add_stop_key("End Forward Projector Using Matrix Parameters"); parser.add_parsing_key("matrix type", &proj_matrix_ptr); @@ -72,161 +64,153 @@ initialise_keymap() } bool -ForwardProjectorByBinUsingProjMatrixByBin:: -post_processing() -{ - //if (ForwardProjectorByBin::post_processing() == true) +ForwardProjectorByBinUsingProjMatrixByBin::post_processing() { + // if (ForwardProjectorByBin::post_processing() == true) // return true; - if (is_null_ptr(proj_matrix_ptr)) - { + if (is_null_ptr(proj_matrix_ptr)) { warning("ForwardProjectorByBinUsingProjMatrixByBin: matrix not set.\n"); return true; } return false; } -ForwardProjectorByBinUsingProjMatrixByBin:: -ForwardProjectorByBinUsingProjMatrixByBin() -{ - set_defaults(); -} +ForwardProjectorByBinUsingProjMatrixByBin::ForwardProjectorByBinUsingProjMatrixByBin() { set_defaults(); } -ForwardProjectorByBinUsingProjMatrixByBin:: -ForwardProjectorByBinUsingProjMatrixByBin( - const shared_ptr& proj_matrix_ptr - ) - : proj_matrix_ptr(proj_matrix_ptr) -{ +ForwardProjectorByBinUsingProjMatrixByBin::ForwardProjectorByBinUsingProjMatrixByBin( + const shared_ptr& proj_matrix_ptr) + : proj_matrix_ptr(proj_matrix_ptr) { assert(!is_null_ptr(proj_matrix_ptr)); } void -ForwardProjectorByBinUsingProjMatrixByBin:: -set_up(const shared_ptr& proj_data_info_ptr, - const shared_ptr >& image_info_ptr) -{ +ForwardProjectorByBinUsingProjMatrixByBin::set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& image_info_ptr) { ForwardProjectorByBin::set_up(proj_data_info_ptr, image_info_ptr); proj_matrix_ptr->set_up(proj_data_info_ptr, image_info_ptr); } -const DataSymmetriesForViewSegmentNumbers * -ForwardProjectorByBinUsingProjMatrixByBin::get_symmetries_used() const -{ +const DataSymmetriesForViewSegmentNumbers* +ForwardProjectorByBinUsingProjMatrixByBin::get_symmetries_used() const { if (!this->_already_set_up) error("ForwardProjectorByBin method called without calling set_up first."); return proj_matrix_ptr->get_symmetries_ptr(); } -void -ForwardProjectorByBinUsingProjMatrixByBin:: - actual_forward_project(RelatedViewgrams& viewgrams, - const DiscretisedDensity<3,float>& image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ +void +ForwardProjectorByBinUsingProjMatrixByBin::actual_forward_project(RelatedViewgrams& viewgrams, + const DiscretisedDensity<3, float>& image, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) { if (proj_matrix_ptr->is_cache_enabled()/* && !proj_matrix_ptr->does_cache_store_only_basic_bins()*/) { - // straightforward version which relies on ProjMatrixByBin to sort out all + // straightforward version which relies on ProjMatrixByBin to sort out all // symmetries // would be slow if there's no caching at all, but is very fast if everything is cached - + ProjMatrixElemsForOneBin proj_matrix_row; - + RelatedViewgrams::iterator r_viewgrams_iter = viewgrams.begin(); - - while( r_viewgrams_iter!=viewgrams.end()) - { + + while (r_viewgrams_iter != viewgrams.end()) { Viewgram& viewgram = *r_viewgrams_iter; const int view_num = viewgram.get_view_num(); const int segment_num = viewgram.get_segment_num(); - - for ( int tang_pos = min_tangential_pos_num ;tang_pos <= max_tangential_pos_num ;++tang_pos) - for ( int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num ;++ax_pos) - { - Bin bin(segment_num, view_num, ax_pos, tang_pos, 0); + const int timing_num = viewgram.get_timing_pos_num(); + + for (int tang_pos = min_tangential_pos_num; tang_pos <= max_tangential_pos_num; ++tang_pos) + for (int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num; ++ax_pos) { + Bin bin(segment_num, view_num, ax_pos, tang_pos, timing_num, 0.f); proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, bin); - proj_matrix_row.forward_project(bin,image); + proj_matrix_row.forward_project(bin, image); viewgram[ax_pos][tang_pos] = bin.get_bin_value(); } - ++r_viewgrams_iter; - } - } - else - { + ++r_viewgrams_iter; + } + } else { + error("Need to do TOF stuff here"); // Complicated version which handles the symmetries explicitly. - // Faster when no caching is performed, about just as fast when there is caching, + // Faster when no caching is performed, about just as fast when there is caching, // but of only basic bins. - + ProjMatrixElemsForOneBin proj_matrix_row; ProjMatrixElemsForOneBin proj_matrix_row_copy; - const DataSymmetriesForBins* symmetries = proj_matrix_ptr->get_symmetries_ptr(); - - Array<2,int> - already_processed(IndexRange2D(min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num)); - - for ( int tang_pos = min_tangential_pos_num ;tang_pos <= max_tangential_pos_num ;++tang_pos) - for ( int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num ;++ax_pos) - { + const DataSymmetriesForBins* symmetries = proj_matrix_ptr->get_symmetries_ptr(); + + Array<2, int> already_processed( + IndexRange2D(min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num)); + + for (int tang_pos = min_tangential_pos_num; tang_pos <= max_tangential_pos_num; ++tang_pos) + for (int ax_pos = min_axial_pos_num; ax_pos <= max_axial_pos_num; ++ax_pos) { if (already_processed[ax_pos][tang_pos]) - continue; - - Bin basic_bin(viewgrams.get_basic_segment_num(),viewgrams.get_basic_view_num(),ax_pos,tang_pos); + continue; + + Bin basic_bin(viewgrams.get_basic_segment_num(), viewgrams.get_basic_view_num(), ax_pos, tang_pos, + viewgrams.get_basic_timing_pos_num()); symmetries->find_basic_bin(basic_bin); - + proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, basic_bin); - + vector r_ax_poss; - symmetries->get_related_bins_factorised(r_ax_poss,basic_bin, - min_axial_pos_num, max_axial_pos_num, + symmetries->get_related_bins_factorised(r_ax_poss, basic_bin, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); - + for ( #ifndef STIR_NO_NAMESPACES - std:: + std:: #endif - vector::iterator r_ax_poss_iter = r_ax_poss.begin(); - r_ax_poss_iter != r_ax_poss.end(); - ++r_ax_poss_iter) - { + vector::iterator r_ax_poss_iter = r_ax_poss.begin(); + r_ax_poss_iter != r_ax_poss.end(); ++r_ax_poss_iter) { const int axial_pos_tmp = (*r_ax_poss_iter)[1]; const int tang_pos_tmp = (*r_ax_poss_iter)[2]; - + // symmetries might take the ranges out of what the user wants - if ( !(min_axial_pos_num <= axial_pos_tmp && axial_pos_tmp <= max_axial_pos_num && - min_tangential_pos_num <=tang_pos_tmp && tang_pos_tmp <= max_tangential_pos_num)) + if (!(min_axial_pos_num <= axial_pos_tmp && axial_pos_tmp <= max_axial_pos_num && + min_tangential_pos_num <= tang_pos_tmp && tang_pos_tmp <= max_tangential_pos_num)) continue; - + already_processed[axial_pos_tmp][tang_pos_tmp] = 1; - - - for (RelatedViewgrams::iterator viewgram_iter = viewgrams.begin(); - viewgram_iter != viewgrams.end(); - ++viewgram_iter) - { + + for (RelatedViewgrams::iterator viewgram_iter = viewgrams.begin(); viewgram_iter != viewgrams.end(); + ++viewgram_iter) { Viewgram& viewgram = *viewgram_iter; proj_matrix_row_copy = proj_matrix_row; - Bin bin(viewgram_iter->get_segment_num(), - viewgram_iter->get_view_num(), - axial_pos_tmp, - tang_pos_tmp); - - unique_ptr symm_op_ptr = - symmetries->find_symmetry_operation_from_basic_bin(bin); + Bin bin(viewgram_iter->get_segment_num(), viewgram_iter->get_view_num(), axial_pos_tmp, tang_pos_tmp, + viewgram_iter->get_timing_pos_num()); + + unique_ptr symm_op_ptr = symmetries->find_symmetry_operation_from_basic_bin(bin); assert(bin == basic_bin); - + symm_op_ptr->transform_proj_matrix_elems_for_one_bin(proj_matrix_row_copy); - proj_matrix_row_copy.forward_project(bin,image); - + proj_matrix_row_copy.forward_project(bin, image); + viewgram[axial_pos_tmp][tang_pos_tmp] = bin.get_bin_value(); } - } - } - assert(already_processed.sum() == ( - (max_axial_pos_num - min_axial_pos_num + 1) * - (max_tangential_pos_num - min_tangential_pos_num + 1))); + } + } + assert(already_processed.sum() == + ((max_axial_pos_num - min_axial_pos_num + 1) * (max_tangential_pos_num - min_tangential_pos_num + 1))); } } +#if 0 // disabled as currently not used. needs to be written in the new style anyway +void +ForwardProjectorByBinUsingProjMatrixByBin:: + actual_forward_project(Bin& this_bin, + const DiscretisedDensity<3, float> &density) +{ + // KT does not understand this `if` statement. The cache has nothing to do with symmetries etc. + if (proj_matrix_ptr->is_cache_enabled()) + { + ProjMatrixElemsForOneBin proj_matrix_row; + + proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, this_bin); + proj_matrix_row.forward_project(this_bin,density); + } + else + error("ForwardProjectorByBinUsingProjMatrixByBin: Symmetries should be handled by ProjMatrix. Abort. "); +} +#endif + END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing.cxx b/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing.cxx index c1bca49f4f..ff615d95b0 100644 --- a/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing.cxx +++ b/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing.cxx @@ -30,9 +30,9 @@ See STIR/LICENSE.txt for details */ -/* +/* History: - * Matthias Egger: C version + * Matthias Egger: C version * PARAPET project : C++ version @@ -76,73 +76,55 @@ using std::max; START_NAMESPACE_STIR -const char * const -ForwardProjectorByBinUsingRayTracing::registered_name = - "Ray Tracing"; - +const char* const ForwardProjectorByBinUsingRayTracing::registered_name = "Ray Tracing"; void -ForwardProjectorByBinUsingRayTracing:: -set_defaults() -{ +ForwardProjectorByBinUsingRayTracing::set_defaults() { restrict_to_cylindrical_FOV = true; } void -ForwardProjectorByBinUsingRayTracing:: -initialise_keymap() -{ +ForwardProjectorByBinUsingRayTracing::initialise_keymap() { parser.add_start_key("Forward Projector Using Ray Tracing Parameters"); parser.add_key("restrict to cylindrical FOV", &restrict_to_cylindrical_FOV); parser.add_stop_key("End Forward Projector Using Ray Tracing Parameters"); } -ForwardProjectorByBinUsingRayTracing:: - ForwardProjectorByBinUsingRayTracing() -{ - set_defaults(); -} +ForwardProjectorByBinUsingRayTracing::ForwardProjectorByBinUsingRayTracing() { set_defaults(); } -ForwardProjectorByBinUsingRayTracing:: - ForwardProjectorByBinUsingRayTracing( - const shared_ptr& proj_data_info_sptr, - const shared_ptr >& image_info_ptr) -{ +ForwardProjectorByBinUsingRayTracing::ForwardProjectorByBinUsingRayTracing( + const shared_ptr& proj_data_info_sptr, + const shared_ptr>& image_info_ptr) { set_defaults(); set_up(proj_data_info_sptr, image_info_ptr); } void -ForwardProjectorByBinUsingRayTracing:: -set_up(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& image_info_ptr) -{ +ForwardProjectorByBinUsingRayTracing::set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& image_info_ptr) { ForwardProjectorByBin::set_up(proj_data_info_sptr, image_info_ptr); - - if (proj_data_info_sptr->get_num_views()%2 != 0) - { - error("The on-the-fly Ray tracing forward projector cannot handle data with odd number of views. Use another projector. Sorry."); - } + + if (proj_data_info_sptr->get_num_views() % 2 != 0) { + error("The on-the-fly Ray tracing forward projector cannot handle data with odd number of views. Use another projector. " + "Sorry."); + } symmetries_ptr.reset(new DataSymmetriesForBins_PET_CartesianGrid(proj_data_info_sptr, image_info_ptr)); // check if data are according to what we can handle - const VoxelsOnCartesianGrid * vox_image_info_ptr = - dynamic_cast*> (image_info_ptr.get()); + const VoxelsOnCartesianGrid* vox_image_info_ptr = + dynamic_cast*>(image_info_ptr.get()); if (vox_image_info_ptr == NULL) error("ForwardProjectorByBinUsingRayTracing initialised with a wrong type of DiscretisedDensity\n"); const CartesianCoordinate3D voxel_size = vox_image_info_ptr->get_voxel_size(); - const float sampling_distance_of_adjacent_LORs_xy = - proj_data_info_sptr->get_sampling_in_s(Bin(0,0,0,0)); - + const float sampling_distance_of_adjacent_LORs_xy = proj_data_info_sptr->get_sampling_in_s(Bin(0, 0, 0, 0)); // z_origin_in_planes should be an integer - const float z_origin_in_planes = - image_info_ptr->get_origin().z()/voxel_size.z(); + const float z_origin_in_planes = image_info_ptr->get_origin().z() / voxel_size.z(); if (fabs(round(z_origin_in_planes) - z_origin_in_planes) > 1.E-4) error("ForwardProjectorByBinUsingRayTracing: the shift in the " "z-direction of the origin (which is %g) should be a multiple of the plane " @@ -150,615 +132,462 @@ set_up(const shared_ptr& proj_data_info_sptr, image_info_ptr->get_origin().z(), voxel_size.z()); // num_planes_per_axial_pos should currently be an integer - for (int segment_num = proj_data_info_sptr->get_min_segment_num(); - segment_num <= proj_data_info_sptr->get_max_segment_num(); - ++segment_num) - { - const float num_planes_per_axial_pos = - symmetries_ptr->get_num_planes_per_axial_pos(segment_num); + for (int segment_num = proj_data_info_sptr->get_min_segment_num(); segment_num <= proj_data_info_sptr->get_max_segment_num(); + ++segment_num) { + const float num_planes_per_axial_pos = symmetries_ptr->get_num_planes_per_axial_pos(segment_num); if (fabs(round(num_planes_per_axial_pos) - num_planes_per_axial_pos) > 1.E-4) error("ForwardProjectorByBinUsingRayTracing: the number of image planes " "per axial_pos (which is %g for segment %d) should be an integer\n", - num_planes_per_axial_pos, segment_num); + num_planes_per_axial_pos, segment_num); } - // KT 20/06/2001 converted from assert to a warning - if(sampling_distance_of_adjacent_LORs_xy > voxel_size.x() + 1.E-3 || - sampling_distance_of_adjacent_LORs_xy > voxel_size.y() + 1.E-3) - warning("ForwardProjectorByBinUsingRayTracing assumes that pixel size (in x,y) " - "is greater than or equal to the bin size.\n" - "As this is NOT the case with the current data, the projector will " - "completely miss some voxels for some (or all) views."); + if (sampling_distance_of_adjacent_LORs_xy > voxel_size.x() + 1.E-3 || + sampling_distance_of_adjacent_LORs_xy > voxel_size.y() + 1.E-3) + warning("ForwardProjectorByBinUsingRayTracing assumes that pixel size (in x,y) " + "is greater than or equal to the bin size.\n" + "As this is NOT the case with the current data, the projector will " + "completely miss some voxels for some (or all) views."); } - -const DataSymmetriesForViewSegmentNumbers * -ForwardProjectorByBinUsingRayTracing::get_symmetries_used() const -{ +const DataSymmetriesForViewSegmentNumbers* +ForwardProjectorByBinUsingRayTracing::get_symmetries_used() const { if (!this->_already_set_up) error("ForwardProjectorByBin method called without calling set_up first."); - return symmetries_ptr.get(); + return symmetries_ptr.get(); } -void -ForwardProjectorByBinUsingRayTracing:: -actual_forward_project(RelatedViewgrams& viewgrams, - const DiscretisedDensity<3,float>& density, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) +void +ForwardProjectorByBinUsingRayTracing::actual_forward_project(RelatedViewgrams& viewgrams, + const DiscretisedDensity<3, float>& density, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num) { // this will throw an exception when the cast does not work - const VoxelsOnCartesianGrid& image = - dynamic_cast&>(density); + const VoxelsOnCartesianGrid& image = dynamic_cast&>(density); const int num_views = viewgrams.get_proj_data_info_sptr()->get_num_views(); - if (viewgrams.get_basic_segment_num() == 0) - { - if (viewgrams.get_num_viewgrams() == 1) - { - Viewgram & pos_view = *viewgrams.begin(); - forward_project_view_2D( - pos_view, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); + if (viewgrams.get_basic_segment_num() == 0) { + if (viewgrams.get_num_viewgrams() == 1) { + Viewgram& pos_view = *viewgrams.begin(); + forward_project_view_2D(pos_view, image, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); - } - else - if (viewgrams.get_num_viewgrams() == 2) - { + } else if (viewgrams.get_num_viewgrams() == 2) { assert(viewgrams.get_basic_view_num() >= 0); - assert(viewgrams.get_basic_view_num() < num_views/2); - Viewgram & pos_view = *viewgrams.begin(); - if ((viewgrams.begin()+1)->get_view_num() == pos_view.get_view_num() + num_views/2) - { - Viewgram & pos_plus90 =*(viewgrams.begin()+1); - if (pos_plus90.get_view_num() != pos_view.get_view_num() + num_views/2) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 2D case with 2 viewgrams\n"); - - forward_project_view_plus_90_2D( - pos_view, pos_plus90, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - } - else - { - Viewgram & pos_min180 =*(viewgrams.begin()+1); - if (pos_min180.get_view_num() != num_views - pos_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 2D case with 2 viewgrams\n"); - - forward_project_view_min_180_2D( - pos_view, pos_min180, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - } - } - else - { + assert(viewgrams.get_basic_view_num() < num_views / 2); + Viewgram& pos_view = *viewgrams.begin(); + if ((viewgrams.begin() + 1)->get_view_num() == pos_view.get_view_num() + num_views / 2) { + Viewgram& pos_plus90 = *(viewgrams.begin() + 1); + if (pos_plus90.get_view_num() != pos_view.get_view_num() + num_views / 2) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 2D case with 2 viewgrams\n"); + + forward_project_view_plus_90_2D(pos_view, pos_plus90, image, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); + } else { + Viewgram& pos_min180 = *(viewgrams.begin() + 1); + if (pos_min180.get_view_num() != num_views - pos_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 2D case with 2 viewgrams\n"); + + forward_project_view_min_180_2D(pos_view, pos_min180, image, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); + } + } else { assert(viewgrams.get_basic_view_num() > 0); - assert(viewgrams.get_basic_view_num() < num_views/4); - Viewgram & pos_view = *(viewgrams.begin()); - Viewgram & pos_plus90 =*(viewgrams.begin()+1); - Viewgram & pos_min180 =*(viewgrams.begin()+2); - Viewgram & pos_min90 =*(viewgrams.begin()+3); - - if (pos_plus90.get_view_num() != pos_view.get_view_num() + num_views/2) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 2D case with 4 viewgrams\n"); + assert(viewgrams.get_basic_view_num() < num_views / 4); + Viewgram& pos_view = *(viewgrams.begin()); + Viewgram& pos_plus90 = *(viewgrams.begin() + 1); + Viewgram& pos_min180 = *(viewgrams.begin() + 2); + Viewgram& pos_min90 = *(viewgrams.begin() + 3); + + if (pos_plus90.get_view_num() != pos_view.get_view_num() + num_views / 2) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 2D case with 4 viewgrams\n"); if (pos_min180.get_view_num() != num_views - pos_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 2D case with 4 viewgrams\n"); - if (pos_min90.get_view_num() != num_views/2 - pos_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 2D case with 4 viewgrams\n"); - - forward_project_all_symmetries_2D( - pos_view, pos_plus90, - pos_min180, pos_min90, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 2D case with 4 viewgrams\n"); + if (pos_min90.get_view_num() != num_views / 2 - pos_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 2D case with 4 viewgrams\n"); + forward_project_all_symmetries_2D(pos_view, pos_plus90, pos_min180, pos_min90, image, min_axial_pos_num, max_axial_pos_num, + min_tangential_pos_num, max_tangential_pos_num); } - } - else - { + } else { // segment symmetry - if (viewgrams.get_num_viewgrams() == 2) - { - Viewgram & pos_view = *(viewgrams.begin()+0); - Viewgram & neg_view =*(viewgrams.begin()+1); - - if (pos_view.get_view_num() != neg_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 2 viewgrams\n"); - if (neg_view.get_segment_num() != - pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 2 viewgrams\n"); - - forward_project_delta( - pos_view, neg_view, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - } - else if (viewgrams.get_num_viewgrams() == 4) - { - Viewgram & pos_view = *(viewgrams.begin()+0); - Viewgram & neg_view =*(viewgrams.begin()+1); - if (neg_view.get_view_num() != pos_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 2 viewgrams\n"); - if (neg_view.get_segment_num() != - pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); - - if ((viewgrams.begin()+2)->get_view_num() == pos_view.get_view_num() + num_views/2) - { - Viewgram & pos_plus90 =*(viewgrams.begin()+2); - Viewgram & neg_plus90 =*(viewgrams.begin()+3); - if (pos_plus90.get_view_num() != pos_view.get_view_num() + num_views/2) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); - if (neg_plus90.get_view_num() != neg_view.get_view_num() + num_views/2) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); - if (pos_plus90.get_segment_num() != pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); - if (neg_plus90.get_segment_num() != - pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); - forward_project_view_plus_90_and_delta( - pos_view, neg_view, pos_plus90, neg_plus90, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - } - else - { - Viewgram & pos_min180 =*(viewgrams.begin()+2); - Viewgram & neg_min180 =*(viewgrams.begin()+3); - if (pos_min180.get_view_num() != num_views - pos_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); - if (neg_min180.get_view_num() != num_views - neg_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); - if (pos_min180.get_segment_num() != pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); - if (neg_min180.get_segment_num() != - pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); - - forward_project_view_min_180_and_delta( - pos_view, neg_view, pos_min180, neg_min180, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - } - } - else if (viewgrams.get_num_viewgrams() == 8) - { - assert(viewgrams.get_basic_view_num() > 0); - assert(viewgrams.get_basic_view_num() < num_views/4); - Viewgram & pos_view = *(viewgrams.begin()+0); - Viewgram & neg_view =*(viewgrams.begin()+1); - Viewgram & pos_plus90 =*(viewgrams.begin()+2); - Viewgram & neg_plus90 =*(viewgrams.begin()+3); - Viewgram & pos_min180 =*(viewgrams.begin()+4); - Viewgram & neg_min180=*(viewgrams.begin()+5); - Viewgram & pos_min90=*(viewgrams.begin()+6); - Viewgram & neg_min90 =*(viewgrams.begin()+7); - - if (pos_plus90.get_view_num() != pos_view.get_view_num() + num_views/2) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - if (pos_min180.get_view_num() != num_views - pos_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - if (pos_min90.get_view_num() != num_views/2 - pos_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - - if (neg_view.get_view_num() != pos_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - if (neg_min90.get_view_num() != num_views/2 - neg_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - if (neg_plus90.get_view_num() != neg_view.get_view_num() + num_views/2) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - if (neg_min180.get_view_num() != num_views - neg_view.get_view_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - - if (pos_plus90.get_segment_num() != pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - if (pos_min90.get_segment_num() != pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - if (pos_min180.get_segment_num() != pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - - if (neg_view.get_segment_num() != - pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - if (neg_plus90.get_segment_num() != - pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - if (neg_min90.get_segment_num() != - pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - if (neg_min180.get_segment_num() != - pos_view.get_segment_num()) - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); - - forward_project_all_symmetries( - pos_view, neg_view, pos_plus90, neg_plus90, - pos_min180, neg_min180, pos_min90, neg_min90, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - - } - else // other number of viewgrams - { - error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case\n"); + if (viewgrams.get_num_viewgrams() == 2) { + Viewgram& pos_view = *(viewgrams.begin() + 0); + Viewgram& neg_view = *(viewgrams.begin() + 1); + + if (pos_view.get_view_num() != neg_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 2 viewgrams\n"); + if (neg_view.get_segment_num() != -pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 2 viewgrams\n"); + + forward_project_delta(pos_view, neg_view, image, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); + } else if (viewgrams.get_num_viewgrams() == 4) { + Viewgram& pos_view = *(viewgrams.begin() + 0); + Viewgram& neg_view = *(viewgrams.begin() + 1); + if (neg_view.get_view_num() != pos_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 2 viewgrams\n"); + if (neg_view.get_segment_num() != -pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); + + if ((viewgrams.begin() + 2)->get_view_num() == pos_view.get_view_num() + num_views / 2) { + Viewgram& pos_plus90 = *(viewgrams.begin() + 2); + Viewgram& neg_plus90 = *(viewgrams.begin() + 3); + if (pos_plus90.get_view_num() != pos_view.get_view_num() + num_views / 2) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); + if (neg_plus90.get_view_num() != neg_view.get_view_num() + num_views / 2) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); + if (pos_plus90.get_segment_num() != pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); + if (neg_plus90.get_segment_num() != -pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); + forward_project_view_plus_90_and_delta(pos_view, neg_view, pos_plus90, neg_plus90, image, min_axial_pos_num, + max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); + } else { + Viewgram& pos_min180 = *(viewgrams.begin() + 2); + Viewgram& neg_min180 = *(viewgrams.begin() + 3); + if (pos_min180.get_view_num() != num_views - pos_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); + if (neg_min180.get_view_num() != num_views - neg_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); + if (pos_min180.get_segment_num() != pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); + if (neg_min180.get_segment_num() != -pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 4 viewgrams\n"); + + forward_project_view_min_180_and_delta(pos_view, neg_view, pos_min180, neg_min180, image, min_axial_pos_num, + max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); } + } else if (viewgrams.get_num_viewgrams() == 8) { + assert(viewgrams.get_basic_view_num() > 0); + assert(viewgrams.get_basic_view_num() < num_views / 4); + Viewgram& pos_view = *(viewgrams.begin() + 0); + Viewgram& neg_view = *(viewgrams.begin() + 1); + Viewgram& pos_plus90 = *(viewgrams.begin() + 2); + Viewgram& neg_plus90 = *(viewgrams.begin() + 3); + Viewgram& pos_min180 = *(viewgrams.begin() + 4); + Viewgram& neg_min180 = *(viewgrams.begin() + 5); + Viewgram& pos_min90 = *(viewgrams.begin() + 6); + Viewgram& neg_min90 = *(viewgrams.begin() + 7); + + if (pos_plus90.get_view_num() != pos_view.get_view_num() + num_views / 2) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + if (pos_min180.get_view_num() != num_views - pos_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + if (pos_min90.get_view_num() != num_views / 2 - pos_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + + if (neg_view.get_view_num() != pos_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + if (neg_min90.get_view_num() != num_views / 2 - neg_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + if (neg_plus90.get_view_num() != neg_view.get_view_num() + num_views / 2) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + if (neg_min180.get_view_num() != num_views - neg_view.get_view_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + + if (pos_plus90.get_segment_num() != pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + if (pos_min90.get_segment_num() != pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + if (pos_min180.get_segment_num() != pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + + if (neg_view.get_segment_num() != -pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + if (neg_plus90.get_segment_num() != -pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + if (neg_min90.get_segment_num() != -pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + if (neg_min180.get_segment_num() != -pos_view.get_segment_num()) + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case with 8 viewgrams\n"); + + forward_project_all_symmetries(pos_view, neg_view, pos_plus90, neg_plus90, pos_min180, neg_min180, pos_min90, neg_min90, + image, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); + + } else // other number of viewgrams + { + error("ForwardProjectorUsingRayTracing: error in symmetries. Check 3D case\n"); + } } // oblique case - - } - - /* The version which uses all possible symmetries. Here 0<=view < num_views/4 (= 45 degrees) */ -void -ForwardProjectorByBinUsingRayTracing:: -forward_project_all_symmetries( - Viewgram & pos_view, - Viewgram & neg_view, - Viewgram & pos_plus90, - Viewgram & neg_plus90, - Viewgram & pos_min180, - Viewgram & neg_min180, - Viewgram & pos_min90, - Viewgram & neg_min90, - const VoxelsOnCartesianGrid& image, - const int min_ax_pos_num, const int max_ax_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ +void +ForwardProjectorByBinUsingRayTracing::forward_project_all_symmetries( + Viewgram& pos_view, Viewgram& neg_view, Viewgram& pos_plus90, Viewgram& neg_plus90, + Viewgram& pos_min180, Viewgram& neg_min180, Viewgram& pos_min90, Viewgram& neg_min90, + const VoxelsOnCartesianGrid& image, const int min_ax_pos_num, const int max_ax_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num) const { // KT 20/06/2001 should now work for non-arccorrected data as well const shared_ptr proj_data_info_sptr = - dynamic_pointer_cast - (pos_view.get_proj_data_info_sptr()); + dynamic_pointer_cast(pos_view.get_proj_data_info_sptr()); if (is_null_ptr(proj_data_info_sptr)) error("ForwardProjectorByBinUsingRayTracing::forward_project called with wrong type of ProjDataInfo\n"); - - const int nviews = pos_view.get_proj_data_info_sptr()->get_num_views(); - + + const int nviews = pos_view.get_proj_data_info_sptr()->get_num_views(); + const int segment_num = pos_view.get_segment_num(); + // const int timing_pos_num = pos_view.get_timing_pos_num(); const float delta = proj_data_info_sptr->get_average_ring_difference(segment_num); const int view = pos_view.get_view_num(); assert(delta > 0); assert(view >= 0); - /* removed assertions which would break the temporary 2,4 parameter forward_project + /* removed assertions which would break the temporary 2,4 parameter forward_project assert(view <= view90); - + assert(pos_plus90.get_view_num() == nviews / 2 + pos_view.get_view_num()); assert(pos_min90.get_view_num() == nviews / 2 - pos_view.get_view_num()); assert(pos_min180.get_view_num() == nviews - pos_view.get_view_num()); - + assert(neg_view.get_view_num() == pos_view.get_view_num()); assert(neg_plus90.get_view_num() == pos_plus90.get_view_num()); assert(neg_min90.get_view_num() == pos_min90.get_view_num()); assert(neg_min180.get_view_num() == pos_min180.get_view_num()); */ - //assert(image.get_min_z() == 0); + // assert(image.get_min_z() == 0); + + assert(delta == -proj_data_info_sptr->get_average_ring_difference(neg_view.get_segment_num())); - assert(delta == - -proj_data_info_sptr->get_average_ring_difference(neg_view.get_segment_num())); - // KT 21/05/98 added const where possible // TODO C value depends whether you are in Double or not, // If double C==2 => do 2*ax_pos0 and 2*ax_pos0+1 - const int C=1; - - int D, tang_pos_num; + const int C = 1; + + int D, tang_pos_num; int ax_pos0, my_ax_pos0; const float R = proj_data_info_sptr->get_ring_radius(); - + // a variable which will be used in the loops over tang_pos_num to get s_in_mm - Bin bin(pos_view.get_segment_num(), pos_view.get_view_num(),min_ax_pos_num,0); + Bin bin(pos_view.get_segment_num(), pos_view.get_view_num(), min_ax_pos_num, 0, pos_view.get_timing_pos_num()); - // KT 20/06/2001 rewrote using get_phi + // KT 20/06/2001 rewrote using get_phi const float cphi = cos(proj_data_info_sptr->get_phi(bin)); const float sphi = sin(proj_data_info_sptr->get_phi(bin)); // KT 20/06/2001 write using symmetries member // find correspondence between ring coordinates and image coordinates: // z = num_planes_per_axial_pos * ring + axial_pos_to_z_offset - const int num_planes_per_axial_pos = - round(symmetries_ptr->get_num_planes_per_axial_pos(segment_num)); - const float axial_pos_to_z_offset = - symmetries_ptr->get_axial_pos_to_z_offset(segment_num); - + const int num_planes_per_axial_pos = round(symmetries_ptr->get_num_planes_per_axial_pos(segment_num)); + const float axial_pos_to_z_offset = symmetries_ptr->get_axial_pos_to_z_offset(segment_num); + // KT 20/06/2001 parameters to find 'basic' range of tang_pos_num - const int max_abs_tangential_pos_num = - max(max_tangential_pos_num, -min_tangential_pos_num); - const int min_abs_tangential_pos_num = - max_tangential_pos_num<0 ? - -max_tangential_pos_num - : (min_tangential_pos_num>0 ? - min_tangential_pos_num - : 0 ); + const int max_abs_tangential_pos_num = max(max_tangential_pos_num, -min_tangential_pos_num); + const int min_abs_tangential_pos_num = + max_tangential_pos_num < 0 ? -max_tangential_pos_num : (min_tangential_pos_num > 0 ? min_tangential_pos_num : 0); // in the loop, the case tang_pos_num==0 will be treated separately (because it's self-symmetric) - const int min_tang_pos_num_in_loop = - min_abs_tangential_pos_num==0 ? 1 : min_abs_tangential_pos_num; - + const int min_tang_pos_num_in_loop = min_abs_tangential_pos_num == 0 ? 1 : min_abs_tangential_pos_num; + start_timers(); - - Array <4,float> Projall(IndexRange4D(min_ax_pos_num, max_ax_pos_num, 0, 1, 0, 1, 0, 3)); - // KT 21/05/98 removed as now automatically zero - // Projall.fill(0); + Array<4, float> Projall(IndexRange4D(min_ax_pos_num, max_ax_pos_num, 0, 1, 0, 1, 0, 3)); + // KT 21/05/98 removed as now automatically zero + // Projall.fill(0); - // In the case that axial sampling for the projection data = 2*voxel_size.z() - // we draw 2 LORs, at -1/4 and +1/4 of the centre of the bin - // If we don't do this, we will miss voxels in the forward projection step. + // In the case that axial sampling for the projection data = 2*voxel_size.z() + // we draw 2 LORs, at -1/4 and +1/4 of the centre of the bin + // If we don't do this, we will miss voxels in the forward projection step. - // When the axial sampling is the same as the voxel size, we take just - // 1 LOR. - float offset_start = -.25F; - float offset_incr = .5F; + // When the axial sampling is the same as the voxel size, we take just + // 1 LOR. + float offset_start = -.25F; + float offset_incr = .5F; - int num_lors_per_virtual_ring = 2; - - if (num_planes_per_axial_pos == 1) - { - offset_start = 0; - offset_incr=1; - num_lors_per_virtual_ring = 1; - } + int num_lors_per_virtual_ring = 2; + if (num_planes_per_axial_pos == 1) { + offset_start = 0; + offset_incr = 1; + num_lors_per_virtual_ring = 1; + } - for (float offset = offset_start; offset < 0.3; offset += offset_incr) - { - if (view == 0 || 4*view == nviews ) { /* phi=0 or 45 */ - for (D = 0; D < C; D++) { - if (min_abs_tangential_pos_num==0) - { - /* Here tang_pos_num=0 and phi=0 or 45*/ + for (float offset = offset_start; offset < 0.3; offset += offset_incr) { + if (view == 0 || 4 * view == nviews) { /* phi=0 or 45 */ + for (D = 0; D < C; D++) { + if (min_abs_tangential_pos_num == 0) { + /* Here tang_pos_num=0 and phi=0 or 45*/ - if (proj_Siddon + if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - < 2>( + <2>( #else - (2, + (2, #endif - Projall, image, proj_data_info_sptr, cphi, sphi, - delta + D, 0, R,min_ax_pos_num, max_ax_pos_num, - offset, num_planes_per_axial_pos, axial_pos_to_z_offset, - 1.F / num_lors_per_virtual_ring, - restrict_to_cylindrical_FOV)) - for (ax_pos0 = min_ax_pos_num; ax_pos0 <= max_ax_pos_num; ax_pos0++) { - my_ax_pos0 = C * ax_pos0 + D; - - pos_view[my_ax_pos0][0] += Projall[ax_pos0][0][0][0]; - pos_plus90[my_ax_pos0][0] += Projall[ax_pos0][0][0][2]; - neg_view[my_ax_pos0][0] += Projall[ax_pos0][1][0][0]; - neg_plus90[my_ax_pos0][0] += Projall[ax_pos0][1][0][2]; - } - } - /* Now tang_pos_num!=0 and phi=0 or 45 */ - for (tang_pos_num = min_tang_pos_num_in_loop; tang_pos_num <= max_abs_tangential_pos_num; tang_pos_num++) - { - bin.tangential_pos_num() = tang_pos_num; - const float s_in_mm = proj_data_info_sptr->get_s(bin); - if (proj_Siddon + Projall, image, proj_data_info_sptr, cphi, sphi, delta + D, 0, R, min_ax_pos_num, max_ax_pos_num, offset, + num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / num_lors_per_virtual_ring, restrict_to_cylindrical_FOV)) + for (ax_pos0 = min_ax_pos_num; ax_pos0 <= max_ax_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + + pos_view[my_ax_pos0][0] += Projall[ax_pos0][0][0][0]; + pos_plus90[my_ax_pos0][0] += Projall[ax_pos0][0][0][2]; + neg_view[my_ax_pos0][0] += Projall[ax_pos0][1][0][0]; + neg_plus90[my_ax_pos0][0] += Projall[ax_pos0][1][0][2]; + } + } + /* Now tang_pos_num!=0 and phi=0 or 45 */ + for (tang_pos_num = min_tang_pos_num_in_loop; tang_pos_num <= max_abs_tangential_pos_num; tang_pos_num++) { + bin.tangential_pos_num() = tang_pos_num; + const float s_in_mm = proj_data_info_sptr->get_s(bin); + if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <1>( + <1>( #else - (1, + (1, #endif - Projall, image, proj_data_info_sptr, cphi, sphi, - delta + D, s_in_mm, R,min_ax_pos_num, max_ax_pos_num, - offset, num_planes_per_axial_pos, axial_pos_to_z_offset, - 1.F/num_lors_per_virtual_ring, - restrict_to_cylindrical_FOV)) - for (ax_pos0 = min_ax_pos_num; ax_pos0 <= max_ax_pos_num; ax_pos0++) { - my_ax_pos0 = C * ax_pos0 + D; - if (tang_pos_num<=max_tangential_pos_num) - { - pos_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][0]; - pos_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][2]; - neg_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][0]; - neg_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][2]; - } - if (-tang_pos_num>=min_tangential_pos_num) - { - pos_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][0]; - pos_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][2]; - neg_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][0]; - neg_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][2]; - } - } - } + Projall, image, proj_data_info_sptr, cphi, sphi, delta + D, s_in_mm, R, min_ax_pos_num, max_ax_pos_num, offset, + num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / num_lors_per_virtual_ring, restrict_to_cylindrical_FOV)) + for (ax_pos0 = min_ax_pos_num; ax_pos0 <= max_ax_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + if (tang_pos_num <= max_tangential_pos_num) { + pos_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][0]; + pos_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][2]; + neg_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][0]; + neg_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][2]; + } + if (-tang_pos_num >= min_tangential_pos_num) { + pos_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][0]; + pos_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][2]; + neg_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][0]; + neg_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][2]; + } } - } else { - - - for (D = 0; D < C; D++) { - if (min_abs_tangential_pos_num==0) - { - /* Here tang_pos_num==0 and phi!=k*45 */ - if (proj_Siddon + } + } + } else { + + for (D = 0; D < C; D++) { + if (min_abs_tangential_pos_num == 0) { + /* Here tang_pos_num==0 and phi!=k*45 */ + if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <4>( + <4>( #else - (4, + (4, #endif - Projall, image, proj_data_info_sptr, cphi, sphi, - delta + D, 0, R,min_ax_pos_num, max_ax_pos_num, - offset, num_planes_per_axial_pos, axial_pos_to_z_offset , - 1.F/num_lors_per_virtual_ring, - restrict_to_cylindrical_FOV)) - for (ax_pos0 = min_ax_pos_num; ax_pos0 <= max_ax_pos_num; ax_pos0++) { - my_ax_pos0 = C * ax_pos0 + D; - pos_view[my_ax_pos0][0] += Projall[ax_pos0][0][0][0]; - pos_min90[my_ax_pos0][0] += Projall[ax_pos0][0][0][1]; - pos_plus90[my_ax_pos0][0] += Projall[ax_pos0][0][0][2]; - pos_min180[my_ax_pos0][0] += Projall[ax_pos0][0][0][3]; - neg_view[my_ax_pos0][0] += Projall[ax_pos0][1][0][0]; - neg_min90[my_ax_pos0][0] += Projall[ax_pos0][1][0][1]; - neg_plus90[my_ax_pos0][0] += Projall[ax_pos0][1][0][2]; - neg_min180[my_ax_pos0][0] += Projall[ax_pos0][1][0][3]; - } - } - - - /* Here tang_pos_num!=0 and phi!=k*45. */ - for (tang_pos_num = min_tang_pos_num_in_loop; tang_pos_num <= max_abs_tangential_pos_num; tang_pos_num++) { - bin.tangential_pos_num() = tang_pos_num; - const float s_in_mm = proj_data_info_sptr->get_s(bin); - - if (proj_Siddon + Projall, image, proj_data_info_sptr, cphi, sphi, delta + D, 0, R, min_ax_pos_num, max_ax_pos_num, offset, + num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / num_lors_per_virtual_ring, restrict_to_cylindrical_FOV)) + for (ax_pos0 = min_ax_pos_num; ax_pos0 <= max_ax_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + pos_view[my_ax_pos0][0] += Projall[ax_pos0][0][0][0]; + pos_min90[my_ax_pos0][0] += Projall[ax_pos0][0][0][1]; + pos_plus90[my_ax_pos0][0] += Projall[ax_pos0][0][0][2]; + pos_min180[my_ax_pos0][0] += Projall[ax_pos0][0][0][3]; + neg_view[my_ax_pos0][0] += Projall[ax_pos0][1][0][0]; + neg_min90[my_ax_pos0][0] += Projall[ax_pos0][1][0][1]; + neg_plus90[my_ax_pos0][0] += Projall[ax_pos0][1][0][2]; + neg_min180[my_ax_pos0][0] += Projall[ax_pos0][1][0][3]; + } + } + + /* Here tang_pos_num!=0 and phi!=k*45. */ + for (tang_pos_num = min_tang_pos_num_in_loop; tang_pos_num <= max_abs_tangential_pos_num; tang_pos_num++) { + bin.tangential_pos_num() = tang_pos_num; + const float s_in_mm = proj_data_info_sptr->get_s(bin); + + if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <3>( + <3>( #else - (3, + (3, #endif - Projall, image, proj_data_info_sptr, cphi, sphi, - delta + D, s_in_mm, R,min_ax_pos_num, max_ax_pos_num, - offset, num_planes_per_axial_pos, axial_pos_to_z_offset , - 1.F/num_lors_per_virtual_ring, - restrict_to_cylindrical_FOV)) - for (ax_pos0 = min_ax_pos_num; ax_pos0 <= max_ax_pos_num; ax_pos0++) - { - my_ax_pos0 = C * ax_pos0 + D; - if (tang_pos_num<=max_tangential_pos_num) - { - pos_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][0]; - pos_min90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][1]; - pos_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][2]; - pos_min180[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][3]; - neg_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][0]; - neg_min90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][1]; - neg_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][2]; - neg_min180[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][3]; - } - if (-tang_pos_num>=min_tangential_pos_num) - { - pos_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][0]; - pos_min90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][1]; - pos_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][2]; - pos_min180[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][3]; - neg_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][0]; - neg_min90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][1]; - neg_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][2]; - neg_min180[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][3]; - } - } - } + Projall, image, proj_data_info_sptr, cphi, sphi, delta + D, s_in_mm, R, min_ax_pos_num, max_ax_pos_num, offset, + num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / num_lors_per_virtual_ring, restrict_to_cylindrical_FOV)) + for (ax_pos0 = min_ax_pos_num; ax_pos0 <= max_ax_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + if (tang_pos_num <= max_tangential_pos_num) { + pos_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][0]; + pos_min90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][1]; + pos_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][2]; + pos_min180[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][3]; + neg_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][0]; + neg_min90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][1]; + neg_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][2]; + neg_min180[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][1][0][3]; + } + if (-tang_pos_num >= min_tangential_pos_num) { + pos_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][0]; + pos_min90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][1]; + pos_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][2]; + pos_min180[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][3]; + neg_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][0]; + neg_min90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][1]; + neg_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][2]; + neg_min180[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][1][1][3]; + } } + } + } + } // end of } else { + } // end of test for offset loop - }// end of } else { - }// end of test for offset loop - - stop_timers(); - + stop_timers(); } - /* This function projects 2 viewgrams related by segment symmetry. */ -void -ForwardProjectorByBinUsingRayTracing:: - forward_project_delta(Viewgram & pos_view, - Viewgram & neg_view, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ +void +ForwardProjectorByBinUsingRayTracing::forward_project_delta(Viewgram& pos_view, Viewgram& neg_view, + const VoxelsOnCartesianGrid& image, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) const { assert(pos_view.get_segment_num() > 0); assert(pos_view.get_view_num() >= 0); assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views()); Viewgram dummy = pos_view; - - forward_project_all_symmetries( - pos_view, - neg_view, - dummy, - dummy, - dummy, - dummy, - dummy, - dummy, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); + forward_project_all_symmetries(pos_view, neg_view, dummy, dummy, dummy, dummy, dummy, dummy, image, min_axial_pos_num, + max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); } - /* This function projects 4 viewgrams related by symmetry. Here 0<=view < num_views/2 (= 90 degrees) */ -void -ForwardProjectorByBinUsingRayTracing:: - forward_project_view_plus_90_and_delta(Viewgram & pos_view, - Viewgram & neg_view, - Viewgram & pos_plus90, - Viewgram & neg_plus90, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ +void +ForwardProjectorByBinUsingRayTracing::forward_project_view_plus_90_and_delta( + Viewgram& pos_view, Viewgram& neg_view, Viewgram& pos_plus90, Viewgram& neg_plus90, + const VoxelsOnCartesianGrid& image, const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num) const { assert(pos_view.get_segment_num() > 0); assert(pos_view.get_view_num() >= 0); - assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views()/2); + assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views() / 2); Viewgram dummy = pos_view; - - forward_project_all_symmetries( - pos_view, - neg_view, - pos_plus90, - neg_plus90, - dummy, - dummy, - dummy, - dummy, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); + forward_project_all_symmetries(pos_view, neg_view, pos_plus90, neg_plus90, dummy, dummy, dummy, dummy, image, min_axial_pos_num, + max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); } - -void -ForwardProjectorByBinUsingRayTracing:: - forward_project_view_min_180_and_delta(Viewgram & pos_view, - Viewgram & neg_view, - Viewgram & pos_min180, - Viewgram & neg_min180, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ +void +ForwardProjectorByBinUsingRayTracing::forward_project_view_min_180_and_delta( + Viewgram& pos_view, Viewgram& neg_view, Viewgram& pos_min180, Viewgram& neg_min180, + const VoxelsOnCartesianGrid& image, const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num) const { assert(pos_view.get_segment_num() > 0); assert(pos_view.get_view_num() >= 0); - assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views()/2); + assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views() / 2); Viewgram dummy = pos_view; - forward_project_all_symmetries( - pos_view, - neg_view, - dummy, - dummy, - pos_min180, - neg_min180, - dummy, - dummy, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); + forward_project_all_symmetries(pos_view, neg_view, dummy, dummy, pos_min180, neg_min180, dummy, dummy, image, min_axial_pos_num, + max_axial_pos_num, min_tangential_pos_num, max_tangential_pos_num); } #if 0 @@ -933,11 +762,11 @@ void ForwardProjectorByBinUsingRayTracing::forward_project_2D(Sinogram &s /* Here tang_pos_num=0 and phi=0 or 45*/ if (proj_Siddon -#ifndef STIR_SIDDON_NO_TEMPLATE +# ifndef STIR_SIDDON_NO_TEMPLATE <2>( -#else +# else (2, -#endif +# endif Projall,image,proj_data_cyl_ptr, cphi, sphi, delta + D, 0, R,min_ax_pos, max_ax_pos, offset, num_planes_per_axial_pos, 0, @@ -951,11 +780,11 @@ void ForwardProjectorByBinUsingRayTracing::forward_project_2D(Sinogram &s /* Now tang_pos_num!=0 and phi=0 or 45 */ for (tang_pos_num = min_tang_pos_num_in_loop; tang_pos_num <= max_abs_tangential_pos_num; tang_pos_num++) { if (proj_Siddon -#ifndef STIR_SIDDON_NO_TEMPLATE +# ifndef STIR_SIDDON_NO_TEMPLATE <1>( -#else +# else (1, -#endif +# endif Projall,image,proj_data_cyl_ptr, cphi, sphi, delta + D, tang_pos_num, R,min_ax_pos,max_ax_pos, offset, num_planes_per_axial_pos, 0, @@ -976,11 +805,11 @@ void ForwardProjectorByBinUsingRayTracing::forward_project_2D(Sinogram &s for (D = 0; D < C; D++) { /* Here tang_pos_num==0 and phi!=k*45 */ if (proj_Siddon -#ifndef STIR_SIDDON_NO_TEMPLATE +# ifndef STIR_SIDDON_NO_TEMPLATE <4>( -#else +# else (4, -#endif +# endif Projall,image,proj_data_cyl_ptr, cphi, sphi, delta + D, 0, R,min_ax_pos,max_ax_pos, offset, num_planes_per_axial_pos, 0, @@ -997,11 +826,11 @@ void ForwardProjectorByBinUsingRayTracing::forward_project_2D(Sinogram &s /* Here tang_pos_num!=0 and phi!=k*45. */ for (tang_pos_num = min_tang_pos_num_in_loop; tang_pos_num <= max_abs_tangential_pos_num; tang_pos_num++) { if (proj_Siddon -#ifndef STIR_SIDDON_NO_TEMPLATE +# ifndef STIR_SIDDON_NO_TEMPLATE <3>( -#else +# else (3, -#endif +# endif Projall,image,proj_data_cyl_ptr, cphi, sphi, delta + D, tang_pos_num, R,min_ax_pos, max_ax_pos, offset, num_planes_per_axial_pos, 0, @@ -1031,423 +860,339 @@ void ForwardProjectorByBinUsingRayTracing::forward_project_2D(Sinogram &s #endif // old 2D versions -void -ForwardProjectorByBinUsingRayTracing:: -forward_project_view_2D(Viewgram & pos_view, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ +void +ForwardProjectorByBinUsingRayTracing::forward_project_view_2D(Viewgram& pos_view, + const VoxelsOnCartesianGrid& image, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) const { assert(pos_view.get_segment_num() == 0); assert(pos_view.get_view_num() >= 0); assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views()); Viewgram dummy = pos_view; - forward_project_all_symmetries_2D( - pos_view, - dummy, - dummy, - dummy, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - + forward_project_all_symmetries_2D(pos_view, dummy, dummy, dummy, image, min_axial_pos_num, max_axial_pos_num, + min_tangential_pos_num, max_tangential_pos_num); } -void -ForwardProjectorByBinUsingRayTracing:: -forward_project_view_plus_90_2D(Viewgram & pos_view, - Viewgram & pos_plus90, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ +void +ForwardProjectorByBinUsingRayTracing::forward_project_view_plus_90_2D(Viewgram& pos_view, Viewgram& pos_plus90, + const VoxelsOnCartesianGrid& image, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) const { assert(pos_view.get_segment_num() == 0); assert(pos_view.get_view_num() >= 0); - assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views()/2); + assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views() / 2); Viewgram dummy = pos_view; - forward_project_all_symmetries_2D( - pos_view, - pos_plus90, - dummy, - dummy, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); + forward_project_all_symmetries_2D(pos_view, pos_plus90, dummy, dummy, image, min_axial_pos_num, max_axial_pos_num, + min_tangential_pos_num, max_tangential_pos_num); } - -void -ForwardProjectorByBinUsingRayTracing:: -forward_project_view_min_180_2D(Viewgram & pos_view, - Viewgram & pos_min180, - const VoxelsOnCartesianGrid & image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ +void +ForwardProjectorByBinUsingRayTracing::forward_project_view_min_180_2D(Viewgram& pos_view, Viewgram& pos_min180, + const VoxelsOnCartesianGrid& image, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) const { assert(pos_view.get_segment_num() == 0); assert(pos_view.get_view_num() >= 0); - assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views()/2); + assert(pos_view.get_view_num() < pos_view.get_proj_data_info_sptr()->get_num_views() / 2); Viewgram dummy = pos_view; - forward_project_all_symmetries_2D( - pos_view, - dummy, - pos_min180, - dummy, - image, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); + forward_project_all_symmetries_2D(pos_view, dummy, pos_min180, dummy, image, min_axial_pos_num, max_axial_pos_num, + min_tangential_pos_num, max_tangential_pos_num); } - - -void -ForwardProjectorByBinUsingRayTracing:: -forward_project_all_symmetries_2D(Viewgram & pos_view, - Viewgram & pos_plus90, - Viewgram & pos_min180, - Viewgram & pos_min90, - const VoxelsOnCartesianGrid& image, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ +void +ForwardProjectorByBinUsingRayTracing::forward_project_all_symmetries_2D(Viewgram& pos_view, Viewgram& pos_plus90, + Viewgram& pos_min180, Viewgram& pos_min90, + const VoxelsOnCartesianGrid& image, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) const { start_timers(); // KT 20/06/2001 should now work for non-arccorrected data as well const shared_ptr proj_data_info_sptr = - dynamic_pointer_cast - (pos_view.get_proj_data_info_sptr()); + dynamic_pointer_cast(pos_view.get_proj_data_info_sptr()); if (is_null_ptr(proj_data_info_sptr)) error("ForwardProjectorByBinUsingRayTracing::forward_project called with wrong type of ProjDataInfo\n"); - - const int nviews = pos_view.get_proj_data_info_sptr()->get_num_views(); - + + const int nviews = pos_view.get_proj_data_info_sptr()->get_num_views(); + const int segment_num = pos_view.get_segment_num(); + // const int timing_pos_num = pos_view.get_timing_pos_num(); const float delta = proj_data_info_sptr->get_average_ring_difference(segment_num); const int view = pos_view.get_view_num(); assert(delta == 0); assert(view >= 0); - /* remove assertions which would break the temporary 1,2 parameter forward_project. - Now checked before calling + Now checked before calling assert(pos_plus90.get_view_num() == nviews / 2 + pos_view.get_view_num()); assert(pos_min90.get_view_num() == nviews / 2 - pos_view.get_view_num()); assert(pos_min180.get_view_num() == nviews - pos_view.get_view_num()); */ - //assert(neg_view.get_view_num() == pos_view.get_view_num()); - //assert(neg_plus90.get_view_num() == pos_plus90.get_view_num()); - //assert(neg_min90.get_view_num() == pos_min90.get_view_num()); - //assert(neg_min180.get_view_num() == pos_min180.get_view_num()); - + // assert(neg_view.get_view_num() == pos_view.get_view_num()); + // assert(neg_plus90.get_view_num() == pos_plus90.get_view_num()); + // assert(neg_min90.get_view_num() == pos_min90.get_view_num()); + // assert(neg_min180.get_view_num() == pos_min180.get_view_num()); + // KT 21/05/98 added const where possible // TODO C value depends whether you are in Double or not, // If double C==2 => do 2*ax_pos0 and 2*ax_pos0+1 - const int C=1; - - int D, tang_pos_num; + const int C = 1; + + int D, tang_pos_num; int my_ax_pos0; const float R = proj_data_info_sptr->get_ring_radius(); // a variable which will be used in the loops over tang_pos_num to get s_in_mm - Bin bin(pos_view.get_segment_num(), pos_view.get_view_num(),min_axial_pos_num,0); - - // KT 20/06/2001 rewrote using get_phi + Bin bin(pos_view.get_segment_num(), pos_view.get_view_num(), min_axial_pos_num, 0, pos_view.get_timing_pos_num()); + + // KT 20/06/2001 rewrote using get_phi const float cphi = cos(proj_data_info_sptr->get_phi(bin)); const float sphi = sin(proj_data_info_sptr->get_phi(bin)); // find correspondence between ring coordinates and image coordinates: // z = num_planes_per_axial_pos * ax_pos_num + axial_pos_to_z_offset // KT 20/06/2001 write using symmetries member - const int num_planes_per_axial_pos = - round(symmetries_ptr->get_num_planes_per_axial_pos(segment_num)); - const float axial_pos_to_z_offset = - symmetries_ptr->get_axial_pos_to_z_offset(segment_num); - - const int max_abs_tangential_pos_num = - max(max_tangential_pos_num, -min_tangential_pos_num); - - const int min_abs_tangential_pos_num = - max_tangential_pos_num<0 ? - -max_tangential_pos_num - : (min_tangential_pos_num>0 ? - min_tangential_pos_num - : 0 ); - const int min_tang_pos_num_in_loop = - min_abs_tangential_pos_num==0 ? 1 : min_abs_tangential_pos_num; - + const int num_planes_per_axial_pos = round(symmetries_ptr->get_num_planes_per_axial_pos(segment_num)); + const float axial_pos_to_z_offset = symmetries_ptr->get_axial_pos_to_z_offset(segment_num); + + const int max_abs_tangential_pos_num = max(max_tangential_pos_num, -min_tangential_pos_num); + + const int min_abs_tangential_pos_num = + max_tangential_pos_num < 0 ? -max_tangential_pos_num : (min_tangential_pos_num > 0 ? min_tangential_pos_num : 0); + const int min_tang_pos_num_in_loop = min_abs_tangential_pos_num == 0 ? 1 : min_abs_tangential_pos_num; + + Array<4, float> Projall(IndexRange4D(min_axial_pos_num, max_axial_pos_num, 0, 1, 0, 1, 0, 3)); + Array<4, float> Projall2(IndexRange4D(min_axial_pos_num, max_axial_pos_num + 1, 0, 1, 0, 1, 0, 3)); - - Array <4,float> Projall(IndexRange4D(min_axial_pos_num, max_axial_pos_num, 0, 1, 0, 1, 0, 3)); - Array <4,float> Projall2(IndexRange4D(min_axial_pos_num, max_axial_pos_num+1, 0, 1, 0, 1, 0, 3)); - // What to do when num_planes_per_axial_pos==2 ? - // In the 2D case, the approach followed in 3D is ill-defined, as we would be + // In the 2D case, the approach followed in 3D is ill-defined, as we would be // forward projecting right along the edges of the voxels. - // Instead, we take for the contribution to an axial_pos_num, + // Instead, we take for the contribution to an axial_pos_num, // 1/2 left_voxel + centre_voxel + 1/2 right_voxel - + int num_lors_per_virtual_ring = 2; - - if (num_planes_per_axial_pos == 1) - { + + if (num_planes_per_axial_pos == 1) { num_lors_per_virtual_ring = 1; } - - - - if (view == 0 || 4*view == nviews ) - { /* phi=0 or 45 */ - for (D = 0; D < C; D++) - { - if (min_abs_tangential_pos_num==0) - { - /* Here tang_pos_num=0 and phi=0 or 45*/ - { - if (proj_Siddon + + if (view == 0 || 4 * view == nviews) { /* phi=0 or 45 */ + for (D = 0; D < C; D++) { + if (min_abs_tangential_pos_num == 0) { + /* Here tang_pos_num=0 and phi=0 or 45*/ + { + if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <2>( + <2>( #else - (2, + (2, #endif - Projall, image, proj_data_info_sptr, cphi, sphi, - delta + D, 0, R,min_axial_pos_num, max_axial_pos_num, - 0.F/*==offset*/, num_planes_per_axial_pos, axial_pos_to_z_offset , - 1.F/num_lors_per_virtual_ring, - restrict_to_cylindrical_FOV)) - for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) - { - my_ax_pos0 = C * ax_pos0 + D; - - pos_view[my_ax_pos0][0] += Projall[ax_pos0][0][0][0]; - pos_plus90[my_ax_pos0][0] +=Projall[ax_pos0][0][0][2]; - } - } - - if (num_planes_per_axial_pos == 2) - { - if (proj_Siddon + Projall, image, proj_data_info_sptr, cphi, sphi, delta + D, 0, R, min_axial_pos_num, max_axial_pos_num, + 0.F /*==offset*/, num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / num_lors_per_virtual_ring, + restrict_to_cylindrical_FOV)) + for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + + pos_view[my_ax_pos0][0] += Projall[ax_pos0][0][0][0]; + pos_plus90[my_ax_pos0][0] += Projall[ax_pos0][0][0][2]; + } + } + + if (num_planes_per_axial_pos == 2) { + if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <2>( + <2>( #else - (2, + (2, #endif - Projall2, image, proj_data_info_sptr, cphi, sphi, - delta + D, 0, R, min_axial_pos_num, max_axial_pos_num+1, - -0.5F/*==offset*/, num_planes_per_axial_pos, axial_pos_to_z_offset , - 1.F/4, - restrict_to_cylindrical_FOV)) - for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) - { - my_ax_pos0 = C * ax_pos0 + D; - pos_view[my_ax_pos0][0] += (Projall2[ax_pos0+1][0][0][0]+ Projall2[ax_pos0][0][0][0]); - pos_plus90[my_ax_pos0][0] += (Projall2[ax_pos0+1][0][0][2]+ Projall2[ax_pos0][0][0][2]); - } - } - } - + Projall2, image, proj_data_info_sptr, cphi, sphi, delta + D, 0, R, min_axial_pos_num, max_axial_pos_num + 1, + -0.5F /*==offset*/, num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / 4, restrict_to_cylindrical_FOV)) + for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + pos_view[my_ax_pos0][0] += (Projall2[ax_pos0 + 1][0][0][0] + Projall2[ax_pos0][0][0][0]); + pos_plus90[my_ax_pos0][0] += (Projall2[ax_pos0 + 1][0][0][2] + Projall2[ax_pos0][0][0][2]); + } + } + } + /* Now tang_pos_num!=0 and phi=0 or 45 */ - for (tang_pos_num = min_tang_pos_num_in_loop; tang_pos_num <= max_abs_tangential_pos_num; tang_pos_num++) - { - bin.tangential_pos_num() = tang_pos_num; - const float s_in_mm = proj_data_info_sptr->get_s(bin); - + for (tang_pos_num = min_tang_pos_num_in_loop; tang_pos_num <= max_abs_tangential_pos_num; tang_pos_num++) { + bin.tangential_pos_num() = tang_pos_num; + const float s_in_mm = proj_data_info_sptr->get_s(bin); - { + { if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <1>( + <1>( #else - (1, + (1, #endif - Projall, image, proj_data_info_sptr, cphi, sphi, - delta + D, s_in_mm, R,min_axial_pos_num, max_axial_pos_num, - 0.F, num_planes_per_axial_pos, axial_pos_to_z_offset, - 1.F/num_lors_per_virtual_ring, - restrict_to_cylindrical_FOV)) - for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) - { - my_ax_pos0 = C * ax_pos0 + D; - if (tang_pos_num<=max_tangential_pos_num) - { - pos_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][0]; - pos_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][2]; - } - if (-tang_pos_num>=min_tangential_pos_num) - { - pos_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][0]; - pos_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][2]; - } - } + Projall, image, proj_data_info_sptr, cphi, sphi, delta + D, s_in_mm, R, min_axial_pos_num, max_axial_pos_num, + 0.F, num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / num_lors_per_virtual_ring, + restrict_to_cylindrical_FOV)) + for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + if (tang_pos_num <= max_tangential_pos_num) { + pos_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][0]; + pos_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][2]; + } + if (-tang_pos_num >= min_tangential_pos_num) { + pos_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][0]; + pos_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][2]; + } + } } - if (num_planes_per_axial_pos == 2) - { + if (num_planes_per_axial_pos == 2) { if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <1>( + <1>( #else - (1, + (1, #endif - Projall2, image, proj_data_info_sptr, cphi, sphi, - delta + D, s_in_mm, R,min_axial_pos_num, max_axial_pos_num+1, - -0.5F, num_planes_per_axial_pos, axial_pos_to_z_offset, - 1.F/4, - restrict_to_cylindrical_FOV)) - for (int ax_pos0 =min_axial_pos_num; ax_pos0 <=max_axial_pos_num; ax_pos0++) - { - my_ax_pos0 = C * ax_pos0 + D; - if (tang_pos_num<=max_tangential_pos_num) - { - pos_view[my_ax_pos0][tang_pos_num] +=(Projall2[ax_pos0][0][0][0]+Projall2[ax_pos0+1][0][0][0]); - pos_plus90[my_ax_pos0][tang_pos_num] += (Projall2[ax_pos0][0][0][2]+Projall2[ax_pos0+1][0][0][2]); - } - if (-tang_pos_num>=min_tangential_pos_num) - { - pos_view[my_ax_pos0][-tang_pos_num] +=(Projall2[ax_pos0][0][1][0]+Projall2[ax_pos0+1][0][1][0]); - pos_plus90[my_ax_pos0][-tang_pos_num] +=(Projall2[ax_pos0][0][1][2]+Projall2[ax_pos0+1][0][1][2]); - } - } + Projall2, image, proj_data_info_sptr, cphi, sphi, delta + D, s_in_mm, R, min_axial_pos_num, + max_axial_pos_num + 1, -0.5F, num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / 4, + restrict_to_cylindrical_FOV)) + for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + if (tang_pos_num <= max_tangential_pos_num) { + pos_view[my_ax_pos0][tang_pos_num] += (Projall2[ax_pos0][0][0][0] + Projall2[ax_pos0 + 1][0][0][0]); + pos_plus90[my_ax_pos0][tang_pos_num] += (Projall2[ax_pos0][0][0][2] + Projall2[ax_pos0 + 1][0][0][2]); + } + if (-tang_pos_num >= min_tangential_pos_num) { + pos_view[my_ax_pos0][-tang_pos_num] += (Projall2[ax_pos0][0][1][0] + Projall2[ax_pos0 + 1][0][1][0]); + pos_plus90[my_ax_pos0][-tang_pos_num] += (Projall2[ax_pos0][0][1][2] + Projall2[ax_pos0 + 1][0][1][2]); + } + } } - } // Loop over tang_pos_num - } // Loop over D - } - else - { - // general phi - for (D = 0; D < C; D++) - { - if (min_abs_tangential_pos_num==0) - { - /* Here tang_pos_num==0 and phi!=k*45 */ - { - if (proj_Siddon + } // Loop over tang_pos_num + } // Loop over D + } else { + // general phi + for (D = 0; D < C; D++) { + if (min_abs_tangential_pos_num == 0) { + /* Here tang_pos_num==0 and phi!=k*45 */ + { + if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <4>( + <4>( #else - (4, + (4, #endif - Projall, image, proj_data_info_sptr, cphi, sphi, - delta + D, 0, R,min_axial_pos_num, max_axial_pos_num, - 0.F, num_planes_per_axial_pos, axial_pos_to_z_offset , - 1.F/num_lors_per_virtual_ring, - restrict_to_cylindrical_FOV)) - for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) - { - my_ax_pos0 = C * ax_pos0 + D; - pos_view[my_ax_pos0][0] += Projall[ax_pos0][0][0][0]; - pos_min90[my_ax_pos0][0] += Projall[ax_pos0][0][0][1]; - pos_plus90[my_ax_pos0][0] += Projall[ax_pos0][0][0][2]; - pos_min180[my_ax_pos0][0] += Projall[ax_pos0][0][0][3]; - } - } - - if (num_planes_per_axial_pos == 2) - { - if (proj_Siddon + Projall, image, proj_data_info_sptr, cphi, sphi, delta + D, 0, R, min_axial_pos_num, max_axial_pos_num, 0.F, + num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / num_lors_per_virtual_ring, restrict_to_cylindrical_FOV)) + for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + pos_view[my_ax_pos0][0] += Projall[ax_pos0][0][0][0]; + pos_min90[my_ax_pos0][0] += Projall[ax_pos0][0][0][1]; + pos_plus90[my_ax_pos0][0] += Projall[ax_pos0][0][0][2]; + pos_min180[my_ax_pos0][0] += Projall[ax_pos0][0][0][3]; + } + } + + if (num_planes_per_axial_pos == 2) { + if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <4>( + <4>( #else - (4, + (4, #endif - Projall2, image, proj_data_info_sptr, cphi, sphi, - delta + D, 0, R,min_axial_pos_num, max_axial_pos_num, - -0.5F, num_planes_per_axial_pos, axial_pos_to_z_offset , - 1.F/4, - restrict_to_cylindrical_FOV)) - for (int ax_pos0 = min_axial_pos_num; ax_pos0 <=max_axial_pos_num; ax_pos0++) - { - my_ax_pos0 = C * ax_pos0 + D; - pos_view[my_ax_pos0][0] += (Projall2[ax_pos0][0][0][0]+Projall2[ax_pos0+1][0][0][0]); - pos_min90[my_ax_pos0][0] += (Projall2[ax_pos0][0][0][1]+Projall2[ax_pos0+1][0][0][1]); - pos_plus90[my_ax_pos0][0] +=(Projall2[ax_pos0][0][0][2]+Projall2[ax_pos0+1][0][0][2]); - pos_min180[my_ax_pos0][0] +=(Projall2[ax_pos0][0][0][3]+Projall2[ax_pos0+1][0][0][3]); - } - } - } - + Projall2, image, proj_data_info_sptr, cphi, sphi, delta + D, 0, R, min_axial_pos_num, max_axial_pos_num, -0.5F, + num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / 4, restrict_to_cylindrical_FOV)) + for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + pos_view[my_ax_pos0][0] += (Projall2[ax_pos0][0][0][0] + Projall2[ax_pos0 + 1][0][0][0]); + pos_min90[my_ax_pos0][0] += (Projall2[ax_pos0][0][0][1] + Projall2[ax_pos0 + 1][0][0][1]); + pos_plus90[my_ax_pos0][0] += (Projall2[ax_pos0][0][0][2] + Projall2[ax_pos0 + 1][0][0][2]); + pos_min180[my_ax_pos0][0] += (Projall2[ax_pos0][0][0][3] + Projall2[ax_pos0 + 1][0][0][3]); + } + } + } + /* Here tang_pos_num!=0 and phi!=k*45. */ - for (tang_pos_num = min_tang_pos_num_in_loop; tang_pos_num <= max_abs_tangential_pos_num; tang_pos_num++) - { - bin.tangential_pos_num() = tang_pos_num; - const float s_in_mm = proj_data_info_sptr->get_s(bin); + for (tang_pos_num = min_tang_pos_num_in_loop; tang_pos_num <= max_abs_tangential_pos_num; tang_pos_num++) { + bin.tangential_pos_num() = tang_pos_num; + const float s_in_mm = proj_data_info_sptr->get_s(bin); - { + { if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <3>( + <3>( #else - (3, + (3, #endif - Projall, image, proj_data_info_sptr, cphi, sphi, - delta + D, s_in_mm, R,min_axial_pos_num, max_axial_pos_num, - 0.F, num_planes_per_axial_pos, axial_pos_to_z_offset , - 1.F/num_lors_per_virtual_ring, - restrict_to_cylindrical_FOV)) - for (int ax_pos0 = min_axial_pos_num; ax_pos0<= max_axial_pos_num; ax_pos0++) - { - my_ax_pos0 = C * ax_pos0 + D; - if (tang_pos_num<=max_tangential_pos_num) - { - pos_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][0]; - pos_min90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][1]; - pos_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][2]; - pos_min180[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][3]; - } - if (-tang_pos_num>=min_tangential_pos_num) - { - pos_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][0]; - pos_min90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][1]; - pos_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][2]; - pos_min180[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][3]; - } - } - } - if (num_planes_per_axial_pos == 2) - { - if (proj_Siddon + Projall, image, proj_data_info_sptr, cphi, sphi, delta + D, s_in_mm, R, min_axial_pos_num, max_axial_pos_num, + 0.F, num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / num_lors_per_virtual_ring, + restrict_to_cylindrical_FOV)) + for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + if (tang_pos_num <= max_tangential_pos_num) { + pos_view[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][0]; + pos_min90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][1]; + pos_plus90[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][2]; + pos_min180[my_ax_pos0][tang_pos_num] += Projall[ax_pos0][0][0][3]; + } + if (-tang_pos_num >= min_tangential_pos_num) { + pos_view[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][0]; + pos_min90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][1]; + pos_plus90[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][2]; + pos_min180[my_ax_pos0][-tang_pos_num] += Projall[ax_pos0][0][1][3]; + } + } + } + if (num_planes_per_axial_pos == 2) { + if (proj_Siddon #ifndef STIR_SIDDON_NO_TEMPLATE - <3>( + <3>( #else - (3, + (3, #endif - Projall2, image, proj_data_info_sptr, cphi, sphi, - delta + D, s_in_mm, R,min_axial_pos_num, max_axial_pos_num+1, - -0.5F, num_planes_per_axial_pos, axial_pos_to_z_offset , - 1.F/4, - restrict_to_cylindrical_FOV)) - for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) - { - my_ax_pos0 = C * ax_pos0 + D; - if (tang_pos_num<=max_tangential_pos_num) - { - pos_view[ my_ax_pos0][tang_pos_num] +=(Projall2[ax_pos0][0][0][0]+Projall2[ax_pos0+1][0][0][0]); - pos_min90[my_ax_pos0][tang_pos_num] += (Projall2[ax_pos0][0][0][1]+Projall2[ax_pos0+1][0][0][1]); - pos_plus90[ my_ax_pos0][tang_pos_num] +=(Projall2[ax_pos0][0][0][2]+Projall2[ax_pos0+1][0][0][2]); - pos_min180[ my_ax_pos0][tang_pos_num] += (Projall2[ax_pos0][0][0][3]+Projall2[ax_pos0+1][0][0][3]); - } - if (-tang_pos_num>=min_tangential_pos_num) - { - pos_view[ my_ax_pos0][-tang_pos_num] += (Projall2[ax_pos0][0][1][0] +Projall2[ax_pos0+1][0][1][0]); - pos_min90[ my_ax_pos0][-tang_pos_num] +=(Projall2[ax_pos0][0][1][1]+Projall2[ax_pos0+1][0][1][1]); - pos_plus90[ my_ax_pos0][-tang_pos_num] += (Projall2[ax_pos0][0][1][2]+ Projall2[ax_pos0+1][0][1][2]); - pos_min180[ my_ax_pos0][-tang_pos_num] += ( Projall2[ax_pos0][0][1][3]+ Projall2[ax_pos0+1][0][1][3]); - } - } - } - - }// end of loop over tang_pos_num - - }// end loop over D - }// end of else - + Projall2, image, proj_data_info_sptr, cphi, sphi, delta + D, s_in_mm, R, min_axial_pos_num, + max_axial_pos_num + 1, -0.5F, num_planes_per_axial_pos, axial_pos_to_z_offset, 1.F / 4, + restrict_to_cylindrical_FOV)) + for (int ax_pos0 = min_axial_pos_num; ax_pos0 <= max_axial_pos_num; ax_pos0++) { + my_ax_pos0 = C * ax_pos0 + D; + if (tang_pos_num <= max_tangential_pos_num) { + pos_view[my_ax_pos0][tang_pos_num] += (Projall2[ax_pos0][0][0][0] + Projall2[ax_pos0 + 1][0][0][0]); + pos_min90[my_ax_pos0][tang_pos_num] += (Projall2[ax_pos0][0][0][1] + Projall2[ax_pos0 + 1][0][0][1]); + pos_plus90[my_ax_pos0][tang_pos_num] += (Projall2[ax_pos0][0][0][2] + Projall2[ax_pos0 + 1][0][0][2]); + pos_min180[my_ax_pos0][tang_pos_num] += (Projall2[ax_pos0][0][0][3] + Projall2[ax_pos0 + 1][0][0][3]); + } + if (-tang_pos_num >= min_tangential_pos_num) { + pos_view[my_ax_pos0][-tang_pos_num] += (Projall2[ax_pos0][0][1][0] + Projall2[ax_pos0 + 1][0][1][0]); + pos_min90[my_ax_pos0][-tang_pos_num] += (Projall2[ax_pos0][0][1][1] + Projall2[ax_pos0 + 1][0][1][1]); + pos_plus90[my_ax_pos0][-tang_pos_num] += (Projall2[ax_pos0][0][1][2] + Projall2[ax_pos0 + 1][0][1][2]); + pos_min180[my_ax_pos0][-tang_pos_num] += (Projall2[ax_pos0][0][1][3] + Projall2[ax_pos0 + 1][0][1][3]); + } + } + } + + } // end of loop over tang_pos_num + + } // end loop over D + } // end of else + stop_timers(); } +#if 0 // disabled as currently not used. needs to be written in the new style anyway +void +ForwardProjectorByBinUsingRayTracing:: + actual_forward_project(Bin& this_bin, + const DiscretisedDensity<3,float>& density) +{ + error("ForwardProjectorByBinUsingRayTracing does not support single-bin forward projection. Abort."); +} +#endif END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing_Siddon.cxx b/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing_Siddon.cxx index 59d461673b..4e08164546 100644 --- a/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing_Siddon.cxx +++ b/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing_Siddon.cxx @@ -67,15 +67,15 @@ using std::max; START_NAMESPACE_STIR template -static inline int sign(const T& t) -{ - return t<0 ? -1 : 1; +static inline int +sign(const T& t) { + return t < 0 ? -1 : 1; } /*! This function uses a 3D version of Siddon's algorithm for forward projecting. See M. Egger's thesis for details. - In addition to the symmetries is segment and view, it also uses s,-s symmetry + In addition to the symmetries is segment and view, it also uses s,-s symmetry (while being careful when s=0 to avoid self-symmetric cases) For historical reasons, 'axial_pos_num' is here called 'ring'. rmin,rmax are @@ -84,31 +84,23 @@ static inline int sign(const T& t) See RayTraceVoxelsOnCartesianGrid for a shorter and clearer version of the Siddon algorithm. */ - // KT 20/06/2001 should now work for non-arccorrected data as well, pass s_in_mm #ifndef STIR_SIDDON_NO_TEMPLATE template #endif bool -ForwardProjectorByBinUsingRayTracing:: -proj_Siddon( +ForwardProjectorByBinUsingRayTracing::proj_Siddon( #ifdef STIR_SIDDON_NO_TEMPLATE - int Siddon, + int Siddon, #endif - Array <4,float> & Projptr, const VoxelsOnCartesianGrid &Bild, - const shared_ptr proj_data_info_sptr, - const float cphi, const float sphi, const float delta, const - float s_in_mm, - const float R, const int rmin, const int rmax, const float offset, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset, - const float norm_factor, - const bool restrict_to_cylindrical_FOV) -{ + Array<4, float>& Projptr, const VoxelsOnCartesianGrid& Bild, + const shared_ptr proj_data_info_sptr, const float cphi, const float sphi, const float delta, + const float s_in_mm, const float R, const int rmin, const int rmax, const float offset, const int num_planes_per_axial_pos, + const float axial_pos_to_z_offset, const float norm_factor, const bool restrict_to_cylindrical_FOV) { /* - * Siddon == 1 => Phiplus90_r0ab + * Siddon == 1 => Phiplus90_r0ab * Siddon == 2 => Phiplus90s0_r0ab - * Siddon == 3 => Symall_r0ab + * Siddon == 3 => Symall_r0ab * Siddon == 4 => s0_r0ab */ @@ -122,15 +114,13 @@ proj_Siddon( having been applied first, so the end_point-start_point coordinates always have particular signs. In the notation of RayTraceVoxelsOnCartesianGrid(): */ - const int sign_x=-1; - const int sign_y=+1; - const int sign_z=+1; + const int sign_x = -1; + const int sign_y = +1; + const int sign_z = +1; // in our current coordinate system, the following constant is always 2 const int num_planes_per_physical_ring = 2; - assert(fabs(Bild.get_voxel_size().z() * num_planes_per_physical_ring/ proj_data_info_sptr->get_ring_spacing() -1) < 10E-4); - - + assert(fabs(Bild.get_voxel_size().z() * num_planes_per_physical_ring / proj_data_info_sptr->get_ring_spacing() - 1) < 10E-4); #ifdef NEWSCALE /* KT 16/02/98 removed division by voxel_size.x() to get line integrals in mm @@ -143,112 +133,102 @@ proj_Siddon( // KT 1/12/2003 no longer subtract -1 as determination of first and last voxel is now // no longer sensitive to rounding error - const float fovrad_in_mm = - min((min(Bild.get_max_x(), -Bild.get_min_x()))*Bild.get_voxel_size().x(), - (min(Bild.get_max_y(), -Bild.get_min_y()))*Bild.get_voxel_size().y()); + const float fovrad_in_mm = min((min(Bild.get_max_x(), -Bild.get_min_x())) * Bild.get_voxel_size().x(), + (min(Bild.get_max_y(), -Bild.get_min_y())) * Bild.get_voxel_size().y()); const CartesianCoordinate3D& voxel_size = Bild.get_voxel_size(); - CartesianCoordinate3D start_point; + CartesianCoordinate3D start_point; CartesianCoordinate3D stop_point; { /* parametrisation of LOR is - X= s*cphi + a*sphi, - Y= s*sphi - a*cphi, + X= s*cphi + a*sphi, + Y= s*sphi - a*cphi, // Z= t/costheta+offset_in_z - a*tantheta Z= num_planes_per_axial_pos * (rmin + offset) + axial_pos_to_z_offset + + num_planes_per_physical_ring * delta/2 * (1 - a / TMP); - with TMP = sqrt(R*R - square(s_in_mm)); - The Z parametrisation can be understood by noting that at a=TMP, the LOR - intersects the detector cylinder with radius R. + with TMP = sqrt(R*R - square(s_in_mm)); + The Z parametrisation can be understood by noting that at a=TMP, the LOR + intersects the detector cylinder with radius R. - find now min_a, max_a such that end-points intersect border of FOV + find now min_a, max_a such that end-points intersect border of FOV */ float max_a; float min_a; - - if (restrict_to_cylindrical_FOV) - { - if (fabs(s_in_mm) >= fovrad_in_mm) - return false; - // a has to be such that X^2+Y^2 == fovrad^2 + + if (restrict_to_cylindrical_FOV) { + if (fabs(s_in_mm) >= fovrad_in_mm) + return false; + // a has to be such that X^2+Y^2 == fovrad^2 max_a = sqrt(square(fovrad_in_mm) - square(s_in_mm)); min_a = -max_a; } // restrict_to_cylindrical_FOV - else - { + else { // use FOV which is square. // note that we use square and not rectangular as otherwise symmetries // would take us out of the FOV. TODO /* - a has to be such that + a has to be such that |X| <= fovrad_in_mm && |Y| <= fovrad_in_mm */ - if (fabs(cphi) < 1.E-3 || fabs(sphi) < 1.E-3) - { + if (fabs(cphi) < 1.E-3 || fabs(sphi) < 1.E-3) { if (fovrad_in_mm < fabs(s_in_mm)) return false; max_a = fovrad_in_mm; min_a = -fovrad_in_mm; - } - else - { - max_a = min((fovrad_in_mm*sign(sphi) - s_in_mm*cphi)/sphi, - (fovrad_in_mm*sign(cphi) + s_in_mm*sphi)/cphi); - min_a = max((-fovrad_in_mm*sign(sphi) - s_in_mm*cphi)/sphi, - (-fovrad_in_mm*sign(cphi) + s_in_mm*sphi)/cphi); - if (min_a > max_a - 1.E-3*voxel_size.x()) + } else { + max_a = min((fovrad_in_mm * sign(sphi) - s_in_mm * cphi) / sphi, (fovrad_in_mm * sign(cphi) + s_in_mm * sphi) / cphi); + min_a = max((-fovrad_in_mm * sign(sphi) - s_in_mm * cphi) / sphi, (-fovrad_in_mm * sign(cphi) + s_in_mm * sphi) / cphi); + if (min_a > max_a - 1.E-3 * voxel_size.x()) return false; } - - } //!restrict_to_cylindrical_FOV - const float TMP = sqrt(R*R - square(s_in_mm)); - - start_point.x() = (s_in_mm*cphi + max_a*sphi)/voxel_size.x(); - start_point.y() = (s_in_mm*sphi - max_a*cphi)/voxel_size.y(); - //start_point.z() = (t_in_mm/costheta+offset_in_z - max_a*tantheta)/voxel_size.z(); + + } //! restrict_to_cylindrical_FOV + const float TMP = sqrt(R * R - square(s_in_mm)); + + start_point.x() = (s_in_mm * cphi + max_a * sphi) / voxel_size.x(); + start_point.y() = (s_in_mm * sphi - max_a * cphi) / voxel_size.y(); + // start_point.z() = (t_in_mm/costheta+offset_in_z - max_a*tantheta)/voxel_size.z(); start_point.z() = num_planes_per_axial_pos * (rmin + offset) + axial_pos_to_z_offset + - + num_planes_per_physical_ring * delta/2 * (1 - max_a / TMP); + +num_planes_per_physical_ring * delta / 2 * (1 - max_a / TMP); - stop_point.x() = (s_in_mm*cphi + min_a*sphi)/voxel_size.x(); - stop_point.y() = (s_in_mm*sphi - min_a*cphi)/voxel_size.y(); - //stop_point.z() = (t_in_mm/costheta+offset_in_z - min_a*tantheta)/voxel_size.z(); - stop_point.z() = num_planes_per_axial_pos * (rmin + offset) + axial_pos_to_z_offset + - + num_planes_per_physical_ring * delta/2 * (1 - min_a / TMP); + stop_point.x() = (s_in_mm * cphi + min_a * sphi) / voxel_size.x(); + stop_point.y() = (s_in_mm * sphi - min_a * cphi) / voxel_size.y(); + // stop_point.z() = (t_in_mm/costheta+offset_in_z - min_a*tantheta)/voxel_size.z(); + stop_point.z() = num_planes_per_axial_pos * (rmin + offset) + axial_pos_to_z_offset + + +num_planes_per_physical_ring * delta / 2 * (1 - min_a / TMP); } // find voxel which contains the start_point, and go to its 'left' edge - const float xmin = round(start_point.x()) - sign_x*0.5F; - const float ymin = round(start_point.y()) - sign_y*0.5F; - const float zmin = round(start_point.z()) - sign_z*0.5F; + const float xmin = round(start_point.x()) - sign_x * 0.5F; + const float ymin = round(start_point.y()) - sign_y * 0.5F; + const float zmin = round(start_point.z()) - sign_z * 0.5F; // find voxel which contains the end_point, and go to its 'right' edge - const float xmax = round(stop_point.x()) + sign_x*0.5F; - const float ymax = round(stop_point.y()) + sign_y*0.5F; - const float zmax = round(stop_point.z()) + sign_z*0.5F; + const float xmax = round(stop_point.x()) + sign_x * 0.5F; + const float ymax = round(stop_point.y()) + sign_y * 0.5F; + const float zmax = round(stop_point.z()) + sign_z * 0.5F; - const CartesianCoordinate3D difference = stop_point-start_point; + const CartesianCoordinate3D difference = stop_point - start_point; assert(difference.x() <= .00001F); assert(difference.y() >= -.00001F); assert(difference.z() >= -.00001F); const float small_difference = 1.E-5F; - const bool zero_diff_in_x = fabs(difference.x())<=small_difference; - const bool zero_diff_in_y = fabs(difference.y())<=small_difference; - const bool zero_diff_in_z = fabs(difference.z())<=small_difference; + const bool zero_diff_in_x = fabs(difference.x()) <= small_difference; + const bool zero_diff_in_y = fabs(difference.y()) <= small_difference; + const bool zero_diff_in_z = fabs(difference.z()) <= small_difference; // d12 is distance between the 2 points (times normalisation_const) - const float d12 = - static_cast(norm(difference*Bild.get_voxel_size()) * normalisation_constant); - // KT 16/02/98 multiply with d12 to get normalisation right from the start - const float inc_x = (zero_diff_in_x) ? 1000000.F*d12 : d12 / (sign_x*difference.x()); - const float inc_y = (zero_diff_in_y) ? 1000000.F*d12 : d12 / (sign_y*difference.y()); - const float inc_z = (zero_diff_in_z) ? 1000000.F*d12 : d12 / (sign_z*difference.z()); - + const float d12 = static_cast(norm(difference * Bild.get_voxel_size()) * normalisation_constant); + // KT 16/02/98 multiply with d12 to get normalisation right from the start + const float inc_x = (zero_diff_in_x) ? 1000000.F * d12 : d12 / (sign_x * difference.x()); + const float inc_y = (zero_diff_in_y) ? 1000000.F * d12 : d12 / (sign_y * difference.y()); + const float inc_z = (zero_diff_in_z) ? 1000000.F * d12 : d12 / (sign_z * difference.z()); /* Find the a? values of the intersection points of the LOR with the planes between voxels. Note on special handling of rays parallel to one of the planes: - + The corresponding a? value would be -infinity. We just set it to - a value low enough such that the start value of 'a' is not compromised + a value low enough such that the start value of 'a' is not compromised further on. Normally a? = (?min-start_point.?) * inc_? * sign_? @@ -269,7 +249,7 @@ proj_Siddon( /* The smallest a? value, gives the end of the 'a'-row */ /* (Note: doc is copied from RayTraceVoxelsOnCartesianGrid. Would need to be adapted a bit) - Find a?end for the last intersections with the coordinate planes. + Find a?end for the last intersections with the coordinate planes. amax will then be the smallest of all these a?end. If the LOR is parallel to a plane, take care that its a?end is larger than all the others. @@ -278,37 +258,35 @@ proj_Siddon( In fact, we will take a?end slightly smaller than the actual last value (i.e. we multiply with a factor .9999). This is to avoid rounding errors in the loop below. In this loop, we try to detect the end of the LOR by comparing a (which is either ax,ay or az) with - aend. With exact arithmetic, a? would have been incremented exactly to - a?_end_actual = a?start + (?max-?end)*inc_?*sign_?, + aend. With exact arithmetic, a? would have been incremented exactly to + a?_end_actual = a?start + (?max-?end)*inc_?*sign_?, so we could loop until a==aend_actual. However, because of numerical precision, - a? might turn out be a tiny bit smaller then a?_end_actual. So, we set aend a + a? might turn out be a tiny bit smaller then a?_end_actual. So, we set aend a (somewhat less tiny) bit smaller than aend_actual, and loop while (a= 0 && Zdup <= maxplane) { - Projptr[ring0][0][0][0] += d * Bild[Zdup][Y][X]; - Projptr[ring0][0][0][2] += d * Bild[Zdup][X][-Y]; - if ((Siddon == 4) || (Siddon == 3)) { - Projptr[ring0][1][0][1] += d * Bild[Zdup][X][Y]; - Projptr[ring0][1][0][3] += d * Bild[Zdup][Y][-X]; - } - if ((Siddon == 1) || (Siddon == 3)) { - Projptr[ring0][1][1][0] += d * Bild[Zdup][-Y][-X]; - Projptr[ring0][1][1][2] += d * Bild[Zdup][-X][Y]; - } - if (Siddon == 3) { - Projptr[ring0][0][1][1] += d * Bild[Zdup][-X][-Y]; - Projptr[ring0][0][1][3] += d * Bild[Zdup][-Y][X]; - } - } - if (Qdup >= 0 && Qdup <= maxplane) { - if ((Siddon == 4) || (Siddon == 3)) { - Projptr[ring0][0][0][1] += d * Bild[Qdup][X][Y]; - Projptr[ring0][0][0][3] += d * Bild[Qdup][Y][-X]; - } - if ((Siddon == 1) || (Siddon == 3)) { - Projptr[ring0][0][1][0] += d * Bild[Qdup][-Y][-X]; - Projptr[ring0][0][1][2] += d * Bild[Qdup][-X][Y]; - } - if (Siddon == 3) { - Projptr[ring0][1][1][1] += d * Bild[Qdup][-X][-Y]; - Projptr[ring0][1][1][3] += d * Bild[Qdup][-Y][X]; - } - Projptr[ring0][1][0][0] += d * Bild[Qdup][Y][X]; - Projptr[ring0][1][0][2] += d * Bild[Qdup][X][-Y]; - } - - } - a = ax ; ax += inc_x; - X--; - } else { /* LOR leaves voxel through xy-plane */ - const float d = az - a; - int Zdup = Z; - int Qdup = Q; - for (int ring0 = rmin; - ring0 <= rmax; - ring0++, Zdup += num_planes_per_axial_pos, Qdup +=num_planes_per_axial_pos ) - { - /* all symmetries except in 's'*/ - if (Zdup >= 0 && Zdup <= maxplane) { - Projptr[ring0][0][0][0] += d * Bild[Zdup][Y][X]; - Projptr[ring0][0][0][2] += d * Bild[Zdup][X][-Y]; - if ((Siddon == 4) || (Siddon == 3)) { - Projptr[ring0][1][0][1] += d * Bild[Zdup][X][Y]; - Projptr[ring0][1][0][3] += d * Bild[Zdup][Y][-X]; - } - if ((Siddon == 1) || (Siddon == 3)) { - Projptr[ring0][1][1][0] += d * Bild[Zdup][-Y][-X]; - Projptr[ring0][1][1][2] += d * Bild[Zdup][-X][Y]; - } - if (Siddon == 3) { - Projptr[ring0][0][1][1] += d * Bild[Zdup][-X][-Y]; - Projptr[ring0][0][1][3] += d * Bild[Zdup][-Y][X]; - - } - } - if (Qdup >= 0 && Qdup <= maxplane) { - if ((Siddon == 4) || (Siddon == 3)) { - Projptr[ring0][0][0][1] += d * Bild[Qdup][X][Y]; - Projptr[ring0][0][0][3] += d * Bild[Qdup][Y][-X]; - } - if ((Siddon == 1) || (Siddon == 3)) { - Projptr[ring0][0][1][0] += d * Bild[Qdup][-Y][-X]; - Projptr[ring0][0][1][2] += d * Bild[Qdup][-X][Y]; - } - if (Siddon == 3) { - Projptr[ring0][1][1][1] += d * Bild[Qdup][-X][-Y]; - Projptr[ring0][1][1][3] += d * Bild[Qdup][-Y][X]; - } - Projptr[ring0][1][0][0] += d * Bild[Qdup][Y][X]; - Projptr[ring0][1][0][2] += d * Bild[Qdup][X][-Y]; - } - - } - a = az ; az += inc_z; - Z++; - Q--; + if (ax < az) { /* LOR leaves voxel through yz-plane */ + const float d = ax - a; + int Zdup = Z; + int Qdup = Q; + for (int ring0 = rmin; ring0 <= rmax; ring0++, Zdup += num_planes_per_axial_pos, Qdup += num_planes_per_axial_pos) { + /* Alle Symetrien ausser s */ + if (Zdup >= 0 && Zdup <= maxplane) { + Projptr[ring0][0][0][0] += d * Bild[Zdup][Y][X]; + Projptr[ring0][0][0][2] += d * Bild[Zdup][X][-Y]; + if ((Siddon == 4) || (Siddon == 3)) { + Projptr[ring0][1][0][1] += d * Bild[Zdup][X][Y]; + Projptr[ring0][1][0][3] += d * Bild[Zdup][Y][-X]; + } + if ((Siddon == 1) || (Siddon == 3)) { + Projptr[ring0][1][1][0] += d * Bild[Zdup][-Y][-X]; + Projptr[ring0][1][1][2] += d * Bild[Zdup][-X][Y]; + } + if (Siddon == 3) { + Projptr[ring0][0][1][1] += d * Bild[Zdup][-X][-Y]; + Projptr[ring0][0][1][3] += d * Bild[Zdup][-Y][X]; + } + } + if (Qdup >= 0 && Qdup <= maxplane) { + if ((Siddon == 4) || (Siddon == 3)) { + Projptr[ring0][0][0][1] += d * Bild[Qdup][X][Y]; + Projptr[ring0][0][0][3] += d * Bild[Qdup][Y][-X]; + } + if ((Siddon == 1) || (Siddon == 3)) { + Projptr[ring0][0][1][0] += d * Bild[Qdup][-Y][-X]; + Projptr[ring0][0][1][2] += d * Bild[Qdup][-X][Y]; + } + if (Siddon == 3) { + Projptr[ring0][1][1][1] += d * Bild[Qdup][-X][-Y]; + Projptr[ring0][1][1][3] += d * Bild[Qdup][-Y][X]; + } + Projptr[ring0][1][0][0] += d * Bild[Qdup][Y][X]; + Projptr[ring0][1][0][2] += d * Bild[Qdup][X][-Y]; + } + } + a = ax; + ax += inc_x; + X--; + } else { /* LOR leaves voxel through xy-plane */ + const float d = az - a; + int Zdup = Z; + int Qdup = Q; + for (int ring0 = rmin; ring0 <= rmax; ring0++, Zdup += num_planes_per_axial_pos, Qdup += num_planes_per_axial_pos) { + /* all symmetries except in 's'*/ + if (Zdup >= 0 && Zdup <= maxplane) { + Projptr[ring0][0][0][0] += d * Bild[Zdup][Y][X]; + Projptr[ring0][0][0][2] += d * Bild[Zdup][X][-Y]; + if ((Siddon == 4) || (Siddon == 3)) { + Projptr[ring0][1][0][1] += d * Bild[Zdup][X][Y]; + Projptr[ring0][1][0][3] += d * Bild[Zdup][Y][-X]; + } + if ((Siddon == 1) || (Siddon == 3)) { + Projptr[ring0][1][1][0] += d * Bild[Zdup][-Y][-X]; + Projptr[ring0][1][1][2] += d * Bild[Zdup][-X][Y]; + } + if (Siddon == 3) { + Projptr[ring0][0][1][1] += d * Bild[Zdup][-X][-Y]; + Projptr[ring0][0][1][3] += d * Bild[Zdup][-Y][X]; + } + } + if (Qdup >= 0 && Qdup <= maxplane) { + if ((Siddon == 4) || (Siddon == 3)) { + Projptr[ring0][0][0][1] += d * Bild[Qdup][X][Y]; + Projptr[ring0][0][0][3] += d * Bild[Qdup][Y][-X]; + } + if ((Siddon == 1) || (Siddon == 3)) { + Projptr[ring0][0][1][0] += d * Bild[Qdup][-Y][-X]; + Projptr[ring0][0][1][2] += d * Bild[Qdup][-X][Y]; + } + if (Siddon == 3) { + Projptr[ring0][1][1][1] += d * Bild[Qdup][-X][-Y]; + Projptr[ring0][1][1][3] += d * Bild[Qdup][-Y][X]; + } + Projptr[ring0][1][0][0] += d * Bild[Qdup][Y][X]; + Projptr[ring0][1][0][2] += d * Bild[Qdup][X][-Y]; + } + } + a = az; + az += inc_z; + Z++; + Q--; } - else if (ay < az) { /* LOR leaves voxel through xz-plane */ + else if (ay < az) { /* LOR leaves voxel through xz-plane */ const float d = ay - a; int Zdup = Z; int Qdup = Q; - for (int ring0 = rmin; - ring0 <= rmax; - ring0++, Zdup += num_planes_per_axial_pos, Qdup +=num_planes_per_axial_pos ) - { - /* all symmetries except in 's' */ - if (Zdup >= 0 && Zdup <= maxplane) { - Projptr[ring0][0][0][0] += d * Bild[Zdup][Y][X]; - Projptr[ring0][0][0][2] += d * Bild[Zdup][X][-Y]; - if ((Siddon == 4) || (Siddon == 3)) { - Projptr[ring0][1][0][1] += d * Bild[Zdup][X][Y]; - Projptr[ring0][1][0][3] += d * Bild[Zdup][Y][-X]; - } - if ((Siddon == 1) || (Siddon == 3)) { - Projptr[ring0][1][1][0] += d * Bild[Zdup][-Y][-X]; - Projptr[ring0][1][1][2] += d * Bild[Zdup][-X][Y]; - } - if (Siddon == 3) { - Projptr[ring0][0][1][1] += d * Bild[Zdup][-X][-Y]; - Projptr[ring0][0][1][3] += d * Bild[Zdup][-Y][X]; - } - } - if (Qdup >= 0 && Qdup <= maxplane) { - if ((Siddon == 4) || (Siddon == 3)) { - Projptr[ring0][0][0][1] += d * Bild[Qdup][X][Y]; - Projptr[ring0][0][0][3] += d * Bild[Qdup][Y][-X]; - } - if ((Siddon == 1) || (Siddon == 3)) { - Projptr[ring0][0][1][0] += d * Bild[Qdup][-Y][-X]; - Projptr[ring0][0][1][2] += d * Bild[Qdup][-X][Y]; - } - if (Siddon == 3) { - Projptr[ring0][1][1][1] += d * Bild[Qdup][-X][-Y]; - Projptr[ring0][1][1][3] += d * Bild[Qdup][-Y][X]; - } - Projptr[ring0][1][0][0] += d * Bild[Qdup][Y][X]; - Projptr[ring0][1][0][2] += d * Bild[Qdup][X][-Y]; - } - + for (int ring0 = rmin; ring0 <= rmax; ring0++, Zdup += num_planes_per_axial_pos, Qdup += num_planes_per_axial_pos) { + /* all symmetries except in 's' */ + if (Zdup >= 0 && Zdup <= maxplane) { + Projptr[ring0][0][0][0] += d * Bild[Zdup][Y][X]; + Projptr[ring0][0][0][2] += d * Bild[Zdup][X][-Y]; + if ((Siddon == 4) || (Siddon == 3)) { + Projptr[ring0][1][0][1] += d * Bild[Zdup][X][Y]; + Projptr[ring0][1][0][3] += d * Bild[Zdup][Y][-X]; + } + if ((Siddon == 1) || (Siddon == 3)) { + Projptr[ring0][1][1][0] += d * Bild[Zdup][-Y][-X]; + Projptr[ring0][1][1][2] += d * Bild[Zdup][-X][Y]; + } + if (Siddon == 3) { + Projptr[ring0][0][1][1] += d * Bild[Zdup][-X][-Y]; + Projptr[ring0][0][1][3] += d * Bild[Zdup][-Y][X]; + } + } + if (Qdup >= 0 && Qdup <= maxplane) { + if ((Siddon == 4) || (Siddon == 3)) { + Projptr[ring0][0][0][1] += d * Bild[Qdup][X][Y]; + Projptr[ring0][0][0][3] += d * Bild[Qdup][Y][-X]; + } + if ((Siddon == 1) || (Siddon == 3)) { + Projptr[ring0][0][1][0] += d * Bild[Qdup][-Y][-X]; + Projptr[ring0][0][1][2] += d * Bild[Qdup][-X][Y]; + } + if (Siddon == 3) { + Projptr[ring0][1][1][1] += d * Bild[Qdup][-X][-Y]; + Projptr[ring0][1][1][3] += d * Bild[Qdup][-Y][X]; + } + Projptr[ring0][1][0][0] += d * Bild[Qdup][Y][X]; + Projptr[ring0][1][0][2] += d * Bild[Qdup][X][-Y]; + } } - a = ay; ay += inc_y; + a = ay; + ay += inc_y; Y++; - } else {/* LOR leaves voxel through xy-plane */ + } else { /* LOR leaves voxel through xy-plane */ const float d = az - a; int Zdup = Z; int Qdup = Q; - for (int ring0 = rmin; - ring0 <= rmax; - ring0++, Zdup += num_planes_per_axial_pos, Qdup +=num_planes_per_axial_pos ) - { - /* all symmetries except in 's' */ - if (Zdup >= 0 && Zdup <= maxplane) { - Projptr[ring0][0][0][0] += d * Bild[Zdup][Y][X]; - Projptr[ring0][0][0][2] += d * Bild[Zdup][X][-Y]; - if ((Siddon == 4) || (Siddon == 3)) { - Projptr[ring0][1][0][1] += d * Bild[Zdup][X][Y]; - Projptr[ring0][1][0][3] += d * Bild[Zdup][Y][-X]; - } - if ((Siddon == 1) || (Siddon == 3)) { - Projptr[ring0][1][1][0] += d * Bild[Zdup][-Y][-X]; - Projptr[ring0][1][1][2] += d * Bild[Zdup][-X][Y]; - } - if (Siddon == 3) { - Projptr[ring0][0][1][1] += d * Bild[Zdup][-X][-Y]; - Projptr[ring0][0][1][3] += d * Bild[Zdup][-Y][X]; - } - } - if (Qdup >= 0 && Qdup <= maxplane) { - if ((Siddon == 4) || (Siddon == 3)) { - Projptr[ring0][0][0][1] += d * Bild[Qdup][X][Y]; - Projptr[ring0][0][0][3] += d * Bild[Qdup][Y][-X]; - } - if ((Siddon == 1) || (Siddon == 3)) { - Projptr[ring0][0][1][0] += d * Bild[Qdup][-Y][-X]; - Projptr[ring0][0][1][2] += d * Bild[Qdup][-X][Y]; - } - if (Siddon == 3) { - Projptr[ring0][1][1][1] += d * Bild[Qdup][-X][-Y]; - Projptr[ring0][1][1][3] += d * Bild[Qdup][-Y][X]; - } - Projptr[ring0][1][0][0] += d * Bild[Qdup][Y][X]; - Projptr[ring0][1][0][2] += d * Bild[Qdup][X][-Y]; - } - + for (int ring0 = rmin; ring0 <= rmax; ring0++, Zdup += num_planes_per_axial_pos, Qdup += num_planes_per_axial_pos) { + /* all symmetries except in 's' */ + if (Zdup >= 0 && Zdup <= maxplane) { + Projptr[ring0][0][0][0] += d * Bild[Zdup][Y][X]; + Projptr[ring0][0][0][2] += d * Bild[Zdup][X][-Y]; + if ((Siddon == 4) || (Siddon == 3)) { + Projptr[ring0][1][0][1] += d * Bild[Zdup][X][Y]; + Projptr[ring0][1][0][3] += d * Bild[Zdup][Y][-X]; + } + if ((Siddon == 1) || (Siddon == 3)) { + Projptr[ring0][1][1][0] += d * Bild[Zdup][-Y][-X]; + Projptr[ring0][1][1][2] += d * Bild[Zdup][-X][Y]; + } + if (Siddon == 3) { + Projptr[ring0][0][1][1] += d * Bild[Zdup][-X][-Y]; + Projptr[ring0][0][1][3] += d * Bild[Zdup][-Y][X]; + } + } + if (Qdup >= 0 && Qdup <= maxplane) { + if ((Siddon == 4) || (Siddon == 3)) { + Projptr[ring0][0][0][1] += d * Bild[Qdup][X][Y]; + Projptr[ring0][0][0][3] += d * Bild[Qdup][Y][-X]; + } + if ((Siddon == 1) || (Siddon == 3)) { + Projptr[ring0][0][1][0] += d * Bild[Qdup][-Y][-X]; + Projptr[ring0][0][1][2] += d * Bild[Qdup][-X][Y]; + } + if (Siddon == 3) { + Projptr[ring0][1][1][1] += d * Bild[Qdup][-X][-Y]; + Projptr[ring0][1][1][3] += d * Bild[Qdup][-Y][X]; + } + Projptr[ring0][1][0][0] += d * Bild[Qdup][Y][X]; + Projptr[ring0][1][0][2] += d * Bild[Qdup][X][-Y]; + } } - a = az ; az += inc_z; + a = az; + az += inc_z; Z++; Q--; } - } /* Ende while (a(Array<4,float> &Projptr, const VoxelsOnCartesianGrid &, - const shared_ptr proj_data_info_sptr, - const float cphi, const float sphi, const float delta, - const float s_in_mm, - const float R, const int min_ax_pos_num, const int max_ax_pos_num, const float offset, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset, - const float norm_factor, - const bool restrict_to_cylindrical_FOV); - - -template -bool -ForwardProjectorByBinUsingRayTracing:: -proj_Siddon<2>(Array<4,float> &Projptr, const VoxelsOnCartesianGrid &, - const shared_ptr proj_data_info_sptr, - const float cphi, const float sphi, const float delta, - const float s_in_mm, - const float R, const int min_ax_pos_num, const int max_ax_pos_num, const float offset, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset, - const float norm_factor, - const bool restrict_to_cylindrical_FOV); - - -template -bool -ForwardProjectorByBinUsingRayTracing:: -proj_Siddon<3>(Array<4,float> &Projptr, const VoxelsOnCartesianGrid &, - const shared_ptr proj_data_info_sptr, - const float cphi, const float sphi, const float delta, - const float s_in_mm, - const float R, const int min_ax_pos_num, const int max_ax_pos_num, const float offset, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset, - const float norm_factor, - const bool restrict_to_cylindrical_FOV); - - -template -bool -ForwardProjectorByBinUsingRayTracing:: -proj_Siddon<4>(Array<4,float> &Projptr, const VoxelsOnCartesianGrid &, - const shared_ptr proj_data_info_sptr, - const float cphi, const float sphi, const float delta, - const float s_in_mm, - const float R, const int min_ax_pos_num, const int max_ax_pos_num, const float offset, - const int num_planes_per_axial_pos, - const float axial_pos_to_z_offset, - const float norm_factor, - const bool restrict_to_cylindrical_FOV); - -#endif +template bool ForwardProjectorByBinUsingRayTracing::proj_Siddon<1>( + Array<4, float>& Projptr, const VoxelsOnCartesianGrid&, + const shared_ptr proj_data_info_sptr, const float cphi, const float sphi, const float delta, + const float s_in_mm, const float R, const int min_ax_pos_num, const int max_ax_pos_num, const float offset, + const int num_planes_per_axial_pos, const float axial_pos_to_z_offset, const float norm_factor, + const bool restrict_to_cylindrical_FOV); + +template bool ForwardProjectorByBinUsingRayTracing::proj_Siddon<2>( + Array<4, float>& Projptr, const VoxelsOnCartesianGrid&, + const shared_ptr proj_data_info_sptr, const float cphi, const float sphi, const float delta, + const float s_in_mm, const float R, const int min_ax_pos_num, const int max_ax_pos_num, const float offset, + const int num_planes_per_axial_pos, const float axial_pos_to_z_offset, const float norm_factor, + const bool restrict_to_cylindrical_FOV); + +template bool ForwardProjectorByBinUsingRayTracing::proj_Siddon<3>( + Array<4, float>& Projptr, const VoxelsOnCartesianGrid&, + const shared_ptr proj_data_info_sptr, const float cphi, const float sphi, const float delta, + const float s_in_mm, const float R, const int min_ax_pos_num, const int max_ax_pos_num, const float offset, + const int num_planes_per_axial_pos, const float axial_pos_to_z_offset, const float norm_factor, + const bool restrict_to_cylindrical_FOV); + +template bool ForwardProjectorByBinUsingRayTracing::proj_Siddon<4>( + Array<4, float>& Projptr, const VoxelsOnCartesianGrid&, + const shared_ptr proj_data_info_sptr, const float cphi, const float sphi, const float delta, + const float s_in_mm, const float R, const int min_ax_pos_num, const int max_ax_pos_num, const float offset, + const int num_planes_per_axial_pos, const float axial_pos_to_z_offset, const float norm_factor, + const bool restrict_to_cylindrical_FOV); + +#endif END_NAMESPACE_STIR diff --git a/src/recon_buildblock/FourierRebinning.cxx b/src/recon_buildblock/FourierRebinning.cxx index ed8a16199f..582de858ce 100644 --- a/src/recon_buildblock/FourierRebinning.cxx +++ b/src/recon_buildblock/FourierRebinning.cxx @@ -1,6 +1,6 @@ -/*! - \file - \brief FORE kernel +/*! + \file + \brief FORE kernel \ingroup recon_buildblock \author Matthias Egger \author Claire LABBE @@ -30,13 +30,12 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/FourierRebinning.h" #include "stir/Scanner.h" #include "stir/ProjDataInfoCylindrical.h" #include "stir/ProjDataInterfile.h" #include "stir/SegmentBySinogram.h" -#include "stir/Bin.h" +#include "stir/Bin.h" #include "stir/IndexRange3D.h" #include "stir/IndexRange2D.h" #include "stir/Succeeded.h" @@ -61,47 +60,36 @@ using std::ios; using std::ofstream; #endif - START_NAMESPACE_STIR +const char* const FourierRebinning::registered_name = "FORE"; -const char * const -FourierRebinning::registered_name = "FORE"; - void -FourierRebinning:: -initialise_keymap() -{ +FourierRebinning::initialise_keymap() { base_type::initialise_keymap(); parser.add_start_key("FORE Parameters"); parser.add_stop_key("End FORE Parameters"); parser.add_key("Smallest angular frequency", &kmin); - parser.add_key("Smallest transaxial frequency",&wmin); + parser.add_key("Smallest transaxial frequency", &wmin); parser.add_key("Delta max for small omega", &deltamin); parser.add_key("Index for consistency", &kc); parser.add_key("FORE debug level", &fore_debug_level); - } - -bool -FourierRebinning:: -post_processing() -{ +bool +FourierRebinning::post_processing() { if (base_type::post_processing() == true) return true; // TODO check other parameterssegment return false; -} +} void -FourierRebinning:: -set_defaults() -{ +FourierRebinning::set_defaults() { base_type::set_defaults(); -//CON There is probably nothing like a set of FORE parameters which make sense for all scanners. -//CON Therefore default it to illegal values such that the application will terminate if the user -//CON does not set them to values which make sense via the parameter file or the set functions. + // CON There is probably nothing like a set of FORE parameters which make sense for all scanners. + // CON Therefore default it to illegal values such that the application will terminate if the user + // CON does not set them to values which make sense via the parameter file or the set functions. kmin = -1; wmin = -1; deltamin = -1; @@ -109,578 +97,534 @@ set_defaults() fore_debug_level = 0; } -FourierRebinning:: -FourierRebinning() -{ - set_defaults(); -} - +FourierRebinning::FourierRebinning() { set_defaults(); } Succeeded -FourierRebinning:: -rebin() -{ +FourierRebinning::rebin() { + + if (proj_data_sptr->get_proj_data_info_sptr()->is_tof_data()) { + error("FORE Rebinning :: Not supported for TOF data. Aborted"); + return Succeeded::no; + } start_timers(); CPUTimer timer; timer.start(); - - //CON return value + + // CON return value Succeeded success = Succeeded::yes; - - //CL Find the number of views and tangential positions power of two + + // CL Find the number of views and tangential positions power of two int num_views_pow2; - for ( num_views_pow2 = 1; num_views_pow2 < 2*proj_data_sptr->get_num_views() && num_views_pow2 < (1<<15); num_views_pow2*=2); + for (num_views_pow2 = 1; num_views_pow2 < 2 * proj_data_sptr->get_num_views() && num_views_pow2 < (1 << 15); + num_views_pow2 *= 2) + ; int num_tang_poss_pow2; - for ( num_tang_poss_pow2 = 1; num_tang_poss_pow2 < proj_data_sptr->get_num_tangential_poss() && num_tang_poss_pow2 < (1<<15); num_tang_poss_pow2*=2); - - //CL Initialise the 2D Fourier transform of all rebinned sinograms P(w,k)=0 - const int num_planes = proj_data_sptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings()*2-1; + for (num_tang_poss_pow2 = 1; num_tang_poss_pow2 < proj_data_sptr->get_num_tangential_poss() && num_tang_poss_pow2 < (1 << 15); + num_tang_poss_pow2 *= 2) + ; + + // CL Initialise the 2D Fourier transform of all rebinned sinograms P(w,k)=0 + const int num_planes = proj_data_sptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings() * 2 - 1; - Array<3,std::complex > FT_rebinned_data(IndexRange3D(0, num_planes-1, 0, num_views_pow2-1, 0, num_tang_poss_pow2-1)); - Array<3,float> Weights_for_FT_rebinned_data(IndexRange3D(0, num_planes-1, 0,num_views_pow2-1, 0,num_tang_poss_pow2-1)); - //CON some statistics - PETCount_rebinned num_rebinned(0,0,0); + Array<3, std::complex> FT_rebinned_data( + IndexRange3D(0, num_planes - 1, 0, num_views_pow2 - 1, 0, num_tang_poss_pow2 - 1)); + Array<3, float> Weights_for_FT_rebinned_data(IndexRange3D(0, num_planes - 1, 0, num_views_pow2 - 1, 0, num_tang_poss_pow2 - 1)); + // CON some statistics + PETCount_rebinned num_rebinned(0, 0, 0); - //CON Create the output (rebinned projection data) data structure and set the properties of the rebinned sinograms + // CON Create the output (rebinned projection data) data structure and set the properties of the rebinned sinograms shared_ptr rebinned_proj_data_sptr; - //CON initialise the new projection data properties by copying the properties from the input projection data. - shared_ptr rebinned_proj_data_info_sptr - ( proj_data_sptr->get_proj_data_info_sptr()->clone()); - //CON Adapt the properties that will be modified by the rebinning. - rebinned_proj_data_info_sptr->set_num_views(num_views_pow2/2); - //CON After rebinning we have of course only "direct" sinograms left e.q only segment 0 exists - rebinned_proj_data_info_sptr->reduce_segment_range(0,0); - //CON maximal ring difference a LOR in the largest segment that is going to be rebinned - const int max_delta = dynamic_cast - (*proj_data_sptr->get_proj_data_info_sptr()).get_max_ring_difference(max_segment_num_to_process); - //CON The maximum/minimum ring difference covered by LORs written to the rebinned sinogram changed to the maximum ring - //CON difference covered by the largest segment that has been rebinned. + // CON initialise the new projection data properties by copying the properties from the input projection data. + shared_ptr rebinned_proj_data_info_sptr(proj_data_sptr->get_proj_data_info_sptr()->clone()); + // CON Adapt the properties that will be modified by the rebinning. + rebinned_proj_data_info_sptr->set_num_views(num_views_pow2 / 2); + // CON After rebinning we have of course only "direct" sinograms left e.q only segment 0 exists + rebinned_proj_data_info_sptr->reduce_segment_range(0, 0); + // CON maximal ring difference a LOR in the largest segment that is going to be rebinned + const int max_delta = dynamic_cast(*proj_data_sptr->get_proj_data_info_sptr()) + .get_max_ring_difference(max_segment_num_to_process); + // CON The maximum/minimum ring difference covered by LORs written to the rebinned sinogram changed to the maximum ring + // CON difference covered by the largest segment that has been rebinned. dynamic_cast(*rebinned_proj_data_info_sptr).set_min_ring_difference(-max_delta, 0); dynamic_cast(*rebinned_proj_data_info_sptr).set_max_ring_difference(max_delta, 0); - //CON minimal and maximal axial position number. As usual we start with axial position 0 in segment 0 + // CON minimal and maximal axial position number. As usual we start with axial position 0 in segment 0 rebinned_proj_data_info_sptr->set_min_axial_pos_num(0, 0); - rebinned_proj_data_info_sptr->set_max_axial_pos_num(num_planes-1,0); - //CON create the output (interfile) file to where the rebinned data will be written. - rebinned_proj_data_sptr.reset(new ProjDataInterfile (proj_data_sptr->get_exam_info_sptr(), - rebinned_proj_data_info_sptr,output_filename_prefix)); - //CON get scanner related parameters needed for the rebinning kernel. - //CON create a scanner object. The scanner type is identified from the projection data info. + rebinned_proj_data_info_sptr->set_max_axial_pos_num(num_planes - 1, 0); + // CON create the output (interfile) file to where the rebinned data will be written. + rebinned_proj_data_sptr.reset( + new ProjDataInterfile(proj_data_sptr->get_exam_info_sptr(), rebinned_proj_data_info_sptr, output_filename_prefix)); + // CON get scanner related parameters needed for the rebinning kernel. + // CON create a scanner object. The scanner type is identified from the projection data info. const Scanner* scanner = rebinned_proj_data_sptr->get_proj_data_info_sptr()->get_scanner_ptr(); - const float half_distance_between_rings = scanner->get_ring_spacing()/2.F; - const float sampling_distance_in_s = rebinned_proj_data_info_sptr->get_sampling_in_s(Bin(0,0,0,0)); - const float radial_sampling_freq_w = float(2.*_PI)/sampling_distance_in_s/num_tang_poss_pow2; - //CON D = #bins * binsize, R = D / 2 - const float R_field_of_view_mm = ((int) (rebinned_proj_data_info_sptr->get_num_tangential_poss() / 2) - 1)*sampling_distance_in_s; + const float half_distance_between_rings = scanner->get_ring_spacing() / 2.F; + const float sampling_distance_in_s = rebinned_proj_data_info_sptr->get_sampling_in_s(Bin(0, 0, 0, 0)); + const float radial_sampling_freq_w = float(2. * _PI) / sampling_distance_in_s / num_tang_poss_pow2; + // CON D = #bins * binsize, R = D / 2 + const float R_field_of_view_mm = + ((int)(rebinned_proj_data_info_sptr->get_num_tangential_poss() / 2) - 1) * sampling_distance_in_s; const float scanner_space_between_rings = scanner->get_ring_spacing(); const float scanner_ring_radius = scanner->get_effective_ring_radius(); const float ratio_ring_spacing_to_ring_radius = scanner_space_between_rings / scanner_ring_radius; - //CON Check that the user defineable FORE parameters are inside a possible range of values - if(fore_check_parameters(num_tang_poss_pow2,num_views_pow2,max_segment_num_to_process) != Succeeded::yes){ - error("FORE Rebinning :: Setup failed "); - }; - - //CON Loop over all positive segments. Negative segments (those with negative (opposite) ring differences - //CON will be merged with the positive segment 180 degree sinograms to form a 360 degree segment. - for (int seg_num=0; seg_num <=max_segment_num_to_process ; seg_num++){ - + // CON Check that the user defineable FORE parameters are inside a possible range of values + if (fore_check_parameters(num_tang_poss_pow2, num_views_pow2, max_segment_num_to_process) != Succeeded::yes) { + error("FORE Rebinning :: Setup failed "); + }; + + // CON Loop over all positive segments. Negative segments (those with negative (opposite) ring differences + // CON will be merged with the positive segment 180 degree sinograms to form a 360 degree segment. + for (int seg_num = 0; seg_num <= max_segment_num_to_process; seg_num++) { + info(boost::format("FORE Rebinning :: Processing segment No %1% *") % seg_num); - // TODO at present, the processing is done by segment. However, it's fairly easy to - // change this to by sinogram (the rebinning call below will do everything - // as a loop over axial_pos anyway). - // This would save some memory overhead, and increase potential for parallelisation later. - // (The parallelised version of FORE in PARAPET was organised this way). - - //CON get one (positive) segment - SegmentBySinogram segment = proj_data_sptr->get_segment_by_sinogram(seg_num); - - //CON Retrieve some segment dependent properties needed for the rebinning kernel - const ProjDataInfoCylindrical& proj_data_info_cylindrical = dynamic_cast(*segment.get_proj_data_info_sptr()); - const float average_ring_difference_in_segment = proj_data_info_cylindrical.get_average_ring_difference(segment.get_segment_num()); - - - //CL Form a 360 degree sinogram by merging two 180 degree segments with opposite ring difference - //CL to get a new segment sampled over 2*pi (where 0 < view < pi) - //CON See DeFrise paper (exact and approximate rebinning algorithms for 3D PET data), Sec IV,C (p153) - //KT TODO this is currently not a good idea, as all ProjDataInfo classes assume that - //KT views go from 0 to Pi. - //CON Get the corresponding (negative) segment with the same absolute but opposite obliqueness - const SegmentBySinogram segment_neg = proj_data_sptr->get_segment_by_sinogram(-seg_num); - //CON Expand the (positive) segment such that the two segments can be merged - segment.grow(IndexRange3D(segment.get_min_axial_pos_num(), segment.get_max_axial_pos_num(), - 0,2*segment.get_num_views()-1, segment.get_min_tangential_pos_num(), segment.get_max_tangential_pos_num() - )); - - - //CON merge the two segments to form "360 degrees" sinograms - const int min_tangential_pos_num = std::max(segment_neg.get_min_tangential_pos_num(), - -segment.get_max_tangential_pos_num()); - - - const int max_tangential_pos_num = std::min(segment_neg.get_max_tangential_pos_num(), - -segment.get_min_tangential_pos_num()); - - - for (int ring = segment.get_min_axial_pos_num(); ring <= segment.get_max_axial_pos_num(); ring++) - for (int view = segment_neg.get_min_view_num(); view <= segment_neg.get_max_view_num(); view++) - for( int tangential_pos_num = min_tangential_pos_num; tangential_pos_num<=max_tangential_pos_num; tangential_pos_num++) - segment[ring][view+segment_neg.get_num_views()][tangential_pos_num] = segment_neg[ring][view][-tangential_pos_num]; - - // CON in debug mode visualize the segment - if(fore_debug_level>=2) - { - char s[100]; - sprintf(s, "(extended) segment by sinogram %d",segment.get_segment_num()); - display(segment, segment.find_max(), s); - } - - //CON the sinogramm dimensions need to have a dimension which is a power of 2 (required by the FFT algorithm) - //CON for s (radial coordinate) pad the sinogramm with zeros to form a larger array. - //CON the phi (azimuthal cordinate (view)) coordinate is periodic. The samples need to be interpolated to the - //CON to the new matrix size. Do this by linear interpolation. - //CON -> DeFrise p. 153 Sec IV.C + // TODO at present, the processing is done by segment. However, it's fairly easy to + // change this to by sinogram (the rebinning call below will do everything + // as a loop over axial_pos anyway). + // This would save some memory overhead, and increase potential for parallelisation later. + // (The parallelised version of FORE in PARAPET was organised this way). + + // CON get one (positive) segment + SegmentBySinogram segment = proj_data_sptr->get_segment_by_sinogram(seg_num); + + // CON Retrieve some segment dependent properties needed for the rebinning kernel + const ProjDataInfoCylindrical& proj_data_info_cylindrical = + dynamic_cast(*segment.get_proj_data_info_sptr()); + const float average_ring_difference_in_segment = + proj_data_info_cylindrical.get_average_ring_difference(segment.get_segment_num()); + + // CL Form a 360 degree sinogram by merging two 180 degree segments with opposite ring difference + // CL to get a new segment sampled over 2*pi (where 0 < view < pi) + // CON See DeFrise paper (exact and approximate rebinning algorithms for 3D PET data), Sec IV,C (p153) + // KT TODO this is currently not a good idea, as all ProjDataInfo classes assume that + // KT views go from 0 to Pi. + // CON Get the corresponding (negative) segment with the same absolute but opposite obliqueness + const SegmentBySinogram segment_neg = proj_data_sptr->get_segment_by_sinogram(-seg_num); + // CON Expand the (positive) segment such that the two segments can be merged + segment.grow(IndexRange3D(segment.get_min_axial_pos_num(), segment.get_max_axial_pos_num(), 0, + 2 * segment.get_num_views() - 1, segment.get_min_tangential_pos_num(), + segment.get_max_tangential_pos_num())); + + // CON merge the two segments to form "360 degrees" sinograms + const int min_tangential_pos_num = std::max(segment_neg.get_min_tangential_pos_num(), -segment.get_max_tangential_pos_num()); + + const int max_tangential_pos_num = std::min(segment_neg.get_max_tangential_pos_num(), -segment.get_min_tangential_pos_num()); + + for (int ring = segment.get_min_axial_pos_num(); ring <= segment.get_max_axial_pos_num(); ring++) + for (int view = segment_neg.get_min_view_num(); view <= segment_neg.get_max_view_num(); view++) + for (int tangential_pos_num = min_tangential_pos_num; tangential_pos_num <= max_tangential_pos_num; tangential_pos_num++) + segment[ring][view + segment_neg.get_num_views()][tangential_pos_num] = segment_neg[ring][view][-tangential_pos_num]; + + // CON in debug mode visualize the segment + if (fore_debug_level >= 2) { + char s[100]; + sprintf(s, "(extended) segment by sinogram %d", segment.get_segment_num()); + display(segment, segment.find_max(), s); + } + + // CON the sinogramm dimensions need to have a dimension which is a power of 2 (required by the FFT algorithm) + // CON for s (radial coordinate) pad the sinogramm with zeros to form a larger array. + // CON the phi (azimuthal cordinate (view)) coordinate is periodic. The samples need to be interpolated to the + // CON to the new matrix size. Do this by linear interpolation. + // CON -> DeFrise p. 153 Sec IV.C do_adjust_nb_views_to_pow2(segment); - - //CON The sinogramm data is now in the required format and ready for rebinning. - //CON The rebinned data is stored in a 3 dimensional array of complex numbers (FT_rebinned_data). - //CON FT_rebinned_data[plane][w(FT of s)][k(FT of phi)] - //CON Weight has the same dimensions. It stores normalisation factors (floats) - //CON to take into account the variable number of contributions to each frequency. - do_rebinning(FT_rebinned_data, Weights_for_FT_rebinned_data, num_rebinned, segment, - num_tang_poss_pow2, num_views_pow2, num_planes, average_ring_difference_in_segment, - half_distance_between_rings, sampling_distance_in_s, radial_sampling_freq_w, R_field_of_view_mm, - ratio_ring_spacing_to_ring_radius); - - } //CON end loop over segments. - - - //CON Some statistics + // CON The sinogramm data is now in the required format and ready for rebinning. + // CON The rebinned data is stored in a 3 dimensional array of complex numbers (FT_rebinned_data). + // CON FT_rebinned_data[plane][w(FT of s)][k(FT of phi)] + // CON Weight has the same dimensions. It stores normalisation factors (floats) + // CON to take into account the variable number of contributions to each frequency. + do_rebinning(FT_rebinned_data, Weights_for_FT_rebinned_data, num_rebinned, segment, num_tang_poss_pow2, num_views_pow2, + num_planes, average_ring_difference_in_segment, half_distance_between_rings, sampling_distance_in_s, + radial_sampling_freq_w, R_field_of_view_mm, ratio_ring_spacing_to_ring_radius); + + } // CON end loop over segments. + + // CON Some statistics std::cout << "\nFORE Rebinning :: Total rebinning count: \n"; do_display_count(num_rebinned); - info("FORE Rebinning :: Inverse FFT the rebinned sinograms " ); - //CL now finally fill in the new sinogram s + info("FORE Rebinning :: Inverse FFT the rebinned sinograms "); + // CL now finally fill in the new sinogram s SegmentBySinogram sino2D_rebinned = rebinned_proj_data_sptr->get_empty_segment_by_sinogram(0); - - for (int plane=FT_rebinned_data.get_min_index();plane <= FT_rebinned_data.get_max_index(); plane++){ - - if(plane%10==0) info(boost::format("FORE Rebinning :: Inv FFT rebinned z-position (slice) = %1%") % plane); - - //CON Create a temporary 2D array of complex numbers to store the rebinned and summed fourier coefficients for one slice. - //CON This data is then inverse FFTd and copied to a sinogram data structure. - //CON Strictly seen this temporary data structure is no longer necessary because the inv. FFT could now be - //CON be done on FT_rebinned_data itself. Since one has to anyway access the full FTdata matrix to apply - //CON the rebinning weights - //CON before the inv. FFT can be applied this is not much overhead and it can be left like it was done when still - //CON using the numerical receipies FFT code. - Array<2, std::complex > FT_rebinned_sinogram(IndexRange2D(0,num_tang_poss_pow2-1,0,num_views_pow2/2)); - //CON fourier_for_real_data will resize the array to its appropriate dimensions - Array<2,float> rebinned_sinogram(IndexRange2D(0,1,0,1)); - - //CON Normalise the rebinned sinograms by applying the weight factors - //CON See DeFrise IV.D p154. - for (int j = 0; j < num_tang_poss_pow2; j++) { - for (int i = 0; i <= num_views_pow2/2; i++) { - const float Actual_Weight = (Weights_for_FT_rebinned_data[plane][i][j] == 0) ? 0 : - 1.F/(Weights_for_FT_rebinned_data[plane][i][j]); - FT_rebinned_sinogram[j][i] = FT_rebinned_data[plane][i][j]* Actual_Weight; - - } - } - - if(fore_debug_level>=3) - { + for (int plane = FT_rebinned_data.get_min_index(); plane <= FT_rebinned_data.get_max_index(); plane++) { + + if (plane % 10 == 0) + info(boost::format("FORE Rebinning :: Inv FFT rebinned z-position (slice) = %1%") % plane); + + // CON Create a temporary 2D array of complex numbers to store the rebinned and summed fourier coefficients for one slice. + // CON This data is then inverse FFTd and copied to a sinogram data structure. + // CON Strictly seen this temporary data structure is no longer necessary because the inv. FFT could now be + // CON be done on FT_rebinned_data itself. Since one has to anyway access the full FTdata matrix to apply + // CON the rebinning weights + // CON before the inv. FFT can be applied this is not much overhead and it can be left like it was done when still + // CON using the numerical receipies FFT code. + Array<2, std::complex> FT_rebinned_sinogram(IndexRange2D(0, num_tang_poss_pow2 - 1, 0, num_views_pow2 / 2)); + // CON fourier_for_real_data will resize the array to its appropriate dimensions + Array<2, float> rebinned_sinogram(IndexRange2D(0, 1, 0, 1)); + + // CON Normalise the rebinned sinograms by applying the weight factors + // CON See DeFrise IV.D p154. + for (int j = 0; j < num_tang_poss_pow2; j++) { + for (int i = 0; i <= num_views_pow2 / 2; i++) { + const float Actual_Weight = + (Weights_for_FT_rebinned_data[plane][i][j] == 0) ? 0 : 1.F / (Weights_for_FT_rebinned_data[plane][i][j]); + FT_rebinned_sinogram[j][i] = FT_rebinned_data[plane][i][j] * Actual_Weight; + } + } + + if (fore_debug_level >= 3) { char s[100]; - Array<2,float> real(FT_rebinned_sinogram.get_index_range()); - for (int i = 0; i < num_views_pow2; i++) - for (int j = 0; j <= num_tang_poss_pow2/2; j++) + Array<2, float> real(FT_rebinned_sinogram.get_index_range()); + for (int i = 0; i < num_views_pow2; i++) + for (int j = 0; j <= num_tang_poss_pow2 / 2; j++) real[i][j] = FT_rebinned_sinogram[i][j].real(); - sprintf(s, "real part of FT of rebinned (extended) sinogram %d",plane); + sprintf(s, "real part of FT of rebinned (extended) sinogram %d", plane); display(real, s, real.find_max()); - for (int i = 0; i < num_views_pow2; i++) - for (int j = 0; j <= num_tang_poss_pow2/2; j++) + for (int i = 0; i < num_views_pow2; i++) + for (int j = 0; j <= num_tang_poss_pow2 / 2; j++) real[i][j] = FT_rebinned_sinogram[i][j].imag(); - sprintf(s, "imag part of FT of rebinned (extended) sinogram %d",plane); + sprintf(s, "imag part of FT of rebinned (extended) sinogram %d", plane); display(real, s, real.find_max()); } - - //CON inverse FFT the rebinned sinograms - rebinned_sinogram = inverse_fourier_for_real_data(FT_rebinned_sinogram); - - //CL Keep only one half of data [o.._PI] - for (int i=0;i<(int)(num_views_pow2/2);i++) - for (int j=0;j Min = %1%, Max= %2%, Sum = %3%") - % sino2D_rebinned.find_min() - % sino2D_rebinned.find_max() - % sino2D_rebinned.sum()); - - //CON finally write the rebinned sinograms to file - const Succeeded success_this_sino = - rebinned_proj_data_sptr->set_segment(sino2D_rebinned); - - - if (success == Succeeded::yes && success_this_sino == Succeeded::no) - success = Succeeded::no; - stop_timers(); -//CON presently not very useful. Maybe one could define a vriable fore_debug_level and -//CON only write in case of debugging - if(fore_debug_level>0) - do_log_file(); - - return success; -} + // CON inverse FFT the rebinned sinograms + rebinned_sinogram = inverse_fourier_for_real_data(FT_rebinned_sinogram); + // CL Keep only one half of data [o.._PI] + for (int i = 0; i < (int)(num_views_pow2 / 2); i++) + for (int j = 0; j < num_tang_poss_pow2; j++) + if ((j + sino2D_rebinned.get_min_tangential_pos_num()) <= sino2D_rebinned.get_max_tangential_pos_num()) + sino2D_rebinned[plane][i][j + sino2D_rebinned.get_min_tangential_pos_num()] = rebinned_sinogram[j][i]; + } // CON end loop over planes -void -FourierRebinning:: -do_rebinning(Array<3,std::complex > &FT_rebinned_data, Array<3,float> &Weights_for_FT_rebinned_data, - PETCount_rebinned &count_rebinned, - const SegmentBySinogram &segment, const int num_tang_poss_pow2, - const int num_views_pow2, const int num_planes, const float average_ring_difference_in_segment, - const float half_distance_between_rings, const float sampling_distance_in_s, - const float radial_sampling_freq_w, const float R_field_of_view_mm, - const float ratio_ring_spacing_to_ring_radius) - - - { - const int local_rebinned = count_rebinned.total; - const int local_miss= count_rebinned.miss; - const int local_ssrb= count_rebinned.ssrb; - -//CON Loop over all slices, FFT the sinograms and call the actual rebinning kernel. - for (int axial_pos_num = segment.get_min_axial_pos_num(); axial_pos_num <= segment.get_max_axial_pos_num() ;axial_pos_num++) - { - - if(axial_pos_num%10 == 0) info(boost::format("FORE Rebinning z (slice) = %1%") % axial_pos_num); - Array<2,float> current_sinogram(IndexRange2D(0,num_tang_poss_pow2-1,0,num_views_pow2-1)); - - //CL Calculate the 2D FFT of P(w,k) of the merged segment - //CON copy the sinogram data of slice axial_pos_num from the segment array to slicedata - //CON the sinogram is flipped. This will taken account for in the rebinning, where the assignment of the FFT - //CON coefficients are assigned opposite. - for (int j = 0; j < segment.get_num_tangential_poss(); j++) - for (int i = 0; i < num_views_pow2; i++) - current_sinogram[j][i] = segment[axial_pos_num][i][j + segment.get_min_tangential_pos_num()]; - - //CON FFT slicedata - const Array<2,std::complex > FT_current_sinogram = fourier_for_real_data(current_sinogram); + info(boost::format("FORE Rebinning :: 2D Rebinned sinograms => Min = %1%, Max= %2%, Sum = %3%") % sino2D_rebinned.find_min() % + sino2D_rebinned.find_max() % sino2D_rebinned.sum()); - //CON determine the axial position of the middle of the LOR in mm relative to Bin(segment=0,view=0,axial_pos=0,tang_pos=0) - const ProjDataInfo& proj_data_info = *segment.get_proj_data_info_sptr(); - const float z_in_mm = proj_data_info.get_m(Bin(segment.get_segment_num(),0,axial_pos_num,0)) - proj_data_info.get_m(Bin(0,0,0,0)); - - //CON Call the rebinning kernel. - rebinning(FT_rebinned_data,Weights_for_FT_rebinned_data,count_rebinned,FT_current_sinogram, - z_in_mm, average_ring_difference_in_segment, num_views_pow2, - num_tang_poss_pow2,half_distance_between_rings,sampling_distance_in_s,radial_sampling_freq_w, - R_field_of_view_mm,ratio_ring_spacing_to_ring_radius); - - }//CL End of loop of axial_pos_num - - if(fore_debug_level > 0){ - info(boost::format("Total rebinned: %1%\n" - "Total missed: %2%\n" - "Total rebinned SSRB: %3%") - % (count_rebinned.total - local_rebinned) % (count_rebinned.miss - local_miss) % (count_rebinned.ssrb - local_ssrb) ); - } + // CON finally write the rebinned sinograms to file + const Succeeded success_this_sino = rebinned_proj_data_sptr->set_segment(sino2D_rebinned); + + if (success == Succeeded::yes && success_this_sino == Succeeded::no) + success = Succeeded::no; + stop_timers(); + // CON presently not very useful. Maybe one could define a vriable fore_debug_level and + // CON only write in case of debugging + if (fore_debug_level > 0) + do_log_file(); + return success; } +void +FourierRebinning::do_rebinning(Array<3, std::complex>& FT_rebinned_data, Array<3, float>& Weights_for_FT_rebinned_data, + PETCount_rebinned& count_rebinned, const SegmentBySinogram& segment, + const int num_tang_poss_pow2, const int num_views_pow2, const int num_planes, + const float average_ring_difference_in_segment, const float half_distance_between_rings, + const float sampling_distance_in_s, const float radial_sampling_freq_w, + const float R_field_of_view_mm, const float ratio_ring_spacing_to_ring_radius) +{ + const int local_rebinned = count_rebinned.total; + const int local_miss = count_rebinned.miss; + const int local_ssrb = count_rebinned.ssrb; + + // CON Loop over all slices, FFT the sinograms and call the actual rebinning kernel. + for (int axial_pos_num = segment.get_min_axial_pos_num(); axial_pos_num <= segment.get_max_axial_pos_num(); axial_pos_num++) { + + if (axial_pos_num % 10 == 0) + info(boost::format("FORE Rebinning z (slice) = %1%") % axial_pos_num); + Array<2, float> current_sinogram(IndexRange2D(0, num_tang_poss_pow2 - 1, 0, num_views_pow2 - 1)); + + // CL Calculate the 2D FFT of P(w,k) of the merged segment + // CON copy the sinogram data of slice axial_pos_num from the segment array to slicedata + // CON the sinogram is flipped. This will taken account for in the rebinning, where the assignment of the FFT + // CON coefficients are assigned opposite. + for (int j = 0; j < segment.get_num_tangential_poss(); j++) + for (int i = 0; i < num_views_pow2; i++) + current_sinogram[j][i] = segment[axial_pos_num][i][j + segment.get_min_tangential_pos_num()]; + // CON FFT slicedata + const Array<2, std::complex> FT_current_sinogram = fourier_for_real_data(current_sinogram); -void -FourierRebinning:: -rebinning(Array<3,std::complex > &FT_rebinned_data, Array<3,float> &Weights_for_FT_rebinned_data, - PETCount_rebinned &num_rebinned, const Array<2,std::complex > &FT_current_sinogram, - const float z_in_mm, const float delta, - const int num_views_pow2, const int num_tang_poss_pow2, const float half_distance_between_rings, - const float sampling_distance_in_s, const float radial_sampling_freq_w, const float R_field_of_view_mm, - const float ratio_ring_spacing_to_ring_radius) -{ + // CON determine the axial position of the middle of the LOR in mm relative to Bin(segment=0,view=0,axial_pos=0,tang_pos=0) + const ProjDataInfo& proj_data_info = *segment.get_proj_data_info_sptr(); + const float z_in_mm = + proj_data_info.get_m(Bin(segment.get_segment_num(), 0, axial_pos_num, 0)) - proj_data_info.get_m(Bin(0, 0, 0, 0)); + + // CON Call the rebinning kernel. + rebinning(FT_rebinned_data, Weights_for_FT_rebinned_data, count_rebinned, FT_current_sinogram, z_in_mm, + average_ring_difference_in_segment, num_views_pow2, num_tang_poss_pow2, half_distance_between_rings, + sampling_distance_in_s, radial_sampling_freq_w, R_field_of_view_mm, ratio_ring_spacing_to_ring_radius); + + } // CL End of loop of axial_pos_num + + if (fore_debug_level > 0) { + info(boost::format("Total rebinned: %1%\n" + "Total missed: %2%\n" + "Total rebinned SSRB: %3%") % + (count_rebinned.total - local_rebinned) % (count_rebinned.miss - local_miss) % (count_rebinned.ssrb - local_ssrb)); + } +} - - //CON prevent rebinning to non existing z-positions (sinograms) +void +FourierRebinning::rebinning(Array<3, std::complex>& FT_rebinned_data, Array<3, float>& Weights_for_FT_rebinned_data, + PETCount_rebinned& num_rebinned, const Array<2, std::complex>& FT_current_sinogram, + const float z_in_mm, const float delta, const int num_views_pow2, const int num_tang_poss_pow2, + const float half_distance_between_rings, const float sampling_distance_in_s, + const float radial_sampling_freq_w, const float R_field_of_view_mm, + const float ratio_ring_spacing_to_ring_radius) { + + // CON prevent rebinning to non existing z-positions (sinograms) const int maxplane = FT_rebinned_data.get_max_index(); - //CON determine z position (sino identifier) - const int z = round(z_in_mm/half_distance_between_rings); + // CON determine z position (sino identifier) + const int z = round(z_in_mm / half_distance_between_rings); // TODO replace call to error() by warning() and returning Succeeded::no - if(fabs(static_cast(z_in_mm/half_distance_between_rings - z)) > .0001) - error("FORE rebinning :: rebinning kernel expected integer z coordinate but found a non integer value %g\n", z_in_mm); - - //CL t is the tangent of the angle theta between the LOR and the transaxial plane - const float t = delta * ratio_ring_spacing_to_ring_radius / 2.F; - - - //CON The continuous frequency "w" corresponds the radial coordinate "s" - //CON The integer Fourier index "k" corresponds to the azimuthal angle "view" - - //CON FORE regime (rebinning) - //CON Iterate over all frequency tuples (w,k) starting from wmin,kmin up to num_tang_poss_pow2/2,num_views_pow2/2 - - for (int j = wmin; j <= num_tang_poss_pow2/2;j++) { - for (int i = kmin; i <= num_views_pow2/2; i++) { - - float w = static_cast(j) * radial_sampling_freq_w; - float k = static_cast(i); - - //CON FORE consistency criteria . FORE is a good approximation only if w and k are large - //CON (FORE is a high frequency approximation). - //CON For small w and k second order corrections become important. - //CON FORE is a good approximation if: abs(w/k) > Romega, k>klim || w>wlim. - //CON see DeFrise III.C, p150. - //CON i>kc is an additional consistency criteria. The components of a 2D FFT sinogram are - //CON negligible when |-k/w| is larger than the - //CON the radius of the scanners FOV.These contributions can be forced to zero therefore avoiding - //CON large z-shifts which results in z-positions outside the axial range of the scanner. - if ((k > w * R_field_of_view_mm) && (i > kc)){ - continue; - } - - //CON FORE establishes a relation of the 2D FT of an oblique sinogram to the 2D FT of a direct sinogram - //CON shifted in z by a frequency dependent value (zshift). - //CON see DeFrise, III.B Formula 28 - float zshift; - if(w==0) zshift = 0.; - else zshift = t * k / w; //CL in mm - - //CON first evaluate the positive frequency for a given bin (w,k). The FFT is stored in data such, that in the first - //CON two dimensions the positive frequencies are stored. Starting with the zero frequency, followed by the smallest - //CON positive frequency and so on. The smallest negative frequency is in the last index value. - //CON Due to the ordering of positive and negative frequencies and the fact that this is the FFT of real data - //CON the assignment of the positive and negative frequency - //CON contributions to the rebinned data matrix in F-space can be done here in one pass. - for(int shift_direction=POSITIVE_Z_SHIFT; shift_direction<=NEGATIVE_Z_SHIFT; shift_direction+=CHANGE_Z_SHIFT){ - - int jj = j; - - if(shift_direction==NEGATIVE_Z_SHIFT && j > 0) jj = num_tang_poss_pow2 - j; - - //CON new_z_sl is the z-coordinate of the shifted z-position this contribution is assigned to. - const float new_z_sl = static_cast(z) + shift_direction * zshift/half_distance_between_rings; - //CON find the nearest "real" direct sinogram located at z < new_z_sl - const int small_z = static_cast(floor(new_z_sl)); - //CON distance between the direct sinogram and the z-position this F-space contribution was assigned to. - const float m = new_z_sl - small_z; - //CON Assign the F-space contributions from the given oblique sinogram to the neighbouring direct sinogram. - //CON The contribution is weighted by the - //CON z-"distance" of the calculated shifted z-position to the neighbouring direct sinogram with z < zshift. - if (small_z >= 0 && small_z <= maxplane) { - const float OneMinusM = 1.F - m; - FT_rebinned_data[small_z][i][jj] += (FT_current_sinogram[jj][i] * OneMinusM); - Weights_for_FT_rebinned_data[small_z][i][jj] += OneMinusM; - num_rebinned.total += 1; - } else { - num_rebinned.miss += 1; - } - //CON same for z > zshift - if (small_z >= -1 && small_z < maxplane) { - FT_rebinned_data[small_z + 1][i][jj] += (FT_current_sinogram[jj][i] * m); - Weights_for_FT_rebinned_data[small_z + 1][i][jj] += m; - } - - }//CON shift_direction - }//CON end j - }//CON end i - -//CL Particular cases for small frequencies i.e Small w -//CON Due to this they will only contribute to one direct sinogram. -//CON This is SSRB where each oblique sinogramm is an estimate of the direct sinogram -//CON P(w,k,z,d) = P(w,k,z,0) -//CON Only sinograms with an obliqueness smaller than deltamin (set by parameter file) are accepted - const int small_z = z; + if (fabs(static_cast(z_in_mm / half_distance_between_rings - z)) > .0001) + error("FORE rebinning :: rebinning kernel expected integer z coordinate but found a non integer value %g\n", z_in_mm); + + // CL t is the tangent of the angle theta between the LOR and the transaxial plane + const float t = delta * ratio_ring_spacing_to_ring_radius / 2.F; + + // CON The continuous frequency "w" corresponds the radial coordinate "s" + // CON The integer Fourier index "k" corresponds to the azimuthal angle "view" + + // CON FORE regime (rebinning) + // CON Iterate over all frequency tuples (w,k) starting from wmin,kmin up to num_tang_poss_pow2/2,num_views_pow2/2 + + for (int j = wmin; j <= num_tang_poss_pow2 / 2; j++) { + for (int i = kmin; i <= num_views_pow2 / 2; i++) { + + float w = static_cast(j) * radial_sampling_freq_w; + float k = static_cast(i); + + // CON FORE consistency criteria . FORE is a good approximation only if w and k are large + // CON (FORE is a high frequency approximation). + // CON For small w and k second order corrections become important. + // CON FORE is a good approximation if: abs(w/k) > Romega, k>klim || w>wlim. + // CON see DeFrise III.C, p150. + // CON i>kc is an additional consistency criteria. The components of a 2D FFT sinogram are + // CON negligible when |-k/w| is larger than the + // CON the radius of the scanners FOV.These contributions can be forced to zero therefore avoiding + // CON large z-shifts which results in z-positions outside the axial range of the scanner. + if ((k > w * R_field_of_view_mm) && (i > kc)) { + continue; + } + + // CON FORE establishes a relation of the 2D FT of an oblique sinogram to the 2D FT of a direct sinogram + // CON shifted in z by a frequency dependent value (zshift). + // CON see DeFrise, III.B Formula 28 + float zshift; + if (w == 0) + zshift = 0.; + else + zshift = t * k / w; // CL in mm + + // CON first evaluate the positive frequency for a given bin (w,k). The FFT is stored in data such, that in the first + // CON two dimensions the positive frequencies are stored. Starting with the zero frequency, followed by the smallest + // CON positive frequency and so on. The smallest negative frequency is in the last index value. + // CON Due to the ordering of positive and negative frequencies and the fact that this is the FFT of real data + // CON the assignment of the positive and negative frequency + // CON contributions to the rebinned data matrix in F-space can be done here in one pass. + for (int shift_direction = POSITIVE_Z_SHIFT; shift_direction <= NEGATIVE_Z_SHIFT; shift_direction += CHANGE_Z_SHIFT) { + + int jj = j; + + if (shift_direction == NEGATIVE_Z_SHIFT && j > 0) + jj = num_tang_poss_pow2 - j; + + // CON new_z_sl is the z-coordinate of the shifted z-position this contribution is assigned to. + const float new_z_sl = static_cast(z) + shift_direction * zshift / half_distance_between_rings; + // CON find the nearest "real" direct sinogram located at z < new_z_sl + const int small_z = static_cast(floor(new_z_sl)); + // CON distance between the direct sinogram and the z-position this F-space contribution was assigned to. + const float m = new_z_sl - small_z; + // CON Assign the F-space contributions from the given oblique sinogram to the neighbouring direct sinogram. + // CON The contribution is weighted by the + // CON z-"distance" of the calculated shifted z-position to the neighbouring direct sinogram with z < zshift. + if (small_z >= 0 && small_z <= maxplane) { + const float OneMinusM = 1.F - m; + FT_rebinned_data[small_z][i][jj] += (FT_current_sinogram[jj][i] * OneMinusM); + Weights_for_FT_rebinned_data[small_z][i][jj] += OneMinusM; + num_rebinned.total += 1; + } else { + num_rebinned.miss += 1; + } + // CON same for z > zshift + if (small_z >= -1 && small_z < maxplane) { + FT_rebinned_data[small_z + 1][i][jj] += (FT_current_sinogram[jj][i] * m); + Weights_for_FT_rebinned_data[small_z + 1][i][jj] += m; + } + + } // CON shift_direction + } // CON end j + } // CON end i + + // CL Particular cases for small frequencies i.e Small w + // CON Due to this they will only contribute to one direct sinogram. + // CON This is SSRB where each oblique sinogramm is an estimate of the direct sinogram + // CON P(w,k,z,d) = P(w,k,z,0) + // CON Only sinograms with an obliqueness smaller than deltamin (set by parameter file) are accepted + const int small_z = z; if (delta <= deltamin) { - //CL First, treat small w's then k=1..kNyq-1 : - //CON Same logic as in FORE, except that no zshift position is calculated. It is assumed that the obliqueness is small - //CON and therefore there will be only contributions to one direct sinogram and the weights are therefore always 1. - - for (int j = 0; j < wmin; j++){ - for (int i = 0; i <= num_views_pow2/2; i++) { - - for(int shift_direction=POSITIVE_Z_SHIFT;shift_direction<=NEGATIVE_Z_SHIFT;shift_direction+=CHANGE_Z_SHIFT){ - - int jj=j; - - // Take reverse ordering of tangential position in the negative segment into account (?) - if(shift_direction==NEGATIVE_Z_SHIFT && j > 0) - jj=num_tang_poss_pow2 - j; - - - if (small_z >= 0 && small_z <= maxplane ) { - - FT_rebinned_data[small_z][i][jj] += FT_current_sinogram[jj][i]; - Weights_for_FT_rebinned_data[small_z][i][jj] += 1.; - if(j==1) num_rebinned.ssrb += 1; - } - - } // end shift_direction - } // end for j - } // end for i - - -//CL Small k : -//CL Next treat small k's and w=wNyq=(num_tang_poss_pow2 / 2)+1, k=1..klim : - for (int j = wmin; j <= num_tang_poss_pow2/2; j++) { - for (int i = 0; i <= kmin; i++) { - - for(int shift_direction=POSITIVE_Z_SHIFT;shift_direction<=NEGATIVE_Z_SHIFT;shift_direction+=CHANGE_Z_SHIFT){ - - int jj=j; - - // Take reverse ordering of tangential position in the negative segment into account (?) - if(shift_direction==NEGATIVE_Z_SHIFT && j > 0) - jj=num_tang_poss_pow2 - j; - - - if (small_z >= 0 && small_z <= maxplane ) { - FT_rebinned_data[small_z][i][jj] += FT_current_sinogram[jj][i]; - Weights_for_FT_rebinned_data[small_z][i][jj] += 1.; - num_rebinned.ssrb += 1; - } - - } // shift_direction - } // end for j - } // end for i - - } // end delta < deltamin - - } - - - -void -FourierRebinning:: -do_log_file() -{//CL Saving time details and write them to log file - char file[200]; - sprintf(file,"%s.log",output_filename_prefix.c_str()); - - std::ofstream logfile(file); - - if (logfile.fail() || logfile.bad()) { - warning("FORE Rebinning :: Error opening log file\n"); - } + // CL First, treat small w's then k=1..kNyq-1 : + // CON Same logic as in FORE, except that no zshift position is calculated. It is assumed that the obliqueness is small + // CON and therefore there will be only contributions to one direct sinogram and the weights are therefore always 1. - std::time_t now = std::time(NULL); - logfile << "FORE Rebinning :: Date of the FORE image reconstruction : " << std::asctime(std::localtime(&now)) - << parameter_info() - << "\n\n CPU Time :\n" << get_CPU_timer_value() << '\n'; -} + for (int j = 0; j < wmin; j++) { + for (int i = 0; i <= num_views_pow2 / 2; i++) { + for (int shift_direction = POSITIVE_Z_SHIFT; shift_direction <= NEGATIVE_Z_SHIFT; shift_direction += CHANGE_Z_SHIFT) { -void -FourierRebinning:: -do_display_count(PETCount_rebinned &count) -{// Display rebinning statistics - std::cout << "FORE Rebinning :: Total rebinned: " << count.total << '\n' - << " Total missed: " << count.miss << '\n'; - - if (count.miss != 0) - std::cout << " (" << 100. * count.miss / (count.miss + count.ssrb) - << " percent)\n"; - std::cout << "FORE Rebinning :: Total rebinned SSRB: " << count.ssrb << std::endl; -} + int jj = j; + // Take reverse ordering of tangential position in the negative segment into account (?) + if (shift_direction == NEGATIVE_Z_SHIFT && j > 0) + jj = num_tang_poss_pow2 - j; -void -FourierRebinning:: -do_adjust_nb_views_to_pow2(SegmentBySinogram &segment) -{ -// Adjustment of the number of views to a power of two -//CON Use the STIR overlap_interpolate method and remove the simlar private implementation (adjust_pow2) here. - const int num_views_pow2 = stir::round(pow(2.,((int)ceil(log ((float)segment.get_num_views())/log(2.))))); - const float offset_for_overlap_interpolate = 0.F; - - if (num_views_pow2 == segment.get_num_views()) - return; - - //CON Create the projection data info ptr for the resized segment - shared_ptr out_proj_data_info_sptr(segment.get_proj_data_info_sptr()->clone()); - out_proj_data_info_sptr->set_num_views(num_views_pow2); - //CON the re-dimensioned segment - SegmentBySinogram out_segment = - out_proj_data_info_sptr->get_empty_segment_by_sinogram(segment.get_segment_num()); - - for (int axial_pos_num = segment.get_min_axial_pos_num(); axial_pos_num <= segment.get_max_axial_pos_num(); - axial_pos_num++) - { - const Sinogram sino2D = segment.get_sinogram(axial_pos_num); - Sinogram out_sino2D = out_segment.get_sinogram(axial_pos_num); - - float extension_factor = static_cast(out_sino2D.get_num_views())/ static_cast(sino2D.get_num_views()); - overlap_interpolate(out_sino2D, sino2D,extension_factor,offset_for_overlap_interpolate,true); - - out_segment.set_sinogram(out_sino2D); - } - segment = out_segment; -} + if (small_z >= 0 && small_z <= maxplane) { -Succeeded FourierRebinning:: -fore_check_parameters(int num_tang_poss_pow2, int num_views_pow2, int max_segment_num_to_process){ + FT_rebinned_data[small_z][i][jj] += FT_current_sinogram[jj][i]; + Weights_for_FT_rebinned_data[small_z][i][jj] += 1.; + if (j == 1) + num_rebinned.ssrb += 1; + } -//CON Check if the parameters given make sense. + } // end shift_direction + } // end for j + } // end for i - if(deltamin<0) { - warning("FORE initialisation :: The deltamin parameter must be an integer value >= 0"); - return Succeeded::no; + // CL Small k : + // CL Next treat small k's and w=wNyq=(num_tang_poss_pow2 / 2)+1, k=1..klim : + for (int j = wmin; j <= num_tang_poss_pow2 / 2; j++) { + for (int i = 0; i <= kmin; i++) { - } + for (int shift_direction = POSITIVE_Z_SHIFT; shift_direction <= NEGATIVE_Z_SHIFT; shift_direction += CHANGE_Z_SHIFT) { + int jj = j; - if(wmin < 0 || kmin < 0){ - warning("FORE initialisation :: The parameters wmin and kmin must be >=0\n" - " Negative frequencies are not allowed. Due to symmetry reasons they are implicitly defined by the positive wmin/kmin cut off values"); - return Succeeded::no; - } + // Take reverse ordering of tangential position in the negative segment into account (?) + if (shift_direction == NEGATIVE_Z_SHIFT && j > 0) + jj = num_tang_poss_pow2 - j; + if (small_z >= 0 && small_z <= maxplane) { + FT_rebinned_data[small_z][i][jj] += FT_current_sinogram[jj][i]; + Weights_for_FT_rebinned_data[small_z][i][jj] += 1.; + num_rebinned.ssrb += 1; + } - if(wmin >= num_tang_poss_pow2/2 || kmin >= num_views_pow2/2) { - warning(boost::format("FORE initialisation :: The parameter wmin or kmin is larger than the highest frequency component computed by the FFT algorithm\n" - " Choose an value smaller than the largest frequency\n" - " kmin must be smaller than %1% and wmin must be smaller than %2%") - % (num_tang_poss_pow2/2) % (num_views_pow2/2)); - return Succeeded::no; - } + } // shift_direction + } // end for j + } // end for i + } // end delta < deltamin +} + +void +FourierRebinning::do_log_file() { // CL Saving time details and write them to log file + char file[200]; + sprintf(file, "%s.log", output_filename_prefix.c_str()); + + std::ofstream logfile(file); + + if (logfile.fail() || logfile.bad()) { + warning("FORE Rebinning :: Error opening log file\n"); + } + + std::time_t now = std::time(NULL); + logfile << "FORE Rebinning :: Date of the FORE image reconstruction : " << std::asctime(std::localtime(&now)) + << parameter_info() << "\n\n CPU Time :\n" + << get_CPU_timer_value() << '\n'; +} + +void +FourierRebinning::do_display_count(PETCount_rebinned& count) { // Display rebinning statistics + std::cout << "FORE Rebinning :: Total rebinned: " << count.total << '\n' + << " Total missed: " << count.miss << '\n'; + + if (count.miss != 0) + std::cout << " (" << 100. * count.miss / (count.miss + count.ssrb) << " percent)\n"; + std::cout << "FORE Rebinning :: Total rebinned SSRB: " << count.ssrb << std::endl; +} - if(kc >= num_views_pow2/2) { - warning(boost::format("FORE initialisation :: Your parameter kc is larger than the highest frequency component in w (FTT of radial coordinate s)\n" - " Choose an value smaller than the largest frequency\n" - " kc must be smaller than %1%") - % num_views_pow2); - return Succeeded::no; - } +void +FourierRebinning::do_adjust_nb_views_to_pow2(SegmentBySinogram& segment) { + // Adjustment of the number of views to a power of two + // CON Use the STIR overlap_interpolate method and remove the simlar private implementation (adjust_pow2) here. + const int num_views_pow2 = stir::round(pow(2., ((int)ceil(log((float)segment.get_num_views()) / log(2.))))); + const float offset_for_overlap_interpolate = 0.F; + if (num_views_pow2 == segment.get_num_views()) + return; - if(max_segment_num_to_process > proj_data_sptr->get_num_segments()){ - warning(boost::format("FORE initialisation :: Your data set stores %1% segments\n" - " The maximum number of segments to process variable is larger than that.") - % (proj_data_sptr->get_num_segments()/2+1)); - return Succeeded::no; - } + // CON Create the projection data info ptr for the resized segment + shared_ptr out_proj_data_info_sptr(segment.get_proj_data_info_sptr()->clone()); + out_proj_data_info_sptr->set_num_views(num_views_pow2); + // CON the re-dimensioned segment + SegmentBySinogram out_segment = out_proj_data_info_sptr->get_empty_segment_by_sinogram(segment.get_segment_num()); + for (int axial_pos_num = segment.get_min_axial_pos_num(); axial_pos_num <= segment.get_max_axial_pos_num(); axial_pos_num++) { + const Sinogram sino2D = segment.get_sinogram(axial_pos_num); + Sinogram out_sino2D = out_segment.get_sinogram(axial_pos_num); - if(max_segment_num_to_process < 0){ - warning("FORE initialisation :: The maximum segment number to process must be an integer value >=0"); - return Succeeded::no; - } + float extension_factor = static_cast(out_sino2D.get_num_views()) / static_cast(sino2D.get_num_views()); + overlap_interpolate(out_sino2D, sino2D, extension_factor, offset_for_overlap_interpolate, true); - return Succeeded::yes; + out_segment.set_sinogram(out_sino2D); + } + segment = out_segment; } +Succeeded +FourierRebinning::fore_check_parameters(int num_tang_poss_pow2, int num_views_pow2, int max_segment_num_to_process) { + + // CON Check if the parameters given make sense. + + if (deltamin < 0) { + warning("FORE initialisation :: The deltamin parameter must be an integer value >= 0"); + return Succeeded::no; + } + + if (wmin < 0 || kmin < 0) { + warning("FORE initialisation :: The parameters wmin and kmin must be >=0\n" + " Negative frequencies are not allowed. Due to symmetry reasons they are implicitly defined by " + "the positive wmin/kmin cut off values"); + return Succeeded::no; + } + + if (wmin >= num_tang_poss_pow2 / 2 || kmin >= num_views_pow2 / 2) { + warning(boost::format("FORE initialisation :: The parameter wmin or kmin is larger than the highest frequency component " + "computed by the FFT algorithm\n" + " Choose an value smaller than the largest frequency\n" + " kmin must be smaller than %1% and wmin must be smaller than %2%") % + (num_tang_poss_pow2 / 2) % (num_views_pow2 / 2)); + return Succeeded::no; + } + + if (kc >= num_views_pow2 / 2) { + warning(boost::format("FORE initialisation :: Your parameter kc is larger than the highest frequency component in w (FTT of " + "radial coordinate s)\n" + " Choose an value smaller than the largest frequency\n" + " kc must be smaller than %1%") % + num_views_pow2); + return Succeeded::no; + } + + if (max_segment_num_to_process > proj_data_sptr->get_num_segments()) { + warning(boost::format("FORE initialisation :: Your data set stores %1% segments\n" + " The maximum number of segments to process variable is larger than that.") % + (proj_data_sptr->get_num_segments() / 2 + 1)); + return Succeeded::no; + } + + if (max_segment_num_to_process < 0) { + warning("FORE initialisation :: The maximum segment number to process must be an integer value >=0"); + return Succeeded::no; + } + + return Succeeded::yes; +} END_NAMESPACE_STIR diff --git a/src/recon_buildblock/GeneralisedObjectiveFunction.cxx b/src/recon_buildblock/GeneralisedObjectiveFunction.cxx index 44a794b620..e278f30dbf 100644 --- a/src/recon_buildblock/GeneralisedObjectiveFunction.cxx +++ b/src/recon_buildblock/GeneralisedObjectiveFunction.cxx @@ -2,6 +2,7 @@ // /* Copyright (C) 2003- 2011, Hammersmith Imanet Ltd + Copyright (C) 2016, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -21,6 +22,7 @@ \ingroup GeneralisedObjectiveFunction \brief Declaration of class stir::GeneralisedObjectiveFunction + \author Nikos Efthimiou \author Kris Thielemans \author Sanida Mustafovic @@ -32,98 +34,82 @@ #include "stir/Succeeded.h" #include "stir/modelling/ParametricDiscretisedDensity.h" #include "stir/modelling/KineticParameters.h" - +#include "stir/info.h" using std::string; START_NAMESPACE_STIR template void -GeneralisedObjectiveFunction:: -set_defaults() -{ +GeneralisedObjectiveFunction::set_defaults() { this->prior_sptr.reset(); // note: cannot use set_num_subsets(1) here, as other parameters (such as projectors) are not set-up yet. this->num_subsets = 1; + use_tof = false; } template void -GeneralisedObjectiveFunction:: -initialise_keymap() -{ +GeneralisedObjectiveFunction::initialise_keymap() { this->parser.add_parsing_key("prior type", &prior_sptr); + this->parser.add_key("Use TOF information", &use_tof); } template -GeneralisedObjectiveFunction:: -~GeneralisedObjectiveFunction() -{} +GeneralisedObjectiveFunction::~GeneralisedObjectiveFunction() {} template -Succeeded -GeneralisedObjectiveFunction:: -set_up(shared_ptr const& target_data_ptr) -{ - if (target_data_ptr->get_exam_info().imaging_modality.is_unknown() - || this->get_input_data().get_exam_info().imaging_modality.is_unknown()) +Succeeded +GeneralisedObjectiveFunction::set_up(shared_ptr const& target_data_ptr) { + if (target_data_ptr->get_exam_info().imaging_modality.is_unknown() || + this->get_input_data().get_exam_info().imaging_modality.is_unknown()) warning("Imaging modality is unknown for either the target or the input data or both.\n" "Going ahead anyway."); - else if (target_data_ptr->get_exam_info().imaging_modality != - this->get_input_data().get_exam_info().imaging_modality) + else if (target_data_ptr->get_exam_info().imaging_modality != this->get_input_data().get_exam_info().imaging_modality) error("Imaging modality should be the same for the target and the input data"); - if (!is_null_ptr(this->prior_sptr) && - this->prior_sptr->set_up(target_data_ptr) == Succeeded::no) + if (!is_null_ptr(this->prior_sptr) && this->prior_sptr->set_up(target_data_ptr) == Succeeded::no) return Succeeded::no; - if (this->num_subsets <= 0) - { - warning("Number of subsets %d should be larger than 0.", - this->num_subsets); - return Succeeded::no; - } + if (this->num_subsets <= 0) { + warning("Number of subsets %d should be larger than 0.", this->num_subsets); + return Succeeded::no; + } + + if (use_tof) { + info("Time-Of-Flight reconstruction activated!"); + } - return Succeeded::yes; + return Succeeded::yes; } template -GeneralisedPrior * const -GeneralisedObjectiveFunction:: -get_prior_ptr() const -{ return this->prior_sptr.get(); } +GeneralisedPrior* const +GeneralisedObjectiveFunction::get_prior_ptr() const { + return this->prior_sptr.get(); +} template -shared_ptr > -GeneralisedObjectiveFunction:: -get_prior_sptr() -{ - return this->prior_sptr; +shared_ptr> +GeneralisedObjectiveFunction::get_prior_sptr() { + return this->prior_sptr; } template void -GeneralisedObjectiveFunction:: -set_prior_sptr(const shared_ptr >& arg) -{ +GeneralisedObjectiveFunction::set_prior_sptr(const shared_ptr>& arg) { this->prior_sptr = arg; } template bool -GeneralisedObjectiveFunction:: -prior_is_zero() const -{ - return - is_null_ptr(this->prior_sptr) || - this->prior_sptr->get_penalisation_factor() == 0; +GeneralisedObjectiveFunction::prior_is_zero() const { + return is_null_ptr(this->prior_sptr) || this->prior_sptr->get_penalisation_factor() == 0; } template double -GeneralisedObjectiveFunction:: -compute_penalty(const TargetT& current_estimate) -{ +GeneralisedObjectiveFunction::compute_penalty(const TargetT& current_estimate) { if (this->prior_is_zero()) return 0.; else @@ -132,212 +118,161 @@ compute_penalty(const TargetT& current_estimate) template double -GeneralisedObjectiveFunction:: -compute_penalty(const TargetT& current_estimate, - const int subset_num) -{ - return this->compute_penalty(current_estimate)/this->get_num_subsets(); +GeneralisedObjectiveFunction::compute_penalty(const TargetT& current_estimate, const int subset_num) { + return this->compute_penalty(current_estimate) / this->get_num_subsets(); } template -void -GeneralisedObjectiveFunction:: -compute_sub_gradient(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) -{ +void +GeneralisedObjectiveFunction::compute_sub_gradient(TargetT& gradient, const TargetT& current_estimate, + const int subset_num) { assert(gradient.get_index_range() == current_estimate.get_index_range()); - if (subset_num<0 || subset_num>=this->get_num_subsets()) + if (subset_num < 0 || subset_num >= this->get_num_subsets()) error("compute_sub_gradient subset_num out-of-range error"); - this->compute_sub_gradient_without_penalty(gradient, - current_estimate, - subset_num); - if (!this->prior_is_zero()) - { - shared_ptr prior_gradient_sptr(gradient.get_empty_copy()); - this->prior_sptr->compute_gradient(*prior_gradient_sptr, current_estimate); - - // (*prior_gradient_sptr)/= num_subsets; - // gradient -= *prior_gradient_sptr; - typename TargetT::const_full_iterator prior_gradient_iter = prior_gradient_sptr->begin_all_const(); - const typename TargetT::const_full_iterator end_prior_gradient_iter = prior_gradient_sptr->end_all_const(); - typename TargetT::full_iterator gradient_iter = gradient.begin_all(); - while (prior_gradient_iter!=end_prior_gradient_iter) - { - *gradient_iter -= (*prior_gradient_iter)/this->get_num_subsets(); - ++gradient_iter; ++prior_gradient_iter; - } - } + this->compute_sub_gradient_without_penalty(gradient, current_estimate, subset_num); + if (!this->prior_is_zero()) { + shared_ptr prior_gradient_sptr(gradient.get_empty_copy()); + this->prior_sptr->compute_gradient(*prior_gradient_sptr, current_estimate); + + // (*prior_gradient_sptr)/= num_subsets; + // gradient -= *prior_gradient_sptr; + typename TargetT::const_full_iterator prior_gradient_iter = prior_gradient_sptr->begin_all_const(); + const typename TargetT::const_full_iterator end_prior_gradient_iter = prior_gradient_sptr->end_all_const(); + typename TargetT::full_iterator gradient_iter = gradient.begin_all(); + while (prior_gradient_iter != end_prior_gradient_iter) { + *gradient_iter -= (*prior_gradient_iter) / this->get_num_subsets(); + ++gradient_iter; + ++prior_gradient_iter; + } + } } template -int -GeneralisedObjectiveFunction:: -get_num_subsets() const -{ +int +GeneralisedObjectiveFunction::get_num_subsets() const { return this->num_subsets; } +template +bool +GeneralisedObjectiveFunction::get_tof_status() const { + return this->use_tof; +} + template double -GeneralisedObjectiveFunction:: -compute_objective_function_without_penalty(const TargetT& current_estimate) -{ +GeneralisedObjectiveFunction::compute_objective_function_without_penalty(const TargetT& current_estimate) { double result = 0.; - for (int subset_num=0; subset_numget_num_subsets(); ++subset_num) - result += - this->compute_objective_function_without_penalty(current_estimate, subset_num); + for (int subset_num = 0; subset_num < this->get_num_subsets(); ++subset_num) + result += this->compute_objective_function_without_penalty(current_estimate, subset_num); return result; } template double -GeneralisedObjectiveFunction:: -compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num) -{ - if (subset_num<0 || subset_num>=this->get_num_subsets()) +GeneralisedObjectiveFunction::compute_objective_function_without_penalty(const TargetT& current_estimate, + const int subset_num) { + if (subset_num < 0 || subset_num >= this->get_num_subsets()) error("compute_objective_function_without_penalty subset_num out-of-range error"); - return - this->actual_compute_objective_function_without_penalty(current_estimate, subset_num); + return this->actual_compute_objective_function_without_penalty(current_estimate, subset_num); } template double -GeneralisedObjectiveFunction:: -compute_objective_function(const TargetT& current_estimate, - const int subset_num) -{ - return - this->compute_objective_function_without_penalty(current_estimate, subset_num) - - this->compute_penalty(current_estimate, subset_num); +GeneralisedObjectiveFunction::compute_objective_function(const TargetT& current_estimate, const int subset_num) { + return this->compute_objective_function_without_penalty(current_estimate, subset_num) - + this->compute_penalty(current_estimate, subset_num); } template double -GeneralisedObjectiveFunction:: -compute_objective_function(const TargetT& current_estimate) -{ - return - this->compute_objective_function_without_penalty(current_estimate) - - this->compute_penalty(current_estimate); +GeneralisedObjectiveFunction::compute_objective_function(const TargetT& current_estimate) { + return this->compute_objective_function_without_penalty(current_estimate) - this->compute_penalty(current_estimate); } /////////////////////// Approximate Hessian template -Succeeded -GeneralisedObjectiveFunction:: -add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const -{ - if (subset_num<0 || subset_num>=this->get_num_subsets()) +Succeeded +GeneralisedObjectiveFunction::add_multiplication_with_approximate_sub_Hessian_without_penalty( + TargetT& output, const TargetT& input, const int subset_num) const { + if (subset_num < 0 || subset_num >= this->get_num_subsets()) error("add_multiplication_with_approximate_sub_Hessian_without_penalty subset_num out-of-range error"); { string explanation; - if (!output.has_same_characteristics(input, - explanation)) - { - warning("GeneralisedObjectiveFunction:\n" - "input and output for add_multiplication_with_approximate_sub_Hessian_without_penalty\n" - "should have the same characteristics.\n%s", - explanation.c_str()); - return Succeeded::no; - } + if (!output.has_same_characteristics(input, explanation)) { + warning("GeneralisedObjectiveFunction:\n" + "input and output for add_multiplication_with_approximate_sub_Hessian_without_penalty\n" + "should have the same characteristics.\n%s", + explanation.c_str()); + return Succeeded::no; + } } - return - this->actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(output, - input, - subset_num); + return this->actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(output, input, subset_num); } template -Succeeded -GeneralisedObjectiveFunction:: -add_multiplication_with_approximate_sub_Hessian(TargetT& output, - const TargetT& input, - const int subset_num) const -{ - if (this->add_multiplication_with_approximate_sub_Hessian_without_penalty(output, input, subset_num) == - Succeeded::no) +Succeeded +GeneralisedObjectiveFunction::add_multiplication_with_approximate_sub_Hessian(TargetT& output, const TargetT& input, + const int subset_num) const { + if (this->add_multiplication_with_approximate_sub_Hessian_without_penalty(output, input, subset_num) == Succeeded::no) return Succeeded::no; - if (!this->prior_is_zero()) - { - // TODO used boost:scoped_ptr - shared_ptr prior_output_sptr(output.get_empty_copy()); - if (this->prior_sptr->add_multiplication_with_approximate_Hessian(*prior_output_sptr, output) == - Succeeded::no) - return Succeeded::no; - - - // (*prior_output_sptr)/= num_subsets; - // output -= *prior_output_sptr; - typename TargetT::const_full_iterator prior_output_iter = prior_output_sptr->begin_all_const(); - const typename TargetT::const_full_iterator end_prior_output_iter = prior_output_sptr->end_all_const(); - typename TargetT::full_iterator output_iter = output.begin_all(); - while (prior_output_iter!=end_prior_output_iter) - { - *output_iter -= (*prior_output_iter)/this->get_num_subsets(); - ++output_iter; ++prior_output_iter; - } - } + if (!this->prior_is_zero()) { + // TODO used boost:scoped_ptr + shared_ptr prior_output_sptr(output.get_empty_copy()); + if (this->prior_sptr->add_multiplication_with_approximate_Hessian(*prior_output_sptr, output) == Succeeded::no) + return Succeeded::no; - return Succeeded::yes; + // (*prior_output_sptr)/= num_subsets; + // output -= *prior_output_sptr; + typename TargetT::const_full_iterator prior_output_iter = prior_output_sptr->begin_all_const(); + const typename TargetT::const_full_iterator end_prior_output_iter = prior_output_sptr->end_all_const(); + typename TargetT::full_iterator output_iter = output.begin_all(); + while (prior_output_iter != end_prior_output_iter) { + *output_iter -= (*prior_output_iter) / this->get_num_subsets(); + ++output_iter; + ++prior_output_iter; + } + } + return Succeeded::yes; } - template -Succeeded -GeneralisedObjectiveFunction:: -add_multiplication_with_approximate_Hessian_without_penalty(TargetT& output, - const TargetT& input) const -{ - for (int subset_num=0; subset_numget_num_subsets(); ++subset_num) - { - if (this->add_multiplication_with_approximate_sub_Hessian_without_penalty(output, - input, - subset_num) == - Succeeded::no) - return Succeeded::no; - } +Succeeded +GeneralisedObjectiveFunction::add_multiplication_with_approximate_Hessian_without_penalty(TargetT& output, + const TargetT& input) const { + for (int subset_num = 0; subset_num < this->get_num_subsets(); ++subset_num) { + if (this->add_multiplication_with_approximate_sub_Hessian_without_penalty(output, input, subset_num) == Succeeded::no) + return Succeeded::no; + } return Succeeded::yes; } template -Succeeded -GeneralisedObjectiveFunction:: -add_multiplication_with_approximate_Hessian(TargetT& output, - const TargetT& input) const -{ - for (int subset_num=0; subset_numget_num_subsets(); ++subset_num) - { - if (this->add_multiplication_with_approximate_sub_Hessian(output, - input, - subset_num) == - Succeeded::no) - return Succeeded::no; - } +Succeeded +GeneralisedObjectiveFunction::add_multiplication_with_approximate_Hessian(TargetT& output, const TargetT& input) const { + for (int subset_num = 0; subset_num < this->get_num_subsets(); ++subset_num) { + if (this->add_multiplication_with_approximate_sub_Hessian(output, input, subset_num) == Succeeded::no) + return Succeeded::no; + } return Succeeded::yes; } template -Succeeded -GeneralisedObjectiveFunction:: -actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const -{ +Succeeded +GeneralisedObjectiveFunction::actual_add_multiplication_with_approximate_sub_Hessian_without_penalty( + TargetT& output, const TargetT& input, const int subset_num) const { error("GeneralisedObjectiveFunction:\n" - "actual_add_multiplication_with_approximate_sub_Hessian_without_penalty implementation is not overloaded by your objective function."); + "actual_add_multiplication_with_approximate_sub_Hessian_without_penalty implementation is not overloaded by your " + "objective function."); return Succeeded::no; } @@ -345,15 +280,10 @@ actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& template Succeeded -GeneralisedObjectiveFunction:: -accumulate_Hessian_times_input(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input) const -{ - for (int subset_num=0; subset_numget_num_subsets(); ++subset_num) - { - if (this->accumulate_sub_Hessian_times_input(output, - current_image_estimate, input, subset_num) == Succeeded::no) +GeneralisedObjectiveFunction::accumulate_Hessian_times_input(TargetT& output, const TargetT& current_image_estimate, + const TargetT& input) const { + for (int subset_num = 0; subset_num < this->get_num_subsets(); ++subset_num) { + if (this->accumulate_sub_Hessian_times_input(output, current_image_estimate, input, subset_num) == Succeeded::no) return Succeeded::no; } return Succeeded::yes; @@ -361,15 +291,12 @@ accumulate_Hessian_times_input(TargetT& output, template Succeeded -GeneralisedObjectiveFunction:: -accumulate_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input) const -{ - for (int subset_num=0; subset_numget_num_subsets(); ++subset_num) - { - if (this->accumulate_sub_Hessian_times_input_without_penalty(output, - current_image_estimate, input, subset_num) == Succeeded::no) +GeneralisedObjectiveFunction::accumulate_Hessian_times_input_without_penalty(TargetT& output, + const TargetT& current_image_estimate, + const TargetT& input) const { + for (int subset_num = 0; subset_num < this->get_num_subsets(); ++subset_num) { + if (this->accumulate_sub_Hessian_times_input_without_penalty(output, current_image_estimate, input, subset_num) == + Succeeded::no) return Succeeded::no; } return Succeeded::yes; @@ -377,31 +304,25 @@ accumulate_Hessian_times_input_without_penalty(TargetT& output, template Succeeded -GeneralisedObjectiveFunction:: -accumulate_sub_Hessian_times_input(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input, - const int subset_num) const -{ +GeneralisedObjectiveFunction::accumulate_sub_Hessian_times_input(TargetT& output, const TargetT& current_image_estimate, + const TargetT& input, const int subset_num) const { if (this->accumulate_sub_Hessian_times_input_without_penalty(output, current_image_estimate, input, subset_num) == Succeeded::no) return Succeeded::no; - if (!this->prior_is_zero()) - { + if (!this->prior_is_zero()) { // TODO used boost:scoped_ptr - shared_ptr prior_output_sptr(output.get_empty_copy()); - if (this->prior_sptr->accumulate_Hessian_times_input(*prior_output_sptr, current_image_estimate, output) == - Succeeded::no) + shared_ptr prior_output_sptr(output.get_empty_copy()); + if (this->prior_sptr->accumulate_Hessian_times_input(*prior_output_sptr, current_image_estimate, output) == Succeeded::no) return Succeeded::no; typename TargetT::const_full_iterator prior_output_iter = prior_output_sptr->begin_all_const(); const typename TargetT::const_full_iterator end_prior_output_iter = prior_output_sptr->end_all_const(); typename TargetT::full_iterator output_iter = output.begin_all(); - while (prior_output_iter!=end_prior_output_iter) - { - *output_iter -= (*prior_output_iter)/this->get_num_subsets(); - ++output_iter; ++prior_output_iter; + while (prior_output_iter != end_prior_output_iter) { + *output_iter -= (*prior_output_iter) / this->get_num_subsets(); + ++output_iter; + ++prior_output_iter; } } return Succeeded::yes; @@ -409,13 +330,11 @@ accumulate_sub_Hessian_times_input(TargetT& output, template Succeeded -GeneralisedObjectiveFunction:: -accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input, - const int subset_num) const -{ - if (subset_num<0 || subset_num>=this->get_num_subsets()) +GeneralisedObjectiveFunction::accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, + const TargetT& current_image_estimate, + const TargetT& input, + const int subset_num) const { + if (subset_num < 0 || subset_num >= this->get_num_subsets()) error("accumulate_sub_Hessian_times_input_without_penalty subset_num out-of-range error"); { @@ -437,77 +356,55 @@ accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, } } - - return this->actual_accumulate_sub_Hessian_times_input_without_penalty(output, - current_image_estimate, - input, - subset_num); + return this->actual_accumulate_sub_Hessian_times_input_without_penalty(output, current_image_estimate, input, subset_num); } template Succeeded -GeneralisedObjectiveFunction:: -actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& input, - const TargetT& current_image_estimate, - const int subset_num) const -{ +GeneralisedObjectiveFunction::actual_accumulate_sub_Hessian_times_input_without_penalty( + TargetT& output, const TargetT& input, const TargetT& current_image_estimate, const int subset_num) const { error("GeneralisedObjectiveFunction:\n" "actual_accumulate_sub_Hessian_times_input_without_penalty implementation is not overloaded by your objective function."); return Succeeded::no; } - /////////////////////// other functions template std::string -GeneralisedObjectiveFunction:: -get_objective_function_values_report(const TargetT& current_estimate) -{ +GeneralisedObjectiveFunction::get_objective_function_values_report(const TargetT& current_estimate) { #ifdef BOOST_NO_STRINGSTREAM char str[10000]; ostrstream s(str, 10000); #else std::ostringstream s; #endif - const double no_penalty = - this->compute_objective_function_without_penalty(current_estimate); - const double penalty = - this->compute_penalty(current_estimate); - s << "Objective function without penalty " << no_penalty - << "\nPenalty " << penalty - << "\nDifference (i.e. total) " << no_penalty-penalty - << '\n'; + const double no_penalty = this->compute_objective_function_without_penalty(current_estimate); + const double penalty = this->compute_penalty(current_estimate); + s << "Objective function without penalty " << no_penalty << "\nPenalty " << penalty + << "\nDifference (i.e. total) " << no_penalty - penalty << '\n'; return s.str(); } -template +template bool -GeneralisedObjectiveFunction:: -subsets_are_approximately_balanced() const -{ +GeneralisedObjectiveFunction::subsets_are_approximately_balanced() const { std::string dummy; return this->actual_subsets_are_approximately_balanced(dummy); } -template +template bool -GeneralisedObjectiveFunction:: -subsets_are_approximately_balanced(std::string& warning_message) const -{ +GeneralisedObjectiveFunction::subsets_are_approximately_balanced(std::string& warning_message) const { return this->actual_subsets_are_approximately_balanced(warning_message); } +#ifdef _MSC_VER +// prevent warning message on instantiation of abstract class +# pragma warning(disable : 4661) +#endif -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif - -template class GeneralisedObjectiveFunction >; -template class GeneralisedObjectiveFunction; +template class GeneralisedObjectiveFunction>; +template class GeneralisedObjectiveFunction; END_NAMESPACE_STIR - - diff --git a/src/recon_buildblock/GeneralisedPrior.cxx b/src/recon_buildblock/GeneralisedPrior.cxx index 156af7d71c..8155b99faf 100644 --- a/src/recon_buildblock/GeneralisedPrior.cxx +++ b/src/recon_buildblock/GeneralisedPrior.cxx @@ -20,9 +20,9 @@ \file \ingroup priors \brief implementation of the stir::GeneralisedPrior - + \author Kris Thielemans - \author Sanida Mustafovic + \author Sanida Mustafovic */ #include "stir/recon_buildblock/GeneralisedPrior.h" @@ -33,68 +33,56 @@ START_NAMESPACE_STIR - template -void -GeneralisedPrior::initialise_keymap() -{ - this->parser.add_key("penalisation factor", &this->penalisation_factor); +void +GeneralisedPrior::initialise_keymap() { + this->parser.add_key("penalisation factor", &this->penalisation_factor); } - template void -GeneralisedPrior::set_defaults() -{ +GeneralisedPrior::set_defaults() { _already_set_up = false; - this->penalisation_factor = 0; + this->penalisation_factor = 0; } template -Succeeded -GeneralisedPrior:: -set_up(shared_ptr const&) -{ +Succeeded +GeneralisedPrior::set_up(shared_ptr const&) { _already_set_up = true; return Succeeded::yes; } template -Succeeded -GeneralisedPrior:: -add_multiplication_with_approximate_Hessian(TargetT& output, - const TargetT& input) const -{ +Succeeded +GeneralisedPrior::add_multiplication_with_approximate_Hessian(TargetT& output, const TargetT& input) const { error("GeneralisedPrior:\n" - "add_multiplication_with_approximate_Hessian implementation is not overloaded by your prior."); + "add_multiplication_with_approximate_Hessian implementation is not overloaded by your prior."); return Succeeded::no; } template Succeeded -GeneralisedPrior:: -accumulate_Hessian_times_input(TargetT& output, - const TargetT& current_estimate, - const TargetT& input) const -{ +GeneralisedPrior::accumulate_Hessian_times_input(TargetT& output, const TargetT& current_estimate, + const TargetT& input) const { error("GeneralisedPrior:\n" "accumulate_Hessian_times_input implementation is not overloaded by your prior."); return Succeeded::no; } -template -void GeneralisedPrior::check(TargetT const& current_estimate) const -{ - if (!_already_set_up) +template +void +GeneralisedPrior::check(TargetT const& current_estimate) const { + if (!_already_set_up) error("The prior should already be set-up, but it's not."); } -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif +#ifdef _MSC_VER +// prevent warning message on instantiation of abstract class +# pragma warning(disable : 4661) +#endif -template class GeneralisedPrior >; -template class GeneralisedPrior; +template class GeneralisedPrior>; +template class GeneralisedPrior; END_NAMESPACE_STIR diff --git a/src/recon_buildblock/IterativeReconstruction.cxx b/src/recon_buildblock/IterativeReconstruction.cxx index bc5ac12fb4..6cef2518b4 100644 --- a/src/recon_buildblock/IterativeReconstruction.cxx +++ b/src/recon_buildblock/IterativeReconstruction.cxx @@ -23,13 +23,13 @@ \file \ingroup recon_buildblock - \brief implementation of the stir::IterativeReconstruction class - + \brief implementation of the stir::IterativeReconstruction class + \author Matthew Jacobson \author Kris Thielemans \author Sanida Mustafovic \author PARAPET project - + */ #include // for time(), used as seed for random stuff @@ -55,118 +55,100 @@ using std::endl; using std::string; #endif - START_NAMESPACE_STIR //********* parameters **************** template -void -IterativeReconstruction::set_defaults() -{ +void +IterativeReconstruction::set_defaults() { base_type::set_defaults(); this->objective_function_sptr.reset(); this->num_subsets = 1; this->start_subset_num = 0; this->num_subiterations = 1; - this->start_subiteration_num =1; + this->start_subiteration_num = 1; // default to all 1's this->initial_data_filename = "1"; - this->max_num_full_iterations=NumericInfo().max_value(); + this->max_num_full_iterations = NumericInfo().max_value(); this->save_interval = 1; this->inter_iteration_filter_interval = 0; this->inter_iteration_filter_ptr.reset(); -//MJ 02/08/99 added subset randomization + // MJ 02/08/99 added subset randomization this->randomise_subset_order = false; this->report_objective_function_values_interval = 0; - } template -void -IterativeReconstruction::initialise_keymap() -{ +void +IterativeReconstruction::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_parsing_key("objective function type", &objective_function_sptr); - this->parser.add_key("number of subiterations", &num_subiterations); - this->parser.add_key("start at subiteration number", &start_subiteration_num); - this->parser.add_key("save estimates at subiteration intervals", &save_interval); + this->parser.add_key("number of subiterations", &num_subiterations); + this->parser.add_key("start at subiteration number", &start_subiteration_num); + this->parser.add_key("save estimates at subiteration intervals", &save_interval); this->parser.add_key("initial estimate", &initial_data_filename); this->parser.add_key("number of subsets", &this->num_subsets); this->parser.add_key("start at subset", &start_subset_num); this->parser.add_key("uniformly randomise subset order", &randomise_subset_order); - this->parser.add_key("inter-iteration filter subiteration interval",&inter_iteration_filter_interval); + this->parser.add_key("inter-iteration filter subiteration interval", &inter_iteration_filter_interval); this->parser.add_parsing_key("inter-iteration filter type", &inter_iteration_filter_ptr); - this->parser.add_key("report objective function values interval", - &this->report_objective_function_values_interval); + this->parser.add_key("report objective function values interval", &this->report_objective_function_values_interval); } template -void IterativeReconstruction:: -ask_parameters() -{ +void +IterativeReconstruction::ask_parameters() { base_type::ask_parameters(); - char initial_data_filename_char[max_filename_length]; - // KT 21/10/98 use new order of arguments - ask_filename_with_extension(initial_data_filename_char, - "Get initial estimate from which file (1 = 1's): ", ""); - - this->initial_data_filename=initial_data_filename_char; - - this->num_subsets= ask_num("Number of ordered sets: ", 1,100000000,1); - this->num_subiterations=ask_num("Number of subiterations", - 1,NumericInfo().max_value(),this->num_subsets); - - this->start_subiteration_num=ask_num("Start at what subiteration number : ", 1,NumericInfo().max_value(),1); - - this->start_subset_num=ask_num("Start with which ordered set : ", - 0,this->num_subsets-1,0); - - this->save_interval=ask_num("Save estimates at sub-iteration intervals of: ", - 1,this->num_subiterations,this->num_subiterations); - - - this->inter_iteration_filter_interval= - ask_num("Do inter-iteration filtering at sub-iteration intervals of: ", - 0, this->num_subiterations, 0); - - if(this->inter_iteration_filter_interval>0 ) - { - cerr<initial_data_filename = initial_data_filename_char; + + this->num_subsets = ask_num("Number of ordered sets: ", 1, 100000000, 1); + this->num_subiterations = ask_num("Number of subiterations", 1, NumericInfo().max_value(), this->num_subsets); + + this->start_subiteration_num = ask_num("Start at what subiteration number : ", 1, NumericInfo().max_value(), 1); + + this->start_subset_num = ask_num("Start with which ordered set : ", 0, this->num_subsets - 1, 0); + + this->save_interval = + ask_num("Save estimates at sub-iteration intervals of: ", 1, this->num_subiterations, this->num_subiterations); + + this->inter_iteration_filter_interval = + ask_num("Do inter-iteration filtering at sub-iteration intervals of: ", 0, this->num_subiterations, 0); + + if (this->inter_iteration_filter_interval > 0) { + cerr << endl << "Supply inter-iteration filter type:\nPossible values:\n"; DataProcessor::list_registered_names(cerr); - + const string inter_iteration_filter_type = ask_string(""); - - this->inter_iteration_filter_ptr. - reset(DataProcessor::read_registered_object(0, inter_iteration_filter_type)); - } - - - - this->randomise_subset_order= - ask("Randomly generate subset order?", false); - - -} + this->inter_iteration_filter_ptr.reset(DataProcessor::read_registered_object(0, inter_iteration_filter_type)); + } + + this->randomise_subset_order = ask("Randomly generate subset order?", false); +} template -bool IterativeReconstruction:: -post_processing() -{ +bool +IterativeReconstruction::post_processing() { if (base_type::post_processing()) return true; - if (is_null_ptr(this->objective_function_sptr)) - { warning("You have to specify an objective function"); return true; } + if (is_null_ptr(this->objective_function_sptr)) { + warning("You have to specify an objective function"); + return true; + } - if (this->initial_data_filename.length() == 0) - { warning("You need to specify an initial estimate file"); return true; } + if (this->initial_data_filename.length() == 0) { + warning("You need to specify an initial estimate file"); + return true; + } return false; } @@ -174,188 +156,159 @@ post_processing() //************ get_ functions **************** template GeneralisedObjectiveFunction const& -IterativeReconstruction:: -get_objective_function() const -{ return *this->objective_function_sptr; } +IterativeReconstruction::get_objective_function() const { + return *this->objective_function_sptr; +} template -shared_ptr > -IterativeReconstruction:: -get_objective_function_sptr() const -{ return this->objective_function_sptr; } +shared_ptr> +IterativeReconstruction::get_objective_function_sptr() const { + return this->objective_function_sptr; +} template const int -IterativeReconstruction:: -get_max_num_full_iterations() const -{ return this->max_num_full_iterations; } +IterativeReconstruction::get_max_num_full_iterations() const { + return this->max_num_full_iterations; +} template -const int -IterativeReconstruction:: -get_num_subsets() const -{ return this->num_subsets; } +const int +IterativeReconstruction::get_num_subsets() const { + return this->num_subsets; +} template -const int -IterativeReconstruction:: -get_num_subiterations() const -{ return this->num_subiterations; } +const int +IterativeReconstruction::get_num_subiterations() const { + return this->num_subiterations; +} template const int -IterativeReconstruction:: -get_start_subiteration_num() const -{ return this->start_subiteration_num; } +IterativeReconstruction::get_start_subiteration_num() const { + return this->start_subiteration_num; +} template -const int -IterativeReconstruction:: -get_start_subset_num() const -{ return this->start_subset_num; } +const int +IterativeReconstruction::get_start_subset_num() const { + return this->start_subset_num; +} template const int -IterativeReconstruction:: -get_save_interval() const -{ return this->save_interval; } +IterativeReconstruction::get_save_interval() const { + return this->save_interval; +} template const bool -IterativeReconstruction:: -get_randomise_subset_order() const -{ return this->randomise_subset_order; } +IterativeReconstruction::get_randomise_subset_order() const { + return this->randomise_subset_order; +} template -const DataProcessor& -IterativeReconstruction:: -get_inter_iteration_filter() const -{ return *this->inter_iteration_filter_ptr; } +const DataProcessor& +IterativeReconstruction::get_inter_iteration_filter() const { + return *this->inter_iteration_filter_ptr; +} template -shared_ptr > -IterativeReconstruction:: -get_inter_iteration_filter_sptr() -{ - return this->inter_iteration_filter_ptr; +shared_ptr> +IterativeReconstruction::get_inter_iteration_filter_sptr() { + return this->inter_iteration_filter_ptr; } template -const int -IterativeReconstruction:: -get_inter_iteration_filter_interval() const -{ return this->inter_iteration_filter_interval; } +const int +IterativeReconstruction::get_inter_iteration_filter_interval() const { + return this->inter_iteration_filter_interval; +} template -const int -IterativeReconstruction:: -get_report_objective_function_values_interval() const -{ return this->report_objective_function_values_interval; } +const int +IterativeReconstruction::get_report_objective_function_values_interval() const { + return this->report_objective_function_values_interval; +} //************ set_ functions **************** template void -IterativeReconstruction:: -set_objective_function_sptr(const shared_ptr >& arg) -{ - this->objective_function_sptr = arg; +IterativeReconstruction::set_objective_function_sptr(const shared_ptr>& arg) { + this->objective_function_sptr = arg; } template void -IterativeReconstruction:: -set_max_num_full_iterations(const int arg) -{ - this->max_num_full_iterations = arg; +IterativeReconstruction::set_max_num_full_iterations(const int arg) { + this->max_num_full_iterations = arg; } template void -IterativeReconstruction:: -set_num_subsets(const int arg) -{ +IterativeReconstruction::set_num_subsets(const int arg) { this->_already_set_up = false; - this->num_subsets = arg; + this->num_subsets = arg; } template void -IterativeReconstruction:: -set_num_subiterations(const int arg) -{ - this->num_subiterations = arg; +IterativeReconstruction::set_num_subiterations(const int arg) { + this->num_subiterations = arg; } template void -IterativeReconstruction:: -set_start_subiteration_num(const int arg) -{ - this->start_subiteration_num = arg; +IterativeReconstruction::set_start_subiteration_num(const int arg) { + this->start_subiteration_num = arg; } template void -IterativeReconstruction:: -set_start_subset_num(const int arg) -{ - if (arg<0 || arg>= this->num_subsets) +IterativeReconstruction::set_start_subset_num(const int arg) { + if (arg < 0 || arg >= this->num_subsets) error("set_start_subset_num out-of-range error"); - this->start_subset_num = arg; + this->start_subset_num = arg; } template void -IterativeReconstruction:: -set_save_interval(const int arg) -{ - this->save_interval = arg; +IterativeReconstruction::set_save_interval(const int arg) { + this->save_interval = arg; } template void -IterativeReconstruction:: -set_randomise_subset_order(const bool arg) -{ - this->randomise_subset_order = arg; +IterativeReconstruction::set_randomise_subset_order(const bool arg) { + this->randomise_subset_order = arg; } template void -IterativeReconstruction:: -set_inter_iteration_filter_ptr(const shared_ptr >& arg) -{ - this->inter_iteration_filter_ptr = arg; +IterativeReconstruction::set_inter_iteration_filter_ptr(const shared_ptr>& arg) { + this->inter_iteration_filter_ptr = arg; } template void -IterativeReconstruction:: -set_inter_iteration_filter_interval(const int arg) -{ - this->inter_iteration_filter_interval = arg; +IterativeReconstruction::set_inter_iteration_filter_interval(const int arg) { + this->inter_iteration_filter_interval = arg; } template void -IterativeReconstruction:: -set_report_objective_function_values_interval(const int arg) -{ +IterativeReconstruction::set_report_objective_function_values_interval(const int arg) { this->report_objective_function_values_interval = arg; } //************ other functions **************** template -IterativeReconstruction:: -IterativeReconstruction() -{ -} +IterativeReconstruction::IterativeReconstruction() {} template std::string -IterativeReconstruction:: -make_filename_prefix_subiteration_num(const std::string& filename_prefix) const -{ +IterativeReconstruction::make_filename_prefix_subiteration_num(const std::string& filename_prefix) const { char num[50]; sprintf(num, "_%d", subiteration_num); return filename_prefix + num; @@ -363,39 +316,31 @@ make_filename_prefix_subiteration_num(const std::string& filename_prefix) const template std::string -IterativeReconstruction:: -make_filename_prefix_subiteration_num() const -{ - return - this->make_filename_prefix_subiteration_num(this->output_filename_prefix); +IterativeReconstruction::make_filename_prefix_subiteration_num() const { + return this->make_filename_prefix_subiteration_num(this->output_filename_prefix); } template -TargetT * -IterativeReconstruction::get_initial_data_ptr() const -{ +TargetT* +IterativeReconstruction::get_initial_data_ptr() const { if (is_null_ptr(this->objective_function_sptr)) error("objective function needs to be set before calling get_initial_data_ptr"); - TargetT * result; + TargetT* result; - if(this->initial_data_filename=="0") - { + if (this->initial_data_filename == "0") { result = this->objective_function_sptr->construct_target_ptr(); - } - else if(this->initial_data_filename=="1") - { + } else if (this->initial_data_filename == "1") { result = this->objective_function_sptr->construct_target_ptr(); std::fill(result->begin_all(), result->end_all(), 1.F); + } else { + result = TargetT::read_from_file(this->initial_data_filename); + result->set_exam_info(*this->get_input_data().get_exam_info_sptr()); } - else - { - result = TargetT::read_from_file(this->initial_data_filename); - result->set_exam_info(*this->get_input_data().get_exam_info_sptr()); - } if (this->_already_set_up) if (!this->target_data_sptr->has_same_characteristics(*result)) - error("IterativeReconstruction::get_initial_data_ptr() results in different characteristics than what was used for set_up()"); + error( + "IterativeReconstruction::get_initial_data_ptr() results in different characteristics than what was used for set_up()"); return result; } @@ -403,18 +348,15 @@ IterativeReconstruction::get_initial_data_ptr() const // KT 10122001 new // NE Updated to be able to define the dataset to reconstruct. template -Succeeded -IterativeReconstruction:: -reconstruct() -{ +Succeeded +IterativeReconstruction::reconstruct() { this->start_timers(); this->target_data_sptr.reset(this->get_initial_data_ptr()); - if (this->set_up(this->target_data_sptr) == Succeeded::no) - { - this->stop_timers(); - return Succeeded::no; - } + if (this->set_up(this->target_data_sptr) == Succeeded::no) { + this->stop_timers(); + return Succeeded::no; + } this->stop_timers(); @@ -422,10 +364,8 @@ reconstruct() } template -Succeeded -IterativeReconstruction:: -reconstruct(shared_ptr const& target_data_sptr) -{ +Succeeded +IterativeReconstruction::reconstruct(shared_ptr const& target_data_sptr) { this->start_timers(); this->check(*target_data_sptr); #if 0 @@ -436,76 +376,81 @@ reconstruct(shared_ptr const& target_data_sptr) } #endif - for(subiteration_num=start_subiteration_num;subiteration_num<=num_subiterations && this->terminate_iterations==false; subiteration_num++) - { + for (subiteration_num = start_subiteration_num; subiteration_num <= num_subiterations && this->terminate_iterations == false; + subiteration_num++) { this->update_estimate(*target_data_sptr); this->end_of_iteration_processing(*target_data_sptr); } this->stop_timers(); - cerr << "Total CPU Time " << this->get_CPU_timer_value() << "secs"<get_CPU_timer_value() << "secs" << endl; // currently, if there was something wrong, the programme is just aborted // so, if we get here, everything was fine return Succeeded::yes; - } - template Succeeded -IterativeReconstruction:: -set_up(shared_ptr const& target_data_sptr) -{ +IterativeReconstruction::set_up(shared_ptr const& target_data_sptr) { if (base_type::set_up(target_data_sptr) == Succeeded::no) return Succeeded::no; - //initialize iteration loop terminator - this->terminate_iterations=false; + // initialize iteration loop terminator + this->terminate_iterations = false; + if (this->num_subsets < 1) { + warning("number of subsets should be positive"); + return Succeeded::no; + } - if (this->num_subsets<1 ) - { warning("number of subsets should be positive"); return Succeeded::no; } - - if (is_null_ptr(this->objective_function_sptr)) - { warning("You have to specify an objective function"); return Succeeded::no; } + if (is_null_ptr(this->objective_function_sptr)) { + warning("You have to specify an objective function"); + return Succeeded::no; + } - const int new_num_subsets = - this->objective_function_sptr->set_num_subsets(this->num_subsets); - if (new_num_subsets!=this->num_subsets) - { - warning("Number of subsets requested : %d, but actual number used is %d\n", - this->num_subsets, new_num_subsets); - this->num_subsets = new_num_subsets; - } + const int new_num_subsets = this->objective_function_sptr->set_num_subsets(this->num_subsets); + if (new_num_subsets != this->num_subsets) { + warning("Number of subsets requested : %d, but actual number used is %d\n", this->num_subsets, new_num_subsets); + this->num_subsets = new_num_subsets; + } if (this->objective_function_sptr->set_up(target_data_sptr) == Succeeded::no) return Succeeded::no; - if (this->num_subiterations<1) - { warning("Range error in number of subiterations"); return Succeeded::no; } - - if(this->start_subset_num<0 || this->start_subset_num>=this->num_subsets) - { warning("Range error in starting subset"); return Succeeded::no; } + if (this->num_subiterations < 1) { + warning("Range error in number of subiterations"); + return Succeeded::no; + } - if(this->save_interval<1 || this->save_interval>this->num_subiterations) - { warning("Range error in iteration save interval"); return Succeeded::no;} - - if (this->inter_iteration_filter_interval<0) - { warning("Range error in inter-iteration filter interval "); return Succeeded::no; } + if (this->start_subset_num < 0 || this->start_subset_num >= this->num_subsets) { + warning("Range error in starting subset"); + return Succeeded::no; + } + + if (this->save_interval < 1 || this->save_interval > this->num_subiterations) { + warning("Range error in iteration save interval"); + return Succeeded::no; + } + + if (this->inter_iteration_filter_interval < 0) { + warning("Range error in inter-iteration filter interval "); + return Succeeded::no; + } + + if (this->start_subiteration_num < 1) { + warning("Range error in starting subiteration number"); + return Succeeded::no; + } - if (this->start_subiteration_num<1) - { warning("Range error in starting subiteration number"); return Succeeded::no; } - ////////////////// subset order // KT 05/07/2000 made randomise_subset_order int - if (this->randomise_subset_order!=0){ - srand((unsigned int) (time(NULL)) ); //seed the rand() function + if (this->randomise_subset_order != 0) { + srand((unsigned int)(time(NULL))); // seed the rand() function } - // Building filters // This is not really necessary, as apply would call this anyway. // However, we have it here such that any errors in building the filters would @@ -533,101 +478,80 @@ set_up(shared_ptr const& target_data_sptr) error("Error building inter iteration filter\n"); } #endif - + return Succeeded::yes; } template -void IterativeReconstruction:: -end_of_iteration_processing(TargetT ¤t_estimate) -{ - std::stringstream cerr; +void +IterativeReconstruction::end_of_iteration_processing(TargetT& current_estimate) { + std::stringstream cerr; + + if (this->report_objective_function_values_interval > 0 && + (this->subiteration_num % this->report_objective_function_values_interval == 0 || + this->subiteration_num == this->num_subiterations)) { + /*std::*/ cerr << "Objective function values (before any additional filtering):\n" + << this->objective_function_sptr->get_objective_function_values_report(current_estimate); + } - if (this->report_objective_function_values_interval>0 && - (this->subiteration_num%this->report_objective_function_values_interval == 0 - || this->subiteration_num==this->num_subiterations)) - { - /*std::*/cerr << "Objective function values (before any additional filtering):\n" - << this->objective_function_sptr-> - get_objective_function_values_report(current_estimate); - } - - if(this->inter_iteration_filter_interval>0 && - !is_null_ptr(this->inter_iteration_filter_ptr) && - this->subiteration_num%this->inter_iteration_filter_interval==0) - { - cerr<inter_iteration_filter_ptr->apply(current_estimate); - } - - - cerr<< this->method_info() - << " subiteration #"<subiteration_num==this->num_subiterations && - !is_null_ptr(this->post_filter_sptr) ) - { - cerr<inter_iteration_filter_interval > 0 && !is_null_ptr(this->inter_iteration_filter_ptr) && + this->subiteration_num % this->inter_iteration_filter_interval == 0) { + cerr << endl << "Applying inter-iteration filter" << endl; + this->inter_iteration_filter_ptr->apply(current_estimate); + } + + cerr << this->method_info() << " subiteration #" << subiteration_num << " completed" << endl; + cerr << " min and max in current estimate " << *std::min_element(current_estimate.begin_all(), current_estimate.end_all()) + << " " << *std::max_element(current_estimate.begin_all(), current_estimate.end_all()) << endl; + + if (this->subiteration_num == this->num_subiterations && !is_null_ptr(this->post_filter_sptr)) { + cerr << endl << "Applying post-filter" << endl; this->post_filter_sptr->apply(current_estimate); - - cerr << " min and max after post-filtering " - << *std::min_element(current_estimate.begin_all(), current_estimate.end_all()) - << " " - << *std::max_element(current_estimate.begin_all(), current_estimate.end_all()) << endl; + + cerr << " min and max after post-filtering " << *std::min_element(current_estimate.begin_all(), current_estimate.end_all()) + << " " << *std::max_element(current_estimate.begin_all(), current_estimate.end_all()) << endl; } - + writeText(cerr.str().c_str(), INFORMATION_CHANNEL); // Save intermediate (or last) iteration -- if the output is not disabled - if((!(this->subiteration_num%this->save_interval) || - this->subiteration_num==this->num_subiterations) && !this->_disable_output) - { - this->output_file_format_ptr-> - write_to_file(this->make_filename_prefix_subiteration_num(), - current_estimate); - } + if ((!(this->subiteration_num % this->save_interval) || this->subiteration_num == this->num_subiterations) && + !this->_disable_output) { + this->output_file_format_ptr->write_to_file(this->make_filename_prefix_subiteration_num(), current_estimate); + } } template -VectorWithOffset -IterativeReconstruction:: -randomly_permute_subset_order() const -{ +VectorWithOffset +IterativeReconstruction::randomly_permute_subset_order() const { - VectorWithOffset temp_array(this->num_subsets),final_array(this->num_subsets); + VectorWithOffset temp_array(this->num_subsets), final_array(this->num_subsets); int index; - for(int i=0;inum_subsets;i++) temp_array[i]=i; - - for (int i=0;inum_subsets;i++) - { + for (int i = 0; i < this->num_subsets; i++) + temp_array[i] = i; - index = (int) (((float)rand()/(float)RAND_MAX)*(this->num_subsets-i)); - if (index==this->num_subsets-i) index--; - final_array[i]=temp_array[index]; - + for (int i = 0; i < this->num_subsets; i++) { - for (int j=index;jnum_subsets-(i+1);j++) - temp_array[j]=temp_array[j+1]; + index = (int)(((float)rand() / (float)RAND_MAX) * (this->num_subsets - i)); + if (index == this->num_subsets - i) + index--; + final_array[i] = temp_array[index]; - } - - cerr<num_subsets;i++) cerr<num_subsets - (i + 1); j++) + temp_array[j] = temp_array[j + 1]; + } - return final_array; + cerr << endl << "Generating new subset sequence: "; + for (int i = 0; i < this->num_subsets; i++) + cerr << final_array[i] << " "; + return final_array; } template void -IterativeReconstruction:: -set_input_data(const shared_ptr &arg) -{ +IterativeReconstruction::set_input_data(const shared_ptr& arg) { this->_already_set_up = false; if (is_null_ptr(this->objective_function_sptr)) error("objective function needs to be set before calling set_input_data"); @@ -636,41 +560,30 @@ set_input_data(const shared_ptr &arg) template const ExamData& -IterativeReconstruction:: -get_input_data() const -{ +IterativeReconstruction::get_input_data() const { if (is_null_ptr(this->objective_function_sptr)) error("objective function needs to be set before calling get_input_data"); return this->objective_function_sptr->get_input_data(); } - template int -IterativeReconstruction:: -get_subset_num() -{ - if(this->randomise_subset_order && (this->subiteration_num-1)%this->num_subsets==0) - { - this->_current_subset_array = this->randomly_permute_subset_order(); +IterativeReconstruction::get_subset_num() { + if (this->randomise_subset_order && (this->subiteration_num - 1) % this->num_subsets == 0) { + this->_current_subset_array = this->randomly_permute_subset_order(); }; - - return - this->randomise_subset_order - ? this->_current_subset_array[(this->subiteration_num-1)%this->num_subsets] - : (this->subiteration_num+this->start_subset_num-1)%this->num_subsets; + + return this->randomise_subset_order ? this->_current_subset_array[(this->subiteration_num - 1) % this->num_subsets] + : (this->subiteration_num + this->start_subset_num - 1) % this->num_subsets; } -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif -template class IterativeReconstruction >; -template class IterativeReconstruction; +template class IterativeReconstruction>; +template class IterativeReconstruction; END_NAMESPACE_STIR - - - diff --git a/src/recon_buildblock/LogcoshPrior.cxx b/src/recon_buildblock/LogcoshPrior.cxx index c05f4dd3ff..9e745def38 100644 --- a/src/recon_buildblock/LogcoshPrior.cxx +++ b/src/recon_buildblock/LogcoshPrior.cxx @@ -45,8 +45,7 @@ START_NAMESPACE_STIR template void -LogcoshPrior::initialise_keymap() -{ +LogcoshPrior::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Logcosh Prior Parameters"); this->parser.add_key("only 2D", &only_2D); @@ -59,46 +58,39 @@ LogcoshPrior::initialise_keymap() template bool -LogcoshPrior::post_processing() -{ - if (base_type::post_processing()==true) +LogcoshPrior::post_processing() { + if (base_type::post_processing() == true) return true; if (kappa_filename.size() != 0) - this->kappa_ptr = read_from_file >(kappa_filename); + this->kappa_ptr = read_from_file>(kappa_filename); bool warn_about_even_size = false; - if (this->weights.size() ==0) - { + if (this->weights.size() == 0) { // will call compute_weights() to fill it in - } - else - { - if (!this->weights.is_regular()) - { + } else { + if (!this->weights.is_regular()) { warning("Sorry. LogcoshPrior currently only supports regular arrays for the weights"); return true; } const unsigned int size_z = this->weights.size(); - if (size_z%2==0) + if (size_z % 2 == 0) warn_about_even_size = true; - const int min_index_z = -static_cast(size_z/2); + const int min_index_z = -static_cast(size_z / 2); this->weights.set_min_index(min_index_z); - for (int z = min_index_z; z<= this->weights.get_max_index(); ++z) - { + for (int z = min_index_z; z <= this->weights.get_max_index(); ++z) { const unsigned int size_y = this->weights[z].size(); - if (size_y%2==0) + if (size_y % 2 == 0) warn_about_even_size = true; - const int min_index_y = -static_cast(size_y/2); + const int min_index_y = -static_cast(size_y / 2); this->weights[z].set_min_index(min_index_y); - for (int y = min_index_y; y<= this->weights[z].get_max_index(); ++y) - { + for (int y = min_index_y; y <= this->weights[z].get_max_index(); ++y) { const unsigned int size_x = this->weights[z][y].size(); - if (size_x%2==0) + if (size_x % 2 == 0) warn_about_even_size = true; - const int min_index_x = -static_cast(size_x/2); + const int min_index_x = -static_cast(size_x / 2); this->weights[z][y].set_min_index(min_index_x); } } @@ -108,13 +100,11 @@ LogcoshPrior::post_processing() warning("Parsing LogcoshPrior: even number of weights occurred in either x,y or z dimension.\n" "I'll (effectively) make this odd by appending a 0 at the end."); return false; - } template void -LogcoshPrior::set_defaults() -{ +LogcoshPrior::set_defaults() { base_type::set_defaults(); this->only_2D = false; this->scalar = 1.0; @@ -123,30 +113,22 @@ LogcoshPrior::set_defaults() } template <> -const char * const - LogcoshPrior::registered_name = - "Logcosh"; +const char* const LogcoshPrior::registered_name = "Logcosh"; template -LogcoshPrior::LogcoshPrior() -{ +LogcoshPrior::LogcoshPrior() { set_defaults(); } - template -LogcoshPrior::LogcoshPrior(const bool only_2D_v, float penalisation_factor_v) - : only_2D(only_2D_v) -{ +LogcoshPrior::LogcoshPrior(const bool only_2D_v, float penalisation_factor_v) : only_2D(only_2D_v) { set_defaults(); this->penalisation_factor = penalisation_factor_v; } - template LogcoshPrior::LogcoshPrior(const bool only_2D_v, float penalisation_factor_v, const float scalar_v) - : only_2D(only_2D_v), scalar(scalar_v) -{ + : only_2D(only_2D_v), scalar(scalar_v) { set_defaults(); this->penalisation_factor = penalisation_factor_v; this->scalar = scalar_v; @@ -154,17 +136,17 @@ LogcoshPrior::LogcoshPrior(const bool only_2D_v, float penalisation_facto //! get penalty weights for the neighbourhood template -Array<3,float> -LogcoshPrior:: -get_weights() const -{ return this->weights; } +Array<3, float> +LogcoshPrior::get_weights() const { + return this->weights; +} //! set penalty weights for the neighbourhood template void -LogcoshPrior:: -set_weights(const Array<3,float>& w) -{ this->weights = w; } +LogcoshPrior::set_weights(const Array<3, float>& w) { + this->weights = w; +} //! get current kappa image /*! \warning As this function returns a shared_ptr, this is dangerous. You should not @@ -172,81 +154,67 @@ set_weights(const Array<3,float>& w) Unpredictable results will occur. */ template -shared_ptr > -LogcoshPrior:: -get_kappa_sptr() const -{ return this->kappa_ptr; } +shared_ptr> +LogcoshPrior::get_kappa_sptr() const { + return this->kappa_ptr; +} //! set kappa image template void -LogcoshPrior:: -set_kappa_sptr(const shared_ptr >& k) -{ this->kappa_ptr = k; } +LogcoshPrior::set_kappa_sptr(const shared_ptr>& k) { + this->kappa_ptr = k; +} //! Get the scalar value template float -LogcoshPrior:: -get_scalar() const -{ return this->scalar; } +LogcoshPrior::get_scalar() const { + return this->scalar; +} //! Set the scalar value template void -LogcoshPrior:: -set_scalar(const float scalar_v) -{ scalar = scalar_v; } - +LogcoshPrior::set_scalar(const float scalar_v) { + scalar = scalar_v; +} // TODO move to set_up // initialise to 1/Euclidean distance static void -compute_weights(Array<3,float>& weights, const CartesianCoordinate3D& grid_spacing, const bool only_2D) -{ +compute_weights(Array<3, float>& weights, const CartesianCoordinate3D& grid_spacing, const bool only_2D) { int min_dz, max_dz; - if (only_2D) - { + if (only_2D) { min_dz = max_dz = 0; - } - else - { + } else { min_dz = -1; max_dz = 1; } - weights = Array<3,float>(IndexRange3D(min_dz,max_dz,-1,1,-1,1)); - for (int z=min_dz;z<=max_dz;++z) - for (int y=-1;y<=1;++y) - for (int x=-1;x<=1;++x) - { - if (z==0 && y==0 && x==0) + weights = Array<3, float>(IndexRange3D(min_dz, max_dz, -1, 1, -1, 1)); + for (int z = min_dz; z <= max_dz; ++z) + for (int y = -1; y <= 1; ++y) + for (int x = -1; x <= 1; ++x) { + if (z == 0 && y == 0 && x == 0) weights[0][0][0] = 0; - else - { + else { weights[z][y][x] = - grid_spacing.x()/ - sqrt(square(x*grid_spacing.x())+ - square(y*grid_spacing.y())+ - square(z*grid_spacing.z())); + grid_spacing.x() / sqrt(square(x * grid_spacing.x()) + square(y * grid_spacing.y()) + square(z * grid_spacing.z())); } } } template double -LogcoshPrior:: -compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ - if (this->penalisation_factor==0) - { +LogcoshPrior::compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) { + if (this->penalisation_factor == 0) { return 0.; } - const DiscretisedDensityOnCartesianGrid<3,elemT>& current_image_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,elemT> &>(current_image_estimate); + const DiscretisedDensityOnCartesianGrid<3, elemT>& current_image_cast = + dynamic_cast&>(current_image_estimate); - if (this->weights.get_length() ==0) - { + if (this->weights.get_length() == 0) { compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); } @@ -258,26 +226,23 @@ compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) double result = 0.; const int min_z = current_image_estimate.get_min_index(); const int max_z = current_image_estimate.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - const int min_dz = max(weights.get_min_index(), min_z-z); - const int max_dz = min(weights.get_max_index(), max_z-z); + for (int z = min_z; z <= max_z; z++) { + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); const int min_y = current_image_estimate[z].get_min_index(); const int max_y = current_image_estimate[z].get_max_index(); - for (int y=min_y;y<= max_y;y++) - { - const int min_dy = max(weights[0].get_min_index(), min_y-y); - const int max_dy = min(weights[0].get_max_index(), max_y-y); + for (int y = min_y; y <= max_y; y++) { + const int min_dy = max(weights[0].get_min_index(), min_y - y); + const int max_dy = min(weights[0].get_max_index(), max_y - y); const int min_x = current_image_estimate[z][y].get_min_index(); const int max_x = current_image_estimate[z][y].get_max_index(); - for (int x=min_x;x<= max_x;x++) - { - const int min_dx = max(weights[0][0].get_min_index(), min_x-x); - const int max_dx = min(weights[0][0].get_max_index(), max_x-x); + for (int x = min_x; x <= max_x; x++) { + const int min_dx = max(weights[0][0].get_min_index(), min_x - x); + const int max_dx = min(weights[0][0].get_max_index(), max_x - x); /* formula: sum_dx,dy,dz @@ -285,41 +250,36 @@ compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) log(cosh(current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx])) * (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; */ - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { // 1/scalar^2 * log(cosh(x * scalar)) - elemT voxel_diff= current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx]; - elemT current = weights[dz][dy][dx] * 1/(this->scalar*this->scalar) * logcosh(this->scalar*voxel_diff); + elemT voxel_diff = current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx]; + elemT current = weights[dz][dy][dx] * 1 / (this->scalar * this->scalar) * logcosh(this->scalar * voxel_diff); if (do_kappa) - current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; result += static_cast(current); } } } } - return result * this->penalisation_factor/2.0; + return result * this->penalisation_factor / 2.0; } template void -LogcoshPrior:: -compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ +LogcoshPrior::compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, + const DiscretisedDensity<3, elemT>& current_image_estimate) { assert(prior_gradient.has_same_characteristics(current_image_estimate)); - if (this->penalisation_factor==0) - { + if (this->penalisation_factor == 0) { prior_gradient.fill(0); return; } - const DiscretisedDensityOnCartesianGrid<3,elemT>& current_image_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,elemT> &>(current_image_estimate); + const DiscretisedDensityOnCartesianGrid<3, elemT>& current_image_cast = + dynamic_cast&>(current_image_estimate); - if (this->weights.get_length() ==0) - { + if (this->weights.get_length() == 0) { compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); } @@ -329,42 +289,38 @@ compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, const int min_z = current_image_estimate.get_min_index(); const int max_z = current_image_estimate.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - const int min_dz = max(weights.get_min_index(), min_z-z); - const int max_dz = min(weights.get_max_index(), max_z-z); + for (int z = min_z; z <= max_z; z++) { + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); const int min_y = current_image_estimate[z].get_min_index(); const int max_y = current_image_estimate[z].get_max_index(); - for (int y=min_y;y<= max_y;y++) - { - const int min_dy = max(weights[0].get_min_index(), min_y-y); - const int max_dy = min(weights[0].get_max_index(), max_y-y); + for (int y = min_y; y <= max_y; y++) { + const int min_dy = max(weights[0].get_min_index(), min_y - y); + const int max_dy = min(weights[0].get_max_index(), max_y - y); const int min_x = current_image_estimate[z][y].get_min_index(); const int max_x = current_image_estimate[z][y].get_max_index(); - for (int x=min_x;x<= max_x;x++) - { - const int min_dx = max(weights[0][0].get_min_index(), min_x-x); - const int max_dx = min(weights[0][0].get_max_index(), max_x-x); + for (int x = min_x; x <= max_x; x++) { + const int min_dx = max(weights[0][0].get_min_index(), min_x - x); + const int max_dx = min(weights[0][0].get_max_index(), max_x - x); elemT gradient = 0; - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { // 1/scalar * tanh(x * scalar) - elemT voxel_diff= current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx]; - elemT current = weights[dz][dy][dx] * (1/this->scalar) * tanh(this->scalar*voxel_diff); + elemT voxel_diff = current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx]; + elemT current = weights[dz][dy][dx] * (1 / this->scalar) * tanh(this->scalar * voxel_diff); if (do_kappa) - current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; gradient += current; } - prior_gradient[z][y][x]= gradient * this->penalisation_factor; + prior_gradient[z][y][x] = gradient * this->penalisation_factor; } } } @@ -373,37 +329,31 @@ compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, static int count = 0; ++count; - if (gradient_filename_prefix.size()>0) - { - char *filename = new char[gradient_filename_prefix.size()+100]; + if (gradient_filename_prefix.size() > 0) { + char* filename = new char[gradient_filename_prefix.size() + 100]; sprintf(filename, "%s%d.v", gradient_filename_prefix.c_str(), count); - OutputFileFormat >::default_sptr()-> - write_to_file(filename, prior_gradient); + OutputFileFormat>::default_sptr()->write_to_file(filename, prior_gradient); delete[] filename; } } template void -LogcoshPrior:: -compute_Hessian(DiscretisedDensity<3,elemT>& prior_Hessian_for_single_densel, - const BasicCoordinate<3,int>& coords, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ - assert( prior_Hessian_for_single_densel.has_same_characteristics(current_image_estimate)); +LogcoshPrior::compute_Hessian(DiscretisedDensity<3, elemT>& prior_Hessian_for_single_densel, + const BasicCoordinate<3, int>& coords, + const DiscretisedDensity<3, elemT>& current_image_estimate) { + assert(prior_Hessian_for_single_densel.has_same_characteristics(current_image_estimate)); prior_Hessian_for_single_densel.fill(0); - if (this->penalisation_factor==0) - { + if (this->penalisation_factor == 0) { return; } - const DiscretisedDensityOnCartesianGrid<3,elemT>& current_image_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,elemT> &>(current_image_estimate); + const DiscretisedDensityOnCartesianGrid<3, elemT>& current_image_cast = + dynamic_cast&>(current_image_estimate); - DiscretisedDensityOnCartesianGrid<3,elemT>& prior_Hessian_for_single_densel_cast = - dynamic_cast &>(prior_Hessian_for_single_densel); + DiscretisedDensityOnCartesianGrid<3, elemT>& prior_Hessian_for_single_densel_cast = + dynamic_cast&>(prior_Hessian_for_single_densel); - if (weights.get_length() ==0) - { + if (weights.get_length() == 0) { compute_weights(weights, current_image_cast.get_grid_spacing(), this->only_2D); } @@ -415,52 +365,48 @@ compute_Hessian(DiscretisedDensity<3,elemT>& prior_Hessian_for_single_densel, const int z = coords[1]; const int y = coords[2]; const int x = coords[3]; - const int min_dz = max(weights.get_min_index(), prior_Hessian_for_single_densel.get_min_index()-z); - const int max_dz = min(weights.get_max_index(), prior_Hessian_for_single_densel.get_max_index()-z); + const int min_dz = max(weights.get_min_index(), prior_Hessian_for_single_densel.get_min_index() - z); + const int max_dz = min(weights.get_max_index(), prior_Hessian_for_single_densel.get_max_index() - z); - const int min_dy = max(weights[0].get_min_index(), prior_Hessian_for_single_densel[z].get_min_index()-y); - const int max_dy = min(weights[0].get_max_index(), prior_Hessian_for_single_densel[z].get_max_index()-y); + const int min_dy = max(weights[0].get_min_index(), prior_Hessian_for_single_densel[z].get_min_index() - y); + const int max_dy = min(weights[0].get_max_index(), prior_Hessian_for_single_densel[z].get_max_index() - y); - const int min_dx = max(weights[0][0].get_min_index(), prior_Hessian_for_single_densel[z][y].get_min_index()-x); - const int max_dx = min(weights[0][0].get_max_index(), prior_Hessian_for_single_densel[z][y].get_max_index()-x); + const int min_dx = max(weights[0][0].get_min_index(), prior_Hessian_for_single_densel[z][y].get_min_index() - x); + const int max_dx = min(weights[0][0].get_max_index(), prior_Hessian_for_single_densel[z][y].get_max_index() - x); elemT diagonal = 0; - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { // sech^2(x * scalar); sech(x) = 1/cosh(x) - elemT voxel_diff= current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx]; + elemT voxel_diff = current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx]; elemT current = weights[dz][dy][dx] * Hessian(voxel_diff, this->scalar); if (do_kappa) - current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; diagonal += current; - prior_Hessian_for_single_densel_cast[z+dz][y+dy][x+dx] = -current*this->penalisation_factor; + prior_Hessian_for_single_densel_cast[z + dz][y + dy][x + dx] = -current * this->penalisation_factor; } - prior_Hessian_for_single_densel[z][y][x]= diagonal * this->penalisation_factor; + prior_Hessian_for_single_densel[z][y][x] = diagonal * this->penalisation_factor; } template void -LogcoshPrior::parabolic_surrogate_curvature(DiscretisedDensity<3,elemT>& parabolic_surrogate_curvature, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ +LogcoshPrior::parabolic_surrogate_curvature(DiscretisedDensity<3, elemT>& parabolic_surrogate_curvature, + const DiscretisedDensity<3, elemT>& current_image_estimate) { - assert( parabolic_surrogate_curvature.has_same_characteristics(current_image_estimate)); - if (this->penalisation_factor==0) - { + assert(parabolic_surrogate_curvature.has_same_characteristics(current_image_estimate)); + if (this->penalisation_factor == 0) { parabolic_surrogate_curvature.fill(0); return; } - const DiscretisedDensityOnCartesianGrid<3,elemT>& current_image_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,elemT> &>(current_image_estimate); + const DiscretisedDensityOnCartesianGrid<3, elemT>& current_image_cast = + dynamic_cast&>(current_image_estimate); - if (weights.get_length() ==0) - { + if (weights.get_length() == 0) { compute_weights(weights, current_image_cast.get_grid_spacing(), this->only_2D); } @@ -471,68 +417,60 @@ LogcoshPrior::parabolic_surrogate_curvature(DiscretisedDensity<3,elemT>& const int min_z = current_image_estimate.get_min_index(); const int max_z = current_image_estimate.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - const int min_dz = max(weights.get_min_index(), min_z-z); - const int max_dz = min(weights.get_max_index(), max_z-z); + for (int z = min_z; z <= max_z; z++) { + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); const int min_y = current_image_estimate[z].get_min_index(); const int max_y = current_image_estimate[z].get_max_index(); - for (int y=min_y;y<= max_y;y++) - { - const int min_dy = max(weights[0].get_min_index(), min_y-y); - const int max_dy = min(weights[0].get_max_index(), max_y-y); + for (int y = min_y; y <= max_y; y++) { + const int min_dy = max(weights[0].get_min_index(), min_y - y); + const int max_dy = min(weights[0].get_max_index(), max_y - y); const int min_x = current_image_estimate[z][y].get_min_index(); const int max_x = current_image_estimate[z][y].get_max_index(); - for (int x=min_x;x<= max_x;x++) - { - const int min_dx = max(weights[0][0].get_min_index(), min_x-x); - const int max_dx = min(weights[0][0].get_max_index(), max_x-x); + for (int x = min_x; x <= max_x; x++) { + const int min_dx = max(weights[0][0].get_min_index(), min_x - x); + const int max_dx = min(weights[0][0].get_max_index(), max_x - x); elemT gradient = 0; - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { // psi'(t)/t = tanh/t - elemT voxel_diff=current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx]; + elemT voxel_diff = current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx]; elemT current = weights[dz][dy][dx] * surrogate(voxel_diff, this->scalar); if (do_kappa) - current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; gradient += current; } - parabolic_surrogate_curvature[z][y][x]= gradient * this->penalisation_factor; + parabolic_surrogate_curvature[z][y][x] = gradient * this->penalisation_factor; } } } - info(boost::format("parabolic_surrogate_curvature max %1%, min %2%\n") % parabolic_surrogate_curvature.find_max() % parabolic_surrogate_curvature.find_min()); + info(boost::format("parabolic_surrogate_curvature max %1%, min %2%\n") % parabolic_surrogate_curvature.find_max() % + parabolic_surrogate_curvature.find_min()); } template Succeeded -LogcoshPrior:: -accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& current_estimate, - const DiscretisedDensity<3,elemT>& input) const -{ +LogcoshPrior::accumulate_Hessian_times_input(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& current_estimate, + const DiscretisedDensity<3, elemT>& input) const { // TODO this function overlaps enormously with parabolic_surrogate_curvature // the only difference is that parabolic_surrogate_curvature uses input==1 - assert( output.has_same_characteristics(input)); - if (this->penalisation_factor==0) - { + assert(output.has_same_characteristics(input)); + if (this->penalisation_factor == 0) { return Succeeded::yes; } - DiscretisedDensityOnCartesianGrid<3,elemT>& output_cast = - dynamic_cast &>(output); + DiscretisedDensityOnCartesianGrid<3, elemT>& output_cast = dynamic_cast&>(output); - if (weights.get_length() ==0) - { + if (weights.get_length() == 0) { compute_weights(weights, output_cast.get_grid_spacing(), this->only_2D); } @@ -543,37 +481,33 @@ accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, const int min_z = output.get_min_index(); const int max_z = output.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - const int min_dz = max(weights.get_min_index(), min_z-z); - const int max_dz = min(weights.get_max_index(), max_z-z); + for (int z = min_z; z <= max_z; z++) { + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); const int min_y = output[z].get_min_index(); const int max_y = output[z].get_max_index(); - for (int y=min_y;y<= max_y;y++) - { - const int min_dy = max(weights[0].get_min_index(), min_y-y); - const int max_dy = min(weights[0].get_max_index(), max_y-y); + for (int y = min_y; y <= max_y; y++) { + const int min_dy = max(weights[0].get_min_index(), min_y - y); + const int max_dy = min(weights[0].get_max_index(), max_y - y); const int min_x = output[z][y].get_min_index(); const int max_x = output[z][y].get_max_index(); - for (int x=min_x;x<= max_x;x++) - { - const int min_dx = max(weights[0][0].get_min_index(), min_x-x); - const int max_dx = min(weights[0][0].get_max_index(), max_x-x); + for (int x = min_x; x <= max_x; x++) { + const int min_dx = max(weights[0][0].get_min_index(), min_x - x); + const int max_dx = min(weights[0][0].get_max_index(), max_x - x); elemT result = 0; - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { - elemT voxel_diff= current_estimate[z][y][x] - current_estimate[z+dz][y+dy][x+dx]; - elemT current = weights[dz][dy][dx] * Hessian( voxel_diff, this->scalar) * input[z+dz][y+dy][x+dx]; + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { + elemT voxel_diff = current_estimate[z][y][x] - current_estimate[z + dz][y + dy][x + dx]; + elemT current = weights[dz][dy][dx] * Hessian(voxel_diff, this->scalar) * input[z + dz][y + dy][x + dx]; if (do_kappa) - current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; result += current; } @@ -585,12 +519,12 @@ accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, return Succeeded::yes; } -# ifdef _MSC_VER - // prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif +# pragma warning(disable : 4660) +#endif - template class LogcoshPrior; +template class LogcoshPrior; END_NAMESPACE_STIR diff --git a/src/recon_buildblock/NiftyPET_projector/BackProjectorByBinNiftyPET.cxx b/src/recon_buildblock/NiftyPET_projector/BackProjectorByBinNiftyPET.cxx index 2dab2c4994..ab2fc28430 100644 --- a/src/recon_buildblock/NiftyPET_projector/BackProjectorByBinNiftyPET.cxx +++ b/src/recon_buildblock/NiftyPET_projector/BackProjectorByBinNiftyPET.cxx @@ -8,7 +8,7 @@ \brief non-inline implementations for stir::BackProjectorByBinNiftyPET \author Richard Brown - + */ /* Copyright (C) 2019, University College London @@ -38,24 +38,16 @@ START_NAMESPACE_STIR ////////////////////////////////////////////////////////// -const char * const -BackProjectorByBinNiftyPET::registered_name = - "NiftyPET"; - -BackProjectorByBinNiftyPET::BackProjectorByBinNiftyPET() : - _cuda_device(0), _cuda_verbosity(true), _use_truncation(false) -{ - this->_already_set_up = false; -} +const char* const BackProjectorByBinNiftyPET::registered_name = "NiftyPET"; -BackProjectorByBinNiftyPET::~BackProjectorByBinNiftyPET() -{ +BackProjectorByBinNiftyPET::BackProjectorByBinNiftyPET() : _cuda_device(0), _cuda_verbosity(true), _use_truncation(false) { + this->_already_set_up = false; } +BackProjectorByBinNiftyPET::~BackProjectorByBinNiftyPET() {} + void -BackProjectorByBinNiftyPET:: -initialise_keymap() -{ +BackProjectorByBinNiftyPET::initialise_keymap() { parser.add_start_key("Back Projector Using NiftyPET Parameters"); parser.add_stop_key("End Back Projector Using NiftyPET Parameters"); parser.add_key("CUDA device", &_cuda_device); @@ -63,106 +55,91 @@ initialise_keymap() } void -BackProjectorByBinNiftyPET:: -set_up(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_info_sptr) -{ - BackProjectorByBin::set_up(proj_data_info_sptr,density_info_sptr); - check(*proj_data_info_sptr, *_density_sptr); - _symmetries_sptr.reset(new TrivialDataSymmetriesForBins(proj_data_info_sptr)); - - // Get span - shared_ptr - proj_data_info_cy_no_ar_cor_sptr( - dynamic_pointer_cast( - proj_data_info_sptr)); - if (is_null_ptr(proj_data_info_cy_no_ar_cor_sptr)) - error("BackProjectorByBinNiftyPET: Failed casting to ProjDataInfoCylindricalNoArcCorr"); - int span = proj_data_info_cy_no_ar_cor_sptr->get_max_ring_difference(0) - - proj_data_info_cy_no_ar_cor_sptr->get_min_ring_difference(0) + 1; - - // Set up the niftyPET binary helper - _helper.set_cuda_device_id ( _cuda_device ); - _helper.set_scanner_type(proj_data_info_sptr->get_scanner_ptr()->get_type()); - _helper.set_span ( static_cast(span) ); - _helper.set_att(0); - _helper.set_verbose(_cuda_verbosity); - _helper.set_up(); - - // Create sinogram - _np_sino_w_gaps = _helper.create_niftyPET_sinogram_with_gaps(); +BackProjectorByBinNiftyPET::set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& density_info_sptr) { + BackProjectorByBin::set_up(proj_data_info_sptr, density_info_sptr); + check(*proj_data_info_sptr, *_density_sptr); + _symmetries_sptr.reset(new TrivialDataSymmetriesForBins(proj_data_info_sptr)); + + // Get span + shared_ptr proj_data_info_cy_no_ar_cor_sptr( + dynamic_pointer_cast(proj_data_info_sptr)); + if (is_null_ptr(proj_data_info_cy_no_ar_cor_sptr)) + error("BackProjectorByBinNiftyPET: Failed casting to ProjDataInfoCylindricalNoArcCorr"); + int span = proj_data_info_cy_no_ar_cor_sptr->get_max_ring_difference(0) - + proj_data_info_cy_no_ar_cor_sptr->get_min_ring_difference(0) + 1; + + // Set up the niftyPET binary helper + _helper.set_cuda_device_id(_cuda_device); + _helper.set_scanner_type(proj_data_info_sptr->get_scanner_ptr()->get_type()); + _helper.set_span(static_cast(span)); + _helper.set_att(0); + _helper.set_verbose(_cuda_verbosity); + _helper.set_up(); + + // Create sinogram + _np_sino_w_gaps = _helper.create_niftyPET_sinogram_with_gaps(); } -const DataSymmetriesForViewSegmentNumbers * -BackProjectorByBinNiftyPET:: -get_symmetries_used() const -{ +const DataSymmetriesForViewSegmentNumbers* +BackProjectorByBinNiftyPET::get_symmetries_used() const { if (!this->_already_set_up) error("BackProjectorByBin method called without calling set_up first."); return _symmetries_sptr.get(); } void -BackProjectorByBinNiftyPET:: -back_project(const ProjData& proj_data, int subset_num, int num_subsets) -{ - // Check the user has tried to project all data - if (subset_num != 0 || num_subsets != 1) - error("BackProjectorByBinNiftyPET::back_project " - "only works with all data (no subsets)."); - - _helper.convert_proj_data_stir_to_niftyPET(_np_sino_w_gaps,proj_data); +BackProjectorByBinNiftyPET::back_project(const ProjData& proj_data, int subset_num, int num_subsets) { + // Check the user has tried to project all data + if (subset_num != 0 || num_subsets != 1) + error("BackProjectorByBinNiftyPET::back_project " + "only works with all data (no subsets)."); + + _helper.convert_proj_data_stir_to_niftyPET(_np_sino_w_gaps, proj_data); } void -BackProjectorByBinNiftyPET:: -get_output(DiscretisedDensity<3,float> &density) const -{ - // --------------------------------------------------------------- // - // Remove gaps from sinogram - // --------------------------------------------------------------- // - - std::vector sino_no_gaps = _helper.create_niftyPET_sinogram_no_gaps(); - _helper.remove_gaps(sino_no_gaps, _np_sino_w_gaps); - - // --------------------------------------------------------------- // - // Back project - // --------------------------------------------------------------- // - - std::vector np_im = _helper.create_niftyPET_image(); - _helper.back_project(np_im,sino_no_gaps); - - // --------------------------------------------------------------- // - // NiftyPET -> STIR image conversion - // --------------------------------------------------------------- // - - _helper.convert_image_niftyPET_to_stir(density,np_im); - - // After the back projection, we enforce a truncation outside of the FOV. - // This is because the NiftyPET FOV is smaller than the STIR FOV and this - // could cause some voxel values to spiral out of control. - if (_use_truncation) - truncate_rim(density,17); +BackProjectorByBinNiftyPET::get_output(DiscretisedDensity<3, float>& density) const { + // --------------------------------------------------------------- // + // Remove gaps from sinogram + // --------------------------------------------------------------- // + + std::vector sino_no_gaps = _helper.create_niftyPET_sinogram_no_gaps(); + _helper.remove_gaps(sino_no_gaps, _np_sino_w_gaps); + + // --------------------------------------------------------------- // + // Back project + // --------------------------------------------------------------- // + + std::vector np_im = _helper.create_niftyPET_image(); + _helper.back_project(np_im, sino_no_gaps); + + // --------------------------------------------------------------- // + // NiftyPET -> STIR image conversion + // --------------------------------------------------------------- // + + _helper.convert_image_niftyPET_to_stir(density, np_im); + + // After the back projection, we enforce a truncation outside of the FOV. + // This is because the NiftyPET FOV is smaller than the STIR FOV and this + // could cause some voxel values to spiral out of control. + if (_use_truncation) + truncate_rim(density, 17); } void -BackProjectorByBinNiftyPET:: -start_accumulating_in_new_target() -{ - // Call base level - BackProjectorByBin::start_accumulating_in_new_target(); - // Also reset the NiftyPET sinogram - _np_sino_w_gaps = _helper.create_niftyPET_sinogram_with_gaps(); +BackProjectorByBinNiftyPET::start_accumulating_in_new_target() { + // Call base level + BackProjectorByBin::start_accumulating_in_new_target(); + // Also reset the NiftyPET sinogram + _np_sino_w_gaps = _helper.create_niftyPET_sinogram_with_gaps(); } void -BackProjectorByBinNiftyPET:: -actual_back_project(const RelatedViewgrams& related_viewgrams, - const int, const int, - const int, const int) -{ - for(stir::RelatedViewgrams::const_iterator iter = related_viewgrams.begin(); iter != related_viewgrams.end(); ++iter) - _helper.convert_viewgram_stir_to_niftyPET(_np_sino_w_gaps,*iter); +BackProjectorByBinNiftyPET::actual_back_project(const RelatedViewgrams& related_viewgrams, const int, const int, const int, + const int) { + for (stir::RelatedViewgrams::const_iterator iter = related_viewgrams.begin(); iter != related_viewgrams.end(); ++iter) + _helper.convert_viewgram_stir_to_niftyPET(_np_sino_w_gaps, *iter); } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.cxx b/src/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.cxx index 0635abcaf0..4b9fbb51de 100644 --- a/src/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.cxx +++ b/src/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.cxx @@ -40,24 +40,16 @@ START_NAMESPACE_STIR ////////////////////////////////////////////////////////// -const char * const -ForwardProjectorByBinNiftyPET::registered_name = - "NiftyPET"; - -ForwardProjectorByBinNiftyPET::ForwardProjectorByBinNiftyPET() : - _cuda_device(0), _cuda_verbosity(true), _use_truncation(false) -{ - this->_already_set_up = false; -} +const char* const ForwardProjectorByBinNiftyPET::registered_name = "NiftyPET"; -ForwardProjectorByBinNiftyPET::~ForwardProjectorByBinNiftyPET() -{ +ForwardProjectorByBinNiftyPET::ForwardProjectorByBinNiftyPET() : _cuda_device(0), _cuda_verbosity(true), _use_truncation(false) { + this->_already_set_up = false; } +ForwardProjectorByBinNiftyPET::~ForwardProjectorByBinNiftyPET() {} + void -ForwardProjectorByBinNiftyPET:: -initialise_keymap() -{ +ForwardProjectorByBinNiftyPET::initialise_keymap() { parser.add_start_key("Forward Projector Using NiftyPET Parameters"); parser.add_stop_key("End Forward Projector Using NiftyPET Parameters"); parser.add_key("CUDA device", &_cuda_device); @@ -65,108 +57,91 @@ initialise_keymap() } void -ForwardProjectorByBinNiftyPET:: -set_up(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_info_sptr) -{ - ForwardProjectorByBin::set_up(proj_data_info_sptr,density_info_sptr); - check(*proj_data_info_sptr, *_density_sptr); - _symmetries_sptr.reset(new TrivialDataSymmetriesForBins(proj_data_info_sptr)); - - // Get span - shared_ptr - proj_data_info_cy_no_ar_cor_sptr( - dynamic_pointer_cast( - proj_data_info_sptr)); - if (is_null_ptr(proj_data_info_cy_no_ar_cor_sptr)) - error("ForwardProjectorByBinNiftyPET: Failed casting to ProjDataInfoCylindricalNoArcCorr"); - int span = proj_data_info_cy_no_ar_cor_sptr->get_max_ring_difference(0) - - proj_data_info_cy_no_ar_cor_sptr->get_min_ring_difference(0) + 1; - - // Initialise projected_data_sptr from this->_proj_data_info_sptr - _projected_data_sptr.reset( - new ProjDataInMemory(this->_density_sptr->get_exam_info_sptr(), proj_data_info_sptr)); - - // Set up the niftyPET binary helper - _helper.set_scanner_type(proj_data_info_sptr->get_scanner_ptr()->get_type()); - _helper.set_cuda_device_id ( _cuda_device ); - _helper.set_span ( static_cast(span) ); - _helper.set_att(0); - _helper.set_verbose(_cuda_verbosity); - _helper.set_up(); +ForwardProjectorByBinNiftyPET::set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& density_info_sptr) { + ForwardProjectorByBin::set_up(proj_data_info_sptr, density_info_sptr); + check(*proj_data_info_sptr, *_density_sptr); + _symmetries_sptr.reset(new TrivialDataSymmetriesForBins(proj_data_info_sptr)); + + // Get span + shared_ptr proj_data_info_cy_no_ar_cor_sptr( + dynamic_pointer_cast(proj_data_info_sptr)); + if (is_null_ptr(proj_data_info_cy_no_ar_cor_sptr)) + error("ForwardProjectorByBinNiftyPET: Failed casting to ProjDataInfoCylindricalNoArcCorr"); + int span = proj_data_info_cy_no_ar_cor_sptr->get_max_ring_difference(0) - + proj_data_info_cy_no_ar_cor_sptr->get_min_ring_difference(0) + 1; + + // Initialise projected_data_sptr from this->_proj_data_info_sptr + _projected_data_sptr.reset(new ProjDataInMemory(this->_density_sptr->get_exam_info_sptr(), proj_data_info_sptr)); + + // Set up the niftyPET binary helper + _helper.set_scanner_type(proj_data_info_sptr->get_scanner_ptr()->get_type()); + _helper.set_cuda_device_id(_cuda_device); + _helper.set_span(static_cast(span)); + _helper.set_att(0); + _helper.set_verbose(_cuda_verbosity); + _helper.set_up(); } -const DataSymmetriesForViewSegmentNumbers * -ForwardProjectorByBinNiftyPET:: -get_symmetries_used() const -{ +const DataSymmetriesForViewSegmentNumbers* +ForwardProjectorByBinNiftyPET::get_symmetries_used() const { if (!this->_already_set_up) error("ForwardProjectorByBin method called without calling set_up first."); return _symmetries_sptr.get(); } void -ForwardProjectorByBinNiftyPET:: -actual_forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int, const int, - const int, const int) -{ - throw std::runtime_error("Need to use set_input() if wanting to use ForwardProjectorByBinNiftyPET."); +ForwardProjectorByBinNiftyPET::actual_forward_project(RelatedViewgrams&, const DiscretisedDensity<3, float>&, const int, + const int, const int, const int) { + throw std::runtime_error("Need to use set_input() if wanting to use ForwardProjectorByBinNiftyPET."); } void -ForwardProjectorByBinNiftyPET:: -actual_forward_project(RelatedViewgrams& viewgrams, - const int, const int, - const int, const int) -{ -// if (min_axial_pos_num != _proj_data_info_sptr->get_min_axial_pos_num() || -// ... ) -// error(); - - viewgrams = _projected_data_sptr->get_related_viewgrams( - viewgrams.get_basic_view_segment_num(), _symmetries_sptr); +ForwardProjectorByBinNiftyPET::actual_forward_project(RelatedViewgrams& viewgrams, const int, const int, const int, + const int) { + // if (min_axial_pos_num != _proj_data_info_sptr->get_min_axial_pos_num() || + // ... ) + // error(); + + viewgrams = _projected_data_sptr->get_related_viewgrams(viewgrams.get_basic_view_segment_num(), _symmetries_sptr); } void -ForwardProjectorByBinNiftyPET:: -set_input(const DiscretisedDensity<3,float> & density) -{ - ForwardProjectorByBin::set_input(density); +ForwardProjectorByBinNiftyPET::set_input(const DiscretisedDensity<3, float>& density) { + ForwardProjectorByBin::set_input(density); - // Before forward projection, we enforce a truncation outside of the FOV. - // This is because the NiftyPET FOV is smaller than the STIR FOV and this - // could cause some voxel values to spiral out of control. - if (_use_truncation) - truncate_rim(*_density_sptr,17); + // Before forward projection, we enforce a truncation outside of the FOV. + // This is because the NiftyPET FOV is smaller than the STIR FOV and this + // could cause some voxel values to spiral out of control. + if (_use_truncation) + truncate_rim(*_density_sptr, 17); - // --------------------------------------------------------------- // - // STIR -> NiftyPET image data conversion - // --------------------------------------------------------------- // + // --------------------------------------------------------------- // + // STIR -> NiftyPET image data conversion + // --------------------------------------------------------------- // - std::vector np_vec = _helper.create_niftyPET_image(); - _helper.convert_image_stir_to_niftyPET(np_vec,*_density_sptr); + std::vector np_vec = _helper.create_niftyPET_image(); + _helper.convert_image_stir_to_niftyPET(np_vec, *_density_sptr); - // --------------------------------------------------------------- // - // Forward projection - // --------------------------------------------------------------- // + // --------------------------------------------------------------- // + // Forward projection + // --------------------------------------------------------------- // - std::vector sino_no_gaps = _helper.create_niftyPET_sinogram_no_gaps(); - _helper.forward_project(sino_no_gaps, np_vec); + std::vector sino_no_gaps = _helper.create_niftyPET_sinogram_no_gaps(); + _helper.forward_project(sino_no_gaps, np_vec); - // --------------------------------------------------------------- // - // Put gaps back into sinogram - // --------------------------------------------------------------- // + // --------------------------------------------------------------- // + // Put gaps back into sinogram + // --------------------------------------------------------------- // - std::vector sino_w_gaps = _helper.create_niftyPET_sinogram_with_gaps(); - _helper.put_gaps(sino_w_gaps, sino_no_gaps); + std::vector sino_w_gaps = _helper.create_niftyPET_sinogram_with_gaps(); + _helper.put_gaps(sino_w_gaps, sino_no_gaps); - // --------------------------------------------------------------- // - // NiftyPET -> STIR projection data conversion - // --------------------------------------------------------------- // + // --------------------------------------------------------------- // + // NiftyPET -> STIR projection data conversion + // --------------------------------------------------------------- // - _helper.convert_proj_data_niftyPET_to_stir(*_projected_data_sptr,sino_w_gaps); + _helper.convert_proj_data_niftyPET_to_stir(*_projected_data_sptr, sino_w_gaps); } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/NiftyPET_projector/NiftyPETHelper.cxx b/src/recon_buildblock/NiftyPET_projector/NiftyPETHelper.cxx index c5e7bdc32d..6028679292 100644 --- a/src/recon_buildblock/NiftyPET_projector/NiftyPETHelper.cxx +++ b/src/recon_buildblock/NiftyPET_projector/NiftyPETHelper.cxx @@ -57,1255 +57,1169 @@ START_NAMESPACE_STIR NiftyPETHelper::~NiftyPETHelper() {} -static void delete_axialLUT(axialLUT *axlut_ptr) -{ - if (!axlut_ptr) return; - delete [] axlut_ptr->li2rno; - delete [] axlut_ptr->li2sn; - delete [] axlut_ptr->li2nos; - delete [] axlut_ptr->sn1_rno; - delete [] axlut_ptr->sn1_sn11; - delete [] axlut_ptr->sn1_ssrb; - delete [] axlut_ptr->sn1_sn11no; +static void +delete_axialLUT(axialLUT* axlut_ptr) { + if (!axlut_ptr) + return; + delete[] axlut_ptr->li2rno; + delete[] axlut_ptr->li2sn; + delete[] axlut_ptr->li2nos; + delete[] axlut_ptr->sn1_rno; + delete[] axlut_ptr->sn1_sn11; + delete[] axlut_ptr->sn1_ssrb; + delete[] axlut_ptr->sn1_sn11no; } -static void delete_txLUT(txLUTs *txluts_ptr) -{ - if (!txluts_ptr) return; - free(txluts_ptr->s2cF); - free(txluts_ptr->c2sF); - free(txluts_ptr->cr2s); - free(txluts_ptr->s2c); - free(txluts_ptr->s2cr); - free(txluts_ptr->aw2sn); - free(txluts_ptr->aw2ali); - free(txluts_ptr->crsr); - free(txluts_ptr->msino); - free(txluts_ptr->cij); +static void +delete_txLUT(txLUTs* txluts_ptr) { + if (!txluts_ptr) + return; + free(txluts_ptr->s2cF); + free(txluts_ptr->c2sF); + free(txluts_ptr->cr2s); + free(txluts_ptr->s2c); + free(txluts_ptr->s2cr); + free(txluts_ptr->aw2sn); + free(txluts_ptr->aw2ali); + free(txluts_ptr->crsr); + free(txluts_ptr->msino); + free(txluts_ptr->cij); } -static -shared_ptr get_cnst(const Scanner &scanner, const bool cuda_verbose, const char cuda_device, const char span) -{ - shared_ptr cnt_sptr = MAKE_SHARED(); - - cnt_sptr->DEVID = cuda_device; // device (GPU) ID. allows choosing the device on which to perform calculations - cnt_sptr->VERBOSE = cuda_verbose; - - if (scanner.get_type() == Scanner::Siemens_mMR) { - if (!(span==0 || span==1 || span==11)) - throw std::runtime_error("NiftyPETHelper::getcnst() " - "only spans 0, 1 and 11 supported for scanner type: " + scanner.get_name()); - - cnt_sptr->A = NSANGLES; //sino angles - cnt_sptr->W = NSBINS; // sino bins for any angular index - cnt_sptr->aw = AW; //sino bins (active only) - - cnt_sptr->NCRS = nCRS; //number of crystals - cnt_sptr->NCRSR = nCRSR; //reduced number of crystals by gaps - cnt_sptr->NRNG = NRINGS; //number of axial rings - cnt_sptr->D = -1; //number of linear indexes along Michelogram diagonals /*unknown*/ - cnt_sptr->Bt = -1; //number of buckets transaxially /*unknown*/ - - cnt_sptr->B = NBUCKTS; //number of buckets (total) - cnt_sptr->Cbt = 32552; //number of crystals in bucket transaxially /*unknown*/ - cnt_sptr->Cba = 3; //number of crystals in bucket axially /*unknown*/ - - cnt_sptr->NSN1 = NSINOS; //number of sinos in span-1 - cnt_sptr->NSN11 = NSINOS11; //in span-11 - cnt_sptr->NSN64 = NRINGS*NRINGS; //with no MRD limit - - cnt_sptr->SPN = span; //span-1 (s=1) or span-11 (s=11, default) or SSRB (s=0) - cnt_sptr->NSEG0 = SEG0; - - cnt_sptr->RNG_STRT = 0; - cnt_sptr->RNG_END = NRINGS; - - cnt_sptr->TGAP = 9; // get the crystal gaps right in the sinogram, period and offset given /*unknown*/ - cnt_sptr->OFFGAP = 1; /*unknown*/ - - cnt_sptr->NSCRS = 21910; // number of scatter crystals used in scatter estimation /*unknown*/ - std::vector sct_irng = {0, 10, 19, 28, 35, 44, 53, 63}; // scatter ring definition - cnt_sptr->NSRNG = int(sct_irng.size()); - cnt_sptr->MRD = mxRD; // maximum ring difference - - cnt_sptr->ALPHA = aLPHA; //angle subtended by a crystal - float R = 32.8f; // ring radius - cnt_sptr->RE = R + 0.67f; // effective ring radius accounting for the depth of interaction - cnt_sptr->AXR = SZ_RING; //axial crystal dim - - cnt_sptr->COSUPSMX = 0.725f; //cosine of max allowed scatter angle - cnt_sptr->COSSTP = (1-cnt_sptr->COSUPSMX)/(255); //cosine step - - cnt_sptr->TOFBINN = 1; // number of TOF bins - cnt_sptr->TOFBINS = 3.9e-10f; // size of TOF bin in [ps] - float CLGHT = 29979245800.f; // speed of light [cm/s] - cnt_sptr->TOFBIND = cnt_sptr->TOFBINS * CLGHT; // size of TOF BIN in cm of travelled distance - cnt_sptr->ITOFBIND = 1.f / cnt_sptr->TOFBIND; // inverse of above - - cnt_sptr->BTP = 0; //0: no bootstrapping, 1: no-parametric, 2: parametric (recommended) - cnt_sptr->BTPRT = 1.f; // ratio of bootstrapped/original events in the target sinogram (1.0 default) - - cnt_sptr->ETHRLD = 0.05f; // intensity percentage threshold of voxels to be considered in the image - } - else - throw std::runtime_error("NiftyPETHelper::getcnst() " - "not implemented for scanner type: " + scanner.get_name()); - return cnt_sptr; +static shared_ptr +get_cnst(const Scanner& scanner, const bool cuda_verbose, const char cuda_device, const char span) { + shared_ptr cnt_sptr = MAKE_SHARED(); + + cnt_sptr->DEVID = cuda_device; // device (GPU) ID. allows choosing the device on which to perform calculations + cnt_sptr->VERBOSE = cuda_verbose; + + if (scanner.get_type() == Scanner::Siemens_mMR) { + if (!(span == 0 || span == 1 || span == 11)) + throw std::runtime_error("NiftyPETHelper::getcnst() " + "only spans 0, 1 and 11 supported for scanner type: " + + scanner.get_name()); + + cnt_sptr->A = NSANGLES; // sino angles + cnt_sptr->W = NSBINS; // sino bins for any angular index + cnt_sptr->aw = AW; // sino bins (active only) + + cnt_sptr->NCRS = nCRS; // number of crystals + cnt_sptr->NCRSR = nCRSR; // reduced number of crystals by gaps + cnt_sptr->NRNG = NRINGS; // number of axial rings + cnt_sptr->D = -1; // number of linear indexes along Michelogram diagonals /*unknown*/ + cnt_sptr->Bt = -1; // number of buckets transaxially /*unknown*/ + + cnt_sptr->B = NBUCKTS; // number of buckets (total) + cnt_sptr->Cbt = 32552; // number of crystals in bucket transaxially /*unknown*/ + cnt_sptr->Cba = 3; // number of crystals in bucket axially /*unknown*/ + + cnt_sptr->NSN1 = NSINOS; // number of sinos in span-1 + cnt_sptr->NSN11 = NSINOS11; // in span-11 + cnt_sptr->NSN64 = NRINGS * NRINGS; // with no MRD limit + + cnt_sptr->SPN = span; // span-1 (s=1) or span-11 (s=11, default) or SSRB (s=0) + cnt_sptr->NSEG0 = SEG0; + + cnt_sptr->RNG_STRT = 0; + cnt_sptr->RNG_END = NRINGS; + + cnt_sptr->TGAP = 9; // get the crystal gaps right in the sinogram, period and offset given /*unknown*/ + cnt_sptr->OFFGAP = 1; /*unknown*/ + + cnt_sptr->NSCRS = 21910; // number of scatter crystals used in scatter estimation /*unknown*/ + std::vector sct_irng = {0, 10, 19, 28, 35, 44, 53, 63}; // scatter ring definition + cnt_sptr->NSRNG = int(sct_irng.size()); + cnt_sptr->MRD = mxRD; // maximum ring difference + + cnt_sptr->ALPHA = aLPHA; // angle subtended by a crystal + float R = 32.8f; // ring radius + cnt_sptr->RE = R + 0.67f; // effective ring radius accounting for the depth of interaction + cnt_sptr->AXR = SZ_RING; // axial crystal dim + + cnt_sptr->COSUPSMX = 0.725f; // cosine of max allowed scatter angle + cnt_sptr->COSSTP = (1 - cnt_sptr->COSUPSMX) / (255); // cosine step + + cnt_sptr->TOFBINN = 1; // number of TOF bins + cnt_sptr->TOFBINS = 3.9e-10f; // size of TOF bin in [ps] + float CLGHT = 29979245800.f; // speed of light [cm/s] + cnt_sptr->TOFBIND = cnt_sptr->TOFBINS * CLGHT; // size of TOF BIN in cm of travelled distance + cnt_sptr->ITOFBIND = 1.f / cnt_sptr->TOFBIND; // inverse of above + + cnt_sptr->BTP = 0; // 0: no bootstrapping, 1: no-parametric, 2: parametric (recommended) + cnt_sptr->BTPRT = 1.f; // ratio of bootstrapped/original events in the target sinogram (1.0 default) + + cnt_sptr->ETHRLD = 0.05f; // intensity percentage threshold of voxels to be considered in the image + } else + throw std::runtime_error("NiftyPETHelper::getcnst() " + "not implemented for scanner type: " + + scanner.get_name()); + return cnt_sptr; } -static inline unsigned to_1d_idx(const unsigned nrow, const unsigned ncol, const unsigned row, const unsigned col) -{ - return col + ncol*row; +static inline unsigned +to_1d_idx(const unsigned nrow, const unsigned ncol, const unsigned row, const unsigned col) { + return col + ncol * row; } -template -dataType* create_heap_array(const unsigned numel, const dataType val = dataType(0)) -{ - dataType *array = new dataType[numel]; - std::fill(array, array+numel, val); - return array; +template +dataType* +create_heap_array(const unsigned numel, const dataType val = dataType(0)) { + dataType* array = new dataType[numel]; + std::fill(array, array + numel, val); + return array; } /// Converted from mmraux.py axial_lut -static void get_axLUT_sptr(shared_ptr &axlut_sptr, std::vector &li2rng, std::vector &li2sn_s, std::vector &li2nos_c, const Cnst &cnt) -{ - const int NRNG = cnt.NRNG; - int NRNG_c, NSN1_c; - - if (cnt.SPN == 1) { - // number of rings calculated for the given ring range (optionally we can use only part of the axial FOV) - NRNG_c = cnt.RNG_END - cnt.RNG_STRT; - // number of sinos in span-1 - NSN1_c = NRNG_c*NRNG_c; - // correct for the max. ring difference in the full axial extent (don't use ring range (1,63) as for this case no correction) - if (NRNG_c==64) - NSN1_c -= 12; +static void +get_axLUT_sptr(shared_ptr& axlut_sptr, std::vector& li2rng, std::vector& li2sn_s, + std::vector& li2nos_c, const Cnst& cnt) { + const int NRNG = cnt.NRNG; + int NRNG_c, NSN1_c; + + if (cnt.SPN == 1) { + // number of rings calculated for the given ring range (optionally we can use only part of the axial FOV) + NRNG_c = cnt.RNG_END - cnt.RNG_STRT; + // number of sinos in span-1 + NSN1_c = NRNG_c * NRNG_c; + // correct for the max. ring difference in the full axial extent (don't use ring range (1,63) as for this case no correction) + if (NRNG_c == 64) + NSN1_c -= 12; + } else { + NRNG_c = NRNG; + NSN1_c = cnt.NSN1; + if (cnt.RNG_END != NRNG || cnt.RNG_STRT != 0) + throw std::runtime_error("NiftyPETHelper::get_axLUT: the reduced axial FOV only works in span=1."); + } + + // ring dimensions + std::vector rng(NRNG * 2); + float z = -.5f * float(NRNG) * cnt.AXR; + for (unsigned i = 0; i < unsigned(NRNG); ++i) { + rng[to_1d_idx(NRNG, 2, i, 0)] = z; + z += cnt.AXR; + rng[to_1d_idx(NRNG, 2, i, 1)] = z; + } + + // --create mapping from ring difference to segment number + // ring difference range + std::vector rd(2 * cnt.MRD + 1); + for (unsigned i = 0; i < rd.size(); ++i) + rd[i] = i - cnt.MRD; + // ring difference to segment + std::vector rd2sg(rd.size() * 2, -1); + // minimum and maximum ring difference for each segment + std::vector minrd = {-5, -16, 6, -27, 17, -38, 28, -49, 39, -60, 50}; + std::vector maxrd = {5, -6, 16, -17, 27, -28, 38, -39, 49, -50, 60}; + for (unsigned i = 0; i < rd.size(); ++i) { + for (unsigned iseg = 0; iseg < minrd.size(); ++iseg) { + if (rd[i] >= minrd[iseg] && rd[i] <= maxrd[iseg]) { + rd2sg[to_1d_idx(rd.size(), 2, i, 0)] = rd[i]; + rd2sg[to_1d_idx(rd.size(), 2, i, 1)] = iseg; + } } - else { - NRNG_c = NRNG; - NSN1_c = cnt.NSN1; - if (cnt.RNG_END!=NRNG || cnt.RNG_STRT!=0) - throw std::runtime_error("NiftyPETHelper::get_axLUT: the reduced axial FOV only works in span=1."); + } + + // create two Michelograms for segments (Mseg) + // and absolute axial position for individual sinos (Mssrb) which is single slice rebinning + std::vector Mssrb(NRNG * NRNG, -1); + std::vector Mseg(NRNG * NRNG, -1); + for (int r1 = cnt.RNG_STRT; r1 < cnt.RNG_END; ++r1) { + for (int r0 = cnt.RNG_STRT; r0 < cnt.RNG_END; ++r0) { + if (abs(r0 - r1) > cnt.MRD) + continue; + int ssp = r0 + r1; // segment sino position (axially: 0-126) + int rdd = r1 - r0; + int jseg = -1; + for (unsigned i = 0; i < rd.size(); ++i) + if (rd2sg[to_1d_idx(rd.size(), 2, i, 0)] == rdd) + jseg = rd2sg[to_1d_idx(rd.size(), 2, i, 1)]; + Mssrb[to_1d_idx(NRNG, NRNG, r1, r0)] = ssp; + Mseg[to_1d_idx(NRNG, NRNG, r1, r0)] = jseg; // negative segments are on top diagonals } - - // ring dimensions - std::vector rng(NRNG*2); - float z = -.5f*float(NRNG)*cnt.AXR; - for (unsigned i=0; i Msn(NRNG * NRNG, -1); + // number of span-1 sinos per sino in span-11 + std::vector Mnos(NRNG * NRNG, -1); + std::vector seg = {127, 115, 115, 93, 93, 71, 71, 49, 49, 27, 27}; + std::vector msk(NRNG * NRNG, 0); + std::vector Mtmp(NRNG * NRNG); + int i = 0; + for (unsigned iseg = 0; iseg < seg.size(); ++iseg) { + // msk = (Mseg==iseg) + for (unsigned a = 0; a < unsigned(NRNG * NRNG); ++a) + msk[a] = Mseg[a] == int(iseg) ? 1 : 0; + // Mtmp = np.copy(Mssrb) + // Mtmp[~msk] = -1 + for (unsigned a = 0; a < unsigned(NRNG * NRNG); ++a) + Mtmp[a] = msk[a] ? Mssrb[a] : -1; + + // uq = np.unique(Mtmp[msk]) + std::vector uq; + for (unsigned a = 0; a < unsigned(NRNG * NRNG); ++a) + if (msk[a] && std::find(uq.begin(), uq.end(), Mtmp[a]) == uq.end()) + uq.push_back(Mtmp[a]); + // for u in range(0,len(uq)): + for (unsigned u = 0; u < uq.size(); ++u) { + // Msn [ Mtmp==uq[u] ] = i + for (unsigned a = 0; a < unsigned(NRNG * NRNG); ++a) + if (Mtmp[a] == uq[u]) + Msn[a] = i; + // Mnos[ Mtmp==uq[u] ] = np.sum(Mtmp==uq[u]) + int sum = 0; + for (unsigned a = 0; a < unsigned(NRNG * NRNG); ++a) + if (Mtmp[a] == uq[u]) + ++sum; + for (unsigned a = 0; a < unsigned(NRNG * NRNG); ++a) + if (Mtmp[a] == uq[u]) + Mnos[a] = sum; + ++i; } - - // --create mapping from ring difference to segment number - // ring difference range - std::vector rd(2*cnt.MRD+1); - for (unsigned i=0; i rd2sg(rd.size()*2, -1); - // minimum and maximum ring difference for each segment - std::vector minrd = {-5,-16, 6,-27,17,-38,28,-49,39,-60,50}; - std::vector maxrd = { 5, -6,16,-17,27,-28,38,-39,49,-50,60}; - for (unsigned i=0; i=minrd[iseg] && rd[i]<=maxrd[iseg]) { - rd2sg[to_1d_idx(rd.size(),2,i,0)] = rd[i]; - rd2sg[to_1d_idx(rd.size(),2,i,1)] = iseg; - } + } + + //====full LUT + short* sn1_rno = create_heap_array(NSN1_c * 2, 0); + short* sn1_ssrb = create_heap_array(NSN1_c, 0); + short* sn1_sn11 = create_heap_array(NSN1_c, 0); + char* sn1_sn11no = create_heap_array(NSN1_c, 0); + int sni = 0; // full linear index, up to 4084 + // michelogram of sino numbers for spn-1 + std::vector Msn1(NRNG * NRNG, -1); + for (unsigned ro = 0; ro < unsigned(NRNG); ++ro) { + unsigned oblique = ro == 0 ? 1 : 2; + // for m in range(oblique): + for (unsigned m = 0; m < oblique; ++m) { + // strt = NRNG*(ro+Cnt['RNG_STRT']) + Cnt['RNG_STRT'] + int strt = NRNG * (ro + cnt.RNG_STRT) + cnt.RNG_STRT; + int stop = (cnt.RNG_STRT + NRNG_c) * NRNG; + int step = NRNG + 1; + + // goes along a diagonal started in the first row at r1 + // for li in range(strt, stop, step): + for (int li = strt; li < stop; li += step) { + int r1, r0; + // linear indecies of michelogram --> subscript indecies for positive and negative RDs + if (m == 0) { + r1 = floor(float(li) / float(NRNG)); + r0 = li - r1 * NRNG; } - } - - // create two Michelograms for segments (Mseg) - // and absolute axial position for individual sinos (Mssrb) which is single slice rebinning - std::vector Mssrb(NRNG*NRNG, -1); - std::vector Mseg(NRNG*NRNG, -1); - for (int r1=cnt.RNG_STRT; r1cnt.MRD) - continue; - int ssp = r0+r1; // segment sino position (axially: 0-126) - int rdd = r1-r0; - int jseg = -1; - for (unsigned i=0; iMRD + if (Msn[to_1d_idx(NRNG, NRNG, r1, r0)] < 0) + continue; - // create a Michelogram map from rings to sino number in span-11 (1..837) - std::vector Msn(NRNG*NRNG, -1); - // number of span-1 sinos per sino in span-11 - std::vector Mnos(NRNG*NRNG, -1); - std::vector seg = {127,115,115,93,93,71,71,49,49,27,27}; - std::vector msk(NRNG*NRNG, 0); - std::vector Mtmp(NRNG*NRNG); - int i=0; - for (unsigned iseg=0; iseg uq; - for (unsigned a=0; a(NSN1_c*2, 0); - short *sn1_ssrb = create_heap_array(NSN1_c, 0); - short *sn1_sn11 = create_heap_array(NSN1_c, 0); - char *sn1_sn11no = create_heap_array(NSN1_c, 0); - int sni = 0; // full linear index, up to 4084 - // michelogram of sino numbers for spn-1 - std::vector Msn1(NRNG*NRNG, -1); - for (unsigned ro=0; ro subscript indecies for positive and negative RDs - if (m==0) { - r1 = floor(float(li)/float(NRNG)); - r0 = li - r1*NRNG; - } - // for positive now (? or vice versa) - else { - r0 = floor(float(li)/float(NRNG)); - r1 = li - r0*NRNG; - } - // avoid case when RD>MRD - if (Msn[to_1d_idx(NRNG,NRNG,r1,r0)]<0) - continue; - - sn1_rno[to_1d_idx(NSN1_c,2, sni,0)] = r0; - sn1_rno[to_1d_idx(NSN1_c,2, sni,1)] = r1; - - sn1_ssrb[sni] = Mssrb[to_1d_idx(NRNG,NRNG,r1,r0)]; - sn1_sn11[sni] = Msn[to_1d_idx(NRNG,NRNG,r0,r1)]; - - sn1_sn11no[sni] = Mnos[to_1d_idx(NRNG,NRNG,r0,r1)]; - - Msn1[to_1d_idx(NRNG,NRNG,r0,r1)] = sni; - //-- - sni += 1; - } - } - } + sn1_ssrb[sni] = Mssrb[to_1d_idx(NRNG, NRNG, r1, r0)]; + sn1_sn11[sni] = Msn[to_1d_idx(NRNG, NRNG, r0, r1)]; - // span-11 sino to SSRB - // sn11_ssrb = np.zeros(Cnt['NSN11'], dtype=np.int32); - std::vector sn11_ssrb(cnt.NSN11, -1); - // sn1_ssrno = np.zeros(Cnt['NSEG0'], dtype=np.int8) - std::vector sn1_ssrno(cnt.NSEG0, 0); - // for i in range(NSN1_c): - for (unsigned i=0; i sn11_ssrno(cnt.NSEG0, 0); - // for i in range(Cnt['NSN11']): - for (unsigned i=0; i0: sn11_ssrno[sn11_ssrb[i]] += 1 - if (sn11_ssrb[i]>0) - sn11_ssrno[sn11_ssrb[i]] += 1; - - // sn11_ssrb = sn11_ssrb[sn11_ssrb>=0] - for (unsigned i=0; i(NLI2R_c*2); - // the same as above but to sinos in span-11 - int *li2sn = create_heap_array(NLI2R_c*2); - std::vector li2sn1(NLI2R_c*2); - li2rng = std::vector(NLI2R_c*2); - // ...to number of sinos (nos) - int *li2nos = create_heap_array(NLI2R_c); - - int dli = 0; - for (unsigned ro=0; ro(NLI2R_c*2); - for (unsigned i=0; i(NLI2R_c); - for (unsigned i=0; i(new axialLUT, delete_axialLUT); - axlut_sptr->li2rno = li2r; // int linear indx to ring indx - axlut_sptr->li2sn = li2sn; // int linear michelogram index (along diagonals) to sino index - axlut_sptr->li2nos = li2nos; // int linear indx to no of sinos in span-11 - axlut_sptr->sn1_rno = sn1_rno; // short - axlut_sptr->sn1_sn11 = sn1_sn11; // short - axlut_sptr->sn1_ssrb = sn1_ssrb; // short - axlut_sptr->sn1_sn11no = sn1_sn11no; // char - // array sizes - axlut_sptr->Nli2rno[0] = NLI2R_c; - axlut_sptr->Nli2rno[1] = 2; - axlut_sptr->Nli2sn[0] = NLI2R_c; - axlut_sptr->Nli2sn[1] = 2; - axlut_sptr->Nli2nos = NLI2R_c; + } + + // span-11 sino to SSRB + // sn11_ssrb = np.zeros(Cnt['NSN11'], dtype=np.int32); + std::vector sn11_ssrb(cnt.NSN11, -1); + // sn1_ssrno = np.zeros(Cnt['NSEG0'], dtype=np.int8) + std::vector sn1_ssrno(cnt.NSEG0, 0); + // for i in range(NSN1_c): + for (unsigned i = 0; i < unsigned(NSN1_c); ++i) { + sn11_ssrb[sn1_sn11[i]] = sn1_ssrb[i]; + sn1_ssrno[sn1_ssrb[i]] += 1; + } + + // sn11_ssrno = np.zeros(Cnt['NSEG0'], dtype=np.int8) + std::vector sn11_ssrno(cnt.NSEG0, 0); + // for i in range(Cnt['NSN11']): + for (unsigned i = 0; i < unsigned(cnt.NSN11); ++i) + // if sn11_ssrb[i]>0: sn11_ssrno[sn11_ssrb[i]] += 1 + if (sn11_ssrb[i] > 0) + sn11_ssrno[sn11_ssrb[i]] += 1; + + // sn11_ssrb = sn11_ssrb[sn11_ssrb>=0] + for (unsigned i = 0; i < unsigned(cnt.NSN11); ++i) + if (sn11_ssrb[i] < 0) + sn11_ssrb[i] = 0; + + // --------------------------------------------------------------------- + // linear index (along diagonals of Michelogram) to rings + // the number of Michelogram elements considered in projection calculations + int NLI2R_c = int(float(NRNG_c * NRNG_c) / 2.f + float(NRNG_c) / 2.f); + + // if the whole scanner is used then account for the MRD and subtract 6 ring permutations + if (NRNG_c == NRNG) + NLI2R_c -= 6; + + int* li2r = create_heap_array(NLI2R_c * 2); + // the same as above but to sinos in span-11 + int* li2sn = create_heap_array(NLI2R_c * 2); + std::vector li2sn1(NLI2R_c * 2); + li2rng = std::vector(NLI2R_c * 2); + // ...to number of sinos (nos) + int* li2nos = create_heap_array(NLI2R_c); + + int dli = 0; + for (unsigned ro = 0; ro < unsigned(NRNG_c); ++ro) { + // selects the sub-Michelogram of the whole Michelogram + unsigned strt = NRNG * (ro + cnt.RNG_STRT) + cnt.RNG_STRT; + unsigned stop = (cnt.RNG_STRT + NRNG_c) * NRNG; + unsigned step = NRNG + 1; + + // goes along a diagonal started in the first row at r2o + for (unsigned li = strt; li < stop; li += step) { + // from the linear indexes of Michelogram get the subscript indexes + unsigned r1 = floor(float(li) / float(NRNG)); + unsigned r0 = li - r1 * NRNG; + if (Msn[to_1d_idx(NRNG, NRNG, r1, r0)] < 0) + continue; + + li2r[to_1d_idx(NLI2R_c, 2, dli, 0)] = r0; + li2r[to_1d_idx(NLI2R_c, 2, dli, 1)] = r1; + //--//rng[to_1d_idx(NRNG,2,i,1)] = z; + li2rng[to_1d_idx(NLI2R_c, 2, dli, 0)] = rng[to_1d_idx(NRNG, 2, r0, 0)]; + li2rng[to_1d_idx(NLI2R_c, 2, dli, 1)] = rng[to_1d_idx(NRNG, 2, r1, 0)]; + //-- + li2sn[to_1d_idx(NLI2R_c, 2, dli, 0)] = Msn[to_1d_idx(NRNG, NRNG, r0, r1)]; + li2sn[to_1d_idx(NLI2R_c, 2, dli, 1)] = Msn[to_1d_idx(NRNG, NRNG, r1, r0)]; + + li2sn1[to_1d_idx(NLI2R_c, 2, dli, 0)] = Msn1[to_1d_idx(NRNG, NRNG, r0, r1)]; + li2sn1[to_1d_idx(NLI2R_c, 2, dli, 1)] = Msn1[to_1d_idx(NRNG, NRNG, r1, r0)]; + + li2nos[dli] = Mnos[to_1d_idx(NRNG, NRNG, r1, r0)]; + + ++dli; + } + } + + // Need some results in a different data type + li2sn_s = std::vector(NLI2R_c * 2); + for (unsigned i = 0; i < unsigned(NLI2R_c * 2); ++i) + li2sn_s[i] = short(li2sn[i]); + li2nos_c = std::vector(NLI2R_c); + for (unsigned i = 0; i < unsigned(NLI2R_c); ++i) + li2nos_c[i] = char(li2nos[i]); + + // Fill in struct + axlut_sptr = shared_ptr(new axialLUT, delete_axialLUT); + axlut_sptr->li2rno = li2r; // int linear indx to ring indx + axlut_sptr->li2sn = li2sn; // int linear michelogram index (along diagonals) to sino index + axlut_sptr->li2nos = li2nos; // int linear indx to no of sinos in span-11 + axlut_sptr->sn1_rno = sn1_rno; // short + axlut_sptr->sn1_sn11 = sn1_sn11; // short + axlut_sptr->sn1_ssrb = sn1_ssrb; // short + axlut_sptr->sn1_sn11no = sn1_sn11no; // char + // array sizes + axlut_sptr->Nli2rno[0] = NLI2R_c; + axlut_sptr->Nli2rno[1] = 2; + axlut_sptr->Nli2sn[0] = NLI2R_c; + axlut_sptr->Nli2sn[1] = 2; + axlut_sptr->Nli2nos = NLI2R_c; } -static -void get_txLUT_sptr(shared_ptr &txlut_sptr, std::vector &crs, std::vector &s2c, Cnst &cnt) -{ - txlut_sptr = shared_ptr(new txLUTs, delete_txLUT); - *txlut_sptr = get_txlut(cnt); - - s2c = std::vector(txlut_sptr->naw*2); - for (unsigned i=0; inaw); ++i) { - s2c[ 2*i ] = txlut_sptr->s2c[i].c0; - s2c[2*i+1] = txlut_sptr->s2c[i].c1; - } - // from mmraux.py - const float bw = 3.209f; // block width - // const float dg = 0.474f; // block gap [cm] - const int NTBLK = 56; - const float alpha = 2*M_PI/float(NTBLK); // 2*pi/NTBLK - crs = std::vector(4 * cnt.NCRS); - float phi = 0.5f*M_PI - alpha/2.f - 0.001f; - for (int bi=0; bi& txlut_sptr, std::vector& crs, std::vector& s2c, Cnst& cnt) { + txlut_sptr = shared_ptr(new txLUTs, delete_txLUT); + *txlut_sptr = get_txlut(cnt); + + s2c = std::vector(txlut_sptr->naw * 2); + for (unsigned i = 0; i < unsigned(txlut_sptr->naw); ++i) { + s2c[2 * i] = txlut_sptr->s2c[i].c0; + s2c[2 * i + 1] = txlut_sptr->s2c[i].c1; + } + // from mmraux.py + const float bw = 3.209f; // block width + // const float dg = 0.474f; // block gap [cm] + const int NTBLK = 56; + const float alpha = 2 * M_PI / float(NTBLK); // 2*pi/NTBLK + crs = std::vector(4 * cnt.NCRS); + float phi = 0.5f * M_PI - alpha / 2.f - 0.001f; + for (int bi = 0; bi < NTBLK; ++bi) { + //-tangent point (ring against detector block) + // ye = RE*np.sin(phi) + // xe = RE*np.cos(phi) + float y = cnt.RE * sin(phi); + float x = cnt.RE * cos(phi); + //-vector for the face of crystals + float pv[2] = {-y, x}; + float pv_ = pow(pv[0] * pv[0] + pv[1] * pv[1], 0.5f); + pv[0] /= pv_; + pv[1] /= pv_; + // update phi for next block + phi -= alpha; + //-end block points + float xcp = x + (bw / 2) * pv[0]; + float ycp = y + (bw / 2) * pv[1]; + for (unsigned n = 1; n < 9; ++n) { + int c = bi * 9 + n - 1; + crs[to_1d_idx(4, cnt.NCRS, 0, c)] = xcp; + crs[to_1d_idx(4, cnt.NCRS, 1, c)] = ycp; + float xc = x + (bw / 2 - float(n) * bw / 8) * pv[0]; + float yc = y + (bw / 2 - float(n) * bw / 8) * pv[1]; + crs[to_1d_idx(4, cnt.NCRS, 2, c)] = xc; + crs[to_1d_idx(4, cnt.NCRS, 3, c)] = yc; + xcp = xc; + ycp = yc; } + } } void -NiftyPETHelper:: -set_up() -{ - if (_span < 0) - throw std::runtime_error("NiftyPETHelper::set_up() " - "sinogram span not set."); - - if (_att < 0) - throw std::runtime_error("NiftyPETHelper::set_up() " - "emission or transmission mode (att) not set."); - - if (_scanner_type == Scanner::Unknown_scanner) - throw std::runtime_error("NiftyPETHelper::set_up() " - "scanner type not set."); - - // Get consts - _cnt_sptr = get_cnst(_scanner_type, _verbose, _devid, _span); - - // Get txLUT - get_txLUT_sptr(_txlut_sptr, _crs, _s2c, *_cnt_sptr); - - // Get axLUT - get_axLUT_sptr(_axlut_sptr, _li2rng, _li2sn, _li2nos, *_cnt_sptr); - - switch(_cnt_sptr->SPN){ - case 11: - _nsinos = _cnt_sptr->NSN11; break; - case 1: - _nsinos = _cnt_sptr->NSEG0; break; - default: - throw std::runtime_error("Unsupported span"); - } - - // isub - _isub = std::vector(unsigned(AW)); - for (unsigned i = 0; iSPN) { + case 11: + _nsinos = _cnt_sptr->NSN11; + break; + case 1: + _nsinos = _cnt_sptr->NSEG0; + break; + default: + throw std::runtime_error("Unsupported span"); + } + + // isub + _isub = std::vector(unsigned(AW)); + for (unsigned i = 0; i < unsigned(AW); i++) + _isub[i] = int(i); + + _already_set_up = true; } void -NiftyPETHelper:: -check_set_up() const -{ - if (!_already_set_up) - throw std::runtime_error("NiftyPETHelper::check_set_up() " - "Make sure filenames have been set and set_up has been run."); +NiftyPETHelper::check_set_up() const { + if (!_already_set_up) + throw std::runtime_error("NiftyPETHelper::check_set_up() " + "Make sure filenames have been set and set_up has been run."); } std::vector -NiftyPETHelper:: -create_niftyPET_image() -{ - return std::vector(SZ_IMZ*SZ_IMX*SZ_IMY,0); +NiftyPETHelper::create_niftyPET_image() { + return std::vector(SZ_IMZ * SZ_IMX * SZ_IMY, 0); } -shared_ptr > -NiftyPETHelper:: -create_stir_im() -{ - int nz(SZ_IMZ), nx(SZ_IMX), ny(SZ_IMY); - float sz(SZ_VOXZ*10.f), sx(SZ_VOXY*10.f), sy(SZ_VOXY*10.f); - shared_ptr > out_im_stir_sptr = - MAKE_SHARED >( - IndexRange3D(0, nz - 1, -(ny / 2), -(ny / 2) + ny - 1, -(nx / 2), -(nx / 2) + nx - 1), - CartesianCoordinate3D(0.f, 0.f, 0.f), - CartesianCoordinate3D(sz, sy, sx)); - return out_im_stir_sptr; +shared_ptr> +NiftyPETHelper::create_stir_im() { + int nz(SZ_IMZ), nx(SZ_IMX), ny(SZ_IMY); + float sz(SZ_VOXZ * 10.f), sx(SZ_VOXY * 10.f), sy(SZ_VOXY * 10.f); + shared_ptr> out_im_stir_sptr = MAKE_SHARED>( + IndexRange3D(0, nz - 1, -(ny / 2), -(ny / 2) + ny - 1, -(nx / 2), -(nx / 2) + nx - 1), + CartesianCoordinate3D(0.f, 0.f, 0.f), CartesianCoordinate3D(sz, sy, sx)); + return out_im_stir_sptr; } std::vector -NiftyPETHelper:: -create_niftyPET_sinogram_no_gaps() const -{ - check_set_up(); - return std::vector(_isub.size() * static_cast(_nsinos), 0); +NiftyPETHelper::create_niftyPET_sinogram_no_gaps() const { + check_set_up(); + return std::vector(_isub.size() * static_cast(_nsinos), 0); } std::vector -NiftyPETHelper:: -create_niftyPET_sinogram_with_gaps() const -{ - return std::vector(NSBINS*NSANGLES*unsigned(_nsinos), 0); +NiftyPETHelper::create_niftyPET_sinogram_with_gaps() const { + return std::vector(NSBINS * NSANGLES * unsigned(_nsinos), 0); } -void get_stir_indices_and_dims(int stir_dim[3], Coordinate3D &min_indices, Coordinate3D &max_indices, const DiscretisedDensity<3,float >&stir) -{ - if (!stir.get_regular_range(min_indices, max_indices)) - throw std::runtime_error("NiftyPETHelper::set_input - " - "expected image to have regular range."); - for (int i=0; i<3; ++i) - stir_dim[i] = max_indices[i + 1] - min_indices[i + 1] + 1; +void +get_stir_indices_and_dims(int stir_dim[3], Coordinate3D& min_indices, Coordinate3D& max_indices, + const DiscretisedDensity<3, float>& stir) { + if (!stir.get_regular_range(min_indices, max_indices)) + throw std::runtime_error("NiftyPETHelper::set_input - " + "expected image to have regular range."); + for (int i = 0; i < 3; ++i) + stir_dim[i] = max_indices[i + 1] - min_indices[i + 1] + 1; } -unsigned convert_NiftyPET_im_3d_to_1d_idx(const unsigned x, const unsigned y, const unsigned z) -{ - return z*SZ_IMX*SZ_IMY + y*SZ_IMX + x; +unsigned +convert_NiftyPET_im_3d_to_1d_idx(const unsigned x, const unsigned y, const unsigned z) { + return z * SZ_IMX * SZ_IMY + y * SZ_IMX + x; } unsigned -NiftyPETHelper:: -convert_NiftyPET_proj_3d_to_1d_idx(const unsigned ang, const unsigned bins, const unsigned sino) const -{ - return sino*NSANGLES*NSBINS + ang*NSBINS + bins; +NiftyPETHelper::convert_NiftyPET_proj_3d_to_1d_idx(const unsigned ang, const unsigned bins, const unsigned sino) const { + return sino * NSANGLES * NSBINS + ang * NSBINS + bins; } void -NiftyPETHelper:: -permute(std::vector &output_array, const std::vector &orig_array, const unsigned output_dims[3], const unsigned permute_order[3]) const -{ +NiftyPETHelper::permute(std::vector& output_array, const std::vector& orig_array, const unsigned output_dims[3], + const unsigned permute_order[3]) const { #ifndef NDEBUG - // Check that in the permute order, each number is between 0 and 2 (can't be <0 because it's unsigned) - for (unsigned i=0; i<3; ++i) - if (permute_order[i]>2) - throw std::runtime_error("Permute order values should be between 0 and 2."); - // Check that each number is unique - for (unsigned i=0; i<3; ++i) - for (unsigned j=i+1; j<3; ++j) - if (permute_order[i] == permute_order[j]) - throw std::runtime_error("Permute order values should be unique."); - // Check that size of output_dims==arr.size() - assert(orig_array.size() == output_dims[0]*output_dims[1]*output_dims[2]); - // Check that output array is same size as input array - assert(orig_array.size() == output_array.size()); + // Check that in the permute order, each number is between 0 and 2 (can't be <0 because it's unsigned) + for (unsigned i = 0; i < 3; ++i) + if (permute_order[i] > 2) + throw std::runtime_error("Permute order values should be between 0 and 2."); + // Check that each number is unique + for (unsigned i = 0; i < 3; ++i) + for (unsigned j = i + 1; j < 3; ++j) + if (permute_order[i] == permute_order[j]) + throw std::runtime_error("Permute order values should be unique."); + // Check that size of output_dims==arr.size() + assert(orig_array.size() == output_dims[0] * output_dims[1] * output_dims[2]); + // Check that output array is same size as input array + assert(orig_array.size() == output_array.size()); #endif - // Calculate old dimensions - unsigned old_dims[3]; - for (unsigned i=0; i<3; ++i) - old_dims[permute_order[i]] = output_dims[i]; + // Calculate old dimensions + unsigned old_dims[3]; + for (unsigned i = 0; i < 3; ++i) + old_dims[permute_order[i]] = output_dims[i]; - // Loop over all elements - for (unsigned old_1d_idx=0; old_1d_idx &sino_no_gaps, const std::vector &sino_w_gaps) const -{ - check_set_up(); - assert(!sino_no_gaps.empty()); - - if (_verbose) - getMemUse(); - - ::remove_gaps(sino_no_gaps.data(), - const_cast(sino_w_gaps.data()), - _nsinos, - _txlut_sptr->aw2ali, - *_cnt_sptr); +NiftyPETHelper::remove_gaps(std::vector& sino_no_gaps, const std::vector& sino_w_gaps) const { + check_set_up(); + assert(!sino_no_gaps.empty()); + + if (_verbose) + getMemUse(); + + ::remove_gaps(sino_no_gaps.data(), const_cast(sino_w_gaps.data()), _nsinos, _txlut_sptr->aw2ali, *_cnt_sptr); } void -NiftyPETHelper:: -put_gaps(std::vector &sino_w_gaps, const std::vector &sino_no_gaps) const -{ - check_set_up(); - assert(!sino_w_gaps.empty()); - - std::vector unpermuted_sino_w_gaps = this->create_niftyPET_sinogram_with_gaps(); - - if (_verbose) - getMemUse(); - - ::put_gaps(unpermuted_sino_w_gaps.data(), - const_cast(sino_no_gaps.data()), - _txlut_sptr->aw2ali, - *_cnt_sptr); - - // Permute the data (as this is done on the NiftyPET python side after put gaps - unsigned output_dims[3] = {837, 252, 344}; - unsigned permute_order[3] = {2,0,1}; - this->permute(sino_w_gaps,unpermuted_sino_w_gaps,output_dims,permute_order); +NiftyPETHelper::put_gaps(std::vector& sino_w_gaps, const std::vector& sino_no_gaps) const { + check_set_up(); + assert(!sino_w_gaps.empty()); + + std::vector unpermuted_sino_w_gaps = this->create_niftyPET_sinogram_with_gaps(); + + if (_verbose) + getMemUse(); + + ::put_gaps(unpermuted_sino_w_gaps.data(), const_cast(sino_no_gaps.data()), _txlut_sptr->aw2ali, *_cnt_sptr); + + // Permute the data (as this is done on the NiftyPET python side after put gaps + unsigned output_dims[3] = {837, 252, 344}; + unsigned permute_order[3] = {2, 0, 1}; + this->permute(sino_w_gaps, unpermuted_sino_w_gaps, output_dims, permute_order); } void -NiftyPETHelper:: -back_project(std::vector &image, const std::vector &sino_no_gaps) const -{ - check_set_up(); - assert(!image.empty()); - - std::vector unpermuted_image = this->create_niftyPET_image(); - - if (_verbose) - getMemUse(); - - gpu_bprj(unpermuted_image.data(), - const_cast(sino_no_gaps.data()), - const_cast(_li2rng.data()), - const_cast(_li2sn.data()), - const_cast(_li2nos.data()), - const_cast(_s2c.data()), - _txlut_sptr->aw2ali, - const_cast(_crs.data()), - const_cast(_isub.data()), - int(_isub.size()), - AW, - 4, // n0crs - nCRS, - *_cnt_sptr); - - // Permute the data (as this is done on the NiftyPET python side after back projection - unsigned output_dims[3] = {127,320,320}; - unsigned permute_order[3] = {2,0,1}; - this->permute(image,unpermuted_image,output_dims,permute_order); +NiftyPETHelper::back_project(std::vector& image, const std::vector& sino_no_gaps) const { + check_set_up(); + assert(!image.empty()); + + std::vector unpermuted_image = this->create_niftyPET_image(); + + if (_verbose) + getMemUse(); + + gpu_bprj(unpermuted_image.data(), const_cast(sino_no_gaps.data()), const_cast(_li2rng.data()), + const_cast(_li2sn.data()), const_cast(_li2nos.data()), const_cast(_s2c.data()), + _txlut_sptr->aw2ali, const_cast(_crs.data()), const_cast(_isub.data()), int(_isub.size()), AW, + 4, // n0crs + nCRS, *_cnt_sptr); + + // Permute the data (as this is done on the NiftyPET python side after back projection + unsigned output_dims[3] = {127, 320, 320}; + unsigned permute_order[3] = {2, 0, 1}; + this->permute(image, unpermuted_image, output_dims, permute_order); } void -NiftyPETHelper:: -forward_project(std::vector &sino_no_gaps, const std::vector &image) const -{ - check_set_up(); - assert(!sino_no_gaps.empty()); - - // Permute the data (as this is done on the NiftyPET python side before forward projection - unsigned output_dims[3] = {320,320,127}; - unsigned permute_order[3] = {1,2,0}; - std::vector permuted_image = this->create_niftyPET_image(); - this->permute(permuted_image,image,output_dims,permute_order); - - if (_verbose) - getMemUse(); - - gpu_fprj(sino_no_gaps.data(), - permuted_image.data(), - const_cast(_li2rng.data()), - const_cast(_li2sn.data()), - const_cast(_li2nos.data()), - const_cast(_s2c.data()), - _txlut_sptr->aw2ali, - const_cast(_crs.data()), - const_cast(_isub.data()), - int(_isub.size()), - AW, - 4, // n0crs - nCRS, - *_cnt_sptr, - _att); +NiftyPETHelper::forward_project(std::vector& sino_no_gaps, const std::vector& image) const { + check_set_up(); + assert(!sino_no_gaps.empty()); + + // Permute the data (as this is done on the NiftyPET python side before forward projection + unsigned output_dims[3] = {320, 320, 127}; + unsigned permute_order[3] = {1, 2, 0}; + std::vector permuted_image = this->create_niftyPET_image(); + this->permute(permuted_image, image, output_dims, permute_order); + + if (_verbose) + getMemUse(); + + gpu_fprj(sino_no_gaps.data(), permuted_image.data(), const_cast(_li2rng.data()), const_cast(_li2sn.data()), + const_cast(_li2nos.data()), const_cast(_s2c.data()), _txlut_sptr->aw2ali, + const_cast(_crs.data()), const_cast(_isub.data()), int(_isub.size()), AW, + 4, // n0crs + nCRS, *_cnt_sptr, _att); } shared_ptr -NiftyPETHelper::create_stir_sino() -{ - const int span=11; - const int max_ring_diff=60; - const int view_mash_factor=1; - shared_ptr ei_sptr = MAKE_SHARED(); - ei_sptr->imaging_modality = ImagingModality::PT; - shared_ptr scanner_sptr(Scanner::get_scanner_from_name("mMR")); - int num_views = scanner_sptr->get_num_detectors_per_ring() / 2 / view_mash_factor; - int num_tang_pos = scanner_sptr->get_max_num_non_arccorrected_bins(); - shared_ptr pdi_sptr = ProjDataInfo::construct_proj_data_info - (scanner_sptr, span, max_ring_diff, num_views, num_tang_pos, false); - shared_ptr pd_sptr = MAKE_SHARED(ei_sptr, pdi_sptr); - return pd_sptr; +NiftyPETHelper::create_stir_sino() { + const int span = 11; + const int max_ring_diff = 60; + const int view_mash_factor = 1; + shared_ptr ei_sptr = MAKE_SHARED(); + ei_sptr->imaging_modality = ImagingModality::PT; + shared_ptr scanner_sptr(Scanner::get_scanner_from_name("mMR")); + int num_views = scanner_sptr->get_num_detectors_per_ring() / 2 / view_mash_factor; + int num_tang_pos = scanner_sptr->get_max_num_non_arccorrected_bins(); + shared_ptr pdi_sptr = + ProjDataInfo::construct_proj_data_info(scanner_sptr, span, max_ring_diff, num_views, num_tang_pos, false); + shared_ptr pd_sptr = MAKE_SHARED(ei_sptr, pdi_sptr); + return pd_sptr; } template -static -dataType * -read_from_binary_file(std::ifstream &file, const unsigned long num_elements) -{ - // Get current position, get size to end and go back to current position - const unsigned long current_pos = file.tellg(); - file.seekg(std::ios::cur, std::ios::end); - const unsigned long remaining_elements = file.tellg() / sizeof(dataType); - file.seekg(current_pos, std::ios::beg); - - if (remaining_elements(num_elements); - file.read(reinterpret_cast(contents), num_elements*sizeof(dataType)); - return contents; +static dataType* +read_from_binary_file(std::ifstream& file, const unsigned long num_elements) { + // Get current position, get size to end and go back to current position + const unsigned long current_pos = file.tellg(); + file.seekg(std::ios::cur, std::ios::end); + const unsigned long remaining_elements = file.tellg() / sizeof(dataType); + file.seekg(current_pos, std::ios::beg); + + if (remaining_elements < num_elements) + throw std::runtime_error("File smaller than requested."); + + dataType* contents = create_heap_array(num_elements); + file.read(reinterpret_cast(contents), num_elements * sizeof(dataType)); + return contents; } /// Read numpy file. No error checking here (assume not fortran order etc.) /// Use std::cout << header if debugging. -static -float * -read_numpy_axf1(const unsigned long num_elements) -{ - const char* NP_SOURCE = std::getenv("NP_SOURCE"); - if (!NP_SOURCE) - throw std::runtime_error("NP_SOURCE not defined, cannot find data"); - - std::string numpy_filename = std::string(NP_SOURCE) + "/niftypet/auxdata/AxialFactorForSpan1.npy"; - // Skip over the header (first newline) - std::ifstream numpy_file(numpy_filename, std::ios::in | std::ios::binary); - if (!numpy_file.is_open()) - throw std::runtime_error("Failed to open numpy file: " + numpy_filename); - - std::string header; - std::getline(numpy_file, header); - // Read - float * axf1 = read_from_binary_file(numpy_file,num_elements); - - // Close file - numpy_file.close(); - - return axf1; +static float* +read_numpy_axf1(const unsigned long num_elements) { + const char* NP_SOURCE = std::getenv("NP_SOURCE"); + if (!NP_SOURCE) + throw std::runtime_error("NP_SOURCE not defined, cannot find data"); + + std::string numpy_filename = std::string(NP_SOURCE) + "/niftypet/auxdata/AxialFactorForSpan1.npy"; + // Skip over the header (first newline) + std::ifstream numpy_file(numpy_filename, std::ios::in | std::ios::binary); + if (!numpy_file.is_open()) + throw std::runtime_error("Failed to open numpy file: " + numpy_filename); + + std::string header; + std::getline(numpy_file, header); + // Read + float* axf1 = read_from_binary_file(numpy_file, num_elements); + + // Close file + numpy_file.close(); + + return axf1; } // Taken from mmrnorm.py -static -NormCmp get_norm_helper_struct(const std::string &norm_binary_file, const Cnst &cnt) -{ - // Open the norm binary file - std::ifstream norm_file(norm_binary_file, std::ios::in | std::ios::binary); - if (!norm_file.is_open()) - throw std::runtime_error("Failed to open norm binary: " + norm_binary_file); - - NormCmp normc; - - // Dimensions of arrays - normc.ngeo[0] = cnt.NSEG0; - normc.ngeo[1] = cnt.W; - normc.ncinf[0] = cnt.W; - normc.ncinf[1] = 9; - normc.nceff[0] = cnt.NRNG; - normc.nceff[1] = cnt.NCRS; - normc.naxe = cnt.NSN11; - normc.nrdt = cnt.NRNG; - normc.ncdt = 9; - - // geo - normc.geo = read_from_binary_file(norm_file, normc.ngeo[0]*normc.ngeo[1]); - // crystal interference - normc.cinf = read_from_binary_file(norm_file, normc.ncinf[0]*normc.ncinf[1]); - // crystal efficiencies - normc.ceff = read_from_binary_file(norm_file, normc.nceff[0]*normc.nceff[1]); - // axial effects - normc.axe1 = read_from_binary_file(norm_file, normc.naxe); - // paralyzing ring DT parameters - normc.dtp = read_from_binary_file(norm_file, normc.nrdt); - // non-paralyzing ring DT parameters - normc.dtnp = read_from_binary_file(norm_file, normc.nrdt); - // TX crystal DT parameter - normc.dtc = read_from_binary_file(norm_file, normc.ncdt); - // additional axial effects - normc.axe2 = read_from_binary_file(norm_file, normc.naxe); - - // Close file - norm_file.close(); - - // One of the pieces of data is stored as a numpy file. Read it. - normc.axf1 = read_numpy_axf1(NSINOS); - - return normc; +static NormCmp +get_norm_helper_struct(const std::string& norm_binary_file, const Cnst& cnt) { + // Open the norm binary file + std::ifstream norm_file(norm_binary_file, std::ios::in | std::ios::binary); + if (!norm_file.is_open()) + throw std::runtime_error("Failed to open norm binary: " + norm_binary_file); + + NormCmp normc; + + // Dimensions of arrays + normc.ngeo[0] = cnt.NSEG0; + normc.ngeo[1] = cnt.W; + normc.ncinf[0] = cnt.W; + normc.ncinf[1] = 9; + normc.nceff[0] = cnt.NRNG; + normc.nceff[1] = cnt.NCRS; + normc.naxe = cnt.NSN11; + normc.nrdt = cnt.NRNG; + normc.ncdt = 9; + + // geo + normc.geo = read_from_binary_file(norm_file, normc.ngeo[0] * normc.ngeo[1]); + // crystal interference + normc.cinf = read_from_binary_file(norm_file, normc.ncinf[0] * normc.ncinf[1]); + // crystal efficiencies + normc.ceff = read_from_binary_file(norm_file, normc.nceff[0] * normc.nceff[1]); + // axial effects + normc.axe1 = read_from_binary_file(norm_file, normc.naxe); + // paralyzing ring DT parameters + normc.dtp = read_from_binary_file(norm_file, normc.nrdt); + // non-paralyzing ring DT parameters + normc.dtnp = read_from_binary_file(norm_file, normc.nrdt); + // TX crystal DT parameter + normc.dtc = read_from_binary_file(norm_file, normc.ncdt); + // additional axial effects + normc.axe2 = read_from_binary_file(norm_file, normc.naxe); + + // Close file + norm_file.close(); + + // One of the pieces of data is stored as a numpy file. Read it. + normc.axf1 = read_numpy_axf1(NSINOS); + + return normc; } /// Get bucket singles (from mmrhist.py) std::vector -get_buckets(unsigned int *bck, const unsigned B, const unsigned nitag) -{ - // number of single rates reported for the given second - // nsr = (hstout['bck'][1,:,:]>>30) - std::vector nsr(nitag * B); - for (unsigned i=0; i> 30; - - - // average in a second period - // hstout['bck'][0,nsr>0] /= nsr[nsr>0] - for (unsigned i=0; i0) - bck[nitag * B + to_1d_idx(nitag,B,i,j)] /= - nsr[to_1d_idx(nitag,B,i,j)]; - - // time indices when single rates given - // tmsk = np.sum(nsr,axis=1)>0 - std::vector tmsk(nitag,false); - for (unsigned i=0; i0) { - tmsk[i] = true; - break; - } - - // single_rate = np.copy(hstout['bck'][0,tmsk,:]) - std::vector single_rate; - for (unsigned i=0; i buckets(B,0); - for (unsigned i=0; i>30) + std::vector nsr(nitag * B); + for (unsigned i = 0; i < nitag; ++i) + for (unsigned j = 0; j < B; ++j) + nsr[to_1d_idx(nitag, B, i, j)] = bck[nitag * B + to_1d_idx(nitag, B, i, j)] >> 30; + + // average in a second period + // hstout['bck'][0,nsr>0] /= nsr[nsr>0] + for (unsigned i = 0; i < nitag; ++i) + for (unsigned j = 0; j < B; ++j) + if (nsr[to_1d_idx(nitag, B, i, j)] > 0) + bck[nitag * B + to_1d_idx(nitag, B, i, j)] /= nsr[to_1d_idx(nitag, B, i, j)]; + + // time indices when single rates given + // tmsk = np.sum(nsr,axis=1)>0 + std::vector tmsk(nitag, false); + for (unsigned i = 0; i < nitag; ++i) + for (unsigned j = 0; j < B; ++j) + if (nsr[to_1d_idx(nitag, B, i, j)] > 0) { + tmsk[i] = true; + break; + } + + // single_rate = np.copy(hstout['bck'][0,tmsk,:]) + std::vector single_rate; + for (unsigned i = 0; i < nitag; ++i) + if (tmsk[i]) + for (unsigned j = 0; j < B; ++j) + single_rate.push_back(bck[to_1d_idx(nitag, B, i, j)]); + unsigned sr_dim0 = single_rate.size() / B; + + // get the average bucket singles: + // buckets = np.int32( np.sum(single_rate,axis=0)/single_rate.shape[0] ) + std::vector buckets(B, 0); + for (unsigned i = 0; i < sr_dim0; ++i) + for (unsigned j = 0; j < B; ++j) + buckets[j] += int(single_rate[to_1d_idx(sr_dim0, B, i, j)]); + for (unsigned i = 0; i < B; ++i) + buckets[i] /= sr_dim0; + + return buckets; } void -NiftyPETHelper:: -lm_to_proj_data(shared_ptr &prompts_sptr, shared_ptr &delayeds_sptr, - shared_ptr &randoms_sptr, shared_ptr &norm_sptr, - const int tstart, const int tstop, - const std::string &lm_binary_file, const std::string &norm_binary_file) const -{ - check_set_up(); - - // Get LM file as absolute path - std::string lm_abs = lm_binary_file; - if (!FilePath::is_absolute(lm_binary_file)) { - FilePath fp_lm_binary(lm_binary_file); - fp_lm_binary.prepend_directory_name(FilePath::get_current_working_directory()); - lm_abs = fp_lm_binary.get_as_string(); - } - - // Get listmode info - getLMinfo(const_cast(lm_abs.c_str()), *_cnt_sptr); - free(lmprop.atag); - free(lmprop.btag); - free(lmprop.ele4chnk); - free(lmprop.ele4thrd); - free(lmprop.t2dfrm); - - // preallocate all the output arrays - in def.h VTIME=2 (), MXNITAG=5400 (max time 1h30) - const int nitag = lmprop.nitag; - const int pow_2_MXNITAG = pow(2,VTIME); - int tn; - if (nitag>MXNITAG) - tn = MXNITAG/pow_2_MXNITAG; - else - tn = (nitag+pow_2_MXNITAG-1)/pow_2_MXNITAG; - - unsigned short frames(0); - int nfrm(1); - - // structure of output data - // var | type | python var | description | shape - // ------+--------------------|------------+----------------------------------+----------------------------------------------------------------- - // nitag | int | | gets set inside lmproc | - // sne | int | | gets set inside lmproc | - // snv | unsigned int * | pvs | sino views | [ tn, Cnt['NSEG0'], Cnt['NSBINS'] ] - // hcp | unsigned int * | phc | head curve prompts | [ nitag ] - // hcd | unsigned int * | dhc | head curve delayeds | [ nitag ] - // fan | unsigned int * | fan | fansums | [ nfrm, Cnt['NRNG'], Cnt['NCRS'] ] - // bck | unsigned int * | bck | buckets (singles) | [ 2, nitag, Cnt['NBCKT'] ] - // mss | float * | mss | centre of mass (axially) | [ nitag ] - // ssr | unsigned int * | ssr | | [ Cnt['NSEG0'], Cnt['NSANGLES'], Cnt['NSBINS'] ] - // psn | void * | psino | if nfrm==1, unsigned int* | [ nfrm, nsinos, Cnt['NSANGLES'], Cnt['NSBINS'] ] - // dsn | void * | dsino | if nfrm==1, unsigned int* | [ nfrm, nsinos, Cnt['NSANGLES'], Cnt['NSBINS'] ] - // psm | unsigned long long | | gets set inside lmproc | - // dsm | unsigned long long | | gets set inside lmproc | - // tot | unsigned int | | gets set inside lmproc | - const unsigned int num_sino_elements = _nsinos * _cnt_sptr->A * _cnt_sptr->W; - hstout dicout; - dicout.snv = create_heap_array(tn * _cnt_sptr->NSEG0 * _cnt_sptr->W); - dicout.hcp = create_heap_array(nitag); - dicout.hcd = create_heap_array(nitag); - dicout.fan = create_heap_array(nfrm * _cnt_sptr->NRNG * _cnt_sptr->NCRS); - dicout.bck = create_heap_array(2 * nitag * _cnt_sptr->B); - dicout.mss = create_heap_array (nitag); - dicout.ssr = create_heap_array(_cnt_sptr->NSEG0 * _cnt_sptr->A * _cnt_sptr->W); - if (nfrm == 1) { - dicout.psn = create_heap_array(nfrm * num_sino_elements); - dicout.dsn = create_heap_array(nfrm * num_sino_elements); - } - else - throw std::runtime_error("NiftyPETHelper::lm_to_proj_data: If nfrm>1, " - "dicout.psn and dicout.dsn should be unsigned char*. Not " - "tested, but should be pretty easy."); - - lmproc(dicout, // hstout (struct): output - const_cast(lm_abs.c_str()), // char *: binary filename (.s, .bf) - &frames, // unsigned short *: think for one frame, frames = 0 - nfrm, // int: num frames - tstart, // int - tstop, // int - _txlut_sptr->s2cF, // *LORcc (struct) - *_axlut_sptr, // axialLUT (struct) - *_cnt_sptr); // Cnst (struct) - - // Convert prompts and delayeds to STIR sinogram - const unsigned short *psn_int = (const unsigned short*)dicout.psn; - const unsigned short *dsn_int = (const unsigned short*)dicout.dsn; - std::vector np_prompts = create_niftyPET_sinogram_with_gaps(); - std::vector np_delayeds = create_niftyPET_sinogram_with_gaps(); - for (unsigned i=0; i cmap(_cnt_sptr->NCRS*_cnt_sptr->NRNG, 0); - - // Estiamte randoms from delayeds - std::vector np_randoms = create_niftyPET_sinogram_with_gaps(); - gpu_randoms(np_randoms.data(), // float *rsn - cmap.data(), // float *cmap, - dicout.fan, // unsigned int * fansums, - *_txlut_sptr, // txLUTs txlut, - _axlut_sptr->sn1_rno, // short *sn1_rno, - _axlut_sptr->sn1_sn11, // short *sn1_sn11, - *_cnt_sptr // const Cnst Cnt) - ); - - randoms_sptr = create_stir_sino(); - convert_proj_data_niftyPET_to_stir(*randoms_sptr, np_randoms); - - // If norm binary has been supplied, generate the norm sinogram - if (!norm_binary_file.empty()) { - - // Get helper - NormCmp normc = get_norm_helper_struct(norm_binary_file, *_cnt_sptr); - - // Get bucket singles - std::vector buckets = get_buckets(dicout.bck, unsigned(_cnt_sptr->B), unsigned(nitag)); - - std::vector np_norm_no_gaps = this->create_niftyPET_sinogram_no_gaps(); - - // Do the conversion - norm_from_components(np_norm_no_gaps.data(), - normc, - *_axlut_sptr, - _txlut_sptr->aw2ali, - buckets.data(), - *_cnt_sptr); - - // Add gaps - std::vector np_norm_w_gaps = this->create_niftyPET_sinogram_with_gaps(); - put_gaps(np_norm_w_gaps,np_norm_no_gaps); - - // Convert to STIR sinogram - norm_sptr = create_stir_sino(); - convert_proj_data_niftyPET_to_stir(*norm_sptr, np_norm_w_gaps); - - // Clear up - delete [] normc.geo; - delete [] normc.cinf; - delete [] normc.ceff; - delete [] normc.axe1; - delete [] normc.dtp; - delete [] normc.dtnp; - delete [] normc.dtc; - delete [] normc.axe2; - delete [] normc.axf1; - } +NiftyPETHelper::lm_to_proj_data(shared_ptr& prompts_sptr, shared_ptr& delayeds_sptr, + shared_ptr& randoms_sptr, shared_ptr& norm_sptr, const int tstart, + const int tstop, const std::string& lm_binary_file, const std::string& norm_binary_file) const { + check_set_up(); + + // Get LM file as absolute path + std::string lm_abs = lm_binary_file; + if (!FilePath::is_absolute(lm_binary_file)) { + FilePath fp_lm_binary(lm_binary_file); + fp_lm_binary.prepend_directory_name(FilePath::get_current_working_directory()); + lm_abs = fp_lm_binary.get_as_string(); + } + + // Get listmode info + getLMinfo(const_cast(lm_abs.c_str()), *_cnt_sptr); + free(lmprop.atag); + free(lmprop.btag); + free(lmprop.ele4chnk); + free(lmprop.ele4thrd); + free(lmprop.t2dfrm); + + // preallocate all the output arrays - in def.h VTIME=2 (), MXNITAG=5400 (max time 1h30) + const int nitag = lmprop.nitag; + const int pow_2_MXNITAG = pow(2, VTIME); + int tn; + if (nitag > MXNITAG) + tn = MXNITAG / pow_2_MXNITAG; + else + tn = (nitag + pow_2_MXNITAG - 1) / pow_2_MXNITAG; + + unsigned short frames(0); + int nfrm(1); + + // structure of output data + // var | type | python var | description | shape + // ------+--------------------|------------+----------------------------------+----------------------------------------------------------------- + // nitag | int | | gets set inside lmproc | + // sne | int | | gets set inside lmproc | + // snv | unsigned int * | pvs | sino views | [ tn, Cnt['NSEG0'], Cnt['NSBINS'] ] + // hcp | unsigned int * | phc | head curve prompts | [ nitag ] hcd | unsigned int * | dhc | + // head curve delayeds | [ nitag ] fan | unsigned int * + // | fan | fansums | [ nfrm, Cnt['NRNG'], Cnt['NCRS'] ] bck | + // unsigned int * | bck | buckets (singles) | [ 2, nitag, Cnt['NBCKT'] ] mss | + // float * | mss | centre of mass (axially) | [ nitag ] ssr | unsigned int * | ssr | | [ + // Cnt['NSEG0'], Cnt['NSANGLES'], Cnt['NSBINS'] ] psn | void * | psino | if nfrm==1, + // unsigned int* | [ nfrm, nsinos, Cnt['NSANGLES'], Cnt['NSBINS'] ] dsn | void * | dsino + // | if nfrm==1, unsigned int* | [ nfrm, nsinos, Cnt['NSANGLES'], Cnt['NSBINS'] ] psm | unsigned long + // long | | gets set inside lmproc | dsm | unsigned long long | | gets set inside lmproc | tot + // | unsigned int | | gets set inside lmproc | + const unsigned int num_sino_elements = _nsinos * _cnt_sptr->A * _cnt_sptr->W; + hstout dicout; + dicout.snv = create_heap_array(tn * _cnt_sptr->NSEG0 * _cnt_sptr->W); + dicout.hcp = create_heap_array(nitag); + dicout.hcd = create_heap_array(nitag); + dicout.fan = create_heap_array(nfrm * _cnt_sptr->NRNG * _cnt_sptr->NCRS); + dicout.bck = create_heap_array(2 * nitag * _cnt_sptr->B); + dicout.mss = create_heap_array(nitag); + dicout.ssr = create_heap_array(_cnt_sptr->NSEG0 * _cnt_sptr->A * _cnt_sptr->W); + if (nfrm == 1) { + dicout.psn = create_heap_array(nfrm * num_sino_elements); + dicout.dsn = create_heap_array(nfrm * num_sino_elements); + } else + throw std::runtime_error("NiftyPETHelper::lm_to_proj_data: If nfrm>1, " + "dicout.psn and dicout.dsn should be unsigned char*. Not " + "tested, but should be pretty easy."); + + lmproc(dicout, // hstout (struct): output + const_cast(lm_abs.c_str()), // char *: binary filename (.s, .bf) + &frames, // unsigned short *: think for one frame, frames = 0 + nfrm, // int: num frames + tstart, // int + tstop, // int + _txlut_sptr->s2cF, // *LORcc (struct) + *_axlut_sptr, // axialLUT (struct) + *_cnt_sptr); // Cnst (struct) + + // Convert prompts and delayeds to STIR sinogram + const unsigned short* psn_int = (const unsigned short*)dicout.psn; + const unsigned short* dsn_int = (const unsigned short*)dicout.dsn; + std::vector np_prompts = create_niftyPET_sinogram_with_gaps(); + std::vector np_delayeds = create_niftyPET_sinogram_with_gaps(); + for (unsigned i = 0; i < num_sino_elements; ++i) { + np_prompts[i] = float(psn_int[i]); + np_delayeds[i] = float(dsn_int[i]); + } + prompts_sptr = create_stir_sino(); + delayeds_sptr = create_stir_sino(); + convert_proj_data_niftyPET_to_stir(*prompts_sptr, np_prompts); + convert_proj_data_niftyPET_to_stir(*delayeds_sptr, np_delayeds); + + // estimated crystal map of singles + // cmap = np.zeros((Cnt['NCRS'], Cnt['NRNG']), dtype=np.float32) + std::vector cmap(_cnt_sptr->NCRS * _cnt_sptr->NRNG, 0); + + // Estiamte randoms from delayeds + std::vector np_randoms = create_niftyPET_sinogram_with_gaps(); + gpu_randoms(np_randoms.data(), // float *rsn + cmap.data(), // float *cmap, + dicout.fan, // unsigned int * fansums, + *_txlut_sptr, // txLUTs txlut, + _axlut_sptr->sn1_rno, // short *sn1_rno, + _axlut_sptr->sn1_sn11, // short *sn1_sn11, + *_cnt_sptr // const Cnst Cnt) + ); + + randoms_sptr = create_stir_sino(); + convert_proj_data_niftyPET_to_stir(*randoms_sptr, np_randoms); + + // If norm binary has been supplied, generate the norm sinogram + if (!norm_binary_file.empty()) { + + // Get helper + NormCmp normc = get_norm_helper_struct(norm_binary_file, *_cnt_sptr); + + // Get bucket singles + std::vector buckets = get_buckets(dicout.bck, unsigned(_cnt_sptr->B), unsigned(nitag)); + + std::vector np_norm_no_gaps = this->create_niftyPET_sinogram_no_gaps(); + + // Do the conversion + norm_from_components(np_norm_no_gaps.data(), normc, *_axlut_sptr, _txlut_sptr->aw2ali, buckets.data(), *_cnt_sptr); + + // Add gaps + std::vector np_norm_w_gaps = this->create_niftyPET_sinogram_with_gaps(); + put_gaps(np_norm_w_gaps, np_norm_no_gaps); + + // Convert to STIR sinogram + norm_sptr = create_stir_sino(); + convert_proj_data_niftyPET_to_stir(*norm_sptr, np_norm_w_gaps); // Clear up - delete [] dicout.snv; - delete [] dicout.hcp; - delete [] dicout.hcd; - delete [] dicout.fan; - delete [] dicout.bck; - delete [] dicout.mss; - delete [] dicout.ssr; - if (nfrm == 1) { - delete [] (unsigned short*)dicout.psn; - delete [] (unsigned short*)dicout.dsn; - } - else - throw std::runtime_error("NiftyPETHelper::lm_to_proj_data: If nfrm>1, " - "need to cast before deleting as is stored as void*."); + delete[] normc.geo; + delete[] normc.cinf; + delete[] normc.ceff; + delete[] normc.axe1; + delete[] normc.dtp; + delete[] normc.dtnp; + delete[] normc.dtc; + delete[] normc.axe2; + delete[] normc.axf1; + } + + // Clear up + delete[] dicout.snv; + delete[] dicout.hcp; + delete[] dicout.hcd; + delete[] dicout.fan; + delete[] dicout.bck; + delete[] dicout.mss; + delete[] dicout.ssr; + if (nfrm == 1) { + delete[](unsigned short*) dicout.psn; + delete[](unsigned short*) dicout.dsn; + } else + throw std::runtime_error("NiftyPETHelper::lm_to_proj_data: If nfrm>1, " + "need to cast before deleting as is stored as void*."); } -void check_im_sizes(const int stir_dim[3], const int np_dim[3]) -{ - for (int i=0; i<3; ++i) - if (stir_dim[i] != np_dim[i]) - throw std::runtime_error((boost::format( - "NiftyPETHelper::check_im_sizes() - " - "STIR image (%1%, %2%, %3%) should be == (%4%,%5%,%6%).") - % stir_dim[0] % stir_dim[1] % stir_dim[2] - % np_dim[0] % np_dim[1] % np_dim[2]).str()); +void +check_im_sizes(const int stir_dim[3], const int np_dim[3]) { + for (int i = 0; i < 3; ++i) + if (stir_dim[i] != np_dim[i]) + throw std::runtime_error((boost::format("NiftyPETHelper::check_im_sizes() - " + "STIR image (%1%, %2%, %3%) should be == (%4%,%5%,%6%).") % + stir_dim[0] % stir_dim[1] % stir_dim[2] % np_dim[0] % np_dim[1] % np_dim[2]) + .str()); } -void check_voxel_spacing(const DiscretisedDensity<3, float> &stir) -{ - // Requires image to be a VoxelsOnCartesianGrid - const VoxelsOnCartesianGrid &stir_vocg = - dynamic_cast&>(stir); - const BasicCoordinate<3,float> stir_spacing = stir_vocg.get_grid_spacing(); - - // Get NiftyPET image spacing (need to *10 for mm) - float np_spacing[3] = { 10.f*SZ_VOXZ, 10.f*SZ_VOXY, 10.f*SZ_VOXY }; - - for (unsigned i=0; i<3; ++i) - if (std::abs(stir_spacing[int(i)+1] - np_spacing[i]) > 1e-4f) - throw std::runtime_error((boost::format( - "NiftyPETHelper::check_voxel_spacing() - " - "STIR image (%1%, %2%, %3%) should be == (%4%,%5%,%6%).") - % stir_spacing[1] % stir_spacing[2] % stir_spacing[3] - % np_spacing[0] % np_spacing[1] % np_spacing[2]).str()); +void +check_voxel_spacing(const DiscretisedDensity<3, float>& stir) { + // Requires image to be a VoxelsOnCartesianGrid + const VoxelsOnCartesianGrid& stir_vocg = dynamic_cast&>(stir); + const BasicCoordinate<3, float> stir_spacing = stir_vocg.get_grid_spacing(); + + // Get NiftyPET image spacing (need to *10 for mm) + float np_spacing[3] = {10.f * SZ_VOXZ, 10.f * SZ_VOXY, 10.f * SZ_VOXY}; + + for (unsigned i = 0; i < 3; ++i) + if (std::abs(stir_spacing[int(i) + 1] - np_spacing[i]) > 1e-4f) + throw std::runtime_error((boost::format("NiftyPETHelper::check_voxel_spacing() - " + "STIR image (%1%, %2%, %3%) should be == (%4%,%5%,%6%).") % + stir_spacing[1] % stir_spacing[2] % stir_spacing[3] % np_spacing[0] % np_spacing[1] % + np_spacing[2]) + .str()); } void -NiftyPETHelper:: -convert_image_stir_to_niftyPET(std::vector &np_vec, const DiscretisedDensity<3, float> &stir) -{ - // Get the dimensions of the input image - Coordinate3D min_indices; - Coordinate3D max_indices; - int stir_dim[3]; - get_stir_indices_and_dims(stir_dim,min_indices,max_indices,stir); - - // NiftyPET requires the image to be (z,x,y)=(SZ_IMZ,SZ_IMX,SZ_IMY) - // which at the time of writing was (127,320,320). - const int np_dim[3] = {SZ_IMZ,SZ_IMX,SZ_IMY}; - check_im_sizes(stir_dim,np_dim); - check_voxel_spacing(stir); - - // Copy data from STIR to NiftyPET image - unsigned np_z, np_y, np_x, np_1d; - for (int z = min_indices[1]; z <= max_indices[1]; z++) { - for (int y = min_indices[2]; y <= max_indices[2]; y++) { - for (int x = min_indices[3]; x <= max_indices[3]; x++) { - // Convert the stir 3d index to a NiftyPET 1d index - np_z = unsigned(z - min_indices[1]); - np_y = unsigned(y - min_indices[2]); - np_x = unsigned(x - min_indices[3]); - np_1d = convert_NiftyPET_im_3d_to_1d_idx(np_x,np_y,np_z); - np_vec[np_1d] = stir[z][y][x]; - } - } +NiftyPETHelper::convert_image_stir_to_niftyPET(std::vector& np_vec, const DiscretisedDensity<3, float>& stir) { + // Get the dimensions of the input image + Coordinate3D min_indices; + Coordinate3D max_indices; + int stir_dim[3]; + get_stir_indices_and_dims(stir_dim, min_indices, max_indices, stir); + + // NiftyPET requires the image to be (z,x,y)=(SZ_IMZ,SZ_IMX,SZ_IMY) + // which at the time of writing was (127,320,320). + const int np_dim[3] = {SZ_IMZ, SZ_IMX, SZ_IMY}; + check_im_sizes(stir_dim, np_dim); + check_voxel_spacing(stir); + + // Copy data from STIR to NiftyPET image + unsigned np_z, np_y, np_x, np_1d; + for (int z = min_indices[1]; z <= max_indices[1]; z++) { + for (int y = min_indices[2]; y <= max_indices[2]; y++) { + for (int x = min_indices[3]; x <= max_indices[3]; x++) { + // Convert the stir 3d index to a NiftyPET 1d index + np_z = unsigned(z - min_indices[1]); + np_y = unsigned(y - min_indices[2]); + np_x = unsigned(x - min_indices[3]); + np_1d = convert_NiftyPET_im_3d_to_1d_idx(np_x, np_y, np_z); + np_vec[np_1d] = stir[z][y][x]; + } } + } } void -NiftyPETHelper:: -convert_image_niftyPET_to_stir(DiscretisedDensity<3,float> &stir, const std::vector &np_vec) -{ - // Get the dimensions of the input image - Coordinate3D min_indices; - Coordinate3D max_indices; - int stir_dim[3]; - get_stir_indices_and_dims(stir_dim,min_indices,max_indices,stir); - - // NiftyPET requires the image to be (z,x,y)=(SZ_IMZ,SZ_IMX,SZ_IMY) - // which at the time of writing was (127,320,320). - const int np_dim[3] = {SZ_IMZ,SZ_IMX,SZ_IMY}; - check_im_sizes(stir_dim,np_dim); - check_voxel_spacing(stir); - - // Copy data from NiftyPET to STIR image - unsigned np_z, np_y, np_x, np_1d; - for (int z = min_indices[1]; z <= max_indices[1]; z++) { - for (int y = min_indices[2]; y <= max_indices[2]; y++) { - for (int x = min_indices[3]; x <= max_indices[3]; x++) { - // Convert the stir 3d index to a NiftyPET 1d index - np_z = unsigned(z - min_indices[1]); - np_y = unsigned(y - min_indices[2]); - np_x = unsigned(x - min_indices[3]); - np_1d = convert_NiftyPET_im_3d_to_1d_idx(np_x,np_y,np_z); - stir[z][y][x] = np_vec[np_1d]; - } - } +NiftyPETHelper::convert_image_niftyPET_to_stir(DiscretisedDensity<3, float>& stir, const std::vector& np_vec) { + // Get the dimensions of the input image + Coordinate3D min_indices; + Coordinate3D max_indices; + int stir_dim[3]; + get_stir_indices_and_dims(stir_dim, min_indices, max_indices, stir); + + // NiftyPET requires the image to be (z,x,y)=(SZ_IMZ,SZ_IMX,SZ_IMY) + // which at the time of writing was (127,320,320). + const int np_dim[3] = {SZ_IMZ, SZ_IMX, SZ_IMY}; + check_im_sizes(stir_dim, np_dim); + check_voxel_spacing(stir); + + // Copy data from NiftyPET to STIR image + unsigned np_z, np_y, np_x, np_1d; + for (int z = min_indices[1]; z <= max_indices[1]; z++) { + for (int y = min_indices[2]; y <= max_indices[2]; y++) { + for (int x = min_indices[3]; x <= max_indices[3]; x++) { + // Convert the stir 3d index to a NiftyPET 1d index + np_z = unsigned(z - min_indices[1]); + np_y = unsigned(y - min_indices[2]); + np_x = unsigned(x - min_indices[3]); + np_1d = convert_NiftyPET_im_3d_to_1d_idx(np_x, np_y, np_z); + stir[z][y][x] = np_vec[np_1d]; + } } + } } void -get_vals_for_proj_data_conversion(std::vector &sizes, std::vector &segment_sequence, - int &num_sinograms, int &min_view, int &max_view, - int &min_tang_pos, int &max_tang_pos, - const ProjDataInfo& proj_data_info, const std::vector &np_vec) -{ - const ProjDataInfoCylindricalNoArcCorr * info_sptr = - dynamic_cast(&proj_data_info); - if (is_null_ptr(info_sptr)) - error("NiftyPETHelper: only works with cylindrical projection data without arc-correction"); - - segment_sequence = ecat::find_segment_sequence(proj_data_info); - sizes.resize(segment_sequence.size()); - for (std::size_t s=0U; s& sizes, std::vector& segment_sequence, int& num_sinograms, int& min_view, + int& max_view, int& min_tang_pos, int& max_tang_pos, const ProjDataInfo& proj_data_info, + const std::vector& np_vec) { + const ProjDataInfoCylindricalNoArcCorr* info_sptr = dynamic_cast(&proj_data_info); + if (is_null_ptr(info_sptr)) + error("NiftyPETHelper: only works with cylindrical projection data without arc-correction"); + + segment_sequence = ecat::find_segment_sequence(proj_data_info); + sizes.resize(segment_sequence.size()); + for (std::size_t s = 0U; s < segment_sequence.size(); ++s) + sizes[s] = proj_data_info.get_num_axial_poss(segment_sequence[s]); + + // Get dimensions of STIR sinogram + min_view = proj_data_info.get_min_view_num(); + max_view = proj_data_info.get_max_view_num(); + min_tang_pos = proj_data_info.get_min_tangential_pos_num(); + max_tang_pos = proj_data_info.get_max_tangential_pos_num(); + + num_sinograms = proj_data_info.get_num_axial_poss(0); + for (int s = 1; s <= proj_data_info.get_max_segment_num(); ++s) + num_sinograms += 2 * proj_data_info.get_num_axial_poss(s); + + int num_proj_data_elems = num_sinograms * (1 + max_view - min_view) * (1 + max_tang_pos - min_tang_pos); + + // Make sure they're the same size + if (np_vec.size() != unsigned(num_proj_data_elems)) + error(boost::format("NiftyPETHelper::get_vals_for_proj_data_conversion " + "NiftyPET and STIR sinograms are different sizes (%1% for STIR versus %2% for NP") % + num_proj_data_elems % np_vec.size()); } -void get_stir_segment_and_axial_pos_from_NiftyPET_sino(int &segment, int &axial_pos, const unsigned np_sino, const std::vector &sizes, const std::vector &segment_sequence) -{ - int z = int(np_sino); - for (unsigned i=0; i& sizes, const std::vector& segment_sequence) { + int z = int(np_sino); + for (unsigned i = 0; i < segment_sequence.size(); ++i) { + if (z < sizes[i]) { + axial_pos = z; + segment = segment_sequence[i]; + return; + } else { + z -= sizes[i]; } + } } -void get_NiftyPET_sino_from_stir_segment_and_axial_pos(unsigned &np_sino, const int segment, const int axial_pos, const std::vector &sizes, const std::vector &segment_sequence) -{ - np_sino = 0U; - for (unsigned i=0; i& sizes, const std::vector& segment_sequence) { + np_sino = 0U; + for (unsigned i = 0; i < segment_sequence.size(); ++i) { + if (segment == segment_sequence[i]) { + np_sino += axial_pos; + return; + } else { + np_sino += sizes[i]; } - throw std::runtime_error("NiftyPETHelper::get_NiftyPET_sino_from_stir_segment_and_axial_pos(): Failed to find NiftyPET sinogram."); + } + throw std::runtime_error( + "NiftyPETHelper::get_NiftyPET_sino_from_stir_segment_and_axial_pos(): Failed to find NiftyPET sinogram."); } void -NiftyPETHelper:: -convert_viewgram_stir_to_niftyPET(std::vector &np_vec, const Viewgram& viewgram) const -{ - // Get the values (and LUT) to be able to switch between STIR and NiftyPET projDatas - std::vector sizes, segment_sequence; - int num_sinograms, min_view, max_view, min_tang_pos, max_tang_pos; - get_vals_for_proj_data_conversion(sizes, segment_sequence, num_sinograms, min_view, max_view, - min_tang_pos, max_tang_pos, *viewgram.get_proj_data_info_sptr(), np_vec); - - const int segment = viewgram.get_segment_num(); - const int view = viewgram.get_view_num(); +NiftyPETHelper::convert_viewgram_stir_to_niftyPET(std::vector& np_vec, const Viewgram& viewgram) const { + // Get the values (and LUT) to be able to switch between STIR and NiftyPET projDatas + std::vector sizes, segment_sequence; + int num_sinograms, min_view, max_view, min_tang_pos, max_tang_pos; + get_vals_for_proj_data_conversion(sizes, segment_sequence, num_sinograms, min_view, max_view, min_tang_pos, max_tang_pos, + *viewgram.get_proj_data_info_sptr(), np_vec); - // Loop over the STIR view and tangential position - for (int ax_pos=viewgram.get_min_axial_pos_num(); ax_pos<=viewgram.get_max_axial_pos_num(); ++ax_pos) { + const int segment = viewgram.get_segment_num(); + const int view = viewgram.get_view_num(); - unsigned np_sino; + // Loop over the STIR view and tangential position + for (int ax_pos = viewgram.get_min_axial_pos_num(); ax_pos <= viewgram.get_max_axial_pos_num(); ++ax_pos) { - // Convert the NiftyPET sinogram to STIR's segment and axial position - get_NiftyPET_sino_from_stir_segment_and_axial_pos(np_sino, segment, ax_pos, sizes, segment_sequence); + unsigned np_sino; - for (int tang_pos=min_tang_pos; tang_pos<=max_tang_pos; ++tang_pos) { + // Convert the NiftyPET sinogram to STIR's segment and axial position + get_NiftyPET_sino_from_stir_segment_and_axial_pos(np_sino, segment, ax_pos, sizes, segment_sequence); - unsigned np_ang = unsigned(view-min_view); - unsigned np_bin = unsigned(tang_pos-min_tang_pos); - unsigned np_1d = convert_NiftyPET_proj_3d_to_1d_idx(np_ang,np_bin,np_sino); - np_vec.at(np_1d) = viewgram.at(ax_pos).at(tang_pos); - } + for (int tang_pos = min_tang_pos; tang_pos <= max_tang_pos; ++tang_pos) { + + unsigned np_ang = unsigned(view - min_view); + unsigned np_bin = unsigned(tang_pos - min_tang_pos); + unsigned np_1d = convert_NiftyPET_proj_3d_to_1d_idx(np_ang, np_bin, np_sino); + np_vec.at(np_1d) = viewgram.at(ax_pos).at(tang_pos); } + } } void -NiftyPETHelper:: -convert_proj_data_stir_to_niftyPET(std::vector &np_vec, const ProjData& stir) const -{ - const int min_view = stir.get_min_view_num(); - const int max_view = stir.get_max_view_num(); - const int min_segment = stir.get_min_segment_num(); - const int max_segment = stir.get_max_segment_num(); - - for (int view=min_view; view<=max_view; ++view) { - for (int segment=min_segment; segment<=max_segment; ++segment) { - convert_viewgram_stir_to_niftyPET(np_vec, stir.get_viewgram(view,segment)); - } +NiftyPETHelper::convert_proj_data_stir_to_niftyPET(std::vector& np_vec, const ProjData& stir) const { + const int min_view = stir.get_min_view_num(); + const int max_view = stir.get_max_view_num(); + const int min_segment = stir.get_min_segment_num(); + const int max_segment = stir.get_max_segment_num(); + + for (int view = min_view; view <= max_view; ++view) { + for (int segment = min_segment; segment <= max_segment; ++segment) { + convert_viewgram_stir_to_niftyPET(np_vec, stir.get_viewgram(view, segment)); } + } } void -NiftyPETHelper:: -convert_proj_data_niftyPET_to_stir(ProjData &stir, const std::vector &np_vec) const -{ - // Get the values (and LUT) to be able to switch between STIR and NiftyPET projDatas - std::vector sizes, segment_sequence; - int num_sinograms, min_view, max_view, min_tang_pos, max_tang_pos; - get_vals_for_proj_data_conversion(sizes, segment_sequence, num_sinograms, min_view, max_view, - min_tang_pos, max_tang_pos, *stir.get_proj_data_info_sptr(), np_vec); - - int segment, axial_pos; - // Loop over all NiftyPET sinograms - for (unsigned np_sino = 0; np_sino < unsigned(num_sinograms); ++np_sino) { - - // Convert the NiftyPET sinogram to STIR's segment and axial position - get_stir_segment_and_axial_pos_from_NiftyPET_sino(segment, axial_pos, np_sino, sizes, segment_sequence); - - // Get the corresponding STIR sinogram - Sinogram sino = stir.get_empty_sinogram(axial_pos,segment); - - // Loop over the STIR view and tangential position - for (int view=min_view; view<=max_view; ++view) { - for (int tang_pos=min_tang_pos; tang_pos<=max_tang_pos; ++tang_pos) { - - unsigned np_ang = unsigned(view-min_view); - unsigned np_bin = unsigned(tang_pos-min_tang_pos); - unsigned np_1d = convert_NiftyPET_proj_3d_to_1d_idx(np_ang,np_bin,np_sino); - sino.at(view).at(tang_pos) = np_vec.at(np_1d); - } - } - stir.set_sinogram(sino); +NiftyPETHelper::convert_proj_data_niftyPET_to_stir(ProjData& stir, const std::vector& np_vec) const { + // Get the values (and LUT) to be able to switch between STIR and NiftyPET projDatas + std::vector sizes, segment_sequence; + int num_sinograms, min_view, max_view, min_tang_pos, max_tang_pos; + get_vals_for_proj_data_conversion(sizes, segment_sequence, num_sinograms, min_view, max_view, min_tang_pos, max_tang_pos, + *stir.get_proj_data_info_sptr(), np_vec); + + int segment, axial_pos; + // Loop over all NiftyPET sinograms + for (unsigned np_sino = 0; np_sino < unsigned(num_sinograms); ++np_sino) { + + // Convert the NiftyPET sinogram to STIR's segment and axial position + get_stir_segment_and_axial_pos_from_NiftyPET_sino(segment, axial_pos, np_sino, sizes, segment_sequence); + + // Get the corresponding STIR sinogram + Sinogram sino = stir.get_empty_sinogram(axial_pos, segment); + + // Loop over the STIR view and tangential position + for (int view = min_view; view <= max_view; ++view) { + for (int tang_pos = min_tang_pos; tang_pos <= max_tang_pos; ++tang_pos) { + + unsigned np_ang = unsigned(view - min_view); + unsigned np_bin = unsigned(tang_pos - min_tang_pos); + unsigned np_1d = convert_NiftyPET_proj_3d_to_1d_idx(np_ang, np_bin, np_sino); + sino.at(view).at(tang_pos) = np_vec.at(np_1d); + } } + stir.set_sinogram(sino); + } } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.cxx b/src/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.cxx index 89ea36ded3..b70e6f2052 100644 --- a/src/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.cxx +++ b/src/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.cxx @@ -6,9 +6,9 @@ \ingroup NiftyPET \brief non-inline implementations for stir::ProjectorByBinPairUsingNiftyPET - + \author Richard Brown - + */ /* Copyright (C) 2019, University College London @@ -27,52 +27,41 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.h" #include "stir/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.h" #include "stir/recon_buildblock/NiftyPET_projector/BackProjectorByBinNiftyPET.h" START_NAMESPACE_STIR +const char* const ProjectorByBinPairUsingNiftyPET::registered_name = "NiftyPET"; -const char * const -ProjectorByBinPairUsingNiftyPET::registered_name = - "NiftyPET"; - - -void -ProjectorByBinPairUsingNiftyPET::initialise_keymap() -{ +void +ProjectorByBinPairUsingNiftyPET::initialise_keymap() { base_type::initialise_keymap(); parser.add_start_key("Projector Pair Using NiftyPET Parameters"); parser.add_stop_key("End Projector Pair Using NiftyPET Parameters"); - parser.add_key("verbosity",&_verbosity); - parser.add_key("use_truncation",&_use_truncation); + parser.add_key("verbosity", &_verbosity); + parser.add_key("use_truncation", &_use_truncation); } - void -ProjectorByBinPairUsingNiftyPET::set_defaults() -{ +ProjectorByBinPairUsingNiftyPET::set_defaults() { base_type::set_defaults(); this->set_verbosity(true); this->set_use_truncation(false); } bool -ProjectorByBinPairUsingNiftyPET::post_processing() -{ - this->set_verbosity(this->_verbosity); - this->set_use_truncation(this->_use_truncation); +ProjectorByBinPairUsingNiftyPET::post_processing() { + this->set_verbosity(this->_verbosity); + this->set_use_truncation(this->_use_truncation); if (base_type::post_processing()) return true; return false; } -ProjectorByBinPairUsingNiftyPET:: -ProjectorByBinPairUsingNiftyPET() -{ +ProjectorByBinPairUsingNiftyPET::ProjectorByBinPairUsingNiftyPET() { this->forward_projector_sptr.reset(new ForwardProjectorByBinNiftyPET); this->back_projector_sptr.reset(new BackProjectorByBinNiftyPET); set_defaults(); @@ -82,7 +71,7 @@ ProjectorByBinPairUsingNiftyPET() ProjectorByBinPairUsingNiftyPET:: set_up(const shared_ptr& proj_data_info_sptr, const shared_ptr >& image_info_sptr) -{ +{ // proj_matrix_sptr->set_up() not needed as the projection matrix will be set_up indirectly by // the forward_projector->set_up (which is called in the base class) // proj_matrix_sptr->set_up(proj_data_info_sptr, image_info_sptr); @@ -93,34 +82,34 @@ set_up(const shared_ptr& proj_data_info_sptr, return Succeeded::yes; }*/ -void ProjectorByBinPairUsingNiftyPET::set_verbosity(const bool verbosity) -{ - _verbosity = verbosity; - - shared_ptr fwd_prj_downcast_sptr = - dynamic_pointer_cast(this->forward_projector_sptr); - if (fwd_prj_downcast_sptr) - fwd_prj_downcast_sptr->set_verbosity(_verbosity); - - shared_ptr bck_prj_downcast_sptr = - dynamic_pointer_cast(this->back_projector_sptr); - if (bck_prj_downcast_sptr) - bck_prj_downcast_sptr->set_verbosity(_verbosity); +void +ProjectorByBinPairUsingNiftyPET::set_verbosity(const bool verbosity) { + _verbosity = verbosity; + + shared_ptr fwd_prj_downcast_sptr = + dynamic_pointer_cast(this->forward_projector_sptr); + if (fwd_prj_downcast_sptr) + fwd_prj_downcast_sptr->set_verbosity(_verbosity); + + shared_ptr bck_prj_downcast_sptr = + dynamic_pointer_cast(this->back_projector_sptr); + if (bck_prj_downcast_sptr) + bck_prj_downcast_sptr->set_verbosity(_verbosity); } -void ProjectorByBinPairUsingNiftyPET::set_use_truncation(const bool use_truncation) -{ - _use_truncation = use_truncation; - - shared_ptr fwd_prj_downcast_sptr = - dynamic_pointer_cast(this->forward_projector_sptr); - if (fwd_prj_downcast_sptr) - fwd_prj_downcast_sptr->set_use_truncation(_use_truncation); - - shared_ptr bck_prj_downcast_sptr = - dynamic_pointer_cast(this->back_projector_sptr); - if (bck_prj_downcast_sptr) - bck_prj_downcast_sptr->set_use_truncation(_use_truncation); +void +ProjectorByBinPairUsingNiftyPET::set_use_truncation(const bool use_truncation) { + _use_truncation = use_truncation; + + shared_ptr fwd_prj_downcast_sptr = + dynamic_pointer_cast(this->forward_projector_sptr); + if (fwd_prj_downcast_sptr) + fwd_prj_downcast_sptr->set_use_truncation(_use_truncation); + + shared_ptr bck_prj_downcast_sptr = + dynamic_pointer_cast(this->back_projector_sptr); + if (bck_prj_downcast_sptr) + bck_prj_downcast_sptr->set_use_truncation(_use_truncation); } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/PLSPrior.cxx b/src/recon_buildblock/PLSPrior.cxx index 3d9fa9f954..42989c293d 100644 --- a/src/recon_buildblock/PLSPrior.cxx +++ b/src/recon_buildblock/PLSPrior.cxx @@ -46,8 +46,7 @@ START_NAMESPACE_STIR template void -PLSPrior::initialise_keymap() -{ +PLSPrior::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("PLS Prior Parameters"); this->parser.add_key("only 2D", &only_2D); @@ -59,69 +58,65 @@ PLSPrior::initialise_keymap() this->parser.add_stop_key("END PLS Prior Parameters"); } - template Succeeded -PLSPrior::set_up (shared_ptr > const& target_sptr) -{ - base_type::set_up(target_sptr); - - if (is_null_ptr( this->anatomical_sptr)) - { - error("PLS prior needs an anatomical image"); - return Succeeded::no; - } +PLSPrior::set_up(shared_ptr> const& target_sptr) { + base_type::set_up(target_sptr); + + if (is_null_ptr(this->anatomical_sptr)) { + error("PLS prior needs an anatomical image"); + return Succeeded::no; + } - if(! (*target_sptr).has_same_characteristics(*this->anatomical_sptr)) - error("anatomical and target images are not compatible! Make sure they are"); + if (!(*target_sptr).has_same_characteristics(*this->anatomical_sptr)) + error("anatomical and target images are not compatible! Make sure they are"); - shared_ptr > anatomical_im_grad_z_sptr; - if (!only_2D) - anatomical_im_grad_z_sptr.reset(this->anatomical_sptr->get_empty_copy ()); + shared_ptr> anatomical_im_grad_z_sptr; + if (!only_2D) + anatomical_im_grad_z_sptr.reset(this->anatomical_sptr->get_empty_copy()); - shared_ptr > anatomical_im_grad_y_sptr(this->anatomical_sptr->get_empty_copy ()); - shared_ptr > anatomical_im_grad_x_sptr(this->anatomical_sptr->get_empty_copy ()); - shared_ptr > norm_sptr(this->anatomical_sptr->get_empty_copy ()); + shared_ptr> anatomical_im_grad_y_sptr(this->anatomical_sptr->get_empty_copy()); + shared_ptr> anatomical_im_grad_x_sptr(this->anatomical_sptr->get_empty_copy()); + shared_ptr> norm_sptr(this->anatomical_sptr->get_empty_copy()); - if (!only_2D) - compute_image_gradient_element ((*anatomical_im_grad_z_sptr),0,*this->anatomical_sptr); + if (!only_2D) + compute_image_gradient_element((*anatomical_im_grad_z_sptr), 0, *this->anatomical_sptr); - compute_image_gradient_element (*anatomical_im_grad_y_sptr,1,*this->anatomical_sptr); - compute_image_gradient_element (*anatomical_im_grad_x_sptr,2,*this->anatomical_sptr); + compute_image_gradient_element(*anatomical_im_grad_y_sptr, 1, *this->anatomical_sptr); + compute_image_gradient_element(*anatomical_im_grad_x_sptr, 2, *this->anatomical_sptr); - if (!only_2D) - this->set_anatomical_grad_sptr (anatomical_im_grad_z_sptr,0); + if (!only_2D) + this->set_anatomical_grad_sptr(anatomical_im_grad_z_sptr, 0); - this->set_anatomical_grad_sptr (anatomical_im_grad_y_sptr,1); - this->set_anatomical_grad_sptr (anatomical_im_grad_x_sptr,2); + this->set_anatomical_grad_sptr(anatomical_im_grad_y_sptr, 1); + this->set_anatomical_grad_sptr(anatomical_im_grad_x_sptr, 2); - compute_normalisation_anatomical_gradient (*norm_sptr,*anatomical_im_grad_z_sptr,*anatomical_im_grad_y_sptr,*anatomical_im_grad_x_sptr ); + compute_normalisation_anatomical_gradient(*norm_sptr, *anatomical_im_grad_z_sptr, *anatomical_im_grad_y_sptr, + *anatomical_im_grad_x_sptr); - this->set_anatomical_grad_norm_sptr (shared_ptr >(norm_sptr)); + this->set_anatomical_grad_norm_sptr(shared_ptr>(norm_sptr)); -return Succeeded::yes; + return Succeeded::yes; } template bool -PLSPrior::post_processing() -{ - if (base_type::post_processing()==true) +PLSPrior::post_processing() { + if (base_type::post_processing() == true) return true; if (kappa_filename.size() != 0) this->set_kappa_filename(kappa_filename); if (anatomical_filename.size() != 0) - this->set_anatomical_filename(anatomical_filename); + this->set_anatomical_filename(anatomical_filename); return false; - } template -void PLSPrior::check(DiscretisedDensity<3,elemT> const& current_image_estimate) const -{ +void +PLSPrior::check(DiscretisedDensity<3, elemT> const& current_image_estimate) const { // Do base-class check base_type::check(current_image_estimate); @@ -132,557 +127,484 @@ void PLSPrior::check(DiscretisedDensity<3,elemT> const& current_image_est template void -PLSPrior::set_defaults() -{ +PLSPrior::set_defaults() { base_type::set_defaults(); this->only_2D = false; - this->alpha=1; - this->eta=1; + this->alpha = 1; + this->eta = 1; this->kappa_ptr.reset(); } template <> -const char * const -PLSPrior::registered_name = - "PLS"; +const char* const PLSPrior::registered_name = "PLS"; template -PLSPrior::PLSPrior() -{ +PLSPrior::PLSPrior() { set_defaults(); } - template -PLSPrior::PLSPrior(const bool only_2D_v, float penalisation_factor_v) - : only_2D(only_2D_v) -{ +PLSPrior::PLSPrior(const bool only_2D_v, float penalisation_factor_v) : only_2D(only_2D_v) { set_defaults(); this->penalisation_factor = penalisation_factor_v; } template -shared_ptr > -PLSPrior:: -get_anatomical_grad_sptr(int direction) const{ - - if(direction==2){ - return this->anatomical_grad_x_sptr;} - if(direction==1){ - return this->anatomical_grad_y_sptr; - } - if(direction==0){ - return this->anatomical_grad_z_sptr; - } - error(boost::format("PLSPrior::get_anatomical_grad_sptr called with out-of-range argument: %1%") % direction); - // will never get here, but this avoids a compiler warning - shared_ptr > dummy; - return dummy; +shared_ptr> +PLSPrior::get_anatomical_grad_sptr(int direction) const { + + if (direction == 2) { + return this->anatomical_grad_x_sptr; + } + if (direction == 1) { + return this->anatomical_grad_y_sptr; + } + if (direction == 0) { + return this->anatomical_grad_z_sptr; + } + error(boost::format("PLSPrior::get_anatomical_grad_sptr called with out-of-range argument: %1%") % direction); + // will never get here, but this avoids a compiler warning + shared_ptr> dummy; + return dummy; } template -shared_ptr > -PLSPrior:: -get_norm_sptr () const{ -return this->norm_sptr; +shared_ptr> +PLSPrior::get_norm_sptr() const { + return this->norm_sptr; } template -shared_ptr > -PLSPrior:: -get_anatomical_image_sptr() const{ -return this->anatomical_sptr; +shared_ptr> +PLSPrior::get_anatomical_image_sptr() const { + return this->anatomical_sptr; } template double -PLSPrior:: -get_eta() const{ -return this->eta; +PLSPrior::get_eta() const { + return this->eta; } template double -PLSPrior:: -get_alpha() const{ -return this->alpha; +PLSPrior::get_alpha() const { + return this->alpha; } template void -PLSPrior:: -set_anatomical_image_sptr (const shared_ptr >& arg) -{ - this->anatomical_sptr = arg; - this->anatomical_filename = ""; // Clear filename in case it was set. +PLSPrior::set_anatomical_image_sptr(const shared_ptr>& arg) { + this->anatomical_sptr = arg; + this->anatomical_filename = ""; // Clear filename in case it was set. } template void -PLSPrior:: -set_eta (const double arg) -{ this->eta = arg; } +PLSPrior::set_eta(const double arg) { + this->eta = arg; +} template void -PLSPrior:: -set_alpha (const double arg) -{ this->alpha = arg; } +PLSPrior::set_alpha(const double arg) { + this->alpha = arg; +} template void -PLSPrior::set_anatomical_grad_sptr(const shared_ptr >& arg, int direction){ +PLSPrior::set_anatomical_grad_sptr(const shared_ptr>& arg, int direction) { - if(direction==2){ - this->anatomical_grad_x_sptr=arg;} - if(direction==1){ - this->anatomical_grad_y_sptr=arg; - } - if(direction==0){ - this->anatomical_grad_z_sptr=arg; - } + if (direction == 2) { + this->anatomical_grad_x_sptr = arg; + } + if (direction == 1) { + this->anatomical_grad_y_sptr = arg; + } + if (direction == 0) { + this->anatomical_grad_z_sptr = arg; + } } template void -PLSPrior::set_anatomical_grad_norm_sptr (const shared_ptr >& arg){ - +PLSPrior::set_anatomical_grad_norm_sptr(const shared_ptr>& arg) { - this->norm_sptr=arg; + this->norm_sptr = arg; } - //! get current kappa image - /*! \warning As this function returns a shared_ptr, this is dangerous. You should not - modify the image by manipulating the image refered to by this pointer. - Unpredictable results will occur. - */ +//! get current kappa image +/*! \warning As this function returns a shared_ptr, this is dangerous. You should not + modify the image by manipulating the image refered to by this pointer. + Unpredictable results will occur. +*/ template -shared_ptr > -PLSPrior:: -get_kappa_sptr() const -{ return this->kappa_ptr; } +shared_ptr> +PLSPrior::get_kappa_sptr() const { + return this->kappa_ptr; +} //! set kappa image template void -PLSPrior:: -set_kappa_sptr(const shared_ptr >& k) -{ - this->kappa_ptr = k; - kappa_filename = ""; // Clear filename in case it was set. +PLSPrior::set_kappa_sptr(const shared_ptr>& k) { + this->kappa_ptr = k; + kappa_filename = ""; // Clear filename in case it was set. } //! Set kappa filename -template void PLSPrior::set_kappa_filename(const std::string& filename) -{ - kappa_filename = filename; - this->kappa_ptr = read_from_file >(kappa_filename); - info(boost::format("Reading kappa data '%1%'") % kappa_filename ); +template +void +PLSPrior::set_kappa_filename(const std::string& filename) { + kappa_filename = filename; + this->kappa_ptr = read_from_file>(kappa_filename); + info(boost::format("Reading kappa data '%1%'") % kappa_filename); } //! Set anatomical filename -template void PLSPrior::set_anatomical_filename(const std::string& filename) -{ - anatomical_filename = filename; - this->anatomical_sptr = read_from_file >(anatomical_filename); - info(boost::format("Reading anatomical data '%1%'") % anatomical_filename ); +template +void +PLSPrior::set_anatomical_filename(const std::string& filename) { + anatomical_filename = filename; + this->anatomical_sptr = read_from_file>(anatomical_filename); + info(boost::format("Reading anatomical data '%1%'") % anatomical_filename); } template -void PLSPrior::compute_image_gradient_element(DiscretisedDensity<3,elemT> & image_gradient_elem, int direction, const DiscretisedDensity<3,elemT> & image ){ -//std::cout<<"dentro ="<max_z) - continue; - image_gradient_elem[z][y][x]=image[z+1][y][x]- image[z][y][x]; - - } - if(direction==1){ - if(y+1>max_y) - continue; - image_gradient_elem[z][y][x]=image[z][y+1][x]- image[z][y][x]; -// std::cout<<"grady ="<max_x ) - continue; - image_gradient_elem[z][y][x]=image[z][y][x+1]- image[z][y][x]; - } - - } - } - } - +void +PLSPrior::compute_image_gradient_element(DiscretisedDensity<3, elemT>& image_gradient_elem, int direction, + const DiscretisedDensity<3, elemT>& image) { + // std::cout<<"dentro ="< max_z) + continue; + image_gradient_elem[z][y][x] = image[z + 1][y][x] - image[z][y][x]; + } + if (direction == 1) { + if (y + 1 > max_y) + continue; + image_gradient_elem[z][y][x] = image[z][y + 1][x] - image[z][y][x]; + // std::cout<<"grady ="< max_x) + continue; + image_gradient_elem[z][y][x] = image[z][y][x + 1] - image[z][y][x]; + } + } + } + } } template void -PLSPrior::compute_normalisation_anatomical_gradient(DiscretisedDensity<3,elemT> &norm_im_grad, - const DiscretisedDensity<3,elemT> &image_grad_z, - const DiscretisedDensity<3,elemT> &image_grad_y, - const DiscretisedDensity<3,elemT> &image_grad_x){ - - const int min_z = image_grad_x.get_min_index(); - const int max_z = image_grad_x.get_max_index(); - +PLSPrior::compute_normalisation_anatomical_gradient(DiscretisedDensity<3, elemT>& norm_im_grad, + const DiscretisedDensity<3, elemT>& image_grad_z, + const DiscretisedDensity<3, elemT>& image_grad_y, + const DiscretisedDensity<3, elemT>& image_grad_x) { - for (int z=min_z; z<=max_z; z++) - { + const int min_z = image_grad_x.get_min_index(); + const int max_z = image_grad_x.get_max_index(); - const int min_y = image_grad_x[z].get_min_index(); - const int max_y = image_grad_x[z].get_max_index(); + for (int z = min_z; z <= max_z; z++) { + const int min_y = image_grad_x[z].get_min_index(); + const int max_y = image_grad_x[z].get_max_index(); + for (int y = min_y; y <= max_y; y++) { - for (int y=min_y;y<= max_y;y++) - { + const int min_x = image_grad_x[z][y].get_min_index(); + const int max_x = image_grad_x[z][y].get_max_index(); - const int min_x = image_grad_x[z][y].get_min_index(); - const int max_x = image_grad_x[z][y].get_max_index(); - - - - for (int x=min_x;x<= max_x;x++) - { - if(only_2D){ - norm_im_grad[z][y][x] = sqrt (square(image_grad_y[z][y][x]) + square(image_grad_x[z][y][x]) + square(this->eta));} - else{ - norm_im_grad[z][y][x] = sqrt (square(image_grad_z[z][y][x]) + square(image_grad_y[z][y][x]) + - square(image_grad_x[z][y][x]) + square(this->eta)); - - } - } - - } - } + for (int x = min_x; x <= max_x; x++) { + if (only_2D) { + norm_im_grad[z][y][x] = sqrt(square(image_grad_y[z][y][x]) + square(image_grad_x[z][y][x]) + square(this->eta)); + } else { + norm_im_grad[z][y][x] = sqrt(square(image_grad_z[z][y][x]) + square(image_grad_y[z][y][x]) + + square(image_grad_x[z][y][x]) + square(this->eta)); + } + } + } + } } template void -PLSPrior:: -compute_inner_product_and_penalty(DiscretisedDensity<3,elemT> &inner_product, - DiscretisedDensity<3,elemT> &penalty, - DiscretisedDensity<3,elemT> &pet_im_grad_z, - DiscretisedDensity<3,elemT> &pet_im_grad_y, - DiscretisedDensity<3,elemT> &pet_im_grad_x, - const DiscretisedDensity<3,elemT> &pet_image){ - - - - if(!only_2D) - compute_image_gradient_element (pet_im_grad_z,0,pet_image); - - compute_image_gradient_element (pet_im_grad_y,1,pet_image); - compute_image_gradient_element (pet_im_grad_x,2,pet_image); - +PLSPrior::compute_inner_product_and_penalty(DiscretisedDensity<3, elemT>& inner_product, + DiscretisedDensity<3, elemT>& penalty, + DiscretisedDensity<3, elemT>& pet_im_grad_z, + DiscretisedDensity<3, elemT>& pet_im_grad_y, + DiscretisedDensity<3, elemT>& pet_im_grad_x, + const DiscretisedDensity<3, elemT>& pet_image) { - const int min_z = pet_image.get_min_index(); - const int max_z = pet_image.get_max_index(); + if (!only_2D) + compute_image_gradient_element(pet_im_grad_z, 0, pet_image); + compute_image_gradient_element(pet_im_grad_y, 1, pet_image); + compute_image_gradient_element(pet_im_grad_x, 2, pet_image); - for (int z=min_z; z<=max_z; z++) - { + const int min_z = pet_image.get_min_index(); + const int max_z = pet_image.get_max_index(); - const int min_y = pet_image[z].get_min_index(); - const int max_y = pet_image[z].get_max_index(); + for (int z = min_z; z <= max_z; z++) { + const int min_y = pet_image[z].get_min_index(); + const int max_y = pet_image[z].get_max_index(); + for (int y = min_y; y <= max_y; y++) { - for (int y=min_y;y<= max_y;y++) - { + const int min_x = pet_image[z][y].get_min_index(); + const int max_x = pet_image[z][y].get_max_index(); - const int min_x = pet_image[z][y].get_min_index(); - const int max_x = pet_image[z][y].get_max_index(); + for (int x = min_x; x <= max_x; x++) { + if (only_2D) { + inner_product[z][y][x] = ((pet_im_grad_y[z][y][x] * (*anatomical_grad_y_sptr)[z][y][x] / (*get_norm_sptr())[z][y][x]) + + (pet_im_grad_x[z][y][x] * (*anatomical_grad_x_sptr)[z][y][x] / (*get_norm_sptr())[z][y][x])); + penalty[z][y][x] = sqrt(square(this->alpha) + square(pet_im_grad_y[z][y][x]) + square(pet_im_grad_x[z][y][x]) - + square(inner_product[z][y][x])); + } else { + inner_product[z][y][x] = (pet_im_grad_z[z][y][x] * (*anatomical_grad_z_sptr)[z][y][x] + + pet_im_grad_y[z][y][x] * (*anatomical_grad_y_sptr)[z][y][x] + + pet_im_grad_x[z][y][x] * (*anatomical_grad_x_sptr)[z][y][x]) / + (*get_norm_sptr())[z][y][x]; - - for (int x=min_x;x<= max_x;x++) - { - if(only_2D){ - inner_product[z][y][x] = ((pet_im_grad_y[z][y][x]*(*anatomical_grad_y_sptr)[z][y][x]/(*get_norm_sptr())[z][y][x]) + - (pet_im_grad_x[z][y][x]*(*anatomical_grad_x_sptr)[z][y][x]/(*get_norm_sptr())[z][y][x])); - - penalty[z][y][x]= sqrt (square(this->alpha) + square(pet_im_grad_y[z][y][x]) + - square(pet_im_grad_x[z][y][x]) - - square(inner_product[z][y][x])); - } - else{ - inner_product[z][y][x] = (pet_im_grad_z[z][y][x]*(*anatomical_grad_z_sptr)[z][y][x] + - pet_im_grad_y[z][y][x]*(*anatomical_grad_y_sptr)[z][y][x] + - pet_im_grad_x[z][y][x]*(*anatomical_grad_x_sptr)[z][y][x])/(*get_norm_sptr())[z][y][x]; - - penalty[z][y][x]= sqrt (square(this->alpha) + square(pet_im_grad_z[z][y][x]) + - square(pet_im_grad_y[z][y][x]) + - square(pet_im_grad_x[z][y][x]) - - square(inner_product[z][y][x])); - } - } - } - } - + penalty[z][y][x] = sqrt(square(this->alpha) + square(pet_im_grad_z[z][y][x]) + square(pet_im_grad_y[z][y][x]) + + square(pet_im_grad_x[z][y][x]) - square(inner_product[z][y][x])); + } + } + } + } } template double -PLSPrior:: -compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ - if (this->penalisation_factor==0) - { +PLSPrior::compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) { + if (this->penalisation_factor == 0) { return 0.; } this->check(current_image_estimate); - shared_ptr > pet_im_grad_z_sptr; - if(!only_2D) - pet_im_grad_z_sptr.reset(this->anatomical_sptr->get_empty_copy ()); + shared_ptr> pet_im_grad_z_sptr; + if (!only_2D) + pet_im_grad_z_sptr.reset(this->anatomical_sptr->get_empty_copy()); - shared_ptr > pet_im_grad_y_sptr(this->anatomical_sptr->get_empty_copy ()); - shared_ptr > pet_im_grad_x_sptr(this->anatomical_sptr->get_empty_copy ()); + shared_ptr> pet_im_grad_y_sptr(this->anatomical_sptr->get_empty_copy()); + shared_ptr> pet_im_grad_x_sptr(this->anatomical_sptr->get_empty_copy()); - shared_ptr > inner_product_sptr(this->anatomical_sptr.get ()->get_empty_copy ()); - shared_ptr > penalty_sptr(this->anatomical_sptr.get ()->get_empty_copy ()); + shared_ptr> inner_product_sptr(this->anatomical_sptr.get()->get_empty_copy()); + shared_ptr> penalty_sptr(this->anatomical_sptr.get()->get_empty_copy()); - compute_inner_product_and_penalty (*inner_product_sptr, - *penalty_sptr, - *pet_im_grad_z_sptr, - *pet_im_grad_y_sptr, - *pet_im_grad_x_sptr, - current_image_estimate); + compute_inner_product_and_penalty(*inner_product_sptr, *penalty_sptr, *pet_im_grad_z_sptr, *pet_im_grad_y_sptr, + *pet_im_grad_x_sptr, current_image_estimate); const bool do_kappa = !is_null_ptr(kappa_ptr); if (do_kappa && !kappa_ptr->has_same_characteristics(current_image_estimate)) error("PLSPrior: kappa image has not the same index range as the reconstructed image\n"); - double result = 0.; const int min_z = current_image_estimate.get_min_index(); const int max_z = current_image_estimate.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - - const int min_y = current_image_estimate[z].get_min_index(); - const int max_y = current_image_estimate[z].get_max_index(); + for (int z = min_z; z <= max_z; z++) { - for (int y=min_y;y<= max_y;y++) - { + const int min_y = current_image_estimate[z].get_min_index(); + const int max_y = current_image_estimate[z].get_max_index(); - const int min_x = current_image_estimate[z][y].get_min_index(); - const int max_x = current_image_estimate[z][y].get_max_index(); + for (int y = min_y; y <= max_y; y++) { - for (int x=min_x;x<= max_x;x++) - { + const int min_x = current_image_estimate[z][y].get_min_index(); + const int max_x = current_image_estimate[z][y].get_max_index(); - /* formula: - sum_x,y,z + for (int x = min_x; x <= max_x; x++) { - (penalty[z][y][x]) * (*kappa_ptr)[z][y][x]; - */ + /* formula: + sum_x,y,z - elemT current = (*penalty_sptr)[z][y][x]; + (penalty[z][y][x]) * (*kappa_ptr)[z][y][x]; + */ - if (do_kappa) - current *= - (*kappa_ptr)[z][y][x] ; + elemT current = (*penalty_sptr)[z][y][x]; - result += static_cast(current); + if (do_kappa) + current *= (*kappa_ptr)[z][y][x]; - } - } + result += static_cast(current); + } } + } return result * this->penalisation_factor; } template void -PLSPrior:: -compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ +PLSPrior::compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, + const DiscretisedDensity<3, elemT>& current_image_estimate) { this->check(current_image_estimate); - if (this->penalisation_factor==0) - { + if (this->penalisation_factor == 0) { prior_gradient.fill(0); return; } - shared_ptr > pet_im_grad_z_sptr; - shared_ptr > gradientz_sptr; + shared_ptr> pet_im_grad_z_sptr; + shared_ptr> gradientz_sptr; - if(!only_2D){ - pet_im_grad_z_sptr.reset(this->anatomical_sptr->get_empty_copy ()); - gradientz_sptr.reset(this->anatomical_sptr->get_empty_copy ()); + if (!only_2D) { + pet_im_grad_z_sptr.reset(this->anatomical_sptr->get_empty_copy()); + gradientz_sptr.reset(this->anatomical_sptr->get_empty_copy()); } - shared_ptr > pet_im_grad_y_sptr(this->anatomical_sptr->get_empty_copy ()); - shared_ptr > pet_im_grad_x_sptr(this->anatomical_sptr->get_empty_copy ()); + shared_ptr> pet_im_grad_y_sptr(this->anatomical_sptr->get_empty_copy()); + shared_ptr> pet_im_grad_x_sptr(this->anatomical_sptr->get_empty_copy()); - shared_ptr > inner_product_sptr(this->anatomical_sptr->get_empty_copy ()); - shared_ptr > penalty_sptr(this->anatomical_sptr->get_empty_copy ()); + shared_ptr> inner_product_sptr(this->anatomical_sptr->get_empty_copy()); + shared_ptr> penalty_sptr(this->anatomical_sptr->get_empty_copy()); - shared_ptr > gradienty_sptr(this->anatomical_sptr->get_empty_copy ()); - shared_ptr > gradientx_sptr(this->anatomical_sptr->get_empty_copy ()); - - compute_inner_product_and_penalty (*inner_product_sptr, - *penalty_sptr, - *pet_im_grad_z_sptr, - *pet_im_grad_y_sptr, - *pet_im_grad_x_sptr, - current_image_estimate); + shared_ptr> gradienty_sptr(this->anatomical_sptr->get_empty_copy()); + shared_ptr> gradientx_sptr(this->anatomical_sptr->get_empty_copy()); + compute_inner_product_and_penalty(*inner_product_sptr, *penalty_sptr, *pet_im_grad_z_sptr, *pet_im_grad_y_sptr, + *pet_im_grad_x_sptr, current_image_estimate); const bool do_kappa = !is_null_ptr(kappa_ptr); if (do_kappa && !kappa_ptr->has_same_characteristics(current_image_estimate)) error("PLSPrior: kappa image has not the same index range as the reconstructed image\n"); - shared_ptr > gradient_sptr(this->anatomical_sptr->get_empty_copy ()); + shared_ptr> gradient_sptr(this->anatomical_sptr->get_empty_copy()); const int min_z = current_image_estimate.get_min_index(); const int max_z = current_image_estimate.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - - const int min_y = current_image_estimate[z].get_min_index(); - const int max_y = current_image_estimate[z].get_max_index(); - - for (int y=min_y;y<= max_y;y++) - { - - - const int min_x = current_image_estimate[z][y].get_min_index(); - const int max_x = current_image_estimate[z][y].get_max_index(); - - for (int x=min_x;x<= max_x;x++) - { - - if(x+1>max_x || y+1>max_y ||(z+1>max_z && !only_2D)) - continue; - - /* formula: - sum_x,y,z - div * (pet_im_grad[z][y][x]-inner_product[z][y][x]*anatomical_im_grad[z][y][x]/(*get_norm_sptr ())[z][y][x])* - (*kappa_ptr)[z][y][x] /penalty[z][y][x]; - */ - - if(only_2D){ - (*gradientx_sptr)[z][y][x+1] = - (((*pet_im_grad_x_sptr)[z][y][x+1]-(*anatomical_grad_x_sptr)[z][y][x+1]*(*inner_product_sptr)[z][y][x+1]/ - (*get_norm_sptr ())[z][y][x+1])/(*penalty_sptr)[z][y][x+1] - - (((*pet_im_grad_x_sptr)[z][y][x]-(*anatomical_grad_x_sptr)[z][y][x]*(*inner_product_sptr)[z][y][x]/(*get_norm_sptr ())[z][y][x])/ - (*penalty_sptr)[z][y][x]) ); - - (*gradienty_sptr)[z][y+1][x] = - (((*pet_im_grad_y_sptr)[z][y+1][x]-(*anatomical_grad_y_sptr)[z][y+1][x]*(*inner_product_sptr)[z][y+1][x]/ - (*get_norm_sptr ())[z][y+1][x])/(*penalty_sptr)[z][y+1][x] - - (((*pet_im_grad_y_sptr)[z][y][x]-(*anatomical_grad_y_sptr)[z][y][x]*(*inner_product_sptr)[z][y][x]/(*get_norm_sptr ())[z][y][x])/ - (*penalty_sptr)[z][y][x]) ); - } - else{ - - (*gradientx_sptr)[z][y][x+1] = - (((*pet_im_grad_x_sptr)[z][y][x+1]-(*anatomical_grad_x_sptr)[z][y][x+1]*(*inner_product_sptr)[z][y][x+1]/(*get_norm_sptr ())[z][y][x+1])/ - (*penalty_sptr)[z][y][x+1] - - ((*pet_im_grad_x_sptr)[z][y][x]-(*anatomical_grad_x_sptr)[z][y][x]*(*inner_product_sptr)[z][y][x]/(*get_norm_sptr ())[z][y][x])/ - (*penalty_sptr)[z][y][x]); - - (*gradienty_sptr)[z][y+1][x] = - (((*pet_im_grad_y_sptr)[z][y+1][x]-(*anatomical_grad_y_sptr)[z][y+1][x]*(*inner_product_sptr)[z][y+1][x]/ - (*get_norm_sptr ())[z][y+1][x])/(*penalty_sptr)[z][y+1][x] - - (((*pet_im_grad_y_sptr)[z][y][x]-(*anatomical_grad_y_sptr)[z][y][x]*(*inner_product_sptr)[z][y][x]/ - (*get_norm_sptr ())[z][y][x])/(*penalty_sptr)[z][y][x]) ); - - (*gradientz_sptr)[z+1][y][x] = - (((*pet_im_grad_z_sptr)[z+1][y][x]-(*anatomical_grad_z_sptr)[z+1][y][x]*(*inner_product_sptr)[z+1][y][x]/ - (*get_norm_sptr ())[z+1][y][x])/(*penalty_sptr)[z+1][y][x] - - (((*pet_im_grad_z_sptr)[z][y][x]-(*anatomical_grad_z_sptr)[z][y][x]*(*inner_product_sptr)[z][y][x]/ - (*get_norm_sptr ())[z][y][x])/(*penalty_sptr)[z][y][x]) ); - } - }}} - - for (int z=min_z; z<=max_z; z++) - { - - const int min_y = current_image_estimate[z].get_min_index(); - const int max_y = current_image_estimate[z].get_max_index(); - - for (int y=min_y;y<= max_y;y++) - { - + for (int z = min_z; z <= max_z; z++) { + + const int min_y = current_image_estimate[z].get_min_index(); + const int max_y = current_image_estimate[z].get_max_index(); + + for (int y = min_y; y <= max_y; y++) { + + const int min_x = current_image_estimate[z][y].get_min_index(); + const int max_x = current_image_estimate[z][y].get_max_index(); + + for (int x = min_x; x <= max_x; x++) { + + if (x + 1 > max_x || y + 1 > max_y || (z + 1 > max_z && !only_2D)) + continue; + + /* formula: + sum_x,y,z + div * (pet_im_grad[z][y][x]-inner_product[z][y][x]*anatomical_im_grad[z][y][x]/(*get_norm_sptr ())[z][y][x])* + (*kappa_ptr)[z][y][x] /penalty[z][y][x]; + */ + + if (only_2D) { + (*gradientx_sptr)[z][y][x + 1] = + (((*pet_im_grad_x_sptr)[z][y][x + 1] - + (*anatomical_grad_x_sptr)[z][y][x + 1] * (*inner_product_sptr)[z][y][x + 1] / (*get_norm_sptr())[z][y][x + 1]) / + (*penalty_sptr)[z][y][x + 1] - + (((*pet_im_grad_x_sptr)[z][y][x] - + (*anatomical_grad_x_sptr)[z][y][x] * (*inner_product_sptr)[z][y][x] / (*get_norm_sptr())[z][y][x]) / + (*penalty_sptr)[z][y][x])); + + (*gradienty_sptr)[z][y + 1][x] = + (((*pet_im_grad_y_sptr)[z][y + 1][x] - + (*anatomical_grad_y_sptr)[z][y + 1][x] * (*inner_product_sptr)[z][y + 1][x] / (*get_norm_sptr())[z][y + 1][x]) / + (*penalty_sptr)[z][y + 1][x] - + (((*pet_im_grad_y_sptr)[z][y][x] - + (*anatomical_grad_y_sptr)[z][y][x] * (*inner_product_sptr)[z][y][x] / (*get_norm_sptr())[z][y][x]) / + (*penalty_sptr)[z][y][x])); + } else { + + (*gradientx_sptr)[z][y][x + 1] = + (((*pet_im_grad_x_sptr)[z][y][x + 1] - + (*anatomical_grad_x_sptr)[z][y][x + 1] * (*inner_product_sptr)[z][y][x + 1] / (*get_norm_sptr())[z][y][x + 1]) / + (*penalty_sptr)[z][y][x + 1] - + ((*pet_im_grad_x_sptr)[z][y][x] - + (*anatomical_grad_x_sptr)[z][y][x] * (*inner_product_sptr)[z][y][x] / (*get_norm_sptr())[z][y][x]) / + (*penalty_sptr)[z][y][x]); + + (*gradienty_sptr)[z][y + 1][x] = + (((*pet_im_grad_y_sptr)[z][y + 1][x] - + (*anatomical_grad_y_sptr)[z][y + 1][x] * (*inner_product_sptr)[z][y + 1][x] / (*get_norm_sptr())[z][y + 1][x]) / + (*penalty_sptr)[z][y + 1][x] - + (((*pet_im_grad_y_sptr)[z][y][x] - + (*anatomical_grad_y_sptr)[z][y][x] * (*inner_product_sptr)[z][y][x] / (*get_norm_sptr())[z][y][x]) / + (*penalty_sptr)[z][y][x])); + + (*gradientz_sptr)[z + 1][y][x] = + (((*pet_im_grad_z_sptr)[z + 1][y][x] - + (*anatomical_grad_z_sptr)[z + 1][y][x] * (*inner_product_sptr)[z + 1][y][x] / (*get_norm_sptr())[z + 1][y][x]) / + (*penalty_sptr)[z + 1][y][x] - + (((*pet_im_grad_z_sptr)[z][y][x] - + (*anatomical_grad_z_sptr)[z][y][x] * (*inner_product_sptr)[z][y][x] / (*get_norm_sptr())[z][y][x]) / + (*penalty_sptr)[z][y][x])); + } + } + } + } - const int min_x = current_image_estimate[z][y].get_min_index(); - const int max_x = current_image_estimate[z][y].get_max_index(); + for (int z = min_z; z <= max_z; z++) { - for (int x=min_x;x<= max_x;x++) - { - if(only_2D){ + const int min_y = current_image_estimate[z].get_min_index(); + const int max_y = current_image_estimate[z].get_max_index(); - (*gradient_sptr)[z][y][x] = -((*gradienty_sptr)[z][y][x] + (*gradientx_sptr)[z][y][x]); + for (int y = min_y; y <= max_y; y++) { - } - else{ + const int min_x = current_image_estimate[z][y].get_min_index(); + const int max_x = current_image_estimate[z][y].get_max_index(); - (*gradient_sptr)[z][y][x] = -((*gradientz_sptr)[z][y][x] + (*gradienty_sptr)[z][y][x] + (*gradientx_sptr)[z][y][x]); + for (int x = min_x; x <= max_x; x++) { + if (only_2D) { - } + (*gradient_sptr)[z][y][x] = -((*gradienty_sptr)[z][y][x] + (*gradientx_sptr)[z][y][x]); - if (do_kappa) - (*gradient_sptr)[z][y][x] *= - (*kappa_ptr)[z][y][x] ; + } else { + (*gradient_sptr)[z][y][x] = -((*gradientz_sptr)[z][y][x] + (*gradienty_sptr)[z][y][x] + (*gradientx_sptr)[z][y][x]); + } + if (do_kappa) + (*gradient_sptr)[z][y][x] *= (*kappa_ptr)[z][y][x]; - prior_gradient[z][y][x]= (*gradient_sptr)[z][y][x] * this->penalisation_factor; - }}} + prior_gradient[z][y][x] = (*gradient_sptr)[z][y][x] * this->penalisation_factor; + } + } + } info(boost::format("Prior gradient max %1%, min %2%\n") % prior_gradient.find_max() % prior_gradient.find_min()); static int count = 0; ++count; - if (gradient_filename_prefix.size()>0) - { - char *filename = new char[gradient_filename_prefix.size()+100]; - sprintf(filename, "%s%d.v", gradient_filename_prefix.c_str(), count); - write_to_file(filename, prior_gradient); - delete[] filename; - } + if (gradient_filename_prefix.size() > 0) { + char* filename = new char[gradient_filename_prefix.size() + 100]; + sprintf(filename, "%s%d.v", gradient_filename_prefix.c_str(), count); + write_to_file(filename, prior_gradient); + delete[] filename; + } } - -# ifdef _MSC_VER +#ifdef _MSC_VER // prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif - +# pragma warning(disable : 4660) +#endif template class PLSPrior; END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.cxx b/src/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.cxx index 13c816e6a9..9a3fe280f8 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.cxx @@ -30,12 +30,11 @@ START_NAMESPACE_STIR +#ifdef _MSC_VER +// prevent warning message on instantiation of abstract class +# pragma warning(disable : 4661) +#endif // _MSC_VER -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif // _MSC_VER - -template class PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData; +template class PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData; END_NAMESPACE_STIR diff --git a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.cxx b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.cxx index 22b6c184f4..3b74ca9184 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.cxx @@ -42,472 +42,349 @@ using std::string; START_NAMESPACE_STIR -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -set_defaults() -{ +PoissonLogLikelihoodWithLinearModelForMean::set_defaults() { base_type::set_defaults(); - this->sensitivity_filename = ""; - this->subsensitivity_filenames = ""; + this->sensitivity_filename = ""; + this->subsensitivity_filenames = ""; this->recompute_sensitivity = false; this->use_subset_sensitivities = true; this->subsensitivity_sptrs.resize(0); } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -initialise_keymap() -{ +PoissonLogLikelihoodWithLinearModelForMean::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_key("sensitivity filename", &this->sensitivity_filename); this->parser.add_key("subset sensitivity filenames", &this->subsensitivity_filenames); this->parser.add_key("recompute sensitivity", &this->recompute_sensitivity); this->parser.add_key("use_subset_sensitivities", &this->use_subset_sensitivities); - } -template +template bool -PoissonLogLikelihoodWithLinearModelForMean:: -post_processing() -{ +PoissonLogLikelihoodWithLinearModelForMean::post_processing() { if (base_type::post_processing() == true) return true; return false; } -template +template std::string -PoissonLogLikelihoodWithLinearModelForMean:: -get_sensitivity_filename() const -{ +PoissonLogLikelihoodWithLinearModelForMean::get_sensitivity_filename() const { return this->sensitivity_filename; } -template +template std::string -PoissonLogLikelihoodWithLinearModelForMean:: -get_subsensitivity_filenames() const -{ +PoissonLogLikelihoodWithLinearModelForMean::get_subsensitivity_filenames() const { return this->subsensitivity_filenames; } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -set_sensitivity_filename(const std::string& filename) -{ +PoissonLogLikelihoodWithLinearModelForMean::set_sensitivity_filename(const std::string& filename) { this->sensitivity_filename = filename; } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -set_subsensitivity_filenames(const std::string& filenames) -{ +PoissonLogLikelihoodWithLinearModelForMean::set_subsensitivity_filenames(const std::string& filenames) { this->subsensitivity_filenames = filenames; - try - { - const std::string test_sensitivity_filename = - boost::str(boost::format(this->subsensitivity_filenames) % 0); - } - catch (std::exception& e) - { - error("argument %s to set_subsensitivity_filenames is invalid (see boost::format documentation)\n. Error message: %s", filenames.c_str(), e.what()); - } - + try { + const std::string test_sensitivity_filename = boost::str(boost::format(this->subsensitivity_filenames) % 0); + } catch (std::exception& e) { + error("argument %s to set_subsensitivity_filenames is invalid (see boost::format documentation)\n. Error message: %s", + filenames.c_str(), e.what()); + } } - -template -shared_ptr -PoissonLogLikelihoodWithLinearModelForMean:: -get_subset_sensitivity_sptr(const int subset_num) const -{ +template +shared_ptr +PoissonLogLikelihoodWithLinearModelForMean::get_subset_sensitivity_sptr(const int subset_num) const { return this->subsensitivity_sptrs[subset_num]; } -template +template const TargetT& -PoissonLogLikelihoodWithLinearModelForMean:: -get_subset_sensitivity(const int subset_num) const -{ +PoissonLogLikelihoodWithLinearModelForMean::get_subset_sensitivity(const int subset_num) const { return *get_subset_sensitivity_sptr(subset_num); } -template +template const TargetT& -PoissonLogLikelihoodWithLinearModelForMean:: -get_sensitivity() const -{ +PoissonLogLikelihoodWithLinearModelForMean::get_sensitivity() const { return *this->sensitivity_sptr; } -template +template bool -PoissonLogLikelihoodWithLinearModelForMean:: -get_recompute_sensitivity() const -{ +PoissonLogLikelihoodWithLinearModelForMean::get_recompute_sensitivity() const { return this->recompute_sensitivity; } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -set_recompute_sensitivity(const bool arg) -{ +PoissonLogLikelihoodWithLinearModelForMean::set_recompute_sensitivity(const bool arg) { this->recompute_sensitivity = arg; - } -template +template bool -PoissonLogLikelihoodWithLinearModelForMean:: -get_use_subset_sensitivities() const -{ +PoissonLogLikelihoodWithLinearModelForMean::get_use_subset_sensitivities() const { return this->use_subset_sensitivities; } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -set_use_subset_sensitivities(const bool arg) -{ +PoissonLogLikelihoodWithLinearModelForMean::set_use_subset_sensitivities(const bool arg) { this->use_subset_sensitivities = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -set_subset_sensitivity_sptr(const shared_ptr& arg, const int subset_num) -{ +PoissonLogLikelihoodWithLinearModelForMean::set_subset_sensitivity_sptr(const shared_ptr& arg, + const int subset_num) { this->subsensitivity_sptrs[subset_num] = arg; } -template -Succeeded -PoissonLogLikelihoodWithLinearModelForMean:: -set_up(shared_ptr const& target_sptr) -{ +template +Succeeded +PoissonLogLikelihoodWithLinearModelForMean::set_up(shared_ptr const& target_sptr) { if (base_type::set_up(target_sptr) != Succeeded::yes) return Succeeded::no; this->subsensitivity_sptrs.resize(this->num_subsets); - if(!this->recompute_sensitivity) - { - if(is_null_ptr(this->subsensitivity_sptrs[0]) && - ((this->get_use_subset_sensitivities() && this->subsensitivity_filenames=="") || - (!this->get_use_subset_sensitivities() && this->sensitivity_filename==""))) - { - info("(subset)sensitivity filename(s) not set so I will compute the (subset)sensitivities", 2); - this->recompute_sensitivity = true; - // initialisation of pointers will be done below - } - else if(this->sensitivity_filename=="1") - { - if (this->get_use_subset_sensitivities()) - { - error("PoissonLogLikelihoodWithLinearModelForMean limitation:\n" - "currently cannot use subset_sensitivities if sensitivity is forced to 1"); + if (!this->recompute_sensitivity) { + if (is_null_ptr(this->subsensitivity_sptrs[0]) && + ((this->get_use_subset_sensitivities() && this->subsensitivity_filenames == "") || + (!this->get_use_subset_sensitivities() && this->sensitivity_filename == ""))) { + info("(subset)sensitivity filename(s) not set so I will compute the (subset)sensitivities", 2); + this->recompute_sensitivity = true; + // initialisation of pointers will be done below + } else if (this->sensitivity_filename == "1") { + if (this->get_use_subset_sensitivities()) { + error("PoissonLogLikelihoodWithLinearModelForMean limitation:\n" + "currently cannot use subset_sensitivities if sensitivity is forced to 1"); + return Succeeded::no; + } + this->sensitivity_sptr.reset(target_sptr->get_empty_copy()); + std::fill(this->sensitivity_sptr->begin_all(), this->sensitivity_sptr->end_all(), 1); + } else { + // read from file + try { + if (this->get_use_subset_sensitivities()) { + if (this->subsensitivity_filenames.empty()) { + error("'subset sensitivity filenames' is empty. You need to set this before using it."); + return Succeeded::no; + } + // read subsensitivies + for (int subset = 0; subset < this->get_num_subsets(); ++subset) { + std::string current_sensitivity_filename; + try { + current_sensitivity_filename = boost::str(boost::format(this->subsensitivity_filenames) % subset); + } catch (std::exception& e) { + error(boost::format("Error using 'subset sensitivity filenames' pattern (which is set to '%1%'). " + "Check syntax for boost::format. Error is:\n%2%") % + this->subsensitivity_filenames % e.what()); return Succeeded::no; } - this->sensitivity_sptr.reset(target_sptr->get_empty_copy()); - std::fill(this->sensitivity_sptr->begin_all(), this->sensitivity_sptr->end_all(), 1); - } - else - { - // read from file - try - { - if (this->get_use_subset_sensitivities()) - { - if (this->subsensitivity_filenames.empty()) - { - error("'subset sensitivity filenames' is empty. You need to set this before using it."); - return Succeeded::no; - } - // read subsensitivies - for (int subset=0; subsetget_num_subsets(); ++subset) - { - std::string current_sensitivity_filename; - try - { - current_sensitivity_filename = - boost::str(boost::format(this->subsensitivity_filenames) % subset); - } - catch (std::exception& e) - { - error(boost::format("Error using 'subset sensitivity filenames' pattern (which is set to '%1%'). " - "Check syntax for boost::format. Error is:\n%2%") % - this->subsensitivity_filenames % e.what()); - return Succeeded::no; - } - info(boost::format("Reading sensitivity from '%1%'") % current_sensitivity_filename); - - this->subsensitivity_sptrs[subset] = - read_from_file(current_sensitivity_filename); - string explanation; - if (!target_sptr->has_same_characteristics(*this->subsensitivity_sptrs[subset], - explanation)) - { - error("sensitivity and target should have the same characteristics.\n%s", - explanation.c_str()); - return Succeeded::no; - } - } - } - else - { - if (this->sensitivity_filename.empty()) - { - error("'sensitivity filename' is empty. You need to set this before using it."); - return Succeeded::no; - } - // reading single sensitivity - const std::string current_sensitivity_filename = - this->sensitivity_filename; - info(boost::format("Reading sensitivity from '%1%'") % current_sensitivity_filename); - - this->sensitivity_sptr = read_from_file(current_sensitivity_filename); - string explanation; - if (!target_sptr->has_same_characteristics(*this->sensitivity_sptr, - explanation)) - { - error("sensitivity and target should have the same characteristics.\n%s", - explanation.c_str()); - return Succeeded::no; - } - } - } - catch (std::exception& e) - { - error("Error reading sensitivity from file:\n%s", e.what()); + info(boost::format("Reading sensitivity from '%1%'") % current_sensitivity_filename); + + this->subsensitivity_sptrs[subset] = read_from_file(current_sensitivity_filename); + string explanation; + if (!target_sptr->has_same_characteristics(*this->subsensitivity_sptrs[subset], explanation)) { + error("sensitivity and target should have the same characteristics.\n%s", explanation.c_str()); return Succeeded::no; } - // compute total from subsensitivity or vice versa - this->set_total_or_subset_sensitivities(); + } + } else { + if (this->sensitivity_filename.empty()) { + error("'sensitivity filename' is empty. You need to set this before using it."); + return Succeeded::no; + } + // reading single sensitivity + const std::string current_sensitivity_filename = this->sensitivity_filename; + info(boost::format("Reading sensitivity from '%1%'") % current_sensitivity_filename); + + this->sensitivity_sptr = read_from_file(current_sensitivity_filename); + string explanation; + if (!target_sptr->has_same_characteristics(*this->sensitivity_sptr, explanation)) { + error("sensitivity and target should have the same characteristics.\n%s", explanation.c_str()); + return Succeeded::no; + } } - } // end of !recompute_sensitivity case - - if (this->set_up_before_sensitivity(target_sptr) == Succeeded::no) - { - return Succeeded::no; + } catch (std::exception& e) { + error("Error reading sensitivity from file:\n%s", e.what()); + return Succeeded::no; + } + // compute total from subsensitivity or vice versa + this->set_total_or_subset_sensitivities(); } + } // end of !recompute_sensitivity case - if(!this->subsets_are_approximately_balanced() && !this->get_use_subset_sensitivities()) - { - error("Number of subsets %d is such that subsets will be very unbalanced.\n" - "You need to set 'use_subset_sensitivities' to true to handle this.", - this->num_subsets); - return Succeeded::no; - } + if (this->set_up_before_sensitivity(target_sptr) == Succeeded::no) { + return Succeeded::no; + } - if(this->recompute_sensitivity) - { - info("Computing sensitivity"); - CPUTimer sens_timer; - sens_timer.start(); - // preallocate one such that compute_sensitivities knows the size - this->subsensitivity_sptrs[0].reset(target_sptr->get_empty_copy()); - this->compute_sensitivities(); - sens_timer.stop(); - info("Done computing sensitivity"); - info("This took " + boost::lexical_cast(sens_timer.value()) + " seconds CPU time."); - - // write to file - try - { - if (this->get_use_subset_sensitivities()) - { - if (this->subsensitivity_filenames.size()!=0) - { - for (int subset=0; subsetget_num_subsets(); ++subset) - { - const std::string current_sensitivity_filename = - boost::str(boost::format(this->subsensitivity_filenames) % subset); - info(boost::format("Writing sensitivity to '%1%'") % current_sensitivity_filename); - write_to_file(current_sensitivity_filename, - this->get_subset_sensitivity(subset)); - } - } - } - else - { - if (this->sensitivity_filename.size()!=0) - { - const std::string current_sensitivity_filename = - this->sensitivity_filename; - info(boost::format("Writing sensitivity to '%1%'") % current_sensitivity_filename); - write_to_file(current_sensitivity_filename, - this->get_sensitivity()); - } - } + if (!this->subsets_are_approximately_balanced() && !this->get_use_subset_sensitivities()) { + error("Number of subsets %d is such that subsets will be very unbalanced.\n" + "You need to set 'use_subset_sensitivities' to true to handle this.", + this->num_subsets); + return Succeeded::no; + } + + if (this->recompute_sensitivity) { + info("Computing sensitivity"); + CPUTimer sens_timer; + sens_timer.start(); + // preallocate one such that compute_sensitivities knows the size + this->subsensitivity_sptrs[0].reset(target_sptr->get_empty_copy()); + this->compute_sensitivities(); + sens_timer.stop(); + info("Done computing sensitivity"); + info("This took " + boost::lexical_cast(sens_timer.value()) + " seconds CPU time."); + + // write to file + try { + if (this->get_use_subset_sensitivities()) { + if (this->subsensitivity_filenames.size() != 0) { + for (int subset = 0; subset < this->get_num_subsets(); ++subset) { + const std::string current_sensitivity_filename = boost::str(boost::format(this->subsensitivity_filenames) % subset); + info(boost::format("Writing sensitivity to '%1%'") % current_sensitivity_filename); + write_to_file(current_sensitivity_filename, this->get_subset_sensitivity(subset)); + } } - catch (std::exception& e) - { - error("Error writing sensitivity to file:\n%s", e.what()); - return Succeeded::no; + } else { + if (this->sensitivity_filename.size() != 0) { + const std::string current_sensitivity_filename = this->sensitivity_filename; + info(boost::format("Writing sensitivity to '%1%'") % current_sensitivity_filename); + write_to_file(current_sensitivity_filename, this->get_sensitivity()); } + } + } catch (std::exception& e) { + error("Error writing sensitivity to file:\n%s", e.what()); + return Succeeded::no; } - + } + return Succeeded::yes; } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -compute_sub_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) -{ - if (subset_num<0 || subset_num>=this->get_num_subsets()) +PoissonLogLikelihoodWithLinearModelForMean::compute_sub_gradient_without_penalty(TargetT& gradient, + const TargetT& current_estimate, + const int subset_num) { + if (subset_num < 0 || subset_num >= this->get_num_subsets()) error("compute_sub_gradient_without_penalty subset_num out-of-range error"); - this-> - compute_sub_gradient_without_penalty_plus_sensitivity(gradient, - current_estimate, - subset_num); + this->compute_sub_gradient_without_penalty_plus_sensitivity(gradient, current_estimate, subset_num); // compute gradient -= sub_sensitivity { - typename TargetT::full_iterator gradient_iter = - gradient.begin_all(); - const typename TargetT::full_iterator gradient_end = - gradient.end_all(); - typename TargetT::const_full_iterator sensitivity_iter = - this->get_subset_sensitivity(subset_num).begin_all_const(); - while (gradient_iter != gradient_end) - { - *gradient_iter -= (*sensitivity_iter); - ++gradient_iter; ++sensitivity_iter; - } + typename TargetT::full_iterator gradient_iter = gradient.begin_all(); + const typename TargetT::full_iterator gradient_end = gradient.end_all(); + typename TargetT::const_full_iterator sensitivity_iter = this->get_subset_sensitivity(subset_num).begin_all_const(); + while (gradient_iter != gradient_end) { + *gradient_iter -= (*sensitivity_iter); + ++gradient_iter; + ++sensitivity_iter; + } } } - -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -compute_sensitivities() -{ +PoissonLogLikelihoodWithLinearModelForMean::compute_sensitivities() { // check subset balancing - if (this->use_subset_sensitivities == false) - { + if (this->use_subset_sensitivities == false) { std::string warning_message = "PoissonLogLikelihoodWithLinearModelForMean:\n"; - if (!this->subsets_are_approximately_balanced(warning_message)) - { - error("%s\n . you need to set use_subset_sensitivities to true", - warning_message.c_str()); - } + if (!this->subsets_are_approximately_balanced(warning_message)) { + error("%s\n . you need to set use_subset_sensitivities to true", warning_message.c_str()); + } } // end check balancing // compute subset sensitivities - for (int subset_num=0; subset_numnum_subsets; ++subset_num) - { - if (subset_num == 0) - { - std::fill(this->subsensitivity_sptrs[subset_num]->begin_all(), - this->subsensitivity_sptrs[subset_num]->end_all(), - 0); - } - else - { - if (this->get_use_subset_sensitivities()) - { - this->subsensitivity_sptrs[subset_num].reset(this->subsensitivity_sptrs[0]->get_empty_copy()); - } - else - { - // copy subsensitivity[0] pointer to current subset. - // do this as pointer such that we don't use more memory. - // This also means that we just accumulate in subsensitivity[0] for the moment. - // we will correct that below. - this->subsensitivity_sptrs[subset_num] = this->subsensitivity_sptrs[0]; - } - } - this->add_subset_sensitivity(*this->get_subset_sensitivity_sptr(subset_num), subset_num); - } - if (!this->get_use_subset_sensitivities()) - { - // copy full sensitivity (currently stored in subsensitivity[0]) - this->sensitivity_sptr = this->subsensitivity_sptrs[0]; - this->subsensitivity_sptrs[0].reset(); + for (int subset_num = 0; subset_num < this->num_subsets; ++subset_num) { + if (subset_num == 0) { + std::fill(this->subsensitivity_sptrs[subset_num]->begin_all(), this->subsensitivity_sptrs[subset_num]->end_all(), 0); + } else { + if (this->get_use_subset_sensitivities()) { + this->subsensitivity_sptrs[subset_num].reset(this->subsensitivity_sptrs[0]->get_empty_copy()); + } else { + // copy subsensitivity[0] pointer to current subset. + // do this as pointer such that we don't use more memory. + // This also means that we just accumulate in subsensitivity[0] for the moment. + // we will correct that below. + this->subsensitivity_sptrs[subset_num] = this->subsensitivity_sptrs[0]; + } } + this->add_subset_sensitivity(*this->get_subset_sensitivity_sptr(subset_num), subset_num); + } + if (!this->get_use_subset_sensitivities()) { + // copy full sensitivity (currently stored in subsensitivity[0]) + this->sensitivity_sptr = this->subsensitivity_sptrs[0]; + this->subsensitivity_sptrs[0].reset(); + } // compute total from subsensitivity or vice versa this->set_total_or_subset_sensitivities(); } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -set_total_or_subset_sensitivities() -{ - if (this->get_use_subset_sensitivities()) - { - // add subset sensitivities, just in case we need the total somewhere - this->sensitivity_sptr.reset(this->subsensitivity_sptrs[0]->clone()); - for (int subset_num=1; subset_numnum_subsets; ++subset_num) - { - typename TargetT::full_iterator sens_iter = this->sensitivity_sptr->begin_all(); - typename TargetT::full_iterator subsens_iter = this->subsensitivity_sptrs[subset_num]->begin_all(); - while (sens_iter != this->sensitivity_sptr->end_all()) - { - *sens_iter += *subsens_iter; - ++sens_iter; ++ subsens_iter; - } - } +PoissonLogLikelihoodWithLinearModelForMean::set_total_or_subset_sensitivities() { + if (this->get_use_subset_sensitivities()) { + // add subset sensitivities, just in case we need the total somewhere + this->sensitivity_sptr.reset(this->subsensitivity_sptrs[0]->clone()); + for (int subset_num = 1; subset_num < this->num_subsets; ++subset_num) { + typename TargetT::full_iterator sens_iter = this->sensitivity_sptr->begin_all(); + typename TargetT::full_iterator subsens_iter = this->subsensitivity_sptrs[subset_num]->begin_all(); + while (sens_iter != this->sensitivity_sptr->end_all()) { + *sens_iter += *subsens_iter; + ++sens_iter; + ++subsens_iter; + } } - else - { - // copy full sensitivity - this->subsensitivity_sptrs[0].reset(this->sensitivity_sptr->clone()); - // divide subsensitivity[0] by num_subsets - for (typename TargetT::full_iterator subsens_iter = this->subsensitivity_sptrs[0]->begin_all(); - subsens_iter != this->subsensitivity_sptrs[0]->end_all(); - ++subsens_iter) - { - *subsens_iter /= this->num_subsets; - } - // set all other pointers the same - for (int subset_num=1; subset_numnum_subsets; ++subset_num) - this->subsensitivity_sptrs[subset_num] = this->subsensitivity_sptrs[0]; + } else { + // copy full sensitivity + this->subsensitivity_sptrs[0].reset(this->sensitivity_sptr->clone()); + // divide subsensitivity[0] by num_subsets + for (typename TargetT::full_iterator subsens_iter = this->subsensitivity_sptrs[0]->begin_all(); + subsens_iter != this->subsensitivity_sptrs[0]->end_all(); ++subsens_iter) { + *subsens_iter /= this->num_subsets; } - + // set all other pointers the same + for (int subset_num = 1; subset_num < this->num_subsets; ++subset_num) + this->subsensitivity_sptrs[subset_num] = this->subsensitivity_sptrs[0]; + } } - -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -fill_nonidentifiable_target_parameters(TargetT& target, const float value) const -{ +PoissonLogLikelihoodWithLinearModelForMean::fill_nonidentifiable_target_parameters(TargetT& target, + const float value) const { typename TargetT::full_iterator target_iter = target.begin_all(); typename TargetT::full_iterator target_end_iter = target.end_all(); - typename TargetT::const_full_iterator sens_iter = - this->get_sensitivity().begin_all_const(); - - for (; - target_iter != target_end_iter; - ++target_iter, ++sens_iter) - { - if (*sens_iter == 0) - *target_iter = value; - } + typename TargetT::const_full_iterator sens_iter = this->get_sensitivity().begin_all_const(); + + for (; target_iter != target_end_iter; ++target_iter, ++sens_iter) { + if (*sens_iter == 0) + *target_iter = value; + } } -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif +#ifdef _MSC_VER +// prevent warning message on instantiation of abstract class +# pragma warning(disable : 4661) +#endif -template class PoissonLogLikelihoodWithLinearModelForMean >; -template class PoissonLogLikelihoodWithLinearModelForMean; +template class PoissonLogLikelihoodWithLinearModelForMean>; +template class PoissonLogLikelihoodWithLinearModelForMean; END_NAMESPACE_STIR - - diff --git a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.cxx b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.cxx index 290f5b76e4..435e4cea96 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.cxx @@ -1,19 +1,19 @@ /* Copyright (C) 2009- 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup GeneralisedObjectiveFunction @@ -26,11 +26,10 @@ START_NAMESPACE_STIR -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif // _MSC_VER -template class -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion >; +#ifdef _MSC_VER +// prevent warning message on instantiation of abstract class +# pragma warning(disable : 4661) +#endif // _MSC_VER +template class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion>; END_NAMESPACE_STIR diff --git a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.cxx b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.cxx index 0dbab24c41..4ee0e9af0d 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.cxx @@ -1,6 +1,6 @@ // -// -/* +// +/* Copyright (C) 2003- 2011, Hammersmith Imanet Ltd Copyright (C) 2018, University College London This file is part of STIR. @@ -14,22 +14,22 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - See STIR/LICENSE.txt for details -*/ -/*! + See STIR/LICENSE.txt for details +*/ +/*! \file - \ingroup GeneralisedObjectiveFunction + \ingroup GeneralisedObjectiveFunction \brief Declaration of class - stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeData - - \author Kris Thielemans - \author Sanida Mustafovic - -*/ - -#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h" -#include "stir/VoxelsOnCartesianGrid.h" -#include "stir/Succeeded.h" + stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeData + + \author Kris Thielemans + \author Sanida Mustafovic + +*/ + +#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h" +#include "stir/VoxelsOnCartesianGrid.h" +#include "stir/Succeeded.h" #include "stir/IO/read_from_file.h" using std::vector; @@ -37,131 +37,108 @@ using std::pair; START_NAMESPACE_STIR - -template -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData() -{ - this->set_defaults(); -} +template +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::PoissonLogLikelihoodWithLinearModelForMeanAndListModeData() { + this->set_defaults(); +} -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_defaults() -{ - base_type::set_defaults(); - this->list_mode_filename =""; - this->frame_defs_filename =""; - this->list_mode_data_sptr.reset(); +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_defaults() { + base_type::set_defaults(); + this->list_mode_filename = ""; + this->frame_defs_filename = ""; + this->list_mode_data_sptr.reset(); this->current_frame_num = 1; this->num_events_to_use = 0L; - + this->target_parameter_parser.set_defaults(); - -} - -template -void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -initialise_keymap() -{ - base_type::initialise_keymap(); - this->parser.add_key("list mode filename", &this->list_mode_filename); +} + +template +void +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::initialise_keymap() { + base_type::initialise_keymap(); + this->parser.add_key("list mode filename", &this->list_mode_filename); this->target_parameter_parser.add_to_keymap(this->parser); this->parser.add_key("time frame definition filename", &this->frame_defs_filename); // SM TODO -- later do not parse this->parser.add_key("time frame number", &this->current_frame_num); - this->parser.add_parsing_key("Bin Normalisation type", &this->normalisation_sptr); -} + this->parser.add_parsing_key("Bin Normalisation type", &this->normalisation_sptr); +} -template -bool -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::post_processing() -{ - if (base_type::post_processing() == true) - return true; +template +bool +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::post_processing() { + if (base_type::post_processing() == true) + return true; - if (this->list_mode_filename.length() == 0) - { warning("You need to specify an input file\n"); return true; } + if (this->list_mode_filename.length() == 0) { + warning("You need to specify an input file\n"); + return true; + } - this->list_mode_data_sptr= - read_from_file(this->list_mode_filename); + this->list_mode_data_sptr = read_from_file(this->list_mode_filename); - if (this->frame_defs_filename.size()!=0) + if (this->frame_defs_filename.size() != 0) this->frame_defs = TimeFrameDefinitions(this->frame_defs_filename); - else - { - // make a single frame starting from 0. End value will be ignored. - vector > frame_times(1, pair(0,0)); - this->frame_defs = TimeFrameDefinitions(frame_times); - } + else { + // make a single frame starting from 0. End value will be ignored. + vector> frame_times(1, pair(0, 0)); + this->frame_defs = TimeFrameDefinitions(frame_times); + } target_parameter_parser.check_values(); return false; -} +} template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_input_data(const shared_ptr & arg) -{ - this->list_mode_data_sptr = dynamic_pointer_cast(arg); +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_input_data(const shared_ptr& arg) { + this->list_mode_data_sptr = dynamic_pointer_cast(arg); } template const ListModeData& -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -get_input_data() const -{ +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::get_input_data() const { return *this->list_mode_data_sptr; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_additive_proj_data_sptr(const shared_ptr &arg) -{ - this->additive_proj_data_sptr = dynamic_pointer_cast(arg); +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_additive_proj_data_sptr(const shared_ptr& arg) { + this->additive_proj_data_sptr = dynamic_pointer_cast(arg); } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_normalisation_sptr(const shared_ptr& arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_normalisation_sptr( + const shared_ptr& arg) { this->normalisation_sptr = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -start_new_time_frame(const unsigned int) -{} +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::start_new_time_frame(const unsigned int) {} -template +template Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_up(shared_ptr const& target_sptr) -{ - if ( base_type::set_up(target_sptr) != Succeeded::yes) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_up(shared_ptr const& target_sptr) { + if (base_type::set_up(target_sptr) != Succeeded::yes) return Succeeded::no; // handle time frame definitions etc - if(this->num_events_to_use==0 && this->frame_defs_filename.size() == 0) - do_time_frame = true; - - return Succeeded::yes; -} + if (this->num_events_to_use == 0 && this->frame_defs_filename.size() == 0) + do_time_frame = true; -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif - -template class -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData >; + return Succeeded::yes; +} +#ifdef _MSC_VER +// prevent warning message on instantiation of abstract class +# pragma warning(disable : 4661) +#endif +template class PoissonLogLikelihoodWithLinearModelForMeanAndListModeData>; END_NAMESPACE_STIR diff --git a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.cxx b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.cxx index 05fb32d84b..bcd5a26e9c 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.cxx @@ -1,6 +1,7 @@ /* Copyright (C) 2003- 2011, Hammersmith Imanet Ltd Copyright (C) 2014, 2016, 2018, University College London + Copyright (C) 2016, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -17,7 +18,7 @@ /*! \file \ingroup GeneralisedObjectiveFunction - \brief Implementation of class + \brief Implementation of class stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin \author Nikos Efthimiou @@ -25,10 +26,11 @@ \author Sanida Mustafovic */ -#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h" -#include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" +#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h" +#include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" #include "stir/recon_buildblock/ProjMatrixElemsForOneBin.h" #include "stir/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.h" +#include "stir/LORCoordinates.h" #include "stir/ProjDataInfoCylindricalNoArcCorr.h" #include "stir/ProjData.h" #include "stir/listmode/ListRecord.h" @@ -53,502 +55,446 @@ #include "stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h" #include "stir/recon_buildblock/BinNormalisationWithCalibration.h" +#include "stir/recon_buildblock/PresmoothingForwardProjectorByBin.h" +#include "stir/recon_buildblock/PostsmoothingBackProjectorByBin.h" #ifdef STIR_MPI -#include "stir/recon_buildblock/distributed_functions.h" +# include "stir/recon_buildblock/distributed_functions.h" #endif - #include START_NAMESPACE_STIR -template -const char * const -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -registered_name = -"PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin"; - -template -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin() -{ - this->set_defaults(); -} - -template -void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -set_defaults() -{ +template +const char* const PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::registered_name = + "PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin"; + +template +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin< + TargetT>::PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin() { + this->set_defaults(); +} + +template +void +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::set_defaults() { base_type::set_defaults(); this->additive_proj_data_sptr.reset(); - this->additive_projection_data_filename ="0"; - this->max_ring_difference_num_to_process =-1; - this->PM_sptr.reset(new ProjMatrixByBinUsingRayTracing()); + this->additive_projection_data_filename = "0"; + this->max_ring_difference_num_to_process = -1; + this->PM_sptr.reset(new ProjMatrixByBinUsingRayTracing()); this->normalisation_sptr.reset(new TrivialBinNormalisation); this->do_time_frame = false; -} - -template -void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -initialise_keymap() -{ - base_type::initialise_keymap(); - this->parser.add_start_key("PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin Parameters"); - this->parser.add_stop_key("End PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin Parameters"); + this->use_tofsens = false; +} + +template +void +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::initialise_keymap() { + base_type::initialise_keymap(); + this->parser.add_start_key("PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin Parameters"); + this->parser.add_stop_key("End PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin Parameters"); + this->parser.add_key("use time-of-flight sensitivities", &this->use_tofsens); this->parser.add_key("max ring difference num to process", &this->max_ring_difference_num_to_process); - this->parser.add_parsing_key("Matrix type", &this->PM_sptr); - this->parser.add_key("additive sinogram",&this->additive_projection_data_filename); - - this->parser.add_key("num_events_to_use",&this->num_events_to_use); - -} -template -int -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -set_num_subsets(const int new_num_subsets) -{ + this->parser.add_parsing_key("Matrix type", &this->PM_sptr); + this->parser.add_key("additive sinogram", &this->additive_projection_data_filename); + + this->parser.add_key("num_events_to_use", &this->num_events_to_use); +} +template +int +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::set_num_subsets( + const int new_num_subsets) { this->num_subsets = new_num_subsets; return this->num_subsets; } -template +template bool -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -actual_subsets_are_approximately_balanced(std::string& warning_message) const -{ - assert(this->num_subsets>0); - const DataSymmetriesForBins& symmetries = - *this->PM_sptr->get_symmetries_ptr(); - - Array<1,int> num_bins_in_subset(this->num_subsets); - num_bins_in_subset.fill(0); - - - for (int subset_num=0; subset_numnum_subsets; ++subset_num) - { - for (int segment_num = -this->max_ring_difference_num_to_process; - segment_num <= this->max_ring_difference_num_to_process; ++segment_num) - { - for (int axial_num = proj_data_info_sptr->get_min_axial_pos_num(segment_num); - axial_num < proj_data_info_sptr->get_max_axial_pos_num(segment_num); - axial_num ++) - { - // For debugging. - // std::cout <get_min_tangential_pos_num(); - tang_num < proj_data_info_sptr->get_max_tangential_pos_num(); - tang_num ++ ) - { - for(int view_num = proj_data_info_sptr->get_min_view_num() + subset_num; - view_num <= proj_data_info_sptr->get_max_view_num(); - view_num += this->num_subsets) - { - const Bin tmp_bin(segment_num, - view_num, - axial_num, - tang_num, 1); - - if (!this->PM_sptr->get_symmetries_ptr()->is_basic(tmp_bin) ) - continue; - - num_bins_in_subset[subset_num] += - symmetries.num_related_bins(tmp_bin); - - } - } - } - } - } +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::actual_subsets_are_approximately_balanced( + std::string& warning_message) const { + assert(this->num_subsets > 0); + const DataSymmetriesForBins& symmetries = *this->PM_sptr->get_symmetries_ptr(); + + Array<1, int> num_bins_in_subset(this->num_subsets); + num_bins_in_subset.fill(0); + + if (this->num_subsets == 1) + return true; + + for (int subset_num = 0; subset_num < this->num_subsets; ++subset_num) { + for (int timing_pos_num = proj_data_info_sptr->get_min_tof_pos_num(); + timing_pos_num <= proj_data_info_sptr->get_max_tof_pos_num(); ++timing_pos_num) { + for (int segment_num = -this->max_ring_difference_num_to_process; segment_num <= this->max_ring_difference_num_to_process; + ++segment_num) { + for (int axial_num = proj_data_info_sptr->get_min_axial_pos_num(segment_num); + axial_num < proj_data_info_sptr->get_max_axial_pos_num(segment_num); axial_num++) { + // For debugging. + // std::cout <get_min_tangential_pos_num(); + tang_num < proj_data_info_sptr->get_max_tangential_pos_num(); tang_num++) { + for (int view_num = proj_data_info_sptr->get_min_view_num() + subset_num; + view_num <= proj_data_info_sptr->get_max_view_num(); view_num += this->num_subsets) { + const Bin tmp_bin(segment_num, view_num, axial_num, tang_num, timing_pos_num, 1); + + if (!this->PM_sptr->get_symmetries_ptr()->is_basic(tmp_bin)) + continue; - for (int subset_num=1; subset_numnum_subsets; ++subset_num) - { - if(num_bins_in_subset[subset_num] != num_bins_in_subset[0]) - { - std::stringstream str(warning_message); - str <<"Number of subsets is such that subsets will be very unbalanced.\n" - << "Number of Bins in each subset would be:\n" - << num_bins_in_subset - << "\nEither reduce the number of symmetries used by the projector, or\n" - "change the number of subsets. It usually should be a divisor of\n" - << proj_data_info_sptr->get_num_views() - << "/4 (or if that's not an integer, a divisor of " - << proj_data_info_sptr->get_num_views() - << "/2 or " - << proj_data_info_sptr->get_num_views() - << ").\n"; - warning_message = str.str(); - return false; + num_bins_in_subset[subset_num] += symmetries.num_related_bins(tmp_bin); } + } } - return true; + } + } + } + + for (int subset_num = 1; subset_num < this->num_subsets; ++subset_num) { + if (num_bins_in_subset[subset_num] != num_bins_in_subset[0]) { + std::stringstream str(warning_message); + str << "Number of subsets is such that subsets will be very unbalanced.\n" + << "Number of Bins in each subset would be:\n" + << num_bins_in_subset + << "\nEither reduce the number of symmetries used by the projector, or\n" + "change the number of subsets. It usually should be a divisor of\n" + << proj_data_info_sptr->get_num_views() << "/4 (or if that's not an integer, a divisor of " + << proj_data_info_sptr->get_num_views() << "/2 or " << proj_data_info_sptr->get_num_views() << ").\n"; + warning_message = str.str(); + return false; + } + } + return true; } -template -Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -set_up_before_sensitivity(shared_ptr const& target_sptr) -{ +template +Succeeded +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::set_up_before_sensitivity( + shared_ptr const& target_sptr) { #ifdef STIR_MPI - //broadcast objective_function (100=PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin) - distributed::send_int_value(100, -1); + // broadcast objective_function (100=PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin) + distributed::send_int_value(100, -1); #endif - // set projector to be used for the calculations - this->PM_sptr->set_up(proj_data_info_sptr->create_shared_clone(),target_sptr); + // set projector to be used for the calculations + this->PM_sptr->set_up(proj_data_info_sptr->create_shared_clone(), target_sptr); - this->projector_pair_sptr.reset( - new ProjectorByBinPairUsingProjMatrixByBin(this->PM_sptr)); - this->projector_pair_sptr->set_up(proj_data_info_sptr->create_shared_clone(),target_sptr); + // this->PM_sptr->enable_tof(proj_data_info_sptr->create_shared_clone(), this->use_tof); + shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingProjMatrixByBin(this->PM_sptr)); + shared_ptr back_projector_ptr(new BackProjectorByBinUsingProjMatrixByBin(this->PM_sptr)); - if (is_null_ptr(this->normalisation_sptr)) - { - warning("Invalid normalisation object"); - return Succeeded::no; - } + this->projector_pair_sptr.reset(new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); - if (this->normalisation_sptr->set_up( - this->list_mode_data_sptr->get_exam_info_sptr(), proj_data_info_sptr->create_shared_clone()) == Succeeded::no) - return Succeeded::no; + this->projector_pair_sptr->set_up(proj_data_info_sptr->create_shared_clone(), target_sptr); - if (this->current_frame_num<=0) - { - warning("frame_num should be >= 1"); - return Succeeded::no; - } + // sets non-tof backprojector for sensitivity calculation (clone of the back_projector + set projdatainfo to non-tof) + this->sens_backprojector_sptr.reset(projector_pair_sptr->get_back_projector_sptr()->clone()); + if (!this->use_tofsens) + this->sens_backprojector_sptr->set_up(proj_data_info_sptr->create_non_tof_clone(), target_sptr); - if (this->current_frame_num > this->frame_defs.get_num_frames()) - { - warning("frame_num is %d, but should be less than the number of frames %d.", - this->current_frame_num, this->frame_defs.get_num_frames()); - return Succeeded::no; - } + if (is_null_ptr(this->normalisation_sptr)) { + warning("Invalid normalisation object"); + return Succeeded::no; + } + + if (this->normalisation_sptr->set_up(this->list_mode_data_sptr->get_exam_info_sptr(), + proj_data_info_sptr->create_shared_clone()) == Succeeded::no) + return Succeeded::no; + + if (this->current_frame_num <= 0) { + warning("frame_num should be >= 1"); + return Succeeded::no; + } + + if (this->current_frame_num > this->frame_defs.get_num_frames()) { + warning("frame_num is %d, but should be less than the number of frames %d.", this->current_frame_num, + this->frame_defs.get_num_frames()); + return Succeeded::no; + } + + return Succeeded::yes; +} + +template +bool +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::post_processing() { + + if (base_type::post_processing() == true) + return true; - return Succeeded::yes; -} - - -template -bool -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::post_processing() -{ - - if (base_type::post_processing() == true) - return true; - #if 1 - if (is_null_ptr(this->PM_sptr)) + if (is_null_ptr(this->PM_sptr)) - { warning("You need to specify a projection matrix"); return true; } + { + warning("You need to specify a projection matrix"); + return true; + } #else - if(is_null_ptr(this->projector_pair_sptr->get_forward_projector_sptr())) - { - warning("No valid forward projector is defined"); return true; - } + if (is_null_ptr(this->projector_pair_sptr->get_forward_projector_sptr())) { + warning("No valid forward projector is defined"); + return true; + } - if(is_null_ptr(this->projector_pair_sptr->get_back_projector_sptr())) - { - warning("No valid back projector is defined"); return true; - } + if (is_null_ptr(this->projector_pair_sptr->get_back_projector_sptr())) { + warning("No valid back projector is defined"); + return true; + } #endif shared_ptr scanner_sptr(new Scanner(*this->list_mode_data_sptr->get_scanner_ptr())); - if (this->max_ring_difference_num_to_process == -1) - { - this->max_ring_difference_num_to_process = - scanner_sptr->get_num_rings()-1; - } + if (this->max_ring_difference_num_to_process == -1) { + this->max_ring_difference_num_to_process = scanner_sptr->get_num_rings() - 1; + } - if (this->additive_projection_data_filename != "0") - { - info(boost::format("Reading additive projdata data '%1%'") - % additive_projection_data_filename ); - shared_ptr temp_additive_proj_data_sptr = - ProjData::read_from_file(this->additive_projection_data_filename); - this->additive_proj_data_sptr.reset(new ProjDataInMemory(* temp_additive_proj_data_sptr)); - } + if (this->additive_projection_data_filename != "0") { + info(boost::format("Reading additive projdata data '%1%'") % additive_projection_data_filename); + shared_ptr temp_additive_proj_data_sptr = ProjData::read_from_file(this->additive_projection_data_filename); + this->additive_proj_data_sptr.reset(new ProjDataInMemory(*temp_additive_proj_data_sptr)); + } - proj_data_info_sptr = this->list_mode_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); - - if (max_ring_difference_num_to_process > proj_data_info_sptr->get_max_segment_num()) - { - warning("In the parameter file, the 'maximum ring difference' is larger than the number of segments" - "in the listmode file. Abort."); - return true; - } - else if (max_ring_difference_num_to_process < proj_data_info_sptr->get_max_segment_num()) - { - proj_data_info_sptr->reduce_segment_range(-max_ring_difference_num_to_process, - max_ring_difference_num_to_process); - } - - // Daniel: abilitate do_time_frame if there is a fdef file - if (this->frame_defs_filename.size()!=0) - { - this->frame_defs = TimeFrameDefinitions(this->frame_defs_filename); - this->do_time_frame = true; - } - - if(!is_null_ptr(this->additive_proj_data_sptr)) - if (*(this->additive_proj_data_sptr->get_proj_data_info_sptr()) != *proj_data_info_sptr) - { - const ProjDataInfo& add_proj = *(this->additive_proj_data_sptr->get_proj_data_info_sptr()); - const ProjDataInfo& proj = *this->proj_data_info_sptr; - bool ok = - typeid(add_proj) == typeid(proj) && - *add_proj.get_scanner_ptr()== *(proj.get_scanner_ptr()) && - (add_proj.get_min_view_num()==proj.get_min_view_num()) && - (add_proj.get_max_view_num()==proj.get_max_view_num()) && - (add_proj.get_min_tangential_pos_num() ==proj.get_min_tangential_pos_num())&& - (add_proj.get_max_tangential_pos_num() ==proj.get_max_tangential_pos_num()) && - add_proj.get_min_segment_num() <= proj.get_min_segment_num() && - add_proj.get_max_segment_num() >= proj.get_max_segment_num(); - - for (int segment_num=proj.get_min_segment_num(); - ok && segment_num<=proj.get_max_segment_num(); - ++segment_num) - { - ok = - add_proj.get_min_axial_pos_num(segment_num) <= proj.get_min_axial_pos_num(segment_num) && - add_proj.get_max_axial_pos_num(segment_num) >= proj.get_max_axial_pos_num(segment_num); - } - if (!ok) - { - warning(boost::format("Incompatible additive projection data:\nAdditive projdata info:\n%s\nEmission projdata info:\n%s\n" - "--- (end of incompatible projection data info)---\n") - % add_proj.parameter_info() - % proj.parameter_info()); - return true; - } - } + proj_data_info_sptr = this->list_mode_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); - if( this->normalisation_sptr->set_up(this->list_mode_data_sptr->get_exam_info_sptr(), proj_data_info_sptr) - == Succeeded::no) - { -warning("PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin: " - "set-up of normalisation failed."); -return true; + if (max_ring_difference_num_to_process > proj_data_info_sptr->get_max_segment_num()) { + warning("In the parameter file, the 'maximum ring difference' is larger than the number of segments" + "in the listmode file. Abort."); + return true; + } else if (max_ring_difference_num_to_process < proj_data_info_sptr->get_max_segment_num()) { + proj_data_info_sptr->reduce_segment_range(-max_ring_difference_num_to_process, max_ring_difference_num_to_process); + } + + // Daniel: abilitate do_time_frame if there is a fdef file + if (this->frame_defs_filename.size() != 0) { + this->frame_defs = TimeFrameDefinitions(this->frame_defs_filename); + this->do_time_frame = true; + } + + if (!is_null_ptr(this->additive_proj_data_sptr)) + if (*(this->additive_proj_data_sptr->get_proj_data_info_sptr()) != *proj_data_info_sptr) { + const ProjDataInfo& add_proj = *(this->additive_proj_data_sptr->get_proj_data_info_sptr()); + const ProjDataInfo& proj = *this->proj_data_info_sptr; + bool ok = typeid(add_proj) == typeid(proj) && *add_proj.get_scanner_ptr() == *(proj.get_scanner_ptr()) && + (add_proj.get_min_view_num() == proj.get_min_view_num()) && + (add_proj.get_max_view_num() == proj.get_max_view_num()) && + (add_proj.get_min_tangential_pos_num() == proj.get_min_tangential_pos_num()) && + (add_proj.get_max_tangential_pos_num() == proj.get_max_tangential_pos_num()) && + add_proj.get_min_segment_num() <= proj.get_min_segment_num() && + add_proj.get_max_segment_num() >= proj.get_max_segment_num() && + add_proj.get_min_tof_pos_num() <= proj.get_min_tof_pos_num() && + add_proj.get_max_tof_pos_num() >= proj.get_max_tof_pos_num(); + for (int segment_num = proj.get_min_segment_num(); ok && segment_num <= proj.get_max_segment_num(); ++segment_num) { + ok = add_proj.get_min_axial_pos_num(segment_num) <= proj.get_min_axial_pos_num(segment_num) && + add_proj.get_max_axial_pos_num(segment_num) >= proj.get_max_axial_pos_num(segment_num); + } + if (!ok) { + warning(boost::format("Incompatible additive projection data:\nAdditive projdata info:\n%s\nEmission projdata info:\n%s\n" + "--- (end of incompatible projection data info)---\n") % + add_proj.parameter_info() % proj.parameter_info()); + return true; + } } - return false; + if (this->normalisation_sptr->set_up(this->list_mode_data_sptr->get_exam_info_sptr(), proj_data_info_sptr) == Succeeded::no) { + warning("PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin: " + "set-up of normalisation failed."); + return true; + } + + return false; +} -} - -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const -{ +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::add_subset_sensitivity( + TargetT& sensitivity, const int subset_num) const { - const int min_segment_num = proj_data_info_sptr->get_min_segment_num(); - const int max_segment_num = proj_data_info_sptr->get_max_segment_num(); + const int min_segment_num = proj_data_info_sptr->get_min_segment_num(); + const int max_segment_num = proj_data_info_sptr->get_max_segment_num(); - this->projector_pair_sptr->get_back_projector_sptr()-> - start_accumulating_in_new_target(); + this->sens_backprojector_sptr->start_accumulating_in_new_target(); - // warning: has to be same as subset scheme used as in distributable_computation - for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) - { - for (int view = proj_data_info_sptr->get_min_view_num() + subset_num; - view <= proj_data_info_sptr->get_max_view_num(); - view += this->num_subsets) - { - const ViewSegmentNumbers view_segment_num(view, segment_num); + // warning: has to be same as subset scheme used as in distributable_computation + for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) { + for (int view = proj_data_info_sptr->get_min_view_num() + subset_num; view <= proj_data_info_sptr->get_max_view_num(); + view += this->num_subsets) { + const ViewSegmentNumbers view_segment_num(view, segment_num); - if (! this->projector_pair_sptr->get_symmetries_used()->is_basic(view_segment_num)) - continue; - this->add_view_seg_to_sensitivity(view_segment_num); - } + if (!this->projector_pair_sptr->get_symmetries_used()->is_basic(view_segment_num)) + continue; + this->add_view_seg_to_sensitivity(view_segment_num); } - this->projector_pair_sptr->get_back_projector_sptr()-> - get_output(sensitivity); + } + this->sens_backprojector_sptr->get_output(sensitivity); } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -add_view_seg_to_sensitivity(const ViewSegmentNumbers& view_seg_nums) const -{ - shared_ptr symmetries_used - (this->projector_pair_sptr->get_symmetries_used()->clone()); - - RelatedViewgrams viewgrams = - proj_data_info_sptr->get_empty_related_viewgrams(view_seg_nums,symmetries_used); +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::add_view_seg_to_sensitivity( + const ViewSegmentNumbers& view_seg_nums) const { + int min_timing_pos_num = use_tofsens ? this->proj_data_info_sptr->get_min_tof_pos_num() : 0; + int max_timing_pos_num = use_tofsens ? this->proj_data_info_sptr->get_max_tof_pos_num() : 0; + for (int timing_pos_num = min_timing_pos_num; timing_pos_num <= max_timing_pos_num; ++timing_pos_num) { + shared_ptr symmetries_used(this->projector_pair_sptr->get_symmetries_used()->clone()); + + RelatedViewgrams viewgrams = + proj_data_info_sptr->get_empty_related_viewgrams(view_seg_nums, symmetries_used, false, timing_pos_num); + + viewgrams.fill(1.F); + // find efficiencies + { + const double start_frame = this->frame_defs.get_start_time(this->current_frame_num); + const double end_frame = this->frame_defs.get_end_time(this->current_frame_num); + this->normalisation_sptr->undo(viewgrams, start_frame, end_frame); + } + // backproject + { + const int min_ax_pos_num = viewgrams.get_min_axial_pos_num(); + const int max_ax_pos_num = viewgrams.get_max_axial_pos_num(); - viewgrams.fill(1.F); - // find efficiencies - { - const double start_frame = this->frame_defs.get_start_time(this->current_frame_num); - const double end_frame = this->frame_defs.get_end_time(this->current_frame_num); - this->normalisation_sptr->undo(viewgrams,start_frame,end_frame); - } - // backproject - { - const int min_ax_pos_num = - viewgrams.get_min_axial_pos_num(); - const int max_ax_pos_num = - viewgrams.get_max_axial_pos_num(); - - this->projector_pair_sptr->get_back_projector_sptr()-> - back_project(viewgrams, - min_ax_pos_num, max_ax_pos_num); + this->sens_backprojector_sptr->back_project(viewgrams, min_ax_pos_num, max_ax_pos_num); + } } +} +template +std::unique_ptr +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::get_exam_info_uptr_for_target() const { + auto exam_info_uptr = this->get_exam_info_uptr_for_target(); + if (auto norm_ptr = dynamic_cast(get_normalisation_sptr().get())) { + exam_info_uptr->set_calibration_factor(norm_ptr->get_calibration_factor()); + // somehow tell the image that it's calibrated (do we have a way?) + } else { + exam_info_uptr->set_calibration_factor(1.F); + // somehow tell the image that it's not calibrated (do we have a way?) + } + return exam_info_uptr; } -template - std::unique_ptr - PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: - get_exam_info_uptr_for_target() const -{ - auto exam_info_uptr = this->get_exam_info_uptr_for_target(); - if (auto norm_ptr = dynamic_cast(get_normalisation_sptr().get())) - { - exam_info_uptr->set_calibration_factor(norm_ptr->get_calibration_factor()); - // somehow tell the image that it's calibrated (do we have a way?) - } - else - { - exam_info_uptr->set_calibration_factor(1.F); - // somehow tell the image that it's not calibrated (do we have a way?) - } - return exam_info_uptr; +template +TargetT* +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::construct_target_ptr() const { + + return this->target_parameter_parser.create(this->get_input_data()); } +template +void +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin< + TargetT>::compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, const TargetT& current_estimate, + const int subset_num) { -template -TargetT * -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -construct_target_ptr() const -{ - - return - this->target_parameter_parser.create(this->get_input_data()); -} - -template -void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) -{ - - assert(subset_num>=0); - assert(subset_numnum_subsets); - - const double start_time = this->frame_defs.get_start_time(this->current_frame_num); - const double end_time = this->frame_defs.get_end_time(this->current_frame_num); - - long num_used_events = 0; - const float max_quotient = 10000.F; - - //go to the beginning of this frame - // list_mode_data_sptr->set_get_position(start_time); - // TODO implement function that will do this for a random time - this->list_mode_data_sptr->reset(); - double current_time = 0.; - ProjMatrixElemsForOneBin proj_matrix_row; - gradient.fill(0); - shared_ptr record_sptr = this->list_mode_data_sptr->get_empty_record_sptr(); - ListRecord& record = *record_sptr; - - VectorWithOffset - frame_start_positions(1, static_cast(this->frame_defs.get_num_frames())); - - long int more_events = - this->do_time_frame? 1 : this->num_events_to_use; - - while (more_events)//this->list_mode_data_sptr->get_next_record(record) == Succeeded::yes) - { + assert(subset_num >= 0); + assert(subset_num < this->num_subsets); - if (this->list_mode_data_sptr->get_next_record(record) == Succeeded::no) - { - info("End of file!"); - break; //get out of while loop - } + const double start_time = this->frame_defs.get_start_time(this->current_frame_num); + const double end_time = this->frame_defs.get_end_time(this->current_frame_num); - if(record.is_time() && end_time > 0.01) - { - current_time = record.time().get_time_in_secs(); - if (this->do_time_frame && current_time >= end_time) - break; // get out of while loop - if (current_time < start_time) - continue; - } + long num_used_events = 0; + const float max_quotient = 10000.F; - if (record.is_event() && record.event().is_prompt()) - { - Bin measured_bin; - measured_bin.set_bin_value(1.0f); - record.event().get_bin(measured_bin, *proj_data_info_sptr); - - if (measured_bin.get_bin_value() != 1.0f - || measured_bin.segment_num() < proj_data_info_sptr->get_min_segment_num() - || measured_bin.segment_num() > proj_data_info_sptr->get_max_segment_num() - || measured_bin.tangential_pos_num() < proj_data_info_sptr->get_min_tangential_pos_num() - || measured_bin.tangential_pos_num() > proj_data_info_sptr->get_max_tangential_pos_num() - || measured_bin.axial_pos_num() < proj_data_info_sptr->get_min_axial_pos_num(measured_bin.segment_num()) - || measured_bin.axial_pos_num() > proj_data_info_sptr->get_max_axial_pos_num(measured_bin.segment_num())) - { - continue; - } + // Putting the Bins here I avoid rellocation. + Bin measured_bin; + Bin fwd_bin; - measured_bin.set_bin_value(1.0f); - // If more than 1 subsets, check if the current bin belongs to - // the current. - if (this->num_subsets > 1) - { - Bin basic_bin = measured_bin; - this->PM_sptr->get_symmetries_ptr()->find_basic_bin(basic_bin); - if (subset_num != static_cast(basic_bin.view_num() % this->num_subsets)) - continue; - } - this->PM_sptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, measured_bin); - //in_the_range++; - Bin fwd_bin; - fwd_bin.set_bin_value(0.0f); - proj_matrix_row.forward_project(fwd_bin,current_estimate); - // additive sinogram - if (!is_null_ptr(this->additive_proj_data_sptr)) - { - float add_value = this->additive_proj_data_sptr->get_bin_value(measured_bin); - float value= fwd_bin.get_bin_value()+add_value; - fwd_bin.set_bin_value(value); - } - float measured_div_fwd = 0.0f; + // go to the beginning of this frame + // list_mode_data_sptr->set_get_position(start_time); + // TODO implement function that will do this for a random time + this->list_mode_data_sptr->reset(); + double current_time = 0.; + ProjMatrixElemsForOneBin proj_matrix_row; + gradient.fill(0); + shared_ptr record_sptr = this->list_mode_data_sptr->get_empty_record_sptr(); + ListRecord& record = *record_sptr; - if(!this->do_time_frame) - more_events -=1 ; + VectorWithOffset frame_start_positions(1, static_cast(this->frame_defs.get_num_frames())); - num_used_events += 1; + long int more_events = this->do_time_frame ? 1 : (this->num_events_to_use / this->num_subsets); - if (num_used_events%200000L==0) - info( boost::format("Stored Events: %1% ") % num_used_events); + while (more_events) // this->list_mode_data_sptr->get_next_record(record) == Succeeded::yes) + { - if ( measured_bin.get_bin_value() <= max_quotient *fwd_bin.get_bin_value()) - measured_div_fwd = 1.0f /fwd_bin.get_bin_value(); - else - continue; + if (this->list_mode_data_sptr->get_next_record(record) == Succeeded::no) { + info("End of file!"); + break; // get out of while loop + } + + if (record.is_time() && end_time > 0.01) { + current_time = record.time().get_time_in_secs(); + if (this->do_time_frame && current_time >= end_time) + break; // get out of while loop + if (current_time < start_time) + continue; + } + + if (record.is_event() && record.event().is_prompt()) { + measured_bin.set_bin_value(1.0f); + + record.event().get_bin(measured_bin, *proj_data_info_sptr); + + // In theory we have already done all these checks so we can + // remove this if statement. + if (measured_bin.get_bin_value() != 1.0f || measured_bin.segment_num() < proj_data_info_sptr->get_min_segment_num() || + measured_bin.segment_num() > proj_data_info_sptr->get_max_segment_num() || + measured_bin.tangential_pos_num() < proj_data_info_sptr->get_min_tangential_pos_num() || + measured_bin.tangential_pos_num() > proj_data_info_sptr->get_max_tangential_pos_num() || + measured_bin.axial_pos_num() < proj_data_info_sptr->get_min_axial_pos_num(measured_bin.segment_num()) || + measured_bin.axial_pos_num() > proj_data_info_sptr->get_max_axial_pos_num(measured_bin.segment_num()) || + measured_bin.timing_pos_num() < proj_data_info_sptr->get_min_tof_pos_num() || + measured_bin.timing_pos_num() > proj_data_info_sptr->get_max_tof_pos_num()) { + continue; + } - measured_bin.set_bin_value(measured_div_fwd); - proj_matrix_row.back_project(gradient, measured_bin); + measured_bin.set_bin_value(1.0f); + // If more than 1 subsets, check if the current bin belongs to + // the current. + if (this->num_subsets > 1) { + Bin basic_bin = measured_bin; + if (!this->PM_sptr->get_symmetries_ptr()->is_basic(measured_bin)) + this->PM_sptr->get_symmetries_ptr()->find_basic_bin(basic_bin); + + if (subset_num != static_cast(basic_bin.view_num() % this->num_subsets)) { + continue; } + } + + measured_bin.set_bin_value(1.0f); + this->PM_sptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, measured_bin); + // in_the_range++; + fwd_bin.set_bin_value(0.0f); + proj_matrix_row.forward_project(fwd_bin, current_estimate); + // additive sinogram + if (!is_null_ptr(this->additive_proj_data_sptr)) { + float add_value = this->additive_proj_data_sptr->get_bin_value(measured_bin); + float value = fwd_bin.get_bin_value() + add_value; + fwd_bin.set_bin_value(value); + } + float measured_div_fwd = 0.0f; + + if (!this->do_time_frame) + more_events -= 1; + + num_used_events += 1; + + if (num_used_events % 200000L == 0) + info(boost::format("Stored Events: %1% ") % num_used_events); + + if (measured_bin.get_bin_value() <= max_quotient * fwd_bin.get_bin_value()) + measured_div_fwd = 1.0f / fwd_bin.get_bin_value(); + else + continue; + + measured_bin.set_bin_value(measured_div_fwd); + proj_matrix_row.back_project(gradient, measured_bin); } - info(boost::format("Number of used events: %1%") % num_used_events); + } + info(boost::format("Number of used events: %1%") % num_used_events); } -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif - -template class -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin >; +#ifdef _MSC_VER +// prevent warning message on instantiation of abstract class +# pragma warning(disable : 4661) +#endif +template class PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin>; END_NAMESPACE_STIR diff --git a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx index 89d0c1b226..55e4d96a59 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx @@ -39,19 +39,19 @@ #include "stir/DiscretisedDensity.h" #ifdef STIR_MPI -#include "stir/recon_buildblock/DistributedCachingInformation.h" +# include "stir/recon_buildblock/DistributedCachingInformation.h" #endif #include "stir/recon_buildblock/distributable.h" // for get_symmetries_ptr() #include "stir/DataSymmetriesForViewSegmentNumbers.h" // include the following to set defaults #ifndef USE_PMRT -#include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" -#include "stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" +# include "stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h" #else -#include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" -#include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" -#include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" +# include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" +# include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" #endif #include "stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h" #include "stir/recon_buildblock/find_basic_vs_nums_in_subsets.h" @@ -67,7 +67,7 @@ #include #include #ifdef STIR_MPI -#include "stir/recon_buildblock/distributed_functions.h" +# include "stir/recon_buildblock/distributed_functions.h" #endif #include "stir/CPUTimer.h" #include "stir/info.h" @@ -80,60 +80,55 @@ using std::ends; using std::max; #endif - START_NAMESPACE_STIR const int rim_truncation_sino = 0; // TODO get rid of this -template -const char * const -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -registered_name = -"PoissonLogLikelihoodWithLinearModelForMeanAndProjData"; +template +const char* const PoissonLogLikelihoodWithLinearModelForMeanAndProjData::registered_name = + "PoissonLogLikelihoodWithLinearModelForMeanAndProjData"; -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_defaults() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_defaults() { base_type::set_defaults(); - this->input_filename=""; - this->max_segment_num_to_process=-1; + this->input_filename = ""; + this->max_segment_num_to_process = -1; + this->max_timing_pos_num_to_process = 0; // KT 20/06/2001 disabled - //num_views_to_add=1; - this->proj_data_sptr.reset(); //MJ added + // num_views_to_add=1; + this->proj_data_sptr.reset(); // MJ added this->zero_seg0_end_planes = 0; + this->use_tofsens = false; this->additive_projection_data_filename = "0"; this->additive_proj_data_sptr.reset(); - // set default for projector_pair_ptr #ifndef USE_PMRT shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingRayTracing()); shared_ptr back_projector_ptr(new BackProjectorByBinUsingInterpolation()); #else - shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); // PM->set_num_tangential_LORs(5); - shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); - shared_ptr back_projector_ptr(new BackProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr back_projector_ptr(new BackProjectorByBinUsingProjMatrixByBin(PM)); #endif - this->projector_pair_ptr.reset( - new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); + this->projector_pair_ptr.reset(new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); this->normalisation_sptr.reset(new TrivialBinNormalisation); this->frame_num = 1; this->frame_definition_filename = ""; // make a single frame starting from 0 to 1. - vector > frame_times(1, pair(0,1)); + vector> frame_times(1, pair(0, 1)); this->frame_defs = TimeFrameDefinitions(frame_times); this->target_parameter_parser.set_defaults(); - + #ifdef STIR_MPI - //distributed stuff + // distributed stuff this->distributed_cache_enabled = false; this->distributed_tests_enabled = false; this->message_timings_enabled = false; @@ -142,17 +137,16 @@ set_defaults() #endif } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -initialise_keymap() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("PoissonLogLikelihoodWithLinearModelForMeanAndProjData Parameters"); this->parser.add_stop_key("End PoissonLogLikelihoodWithLinearModelForMeanAndProjData Parameters"); - this->parser.add_key("input file",&this->input_filename); + this->parser.add_key("use time-of-flight sensitivities", &this->use_tofsens); + this->parser.add_key("input file", &this->input_filename); // KT 20/06/2001 disabled - //parser.add_key("mash x views", &num_views_to_add); + // parser.add_key("mash x views", &num_views_to_add); this->parser.add_key("maximum absolute segment number to process", &this->max_segment_num_to_process); this->parser.add_key("zero end planes of segment 0", &this->zero_seg0_end_planes); @@ -160,14 +154,14 @@ initialise_keymap() this->target_parameter_parser.add_to_keymap(this->parser); this->parser.add_parsing_key("Projector pair type", &this->projector_pair_ptr); - this->parser.add_key("additive sinogram",&this->additive_projection_data_filename); + this->parser.add_key("additive sinogram", &this->additive_projection_data_filename); // normalisation (and attenuation correction) - this->parser.add_key("time frame definition filename", &this->frame_definition_filename); + this->parser.add_key("time frame definition filename", &this->frame_definition_filename); this->parser.add_key("time frame number", &this->frame_num); this->parser.add_parsing_key("Bin Normalisation type", &this->normalisation_sptr); #ifdef STIR_MPI - //distributed stuff + // distributed stuff this->parser.add_key("enable distributed caching", &distributed_cache_enabled); this->parser.add_key("enable distributed tests", &distributed_tests_enabled); this->parser.add_key("enable message timings", &message_timings_enabled); @@ -176,51 +170,44 @@ initialise_keymap() #endif } -template +template bool -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -post_processing() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::post_processing() { if (base_type::post_processing() == true) return true; - // KT 20/06/2001 disabled as not functional yet + // KT 20/06/2001 disabled as not functional yet #if 0 if (num_views_to_add!=1 && (num_views_to_add<=0 || num_views_to_add%2 != 0)) { warning("The 'mash x views' key has an invalid value (must be 1 or even number)"); return true; } #endif - - if (this->input_filename.length() > 0 ) - { - this->proj_data_sptr= ProjData::read_from_file(input_filename); - if (is_null_ptr(this->proj_data_sptr)) - { - error("Failed to read input file %s", input_filename.c_str()); - return true; - } + if (this->input_filename.length() > 0) { + this->proj_data_sptr = ProjData::read_from_file(input_filename); + + if (is_null_ptr(this->proj_data_sptr)) { + error("Failed to read input file %s", input_filename.c_str()); + return true; + } } target_parameter_parser.check_values(); - if (this->additive_projection_data_filename != "0") - { + if (this->additive_projection_data_filename != "0") { info(boost::format("Reading additive projdata data %1%") % this->additive_projection_data_filename); - this->additive_proj_data_sptr = - ProjData::read_from_file(this->additive_projection_data_filename); + this->additive_proj_data_sptr = ProjData::read_from_file(this->additive_projection_data_filename); }; - // read time frame def - if (this->frame_definition_filename.size()!=0) + // read time frame def + if (this->frame_definition_filename.size() != 0) this->frame_defs = TimeFrameDefinitions(this->frame_definition_filename); - else - { - // make a single frame starting from 0 to 1. - vector > frame_times(1, pair(0,1)); - this->frame_defs = TimeFrameDefinitions(frame_times); - } + else { + // make a single frame starting from 0 to 1. + vector> frame_times(1, pair(0, 1)); + this->frame_defs = TimeFrameDefinitions(frame_times); + } #ifndef STIR_MPI -#if 0 +# if 0 //check caching enabled value if (this->distributed_cache_enabled==true) { @@ -233,361 +220,325 @@ post_processing() warning("STIR must be compiled with MPI-compiler and debug symbols to use distributed testing.\n\tDistributed tests will not be performed!"); this->distributed_tests_enabled=false; } -#endif -#else - //check caching enabled value - if (this->distributed_cache_enabled==true) - info("Will use distributed caching!"); - else info("Distributed caching is disabled. Will use standard distributed version without forced caching!"); - -#ifndef NDEBUG - //check tests enabled value - if (this->distributed_tests_enabled==true) - { - warning("\nWill perform distributed tests! Beware that this decreases the performance"); - distributed::test=true; - } -#else - //check tests enabled value - if (this->distributed_tests_enabled==true) - { - warning("\nDistributed tests only abvailable in debug mode!"); - distributed::test=false; - } -#endif - - //check timing values - if (this->message_timings_enabled==true) - { - info("Will print timings of MPI-Messages! This is used to find bottlenecks!"); - distributed::test_send_receive_times=true; - } - //set timing threshold - distributed::min_threshold=this->message_timings_threshold; - - if (this->rpc_timings_enabled==true) - { - info("Will print run-times of processing RPC_process_related_viewgrams_gradient for every slave! This will give an idea of the parallelization effect!"); - distributed::rpc_time=true; - } - +# endif +#else + // check caching enabled value + if (this->distributed_cache_enabled == true) + info("Will use distributed caching!"); + else + info("Distributed caching is disabled. Will use standard distributed version without forced caching!"); + +# ifndef NDEBUG + // check tests enabled value + if (this->distributed_tests_enabled == true) { + warning("\nWill perform distributed tests! Beware that this decreases the performance"); + distributed::test = true; + } +# else + // check tests enabled value + if (this->distributed_tests_enabled == true) { + warning("\nDistributed tests only abvailable in debug mode!"); + distributed::test = false; + } +# endif + + // check timing values + if (this->message_timings_enabled == true) { + info("Will print timings of MPI-Messages! This is used to find bottlenecks!"); + distributed::test_send_receive_times = true; + } + // set timing threshold + distributed::min_threshold = this->message_timings_threshold; + + if (this->rpc_timings_enabled == true) { + info("Will print run-times of processing RPC_process_related_viewgrams_gradient for every slave! This will give an idea of " + "the parallelization effect!"); + distributed::rpc_time = true; + } + #endif - //this->already_setup = false; - return false; + // this->already_setup = false; + return false; } template -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -PoissonLogLikelihoodWithLinearModelForMeanAndProjData() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::PoissonLogLikelihoodWithLinearModelForMeanAndProjData() { this->set_defaults(); } template -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -~PoissonLogLikelihoodWithLinearModelForMeanAndProjData() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::~PoissonLogLikelihoodWithLinearModelForMeanAndProjData() { end_distributable_computation(); } template -TargetT * -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -construct_target_ptr() const -{ - return - target_parameter_parser.create(this->get_input_data()); +TargetT* +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::construct_target_ptr() const { + return target_parameter_parser.create(this->get_input_data()); } /*************************************************************** get_ functions ***************************************************************/ template -const ProjData& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_proj_data() const -{ return *this->proj_data_sptr; } +const ProjData& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_proj_data() const { + return *this->proj_data_sptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_proj_data_sptr() const -{ return this->proj_data_sptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_proj_data_sptr() const { + return this->proj_data_sptr; +} template -const int -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_max_segment_num_to_process() const -{ return this->max_segment_num_to_process; } +const int +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_max_segment_num_to_process() const { + return this->max_segment_num_to_process; +} template -const bool -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_zero_seg0_end_planes() const -{ return this->zero_seg0_end_planes; } +const int +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_max_timing_pos_num_to_process() const { + return this->max_timing_pos_num_to_process; +} template -const ProjData& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_additive_proj_data() const -{ return *this->additive_proj_data_sptr; } +const bool +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_zero_seg0_end_planes() const { + return this->zero_seg0_end_planes; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_additive_proj_data_sptr() const -{ return this->additive_proj_data_sptr; } +const ProjData& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_additive_proj_data() const { + return *this->additive_proj_data_sptr; +} template -const ProjectorByBinPair& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_projector_pair() const -{ return *this->projector_pair_ptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_additive_proj_data_sptr() const { + return this->additive_proj_data_sptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_projector_pair_sptr() const -{ return this->projector_pair_ptr; } +const ProjectorByBinPair& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_projector_pair() const { + return *this->projector_pair_ptr; +} template -const int -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_time_frame_num() const -{ return this->frame_num; } +const shared_ptr& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_projector_pair_sptr() const { + return this->projector_pair_ptr; +} template -const TimeFrameDefinitions& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_time_frame_definitions() const -{ return this->frame_defs; } +const int +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_time_frame_num() const { + return this->frame_num; +} template -const BinNormalisation& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_normalisation() const -{ return *this->normalisation_sptr; } +const TimeFrameDefinitions& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_time_frame_definitions() const { + return this->frame_defs; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_normalisation_sptr() const -{ return this->normalisation_sptr; } +const BinNormalisation& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_normalisation() const { + return *this->normalisation_sptr; +} +template +const shared_ptr& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_normalisation_sptr() const { + return this->normalisation_sptr; +} /*************************************************************** set_ functions ***************************************************************/ -template +template int -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_num_subsets(const int new_num_subsets) -{ - this->num_subsets = std::max(new_num_subsets,1); +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_num_subsets(const int new_num_subsets) { + this->num_subsets = std::max(new_num_subsets, 1); return this->num_subsets; - } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_proj_data_sptr(const shared_ptr& arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_proj_data_sptr(const shared_ptr& arg) { this->proj_data_sptr = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_max_segment_num_to_process(const int arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_max_segment_num_to_process(const int arg) { this->max_segment_num_to_process = arg; +} +template +void +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_max_timing_pos_num_to_process(const int arg) { + this->max_timing_pos_num_to_process = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_zero_seg0_end_planes(const bool arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_zero_seg0_end_planes(const bool arg) { this->zero_seg0_end_planes = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_additive_proj_data_sptr(const shared_ptr &arg) -{ - this->additive_proj_data_sptr = dynamic_pointer_cast(arg); +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_additive_proj_data_sptr(const shared_ptr& arg) { + this->additive_proj_data_sptr = dynamic_pointer_cast(arg); } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_projector_pair_sptr(const shared_ptr& arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_projector_pair_sptr( + const shared_ptr& arg) { this->projector_pair_ptr = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_frame_num(const int arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_frame_num(const int arg) { this->frame_num = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_frame_definitions(const TimeFrameDefinitions& arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_frame_definitions(const TimeFrameDefinitions& arg) { this->frame_defs = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_normalisation_sptr(const shared_ptr& arg) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_normalisation_sptr(const shared_ptr& arg) { this->normalisation_sptr = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_input_data(const shared_ptr & arg) -{ - this->proj_data_sptr = dynamic_pointer_cast(arg); +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_input_data(const shared_ptr& arg) { + this->proj_data_sptr = dynamic_pointer_cast(arg); } -template +template const ProjData& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_input_data() const -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_input_data() const { return *this->proj_data_sptr; } - /*************************************************************** subset balancing ***************************************************************/ -template +template bool -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -actual_subsets_are_approximately_balanced(std::string& warning_message) const -{ - assert(this->num_subsets>0); +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::actual_subsets_are_approximately_balanced( + std::string& warning_message) const { + assert(this->num_subsets > 0); const DataSymmetriesForViewSegmentNumbers& symmetries = - *this->projector_pair_ptr->get_back_projector_sptr()->get_symmetries_used(); + *this->projector_pair_ptr->get_back_projector_sptr()->get_symmetries_used(); - Array<1,int> num_vs_in_subset(this->num_subsets); + Array<1, int> num_vs_in_subset(this->num_subsets); num_vs_in_subset.fill(0); - for (int subset_num=0; subset_numnum_subsets; ++subset_num) - { - for (int segment_num = -this->max_segment_num_to_process; - segment_num <= this->max_segment_num_to_process; - ++segment_num) - for (int view_num = this->proj_data_sptr->get_min_view_num() + subset_num; - view_num <= this->proj_data_sptr->get_max_view_num(); - view_num += this->num_subsets) - { - const ViewSegmentNumbers view_segment_num(view_num, segment_num); - if (!symmetries.is_basic(view_segment_num)) - continue; - num_vs_in_subset[subset_num] += - symmetries.num_related_view_segment_numbers(view_segment_num); - } - } - for (int subset_num=1; subset_numnum_subsets; ++subset_num) - { - if(num_vs_in_subset[subset_num] != num_vs_in_subset[0]) - { - std::stringstream str(warning_message); - str <<"Number of subsets is such that subsets will be very unbalanced.\n" - << "Number of viewgrams in each subset would be:\n" - << num_vs_in_subset - << "\nEither reduce the number of symmetries used by the projector, or\n" - "change the number of subsets. It usually should be a divisor of\n" - << this->proj_data_sptr->get_num_views() - << "/4 (or if that's not an integer, a divisor of " - << this->proj_data_sptr->get_num_views() - << "/2 or " - << this->proj_data_sptr->get_num_views() - << ").\n"; - warning_message = str.str(); - return false; - } + for (int subset_num = 0; subset_num < this->num_subsets; ++subset_num) { + for (int segment_num = -this->max_segment_num_to_process; segment_num <= this->max_segment_num_to_process; ++segment_num) + for (int view_num = this->proj_data_sptr->get_min_view_num() + subset_num; + view_num <= this->proj_data_sptr->get_max_view_num(); view_num += this->num_subsets) { + const ViewSegmentNumbers view_segment_num(view_num, segment_num); + if (!symmetries.is_basic(view_segment_num)) + continue; + num_vs_in_subset[subset_num] += symmetries.num_related_view_segment_numbers(view_segment_num); + } + } + for (int subset_num = 1; subset_num < this->num_subsets; ++subset_num) { + if (num_vs_in_subset[subset_num] != num_vs_in_subset[0]) { + std::stringstream str(warning_message); + str << "Number of subsets is such that subsets will be very unbalanced.\n" + << "Number of viewgrams in each subset would be:\n" + << num_vs_in_subset + << "\nEither reduce the number of symmetries used by the projector, or\n" + "change the number of subsets. It usually should be a divisor of\n" + << this->proj_data_sptr->get_num_views() << "/4 (or if that's not an integer, a divisor of " + << this->proj_data_sptr->get_num_views() << "/2 or " << this->proj_data_sptr->get_num_views() << ").\n"; + warning_message = str.str(); + return false; } + } return true; } /*************************************************************** set_up() ***************************************************************/ -template -Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_up_before_sensitivity(shared_ptr const& target_sptr) -{ +template +Succeeded +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_up_before_sensitivity( + shared_ptr const& target_sptr) { if (is_null_ptr(this->proj_data_sptr)) - error("you need to set the input data before calling set_up"); + error("you need to set the input data before calling set_up"); - if (this->max_segment_num_to_process==-1) - this->max_segment_num_to_process = - this->proj_data_sptr->get_max_segment_num(); + if (this->max_segment_num_to_process == -1) + this->max_segment_num_to_process = this->proj_data_sptr->get_max_segment_num(); - if (this->max_segment_num_to_process > this->proj_data_sptr->get_max_segment_num()) - { - error("max_segment_num_to_process (%d) is too large", - this->max_segment_num_to_process); - return Succeeded::no; - } + if (this->max_segment_num_to_process > this->proj_data_sptr->get_max_segment_num()) { + error("max_segment_num_to_process (%d) is too large", this->max_segment_num_to_process); + return Succeeded::no; + } + + this->max_timing_pos_num_to_process = this->proj_data_sptr->get_max_tof_pos_num(); shared_ptr proj_data_info_sptr(this->proj_data_sptr->get_proj_data_info_sptr()->clone()); + #if 0 // KT 4/3/2017 disabled this. It isn't necessary and resolves modyfing the projectors in unexpected ways. proj_data_info_sptr-> reduce_segment_range(-this->max_segment_num_to_process, +this->max_segment_num_to_process); #endif - if (is_null_ptr(this->projector_pair_ptr)) - { error("You need to specify a projector pair"); return Succeeded::no; } + if (is_null_ptr(this->projector_pair_ptr)) { + error("You need to specify a projector pair"); + return Succeeded::no; + } // set projectors to be used for the calculations - setup_distributable_computation(this->projector_pair_ptr, - this->proj_data_sptr->get_exam_info_sptr(), - this->proj_data_sptr->get_proj_data_info_sptr(), - target_sptr, - zero_seg0_end_planes, + setup_distributable_computation(this->projector_pair_ptr, this->proj_data_sptr->get_exam_info_sptr(), + this->proj_data_sptr->get_proj_data_info_sptr(), target_sptr, zero_seg0_end_planes, distributed_cache_enabled); - + #ifdef STIR_MPI - //set up distributed caching object - if (distributed_cache_enabled) - { - this->caching_info_ptr = new DistributedCachingInformation(distributed::num_processors); - } - else caching_info_ptr = NULL; -#else - //non parallel version + // set up distributed caching object + if (distributed_cache_enabled) { + this->caching_info_ptr = new DistributedCachingInformation(distributed::num_processors); + } else + caching_info_ptr = NULL; +#else + // non parallel version caching_info_ptr = NULL; -#endif +#endif + + this->projector_pair_ptr->set_up(proj_data_info_sptr, target_sptr); + + // sets non-tof backprojector for sensitivity calculation (clone of the back_projector + set projdatainfo to non-tof) + this->sens_backprojector_sptr.reset(projector_pair_ptr->get_back_projector_sptr()->clone()); + if (!this->use_tofsens) + this->sens_backprojector_sptr->set_up(proj_data_info_sptr->create_non_tof_clone(), target_sptr); - this->projector_pair_ptr->set_up(proj_data_info_sptr, - target_sptr); - // TODO check compatibility between symmetries for forward and backprojector - this->symmetries_sptr.reset( - this->projector_pair_ptr->get_back_projector_sptr()->get_symmetries_used()->clone()); + this->symmetries_sptr.reset(this->projector_pair_ptr->get_back_projector_sptr()->get_symmetries_used()->clone()); - if (is_null_ptr(this->normalisation_sptr)) - { + if (is_null_ptr(this->normalisation_sptr)) { error("Invalid normalisation object"); return Succeeded::no; } @@ -595,18 +546,15 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) if (this->normalisation_sptr->set_up(proj_data_sptr->get_exam_info_sptr(), proj_data_info_sptr) == Succeeded::no) return Succeeded::no; - if (frame_num<=0) - { - error("frame_num should be >= 1"); - return Succeeded::no; - } + if (frame_num <= 0) { + error("frame_num should be >= 1"); + return Succeeded::no; + } - if (static_cast(frame_num)> frame_defs.get_num_frames()) - { - error("frame_num is %d, but should be less than the number of frames %d.", - frame_num, frame_defs.get_num_frames()); - return Succeeded::no; - } + if (static_cast(frame_num) > frame_defs.get_num_frames()) { + error("frame_num is %d, but should be less than the number of frames %d.", frame_num, frame_defs.get_num_frames()); + return Succeeded::no; + } return Succeeded::yes; } @@ -615,60 +563,34 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) functions that compute the value/gradient of the objective function etc ***************************************************************/ -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) -{ - assert(subset_num>=0); - assert(subset_numnum_subsets); - distributable_compute_gradient(this->projector_pair_ptr->get_forward_projector_sptr(), - this->projector_pair_ptr->get_back_projector_sptr(), - this->symmetries_sptr, - gradient, - current_estimate, - this->proj_data_sptr, - subset_num, - this->num_subsets, - -this->max_segment_num_to_process, - this->max_segment_num_to_process, - this->zero_seg0_end_planes!=0, - NULL, - this->additive_proj_data_sptr - , caching_info_ptr - ); - - +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::compute_sub_gradient_without_penalty_plus_sensitivity( + TargetT& gradient, const TargetT& current_estimate, const int subset_num) { + assert(subset_num >= 0); + assert(subset_num < this->num_subsets); + distributable_compute_gradient( + this->projector_pair_ptr->get_forward_projector_sptr(), this->projector_pair_ptr->get_back_projector_sptr(), + this->symmetries_sptr, gradient, current_estimate, this->proj_data_sptr, subset_num, this->num_subsets, + -this->max_segment_num_to_process, this->max_segment_num_to_process, this->zero_seg0_end_planes != 0, NULL, + this->additive_proj_data_sptr, caching_info_ptr, -this->max_timing_pos_num_to_process, this->max_timing_pos_num_to_process); } +template +double +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::actual_compute_objective_function_without_penalty( + const TargetT& current_estimate, const int subset_num) { + double accum = 0.; + + distributable_accumulate_loglikelihood( + this->projector_pair_ptr->get_forward_projector_sptr(), this->projector_pair_ptr->get_back_projector_sptr(), + this->symmetries_sptr, current_estimate, this->proj_data_sptr, subset_num, this->get_num_subsets(), + -this->max_segment_num_to_process, this->max_segment_num_to_process, this->zero_seg0_end_planes != 0, &accum, + this->additive_proj_data_sptr, this->normalisation_sptr, + this->get_time_frame_definitions().get_start_time(this->get_time_frame_num()), + this->get_time_frame_definitions().get_end_time(this->get_time_frame_num()), this->caching_info_ptr, + -this->max_timing_pos_num_to_process, this->max_timing_pos_num_to_process); -template -double -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num) -{ - double accum=0.; - - distributable_accumulate_loglikelihood(this->projector_pair_ptr->get_forward_projector_sptr(), - this->projector_pair_ptr->get_back_projector_sptr(), - this->symmetries_sptr, - current_estimate, - this->proj_data_sptr, - subset_num, this->get_num_subsets(), - -this->max_segment_num_to_process, - this->max_segment_num_to_process, - this->zero_seg0_end_planes != 0, &accum, - this->additive_proj_data_sptr, - this->normalisation_sptr, - this->get_time_frame_definitions().get_start_time(this->get_time_frame_num()), - this->get_time_frame_definitions().get_end_time(this->get_time_frame_num()), - this->caching_info_ptr - ); - - return accum; } @@ -681,29 +603,32 @@ sum_projection_data() const float counts=0.0F; - for (int segment_num = -max_segment_num_to_process; segment_num <= max_segment_num_to_process; segment_num++) + for (int segment_num = -max_segment_num_to_process; segment_num <= max_segment_num_to_process; ++segment_num) { - for (int view_num = proj_data_sptr->get_min_view_num(); - view_num <= proj_data_sptr->get_max_view_num(); - ++view_num) - { - - Viewgram viewgram=proj_data_sptr->get_viewgram(view_num,segment_num); - - //first adjust data - - // KT 05/07/2000 made parameters.zero_seg0_end_planes int - if(segment_num==0 && zero_seg0_end_planes!=0) - { - viewgram[viewgram.get_min_axial_pos_num()].fill(0); - viewgram[viewgram.get_max_axial_pos_num()].fill(0); - } - - truncate_rim(viewgram,rim_truncation_sino); - - //now take totals - counts+=viewgram.sum(); - } + for (int timing_pos_num = -max_timing_pos_num_to_process; timing_pos_num <= max_timing_pos_num_to_process; ++timing_pos_num) + { + for (int view_num = proj_data_sptr->get_min_view_num(); + view_num <= proj_data_sptr->get_max_view_num(); + ++view_num) + { + + Viewgram viewgram=proj_data_sptr->get_viewgram(view_num,segment_num,false,timing_pos_num); + + //first adjust data + + // KT 05/07/2000 made parameters.zero_seg0_end_planes int + if(segment_num==0 && zero_seg0_end_planes!=0) + { + viewgram[viewgram.get_min_axial_pos_num()].fill(0); + viewgram[viewgram.get_max_axial_pos_num()].fill(0); + } + + truncate_rim(viewgram,rim_truncation_sino); + + //now take totals + counts+=viewgram.sum(); + } + } } return counts; @@ -712,63 +637,51 @@ sum_projection_data() const #endif -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::add_subset_sensitivity(TargetT& sensitivity, + const int subset_num) const { const int min_segment_num = -this->max_segment_num_to_process; const int max_segment_num = this->max_segment_num_to_process; #if 1 - shared_ptr sensitivity_this_subset_sptr(sensitivity.clone()); - - // have to create a ProjData object filled with 1 here because otherwise zero_seg0_endplanes will not be effective - shared_ptr sens_proj_data_sptr(new ProjDataInMemory( - this->proj_data_sptr->get_exam_info_sptr(), - this->proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone())); - sens_proj_data_sptr->fill(1.0F); - - distributable_sensitivity_computation(this->projector_pair_ptr->get_forward_projector_sptr(), - this->projector_pair_ptr->get_back_projector_sptr(), - this->symmetries_sptr, - *sensitivity_this_subset_sptr, - sensitivity, - sens_proj_data_sptr, - subset_num, - this->num_subsets, - min_segment_num, - max_segment_num, - this->zero_seg0_end_planes!=0, - NULL, - this->additive_proj_data_sptr, - this->normalisation_sptr, - this->get_time_frame_definitions().get_start_time(this->get_time_frame_num()), - this->get_time_frame_definitions().get_end_time(this->get_time_frame_num()), - this->caching_info_ptr - ); - std::transform(sensitivity.begin_all(), sensitivity.end_all(), - sensitivity_this_subset_sptr->begin_all(), sensitivity.begin_all(), - std::plus()); + shared_ptr sensitivity_this_subset_sptr(sensitivity.clone()); + shared_ptr sens_proj_data_sptr; + // have to create a ProjData object filled with 1 here because otherwise zero_seg0_endplanes will not be effective + if (!this->use_tofsens) + sens_proj_data_sptr.reset(new ProjDataInMemory(this->proj_data_sptr->get_exam_info_sptr(), + this->proj_data_sptr->get_proj_data_info_sptr()->create_non_tof_clone())); + else + sens_proj_data_sptr.reset( + new ProjDataInMemory(this->proj_data_sptr->get_exam_info_sptr(), this->proj_data_sptr->get_proj_data_info_sptr())); + sens_proj_data_sptr->fill(1.0F); + + distributable_sensitivity_computation( + this->projector_pair_ptr->get_forward_projector_sptr(), this->sens_backprojector_sptr, this->symmetries_sptr, + *sensitivity_this_subset_sptr, sensitivity, sens_proj_data_sptr, subset_num, this->num_subsets, min_segment_num, + max_segment_num, this->zero_seg0_end_planes != 0, NULL, this->additive_proj_data_sptr, this->normalisation_sptr, + this->get_time_frame_definitions().get_start_time(this->get_time_frame_num()), + this->get_time_frame_definitions().get_end_time(this->get_time_frame_num()), this->caching_info_ptr, + use_tofsens ? -this->max_timing_pos_num_to_process : 0, use_tofsens ? this->max_timing_pos_num_to_process : 0); + + std::transform(sensitivity.begin_all(), sensitivity.end_all(), sensitivity_this_subset_sptr->begin_all(), + sensitivity.begin_all(), std::plus()); #else // warning: has to be same as subset scheme used as in distributable_computation - for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) - { - //CPUTimer timer; - //timer.start(); - - for (int view = this->proj_data_sptr->get_min_view_num() + subset_num; - view <= this->proj_data_sptr->get_max_view_num(); - view += this->num_subsets) - { + for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) { + // CPUTimer timer; + // timer.start(); + + for (int view = this->proj_data_sptr->get_min_view_num() + subset_num; view <= this->proj_data_sptr->get_max_view_num(); + view += this->num_subsets) { const ViewSegmentNumbers view_segment_num(view, segment_num); - + if (!symmetries_sptr->is_basic(view_segment_num)) continue; this->add_view_seg_to_sensitivity(sensitivity, view_segment_num); } - // cerr<:: add_view_seg_to_sensitivity(TargetT& sensitivity, const ViewSegmentNumbers& view_seg_nums) const { - RelatedViewgrams viewgrams = - this->proj_data_sptr->get_empty_related_viewgrams(view_seg_nums, - this->symmetries_sptr); - viewgrams.fill(1.F); - // find efficiencies - { - const double start_frame = this->frame_defs.get_start_time(this->frame_num); - const double end_frame = this->frame_defs.get_end_time(this->frame_num); - this->normalisation_sptr->undo(viewgrams,start_frame,end_frame); - } - // backproject - { - const int range_to_zero = - view_seg_nums.segment_num() == 0 && this->zero_seg0_end_planes - ? 1 : 0; - const int min_ax_pos_num = - viewgrams.get_min_axial_pos_num() + range_to_zero; - const int max_ax_pos_num = - viewgrams.get_max_axial_pos_num() - range_to_zero; - - this->projector_pair_ptr->get_back_projector_sptr()-> - back_project(sensitivity, viewgrams, - min_ax_pos_num, max_ax_pos_num); - } + int min_timing_pos_num = use_tofsens ? -this->max_timing_pos_num_to_process : 0; + int max_timing_pos_num = use_tofsens ? this->max_timing_pos_num_to_process : 0; + for (int timing_pos_num = min_timing_pos_num; timing_pos_num <= max_timing_pos_num; ++timing_pos_num) + { + RelatedViewgrams viewgrams = + this->proj_data_sptr->get_empty_related_viewgrams(view_seg_nums, + this->symmetries_sptr, false, timing_pos_num); + viewgrams.fill(1.F); + // find efficiencies + { + const double start_frame = this->frame_defs.get_start_time(this->frame_num); + const double end_frame = this->frame_defs.get_end_time(this->frame_num); + this->normalisation_sptr->undo(viewgrams, start_frame, end_frame); + } + // backproject + { + const int range_to_zero = + view_seg_nums.segment_num() == 0 && this->zero_seg0_end_planes + ? 1 : 0; + const int min_ax_pos_num = + viewgrams.get_min_axial_pos_num() + range_to_zero; + const int max_ax_pos_num = + viewgrams.get_max_axial_pos_num() - range_to_zero; + + this->sens_backprojector_sptr->back_project(sensitivity, viewgrams, min_ax_pos_num, max_ax_pos_num); + } + } } #endif -template - std::unique_ptr - PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: - get_exam_info_uptr_for_target() const -{ - auto exam_info_uptr = this->get_exam_info_uptr_for_target(); - if (auto norm_ptr = dynamic_cast(get_normalisation_sptr().get())) - { - exam_info_uptr->set_calibration_factor(norm_ptr->get_calibration_factor()); - // somehow tell the image that it's calibrated - } - else - { - exam_info_uptr->set_calibration_factor(-1.F); - // somehow tell the image that it's not calibrated - } - return exam_info_uptr; +template +std::unique_ptr +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_exam_info_uptr_for_target() const { + auto exam_info_uptr = this->get_exam_info_uptr_for_target(); + if (auto norm_ptr = dynamic_cast(get_normalisation_sptr().get())) { + exam_info_uptr->set_calibration_factor(norm_ptr->get_calibration_factor()); + // somehow tell the image that it's calibrated + } else { + exam_info_uptr->set_calibration_factor(-1.F); + // somehow tell the image that it's not calibrated + } + return exam_info_uptr; } -template +template Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData< + TargetT>::actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, const TargetT& input, + const int subset_num) const { { std::string explanation; - if (!input.has_same_characteristics(this->get_sensitivity(), - explanation)) - { - error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData:\n" - "sensitivity and input for add_multiplication_with_approximate_Hessian_without_penalty\n" - "should have the same characteristics.\n%s", - explanation.c_str()); - return Succeeded::no; - } - } + if (!input.has_same_characteristics(this->get_sensitivity(), explanation)) { + error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData:\n" + "sensitivity and input for add_multiplication_with_approximate_Hessian_without_penalty\n" + "should have the same characteristics.\n%s", + explanation.c_str()); + return Succeeded::no; + } + } - shared_ptr symmetries_sptr( - this->get_projector_pair().get_symmetries_used()->clone()); + shared_ptr symmetries_sptr(this->get_projector_pair().get_symmetries_used()->clone()); - const double start_time = - this->get_time_frame_definitions().get_start_time(this->get_time_frame_num()); - const double end_time = - this->get_time_frame_definitions().get_end_time(this->get_time_frame_num()); + const double start_time = this->get_time_frame_definitions().get_start_time(this->get_time_frame_num()); + const double end_time = this->get_time_frame_definitions().get_end_time(this->get_time_frame_num()); this->get_projector_pair().get_forward_projector_sptr()->set_input(input); this->get_projector_pair().get_back_projector_sptr()->start_accumulating_in_new_target(); - const std::vector vs_nums_to_process = - detail::find_basic_vs_nums_in_subset(* this->get_proj_data().get_proj_data_info_sptr(), - *symmetries_sptr, - -this->get_max_segment_num_to_process(), - this->get_max_segment_num_to_process(), - subset_num, this->get_num_subsets()); + const std::vector vs_nums_to_process = detail::find_basic_vs_nums_in_subset( + *this->get_proj_data().get_proj_data_info_sptr(), *symmetries_sptr, -this->get_max_segment_num_to_process(), + this->get_max_segment_num_to_process(), subset_num, this->get_num_subsets()); info("Forward projecting input image.", 2); #ifdef STIR_OPENMP -#pragma omp parallel for schedule(runtime) +# pragma omp parallel for schedule(runtime) #endif // note: older versions of openmp need an int as loop - for (int i=0; i(vs_nums_to_process.size()); ++i) - { + for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++i) { #ifdef STIR_OPENMP - const int thread_num = omp_get_thread_num(); - info(boost::format("Thread %d/%d calculating segment_num: %d, view_num: %d") - % thread_num % omp_get_num_threads() - % vs_nums_to_process[i].segment_num() % vs_nums_to_process[i].view_num(), 2); + const int thread_num = omp_get_thread_num(); + info(boost::format("Thread %d/%d calculating segment_num: %d, view_num: %d") % thread_num % omp_get_num_threads() % + vs_nums_to_process[i].segment_num() % vs_nums_to_process[i].view_num(), + 2); #else - info(boost::format("calculating segment_num: %d, view_num: %d") - % vs_nums_to_process[i].segment_num() % vs_nums_to_process[i].view_num(), 2); + info(boost::format("calculating segment_num: %d, view_num: %d") % vs_nums_to_process[i].segment_num() % + vs_nums_to_process[i].view_num(), + 2); #endif - const ViewSegmentNumbers view_segment_num=vs_nums_to_process[i]; + const ViewSegmentNumbers view_segment_num = vs_nums_to_process[i]; - // first compute data-term: y*norm^2 - RelatedViewgrams viewgrams = - this->get_proj_data().get_related_viewgrams(view_segment_num, symmetries_sptr); - // TODO add 1 for 1/(y+1) approximation + // first compute data-term: y*norm^2 + RelatedViewgrams viewgrams = this->get_proj_data().get_related_viewgrams(view_segment_num, symmetries_sptr, false); + // TODO add 1 for 1/(y+1) approximation - this->get_normalisation().apply(viewgrams, start_time, end_time); + this->get_normalisation().apply(viewgrams, start_time, end_time); - // smooth TODO + // smooth TODO - this->get_normalisation().apply(viewgrams, start_time, end_time); + RelatedViewgrams tmp_viewgrams; + // set tmp_viewgrams to geometric forward projection of input + { + tmp_viewgrams = this->get_proj_data().get_empty_related_viewgrams(view_segment_num, symmetries_sptr); + this->get_projector_pair().get_forward_projector_sptr()->forward_project(tmp_viewgrams); + } - RelatedViewgrams tmp_viewgrams; - // set tmp_viewgrams to geometric forward projection of input - { - tmp_viewgrams = this->get_proj_data().get_empty_related_viewgrams(view_segment_num, symmetries_sptr); - this->get_projector_pair().get_forward_projector_sptr()-> - forward_project(tmp_viewgrams); - } - - // now divide by the data term - { - int tmp1=0, tmp2=0;// ignore counters returned by divide_and_truncate - divide_and_truncate(tmp_viewgrams, viewgrams, 0, tmp1, tmp2); - } + // now divide by the data term + { + int tmp1 = 0, tmp2 = 0; // ignore counters returned by divide_and_truncate + divide_and_truncate(tmp_viewgrams, viewgrams, 0, tmp1, tmp2); + } - // back-project - this->get_projector_pair().get_back_projector_sptr()-> - back_project(tmp_viewgrams); + // back-project + this->get_projector_pair().get_back_projector_sptr()->back_project(tmp_viewgrams); } // end of loop over view/segments shared_ptr tmp(output.get_empty_copy()); this->get_projector_pair().get_back_projector_sptr()->get_output(*tmp); // output += tmp; - std::transform(output.begin_all(), output.end_all(), - tmp->begin_all(), output.begin_all(), - std::plus()); + std::transform(output.begin_all(), output.end_all(), tmp->begin_all(), output.begin_all(), + std::plus()); return Succeeded::yes; } - -template +template Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input, - const int subset_num) const -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::actual_accumulate_sub_Hessian_times_input_without_penalty( + TargetT& output, const TargetT& current_image_estimate, const TargetT& input, const int subset_num) const { { // check characteristics std::string explanation; - if (!output.has_same_characteristics(this->get_sensitivity(),explanation)) - { + if (!output.has_same_characteristics(this->get_sensitivity(), explanation)) { error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData:\n" "sensitivity and output for add_multiplication_with_approximate_Hessian_without_penalty\n" "should have the same characteristics.\n%s", @@ -944,8 +833,7 @@ actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, return Succeeded::no; } - if (!input.has_same_characteristics(this->get_sensitivity(),explanation)) - { + if (!input.has_same_characteristics(this->get_sensitivity(), explanation)) { error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData:\n" "sensitivity and input for add_multiplication_with_approximate_Hessian_without_penalty\n" "should have the same characteristics.\n%s", @@ -953,8 +841,7 @@ actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, return Succeeded::no; } - if (!current_image_estimate.has_same_characteristics(this->get_sensitivity(),explanation)) - { + if (!current_image_estimate.has_same_characteristics(this->get_sensitivity(), explanation)) { error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData:\n" "sensitivity and current_image_estimate for add_multiplication_with_approximate_Hessian_without_penalty\n" "should have the same characteristics.\n%s", @@ -963,70 +850,61 @@ actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, } } - shared_ptr symmetries_sptr( - this->get_projector_pair().get_symmetries_used()->clone()); + shared_ptr symmetries_sptr(this->get_projector_pair().get_symmetries_used()->clone()); this->get_projector_pair().get_forward_projector_sptr()->set_input(input); this->get_projector_pair().get_back_projector_sptr()->start_accumulating_in_new_target(); - const std::vector vs_nums_to_process = - detail::find_basic_vs_nums_in_subset(* this->get_proj_data().get_proj_data_info_sptr(), - *symmetries_sptr, - -this->get_max_segment_num_to_process(), - this->get_max_segment_num_to_process(), - subset_num, this->get_num_subsets()); - - + const std::vector vs_nums_to_process = detail::find_basic_vs_nums_in_subset( + *this->get_proj_data().get_proj_data_info_sptr(), *symmetries_sptr, -this->get_max_segment_num_to_process(), + this->get_max_segment_num_to_process(), subset_num, this->get_num_subsets()); // Create and populate the input_viewgrams_vec with empty values. // This is needed to make the order of the vector correct w.r.t vs_nums_to_process. - //OMP may mess this up + // OMP may mess this up // Try: std::vector> input_viewgrams_vec(vs_nums_to_process.size()); std::vector> input_viewgrams_vec; - for (int i=0; i(vs_nums_to_process.size()); ++i) - { + for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++i) { const ViewSegmentNumbers view_segment_num = vs_nums_to_process[i]; input_viewgrams_vec.push_back(this->get_proj_data().get_empty_related_viewgrams(view_segment_num, symmetries_sptr)); } - // Forward project input image - info("Forward projecting input image.",2); + info("Forward projecting input image.", 2); #ifdef STIR_OPENMP -#pragma omp parallel for schedule(runtime) +# pragma omp parallel for schedule(runtime) #endif - for (int i=0; i(vs_nums_to_process.size()); ++i) - { // Loop over eah of the viewgrams in input_viewgrams_vec, forward projecting input into them + for (int i = 0; i < static_cast(vs_nums_to_process.size()); + ++i) { // Loop over eah of the viewgrams in input_viewgrams_vec, forward projecting input into them #ifdef STIR_OPENMP const int thread_num = omp_get_thread_num(); - info(boost::format("Thread %d/%d calculating segment_num: %d, view_num: %d") - % thread_num % omp_get_num_threads() - % vs_nums_to_process[i].segment_num() % vs_nums_to_process[i].view_num(), 2); + info(boost::format("Thread %d/%d calculating segment_num: %d, view_num: %d") % thread_num % omp_get_num_threads() % + vs_nums_to_process[i].segment_num() % vs_nums_to_process[i].view_num(), + 2); #else - info(boost::format("calculating segment_num: %d, view_num: %d") - % vs_nums_to_process[i].segment_num() % vs_nums_to_process[i].view_num(), 2); + info(boost::format("calculating segment_num: %d, view_num: %d") % vs_nums_to_process[i].segment_num() % + vs_nums_to_process[i].view_num(), + 2); #endif input_viewgrams_vec[i] = this->get_proj_data().get_empty_related_viewgrams(vs_nums_to_process[i], symmetries_sptr); this->get_projector_pair().get_forward_projector_sptr()->forward_project(input_viewgrams_vec[i]); } - - info("Forward projecting current image estimate and back projecting to output.", 2); this->get_projector_pair().get_forward_projector_sptr()->set_input(current_image_estimate); #ifdef STIR_OPENMP -#pragma omp parallel for schedule(runtime) +# pragma omp parallel for schedule(runtime) #endif - for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++i) - { + for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++i) { #ifdef STIR_OPENMP const int thread_num = omp_get_thread_num(); - info(boost::format("Thread %d/%d calculating segment_num: %d, view_num: %d") - % thread_num % omp_get_num_threads() - % vs_nums_to_process[i].segment_num() % vs_nums_to_process[i].view_num(), 2); + info(boost::format("Thread %d/%d calculating segment_num: %d, view_num: %d") % thread_num % omp_get_num_threads() % + vs_nums_to_process[i].segment_num() % vs_nums_to_process[i].view_num(), + 2); #else - info(boost::format("calculating segment_num: %d, view_num: %d") - % vs_nums_to_process[i].segment_num() % vs_nums_to_process[i].view_num(), 2); + info(boost::format("calculating segment_num: %d, view_num: %d") % vs_nums_to_process[i].segment_num() % + vs_nums_to_process[i].view_num(), + 2); #endif // Compute ybar_sq_viewgram = [ F(current_image_est) + additive ]^2 RelatedViewgrams ybar_sq_viewgram; @@ -1034,7 +912,7 @@ actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, ybar_sq_viewgram = this->get_proj_data().get_empty_related_viewgrams(vs_nums_to_process[i], symmetries_sptr); this->get_projector_pair().get_forward_projector_sptr()->forward_project(ybar_sq_viewgram); - //add additive sinogram to forward projection + // add additive sinogram to forward projection if (!(is_null_ptr(this->get_additive_proj_data_sptr()))) ybar_sq_viewgram += this->get_additive_proj_data().get_related_viewgrams(vs_nums_to_process[i], symmetries_sptr); // square ybar @@ -1047,22 +925,20 @@ actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, { // Mult input_viewgram final_viewgram *= input_viewgrams_vec[i]; - int tmp1 = 0, tmp2 = 0;// ignore counters returned by divide_and_truncate + int tmp1 = 0, tmp2 = 0; // ignore counters returned by divide_and_truncate // Divide final_viewgeam by ybar_sq_viewgram divide_and_truncate(final_viewgram, ybar_sq_viewgram, 0, tmp1, tmp2); } // back-project final_viewgram - this->get_projector_pair().get_back_projector_sptr()-> - back_project(final_viewgram); + this->get_projector_pair().get_back_projector_sptr()->back_project(final_viewgram); } // end of loop over view/segments shared_ptr tmp(output.get_empty_copy()); this->get_projector_pair().get_back_projector_sptr()->get_output(*tmp); // output += tmp; - std::transform(output.begin_all(), output.end_all(), - tmp->begin_all(), output.begin_all(), + std::transform(output.begin_all(), output.end_all(), tmp->begin_all(), output.begin_all(), std::plus()); return Succeeded::yes; @@ -1083,7 +959,7 @@ RPC_process_related_viewgrams_type RPC_process_related_viewgrams_accumulate_logl //! Call-back function for sensitivity_computation RPC_process_related_viewgrams_type RPC_process_related_viewgrams_sensitivity_computation; -#else +#else //! Call-back function for compute_gradient static RPC_process_related_viewgrams_type RPC_process_related_viewgrams_gradient; @@ -1094,131 +970,79 @@ static RPC_process_related_viewgrams_type RPC_process_related_viewgrams_accumula static RPC_process_related_viewgrams_type RPC_process_related_viewgrams_sensitivity_computation; #endif -void distributable_compute_gradient(const shared_ptr& forward_projector_sptr, - const shared_ptr& back_projector_sptr, - const shared_ptr& symmetries_sptr, - DiscretisedDensity<3,float>& output_image, - const DiscretisedDensity<3,float>& input_image, - const shared_ptr& proj_dat, - int subset_num, int num_subsets, - int min_segment, int max_segment, - bool zero_seg0_end_planes, - double* log_likelihood_ptr, - shared_ptr const& additive_binwise_correction, - DistributedCachingInformation* caching_info_ptr - ) -{ - - distributable_computation(forward_projector_sptr, - back_projector_sptr, - symmetries_sptr, - &output_image, &input_image, - proj_dat, true, //i.e. do read projection data - subset_num, num_subsets, - min_segment, max_segment, - zero_seg0_end_planes, - log_likelihood_ptr, - additive_binwise_correction, - /* normalisation info to be ignored */ shared_ptr(), 0., 0., - &RPC_process_related_viewgrams_gradient, - caching_info_ptr - ); +void +distributable_compute_gradient(const shared_ptr& forward_projector_sptr, + const shared_ptr& back_projector_sptr, + const shared_ptr& symmetries_sptr, + DiscretisedDensity<3, float>& output_image, const DiscretisedDensity<3, float>& input_image, + const shared_ptr& proj_dat, int subset_num, int num_subsets, int min_segment, + int max_segment, bool zero_seg0_end_planes, double* log_likelihood_ptr, + shared_ptr const& additive_binwise_correction, + DistributedCachingInformation* caching_info_ptr, int min_timing_pos_num, int max_timing_pos_num) { + + distributable_computation(forward_projector_sptr, back_projector_sptr, symmetries_sptr, &output_image, &input_image, proj_dat, + true, // i.e. do read projection data + subset_num, num_subsets, min_segment, max_segment, zero_seg0_end_planes, log_likelihood_ptr, + additive_binwise_correction, + /* normalisation info to be ignored */ shared_ptr(), 0., 0., + &RPC_process_related_viewgrams_gradient, caching_info_ptr, min_timing_pos_num, max_timing_pos_num); } +void +distributable_accumulate_loglikelihood( + const shared_ptr& forward_projector_sptr, const shared_ptr& back_projector_sptr, + const shared_ptr& symmetries_sptr, const DiscretisedDensity<3, float>& input_image, + const shared_ptr& proj_dat, int subset_num, int num_subsets, int min_segment, int max_segment, + bool zero_seg0_end_planes, double* log_likelihood_ptr, shared_ptr const& additive_binwise_correction, + shared_ptr const& normalisation_sptr, const double start_time_of_frame, const double end_time_of_frame, + DistributedCachingInformation* caching_info_ptr, int min_timing_pos_num, int max_timing_pos_num) -void distributable_accumulate_loglikelihood( - const shared_ptr& forward_projector_sptr, - const shared_ptr& back_projector_sptr, - const shared_ptr& symmetries_sptr, - const DiscretisedDensity<3,float>& input_image, - const shared_ptr& proj_dat, - int subset_num, int num_subsets, - int min_segment, int max_segment, - bool zero_seg0_end_planes, - double* log_likelihood_ptr, - shared_ptr const& additive_binwise_correction, - shared_ptr const& normalisation_sptr, - const double start_time_of_frame, - const double end_time_of_frame, - DistributedCachingInformation* caching_info_ptr - ) - { - distributable_computation(forward_projector_sptr, - back_projector_sptr, - symmetries_sptr, - NULL, &input_image, - proj_dat, true, //i.e. do read projection data - subset_num, num_subsets, - min_segment, max_segment, - zero_seg0_end_planes, - log_likelihood_ptr, - additive_binwise_correction, - normalisation_sptr, - start_time_of_frame, - end_time_of_frame, - &RPC_process_related_viewgrams_accumulate_loglikelihood, - caching_info_ptr - ); + distributable_computation(forward_projector_sptr, back_projector_sptr, symmetries_sptr, NULL, &input_image, proj_dat, + true, // i.e. do read projection data + subset_num, num_subsets, min_segment, max_segment, zero_seg0_end_planes, log_likelihood_ptr, + additive_binwise_correction, normalisation_sptr, start_time_of_frame, end_time_of_frame, + &RPC_process_related_viewgrams_accumulate_loglikelihood, caching_info_ptr, min_timing_pos_num, + max_timing_pos_num); } -void distributable_sensitivity_computation( - const shared_ptr& forward_projector_sptr, - const shared_ptr& back_projector_sptr, - const shared_ptr& symmetries_sptr, - DiscretisedDensity<3,float>& sensitivity, - const DiscretisedDensity<3,float>& input_image, - const shared_ptr& proj_dat, - int subset_num, int num_subsets, - int min_segment, int max_segment, - bool zero_seg0_end_planes, - double* log_likelihood_ptr, - shared_ptr const& additive_binwise_correction, - shared_ptr const& normalisation_sptr, - const double start_time_of_frame, - const double end_time_of_frame, - DistributedCachingInformation* caching_info_ptr - ) +void +distributable_sensitivity_computation(const shared_ptr& forward_projector_sptr, + const shared_ptr& back_projector_sptr, + const shared_ptr& symmetries_sptr, + DiscretisedDensity<3, float>& sensitivity, const DiscretisedDensity<3, float>& input_image, + const shared_ptr& proj_dat, int subset_num, int num_subsets, int min_segment, + int max_segment, bool zero_seg0_end_planes, double* log_likelihood_ptr, + shared_ptr const& additive_binwise_correction, + shared_ptr const& normalisation_sptr, const double start_time_of_frame, + const double end_time_of_frame, DistributedCachingInformation* caching_info_ptr, + int min_timing_pos_num, int max_timing_pos_num) { - distributable_computation(forward_projector_sptr, - back_projector_sptr, - symmetries_sptr, - &sensitivity, &input_image, - proj_dat, true, //i.e. do read projection data - subset_num, num_subsets, - min_segment, max_segment, - zero_seg0_end_planes, - log_likelihood_ptr, - additive_binwise_correction, - normalisation_sptr, - start_time_of_frame, - end_time_of_frame, - &RPC_process_related_viewgrams_sensitivity_computation, - caching_info_ptr - ); - + distributable_computation(forward_projector_sptr, back_projector_sptr, symmetries_sptr, &sensitivity, &input_image, proj_dat, + true, // i.e. do read projection data + subset_num, num_subsets, min_segment, max_segment, zero_seg0_end_planes, log_likelihood_ptr, + additive_binwise_correction, normalisation_sptr, start_time_of_frame, end_time_of_frame, + &RPC_process_related_viewgrams_sensitivity_computation, caching_info_ptr, min_timing_pos_num, + max_timing_pos_num); } - //////////// RPC functions - -void RPC_process_related_viewgrams_gradient( - const shared_ptr& forward_projector_sptr, - const shared_ptr& back_projector_sptr, - RelatedViewgrams* measured_viewgrams_ptr, - int& count, int& count2, double* log_likelihood_ptr /* = NULL */, - const RelatedViewgrams* additive_binwise_correction_ptr, - const RelatedViewgrams* mult_viewgrams_ptr) -{ +void +RPC_process_related_viewgrams_gradient(const shared_ptr& forward_projector_sptr, + const shared_ptr& back_projector_sptr, + RelatedViewgrams* measured_viewgrams_ptr, int& count, int& count2, + double* log_likelihood_ptr /* = NULL */, + const RelatedViewgrams* additive_binwise_correction_ptr, + const RelatedViewgrams* mult_viewgrams_ptr) { assert(measured_viewgrams_ptr != NULL); if (!is_null_ptr(mult_viewgrams_ptr)) error("Internal error: mult_viewgrams_ptr should be zero when computing gradient"); RelatedViewgrams estimated_viewgrams = measured_viewgrams_ptr->get_empty_copy(); - - /*if (distributed::first_iteration) + + /*if (distributed::first_iteration) { stir::RelatedViewgrams::iterator viewgrams_iter = measured_viewgrams_ptr->begin(); stir::RelatedViewgrams::iterator viewgrams_end = measured_viewgrams_ptr->end(); @@ -1226,9 +1050,9 @@ void RPC_process_related_viewgrams_gradient( { printf("\nSLAVE VIEWGRAM\n"); int pos=0; - for ( int tang_pos = -144 ;tang_pos <= 143 ;++tang_pos) + for ( int tang_pos = -144 ;tang_pos <= 143 ;++tang_pos) for ( int ax_pos = 0; ax_pos <= 62 ;++ax_pos) - { + { if (pos>3616 && pos <3632) printf("%f, ",(*viewgrams_iter)[ax_pos][tang_pos]); pos++; } @@ -1237,91 +1061,68 @@ void RPC_process_related_viewgrams_gradient( } */ forward_projector_sptr->forward_project(estimated_viewgrams); - - - - if (additive_binwise_correction_ptr != NULL) - { + + if (additive_binwise_correction_ptr != NULL) { estimated_viewgrams += (*additive_binwise_correction_ptr); } - - - - - // for sinogram division - + divide_and_truncate(*measured_viewgrams_ptr, estimated_viewgrams, rim_truncation_sino, count, count2, log_likelihood_ptr); - - back_projector_sptr->back_project(*measured_viewgrams_ptr); -}; + back_projector_sptr->back_project(*measured_viewgrams_ptr); +}; -void RPC_process_related_viewgrams_accumulate_loglikelihood( - const shared_ptr& forward_projector_sptr, - const shared_ptr& back_projector_sptr, - RelatedViewgrams* measured_viewgrams_ptr, - int& count, int& count2, double* log_likelihood_ptr, - const RelatedViewgrams* additive_binwise_correction_ptr, - const RelatedViewgrams* mult_viewgrams_ptr) -{ +void +RPC_process_related_viewgrams_accumulate_loglikelihood(const shared_ptr& forward_projector_sptr, + const shared_ptr& back_projector_sptr, + RelatedViewgrams* measured_viewgrams_ptr, int& count, int& count2, + double* log_likelihood_ptr, + const RelatedViewgrams* additive_binwise_correction_ptr, + const RelatedViewgrams* mult_viewgrams_ptr) { assert(measured_viewgrams_ptr != NULL); assert(log_likelihood_ptr != NULL); RelatedViewgrams estimated_viewgrams = measured_viewgrams_ptr->get_empty_copy(); forward_projector_sptr->forward_project(estimated_viewgrams); - - if (additive_binwise_correction_ptr != NULL) - { + + if (additive_binwise_correction_ptr != NULL) { estimated_viewgrams += (*additive_binwise_correction_ptr); }; - - if (mult_viewgrams_ptr != NULL) - { + + if (mult_viewgrams_ptr != NULL) { estimated_viewgrams *= (*mult_viewgrams_ptr); } - RelatedViewgrams::iterator meas_viewgrams_iter = - measured_viewgrams_ptr->begin(); - RelatedViewgrams::const_iterator est_viewgrams_iter = - estimated_viewgrams.begin(); + RelatedViewgrams::iterator meas_viewgrams_iter = measured_viewgrams_ptr->begin(); + RelatedViewgrams::const_iterator est_viewgrams_iter = estimated_viewgrams.begin(); // call function that does the actual work, it sits in recon_array_funtions.cxx (TODO) - for (; - meas_viewgrams_iter != measured_viewgrams_ptr->end(); - ++meas_viewgrams_iter, ++est_viewgrams_iter) - accumulate_loglikelihood(*meas_viewgrams_iter, - *est_viewgrams_iter, - rim_truncation_sino, log_likelihood_ptr); -}; - -void RPC_process_related_viewgrams_sensitivity_computation( - const shared_ptr& forward_projector_sptr, - const shared_ptr& back_projector_sptr, - RelatedViewgrams* measured_viewgrams_ptr, - int& count, int& count2, double* log_likelihood_ptr, - const RelatedViewgrams* additive_binwise_correction_ptr, - const RelatedViewgrams* mult_viewgrams_ptr) -{ + for (; meas_viewgrams_iter != measured_viewgrams_ptr->end(); ++meas_viewgrams_iter, ++est_viewgrams_iter) + accumulate_loglikelihood(*meas_viewgrams_iter, *est_viewgrams_iter, rim_truncation_sino, log_likelihood_ptr); +}; + +void +RPC_process_related_viewgrams_sensitivity_computation(const shared_ptr& forward_projector_sptr, + const shared_ptr& back_projector_sptr, + RelatedViewgrams* measured_viewgrams_ptr, int& count, int& count2, + double* log_likelihood_ptr, + const RelatedViewgrams* additive_binwise_correction_ptr, + const RelatedViewgrams* mult_viewgrams_ptr) { assert(measured_viewgrams_ptr != NULL); - if( mult_viewgrams_ptr ) - { + if (mult_viewgrams_ptr) { back_projector_sptr->back_project(*mult_viewgrams_ptr); - } - else - { + } else { back_projector_sptr->back_project(*measured_viewgrams_ptr); } - } -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif +#ifdef _MSC_VER +// prevent warning message on instantiation of abstract class +# pragma warning(disable : 4661) +#endif -template class PoissonLogLikelihoodWithLinearModelForMeanAndProjData >; +template class PoissonLogLikelihoodWithLinearModelForMeanAndProjData>; END_NAMESPACE_STIR diff --git a/src/recon_buildblock/PostsmoothingBackProjectorByBin.cxx b/src/recon_buildblock/PostsmoothingBackProjectorByBin.cxx index cbbb941f88..fcb1460351 100644 --- a/src/recon_buildblock/PostsmoothingBackProjectorByBin.cxx +++ b/src/recon_buildblock/PostsmoothingBackProjectorByBin.cxx @@ -32,23 +32,16 @@ #include "stir/is_null_ptr.h" START_NAMESPACE_STIR -const char * const -PostsmoothingBackProjectorByBin::registered_name = - "Post Smoothing"; - +const char* const PostsmoothingBackProjectorByBin::registered_name = "Post Smoothing"; void -PostsmoothingBackProjectorByBin:: -set_defaults() -{ +PostsmoothingBackProjectorByBin::set_defaults() { original_back_projector_ptr.reset(); _post_data_processor_sptr.reset(); } void -PostsmoothingBackProjectorByBin:: -initialise_keymap() -{ +PostsmoothingBackProjectorByBin::initialise_keymap() { parser.add_start_key("Post Smoothing Back Projector Parameters"); parser.add_stop_key("End Post Smoothing Back Projector Parameters"); parser.add_parsing_key("Original Back projector type", &original_back_projector_ptr); @@ -56,87 +49,86 @@ initialise_keymap() } bool -PostsmoothingBackProjectorByBin:: -post_processing() -{ - if (is_null_ptr(original_back_projector_ptr)) - { +PostsmoothingBackProjectorByBin::post_processing() { + if (is_null_ptr(original_back_projector_ptr)) { warning("Pre Smoothing Back Projector: original back projector needs to be set"); return true; } return false; } -PostsmoothingBackProjectorByBin:: - PostsmoothingBackProjectorByBin() -{ - set_defaults(); +PostsmoothingBackProjectorByBin::PostsmoothingBackProjectorByBin() { set_defaults(); } + +void +PostsmoothingBackProjectorByBin::update_filtered_density_image(DiscretisedDensity<3, float>& density) { + // image_processor_ptr->apply(*filtered_density_sptr); + // density += *filtered_density_sptr; + // filtered_density_sptr->fill(0.f); +} + +BackProjectorByBin* +PostsmoothingBackProjectorByBin::get_original_back_projector_ptr() const { + return original_back_projector_ptr.get(); +} + +PostsmoothingBackProjectorByBin* +PostsmoothingBackProjectorByBin::clone() const { + PostsmoothingBackProjectorByBin* sptr(new PostsmoothingBackProjectorByBin(*this)); + // sptr->original_back_projector_ptr.reset(this->original_back_projector_ptr->clone()); + return sptr; +} + +void +PostsmoothingBackProjectorByBin::init_filtered_density_image(DiscretisedDensity<3, float>& density) { + filtered_density_sptr.reset(density.get_empty_discretised_density()); + assert(density.get_index_range() == filtered_density_sptr->get_index_range()); } -PostsmoothingBackProjectorByBin:: -PostsmoothingBackProjectorByBin( - const shared_ptr& original_back_projector_ptr, - const shared_ptr > >& image_processor_ptr) - : original_back_projector_ptr(original_back_projector_ptr) -{ - _post_data_processor_sptr = image_processor_ptr; +PostsmoothingBackProjectorByBin::PostsmoothingBackProjectorByBin( + const shared_ptr& original_back_projector_ptr, + const shared_ptr>>& image_processor_ptr) + : original_back_projector_ptr(original_back_projector_ptr) { + _post_data_processor_sptr = image_processor_ptr; } -PostsmoothingBackProjectorByBin:: -~PostsmoothingBackProjectorByBin() -{} +PostsmoothingBackProjectorByBin::~PostsmoothingBackProjectorByBin() {} void -PostsmoothingBackProjectorByBin:: -set_up(const shared_ptr& proj_data_info_ptr, - const shared_ptr >& image_info_ptr) -{ +PostsmoothingBackProjectorByBin::set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& image_info_ptr) { BackProjectorByBin::set_up(proj_data_info_ptr, image_info_ptr); original_back_projector_ptr->set_up(proj_data_info_ptr, image_info_ptr); } -const DataSymmetriesForViewSegmentNumbers * -PostsmoothingBackProjectorByBin:: -get_symmetries_used() const -{ +const DataSymmetriesForViewSegmentNumbers* +PostsmoothingBackProjectorByBin::get_symmetries_used() const { return original_back_projector_ptr->get_symmetries_used(); } #ifdef STIR_PROJECTORS_AS_V3 -void -PostsmoothingBackProjectorByBin:: -actual_back_project(DiscretisedDensity<3,float>& density, - const RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - if (!is_null_ptr(image_processor_ptr)) - { - shared_ptr > filtered_density_ptr - (density.get_empty_discretised_density()); - assert(density.get_index_range() == filtered_density_ptr->get_index_range()); - original_back_projector_ptr->back_project(*filtered_density_ptr, viewgrams, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - image_processor_ptr->apply(*filtered_density_ptr); - density += *filtered_density_ptr; - } - else - { - original_back_projector_ptr->back_project(density, viewgrams, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - } +void +PostsmoothingBackProjectorByBin::actual_back_project(DiscretisedDensity<3, float>& density, + const RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { + if (!is_null_ptr(image_processor_ptr)) { + shared_ptr> filtered_density_ptr(density.get_empty_discretised_density()); + assert(density.get_index_range() == filtered_density_ptr->get_index_range()); + original_back_projector_ptr->back_project(*filtered_density_ptr, viewgrams, min_axial_pos_num, max_axial_pos_num, + min_tangential_pos_num, max_tangential_pos_num); + image_processor_ptr->apply(*filtered_density_ptr); + density += *filtered_density_ptr; + } else { + original_back_projector_ptr->back_project(density, viewgrams, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); + } } #endif void -PostsmoothingBackProjectorByBin:: -actual_back_project(const RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - original_back_projector_ptr->back_project(viewgrams, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); +PostsmoothingBackProjectorByBin::actual_back_project(const RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { + original_back_projector_ptr->back_project(viewgrams, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/PresmoothingForwardProjectorByBin.cxx b/src/recon_buildblock/PresmoothingForwardProjectorByBin.cxx index 4d884d4b69..0aec8f6418 100644 --- a/src/recon_buildblock/PresmoothingForwardProjectorByBin.cxx +++ b/src/recon_buildblock/PresmoothingForwardProjectorByBin.cxx @@ -33,23 +33,16 @@ #include "stir/is_null_ptr.h" START_NAMESPACE_STIR -const char * const -PresmoothingForwardProjectorByBin::registered_name = - "Pre Smoothing"; - +const char* const PresmoothingForwardProjectorByBin::registered_name = "Pre Smoothing"; void -PresmoothingForwardProjectorByBin:: -set_defaults() -{ +PresmoothingForwardProjectorByBin::set_defaults() { original_forward_projector_ptr.reset(); _pre_data_processor_sptr.reset(); } void -PresmoothingForwardProjectorByBin:: -initialise_keymap() -{ +PresmoothingForwardProjectorByBin::initialise_keymap() { parser.add_start_key("Pre Smoothing Forward Projector Parameters"); parser.add_stop_key("End Pre Smoothing Forward Projector Parameters"); parser.add_parsing_key("Original Forward projector type", &original_forward_projector_ptr); @@ -57,86 +50,79 @@ initialise_keymap() } bool -PresmoothingForwardProjectorByBin:: -post_processing() -{ - if (is_null_ptr(original_forward_projector_ptr)) - { +PresmoothingForwardProjectorByBin::post_processing() { + if (is_null_ptr(original_forward_projector_ptr)) { warning("Pre Smoothing Forward Projector: original forward projector needs to be set\n"); return true; } return false; } -PresmoothingForwardProjectorByBin:: - PresmoothingForwardProjectorByBin() -{ - set_defaults(); -} +PresmoothingForwardProjectorByBin::PresmoothingForwardProjectorByBin() { set_defaults(); } -PresmoothingForwardProjectorByBin:: -PresmoothingForwardProjectorByBin( - const shared_ptr& original_forward_projector_ptr, - const shared_ptr > >& image_processor_ptr) - : original_forward_projector_ptr(original_forward_projector_ptr) -{ - _pre_data_processor_sptr = image_processor_ptr; +PresmoothingForwardProjectorByBin::PresmoothingForwardProjectorByBin( + const shared_ptr& original_forward_projector_ptr, + const shared_ptr>>& image_processor_ptr) + : original_forward_projector_ptr(original_forward_projector_ptr) { + _pre_data_processor_sptr = image_processor_ptr; } -PresmoothingForwardProjectorByBin:: -~PresmoothingForwardProjectorByBin() -{} +PresmoothingForwardProjectorByBin::~PresmoothingForwardProjectorByBin() {} void -PresmoothingForwardProjectorByBin:: -set_up(const shared_ptr& proj_data_info_ptr, - const shared_ptr >& image_info_ptr) -{ +PresmoothingForwardProjectorByBin::set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& image_info_ptr) { ForwardProjectorByBin::set_up(proj_data_info_ptr, image_info_ptr); original_forward_projector_ptr->set_up(proj_data_info_ptr, image_info_ptr); } -const DataSymmetriesForViewSegmentNumbers * -PresmoothingForwardProjectorByBin:: -get_symmetries_used() const -{ +const DataSymmetriesForViewSegmentNumbers* +PresmoothingForwardProjectorByBin::get_symmetries_used() const { return original_forward_projector_ptr->get_symmetries_used(); } + +// void PresmoothingForwardProjectorByBin:: +// update_filtered_density_image(const DiscretisedDensity<3,float>& density) +//{ +//// filtered_density_sptr.reset(density.get_empty_discretised_density()); +//// image_processor_ptr->apply(*filtered_density_sptr, density); +//// assert(density.get_index_range() == filtered_density_sptr->get_index_range()); +//} + #ifdef STIR_PROJECTORS_AS_V3 -void -PresmoothingForwardProjectorByBin:: -actual_forward_project(RelatedViewgrams& viewgrams, - const DiscretisedDensity<3,float>& density, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) -{ - if (!is_null_ptr(image_processor_ptr)) - { - shared_ptr > filtered_density_ptr(density.get_empty_discretised_density()); - image_processor_ptr->apply(*filtered_density_ptr, density); - assert(density.get_index_range() == filtered_density_ptr->get_index_range()); - original_forward_projector_ptr->forward_project(viewgrams, *filtered_density_ptr, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - } - else - { - original_forward_projector_ptr->forward_project(viewgrams, density, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); - } +void +PresmoothingForwardProjectorByBin::actual_forward_project(RelatedViewgrams& viewgrams, + const DiscretisedDensity<3, float>& density, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, const int max_tangential_pos_num) { + if (!is_null_ptr(image_processor_ptr)) { + shared_ptr> filtered_density_ptr(density.get_empty_discretised_density()); + image_processor_ptr->apply(*filtered_density_ptr, density); + assert(density.get_index_range() == filtered_density_ptr->get_index_range()); + original_forward_projector_ptr->forward_project(viewgrams, *filtered_density_ptr, min_axial_pos_num, max_axial_pos_num, + min_tangential_pos_num, max_tangential_pos_num); + } else { + original_forward_projector_ptr->forward_project(viewgrams, density, min_axial_pos_num, max_axial_pos_num, + min_tangential_pos_num, max_tangential_pos_num); + } } #endif void -PresmoothingForwardProjectorByBin:: -actual_forward_project(RelatedViewgrams& viewgrams, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) +PresmoothingForwardProjectorByBin::actual_forward_project(RelatedViewgrams& viewgrams, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num) { + // No need to do the data processing since it was already done on set_input() + original_forward_projector_ptr->forward_project(viewgrams, min_axial_pos_num, max_axial_pos_num, min_tangential_pos_num, + max_tangential_pos_num); +} + +#if 0 // disabled as currently not used. needs to be written in the new style anyway +void +PresmoothingForwardProjectorByBin::actual_forward_project(Bin&, + const DiscretisedDensity<3,float>&) { - // No need to do the data processing since it was already done on set_input() - original_forward_projector_ptr->forward_project(viewgrams, - min_axial_pos_num, max_axial_pos_num, - min_tangential_pos_num, max_tangential_pos_num); + error("TODO"); } +#endif END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ProjDataRebinning.cxx b/src/recon_buildblock/ProjDataRebinning.cxx index 28c6fc76d6..64ede446eb 100644 --- a/src/recon_buildblock/ProjDataRebinning.cxx +++ b/src/recon_buildblock/ProjDataRebinning.cxx @@ -3,9 +3,9 @@ /*! \file \ingroup recon_buildblock - \brief implementation of the ProjDataRebinning class + \brief implementation of the ProjDataRebinning class \author Kris Thielemans - + */ /* Copyright (C) 2003- 2005, Hammersmith Imanet Ltd @@ -32,45 +32,41 @@ using std::string; START_NAMESPACE_STIR -void -ProjDataRebinning:: -set_defaults() -{ - output_filename_prefix=""; - input_filename=""; - max_segment_num_to_process=-1; +void +ProjDataRebinning::set_defaults() { + output_filename_prefix = ""; + input_filename = ""; + max_segment_num_to_process = -1; } -void -ProjDataRebinning:: -initialise_keymap() -{ - parser.add_key("input file",&input_filename); - //parser.add_key("mash x views", &num_views_to_add); +void +ProjDataRebinning::initialise_keymap() { + parser.add_key("input file", &input_filename); + // parser.add_key("mash x views", &num_views_to_add); parser.add_key("maximum absolute segment number to process", &max_segment_num_to_process); - parser.add_key("output filename prefix",&output_filename_prefix); - + parser.add_key("output filename prefix", &output_filename_prefix); } +bool +ProjDataRebinning::post_processing() { + if (output_filename_prefix.length() == 0) { + warning("You need to specify an output prefix\n"); + return true; + } -bool -ProjDataRebinning:: -post_processing() -{ - if (output_filename_prefix.length() == 0) - { warning("You need to specify an output prefix\n"); return true; } - - if (input_filename.length() == 0) - { warning("You need to specify an input file\n"); return true; } + if (input_filename.length() == 0) { + warning("You need to specify an input file\n"); + return true; + } #if 0 if (num_views_to_add!=1 && (num_views_to_add<=0 || num_views_to_add%2 != 0)) { warning("The 'mash x views' key has an invalid value (must be 1 or even number)\n"); return true; } #endif - - proj_data_sptr= ProjData::read_from_file(input_filename); - + + proj_data_sptr = ProjData::read_from_file(input_filename); + return false; } #if 0 @@ -101,69 +97,55 @@ else } #endif - + Succeeded -ProjDataRebinning:: -set_up() -{ - if (is_null_ptr(proj_data_sptr)) - { - warning("ProjDataRebinning: input projection data not set"); - return Succeeded::no; - } +ProjDataRebinning::set_up() { + if (is_null_ptr(proj_data_sptr)) { + warning("ProjDataRebinning: input projection data not set"); + return Succeeded::no; + } if (max_segment_num_to_process == -1) max_segment_num_to_process = proj_data_sptr->get_max_segment_num(); - else if(max_segment_num_to_process > proj_data_sptr->get_max_segment_num()) - { - warning("ProjDataRebinning: Range error in number of segments to process.\n" - "Max segment number in data is %d while you asked for %d", - proj_data_sptr->get_max_segment_num(), - max_segment_num_to_process); - return Succeeded::no; - } + else if (max_segment_num_to_process > proj_data_sptr->get_max_segment_num()) { + warning("ProjDataRebinning: Range error in number of segments to process.\n" + "Max segment number in data is %d while you asked for %d", + proj_data_sptr->get_max_segment_num(), max_segment_num_to_process); + return Succeeded::no; + } return Succeeded::yes; } -ProjDataRebinning:: -~ProjDataRebinning() -{} +ProjDataRebinning::~ProjDataRebinning() {} -void ProjDataRebinning::set_max_segment_num_to_process(int ns) -{ max_segment_num_to_process = ns; +void +ProjDataRebinning::set_max_segment_num_to_process(int ns) { + max_segment_num_to_process = ns; } -int ProjDataRebinning::get_max_segment_num_to_process() const -{ return max_segment_num_to_process; +int +ProjDataRebinning::get_max_segment_num_to_process() const { + return max_segment_num_to_process; } -void -ProjDataRebinning::set_output_filename_prefix(const string& s) -{ +void +ProjDataRebinning::set_output_filename_prefix(const string& s) { output_filename_prefix = s; } -string -ProjDataRebinning::get_output_filename_prefix() const -{ +string +ProjDataRebinning::get_output_filename_prefix() const { return output_filename_prefix; } - -shared_ptr -ProjDataRebinning:: -get_proj_data_sptr() -{ - /* KT: deleted warning messages about null pointers. - The user should check this, and might not want the have the +shared_ptr +ProjDataRebinning::get_proj_data_sptr() { + /* KT: deleted warning messages about null pointers. + The user should check this, and might not want the have the warnings written to stderr. */ - return proj_data_sptr; - } - + return proj_data_sptr; +} -void -ProjDataRebinning:: -set_input_proj_data_sptr(const shared_ptr& new_proj_data_sptr) -{ +void +ProjDataRebinning::set_input_proj_data_sptr(const shared_ptr& new_proj_data_sptr) { proj_data_sptr = new_proj_data_sptr; -} - +} END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ProjMatrixByBin.cxx b/src/recon_buildblock/ProjMatrixByBin.cxx index 4b06beaee6..d9ede0f986 100644 --- a/src/recon_buildblock/ProjMatrixByBin.cxx +++ b/src/recon_buildblock/ProjMatrixByBin.cxx @@ -2,9 +2,10 @@ \file \ingroup projection - - \brief implementation of the stir::ProjMatrixByBin class - + + \brief implementation of the stir::ProjMatrixByBin class + + \author Nikos Efthimiou \author Mustapha Sadki \author Kris Thielemans \author PARAPET project @@ -13,6 +14,7 @@ Copyright (C) 2000 PARAPET partners Copyright (C) 2000-2009, Hammersmith Imanet Ltd Copyright (C) 2013, 2015 University College London + Copyright (C) 2016, University of Hull This file is part of STIR. @@ -29,85 +31,84 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ProjMatrixByBin.h" #include "stir/recon_buildblock/ProjMatrixElemsForOneBin.h" // define a local preprocessor symbol to keep code relatively clean #ifdef STIR_NO_MUTABLE -#define STIR_MUTABLE_CONST +# define STIR_MUTABLE_CONST #else -#define STIR_MUTABLE_CONST const +# define STIR_MUTABLE_CONST const #endif START_NAMESPACE_STIR -void ProjMatrixByBin::set_defaults() -{ - cache_disabled=false; - cache_stores_only_basic_bins=true; +void +ProjMatrixByBin::set_defaults() { + cache_disabled = false; + cache_stores_only_basic_bins = true; + gauss_sigma_in_mm = 0.f; + r_sqrt2_gauss_sigma = 0.f; } -void -ProjMatrixByBin::initialise_keymap() -{ +void +ProjMatrixByBin::initialise_keymap() { parser.add_key("disable caching", &cache_disabled); parser.add_key("store_only_basic_bins_in_cache", &cache_stores_only_basic_bins); } bool -ProjMatrixByBin::post_processing() -{ +ProjMatrixByBin::post_processing() { return false; } -ProjMatrixByBin::ProjMatrixByBin() -{ - set_defaults(); +ProjMatrixByBin::ProjMatrixByBin() { set_defaults(); } + +void +ProjMatrixByBin::enable_cache(const bool v) { + cache_disabled = !v; } - -void -ProjMatrixByBin:: -enable_cache(const bool v) -{ cache_disabled = !v;} -void -ProjMatrixByBin:: -store_only_basic_bins_in_cache(const bool v) -{ cache_stores_only_basic_bins=v;} +void +ProjMatrixByBin::enable_tof(const shared_ptr& _proj_data_info_sptr, const bool v) { + if (v) { + tof_enabled = true; + proj_data_info_sptr = _proj_data_info_sptr; + gauss_sigma_in_mm = + ProjDataInfo::tof_delta_time_to_mm(proj_data_info_sptr->get_scanner_ptr()->get_timing_resolution()) / 2.355f; + r_sqrt2_gauss_sigma = 1.0f / (gauss_sigma_in_mm * static_cast(sqrt(2.0))); + } +} -bool -ProjMatrixByBin:: -is_cache_enabled() const -{ return !cache_disabled; } +void +ProjMatrixByBin::store_only_basic_bins_in_cache(const bool v) { + cache_stores_only_basic_bins = v; +} -bool -ProjMatrixByBin:: -does_cache_store_only_basic_bins() const -{ return cache_stores_only_basic_bins; } +bool +ProjMatrixByBin::is_cache_enabled() const { + return !cache_disabled; +} -void -ProjMatrixByBin:: -clear_cache() STIR_MUTABLE_CONST -{ +bool +ProjMatrixByBin::does_cache_store_only_basic_bins() const { + return cache_stores_only_basic_bins; +} + +void +ProjMatrixByBin::clear_cache() STIR_MUTABLE_CONST { #ifdef STIR_OPENMP -#pragma omp critical(PROJMATRIXBYBINCLEARCACHE) +# pragma omp critical(PROJMATRIXBYBINCLEARCACHE) #endif - for (int i=this->cache_collection.get_min_index(); - i<=this->cache_collection.get_max_index(); - ++i) - { - for (int j=this->cache_collection[i].get_min_index(); - j<=this->cache_collection[i].get_max_index(); - ++j) - { - this->cache_collection[i][j].clear(); - } + for (int i = this->cache_collection.get_min_index(); i <= this->cache_collection.get_max_index(); ++i) { + for (int j = this->cache_collection[i].get_min_index(); j <= this->cache_collection[i].get_max_index(); ++j) { + this->cache_collection[i][j].clear(); } + } } /* -void +void ProjMatrixByBin:: reserve_num_elements_in_cache(const std::size_t num_elems) { @@ -118,17 +119,21 @@ reserve_num_elements_in_cache(const std::size_t num_elems) */ void -ProjMatrixByBin:: -set_up( - const shared_ptr& proj_data_info_sptr, - const shared_ptr >& /*density_info_ptr*/ // TODO should be Info only - ) -{ +ProjMatrixByBin::set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& /*density_info_ptr*/ // TODO should be Info only +) { const int min_view_num = proj_data_info_sptr->get_min_view_num(); const int max_view_num = proj_data_info_sptr->get_max_view_num(); const int min_segment_num = proj_data_info_sptr->get_min_segment_num(); const int max_segment_num = proj_data_info_sptr->get_max_segment_num(); + if (proj_data_info_sptr->is_tof_data()) + enable_tof(proj_data_info_sptr, true); + else { + tof_enabled = false; + this->proj_data_info_sptr = proj_data_info_sptr; + } + this->cache_collection.recycle(); this->cache_collection.resize(min_view_num, max_view_num); #ifdef STIR_OPENMP @@ -136,113 +141,94 @@ set_up( this->cache_locks.resize(min_view_num, max_view_num); #endif - for (int view_num=min_view_num; view_num<=max_view_num; ++view_num) - { - this->cache_collection[view_num].resize(min_segment_num, max_segment_num); + for (int view_num = min_view_num; view_num <= max_view_num; ++view_num) { + this->cache_collection[view_num].resize(min_segment_num, max_segment_num); #ifdef STIR_OPENMP - this->cache_locks[view_num].resize(min_segment_num, max_segment_num); - for (int seg_num = min_segment_num; seg_num <=max_segment_num; ++seg_num) - omp_init_lock(&this->cache_locks[view_num][seg_num]); + this->cache_locks[view_num].resize(min_segment_num, max_segment_num); + for (int seg_num = min_segment_num; seg_num <= max_segment_num; ++seg_num) + omp_init_lock(&this->cache_locks[view_num][seg_num]); #endif - } + } } - /*! \warning Preconditions
  • abs(axial_pos_num) fits in 17 bits -
  • abs(tangential_pos_num) fits in 11 bits +
  • abs(tangential_pos_num) fits in 11 bits */ ProjMatrixByBin::CacheKey -ProjMatrixByBin::cache_key(const Bin& bin) const -{ - assert(static_cast(abs(bin.axial_pos_num())) < (static_cast(1)<<18)); - assert(abs(bin.tangential_pos_num()) < (1<<12)); - return (CacheKey)( - (static_cast(bin.axial_pos_num()>=0?0:1) << 31) - | (static_cast(abs(bin.axial_pos_num()))<<13) - | (static_cast(bin.tangential_pos_num()>=0?0:1) << 12) - | static_cast(abs(bin.tangential_pos_num())) ); -} +ProjMatrixByBin::cache_key(const Bin& bin) const { + assert(static_cast(abs(bin.axial_pos_num())) < (static_cast(1) << 18)); + assert(abs(bin.tangential_pos_num()) < (1 << 12)); + return (CacheKey)((static_cast(bin.axial_pos_num() >= 0 ? 0 : 1) << 31) | + (static_cast(abs(bin.axial_pos_num())) << 13) | + (static_cast(bin.tangential_pos_num() >= 0 ? 0 : 1) << 12) | + static_cast(abs(bin.tangential_pos_num()))); +} +void +ProjMatrixByBin::cache_proj_matrix_elems_for_one_bin(const ProjMatrixElemsForOneBin& probabilities) STIR_MUTABLE_CONST { + if (cache_disabled) + return; -void -ProjMatrixByBin:: -cache_proj_matrix_elems_for_one_bin( - const ProjMatrixElemsForOneBin& probabilities) STIR_MUTABLE_CONST -{ - if ( cache_disabled ) return; - - //std::cerr << "cached lor size " << probabilities.size() << " capacity " << probabilities.capacity() << std::endl; - // insert probabilities into the collection + // std::cerr << "cached lor size " << probabilities.size() << " capacity " << probabilities.capacity() << std::endl; + // insert probabilities into the collection const Bin bin = probabilities.get_bin(); #ifdef STIR_OPENMP omp_set_lock(&this->cache_locks[bin.view_num()][bin.segment_num()]); #endif - cache_collection[bin.view_num()][bin.segment_num()].insert(MapProjMatrixElemsForOneBin::value_type( cache_key(bin), - probabilities)); + cache_collection[bin.view_num()][bin.segment_num()].insert( + MapProjMatrixElemsForOneBin::value_type(cache_key(bin), probabilities)); #ifdef STIR_OPENMP omp_unset_lock(&this->cache_locks[bin.view_num()][bin.segment_num()]); #endif } - -Succeeded -ProjMatrixByBin:: -get_cached_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& probabilities) const -{ - if ( cache_disabled ) +Succeeded +ProjMatrixByBin::get_cached_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& probabilities) const { + if (cache_disabled) return Succeeded::no; - + const Bin bin = probabilities.get_bin(); #ifndef NDEBUG - if (cache_stores_only_basic_bins) - { + if (cache_stores_only_basic_bins) { // Check that this is a 'basic' coordinate - Bin bin_copy = bin; - assert ( symmetries_sptr->find_basic_bin(bin_copy) == 0); + Bin bin_copy = bin; + assert(symmetries_sptr->find_basic_bin(bin_copy) == 0); } -#endif - - bool found=false; +#endif + + bool found = false; #ifdef STIR_OPENMP omp_set_lock(&this->cache_locks[bin.view_num()][bin.segment_num()]); #endif { - const_MapProjMatrixElemsForOneBinIterator pos = - cache_collection[bin.view_num()][bin.segment_num()].find(cache_key( bin)); - - if ( pos != cache_collection[bin.view_num()][bin.segment_num()]. end()) - { - //cout << Key << " =========>> entry found in cache " << endl; - probabilities = pos->second; - // note: cannot return from inside an OPENMP critical section - //return Succeeded::yes; - found=true; - } + const_MapProjMatrixElemsForOneBinIterator pos = cache_collection[bin.view_num()][bin.segment_num()].find(cache_key(bin)); + + if (pos != cache_collection[bin.view_num()][bin.segment_num()].end()) { + // cout << Key << " =========>> entry found in cache " << endl; + probabilities = pos->second; + // note: cannot return from inside an OPENMP critical section + // return Succeeded::yes; + found = true; + } } #ifdef STIR_OPENMP omp_unset_lock(&this->cache_locks[bin.view_num()][bin.segment_num()]); #endif if (found) - return Succeeded::yes; - else - { - //cout << " This entry is not in the cache :" << Key << endl; - return Succeeded::no; - } + return Succeeded::yes; + else { + // cout << " This entry is not in the cache :" << Key << endl; + return Succeeded::no; + } } +// TODO - -//TODO - - - -////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// #if 0 // KT moved here //! store the projection matrix to the file by rows @@ -293,8 +279,6 @@ void ProjMatrixByBin::write_to_file_by_bin( cout << "End of write_to_file_by_bin " << endl; } - #endif - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ProjMatrixByBinFromFile.cxx b/src/recon_buildblock/ProjMatrixByBinFromFile.cxx index 79cae0d957..7775cbe064 100644 --- a/src/recon_buildblock/ProjMatrixByBinFromFile.cxx +++ b/src/recon_buildblock/ProjMatrixByBinFromFile.cxx @@ -51,21 +51,12 @@ using std::string; START_NAMESPACE_STIR +const char* const ProjMatrixByBinFromFile::registered_name = "From File"; -const char * const -ProjMatrixByBinFromFile::registered_name = -"From File"; +ProjMatrixByBinFromFile::ProjMatrixByBinFromFile() { set_defaults(); } -ProjMatrixByBinFromFile:: -ProjMatrixByBinFromFile() -{ - set_defaults(); -} - -void -ProjMatrixByBinFromFile:: -initialise_keymap() -{ +void +ProjMatrixByBinFromFile::initialise_keymap() { parser.add_start_key("Projection Matrix By Bin From File Parameters"); ProjMatrixByBin::initialise_keymap(); @@ -74,28 +65,26 @@ initialise_keymap() parser.add_key("data_filename", &data_filename); parser.add_key("Version", &this->parsed_version); - parser.add_key("symmetries type", &this->symmetries_type) ; - - //parser.add_key("PET_CartesianGrid symmetries parameters", + parser.add_key("symmetries type", &this->symmetries_type); + + // parser.add_key("PET_CartesianGrid symmetries parameters", // KeyArgument::NONE, &KeyParser::do_nothing); parser.add_key("do_symmetry_90degrees_min_phi", &do_symmetry_90degrees_min_phi); parser.add_key("do_symmetry_180degrees_min_phi", &do_symmetry_180degrees_min_phi); parser.add_key("do_symmetry_swap_segment", &do_symmetry_swap_segment); parser.add_key("do_symmetry_swap_s", &do_symmetry_swap_s); parser.add_key("do_symmetry_shift_z", &do_symmetry_shift_z); - //parser.add_key("End PET_CartesianGrid symmetries parameters", + // parser.add_key("End PET_CartesianGrid symmetries parameters", // KeyArgument::NONE, &KeyParser::do_nothing); parser.add_stop_key("End Projection Matrix By Bin From File Parameters"); } - void -ProjMatrixByBinFromFile::set_defaults() -{ +ProjMatrixByBinFromFile::set_defaults() { ProjMatrixByBin::set_defaults(); - template_density_filename=""; - template_proj_data_filename=""; - data_filename=""; + template_density_filename = ""; + template_proj_data_filename = ""; + data_filename = ""; do_symmetry_90degrees_min_phi = true; do_symmetry_180degrees_min_phi = true; @@ -104,95 +93,70 @@ ProjMatrixByBinFromFile::set_defaults() do_symmetry_shift_z = true; } - bool -ProjMatrixByBinFromFile::post_processing() -{ +ProjMatrixByBinFromFile::post_processing() { if (ProjMatrixByBin::post_processing() == true) return true; - if (this->parsed_version != "1.0") - { - warning("version has to be 1.0"); - return true; - } + if (this->parsed_version != "1.0") { + warning("version has to be 1.0"); + return true; + } this->symmetries_type = standardise_interfile_keyword(this->symmetries_type); - if (this->symmetries_type != standardise_interfile_keyword("PET_CartesianGrid") && this->symmetries_type != "none") - { - warning("symmetries type has to be PET_CartesianGrid or None"); - return true; - } + if (this->symmetries_type != standardise_interfile_keyword("PET_CartesianGrid") && this->symmetries_type != "none") { + warning("symmetries type has to be PET_CartesianGrid or None"); + return true; + } - if (template_density_filename.size()==0) - { - warning("template_density_filename has to be specified.\n"); - return true; - } - if (template_proj_data_filename.size()==0) - { - warning("template_proj_data_filename has to be specified.\n"); - return true; - } - if (data_filename.size()==0) - { - warning("data_filename has to be specified.\n"); - return true; - } + if (template_density_filename.size() == 0) { + warning("template_density_filename has to be specified.\n"); + return true; + } + if (template_proj_data_filename.size() == 0) { + warning("template_proj_data_filename has to be specified.\n"); + return true; + } + if (data_filename.size() == 0) { + warning("data_filename has to be specified.\n"); + return true; + } { - shared_ptr proj_data_sptr = - ProjData::read_from_file(template_proj_data_filename); + shared_ptr proj_data_sptr = ProjData::read_from_file(template_proj_data_filename); this->proj_data_info_ptr.reset(proj_data_sptr->get_proj_data_info_sptr()->clone()); } - shared_ptr > - density_info_sptr(read_from_file >(template_density_filename)); + shared_ptr> density_info_sptr( + read_from_file>(template_density_filename)); { - const VoxelsOnCartesianGrid * image_info_ptr = - dynamic_cast*> (density_info_sptr.get()); + const VoxelsOnCartesianGrid* image_info_ptr = + dynamic_cast*>(density_info_sptr.get()); if (image_info_ptr == NULL) error("ProjMatrixByBinFromFile initialised with a wrong type of DiscretisedDensity"); - + densel_range = image_info_ptr->get_index_range(); voxel_size = image_info_ptr->get_voxel_size(); origin = image_info_ptr->get_origin(); } - - - if (this->symmetries_type == standardise_interfile_keyword("PET_CartesianGrid")) - { - symmetries_sptr.reset( - new DataSymmetriesForBins_PET_CartesianGrid(proj_data_info_ptr, - density_info_sptr, - do_symmetry_90degrees_min_phi, - do_symmetry_180degrees_min_phi, - do_symmetry_swap_segment, - do_symmetry_swap_s, - do_symmetry_shift_z)); - } - else if (this->symmetries_type == "none") - { - symmetries_sptr.reset(new TrivialDataSymmetriesForBins(proj_data_info_ptr)); - } - else - { - error("internal error: symmetries handling in ProjMatrixByBinFromFile"); - } + if (this->symmetries_type == standardise_interfile_keyword("PET_CartesianGrid")) { + symmetries_sptr.reset(new DataSymmetriesForBins_PET_CartesianGrid( + proj_data_info_ptr, density_info_sptr, do_symmetry_90degrees_min_phi, do_symmetry_180degrees_min_phi, + do_symmetry_swap_segment, do_symmetry_swap_s, do_symmetry_shift_z)); + } else if (this->symmetries_type == "none") { + symmetries_sptr.reset(new TrivialDataSymmetriesForBins(proj_data_info_ptr)); + } else { + error("internal error: symmetries handling in ProjMatrixByBinFromFile"); + } return false; } - void -ProjMatrixByBinFromFile:: -set_up( - const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) -{ +ProjMatrixByBinFromFile::set_up(const shared_ptr& proj_data_info_ptr_v, + const shared_ptr>& density_info_ptr // TODO should be Info only +) { - const VoxelsOnCartesianGrid * image_info_ptr = - dynamic_cast*> (density_info_ptr.get()); + const VoxelsOnCartesianGrid* image_info_ptr = dynamic_cast*>(density_info_ptr.get()); if (image_info_ptr == NULL) error("ProjMatrixByBinFromFile set-up with a wrong type of DiscretisedDensity\n"); @@ -208,7 +172,7 @@ set_up( /* do consistency checks on projection data. It's safe as long as the stored range is larger than what we need. */ - if (!( *this->proj_data_info_ptr >= *proj_data_info_ptr_v)) + if (!(*this->proj_data_info_ptr >= *proj_data_info_ptr_v)) error("ProjMatrixByBinFromFile set-up with proj data with wrong characteristics"); // note: currently setting up with proj_data_info stored in the file @@ -216,147 +180,143 @@ set_up( // every LOR that's in the file in the cache ProjMatrixByBin::set_up(this->proj_data_info_ptr, density_info_ptr); - if (read_data() ==Succeeded::no) + if (read_data() == Succeeded::no) error("Something wrong reading the matrix from file. Exiting."); } +ProjMatrixByBinFromFile* +ProjMatrixByBinFromFile::clone() const { + return new ProjMatrixByBinFromFile(*this); +} + // anonymous namespace for local functions namespace { - // static (i.e. private) function to write the data - static Succeeded - write_lor(std::ostream&fst, const ProjMatrixElemsForOneBin& lor) - { - const Bin bin = lor.get_bin(); - { - boost::int32_t c; - c = bin.segment_num(); fst.write ( (char*)&c, sizeof(boost::int32_t)); - c = bin.view_num(); fst.write ( (char*)&c, sizeof(boost::int32_t)); - c = bin.axial_pos_num(); fst.write ( (char*)&c, sizeof(boost::int32_t)); - c = bin.tangential_pos_num(); fst.write ( (char*)&c, sizeof(boost::int32_t)); - } - { - boost::uint32_t c= static_cast(lor.size()); - fst.write( (char*)&c , sizeof(boost::uint32_t)); - } +// static (i.e. private) function to write the data +static Succeeded +write_lor(std::ostream& fst, const ProjMatrixElemsForOneBin& lor) { + const Bin bin = lor.get_bin(); + { + boost::int32_t c; + c = bin.segment_num(); + fst.write((char*)&c, sizeof(boost::int32_t)); + c = bin.view_num(); + fst.write((char*)&c, sizeof(boost::int32_t)); + c = bin.axial_pos_num(); + fst.write((char*)&c, sizeof(boost::int32_t)); + c = bin.tangential_pos_num(); + fst.write((char*)&c, sizeof(boost::int32_t)); + } + { + boost::uint32_t c = static_cast(lor.size()); + fst.write((char*)&c, sizeof(boost::uint32_t)); + } + if (!fst) + return Succeeded::no; + ProjMatrixElemsForOneBin::const_iterator element_ptr = lor.begin(); + // todo add compression in this loop + while (element_ptr != lor.end()) { + boost::int16_t c; + c = static_cast(element_ptr->coord1()); + fst.write((char*)&c, sizeof(boost::int16_t)); + c = static_cast(element_ptr->coord2()); + fst.write((char*)&c, sizeof(boost::int16_t)); + c = static_cast(element_ptr->coord3()); + fst.write((char*)&c, sizeof(boost::int16_t)); + const float value = element_ptr->get_value(); + fst.write((char*)&value, sizeof(float)); if (!fst) return Succeeded::no; - ProjMatrixElemsForOneBin::const_iterator element_ptr = lor.begin(); - // todo add compression in this loop - while (element_ptr != lor.end()) - { - boost::int16_t c; - c = static_cast(element_ptr->coord1()); - fst.write ( (char*)&c, sizeof(boost::int16_t)); - c = static_cast(element_ptr->coord2()); - fst.write ( (char*)&c, sizeof(boost::int16_t)); - c = static_cast(element_ptr->coord3()); - fst.write ( (char*)&c, sizeof(boost::int16_t)); - const float value = element_ptr->get_value(); - fst.write ( (char*)&value, sizeof(float)); - if (!fst) - return Succeeded::no; - - ++element_ptr; - } - return Succeeded::yes; - } - - // return type for read_lor() - class readReturnType - { - public: - enum value { ok, eof, problem }; - readReturnType(const value& v) : v(v) {} - bool operator==(const readReturnType &v2) const { return v == v2.v; } - bool operator!=(const readReturnType &v2) const { return v != v2.v; } - private: - value v; - }; - - // static (i.e. private) function to read an lor - static - readReturnType - read_lor(std::istream&fst, ProjMatrixElemsForOneBin& lor ) - { - lor.erase(); - - { - Bin bin; - boost::int32_t c; - fst.read( (char*)&c, sizeof(boost::int32_t)); bin.segment_num()=c; - if (fst.gcount()==0 && fst.eof()) - { - // we were at EOF - return readReturnType::eof; - } - - fst.read( (char*)&c, sizeof(boost::int32_t)); bin.view_num()=c; - fst.read( (char*)&c, sizeof(boost::int32_t)); bin.axial_pos_num()=c; - fst.read( (char*)&c, sizeof(boost::int32_t)); bin.tangential_pos_num()=c; - bin.set_bin_value(0); - lor.set_bin(bin); - // info(boost::format("Read bin (s:%d,a:%d,v:%d,t:%d)") % - // bin.segment_num()%bin.axial_pos_num()%bin.view_num()%bin.tangential_pos_num()); + ++element_ptr; + } + return Succeeded::yes; +} + +// return type for read_lor() +class readReturnType { +public: + enum value { ok, eof, problem }; + readReturnType(const value& v) : v(v) {} + bool operator==(const readReturnType& v2) const { return v == v2.v; } + bool operator!=(const readReturnType& v2) const { return v != v2.v; } + +private: + value v; +}; + +// static (i.e. private) function to read an lor +static readReturnType +read_lor(std::istream& fst, ProjMatrixElemsForOneBin& lor) { + lor.erase(); + + { + Bin bin; + boost::int32_t c; + fst.read((char*)&c, sizeof(boost::int32_t)); + bin.segment_num() = c; + if (fst.gcount() == 0 && fst.eof()) { + // we were at EOF + return readReturnType::eof; } - boost::uint32_t count; - fst.read ( (char*)&count, sizeof(boost::uint32_t)); - if (!fst || fst.gcount() != 4) - return readReturnType::problem; + fst.read((char*)&c, sizeof(boost::int32_t)); + bin.view_num() = c; + fst.read((char*)&c, sizeof(boost::int32_t)); + bin.axial_pos_num() = c; + fst.read((char*)&c, sizeof(boost::int32_t)); + bin.tangential_pos_num() = c; + bin.set_bin_value(0); + lor.set_bin(bin); + // info(boost::format("Read bin (s:%d,a:%d,v:%d,t:%d)") % + // bin.segment_num()%bin.axial_pos_num()%bin.view_num()%bin.tangential_pos_num()); + } + boost::uint32_t count; + fst.read((char*)&count, sizeof(boost::uint32_t)); - if (count>10000) - error("Unbelievably high count of voxels in LOR: %d", count); - - lor.reserve(count); - - for ( boost::uint32_t i=0; i < count; ++i) - { - boost::int16_t c1,c2,c3; - fst.read ( (char*)&c1, sizeof(boost::int16_t)); - fst.read ( (char*)&c2, sizeof(boost::int16_t)); - fst.read ( (char*)&c3, sizeof(boost::int16_t)); - float value; - fst.read ( (char*)&value, sizeof(float)); - - if (!fst) - return readReturnType::problem; - const ProjMatrixElemsForOneBin::value_type - elem(Coordinate3D(c1,c2,c3), value); - lor.push_back( elem); - } - return readReturnType::ok; + if (!fst || fst.gcount() != 4) + return readReturnType::problem; + + if (count > 10000) + error("Unbelievably high count of voxels in LOR: %d", count); + + lor.reserve(count); + + for (boost::uint32_t i = 0; i < count; ++i) { + boost::int16_t c1, c2, c3; + fst.read((char*)&c1, sizeof(boost::int16_t)); + fst.read((char*)&c2, sizeof(boost::int16_t)); + fst.read((char*)&c3, sizeof(boost::int16_t)); + float value; + fst.read((char*)&value, sizeof(float)); + + if (!fst) + return readReturnType::problem; + const ProjMatrixElemsForOneBin::value_type elem(Coordinate3D(c1, c2, c3), value); + lor.push_back(elem); } + return readReturnType::ok; +} } // end of anonymous namespace - + Succeeded -ProjMatrixByBinFromFile:: -write_to_file(const std::string& output_filename_prefix, - const ProjMatrixByBin& proj_matrix, - const shared_ptr& proj_data_info_sptr, - const DiscretisedDensity<3,float>& template_density) -{ - - string template_density_filename = - output_filename_prefix + "_template_density"; +ProjMatrixByBinFromFile::write_to_file(const std::string& output_filename_prefix, const ProjMatrixByBin& proj_matrix, + const shared_ptr& proj_data_info_sptr, + const DiscretisedDensity<3, float>& template_density) { + + string template_density_filename = output_filename_prefix + "_template_density"; { - if (OutputFileFormat >::default_sptr()-> - write_to_file(template_density_filename, - template_density) != Succeeded::yes) - { - warning("Error writing template image"); - return Succeeded::no; - } + if (OutputFileFormat>::default_sptr()->write_to_file(template_density_filename, + template_density) != Succeeded::yes) { + warning("Error writing template image"); + return Succeeded::no; + } } - string template_proj_data_filename = - output_filename_prefix + "_template_proj_data"; + string template_proj_data_filename = output_filename_prefix + "_template_proj_data"; { // the following constructor will write an interfile header (and empty data) to disk shared_ptr exam_info_sptr(new ExamInfo); - ProjDataInterfile template_projdata(exam_info_sptr, - proj_data_info_sptr, - template_proj_data_filename); + ProjDataInterfile template_projdata(exam_info_sptr, proj_data_info_sptr, template_proj_data_filename); } string header_filename = output_filename_prefix; @@ -366,42 +326,33 @@ write_to_file(const std::string& output_filename_prefix, { std::ofstream header(header_filename.c_str()); - if (!header) - { - warning("Error opening header %s", - header_filename.c_str()); - return Succeeded::no; - } + if (!header) { + warning("Error opening header %s", header_filename.c_str()); + return Succeeded::no; + } header << "Projection Matrix By Bin From File Parameters:=\n" - << "Version := 1.0\n"; + << "Version := 1.0\n"; // TODO symmetries should not be hard-coded - if (!is_null_ptr(dynamic_cast(proj_matrix.get_symmetries_ptr()))) - { - const DataSymmetriesForBins_PET_CartesianGrid& symmetries = - dynamic_cast - (*proj_matrix.get_symmetries_ptr()); - - header << "symmetries type := PET_CartesianGrid\n" - << " PET_CartesianGrid symmetries parameters:=\n" - << " do_symmetry_90degrees_min_phi:= " << (symmetries.using_symmetry_90degrees_min_phi() ? 1 : 0) << '\n' - << " do_symmetry_180degrees_min_phi:= " << (symmetries.using_symmetry_180degrees_min_phi() ? 1 : 0) << '\n' - << " do_symmetry_swap_segment:= " << (symmetries.using_symmetry_swap_segment() ? 1 : 0) << '\n' - << " do_symmetry_swap_s:= " << (symmetries.using_symmetry_swap_s() ? 1 : 0) << '\n' - << " do_symmetry_shift_z:= " << (symmetries.using_symmetry_shift_z() ? 1 : 0) << '\n' - << " End PET_CartesianGrid symmetries parameters:=\n"; - } - else if (!is_null_ptr(dynamic_cast(proj_matrix.get_symmetries_ptr()))) - { - header << "symmetries type := none\n"; - } - else - { - warning("ProjMatrixByBinFromFile does not yet support this type of symmetries. sorry"); - return Succeeded::no; - } - - + if (!is_null_ptr(dynamic_cast(proj_matrix.get_symmetries_ptr()))) { + const DataSymmetriesForBins_PET_CartesianGrid& symmetries = + dynamic_cast(*proj_matrix.get_symmetries_ptr()); + + header << "symmetries type := PET_CartesianGrid\n" + << " PET_CartesianGrid symmetries parameters:=\n" + << " do_symmetry_90degrees_min_phi:= " << (symmetries.using_symmetry_90degrees_min_phi() ? 1 : 0) << '\n' + << " do_symmetry_180degrees_min_phi:= " << (symmetries.using_symmetry_180degrees_min_phi() ? 1 : 0) << '\n' + << " do_symmetry_swap_segment:= " << (symmetries.using_symmetry_swap_segment() ? 1 : 0) << '\n' + << " do_symmetry_swap_s:= " << (symmetries.using_symmetry_swap_s() ? 1 : 0) << '\n' + << " do_symmetry_shift_z:= " << (symmetries.using_symmetry_shift_z() ? 1 : 0) << '\n' + << " End PET_CartesianGrid symmetries parameters:=\n"; + } else if (!is_null_ptr(dynamic_cast(proj_matrix.get_symmetries_ptr()))) { + header << "symmetries type := none\n"; + } else { + warning("ProjMatrixByBinFromFile does not yet support this type of symmetries. sorry"); + return Succeeded::no; + } + header << "template proj data filename:=" << template_proj_data_filename << '\n'; header << "template density filename:=" << template_density_filename << '\n'; @@ -412,7 +363,7 @@ write_to_file(const std::string& output_filename_prefix, std::ofstream fst; open_write_binary(fst, data_filename.c_str()); - + // loop over bins // the complication here is that we cannot just test if each bin in the range is 'basic' // and write only those. The reason is that symmetry operations can construct a @@ -421,9 +372,9 @@ write_to_file(const std::string& output_filename_prefix, // The complication is then that we need to keep track which one we wrote already. // Originally, I did this via a std::list. Checking if a bin was already written // is terribly slow however. Instead, I currently use a vector of shared_ptrs. - // This wastes only a little bit of memory, but the bounds are difficult to + // This wastes only a little bit of memory, but the bounds are difficult to // determine in general. - // A better approach (and simpler) would be to have access to the internal cache of the + // A better approach (and simpler) would be to have access to the internal cache of the // projection matrix. { // defined here to avoid reallocation for every bin @@ -433,31 +384,25 @@ write_to_file(const std::string& output_filename_prefix, std::list already_processed; #else typedef VectorWithOffset tpos_t; - typedef VectorWithOffset > vpos_t; - typedef VectorWithOffset > apos_t; - typedef VectorWithOffset > spos_t; + typedef VectorWithOffset> vpos_t; + typedef VectorWithOffset> apos_t; + typedef VectorWithOffset> spos_t; // vector that will contain (vectors of bools) to check if we wrote a bin already or not // upper boundary takes into account that symmetries convert negative segment_num to positive - spos_t already_processed(proj_data_info_sptr->get_min_segment_num(), - std::max(proj_data_info_sptr->get_max_segment_num(), - -proj_data_info_sptr->get_min_segment_num())); + spos_t already_processed(proj_data_info_sptr->get_min_segment_num(), + std::max(proj_data_info_sptr->get_max_segment_num(), -proj_data_info_sptr->get_min_segment_num())); #endif - for (int segment_num = proj_data_info_sptr->get_min_segment_num(); - segment_num <= proj_data_info_sptr->get_max_segment_num(); - ++segment_num) - for (int axial_pos_num = proj_data_info_sptr->get_min_axial_pos_num(segment_num); - axial_pos_num <= proj_data_info_sptr->get_max_axial_pos_num(segment_num); - ++axial_pos_num) - for (int view_num = proj_data_info_sptr->get_min_view_num(); - view_num <= proj_data_info_sptr->get_max_view_num(); - ++view_num) - for (int tang_pos_num = proj_data_info_sptr->get_min_tangential_pos_num(); - tang_pos_num <= proj_data_info_sptr->get_max_tangential_pos_num(); - ++tang_pos_num) - { - Bin bin(segment_num,view_num, axial_pos_num, tang_pos_num); - proj_matrix.get_symmetries_ptr()->find_basic_bin(bin); + for (int segment_num = proj_data_info_sptr->get_min_segment_num(); segment_num <= proj_data_info_sptr->get_max_segment_num(); + ++segment_num) + for (int axial_pos_num = proj_data_info_sptr->get_min_axial_pos_num(segment_num); + axial_pos_num <= proj_data_info_sptr->get_max_axial_pos_num(segment_num); ++axial_pos_num) + for (int view_num = proj_data_info_sptr->get_min_view_num(); view_num <= proj_data_info_sptr->get_max_view_num(); + ++view_num) + for (int tang_pos_num = proj_data_info_sptr->get_min_tangential_pos_num(); + tang_pos_num <= proj_data_info_sptr->get_max_tangential_pos_num(); ++tang_pos_num) { + Bin bin(segment_num, view_num, axial_pos_num, tang_pos_num); + proj_matrix.get_symmetries_ptr()->find_basic_bin(bin); #if 0 if (std::find(already_processed.begin(), already_processed.end(), bin) != already_processed.end()) @@ -465,73 +410,61 @@ write_to_file(const std::string& output_filename_prefix, already_processed.push_back(bin); #else - if (is_null_ptr(already_processed[bin.segment_num()])) - { - // range attempts to take into account that symmetries normally bring axial_pos_num back to 0 or 1 - already_processed[bin.segment_num()]. - reset(new apos_t(std::min(0,proj_data_info_sptr->get_min_axial_pos_num(bin.segment_num())), - std::max(1,proj_data_info_sptr->get_max_axial_pos_num(bin.segment_num())))); - } - if (is_null_ptr((*already_processed[bin.segment_num()])[bin.axial_pos_num()])) - { - (*already_processed[bin.segment_num()])[bin.axial_pos_num()]. - reset(new vpos_t(proj_data_info_sptr->get_min_view_num(), - proj_data_info_sptr->get_max_view_num())); - } - if (is_null_ptr((*(*already_processed[bin.segment_num()])[bin.axial_pos_num()])[bin.view_num()])) - { - // range takes into account that symmetries bring negative tangential_pos_num to positive - (*(*already_processed[bin.segment_num()])[bin.axial_pos_num()])[bin.view_num()]. - reset(new tpos_t(proj_data_info_sptr->get_min_tangential_pos_num(), - std::max(proj_data_info_sptr->get_max_tangential_pos_num(), - -proj_data_info_sptr->get_min_tangential_pos_num()))); - (*(*already_processed[bin.segment_num()])[bin.axial_pos_num()])[bin.view_num()]->fill(false); - } - if ((*(*(*already_processed[bin.segment_num()])[bin.axial_pos_num()])[bin.view_num()])[bin.tangential_pos_num()]) - continue; - - (*(*(*already_processed[bin.segment_num()])[bin.axial_pos_num()])[bin.view_num()])[bin.tangential_pos_num()]=true; + if (is_null_ptr(already_processed[bin.segment_num()])) { + // range attempts to take into account that symmetries normally bring axial_pos_num back to 0 or 1 + already_processed[bin.segment_num()].reset( + new apos_t(std::min(0, proj_data_info_sptr->get_min_axial_pos_num(bin.segment_num())), + std::max(1, proj_data_info_sptr->get_max_axial_pos_num(bin.segment_num())))); + } + if (is_null_ptr((*already_processed[bin.segment_num()])[bin.axial_pos_num()])) { + (*already_processed[bin.segment_num()])[bin.axial_pos_num()].reset( + new vpos_t(proj_data_info_sptr->get_min_view_num(), proj_data_info_sptr->get_max_view_num())); + } + if (is_null_ptr((*(*already_processed[bin.segment_num()])[bin.axial_pos_num()])[bin.view_num()])) { + // range takes into account that symmetries bring negative tangential_pos_num to positive + (*(*already_processed[bin.segment_num()])[bin.axial_pos_num()])[bin.view_num()].reset( + new tpos_t(proj_data_info_sptr->get_min_tangential_pos_num(), + std::max(proj_data_info_sptr->get_max_tangential_pos_num(), + -proj_data_info_sptr->get_min_tangential_pos_num()))); + (*(*already_processed[bin.segment_num()])[bin.axial_pos_num()])[bin.view_num()]->fill(false); + } + if ((*(*(*already_processed[bin.segment_num()])[bin.axial_pos_num()])[bin.view_num()])[bin.tangential_pos_num()]) + continue; + + (*(*(*already_processed[bin.segment_num()])[bin.axial_pos_num()])[bin.view_num()])[bin.tangential_pos_num()] = true; #endif - //if (!proj_matrix.get_symmetries_ptr()->is_basic(bin)) - // continue; - - proj_matrix.get_proj_matrix_elems_for_one_bin(lor,bin); - if (write_lor(fst, lor) == Succeeded::no) - return Succeeded::no; - } + // if (!proj_matrix.get_symmetries_ptr()->is_basic(bin)) + // continue; + + proj_matrix.get_proj_matrix_elems_for_one_bin(lor, bin); + if (write_lor(fst, lor) == Succeeded::no) + return Succeeded::no; + } } return Succeeded::yes; } Succeeded -ProjMatrixByBinFromFile:: -read_data() -{ +ProjMatrixByBinFromFile::read_data() { std::ifstream fst; open_read_binary(fst, data_filename.c_str()); - + // defined here to avoid reallocation for every bin ProjMatrixElemsForOneBin lor; - while(!fst.eof()) - { - readReturnType return_value=read_lor(fst, lor); - if (return_value == readReturnType::problem) - return Succeeded::no; - if (return_value == readReturnType::eof) - return Succeeded::yes; - this->cache_proj_matrix_elems_for_one_bin(lor); - } + while (!fst.eof()) { + readReturnType return_value = read_lor(fst, lor); + if (return_value == readReturnType::problem) + return Succeeded::no; + if (return_value == readReturnType::eof) + return Succeeded::yes; + this->cache_proj_matrix_elems_for_one_bin(lor); + } return Succeeded::yes; } - -void -ProjMatrixByBinFromFile:: -calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor - ) const -{ - //error("ProjMatrixByBinFromFile element not found in cache (and hence file)"); +void +ProjMatrixByBinFromFile::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { + // error("ProjMatrixByBinFromFile element not found in cache (and hence file)"); lor.erase(); } END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/ProjMatrixByBinSPECTUB.cxx b/src/recon_buildblock/ProjMatrixByBinSPECTUB.cxx index d55d8dec6b..13e2be4016 100644 --- a/src/recon_buildblock/ProjMatrixByBinSPECTUB.cxx +++ b/src/recon_buildblock/ProjMatrixByBinSPECTUB.cxx @@ -42,7 +42,7 @@ #include "stir/info.h" #include "stir/CPUTimer.h" #ifdef STIR_OPENMP -#include "stir/num_threads.h" +# include "stir/num_threads.h" #endif //#include "boost/cstdint.hpp" @@ -69,28 +69,19 @@ /* UB-SPECT global variables */ namespace SPECTUB { - wm_da_type wm; - wmh_type wmh; - float * Rrad; -} +wm_da_type wm; +wmh_type wmh; +float* Rrad; +} // namespace SPECTUB START_NAMESPACE_STIR +const char* const ProjMatrixByBinSPECTUB::registered_name = "SPECT UB"; -const char * const -ProjMatrixByBinSPECTUB::registered_name = -"SPECT UB"; - -ProjMatrixByBinSPECTUB:: -ProjMatrixByBinSPECTUB() -{ - set_defaults(); -} +ProjMatrixByBinSPECTUB::ProjMatrixByBinSPECTUB() { set_defaults(); } -void -ProjMatrixByBinSPECTUB:: -initialise_keymap() -{ +void +ProjMatrixByBinSPECTUB::initialise_keymap() { parser.add_start_key("Projection Matrix By Bin SPECT UB Parameters"); ProjMatrixByBin::initialise_keymap(); @@ -111,31 +102,27 @@ initialise_keymap() parser.add_stop_key("End Projection Matrix By Bin SPECT UB Parameters"); } - void -ProjMatrixByBinSPECTUB::set_defaults() -{ +ProjMatrixByBinSPECTUB::set_defaults() { ProjMatrixByBin::set_defaults(); - - this->already_setup= false; - - this->keep_all_views_in_cache=false; - minimum_weight=0.0; - maximum_number_of_sigmas= 2.; - spatial_resolution_PSF= 0.00001; - psf_type= "Geometrical"; - collimator_slope= 0.; - collimator_sigma_0= 0.; - attenuation_type= "no"; - attenuation_map= ""; - mask_type= "no"; - mask_file= ""; + this->already_setup = false; + + this->keep_all_views_in_cache = false; + minimum_weight = 0.0; + maximum_number_of_sigmas = 2.; + spatial_resolution_PSF = 0.00001; + psf_type = "Geometrical"; + collimator_slope = 0.; + collimator_sigma_0 = 0.; + attenuation_type = "no"; + attenuation_map = ""; + mask_type = "no"; + mask_file = ""; } bool -ProjMatrixByBinSPECTUB::post_processing() -{ +ProjMatrixByBinSPECTUB::post_processing() { if (ProjMatrixByBin::post_processing() == true) return true; @@ -145,604 +132,553 @@ ProjMatrixByBinSPECTUB::post_processing() else this->attenuation_image_sptr.reset(); - this->already_setup= false; + this->already_setup = false; return false; } bool -ProjMatrixByBinSPECTUB:: -get_keep_all_views_in_cache() const -{ +ProjMatrixByBinSPECTUB::get_keep_all_views_in_cache() const { return this->keep_all_views_in_cache; } void -ProjMatrixByBinSPECTUB:: -set_keep_all_views_in_cache(bool value) -{ - if (this->keep_all_views_in_cache != value) - { - this->keep_all_views_in_cache = value; - this->already_setup = false; - } +ProjMatrixByBinSPECTUB::set_keep_all_views_in_cache(bool value) { + if (this->keep_all_views_in_cache != value) { + this->keep_all_views_in_cache = value; + this->already_setup = false; + } } std::string -ProjMatrixByBinSPECTUB:: -get_attenuation_type() const -{ +ProjMatrixByBinSPECTUB::get_attenuation_type() const { return this->attenuation_type; } void -ProjMatrixByBinSPECTUB:: -set_attenuation_type(const std::string& value) -{ - if (this->attenuation_type != boost::algorithm::to_lower_copy(value)) - { - this->attenuation_type = boost::algorithm::to_lower_copy(value); - if ( this->attenuation_type != "no" && this->attenuation_type != "simple" && this->attenuation_type != "full") - error("attenuation_type has to be No, Simple or Full"); - this->already_setup = false; - } +ProjMatrixByBinSPECTUB::set_attenuation_type(const std::string& value) { + if (this->attenuation_type != boost::algorithm::to_lower_copy(value)) { + this->attenuation_type = boost::algorithm::to_lower_copy(value); + if (this->attenuation_type != "no" && this->attenuation_type != "simple" && this->attenuation_type != "full") + error("attenuation_type has to be No, Simple or Full"); + this->already_setup = false; + } } -shared_ptr > -ProjMatrixByBinSPECTUB:: -get_attenuation_image_sptr() const -{ +shared_ptr> +ProjMatrixByBinSPECTUB::get_attenuation_image_sptr() const { return this->attenuation_image_sptr; } void -ProjMatrixByBinSPECTUB:: -set_attenuation_image_sptr(const shared_ptr > value) -{ +ProjMatrixByBinSPECTUB::set_attenuation_image_sptr(const shared_ptr> value) { this->attenuation_image_sptr = value; - if (this->attenuation_type == "no") - { - info("Setting attenuation type to 'simple'"); - this->set_attenuation_type("simple"); - } + if (this->attenuation_type == "no") { + info("Setting attenuation type to 'simple'"); + this->set_attenuation_type("simple"); + } this->already_setup = false; } void -ProjMatrixByBinSPECTUB:: -set_attenuation_image_sptr(const std::string& value) -{ +ProjMatrixByBinSPECTUB::set_attenuation_image_sptr(const std::string& value) { this->attenuation_map = value; - shared_ptr > im_sptr(read_from_file >(this->attenuation_map)); + shared_ptr> im_sptr(read_from_file>(this->attenuation_map)); set_attenuation_image_sptr(im_sptr); } void -ProjMatrixByBinSPECTUB:: -set_resolution_model(const float collimator_sigma_0_in_mm, const float collimator_slope_in_mm, const bool full_3D) -{ +ProjMatrixByBinSPECTUB::set_resolution_model(const float collimator_sigma_0_in_mm, const float collimator_slope_in_mm, + const bool full_3D) { this->collimator_sigma_0 = collimator_sigma_0_in_mm / 10; this->collimator_slope = collimator_slope_in_mm / 10; - if (collimator_slope == 0.F && collimator_sigma_0 == 0.F) - { - this->psf_type = "geometrical"; - } - else if (full_3D) - { - this->psf_type = "3d"; - } - else - { - this->psf_type = "2d"; - } + if (collimator_slope == 0.F && collimator_sigma_0 == 0.F) { + this->psf_type = "geometrical"; + } else if (full_3D) { + this->psf_type = "3d"; + } else { + this->psf_type = "2d"; + } this->already_setup = false; } void -ProjMatrixByBinSPECTUB:: -set_up( - const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) -{ +ProjMatrixByBinSPECTUB::set_up(const shared_ptr& proj_data_info_ptr_v, + const shared_ptr>& density_info_ptr // TODO should be Info only +) { ProjMatrixByBin::set_up(proj_data_info_ptr_v, density_info_ptr); #ifdef STIR_OPENMP - if (!this->keep_all_views_in_cache) - { - warning("SPECTUB matrix can currently only use single-threaded code unless all views are kept. Setting num_threads to 1"); - set_num_threads(1); - } + if (!this->keep_all_views_in_cache) { + warning("SPECTUB matrix can currently only use single-threaded code unless all views are kept. Setting num_threads to 1"); + set_num_threads(1); + } #endif using namespace SPECTUB; - const VoxelsOnCartesianGrid * image_info_ptr = - dynamic_cast*> (density_info_ptr.get()); + const VoxelsOnCartesianGrid* image_info_ptr = dynamic_cast*>(density_info_ptr.get()); if (image_info_ptr == NULL) error("ProjMatrixByBinFromFile set-up with a wrong type of DiscretisedDensity\n"); - if (this->already_setup) - { - if (this->densel_range == image_info_ptr->get_index_range() && - this->voxel_size == image_info_ptr->get_voxel_size() && - this->origin == image_info_ptr->get_origin() && - *proj_data_info_ptr_v == *this->proj_data_info_ptr) - { - // stored matrix should be compatible, so we can just reuse it - return; - } - else - { - this->clear_cache(); - this->delete_UB_SPECT_arrays(); - } + if (this->already_setup) { + if (this->densel_range == image_info_ptr->get_index_range() && this->voxel_size == image_info_ptr->get_voxel_size() && + this->origin == image_info_ptr->get_origin() && *proj_data_info_ptr_v == *this->proj_data_info_ptr) { + // stored matrix should be compatible, so we can just reuse it + return; + } else { + this->clear_cache(); + this->delete_UB_SPECT_arrays(); + } + } + + this->proj_data_info_ptr = proj_data_info_ptr_v; + symmetries_sptr.reset(new TrivialDataSymmetriesForBins(proj_data_info_ptr_v)); + + this->densel_range = image_info_ptr->get_index_range(); + this->voxel_size = image_info_ptr->get_voxel_size(); + this->origin = image_info_ptr->get_origin(); + + const ProjDataInfoCylindricalArcCorr* proj_Data_Info_Cylindrical = + dynamic_cast(this->proj_data_info_ptr.get()); + + CPUTimer timer; + timer.start(); + + //... fill prj structure from projection data info + + prj.Nbin = this->proj_data_info_ptr->get_num_tangential_poss(); + prj.szcm = this->proj_data_info_ptr->get_scanner_ptr()->get_default_bin_size() / 10.; + prj.Nang = this->proj_data_info_ptr->get_num_views(); + + //... fill vol structure from image_info_ptr + vol.Ncol = image_info_ptr->get_x_size(); // Image: number of columns + vol.Nrow = image_info_ptr->get_y_size(); // Image: number of rows + vol.Nsli = image_info_ptr->get_z_size(); // Image: and projections: number of slices + vol.szcm = image_info_ptr->get_voxel_size().x() / 10.; // Image: voxel size (cm) + vol.thcm = image_info_ptr->get_voxel_size().z() / 10.; // Image: slice thickness (cm) + + //..... geometrical and other derived parameters of the volume structure............... + vol.Npix = vol.Ncol * vol.Nrow; + vol.Nvox = vol.Npix * vol.Nsli; + + vol.Ncold2 = (float)vol.Ncol / (float)2.; // half of the matrix Nvox (integer or semi-integer) + vol.Nrowd2 = (float)vol.Nrow / (float)2.; // half of the matrix NbOS (integer or semi-integer) + vol.Nslid2 = (float)vol.Nsli / (float)2.; // half of the number of slices (integer or semi-integer) + + vol.Xcmd2 = vol.Ncold2 * vol.szcm; // Half of the size of the image volume, dimension x (cm); + vol.Ycmd2 = vol.Nrowd2 * vol.szcm; // Half of the size of the image volume, dimension y (cm); + vol.Zcmd2 = vol.Nslid2 * vol.thcm; // Half of the size of the image volume, dimension z (cm); + + vol.x0 = ((float)0.5 - vol.Ncold2) * vol.szcm; // coordinate x of the first voxel + vol.y0 = ((float)0.5 - vol.Nrowd2) * vol.szcm; // coordinate y of the first voxel + vol.z0 = ((float)0.5 - vol.Nslid2) * vol.thcm; // coordinate z of the first voxel + + vol.first_sl = 0; // Image: first slice to take into account (no weight bellow) + vol.last_sl = vol.Nsli; // Image: last slice to take into account (no weights above) + + wmh.vol = vol; + + //...... geometrical dimensions of the voxel structure ................. + vox.szcm = vol.szcm; + vox.thcm = vol.thcm; + + //... projecction parameters .......................................... + prj.ang0 = this->proj_data_info_ptr->get_scanner_ptr()->get_default_intrinsic_tilt() * float(180 / _PI); + prj.incr = proj_Data_Info_Cylindrical->get_azimuthal_angle_sampling() * float(180 / _PI); + prj.thcm = proj_Data_Info_Cylindrical->get_axial_sampling(0) / 10; + + //.......geometrical and other derived parameters of projection structure........... + prj.Nsli = proj_Data_Info_Cylindrical->get_num_axial_poss(0); // number of slices + prj.lngcm = prj.Nbin * prj.szcm; // length in cm of the detection line + prj.Nbp = prj.Nbin * prj.Nsli; // number of bins for each projection angle (2D-projection) + prj.Nbt = prj.Nbp * prj.Nang; // total number of bins considering all the projection angles + prj.Nbind2 = (float)prj.Nbin / (float)2.; // half of the number of bins in a detection line (integer or semi-integer) + prj.lngcmd2 = prj.lngcm / (float)2.; // half of the length of detection line (cm) + prj.Nslid2 = (float)prj.Nsli / (float)2.; // half of the number of slices (integer or semi-integer) + + //... number of subsets (always 1 in STIR) ................................................ + prj.NOS = prj.Nang; // number of subset in which to split the weight matrix + prj.NangOS = prj.Nang / prj.NOS; // number of angles of projection in each subset + prj.NbOS = prj.Nbt / prj.NOS; // total number of bins in each subset + + wmh.prj = prj; + // wmh.NpixAngOS = vol.Npix * prj.NangOS; + + if (abs(wmh.prj.thcm - vox.thcm) > .01F) + error(boost::format("SPECTUB Matrix (probably) only works with equal z-sampling for projection data (%1%) and image (%2%)") % + (wmh.prj.thcm * 10) % (vol.thcm * 10)); + if (abs(wmh.prj.Nsli - vol.Nsli) > .01F) + error(boost::format( + "SPECTUB Matrix (probably) only works with equal number of slices for projection data (%1%) and image (%2%)") % + wmh.prj.Nsli % vol.Nsli); + //....rotation radius ................................................. + const VectorWithOffset radius_all_views = proj_Data_Info_Cylindrical->get_ring_radii_for_all_views(); + + Rrad = new float[wmh.prj.Nang]; + for (int i = 0; i < wmh.prj.Nang; i++) { + // note: convert to cm for UB SPECT library + Rrad[i] = radius_all_views[i] / 10; + } + + //... resolution parameters .............................................. + wmh.min_w = minimum_weight; + wmh.maxsigm = maximum_number_of_sigmas; + wmh.psfres = spatial_resolution_PSF; + + bin.szcm = wmh.prj.szcm; + bin.szcmd2 = bin.szcm / (float)2.; + bin.thcm = wmh.prj.thcm; + bin.thcmd2 = bin.thcm / (float)2.; + bin.szdx = bin.szcm / wmh.psfres; + bin.thdx = bin.thcm / wmh.psfres; + + std::stringstream info_stream; + + //....PSF and collimator parameters ........................................ + boost::algorithm::to_lower(psf_type); + if (psf_type == "geometrical") + wmh.do_psf = false; + else { + wmh.do_psf = true; + + if (psf_type == "3d") { + wmh.do_psf_3d = true; + info_stream << "3D PSF Correction. Parallel geometry" << std::endl; + } else { + if (psf_type == "2d") { + wmh.do_psf_3d = false; + info_stream << "2D PSF Correction. Parallel geometry" << std::endl; + } else { + // error_wm_SPECT( 120, psf_type ); + error("PSF type has to be 2D, 3D or Geometrical"); + } + } + } + + if (wmh.do_psf) { + wmh.predef_col = false; + wmh.COL.A = collimator_slope; + wmh.COL.B = collimator_sigma_0; + } else { + // code to enable fan-beam collimator at some point... (not validated) + // before enabling, you will have to change the parameter file to give parameters of the fan-beam + // int num = collimator_number; + // if ( num ==0 ) { + wmh.COL.do_fb = false; + info_stream << "No correction for PSF. Parallel geometry" << std::endl; + //} + // else { + // wmh.COL.do_fb = true; + // wmh.COL.F = collimator_number; + // info_stream << "No correction for PSF. Fanbeam geometry with focal distance = " << wmh.COL.F << " cm " << std::endl; + //} + } + + //... attenuation parameters ......................... + boost::algorithm::to_lower(attenuation_type); + if (attenuation_type == "no") { + wmh.do_att = false; + } else { + wmh.do_att = true; + + if (attenuation_type == "simple") + wmh.do_full_att = false; + else { + if (attenuation_type == "full") + wmh.do_full_att = true; + else { + // error_wm_SPECT( 123, attenuation_type ); + error("attenuation_type has to be No, Simple or Full"); + } + } + } + + //... masking parameters............................. + boost::algorithm::to_lower(mask_type); + if (mask_type == "no") { + wmh.do_msk = wmh.do_msk_cyl = wmh.do_msk_att = wmh.do_msk_file = false; + } else { + wmh.do_msk = true; + if (mask_type == "cylinder") + wmh.do_msk_cyl = true; + else { + if (mask_type == "attenuation map") + wmh.do_msk_att = true; + else { + if (mask_type == "explicit mask") { + wmh.do_msk_file = true; + + wmh.msk_fn = mask_file; + + info_stream << "MASK filename = " << wmh.msk_fn << std::endl; + } else { + // error_wm_SPECT( 125, mask_type); + error("mask_type has to be No, Cylinder, Attenuation Map or Explicit Mask"); + } + } + } + } + + wmh.do_msk_slc = false; + + if (vol.first_sl > 0 || vol.last_sl < vol.Nsli) { + wmh.do_msk = true; + wmh.do_msk_slc = true; + } + + wm.do_save_STIR = true; + + //:: Control of read parameters + info_stream << "" << std::endl; + info_stream << "Parameters of SPECT UB matrix: (in cm)" << std::endl; + info_stream << "Image grid side row: " << wmh.vol.Nrow << "\tcol: " << wmh.vol.Ncol + << "\ttransverse voxel_size: " << wmh.vol.szcm << std::endl; + info_stream << "Number of slices: " << wmh.vol.Nsli << "\tslice_thickness: " << wmh.vol.thcm << std::endl; + info_stream << "Number of bins: " << wmh.prj.Nbin << "\tbin size: " << wmh.prj.szcm << "\taxial size: " << wmh.prj.thcm + << std::endl; + info_stream << "Number of angles: " << wmh.prj.Nang << "\tAngle increment: " << wmh.prj.incr + << "\tFirst angle: " << wmh.prj.ang0 << std::endl; + info_stream << "Number of subsets: " << wmh.prj.NOS << std::endl; + if (wmh.do_att) { + info_stream << "Correction for attenuation: " << wmh.att_fn << "\t\tdo_msk_att: " << wmh.do_msk_att << std::endl; + info_stream << "Attenuation map: " << wmh.att_fn << std::endl; + } + info_stream << "Rotation radii: {" << Rrad[0]; + for (int i = 1; i < prj.Nang; ++i) { + info_stream << ", " << Rrad[i]; + } + info_stream << "}\n"; + info_stream << "Minimum weight: " << wmh.min_w << std::endl; + + info(info_stream.str()); + + //... to sort angles into subsets ...................................... + + prj.order = new int[prj.Nang]; + index_calc(prj.order); + + //... to fill ang structure ............................................ + + ang = new angle_type[prj.Nang]; + fill_ang(ang); + + //... to fill high resolution discrete distribution functions .............. + + if (!wmh.do_psf) { + + //... trapezoid projection of a square voxel on a line ................. + + for (int i = 0; i < prj.Nang; i++) { + + ang[i].vxprj.val = new float[ang[i].vxprj.lng]; + ang[i].vxprj.acu = new float[ang[i].vxprj.lng]; + + calc_vxprj(&ang[i]); + } + } else { + + //... Gaussian density and distribution functions ........................ + + gaussdens.lngd2 = + (int)(wmh.maxsigm / wmh.psfres); // half of the length of the gaussian density function (in resolution elements) + gaussdens.lng = gaussdens.lngd2 * 2; // length of the gaussian density function (in resolution elements). + gaussdens.res = wmh.psfres; + + gaussdens.val = new float[gaussdens.lng + 1]; // density function allocation + gaussdens.acu = new float[gaussdens.lng]; // distribution function allocation + calc_gauss(&gaussdens); // to calculate N(0,1) density function and distribution function + } + + //... to read attenuation map .................................................. + + if (wmh.do_att || wmh.do_msk_att) { + if (is_null_ptr(attenuation_image_sptr)) + error("Attenation image not set"); + if (!density_info_ptr->has_same_characteristics(*attenuation_image_sptr)) + error("Currently the attenuation map and emission image must have the same dimension, orientation and voxel size"); + + attmap = new float[vol.Nvox]; + std::copy(attenuation_image_sptr->begin_all(), attenuation_image_sptr->end_all(), attmap); + for (int i = 0; i < wmh.vol.Nvox; i++) { + if ((boost::math::isnan)(attmap[i])) { + attmap[i] = 0; + } + } + // read_att_map( attmap ); + } else + attmap = NULL; + + //... to generate mask.......................................................... + + if (wmh.do_msk) { + msk_3d = new bool[vol.Nvox]; + msk_2d = new bool[vol.Npix]; + if (!wmh.do_msk_att && wmh.do_msk_file) { + shared_ptr> mask_sptr(read_from_file>(wmh.msk_fn)); + if (!density_info_ptr->has_same_characteristics(*mask_sptr)) + error("Currently the mask image and emission image must have the same dimension, orientation and voxel size"); + float* mask_from_file = new float[vol.Nvox]; + std::copy(mask_sptr->begin_all(), mask_sptr->end_all(), mask_from_file); + // call UB generate_msk pretending that this mask is an attenuation image + // we do this to avoid using its own read_msk_file + wmh.do_msk_file = false; + wmh.do_msk_att = true; + generate_msk(msk_3d, msk_2d, mask_from_file, &vol); + delete[] mask_from_file; + } else { + generate_msk(msk_3d, msk_2d, attmap, &vol); + } + } else + msk_2d = msk_3d = NULL; + + //... Initialization and memory allocation for the weight matrix ................... + + wm.NbOS = prj.NbOS; // number of rows in the weight matrix + wm.Nvox = vol.Nvox; // number of columnes in the weight matrix + + //... setting PSF maximum size (in bins) and memory allocation for PSF values ....... + + this->maxszb = max_psf_szb(ang); // maximum PSF size (horizontal component of PSF) + NITEMS = new int*[prj.NOS]; + for (int kOS = 0; kOS < prj.NOS; ++kOS) { + NITEMS[kOS] = new int[wm.NbOS]; + } + + //... double array wm.val and wm.col ..................................................... + + if ((wm.val = new (std::nothrow) float*[wm.NbOS]) == NULL) { + // error_wm_SPECT( 200, "wm.val[]" ); + error("Error allocating space to store values for SPECTUB matrix"); + } + if ((wm.col = new (std::nothrow) int*[wm.NbOS]) == NULL) { + // error_wm_SPECT( 200, "wm.col[]" ); + error("Error allocating space to store column indices for SPECTUB matrix"); + } + + //... array wm.ne ......................................................................... + + if ((wm.ne = new (std::nothrow) int[wm.NbOS + 1]) == 0) { + // error_wm_SPECT(200,"wm.ne[]"); + error("Error allocating space to store number of elements for SPECTUB matrix"); + } + + //... STIR indices ....................................................................... + + if (wm.do_save_STIR) { + wm.ns = new int[prj.NbOS]; + wm.nb = new int[prj.NbOS]; + wm.na = new int[prj.NbOS]; + + wm.nx = new short int[vol.Nvox]; + wm.ny = new short int[vol.Nvox]; + wm.nz = new short int[vol.Nvox]; } - this->proj_data_info_ptr=proj_data_info_ptr_v; - symmetries_sptr.reset( - new TrivialDataSymmetriesForBins(proj_data_info_ptr_v)); - - this->densel_range = image_info_ptr->get_index_range(); - this->voxel_size = image_info_ptr->get_voxel_size(); - this->origin = image_info_ptr->get_origin(); - - const ProjDataInfoCylindricalArcCorr * proj_Data_Info_Cylindrical = - dynamic_cast (this->proj_data_info_ptr.get()); - - CPUTimer timer; - timer.start(); - - //... fill prj structure from projection data info - - prj.Nbin = this->proj_data_info_ptr->get_num_tangential_poss(); - prj.szcm = this->proj_data_info_ptr->get_scanner_ptr()->get_default_bin_size()/10.; - prj.Nang = this->proj_data_info_ptr->get_num_views(); - - - //... fill vol structure from image_info_ptr - vol.Ncol = image_info_ptr->get_x_size(); // Image: number of columns - vol.Nrow = image_info_ptr->get_y_size(); // Image: number of rows - vol.Nsli = image_info_ptr->get_z_size(); // Image: and projections: number of slices - vol.szcm = image_info_ptr->get_voxel_size().x()/10.; // Image: voxel size (cm) - vol.thcm = image_info_ptr->get_voxel_size().z()/10.; // Image: slice thickness (cm) - - //..... geometrical and other derived parameters of the volume structure............... - vol.Npix = vol.Ncol * vol.Nrow; - vol.Nvox = vol.Npix * vol.Nsli; - - vol.Ncold2 = (float)vol.Ncol / (float)2.; // half of the matrix Nvox (integer or semi-integer) - vol.Nrowd2 = (float)vol.Nrow / (float)2.; // half of the matrix NbOS (integer or semi-integer) - vol.Nslid2 = (float)vol.Nsli / (float)2.; // half of the number of slices (integer or semi-integer) - - vol.Xcmd2 = vol.Ncold2 * vol.szcm; // Half of the size of the image volume, dimension x (cm); - vol.Ycmd2 = vol.Nrowd2 * vol.szcm; // Half of the size of the image volume, dimension y (cm); - vol.Zcmd2 = vol.Nslid2 * vol.thcm; // Half of the size of the image volume, dimension z (cm); - - vol.x0 = ( (float)0.5 - vol.Ncold2) * vol.szcm; // coordinate x of the first voxel - vol.y0 = ( (float)0.5 - vol.Nrowd2) * vol.szcm; // coordinate y of the first voxel - vol.z0 = ( (float)0.5 - vol.Nslid2) * vol.thcm; // coordinate z of the first voxel - - vol.first_sl = 0; // Image: first slice to take into account (no weight bellow) - vol.last_sl = vol.Nsli; // Image: last slice to take into account (no weights above) - - wmh.vol = vol; - - //...... geometrical dimensions of the voxel structure ................. - vox.szcm = vol.szcm; - vox.thcm = vol.thcm; - - //... projecction parameters .......................................... - prj.ang0 = this->proj_data_info_ptr->get_scanner_ptr()->get_default_intrinsic_tilt() * float(180/_PI); - prj.incr = proj_Data_Info_Cylindrical->get_azimuthal_angle_sampling() * float(180/_PI); - prj.thcm = proj_Data_Info_Cylindrical->get_axial_sampling(0)/10; - - //.......geometrical and other derived parameters of projection structure........... - prj.Nsli = proj_Data_Info_Cylindrical->get_num_axial_poss(0); // number of slices - prj.lngcm = prj.Nbin * prj.szcm; // length in cm of the detection line - prj.Nbp = prj.Nbin * prj.Nsli; // number of bins for each projection angle (2D-projection) - prj.Nbt = prj.Nbp * prj.Nang; // total number of bins considering all the projection angles - prj.Nbind2 = (float)prj.Nbin / (float)2.; // half of the number of bins in a detection line (integer or semi-integer) - prj.lngcmd2 = prj.lngcm / (float)2.; // half of the length of detection line (cm) - prj.Nslid2 = (float)prj.Nsli / (float)2.; // half of the number of slices (integer or semi-integer) - - - //... number of subsets (always 1 in STIR) ................................................ - prj.NOS = prj.Nang; // number of subset in which to split the weight matrix - prj.NangOS = prj.Nang / prj.NOS; // number of angles of projection in each subset - prj.NbOS = prj.Nbt / prj.NOS; // total number of bins in each subset - - wmh.prj = prj; - // wmh.NpixAngOS = vol.Npix * prj.NangOS; - - if (abs(wmh.prj.thcm - vox.thcm)>.01F) - error(boost::format("SPECTUB Matrix (probably) only works with equal z-sampling for projection data (%1%) and image (%2%)") - % (wmh.prj.thcm*10) % (vol.thcm*10)); - if (abs(wmh.prj.Nsli - vol.Nsli)>.01F) - error(boost::format("SPECTUB Matrix (probably) only works with equal number of slices for projection data (%1%) and image (%2%)") - % wmh.prj.Nsli % vol.Nsli); - //....rotation radius ................................................. - const VectorWithOffset radius_all_views = - proj_Data_Info_Cylindrical->get_ring_radii_for_all_views(); - - Rrad = new float [ wmh.prj.Nang ]; - for ( int i = 0 ; i < wmh.prj.Nang ; i++ ) { - // note: convert to cm for UB SPECT library - Rrad[ i ] = radius_all_views[i]/10; - } - - //... resolution parameters .............................................. - wmh.min_w = minimum_weight; - wmh.maxsigm = maximum_number_of_sigmas; - wmh.psfres = spatial_resolution_PSF; - - bin.szcm = wmh.prj.szcm; - bin.szcmd2 = bin.szcm / (float)2.; - bin.thcm = wmh.prj.thcm; - bin.thcmd2 = bin.thcm / (float)2.; - bin.szdx = bin.szcm / wmh.psfres; - bin.thdx = bin.thcm / wmh.psfres; - - std::stringstream info_stream; - - //....PSF and collimator parameters ........................................ - boost::algorithm::to_lower(psf_type); - if ( psf_type == "geometrical" ) wmh.do_psf = false; - else{ - wmh.do_psf = true; - - if ( psf_type == "3d" ) { - wmh.do_psf_3d = true; - info_stream << "3D PSF Correction. Parallel geometry" << std::endl; - } - else { - if ( psf_type== "2d" ) { - wmh.do_psf_3d = false; - info_stream << "2D PSF Correction. Parallel geometry" << std::endl; - } - else - { - //error_wm_SPECT( 120, psf_type ); - error("PSF type has to be 2D, 3D or Geometrical"); - } - } - } - - if ( wmh.do_psf ){ - wmh.predef_col = false; - wmh.COL.A = collimator_slope; - wmh.COL.B = collimator_sigma_0; - } - else{ - // code to enable fan-beam collimator at some point... (not validated) - // before enabling, you will have to change the parameter file to give parameters of the fan-beam - //int num = collimator_number; - //if ( num ==0 ) { - wmh.COL.do_fb = false; - info_stream << "No correction for PSF. Parallel geometry" << std::endl; - //} - //else { - // wmh.COL.do_fb = true; - // wmh.COL.F = collimator_number; - // info_stream << "No correction for PSF. Fanbeam geometry with focal distance = " << wmh.COL.F << " cm " << std::endl; - //} - } - - //... attenuation parameters ......................... - boost::algorithm::to_lower(attenuation_type); - if ( attenuation_type == "no" ) { - wmh.do_att = false; - } - else{ - wmh.do_att = true; - - if ( attenuation_type == "simple" ) wmh.do_full_att = false; - else { - if (attenuation_type == "full" ) wmh.do_full_att = true; - else - { - //error_wm_SPECT( 123, attenuation_type ); - error("attenuation_type has to be No, Simple or Full"); - } - } - } - - //... masking parameters............................. - boost::algorithm::to_lower(mask_type); - if( mask_type == "no" ){ - wmh.do_msk = wmh.do_msk_cyl = wmh.do_msk_att = wmh.do_msk_file = false; - } - else{ - wmh.do_msk = true; - if( mask_type == "cylinder" ) wmh.do_msk_cyl = true; - else { - if( mask_type == "attenuation map" ) wmh.do_msk_att = true; - else{ - if( mask_type == "explicit mask" ){ - wmh.do_msk_file = true; - - wmh.msk_fn = mask_file; - - info_stream << "MASK filename = " << wmh.msk_fn << std::endl; - } - else - { - // error_wm_SPECT( 125, mask_type); - error("mask_type has to be No, Cylinder, Attenuation Map or Explicit Mask"); - } - } - } - } - - wmh.do_msk_slc = false; - - if ( vol.first_sl > 0 || vol.last_sl < vol.Nsli ){ - wmh.do_msk = true; - wmh.do_msk_slc = true; - } - - wm.do_save_STIR = true; - - //:: Control of read parameters - info_stream << "" << std::endl; - info_stream << "Parameters of SPECT UB matrix: (in cm)" << std::endl; - info_stream << "Image grid side row: " << wmh.vol.Nrow << "\tcol: " << wmh.vol.Ncol << "\ttransverse voxel_size: " << wmh.vol.szcm<< std::endl; - info_stream << "Number of slices: " << wmh.vol.Nsli << "\tslice_thickness: " << wmh.vol.thcm << std::endl; - info_stream << "Number of bins: " << wmh.prj.Nbin << "\tbin size: " << wmh.prj.szcm << "\taxial size: " << wmh.prj.thcm << std::endl; - info_stream << "Number of angles: " << wmh.prj.Nang << "\tAngle increment: " << wmh.prj.incr << "\tFirst angle: " << wmh.prj.ang0 << std::endl; - info_stream << "Number of subsets: " << wmh.prj.NOS << std::endl; - if ( wmh.do_att ){ - info_stream << "Correction for attenuation: " << wmh.att_fn << "\t\tdo_msk_att: " << wmh.do_msk_att << std::endl; - info_stream << "Attenuation map: " << wmh.att_fn << std::endl; - } - info_stream << "Rotation radii: {" << Rrad[0]; - for (int i=1; ihas_same_characteristics(*attenuation_image_sptr)) - error("Currently the attenuation map and emission image must have the same dimension, orientation and voxel size"); - - attmap = new float [ vol.Nvox ]; - std::copy(attenuation_image_sptr->begin_all(), attenuation_image_sptr->end_all(),attmap); - for (int i = 0 ; i < wmh.vol.Nvox ; i++ ){ - if ((boost::math::isnan)(attmap [ i ])){ - attmap [ i ] = 0; - } - } - //read_att_map( attmap ); - } - else attmap = NULL; - - //... to generate mask.......................................................... - - if ( wmh.do_msk ) - { - msk_3d = new bool [ vol.Nvox ]; - msk_2d = new bool [ vol.Npix ]; - if (!wmh.do_msk_att && wmh.do_msk_file) - { - shared_ptr > mask_sptr( - read_from_file >(wmh.msk_fn)); - if (!density_info_ptr->has_same_characteristics(*mask_sptr)) - error("Currently the mask image and emission image must have the same dimension, orientation and voxel size"); - float * mask_from_file = new float [ vol.Nvox ]; - std::copy(mask_sptr->begin_all(), mask_sptr->end_all(),mask_from_file); - // call UB generate_msk pretending that this mask is an attenuation image - // we do this to avoid using its own read_msk_file - wmh.do_msk_file = false; - wmh.do_msk_att = true; - generate_msk( msk_3d, msk_2d, mask_from_file, &vol); - delete[] mask_from_file; - } - else - { - generate_msk( msk_3d, msk_2d, attmap, &vol); - } - } - else msk_2d = msk_3d = NULL; - - //... Initialization and memory allocation for the weight matrix ................... + //... memory allocation for wmh ......................................................... - wm.NbOS = prj.NbOS; // number of rows in the weight matrix - wm.Nvox = vol.Nvox; // number of columnes in the weight matrix + wmh.index = new int[wmh.prj.NangOS]; + wmh.Rrad = new float[wmh.prj.NangOS]; - //... setting PSF maximum size (in bins) and memory allocation for PSF values ....... + //.......................................................................................... + //... CALCULATION OF MATRICES .............................................................. + //.......................................................................................... - this->maxszb = max_psf_szb( ang ); // maximum PSF size (horizontal component of PSF) - NITEMS = new int * [prj.NOS]; - for (int kOS=0; kOSalready_setup = true; +} - this->already_setup= true; +ProjMatrixByBinSPECTUB* +ProjMatrixByBinSPECTUB::clone() const { + return new ProjMatrixByBinSPECTUB(*this); } -ProjMatrixByBinSPECTUB:: -~ProjMatrixByBinSPECTUB() -{ - delete_UB_SPECT_arrays(); +ProjMatrixByBinSPECTUB::~ProjMatrixByBinSPECTUB() { + // delete_UB_SPECT_arrays(); } void -ProjMatrixByBinSPECTUB:: -delete_UB_SPECT_arrays() -{ +ProjMatrixByBinSPECTUB::delete_UB_SPECT_arrays() { if (!this->already_setup) return; //... freeing matrix memory.................................... using namespace SPECTUB; - delete [] Rrad; + delete[] Rrad; - if ( !wmh.do_psf ){ - for ( int i = 0 ; i < prj.Nang ; i++ ){ - delete [] ang[ i ].vxprj.val; - delete [] ang[ i ].vxprj.acu ; + if (!wmh.do_psf) { + for (int i = 0; i < prj.Nang; i++) { + delete[] ang[i].vxprj.val; + delete[] ang[i].vxprj.acu; } } - delete [] wm.val; - delete [] wm.col; - delete [] wm.ne; + delete[] wm.val; + delete[] wm.col; + delete[] wm.ne; //... freeing memory ............................................. - delete [] prj.order; - delete [] ang; - for (int kOS=0; kOS(wm.nz[ wm.col[ j ][ i ] ],wm.ny[ wm.col[ j ][ i ] ],wm.nx[ wm.col[ j ][ i ] ]), wm.val[ j ][ i ]); - lor.push_back( elem); + const ProjMatrixElemsForOneBin::value_type elem( + Coordinate3D(wm.nz[wm.col[j][i]], wm.ny[wm.col[j][i]], wm.nx[wm.col[j][i]]), wm.val[j][i]); + lor.push_back(elem); } - delete [] wm.val[ j ]; - delete [] wm.col[ j ]; + delete[] wm.val[j]; + delete[] wm.col[j]; this->cache_proj_matrix_elems_for_one_bin(lor); } - info(boost::format("Total time after transfering to ProjMatrixElemsForOneBin. time %1% (s)") % timer.value(), - 2); - + info(boost::format("Total time after transfering to ProjMatrixElemsForOneBin. time %1% (s)") % timer.value(), 2); } -void -ProjMatrixByBinSPECTUB:: -calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor - ) const -{ - //error("ProjMatrixByBinSPECTUB element not found in cache (and hence file)"); - - const int view_num=lor.get_bin().view_num(); +void +ProjMatrixByBinSPECTUB::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { + // error("ProjMatrixByBinSPECTUB element not found in cache (and hence file)"); + + const int view_num = lor.get_bin().view_num(); // find which "UB-subset" this view is in - int kOS=0; - for (kOS=0; kOSkeep_all_views_in_cache) - { - this->clear_cache(); - subset_already_processed.assign(prj.NOS,false); - } - info(boost::format("Computing matrix elements for view %1%") % view_num, - 2); - compute_one_subset(kOS); - subset_already_processed[kOS]=true; + if (!subset_already_processed[kOS]) { + if (!this->keep_all_views_in_cache) { + this->clear_cache(); + subset_already_processed.assign(prj.NOS, false); } + info(boost::format("Computing matrix elements for view %1%") % view_num, 2); + compute_one_subset(kOS); + subset_already_processed[kOS] = true; + } lor.erase(); } END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/ProjMatrixByBinUsingInterpolation.cxx b/src/recon_buildblock/ProjMatrixByBinUsingInterpolation.cxx index c44d8955eb..906de46578 100644 --- a/src/recon_buildblock/ProjMatrixByBinUsingInterpolation.cxx +++ b/src/recon_buildblock/ProjMatrixByBinUsingInterpolation.cxx @@ -41,36 +41,25 @@ START_NAMESPACE_STIR -ProjMatrixByBinUsingInterpolation::JacobianForIntBP:: -JacobianForIntBP(const ProjDataInfoCylindrical* proj_data_info_ptr, bool exact) - - : R2(square(proj_data_info_ptr->get_ring_radius())), - ring_spacing2 (square(proj_data_info_ptr->get_ring_spacing())), - arccor(dynamic_cast(proj_data_info_ptr)!=0), - backprojection_normalisation - (proj_data_info_ptr->get_ring_spacing()/2/proj_data_info_ptr->get_num_views()), - use_exact_Jacobian_now(exact) -{ - assert(arccor || - dynamic_cast(proj_data_info_ptr)!=0); +ProjMatrixByBinUsingInterpolation::JacobianForIntBP::JacobianForIntBP(const ProjDataInfoCylindrical* proj_data_info_ptr, + bool exact) + + : R2(square(proj_data_info_ptr->get_ring_radius())), ring_spacing2(square(proj_data_info_ptr->get_ring_spacing())), + arccor(dynamic_cast(proj_data_info_ptr) != 0), + backprojection_normalisation(proj_data_info_ptr->get_ring_spacing() / 2 / proj_data_info_ptr->get_num_views()), + use_exact_Jacobian_now(exact) { + assert(arccor || dynamic_cast(proj_data_info_ptr) != 0); } -const char * const -ProjMatrixByBinUsingInterpolation::registered_name = - "Interpolation"; +const char* const ProjMatrixByBinUsingInterpolation::registered_name = "Interpolation"; -ProjMatrixByBinUsingInterpolation:: -ProjMatrixByBinUsingInterpolation() -{ - set_defaults(); -} +ProjMatrixByBinUsingInterpolation::ProjMatrixByBinUsingInterpolation() { set_defaults(); } -void -ProjMatrixByBinUsingInterpolation::initialise_keymap() -{ +void +ProjMatrixByBinUsingInterpolation::initialise_keymap() { parser.add_start_key("Interpolation Matrix Parameters"); parser.add_key("use_piecewise_linear_interpolation", &use_piecewise_linear_interpolation_now); - parser.add_key("use_exact_Jacobian",&use_exact_Jacobian_now); + parser.add_key("use_exact_Jacobian", &use_exact_Jacobian_now); ProjMatrixByBin::initialise_keymap(); parser.add_key("do_symmetry_90degrees_min_phi", &do_symmetry_90degrees_min_phi); parser.add_key("do_symmetry_180degrees_min_phi", &do_symmetry_180degrees_min_phi); @@ -80,10 +69,8 @@ ProjMatrixByBinUsingInterpolation::initialise_keymap() parser.add_stop_key("End Interpolation Matrix Parameters"); } - void -ProjMatrixByBinUsingInterpolation::set_defaults() -{ +ProjMatrixByBinUsingInterpolation::set_defaults() { ProjMatrixByBin::set_defaults(); do_symmetry_90degrees_min_phi = true; do_symmetry_180degrees_min_phi = true; @@ -95,86 +82,70 @@ ProjMatrixByBinUsingInterpolation::set_defaults() use_exact_Jacobian_now = true; } - bool -ProjMatrixByBinUsingInterpolation::post_processing() -{ +ProjMatrixByBinUsingInterpolation::post_processing() { if (ProjMatrixByBin::post_processing() == true) return true; return false; } - void -ProjMatrixByBinUsingInterpolation:: -set_up( +ProjMatrixByBinUsingInterpolation::set_up( const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) -{ + const shared_ptr>& density_info_ptr // TODO should be Info only +) { ProjMatrixByBin::set_up(proj_data_info_ptr_v, density_info_ptr); - proj_data_info_ptr= proj_data_info_ptr_v; + proj_data_info_ptr = proj_data_info_ptr_v; - const VoxelsOnCartesianGrid * image_info_ptr = - dynamic_cast*> (density_info_ptr.get()); + const VoxelsOnCartesianGrid* image_info_ptr = dynamic_cast*>(density_info_ptr.get()); if (image_info_ptr == NULL) error("ProjMatrixByBinUsingInterpolation initialised with a wrong type of DiscretisedDensity\n"); - + densel_range = image_info_ptr->get_index_range(); voxel_size = image_info_ptr->get_voxel_size(); origin = image_info_ptr->get_origin(); - const float z_to_middle = - (densel_range.get_max_index() + densel_range.get_min_index())*voxel_size.z()/2.F; + const float z_to_middle = (densel_range.get_max_index() + densel_range.get_min_index()) * voxel_size.z() / 2.F; origin.z() -= z_to_middle; - symmetries_sptr.reset( - new DataSymmetriesForBins_PET_CartesianGrid(proj_data_info_ptr, - density_info_ptr, - do_symmetry_90degrees_min_phi, - do_symmetry_180degrees_min_phi, - do_symmetry_swap_segment, - do_symmetry_swap_s, - do_symmetry_shift_z)); + symmetries_sptr.reset(new DataSymmetriesForBins_PET_CartesianGrid( + proj_data_info_ptr, density_info_ptr, do_symmetry_90degrees_min_phi, do_symmetry_180degrees_min_phi, + do_symmetry_swap_segment, do_symmetry_swap_s, do_symmetry_shift_z)); - if (dynamic_cast(proj_data_info_ptr.get())==0) + if (dynamic_cast(proj_data_info_ptr.get()) == 0) error("ProjMatrixByBinUsingInterpolation needs ProjDataInfoCylindrical for jacobian\n"); jacobian = JacobianForIntBP(&(proj_data_info_cyl()), use_exact_Jacobian_now); // TODO assumes that all segments have span or not { - const float relative_vox_sampling = - voxel_size.z() / - proj_data_info_ptr->get_sampling_in_m(Bin(0,0,0,0)); - if (use_piecewise_linear_interpolation_now) - { - if (fabs(relative_vox_sampling-.5)<.01) - warning("Using piecewise-linear interpolation\n"); - else - { - warning("Switching OFF piecewise-linear interpolation\n"); - use_piecewise_linear_interpolation_now = false; - if (fabs(relative_vox_sampling-1)>.01) - warning("because non-standard voxel size.\n"); - } + const float relative_vox_sampling = voxel_size.z() / proj_data_info_ptr->get_sampling_in_m(Bin(0, 0, 0, 0)); + if (use_piecewise_linear_interpolation_now) { + if (fabs(relative_vox_sampling - .5) < .01) + warning("Using piecewise-linear interpolation\n"); + else { + warning("Switching OFF piecewise-linear interpolation\n"); + use_piecewise_linear_interpolation_now = false; + if (fabs(relative_vox_sampling - 1) > .01) + warning("because non-standard voxel size.\n"); } - } + } + } } -// point should be w.r.t. middle of the scanner! -static inline -void -find_s_m_of_voxel(float& s, float& m, - const CartesianCoordinate3D& point, - const float cphi, const float sphi, - const float tantheta) -{ - s = (point.x()*cphi+point.y()*sphi); - - m = - point.z()- tantheta*(-point.x()*sphi+point.y()*cphi); + +ProjMatrixByBinUsingInterpolation* +ProjMatrixByBinUsingInterpolation::clone() const { + return new ProjMatrixByBinUsingInterpolation(*this); } +// point should be w.r.t. middle of the scanner! +static inline void +find_s_m_of_voxel(float& s, float& m, const CartesianCoordinate3D& point, const float cphi, const float sphi, + const float tantheta) { + s = (point.x() * cphi + point.y() * sphi); + + m = point.z() - tantheta * (-point.x() * sphi + point.y() * cphi); +} /* @@ -187,59 +158,43 @@ interpolationkernel[s_,ssize_,xsize_] \ */ // piecewise_linear interpolation for bin between -1 and 1 // vox -static inline -float -piecewise_linear_interpolate(const float s, const float vox_size) -{ - if (fabs(s)(2+vox_size)/2) +static inline float +piecewise_linear_interpolate(const float s, const float vox_size) { + if (fabs(s) < fabs(2 - vox_size) / 2) + return std::min(1.F, 2 / vox_size); + else if (fabs(s) > (2 + vox_size) / 2) return 0; else - return (-fabs(s)+(2+vox_size)/2)/vox_size; + return (-fabs(s) + (2 + vox_size) / 2) / vox_size; } // linear interpolation between -1 and 1 -static inline -float -linear_interpolate(const float t) -{ +static inline float +linear_interpolate(const float t) { const float abst = fabs(t); - if (abst>=1) + if (abst >= 1) return 0; else - return 1-abst; + return 1 - abst; } -static inline -float -interpolate_tang_pos(const float tang_pos_diff) -{ +static inline float +interpolate_tang_pos(const float tang_pos_diff) { return linear_interpolate(tang_pos_diff); } - float -ProjMatrixByBinUsingInterpolation:: -get_element(const Bin& bin, - const CartesianCoordinate3D& densel_ctr) const -{ +ProjMatrixByBinUsingInterpolation::get_element(const Bin& bin, const CartesianCoordinate3D& densel_ctr) const { const float phi = proj_data_info_ptr->get_phi(bin); const float cphi = cos(phi); - const float sphi = sin(phi); + const float sphi = sin(phi); const float tantheta = proj_data_info_ptr->get_tantheta(bin); float s_densel, m_densel; - find_s_m_of_voxel(s_densel, m_densel, - densel_ctr, - cphi, sphi, - tantheta); - const float s_diff = - s_densel - proj_data_info_ptr->get_s(bin); + find_s_m_of_voxel(s_densel, m_densel, densel_ctr, cphi, sphi, tantheta); + const float s_diff = s_densel - proj_data_info_ptr->get_s(bin); - const float m_diff = - m_densel - - proj_data_info_ptr->get_m(bin); + const float m_diff = m_densel - proj_data_info_ptr->get_m(bin); #if 0 // alternative way to get m_diff using other code @@ -270,44 +225,28 @@ get_element(const Bin& bin, < .001*proj_data_info_ptr->get_sampling_in_m(bin)); #endif - const float s_max = - std::max(cphi>sphi? voxel_size.x() : voxel_size.y(), - proj_data_info_ptr->get_sampling_in_s(bin)); - float result = interpolate_tang_pos(s_diff/s_max); - if (result==0) + const float s_max = std::max(cphi > sphi ? voxel_size.x() : voxel_size.y(), proj_data_info_ptr->get_sampling_in_s(bin)); + float result = interpolate_tang_pos(s_diff / s_max); + if (result == 0) return 0; - const float m_max = - std::max(voxel_size.z(), - proj_data_info_ptr->get_sampling_in_m(bin)); - - result *= - (use_piecewise_linear_interpolation_now? - piecewise_linear_interpolate(m_diff/m_max, - std::min(voxel_size.z(), - proj_data_info_ptr->get_sampling_in_m(bin)) - /m_max) - : - linear_interpolate(m_diff/m_max) - ); - - if (result==0) + const float m_max = std::max(voxel_size.z(), proj_data_info_ptr->get_sampling_in_m(bin)); + + result *= (use_piecewise_linear_interpolation_now + ? piecewise_linear_interpolate(m_diff / m_max, + std::min(voxel_size.z(), proj_data_info_ptr->get_sampling_in_m(bin)) / m_max) + : linear_interpolate(m_diff / m_max)); + + if (result == 0) return 0; - return - result * - jacobian(proj_data_info_cyl().get_average_ring_difference(bin.segment_num()), - proj_data_info_ptr->get_s(bin)); + return result * jacobian(proj_data_info_cyl().get_average_ring_difference(bin.segment_num()), proj_data_info_ptr->get_s(bin)); } - - -void -ProjMatrixByBinUsingInterpolation:: -calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ + +void +ProjMatrixByBinUsingInterpolation::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { const Bin& bin = lor.get_bin(); - assert(bin.segment_num() >= proj_data_info_ptr->get_min_segment_num()); - assert(bin.segment_num() <= proj_data_info_ptr->get_max_segment_num()); + assert(bin.segment_num() >= proj_data_info_ptr->get_min_segment_num()); + assert(bin.segment_num() <= proj_data_info_ptr->get_max_segment_num()); assert(lor.size() == 0); @@ -325,7 +264,7 @@ calculate_proj_matrix_elems_for_one_bin( Horrible. */ - BasicCoordinate<3,int> c; + BasicCoordinate<3, int> c; int min1; int max1; // find z-range (this would depend on origin and the symmetries though) @@ -351,35 +290,21 @@ calculate_proj_matrix_elems_for_one_bin( /* Here we use geometric info. However, the code below only works for DiscretisedDensityOnCartesianGrid (with a regular_range) */ - min1=densel_range.get_min_index(); + min1 = densel_range.get_min_index(); // find radius of cylinder around all of the image - const float max_radius = - std::max( - std::max(-densel_range[min1].get_min_index(), - densel_range[min1].get_max_index() - )*voxel_size[2], - std::max(-densel_range[min1][0].get_min_index(), - densel_range[min1][0].get_max_index() - )*voxel_size[1] - ); + const float max_radius = + std::max(std::max(-densel_range[min1].get_min_index(), densel_range[min1].get_max_index()) * voxel_size[2], + std::max(-densel_range[min1][0].get_min_index(), densel_range[min1][0].get_max_index()) * voxel_size[1]); // find width of the 'tube of response' - const float z_width_of_TOR = - proj_data_info_ptr->get_sampling_in_m(bin); + const float z_width_of_TOR = proj_data_info_ptr->get_sampling_in_m(bin); // now find where tube enters/leaves image // we use a safety margin here as we could probably use z_width_of_LOR/2 - const float z_middle_LOR = - proj_data_info_ptr->get_m(bin) - origin.z(); - const float min_z_LOR = - z_middle_LOR - - fabs(proj_data_info_ptr->get_tantheta(bin))*max_radius - - z_width_of_TOR; - const float max_z_LOR = - z_middle_LOR + - fabs(proj_data_info_ptr->get_tantheta(bin))*max_radius + - z_width_of_TOR; - - min1 = round(floor(min_z_LOR/voxel_size[1])); - max1 = round(ceil(max_z_LOR/voxel_size[1])); + const float z_middle_LOR = proj_data_info_ptr->get_m(bin) - origin.z(); + const float min_z_LOR = z_middle_LOR - fabs(proj_data_info_ptr->get_tantheta(bin)) * max_radius - z_width_of_TOR; + const float max_z_LOR = z_middle_LOR + fabs(proj_data_info_ptr->get_tantheta(bin)) * max_radius + z_width_of_TOR; + + min1 = round(floor(min_z_LOR / voxel_size[1])); + max1 = round(ceil(max_z_LOR / voxel_size[1])); #endif } /* we loop over all coordinates, but for optimisation do the following: @@ -387,82 +312,73 @@ calculate_proj_matrix_elems_for_one_bin( So, we keep track if a non-zero element was found and break out of the loop if we find a 0 after finding a non-zero. */ - bool found_nonzero1=false, found_nonzero2, found_nonzero3; - for (c[1]=min1; c[1]<=max1; ++c[1]) - { - // note: because c1 can be outside the allowed range, we have - // in principle trouble getting the min_index() for c[2]. - // We'll assume that it is the same as for a(ny) c[1] within the range. - // That's of course ok for VoxelsOnCartesianGrid - const IndexRange<2>& range2d = - densel_range[std::min(std::max(c[1],densel_range.get_min_index()), - densel_range.get_max_index())]; + bool found_nonzero1 = false, found_nonzero2, found_nonzero3; + for (c[1] = min1; c[1] <= max1; ++c[1]) { + // note: because c1 can be outside the allowed range, we have + // in principle trouble getting the min_index() for c[2]. + // We'll assume that it is the same as for a(ny) c[1] within the range. + // That's of course ok for VoxelsOnCartesianGrid + const IndexRange<2>& range2d = + densel_range[std::min(std::max(c[1], densel_range.get_min_index()), densel_range.get_max_index())]; #if 0 const int min2=range2d.get_min_index(); const int max2=range2d.get_max_index(); #else - // TODO ugly stuff to avoid having symmetries obtaining voxels - // which are outside the FOV - // this will break when non-zero origin.y() or x() - // (but then there would be no relevant symmetries I guess) - assert(origin.y()==0); - assert(origin.x()==0); - const int first_min2=range2d.get_min_index(); - const int first_max2=range2d.get_max_index(); - const int min2 = std::max(first_min2, -first_max2); - const int max2 = std::min(-first_min2, first_max2); + // TODO ugly stuff to avoid having symmetries obtaining voxels + // which are outside the FOV + // this will break when non-zero origin.y() or x() + // (but then there would be no relevant symmetries I guess) + assert(origin.y() == 0); + assert(origin.x() == 0); + const int first_min2 = range2d.get_min_index(); + const int first_max2 = range2d.get_max_index(); + const int min2 = std::max(first_min2, -first_max2); + const int max2 = std::min(-first_min2, first_max2); #endif - found_nonzero2=false; - for (c[2]=min2; c[2]<=max2; ++c[2]) - { + found_nonzero2 = false; + for (c[2] = min2; c[2] <= max2; ++c[2]) { #if 0 const int min3=range2d[c[2]].get_min_index(); const int max3=range2d[c[2]].get_max_index(); #else - // TODO ugly stuff to avoid having symmetries obtaining voxels - // which are outside the FOV - // this will break when non-zero origin.y() or x() - const int first_min3=range2d[c[2]].get_min_index(); - const int first_max3=range2d[c[2]].get_max_index(); - const int min3 = std::max(first_min3, -first_max3); - const int max3 = std::min(-first_min3, first_max3); + // TODO ugly stuff to avoid having symmetries obtaining voxels + // which are outside the FOV + // this will break when non-zero origin.y() or x() + const int first_min3 = range2d[c[2]].get_min_index(); + const int first_max3 = range2d[c[2]].get_max_index(); + const int min3 = std::max(first_min3, -first_max3); + const int max3 = std::min(-first_min3, first_max3); #endif - found_nonzero3 = false; - for (c[3]=min3; c[3]<=max3; ++c[3]) - { - // TODO call a virtual function of DiscretisedDensity? - const CartesianCoordinate3D coords = - CartesianCoordinate3D(c[1]*voxel_size[1], - c[2]*voxel_size[2], - c[3]*voxel_size[3]) - +origin; - const float element_value = - get_element(bin, coords); - if (element_value>0) - { - found_nonzero3=true; - lor.push_back(ProjMatrixElemsForOneBin::value_type(c, element_value)); - } + found_nonzero3 = false; + for (c[3] = min3; c[3] <= max3; ++c[3]) { + // TODO call a virtual function of DiscretisedDensity? + const CartesianCoordinate3D coords = + CartesianCoordinate3D(c[1] * voxel_size[1], c[2] * voxel_size[2], c[3] * voxel_size[3]) + origin; + const float element_value = get_element(bin, coords); + if (element_value > 0) { + found_nonzero3 = true; + lor.push_back(ProjMatrixElemsForOneBin::value_type(c, element_value)); + } #ifndef __PMByBinElement_SLOW__ - else if (found_nonzero3) - break; + else if (found_nonzero3) + break; #endif - } - if (found_nonzero3) - found_nonzero2=true; + } + if (found_nonzero3) + found_nonzero2 = true; #ifndef __PMByBinElement_SLOW__ - else if (found_nonzero2) - break; + else if (found_nonzero2) + break; #endif - } - if (found_nonzero2) - found_nonzero1=true; + } + if (found_nonzero2) + found_nonzero1 = true; #ifndef __PMByBinElement_SLOW__ - else if (found_nonzero1) - break; + else if (found_nonzero1) + break; #endif - } + } } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ProjMatrixByBinUsingRayTracing.cxx b/src/recon_buildblock/ProjMatrixByBinUsingRayTracing.cxx index f23289e4a2..45973b1aa4 100644 --- a/src/recon_buildblock/ProjMatrixByBinUsingRayTracing.cxx +++ b/src/recon_buildblock/ProjMatrixByBinUsingRayTracing.cxx @@ -2,6 +2,7 @@ Copyright (C) 2000 PARAPET partners Copyright (C) 2000-2011, Hammersmith Imanet Ltd Copyright (C) 2013-2014, University College London + Copyright (C) 2016, University of Hull This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -23,6 +24,7 @@ \brief non-inline implementations for stir::ProjMatrixByBinUsingRayTracing + \author Nikos Efthimiou \author Mustapha Sadki \author Kris Thielemans \author PARAPET project @@ -34,14 +36,14 @@ added registry things KT 21/02/2002 added option for square FOV - KT 15/05/2002 + KT 15/05/2002 added possibility of multiple LORs in tangential direction call ProjMatrixByBin's new parsing functions - KT 28/06/02 + KT 28/06/02 added option to take actual detector boundaries into account KT 25/09/03 allow disabling more symmetries - allow smaller z- voxel sizes (but z-sampling in the projdata still has to + allow smaller z- voxel sizes (but z-sampling in the projdata still has to be an integer multiple of the z-voxel size). */ @@ -65,26 +67,17 @@ using std::max; #endif START_NAMESPACE_STIR +const char* const ProjMatrixByBinUsingRayTracing::registered_name = "Ray Tracing"; -const char * const -ProjMatrixByBinUsingRayTracing::registered_name = - "Ray Tracing"; - -ProjMatrixByBinUsingRayTracing:: -ProjMatrixByBinUsingRayTracing() -{ - set_defaults(); -} +ProjMatrixByBinUsingRayTracing::ProjMatrixByBinUsingRayTracing() { set_defaults(); } //******************** parsing ************* -void -ProjMatrixByBinUsingRayTracing::initialise_keymap() -{ +void +ProjMatrixByBinUsingRayTracing::initialise_keymap() { ProjMatrixByBin::initialise_keymap(); parser.add_start_key("Ray Tracing Matrix Parameters"); parser.add_key("restrict to cylindrical FOV", &restrict_to_cylindrical_FOV); - parser.add_key("number of rays in tangential direction to trace for each bin", - &num_tangential_LORs); + parser.add_key("number of rays in tangential direction to trace for each bin", &num_tangential_LORs); parser.add_key("use actual detector boundaries", &use_actual_detector_boundaries); parser.add_key("do_symmetry_90degrees_min_phi", &do_symmetry_90degrees_min_phi); parser.add_key("do_symmetry_180degrees_min_phi", &do_symmetry_180degrees_min_phi); @@ -94,10 +87,8 @@ ProjMatrixByBinUsingRayTracing::initialise_keymap() parser.add_stop_key("End Ray Tracing Matrix Parameters"); } - void -ProjMatrixByBinUsingRayTracing::set_defaults() -{ +ProjMatrixByBinUsingRayTracing::set_defaults() { ProjMatrixByBin::set_defaults(); this->restrict_to_cylindrical_FOV = true; this->num_tangential_LORs = 1; @@ -110,16 +101,13 @@ ProjMatrixByBinUsingRayTracing::set_defaults() this->already_setup = false; } - bool -ProjMatrixByBinUsingRayTracing::post_processing() -{ +ProjMatrixByBinUsingRayTracing::post_processing() { if (ProjMatrixByBin::post_processing() == true) return true; - if (this->num_tangential_LORs<1) - { - warning(boost::format("ProjMatrixByBinUsingRayTracing: num_tangential_LORs should be at least 1, but is %d") - % this->num_tangential_LORs); + if (this->num_tangential_LORs < 1) { + warning(boost::format("ProjMatrixByBinUsingRayTracing: num_tangential_LORs should be at least 1, but is %d") % + this->num_tangential_LORs); return true; } this->already_setup = false; @@ -129,130 +117,93 @@ ProjMatrixByBinUsingRayTracing::post_processing() //******************** get/set pairs ************* bool -ProjMatrixByBinUsingRayTracing:: -get_restrict_to_cylindrical_FOV() const -{ +ProjMatrixByBinUsingRayTracing::get_restrict_to_cylindrical_FOV() const { return this->restrict_to_cylindrical_FOV; } void -ProjMatrixByBinUsingRayTracing:: -set_restrict_to_cylindrical_FOV(bool val) -{ +ProjMatrixByBinUsingRayTracing::set_restrict_to_cylindrical_FOV(bool val) { this->already_setup = (this->restrict_to_cylindrical_FOV == val); this->restrict_to_cylindrical_FOV = val; } int -ProjMatrixByBinUsingRayTracing:: -get_num_tangential_LORs() const -{ +ProjMatrixByBinUsingRayTracing::get_num_tangential_LORs() const { return this->num_tangential_LORs; } void -ProjMatrixByBinUsingRayTracing:: -set_num_tangential_LORs(int val) -{ +ProjMatrixByBinUsingRayTracing::set_num_tangential_LORs(int val) { this->already_setup = (this->num_tangential_LORs == val); this->num_tangential_LORs = val; } bool -ProjMatrixByBinUsingRayTracing:: -get_use_actual_detector_boundaries() const -{ +ProjMatrixByBinUsingRayTracing::get_use_actual_detector_boundaries() const { return this->use_actual_detector_boundaries; } void -ProjMatrixByBinUsingRayTracing:: -set_use_actual_detector_boundaries(bool val) -{ +ProjMatrixByBinUsingRayTracing::set_use_actual_detector_boundaries(bool val) { this->already_setup = (this->use_actual_detector_boundaries == val); this->use_actual_detector_boundaries = val; } bool -ProjMatrixByBinUsingRayTracing:: -get_do_symmetry_90degrees_min_phi() const -{ +ProjMatrixByBinUsingRayTracing::get_do_symmetry_90degrees_min_phi() const { return this->do_symmetry_90degrees_min_phi; } void -ProjMatrixByBinUsingRayTracing:: -set_do_symmetry_90degrees_min_phi(bool val) -{ +ProjMatrixByBinUsingRayTracing::set_do_symmetry_90degrees_min_phi(bool val) { this->already_setup = (this->do_symmetry_90degrees_min_phi == val); this->do_symmetry_90degrees_min_phi = val; } - bool -ProjMatrixByBinUsingRayTracing:: -get_do_symmetry_180degrees_min_phi() const -{ +ProjMatrixByBinUsingRayTracing::get_do_symmetry_180degrees_min_phi() const { return this->do_symmetry_180degrees_min_phi; } void -ProjMatrixByBinUsingRayTracing:: -set_do_symmetry_180degrees_min_phi(bool val) -{ +ProjMatrixByBinUsingRayTracing::set_do_symmetry_180degrees_min_phi(bool val) { this->already_setup = (this->do_symmetry_180degrees_min_phi == val); this->do_symmetry_180degrees_min_phi = val; } - bool -ProjMatrixByBinUsingRayTracing:: -get_do_symmetry_swap_segment() const -{ +ProjMatrixByBinUsingRayTracing::get_do_symmetry_swap_segment() const { return this->do_symmetry_swap_segment; } void -ProjMatrixByBinUsingRayTracing:: -set_do_symmetry_swap_segment(bool val) -{ +ProjMatrixByBinUsingRayTracing::set_do_symmetry_swap_segment(bool val) { this->already_setup = (this->do_symmetry_swap_segment == val); this->do_symmetry_swap_segment = val; } - bool -ProjMatrixByBinUsingRayTracing:: -get_do_symmetry_swap_s() const -{ +ProjMatrixByBinUsingRayTracing::get_do_symmetry_swap_s() const { return this->do_symmetry_swap_s; } void -ProjMatrixByBinUsingRayTracing:: -set_do_symmetry_swap_s(bool val) -{ +ProjMatrixByBinUsingRayTracing::set_do_symmetry_swap_s(bool val) { this->already_setup = (this->do_symmetry_swap_s == val); this->do_symmetry_swap_s = val; } - bool -ProjMatrixByBinUsingRayTracing:: -get_do_symmetry_shift_z() const -{ +ProjMatrixByBinUsingRayTracing::get_do_symmetry_shift_z() const { return this->do_symmetry_shift_z; } void -ProjMatrixByBinUsingRayTracing:: -set_do_symmetry_shift_z(bool val) -{ +ProjMatrixByBinUsingRayTracing::set_do_symmetry_shift_z(bool val) { this->already_setup = (this->do_symmetry_shift_z == val); this->do_symmetry_shift_z = val; } - //******************** actual implementation ************* #if 0 @@ -265,82 +216,65 @@ static bool is_multiple(const float a, const float b) #endif void -ProjMatrixByBinUsingRayTracing:: -set_up( - const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) -{ - ProjMatrixByBin::set_up(proj_data_info_ptr_v, density_info_ptr); +ProjMatrixByBinUsingRayTracing::set_up( + const shared_ptr& proj_data_info_sptr_v, + const shared_ptr>& density_info_sptr_v // TODO should be Info only +) { + ProjMatrixByBin::set_up(proj_data_info_sptr_v, density_info_sptr_v); - proj_data_info_ptr= proj_data_info_ptr_v; - const VoxelsOnCartesianGrid * image_info_ptr = - dynamic_cast*> (density_info_ptr.get()); + image_info_sptr.reset(dynamic_cast*>(density_info_sptr_v->clone())); + // const VoxelsOnCartesianGrid * image_info_ptr = + // dynamic_cast*> (density_info_ptr.get()); - if (image_info_ptr == NULL) + if (is_null_ptr(image_info_sptr)) error("ProjMatrixByBinUsingRayTracing initialised with a wrong type of DiscretisedDensity\n"); - - voxel_size = image_info_ptr->get_voxel_size(); - origin = image_info_ptr->get_origin(); - if (abs(origin.x())>.05F || abs(origin.y())>.05F) - error("ProjMatrixByBinUsingRayTracing sadly doesn't support shifted x/y origin yet"); - image_info_ptr->get_regular_range(min_index, max_index); - - symmetries_sptr.reset( - new DataSymmetriesForBins_PET_CartesianGrid(proj_data_info_ptr, - density_info_ptr, - do_symmetry_90degrees_min_phi, - do_symmetry_180degrees_min_phi, - do_symmetry_swap_segment, - do_symmetry_swap_s, - do_symmetry_shift_z)); - const float sampling_distance_of_adjacent_LORs_xy = - proj_data_info_ptr->get_sampling_in_s(Bin(0,0,0,0)); - - if(sampling_distance_of_adjacent_LORs_xy/num_tangential_LORs > voxel_size.x() + 1.E-3 || - sampling_distance_of_adjacent_LORs_xy/num_tangential_LORs > voxel_size.y() + 1.E-3) - warning("WARNING: ProjMatrixByBinUsingRayTracing used for pixel size (in x,y) " - "that is smaller than the bin size divided by num_tangential_LORs.\n" - "This matrix will completely miss some voxels for some (or all) views.\n"); - if(sampling_distance_of_adjacent_LORs_xy < voxel_size.x() - 1.E-3 || - sampling_distance_of_adjacent_LORs_xy < voxel_size.y() - 1.E-3) - warning("WARNING: ProjMatrixByBinUsingRayTracing used for pixel size (in x,y) " - "that is larger than the bin size.\n" - "Backprojecting with this matrix might have artefacts at views 0 and 90 degrees.\n"); - - if (use_actual_detector_boundaries) - { - const ProjDataInfoCylindricalNoArcCorr * proj_data_info_cyl_ptr = - dynamic_cast(proj_data_info_ptr.get()); - if (proj_data_info_cyl_ptr== 0) - { - warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries" - " is reset to false as the projection data should be non-arccorected.\n"); - use_actual_detector_boundaries = false; - } - else - { - bool nocompression = - proj_data_info_cyl_ptr->get_view_mashing_factor()==1; - for (int segment_num=proj_data_info_cyl_ptr->get_min_segment_num(); - nocompression && segment_num <= proj_data_info_cyl_ptr->get_max_segment_num(); - ++segment_num) - nocompression= - proj_data_info_cyl_ptr->get_min_ring_difference(segment_num) == - proj_data_info_cyl_ptr->get_max_ring_difference(segment_num); - - if (!nocompression) - { - warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries" - " is reset to false as the projection data as either mashed or uses axial compression\n"); - use_actual_detector_boundaries = false; - } - } - if (use_actual_detector_boundaries) - warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries==true\n"); + voxel_size = image_info_sptr->get_voxel_size(); + origin = image_info_sptr->get_origin(); + if (abs(origin.x()) > .05F || abs(origin.y()) > .05F) + error("ProjMatrixByBinUsingRayTracing sadly doesn't support shifted x/y origin yet"); + image_info_sptr->get_regular_range(min_index, max_index); + + symmetries_sptr.reset(new DataSymmetriesForBins_PET_CartesianGrid( + proj_data_info_sptr, density_info_sptr_v, do_symmetry_90degrees_min_phi, do_symmetry_180degrees_min_phi, + do_symmetry_swap_segment, do_symmetry_swap_s, do_symmetry_shift_z)); + const float sampling_distance_of_adjacent_LORs_xy = proj_data_info_sptr->get_sampling_in_s(Bin(0, 0, 0, 0)); + + if (sampling_distance_of_adjacent_LORs_xy / num_tangential_LORs > voxel_size.x() + 1.E-3 || + sampling_distance_of_adjacent_LORs_xy / num_tangential_LORs > voxel_size.y() + 1.E-3) + warning("WARNING: ProjMatrixByBinUsingRayTracing used for pixel size (in x,y) " + "that is smaller than the bin size divided by num_tangential_LORs.\n" + "This matrix will completely miss some voxels for some (or all) views.\n"); + if (sampling_distance_of_adjacent_LORs_xy < voxel_size.x() - 1.E-3 || + sampling_distance_of_adjacent_LORs_xy < voxel_size.y() - 1.E-3) + warning("WARNING: ProjMatrixByBinUsingRayTracing used for pixel size (in x,y) " + "that is larger than the bin size.\n" + "Backprojecting with this matrix might have artefacts at views 0 and 90 degrees.\n"); + + if (use_actual_detector_boundaries) { + const ProjDataInfoCylindricalNoArcCorr* proj_data_info_cyl_ptr = + dynamic_cast(proj_data_info_sptr.get()); + if (proj_data_info_cyl_ptr == 0) { + warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries" + " is reset to false as the projection data should be non-arccorected.\n"); + use_actual_detector_boundaries = false; + } else { + bool nocompression = proj_data_info_cyl_ptr->get_view_mashing_factor() == 1; + for (int segment_num = proj_data_info_cyl_ptr->get_min_segment_num(); + nocompression && segment_num <= proj_data_info_cyl_ptr->get_max_segment_num(); ++segment_num) + nocompression = proj_data_info_cyl_ptr->get_min_ring_difference(segment_num) == + proj_data_info_cyl_ptr->get_max_ring_difference(segment_num); + + if (!nocompression) { + warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries" + " is reset to false as the projection data as either mashed or uses axial compression\n"); + use_actual_detector_boundaries = false; + } + } - } + if (use_actual_detector_boundaries) + warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries==true\n"); + } #if 0 // test if our 2D code does not have problems @@ -357,19 +291,20 @@ set_up( } #endif - this->already_setup = true; this->clear_cache(); }; -/* this is used when +ProjMatrixByBinUsingRayTracing* +ProjMatrixByBinUsingRayTracing::clone() const { + return new ProjMatrixByBinUsingRayTracing(*this); +} + +/* this is used when (tantheta==0 && sampling_distance_of_adjacent_LORs_z==2*voxel_size.z()) it adds two adjacents z with their half value */ -static void -add_adjacent_z(ProjMatrixElemsForOneBin& lor, - const float z_of_first_voxel, - const float right_edge_of_TOR); +static void add_adjacent_z(ProjMatrixElemsForOneBin& lor, const float z_of_first_voxel, const float right_edge_of_TOR); #if 0 /* Complicated business to add the same values at z+1 @@ -381,91 +316,76 @@ static void merge_zplus1(ProjMatrixElemsForOneBin& lor); #endif template -static inline int sign(const T& t) -{ - return t<0 ? -1 : 1; +static inline int +sign(const T& t) { + return t < 0 ? -1 : 1; } // just do 1 LOR, returns true if lor is not empty static void -ray_trace_one_lor(ProjMatrixElemsForOneBin& lor, - const float s_in_mm, const float t_in_mm, - const float cphi, const float sphi, - const float costheta, const float tantheta, - const float offset_in_z, - const float fovrad_in_mm, - const CartesianCoordinate3D& voxel_size, - const bool restrict_to_cylindrical_FOV, - const int num_LORs) -{ +ray_trace_one_lor(ProjMatrixElemsForOneBin& lor, const float s_in_mm, const float t_in_mm, const float cphi, const float sphi, + const float costheta, const float tantheta, const float offset_in_z, const float fovrad_in_mm, + const CartesianCoordinate3D& voxel_size, const bool restrict_to_cylindrical_FOV, const int num_LORs) { assert(lor.size() == 0); /* Find Intersection points of LOR and image FOV (assuming infinitely long scanner)*/ /* (in voxel units) */ - CartesianCoordinate3D start_point; + CartesianCoordinate3D start_point; CartesianCoordinate3D stop_point; { /* parametrisation of LOR is - X= s*cphi + a*sphi, - Y= s*sphi - a*cphi, + X= s*cphi + a*sphi, + Y= s*sphi - a*cphi, Z= t/costheta+offset_in_z - a*tantheta - find now min_a, max_a such that end-points intersect border of FOV + find now min_a, max_a such that end-points intersect border of FOV */ float max_a; float min_a; - - if (restrict_to_cylindrical_FOV) - { + + if (restrict_to_cylindrical_FOV) { #ifdef STIR_PMRT_LARGER_FOV - if (fabs(s_in_mm) >= fovrad_in_mm) return; + if (fabs(s_in_mm) >= fovrad_in_mm) + return; #else - if (fabs(s_in_mm) > fovrad_in_mm) return; + if (fabs(s_in_mm) > fovrad_in_mm) + return; #endif - // a has to be such that X^2+Y^2 == fovrad^2 - if (fabs(s_in_mm) == fovrad_in_mm) - { - max_a = min_a = 0; - } - else - { - max_a = sqrt(square(fovrad_in_mm) - square(s_in_mm)); - min_a = -max_a; - } + // a has to be such that X^2+Y^2 == fovrad^2 + if (fabs(s_in_mm) == fovrad_in_mm) { + max_a = min_a = 0; + } else { + max_a = sqrt(square(fovrad_in_mm) - square(s_in_mm)); + min_a = -max_a; + } } // restrict_to_cylindrical_FOV - else - { + else { // use FOV which is square. // note that we use square and not rectangular as otherwise symmetries // would take us out of the FOV. TODO /* - a has to be such that + a has to be such that |X| <= fovrad_in_mm && |Y| <= fovrad_in_mm */ - if (fabs(cphi) < 1.E-3 || fabs(sphi) < 1.E-3) - { + if (fabs(cphi) < 1.E-3 || fabs(sphi) < 1.E-3) { if (fovrad_in_mm < fabs(s_in_mm)) return; max_a = fovrad_in_mm; min_a = -fovrad_in_mm; - } - else - { - max_a = min((fovrad_in_mm*sign(sphi) - s_in_mm*cphi)/sphi, - (fovrad_in_mm*sign(cphi) + s_in_mm*sphi)/cphi); - min_a = max((-fovrad_in_mm*sign(sphi) - s_in_mm*cphi)/sphi, - (-fovrad_in_mm*sign(cphi) + s_in_mm*sphi)/cphi); - if (min_a > max_a - 1.E-3*voxel_size.x()) + } else { + max_a = min((fovrad_in_mm * sign(sphi) - s_in_mm * cphi) / sphi, (fovrad_in_mm * sign(cphi) + s_in_mm * sphi) / cphi); + min_a = max((-fovrad_in_mm * sign(sphi) - s_in_mm * cphi) / sphi, (-fovrad_in_mm * sign(cphi) + s_in_mm * sphi) / cphi); + if (min_a > max_a - 1.E-3 * voxel_size.x()) return; } - - } //!restrict_to_cylindrical_FOV - - start_point.x() = (s_in_mm*cphi + max_a*sphi)/voxel_size.x(); - start_point.y() = (s_in_mm*sphi - max_a*cphi)/voxel_size.y(); - start_point.z() = (t_in_mm/costheta+offset_in_z - max_a*tantheta)/voxel_size.z(); - stop_point.x() = (s_in_mm*cphi + min_a*sphi)/voxel_size.x(); - stop_point.y() = (s_in_mm*sphi - min_a*cphi)/voxel_size.y(); - stop_point.z() = (t_in_mm/costheta+offset_in_z - min_a*tantheta)/voxel_size.z(); + + } //! restrict_to_cylindrical_FOV + + start_point.x() = (s_in_mm * cphi + max_a * sphi) / voxel_size.x(); + start_point.y() = (s_in_mm * sphi - max_a * cphi) / voxel_size.y(); + start_point.z() = (t_in_mm / costheta + offset_in_z - max_a * tantheta) / voxel_size.z(); + stop_point.x() = (s_in_mm * cphi + min_a * sphi) / voxel_size.x(); + stop_point.y() = (s_in_mm * sphi - min_a * cphi) / voxel_size.y(); + stop_point.z() = (t_in_mm / costheta + offset_in_z - min_a * tantheta) / voxel_size.z(); #if 0 // KT 18/05/2005 this is no longer necessary @@ -492,61 +412,52 @@ ray_trace_one_lor(ProjMatrixElemsForOneBin& lor, #endif // find out in which direction we should do the ray tracing to obtain a sorted lor - // we want to go from small z to large z, + // we want to go from small z to large z, // or if z are equal, from small y to large y and so on const bool from_start_to_stop = - start_point.z() < stop_point.z() || - (start_point.z() == stop_point.z() && - (start_point.y() < stop_point.y() || - (start_point.y() == stop_point.y() && - (start_point.x() <= stop_point.x())))); + start_point.z() < stop_point.z() || + (start_point.z() == stop_point.z() && + (start_point.y() < stop_point.y() || (start_point.y() == stop_point.y() && (start_point.x() <= stop_point.x())))); // do actual ray tracing for this LOR - - RayTraceVoxelsOnCartesianGrid(lor, - from_start_to_stop? start_point : stop_point, - !from_start_to_stop? start_point : stop_point, - voxel_size, + + RayTraceVoxelsOnCartesianGrid(lor, from_start_to_stop ? start_point : stop_point, + !from_start_to_stop ? start_point : stop_point, voxel_size, #ifdef NEWSCALE - 1.F/num_LORs // normalise to mm + 1.F / num_LORs // normalise to mm #else - 1/voxel_size.x()/num_LORs // normalise to some kind of 'pixel units' + 1 / voxel_size.x() / num_LORs // normalise to some kind of 'pixel units' #endif - ); + ); #ifndef NDEBUG { // TODO output is still not sorted... why? - //ProjMatrixElemsForOneBin sorted_lor = lor; - //sorted_lor.sort(); - //assert(lor == sorted_lor); + // ProjMatrixElemsForOneBin sorted_lor = lor; + // sorted_lor.sort(); + // assert(lor == sorted_lor); lor.check_state(); } #endif return; } - } ////////////////////////////////////// -void -ProjMatrixByBinUsingRayTracing:: -calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ - if (!this->already_setup) - { - error("ProjMatrixByBinUsingRayTracing used before calling setup"); - } +void +ProjMatrixByBinUsingRayTracing::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { + if (!this->already_setup) { + error("ProjMatrixByBinUsingRayTracing used before calling setup"); + } const Bin bin = lor.get_bin(); - assert(bin.segment_num() >= proj_data_info_ptr->get_min_segment_num()); - assert(bin.segment_num() <= proj_data_info_ptr->get_max_segment_num()); + assert(bin.segment_num() >= proj_data_info_sptr->get_min_segment_num()); + assert(bin.segment_num() <= proj_data_info_sptr->get_max_segment_num()); assert(lor.size() == 0); - + float phi; - float s_in_mm = proj_data_info_ptr->get_s(bin); + float s_in_mm = proj_data_info_sptr->get_s(bin); /* Implementation note. KT initialised s_in_mm above instead of in the if because this meant that gcc 3.0.1 generated identical results to the previous version of this file. @@ -555,69 +466,55 @@ calculate_proj_matrix_elems_for_one_bin( on Linux on x86. A bit of a mistery that. - TODO this is maybe solved now by having more decent handling of + TODO this is maybe solved now by having more decent handling of start and end voxels. */ - if (!use_actual_detector_boundaries) - { - phi = proj_data_info_ptr->get_phi(bin); - //s_in_mm = proj_data_info_ptr->get_s(bin); - } - else - { + if (!use_actual_detector_boundaries) { + phi = proj_data_info_sptr->get_phi(bin); + // s_in_mm = proj_data_info_sptr->get_s(bin); + } else { // can be static_cast later on const ProjDataInfoCylindricalNoArcCorr& proj_data_info_noarccor = - dynamic_cast(*proj_data_info_ptr); + dynamic_cast(*proj_data_info_sptr); // TODO check on 180 degrees for views - const int num_detectors = - proj_data_info_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); - const float ring_radius = - proj_data_info_ptr->get_scanner_ptr()->get_effective_ring_radius(); - - int det_num1=0, det_num2=0; - proj_data_info_noarccor. - get_det_num_pair_for_view_tangential_pos_num(det_num1, - det_num2, - bin.view_num(), - bin.tangential_pos_num()); - phi = static_cast((det_num1+det_num2)*_PI/num_detectors-_PI/2); - const float old_phi=proj_data_info_ptr->get_phi(bin); - if (fabs(phi-old_phi)>2*_PI/num_detectors) - warning("view %d old_phi %g new_phi %g\n",bin.view_num(), old_phi, phi); - - s_in_mm = static_cast(ring_radius*sin((det_num1-det_num2)*_PI/num_detectors+_PI/2)); - const float old_s_in_mm=proj_data_info_ptr->get_s(bin); - if (fabs(s_in_mm-old_s_in_mm)>proj_data_info_ptr->get_sampling_in_s(bin)*.0001) - warning("tangential_pos_num %d old_s_in_mm %g new_s_in_mm %g\n",bin.tangential_pos_num(), old_s_in_mm, s_in_mm); - + const int num_detectors = proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring(); + const float ring_radius = proj_data_info_sptr->get_scanner_ptr()->get_effective_ring_radius(); + + int det_num1 = 0, det_num2 = 0; + proj_data_info_noarccor.get_det_num_pair_for_view_tangential_pos_num(det_num1, det_num2, bin.view_num(), + bin.tangential_pos_num()); + phi = static_cast((det_num1 + det_num2) * _PI / num_detectors - _PI / 2); + const float old_phi = proj_data_info_sptr->get_phi(bin); + if (fabs(phi - old_phi) > 2 * _PI / num_detectors) + warning("view %d old_phi %g new_phi %g\n", bin.view_num(), old_phi, phi); + + s_in_mm = static_cast(ring_radius * sin((det_num1 - det_num2) * _PI / num_detectors + _PI / 2)); + const float old_s_in_mm = proj_data_info_sptr->get_s(bin); + if (fabs(s_in_mm - old_s_in_mm) > proj_data_info_sptr->get_sampling_in_s(bin) * .0001) + warning("tangential_pos_num %d old_s_in_mm %g new_s_in_mm %g\n", bin.tangential_pos_num(), old_s_in_mm, s_in_mm); } - + const float cphi = cos(phi); const float sphi = sin(phi); - - const float tantheta = proj_data_info_ptr->get_tantheta(bin); - const float costheta = 1/sqrt(1+square(tantheta)); - const float t_in_mm = proj_data_info_ptr->get_t(bin); - - const float sampling_distance_of_adjacent_LORs_z = - proj_data_info_ptr->get_sampling_in_t(bin)/costheta; - + + const float tantheta = proj_data_info_sptr->get_tantheta(bin); + const float costheta = 1 / sqrt(1 + square(tantheta)); + const float t_in_mm = proj_data_info_sptr->get_t(bin); + + const float sampling_distance_of_adjacent_LORs_z = proj_data_info_sptr->get_sampling_in_t(bin) / costheta; // find number of LORs we have to take, such that we don't miss voxels // we have to subtract a tiny amount from the quotient, to avoid having too many LORs // solely due to numerical rounding errors - const int num_lors_per_axial_pos = - static_cast(ceil(sampling_distance_of_adjacent_LORs_z / voxel_size.z() - 1.E-3)); + const int num_lors_per_axial_pos = static_cast(ceil(sampling_distance_of_adjacent_LORs_z / voxel_size.z() - 1.E-3)); - assert(num_lors_per_axial_pos>0); + assert(num_lors_per_axial_pos > 0); // theta=0 assumes that centre of 1 voxel coincides with centre of bin. // TODO test - //if (num_lors_per_axial_pos>1 && tantheta==0 num_lors_per_axial_pos%2==0); + // if (num_lors_per_axial_pos>1 && tantheta==0 num_lors_per_axial_pos%2==0); // merging code assumes integer multiple - assert(fabs(sampling_distance_of_adjacent_LORs_z/voxel_size.z() - - num_lors_per_axial_pos) <= 1E-4); - + assert(fabs(sampling_distance_of_adjacent_LORs_z / voxel_size.z() - num_lors_per_axial_pos) <= 1E-4); // find offset in z, taking into account if there are 1 or more LORs // KT 20/06/2001 take origin.z() into account @@ -632,106 +529,73 @@ calculate_proj_matrix_elems_for_one_bin( dz = sampling_distance_of_adjacent_LORs_z/num_lors_per_axial_pos. Then you have to make sure that the middle of the set of rays for this bin corresponds to the middle of the TOR, i.e. the offset given above for 1 ray. - So, we put the rays from + So, we put the rays from -dz*(num_lors_per_axial_pos-1)/2 to +dz*(num_lors_per_axial_pos-1)/2 Now we look at direct rays (tantheta=0).We have to choose rays which - do not go exactly on the edge of 2 planes as this would give unreliable + do not go exactly on the edge of 2 planes as this would give unreliable results due to rounding errors. - In addition, we can give a weight to the rays according to how much the + In addition, we can give a weight to the rays according to how much the voxel overlaps with the TOR (in axial direction). - Note that RayTracing* now sorts this out itself, so we could dispense with this + Note that RayTracing* now sorts this out itself, so we could dispense with this complication here. However, we can do it slightly more efficient here as we might be using 2 rays for one ring. */ const float z_position_of_first_LOR_wrt_centre_of_TOR = - (-sampling_distance_of_adjacent_LORs_z/(2*num_lors_per_axial_pos)* - (num_lors_per_axial_pos-1)) - - origin.z(); - float offset_in_z = - z_position_of_first_LOR_wrt_centre_of_TOR - +(max_index.z()+min_index.z())/2.F * voxel_size.z(); - - if (tantheta==0) - { - // make sure we don't ray-trace exactly between 2 planes - // z-coordinate (in voxel units) will be - // (t_in_mm+offset_in_z)/voxel_size.z(); - // if so, we ray trace first to the voxels at smaller z, but will add the - // other plane later (in add_adjacent_z) - if (fabs(modulo((t_in_mm+offset_in_z)/voxel_size.z(),1.F)-.5)<.001) - offset_in_z -= .1F*voxel_size.z(); - } - + (-sampling_distance_of_adjacent_LORs_z / (2 * num_lors_per_axial_pos) * (num_lors_per_axial_pos - 1)) - origin.z(); + float offset_in_z = z_position_of_first_LOR_wrt_centre_of_TOR + (max_index.z() + min_index.z()) / 2.F * voxel_size.z(); + + if (tantheta == 0) { + // make sure we don't ray-trace exactly between 2 planes + // z-coordinate (in voxel units) will be + // (t_in_mm+offset_in_z)/voxel_size.z(); + // if so, we ray trace first to the voxels at smaller z, but will add the + // other plane later (in add_adjacent_z) + if (fabs(modulo((t_in_mm + offset_in_z) / voxel_size.z(), 1.F) - .5) < .001) + offset_in_z -= .1F * voxel_size.z(); + } // use FOV which is slightly 'inside' the image to avoid // index out of range #ifdef STIR_PMRT_LARGER_FOV - const float fovrad_in_mm = - min((min(max_index.x(), -min_index.x())+.45F)*voxel_size.x(), - (min(max_index.y(), -min_index.y())+.45F)*voxel_size.y()); + const float fovrad_in_mm = min((min(max_index.x(), -min_index.x()) + .45F) * voxel_size.x(), + (min(max_index.y(), -min_index.y()) + .45F) * voxel_size.y()); #else - const float fovrad_in_mm = - min((min(max_index.x(), -min_index.x()))*voxel_size.x(), - (min(max_index.y(), -min_index.y()))*voxel_size.y()); + const float fovrad_in_mm = + min((min(max_index.x(), -min_index.x())) * voxel_size.x(), (min(max_index.y(), -min_index.y())) * voxel_size.y()); #endif - if (num_tangential_LORs == 1) - { - ray_trace_one_lor(lor, s_in_mm, t_in_mm, - cphi, sphi, costheta, tantheta, - offset_in_z, fovrad_in_mm, - voxel_size, - restrict_to_cylindrical_FOV, - num_lors_per_axial_pos); - } - else - { + if (num_tangential_LORs == 1) { + ray_trace_one_lor(lor, s_in_mm, t_in_mm, cphi, sphi, costheta, tantheta, offset_in_z, fovrad_in_mm, voxel_size, + restrict_to_cylindrical_FOV, num_lors_per_axial_pos); + } else { ProjMatrixElemsForOneBin ray_traced_lor; // get_sampling_in_s returns sampling in interleaved case // interleaved case has a sampling which is twice as high - const float s_inc = - (!use_actual_detector_boundaries ? 1 : 2) * - proj_data_info_ptr->get_sampling_in_s(bin)/num_tangential_LORs; - float current_s_in_mm = - s_in_mm - s_inc*(num_tangential_LORs-1)/2.F; - for (int s_LOR_num=1; s_LOR_num<=num_tangential_LORs; ++s_LOR_num, current_s_in_mm+=s_inc) - { + const float s_inc = + (!use_actual_detector_boundaries ? 1 : 2) * proj_data_info_sptr->get_sampling_in_s(bin) / num_tangential_LORs; + float current_s_in_mm = s_in_mm - s_inc * (num_tangential_LORs - 1) / 2.F; + for (int s_LOR_num = 1; s_LOR_num <= num_tangential_LORs; ++s_LOR_num, current_s_in_mm += s_inc) { ray_traced_lor.erase(); - ray_trace_one_lor(ray_traced_lor, current_s_in_mm, t_in_mm, - cphi, sphi, costheta, tantheta, - offset_in_z, fovrad_in_mm, - voxel_size, - restrict_to_cylindrical_FOV, - num_lors_per_axial_pos*num_tangential_LORs); - //std::cerr << "ray traced size " << ray_traced_lor.size() << std::endl; + ray_trace_one_lor(ray_traced_lor, current_s_in_mm, t_in_mm, cphi, sphi, costheta, tantheta, offset_in_z, fovrad_in_mm, + voxel_size, restrict_to_cylindrical_FOV, num_lors_per_axial_pos * num_tangential_LORs); + // std::cerr << "ray traced size " << ray_traced_lor.size() << std::endl; lor.merge(ray_traced_lor); } } - + // now add on other LORs in axial direction - if (lor.size()>0) - { - if (tantheta==0 ) - { - const float z_of_first_voxel= - lor.begin()->coord1() + - origin.z()/voxel_size.z() - - (max_index.z() + min_index.z())/2.F; - const float left_edge_of_TOR = - (t_in_mm - sampling_distance_of_adjacent_LORs_z/2 - )/voxel_size.z(); - const float right_edge_of_TOR = - (t_in_mm + sampling_distance_of_adjacent_LORs_z/2 - )/voxel_size.z(); - - add_adjacent_z(lor, z_of_first_voxel - left_edge_of_TOR, right_edge_of_TOR -left_edge_of_TOR); - } - else if (num_lors_per_axial_pos>1) - { + if (lor.size() > 0) { + if (tantheta == 0) { + const float z_of_first_voxel = lor.begin()->coord1() + origin.z() / voxel_size.z() - (max_index.z() + min_index.z()) / 2.F; + const float left_edge_of_TOR = (t_in_mm - sampling_distance_of_adjacent_LORs_z / 2) / voxel_size.z(); + const float right_edge_of_TOR = (t_in_mm + sampling_distance_of_adjacent_LORs_z / 2) / voxel_size.z(); + + add_adjacent_z(lor, z_of_first_voxel - left_edge_of_TOR, right_edge_of_TOR - left_edge_of_TOR); + } else if (num_lors_per_axial_pos > 1) { #if 0 if (num_lors_per_axial_pos==2) { @@ -739,123 +603,92 @@ calculate_proj_matrix_elems_for_one_bin( } else #endif - { - // make copy of LOR that will be used to add adjacent z - ProjMatrixElemsForOneBin lor_with_next_z = lor; - // reserve enough memory to avoid reallocations - lor.reserve(lor.size()*num_lors_per_axial_pos); - // now add adjacent z - for (int z_index=1; z_index(element_ptr->coord1()+1, - element_ptr->coord2(), - element_ptr->coord3()), - element_ptr->get_value()); - ++element_ptr; - } - // now merge it into the original - lor.merge(lor_with_next_z); - } + { + // make copy of LOR that will be used to add adjacent z + ProjMatrixElemsForOneBin lor_with_next_z = lor; + // reserve enough memory to avoid reallocations + lor.reserve(lor.size() * num_lors_per_axial_pos); + // now add adjacent z + for (int z_index = 1; z_index < num_lors_per_axial_pos; ++z_index) { + // add 1 to each z in the LOR + ProjMatrixElemsForOneBin::iterator element_ptr = lor_with_next_z.begin(); + const ProjMatrixElemsForOneBin::iterator element_end = lor_with_next_z.end(); + while (element_ptr != element_end) { + *element_ptr = ProjMatrixElemsForOneBin::value_type( + Coordinate3D(element_ptr->coord1() + 1, element_ptr->coord2(), element_ptr->coord3()), + element_ptr->get_value()); + ++element_ptr; } - } // if( tantheta!=0 && num_lors_per_axial_pos>1) - } //if (lor.size()!=0) - + // now merge it into the original + lor.merge(lor_with_next_z); + } + } + } // if( tantheta!=0 && num_lors_per_axial_pos>1) + } // if (lor.size()!=0) } -static void -add_adjacent_z(ProjMatrixElemsForOneBin& lor, - const float z_of_first_voxel, - const float right_edge_of_TOR) -{ - assert(lor.size()>0); - assert(z_of_first_voxel+.5>=0); - assert(z_of_first_voxel-.5<=right_edge_of_TOR); +static void +add_adjacent_z(ProjMatrixElemsForOneBin& lor, const float z_of_first_voxel, const float right_edge_of_TOR) { + assert(lor.size() > 0); + assert(z_of_first_voxel + .5 >= 0); + assert(z_of_first_voxel - .5 <= right_edge_of_TOR); // first reserve enough memory for the whole vector // this speeds things up. - const int num_overlapping_voxels = - round(ceil(right_edge_of_TOR-z_of_first_voxel+.5)); + const int num_overlapping_voxels = round(ceil(right_edge_of_TOR - z_of_first_voxel + .5)); lor.reserve(lor.size() * num_overlapping_voxels); - + // point to end of original LOR, i.e. first plane // const ProjMatrixElemsForOneBin::const_iterator element_end = lor.end(); const std::size_t org_size = lor.size(); - for (int z_index= 1; /* no end condition here */; ++z_index) + for (int z_index = 1; /* no end condition here */; ++z_index) { + const float overlap_of_voxel_with_TOR = + std::min(right_edge_of_TOR, z_of_first_voxel + z_index + .5F) - std::max(0.F, z_of_first_voxel + z_index - .5F); + if (overlap_of_voxel_with_TOR <= 0.0001) // check if beyond TOR or overlap too small to bother { - const float overlap_of_voxel_with_TOR = - std::min(right_edge_of_TOR, z_of_first_voxel + z_index + .5F) - - std::max(0.F, z_of_first_voxel + z_index - .5F); - if (overlap_of_voxel_with_TOR<=0.0001) // check if beyond TOR or overlap too small to bother - { - assert(num_overlapping_voxels>=z_index); - break; - } - assert(overlap_of_voxel_with_TOR < 1.0001); - const int new_z = lor.begin()->coord1()+z_index; - if (overlap_of_voxel_with_TOR>.9999) // test if it is 1 - { - // just copy the value - std::size_t count = 0; // counter for elements in original LOR - for ( ProjMatrixElemsForOneBin::const_iterator element_ptr = lor.begin(); - count != org_size; //element_ptr != element_end; - ++element_ptr, ++count) - { - assert(lor.size()+1 <= lor.capacity()); // not really necessary now, but check on reserve() best for performance - assert(new_z == element_ptr->coord1()+z_index); - lor.push_back( - ProjMatrixElemsForOneBin:: - value_type( - Coordinate3D(new_z, - element_ptr->coord2(), - element_ptr->coord3()), - element_ptr->get_value())); - } - } - else - { - // multiply the value with the overlap - std::size_t count = 0; // counter for elements in original LOR - for ( ProjMatrixElemsForOneBin::const_iterator element_ptr = lor.begin(); - count != org_size; //element_ptr != element_end; - ++element_ptr, ++count) - { - assert(lor.size()+1 <= lor.capacity()); - assert(new_z == element_ptr->coord1()+z_index); - lor.push_back( - ProjMatrixElemsForOneBin:: - value_type( - Coordinate3D(new_z, - element_ptr->coord2(), - element_ptr->coord3()), - element_ptr->get_value()*overlap_of_voxel_with_TOR)); - } - } - } // loop over z_index + assert(num_overlapping_voxels >= z_index); + break; + } + assert(overlap_of_voxel_with_TOR < 1.0001); + const int new_z = lor.begin()->coord1() + z_index; + if (overlap_of_voxel_with_TOR > .9999) // test if it is 1 + { + // just copy the value + std::size_t count = 0; // counter for elements in original LOR + for (ProjMatrixElemsForOneBin::const_iterator element_ptr = lor.begin(); count != org_size; // element_ptr != element_end; + ++element_ptr, ++count) { + assert(lor.size() + 1 <= lor.capacity()); // not really necessary now, but check on reserve() best for performance + assert(new_z == element_ptr->coord1() + z_index); + lor.push_back(ProjMatrixElemsForOneBin::value_type(Coordinate3D(new_z, element_ptr->coord2(), element_ptr->coord3()), + element_ptr->get_value())); + } + } else { + // multiply the value with the overlap + std::size_t count = 0; // counter for elements in original LOR + for (ProjMatrixElemsForOneBin::const_iterator element_ptr = lor.begin(); count != org_size; // element_ptr != element_end; + ++element_ptr, ++count) { + assert(lor.size() + 1 <= lor.capacity()); + assert(new_z == element_ptr->coord1() + z_index); + lor.push_back(ProjMatrixElemsForOneBin::value_type(Coordinate3D(new_z, element_ptr->coord2(), element_ptr->coord3()), + element_ptr->get_value() * overlap_of_voxel_with_TOR)); + } + } + } // loop over z_index // now check original z { const float overlap_of_voxel_with_TOR = - std::min(right_edge_of_TOR, z_of_first_voxel + .5F) - - std::max(0.F, z_of_first_voxel - .5F); - assert (overlap_of_voxel_with_TOR>0); + std::min(right_edge_of_TOR, z_of_first_voxel + .5F) - std::max(0.F, z_of_first_voxel - .5F); + assert(overlap_of_voxel_with_TOR > 0); assert(overlap_of_voxel_with_TOR < 1.0001); - if (overlap_of_voxel_with_TOR<.9999) // test if it is 1 - { - // multiply the value with the overlap - std::size_t count = 0; // counter for elements in original LOR - for ( ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - count != org_size; //element_ptr != element_end; - ++element_ptr, ++count) - *element_ptr *= overlap_of_voxel_with_TOR; - } + if (overlap_of_voxel_with_TOR < .9999) // test if it is 1 + { + // multiply the value with the overlap + std::size_t count = 0; // counter for elements in original LOR + for (ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); count != org_size; // element_ptr != element_end; + ++element_ptr, ++count) + *element_ptr *= overlap_of_voxel_with_TOR; + } } #ifndef NDEBUG { @@ -893,7 +726,7 @@ static void merge_zplus1(ProjMatrixElemsForOneBin& lor) lor.reserve(lor.size()*2); cerr << "before merge\n"; -#if 0 +# if 0 ProjMatrixElemsForOneBin::const_iterator iter = lor.begin(); while (iter!= lor.end()) { @@ -902,7 +735,7 @@ static void merge_zplus1(ProjMatrixElemsForOneBin& lor) << '\n'; ++iter; } -#endif +# endif float next_value; @@ -941,4 +774,3 @@ static void merge_zplus1(ProjMatrixElemsForOneBin& lor) #endif END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/ProjMatrixElemsForOneBin.cxx b/src/recon_buildblock/ProjMatrixElemsForOneBin.cxx index 15807d9763..ae8b6a9e73 100644 --- a/src/recon_buildblock/ProjMatrixElemsForOneBin.cxx +++ b/src/recon_buildblock/ProjMatrixElemsForOneBin.cxx @@ -22,15 +22,15 @@ \file \ingroup projection \brief non-inline implementations for stir::ProjMatrixElemsForOneBin - + \author Mustapha Sadki \author Kris Thielemans \author PARAPET project - + */ /* History - KT 15/05/2002 + KT 15/05/2002 rewrote merge(). it worked only on sorted arrays before, while the end-result wasn't sorted */ #include "stir/Succeeded.h" @@ -50,87 +50,67 @@ using std::copy; START_NAMESPACE_STIR - -ProjMatrixElemsForOneBin:: -ProjMatrixElemsForOneBin(const Bin& bin, const int default_capacity) -: bin(bin) -{ - elements.reserve(default_capacity); +ProjMatrixElemsForOneBin::ProjMatrixElemsForOneBin(const Bin& bin, const int default_capacity) : bin(bin) { + elements.reserve(default_capacity); } - -void -ProjMatrixElemsForOneBin:: -reserve(size_type max_number) -{ +void +ProjMatrixElemsForOneBin::reserve(size_type max_number) { elements.reserve(max_number); } - -void ProjMatrixElemsForOneBin::erase() -{ +void +ProjMatrixElemsForOneBin::erase() { elements.resize(0); } -ProjMatrixElemsForOneBin::size_type -ProjMatrixElemsForOneBin:: -capacity() const -{ +ProjMatrixElemsForOneBin::size_type +ProjMatrixElemsForOneBin::capacity() const { return elements.capacity(); } -ProjMatrixElemsForOneBin& ProjMatrixElemsForOneBin::operator*=(const float d) -{ +ProjMatrixElemsForOneBin& +ProjMatrixElemsForOneBin::operator*=(const float d) { // KT 21/02/2002 added check on 1 - if (d != 1.F) - { + if (d != 1.F) { iterator element_ptr = begin(); - while (element_ptr != end()) - { - *element_ptr *= d; + while (element_ptr != end()) { + *element_ptr *= d; ++element_ptr; } - } + } return *this; } -ProjMatrixElemsForOneBin& ProjMatrixElemsForOneBin::operator/=(const float d) -{ - assert( d != 0); +ProjMatrixElemsForOneBin& +ProjMatrixElemsForOneBin::operator/=(const float d) { + assert(d != 0); // KT 21/02/2002 added check on 1 - if (d != 1.F) - { + if (d != 1.F) { iterator element_ptr = begin(); - while (element_ptr != end()) - { + while (element_ptr != end()) { *element_ptr /= d; ++element_ptr; - } + } } return *this; } - -Succeeded ProjMatrixElemsForOneBin::check_state() const -{ +Succeeded +ProjMatrixElemsForOneBin::check_state() const { Succeeded success = Succeeded::yes; - if (size()==0) + if (size() == 0) return success; ProjMatrixElemsForOneBin lor = *this; lor.sort(); - - for (ProjMatrixElemsForOneBin::const_iterator lor_iter = lor.begin(); - lor_iter != lor.end()-1; - ++lor_iter) - { - if (value_type::coordinates_equal(*lor_iter, *(lor_iter+1))) - { - warning("ProjMatrixElemsForOneBin: coordinates occur more than once %d,%d,%d for bin s=%d, v=%d, a=%d, t=%d\n", - lor_iter->coord1(), lor_iter->coord2(), lor_iter->coord3(), - bin.segment_num(), bin.view_num(), - bin.axial_pos_num(), bin.tangential_pos_num()); + + for (ProjMatrixElemsForOneBin::const_iterator lor_iter = lor.begin(); lor_iter != lor.end() - 1; ++lor_iter) { + if (value_type::coordinates_equal(*lor_iter, *(lor_iter + 1))) { + warning("ProjMatrixElemsForOneBin: coordinates occur more than once %d,%d,%d for bin s=%d, tofbin=%d, v=%d, a=%d, t=%d\n", + lor_iter->coord1(), lor_iter->coord2(), lor_iter->coord3(), bin.segment_num(), bin.timing_pos_num(), bin.view_num(), + bin.axial_pos_num(), bin.tangential_pos_num()); #if 0 const_iterator iter = begin(); while (iter!= end()) @@ -147,129 +127,110 @@ Succeeded ProjMatrixElemsForOneBin::check_state() const return success; } - -void ProjMatrixElemsForOneBin::sort() -{ +void +ProjMatrixElemsForOneBin::sort() { // need explicit std:: here to resolve possible name conflict // this might give you trouble if your compiler does not support namespaces #if !defined(STIR_NO_NAMESPACES) || (__GNUC__ == 2 && __GNUC_MINOR__ <= 8) std:: -#endif - sort(begin(), end(), value_type::coordinates_less); +#endif + sort(begin(), end(), value_type::coordinates_less); } - -float ProjMatrixElemsForOneBin::square_sum() const -{ - float sq_sum=0; +float +ProjMatrixElemsForOneBin::square_sum() const { + float sq_sum = 0; const_iterator element_ptr = begin(); - while (element_ptr != end()) - { - sq_sum += square(element_ptr->get_value()); + while (element_ptr != end()) { + sq_sum += square(element_ptr->get_value()); ++element_ptr; - } + } return sq_sum; } // TODO make sure we can have a const argument -void -ProjMatrixElemsForOneBin:: -merge( ProjMatrixElemsForOneBin &lor2 ) -{ +void +ProjMatrixElemsForOneBin::merge(ProjMatrixElemsForOneBin& lor2) { assert(check_state() == Succeeded::yes); assert(lor2.check_state() == Succeeded::yes); - if (lor2.size()==0) + if (lor2.size() == 0) return; #ifndef NDEBUG // we will check at the end of the total probability is conserved, so we compute it first float old_sum = 0; - for (const_iterator iter= begin(); iter != end(); ++iter) - old_sum+= iter->get_value(); - for (const_iterator iter= lor2.begin(); iter != lor2.end(); ++iter) - old_sum+= iter->get_value(); + for (const_iterator iter = begin(); iter != end(); ++iter) + old_sum += iter->get_value(); + for (const_iterator iter = lor2.begin(); iter != lor2.end(); ++iter) + old_sum += iter->get_value(); #endif // KT 15/05/2002 insert sort first, as both implementations assume this sort(); lor2.sort(); iterator element_ptr = begin(); - iterator element_ptr2= lor2.begin(); + iterator element_ptr2 = lor2.begin(); // implementation note: cannot use const_iterator in the line above // as some compilers (including gcc 3.* and VC 7.0) would not compile - // the elements.insert() line below, as the types of the iterators no longer + // the elements.insert() line below, as the types of the iterators no longer // match exactly. #if 1 // KT 15/05/2002 much faster implementation than before, and its output is sorted -#ifndef NDEBUG - //unsigned int insertions = 0; -#endif - while ( element_ptr2 != lor2.end() ) - { - if (element_ptr == end()) - { +# ifndef NDEBUG + // unsigned int insertions = 0; +# endif + while (element_ptr2 != lor2.end()) { + if (element_ptr == end()) { elements.reserve((lor2.end() - element_ptr2) + size()); - elements.insert(end(), element_ptr2, lor2.end()); + elements.insert(end(), element_ptr2, lor2.end()); break; } - if (value_type::coordinates_equal(*element_ptr2, *element_ptr)) - { + if (value_type::coordinates_equal(*element_ptr2, *element_ptr)) { *element_ptr++ += *element_ptr2++; - } - else if (value_type::coordinates_less(*element_ptr2, *element_ptr)) - { + } else if (value_type::coordinates_less(*element_ptr2, *element_ptr)) { element_ptr = elements.insert(element_ptr, *element_ptr2); assert(*element_ptr == *element_ptr2); - ++element_ptr; ++element_ptr2; -#ifndef NDEBUG + ++element_ptr; + ++element_ptr2; +# ifndef NDEBUG //++insertions; -#endif - } - else - { +# endif + } else { ++element_ptr; } } - #else // this old version assumed the input arrays were sorted, but its output wasn't // it could be rewritten to avoid lor2.erase() such that this method could be const // this would probably speed it up anyway - bool found=false; - while ( element_ptr2 != lor2.end() ) - { + bool found = false; + while (element_ptr2 != lor2.end()) { // here it is assumed that the input is sorted // this could be possibly be dropped by initialising dup_xyz = begin() // performance would be bad however - iterator dup_xyz = element_ptr; - while ( dup_xyz != end() ) - { - if (value_type::coordinates_equal(*element_ptr2, *dup_xyz)) - { - *dup_xyz += *element_ptr2; - element_ptr = dup_xyz+1; + iterator dup_xyz = element_ptr; + while (dup_xyz != end()) { + if (value_type::coordinates_equal(*element_ptr2, *dup_xyz)) { + *dup_xyz += *element_ptr2; + element_ptr = dup_xyz + 1; found = true; break; // assume no more duplicated point - } - else + } else ++dup_xyz; } - if( found ) - { - element_ptr2 = lor2.erase(element_ptr2); + if (found) { + element_ptr2 = lor2.erase(element_ptr2); found = false; + } else { + ++element_ptr2; } - else{ - ++element_ptr2; - } } // append the rest (but not sorted) - element_ptr2 = lor2.begin(); - while ( element_ptr2 != lor2.end() ) - { - push_back( *element_ptr2); + element_ptr2 = lor2.begin(); + while (element_ptr2 != lor2.end()) { + push_back(*element_ptr2); ++element_ptr2; } // KT 15/05/2002 added sort for compatiblity with other version @@ -278,18 +239,17 @@ merge( ProjMatrixElemsForOneBin &lor2 ) #ifndef NDEBUG // check that the values sum to the same as before merging float new_sum = 0; - for (const_iterator iter= begin(); iter != end(); ++iter) - new_sum+= iter->get_value(); - assert(fabs(new_sum-old_sum)get_value(); + assert(fabs(new_sum - old_sum) < old_sum * 10E-4); // check that it's sorted - for (const_iterator iter=begin(); iter+1!=end(); ++iter) - assert(value_type::coordinates_less(*iter, *(iter+1))); - //std::cerr << insertions << " insertions, size " << size() << std::endl; + for (const_iterator iter = begin(); iter + 1 != end(); ++iter) + assert(value_type::coordinates_less(*iter, *(iter + 1))); + // std::cerr << insertions << " insertions, size " << size() << std::endl; #endif assert(check_state() == Succeeded::yes); } - #if 0 // todo remove this void ProjMatrixElemsForOneBin::clean_neg_z() @@ -343,108 +303,84 @@ void ProjMatrixElemsForOneBin::read( fstream&fst ) } #endif -/////////////////// projection operations ////////////////////////////////// -void -ProjMatrixElemsForOneBin:: -back_project(DiscretisedDensity<3,float>& density, - const Bin& single) const -{ - { - const float data = single.get_bin_value() ; +/////////////////// projection operations ////////////////////////////////// +void +ProjMatrixElemsForOneBin::back_project(DiscretisedDensity<3, float>& density, const Bin& single) const { + { + const float data = single.get_bin_value(); // KT 21/02/2002 added check on 0 if (data == 0) return; - - BasicCoordinate<3,int> coords; - const_iterator element_ptr = - begin(); - while (element_ptr != end()) - { + + BasicCoordinate<3, int> coords; + const_iterator element_ptr = begin(); + while (element_ptr != end()) { coords = element_ptr->get_coords(); if (coords[1] >= density.get_min_index() && coords[1] <= density.get_max_index()) - density[coords[1]][coords[2]][coords[3]] += element_ptr->get_value() * data; - element_ptr++; - } - } + density[coords[1]][coords[2]][coords[3]] += element_ptr->get_value() * data; + element_ptr++; + } + } } +void +ProjMatrixElemsForOneBin::forward_project(Bin& single, const DiscretisedDensity<3, float>& density) const { + { -void -ProjMatrixElemsForOneBin:: -forward_project(Bin& single, - const DiscretisedDensity<3,float>& density) const -{ - { - - BasicCoordinate<3,int> coords; + BasicCoordinate<3, int> coords; const_iterator element_ptr = begin(); - - while (element_ptr != end()) - { + + while (element_ptr != end()) { coords = element_ptr->get_coords(); - + if (coords[1] >= density.get_min_index() && coords[1] <= density.get_max_index()) single += density[coords[1]][coords[2]][coords[3]] * element_ptr->get_value(); - ++element_ptr; - } - } + ++element_ptr; + } + } } +void +ProjMatrixElemsForOneBin::back_project(DiscretisedDensity<3, float>& density, const RelatedBins& r_bins) const { + const DataSymmetriesForBins* symmetries = r_bins.get_symmetries_ptr(); -void -ProjMatrixElemsForOneBin:: -back_project(DiscretisedDensity<3,float>& density, - const RelatedBins& r_bins) const -{ - const DataSymmetriesForBins* symmetries = r_bins.get_symmetries_ptr(); - - RelatedBins::const_iterator r_bins_iterator =r_bins.begin(); + RelatedBins::const_iterator r_bins_iterator = r_bins.begin(); ProjMatrixElemsForOneBin row_copy; while (r_bins_iterator != r_bins.end()) - - { + + { row_copy = *this; - + Bin symmetric_bin = *r_bins_iterator; // KT 21/02/2002 added check on 0 if (symmetric_bin.get_bin_value() == 0) return; - unique_ptr symm_ptr = - symmetries->find_symmetry_operation_from_basic_bin(symmetric_bin); + unique_ptr symm_ptr = symmetries->find_symmetry_operation_from_basic_bin(symmetric_bin); symm_ptr->transform_proj_matrix_elems_for_one_bin(row_copy); - row_copy.back_project(density,symmetric_bin); - } + row_copy.back_project(density, symmetric_bin); + } } +void +ProjMatrixElemsForOneBin::forward_project(RelatedBins& r_bins, const DiscretisedDensity<3, float>& density) const { + const DataSymmetriesForBins* symmetries = r_bins.get_symmetries_ptr(); -void -ProjMatrixElemsForOneBin:: -forward_project(RelatedBins& r_bins, - const DiscretisedDensity<3,float>& density) const -{ - const DataSymmetriesForBins* symmetries = r_bins.get_symmetries_ptr(); - - RelatedBins::iterator r_bins_iterator =r_bins.begin(); + RelatedBins::iterator r_bins_iterator = r_bins.begin(); ProjMatrixElemsForOneBin row_copy; - + while (r_bins_iterator != r_bins.end()) - - { + + { row_copy = *this; - - unique_ptr symm_op_ptr = - symmetries->find_symmetry_operation_from_basic_bin(*r_bins_iterator); + + unique_ptr symm_op_ptr = symmetries->find_symmetry_operation_from_basic_bin(*r_bins_iterator); symm_op_ptr->transform_proj_matrix_elems_for_one_bin(row_copy); - row_copy.forward_project(*r_bins_iterator,density); - } - + row_copy.forward_project(*r_bins_iterator, density); + } } - -bool -ProjMatrixElemsForOneBin:: -operator==(const ProjMatrixElemsForOneBin& lor) const -{ +bool +ProjMatrixElemsForOneBin::operator==(const ProjMatrixElemsForOneBin& lor) const { // first determine a tolerance for the floating point comparisons // do this by finding the maxumum value in the first lor float max_value = 0; @@ -453,59 +389,51 @@ operator==(const ProjMatrixElemsForOneBin& lor) const // extra brackets here to avoid VC 7.1 complaining about this_iter // being defined here in for() and a few lines further on // (it really shouldn't complain) - for (const_iterator this_iter= begin(); this_iter!= end(); ++this_iter) - { - const float current_value=this_iter->get_value(); - if (current_value> max_value) - max_value = current_value; - } + for (const_iterator this_iter = begin(); this_iter != end(); ++this_iter) { + const float current_value = this_iter->get_value(); + if (current_value > max_value) + max_value = current_value; + } } - const float tolerance = max_value*.002F; + const float tolerance = max_value * .002F; - const_iterator this_iter= begin(); + const_iterator this_iter = begin(); const_iterator lor_iter = lor.begin(); - while (this_iter!= end() && lor_iter!=lor.end()) - { - if (this_iter->get_coords() == lor_iter->get_coords()) - { - // coordinates are equal, so test for value - if (fabs(this_iter->get_value() - lor_iter->get_value()) > tolerance) - return false; - } - else - { - // coordinates are not equal, so check if value of one of them is small and we should skip it - if (this_iter->get_value() < tolerance) - { - ++this_iter; continue; - } - if (lor_iter->get_value() < tolerance) - { - ++lor_iter; continue; - } - // either one is not small - return false; - } - // we got here, so comparison was ok - ++this_iter; - ++lor_iter; - } - for (; this_iter!= end(); ++this_iter) - { - if (this_iter->get_value()> tolerance) - return false; - } - for (; lor_iter!= lor.end(); ++lor_iter) - { - if (lor_iter->get_value()> tolerance) - return false; + while (this_iter != end() && lor_iter != lor.end()) { + if (this_iter->get_coords() == lor_iter->get_coords()) { + // coordinates are equal, so test for value + if (fabs(this_iter->get_value() - lor_iter->get_value()) > tolerance) + return false; + } else { + // coordinates are not equal, so check if value of one of them is small and we should skip it + if (this_iter->get_value() < tolerance) { + ++this_iter; + continue; + } + if (lor_iter->get_value() < tolerance) { + ++lor_iter; + continue; + } + // either one is not small + return false; } + // we got here, so comparison was ok + ++this_iter; + ++lor_iter; + } + for (; this_iter != end(); ++this_iter) { + if (this_iter->get_value() > tolerance) + return false; + } + for (; lor_iter != lor.end(); ++lor_iter) { + if (lor_iter->get_value() > tolerance) + return false; + } return true; - } -bool -ProjMatrixElemsForOneBin:: -operator!=(const ProjMatrixElemsForOneBin& lor) const -{ return !(*this==lor); } +bool +ProjMatrixElemsForOneBin::operator!=(const ProjMatrixElemsForOneBin& lor) const { + return !(*this == lor); +} END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ProjMatrixElemsForOneDensel.cxx b/src/recon_buildblock/ProjMatrixElemsForOneDensel.cxx index 38979c58cc..5f9219cda2 100644 --- a/src/recon_buildblock/ProjMatrixElemsForOneDensel.cxx +++ b/src/recon_buildblock/ProjMatrixElemsForOneDensel.cxx @@ -5,9 +5,9 @@ \file \ingroup projection \brief non-inline implementations for stir::ProjMatrixElemsForOneDensel - + \author Kris Thielemans - + */ /* Copyright (C) 2000- 2009, Hammersmith Imanet Ltd @@ -36,58 +36,42 @@ START_NAMESPACE_STIR - -ProjMatrixElemsForOneDensel:: -ProjMatrixElemsForOneDensel(const Densel& densel, const int default_capacity) -: densel(densel) -{ - elements.reserve(default_capacity); -} - -ProjMatrixElemsForOneDensel:: -ProjMatrixElemsForOneDensel() -{ - elements.reserve(300); +ProjMatrixElemsForOneDensel::ProjMatrixElemsForOneDensel(const Densel& densel, const int default_capacity) : densel(densel) { + elements.reserve(default_capacity); } +ProjMatrixElemsForOneDensel::ProjMatrixElemsForOneDensel() { elements.reserve(300); } -void -ProjMatrixElemsForOneDensel:: -reserve(size_type max_number) -{ +void +ProjMatrixElemsForOneDensel::reserve(size_type max_number) { elements.reserve(max_number); } - -void ProjMatrixElemsForOneDensel::erase() -{ +void +ProjMatrixElemsForOneDensel::erase() { elements.resize(0); } -ProjMatrixElemsForOneDensel& ProjMatrixElemsForOneDensel::operator*=(const float d) -{ +ProjMatrixElemsForOneDensel& +ProjMatrixElemsForOneDensel::operator*=(const float d) { // KT 21/02/2002 added check on 1 - if (d != 1.F) - { + if (d != 1.F) { iterator element_ptr = begin(); - while (element_ptr != end()) - { - *element_ptr *= d; + while (element_ptr != end()) { + *element_ptr *= d; ++element_ptr; - } + } } return *this; } -ProjMatrixElemsForOneDensel& ProjMatrixElemsForOneDensel::operator/=(const float d) -{ - assert( d != 0); +ProjMatrixElemsForOneDensel& +ProjMatrixElemsForOneDensel::operator/=(const float d) { + assert(d != 0); // KT 21/02/2002 added check on 1 - if (d != 1.F) - { + if (d != 1.F) { iterator element_ptr = begin(); - while (element_ptr != end()) - { + while (element_ptr != end()) { *element_ptr /= d; ++element_ptr; } @@ -95,110 +79,91 @@ ProjMatrixElemsForOneDensel& ProjMatrixElemsForOneDensel::operator/=(const float return *this; } - -Succeeded ProjMatrixElemsForOneDensel::check_state() const -{ +Succeeded +ProjMatrixElemsForOneDensel::check_state() const { Succeeded success = Succeeded::yes; - if (size()==0) + if (size() == 0) return success; ProjMatrixElemsForOneDensel lor = *this; lor.sort(); - - for (ProjMatrixElemsForOneDensel::const_iterator lor_iter = lor.begin(); - lor_iter != lor.end()-1; - ++lor_iter) - { - if (value_type::coordinates_equal(*lor_iter, *(lor_iter+1))) - { - warning("ProjMatrixElemsForOneDensel: coordinates occur more than once %d,%d,%d,%d\n", - lor_iter->segment_num(), lor_iter->view_num(), - lor_iter->axial_pos_num(), lor_iter->tangential_pos_num()); + + for (ProjMatrixElemsForOneDensel::const_iterator lor_iter = lor.begin(); lor_iter != lor.end() - 1; ++lor_iter) { + if (value_type::coordinates_equal(*lor_iter, *(lor_iter + 1))) { + warning("ProjMatrixElemsForOneDensel: coordinates occur more than once %d,%d,%d,%d\n", lor_iter->segment_num(), + lor_iter->view_num(), lor_iter->axial_pos_num(), lor_iter->tangential_pos_num()); success = Succeeded::no; } } return success; } - -void ProjMatrixElemsForOneDensel::sort() -{ +void +ProjMatrixElemsForOneDensel::sort() { // need explicit std:: here to resolve possible name conflict // this might give you trouble if your compiler does not support namespaces #if !defined(STIR_NO_NAMESPACES) || (__GNUC__ == 2 && __GNUC_MINOR__ <= 8) std:: -#endif - sort(begin(), end(), value_type::coordinates_less); +#endif + sort(begin(), end(), value_type::coordinates_less); } - -float ProjMatrixElemsForOneDensel::square_sum() const -{ - float sq_sum=0; +float +ProjMatrixElemsForOneDensel::square_sum() const { + float sq_sum = 0; const_iterator element_ptr = begin(); - while (element_ptr != end()) - { - sq_sum += square(element_ptr->get_bin_value()); + while (element_ptr != end()) { + sq_sum += square(element_ptr->get_bin_value()); ++element_ptr; - } + } return sq_sum; } // TODO make sure we can have a const argument // not calling lor2.erase() would probably speed it up anyway -void -ProjMatrixElemsForOneDensel:: -merge( ProjMatrixElemsForOneDensel &lor2 ) -{ +void +ProjMatrixElemsForOneDensel::merge(ProjMatrixElemsForOneDensel& lor2) { assert(check_state() == Succeeded::yes); assert(lor2.check_state() == Succeeded::yes); iterator element_ptr = begin(); - iterator element_ptr2= lor2.begin(); - - bool found=false; - while ( element_ptr2 != lor2.end() ) - { - //unsigned int key = make_key( element_ptr2->x, element_ptr2->y,element_ptr2->z); - iterator dup_xyz = element_ptr; - while ( dup_xyz != end() ) - { - //unsigned int dup_key = make_key( dup_xyz->x,dup_xyz->y,dup_xyz->z); - - //if ( dup_key == key ) - if (value_type::coordinates_equal(*element_ptr2, *dup_xyz)) - { - //TEST///////// - *dup_xyz += *element_ptr2; + iterator element_ptr2 = lor2.begin(); + + bool found = false; + while (element_ptr2 != lor2.end()) { + // unsigned int key = make_key( element_ptr2->x, element_ptr2->y,element_ptr2->z); + iterator dup_xyz = element_ptr; + while (dup_xyz != end()) { + // unsigned int dup_key = make_key( dup_xyz->x,dup_xyz->y,dup_xyz->z); + + // if ( dup_key == key ) + if (value_type::coordinates_equal(*element_ptr2, *dup_xyz)) { + // TEST///////// + *dup_xyz += *element_ptr2; /////////////// - element_ptr = dup_xyz+1; + element_ptr = dup_xyz + 1; found = true; - break; // assume no more duplicated point, only 2 lors - } - else + break; // assume no more duplicated point, only 2 lors + } else ++dup_xyz; } - if( found ) - { - element_ptr2 = lor2.erase(element_ptr2); + if (found) { + element_ptr2 = lor2.erase(element_ptr2); found = false; + } else { + ++element_ptr2; } - else{ - ++element_ptr2; - } } // append the rest - element_ptr2 = lor2.begin(); - while ( element_ptr2 != lor2.end() ) - { - push_back( *element_ptr2); + element_ptr2 = lor2.begin(); + while (element_ptr2 != lor2.end()) { + push_back(*element_ptr2); ++element_ptr2; } assert(check_state() == Succeeded::yes); } - #if 0 // todo remove this void ProjMatrixElemsForOneDensel::clean_neg_z() @@ -252,7 +217,7 @@ void ProjMatrixElemsForOneDensel::read( fstream&fst ) } #endif -/////////////////// projection operations ////////////////////////////////// +/////////////////// projection operations ////////////////////////////////// #if 0 // TODO void diff --git a/src/recon_buildblock/ProjectorByBinPair.cxx b/src/recon_buildblock/ProjectorByBinPair.cxx index 83d618d23c..d0f9df5e66 100644 --- a/src/recon_buildblock/ProjectorByBinPair.cxx +++ b/src/recon_buildblock/ProjectorByBinPair.cxx @@ -5,9 +5,9 @@ \ingroup projection \brief non-inline implementations for stir::ProjectorByBinPair - + \author Kris Thielemans - + */ /* Copyright (C) 2000- 2009, Hammersmith Imanet Ltd @@ -27,28 +27,26 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ProjectorByBinPair.h" #include "stir/ProjDataInfo.h" #include "stir/DiscretisedDensity.h" #include "stir/Succeeded.h" +#include "stir/recon_buildblock/PresmoothingForwardProjectorByBin.h" +#include "stir/recon_buildblock/PostsmoothingBackProjectorByBin.h" +#include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" +#include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" +#include "stir/is_null_ptr.h" #include START_NAMESPACE_STIR - -ProjectorByBinPair:: -ProjectorByBinPair() - : _already_set_up(false) -{ -} +ProjectorByBinPair::ProjectorByBinPair() : _already_set_up(false) {} Succeeded -ProjectorByBinPair:: -set_up(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& image_info_sptr) +ProjectorByBinPair::set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& image_info_sptr) -{ +{ _already_set_up = true; _proj_data_info_sptr = proj_data_info_sptr->create_shared_clone(); _density_info_sptr = image_info_sptr; @@ -57,33 +55,27 @@ set_up(const shared_ptr& proj_data_info_sptr, return Succeeded::yes; } - void -ProjectorByBinPair:: -check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3,float>& density_info) const -{ +ProjectorByBinPair::check(const ProjDataInfo& proj_data_info, const DiscretisedDensity<3, float>& density_info) const { if (!this->_already_set_up) error("ProjectorByBinPair method called without calling set_up first."); if (!(*this->_proj_data_info_sptr >= proj_data_info)) - error(boost::format("ProjectorByBinPair set-up with different geometry for projection data.\nSet_up was with\n%1%\nCalled with\n%2%") - % this->_proj_data_info_sptr->parameter_info() % proj_data_info.parameter_info()); - if (! this->_density_info_sptr->has_same_characteristics(density_info)) + error(boost::format( + "ProjectorByBinPair set-up with different geometry for projection data.\nSet_up was with\n%1%\nCalled with\n%2%") % + this->_proj_data_info_sptr->parameter_info() % proj_data_info.parameter_info()); + if (!this->_density_info_sptr->has_same_characteristics(density_info)) error("ProjectorByBinPair set-up with different geometry for density or volume data."); -} +} -//ForwardProjectorByBin const * +// ForwardProjectorByBin const * const shared_ptr -ProjectorByBinPair:: -get_forward_projector_sptr() const -{ +ProjectorByBinPair::get_forward_projector_sptr() const { return forward_projector_sptr; } -//BackProjectorByBin const * +// BackProjectorByBin const * const shared_ptr -ProjectorByBinPair:: -get_back_projector_sptr() const -{ +ProjectorByBinPair::get_back_projector_sptr() const { return back_projector_sptr; } diff --git a/src/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.cxx b/src/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.cxx index 8c18feeab9..52ae8f6ce1 100644 --- a/src/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.cxx +++ b/src/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.cxx @@ -5,9 +5,9 @@ \ingroup projection \brief non-inline implementations for stir::ProjectorByBinPairUsingProjMatrixByBin - + \author Kris Thielemans - + */ /* Copyright (C) 2000- 2011, Hammersmith Imanet Ltd @@ -27,7 +27,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.h" #include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" #include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" @@ -36,59 +35,45 @@ START_NAMESPACE_STIR +const char* const ProjectorByBinPairUsingProjMatrixByBin::registered_name = "Matrix"; -const char * const -ProjectorByBinPairUsingProjMatrixByBin::registered_name = - "Matrix"; - - -void -ProjectorByBinPairUsingProjMatrixByBin::initialise_keymap() -{ +void +ProjectorByBinPairUsingProjMatrixByBin::initialise_keymap() { base_type::initialise_keymap(); parser.add_start_key("Projector Pair Using Matrix Parameters"); parser.add_stop_key("End Projector Pair Using Matrix Parameters"); - parser.add_parsing_key("Matrix type",&proj_matrix_sptr); + parser.add_parsing_key("Matrix type", &proj_matrix_sptr); } - void -ProjectorByBinPairUsingProjMatrixByBin::set_defaults() -{ +ProjectorByBinPairUsingProjMatrixByBin::set_defaults() { base_type::set_defaults(); this->proj_matrix_sptr.reset(); } bool -ProjectorByBinPairUsingProjMatrixByBin::post_processing() -{ +ProjectorByBinPairUsingProjMatrixByBin::post_processing() { if (base_type::post_processing()) return true; - if (is_null_ptr(proj_matrix_sptr)) - { warning("No valid projection matrix is defined\n"); return true; } + if (is_null_ptr(proj_matrix_sptr)) { + warning("No valid projection matrix is defined\n"); + return true; + } this->forward_projector_sptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(proj_matrix_sptr)); this->back_projector_sptr.reset(new BackProjectorByBinUsingProjMatrixByBin(proj_matrix_sptr)); return false; } -ProjectorByBinPairUsingProjMatrixByBin:: -ProjectorByBinPairUsingProjMatrixByBin() -{ - set_defaults(); -} +ProjectorByBinPairUsingProjMatrixByBin::ProjectorByBinPairUsingProjMatrixByBin() { set_defaults(); } -ProjectorByBinPairUsingProjMatrixByBin:: -ProjectorByBinPairUsingProjMatrixByBin( - const shared_ptr& proj_matrix_sptr_) -{ +ProjectorByBinPairUsingProjMatrixByBin::ProjectorByBinPairUsingProjMatrixByBin( + const shared_ptr& proj_matrix_sptr_) { this->set_proj_matrix_sptr(proj_matrix_sptr_); } Succeeded -ProjectorByBinPairUsingProjMatrixByBin:: -set_up(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& image_info_sptr) -{ +ProjectorByBinPairUsingProjMatrixByBin::set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& image_info_sptr) { // proj_matrix_sptr->set_up() not needed as the projection matrix will be set_up indirectly by // the forward_projector->set_up (which is called in the base class) // proj_matrix_sptr->set_up(proj_data_info_sptr, image_info_sptr); @@ -99,24 +84,18 @@ set_up(const shared_ptr& proj_data_info_sptr, return Succeeded::yes; } -ProjMatrixByBin const * -ProjectorByBinPairUsingProjMatrixByBin:: -get_proj_matrix_ptr() const -{ +ProjMatrixByBin const* +ProjectorByBinPairUsingProjMatrixByBin::get_proj_matrix_ptr() const { return proj_matrix_sptr.get(); } shared_ptr -ProjectorByBinPairUsingProjMatrixByBin:: -get_proj_matrix_sptr() const -{ - return proj_matrix_sptr; +ProjectorByBinPairUsingProjMatrixByBin::get_proj_matrix_sptr() const { + return proj_matrix_sptr; } void -ProjectorByBinPairUsingProjMatrixByBin:: -set_proj_matrix_sptr(const shared_ptr& sptr) -{ +ProjectorByBinPairUsingProjMatrixByBin::set_proj_matrix_sptr(const shared_ptr& sptr) { this->proj_matrix_sptr = sptr; this->forward_projector_sptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(this->proj_matrix_sptr)); this->back_projector_sptr.reset(new BackProjectorByBinUsingProjMatrixByBin(this->proj_matrix_sptr)); diff --git a/src/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.cxx b/src/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.cxx index 5f11846013..deb9d31fad 100644 --- a/src/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.cxx +++ b/src/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.cxx @@ -5,9 +5,9 @@ \ingroup projection \brief non-inline implementations for stir::ProjectorByBinPairUsingSeparateProjectors - + \author Kris Thielemans - + */ /* Copyright (C) 2000- 2011, Hammersmith Imanet Ltd @@ -26,66 +26,53 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h" #include "stir/is_null_ptr.h" #include "stir/Succeeded.h" START_NAMESPACE_STIR +const char* const ProjectorByBinPairUsingSeparateProjectors::registered_name = "Separate Projectors"; -const char * const -ProjectorByBinPairUsingSeparateProjectors::registered_name = - "Separate Projectors"; - - -void -ProjectorByBinPairUsingSeparateProjectors::initialise_keymap() -{ +void +ProjectorByBinPairUsingSeparateProjectors::initialise_keymap() { parser.add_start_key("Projector Pair Using Separate Projectors Parameters"); parser.add_stop_key("End Projector Pair Using Separate Projectors Parameters"); - parser.add_parsing_key("Forward projector type",&forward_projector_sptr); - parser.add_parsing_key("Back projector type",&back_projector_sptr); + parser.add_parsing_key("Forward projector type", &forward_projector_sptr); + parser.add_parsing_key("Back projector type", &back_projector_sptr); } - void -ProjectorByBinPairUsingSeparateProjectors:: -set_defaults() -{ +ProjectorByBinPairUsingSeparateProjectors::set_defaults() { base_type::set_defaults(); forward_projector_sptr.reset(); back_projector_sptr.reset(); } bool -ProjectorByBinPairUsingSeparateProjectors:: -post_processing() -{ +ProjectorByBinPairUsingSeparateProjectors::post_processing() { if (base_type::post_processing()) return true; - if (is_null_ptr(forward_projector_sptr)) - { warning("No valid forward projector is defined\n"); return true; } + if (is_null_ptr(forward_projector_sptr)) { + warning("No valid forward projector is defined\n"); + return true; + } - if (is_null_ptr(back_projector_sptr)) - { warning("No valid back projector is defined\n"); return true; } + if (is_null_ptr(back_projector_sptr)) { + warning("No valid back projector is defined\n"); + return true; + } return false; } -ProjectorByBinPairUsingSeparateProjectors:: -ProjectorByBinPairUsingSeparateProjectors() -{ - set_defaults(); -} +ProjectorByBinPairUsingSeparateProjectors::ProjectorByBinPairUsingSeparateProjectors() { set_defaults(); } -ProjectorByBinPairUsingSeparateProjectors:: -ProjectorByBinPairUsingSeparateProjectors(const shared_ptr& forward_projector_sptr_v, - const shared_ptr& back_projector_sptr_v) -{ +ProjectorByBinPairUsingSeparateProjectors::ProjectorByBinPairUsingSeparateProjectors( + const shared_ptr& forward_projector_sptr_v, + const shared_ptr& back_projector_sptr_v) { forward_projector_sptr = forward_projector_sptr_v; back_projector_sptr = back_projector_sptr_v; } - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/QuadraticPrior.cxx b/src/recon_buildblock/QuadraticPrior.cxx index 68603f2962..ccb75095fd 100644 --- a/src/recon_buildblock/QuadraticPrior.cxx +++ b/src/recon_buildblock/QuadraticPrior.cxx @@ -19,8 +19,8 @@ /*! \file \ingroup priors - \brief implementation of the stir::QuadraticPrior class - + \brief implementation of the stir::QuadraticPrior class + \author Kris Thielemans \author Sanida Mustafovic @@ -44,12 +44,11 @@ using std::max; START_NAMESPACE_STIR template -void -QuadraticPrior::initialise_keymap() -{ +void +QuadraticPrior::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Quadratic Prior Parameters"); - this->parser.add_key("only 2D", &only_2D); + this->parser.add_key("only 2D", &only_2D); this->parser.add_key("kappa filename", &kappa_filename); this->parser.add_key("weights", &weights); this->parser.add_key("gradient filename prefix", &gradient_filename_prefix); @@ -57,523 +56,449 @@ QuadraticPrior::initialise_keymap() } template -bool -QuadraticPrior::post_processing() -{ - if (base_type::post_processing()==true) +bool +QuadraticPrior::post_processing() { + if (base_type::post_processing() == true) return true; if (kappa_filename.size() != 0) - this->kappa_ptr = read_from_file >(kappa_filename); + this->kappa_ptr = read_from_file>(kappa_filename); bool warn_about_even_size = false; - if (this->weights.size() ==0) - { - // will call compute_weights() to fill it in + if (this->weights.size() == 0) { + // will call compute_weights() to fill it in + } else { + if (!this->weights.is_regular()) { + warning("Sorry. QuadraticPrior currently only supports regular arrays for the weights"); + return true; } - else - { - if (!this->weights.is_regular()) - { - warning("Sorry. QuadraticPrior currently only supports regular arrays for the weights"); - return true; - } - const unsigned int size_z = this->weights.size(); - if (size_z%2==0) - warn_about_even_size = true; - const int min_index_z = -static_cast(size_z/2); - this->weights.set_min_index(min_index_z); + const unsigned int size_z = this->weights.size(); + if (size_z % 2 == 0) + warn_about_even_size = true; + const int min_index_z = -static_cast(size_z / 2); + this->weights.set_min_index(min_index_z); - for (int z = min_index_z; z<= this->weights.get_max_index(); ++z) - { - const unsigned int size_y = this->weights[z].size(); - if (size_y%2==0) - warn_about_even_size = true; - const int min_index_y = -static_cast(size_y/2); - this->weights[z].set_min_index(min_index_y); - for (int y = min_index_y; y<= this->weights[z].get_max_index(); ++y) - { - const unsigned int size_x = this->weights[z][y].size(); - if (size_x%2==0) - warn_about_even_size = true; - const int min_index_x = -static_cast(size_x/2); - this->weights[z][y].set_min_index(min_index_x); - } - } + for (int z = min_index_z; z <= this->weights.get_max_index(); ++z) { + const unsigned int size_y = this->weights[z].size(); + if (size_y % 2 == 0) + warn_about_even_size = true; + const int min_index_y = -static_cast(size_y / 2); + this->weights[z].set_min_index(min_index_y); + for (int y = min_index_y; y <= this->weights[z].get_max_index(); ++y) { + const unsigned int size_x = this->weights[z][y].size(); + if (size_x % 2 == 0) + warn_about_even_size = true; + const int min_index_x = -static_cast(size_x / 2); + this->weights[z][y].set_min_index(min_index_x); + } } + } if (warn_about_even_size) warning("Parsing QuadraticPrior: even number of weights occured in either x,y or z dimension.\n" "I'll (effectively) make this odd by appending a 0 at the end."); return false; - } template Succeeded -QuadraticPrior::set_up (shared_ptr > const& target_sptr) -{ +QuadraticPrior::set_up(shared_ptr> const& target_sptr) { base_type::set_up(target_sptr); return Succeeded::yes; } template -void QuadraticPrior::check(DiscretisedDensity<3,elemT> const& current_image_estimate) const -{ +void +QuadraticPrior::check(DiscretisedDensity<3, elemT> const& current_image_estimate) const { // Do base-class check base_type::check(current_image_estimate); } template void -QuadraticPrior::set_defaults() -{ +QuadraticPrior::set_defaults() { base_type::set_defaults(); this->only_2D = false; - this->kappa_ptr.reset(); + this->kappa_ptr.reset(); this->weights.recycle(); } template <> -const char * const -QuadraticPrior::registered_name = - "Quadratic"; +const char* const QuadraticPrior::registered_name = "Quadratic"; template -QuadraticPrior::QuadraticPrior() -{ +QuadraticPrior::QuadraticPrior() { set_defaults(); } - template -QuadraticPrior::QuadraticPrior(const bool only_2D_v, float penalisation_factor_v) - : only_2D(only_2D_v) -{ +QuadraticPrior::QuadraticPrior(const bool only_2D_v, float penalisation_factor_v) : only_2D(only_2D_v) { this->penalisation_factor = penalisation_factor_v; } - - //! get penalty weights for the neigbourhood +//! get penalty weights for the neigbourhood template -Array<3,float> -QuadraticPrior:: -get_weights() const -{ return this->weights; } +Array<3, float> +QuadraticPrior::get_weights() const { + return this->weights; +} - //! set penalty weights for the neigbourhood -template -void -QuadraticPrior:: -set_weights(const Array<3,float>& w) -{ this->weights = w; } - - //! get current kappa image - /*! \warning As this function returns a shared_ptr, this is dangerous. You should not - modify the image by manipulating the image refered to by this pointer. - Unpredictable results will occur. - */ +//! set penalty weights for the neigbourhood template -shared_ptr > -QuadraticPrior:: -get_kappa_sptr() const -{ return this->kappa_ptr; } +void +QuadraticPrior::set_weights(const Array<3, float>& w) { + this->weights = w; +} - //! set kappa image +//! get current kappa image +/*! \warning As this function returns a shared_ptr, this is dangerous. You should not + modify the image by manipulating the image refered to by this pointer. + Unpredictable results will occur. +*/ template -void -QuadraticPrior:: -set_kappa_sptr(const shared_ptr >& k) -{ this->kappa_ptr = k; } +shared_ptr> +QuadraticPrior::get_kappa_sptr() const { + return this->kappa_ptr; +} +//! set kappa image +template +void +QuadraticPrior::set_kappa_sptr(const shared_ptr>& k) { + this->kappa_ptr = k; +} // TODO move to set_up // initialise to 1/Euclidean distance -static void -compute_weights(Array<3,float>& weights, const CartesianCoordinate3D& grid_spacing, const bool only_2D) -{ +static void +compute_weights(Array<3, float>& weights, const CartesianCoordinate3D& grid_spacing, const bool only_2D) { int min_dz, max_dz; - if (only_2D) - { - min_dz = max_dz = 0; - } - else - { - min_dz = -1; - max_dz = 1; - } - weights = Array<3,float>(IndexRange3D(min_dz,max_dz,-1,1,-1,1)); - for (int z=min_dz;z<=max_dz;++z) - for (int y=-1;y<=1;++y) - for (int x=-1;x<=1;++x) - { - if (z==0 && y==0 && x==0) - weights[0][0][0] = 0; - else - { - weights[z][y][x] = - grid_spacing.x()/ - sqrt(square(x*grid_spacing.x())+ - square(y*grid_spacing.y())+ - square(z*grid_spacing.z())); - } + if (only_2D) { + min_dz = max_dz = 0; + } else { + min_dz = -1; + max_dz = 1; + } + weights = Array<3, float>(IndexRange3D(min_dz, max_dz, -1, 1, -1, 1)); + for (int z = min_dz; z <= max_dz; ++z) + for (int y = -1; y <= 1; ++y) + for (int x = -1; x <= 1; ++x) { + if (z == 0 && y == 0 && x == 0) + weights[0][0][0] = 0; + else { + weights[z][y][x] = + grid_spacing.x() / sqrt(square(x * grid_spacing.x()) + square(y * grid_spacing.y()) + square(z * grid_spacing.z())); } + } } template double -QuadraticPrior:: -compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ - if (this->penalisation_factor==0) - { +QuadraticPrior::compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) { + if (this->penalisation_factor == 0) { return 0.; } - + this->check(current_image_estimate); - - const DiscretisedDensityOnCartesianGrid<3,elemT>& current_image_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,elemT> &>(current_image_estimate); - - if (this->weights.get_length() ==0) - { + + const DiscretisedDensityOnCartesianGrid<3, elemT>& current_image_cast = + dynamic_cast&>(current_image_estimate); + + if (this->weights.get_length() == 0) { compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); } - + const bool do_kappa = !is_null_ptr(kappa_ptr); - + if (do_kappa && !kappa_ptr->has_same_characteristics(current_image_estimate)) error("QuadraticPrior: kappa image has not the same index range as the reconstructed image\n"); - double result = 0.; - const int min_z = current_image_estimate.get_min_index(); - const int max_z = current_image_estimate.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - const int min_dz = max(weights.get_min_index(), min_z-z); - const int max_dz = min(weights.get_max_index(), max_z-z); - - const int min_y = current_image_estimate[z].get_min_index(); - const int max_y = current_image_estimate[z].get_max_index(); - - for (int y=min_y;y<= max_y;y++) - { - const int min_dy = max(weights[0].get_min_index(), min_y-y); - const int max_dy = min(weights[0].get_max_index(), max_y-y); - - const int min_x = current_image_estimate[z][y].get_min_index(); - const int max_x = current_image_estimate[z][y].get_max_index(); - - for (int x=min_x;x<= max_x;x++) - { - const int min_dx = max(weights[0][0].get_min_index(), min_x-x); - const int max_dx = min(weights[0][0].get_max_index(), max_x-x); - - /* formula: - sum_dx,dy,dz - 1/4 weights[dz][dy][dx] * - (current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx])^2 * - (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; - */ - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { - elemT current = - weights[dz][dy][dx] * - square(current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx])/4; - - if (do_kappa) - current *= - (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; - - result += static_cast(current); - } - } - } + const int min_z = current_image_estimate.get_min_index(); + const int max_z = current_image_estimate.get_max_index(); + for (int z = min_z; z <= max_z; z++) { + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); + + const int min_y = current_image_estimate[z].get_min_index(); + const int max_y = current_image_estimate[z].get_max_index(); + + for (int y = min_y; y <= max_y; y++) { + const int min_dy = max(weights[0].get_min_index(), min_y - y); + const int max_dy = min(weights[0].get_max_index(), max_y - y); + + const int min_x = current_image_estimate[z][y].get_min_index(); + const int max_x = current_image_estimate[z][y].get_max_index(); + + for (int x = min_x; x <= max_x; x++) { + const int min_dx = max(weights[0][0].get_min_index(), min_x - x); + const int max_dx = min(weights[0][0].get_max_index(), max_x - x); + + /* formula: + sum_dx,dy,dz + 1/4 weights[dz][dy][dx] * + (current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx])^2 * + (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; + */ + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { + elemT current = weights[dz][dy][dx] * + square(current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx]) / 4; + + if (do_kappa) + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; + + result += static_cast(current); + } + } } + } return result * this->penalisation_factor; } template -void -QuadraticPrior:: -compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ - assert( prior_gradient.has_same_characteristics(current_image_estimate)); - if (this->penalisation_factor==0) - { +void +QuadraticPrior::compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, + const DiscretisedDensity<3, elemT>& current_image_estimate) { + assert(prior_gradient.has_same_characteristics(current_image_estimate)); + if (this->penalisation_factor == 0) { prior_gradient.fill(0); return; } this->check(current_image_estimate); - - - const DiscretisedDensityOnCartesianGrid<3,elemT>& current_image_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,elemT> &>(current_image_estimate); - - if (this->weights.get_length() ==0) - { + + const DiscretisedDensityOnCartesianGrid<3, elemT>& current_image_cast = + dynamic_cast&>(current_image_estimate); + + if (this->weights.get_length() == 0) { compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); } - - - + const bool do_kappa = !is_null_ptr(kappa_ptr); if (do_kappa && !kappa_ptr->has_same_characteristics(current_image_estimate)) error("QuadraticPrior: kappa image has not the same index range as the reconstructed image\n"); - const int min_z = current_image_estimate.get_min_index(); - const int max_z = current_image_estimate.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - const int min_dz = max(weights.get_min_index(), min_z-z); - const int max_dz = min(weights.get_max_index(), max_z-z); - - const int min_y = current_image_estimate[z].get_min_index(); - const int max_y = current_image_estimate[z].get_max_index(); - - for (int y=min_y;y<= max_y;y++) - { - const int min_dy = max(weights[0].get_min_index(), min_y-y); - const int max_dy = min(weights[0].get_max_index(), max_y-y); - - const int min_x = current_image_estimate[z][y].get_min_index(); - const int max_x = current_image_estimate[z][y].get_max_index(); - - for (int x=min_x;x<= max_x;x++) - { - const int min_dx = max(weights[0][0].get_min_index(), min_x-x); - const int max_dx = min(weights[0][0].get_max_index(), max_x-x); - - /* formula: - sum_dx,dy,dz - weights[dz][dy][dx] * - (current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx]) * - (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; - */ + const int min_z = current_image_estimate.get_min_index(); + const int max_z = current_image_estimate.get_max_index(); + for (int z = min_z; z <= max_z; z++) { + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); + + const int min_y = current_image_estimate[z].get_min_index(); + const int max_y = current_image_estimate[z].get_max_index(); + + for (int y = min_y; y <= max_y; y++) { + const int min_dy = max(weights[0].get_min_index(), min_y - y); + const int max_dy = min(weights[0].get_max_index(), max_y - y); + + const int min_x = current_image_estimate[z][y].get_min_index(); + const int max_x = current_image_estimate[z][y].get_max_index(); + + for (int x = min_x; x <= max_x; x++) { + const int min_dx = max(weights[0][0].get_min_index(), min_x - x); + const int max_dx = min(weights[0][0].get_max_index(), max_x - x); + + /* formula: + sum_dx,dy,dz + weights[dz][dy][dx] * + (current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx]) * + (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; + */ #if 1 - elemT gradient = 0; - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { - elemT current = - weights[dz][dy][dx] * - (current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx]); - - if (do_kappa) - current *= - (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; - - gradient += current; - } + elemT gradient = 0; + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { + elemT current = + weights[dz][dy][dx] * (current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx]); + + if (do_kappa) + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; + + gradient += current; + } #else - // attempt to speed up by precomputing the sum of weights. - // The current code gives identical results but is actually slower - // than the above, at least when kappas are present. - - - // precompute sum of weights - // TODO without kappas, this is just weights.sum() most of the time, - // but not near edges - float sum_of_weights = 0; - { - if (do_kappa) - { - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - sum_of_weights += weights[dz][dy][dx]*(*kappa_ptr)[z+dz][y+dy][x+dx]; - } - else - { - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - sum_of_weights += weights[dz][dy][dx]; - } - } - // now compute contribution of central term - elemT gradient = sum_of_weights * current_image_estimate[z][y][x] ; - - // subtract the rest - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { - elemT current = - weights[dz][dy][dx] * current_image_estimate[z+dz][y+dy][x+dx]; - - if (do_kappa) - current *= (*kappa_ptr)[z+dz][y+dy][x+dx]; - - gradient -= current; - } - // multiply with central kappa - if (do_kappa) - gradient *= (*kappa_ptr)[z][y][x]; -#endif - prior_gradient[z][y][x]= gradient * this->penalisation_factor; - } + // attempt to speed up by precomputing the sum of weights. + // The current code gives identical results but is actually slower + // than the above, at least when kappas are present. + + // precompute sum of weights + // TODO without kappas, this is just weights.sum() most of the time, + // but not near edges + float sum_of_weights = 0; + { + if (do_kappa) { + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) + sum_of_weights += weights[dz][dy][dx] * (*kappa_ptr)[z + dz][y + dy][x + dx]; + } else { + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) + sum_of_weights += weights[dz][dy][dx]; } + } + // now compute contribution of central term + elemT gradient = sum_of_weights * current_image_estimate[z][y][x]; + + // subtract the rest + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { + elemT current = weights[dz][dy][dx] * current_image_estimate[z + dz][y + dy][x + dx]; + + if (do_kappa) + current *= (*kappa_ptr)[z + dz][y + dy][x + dx]; + + gradient -= current; + } + // multiply with central kappa + if (do_kappa) + gradient *= (*kappa_ptr)[z][y][x]; +#endif + prior_gradient[z][y][x] = gradient * this->penalisation_factor; + } } + } info(boost::format("Prior gradient max %1%, min %2%\n") % prior_gradient.find_max() % prior_gradient.find_min()); static int count = 0; ++count; - if (gradient_filename_prefix.size()>0) - { - char *filename = new char[gradient_filename_prefix.size()+100]; - sprintf(filename, "%s%d.v", gradient_filename_prefix.c_str(), count); - write_to_file(filename, prior_gradient); - delete[] filename; - } + if (gradient_filename_prefix.size() > 0) { + char* filename = new char[gradient_filename_prefix.size() + 100]; + sprintf(filename, "%s%d.v", gradient_filename_prefix.c_str(), count); + write_to_file(filename, prior_gradient); + delete[] filename; + } } template -void -QuadraticPrior:: -compute_Hessian(DiscretisedDensity<3,elemT>& prior_Hessian_for_single_densel, - const BasicCoordinate<3,int>& coords, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ - assert( prior_Hessian_for_single_densel.has_same_characteristics(current_image_estimate)); +void +QuadraticPrior::compute_Hessian(DiscretisedDensity<3, elemT>& prior_Hessian_for_single_densel, + const BasicCoordinate<3, int>& coords, + const DiscretisedDensity<3, elemT>& current_image_estimate) { + assert(prior_Hessian_for_single_densel.has_same_characteristics(current_image_estimate)); prior_Hessian_for_single_densel.fill(0); - if (this->penalisation_factor==0) - { + if (this->penalisation_factor == 0) { return; } - + this->check(current_image_estimate); - - const DiscretisedDensityOnCartesianGrid<3,elemT>& current_image_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,elemT> &>(current_image_estimate); - - DiscretisedDensityOnCartesianGrid<3,elemT>& prior_Hessian_for_single_densel_cast = - dynamic_cast &>(prior_Hessian_for_single_densel); - - if (weights.get_length() ==0) - { + + const DiscretisedDensityOnCartesianGrid<3, elemT>& current_image_cast = + dynamic_cast&>(current_image_estimate); + + DiscretisedDensityOnCartesianGrid<3, elemT>& prior_Hessian_for_single_densel_cast = + dynamic_cast&>(prior_Hessian_for_single_densel); + + if (weights.get_length() == 0) { compute_weights(weights, current_image_cast.get_grid_spacing(), this->only_2D); } - - + const bool do_kappa = !is_null_ptr(kappa_ptr); - + if (do_kappa && kappa_ptr->has_same_characteristics(current_image_estimate)) error("QuadraticPrior: kappa image has not the same index range as the reconstructed image\n"); const int z = coords[1]; const int y = coords[2]; const int x = coords[3]; - const int min_dz = max(weights.get_min_index(), prior_Hessian_for_single_densel.get_min_index()-z); - const int max_dz = min(weights.get_max_index(), prior_Hessian_for_single_densel.get_max_index()-z); - - const int min_dy = max(weights[0].get_min_index(), prior_Hessian_for_single_densel[z].get_min_index()-y); - const int max_dy = min(weights[0].get_max_index(), prior_Hessian_for_single_densel[z].get_max_index()-y); - - const int min_dx = max(weights[0][0].get_min_index(), prior_Hessian_for_single_densel[z][y].get_min_index()-x); - const int max_dx = min(weights[0][0].get_max_index(), prior_Hessian_for_single_densel[z][y].get_max_index()-x); - + const int min_dz = max(weights.get_min_index(), prior_Hessian_for_single_densel.get_min_index() - z); + const int max_dz = min(weights.get_max_index(), prior_Hessian_for_single_densel.get_max_index() - z); + + const int min_dy = max(weights[0].get_min_index(), prior_Hessian_for_single_densel[z].get_min_index() - y); + const int max_dy = min(weights[0].get_max_index(), prior_Hessian_for_single_densel[z].get_max_index() - y); + + const int min_dx = max(weights[0][0].get_min_index(), prior_Hessian_for_single_densel[z][y].get_min_index() - x); + const int max_dx = min(weights[0][0].get_max_index(), prior_Hessian_for_single_densel[z][y].get_max_index() - x); + elemT diagonal = 0; - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { // dz==0,dy==0,dx==0 will have weight 0, so we can just include it in the loop - elemT current = - weights[dz][dy][dx]; - + elemT current = weights[dz][dy][dx]; + if (do_kappa) - current *= - (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; - + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; + diagonal += current; - prior_Hessian_for_single_densel_cast[z+dz][y+dy][x+dx] = -current*this->penalisation_factor; + prior_Hessian_for_single_densel_cast[z + dz][y + dy][x + dx] = -current * this->penalisation_factor; } - - prior_Hessian_for_single_densel[z][y][x]= diagonal * this->penalisation_factor; -} + + prior_Hessian_for_single_densel[z][y][x] = diagonal * this->penalisation_factor; +} template -void -QuadraticPrior::parabolic_surrogate_curvature(DiscretisedDensity<3,elemT>& parabolic_surrogate_curvature, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ - - assert( parabolic_surrogate_curvature.has_same_characteristics(current_image_estimate)); - if (this->penalisation_factor==0) - { +void +QuadraticPrior::parabolic_surrogate_curvature(DiscretisedDensity<3, elemT>& parabolic_surrogate_curvature, + const DiscretisedDensity<3, elemT>& current_image_estimate) { + + assert(parabolic_surrogate_curvature.has_same_characteristics(current_image_estimate)); + if (this->penalisation_factor == 0) { parabolic_surrogate_curvature.fill(0); return; } - + this->check(current_image_estimate); - - const DiscretisedDensityOnCartesianGrid<3,elemT>& current_image_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,elemT> &>(current_image_estimate); - - if (weights.get_length() ==0) - { + + const DiscretisedDensityOnCartesianGrid<3, elemT>& current_image_cast = + dynamic_cast&>(current_image_estimate); + + if (weights.get_length() == 0) { compute_weights(weights, current_image_cast.get_grid_spacing(), this->only_2D); - } - + } + const bool do_kappa = !is_null_ptr(kappa_ptr); - + if (do_kappa && !kappa_ptr->has_same_characteristics(current_image_estimate)) error("QuadraticPrior: kappa image has not the same index range as the reconstructed image\n"); - const int min_z = current_image_estimate.get_min_index(); - const int max_z = current_image_estimate.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - const int min_dz = max(weights.get_min_index(), min_z-z); - const int max_dz = min(weights.get_max_index(), max_z-z); - - const int min_y = current_image_estimate[z].get_min_index(); - const int max_y = current_image_estimate[z].get_max_index(); - - for (int y=min_y;y<= max_y;y++) - { - const int min_dy = max(weights[0].get_min_index(), min_y-y); - const int max_dy = min(weights[0].get_max_index(), max_y-y); - - const int min_x = current_image_estimate[z][y].get_min_index(); - const int max_x = current_image_estimate[z][y].get_max_index(); - for (int x=min_x;x<= max_x;x++) - { - const int min_dx = max(weights[0][0].get_min_index(), min_x-x); - const int max_dx = min(weights[0][0].get_max_index(), max_x-x); - - elemT gradient = 0; - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { - // 1 comes from omega = psi'(t)/t = 2*t/2t =1 - elemT current = - weights[dz][dy][dx] *1; - - if (do_kappa) - current *= - (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; - - gradient += current; - } - - parabolic_surrogate_curvature[z][y][x]= gradient * this->penalisation_factor; - } - } + const int min_z = current_image_estimate.get_min_index(); + const int max_z = current_image_estimate.get_max_index(); + for (int z = min_z; z <= max_z; z++) { + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); + + const int min_y = current_image_estimate[z].get_min_index(); + const int max_y = current_image_estimate[z].get_max_index(); + + for (int y = min_y; y <= max_y; y++) { + const int min_dy = max(weights[0].get_min_index(), min_y - y); + const int max_dy = min(weights[0].get_max_index(), max_y - y); + + const int min_x = current_image_estimate[z][y].get_min_index(); + const int max_x = current_image_estimate[z][y].get_max_index(); + for (int x = min_x; x <= max_x; x++) { + const int min_dx = max(weights[0][0].get_min_index(), min_x - x); + const int max_dx = min(weights[0][0].get_max_index(), max_x - x); + + elemT gradient = 0; + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { + // 1 comes from omega = psi'(t)/t = 2*t/2t =1 + elemT current = weights[dz][dy][dx] * 1; + + if (do_kappa) + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; + + gradient += current; + } + + parabolic_surrogate_curvature[z][y][x] = gradient * this->penalisation_factor; + } } + } - info(boost::format("parabolic_surrogate_curvature max %1%, min %2%\n") % parabolic_surrogate_curvature.find_max() % parabolic_surrogate_curvature.find_min()); + info(boost::format("parabolic_surrogate_curvature max %1%, min %2%\n") % parabolic_surrogate_curvature.find_max() % + parabolic_surrogate_curvature.find_min()); /*{ static int count = 0; ++count; @@ -584,97 +509,82 @@ QuadraticPrior::parabolic_surrogate_curvature(DiscretisedDensity<3,elemT> } template -Succeeded -QuadraticPrior:: -add_multiplication_with_approximate_Hessian(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& input) const -{ +Succeeded +QuadraticPrior::add_multiplication_with_approximate_Hessian(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& input) const { return accumulate_Hessian_times_input(output, input, input); } template Succeeded -QuadraticPrior:: -accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& /*current_estimate*/, - const DiscretisedDensity<3,elemT>& input) const -{ +QuadraticPrior::accumulate_Hessian_times_input(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& /*current_estimate*/, + const DiscretisedDensity<3, elemT>& input) const { // TODO this function overlaps enormously with parabolic_surrogate_curvature // the only difference is that parabolic_surrogate_curvature uses input==1 - assert( output.has_same_characteristics(input)); - if (this->penalisation_factor==0) - { + assert(output.has_same_characteristics(input)); + if (this->penalisation_factor == 0) { return Succeeded::yes; } this->check(input); - - DiscretisedDensityOnCartesianGrid<3,elemT>& output_cast = - dynamic_cast &>(output); - if (weights.get_length() ==0) - { + DiscretisedDensityOnCartesianGrid<3, elemT>& output_cast = dynamic_cast&>(output); + + if (weights.get_length() == 0) { compute_weights(weights, output_cast.get_grid_spacing(), this->only_2D); - } - + } + const bool do_kappa = !is_null_ptr(kappa_ptr); - + if (do_kappa && !kappa_ptr->has_same_characteristics(input)) error("QuadraticPrior: kappa image has not the same index range as the reconstructed image\n"); - const int min_z = output.get_min_index(); - const int max_z = output.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - const int min_dz = max(weights.get_min_index(), min_z-z); - const int max_dz = min(weights.get_max_index(), max_z-z); - - const int min_y = output[z].get_min_index(); - const int max_y = output[z].get_max_index(); - - for (int y=min_y;y<= max_y;y++) - { - const int min_dy = max(weights[0].get_min_index(), min_y-y); - const int max_dy = min(weights[0].get_max_index(), max_y-y); - - const int min_x = output[z][y].get_min_index(); - const int max_x = output[z][y].get_max_index(); - - for (int x=min_x;x<= max_x;x++) - { - const int min_dx = max(weights[0][0].get_min_index(), min_x-x); - const int max_dx = min(weights[0][0].get_max_index(), max_x-x); - - elemT result = 0; - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { - elemT current = - weights[dz][dy][dx] * input[z+dz][y+dy][x+dx]; - - if (do_kappa) - current *= - (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; - result += current; - } - - output[z][y][x] += result * this->penalisation_factor; - } - } + const int min_z = output.get_min_index(); + const int max_z = output.get_max_index(); + for (int z = min_z; z <= max_z; z++) { + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); + + const int min_y = output[z].get_min_index(); + const int max_y = output[z].get_max_index(); + + for (int y = min_y; y <= max_y; y++) { + const int min_dy = max(weights[0].get_min_index(), min_y - y); + const int max_dy = min(weights[0].get_max_index(), max_y - y); + + const int min_x = output[z][y].get_min_index(); + const int max_x = output[z][y].get_max_index(); + + for (int x = min_x; x <= max_x; x++) { + const int min_dx = max(weights[0][0].get_min_index(), min_x - x); + const int max_dx = min(weights[0][0].get_max_index(), max_x - x); + + elemT result = 0; + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { + elemT current = weights[dz][dy][dx] * input[z + dz][y + dy][x + dx]; + + if (do_kappa) + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; + result += current; + } + + output[z][y][x] += result * this->penalisation_factor; + } } + } return Succeeded::yes; } -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif - +# pragma warning(disable : 4660) +#endif template class QuadraticPrior; END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/RayTraceVoxelsOnCartesianGrid.cxx b/src/recon_buildblock/RayTraceVoxelsOnCartesianGrid.cxx index 8d445e7612..f1633e78b5 100644 --- a/src/recon_buildblock/RayTraceVoxelsOnCartesianGrid.cxx +++ b/src/recon_buildblock/RayTraceVoxelsOnCartesianGrid.cxx @@ -21,7 +21,7 @@ \file \ingroup recon_buildblock - \brief Implementation of RayTraceVoxelsOnCartesianGrid + \brief Implementation of RayTraceVoxelsOnCartesianGrid \author Kris Thielemans \author Mustapha Sadki @@ -30,7 +30,7 @@ */ /* Modification history: - KT 30/05/2002 + KT 30/05/2002 start and stop point can now be arbitrarily located treatment of LORs parallel to planes is now scale independent (and checked with asserts) KT 18/05/2005 @@ -52,49 +52,39 @@ using std::max; START_NAMESPACE_STIR static inline bool -is_half_integer(const float a) -{ - return - fabs(floor(a)+.5F - a)<.0001F; +is_half_integer(const float a) { + return fabs(floor(a) + .5F - a) < .0001F; } -void -RayTraceVoxelsOnCartesianGrid - (ProjMatrixElemsForOneBin& lor, - const CartesianCoordinate3D& start_point, - const CartesianCoordinate3D& stop_point, - const CartesianCoordinate3D& voxel_size, - const float normalisation_constant) -{ - - const CartesianCoordinate3D difference = stop_point-start_point; - - if (norm(difference)<=.00001F) - { - // TODO - // not sure how to handle this case as we're normally ray tracing from voxel edges - warning("ray tracing with equal start and end point. Returning zero"); - return; - } +void +RayTraceVoxelsOnCartesianGrid(ProjMatrixElemsForOneBin& lor, const CartesianCoordinate3D& start_point, + const CartesianCoordinate3D& stop_point, const CartesianCoordinate3D& voxel_size, + const float normalisation_constant) { + + const CartesianCoordinate3D difference = stop_point - start_point; + + if (norm(difference) <= .00001F) { + // TODO + // not sure how to handle this case as we're normally ray tracing from voxel edges + warning("ray tracing with equal start and end point. Returning zero"); + return; + } // Find number of contributing elements. This will be used to // make sure there's enough space in the LOR to avoid reallocation. // This will make it faster, but also avoid over-allocation // (as most STL implementations double the allocated size at over-run). const int unsigned lor_size = - static_cast(ceil(fabs(difference.z())) + - ceil(fabs(difference.y())) + - ceil(fabs(difference.x()))) + 3; + static_cast(ceil(fabs(difference.z())) + ceil(fabs(difference.y())) + ceil(fabs(difference.x()))) + 3; // d12 is distance between the 2 points // it turns out we can multiply here with the normalisation_constant // (as that just scales the coordinate system) - const float d12 = - static_cast(norm(difference*voxel_size) * normalisation_constant); - - const int sign_x = difference.x()>=0 ? 1 : -1; - const int sign_y = difference.y()>=0 ? 1 : -1; - const int sign_z = difference.z()>=0 ? 1 : -1; + const float d12 = static_cast(norm(difference * voxel_size) * normalisation_constant); + + const int sign_x = difference.x() >= 0 ? 1 : -1; + const int sign_y = difference.y() >= 0 ? 1 : -1; + const int sign_z = difference.z() >= 0 ? 1 : -1; /* parametrise line in grid units as {z,y,x} = start_point + a difference/d12 @@ -104,52 +94,38 @@ RayTraceVoxelsOnCartesianGrid inc_x = d12*sign_x/difference.x() i.e. inc_x is always positive - Special treatment is necessary when the line is parallel to one of the - coordinate planes. This is determined by comparing difference with the + Special treatment is necessary when the line is parallel to one of the + coordinate planes. This is determined by comparing difference with the constant small_difference below. (Note that difference is in grid-units, so it has a natural scale of 1.) */ const float small_difference = 1.E-4F; - const bool zero_diff_in_x = fabs(difference.x())<=small_difference; - const bool zero_diff_in_y = fabs(difference.y())<=small_difference; - const bool zero_diff_in_z = fabs(difference.z())<=small_difference; + const bool zero_diff_in_x = fabs(difference.x()) <= small_difference; + const bool zero_diff_in_y = fabs(difference.y()) <= small_difference; + const bool zero_diff_in_z = fabs(difference.z()) <= small_difference; /* check if ray is in one of the planes between voxels. - If so, we will ray trace twice, i.e. to the 'left' and 'right', and store half + If so, we will ray trace twice, i.e. to the 'left' and 'right', and store half the value for each voxel. */ { - CartesianCoordinate3D inc(0,0,0); + CartesianCoordinate3D inc(0, 0, 0); // z - if (zero_diff_in_z && is_half_integer(start_point.z())) - { - inc = CartesianCoordinate3D (.5F,0,0); - } - else if (zero_diff_in_y && is_half_integer(start_point.y())) - { - inc = CartesianCoordinate3D (0,.5F,0); - } - else if (zero_diff_in_x && is_half_integer(start_point.x())) - { - inc = CartesianCoordinate3D (0,0,.5F); - } - if (norm(inc)>.1) - { - lor.reserve(lor.size() + 2*lor_size); - RayTraceVoxelsOnCartesianGrid(lor, - start_point - inc, - stop_point - inc, - voxel_size, - normalisation_constant/2); - - RayTraceVoxelsOnCartesianGrid(lor, - start_point + inc, - stop_point + inc, - voxel_size, - normalisation_constant/2); - lor.sort(); - return; - } + if (zero_diff_in_z && is_half_integer(start_point.z())) { + inc = CartesianCoordinate3D(.5F, 0, 0); + } else if (zero_diff_in_y && is_half_integer(start_point.y())) { + inc = CartesianCoordinate3D(0, .5F, 0); + } else if (zero_diff_in_x && is_half_integer(start_point.x())) { + inc = CartesianCoordinate3D(0, 0, .5F); + } + if (norm(inc) > .1) { + lor.reserve(lor.size() + 2 * lor_size); + RayTraceVoxelsOnCartesianGrid(lor, start_point - inc, stop_point - inc, voxel_size, normalisation_constant / 2); + + RayTraceVoxelsOnCartesianGrid(lor, start_point + inc, stop_point + inc, voxel_size, normalisation_constant / 2); + lor.sort(); + return; + } } // now start the normal case @@ -159,17 +135,17 @@ RayTraceVoxelsOnCartesianGrid lor.reserve(lor.size() + lor_size); - const float inc_x = zero_diff_in_x ? d12*1000000.F : d12 / fabs(difference.x()); - const float inc_y = zero_diff_in_y ? d12*1000000.F : d12 / fabs(difference.y()); - const float inc_z = zero_diff_in_z ? d12*1000000.F : d12 / fabs(difference.z()); - - // intersection points with intra-voxel planes : + const float inc_x = zero_diff_in_x ? d12 * 1000000.F : d12 / fabs(difference.x()); + const float inc_y = zero_diff_in_y ? d12 * 1000000.F : d12 / fabs(difference.y()); + const float inc_z = zero_diff_in_z ? d12 * 1000000.F : d12 / fabs(difference.z()); + + // intersection points with intra-voxel planes : // find voxel which contains the end_point, and go to its 'right' edge - const float xmax = round(stop_point.x()) + sign_x*0.5F; - const float ymax = round(stop_point.y()) + sign_y*0.5F; - const float zmax = round(stop_point.z()) + sign_z*0.5F; + const float xmax = round(stop_point.x()) + sign_x * 0.5F; + const float ymax = round(stop_point.y()) + sign_y * 0.5F; + const float zmax = round(stop_point.z()) + sign_z * 0.5F; - /* Find a?end for the last intersections with the coordinate planes. + /* Find a?end for the last intersections with the coordinate planes. amax will then be the smallest of all these a?end. If the LOR is parallel to a plane, take care that its a?end is larger than all the others. @@ -178,26 +154,26 @@ RayTraceVoxelsOnCartesianGrid In fact, we will take a?end slightly smaller than the actual last value (i.e. we multiply with a factor .9999). This is to avoid rounding errors in the loop below. In this loop, we try to detect the end of the LOR by comparing a (which is either ax,ay or az) with - aend. With exact arithmetic, a? would have been incremented exactly to - a?end_exact = a?start + (?max-?end)*inc_?*sign_?, + aend. With exact arithmetic, a? would have been incremented exactly to + a?end_exact = a?start + (?max-?end)*inc_?*sign_?, so we could loop until a==aend_exact. However, because of numerical precision, - a? might turn out be a tiny bit smaller then a?end_exact. So, we set aend a tiny bit + a? might turn out be a tiny bit smaller then a?end_exact. So, we set aend a tiny bit smaller than aend_exact. */ -const float axend = zero_diff_in_x ? d12*1000000.F : (xmax - start_point.x()) * inc_x * sign_x *.9999F; - const float ayend = zero_diff_in_y ? d12*1000000.F : (ymax - start_point.y()) * inc_y * sign_y *.9999F; - const float azend = zero_diff_in_z ? d12*1000000.F : (zmax - start_point.z()) * inc_z * sign_z *.9999F; - + const float axend = zero_diff_in_x ? d12 * 1000000.F : (xmax - start_point.x()) * inc_x * sign_x * .9999F; + const float ayend = zero_diff_in_y ? d12 * 1000000.F : (ymax - start_point.y()) * inc_y * sign_y * .9999F; + const float azend = zero_diff_in_z ? d12 * 1000000.F : (zmax - start_point.z()) * inc_z * sign_z * .9999F; + const float amax = min(axend, min(ayend, azend)); - + // just to be sure, check that axend was set large enough when difference.x() was small. - assert(fabs(difference.x())>small_difference || axend>amax); - assert(fabs(difference.y())>small_difference || ayend>amax); - assert(fabs(difference.z())>small_difference || azend>amax); + assert(fabs(difference.x()) > small_difference || axend > amax); + assert(fabs(difference.y()) > small_difference || ayend > amax); + assert(fabs(difference.z()) > small_difference || azend > amax); // coordinates of the first Voxel: CartesianCoordinate3D current_voxel = round(start_point); - + /* Find the a? values of the intersection points of the LOR with the planes between voxels at the 'left' side of the start_point.. This normally goes as follows: @@ -211,9 +187,9 @@ const float axend = zero_diff_in_x ? d12*1000000.F : (xmax - start_point.x()) * of numerical precision. Note on special handling of rays parallel to one of the planes: - + The corresponding a? value would be -infinity. We just set it to - a value low enough such that the start value of 'a' is not compromised + a value low enough such that the start value of 'a' is not compromised further on. Normally a? = (?min-start_point.?) * inc_? * sign_? @@ -223,56 +199,63 @@ const float axend = zero_diff_in_x ? d12*1000000.F : (xmax - start_point.x()) * -inc_? is a very low number. */ // with the previous xy-plane - float az = zero_diff_in_z ? -inc_z : - ((current_voxel.z() - start_point.z()) - sign_z*0.5F) * inc_z * sign_z; + float az = zero_diff_in_z ? -inc_z : ((current_voxel.z() - start_point.z()) - sign_z * 0.5F) * inc_z * sign_z; // with the previous yz-plane - float ax = zero_diff_in_x ? -inc_x : - ((current_voxel.x() - start_point.x()) - sign_x*0.5F) * inc_x * sign_x; + float ax = zero_diff_in_x ? -inc_x : ((current_voxel.x() - start_point.x()) - sign_x * 0.5F) * inc_x * sign_x; // with the previous xz-plane - float ay = zero_diff_in_y ? -inc_y : - ((current_voxel.y() - start_point.y()) - sign_y*0.5F) * inc_y * sign_y; - - // The biggest a? value gives the start of the a-row + float ay = zero_diff_in_y ? -inc_y : ((current_voxel.y() - start_point.y()) - sign_y * 0.5F) * inc_y * sign_y; + + // The biggest a? value gives the start of the a-row // Note that we should use a=0 if we want to start from start_point // (and not from the 'left' edge of the voxel containing start_point) - float a = max(ax, max(ay,az)); + float a = max(ax, max(ay, az)); // now go the intersections with next plane - if (zero_diff_in_x) ax = axend; else ax += inc_x; - if (zero_diff_in_y) ay = ayend; else ay += inc_y; - if (zero_diff_in_z) az = azend; else az += inc_z; - + if (zero_diff_in_x) + ax = axend; + else + ax += inc_x; + if (zero_diff_in_y) + ay = ayend; + else + ay += inc_y; + if (zero_diff_in_z) + az = azend; + else + az += inc_z; + // just to be sure, check that ax was set large enough when difference.x() was small. - assert(!zero_diff_in_x || ax>amax); - assert(!zero_diff_in_y || ay>amax); - assert(!zero_diff_in_z || az>amax); - - { - // go along the LOR - while ( a < amax) { - if ( ax < ay ) - if ( ax < az ) - { // LOR leaves voxel through yz-plane - lor.push_back(ProjMatrixElemsForOneBin::value_type(current_voxel,ax - a)); - a = ax;ax += inc_x; - current_voxel.x()+=sign_x; - } - else{ // LOR leaves voxel through xy-plane - lor.push_back(ProjMatrixElemsForOneBin::value_type(current_voxel,az - a)); - a = az ; az += inc_z; - current_voxel.z()+=sign_z; - } - else if ( ay < az) { // LOR leaves voxel through xz-plane - lor.push_back(ProjMatrixElemsForOneBin::value_type(current_voxel,ay - a)); - a = ay; ay += inc_y; - current_voxel.y()+=sign_y; - } - else {// LOR leaves voxel through xy-plane - lor.push_back(ProjMatrixElemsForOneBin::value_type(current_voxel,az - a )); - a = az; az += inc_z; - current_voxel.z()+=sign_z; + assert(!zero_diff_in_x || ax > amax); + assert(!zero_diff_in_y || ay > amax); + assert(!zero_diff_in_z || az > amax); + + { + // go along the LOR + while (a < amax) { + if (ax < ay) + if (ax < az) { // LOR leaves voxel through yz-plane + lor.push_back(ProjMatrixElemsForOneBin::value_type(current_voxel, ax - a)); + a = ax; + ax += inc_x; + current_voxel.x() += sign_x; + } else { // LOR leaves voxel through xy-plane + lor.push_back(ProjMatrixElemsForOneBin::value_type(current_voxel, az - a)); + a = az; + az += inc_z; + current_voxel.z() += sign_z; } - } // end of while (a -Reconstruction::Reconstruction() -{ +Reconstruction::Reconstruction() { this->set_defaults(); } - // parameters template -void -Reconstruction::set_defaults() -{ - this->_already_set_up=false; - this->output_filename_prefix=""; - this->output_file_format_ptr = - OutputFileFormat::default_sptr(); +void +Reconstruction::set_defaults() { + this->_already_set_up = false; + this->output_filename_prefix = ""; + this->output_file_format_ptr = OutputFileFormat::default_sptr(); this->post_filter_sptr.reset(); this->_disable_output = false; this->_verbosity = -1; - } template -void -Reconstruction::initialise_keymap() -{ +void +Reconstruction::initialise_keymap() { - this->parser.add_key("output filename prefix",&this->output_filename_prefix); + this->parser.add_key("output filename prefix", &this->output_filename_prefix); this->parser.add_parsing_key("output file format type", &this->output_file_format_ptr); - this->parser.add_parsing_key("post-filter type", &this->post_filter_sptr); + this->parser.add_parsing_key("post-filter type", &this->post_filter_sptr); this->parser.add_key("disable output", &_disable_output); this->parser.add_key("verbosity", &_verbosity); -// parser.add_key("END", &KeyParser::stop_parsing); - + // parser.add_key("END", &KeyParser::stop_parsing); } template -void -Reconstruction::initialise(const std::string& parameter_filename) -{ +void +Reconstruction::initialise(const std::string& parameter_filename) { _already_set_up = false; - if(parameter_filename.size()==0) - { + if (parameter_filename.size() == 0) { this->set_defaults(); this->ask_parameters(); } -else - { + else { this->set_defaults(); - if(!this->parse(parameter_filename.c_str())) - { + if (!this->parse(parameter_filename.c_str())) { error("Error parsing input file %s, exiting", parameter_filename.c_str()); } - } } - template -bool -Reconstruction:: -post_processing() -{ +bool +Reconstruction::post_processing() { - if ((this->_disable_output) & (this->get_registered_name ()=="KOSMAPOSL") ) - { warning("You have disabled the alpha coefficient output. Only emission image files will be written to " - "disk after or during reconstuction"); } + if ((this->_disable_output) & (this->get_registered_name() == "KOSMAPOSL")) { + warning("You have disabled the alpha coefficient output. Only emission image files will be written to " + "disk after or during reconstuction"); + } - else if (this->_disable_output) - { warning("You have disabled the output. No files will be written to " - "disk after or during reconstuction"); } + else if (this->_disable_output) { + warning("You have disabled the output. No files will be written to " + "disk after or during reconstuction"); + } - if (this->output_filename_prefix.length() == 0 && - !this->_disable_output)// KT 160899 changed name of variable - { warning("You need to specify an output prefix"); return true; } + if (this->output_filename_prefix.length() == 0 && !this->_disable_output) // KT 160899 changed name of variable + { + warning("You need to specify an output prefix"); + return true; + } - if (is_null_ptr(this->output_file_format_ptr)) - { warning("output file format has to be set to valid value"); return true; } + if (is_null_ptr(this->output_file_format_ptr)) { + warning("output file format has to be set to valid value"); + return true; + } if (_verbosity >= 0) - Verbosity::set(_verbosity); + Verbosity::set(_verbosity); return false; } template void -Reconstruction:: -set_output_filename_prefix(const std::string& arg) -{ - this->output_filename_prefix = arg; +Reconstruction::set_output_filename_prefix(const std::string& arg) { + this->output_filename_prefix = arg; } template void -Reconstruction:: -set_output_file_format_ptr(const shared_ptr >& arg) -{ - this->output_file_format_ptr = arg; +Reconstruction::set_output_file_format_ptr(const shared_ptr>& arg) { + this->output_file_format_ptr = arg; } template void -Reconstruction:: -set_post_processor_sptr(const shared_ptr > & arg) -{ +Reconstruction::set_post_processor_sptr(const shared_ptr>& arg) { _already_set_up = false; - this->post_filter_sptr = arg; + this->post_filter_sptr = arg; } - + template Succeeded -Reconstruction:: -set_up(shared_ptr const& target_data_sptr_v) -{ +Reconstruction::set_up(shared_ptr const& target_data_sptr_v) { _already_set_up = true; this->target_data_sptr = target_data_sptr_v; - if(!is_null_ptr(this->post_filter_sptr)) - { + if (!is_null_ptr(this->post_filter_sptr)) { info("Building post filter kernel"); - - if (this->post_filter_sptr->set_up(*target_data_sptr) - == Succeeded::no) - { - warning("Error building post filter"); - return Succeeded::no; - } + + if (this->post_filter_sptr->set_up(*target_data_sptr) == Succeeded::no) { + warning("Error building post filter"); + return Succeeded::no; + } } return Succeeded::yes; } template void -Reconstruction:: -check(TargetT const& target_data) const -{ +Reconstruction::check(TargetT const& target_data) const { if (!this->_already_set_up) error("Reconstruction method called without calling set_up first."); - if (! this->target_data_sptr->has_same_characteristics(target_data)) + if (!this->target_data_sptr->has_same_characteristics(target_data)) error("Reconstruction set-up with different geometry for target."); } template void -Reconstruction:: -set_disable_output(bool _val) -{ - this->_disable_output = _val; +Reconstruction::set_disable_output(bool _val) { + this->_disable_output = _val; } template void -Reconstruction:: -set_enable_output(bool _val) -{ - this->_disable_output = _val; +Reconstruction::set_enable_output(bool _val) { + this->_disable_output = _val; } -template < typename TargetT> -shared_ptr -Reconstruction:: -get_target_image() -{ - return target_data_sptr; +template +shared_ptr +Reconstruction::get_target_image() { + return target_data_sptr; } -template class Reconstruction >; -template class Reconstruction; +template class Reconstruction>; +template class Reconstruction; END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/RegisteredObject.cxx b/src/recon_buildblock/RegisteredObject.cxx index b7cc2fffbf..b9e2aaacf6 100644 --- a/src/recon_buildblock/RegisteredObject.cxx +++ b/src/recon_buildblock/RegisteredObject.cxx @@ -32,45 +32,43 @@ #ifdef __STIR_REGISTRY_NOT_INLINE -#pragma message("instantiating RegisteredObject >") -#include "stir/recon_buildblock/GeneralisedPrior.h" +# pragma message("instantiating RegisteredObject >") +# include "stir/recon_buildblock/GeneralisedPrior.h" -#pragma message("instantiating RegisteredObject") -#include "stir/recon_buildblock/ProjMatrixByBin.h" +# pragma message("instantiating RegisteredObject") +# include "stir/recon_buildblock/ProjMatrixByBin.h" -#pragma message("instantiating RegisteredObject") -#include "stir/recon_buildblock/ProjectorByBinPair.h" +# pragma message("instantiating RegisteredObject") +# include "stir/recon_buildblock/ProjectorByBinPair.h" -#pragma message("instantiating RegisteredObject") -#include "stir/recon_buildblock/ForwardProjectorByBin.h" +# pragma message("instantiating RegisteredObject") +# include "stir/recon_buildblock/ForwardProjectorByBin.h" -#pragma message("instantiating RegisteredObject") -#include "stir/recon_buildblock/BackProjectorByBin.h" +# pragma message("instantiating RegisteredObject") +# include "stir/recon_buildblock/BackProjectorByBin.h" -#pragma message("instantiating RegisteredObject") -#include "stir/recon_buildblock/BinNormalisation.h" +# pragma message("instantiating RegisteredObject") +# include "stir/recon_buildblock/BinNormalisation.h" // and others START_NAMESPACE_STIR template -RegisteredObject::RegistryType& -RegisteredObject::registry () -{ +RegisteredObject::RegistryType& +RegisteredObject::registry() { static RegistryType the_registry("None", 0); return the_registry; } # ifdef _MSC_VER -// prevent warning message on reinstantiation, +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) +# pragma warning(disable : 4660) # endif +template RegisteredObject>; -template RegisteredObject >; - -template RegisteredObject; +template RegisteredObject; template RegisteredObject; diff --git a/src/recon_buildblock/RelativeDifferencePrior.cxx b/src/recon_buildblock/RelativeDifferencePrior.cxx index dd6454205d..eb1df317e2 100644 --- a/src/recon_buildblock/RelativeDifferencePrior.cxx +++ b/src/recon_buildblock/RelativeDifferencePrior.cxx @@ -21,7 +21,7 @@ \file \ingroup priors \brief implementation of the stir::RelativeDifferencePrior class - + \author Kris Thielemans \author Sanida Mustafovic \author Robert Twyman @@ -46,12 +46,11 @@ using std::max; START_NAMESPACE_STIR template -void -RelativeDifferencePrior::initialise_keymap() -{ +void +RelativeDifferencePrior::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Relative Difference Prior Parameters"); - this->parser.add_key("only 2D", &only_2D); + this->parser.add_key("only 2D", &only_2D); this->parser.add_key("kappa filename", &kappa_filename); this->parser.add_key("weights", &weights); this->parser.add_key("gradient filename prefix", &gradient_filename_prefix); @@ -61,391 +60,347 @@ RelativeDifferencePrior::initialise_keymap() } template -bool -RelativeDifferencePrior::post_processing() -{ - if (base_type::post_processing()==true) +bool +RelativeDifferencePrior::post_processing() { + if (base_type::post_processing() == true) return true; if (kappa_filename.size() != 0) - this->kappa_ptr = read_from_file >(kappa_filename); + this->kappa_ptr = read_from_file>(kappa_filename); bool warn_about_even_size = false; - if (this->weights.size() ==0) - { - // will call compute_weights() to fill it in + if (this->weights.size() == 0) { + // will call compute_weights() to fill it in + } else { + if (!this->weights.is_regular()) { + warning("Sorry. RelativeDifferencePrior currently only supports regular arrays for the weights"); + return true; } - else - { - if (!this->weights.is_regular()) - { - warning("Sorry. RelativeDifferencePrior currently only supports regular arrays for the weights"); - return true; - } - const unsigned int size_z = this->weights.size(); - if (size_z%2==0) + const unsigned int size_z = this->weights.size(); + if (size_z % 2 == 0) + warn_about_even_size = true; + const int min_index_z = -static_cast(size_z / 2); + this->weights.set_min_index(min_index_z); + + for (int z = min_index_z; z <= this->weights.get_max_index(); ++z) { + const unsigned int size_y = this->weights[z].size(); + if (size_y % 2 == 0) warn_about_even_size = true; - const int min_index_z = -static_cast(size_z/2); - this->weights.set_min_index(min_index_z); - - for (int z = min_index_z; z<= this->weights.get_max_index(); ++z) - { - const unsigned int size_y = this->weights[z].size(); - if (size_y%2==0) - warn_about_even_size = true; - const int min_index_y = -static_cast(size_y/2); - this->weights[z].set_min_index(min_index_y); - for (int y = min_index_y; y<= this->weights[z].get_max_index(); ++y) - { - const unsigned int size_x = this->weights[z][y].size(); - if (size_x%2==0) - warn_about_even_size = true; - const int min_index_x = -static_cast(size_x/2); - this->weights[z][y].set_min_index(min_index_x); - } - } + const int min_index_y = -static_cast(size_y / 2); + this->weights[z].set_min_index(min_index_y); + for (int y = min_index_y; y <= this->weights[z].get_max_index(); ++y) { + const unsigned int size_x = this->weights[z][y].size(); + if (size_x % 2 == 0) + warn_about_even_size = true; + const int min_index_x = -static_cast(size_x / 2); + this->weights[z][y].set_min_index(min_index_x); + } } + } if (warn_about_even_size) warning("Parsing RelativeDifferencePrior: even number of weights occured in either x,y or z dimension.\n" "I'll (effectively) make this odd by appending a 0 at the end."); return false; - } template Succeeded -RelativeDifferencePrior::set_up (shared_ptr > const& target_sptr) -{ +RelativeDifferencePrior::set_up(shared_ptr> const& target_sptr) { base_type::set_up(target_sptr); return Succeeded::yes; } template -void RelativeDifferencePrior::check(DiscretisedDensity<3,elemT> const& current_image_estimate) const -{ +void +RelativeDifferencePrior::check(DiscretisedDensity<3, elemT> const& current_image_estimate) const { // Do base-class check base_type::check(current_image_estimate); } template void -RelativeDifferencePrior::set_defaults() -{ +RelativeDifferencePrior::set_defaults() { base_type::set_defaults(); this->only_2D = false; - this->kappa_ptr.reset(); + this->kappa_ptr.reset(); this->weights.recycle(); this->gamma = 2; this->epsilon = 0.0; } template <> -const char * const -RelativeDifferencePrior::registered_name = - "Relative Difference Prior"; +const char* const RelativeDifferencePrior::registered_name = "Relative Difference Prior"; template -RelativeDifferencePrior::RelativeDifferencePrior() -{ +RelativeDifferencePrior::RelativeDifferencePrior() { set_defaults(); } // Return the value of gamma - a RDP parameter template float -RelativeDifferencePrior:: -get_gamma() const -{ return this->gamma; } +RelativeDifferencePrior::get_gamma() const { + return this->gamma; +} // Set the value of gamma - a RDP parameter template void -RelativeDifferencePrior:: -set_gamma(float g) -{ this->gamma = g; } +RelativeDifferencePrior::set_gamma(float g) { + this->gamma = g; +} // Return the value of epsilon - a RDP parameter template float -RelativeDifferencePrior:: -get_epsilon() const -{ return this->epsilon; } +RelativeDifferencePrior::get_epsilon() const { + return this->epsilon; +} // Set the value of epsilon - a RDP parameter template void -RelativeDifferencePrior:: -set_epsilon(float g) -{ this->epsilon = g; } - +RelativeDifferencePrior::set_epsilon(float g) { + this->epsilon = g; +} template -RelativeDifferencePrior::RelativeDifferencePrior(const bool only_2D_v, float penalisation_factor_v, float gamma_v, float epsilon_v) - : only_2D(only_2D_v) -{ +RelativeDifferencePrior::RelativeDifferencePrior(const bool only_2D_v, float penalisation_factor_v, float gamma_v, + float epsilon_v) + : only_2D(only_2D_v) { this->penalisation_factor = penalisation_factor_v; this->gamma = gamma_v; this->epsilon = epsilon_v; } - - //! get penalty weights for the neighbourhood +//! get penalty weights for the neighbourhood template -Array<3,float> -RelativeDifferencePrior:: -get_weights() const -{ return this->weights; } +Array<3, float> +RelativeDifferencePrior::get_weights() const { + return this->weights; +} - //! set penalty weights for the neighbourhood -template -void -RelativeDifferencePrior:: -set_weights(const Array<3,float>& w) -{ this->weights = w; } - - //! get current kappa image - /*! \warning As this function returns a shared_ptr, this is dangerous. You should not - modify the image by manipulating the image referred to by this pointer. - Unpredictable results will occur. - */ +//! set penalty weights for the neighbourhood template -shared_ptr > -RelativeDifferencePrior:: -get_kappa_sptr() const -{ return this->kappa_ptr; } +void +RelativeDifferencePrior::set_weights(const Array<3, float>& w) { + this->weights = w; +} - //! set kappa image +//! get current kappa image +/*! \warning As this function returns a shared_ptr, this is dangerous. You should not + modify the image by manipulating the image referred to by this pointer. + Unpredictable results will occur. +*/ template -void -RelativeDifferencePrior:: -set_kappa_sptr(const shared_ptr >& k) -{ this->kappa_ptr = k; } +shared_ptr> +RelativeDifferencePrior::get_kappa_sptr() const { + return this->kappa_ptr; +} +//! set kappa image +template +void +RelativeDifferencePrior::set_kappa_sptr(const shared_ptr>& k) { + this->kappa_ptr = k; +} // TODO move to set_up // initialise to 1/Euclidean distance -static void -compute_weights(Array<3,float>& weights, const CartesianCoordinate3D& grid_spacing, const bool only_2D) -{ +static void +compute_weights(Array<3, float>& weights, const CartesianCoordinate3D& grid_spacing, const bool only_2D) { int min_dz, max_dz; - if (only_2D) - { - min_dz = max_dz = 0; - } - else - { - min_dz = -1; - max_dz = 1; - } - weights = Array<3,float>(IndexRange3D(min_dz,max_dz,-1,1,-1,1)); - for (int z=min_dz;z<=max_dz;++z) - for (int y=-1;y<=1;++y) - for (int x=-1;x<=1;++x) - { - if (z==0 && y==0 && x==0) - weights[0][0][0] = 0; - else - { - weights[z][y][x] = - grid_spacing.x()/ - sqrt(square(x*grid_spacing.x())+ - square(y*grid_spacing.y())+ - square(z*grid_spacing.z())); - } + if (only_2D) { + min_dz = max_dz = 0; + } else { + min_dz = -1; + max_dz = 1; + } + weights = Array<3, float>(IndexRange3D(min_dz, max_dz, -1, 1, -1, 1)); + for (int z = min_dz; z <= max_dz; ++z) + for (int y = -1; y <= 1; ++y) + for (int x = -1; x <= 1; ++x) { + if (z == 0 && y == 0 && x == 0) + weights[0][0][0] = 0; + else { + weights[z][y][x] = + grid_spacing.x() / sqrt(square(x * grid_spacing.x()) + square(y * grid_spacing.y()) + square(z * grid_spacing.z())); } + } } template double -RelativeDifferencePrior:: -compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ - if (this->penalisation_factor==0) - { +RelativeDifferencePrior::compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) { + if (this->penalisation_factor == 0) { return 0.; } - + this->check(current_image_estimate); - - const DiscretisedDensityOnCartesianGrid<3,elemT>& current_image_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,elemT> &>(current_image_estimate); - - if (this->weights.get_length() ==0) - { + + const DiscretisedDensityOnCartesianGrid<3, elemT>& current_image_cast = + dynamic_cast&>(current_image_estimate); + + if (this->weights.get_length() == 0) { compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); } - + const bool do_kappa = !is_null_ptr(kappa_ptr); - + if (do_kappa && !kappa_ptr->has_same_characteristics(current_image_estimate)) error("RelativeDifferencePrior: kappa image has not the same index range as the reconstructed image\n"); - double result = 0.; - const int min_z = current_image_estimate.get_min_index(); - const int max_z = current_image_estimate.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - const int min_dz = max(weights.get_min_index(), min_z-z); - const int max_dz = min(weights.get_max_index(), max_z-z); - - const int min_y = current_image_estimate[z].get_min_index(); - const int max_y = current_image_estimate[z].get_max_index(); - - for (int y=min_y;y<= max_y;y++) - { - const int min_dy = max(weights[0].get_min_index(), min_y-y); - const int max_dy = min(weights[0].get_max_index(), max_y-y); - - const int min_x = current_image_estimate[z][y].get_min_index(); - const int max_x = current_image_estimate[z][y].get_max_index(); - - for (int x=min_x;x<= max_x;x++) - { - const int min_dx = max(weights[0][0].get_min_index(), min_x-x); - const int max_dx = min(weights[0][0].get_max_index(), max_x-x); - - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { - elemT current; - if (this->epsilon ==0.0 && current_image_estimate[z][y][x] == 0.0 && current_image_estimate[z+dz][y+dy][x+dx] == 0.0){ - // handle the undefined nature of the function - current = 0.0; - } else { - current = weights[dz][dy][dx] * 0.5 * - (pow(current_image_estimate[z][y][x]-current_image_estimate[z+dz][y+dy][x+dx],2)/ - (current_image_estimate[z][y][x]+current_image_estimate[z+dz][y+dy][x+dx] - + this->gamma * abs(current_image_estimate[z][y][x]-current_image_estimate[z+dz][y+dy][x+dx]) + this->epsilon )); - } - if (do_kappa) - current *= - (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; - - result += static_cast(current); - } - } - } + const int min_z = current_image_estimate.get_min_index(); + const int max_z = current_image_estimate.get_max_index(); + for (int z = min_z; z <= max_z; z++) { + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); + + const int min_y = current_image_estimate[z].get_min_index(); + const int max_y = current_image_estimate[z].get_max_index(); + + for (int y = min_y; y <= max_y; y++) { + const int min_dy = max(weights[0].get_min_index(), min_y - y); + const int max_dy = min(weights[0].get_max_index(), max_y - y); + + const int min_x = current_image_estimate[z][y].get_min_index(); + const int max_x = current_image_estimate[z][y].get_max_index(); + + for (int x = min_x; x <= max_x; x++) { + const int min_dx = max(weights[0][0].get_min_index(), min_x - x); + const int max_dx = min(weights[0][0].get_max_index(), max_x - x); + + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { + elemT current; + if (this->epsilon == 0.0 && current_image_estimate[z][y][x] == 0.0 && + current_image_estimate[z + dz][y + dy][x + dx] == 0.0) { + // handle the undefined nature of the function + current = 0.0; + } else { + current = weights[dz][dy][dx] * 0.5 * + (pow(current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx], 2) / + (current_image_estimate[z][y][x] + current_image_estimate[z + dz][y + dy][x + dx] + + this->gamma * abs(current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx]) + + this->epsilon)); + } + if (do_kappa) + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; + + result += static_cast(current); + } + } } + } return result * this->penalisation_factor; } template -void -RelativeDifferencePrior:: -compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) -{ - assert( prior_gradient.has_same_characteristics(current_image_estimate)); - if (this->penalisation_factor==0) - { +void +RelativeDifferencePrior::compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, + const DiscretisedDensity<3, elemT>& current_image_estimate) { + assert(prior_gradient.has_same_characteristics(current_image_estimate)); + if (this->penalisation_factor == 0) { prior_gradient.fill(0); return; } this->check(current_image_estimate); - - - const DiscretisedDensityOnCartesianGrid<3,elemT>& current_image_cast = - dynamic_cast< const DiscretisedDensityOnCartesianGrid<3,elemT> &>(current_image_estimate); - - if (this->weights.get_length() ==0) - { + + const DiscretisedDensityOnCartesianGrid<3, elemT>& current_image_cast = + dynamic_cast&>(current_image_estimate); + + if (this->weights.get_length() == 0) { compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); } - - + const bool do_kappa = !is_null_ptr(kappa_ptr); if (do_kappa && !kappa_ptr->has_same_characteristics(current_image_estimate)) error("RelativeDifferencePrior: kappa image has not the same index range as the reconstructed image\n"); - const int min_z = current_image_estimate.get_min_index(); - const int max_z = current_image_estimate.get_max_index(); - for (int z=min_z; z<=max_z; z++) - { - const int min_dz = max(weights.get_min_index(), min_z-z); - const int max_dz = min(weights.get_max_index(), max_z-z); - - const int min_y = current_image_estimate[z].get_min_index(); - const int max_y = current_image_estimate[z].get_max_index(); - - for (int y=min_y;y<= max_y;y++) - { - const int min_dy = max(weights[0].get_min_index(), min_y-y); - const int max_dy = min(weights[0].get_max_index(), max_y-y); - - const int min_x = current_image_estimate[z][y].get_min_index(); - const int max_x = current_image_estimate[z][y].get_max_index(); - - for (int x=min_x;x<= max_x;x++) - { - const int min_dx = max(weights[0][0].get_min_index(), min_x-x); - const int max_dx = min(weights[0][0].get_max_index(), max_x-x); - - elemT gradient = 0; - for (int dz=min_dz;dz<=max_dz;++dz) - for (int dy=min_dy;dy<=max_dy;++dy) - for (int dx=min_dx;dx<=max_dx;++dx) - { - - elemT current; - if (this->epsilon ==0.0 && current_image_estimate[z][y][x] == 0.0 && current_image_estimate[z+dz][y+dy][x+dx] == 0.0){ - // handle the undefined nature of the gradient - current = 0.0; - } else { - current = weights[dz][dy][dx] * - (((current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx]) * - (this->gamma * abs(current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx]) + - current_image_estimate[z][y][x] + 3 * current_image_estimate[z+dz][y+dy][x+dx] + 2 * this->epsilon))/ - (square((current_image_estimate[z][y][x] + current_image_estimate[z+dz][y+dy][x+dx]) + - this->gamma * abs(current_image_estimate[z][y][x] - current_image_estimate[z+dz][y+dy][x+dx]) + this->epsilon))); - } - if (do_kappa) - current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; - - gradient += current; - } - - prior_gradient[z][y][x]= gradient * this->penalisation_factor; - } - } + const int min_z = current_image_estimate.get_min_index(); + const int max_z = current_image_estimate.get_max_index(); + for (int z = min_z; z <= max_z; z++) { + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); + + const int min_y = current_image_estimate[z].get_min_index(); + const int max_y = current_image_estimate[z].get_max_index(); + + for (int y = min_y; y <= max_y; y++) { + const int min_dy = max(weights[0].get_min_index(), min_y - y); + const int max_dy = min(weights[0].get_max_index(), max_y - y); + + const int min_x = current_image_estimate[z][y].get_min_index(); + const int max_x = current_image_estimate[z][y].get_max_index(); + + for (int x = min_x; x <= max_x; x++) { + const int min_dx = max(weights[0][0].get_min_index(), min_x - x); + const int max_dx = min(weights[0][0].get_max_index(), max_x - x); + + elemT gradient = 0; + for (int dz = min_dz; dz <= max_dz; ++dz) + for (int dy = min_dy; dy <= max_dy; ++dy) + for (int dx = min_dx; dx <= max_dx; ++dx) { + + elemT current; + if (this->epsilon == 0.0 && current_image_estimate[z][y][x] == 0.0 && + current_image_estimate[z + dz][y + dy][x + dx] == 0.0) { + // handle the undefined nature of the gradient + current = 0.0; + } else { + current = + weights[dz][dy][dx] * + (((current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx]) * + (this->gamma * abs(current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx]) + + current_image_estimate[z][y][x] + 3 * current_image_estimate[z + dz][y + dy][x + dx] + + 2 * this->epsilon)) / + (square((current_image_estimate[z][y][x] + current_image_estimate[z + dz][y + dy][x + dx]) + + this->gamma * abs(current_image_estimate[z][y][x] - current_image_estimate[z + dz][y + dy][x + dx]) + + this->epsilon))); + } + if (do_kappa) + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; + + gradient += current; + } + + prior_gradient[z][y][x] = gradient * this->penalisation_factor; + } } + } info(boost::format("Prior gradient max %1%, min %2%\n") % prior_gradient.find_max() % prior_gradient.find_min()); static int count = 0; ++count; - if (gradient_filename_prefix.size()>0) - { - char *filename = new char[gradient_filename_prefix.size()+100]; - sprintf(filename, "%s%d.v", gradient_filename_prefix.c_str(), count); - write_to_file(filename, prior_gradient); - delete[] filename; - } + if (gradient_filename_prefix.size() > 0) { + char* filename = new char[gradient_filename_prefix.size() + 100]; + sprintf(filename, "%s%d.v", gradient_filename_prefix.c_str(), count); + write_to_file(filename, prior_gradient); + delete[] filename; + } } template -Succeeded -RelativeDifferencePrior:: -add_multiplication_with_approximate_Hessian(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& input) const -{ - error("add_multiplication_with_approximate_Hessian() is not implemented in Relative Difference Prior."); +Succeeded +RelativeDifferencePrior::add_multiplication_with_approximate_Hessian(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& input) const { + error("add_multiplication_with_approximate_Hessian() is not implemented in Relative Difference Prior."); return Succeeded::no; } -# ifdef _MSC_VER -// prevent warning message on reinstantiation, +#ifdef _MSC_VER +// prevent warning message on reinstantiation, // note that we get a linking error if we don't have the explicit instantiation below -# pragma warning(disable:4660) -# endif - +# pragma warning(disable : 4660) +#endif template class RelativeDifferencePrior; END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/SPECTUB_Tools.cxx b/src/recon_buildblock/SPECTUB_Tools.cxx index b3a1a42fef..eab6924624 100644 --- a/src/recon_buildblock/SPECTUB_Tools.cxx +++ b/src/recon_buildblock/SPECTUB_Tools.cxx @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Biomedical Image Group (GIB), Universitat de Barcelona, Barcelona, Spain. + Copyright (c) 2013, Biomedical Image Group (GIB), Universitat de Barcelona, Barcelona, Spain. Copyright (c) 2013, University College London This file is part of STIR. @@ -18,7 +18,7 @@ \author Carles Falcon */ -//system libraries +// system libraries #include #include #include @@ -30,444 +30,457 @@ #include using namespace std; -//using std::string; +// using std::string; //... user defined libraries ....................................... #include "stir/recon_buildblock/SPECTUB_Tools.h" #include "stir/recon_buildblock/SPECTUB_Weight3d.h" - namespace SPECTUB { -#define NUMARG 29 +#define NUMARG 29 #define EPSILON 1e-12 #define EOS '\0' -#define maxim(a,b) ((a)>=(b)?(a):(b)) -#define minim(a,b) ((a)<=(b)?(a):(b)) -#define abs(a) ((a)>=0?(a):(-a)) -#define SIGN(a) (a<-EPSILON?-1:(a>EPSILON?1:0)) +#define maxim(a, b) ((a) >= (b) ? (a) : (b)) +#define minim(a, b) ((a) <= (b) ? (a) : (b)) +#define abs(a) ((a) >= 0 ? (a) : (-a)) +#define SIGN(a) (a < -EPSILON ? -1 : (a > EPSILON ? 1 : 0)) -#define DELIMITER1 '#' //delimiter character in input parameter text file -#define DELIMITER2 '%' //delimiter character in input parameter text file +#define DELIMITER1 '#' // delimiter character in input parameter text file +#define DELIMITER2 '%' // delimiter character in input parameter text file //... global variables .............................................. extern wm_da_type wm; -extern wmh_type wmh; -extern float * Rrad; - +extern wmh_type wmh; +extern float* Rrad; //============================================================================= //=== write_wm_FC ============================================================= //============================================================================= -void write_wm_FC() -{ - FILE *fid; - - int ia_acum = 0; - - if ( (fid = fopen( wm.OSfn.c_str(), "wb" ) ) == NULL ) error_wmtools_SPECT( 31, wm.OSfn ); - - fwrite ( &(wm.NbOS), sizeof(int), 1, fid); // to write number of rows of wm (NbOS) - fwrite ( &(wm.Nvox), sizeof(int), 1, fid); // to write number of columns of wm (Nvox) - - //... number of non-zero elements in the weight matrix ....... - - int ne = 0; - for ( int j=0 ; j < wm.NbOS ; j++ ) ne += wm.ne[j]; +void +write_wm_FC() { + FILE* fid; - fwrite ( &ne, sizeof(int), 1, fid); // to write number of non-zeros element in the weight matrix - - //... to write the array of weights (along rows) .............. - - for ( int i = 0 ; i < wm.NbOS ; i++ ){ - for (int j = 0 ; j < wm.ne[i] ; j++ ){ - fwrite ( &wm.val[ i ][ j ], sizeof(float), 1, fid); - } - } - - //... to write the column index of each weight (volume index of the voxel the weight is associated to) .... - - for ( int i = 0 ; i < wm.NbOS ; i++ ){ - for ( int j = 0 ; j < wm.ne[ i ] ; j++ ){ - fwrite ( &wm.col[ i ][ j ] ,sizeof(int) ,1 , fid); - } - } + int ia_acum = 0; - //... to write the indexs of the array of weights where a change of row happens ......... - - for ( int i = 0 ; i < wm.NbOS ; i++ ){ - fwrite ( &ia_acum, sizeof(int), 1, fid); - ia_acum += wm.ne[i]; - } + if ((fid = fopen(wm.OSfn.c_str(), "wb")) == NULL) + error_wmtools_SPECT(31, wm.OSfn); - //... to write the total number of saved weights .......................... - - fwrite ( &ia_acum, sizeof(int), 1, fid); - - cout << "number of non-zero elemnts: " << ia_acum << endl; + fwrite(&(wm.NbOS), sizeof(int), 1, fid); // to write number of rows of wm (NbOS) + fwrite(&(wm.Nvox), sizeof(int), 1, fid); // to write number of columns of wm (Nvox) + + //... number of non-zero elements in the weight matrix ....... + + int ne = 0; + for (int j = 0; j < wm.NbOS; j++) + ne += wm.ne[j]; + + fwrite(&ne, sizeof(int), 1, fid); // to write number of non-zeros element in the weight matrix + + //... to write the array of weights (along rows) .............. - fclose (fid); + for (int i = 0; i < wm.NbOS; i++) { + for (int j = 0; j < wm.ne[i]; j++) { + fwrite(&wm.val[i][j], sizeof(float), 1, fid); + } + } + + //... to write the column index of each weight (volume index of the voxel the weight is associated to) .... + + for (int i = 0; i < wm.NbOS; i++) { + for (int j = 0; j < wm.ne[i]; j++) { + fwrite(&wm.col[i][j], sizeof(int), 1, fid); + } + } + + //... to write the indexs of the array of weights where a change of row happens ......... + + for (int i = 0; i < wm.NbOS; i++) { + fwrite(&ia_acum, sizeof(int), 1, fid); + ia_acum += wm.ne[i]; + } + + //... to write the total number of saved weights .......................... + + fwrite(&ia_acum, sizeof(int), 1, fid); + + cout << "number of non-zero elemnts: " << ia_acum << endl; + + fclose(fid); } //============================================================================= //=== write_wm_hdr ============================================================ //============================================================================= -void write_wm_hdr() -{ - ofstream stream1( wm.fn_hdr.c_str() ); - if( !stream1 ) error_wmtools_SPECT( 31, wm.fn_hdr ); - - //....... image and projections characteristics......... - - stream1 << "Header for the matrix: " << wm.fn << endl; - stream1 << "number of columns: " << wmh.vol.Ncol << endl; - stream1 << "number of rows: " << wmh.vol.Nrow << endl; - stream1 << "number of slices: " << wmh.vol.Nsli << endl; - stream1 << "voxel size (cm): " << wmh.vol.szcm << endl; - stream1 << "slice thickness (cm): " << wmh.vol.thcm << endl; - - stream1 << "number of bins per line: " << wmh.prj.Nbin << endl; - stream1 << "bin size (cm): " << wmh.prj.szcm << endl; - stream1 << "number of angles: " << wmh.prj.Nang << endl; - stream1 << "first angle (deg): " << wmh.prj.ang0 << endl; - stream1 << "angle increment between consecutive projections (deg): " << wmh.prj.incr << endl; - - stream1 << "first slice to reconstruct : " << wmh.vol.first_sl << endl; - stream1 << "last slice to reconstruct : " << wmh.vol.last_sl << endl; - stream1 << "number of subsets in which to split the matrix: " << wmh.prj.NOS << endl; - stream1 << "number of angles per subsets: " << wmh.prj.NangOS << endl; - - stream1 << "minimum weight (geometrical contribution): " << wmh.min_w << endl; - stream1 << "psf resolution (discretization interval for Gaussian): " << wmh.psfres << endl; - stream1 << "maximum number of sigmas in psf calculation: " << wmh.maxsigm << endl; - - //........ rotation radius................................ - - if ( wmh.fixed_Rrad ) stream1 << "fixed rotation radius :" << wmh.Rrad[ 0 ] << " cm" << endl; - else stream1 << "variable rotation radius from :" << wmh.Rrad_fn << endl; - - //......... psf and collimator parameters ................. +void +write_wm_hdr() { + ofstream stream1(wm.fn_hdr.c_str()); + if (!stream1) + error_wmtools_SPECT(31, wm.fn_hdr); + + //....... image and projections characteristics......... + + stream1 << "Header for the matrix: " << wm.fn << endl; + stream1 << "number of columns: " << wmh.vol.Ncol << endl; + stream1 << "number of rows: " << wmh.vol.Nrow << endl; + stream1 << "number of slices: " << wmh.vol.Nsli << endl; + stream1 << "voxel size (cm): " << wmh.vol.szcm << endl; + stream1 << "slice thickness (cm): " << wmh.vol.thcm << endl; + + stream1 << "number of bins per line: " << wmh.prj.Nbin << endl; + stream1 << "bin size (cm): " << wmh.prj.szcm << endl; + stream1 << "number of angles: " << wmh.prj.Nang << endl; + stream1 << "first angle (deg): " << wmh.prj.ang0 << endl; + stream1 << "angle increment between consecutive projections (deg): " << wmh.prj.incr << endl; + + stream1 << "first slice to reconstruct : " << wmh.vol.first_sl << endl; + stream1 << "last slice to reconstruct : " << wmh.vol.last_sl << endl; + stream1 << "number of subsets in which to split the matrix: " << wmh.prj.NOS << endl; + stream1 << "number of angles per subsets: " << wmh.prj.NangOS << endl; + + stream1 << "minimum weight (geometrical contribution): " << wmh.min_w << endl; + stream1 << "psf resolution (discretization interval for Gaussian): " << wmh.psfres << endl; + stream1 << "maximum number of sigmas in psf calculation: " << wmh.maxsigm << endl; + + //........ rotation radius................................ + + if (wmh.fixed_Rrad) + stream1 << "fixed rotation radius :" << wmh.Rrad[0] << " cm" << endl; + else + stream1 << "variable rotation radius from :" << wmh.Rrad_fn << endl; + + //......... psf and collimator parameters ................. + + stream1 << "psf correction: " << wmh.do_psf << endl; + if (wmh.do_psf) { + if (wmh.do_psf_3d) + stream1 << "\tmode: 3d " << endl; + else + stream1 << "\tmode: 2d " << endl; + if (wmh.predef_col) + stream1 << "\tpredefined collimator number: " << wmh.COL.num << endl; + else + stream1 << "\tcollimator parameters from: " << wmh.col_fn << endl; + + if (wmh.COL.do_fb) + stream1 << "collimator geometry: fanbeam " << endl; + else + stream1 << "collimator geometry: parallel" << endl; + } else { + if (wmh.COL.num == 0) + stream1 << "collimator geometry: parallel " << endl; + else + stream1 << "collimator geometry: fanbeam with focal distance : " << wmh.COL.F << endl; + } - - stream1 << "psf correction: " << wmh.do_psf << endl; - if ( wmh.do_psf ){ - if ( wmh.do_psf_3d ) stream1 << "\tmode: 3d " << endl; - else stream1 << "\tmode: 2d " << endl; - if ( wmh.predef_col ) stream1 << "\tpredefined collimator number: " << wmh.COL.num << endl; - else stream1 << "\tcollimator parameters from: " << wmh.col_fn << endl; - - if ( wmh.COL.do_fb ) stream1 << "collimator geometry: fanbeam " << endl; - else stream1 << "collimator geometry: parallel" << endl; - } - else{ - if ( wmh.COL.num == 0 ) stream1 << "collimator geometry: parallel " << endl; - else stream1 << "collimator geometry: fanbeam with focal distance : " << wmh.COL.F << endl; - } - - stream1 << "attenuation correction: " << wmh.do_att << endl; - if ( wmh.do_att ){ - if ( wmh.do_full_att ) stream1 << "\tmode: full " << endl; - else stream1 << "\tmode: simple " << endl; - } - stream1 << "\tattenuation map: " << wmh.att_fn << endl; - - //......... masking .................................... - - stream1 << "masking: " << wmh.do_msk << endl; - if ( wmh.do_msk ){ - if ( wmh.do_msk_cyl ) stream1 << "\tmask type: cyl" << endl; - if ( wmh.do_msk_att ) stream1 << "\tmask type: att" << endl; - if ( wmh.do_msk_file ){ - stream1 << "\tmask type: file" << endl; - stream1 << "\tmask file name: " << wmh.msk_fn << endl; - } - if ( wmh.do_msk_slc ){ - stream1 << "first slice: " << wmh.vol.first_sl << endl; - stream1 << "last slice: " << wmh.vol.last_sl << endl; - } - - } - stream1.close(); + stream1 << "attenuation correction: " << wmh.do_att << endl; + if (wmh.do_att) { + if (wmh.do_full_att) + stream1 << "\tmode: full " << endl; + else + stream1 << "\tmode: simple " << endl; + } + stream1 << "\tattenuation map: " << wmh.att_fn << endl; + + //......... masking .................................... + + stream1 << "masking: " << wmh.do_msk << endl; + if (wmh.do_msk) { + if (wmh.do_msk_cyl) + stream1 << "\tmask type: cyl" << endl; + if (wmh.do_msk_att) + stream1 << "\tmask type: att" << endl; + if (wmh.do_msk_file) { + stream1 << "\tmask type: file" << endl; + stream1 << "\tmask file name: " << wmh.msk_fn << endl; + } + if (wmh.do_msk_slc) { + stream1 << "first slice: " << wmh.vol.first_sl << endl; + stream1 << "last slice: " << wmh.vol.last_sl << endl; + } + } + stream1.close(); } //============================================================================= //=== write_wm_STIR =========================================================== //============================================================================= -void write_wm_STIR() -{ - int seg_num = 0; // segment number for STIR matrix (always zero) - FILE *fid; - - if ( ( fid = fopen( wm.OSfn.c_str() , "wb" )) == NULL ) error_wmtools_SPECT( 31, wm.OSfn ); - - //...loop for matrix elements: projection index .................. - - for( int j = 0 ; j < wm.NbOS ; j++ ){ - - //... to write projection indices and number of elements ....... - - fwrite( &seg_num, sizeof(int), 1, fid); - fwrite( &wm.na [ j ], sizeof(int), 1, fid); - fwrite( &wm.ns [ j ], sizeof(int), 1, fid); - fwrite( &wm.nb [ j ], sizeof(int), 1, fid); - fwrite( &wm.ne [ j ], sizeof(int), 1, fid); - - //... loop for matrix elements: image indexs.................. - - for ( int i = 0 ; i < wm.ne[ j ] ; i++ ){ - - fwrite( &wm.nz[ wm.col[ j ][ i ] ], sizeof(short int), 1, fid); - fwrite( &wm.ny[ wm.col[ j ][ i ] ], sizeof(short int), 1, fid); - fwrite( &wm.nx[ wm.col[ j ][ i ] ], sizeof(short int), 1, fid); - fwrite( &wm.val[ j ][ i ], sizeof(float),1,fid); - } - } - fclose( fid ); +void +write_wm_STIR() { + int seg_num = 0; // segment number for STIR matrix (always zero) + FILE* fid; + + if ((fid = fopen(wm.OSfn.c_str(), "wb")) == NULL) + error_wmtools_SPECT(31, wm.OSfn); + + //...loop for matrix elements: projection index .................. + + for (int j = 0; j < wm.NbOS; j++) { + + //... to write projection indices and number of elements ....... + + fwrite(&seg_num, sizeof(int), 1, fid); + fwrite(&wm.na[j], sizeof(int), 1, fid); + fwrite(&wm.ns[j], sizeof(int), 1, fid); + fwrite(&wm.nb[j], sizeof(int), 1, fid); + fwrite(&wm.ne[j], sizeof(int), 1, fid); + + //... loop for matrix elements: image indexs.................. + + for (int i = 0; i < wm.ne[j]; i++) { + + fwrite(&wm.nz[wm.col[j][i]], sizeof(short int), 1, fid); + fwrite(&wm.ny[wm.col[j][i]], sizeof(short int), 1, fid); + fwrite(&wm.nx[wm.col[j][i]], sizeof(short int), 1, fid); + fwrite(&wm.val[j][i], sizeof(float), 1, fid); + } + } + fclose(fid); } //============================================================================= //=== index_calc ============================================================== //============================================================================= -void index_calc ( int *indexs ) -{ - if ( wmh.prj.NOS == 1 ){ - for ( int i = 0 ; i < wmh.prj.Nang ; i++ ){ - indexs[ i ] = i; // when one single matrix, sequential order - } - } - else{ - int j, *ple, *iOS, *a, *sa, *dif ; - - iOS = new int [ wmh.prj.NOS ]; - ple = new int [ wmh.prj.NOS ]; - a = new int [ wmh.prj.NOS ]; - sa = new int [ wmh.prj.NOS ]; - dif = new int [ wmh.prj.NOS + 1 ]; - - //... to initialize variables .................................. - - for ( int i = 0 ; i < wmh.prj.NOS ; i++ ){ - iOS[ i ] = ple[ i ] = a[ i ] = sa[ i ] = dif[ i ] = 0; - } - dif[ wmh.prj.NOS ] = 0; - ple[ 0 ] = 1; - - //... to fill differences vector ................................. - - int OS2 = wmh.prj.NOS * wmh.prj.NOS ; - - for ( int i = 1 ; i <= wmh.prj.NOS ; i++ ){ - dif[ i ] += 2 * ( i * ( i - wmh.prj.NOS ) ) + OS2 ; - } - - //... first angle for each subset: angle having a maximum distance with all precedent angles ... - - int im = 0; // first index is always set to zero - - for ( int k = 1 ; k < wmh.prj.NOS ; k++ ){ - - for ( int i = 1 ; i < wmh.prj.NOS ; i++ ){ - if( !ple[ i ] ){ - j = i - im; - a[ i ] = dif[ abs( j ) ]; - } - } - - for( int i = 0 ; i < wmh.prj.NOS ; i++ ){ - a[ i ] *= ( 1 - ple[ i ] ); - sa[ i ] *= ( 1 - ple[ i ] ); - sa[ i ] += a[ i ]; - } - - int m = 0; - int n = 0; - - for ( int i = 0 ; i < wmh.prj.NOS ; i++ ){ - m = maxim( m, sa[ i ] ); - } - - for( int i = 1 ; i < wmh.prj.NOS ; i++ ){ - if( !ple[ i ] ){ - m = minim( m, sa[ i ] ); - } - } - - for ( int i = 1 ; i < wmh.prj.NOS ; i++ ){ - if( sa[ i ] == m ){ - n = maxim( n, a[i] ); - } - } - for ( int i = wmh.prj.NOS - 1 ; i > 0 ; i-- ){ - if( sa[ i ] == m ){ - if( a[ i ] <= n ){ - n = a[ i ]; - im = i; - } - } - } - iOS[ k ] = im; - ple[ im ] = 1; - } - - //... to fill the rest of angles of each subset ................ - - for( int i = 0 ; i < wmh.prj.NOS ; i++ ){ - - for( int j = 0 ; j < wmh.prj.NangOS ; j++ ){ - - indexs[ i * wmh.prj.NangOS + j ] = iOS[ i ] + wmh.prj.NOS * j; - } - } - - delete [] iOS; - delete [] a; - delete [] sa; - delete [] dif; - delete [] ple; - } - +void +index_calc(int* indexs) { + if (wmh.prj.NOS == 1) { + for (int i = 0; i < wmh.prj.Nang; i++) { + indexs[i] = i; // when one single matrix, sequential order + } + } else { + int j, *ple, *iOS, *a, *sa, *dif; + + iOS = new int[wmh.prj.NOS]; + ple = new int[wmh.prj.NOS]; + a = new int[wmh.prj.NOS]; + sa = new int[wmh.prj.NOS]; + dif = new int[wmh.prj.NOS + 1]; + + //... to initialize variables .................................. + + for (int i = 0; i < wmh.prj.NOS; i++) { + iOS[i] = ple[i] = a[i] = sa[i] = dif[i] = 0; + } + dif[wmh.prj.NOS] = 0; + ple[0] = 1; + + //... to fill differences vector ................................. + + int OS2 = wmh.prj.NOS * wmh.prj.NOS; + + for (int i = 1; i <= wmh.prj.NOS; i++) { + dif[i] += 2 * (i * (i - wmh.prj.NOS)) + OS2; + } + + //... first angle for each subset: angle having a maximum distance with all precedent angles ... + + int im = 0; // first index is always set to zero + + for (int k = 1; k < wmh.prj.NOS; k++) { + + for (int i = 1; i < wmh.prj.NOS; i++) { + if (!ple[i]) { + j = i - im; + a[i] = dif[abs(j)]; + } + } + + for (int i = 0; i < wmh.prj.NOS; i++) { + a[i] *= (1 - ple[i]); + sa[i] *= (1 - ple[i]); + sa[i] += a[i]; + } + + int m = 0; + int n = 0; + + for (int i = 0; i < wmh.prj.NOS; i++) { + m = maxim(m, sa[i]); + } + + for (int i = 1; i < wmh.prj.NOS; i++) { + if (!ple[i]) { + m = minim(m, sa[i]); + } + } + + for (int i = 1; i < wmh.prj.NOS; i++) { + if (sa[i] == m) { + n = maxim(n, a[i]); + } + } + for (int i = wmh.prj.NOS - 1; i > 0; i--) { + if (sa[i] == m) { + if (a[i] <= n) { + n = a[i]; + im = i; + } + } + } + iOS[k] = im; + ple[im] = 1; + } + + //... to fill the rest of angles of each subset ................ + + for (int i = 0; i < wmh.prj.NOS; i++) { + + for (int j = 0; j < wmh.prj.NangOS; j++) { + + indexs[i * wmh.prj.NangOS + j] = iOS[i] + wmh.prj.NOS * j; + } + } + + delete[] iOS; + delete[] a; + delete[] sa; + delete[] dif; + delete[] ple; + } } //============================================================================= //=== read rotation radius ================================================== //============================================================================= -void read_Rrad() -{ - string line; - ifstream stream1( wmh.Rrad_fn.c_str() ); - if( !stream1 ) error_wmtools_SPECT( 114, wmh.Rrad_fn ); - - int i = 0; - - while ( !stream1.eof() ){ - getline ( stream1, line ); - Rrad[ i ] = atof ( line.c_str() ); - i++; - } - - if ( i != wmh.prj.Nang ) error_wmtools_SPECT( 11, wmh.Rrad_fn ); - stream1.close(); - - return; +void +read_Rrad() { + string line; + ifstream stream1(wmh.Rrad_fn.c_str()); + if (!stream1) + error_wmtools_SPECT(114, wmh.Rrad_fn); + + int i = 0; + + while (!stream1.eof()) { + getline(stream1, line); + Rrad[i] = atof(line.c_str()); + i++; + } + + if (i != wmh.prj.Nang) + error_wmtools_SPECT(11, wmh.Rrad_fn); + stream1.close(); + + return; } //============================================================================= //=== col params ============================================================== //============================================================================= -//void col_params( collim_type *COL ) +// void col_params( collim_type *COL ) //{ -// cout << "Using collimator: " << COL->num << endl; -// +// cout << "Using collimator: " << COL->num << endl; +// // switch(COL->num){ -// +// // case 1: //...................fanbeam: ELSCINT // COL->F = (float)35.5; // COL->L = (float)4.; -// COL->A_h = (float)0.3369; -// COL->A_v = (float)0.3369; +// COL->A_h = (float)0.3369; +// COL->A_v = (float)0.3369; // COL->D = (float)0.8; // COL->w = (float)0.0866; // COL->insgm = (float)0.17; // COL->do_fb = true; // break; -// +// // case 2: //....................fanbeam: ELSCINT D=0 // COL->F = (float)35.5; // COL->L = (float)4.; -// COL->A_h = (float)0.3369; -// COL->A_v = (float)0.3369; +// COL->A_h = (float)0.3369; +// COL->A_v = (float)0.3369; // COL->D = (float)0.; // COL->w = (float)0.0866; // COL->insgm = (float)0.17; // COL->do_fb = true; // break; -// +// // case 3: //....................parallel 3: low resolution // COL->A = (float)0.0275; // COL->B = (float)0.2; // COL->do_fb = false; // break; -// +// // case 4: //....................parallel 4: high resolution // COL->A = (float)0.0172; // COL->B = (float)0.2; // COL->do_fb = false; // break; -// +// // case 5: //....................parallel 5: (ECAM) // COL->A = (float)0.0167; // COL->B = (float)0.1405; // COL->do_fb = false; // break; -// +// // case 6: //....................fan_beam: prism3000 // COL->F = (float)65.0; // COL->L = (float)2.7; -// COL->A_h = (float)0.3575; -// COL->A_v = (float)0.3360; +// COL->A_h = (float)0.3575; +// COL->A_v = (float)0.3360; // COL->D = (float)0.0; // COL->w = (float)0.0866; // COL->insgm = (float)0.17; // COL->do_fb = true; // break; -// +// // case 10: //...................parallel: ECAM with L=40 mm // COL->A = (float)0.0101; // COL->B = (float)0.0998; // COL->do_fb = false; // break; -// -// case 11: //...................fan beam ELSCINT L=2,405 cm +// +// case 11: //...................fan beam ELSCINT L=2,405 cm // COL->F = (float)35.5; // COL->L = (float)2.405; -// COL->A_h = (float)0.3369; -// COL->A_v = (float)0.3369; +// COL->A_h = (float)0.3369; +// COL->A_v = (float)0.3369; // COL->D = (float)0.8; // COL->w = (float)0.0866; // COL->insgm = (float)0.17; // COL->do_fb = true; -// break; -// +// break; +// // case 13: //...................parallel: Hammamatsu collimator // COL->A = (float)0.0205; // COL->B = (float)0.10245; // COL->do_fb = false; // break; -// +// // case 14: //...................parallel. hexagonal holes. apotema=0.57mm, L=24mm, s=0.125mm -// COL->A = (float)0.0178; +// COL->A = (float)0.0178; // COL->B = (float)0.0886; // COL->do_fb = false; // break; -// +// // case 15: //...................parallel. hexagonal holes apotema=0.57mm, L=24mm, s=0.125mm -// COL->A = (float)0.0247; +// COL->A = (float)0.0247; // COL->B = (float)0.0752; // COL->do_fb = false; // break; -// +// // case 16: //...................parallel: Sentinella S102 colimador: experimental parameters -// COL->A = (float)0.0166; +// COL->A = (float)0.0166; // COL->B = (float)0.0924; // COL->do_fb = false; // break; -// +// // case 17: //...................parallel Infinia Hawkeye: experimental parametres -// COL->A = (float)0.0163; +// COL->A = (float)0.0163; // COL->B = (float)0.1466; // COL->do_fb = false; // break; -// +// // default: // char p[3]; // auxiliar variable for itoa // error_wmtools_SPECT( 21, itoa(COL->num,p)); @@ -478,14 +491,14 @@ void read_Rrad() //=== read collimator params ================================================== //============================================================================= -//void read_col_params( collim_type *COL ) +// void read_col_params( collim_type *COL ) //{ // string line; // ifstream stream1( wmh.col_fn.c_str() ); -// if( !stream1 ) error_wmtools_SPECT( 122, wmh.col_fn ); -// +// if( !stream1 ) error_wmtools_SPECT( 122, wmh.col_fn ); +// // getline ( stream1, line ); -// +// // if ( line[ 0 ] == 'f' ) COL->do_fb = true; // else{ // if ( line[ 0 ] == 'p' ) COL->do_fb = false; @@ -493,426 +506,429 @@ void read_Rrad() // } // // if ( COL->do_fb ){ -// +// // getline ( stream1, line ); // COL->F = atof( line.c_str() ); // Focal length (cm) -// +// // getline ( stream1, line ); // COL->L = atof( line.c_str() ); // collimator to detector distance (? cm) -// +// // getline ( stream1, line ); // COL->A_h = atof( line.c_str() ); // linear factor for dependency of sigma on distance (fanbeam horizontal) -// +// // getline ( stream1, line ); // COL->A_v = atof( line.c_str() ); // linear factor for dependency of sigma on distance (fanbeam vertical) -// +// // getline ( stream1, line ); // COL->D = atof( line.c_str() ); // (?) -// +// // getline ( stream1, line ); // COL->w = atof( line.c_str() ); // collimator thickness (? cm) -// +// // if( !stream1.eof() ) error_wmtools_SPECT( 13, wmh.col_fn ); -// +// // getline ( stream1, line ); // COL->insgm = atof( line.c_str() ); // intrinsic sigma (cristal resolution cm?) -// +// // } // else{ // getline ( stream1, line ); -// COL->A = atof( line.c_str() ); // linear factor for dependency of sigma on distance (parallel): sigma=A*dist+B -// +// COL->A = atof( line.c_str() ); // linear factor for dependency of sigma on distance (parallel): +// sigma=A*dist+B +// // if( !stream1.eof() ) error_wmtools_SPECT( 13, wmh.col_fn ); -// +// // getline ( stream1, line ); -// COL->B = atof( line.c_str() ); // Independent factor for dependency of sigma on distance: sigma=A*dist+B -// } -// +// COL->B = atof( line.c_str() ); // Independent factor for dependency of sigma on distance: sigma=A*dist+B +// } +// // stream1.close(); // return; //} - //========================================================================== //=== calc_sigma_v ========================================================= //========================================================================== -float calc_sigma_v( voxel_type vox, collim_type COL) -{ - float sigma; - if ( COL.do_fb ){ - float xc = (float)2. * COL.A_v * COL.w * ( vox.dv2dp + COL.L + COL.D ) / COL.L; - sigma = sqrt( COL.insgm * COL.insgm + xc * xc ); - - } - else sigma = COL.A * vox.dv2dp + COL.B ; - - return( sigma ); -} +float +calc_sigma_v(voxel_type vox, collim_type COL) { + float sigma; + if (COL.do_fb) { + float xc = (float)2. * COL.A_v * COL.w * (vox.dv2dp + COL.L + COL.D) / COL.L; + sigma = sqrt(COL.insgm * COL.insgm + xc * xc); + } else + sigma = COL.A * vox.dv2dp + COL.B; + + return (sigma); +} //============================================================================= //=== fill_ang ================================================================ //============================================================================= -void fill_ang ( angle_type *ang ) -{ - float DX = (float) 0.5 / wmh.psfres ; - float dg2rd = boost::math::constants::pi() / (float)180. ; - - for ( int i = 0; i < wmh.prj.Nang ; i++ ){ - - //... ratios calculation ....................................................... - - float deg = wmh.prj.ang0 + (float)i * wmh.prj.incr ; // angle in degrees - ang[ i ].cos = cos( deg * dg2rd ); // cosinus of the angle - ang[ i ].sin = sin( deg * dg2rd ); // sinus of the angle - - //... first octave (0->45degrees) equivalent angle and its trigonometric ratios ....... - - float angR = fabs( deg ); - int quad = (int) floor( angR / (float)90. ); // quadrant - - angR = fabs( angR - (float)90. * (float)quad ); // reduced angle: equivalent angle in 0->45degrees interval - if ( angR > (float)45. ) angR = fabs( (float)90. - angR ); - - float sinR = (float)sin( angR * dg2rd ); // sinus of the reduced angle - float cosR = (float)cos( angR * dg2rd ); // cosinus of the reduced angle - - //... parametres of the oblique projection of a square voxel size 1 (half a trapezoid) ....... - - if ( !wmh.do_psf ){ - - if ( angR < EPSILON ){ - - ang[ i ].p = (float)1. ; - ang[ i ].N1 = ang[ i ].N2 = (int) floor( DX ); - ang[ i ].m = ang[ i ].n = (float)0.; - } - else{ - ang[ i ].p = (float)1. / cosR; // plateau highness - ang[ i ].m = -wmh.psfres / ( sinR * cosR ); // slope of the trapezoid in DX units (negative) - ang[ i ].n = ( cosR + sinR ) * (float)0.5 / ( cosR * sinR ); // independent term of the slope of the trapezoid (cm) - ang[ i ].N1 = (int) floor( (float) fabs( cosR - sinR ) * DX ); // index of the first vertice (end of plateau) in res units - ang[ i ].N2 = (int) floor( ( cosR + sinR ) * DX ); // index of the second vertice (end of the slope) in res units - } - - ang[ i ].vxprj.lngd2 = ang[ i ].N2; - ang[ i ].vxprj.lng = 2 * ang[ i ].N2; - ang[ i ].vxprj.res = wmh.psfres; - } - //... rotation radius ................................................................ - - ang[ i ].Rrad = Rrad[ i ]; // assignation of (variable) rotation radius - - //... coordinates of the first bin of each projection and increments for consecutive bins .... - - if(wmh.do_att){ - - ang[ i ].incx = wmh.prj.szcm * ang[ i ].cos; - ang[ i ].incy = wmh.prj.szcm * ang[ i ].sin; - - ang[ i ].xbin0 = -ang[ i ].Rrad * ang[ i ].sin - wmh.prj.lngcmd2 * ang[ i ].cos ; - ang[ i ].ybin0 = ang[ i ].Rrad * ang[ i ].cos - wmh.prj.lngcmd2 * ang[ i ].sin ; - } - } +void +fill_ang(angle_type* ang) { + float DX = (float)0.5 / wmh.psfres; + float dg2rd = boost::math::constants::pi() / (float)180.; + + for (int i = 0; i < wmh.prj.Nang; i++) { + + //... ratios calculation ....................................................... + + float deg = wmh.prj.ang0 + (float)i * wmh.prj.incr; // angle in degrees + ang[i].cos = cos(deg * dg2rd); // cosinus of the angle + ang[i].sin = sin(deg * dg2rd); // sinus of the angle + + //... first octave (0->45degrees) equivalent angle and its trigonometric ratios ....... + + float angR = fabs(deg); + int quad = (int)floor(angR / (float)90.); // quadrant + + angR = fabs(angR - (float)90. * (float)quad); // reduced angle: equivalent angle in 0->45degrees interval + if (angR > (float)45.) + angR = fabs((float)90. - angR); + + float sinR = (float)sin(angR * dg2rd); // sinus of the reduced angle + float cosR = (float)cos(angR * dg2rd); // cosinus of the reduced angle + + //... parametres of the oblique projection of a square voxel size 1 (half a trapezoid) ....... + + if (!wmh.do_psf) { + + if (angR < EPSILON) { + + ang[i].p = (float)1.; + ang[i].N1 = ang[i].N2 = (int)floor(DX); + ang[i].m = ang[i].n = (float)0.; + } else { + ang[i].p = (float)1. / cosR; // plateau highness + ang[i].m = -wmh.psfres / (sinR * cosR); // slope of the trapezoid in DX units (negative) + ang[i].n = (cosR + sinR) * (float)0.5 / (cosR * sinR); // independent term of the slope of the trapezoid (cm) + ang[i].N1 = (int)floor((float)fabs(cosR - sinR) * DX); // index of the first vertice (end of plateau) in res units + ang[i].N2 = (int)floor((cosR + sinR) * DX); // index of the second vertice (end of the slope) in res units + } + + ang[i].vxprj.lngd2 = ang[i].N2; + ang[i].vxprj.lng = 2 * ang[i].N2; + ang[i].vxprj.res = wmh.psfres; + } + //... rotation radius ................................................................ + + ang[i].Rrad = Rrad[i]; // assignation of (variable) rotation radius + + //... coordinates of the first bin of each projection and increments for consecutive bins .... + + if (wmh.do_att) { + + ang[i].incx = wmh.prj.szcm * ang[i].cos; + ang[i].incy = wmh.prj.szcm * ang[i].sin; + + ang[i].xbin0 = -ang[i].Rrad * ang[i].sin - wmh.prj.lngcmd2 * ang[i].cos; + ang[i].ybin0 = ang[i].Rrad * ang[i].cos - wmh.prj.lngcmd2 * ang[i].sin; + } + } } //============================================================================= //=== generate msk ============================================================ //============================================================================= -void generate_msk ( bool *msk_3d, bool *msk_2d, float *attmap, volume_type * vol ) -{ - //... initialzation of msk to true ......................... - - for ( int i = 0 ; i < vol->Nvox ; i++ ){ - msk_3d[ i ] = true; - } - - //... initialzation of msk_2d to false ..................... - - for ( int i = 0 ; i < vol->Npix ; i++ ){ - msk_2d[ i ] = false; - } - - //... to create mask from attenuation map .................. - - if ( wmh.do_msk_att ){ - for ( int i = 0 ; i < wmh.vol.Nvox ; i++ ){ - msk_3d[ i ] = ( attmap[ i ] > EPSILON ); - } - } - else { - //... to create a cylindrical mask...................... - - if (wmh.do_msk_cyl){ - - float Rmax2,xi,yi; - - if ( vol->Nrow >= vol->Ncol ) Rmax2 = vol->Nrowd2 * vol->Nrowd2; // Maximum allowed radius (distance from volume centre) - else Rmax2 = vol->Ncold2 * vol->Ncold2; - - int ip = -1; // in-plane index of the voxel - - for ( int i = 0 ; i < vol->Ncol ; i++ ){ - - xi = i - vol->Ncold2 + (float)0.5 ; - xi *= xi; - - for ( int j=0 ; j < vol->Nrow ; j++ ){ - - ip++; - yi = j - vol->Nrowd2 + (float)0.5 ; - yi *= yi; - - if ( ( xi + yi ) > Rmax2 ){ - - for ( int k = 0 ; k < vol->Nsli ; k ++){ - - msk_3d[ ip + k * vol->Npix ] = false; // loop for all the slices - } - } - } - } - } - - else { - //... to read a mask from a (int) file .................... - - if ( wmh.do_msk_file ) read_msk_file( msk_3d ); - } - } +void +generate_msk(bool* msk_3d, bool* msk_2d, float* attmap, volume_type* vol) { + //... initialzation of msk to true ......................... - - //... to apply slice mask (to remove slices from matrix) .............. - - if ( wmh.do_msk_slc ){ - for ( int i = 0 ; i < wmh.vol.first_sl ; i++ ){ - for ( int j = 0 ; j < wmh.vol.Npix ; j++ ) { - msk_3d[ i * wmh.vol.Npix + j ] = false; - } - } - for ( int i = wmh.vol.last_sl ; i < wmh.vol.Nsli ; i++ ){ - for ( int j = 0 ; j < wmh.vol.Npix ; j++ ) { - msk_3d[ i * wmh.vol.Npix + j ] = false; - } - } - } - - //... to collapse mask to 2d_mask ......... - - if ( wmh.do_msk_cyl ){ - for ( int i = 0 ; i < wmh.vol.Npix ; i++ ){ - msk_2d[ i ] = msk_3d[ i + wmh.vol.first_sl * wmh.vol.Npix ]; - } - } - else{ - for ( int i = 0 ; i < wmh.vol.Npix ; i++ ){ - - for ( int k = wmh.vol.first_sl ; k < wmh.vol.last_sl ; k++ ){ - - if ( msk_3d[ k * wmh.vol.Npix + i ] ){ - msk_2d[ i ] = true; - break; - } - } - } - } + for (int i = 0; i < vol->Nvox; i++) { + msk_3d[i] = true; + } + + //... initialzation of msk_2d to false ..................... + + for (int i = 0; i < vol->Npix; i++) { + msk_2d[i] = false; + } + + //... to create mask from attenuation map .................. + + if (wmh.do_msk_att) { + for (int i = 0; i < wmh.vol.Nvox; i++) { + msk_3d[i] = (attmap[i] > EPSILON); + } + } else { + //... to create a cylindrical mask...................... + + if (wmh.do_msk_cyl) { + + float Rmax2, xi, yi; + + if (vol->Nrow >= vol->Ncol) + Rmax2 = vol->Nrowd2 * vol->Nrowd2; // Maximum allowed radius (distance from volume centre) + else + Rmax2 = vol->Ncold2 * vol->Ncold2; + + int ip = -1; // in-plane index of the voxel + + for (int i = 0; i < vol->Ncol; i++) { + + xi = i - vol->Ncold2 + (float)0.5; + xi *= xi; + + for (int j = 0; j < vol->Nrow; j++) { + + ip++; + yi = j - vol->Nrowd2 + (float)0.5; + yi *= yi; + + if ((xi + yi) > Rmax2) { + + for (int k = 0; k < vol->Nsli; k++) { + + msk_3d[ip + k * vol->Npix] = false; // loop for all the slices + } + } + } + } + } + + else { + //... to read a mask from a (int) file .................... + + if (wmh.do_msk_file) + read_msk_file(msk_3d); + } + } + + //... to apply slice mask (to remove slices from matrix) .............. + + if (wmh.do_msk_slc) { + for (int i = 0; i < wmh.vol.first_sl; i++) { + for (int j = 0; j < wmh.vol.Npix; j++) { + msk_3d[i * wmh.vol.Npix + j] = false; + } + } + for (int i = wmh.vol.last_sl; i < wmh.vol.Nsli; i++) { + for (int j = 0; j < wmh.vol.Npix; j++) { + msk_3d[i * wmh.vol.Npix + j] = false; + } + } + } + + //... to collapse mask to 2d_mask ......... + + if (wmh.do_msk_cyl) { + for (int i = 0; i < wmh.vol.Npix; i++) { + msk_2d[i] = msk_3d[i + wmh.vol.first_sl * wmh.vol.Npix]; + } + } else { + for (int i = 0; i < wmh.vol.Npix; i++) { + + for (int k = wmh.vol.first_sl; k < wmh.vol.last_sl; k++) { + + if (msk_3d[k * wmh.vol.Npix + i]) { + msk_2d[i] = true; + break; + } + } + } + } } //============================================================================= //=== read_mask file ========================================================== //============================================================================= -void read_msk_file( bool *msk ) -{ - FILE *fid; - int *aux; - - aux = new int [ wmh.vol.Nvox ]; - - if ( (fid = fopen( wmh.msk_fn.c_str() , "rb")) == NULL) error_wmtools_SPECT( 126, wmh.msk_fn); - fread( aux, sizeof(int), wmh.vol.Nvox, fid); - fclose(fid); - - for (int i = 0 ; i < wmh.vol.Nvox ; i ++ ){ - msk[i] = ( aux[i] != 0 ); - } - - delete [] aux; +void +read_msk_file(bool* msk) { + FILE* fid; + int* aux; + + aux = new int[wmh.vol.Nvox]; + + if ((fid = fopen(wmh.msk_fn.c_str(), "rb")) == NULL) + error_wmtools_SPECT(126, wmh.msk_fn); + fread(aux, sizeof(int), wmh.vol.Nvox, fid); + fclose(fid); + + for (int i = 0; i < wmh.vol.Nvox; i++) { + msk[i] = (aux[i] != 0); + } + + delete[] aux; } //============================================================================= //=== read_att_map ============================================================ //============================================================================= -void read_att_map( float *attmap ) -{ - FILE *fid; - if ( ( fid = fopen( wmh.att_fn.c_str() , "rb") ) == NULL ) error_wmtools_SPECT ( 124, wmh.att_fn ); - fread( attmap, sizeof(float), wmh.vol.Nvox, fid); - - bool exist_nan = false; - - for (int i = 0 ; i < wmh.vol.Nvox ; i++ ){ - if ((boost::math::isnan)(attmap [ i ])){ - attmap [ i ] = 0; - exist_nan = true; - } - } - - if ( exist_nan ) cout << "WARNING: att map contains NaN values. Converted to zero" << endl; - - fclose(fid); +void +read_att_map(float* attmap) { + FILE* fid; + if ((fid = fopen(wmh.att_fn.c_str(), "rb")) == NULL) + error_wmtools_SPECT(124, wmh.att_fn); + fread(attmap, sizeof(float), wmh.vol.Nvox, fid); + + bool exist_nan = false; + + for (int i = 0; i < wmh.vol.Nvox; i++) { + if ((boost::math::isnan)(attmap[i])) { + attmap[i] = 0; + exist_nan = true; + } + } + + if (exist_nan) + cout << "WARNING: att map contains NaN values. Converted to zero" << endl; + + fclose(fid); } //========================================================================== //=== max_psf_szb ========================================================== //========================================================================== -int max_psf_szb( angle_type *ang ) -{ - int maxszb; - float Rrad_max = ang[0].Rrad; - - for( int i = 1; i < wmh.prj.Nang ; i++ ){ - if ( ang[ i ].Rrad > Rrad_max ) Rrad_max = ang[ i ].Rrad; // maximum rotation radius - } - - if ( !wmh.do_psf ){ // NO-PSF - - if ( !wmh.COL.do_fb ){ // parallel - maxszb = (int)( (float) sqrt( (float)2. ) * wmh.vol.szcm / wmh.prj.szcm ) + 3; - } - - else{ // fanbeam - float dpmax = wmh.vol.szcm * maxim( wmh.vol.Ncold2, wmh.vol.Nrowd2) + Rrad_max; - - float lon = wmh.COL.F - dpmax; - if ( lon < EPSILON ) error_wmtools_SPECT( 46, ""); - - //... maximum lenght of psf in bins ........................ - - float f = (int)( (float) sqrt( (float)2. ) * (wmh.vol.szcm / wmh.prj.szcm) * ( wmh.COL.F / lon ) ) + 3; - maxszb = minim ( f , wmh.prj.Nbin ); - } - } - else{ // PSF - voxel_type vox; - - if ( wmh.COL.do_fb ){ - vox.costhe = (float)1. / sqrt( wmh.prj.lngcmd2 * wmh.prj.lngcmd2 / ( wmh.COL.F * wmh.COL.F ) + (float)1.); - } - //... maximum length of psf in bins ........................ - - vox.dv2dp = Rrad_max + wmh.vol.szcm * maxim( wmh.vol.Ncold2, wmh.vol.Nrowd2 ) * (float)1.5; - float sig_h_max_cm = calc_sigma_h( vox, wmh.COL ); - maxszb = (int)floor( wmh.maxsigm * (float)2. * sig_h_max_cm / wmh.prj.szcm ) + 3; - - if ( wmh.do_psf_3d ){ - float sig_v_max_cm = calc_sigma_v( vox, wmh.COL ); - int maxszb_v = (int)floor( wmh.maxsigm * (float)2. * sig_v_max_cm / wmh.prj.thcm ) + 3; - maxszb = maxim( maxszb , maxszb_v ); - } - } +int +max_psf_szb(angle_type* ang) { + int maxszb; + float Rrad_max = ang[0].Rrad; - return( maxszb ); + for (int i = 1; i < wmh.prj.Nang; i++) { + if (ang[i].Rrad > Rrad_max) + Rrad_max = ang[i].Rrad; // maximum rotation radius + } + + if (!wmh.do_psf) { // NO-PSF + + if (!wmh.COL.do_fb) { // parallel + maxszb = (int)((float)sqrt((float)2.) * wmh.vol.szcm / wmh.prj.szcm) + 3; + } + + else { // fanbeam + float dpmax = wmh.vol.szcm * maxim(wmh.vol.Ncold2, wmh.vol.Nrowd2) + Rrad_max; + + float lon = wmh.COL.F - dpmax; + if (lon < EPSILON) + error_wmtools_SPECT(46, ""); + + //... maximum lenght of psf in bins ........................ + + float f = (int)((float)sqrt((float)2.) * (wmh.vol.szcm / wmh.prj.szcm) * (wmh.COL.F / lon)) + 3; + maxszb = minim(f, wmh.prj.Nbin); + } + } else { // PSF + voxel_type vox; + + if (wmh.COL.do_fb) { + vox.costhe = (float)1. / sqrt(wmh.prj.lngcmd2 * wmh.prj.lngcmd2 / (wmh.COL.F * wmh.COL.F) + (float)1.); + } + //... maximum length of psf in bins ........................ + + vox.dv2dp = Rrad_max + wmh.vol.szcm * maxim(wmh.vol.Ncold2, wmh.vol.Nrowd2) * (float)1.5; + float sig_h_max_cm = calc_sigma_h(vox, wmh.COL); + maxszb = (int)floor(wmh.maxsigm * (float)2. * sig_h_max_cm / wmh.prj.szcm) + 3; + + if (wmh.do_psf_3d) { + float sig_v_max_cm = calc_sigma_v(vox, wmh.COL); + int maxszb_v = (int)floor(wmh.maxsigm * (float)2. * sig_v_max_cm / wmh.prj.thcm) + 3; + maxszb = maxim(maxszb, maxszb_v); + } + } + + return (maxszb); } //========================================================================== //=== calc_sigma_h ========================================================= //========================================================================== -float calc_sigma_h( voxel_type vox, collim_type COL ) -{ - float sigma; - - if ( COL.do_fb ){ - float denom = sqrt( COL.L * COL.L * (COL.F - vox.dv2dp) * (COL.F - vox.dv2dp) - COL.w * COL.w * (COL.L + (float)2. * vox.dv2dp) * (COL.L + (float)2. * vox.dv2dp)); - float xc = COL.A_h * (vox.dv2dp + COL.L + COL.D) * COL.w * ( (float)2. * COL.F + COL.L) / (vox.costhe * denom); - sigma = sqrt( COL.insgm * COL.insgm + xc * xc ); - } - else sigma = COL.A * vox.dv2dp + COL.B ; - - return( sigma ); +float +calc_sigma_h(voxel_type vox, collim_type COL) { + float sigma; + + if (COL.do_fb) { + float denom = sqrt(COL.L * COL.L * (COL.F - vox.dv2dp) * (COL.F - vox.dv2dp) - + COL.w * COL.w * (COL.L + (float)2. * vox.dv2dp) * (COL.L + (float)2. * vox.dv2dp)); + float xc = COL.A_h * (vox.dv2dp + COL.L + COL.D) * COL.w * ((float)2. * COL.F + COL.L) / (vox.costhe * denom); + sigma = sqrt(COL.insgm * COL.insgm + xc * xc); + } else + sigma = COL.A * vox.dv2dp + COL.B; + + return (sigma); } //============================================================================= //=== itoa ==================================================================== //============================================================================= -char *itoa(int n,char *s) -{ - int i,sign; - char c; - - if((sign=n)<0) { - n=-n; - } - - i=0; - do{ - s[i++]=n%10+'0'; - } - while((n/=10)>0); - - if(sign<0) { - s[i++]='-'; - } - - s[i]=EOS; - - for(int low=0,hi=i-1;low 0); + + if (sign < 0) { + s[i++] = '-'; + } + + s[i] = EOS; + + for (int low = 0, hi = i - 1; low < hi; low++, hi--) { + c = s[low]; + s[low] = s[hi]; + s[hi] = c; + } + + return (s); } //============================================================================= //=== free_wm ================================================================= //============================================================================= -void free_wm( wm_type *f ) -{ - delete [] f->ar; - delete [] f->ja; - delete [] f->ia; +void +free_wm(wm_type* f) { + delete[] f->ar; + delete[] f->ja; + delete[] f->ia; } //============================================================================= //=== free_wm_da ============================================================== //============================================================================= -void free_wm_da( wm_da_type *f ) -{ - for(int i=0; i< f->NbOS; i++){ - delete [] f->val[i]; - delete [] f->col[i]; - } - delete [] f->val; - delete [] f->col; - delete [] f->ne; - - if ( f->do_save_STIR ){ - delete [] f->nb; - delete [] f->ns; - delete [] f->na; - delete [] f->nx; - delete [] f->ny; - delete [] f->nz; - } +void +free_wm_da(wm_da_type* f) { + for (int i = 0; i < f->NbOS; i++) { + delete[] f->val[i]; + delete[] f->col[i]; + } + delete[] f->val; + delete[] f->col; + delete[] f->ne; + + if (f->do_save_STIR) { + delete[] f->nb; + delete[] f->ns; + delete[] f->na; + delete[] f->nx; + delete[] f->ny; + delete[] f->nz; + } } //============================================================================= //== error_wmtools_SPECT ====================================================== //============================================================================= -void error_wmtools_SPECT( int nerr, string txt ) -{ +void +error_wmtools_SPECT(int nerr, string txt) { #if 0 switch(nerr){ case 11: printf("\n\nError wm_SPECT: number of variable rotation radius in file: %s different from number of angles\n",txt.c_str());break; @@ -937,28 +953,54 @@ void error_wmtools_SPECT( int nerr, string txt ) exit(0); #else using stir::error; - switch(nerr){ - case 11: printf("\n\nError wm_SPECT: number of variable rotation radius in file: %s different from number of angles\n",txt.c_str());break; - case 12: error("\n\nError wm_SPECT: first parameter in collimator file should be 'p' or 'f' to indicate parallel or fanbeam collimator\n");break; - case 13: printf("\n\nError wm_SPECT: not enough parameters in collimator file: %s \n",txt.c_str());break; - case 21: printf("\n\nError wmtools_SPECT: undefined collimator. Collimator %s not found\n",txt.c_str()); break; - case 30: printf("\n\nError wmtools_SPECT: can not open %s for reading\n",txt.c_str()); break; - case 31: printf("\n\nError wmtools_SPECT: can not open %s for writing\n",txt.c_str()); break; - case 46: error( "\n\nError weight3d: there are voxels near or further than de FOCAL lenght\n"); break; - case 50: printf("\n\nError wmtools_SPECT: No header stored in %s \n",txt.c_str()); break; - + switch (nerr) { + case 11: + printf("\n\nError wm_SPECT: number of variable rotation radius in file: %s different from number of angles\n", txt.c_str()); + break; + case 12: + error("\n\nError wm_SPECT: first parameter in collimator file should be 'p' or 'f' to indicate parallel or fanbeam " + "collimator\n"); + break; + case 13: + printf("\n\nError wm_SPECT: not enough parameters in collimator file: %s \n", txt.c_str()); + break; + case 21: + printf("\n\nError wmtools_SPECT: undefined collimator. Collimator %s not found\n", txt.c_str()); + break; + case 30: + printf("\n\nError wmtools_SPECT: can not open %s for reading\n", txt.c_str()); + break; + case 31: + printf("\n\nError wmtools_SPECT: can not open %s for writing\n", txt.c_str()); + break; + case 46: + error("\n\nError weight3d: there are voxels near or further than de FOCAL lenght\n"); + break; + case 50: + printf("\n\nError wmtools_SPECT: No header stored in %s \n", txt.c_str()); + break; + //... error: value of argv[].......................... - - case 114: printf("\n\nError wm_SPECT: file with variable rotation radius: %s not found\n",txt.c_str());break; - case 122: printf("\n\nError wm_SPECT: file with variable collimator parameters: %s not found\n",txt.c_str());break; - case 124: printf("\n\nError wm_SPECT: can not open attenuation map-> argv[24]: %s for reading\n",txt.c_str()); break; - case 126: printf("\n\nError wm_SPECT: can not open file mask-> argv[26]: %s for reading\n",txt.c_str()); break; - - default: error("\n\nError wmtools_SPECT: unknown error number on error_wmtools_SPECT()"); + + case 114: + printf("\n\nError wm_SPECT: file with variable rotation radius: %s not found\n", txt.c_str()); + break; + case 122: + printf("\n\nError wm_SPECT: file with variable collimator parameters: %s not found\n", txt.c_str()); + break; + case 124: + printf("\n\nError wm_SPECT: can not open attenuation map-> argv[24]: %s for reading\n", txt.c_str()); + break; + case 126: + printf("\n\nError wm_SPECT: can not open file mask-> argv[26]: %s for reading\n", txt.c_str()); + break; + + default: + error("\n\nError wmtools_SPECT: unknown error number on error_wmtools_SPECT()"); } - + #endif -} +} #if 0 void error_wm_SPECT( int nerr, string txt) diff --git a/src/recon_buildblock/SPECTUB_Weight3d.cxx b/src/recon_buildblock/SPECTUB_Weight3d.cxx index 5dcd6a70e0..ebd8741399 100644 --- a/src/recon_buildblock/SPECTUB_Weight3d.cxx +++ b/src/recon_buildblock/SPECTUB_Weight3d.cxx @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Biomedical Image Group (GIB), Universitat de Barcelona, Barcelona, Spain. + Copyright (c) 2013, Biomedical Image Group (GIB), Universitat de Barcelona, Barcelona, Spain. Copyright (c) 2013, University College London This file is part of STIR. @@ -19,8 +19,7 @@ \author Carles Falcon */ - -//user defined libraries +// user defined libraries #include "stir/recon_buildblock/SPECTUB_Tools.h" #include "stir/recon_buildblock/SPECTUB_Weight3d.h" @@ -29,7 +28,7 @@ #include #include "stir/spatial_transformation/InvertAxis.h" -//system libraries +// system libraries #include #include #include @@ -41,923 +40,935 @@ namespace SPECTUB { #define EPSILON 1e-12 #define EOS '\0' -#define maxim(a,b) ((a)>=(b)?(a):(b)) -#define minim(a,b) ((a)<=(b)?(a):(b)) -#define abs(a) ((a)>=0?(a):(-a)) -#define SIGN(a) (a<-EPSILON?-1:(a>EPSILON?1:0)) - -#define REF_DIST 5. //reference distance for fanbeam PSF +#define maxim(a, b) ((a) >= (b) ? (a) : (b)) +#define minim(a, b) ((a) <= (b) ? (a) : (b)) +#define abs(a) ((a) >= 0 ? (a) : (-a)) +#define SIGN(a) (a < -EPSILON ? -1 : (a > EPSILON ? 1 : 0)) + +#define REF_DIST 5. // reference distance for fanbeam PSF using namespace std; //========================================================================== //=== wm_calculation ======================================================= //========================================================================== -void wm_calculation( const int kOS, - const angle_type *const ang, - voxel_type vox, - bin_type bin, - const volume_type& vol, - const proj_type& prj, - const float *attmap, - const bool *msk_3d, - const bool *msk_2d, - const int maxszb, - const discrf_type *const gaussdens, - const int *const NITEMS) -{ - - float weight; - float coeff_att = (float) 1.; - int jp; - float eff; - - //... variables for geometric component .............................................. - - psf1d_type psf1d_h, psf1d_v; - - psf1d_h.maxszb = maxszb; - psf1d_h.val = new float [ maxszb ]; - psf1d_h.ind = new int [ maxszb ]; - - if ( wmh.do_psf_3d ){ - psf1d_v.maxszb = maxszb; - psf1d_v.val = new float [ maxszb ]; - psf1d_v.ind = new int [ maxszb ]; +void +wm_calculation(const int kOS, const angle_type* const ang, voxel_type vox, bin_type bin, const volume_type& vol, + const proj_type& prj, const float* attmap, const bool* msk_3d, const bool* msk_2d, const int maxszb, + const discrf_type* const gaussdens, const int* const NITEMS) { + + float weight; + float coeff_att = (float)1.; + int jp; + float eff; + + //... variables for geometric component .............................................. + + psf1d_type psf1d_h, psf1d_v; + + psf1d_h.maxszb = maxszb; + psf1d_h.val = new float[maxszb]; + psf1d_h.ind = new int[maxszb]; + + if (wmh.do_psf_3d) { + psf1d_v.maxszb = maxszb; + psf1d_v.val = new float[maxszb]; + psf1d_v.ind = new int[maxszb]; + } + + psf2da_type psf; + + psf.maxszb_h = maxszb; + if (wmh.do_psf_3d) + psf.maxszb_v = maxszb; + else + psf.maxszb_v = 1; + psf.maxszb_t = psf.maxszb_h * psf.maxszb_v; + + psf.val = new float[psf.maxszb_t]; // allocation for PSF values + psf.ib = new int[psf.maxszb_t]; // allocation for PSF indices + psf.jb = new int[psf.maxszb_t]; // allocation for PSF indices + + //... variables for attenuation component ............................................. + + attpth_type* attpth = 0; // initialise to avoid compiler warning + int sizeattpth = 1; // initialise to avoid compiler warning + + if (wmh.do_att || wmh.do_msk_att) { + + if (!wmh.do_full_att) + sizeattpth = 1; + else + sizeattpth = psf.maxszb_t; + + attpth = new attpth_type[sizeattpth]; + attpth[0].maxlng = vol.Ncol + vol.Nrow + vol.Nsli; // maximum length of an attenuation path + + for (int i = 0; i < sizeattpth; i++) { + + attpth[i].dl = new float[attpth[0].maxlng]; + attpth[i].iv = new int[attpth[0].maxlng]; + attpth[i].maxlng = attpth[0].maxlng; } - - psf2da_type psf; - - psf.maxszb_h = maxszb; - if ( wmh.do_psf_3d ) psf.maxszb_v = maxszb; - else psf.maxszb_v = 1; - psf.maxszb_t = psf.maxszb_h * psf.maxszb_v; - - psf.val = new float [ psf.maxszb_t ]; // allocation for PSF values - psf.ib = new int [ psf.maxszb_t ]; // allocation for PSF indices - psf.jb = new int [ psf.maxszb_t ]; // allocation for PSF indices - - //... variables for attenuation component ............................................. - - attpth_type *attpth = 0; // initialise to avoid compiler warning - int sizeattpth = 1; // initialise to avoid compiler warning - - if ( wmh.do_att || wmh.do_msk_att ){ + } - if ( !wmh.do_full_att ) sizeattpth = 1 ; - else sizeattpth = psf.maxszb_t ; - - attpth = new attpth_type [ sizeattpth ] ; - attpth[ 0 ].maxlng = vol.Ncol + vol.Nrow + vol.Nsli ; // maximum length of an attenuation path - - for (int i = 0 ; i < sizeattpth ; i++ ){ - - attpth[ i ].dl = new float [ attpth[ 0 ].maxlng ]; - attpth[ i ].iv = new int [ attpth[ 0 ].maxlng ]; - attpth[ i ].maxlng = attpth[ 0 ].maxlng; - } - } - - //... to fill projection indices for STIR format ............................. - - if ( wm.do_save_STIR ){ - - jp = -1; // projection index (row index of the weight matrix ) - int j1; - - for ( int j = 0 ; j < prj.NangOS ; j++ ){ - - j1 = wmh.index[ j ]; - - for ( int k = 0 ; k < prj.Nsli ; k++ ){ - - for ( int i = 0 ; i < prj.Nbin ; i++){ - - jp++; - wm.na[ jp ] = j1; - wm.nb[ jp ] = i - (int)prj.Nbind2; - wm.ns[ jp ] = k; - } - } - } - } - - //=== LOOP1: IMAGE ROWS ======================================================================= - - for ( vox.irow = 0 ; vox.irow < vol.Nrow ; vox.irow++ ){ - - //cout << "weights: " << 100.*(vox.irow+1)/vol.Nrow << "%" << endl; - - vox.y = vol.y0 + vox.irow * vol.szcm ; // y coordinate of the voxel (index 0->Nrow-1: irow) - - //=== LOOP2: IMAGE COLUMNS ================================================================= - - for ( vox.icol = 0 ; vox.icol < vol.Ncol ; vox.icol++ ){ - - vox.x = vol.x0 + vox.icol * vol.szcm ; // x coordinate of the voxel (index 0->Ncol-1: icol) - vox.ip = vox.irow * vol.Ncol + vox.icol ; // in-plane index of the voxel considering the slice as an array - - //... to apply mask ......................................... - - if ( wmh.do_msk){ - - if ( !msk_2d[ vox.ip ] ) continue; // to skip voxel if it is outside the 2d_mask - } - - //=== LOOP3: ANGLES INTO SUBSETS ======================================================== - - for( int k = 0 ; k < prj.NangOS ; k++ ){ - - int ka = wmh.index[ k ]; // angle index of the current projection (considering the whole set of projections) - - //... perpendicular distance form voxel to detection plane ........................... - - vox.dv2dp = vox.x * ang[ ka ].sin - vox.y * ang[ ka ].cos + ang[ ka ].Rrad ; - - if ( vox.dv2dp <= 0. ) continue; // skipping voxel if it is beyond the detection plane (corner voxels) - - //... x coordinate in the rotated frame .............................................. - - vox.x1 = vox.x * ang[ ka ].cos + vox.y * ang[ ka ].sin ; - - //... to project voxels onto the detection plane and to calculate other distances ..... - - voxel_projection( &vox , &eff , prj.lngcmd2 ); - - //... setting PSF to zero ......................................... - - // for ( int i = 0 ; i < nel ; i++ ){ - // - // psf.val[ i ] = (float)0.; - // psf.ib[ i ] = psf.jb[ i ] = 0; - // } - - //... correction for PSF .............................. - - if ( !wmh.do_psf ) fill_psf_no ( &psf, &psf1d_h, vox, &ang[ ka ], bin.szdx ); - - else{ - - if ( wmh.do_psf_3d ) fill_psf_3d ( &psf, &psf1d_h, &psf1d_v, vox, gaussdens, bin.szdx, bin.thdx, bin.thcmd2 ); - - else fill_psf_2d ( &psf, &psf1d_h, vox, gaussdens, bin.szdx ); - } - - //... correction for attenuation ................................................. - - if ( wmh.do_att ){ - - vox.z = (float)0. ; - - if ( !wmh.do_full_att ){ // simple correction for attenuation - - bin.x = ang[ ka ].xbin0 + vox.xd0 * ang[ ka ].cos; // x coord of the projection of the center of the voxel in the detection line - bin.y = ang[ ka ].ybin0 + vox.xd0 * ang[ ka ].sin; - bin.z = (float)0. ; - - calc_att_path( bin, vox, vol, &attpth[ 0 ]); - } - else{ // full correction for attenuation - - for ( int i = 0 ; i < psf.Nib ; i++ ){ - - bin.x = ang[ ka ].xbin0 + ang[ ka ].incx * ( (float)psf.ib[ i ] + (float)0.5 ); - bin.y = ang[ ka ].ybin0 + ang[ ka ].incy * ( (float)psf.ib[ i ] + (float)0.5 ); - bin.z = (float)psf.jb[ i ] * vox.thcm ; - - calc_att_path( bin, vox, vol, &attpth[ i ]); - } - } - } - - //=== LOOP4: IMAGE SLICES ================================================================ - - for ( vox.islc = vol.first_sl ; vox.islc < vol.last_sl ; vox.islc++ ){ - - vox.iv = vox.ip + vox.islc * vol.Npix ; // volume index of the voxel (volume as an array) - - if ( wmh.do_msk ){ - if ( !msk_3d[ vox.iv ] ) continue; - } - - if ( wmh.do_att && !wmh.do_full_att ) coeff_att = calc_att( &attpth[ 0 ], attmap , vox.islc ); - - //... weight matrix values calculation ....................................... - - for ( int ie = 0 ; ie < psf.Nib ; ie++ ){ - - if ( psf.ib[ ie ] < 0 ) continue; - if ( psf.ib[ ie ] >= prj.Nbin ) continue; - - int ks = ( vox.islc + psf.jb[ ie ] ); - - if ( ks < 0 ) continue; - if ( ks >= vol.Nsli ) continue; - - jp = k * prj.Nbp + ks * prj.Nbin + psf.ib[ ie ]; - - if ( wmh.do_full_att ) coeff_att = calc_att( &attpth[ ie ], attmap, vox.islc ); - - weight = psf.val[ ie ] * eff * coeff_att ; - - //... fill image STIR indices ........................... - - if ( wm.do_save_STIR ){ - stir::InvertAxis invert; - wm.nx[ vox.iv ] = (short int)invert.invert_axis_index(( vox.icol - (int) floor( vol.Ncold2 ) ),vol.Ncold2*2, "x"); // centered index for STIR format - wm.ny[ vox.iv ] = (short int)( vox.irow - (int) floor( vol.Nrowd2 ) ); // centered index for STIR format - wm.nz[ vox.iv ] = (short int) vox.islc ; // non-centered index for STIR format - } - - //... fill wm values ..................... - - wm.col[ jp ][ wm.ne[ jp ] ] = vox.iv; - wm.val[ jp ][ wm.ne[ jp ] ] = weight; - wm.ne[ jp ]++; - - if ( wm.ne[ jp ] >= NITEMS[ jp ] ) error_weight3d(45, "" ); - } - } // end of LOOP4: image slices - } // end of LOOP3: projection angle into subset - } // end of LOOP2: image rows - } // end of LOOP1: image cols - - //... detele allocated memory .............. - - delete [] psf1d_h.val ; - delete [] psf1d_h.ind ; - - if ( wmh.do_psf_3d ){ - delete [] psf1d_v.val ; - delete [] psf1d_v.ind ; - } + //... to fill projection indices for STIR format ............................. - delete [] psf.val; - delete [] psf.ib; - delete [] psf.jb; - - if ( wmh.do_att ){ - for ( int i = 0 ; i < sizeattpth ; i++ ){ - delete [] attpth[ i ].dl; - delete [] attpth[ i ].iv; - } - delete [] attpth; - } -} + if (wm.do_save_STIR) { + + jp = -1; // projection index (row index of the weight matrix ) + int j1; + + for (int j = 0; j < prj.NangOS; j++) { + + j1 = wmh.index[j]; + + for (int k = 0; k < prj.Nsli; k++) { + + for (int i = 0; i < prj.Nbin; i++) { + + jp++; + wm.na[jp] = j1; + wm.nb[jp] = i - (int)prj.Nbind2; + wm.ns[jp] = k; + } + } + } + } + + //=== LOOP1: IMAGE ROWS ======================================================================= + + for (vox.irow = 0; vox.irow < vol.Nrow; vox.irow++) { + + // cout << "weights: " << 100.*(vox.irow+1)/vol.Nrow << "%" << endl; + + vox.y = vol.y0 + vox.irow * vol.szcm; // y coordinate of the voxel (index 0->Nrow-1: irow) + + //=== LOOP2: IMAGE COLUMNS ================================================================= + + for (vox.icol = 0; vox.icol < vol.Ncol; vox.icol++) { + + vox.x = vol.x0 + vox.icol * vol.szcm; // x coordinate of the voxel (index 0->Ncol-1: icol) + vox.ip = vox.irow * vol.Ncol + vox.icol; // in-plane index of the voxel considering the slice as an array + + //... to apply mask ......................................... + + if (wmh.do_msk) { + + if (!msk_2d[vox.ip]) + continue; // to skip voxel if it is outside the 2d_mask + } + + //=== LOOP3: ANGLES INTO SUBSETS ======================================================== + + for (int k = 0; k < prj.NangOS; k++) { + + int ka = wmh.index[k]; // angle index of the current projection (considering the whole set of projections) + + //... perpendicular distance form voxel to detection plane ........................... + + vox.dv2dp = vox.x * ang[ka].sin - vox.y * ang[ka].cos + ang[ka].Rrad; + + if (vox.dv2dp <= 0.) + continue; // skipping voxel if it is beyond the detection plane (corner voxels) + + //... x coordinate in the rotated frame .............................................. + + vox.x1 = vox.x * ang[ka].cos + vox.y * ang[ka].sin; + + //... to project voxels onto the detection plane and to calculate other distances ..... + + voxel_projection(&vox, &eff, prj.lngcmd2); + + //... setting PSF to zero ......................................... + + // for ( int i = 0 ; i < nel ; i++ ){ + // + // psf.val[ i ] = (float)0.; + // psf.ib[ i ] = psf.jb[ i ] = 0; + // } + + //... correction for PSF .............................. + + if (!wmh.do_psf) + fill_psf_no(&psf, &psf1d_h, vox, &ang[ka], bin.szdx); + + else { + + if (wmh.do_psf_3d) + fill_psf_3d(&psf, &psf1d_h, &psf1d_v, vox, gaussdens, bin.szdx, bin.thdx, bin.thcmd2); + + else + fill_psf_2d(&psf, &psf1d_h, vox, gaussdens, bin.szdx); + } + + //... correction for attenuation ................................................. + + if (wmh.do_att) { + + vox.z = (float)0.; + + if (!wmh.do_full_att) { // simple correction for attenuation + + bin.x = ang[ka].xbin0 + + vox.xd0 * ang[ka].cos; // x coord of the projection of the center of the voxel in the detection line + bin.y = ang[ka].ybin0 + vox.xd0 * ang[ka].sin; + bin.z = (float)0.; + + calc_att_path(bin, vox, vol, &attpth[0]); + } else { // full correction for attenuation + + for (int i = 0; i < psf.Nib; i++) { + + bin.x = ang[ka].xbin0 + ang[ka].incx * ((float)psf.ib[i] + (float)0.5); + bin.y = ang[ka].ybin0 + ang[ka].incy * ((float)psf.ib[i] + (float)0.5); + bin.z = (float)psf.jb[i] * vox.thcm; + + calc_att_path(bin, vox, vol, &attpth[i]); + } + } + } + + //=== LOOP4: IMAGE SLICES ================================================================ + + for (vox.islc = vol.first_sl; vox.islc < vol.last_sl; vox.islc++) { + + vox.iv = vox.ip + vox.islc * vol.Npix; // volume index of the voxel (volume as an array) + + if (wmh.do_msk) { + if (!msk_3d[vox.iv]) + continue; + } + + if (wmh.do_att && !wmh.do_full_att) + coeff_att = calc_att(&attpth[0], attmap, vox.islc); + + //... weight matrix values calculation ....................................... + + for (int ie = 0; ie < psf.Nib; ie++) { + + if (psf.ib[ie] < 0) + continue; + if (psf.ib[ie] >= prj.Nbin) + continue; + + int ks = (vox.islc + psf.jb[ie]); + + if (ks < 0) + continue; + if (ks >= vol.Nsli) + continue; + + jp = k * prj.Nbp + ks * prj.Nbin + psf.ib[ie]; + + if (wmh.do_full_att) + coeff_att = calc_att(&attpth[ie], attmap, vox.islc); + + weight = psf.val[ie] * eff * coeff_att; + + //... fill image STIR indices ........................... + + if (wm.do_save_STIR) { + stir::InvertAxis invert; + wm.nx[vox.iv] = (short int)invert.invert_axis_index((vox.icol - (int)floor(vol.Ncold2)), vol.Ncold2 * 2, + "x"); // centered index for STIR format + wm.ny[vox.iv] = (short int)(vox.irow - (int)floor(vol.Nrowd2)); // centered index for STIR format + wm.nz[vox.iv] = (short int)vox.islc; // non-centered index for STIR format + } + + //... fill wm values ..................... + + wm.col[jp][wm.ne[jp]] = vox.iv; + wm.val[jp][wm.ne[jp]] = weight; + wm.ne[jp]++; + + if (wm.ne[jp] >= NITEMS[jp]) + error_weight3d(45, ""); + } + } // end of LOOP4: image slices + } // end of LOOP3: projection angle into subset + } // end of LOOP2: image rows + } // end of LOOP1: image cols + + //... detele allocated memory .............. + delete[] psf1d_h.val; + delete[] psf1d_h.ind; + + if (wmh.do_psf_3d) { + delete[] psf1d_v.val; + delete[] psf1d_v.ind; + } + + delete[] psf.val; + delete[] psf.ib; + delete[] psf.jb; + + if (wmh.do_att) { + for (int i = 0; i < sizeattpth; i++) { + delete[] attpth[i].dl; + delete[] attpth[i].iv; + } + delete[] attpth; + } +} //============================================================================= //=== wm_size_estimation ==================================================== //============================================================================= -void wm_size_estimation (int kOS, - const angle_type * const ang, - voxel_type vox, - bin_type bin, - const volume_type& vol, - const proj_type& prj, - const bool * const msk_3d, - const bool *const msk_2d, - const int maxszb, - const discrf_type * const gaussdens, - int *NITEMS) -{ - int jp; - float eff; - - //... variables for geometric component .............................................. - - psf1d_type psf1d_h, psf1d_v; - - psf1d_h.maxszb = maxszb; - psf1d_h.val = new float [ maxszb ]; - psf1d_h.ind = new int [ maxszb ]; - - if ( wmh.do_psf_3d ){ - psf1d_v.maxszb = maxszb; - psf1d_v.val = new float [ maxszb ]; - psf1d_v.ind = new int [ maxszb ]; - } - - psf2da_type psf; - - psf.maxszb_h = maxszb; - if ( wmh.do_psf_3d ) psf.maxszb_v = maxszb; - else psf.maxszb_v = 1; - psf.maxszb_t = psf.maxszb_h * psf.maxszb_v; - - psf.val = new float [ psf.maxszb_t ]; // allocation for PSF values - psf.ib = new int [ psf.maxszb_t ]; // allocation for PSF indices - psf.jb = new int [ psf.maxszb_t ]; // allocation for PSF indices - - //=== LOOP1: IMAGE ROWS ======================================================================= - - for ( vox.irow = 0 ; vox.irow < vol.Nrow ; vox.irow++ ){ - - vox.y = vol.y0 + vox.irow * vol.szcm ; // y coordinate of the voxel (index 0->Nrow-1: irow) - - //=== LOOP2: IMAGE COLUMNS ================================================================= - - for ( vox.icol = 0 ; vox.icol < vol.Ncol ; vox.icol++ ){ - - vox.x = vol.x0 + vox.icol * vol.szcm ; // x coordinate of the voxel (index 0->Ncol-1: icol) - vox.ip = vox.irow * vol.Ncol + vox.icol ; // in-plane index of the voxel considering the slice as an array - - //... to apply mask ......................................... - - if ( wmh.do_msk){ - - if ( !msk_2d[ vox.ip ] ) continue; // to skip voxel if it is outside the 2d_mask - } - - //=== LOOP3: ANGLES INTO SUBSETS ======================================================== - - for( int k = 0 ; k < prj.NangOS ; k++ ){ - - int ka = wmh.index[ k ]; // angle index of the current projection (considering the whole set of projections) - - //... perpendicular distance form voxel to detection plane ........................... - - vox.dv2dp = vox.x * ang[ ka ].sin - vox.y * ang[ ka ].cos + ang[ ka ].Rrad ; - - if ( vox.dv2dp <= 0. ) continue; // skipping voxel if it is beyond the detection plane (corner voxels) - - //... x coordinate in the rotated frame .............................................. - - vox.x1 = vox.x * ang[ ka ].cos + vox.y * ang[ ka ].sin ; - - //... to project voxels onto the detection plane and to calculate other distances ..... - - voxel_projection( &vox , &eff , prj.lngcmd2 ); - - //... setting PSF to zero ......................................... - -// for ( int i = 0 ; i < psf.maxszb ; i++ ){ -// psf.val[ i ] = (float) 0.; -// psf.ib[ i ] = psf.jb[ i ] = 0; -// } - - //... correction for PSF .............................. - - if ( !wmh.do_psf ) fill_psf_no ( &psf, &psf1d_h, vox, &ang[ ka ], bin.szdx ); - - else{ - - if ( wmh.do_psf_3d ) fill_psf_3d ( &psf, &psf1d_h, &psf1d_v, vox, gaussdens, bin.szdx, bin.thdx, bin.thcmd2 ); - - else fill_psf_2d ( &psf, &psf1d_h, vox, gaussdens, bin.szdx ); - } - - - //=== LOOP4: IMAGE SLICES ================================================================ - - for ( vox.islc = vol.first_sl ; vox.islc < vol.last_sl ; vox.islc++ ){ - - vox.iv = vox.ip + vox.islc * vol.Npix ; // volume index of the voxel (volume as an array) - - if ( wmh.do_msk ){ - if ( !msk_3d[ vox.iv ] ) continue; - } - - //... weight matrix values calculation ....................................... - - for ( int ie = 0 ; ie < psf.Nib ; ie++ ){ - - if ( psf.ib[ ie ] < 0 ) continue; - if ( psf.ib[ ie ] >= prj.Nbin ) continue; - - int ks = ( vox.islc + psf.jb[ ie ] ); - - if ( ks < 0 ) continue; - if ( ks >= vol.Nsli ) continue; - - jp = k * prj.Nbp + ks * prj.Nbin + psf.ib[ ie ]; - - NITEMS[ jp ]++; - } - } - } // end of LOOP3: projection angle into subset - } // end of LOOP2: image rows - } // end of LOOP1: image cols - - //... detele allocated memory .............. - - delete [] psf1d_h.val ; - delete [] psf1d_h.ind ; - - if ( wmh.do_psf_3d ){ - delete [] psf1d_v.val ; - delete [] psf1d_v.ind ; - } - - delete [] psf.val; - delete [] psf.ib; - delete [] psf.jb; -} +void +wm_size_estimation(int kOS, const angle_type* const ang, voxel_type vox, bin_type bin, const volume_type& vol, + const proj_type& prj, const bool* const msk_3d, const bool* const msk_2d, const int maxszb, + const discrf_type* const gaussdens, int* NITEMS) { + int jp; + float eff; + + //... variables for geometric component .............................................. + + psf1d_type psf1d_h, psf1d_v; + + psf1d_h.maxszb = maxszb; + psf1d_h.val = new float[maxszb]; + psf1d_h.ind = new int[maxszb]; + + if (wmh.do_psf_3d) { + psf1d_v.maxszb = maxszb; + psf1d_v.val = new float[maxszb]; + psf1d_v.ind = new int[maxszb]; + } + + psf2da_type psf; + + psf.maxszb_h = maxszb; + if (wmh.do_psf_3d) + psf.maxszb_v = maxszb; + else + psf.maxszb_v = 1; + psf.maxszb_t = psf.maxszb_h * psf.maxszb_v; + + psf.val = new float[psf.maxszb_t]; // allocation for PSF values + psf.ib = new int[psf.maxszb_t]; // allocation for PSF indices + psf.jb = new int[psf.maxszb_t]; // allocation for PSF indices + + //=== LOOP1: IMAGE ROWS ======================================================================= + + for (vox.irow = 0; vox.irow < vol.Nrow; vox.irow++) { + + vox.y = vol.y0 + vox.irow * vol.szcm; // y coordinate of the voxel (index 0->Nrow-1: irow) + + //=== LOOP2: IMAGE COLUMNS ================================================================= + + for (vox.icol = 0; vox.icol < vol.Ncol; vox.icol++) { + + vox.x = vol.x0 + vox.icol * vol.szcm; // x coordinate of the voxel (index 0->Ncol-1: icol) + vox.ip = vox.irow * vol.Ncol + vox.icol; // in-plane index of the voxel considering the slice as an array + + //... to apply mask ......................................... + + if (wmh.do_msk) { + + if (!msk_2d[vox.ip]) + continue; // to skip voxel if it is outside the 2d_mask + } + + //=== LOOP3: ANGLES INTO SUBSETS ======================================================== + + for (int k = 0; k < prj.NangOS; k++) { + + int ka = wmh.index[k]; // angle index of the current projection (considering the whole set of projections) + + //... perpendicular distance form voxel to detection plane ........................... + + vox.dv2dp = vox.x * ang[ka].sin - vox.y * ang[ka].cos + ang[ka].Rrad; + + if (vox.dv2dp <= 0.) + continue; // skipping voxel if it is beyond the detection plane (corner voxels) + + //... x coordinate in the rotated frame .............................................. + + vox.x1 = vox.x * ang[ka].cos + vox.y * ang[ka].sin; + + //... to project voxels onto the detection plane and to calculate other distances ..... + + voxel_projection(&vox, &eff, prj.lngcmd2); + + //... setting PSF to zero ......................................... + + // for ( int i = 0 ; i < psf.maxszb ; i++ ){ + // psf.val[ i ] = (float) 0.; + // psf.ib[ i ] = psf.jb[ i ] = 0; + // } + + //... correction for PSF .............................. + + if (!wmh.do_psf) + fill_psf_no(&psf, &psf1d_h, vox, &ang[ka], bin.szdx); + + else { + + if (wmh.do_psf_3d) + fill_psf_3d(&psf, &psf1d_h, &psf1d_v, vox, gaussdens, bin.szdx, bin.thdx, bin.thcmd2); + + else + fill_psf_2d(&psf, &psf1d_h, vox, gaussdens, bin.szdx); + } + + //=== LOOP4: IMAGE SLICES ================================================================ + + for (vox.islc = vol.first_sl; vox.islc < vol.last_sl; vox.islc++) { + + vox.iv = vox.ip + vox.islc * vol.Npix; // volume index of the voxel (volume as an array) + + if (wmh.do_msk) { + if (!msk_3d[vox.iv]) + continue; + } + + //... weight matrix values calculation ....................................... + + for (int ie = 0; ie < psf.Nib; ie++) { + + if (psf.ib[ie] < 0) + continue; + if (psf.ib[ie] >= prj.Nbin) + continue; + + int ks = (vox.islc + psf.jb[ie]); + + if (ks < 0) + continue; + if (ks >= vol.Nsli) + continue; + + jp = k * prj.Nbp + ks * prj.Nbin + psf.ib[ie]; + + NITEMS[jp]++; + } + } + } // end of LOOP3: projection angle into subset + } // end of LOOP2: image rows + } // end of LOOP1: image cols + + //... detele allocated memory .............. + + delete[] psf1d_h.val; + delete[] psf1d_h.ind; + + if (wmh.do_psf_3d) { + delete[] psf1d_v.val; + delete[] psf1d_v.ind; + } + + delete[] psf.val; + delete[] psf.ib; + delete[] psf.jb; +} //========================================================================== //=== calc_gauss =========================================================== //========================================================================== -void calc_gauss( discrf_type *gaussdens ) -{ - const float K0 = 1.0f/boost::math::constants::root_two_pi(); //Normalization factor: 1/sqrt(2*M_PI) - float x = 0; - float g; - - gaussdens->val[ gaussdens->lngd2 ] = K0; - float resd2 = gaussdens->res / (float)2.0; - - - for( int i = 1 ; i <= gaussdens->lngd2 ; i++ ){ - - x += gaussdens->res; - g = K0 * exp( - x * x / (float)2.); - gaussdens->val[ gaussdens->lngd2 + i ] = gaussdens->val[ gaussdens->lngd2 - i ] = g; - } - - gaussdens->acu[ 0 ] = gaussdens->val[ 0 ] * resd2 ; - - for ( int i = 1 ; i < gaussdens->lng ; i++ ){ - gaussdens->acu[ i ] = gaussdens->acu[ i - 1 ] + ( gaussdens->val[ i -1 ] + gaussdens->val[ i ] ) * resd2; - } - - for ( int i = 0 ; i < gaussdens->lng ; i++ ){ - gaussdens->acu[ i ] = (gaussdens->acu[ i ] - gaussdens->acu[ 0 ] ) / gaussdens->acu[ gaussdens->lng - 1 ]; - } +void +calc_gauss(discrf_type* gaussdens) { + const float K0 = 1.0f / boost::math::constants::root_two_pi(); // Normalization factor: 1/sqrt(2*M_PI) + float x = 0; + float g; + + gaussdens->val[gaussdens->lngd2] = K0; + float resd2 = gaussdens->res / (float)2.0; + + for (int i = 1; i <= gaussdens->lngd2; i++) { + + x += gaussdens->res; + g = K0 * exp(-x * x / (float)2.); + gaussdens->val[gaussdens->lngd2 + i] = gaussdens->val[gaussdens->lngd2 - i] = g; + } + + gaussdens->acu[0] = gaussdens->val[0] * resd2; + + for (int i = 1; i < gaussdens->lng; i++) { + gaussdens->acu[i] = gaussdens->acu[i - 1] + (gaussdens->val[i - 1] + gaussdens->val[i]) * resd2; + } + + for (int i = 0; i < gaussdens->lng; i++) { + gaussdens->acu[i] = (gaussdens->acu[i] - gaussdens->acu[0]) / gaussdens->acu[gaussdens->lng - 1]; + } } //========================================================================== //=== calc_vxprj ========================================================= //========================================================================== -void calc_vxprj( angle_type *ang ) -{ - //... initialization to zero ..................................... - - for ( int j = 0 ; j < ang->vxprj.lng ; j++ ) ang->vxprj.acu[ j ] = ang->vxprj.val[ j ] = (float)0.; - - //... total number of points (at DX resolution) ........................ - - int Nmax= 2 * ang->N2 ; - float resd2 = ang->vxprj.res / (float)2.0; - - //... plateau........................................................... - - for ( int i = 0 ; i < ang->N1 ; i++ ){ - ang->vxprj.val[ ang->N2 - i - 1 ] = ang->vxprj.val[ ang->N2 + i ] = ang->p; - } - - //... slopes of the trapezoid .......................................... - - for ( int i = ang->N1 ; i < ang->N2 ; i++ ){ - ang->vxprj.val[ ang->N2 - i - 1 ] = ang->vxprj.val[ ang->N2 + i ] = maxim (ang->m * ((float)i + (float)0.5) + ang->n, 0); - } - - //... cumulative sum ................................................... - - ang->vxprj.acu[ 0 ] = ang->vxprj.val[ 0 ] * resd2 ; - - for ( int i = 1 ; i < Nmax ; i++ ){ - ang->vxprj.acu[ i ] = ang->vxprj.acu[ i - 1 ] + ( ang->vxprj.val[ i -1 ] + ang->vxprj.val[ i ] ) * resd2; - } - - //... forcing distribution function to have area 1 ...................... - - for ( int i = 0 ; i < Nmax ; i++ ){ - ang->vxprj.acu[ i ] /= ang->vxprj.acu[ Nmax - 1 ]; - } -} +void +calc_vxprj(angle_type* ang) { + //... initialization to zero ..................................... + + for (int j = 0; j < ang->vxprj.lng; j++) + ang->vxprj.acu[j] = ang->vxprj.val[j] = (float)0.; + //... total number of points (at DX resolution) ........................ + + int Nmax = 2 * ang->N2; + float resd2 = ang->vxprj.res / (float)2.0; + + //... plateau........................................................... + + for (int i = 0; i < ang->N1; i++) { + ang->vxprj.val[ang->N2 - i - 1] = ang->vxprj.val[ang->N2 + i] = ang->p; + } + + //... slopes of the trapezoid .......................................... + + for (int i = ang->N1; i < ang->N2; i++) { + ang->vxprj.val[ang->N2 - i - 1] = ang->vxprj.val[ang->N2 + i] = maxim(ang->m * ((float)i + (float)0.5) + ang->n, 0); + } + + //... cumulative sum ................................................... + + ang->vxprj.acu[0] = ang->vxprj.val[0] * resd2; + + for (int i = 1; i < Nmax; i++) { + ang->vxprj.acu[i] = ang->vxprj.acu[i - 1] + (ang->vxprj.val[i - 1] + ang->vxprj.val[i]) * resd2; + } + + //... forcing distribution function to have area 1 ...................... + + for (int i = 0; i < Nmax; i++) { + ang->vxprj.acu[i] /= ang->vxprj.acu[Nmax - 1]; + } +} //========================================================================== //=== voxel_projection ===================================================== //========================================================================== -void voxel_projection ( voxel_type *vox, float * eff, float lngcmd2) -{ - - if ( wmh.COL.do_fb ){ // fan_beam - - //... angle between voxel-focal line and center-focal line and distance from voxel projection to detection line relevant points........ - - vox->costhe = cos( atan ( vox->x1 / ( wmh.COL.F - vox->dv2dp ) ) ); - vox->xdc = wmh.COL.F * vox->x1 / ( wmh.COL.F - vox->dv2dp ); // distance to the center of the detection line - vox->xd0 = vox->xdc + lngcmd2 ; // distance to the begin of the detection line - - //... efficiency correction ............................................................... - - if ( wmh.do_psf ) *eff = vox->costhe * vox->costhe * ( wmh.COL.F - REF_DIST ) / ( wmh.COL.F - vox->dv2dp ); - else *eff = (float) 1.; - - } - else{ // parallel - - //... distance from projected voxel (center) to the begin of the detection line ............ - - vox->xd0 = vox->x1 + lngcmd2; - - *eff = (float) 1. ; - } +void +voxel_projection(voxel_type* vox, float* eff, float lngcmd2) { + + if (wmh.COL.do_fb) { // fan_beam + + //... angle between voxel-focal line and center-focal line and distance from voxel projection to detection line relevant + // points........ + + vox->costhe = cos(atan(vox->x1 / (wmh.COL.F - vox->dv2dp))); + vox->xdc = wmh.COL.F * vox->x1 / (wmh.COL.F - vox->dv2dp); // distance to the center of the detection line + vox->xd0 = vox->xdc + lngcmd2; // distance to the begin of the detection line + + //... efficiency correction ............................................................... + + if (wmh.do_psf) + *eff = vox->costhe * vox->costhe * (wmh.COL.F - REF_DIST) / (wmh.COL.F - vox->dv2dp); + else + *eff = (float)1.; + + } else { // parallel + + //... distance from projected voxel (center) to the begin of the detection line ............ + + vox->xd0 = vox->x1 + lngcmd2; + + *eff = (float)1.; + } } //========================================================================== //=== fill_psf_no ========================================================== //========================================================================== -void fill_psf_no( psf2da_type *psf, psf1d_type * psf1d_h, const voxel_type& vox, angle_type const *const ang , float szdx ) -{ - psf1d_h->sgmcm = vox.szcm; +void +fill_psf_no(psf2da_type* psf, psf1d_type* psf1d_h, const voxel_type& vox, angle_type const* const ang, float szdx) { + psf1d_h->sgmcm = vox.szcm; - if ( wmh.COL.do_fb){ - if ( fabs( vox.x1 ) > EPSILON ) psf1d_h->sgmcm *= vox.xdc / vox.x1; // fb expanded projection of the voxel - } - - psf1d_h->di = min( (int) floor( szdx / psf1d_h->sgmcm ), ang->vxprj.lng -1 ) ; - psf1d_h->lngcm = ( fabs ( ang->sin ) + fabs( ang->cos ) ) * psf1d_h->sgmcm ; - - psf1d_h->lngcmd2 = psf1d_h->lngcm / (float)2.; - psf1d_h->efres = ang->vxprj.res * psf1d_h->sgmcm; // to resize discretization resolution once applied sgmcm - - calc_psf_bin( vox.xd0, wmh.prj.szcm, &ang->vxprj, psf1d_h ); - - for ( int ie = 0 ; ie < psf1d_h->Nib ; ie++ ){ - - psf->val [ ie ] = psf1d_h->val[ ie ]; - psf->ib [ ie ] = psf1d_h->ind[ ie ]; - psf->jb [ ie ] = 0; - } - psf->Nib = psf1d_h->Nib; + if (wmh.COL.do_fb) { + if (fabs(vox.x1) > EPSILON) + psf1d_h->sgmcm *= vox.xdc / vox.x1; // fb expanded projection of the voxel + } + + psf1d_h->di = min((int)floor(szdx / psf1d_h->sgmcm), ang->vxprj.lng - 1); + psf1d_h->lngcm = (fabs(ang->sin) + fabs(ang->cos)) * psf1d_h->sgmcm; + + psf1d_h->lngcmd2 = psf1d_h->lngcm / (float)2.; + psf1d_h->efres = ang->vxprj.res * psf1d_h->sgmcm; // to resize discretization resolution once applied sgmcm + + calc_psf_bin(vox.xd0, wmh.prj.szcm, &ang->vxprj, psf1d_h); + + for (int ie = 0; ie < psf1d_h->Nib; ie++) { + + psf->val[ie] = psf1d_h->val[ie]; + psf->ib[ie] = psf1d_h->ind[ie]; + psf->jb[ie] = 0; + } + psf->Nib = psf1d_h->Nib; } //========================================================================== //=== fill_psf_2d ========================================================== //========================================================================== -void fill_psf_2d( psf2da_type *psf, psf1d_type * psf1d_h, const voxel_type& vox, discrf_type const* const gaussdens, float szdx ) -{ - - psf1d_h->sgmcm = calc_sigma_h( vox, wmh.COL ); - - psf1d_h->di = min ( (int) floor( szdx / psf1d_h->sgmcm ), gaussdens->lng -1) ; - psf1d_h->lngcmd2 = psf1d_h->sgmcm * wmh.maxsigm ; - psf1d_h->lngcm = psf1d_h->lngcmd2 * (float)2.; - - psf1d_h->efres = gaussdens->res * psf1d_h->sgmcm ; - - calc_psf_bin( vox.xd0, wmh.prj.szcm, gaussdens, psf1d_h ); - - for ( int ie = 0 ; ie < psf1d_h->Nib ; ie++ ){ - - psf->val [ ie ] = psf1d_h->val[ ie ]; - psf->ib [ ie ] = psf1d_h->ind[ ie ]; - psf->jb [ ie ] = 0; - - } - psf->Nib = psf1d_h->Nib; +void +fill_psf_2d(psf2da_type* psf, psf1d_type* psf1d_h, const voxel_type& vox, discrf_type const* const gaussdens, float szdx) { + + psf1d_h->sgmcm = calc_sigma_h(vox, wmh.COL); + + psf1d_h->di = min((int)floor(szdx / psf1d_h->sgmcm), gaussdens->lng - 1); + psf1d_h->lngcmd2 = psf1d_h->sgmcm * wmh.maxsigm; + psf1d_h->lngcm = psf1d_h->lngcmd2 * (float)2.; + + psf1d_h->efres = gaussdens->res * psf1d_h->sgmcm; + + calc_psf_bin(vox.xd0, wmh.prj.szcm, gaussdens, psf1d_h); + + for (int ie = 0; ie < psf1d_h->Nib; ie++) { + + psf->val[ie] = psf1d_h->val[ie]; + psf->ib[ie] = psf1d_h->ind[ie]; + psf->jb[ie] = 0; + } + psf->Nib = psf1d_h->Nib; } //========================================================================== //=== fill_psf_3d ========================================================== //========================================================================== -void fill_psf_3d (psf2da_type *psf, - psf1d_type *psf1d_h, - psf1d_type *psf1d_v, - const voxel_type& vox, discrf_type const * const gaussdens, float szdx, float thdx, float thcmd2 ) -{ - - //... horizontal component ........................... +void +fill_psf_3d(psf2da_type* psf, psf1d_type* psf1d_h, psf1d_type* psf1d_v, const voxel_type& vox, discrf_type const* const gaussdens, + float szdx, float thdx, float thcmd2) { - psf1d_h->sgmcm = calc_sigma_h( vox, wmh.COL); - psf1d_h->lngcmd2 = psf1d_h->sgmcm * wmh.maxsigm ; - psf1d_h->lngcm = psf1d_h->lngcmd2 * (float)2.; - psf1d_h->di = min( (int) floor( szdx / psf1d_h->sgmcm ), gaussdens->lng - 1 ) ; - psf1d_h->efres = gaussdens->res * psf1d_h->sgmcm ; - - //... setting PSF to zero ......................................... - -// for ( int i = 0 ; i < psf1d_h->maxszb ; i++ ){ -// psf1d_h->val[ i ] = (float)0.; -// psf1d_h->ind[ i ] = 0; -// } - - //... calculation of the horizontal component of psf ................... - - calc_psf_bin( vox.xd0, wmh.prj.szcm, gaussdens, psf1d_h ); + //... horizontal component ........................... - //... vertical component .............................. - - psf1d_v->sgmcm = calc_sigma_v( vox, wmh.COL); - psf1d_v->lngcmd2 = psf1d_v->sgmcm * wmh.maxsigm; - psf1d_v->lngcm = psf1d_v->lngcmd2 * (float)2.; - psf1d_v->di = min( (int) floor( thdx / psf1d_v->sgmcm ), gaussdens->lng - 1 ) ; - psf1d_v->efres = gaussdens->res * psf1d_v->sgmcm ; - - //... setting PSF to zero ......................................... - -// for ( int i = 0 ; i < psf1d_v->maxszb ; i++ ){ -// psf1d_v->val[ i ] = (float)0.; -// psf1d_v->ind[ i ] = 0; -// } - - //... calculation of the vertical component of psf .................... - - calc_psf_bin( thcmd2, wmh.prj.thcm, gaussdens, psf1d_v ); - - //... mixing and setting PSF area to 1 (to correct for tail truncation of Gaussian function) ..... - - float w; - float area = 0; - int ip = 0; - float Nib_hp2 = (float) ( psf1d_h->Nib * psf1d_h->Nib )/ (float)4. ; - float Nib_vp2 = (float) ( psf1d_v->Nib * psf1d_v->Nib )/ (float)4. ; - - for ( int i = 0 ; i < psf1d_h->Nib ; i++ ){ - - float b = ( (float) psf1d_h->ind [ 0 ] + (float) psf1d_h->ind [ psf1d_h->Nib - 1 ] ) / (float)2. ; - float a = ( (float) psf1d_h->ind [ i ] - b ) * ( (float) psf1d_h->ind [ i ] - b ) / Nib_hp2 ; - - for ( int j = 0 ; j < psf1d_v->Nib ; j++ ){ - - if ( ( a + (float)( psf1d_v->ind [ j ] * psf1d_v->ind [ j ] ) / Nib_vp2 ) > (float)1. ) continue; - - w = psf1d_h->val[ i ] * psf1d_v->val[ j ]; - - if ( w < wmh.min_w ) continue; - - psf->val[ ip ] = w; - psf->ib [ ip ] = psf1d_h->ind [ i ]; - psf->jb [ ip ] = psf1d_v->ind [ j ]; - ip++; - - area += w; - } - } - psf->Nib = ip; - - for( int i = 0 ; i < ip ; i++ ) psf->val[ i ] /= area ; - + psf1d_h->sgmcm = calc_sigma_h(vox, wmh.COL); + psf1d_h->lngcmd2 = psf1d_h->sgmcm * wmh.maxsigm; + psf1d_h->lngcm = psf1d_h->lngcmd2 * (float)2.; + psf1d_h->di = min((int)floor(szdx / psf1d_h->sgmcm), gaussdens->lng - 1); + psf1d_h->efres = gaussdens->res * psf1d_h->sgmcm; + + //... setting PSF to zero ......................................... + + // for ( int i = 0 ; i < psf1d_h->maxszb ; i++ ){ + // psf1d_h->val[ i ] = (float)0.; + // psf1d_h->ind[ i ] = 0; + // } + + //... calculation of the horizontal component of psf ................... + + calc_psf_bin(vox.xd0, wmh.prj.szcm, gaussdens, psf1d_h); + + //... vertical component .............................. + + psf1d_v->sgmcm = calc_sigma_v(vox, wmh.COL); + psf1d_v->lngcmd2 = psf1d_v->sgmcm * wmh.maxsigm; + psf1d_v->lngcm = psf1d_v->lngcmd2 * (float)2.; + psf1d_v->di = min((int)floor(thdx / psf1d_v->sgmcm), gaussdens->lng - 1); + psf1d_v->efres = gaussdens->res * psf1d_v->sgmcm; + + //... setting PSF to zero ......................................... + + // for ( int i = 0 ; i < psf1d_v->maxszb ; i++ ){ + // psf1d_v->val[ i ] = (float)0.; + // psf1d_v->ind[ i ] = 0; + // } + + //... calculation of the vertical component of psf .................... + + calc_psf_bin(thcmd2, wmh.prj.thcm, gaussdens, psf1d_v); + + //... mixing and setting PSF area to 1 (to correct for tail truncation of Gaussian function) ..... + + float w; + float area = 0; + int ip = 0; + float Nib_hp2 = (float)(psf1d_h->Nib * psf1d_h->Nib) / (float)4.; + float Nib_vp2 = (float)(psf1d_v->Nib * psf1d_v->Nib) / (float)4.; + + for (int i = 0; i < psf1d_h->Nib; i++) { + + float b = ((float)psf1d_h->ind[0] + (float)psf1d_h->ind[psf1d_h->Nib - 1]) / (float)2.; + float a = ((float)psf1d_h->ind[i] - b) * ((float)psf1d_h->ind[i] - b) / Nib_hp2; + + for (int j = 0; j < psf1d_v->Nib; j++) { + + if ((a + (float)(psf1d_v->ind[j] * psf1d_v->ind[j]) / Nib_vp2) > (float)1.) + continue; + + w = psf1d_h->val[i] * psf1d_v->val[j]; + + if (w < wmh.min_w) + continue; + + psf->val[ip] = w; + psf->ib[ip] = psf1d_h->ind[i]; + psf->jb[ip] = psf1d_v->ind[j]; + ip++; + + area += w; + } + } + psf->Nib = ip; + + for (int i = 0; i < ip; i++) + psf->val[i] /= area; } //========================================================================== //=== calc_psf_bin ========================================================= //========================================================================== -void calc_psf_bin (float center_psf, - float binszcm, - discrf_type const * const vxprj, - psf1d_type *psf) -{ - float weight, preval; +void +calc_psf_bin(float center_psf, float binszcm, discrf_type const* const vxprj, psf1d_type* psf) { + float weight, preval; - //... position (in cm and bin index) of the first extrem of the vxprj on the detection line........ - - float beg_psf = center_psf - psf->lngcmd2; // position of the begin of the psf in the detection line (cm) - int jm = (int) floor( beg_psf / binszcm ); // first index in detection line interacting with psf (it can be negative) - float r_nextb = (float)( jm + 1 ) * binszcm ; // position of the next change of bin (cm) - int i1 = min( (int) floor( ( r_nextb - beg_psf ) / psf->efres) , vxprj->lng -1 ) ; // index in vxprj distribution in which happens the change of bin - int Ncb = ( vxprj->lng - i1 - 1 ) / psf->di ; // number of complete bins covered by PSF - - //... first weigth calculation ............................................................................... - - int ip = 0; // counter for the number of surviving weights - float area = (float)0. ; - - weight = vxprj->acu[ i1 ] - vxprj->acu[ 0 ]; - - if ( weight >= wmh.min_w ){ - psf->val[ ip ] = weight; - psf->ind[ ip ] = jm; - area += weight; - ip++; - } - - //... weight for the complete bins ................................................................... - - preval = vxprj->acu[ i1 ]; - - for ( int i = 0 ; i < Ncb ; i++ ){ - jm++; - i1 += psf->di; - weight = vxprj->acu[ i1 ] - preval ; - preval = vxprj->acu[ i1 ]; - - if ( weight >= wmh.min_w){ - psf->val[ ip ] = weight; - psf->ind[ ip ] = jm; - area += weight; - ip++; - } - } - - //... weight for the last bin ................................................................... + //... position (in cm and bin index) of the first extrem of the vxprj on the detection line........ - weight = (float)1. - preval ; - jm++; - - if ( weight >= wmh.min_w){ - psf->val[ ip ] = weight; - psf->ind[ ip ] = jm; - area += weight; - ip++; - } - - if ( ip >= psf->maxszb ) - error_weight3d( 47, "" ); - for (int i = 0 ; i < ip ; i++) psf->val[ i ] /= area; - psf->Nib = ip; + float beg_psf = center_psf - psf->lngcmd2; // position of the begin of the psf in the detection line (cm) + int jm = (int)floor(beg_psf / binszcm); // first index in detection line interacting with psf (it can be negative) + float r_nextb = (float)(jm + 1) * binszcm; // position of the next change of bin (cm) + int i1 = min((int)floor((r_nextb - beg_psf) / psf->efres), + vxprj->lng - 1); // index in vxprj distribution in which happens the change of bin + int Ncb = (vxprj->lng - i1 - 1) / psf->di; // number of complete bins covered by PSF + + //... first weigth calculation ............................................................................... + + int ip = 0; // counter for the number of surviving weights + float area = (float)0.; + + weight = vxprj->acu[i1] - vxprj->acu[0]; + + if (weight >= wmh.min_w) { + psf->val[ip] = weight; + psf->ind[ip] = jm; + area += weight; + ip++; + } + + //... weight for the complete bins ................................................................... + + preval = vxprj->acu[i1]; + + for (int i = 0; i < Ncb; i++) { + jm++; + i1 += psf->di; + weight = vxprj->acu[i1] - preval; + preval = vxprj->acu[i1]; + + if (weight >= wmh.min_w) { + psf->val[ip] = weight; + psf->ind[ip] = jm; + area += weight; + ip++; + } + } + + //... weight for the last bin ................................................................... + + weight = (float)1. - preval; + jm++; + if (weight >= wmh.min_w) { + psf->val[ip] = weight; + psf->ind[ip] = jm; + area += weight; + ip++; + } + + if (ip >= psf->maxszb) + error_weight3d(47, ""); + for (int i = 0; i < ip; i++) + psf->val[i] /= area; + psf->Nib = ip; } //============================================================================= //=== cal_att_path ============================================================ //============================================================================= -void calc_att_path(const bin_type& bin, const voxel_type& vox, const volume_type& vol, attpth_type *attpth ) -{ - float dx, dy, dz; - float dlast_x, dlast_y, dlast_z, dlast; - float next_x, next_y, next_z; - int cas; - - //... to initializate attpth to zero.............................. - -// for (int i = 0 ; i < attpth->maxlng ; i++ ){ -// attpth->dl [ i ] = (float) 0.; -// attpth->iv [ i ] = 0; -// } - - //... vector from voxel to bin and the sign of its components .... - - float ux = bin.x - vox.x; // first component of voxel_to_bin vector - float uy = bin.y - vox.y; // second component of voxel_to_bin vector - float uz = bin.z - vox.z; // third component of voxel_to_bin vector - - int signx = SIGN(ux); // sign of ux - int signy = SIGN(uy); // sign of uy - int signz = SIGN(uz); // sign of uz - - //... corresponding unary vector ................................... - - float dpb = sqrt(ux*ux + uy*uy + uz*uz); // distance from voxel_to_bin (modulus of [ux,uy,uz]) - ux /= dpb; // unit vector ux - uy /= dpb; // unit vector uy - uz /= dpb; // unit vector uz - - //... next and last distance to the attenuation map grip .................. - - if ( signx < 0 ){ - next_x = ( (float) vox.icol - (float) 0.5 ) * vox.szcm + vol.x0; - dlast_x = ( -vol.Xcmd2 - vox.x ) / ( ux + EPSILON ) ; - } - else{ - next_x = ( (float) vox.icol + (float) 0.5 ) * vox.szcm + vol.x0; - dlast_x = ( vol.Xcmd2 - vox.x ) / ( ux + EPSILON ) ; - } - - if ( signy < 0 ){ - next_y = ( (float) vox.irow - (float) 0.5 ) * vox.szcm + vol.y0; - dlast_y = ( -vol.Ycmd2 - vox.y ) / ( uy + EPSILON ) ; - } - else{ - next_y = ( (float) vox.irow + (float) 0.5 ) * vox.szcm + vol.y0; - dlast_y = ( vol.Ycmd2 - vox.y ) / ( uy + EPSILON ) ; - } - - if ( signz < 0 ){ - next_z = ( - (float) 0.5 ) * vox.thcm ; - dlast_z = ( -vol.Zcmd2 - vox.z ) / ( uz + EPSILON ) ; - } - else{ - next_z = ( (float) 0.5 ) * vox.thcm ; - dlast_z = ( vol.Zcmd2 - vox.z ) / ( uz + EPSILON ) ; - } - - dlast = minim ( minim ( dlast_x, dlast_y ) , minim ( dlast_z , dpb ) ); - - // ... distance to next planes avoiding high values for parallel or almost parallel lines ... - - dx = ( next_x - vox.x ) / ( ux + EPSILON ) ; - dy = ( next_y - vox.y ) / ( uy + EPSILON ) ; - dz = ( next_z - vox.z ) / ( uz + EPSILON ) ; - - //... variables initialization ..................................... - - float dant = (float)0. ; // previous distance (distance from voxel to the last change of voxel in the attenuation map) - int ni = 0 ; // number of voxels in the attenuation path - int iv = vox.ip ; // voxel index on the attenuation map - - //... loop while attenuation ray is inside the attenuation map - - for(;;){ - - cas = comp_dist( dx, dy, dz, dlast ); - - if ( cas == 0 ){ - - attpth->lng = ni; - return; - } - - else{ - - if ( ni >= attpth->maxlng ) error_weight3d(49, ""); - - attpth->iv[ ni ] = iv ; - - switch(cas){ - case 1: - attpth->dl[ ni ] = ( dx - dant ) ; - dant = dx ; - iv += signx ; - next_x += vox.szcm * signx ; - dx = ( next_x - vox.x ) / ( ux + EPSILON ) ; - break; - case 2: - attpth->dl[ ni ] = ( dy - dant ) ; - dant = dy ; - iv += signy * vol.Ncol ; - next_y += vox.szcm * signy ; - dy = ( next_y - vox.y ) / ( uy + EPSILON ) ; - break; - case 3: - attpth->dl[ ni ] = ( dz - dant ) ; - dant = dz; - iv += signz * vol.Npix ; - next_z += vox.thcm * signz ; - dz = ( next_z - vox.z ) / ( uz + EPSILON ) ; - break; - default: - error_weight3d (40, ""); - } - ni++; - } - } +void +calc_att_path(const bin_type& bin, const voxel_type& vox, const volume_type& vol, attpth_type* attpth) { + float dx, dy, dz; + float dlast_x, dlast_y, dlast_z, dlast; + float next_x, next_y, next_z; + int cas; + + //... to initializate attpth to zero.............................. + + // for (int i = 0 ; i < attpth->maxlng ; i++ ){ + // attpth->dl [ i ] = (float) 0.; + // attpth->iv [ i ] = 0; + // } + + //... vector from voxel to bin and the sign of its components .... + + float ux = bin.x - vox.x; // first component of voxel_to_bin vector + float uy = bin.y - vox.y; // second component of voxel_to_bin vector + float uz = bin.z - vox.z; // third component of voxel_to_bin vector + + int signx = SIGN(ux); // sign of ux + int signy = SIGN(uy); // sign of uy + int signz = SIGN(uz); // sign of uz + + //... corresponding unary vector ................................... + + float dpb = sqrt(ux * ux + uy * uy + uz * uz); // distance from voxel_to_bin (modulus of [ux,uy,uz]) + ux /= dpb; // unit vector ux + uy /= dpb; // unit vector uy + uz /= dpb; // unit vector uz + + //... next and last distance to the attenuation map grip .................. + + if (signx < 0) { + next_x = ((float)vox.icol - (float)0.5) * vox.szcm + vol.x0; + dlast_x = (-vol.Xcmd2 - vox.x) / (ux + EPSILON); + } else { + next_x = ((float)vox.icol + (float)0.5) * vox.szcm + vol.x0; + dlast_x = (vol.Xcmd2 - vox.x) / (ux + EPSILON); + } + + if (signy < 0) { + next_y = ((float)vox.irow - (float)0.5) * vox.szcm + vol.y0; + dlast_y = (-vol.Ycmd2 - vox.y) / (uy + EPSILON); + } else { + next_y = ((float)vox.irow + (float)0.5) * vox.szcm + vol.y0; + dlast_y = (vol.Ycmd2 - vox.y) / (uy + EPSILON); + } + + if (signz < 0) { + next_z = (-(float)0.5) * vox.thcm; + dlast_z = (-vol.Zcmd2 - vox.z) / (uz + EPSILON); + } else { + next_z = ((float)0.5) * vox.thcm; + dlast_z = (vol.Zcmd2 - vox.z) / (uz + EPSILON); + } + + dlast = minim(minim(dlast_x, dlast_y), minim(dlast_z, dpb)); + + // ... distance to next planes avoiding high values for parallel or almost parallel lines ... + + dx = (next_x - vox.x) / (ux + EPSILON); + dy = (next_y - vox.y) / (uy + EPSILON); + dz = (next_z - vox.z) / (uz + EPSILON); + + //... variables initialization ..................................... + + float dant = (float)0.; // previous distance (distance from voxel to the last change of voxel in the attenuation map) + int ni = 0; // number of voxels in the attenuation path + int iv = vox.ip; // voxel index on the attenuation map + + //... loop while attenuation ray is inside the attenuation map + + for (;;) { + + cas = comp_dist(dx, dy, dz, dlast); + + if (cas == 0) { + + attpth->lng = ni; + return; + } + + else { + + if (ni >= attpth->maxlng) + error_weight3d(49, ""); + + attpth->iv[ni] = iv; + + switch (cas) { + case 1: + attpth->dl[ni] = (dx - dant); + dant = dx; + iv += signx; + next_x += vox.szcm * signx; + dx = (next_x - vox.x) / (ux + EPSILON); + break; + case 2: + attpth->dl[ni] = (dy - dant); + dant = dy; + iv += signy * vol.Ncol; + next_y += vox.szcm * signy; + dy = (next_y - vox.y) / (uy + EPSILON); + break; + case 3: + attpth->dl[ni] = (dz - dant); + dant = dz; + iv += signz * vol.Npix; + next_z += vox.thcm * signz; + dz = (next_z - vox.z) / (uz + EPSILON); + break; + default: + error_weight3d(40, ""); + } + ni++; + } + } } //============================================================================= //=== comp_dist =============================================================== //============================================================================= -int comp_dist( float dx, - float dy, - float dz, - float dlast) -{ - int cas; - - if ( dx < dy){ - if ( dx< dz) { - if ( dx > dlast ) cas = 0; // case 0: end of the iteration - else cas = 1; // case 1: minimum value = dx. Next index change in attenuation map is in x direction - } - else { - if ( dz > dlast ) cas = 0; // case 0: end of the iteration - else cas = 3; // case 3: minimum value = dz. Next index change in attenuation map is in z direction - } - } - else{ - if ( dy < dz) { - if ( dy > dlast ) cas = 0; // case 0: end of the iteration - else cas = 2; // case 2: minimum value = dy. Next index change in attenuation map is in y direction - } - else { - if ( dz > dlast ) cas = 0; // case 0: end of the iteration - else cas = 3; // case 3: minimum value = dz. Next index change in attenuation map is in z direction } - } - } - return( cas ); +int +comp_dist(float dx, float dy, float dz, float dlast) { + int cas; + + if (dx < dy) { + if (dx < dz) { + if (dx > dlast) + cas = 0; // case 0: end of the iteration + else + cas = 1; // case 1: minimum value = dx. Next index change in attenuation map is in x direction + } else { + if (dz > dlast) + cas = 0; // case 0: end of the iteration + else + cas = 3; // case 3: minimum value = dz. Next index change in attenuation map is in z direction + } + } else { + if (dy < dz) { + if (dy > dlast) + cas = 0; // case 0: end of the iteration + else + cas = 2; // case 2: minimum value = dy. Next index change in attenuation map is in y direction + } else { + if (dz > dlast) + cas = 0; // case 0: end of the iteration + else + cas = 3; // case 3: minimum value = dz. Next index change in attenuation map is in z direction } + } + } + return (cas); } //============================================================================= //=== cal_att ================================================================= //============================================================================= -float calc_att( const attpth_type *const attpth, const float *const attmap , int nsli ){ - - float att_coef = (float)0.; - int iv; - - for ( int i = 0 ; i < attpth->lng ; i++ ){ - - iv = attpth->iv[ i ] + wmh.vol.Npix * nsli ; - - if ( iv < 0 || iv >= wmh.vol.Nvox ) break; - - att_coef += attpth->dl[ i ] * attmap[ iv ]; - } - - att_coef = exp( -att_coef ); - return( att_coef ); +float +calc_att(const attpth_type* const attpth, const float* const attmap, int nsli) { + + float att_coef = (float)0.; + int iv; + + for (int i = 0; i < attpth->lng; i++) { + + iv = attpth->iv[i] + wmh.vol.Npix * nsli; + + if (iv < 0 || iv >= wmh.vol.Nvox) + break; + + att_coef += attpth->dl[i] * attmap[iv]; + } + + att_coef = exp(-att_coef); + return (att_coef); } //========================================================================== //=== error_weight3d ======================================================= //========================================================================== -void error_weight3d ( int nerr, const string& text ) -{ +void +error_weight3d(int nerr, const string& text) { #if 0 switch(nerr){ case 13: printf( "\n\nError weight3d: wm.NbOS and/or wm.Nvox are negative"); break; @@ -974,24 +985,41 @@ void error_weight3d ( int nerr, const string& text ) exit(0); #else - using stir::error; - switch(nerr){ - case 13: error( "\n\nError weight3d: wm.NbOS and/or wm.Nvox are negative"); break; - case 21: printf( "\n\nError weight3d: undefined collimator. Collimator %s not found\n",text.c_str() ); break; - case 30: printf( "\n\nError weight3d: can not open \n%s for reading\n", text.c_str() ); break; - case 31: printf( "\n\nError weight3d: can not open \n%s for writing\n", text.c_str() ); break; - case 40: error( "\n\nError weight3d: wrong codification in comp_dist function");break; - case 45: error( "\n\nError weight3d: Realloc needed for WM\n"); break; - case 47: error( "\n\nError weight3d: psf length greater than maxszb in calc_psf_bin\n"); break; - case 49: error( "\n\nError weight3d: attpth larger than allocated\n"); break; - case 50: printf( "\n\nError weight3d: No header stored in %s \n",text.c_str() ); break; - default: error( "\n\nError weight3d: unknown error number on error_weight3d()"); - } - - exit(0); -#endif -} - + using stir::error; + switch (nerr) { + case 13: + error("\n\nError weight3d: wm.NbOS and/or wm.Nvox are negative"); + break; + case 21: + printf("\n\nError weight3d: undefined collimator. Collimator %s not found\n", text.c_str()); + break; + case 30: + printf("\n\nError weight3d: can not open \n%s for reading\n", text.c_str()); + break; + case 31: + printf("\n\nError weight3d: can not open \n%s for writing\n", text.c_str()); + break; + case 40: + error("\n\nError weight3d: wrong codification in comp_dist function"); + break; + case 45: + error("\n\nError weight3d: Realloc needed for WM\n"); + break; + case 47: + error("\n\nError weight3d: psf length greater than maxszb in calc_psf_bin\n"); + break; + case 49: + error("\n\nError weight3d: attpth larger than allocated\n"); + break; + case 50: + printf("\n\nError weight3d: No header stored in %s \n", text.c_str()); + break; + default: + error("\n\nError weight3d: unknown error number on error_weight3d()"); + } + exit(0); +#endif +} } // namespace SPECTUB diff --git a/src/recon_buildblock/SqrtHessianRowSum.cxx b/src/recon_buildblock/SqrtHessianRowSum.cxx index b86d938c91..7a788e859d 100644 --- a/src/recon_buildblock/SqrtHessianRowSum.cxx +++ b/src/recon_buildblock/SqrtHessianRowSum.cxx @@ -33,29 +33,22 @@ #include "stir/recon_buildblock/GeneralisedObjectiveFunction.h" #include "stir/unique_ptr.h" - START_NAMESPACE_STIR template -SqrtHessianRowSum:: -SqrtHessianRowSum() -{ +SqrtHessianRowSum::SqrtHessianRowSum() { this->set_defaults(); } template -SqrtHessianRowSum:: -SqrtHessianRowSum(const std::string& filename) -{ +SqrtHessianRowSum::SqrtHessianRowSum(const std::string& filename) { this->set_defaults(); this->parse(filename.c_str()); } template void -SqrtHessianRowSum:: -set_defaults() -{ +SqrtHessianRowSum::set_defaults() { output_file_format_sptr = OutputFileFormat::default_sptr(); output_filename = ""; set_use_approximate_hessian(true); @@ -66,8 +59,7 @@ set_defaults() template void -SqrtHessianRowSum::initialise_keymap() -{ +SqrtHessianRowSum::initialise_keymap() { parser.add_start_key("SqrtHessianRowSum Parameters"); parser.add_key("output filename", &output_filename); parser.add_key("input image filename", &input_image_filename); @@ -79,11 +71,9 @@ SqrtHessianRowSum::initialise_keymap() template bool -SqrtHessianRowSum::post_processing() -{ +SqrtHessianRowSum::post_processing() { - if (input_image_filename.empty()) - { + if (input_image_filename.empty()) { error("Please define input_image_filename."); return true; } @@ -92,96 +82,74 @@ SqrtHessianRowSum::post_processing() } template -GeneralisedObjectiveFunction const& -SqrtHessianRowSum:: -get_objective_function_sptr() -{ - return static_cast&> (*objective_function_sptr); +GeneralisedObjectiveFunction const& +SqrtHessianRowSum::get_objective_function_sptr() { + return static_cast&>(*objective_function_sptr); } template void -SqrtHessianRowSum:: -set_objective_function_sptr(const shared_ptr >& obj_fun) -{ - this->objective_function_sptr = obj_fun; +SqrtHessianRowSum::set_objective_function_sptr(const shared_ptr>& obj_fun) { + this->objective_function_sptr = obj_fun; // it might be that it's already set-up, but we don't know _already_setup = false; } template -shared_ptr -SqrtHessianRowSum:: -get_input_image_sptr() -{ +shared_ptr +SqrtHessianRowSum::get_input_image_sptr() { return input_image_sptr; } template void -SqrtHessianRowSum:: -set_input_image_sptr(shared_ptr const& image_sptr) -{ +SqrtHessianRowSum::set_input_image_sptr(shared_ptr const& image_sptr) { if (_already_setup) _already_setup = input_image_sptr->has_same_characteristics(*image_sptr); input_image_sptr = image_sptr; } template -shared_ptr -SqrtHessianRowSum:: -get_output_target_sptr() -{ +shared_ptr +SqrtHessianRowSum::get_output_target_sptr() { return output_target_sptr; } template bool -SqrtHessianRowSum:: -get_use_approximate_hessian() const -{ +SqrtHessianRowSum::get_use_approximate_hessian() const { return use_approximate_hessian; } template void -SqrtHessianRowSum:: -set_use_approximate_hessian(bool use_approximate) -{ +SqrtHessianRowSum::set_use_approximate_hessian(bool use_approximate) { use_approximate_hessian = use_approximate; } template bool -SqrtHessianRowSum:: -get_compute_with_penalty() const -{ +SqrtHessianRowSum::get_compute_with_penalty() const { return compute_with_penalty; } template void -SqrtHessianRowSum:: -set_compute_with_penalty(bool with_penalty) -{ +SqrtHessianRowSum::set_compute_with_penalty(bool with_penalty) { compute_with_penalty = with_penalty; } template void -SqrtHessianRowSum:: -set_up() -{ - if (is_null_ptr(this->objective_function_sptr)) - { +SqrtHessianRowSum::set_up() { + if (is_null_ptr(this->objective_function_sptr)) { error("objective_function_sptr is null"); } - if (is_null_ptr(this->input_image_sptr)) - { + if (is_null_ptr(this->input_image_sptr)) { error("input_image_sptr is null"); } objective_function_sptr->set_up(input_image_sptr); - output_target_sptr = unique_ptr(input_image_sptr->get_empty_copy()); + output_target_sptr = unique_ptr(input_image_sptr->get_empty_copy()); std::fill(output_target_sptr->begin_all(), output_target_sptr->end_all(), 0.F); _already_setup = true; @@ -189,39 +157,30 @@ set_up() template void -SqrtHessianRowSum:: -process_data() -{ - if (get_use_approximate_hessian()) - { +SqrtHessianRowSum::process_data() { + if (get_use_approximate_hessian()) { // Compute the SqrtHessianRowSum image using the approximate hessian // The input image is used as a template for this method compute_approximate_Hessian_row_sum(); - } - else - { + } else { // Compute the SqrtHessianRowSum image with the full Hessian at the input image estimate. // The input image here is assumed to be the current_image_estimate at the point the Hessian will be computed compute_Hessian_row_sum(); } // Square Root the output of the Hessian_row_sum methods - std::for_each(output_target_sptr->begin_all(), output_target_sptr->end_all(), - [](float& a) { return a=sqrt(a); } ); + std::for_each(output_target_sptr->begin_all(), output_target_sptr->end_all(), [](float& a) { return a = sqrt(a); }); // Save the output - if (!output_filename.empty()) - { - output_file_format_sptr->write_to_file(output_filename, *output_target_sptr); - info("Output image of sqrt Hessian row sum has been computed and saved as " + output_filename + "."); - } + if (!output_filename.empty()) { + output_file_format_sptr->write_to_file(output_filename, *output_target_sptr); + info("Output image of sqrt Hessian row sum has been computed and saved as " + output_filename + "."); + } } template void -SqrtHessianRowSum:: -compute_Hessian_row_sum() -{ +SqrtHessianRowSum::compute_Hessian_row_sum() { if (!_already_setup) error("set_up() needs to be called first"); @@ -232,18 +191,17 @@ compute_Hessian_row_sum() if (get_compute_with_penalty()) objective_function_sptr->accumulate_Hessian_times_input(*output_target_sptr, *input_image_sptr, *ones_image_sptr); else - objective_function_sptr->accumulate_Hessian_times_input_without_penalty(*output_target_sptr, *input_image_sptr, *ones_image_sptr); + objective_function_sptr->accumulate_Hessian_times_input_without_penalty(*output_target_sptr, *input_image_sptr, + *ones_image_sptr); } template void -SqrtHessianRowSum:: -compute_approximate_Hessian_row_sum() -{ +SqrtHessianRowSum::compute_approximate_Hessian_row_sum() { if (!_already_setup) error("set_up() needs to be called first"); - output_target_sptr = unique_ptr(input_image_sptr->get_empty_copy()); + output_target_sptr = unique_ptr(input_image_sptr->get_empty_copy()); std::fill(output_target_sptr->begin_all(), output_target_sptr->end_all(), 0.F); info("Computing the approximate Hessian row sum, this may take a while..."); // Setup image @@ -254,11 +212,10 @@ compute_approximate_Hessian_row_sum() if (get_compute_with_penalty()) info("approximate Hessian row sum: Priors do not have an approximation of the Hessian. Ignoring the prior!"); - objective_function_sptr->add_multiplication_with_approximate_Hessian_without_penalty(*output_target_sptr, - *ones_image_sptr); + objective_function_sptr->add_multiplication_with_approximate_Hessian_without_penalty(*output_target_sptr, *ones_image_sptr); } -template class SqrtHessianRowSum >; -template class SqrtHessianRowSum; -//template class SqrtHessianRowSum; +template class SqrtHessianRowSum>; +template class SqrtHessianRowSum; +// template class SqrtHessianRowSum; END_NAMESPACE_STIR diff --git a/src/recon_buildblock/SymmetryOperation.cxx b/src/recon_buildblock/SymmetryOperation.cxx index d8e12078b1..e67cd815b6 100644 --- a/src/recon_buildblock/SymmetryOperation.cxx +++ b/src/recon_buildblock/SymmetryOperation.cxx @@ -34,18 +34,14 @@ START_NAMESPACE_STIR -void -SymmetryOperation:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +void +SymmetryOperation::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); - + ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -53,25 +49,19 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation::transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} END_NAMESPACE_STIR diff --git a/src/recon_buildblock/SymmetryOperations_PET_CartesianGrid.cxx b/src/recon_buildblock/SymmetryOperations_PET_CartesianGrid.cxx index 77223e7e09..d801f11a74 100644 --- a/src/recon_buildblock/SymmetryOperations_PET_CartesianGrid.cxx +++ b/src/recon_buildblock/SymmetryOperations_PET_CartesianGrid.cxx @@ -40,21 +40,16 @@ #include "stir/Coordinate3D.h" #include "stir/recon_buildblock/ProjMatrixElemsForOneDensel.h" - START_NAMESPACE_STIR void -SymmetryOperation_PET_CartesianGrid_z_shift:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_z_shift::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { // TODO possibly an explicit z_shift here would be quicker, although a smart compiler should see it Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); @@ -63,39 +58,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_z_shift:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_z_shift::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xmx_zq:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xmx_zq::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -103,39 +89,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_xmx_zq:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_zq::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -143,39 +120,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -183,39 +151,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xy_yx_zq::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xmy_yx:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xmy_yx::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -223,39 +182,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_xmy_yx:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_yx::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xy_yx:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xy_yx::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -263,39 +213,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_xy_yx:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xy_yx::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xmx:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xmx::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -303,39 +244,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_xmx:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmx::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_ymy:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_ymy::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -343,35 +275,26 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_ymy:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_ymy::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_zq:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_zq::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -379,39 +302,31 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_zq:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_zq::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq::transform_proj_matrix_elems_for_one_bin( + ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -419,39 +334,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -459,39 +365,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xy_ymx:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xy_ymx::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -499,39 +396,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_xy_ymx:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xy_ymx::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -539,39 +427,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_ymy_zq:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_ymy_zq::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -579,39 +458,30 @@ transform_proj_matrix_elems_for_one_bin( } } - -void -SymmetryOperation_PET_CartesianGrid_swap_ymy_zq:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_ymy_zq::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy::transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -619,38 +489,31 @@ transform_proj_matrix_elems_for_one_bin( } } -void -SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} void -SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq:: -transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const -{ +SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq::transform_proj_matrix_elems_for_one_bin( + ProjMatrixElemsForOneBin& lor) const { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - while (element_ptr != lor.end()) - { + while (element_ptr != lor.end()) { Coordinate3D c(element_ptr->get_coords()); self::transform_image_coordinates(c); *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); @@ -658,26 +521,20 @@ transform_proj_matrix_elems_for_one_bin( } } - - -void -SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq:: -transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probs) const -{ +void +SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq::transform_proj_matrix_elems_for_one_densel( + ProjMatrixElemsForOneDensel& probs) const { Densel densel = probs.get_densel(); transform_image_coordinates(densel); probs.set_densel(densel); - + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); - while (element_ptr != probs.end()) - { + while (element_ptr != probs.end()) { Bin c(*element_ptr); self::transform_bin_coordinates(c); *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); ++element_ptr; } -} - +} END_NAMESPACE_STIR diff --git a/src/recon_buildblock/TrivialBinNormalisation.cxx b/src/recon_buildblock/TrivialBinNormalisation.cxx index d600f1d073..f5a8813a48 100644 --- a/src/recon_buildblock/TrivialBinNormalisation.cxx +++ b/src/recon_buildblock/TrivialBinNormalisation.cxx @@ -29,8 +29,6 @@ START_NAMESPACE_STIR -const char * const -TrivialBinNormalisation::registered_name = "None"; +const char* const TrivialBinNormalisation::registered_name = "None"; END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/TrivialDataSymmetriesForBins.cxx b/src/recon_buildblock/TrivialDataSymmetriesForBins.cxx index e210bf052b..0101c6e7da 100644 --- a/src/recon_buildblock/TrivialDataSymmetriesForBins.cxx +++ b/src/recon_buildblock/TrivialDataSymmetriesForBins.cxx @@ -19,7 +19,7 @@ /*! \file \ingroup symmetries - \brief non-inline implementations for class + \brief non-inline implementations for class stir::TrivialDataSymmetriesForBins \author Kris Thielemans @@ -32,129 +32,91 @@ using std::vector; START_NAMESPACE_STIR -TrivialDataSymmetriesForBins:: -TrivialDataSymmetriesForBins -( - const shared_ptr& proj_data_info_ptr) - : DataSymmetriesForBins(proj_data_info_ptr) -{ -} - +TrivialDataSymmetriesForBins::TrivialDataSymmetriesForBins(const shared_ptr& proj_data_info_ptr) + : DataSymmetriesForBins(proj_data_info_ptr) {} #ifndef STIR_NO_COVARIANT_RETURN_TYPES - TrivialDataSymmetriesForBins * +TrivialDataSymmetriesForBins* #else - DataSymmetriesForViewSegmentNumbers * +DataSymmetriesForViewSegmentNumbers* #endif -TrivialDataSymmetriesForBins:: -clone() const -{ +TrivialDataSymmetriesForBins::clone() const { return new TrivialDataSymmetriesForBins(*this); } int -TrivialDataSymmetriesForBins::num_related_bins(const Bin& b) const -{ +TrivialDataSymmetriesForBins::num_related_bins(const Bin& b) const { return 1; } -bool TrivialDataSymmetriesForBins::find_basic_bin(Bin& b) const -{ +bool +TrivialDataSymmetriesForBins::find_basic_bin(Bin& b) const { return false; } - bool -TrivialDataSymmetriesForBins:: -is_basic(const Bin& b) const -{ +TrivialDataSymmetriesForBins::is_basic(const Bin& b) const { return true; } - void -TrivialDataSymmetriesForBins:: -get_related_bins_factorised(vector& axtan_pos_nums, const Bin& b, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ - if (b.axial_pos_num() >= min_axial_pos_num && - b.axial_pos_num() <= max_axial_pos_num && - b.tangential_pos_num() >= min_tangential_pos_num && - b.tangential_pos_num() <= max_tangential_pos_num) - { - axtan_pos_nums.resize(1); - axtan_pos_nums[0] = - AxTangPosNumbers(b.axial_pos_num(), - b.tangential_pos_num()); - } - else - { - axtan_pos_nums.resize(0); - } +TrivialDataSymmetriesForBins::get_related_bins_factorised(vector& axtan_pos_nums, const Bin& b, + const int min_axial_pos_num, const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) const { + if (b.axial_pos_num() >= min_axial_pos_num && b.axial_pos_num() <= max_axial_pos_num && + b.tangential_pos_num() >= min_tangential_pos_num && b.tangential_pos_num() <= max_tangential_pos_num) { + axtan_pos_nums.resize(1); + axtan_pos_nums[0] = AxTangPosNumbers(b.axial_pos_num(), b.tangential_pos_num()); + } else { + axtan_pos_nums.resize(0); + } } void -TrivialDataSymmetriesForBins:: -get_related_bins(vector& rel_b, const Bin& b, - const int min_axial_pos_num, const int max_axial_pos_num, - const int min_tangential_pos_num, const int max_tangential_pos_num) const -{ - if (b.axial_pos_num() >= min_axial_pos_num && - b.axial_pos_num() <= max_axial_pos_num && - b.tangential_pos_num() >= min_tangential_pos_num && - b.tangential_pos_num() <= max_tangential_pos_num) - { - rel_b.resize(1); - rel_b[0] = b; - } - else - { - rel_b.resize(0); - } +TrivialDataSymmetriesForBins::get_related_bins(vector& rel_b, const Bin& b, const int min_axial_pos_num, + const int max_axial_pos_num, const int min_tangential_pos_num, + const int max_tangential_pos_num, const int min_timing_pos_num, + const int max_timing_pos_num) const { + if (b.axial_pos_num() >= min_axial_pos_num && b.axial_pos_num() <= max_axial_pos_num && + b.tangential_pos_num() >= min_tangential_pos_num && b.tangential_pos_num() <= max_tangential_pos_num && + b.timing_pos_num() >= min_timing_pos_num && b.timing_pos_num() <= max_timing_pos_num) { + rel_b.resize(1); + rel_b[0] = b; + } else { + rel_b.resize(0); + } } unique_ptr -TrivialDataSymmetriesForBins:: -find_symmetry_operation_from_basic_bin(Bin&) const -{ +TrivialDataSymmetriesForBins::find_symmetry_operation_from_basic_bin(Bin&) const { return unique_ptr(new TrivialSymmetryOperation); } unique_ptr -TrivialDataSymmetriesForBins:: -find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers& vs) const -{ +TrivialDataSymmetriesForBins::find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers& vs) const { return unique_ptr(new TrivialSymmetryOperation); } void -TrivialDataSymmetriesForBins:: -get_related_view_segment_numbers(vector& all, const ViewSegmentNumbers& v_s) const -{ +TrivialDataSymmetriesForBins::get_related_view_segment_numbers(vector& all, + const ViewSegmentNumbers& v_s) const { all.resize(1); all[0] = v_s; } - int -TrivialDataSymmetriesForBins:: -num_related_view_segment_numbers(const ViewSegmentNumbers&) const -{ +TrivialDataSymmetriesForBins::num_related_view_segment_numbers(const ViewSegmentNumbers&) const { return 1; } bool -TrivialDataSymmetriesForBins:: -find_basic_view_segment_numbers(ViewSegmentNumbers&) const -{ +TrivialDataSymmetriesForBins::find_basic_view_segment_numbers(ViewSegmentNumbers&) const { return false; } -bool -TrivialDataSymmetriesForBins:: -blindly_equals(const root_type * const) const -{ +bool +TrivialDataSymmetriesForBins::blindly_equals(const root_type* const) const { return true; } diff --git a/src/recon_buildblock/distributable.cxx b/src/recon_buildblock/distributable.cxx index b942b70bab..e530bd5d4a 100644 --- a/src/recon_buildblock/distributable.cxx +++ b/src/recon_buildblock/distributable.cxx @@ -23,8 +23,8 @@ \brief Implementation of stir::distributable_computation() and related functions - \author Kris Thielemans - \author Alexey Zverovich + \author Kris Thielemans + \author Alexey Zverovich \author Matthew Jacobson \author PARAPET project \author Tobias Beisel @@ -32,7 +32,7 @@ /* Modification history: KT 30/05/2002 get rid of dependence on specific symmetries (i.e. views up to 45 degrees) - + Tobias Beisel 16/06/2007 added MPI support added function for Cached MPI support @@ -60,315 +60,261 @@ #include #ifdef STIR_MPI -#include "stir/recon_buildblock/distributableMPICacheEnabled.h" -#include "stir/recon_buildblock/distributed_functions.h" -#include "stir/recon_buildblock/distributed_test_functions.h" -#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" // needed for RPC functions +# include "stir/recon_buildblock/distributableMPICacheEnabled.h" +# include "stir/recon_buildblock/distributed_functions.h" +# include "stir/recon_buildblock/distributed_test_functions.h" +# include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" // needed for RPC functions #endif #ifdef STIR_OPENMP # ifdef STIR_MPI # error Cannot use both OPENMP and MP # endif -#include +# include #endif #include "stir/num_threads.h" START_NAMESPACE_STIR -/* WARNING: the sequence of steps here has to match what is on the receiving end +/* WARNING: the sequence of steps here has to match what is on the receiving end in DistributedWorker */ -void setup_distributable_computation( - const shared_ptr& proj_pair_sptr, - const shared_ptr& exam_info_sptr, - const shared_ptr proj_data_info_sptr, - const shared_ptr >& target_sptr, - const bool zero_seg0_end_planes, - const bool distributed_cache_enabled) -{ +void +setup_distributable_computation(const shared_ptr& proj_pair_sptr, + const shared_ptr& exam_info_sptr, + const shared_ptr proj_data_info_sptr, + const shared_ptr>& target_sptr, + const bool zero_seg0_end_planes, const bool distributed_cache_enabled) { set_num_threads(); #ifdef STIR_OPENMP - info(boost::format("Using distributable_computation with %d threads on %d processors.") - % omp_get_max_threads() % omp_get_num_procs()); + info(boost::format("Using distributable_computation with %d threads on %d processors.") % omp_get_max_threads() % + omp_get_num_procs()); #endif #ifdef STIR_MPI distributed::first_iteration = true; - - //broadcast type of computation (currently only 1 available) + + // broadcast type of computation (currently only 1 available) distributed::send_int_value(task_setup_distributable_computation, -1); - //broadcast zero_seg0_end_planes + // broadcast zero_seg0_end_planes distributed::send_bool_value(zero_seg0_end_planes, -1, -1); - - //broadcast target_sptr + + // broadcast target_sptr distributed::send_image_parameters(target_sptr.get(), -1, -1); distributed::send_image_estimate(target_sptr.get(), -1); - - //sending Data_info + + // sending Data_info distributed::send_exam_and_proj_data_info(*exam_info_sptr, *proj_data_info_sptr, -1); - //send projector pair + // send projector pair distributed::send_projectors(proj_pair_sptr, -1); - //send configuration values for distributed computation + // send configuration values for distributed computation int configurations[4]; - configurations[0]=distributed::test?1:0; - configurations[1]=distributed::test_send_receive_times?1:0; - configurations[2]=distributed::rpc_time?1:0; - configurations[3]=distributed_cache_enabled?1:0; + configurations[0] = distributed::test ? 1 : 0; + configurations[1] = distributed::test_send_receive_times ? 1 : 0; + configurations[2] = distributed::rpc_time ? 1 : 0; + configurations[3] = distributed_cache_enabled ? 1 : 0; distributed::send_int_values(configurations, 4, distributed::STIR_MPI_CONF_TAG, -1); - + distributed::send_double_values(&distributed::min_threshold, 1, distributed::STIR_MPI_CONF_TAG, -1); - -#ifndef NDEBUG - //test sending parameter_info - if (distributed::test) + +# ifndef NDEBUG + // test sending parameter_info + if (distributed::test) distributed::test_parameter_info_master(proj_pair_sptr->stir::ParsingObject::parameter_info(), 1, "projector_pair_ptr"); -#endif +# endif #endif // STIR_MPI } -void end_distributable_computation() -{ +void +end_distributable_computation() { #ifdef STIR_MPI - int my_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &my_rank) ; /*Gets the rank of the Processor*/ - if (my_rank==0) - { - //broadcast end of processing notification - distributed::send_int_value(task_stop_processing, -1); - } + int my_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); /*Gets the rank of the Processor*/ + if (my_rank == 0) { + // broadcast end of processing notification + distributed::send_int_value(task_stop_processing, -1); + } #endif - } template static void -zero_end_sinograms(ViewgramsPtr viewgrams_ptr) -{ - if (!is_null_ptr(viewgrams_ptr)) - { - const int min_ax_pos_num = viewgrams_ptr->get_min_axial_pos_num(); - const int max_ax_pos_num = viewgrams_ptr->get_max_axial_pos_num(); - for (RelatedViewgrams::iterator r_viewgrams_iter = viewgrams_ptr->begin(); - r_viewgrams_iter != viewgrams_ptr->end(); - ++r_viewgrams_iter) - { - (*r_viewgrams_iter)[min_ax_pos_num].fill(0); - (*r_viewgrams_iter)[max_ax_pos_num].fill(0); - } +zero_end_sinograms(ViewgramsPtr viewgrams_ptr) { + if (!is_null_ptr(viewgrams_ptr)) { + const int min_ax_pos_num = viewgrams_ptr->get_min_axial_pos_num(); + const int max_ax_pos_num = viewgrams_ptr->get_max_axial_pos_num(); + for (RelatedViewgrams::iterator r_viewgrams_iter = viewgrams_ptr->begin(); r_viewgrams_iter != viewgrams_ptr->end(); + ++r_viewgrams_iter) { + (*r_viewgrams_iter)[min_ax_pos_num].fill(0); + (*r_viewgrams_iter)[max_ax_pos_num].fill(0); } + } } -static -void get_viewgrams(shared_ptr >& y, - shared_ptr >& additive_binwise_correction_viewgrams, - shared_ptr >& mult_viewgrams_sptr, - const shared_ptr& proj_dat_ptr, - const bool read_from_proj_dat, - const bool zero_seg0_end_planes, - const shared_ptr& binwise_correction, - const shared_ptr& normalisation_sptr, - const double start_time_of_frame, - const double end_time_of_frame, - const shared_ptr& symmetries_ptr, - const ViewSegmentNumbers& view_segment_num - ) -{ - if (!is_null_ptr(binwise_correction)) - { +static void +get_viewgrams(shared_ptr>& y, shared_ptr>& additive_binwise_correction_viewgrams, + shared_ptr>& mult_viewgrams_sptr, const shared_ptr& proj_dat_ptr, + const bool read_from_proj_dat, const bool zero_seg0_end_planes, const shared_ptr& binwise_correction, + const shared_ptr& normalisation_sptr, const double start_time_of_frame, + const double end_time_of_frame, const shared_ptr& symmetries_ptr, + const ViewSegmentNumbers& view_segment_num, const int timing_pos_num) { + if (!is_null_ptr(binwise_correction)) { #ifdef STIR_OPENMP -#pragma omp critical(ADDSINO) +# pragma omp critical(ADDSINO) #endif -#if !defined(_MSC_VER) || _MSC_VER>1300 - additive_binwise_correction_viewgrams.reset( - new RelatedViewgrams - (binwise_correction->get_related_viewgrams(view_segment_num, symmetries_ptr))); +#if !defined(_MSC_VER) || _MSC_VER > 1300 + additive_binwise_correction_viewgrams.reset(new RelatedViewgrams( + binwise_correction->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); #else - RelatedViewgrams tmp(binwise_correction-> - get_related_viewgrams(view_segment_num, symmetries_ptr)); - additive_binwise_correction_viewgrams.reset(new RelatedViewgrams(tmp)); + RelatedViewgrams tmp( + binwise_correction->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num)); + additive_binwise_correction_viewgrams.reset(new RelatedViewgrams(tmp)); #endif - } - - if (read_from_proj_dat) - { + } + + if (read_from_proj_dat) { #ifdef STIR_OPENMP -#pragma omp critical(VIEW) +# pragma omp critical(VIEW) #endif -#if !defined(_MSC_VER) || _MSC_VER>1300 - y.reset(new RelatedViewgrams - (proj_dat_ptr->get_related_viewgrams(view_segment_num, symmetries_ptr))); +#if !defined(_MSC_VER) || _MSC_VER > 1300 + y.reset(new RelatedViewgrams( + proj_dat_ptr->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); #else - // workaround VC++ 6.0 bug - RelatedViewgrams tmp(proj_dat_ptr-> - get_related_viewgrams(view_segment_num, symmetries_ptr)); - y.reset(new RelatedViewgrams(tmp)); -#endif - } - else - { - y.reset(new RelatedViewgrams - (proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr))); - } + // workaround VC++ 6.0 bug + RelatedViewgrams tmp(proj_dat_ptr->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num)); + y.reset(new RelatedViewgrams(tmp)); +#endif + } else { + y.reset(new RelatedViewgrams( + proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); + } // multiplicative correction - if (!is_null_ptr(normalisation_sptr) && !normalisation_sptr->is_trivial()) - { - mult_viewgrams_sptr.reset( - new RelatedViewgrams(proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr))); - mult_viewgrams_sptr->fill(1.F); + if (!is_null_ptr(normalisation_sptr) && !normalisation_sptr->is_trivial()) { + mult_viewgrams_sptr.reset(new RelatedViewgrams( + proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); + mult_viewgrams_sptr->fill(1.F); #ifdef STIR_OPENMP -#pragma omp critical(MULT) +# pragma omp critical(MULT) #endif - normalisation_sptr->undo(*mult_viewgrams_sptr,start_time_of_frame,end_time_of_frame); - } - - if (view_segment_num.segment_num()==0 && zero_seg0_end_planes) - { - zero_end_sinograms(y); - zero_end_sinograms(additive_binwise_correction_viewgrams); - zero_end_sinograms(mult_viewgrams_sptr); - } + normalisation_sptr->undo(*mult_viewgrams_sptr, start_time_of_frame, end_time_of_frame); + } + + if (view_segment_num.segment_num() == 0 && zero_seg0_end_planes) { + zero_end_sinograms(y); + zero_end_sinograms(additive_binwise_correction_viewgrams); + zero_end_sinograms(mult_viewgrams_sptr); + } } #ifdef STIR_MPI -void send_viewgrams(const shared_ptr >& y, - const shared_ptr >& additive_binwise_correction_viewgrams, - const shared_ptr >& mult_viewgrams_sptr, - const int next_receiver) -{ - distributed::send_view_segment_numbers( y->get_basic_view_segment_num(), NEW_VIEWGRAM_TAG, next_receiver); - -#ifndef NDEBUG - //test sending related viegrams - shared_ptr - symmetries_sptr(y->get_symmetries_ptr()->clone()); - if (distributed::test && distributed::first_iteration==true && next_receiver==1) - distributed::test_related_viewgrams_master(y->get_proj_data_info_sptr()->create_shared_clone(), - symmetries_sptr, y.get(), next_receiver); -#endif +void +send_viewgrams(const shared_ptr>& y, + const shared_ptr>& additive_binwise_correction_viewgrams, + const shared_ptr>& mult_viewgrams_sptr, const int next_receiver) { + distributed::send_view_segment_numbers(y->get_basic_view_segment_num(), NEW_VIEWGRAM_TAG, next_receiver); + distributed::send_int_value(y->get_basic_timing_pos_num(), next_receiver); + +# ifndef NDEBUG + // test sending related viegrams + shared_ptr symmetries_sptr(y->get_symmetries_ptr()->clone()); + if (distributed::test && distributed::first_iteration == true && next_receiver == 1) + distributed::test_related_viewgrams_master(y->get_proj_data_info_sptr()->create_shared_clone(), symmetries_sptr, y.get(), + next_receiver); +# endif - //TODO: this could also be done by using MPI_Probe at the slave to find out what to recieve next - if (is_null_ptr(additive_binwise_correction_viewgrams)) - { //tell slaves that recieving additive_binwise_correction_viewgrams is not needed - distributed::send_bool_value(false, BINWISE_CORRECTION_TAG, next_receiver); - } - else - { - //tell slaves to receive additive_binwise_correction_viewgrams - distributed::send_bool_value(true, BINWISE_CORRECTION_TAG, next_receiver); - distributed::send_related_viewgrams(additive_binwise_correction_viewgrams.get(), next_receiver); - } - if (is_null_ptr(mult_viewgrams_sptr)) - { - //tell slaves that recieving mult_viewgrams is not needed - distributed::send_bool_value(false, BINWISE_MULT_TAG, next_receiver); - } - else - { - //tell slaves to receive mult_viewgrams - distributed::send_bool_value(true, BINWISE_MULT_TAG, next_receiver); - distributed::send_related_viewgrams(mult_viewgrams_sptr.get(), next_receiver); - } + // TODO: this could also be done by using MPI_Probe at the slave to find out what to recieve next + if (is_null_ptr(additive_binwise_correction_viewgrams)) { // tell slaves that recieving additive_binwise_correction_viewgrams is + // not needed + distributed::send_bool_value(false, BINWISE_CORRECTION_TAG, next_receiver); + } else { + // tell slaves to receive additive_binwise_correction_viewgrams + distributed::send_bool_value(true, BINWISE_CORRECTION_TAG, next_receiver); + distributed::send_related_viewgrams(additive_binwise_correction_viewgrams.get(), next_receiver); + } + if (is_null_ptr(mult_viewgrams_sptr)) { + // tell slaves that recieving mult_viewgrams is not needed + distributed::send_bool_value(false, BINWISE_MULT_TAG, next_receiver); + } else { + // tell slaves to receive mult_viewgrams + distributed::send_bool_value(true, BINWISE_MULT_TAG, next_receiver); + distributed::send_related_viewgrams(mult_viewgrams_sptr.get(), next_receiver); + } // send y distributed::send_related_viewgrams(y.get(), next_receiver); } #endif -void distributable_computation( - const shared_ptr& forward_projector_ptr, - const shared_ptr& back_projector_ptr, - const shared_ptr& symmetries_ptr, - DiscretisedDensity<3,float>* output_image_ptr, - const DiscretisedDensity<3,float>* input_image_ptr, - const shared_ptr& proj_dat_ptr, - const bool read_from_proj_dat, - int subset_num, int num_subsets, - int min_segment_num, int max_segment_num, - bool zero_seg0_end_planes, - double* log_likelihood_ptr, - const shared_ptr& binwise_correction, - const shared_ptr normalisation_sptr, - const double start_time_of_frame, - const double end_time_of_frame, - RPC_process_related_viewgrams_type * RPC_process_related_viewgrams, - DistributedCachingInformation* caching_info_ptr) +void +distributable_computation(const shared_ptr& forward_projector_ptr, + const shared_ptr& back_projector_ptr, + const shared_ptr& symmetries_ptr, + DiscretisedDensity<3, float>* output_image_ptr, const DiscretisedDensity<3, float>* input_image_ptr, + const shared_ptr& proj_dat_ptr, const bool read_from_proj_dat, int subset_num, + int num_subsets, int min_segment_num, int max_segment_num, bool zero_seg0_end_planes, + double* log_likelihood_ptr, const shared_ptr& binwise_correction, + const shared_ptr normalisation_sptr, const double start_time_of_frame, + const double end_time_of_frame, RPC_process_related_viewgrams_type* RPC_process_related_viewgrams, + DistributedCachingInformation* caching_info_ptr, int min_timing_pos_num, int max_timing_pos_num) { -#ifdef STIR_MPI +#ifdef STIR_MPI // TODO need to differentiate depending on RPC_process_related_viewgrams int task_id; if (RPC_process_related_viewgrams == &RPC_process_related_viewgrams_accumulate_loglikelihood) - task_id=task_do_distributable_loglikelihood_computation; + task_id = task_do_distributable_loglikelihood_computation; else if (RPC_process_related_viewgrams == &RPC_process_related_viewgrams_gradient) - task_id=task_do_distributable_gradient_computation; + task_id = task_do_distributable_gradient_computation; else if (RPC_process_related_viewgrams == &RPC_process_related_viewgrams_sensitivity_computation) - task_id=task_do_distributable_sensitivity_computation; - /* else if (RPC_process_related_viewgrams == & - case - task_id=task_do_distributable_sensitivity_computation;break; - */ - else - { - error("distributable_computation: unknown RPC task"); - task_id = 0; // avoid compiler warning about "possibly unitialised" when using it - } + task_id = task_do_distributable_sensitivity_computation; + /* else if (RPC_process_related_viewgrams == & + case + task_id=task_do_distributable_sensitivity_computation;break; + */ + else { + error("distributable_computation: unknown RPC task"); + task_id = 0; // avoid compiler warning about "possibly unitialised" when using it + } distributed::send_int_value(task_id, -1); - if (caching_info_ptr != NULL) - { - distributable_computation_cache_enabled( - forward_projector_ptr, - back_projector_ptr, - symmetries_ptr, - output_image_ptr, - input_image_ptr, - proj_dat_ptr, - read_from_proj_dat, - subset_num, num_subsets, - min_segment_num, max_segment_num, - zero_seg0_end_planes, - log_likelihood_ptr, - binwise_correction, - normalisation_sptr, - start_time_of_frame, - end_time_of_frame, - RPC_process_related_viewgrams, - caching_info_ptr); - return; - } + if (caching_info_ptr != NULL) { + distributable_computation_cache_enabled( + forward_projector_ptr, back_projector_ptr, symmetries_ptr, output_image_ptr, input_image_ptr, proj_dat_ptr, + read_from_proj_dat, subset_num, num_subsets, min_segment_num, max_segment_num, zero_seg0_end_planes, log_likelihood_ptr, + binwise_correction, normalisation_sptr, start_time_of_frame, end_time_of_frame, RPC_process_related_viewgrams, + caching_info_ptr, min_timing_pos_num, max_timing_pos_num); + return; + } + // test distributed functions (see DistributedTestFunctions.h for details) - //test distributed functions (see DistributedTestFunctions.h for details) +# ifndef NDEBUG + if (distributed::test && distributed::first_iteration) { + distributed::test_image_estimate_master(input_image_ptr, 1); + distributed::test_parameter_info_master(proj_dat_ptr->get_proj_data_info_sptr()->parameter_info(), 1, "proj_data_info"); + distributed::test_bool_value_master(true, 1); + distributed::test_int_value_master(444, 1); + distributed::test_int_values_master(1); -#ifndef NDEBUG - if (distributed::test && distributed::first_iteration) - { - distributed::test_image_estimate_master(input_image_ptr, 1); - distributed::test_parameter_info_master(proj_dat_ptr->get_proj_data_info_sptr()->parameter_info(), 1, "proj_data_info"); - distributed::test_bool_value_master(true, 1); - distributed::test_int_value_master(444, 1); - distributed::test_int_values_master(1); - - Viewgram viewgram(proj_dat_ptr->get_proj_data_info_sptr()->create_shared_clone(), 44, 0); - for ( int tang_pos = viewgram.get_min_tangential_pos_num(); tang_pos <= viewgram.get_max_tangential_pos_num() ;++tang_pos) - for ( int ax_pos = viewgram.get_min_axial_pos_num(); ax_pos <= viewgram.get_max_axial_pos_num() ;++ax_pos) - viewgram[ax_pos][tang_pos]= rand(); - - distributed::test_viewgram_master(viewgram, proj_dat_ptr->get_proj_data_info_sptr()->create_shared_clone()); - } -#endif - - //send if log_likelihood_ptr is valid and so needs to be accumulated - distributed::send_bool_value(!is_null_ptr(log_likelihood_ptr),USE_DOUBLE_ARG_TAG,-1); - //send the current image estimate + Viewgram viewgram(proj_dat_ptr->get_proj_data_info_sptr()->create_shared_clone(), 44, 0); + for (int tang_pos = viewgram.get_min_tangential_pos_num(); tang_pos <= viewgram.get_max_tangential_pos_num(); ++tang_pos) + for (int ax_pos = viewgram.get_min_axial_pos_num(); ax_pos <= viewgram.get_max_axial_pos_num(); ++ax_pos) + viewgram[ax_pos][tang_pos] = rand(); + + distributed::test_viewgram_master(viewgram, proj_dat_ptr->get_proj_data_info_sptr()->create_shared_clone()); + } +# endif + + // send if log_likelihood_ptr is valid and so needs to be accumulated + distributed::send_bool_value(!is_null_ptr(log_likelihood_ptr), USE_DOUBLE_ARG_TAG, -1); + // send the current image estimate distributed::send_image_estimate(input_image_ptr, -1); - //send if output_image_ptr is valid and so needs to be accumulated - distributed::send_bool_value(!is_null_ptr(output_image_ptr),USE_OUTPUT_IMAGE_ARG_TAG,-1); - + // send if output_image_ptr is valid and so needs to be accumulated + distributed::send_bool_value(!is_null_ptr(output_image_ptr), USE_OUTPUT_IMAGE_ARG_TAG, -1); + #endif CPUTimer CPU_timer; @@ -377,35 +323,33 @@ void distributable_computation( wall_clock_timer.start(); assert(min_segment_num <= max_segment_num); - assert(subset_num >=0); + assert(min_timing_pos_num <= max_timing_pos_num); + assert(subset_num >= 0); assert(subset_num < num_subsets); - + assert(!is_null_ptr(proj_dat_ptr)); - + if (output_image_ptr != NULL) output_image_ptr->fill(0); - - if (log_likelihood_ptr != NULL) - { - (*log_likelihood_ptr) = 0.0; - }; + + if (log_likelihood_ptr != NULL) { + (*log_likelihood_ptr) = 0.0; + }; if (zero_seg0_end_planes) info("End-planes of segment 0 will be zeroed"); - const std::vector vs_nums_to_process = - detail::find_basic_vs_nums_in_subset(*proj_dat_ptr->get_proj_data_info_sptr(), *symmetries_ptr, - min_segment_num, max_segment_num, - subset_num, num_subsets); - - int count=0, count2=0; - + const std::vector vs_nums_to_process = detail::find_basic_vs_nums_in_subset( + *proj_dat_ptr->get_proj_data_info_sptr(), *symmetries_ptr, min_segment_num, max_segment_num, subset_num, num_subsets); + + int count = 0, count2 = 0; + #ifdef STIR_MPI - int sent_count=0; //counts the work packages sent - int working_slaves_count=0; //counts the number of slaves which are currently working - int next_receiver=1; //always stores the next slave to be provided with work + int sent_count = 0; // counts the work packages sent + int working_slaves_count = 0; // counts the number of slaves which are currently working + int next_receiver = 1; // always stores the next slave to be provided with work #endif - //double total_seq_rpc_time=0.0; //sums up times used for RPC_process_related_viewgrams + // double total_seq_rpc_time=0.0; //sums up times used for RPC_process_related_viewgrams forward_projector_ptr->set_input(*input_image_ptr); if (output_image_ptr != NULL) @@ -414,99 +358,90 @@ void distributable_computation( #ifdef STIR_OPENMP std::vector local_log_likelihoods; std::vector local_counts, local_count2s; -#pragma omp parallel shared(local_log_likelihoods, local_counts, local_count2s) +# pragma omp parallel shared(local_log_likelihoods, local_counts, local_count2s) #endif // start of threaded section if openmp - { + { #ifdef STIR_OPENMP -#pragma omp single +# pragma omp single { info(boost::format("Starting loop with %1% threads") % omp_get_num_threads(), 2); local_log_likelihoods.resize(omp_get_max_threads(), 0.); local_counts.resize(omp_get_max_threads(), 0); local_count2s.resize(omp_get_max_threads(), 0); } -#pragma omp for schedule(runtime) +# pragma omp for schedule(runtime) #endif - // note: older versions of openmp need an int as loop - for (int i=0; i(vs_nums_to_process.size()); ++i) - { - const ViewSegmentNumbers view_segment_num=vs_nums_to_process[i]; - - shared_ptr > y; - shared_ptr > additive_binwise_correction_viewgrams; - shared_ptr > mult_viewgrams_sptr; - - get_viewgrams(y, additive_binwise_correction_viewgrams, mult_viewgrams_sptr, - proj_dat_ptr, read_from_proj_dat, - zero_seg0_end_planes, - binwise_correction, - normalisation_sptr, start_time_of_frame, end_time_of_frame, - symmetries_ptr, view_segment_num); -#ifdef STIR_MPI - - //send viewgrams, the slave will immediatelly start calculation - send_viewgrams(y, additive_binwise_correction_viewgrams, mult_viewgrams_sptr, - next_receiver); - working_slaves_count++; - sent_count++; - - //give every slave some work before waiting for requests - if (sent_count < distributed::num_processors-1) // note: -1 as master doesn't get any viewgrams - next_receiver++; - else - { - //wait for available notification - int int_values[2]; - const MPI_Status status=distributed::receive_int_values(int_values, 2, AVAILABLE_NOTIFICATION_TAG); - next_receiver=status.MPI_SOURCE; - working_slaves_count--; - - //reduce count values - count+=int_values[0]; - count2+=int_values[1]; - } + + for (int timing_pos_num = min_timing_pos_num; timing_pos_num <= max_timing_pos_num; ++timing_pos_num) { + // note: older versions of openmp need an int as loop + for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++i) { + const ViewSegmentNumbers view_segment_num = vs_nums_to_process[i]; + + shared_ptr> y; + shared_ptr> additive_binwise_correction_viewgrams; + shared_ptr> mult_viewgrams_sptr; + + get_viewgrams(y, additive_binwise_correction_viewgrams, mult_viewgrams_sptr, proj_dat_ptr, read_from_proj_dat, + zero_seg0_end_planes, binwise_correction, normalisation_sptr, start_time_of_frame, end_time_of_frame, + symmetries_ptr, view_segment_num, timing_pos_num); +#ifdef STIR_MPI + + // send viewgrams, the slave will immediatelly start calculation + send_viewgrams(y, additive_binwise_correction_viewgrams, mult_viewgrams_sptr, next_receiver); + working_slaves_count++; + sent_count++; + + // give every slave some work before waiting for requests + if (sent_count < distributed::num_processors - 1) // note: -1 as master doesn't get any viewgrams + next_receiver++; + else { + // wait for available notification + int int_values[2]; + const MPI_Status status = distributed::receive_int_values(int_values, 2, AVAILABLE_NOTIFICATION_TAG); + next_receiver = status.MPI_SOURCE; + working_slaves_count--; + + // reduce count values + count += int_values[0]; + count2 += int_values[1]; + } #else // STIR_MPI -#ifdef STIR_OPENMP - const int thread_num=omp_get_thread_num(); - info(boost::format("Thread %d/%d calculating segment_num: %d, view_num: %d") - % thread_num % omp_get_num_threads() - % view_segment_num.segment_num() % view_segment_num.view_num(), 2); -#else - info(boost::format("calculating segment_num: %d, view_num: %d") - % view_segment_num.segment_num() % view_segment_num.view_num(), 2); -#endif +# ifdef STIR_OPENMP + const int thread_num = omp_get_thread_num(); + info(boost::format("Thread %d/%d calculating segment_num: %d, view_num: %d, timing_pos_num: %d") % thread_num % + omp_get_num_threads() % view_segment_num.segment_num() % view_segment_num.view_num() % timing_pos_num, + 2); +# else + info(boost::format("calculating segment_num: %d, view_num: %d, timing_pos_num: %d") % view_segment_num.segment_num() % + view_segment_num.view_num() % timing_pos_num, + 2); +# endif + +# ifdef STIR_OPENMP + RPC_process_related_viewgrams(forward_projector_ptr, back_projector_ptr, y.get(), local_counts[thread_num], + local_count2s[thread_num], + is_null_ptr(log_likelihood_ptr) ? NULL : &local_log_likelihoods[thread_num], + additive_binwise_correction_viewgrams.get(), mult_viewgrams_sptr.get()); + +# else + RPC_process_related_viewgrams(forward_projector_ptr, back_projector_ptr, y.get(), count, count2, log_likelihood_ptr, + additive_binwise_correction_viewgrams.get(), mult_viewgrams_sptr.get()); +# endif // OPENMP +#endif // MPI + } // end of for-loop + } // end of for-loop over timing_pos_num + } // end of parallel section of openmp -#ifdef STIR_OPENMP - RPC_process_related_viewgrams(forward_projector_ptr, - back_projector_ptr, - y.get(), - local_counts[thread_num], local_count2s[thread_num], - is_null_ptr(log_likelihood_ptr)? NULL : &local_log_likelihoods[thread_num], - additive_binwise_correction_viewgrams.get(), - mult_viewgrams_sptr.get()); - -#else - RPC_process_related_viewgrams(forward_projector_ptr, - back_projector_ptr, - y.get(), count, count2, log_likelihood_ptr, - additive_binwise_correction_viewgrams.get(), - mult_viewgrams_sptr.get()); -#endif // OPENMP -#endif // MPI - } // end of for-loop - } // end of parallel section of openmp - #ifdef STIR_OPENMP // "reduce" data constructed by threads { - if (log_likelihood_ptr != NULL) - { - for (int i=0; i(local_log_likelihoods.size()); ++i) - *log_likelihood_ptr += local_log_likelihoods[i]; // accumulate all (as they were initialised to zero) - } + if (log_likelihood_ptr != NULL) { + for (int i = 0; i < static_cast(local_log_likelihoods.size()); ++i) + *log_likelihood_ptr += local_log_likelihoods[i]; // accumulate all (as they were initialised to zero) + } count += std::accumulate(local_counts.begin(), local_counts.end(), 0); count2 += std::accumulate(local_count2s.begin(), local_count2s.end(), 0); } @@ -514,61 +449,61 @@ void distributable_computation( if (output_image_ptr != NULL) back_projector_ptr->get_output(*output_image_ptr); #ifdef STIR_MPI - //end of iteration processing + // end of iteration processing // receive remaining available notifications { - while(working_slaves_count>0) - { - int int_values[2]; - distributed::receive_int_values(int_values, 2, AVAILABLE_NOTIFICATION_TAG); - working_slaves_count--; - - //reduce count values - count+=int_values[0]; - count2+=int_values[1]; - } + while (working_slaves_count > 0) { + int int_values[2]; + distributed::receive_int_values(int_values, 2, AVAILABLE_NOTIFICATION_TAG); + working_slaves_count--; + + // reduce count values + count += int_values[0]; + count2 += int_values[1]; + } } - distributed::first_iteration=false; - - //broadcast end of iteration notification - int int_values[2]; int_values[0]=3; int_values[1]=4; // values are ignored + distributed::first_iteration = false; + + // broadcast end of iteration notification + int int_values[2]; + int_values[0] = 3; + int_values[1] = 4; // values are ignored distributed::send_int_values(int_values, 2, END_ITERATION_TAG, -1); - - //reduce output image + + // reduce output image if (!is_null_ptr(output_image_ptr)) distributed::reduce_received_output_image(output_image_ptr, 0); // and log_likelihood - if (!is_null_ptr(log_likelihood_ptr)) - { - double buffer = 0.0; - MPI_Reduce(&buffer, log_likelihood_ptr, /*size*/1, MPI_DOUBLE, MPI_SUM, /*destination*/ 0, MPI_COMM_WORLD); - } + if (!is_null_ptr(log_likelihood_ptr)) { + double buffer = 0.0; + MPI_Reduce(&buffer, log_likelihood_ptr, /*size*/ 1, MPI_DOUBLE, MPI_SUM, /*destination*/ 0, MPI_COMM_WORLD); + } + + // reduce timed rpc-value + if (distributed::rpc_time) { + printf("Master: Reducing timer value\n"); + double send = 0; + double receive; + MPI_Reduce(&send, &receive, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + distributed::total_rpc_time += (receive / (distributed::num_processors - 1)); + + printf("Average time used by slaves for RPC processing: %f secs\n", distributed::total_rpc_time); + distributed::total_rpc_time_slaves += receive; + } - //reduce timed rpc-value - if(distributed::rpc_time) - { - printf("Master: Reducing timer value\n"); - double send = 0; - double receive; - MPI_Reduce(&send, &receive, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); - distributed::total_rpc_time+=(receive/(distributed::num_processors-1)); - - printf("Average time used by slaves for RPC processing: %f secs\n", distributed::total_rpc_time); - distributed::total_rpc_time_slaves+=receive; - } - #endif { - // TODO this message relies on knowledge of count, count2 which might be inappropriate for + // TODO this message relies on knowledge of count, count2 which might be inappropriate for // the call-back function - info(boost::format("Number of (cancelled) singularities: %1%\nNumber of (cancelled) negative numerators: %2%") % count % count2); + info(boost::format("Number of (cancelled) singularities: %1%\nNumber of (cancelled) negative numerators: %2%") % count % + count2); } CPU_timer.stop(); wall_clock_timer.stop(); - info(boost::format("Computation times for distributable_computation, CPU %1%s, wall-clock %2%s") - % CPU_timer.value() % wall_clock_timer.value()); + info(boost::format("Computation times for distributable_computation, CPU %1%s, wall-clock %2%s") % CPU_timer.value() % + wall_clock_timer.value()); } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/distributableMPICacheEnabled.cxx b/src/recon_buildblock/distributableMPICacheEnabled.cxx index d8622580c2..ad66adb4bc 100644 --- a/src/recon_buildblock/distributableMPICacheEnabled.cxx +++ b/src/recon_buildblock/distributableMPICacheEnabled.cxx @@ -24,8 +24,8 @@ \brief Implementation of stir::distributable_computation_cache_enabled() \todo merge with distributable.cxx - \author Kris Thielemans - \author Alexey Zverovich + \author Kris Thielemans + \author Alexey Zverovich \author Matthew Jacobson \author PARAPET project \author Tobias Beisel @@ -33,7 +33,7 @@ /* Modification history: KT 30/05/2002 get rid of dependence on specific symmetries (i.e. views up to 45 degrees) - + TB 30/06/2007 added MPI support KT 2011 @@ -53,9 +53,9 @@ #include "stir/recon_buildblock/find_basic_vs_nums_in_subsets.h" #include "stir/info.h" #ifdef STIR_MPI -#include "stir/recon_buildblock/distributed_functions.h" -#include "stir/recon_buildblock/distributed_test_functions.h" -#include "stir/recon_buildblock/DistributedCachingInformation.h" +# include "stir/recon_buildblock/distributed_functions.h" +# include "stir/recon_buildblock/distributed_test_functions.h" +# include "stir/recon_buildblock/DistributedCachingInformation.h" #endif START_NAMESPACE_STIR @@ -64,313 +64,267 @@ START_NAMESPACE_STIR template static void -zero_end_sinograms(ViewgramsPtr viewgrams_ptr) -{ - if (!is_null_ptr(viewgrams_ptr)) - { - const int min_ax_pos_num = viewgrams_ptr->get_min_axial_pos_num(); - const int max_ax_pos_num = viewgrams_ptr->get_max_axial_pos_num(); - for (RelatedViewgrams::iterator r_viewgrams_iter = viewgrams_ptr->begin(); - r_viewgrams_iter != viewgrams_ptr->end(); - ++r_viewgrams_iter) - { - (*r_viewgrams_iter)[min_ax_pos_num].fill(0); - (*r_viewgrams_iter)[max_ax_pos_num].fill(0); - } +zero_end_sinograms(ViewgramsPtr viewgrams_ptr) { + if (!is_null_ptr(viewgrams_ptr)) { + const int min_ax_pos_num = viewgrams_ptr->get_min_axial_pos_num(); + const int max_ax_pos_num = viewgrams_ptr->get_max_axial_pos_num(); + for (RelatedViewgrams::iterator r_viewgrams_iter = viewgrams_ptr->begin(); r_viewgrams_iter != viewgrams_ptr->end(); + ++r_viewgrams_iter) { + (*r_viewgrams_iter)[min_ax_pos_num].fill(0); + (*r_viewgrams_iter)[max_ax_pos_num].fill(0); } + } } -static -void get_viewgrams(shared_ptr >& y, - shared_ptr >& additive_binwise_correction_viewgrams, - shared_ptr >& mult_viewgrams_sptr, - const shared_ptr& proj_dat_ptr, - const bool read_from_proj_dat, - const bool zero_seg0_end_planes, - const shared_ptr& binwise_correction, - const shared_ptr& normalisation_sptr, - const double start_time_of_frame, - const double end_time_of_frame, - const shared_ptr& symmetries_ptr, - const ViewSegmentNumbers& view_segment_num - ) -{ - if (!is_null_ptr(binwise_correction)) - { -#if !defined(_MSC_VER) || _MSC_VER>1300 - additive_binwise_correction_viewgrams.reset( - new RelatedViewgrams - (binwise_correction->get_related_viewgrams(view_segment_num, symmetries_ptr))); +static void +get_viewgrams(shared_ptr>& y, shared_ptr>& additive_binwise_correction_viewgrams, + shared_ptr>& mult_viewgrams_sptr, const shared_ptr& proj_dat_ptr, + const bool read_from_proj_dat, const bool zero_seg0_end_planes, const shared_ptr& binwise_correction, + const shared_ptr& normalisation_sptr, const double start_time_of_frame, + const double end_time_of_frame, const shared_ptr& symmetries_ptr, + const ViewSegmentNumbers& view_segment_num, const int timing_pos_num) { + if (!is_null_ptr(binwise_correction)) { +#if !defined(_MSC_VER) || _MSC_VER > 1300 + additive_binwise_correction_viewgrams.reset(new RelatedViewgrams( + binwise_correction->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); #else - RelatedViewgrams tmp(binwise_correction-> - get_related_viewgrams(view_segment_num, symmetries_ptr)); - additive_binwise_correction_viewgrams = new RelatedViewgrams(tmp); -#endif - } - - if (read_from_proj_dat) - { -#if !defined(_MSC_VER) || _MSC_VER>1300 - y.reset(new RelatedViewgrams - (proj_dat_ptr->get_related_viewgrams(view_segment_num, symmetries_ptr))); + RelatedViewgrams tmp( + binwise_correction->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num)); + additive_binwise_correction_viewgrams = new RelatedViewgrams(tmp); +#endif + } + + if (read_from_proj_dat) { +#if !defined(_MSC_VER) || _MSC_VER > 1300 + y.reset(new RelatedViewgrams( + proj_dat_ptr->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); #else - // workaround VC++ 6.0 bug - RelatedViewgrams tmp(proj_dat_ptr-> - get_related_viewgrams(view_segment_num, symmetries_ptr)); - y = new RelatedViewgrams(tmp); -#endif - } - else - { - y.reset(new RelatedViewgrams - (proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr))); - } + // workaround VC++ 6.0 bug + RelatedViewgrams tmp(proj_dat_ptr->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num)); + y = new RelatedViewgrams(tmp); +#endif + } else { + y.reset(new RelatedViewgrams( + proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); + } // multiplicative correction - if (!is_null_ptr(normalisation_sptr) && !normalisation_sptr->is_trivial()) - { - mult_viewgrams_sptr.reset( - new RelatedViewgrams(proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr))); - mult_viewgrams_sptr->fill(1.F); - normalisation_sptr->undo(*mult_viewgrams_sptr,start_time_of_frame,end_time_of_frame); - } - - if (view_segment_num.segment_num()==0 && zero_seg0_end_planes) - { - zero_end_sinograms(y); - zero_end_sinograms(additive_binwise_correction_viewgrams); - zero_end_sinograms(mult_viewgrams_sptr); - } + if (!is_null_ptr(normalisation_sptr) && !normalisation_sptr->is_trivial()) { + mult_viewgrams_sptr.reset(new RelatedViewgrams( + proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); + mult_viewgrams_sptr->fill(1.F); + normalisation_sptr->undo(*mult_viewgrams_sptr, start_time_of_frame, end_time_of_frame); + } + + if (view_segment_num.segment_num() == 0 && zero_seg0_end_planes) { + zero_end_sinograms(y); + zero_end_sinograms(additive_binwise_correction_viewgrams); + zero_end_sinograms(mult_viewgrams_sptr); + } } -static void send_viewgrams(const shared_ptr >& y, - const shared_ptr >& additive_binwise_correction_viewgrams, - const shared_ptr >& mult_viewgrams_sptr, - const int next_receiver) -{ - distributed::send_view_segment_numbers( y->get_basic_view_segment_num(), NEW_VIEWGRAM_TAG, next_receiver); +static void +send_viewgrams(const shared_ptr>& y, + const shared_ptr>& additive_binwise_correction_viewgrams, + const shared_ptr>& mult_viewgrams_sptr, const int next_receiver) { + distributed::send_view_segment_numbers(y->get_basic_view_segment_num(), NEW_VIEWGRAM_TAG, next_receiver); + distributed::send_int_value(y->get_basic_timing_pos_num(), next_receiver); #ifndef NDEBUG - //test sending related viewgrams - shared_ptr - symmetries_sptr(y->get_symmetries_ptr()->clone()); - if (distributed::test && distributed::first_iteration==true && next_receiver==1) - distributed::test_related_viewgrams_master(y->get_proj_data_info_sptr()->create_shared_clone(), - symmetries_sptr, y.get(), next_receiver); + // test sending related viewgrams + shared_ptr symmetries_sptr(y->get_symmetries_ptr()->clone()); + if (distributed::test && distributed::first_iteration == true && next_receiver == 1) + distributed::test_related_viewgrams_master(y->get_proj_data_info_sptr()->create_shared_clone(), symmetries_sptr, y.get(), + next_receiver); #endif - //TODO: this could also be done by using MPI_Probe at the slave to find out what to recieve next - if (is_null_ptr(additive_binwise_correction_viewgrams)) - { //tell slaves that recieving additive_binwise_correction_viewgrams is not needed - distributed::send_bool_value(false, BINWISE_CORRECTION_TAG, next_receiver); - } - else - { - //tell slaves to receive additive_binwise_correction_viewgrams - distributed::send_bool_value(true, BINWISE_CORRECTION_TAG, next_receiver); - distributed::send_related_viewgrams(additive_binwise_correction_viewgrams.get(), next_receiver); - } - if (is_null_ptr(mult_viewgrams_sptr)) - { - //tell slaves that recieving mult_viewgrams is not needed - distributed::send_bool_value(false, BINWISE_MULT_TAG, next_receiver); - } - else - { - //tell slaves to receive mult_viewgrams - distributed::send_bool_value(true, BINWISE_MULT_TAG, next_receiver); - distributed::send_related_viewgrams(mult_viewgrams_sptr.get(), next_receiver); - } + // TODO: this could also be done by using MPI_Probe at the slave to find out what to recieve next + if (is_null_ptr(additive_binwise_correction_viewgrams)) { // tell slaves that recieving additive_binwise_correction_viewgrams is + // not needed + distributed::send_bool_value(false, BINWISE_CORRECTION_TAG, next_receiver); + } else { + // tell slaves to receive additive_binwise_correction_viewgrams + distributed::send_bool_value(true, BINWISE_CORRECTION_TAG, next_receiver); + distributed::send_related_viewgrams(additive_binwise_correction_viewgrams.get(), next_receiver); + } + if (is_null_ptr(mult_viewgrams_sptr)) { + // tell slaves that recieving mult_viewgrams is not needed + distributed::send_bool_value(false, BINWISE_MULT_TAG, next_receiver); + } else { + // tell slaves to receive mult_viewgrams + distributed::send_bool_value(true, BINWISE_MULT_TAG, next_receiver); + distributed::send_related_viewgrams(mult_viewgrams_sptr.get(), next_receiver); + } // send y distributed::send_related_viewgrams(y.get(), next_receiver); } -void distributable_computation_cache_enabled( - const shared_ptr& forward_projector_ptr, - const shared_ptr& back_projector_ptr, - const shared_ptr& symmetries_ptr, - DiscretisedDensity<3,float>* output_image_ptr, - const DiscretisedDensity<3,float>* input_image_ptr, - const shared_ptr& proj_dat_ptr, - const bool read_from_proj_dat, - int subset_num, int num_subsets, - int min_segment_num, int max_segment_num, - bool zero_seg0_end_planes, - double* log_likelihood_ptr, - const shared_ptr& binwise_correction, - const shared_ptr normalise_sptr, - const double start_time_of_frame, - const double end_time_of_frame, - RPC_process_related_viewgrams_type * RPC_process_related_viewgrams, - DistributedCachingInformation* caching_info_ptr - ) -{ - //test distributed functions (see DistributedTestFunctions.h for details) +void +distributable_computation_cache_enabled( + const shared_ptr& forward_projector_ptr, const shared_ptr& back_projector_ptr, + const shared_ptr& symmetries_ptr, DiscretisedDensity<3, float>* output_image_ptr, + const DiscretisedDensity<3, float>* input_image_ptr, const shared_ptr& proj_dat_ptr, const bool read_from_proj_dat, + int subset_num, int num_subsets, int min_segment_num, int max_segment_num, bool zero_seg0_end_planes, + double* log_likelihood_ptr, const shared_ptr& binwise_correction, const shared_ptr normalise_sptr, + const double start_time_of_frame, const double end_time_of_frame, + RPC_process_related_viewgrams_type* RPC_process_related_viewgrams, DistributedCachingInformation* caching_info_ptr, + int min_timing_pos_num, int max_timing_pos_num) { + // test distributed functions (see DistributedTestFunctions.h for details) #ifndef NDEBUG - if (distributed::test && distributed::first_iteration) - { - distributed::test_image_estimate_master(input_image_ptr, 1); - distributed::test_parameter_info_master(proj_dat_ptr->get_proj_data_info_sptr()->parameter_info(), 1, "proj_data_info"); - distributed::test_bool_value_master(true, 1); - distributed::test_int_value_master(444, 1); - distributed::test_int_values_master(1); - - Viewgram viewgram(proj_dat_ptr->get_proj_data_info_sptr()->create_shared_clone(), 44, 0); - for ( int tang_pos = viewgram.get_min_tangential_pos_num(); tang_pos <= viewgram.get_max_tangential_pos_num() ;++tang_pos) - for ( int ax_pos = viewgram.get_min_axial_pos_num(); ax_pos <= viewgram.get_max_axial_pos_num() ;++ax_pos) - viewgram[ax_pos][tang_pos]= rand(); - - distributed::test_viewgram_master(viewgram, proj_dat_ptr->get_proj_data_info_sptr()->create_shared_clone()); - } + if (distributed::test && distributed::first_iteration) { + distributed::test_image_estimate_master(input_image_ptr, 1); + distributed::test_parameter_info_master(proj_dat_ptr->get_proj_data_info_sptr()->parameter_info(), 1, "proj_data_info"); + distributed::test_bool_value_master(true, 1); + distributed::test_int_value_master(444, 1); + distributed::test_int_values_master(1); + + Viewgram viewgram(proj_dat_ptr->get_proj_data_info_sptr()->create_shared_clone(), 44, 0); + for (int tang_pos = viewgram.get_min_tangential_pos_num(); tang_pos <= viewgram.get_max_tangential_pos_num(); ++tang_pos) + for (int ax_pos = viewgram.get_min_axial_pos_num(); ax_pos <= viewgram.get_max_axial_pos_num(); ++ax_pos) + viewgram[ax_pos][tang_pos] = rand(); + + distributed::test_viewgram_master(viewgram, proj_dat_ptr->get_proj_data_info_sptr()->create_shared_clone()); + } #endif - - //send if log_likelihood_ptr is valid and so needs to be accumulated - distributed::send_bool_value(!is_null_ptr(log_likelihood_ptr),USE_DOUBLE_ARG_TAG,-1); - //send the current image estimate + + // send if log_likelihood_ptr is valid and so needs to be accumulated + distributed::send_bool_value(!is_null_ptr(log_likelihood_ptr), USE_DOUBLE_ARG_TAG, -1); + // send the current image estimate distributed::send_image_estimate(input_image_ptr, -1); - //send if output_image_ptr is valid and so needs to be accumulated - distributed::send_bool_value(!is_null_ptr(output_image_ptr),USE_OUTPUT_IMAGE_ARG_TAG,-1); - + // send if output_image_ptr is valid and so needs to be accumulated + distributed::send_bool_value(!is_null_ptr(output_image_ptr), USE_OUTPUT_IMAGE_ARG_TAG, -1); + assert(min_segment_num <= max_segment_num); - assert(subset_num >=0); + assert(min_timing_pos_num <= max_timing_pos_num); + assert(subset_num >= 0); assert(subset_num < num_subsets); - - assert(!is_null_ptr(proj_dat_ptr)); + + assert(!is_null_ptr(proj_dat_ptr)); if (output_image_ptr != NULL) output_image_ptr->fill(0); - - if (log_likelihood_ptr != NULL) - { - (*log_likelihood_ptr) = 0.0; - }; - + + if (log_likelihood_ptr != NULL) { + (*log_likelihood_ptr) = 0.0; + }; + // needed for several send/receive operations int int_values[2]; - - int working_slaves_count=0; //counts the number of slaves which are currently working - int next_receiver=1; //always stores the next slave to be provided with work - - int count=0, count2=0; - - const std::vector vs_nums_to_process = - detail::find_basic_vs_nums_in_subset(*proj_dat_ptr->get_proj_data_info_sptr(), *symmetries_ptr, - min_segment_num, max_segment_num, - subset_num, num_subsets); - - const std::size_t num_vs = vs_nums_to_process.size(); - + + int working_slaves_count = 0; // counts the number of slaves which are currently working + int next_receiver = 1; // always stores the next slave to be provided with work + + int count = 0, count2 = 0; + + const std::vector vs_nums_to_process = detail::find_basic_vs_nums_in_subset( + *proj_dat_ptr->get_proj_data_info_sptr(), *symmetries_ptr, min_segment_num, max_segment_num, subset_num, num_subsets); + + const std::size_t num_vs = vs_nums_to_process.size(); + CPUTimer iteration_timer; iteration_timer.start(); - - //initialize the caching values for the new iteration + + // initialize the caching values for the new iteration caching_info_ptr->initialise_new_subiteration(vs_nums_to_process); - - //while not all vs_nums are processed repeat - for (std::size_t processed_count = 1; processed_count <= num_vs; ++processed_count) - { - ViewSegmentNumbers view_segment_num; - - //check whether the slave will receive a new or an already cached viewgram - const bool new_viewgrams = - caching_info_ptr->get_unprocessed_vs_num(view_segment_num, next_receiver); - // view_segment_num = vs_nums_to_process[processed_count-1]; - - //the slave has not yet processed this vs_num, so the viewgrams have to be sent - if (new_viewgrams==true) - { - info(boost::format("Sending segment %1%, view %2% to slave %3%\n") % view_segment_num.segment_num() % view_segment_num.view_num() % next_receiver); - - shared_ptr > y; - shared_ptr > additive_binwise_correction_viewgrams; - shared_ptr > mult_viewgrams_sptr; - - get_viewgrams(y, additive_binwise_correction_viewgrams, mult_viewgrams_sptr, - proj_dat_ptr, read_from_proj_dat, - zero_seg0_end_planes, - binwise_correction, - normalise_sptr, start_time_of_frame, end_time_of_frame, - symmetries_ptr, view_segment_num); - - //send viewgrams, the slave will immediatelly start calculation - send_viewgrams(y, additive_binwise_correction_viewgrams, mult_viewgrams_sptr, - next_receiver); - } // if(new_viewgram) - else - { - info(boost::format("Re-using segment %1%, view %2% to slave %3%\n") % view_segment_num.segment_num() % view_segment_num.view_num() % next_receiver); - //send vs_num with reuse-tag, the slave will immediatelly start calculation - distributed::send_view_segment_numbers( view_segment_num, REUSE_VIEWGRAM_TAG, next_receiver); - } + + // while not all vs_nums are processed repeat + for (std::size_t processed_count = 1; processed_count <= num_vs; ++processed_count) { + ViewSegmentNumbers view_segment_num; + + // check whether the slave will receive a new or an already cached viewgram + const bool new_viewgrams = caching_info_ptr->get_unprocessed_vs_num(view_segment_num, next_receiver); + // view_segment_num = vs_nums_to_process[processed_count-1]; + + for (int timing_pos_num = min_timing_pos_num; timing_pos_num <= max_timing_pos_num; ++timing_pos_num) { + + // the slave has not yet processed this vs_num, so the viewgrams have to be sent + if (new_viewgrams == true) { + info(boost::format("Sending segment %1%, view %2%, TOF bin %3% to slave %4%\n") % view_segment_num.segment_num() % + view_segment_num.view_num() % timing_pos_num % next_receiver); + + shared_ptr> y; + shared_ptr> additive_binwise_correction_viewgrams; + shared_ptr> mult_viewgrams_sptr; + + get_viewgrams(y, additive_binwise_correction_viewgrams, mult_viewgrams_sptr, proj_dat_ptr, read_from_proj_dat, + zero_seg0_end_planes, binwise_correction, normalise_sptr, start_time_of_frame, end_time_of_frame, + symmetries_ptr, view_segment_num, timing_pos_num); + + // send viewgrams, the slave will immediatelly start calculation + send_viewgrams(y, additive_binwise_correction_viewgrams, mult_viewgrams_sptr, next_receiver); + } // if(new_viewgram) + else { + info(boost::format("Re-using segment %1%, view %2%, TOF bin %3% to slave %4%\n") % view_segment_num.segment_num() % + view_segment_num.view_num() % timing_pos_num % next_receiver); + // send vs_num with reuse-tag, the slave will immediatelly start calculation + distributed::send_view_segment_numbers(view_segment_num, REUSE_VIEWGRAM_TAG, next_receiver); + } working_slaves_count++; - - if (int(processed_count) 0) - { - status=distributed::receive_int_values(int_values, 2, AVAILABLE_NOTIFICATION_TAG); - working_slaves_count--; - - //reduce count values - count+=int_values[0]; - count2+=int_values[1]; + + if (int(processed_count) < distributed::num_processors - 1) // note: -1 as master doesn't get any viewgrams + { + // give every slave some work before waiting for requests + next_receiver++; + } else { + const MPI_Status status = distributed::receive_int_values(int_values, 2, AVAILABLE_NOTIFICATION_TAG); + next_receiver = status.MPI_SOURCE; + working_slaves_count--; + + // reduce count values + count += int_values[0]; + count2 += int_values[1]; + } } - + } // end loop over vs_nums + + distributed::first_iteration = false; + + // receive remaining available notifications + MPI_Status status; + while (working_slaves_count > 0) { + status = distributed::receive_int_values(int_values, 2, AVAILABLE_NOTIFICATION_TAG); + working_slaves_count--; + + // reduce count values + count += int_values[0]; + count2 += int_values[1]; + } + // in the cache-enabled distributed case, this message is only printed once per iteration - // TODO this message relies on knowledge of count, count2 which might be inappropriate for + // TODO this message relies on knowledge of count, count2 which might be inappropriate for // the call-back function #ifndef STIR_NO_RUNNING_LOG - info(boost::format("\tNumber of (cancelled) singularities: %1%\n\tNumber of (cancelled) negative numerators: %2%\n\tIteration: %3%secs\n") % count % count2 % iteration_timer.value()); + info(boost::format("\tNumber of (cancelled) singularities: %1%\n\tNumber of (cancelled) negative numerators: %2%\n\tIteration: " + "%3%secs\n") % + count % count2 % iteration_timer.value()); #endif - - int_values[0]=3; - int_values[1]=4; - - //send end_iteration notification + + int_values[0] = 3; + int_values[1] = 4; + + // send end_iteration notification distributed::send_int_values(int_values, 2, END_ITERATION_TAG, -1); - - //reduce output image + + // reduce output image if (!is_null_ptr(output_image_ptr)) distributed::reduce_received_output_image(output_image_ptr, 0); // and log_likelihood - if (!is_null_ptr(log_likelihood_ptr)) - { - double buffer = 0.0; - MPI_Reduce(&buffer, log_likelihood_ptr, /*size*/1, MPI_DOUBLE, MPI_SUM, /*destination*/ 0, MPI_COMM_WORLD); - } - - //reduce timed rpc-value - if(distributed::rpc_time) - { - printf("Master: Reducing timer value\n"); - double send = 0; - double receive; - MPI_Reduce(&send, &receive, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); - distributed::total_rpc_time+=(receive/(distributed::num_processors-1)); - - printf("Average time used by slaves for RPC processing: %f secs\n", distributed::total_rpc_time); - distributed::total_rpc_time_slaves+=receive; - } - + if (!is_null_ptr(log_likelihood_ptr)) { + double buffer = 0.0; + MPI_Reduce(&buffer, log_likelihood_ptr, /*size*/ 1, MPI_DOUBLE, MPI_SUM, /*destination*/ 0, MPI_COMM_WORLD); + } + + // reduce timed rpc-value + if (distributed::rpc_time) { + printf("Master: Reducing timer value\n"); + double send = 0; + double receive; + MPI_Reduce(&send, &receive, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + distributed::total_rpc_time += (receive / (distributed::num_processors - 1)); + + printf("Average time used by slaves for RPC processing: %f secs\n", distributed::total_rpc_time); + distributed::total_rpc_time_slaves += receive; + } } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/distributed_functions.cxx b/src/recon_buildblock/distributed_functions.cxx index 5d195f2791..d81b1425d3 100644 --- a/src/recon_buildblock/distributed_functions.cxx +++ b/src/recon_buildblock/distributed_functions.cxx @@ -22,7 +22,7 @@ \brief Implementation of functions in distributed namespace - \author Tobias Beisel + \author Tobias Beisel \author Kris Thielemans */ @@ -41,764 +41,885 @@ using std::ios; -namespace distributed -{ - //timings and tests - bool rpc_time=false; - bool test_send_receive_times=false; - - double total_rpc_time=0; - double min_threshold=0.1; - double total_rpc_time_slaves=0.0; - double total_rpc_time_2=0.0; - bool test=false; - - - //global variable often used - int num_processors; - int length; - - int processor; - bool first_iteration; - int iteration_counter=0; - int image_buffer_size; - MPI_Status status; - float parameters[6]; //array for receiving image parameters - int sizes[6]; //array for receiving image dimensions - - stir::HighResWallClockTimer t; - - - //--------------------------------------Send Operations------------------------------------- - - void send_int_value(int value, int destination) - { - int i = value; +namespace distributed { +// timings and tests +bool rpc_time = false; +bool test_send_receive_times = false; + +double total_rpc_time = 0; +double min_threshold = 0.1; +double total_rpc_time_slaves = 0.0; +double total_rpc_time_2 = 0.0; +bool test = false; + +// global variable often used +int num_processors; +int length; + +int processor; +bool first_iteration; +int iteration_counter = 0; +int image_buffer_size; +MPI_Status status; +float parameters[6]; // array for receiving image parameters +int sizes[6]; // array for receiving image dimensions -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} +stir::HighResWallClockTimer t; + +//--------------------------------------Send Operations------------------------------------- + +void +send_int_value(int value, int destination) { + int i = value; + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - - if (destination == -1) MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD); - else MPI_Send(&i, 1, MPI_INT, destination, INT_TAG, MPI_COMM_WORLD); -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Master/Slave: sending int value took " << t.value() << " seconds" << std::endl; + if (destination == -1) + MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD); + else + MPI_Send(&i, 1, MPI_INT, destination, INT_TAG, MPI_COMM_WORLD); + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master/Slave: sending int value took " << t.value() << " seconds" << std::endl; #endif +} + +void +send_string(const std::string& str, int tag, int destination) { + // prepare sending parameter info + length = str.length() + 1; + char* buf = new char[length]; + strcpy(buf, str.c_str()); + + // send parameter info +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); } - - void send_string(const std::string& str, int tag, int destination) - { - //prepare sending parameter info - length=str.length()+1; - char * buf= new char[length]; - strcpy(buf, str.c_str()); - - //send parameter info -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} -#endif - - if (destination == -1) - for (int processor=1; processormin_threshold) std::cout << "Master/Slave: sending string took " << t.value() << " seconds" << std::endl; -#endif - - delete[] buf; +#endif + + if (destination == -1) + for (int processor = 1; processor < num_processors; processor++) { + MPI_Send(&length, 1, MPI_INT, processor, tag, MPI_COMM_WORLD); + MPI_Send(buf, length, MPI_CHAR, processor, tag, MPI_COMM_WORLD); + } + else { + MPI_Send(&length, 1, MPI_INT, destination, tag, MPI_COMM_WORLD); + MPI_Send(buf, length, MPI_CHAR, destination, tag, MPI_COMM_WORLD); } - - void send_bool_value(bool value, int tag, int destination) - { - int i; - if (value==true) i=1; - else i=0; - + #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master/Slave: sending string took " << t.value() << " seconds" << std::endl; #endif - - if (destination==-1||tag ==-1) MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD); - else MPI_Send(&i, 1, MPI_INT, destination, tag, MPI_COMM_WORLD); - + + delete[] buf; +} + +void +send_bool_value(bool value, int tag, int destination) { + int i; + if (value == true) + i = 1; + else + i = 0; + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); + } +#endif + + if (destination == -1 || tag == -1) + MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD); + else + MPI_Send(&i, 1, MPI_INT, destination, tag, MPI_COMM_WORLD); + #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Master/Slave: sending bool value took " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master/Slave: sending bool value took " << t.value() << " seconds" << std::endl; #endif +} +void +send_int_values(int* values, int count, int tag, int destination) { +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); } - - void send_int_values(int * values, int count, int tag, int destination) - { +#endif + + if (destination == -1) { + for (processor = 1; processor < num_processors; processor++) + MPI_Send(values, count, MPI_INT, processor, tag, MPI_COMM_WORLD); + } else + MPI_Send(values, count, MPI_INT, destination, tag, MPI_COMM_WORLD); + #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) + t.stop(); + int my_rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); /*Gets the rank of the Processor*/ + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master/Slave " << my_rank << ": sending int values took " << t.value() << " seconds" << std::endl; #endif - - if (destination == -1) - { - for (processor=1; processormin_threshold) std::cout << "Master/Slave " << my_rank << ": sending int values took " << t.value() << " seconds"<< std::endl; + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif + if (destination == -1) { + for (processor = 1; processor < num_processors; processor++) + MPI_Send(values, count, MPI_DOUBLE, processor, tag, MPI_COMM_WORLD); + } else + MPI_Send(values, count, MPI_DOUBLE, destination, tag, MPI_COMM_WORLD); + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master: sending double values took " << t.value() << " seconds" << std::endl; +#endif +} + +void +send_view_segment_numbers(const stir::ViewSegmentNumbers& vs_num, int tag, int destination) { + int int_values[2]; + int_values[0] = vs_num.view_num(); + int_values[1] = vs_num.segment_num(); + distributed::send_int_values(int_values, 2, tag, destination); +} + +void +send_image_parameters(const stir::DiscretisedDensity<3, float>* input_image_ptr, int tag, int destination) { + // cast to allow getting image dimensions and grid_spacing + const stir::VoxelsOnCartesianGrid* image = dynamic_cast*>(input_image_ptr); + + // input_image dimensions + int sizes[6]; + sizes[0] = image->get_min_x(); + sizes[1] = image->get_min_y(); + sizes[2] = image->get_min_z(); + sizes[3] = image->get_max_x(); + sizes[4] = image->get_max_y(); + sizes[5] = image->get_max_z(); + + // buffer for input_image-array + image_buffer_size = (sizes[3] - sizes[0] + 1) * (sizes[4] - sizes[1] + 1) * (sizes[5] - sizes[2] + 1); + + // get origin of input_image_ptr + stir::CartesianCoordinate3D origin = input_image_ptr->get_origin(); + + // get grid_spacing of input_image_ptr + stir::CartesianCoordinate3D grid_spacing = image->get_grid_spacing(); + + float parameters[6]; + parameters[0] = origin.x(); + parameters[1] = origin.y(); + parameters[2] = origin.z(); + parameters[3] = grid_spacing.x(); + parameters[4] = grid_spacing.y(); + parameters[5] = grid_spacing.z(); + + // Sending image parameters +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); } - - void send_double_values(double * values, int count, int tag, int destination) - { +#endif + if (tag == -1 || destination == -1) + MPI_Bcast(parameters, 6, MPI_FLOAT, 0, MPI_COMM_WORLD); + else + MPI_Send(parameters, 6, MPI_FLOAT, destination, tag, MPI_COMM_WORLD); + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master/Slave: sending image parameters took " << t.value() << " seconds" << std::endl; +#endif + + // send dimensions to construct IndexRange-object #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - - if (destination == -1) - { - for (processor=1; processormin_threshold) std::cout << "Master: sending double values took " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master/Slave: sending image dimensions took " << t.value() << " seconds" << std::endl; #endif +} + +void +send_image_estimate(const stir::DiscretisedDensity<3, float>* input_image_ptr, int destination) { + float* image_buf = new float[image_buffer_size]; + + // serialize input_image into 1-demnsional array + std::copy(input_image_ptr->begin_all(), input_image_ptr->end_all(), image_buf); + + // send input image +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); } +#endif - void send_view_segment_numbers(const stir::ViewSegmentNumbers& vs_num, int tag, int destination) - { - int int_values[2]; - int_values[0]=vs_num.view_num(); - int_values[1]=vs_num.segment_num(); - distributed::send_int_values(int_values, 2, tag, destination); + if (destination == -1) { + MPI_Bcast(image_buf, image_buffer_size, MPI_FLOAT, 0, MPI_COMM_WORLD); + // for (int processor=1; processor min_threshold) + std::cout << "Master/Slave: sending image values took " << t.value() << " seconds" << std::endl; +#endif +} + +void +send_exam_and_proj_data_info(const stir::ExamInfo& exam_info, const stir::ProjDataInfo& proj_data_info, int destination) { + // KT TODO there must be a better way than writing to a temporary file on disk + stir::shared_ptr exam_info_sptr(new stir::ExamInfo(exam_info)); + stir::ProjDataInterfile projection_data_for_slave(exam_info_sptr, proj_data_info.create_shared_clone(), "for_slave"); + + std::ifstream is("for_slave.hs", ios::binary); + + // get length of file: + is.seekg(0, ios::end); + length = is.tellg(); + is.seekg(0, ios::beg); + + length++; + + char* file_buffer = new char[length]; + + // read data as a block: + is.read(file_buffer, length - 1); + is.close(); + file_buffer[length - 1] = '\0'; + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); } +#endif - void send_image_parameters(const stir::DiscretisedDensity<3,float>* input_image_ptr, int tag, int destination) - { - //cast to allow getting image dimensions and grid_spacing - const stir::VoxelsOnCartesianGrid* image = - dynamic_cast* >(input_image_ptr); - - //input_image dimensions - int sizes[6]; - sizes[0] = image->get_min_x(); - sizes[1] = image->get_min_y(); - sizes[2] = image->get_min_z(); - sizes[3] = image->get_max_x(); - sizes[4] = image->get_max_y(); - sizes[5] = image->get_max_z(); - - //buffer for input_image-array - image_buffer_size=(sizes[3]-sizes[0]+1)*(sizes[4]-sizes[1]+1)*(sizes[5]-sizes[2]+1); - - //get origin of input_image_ptr - stir::CartesianCoordinate3D origin = input_image_ptr->get_origin(); - - //get grid_spacing of input_image_ptr - stir::CartesianCoordinate3D grid_spacing = image->get_grid_spacing(); - - float parameters[6]; - parameters[0] = origin.x(); - parameters[1] = origin.y(); - parameters[2] = origin.z(); - parameters[3] = grid_spacing.x(); - parameters[4] = grid_spacing.y(); - parameters[5] = grid_spacing.z(); - - - //Sending image parameters -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} -#endif - - if (tag == -1 || destination == -1) MPI_Bcast(parameters, 6, MPI_FLOAT, 0, MPI_COMM_WORLD); - else MPI_Send(parameters, 6, MPI_FLOAT, destination, tag, MPI_COMM_WORLD); - -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Master/Slave: sending image parameters took " << t.value() << " seconds" << std::endl; -#endif - - //send dimensions to construct IndexRange-object -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} -#endif - - if (tag == -1 || destination == -1) MPI_Bcast(sizes, 6, MPI_INT, 0, MPI_COMM_WORLD); - else MPI_Send(sizes, 6, MPI_INT, destination, tag, MPI_COMM_WORLD); - -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Master/Slave: sending image dimensions took " << t.value() << " seconds" << std::endl; -#endif - + // send text_buffer + if (destination == -1) + for (processor = 1; processor < num_processors; processor++) { + MPI_Send(&length, 1, MPI_INT, processor, PROJECTION_DATA_INFO_TAG, MPI_COMM_WORLD); + MPI_Send(file_buffer, length, MPI_CHAR, processor, PROJECTION_DATA_INFO_TAG, MPI_COMM_WORLD); + } + else { + MPI_Send(&length, 1, MPI_INT, destination, PROJECTION_DATA_INFO_TAG, MPI_COMM_WORLD); + MPI_Send(file_buffer, length, MPI_CHAR, destination, PROJECTION_DATA_INFO_TAG, MPI_COMM_WORLD); } - - void send_image_estimate(const stir::DiscretisedDensity<3,float>* input_image_ptr, int destination) - { - float *image_buf = new float[image_buffer_size]; - - //serialize input_image into 1-demnsional array - std::copy(input_image_ptr->begin_all(), input_image_ptr->end_all(), image_buf); - - //send input image -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} -#endif - - if (destination == -1) - { - MPI_Bcast(image_buf, image_buffer_size, MPI_FLOAT, 0, MPI_COMM_WORLD); - //for (int processor=1; processormin_threshold) std::cout << "Master/Slave: sending image values took " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master: sending projection_data_info took " << t.value() << " seconds" << std::endl; #endif + + if (remove("for_slave.hs") != 0) + stir::warning("Error deleting temporary file"); + if (remove("for_slave.s") != 0) + stir::warning("Error deleting temporary file"); + + delete[] file_buffer; +} + +void +send_related_viewgrams(stir::RelatedViewgrams* viewgrams, int destination) { + // broadcast count of viewgrams to be received + int num_viewgrams = viewgrams->get_num_viewgrams(); + + // run through viewgrams + stir::RelatedViewgrams::iterator viewgrams_iter = viewgrams->begin(); + const stir::RelatedViewgrams::iterator viewgrams_end = viewgrams->end(); + + send_int_values(&num_viewgrams, 1, VIEWGRAM_COUNT_TAG, destination); + + while (viewgrams_iter != viewgrams_end) { + send_viewgram(*viewgrams_iter, destination); + ++viewgrams_iter; } - - void send_exam_and_proj_data_info(const stir::ExamInfo& exam_info, const stir::ProjDataInfo& proj_data_info, int destination) - { - // KT TODO there must be a better way than writing to a temporary file on disk - stir::shared_ptr exam_info_sptr(new stir::ExamInfo(exam_info)); - stir::ProjDataInterfile projection_data_for_slave(exam_info_sptr, proj_data_info.create_shared_clone(),"for_slave"); - - std::ifstream is("for_slave.hs", ios::binary ); - - // get length of file: - is.seekg (0, ios::end); - length = is.tellg(); - is.seekg (0, ios::beg); - - length++; - - char * file_buffer = new char[length]; - - // read data as a block: - is.read (file_buffer,length-1); - is.close(); - file_buffer[length-1]='\0'; - -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} -#endif - - //send text_buffer - if (destination==-1) - for (processor=1; processormin_threshold) std::cout << "Master: sending projection_data_info took " << t.value() << " seconds" << std::endl; -#endif - - - if( remove( "for_slave.hs" ) != 0 ) - stir::warning( "Error deleting temporary file" ); - if( remove( "for_slave.s" ) != 0 ) - stir::warning( "Error deleting temporary file" ); - - delete[] file_buffer; - } - - void send_related_viewgrams(stir::RelatedViewgrams* viewgrams, int destination) - { - //broadcast count of viewgrams to be received - int num_viewgrams=viewgrams->get_num_viewgrams(); - - //run through viewgrams - stir::RelatedViewgrams::iterator viewgrams_iter = viewgrams->begin(); - const stir::RelatedViewgrams::iterator viewgrams_end = viewgrams->end(); - - send_int_values(&num_viewgrams, 1, VIEWGRAM_COUNT_TAG, destination); - - while (viewgrams_iter!= viewgrams_end) - { - send_viewgram(*viewgrams_iter, destination); - ++viewgrams_iter; - } +} + +void +send_viewgram(const stir::Viewgram& viewgram, int destination) { + // send dimensions of viewgram (axial and tangential positions and the view and segment numbers) + int viewgram_values[7]; + viewgram_values[0] = viewgram.get_min_axial_pos_num(); + viewgram_values[1] = viewgram.get_max_axial_pos_num(); + viewgram_values[2] = viewgram.get_min_tangential_pos_num(); + viewgram_values[3] = viewgram.get_max_tangential_pos_num(); + viewgram_values[4] = viewgram.get_view_num(); + viewgram_values[5] = viewgram.get_segment_num(); + viewgram_values[6] = viewgram.get_timing_pos_num(); + + send_int_values(viewgram_values, 7, VIEWGRAM_DIMENSIONS_TAG, destination); + + // allocate send-buffer + int buffer_size = (viewgram_values[1] - viewgram_values[0] + 1) * (viewgram_values[3] - viewgram_values[2] + 1); + float* viewgram_buf = new float[buffer_size]; + std::copy(viewgram.begin_all(), viewgram.end_all(), viewgram_buf); + + // send array +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); } - - void send_viewgram(const stir::Viewgram& viewgram, int destination) - { - //send dimensions of viewgram (axial and tangential positions and the view and segment numbers) - int viewgram_values[6]; - viewgram_values[0] = viewgram.get_min_axial_pos_num(); - viewgram_values[1] = viewgram.get_max_axial_pos_num(); - viewgram_values[2] = viewgram.get_min_tangential_pos_num(); - viewgram_values[3] = viewgram.get_max_tangential_pos_num(); - viewgram_values[4] = viewgram.get_view_num(); - viewgram_values[5] = viewgram.get_segment_num(); - - send_int_values(viewgram_values, 6, VIEWGRAM_DIMENSIONS_TAG, destination); - - //allocate send-buffer - int buffer_size=(viewgram_values[1]-viewgram_values[0]+1)*(viewgram_values[3]-viewgram_values[2]+1); - float *viewgram_buf = new float[buffer_size]; - std::copy(viewgram.begin_all(), viewgram.end_all(), viewgram_buf); - - //send array -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} #endif - MPI_Send(viewgram_buf, buffer_size, MPI_FLOAT, destination, VIEWGRAM_TAG, MPI_COMM_WORLD); + MPI_Send(viewgram_buf, buffer_size, MPI_FLOAT, destination, VIEWGRAM_TAG, MPI_COMM_WORLD); #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Master: sending viewgram took " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master: sending viewgram took " << t.value() << " seconds" << std::endl; #endif - - delete[] viewgram_buf; - } - void send_projectors(const stir::shared_ptr &proj_pair_sptr, int destination) - { - //send registered name of projector pair - distributed::send_string(proj_pair_sptr->get_registered_name(), REGISTERED_NAME_TAG, destination); - - //send parameter info of projector pair - distributed::send_string(proj_pair_sptr->stir::ParsingObject::parameter_info(), PARAMETER_INFO_TAG, destination); + delete[] viewgram_buf; +} - } - - //--------------------------------------Receive Operations------------------------------------- - - int receive_int_value(int source) - { - int i; +void +send_projectors(const stir::shared_ptr& proj_pair_sptr, int destination) { + // send registered name of projector pair + distributed::send_string(proj_pair_sptr->get_registered_name(), REGISTERED_NAME_TAG, destination); + + // send parameter info of projector pair + distributed::send_string(proj_pair_sptr->stir::ParsingObject::parameter_info(), PARAMETER_INFO_TAG, destination); +} + +//--------------------------------------Receive Operations------------------------------------- + +int +receive_int_value(int source) { + int i; #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - - if (source==-1) MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD); - else MPI_Recv(&i, 1, MPI_INT, source, INT_TAG, MPI_COMM_WORLD, &status); - + + if (source == -1) + MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD); + else + MPI_Recv(&i, 1, MPI_INT, source, INT_TAG, MPI_COMM_WORLD, &status); + #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received int value after " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received int value after " << t.value() << " seconds" << std::endl; #endif - - return i; - } - - std::string receive_string(int tag, int source) - { + + return i; +} + +std::string +receive_string(int tag, int source) { #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - - MPI_Recv(&length, 1, MPI_INT, source, tag, MPI_COMM_WORLD, &status); - char * buf= new char[length]; - MPI_Recv(buf, length, MPI_CHAR, source, tag, MPI_COMM_WORLD, & status); - + + MPI_Recv(&length, 1, MPI_INT, source, tag, MPI_COMM_WORLD, &status); + char* buf = new char[length]; + MPI_Recv(buf, length, MPI_CHAR, source, tag, MPI_COMM_WORLD, &status); + #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received string value after " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received string value after " << t.value() << " seconds" << std::endl; #endif - - //convert to string - std::string str(buf); - delete[] buf; - return str; - } - - void receive_and_initialize_projectors(stir::shared_ptr &projector_pair_ptr, int source) - { - //Receive projector-pair registered_keyword -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} -#endif - // KT TODO. use receive_string() to clean-up code - - MPI_Recv(&length, 1, MPI_INT, source, REGISTERED_NAME_TAG, MPI_COMM_WORLD, &status); - char * buf= new char[length]; - MPI_Recv(buf, length, MPI_CHAR, source, REGISTERED_NAME_TAG, MPI_COMM_WORLD, & status); - -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received REGISTERED_NAME_TAG value after " << t.value() << " seconds" << std::endl; -#endif - - //convert to string - std::string registered_name_proj_pair(buf); - delete[] buf; - - //Receive parameter info -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} -#endif - - MPI_Recv(&length, 1, MPI_INT, source, PARAMETER_INFO_TAG, MPI_COMM_WORLD, &status); - - char * buf3= new char[length]; - MPI_Recv(buf3, length, MPI_CHAR, source, PARAMETER_INFO_TAG, MPI_COMM_WORLD, & status); - -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received parameter info value after " << t.value() << " seconds" << std::endl; -#endif - - //convert to string - std::string parameter_info(buf3); - delete[] buf3; - - //construct new Backprojector and Forward Projector, projector_pair_ptr - std::istringstream parameter_info_stream(parameter_info); - - projector_pair_ptr. - reset(stir::RegisteredObject:: - read_registered_object(¶meter_info_stream, registered_name_proj_pair)); - } - - bool receive_bool_value(int tag, int source) - { - int i = 0; // initialise to avoid compiler warning - + + // convert to string + std::string str(buf); + delete[] buf; + return str; +} + +void +receive_and_initialize_projectors(stir::shared_ptr& projector_pair_ptr, int source) { + // Receive projector-pair registered_keyword #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - - if (tag==-1 || source == -1) MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD); - else MPI_Recv(&i, 1, MPI_INT, source, tag, MPI_COMM_WORLD, &status); - + // KT TODO. use receive_string() to clean-up code + + MPI_Recv(&length, 1, MPI_INT, source, REGISTERED_NAME_TAG, MPI_COMM_WORLD, &status); + char* buf = new char[length]; + MPI_Recv(buf, length, MPI_CHAR, source, REGISTERED_NAME_TAG, MPI_COMM_WORLD, &status); + #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received bool value after " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received REGISTERED_NAME_TAG value after " << t.value() << " seconds" << std::endl; #endif - - return i!=0; - } - - MPI_Status receive_int_values(int * values, int count, int tag) - { + // convert to string + std::string registered_name_proj_pair(buf); + delete[] buf; + + // Receive parameter info #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - if (tag == ARBITRARY_TAG) MPI_Recv(values, count, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); - else MPI_Recv(values, count, MPI_INT, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status); + MPI_Recv(&length, 1, MPI_INT, source, PARAMETER_INFO_TAG, MPI_COMM_WORLD, &status); + + char* buf3 = new char[length]; + MPI_Recv(buf3, length, MPI_CHAR, source, PARAMETER_INFO_TAG, MPI_COMM_WORLD, &status); #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - int my_rank=0; - MPI_Comm_rank(MPI_COMM_WORLD, &my_rank) ; /*Gets the rank of the Processor*/ - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Master/Slave " << my_rank << ": received "<< count << " int values after " << t.value() << " seconds"<< std::endl; + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received parameter info value after " << t.value() << " seconds" << std::endl; #endif - return status; + // convert to string + std::string parameter_info(buf3); + delete[] buf3; + + // construct new Backprojector and Forward Projector, projector_pair_ptr + std::istringstream parameter_info_stream(parameter_info); + + projector_pair_ptr.reset(stir::RegisteredObject::read_registered_object(¶meter_info_stream, + registered_name_proj_pair)); +} + +bool +receive_bool_value(int tag, int source) { + int i = 0; // initialise to avoid compiler warning + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); } - - MPI_Status receive_double_values(double * values, int count, int tag) - { +#endif + + if (tag == -1 || source == -1) + MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD); + else + MPI_Recv(&i, 1, MPI_INT, source, tag, MPI_COMM_WORLD, &status); + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received bool value after " << t.value() << " seconds" << std::endl; +#endif + + return i != 0; +} + +MPI_Status +receive_int_values(int* values, int count, int tag) { #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - - if (tag == ARBITRARY_TAG) MPI_Recv(values, count, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); - else MPI_Recv(values, count, MPI_DOUBLE, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status); - + + if (tag == ARBITRARY_TAG) + MPI_Recv(values, count, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); + else + MPI_Recv(values, count, MPI_INT, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status); + #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received double values after " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) + t.stop(); + int my_rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); /*Gets the rank of the Processor*/ + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master/Slave " << my_rank << ": received " << count << " int values after " << t.value() << " seconds" + << std::endl; #endif - - return status; + + return status; +} + +MPI_Status +receive_double_values(double* values, int count, int tag) { + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); } +#endif - MPI_Status receive_view_segment_numbers(stir::ViewSegmentNumbers& vs_num, int tag) - { - int int_values[2]; - const MPI_Status status = distributed::receive_int_values(int_values, 2, tag); - vs_num.view_num() = int_values[0]; - vs_num.segment_num() = int_values[1]; - return status; + if (tag == ARBITRARY_TAG) + MPI_Recv(values, count, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); + else + MPI_Recv(values, count, MPI_DOUBLE, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status); + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received double values after " << t.value() << " seconds" << std::endl; +#endif + + return status; +} + +MPI_Status +receive_view_segment_numbers(stir::ViewSegmentNumbers& vs_num, int tag) { + int int_values[2]; + const MPI_Status status = distributed::receive_int_values(int_values, 2, tag); + vs_num.view_num() = int_values[0]; + vs_num.segment_num() = int_values[1]; + return status; +} + +void +receive_and_set_image_parameters(stir::shared_ptr>& image_ptr, int& buffer, int tag, + int source) { + // receive image parameters (origin and grid_spacing) +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); } - - void receive_and_set_image_parameters(stir::shared_ptr > &image_ptr, int &buffer, int tag, int source) - { - //receive image parameters (origin and grid_spacing) -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} #endif - - if (tag==-1) MPI_Bcast(parameters, 6, MPI_FLOAT, source, MPI_COMM_WORLD); - else MPI_Recv(parameters, 6, MPI_FLOAT, source, tag, MPI_COMM_WORLD, &status); + + if (tag == -1) + MPI_Bcast(parameters, 6, MPI_FLOAT, source, MPI_COMM_WORLD); + else + MPI_Recv(parameters, 6, MPI_FLOAT, source, tag, MPI_COMM_WORLD, &status); #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received origin and grid_spacing after " << t.value() << " seconds" << std::endl; - - //receive dimensions of Image-data - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received origin and grid_spacing after " << t.value() << " seconds" << std::endl; + + // receive dimensions of Image-data + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - - if (tag==-1) MPI_Bcast(sizes, 6, MPI_INT, source, MPI_COMM_WORLD); - else MPI_Recv(sizes, 6, MPI_INT, source, tag, MPI_COMM_WORLD, &status); -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received image dimensions after " << t.value() << " seconds" << std::endl; + if (tag == -1) + MPI_Bcast(sizes, 6, MPI_INT, source, MPI_COMM_WORLD); + else + MPI_Recv(sizes, 6, MPI_INT, source, tag, MPI_COMM_WORLD, &status); + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received image dimensions after " << t.value() << " seconds" << std::endl; #endif - - buffer=(sizes[3]-sizes[0]+1)*(sizes[4]-sizes[1]+1)*(sizes[5]-sizes[2]+1); - - //construct new index range from received values - stir::IndexRange<3> - range(stir::CartesianCoordinate3D(sizes[2],sizes[1],sizes[0]), - stir::CartesianCoordinate3D(sizes[5],sizes[4],sizes[3])); - - //construct new image object to save received input-image values - stir::CartesianCoordinate3D origin( parameters[2], parameters[1], parameters[0]); - stir::CartesianCoordinate3D grid_spacing(parameters[5], parameters[4], parameters[3]); + + buffer = (sizes[3] - sizes[0] + 1) * (sizes[4] - sizes[1] + 1) * (sizes[5] - sizes[2] + 1); + + // construct new index range from received values + stir::IndexRange<3> range(stir::CartesianCoordinate3D(sizes[2], sizes[1], sizes[0]), + stir::CartesianCoordinate3D(sizes[5], sizes[4], sizes[3])); + + // construct new image object to save received input-image values + stir::CartesianCoordinate3D origin(parameters[2], parameters[1], parameters[0]); + stir::CartesianCoordinate3D grid_spacing(parameters[5], parameters[4], parameters[3]); #if 0 stir::VoxelsOnCartesianGrid *voxels = new stir::VoxelsOnCartesianGrid(range, origin, grid_spacing); stir::shared_ptr > tmpPtr(voxels); //point pointer to newly created image_estimate - image_ptr = *(stir::shared_ptr >*)&tmpPtr; + image_ptr = *(stir::shared_ptr >*)&tmpPtr; #else - image_ptr.reset(new stir::VoxelsOnCartesianGrid(range, origin, grid_spacing)); + image_ptr.reset(new stir::VoxelsOnCartesianGrid(range, origin, grid_spacing)); #endif - } - - MPI_Status receive_image_values_and_fill_image_ptr(stir::shared_ptr > &image_ptr, int buffer_size, int source) - { - //buffer for input_image - float * buffer = new float[buffer_size]; - if (buffer == 0) - stir::error("Ran out of memory"); +} -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} +MPI_Status +receive_image_values_and_fill_image_ptr(stir::shared_ptr>& image_ptr, int buffer_size, + int source) { + // buffer for input_image + float* buffer = new float[buffer_size]; + if (buffer == 0) + stir::error("Ran out of memory"); + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - - MPI_Bcast(buffer, buffer_size, MPI_FLOAT, source, MPI_COMM_WORLD); - //else MPI_Recv(buffer, buffer_size, MPI_FLOAT, source, IMAGE_ESTIMATE_TAG, MPI_COMM_WORLD, & status); -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received image values after " << t.value() << " seconds" << std::endl; + MPI_Bcast(buffer, buffer_size, MPI_FLOAT, source, MPI_COMM_WORLD); + // else MPI_Recv(buffer, buffer_size, MPI_FLOAT, source, IMAGE_ESTIMATE_TAG, MPI_COMM_WORLD, & status); + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received image values after " << t.value() << " seconds" << std::endl; #endif - - std::copy(buffer, buffer + buffer_size, image_ptr->begin_all()); - delete[] buffer; - return status; - } - - void receive_and_construct_exam_and_proj_data_info_ptr(stir::shared_ptr& exam_info_sptr, - stir::shared_ptr& proj_data_info_sptr, - int source) - { - int len; - //receive projection data info pointer + std::copy(buffer, buffer + buffer_size, image_ptr->begin_all()); + delete[] buffer; + + return status; +} + +void +receive_and_construct_exam_and_proj_data_info_ptr(stir::shared_ptr& exam_info_sptr, + stir::shared_ptr& proj_data_info_sptr, int source) { + int len; + // receive projection data info pointer #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - - MPI_Recv(&len, 1, MPI_INT, source, PROJECTION_DATA_INFO_TAG, MPI_COMM_WORLD, &status); - boost::shared_array proj_data_info_buf(new char[len]); - MPI_Recv(proj_data_info_buf.get(), len, MPI_CHAR, source, PROJECTION_DATA_INFO_TAG, MPI_COMM_WORLD, & status); -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received proj_data_info after " << t.value() << " seconds" << std::endl; + MPI_Recv(&len, 1, MPI_INT, source, PROJECTION_DATA_INFO_TAG, MPI_COMM_WORLD, &status); + boost::shared_array proj_data_info_buf(new char[len]); + MPI_Recv(proj_data_info_buf.get(), len, MPI_CHAR, source, PROJECTION_DATA_INFO_TAG, MPI_COMM_WORLD, &status); + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received proj_data_info after " << t.value() << " seconds" << std::endl; #endif - - //construct projector_info_ptr - std::istringstream projector_info_ptr_stream(proj_data_info_buf.get()); - - stir::InterfileHeader hdr; - std::ios::off_type offset = projector_info_ptr_stream.tellg(); - if (!hdr.parse(projector_info_ptr_stream, false)) // parse without warnings - { - stir::error("Error receiving projection data info. Text does not seem to be in Interfile format"); - } - projector_info_ptr_stream.seekg(offset); - exam_info_sptr = hdr.get_exam_info_sptr(); - if (hdr.get_exam_info().imaging_modality.get_modality() == - stir::ImagingModality::NM) - { - stir::InterfilePDFSHeaderSPECT hdr; - if (!hdr.parse(projector_info_ptr_stream)) - stir::error("Error receiving projection data info. Text does not seem to be in Interfile format"); - proj_data_info_sptr = - stir::shared_ptr (hdr.data_info_sptr->clone()); - } - else - { - stir::InterfilePDFSHeader hdr; - if (!hdr.parse(projector_info_ptr_stream)) - stir::error("Error receiving projection data info. Text does not seem to be in Interfile format"); - - proj_data_info_sptr = - stir::shared_ptr (hdr.data_info_ptr->clone()); - } - } - - void receive_and_construct_related_viewgrams(stir::RelatedViewgrams*& viewgrams, - const stir::shared_ptr& proj_data_info_ptr, - const stir::shared_ptr symmetries_sptr, - int source) + + // construct projector_info_ptr + std::istringstream projector_info_ptr_stream(proj_data_info_buf.get()); + + stir::InterfileHeader hdr; + std::ios::off_type offset = projector_info_ptr_stream.tellg(); + if (!hdr.parse(projector_info_ptr_stream, false)) // parse without warnings { - //receive count of viewgrams - int int_values[1]; - status=distributed::receive_int_values(int_values, 1, VIEWGRAM_COUNT_TAG); - - std::vector > viewgrams_vector; - - viewgrams_vector.reserve(int_values[0]); - - for (int i=0; i* vg = NULL; - - //receive a viewgram from Master - receive_and_construct_viewgram(vg, proj_data_info_ptr, source); - - //add viewgram to Viewgram-vector - viewgrams_vector.push_back(*vg); - delete vg; - } - - //use viewgram-vector and symmetries-pointer to construct related viewgrams element - viewgrams = new stir::RelatedViewgrams(viewgrams_vector, symmetries_sptr); + stir::error("Error receiving projection data info. Text does not seem to be in Interfile format"); } - - void receive_and_construct_viewgram(stir::Viewgram*& viewgram_ptr, - const stir::shared_ptr& proj_data_info_ptr, - int source) - { + projector_info_ptr_stream.seekg(offset); + exam_info_sptr = hdr.get_exam_info_sptr(); + if (hdr.get_exam_info().imaging_modality.get_modality() == stir::ImagingModality::NM) { + stir::InterfilePDFSHeaderSPECT hdr; + if (!hdr.parse(projector_info_ptr_stream)) + stir::error("Error receiving projection data info. Text does not seem to be in Interfile format"); + proj_data_info_sptr = stir::shared_ptr(hdr.data_info_sptr->clone()); + } else { + stir::InterfilePDFSHeader hdr; + if (!hdr.parse(projector_info_ptr_stream)) + stir::error("Error receiving projection data info. Text does not seem to be in Interfile format"); + + proj_data_info_sptr = stir::shared_ptr(hdr.data_info_ptr->clone()); + } +} + +void +receive_and_construct_related_viewgrams(stir::RelatedViewgrams*& viewgrams, + const stir::shared_ptr& proj_data_info_ptr, + const stir::shared_ptr symmetries_sptr, + int source) { + // receive count of viewgrams + int int_values[1]; + status = distributed::receive_int_values(int_values, 1, VIEWGRAM_COUNT_TAG); + + std::vector> viewgrams_vector; + + viewgrams_vector.reserve(int_values[0]); + + for (int i = 0; i < int_values[0]; i++) { + stir::Viewgram* vg = NULL; + + // receive a viewgram from Master + receive_and_construct_viewgram(vg, proj_data_info_ptr, source); + + // add viewgram to Viewgram-vector + viewgrams_vector.push_back(*vg); + delete vg; + } + + // use viewgram-vector and symmetries-pointer to construct related viewgrams element + viewgrams = new stir::RelatedViewgrams(viewgrams_vector, symmetries_sptr); +} + +void +receive_and_construct_viewgram(stir::Viewgram*& viewgram_ptr, + const stir::shared_ptr& proj_data_info_ptr, int source) { #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - //receive dimension of viewgram (vlues 0-3) and view_num + segment_num (values 4-5) - int viewgram_values[6]; - - status = receive_int_values(viewgram_values, 6, VIEWGRAM_DIMENSIONS_TAG); - - const int v_num = viewgram_values[4]; - const int s_num = viewgram_values[5]; - - viewgram_ptr= new stir::Viewgram(proj_data_info_ptr, v_num, s_num); - - //allocate receive-buffer - const int buffer_size=(viewgram_values[1]-viewgram_values[0]+1)*(viewgram_values[3]-viewgram_values[2]+1); - float *viewgram_buf = new float[buffer_size]; - - //receive viewgram array + // receive dimension of viewgram (vlues 0-3) and view_num + segment_num (values 4-5) and timing_pos_num (value 6) + int viewgram_values[7]; + + status = receive_int_values(viewgram_values, 7, VIEWGRAM_DIMENSIONS_TAG); - MPI_Recv(viewgram_buf, buffer_size, MPI_FLOAT, source, VIEWGRAM_TAG, MPI_COMM_WORLD, &status); + const int v_num = viewgram_values[4]; + const int s_num = viewgram_values[5]; + const int t_num = viewgram_values[6]; - std::copy(viewgram_buf, viewgram_buf+buffer_size, viewgram_ptr->begin_all()); + viewgram_ptr = new stir::Viewgram(proj_data_info_ptr, v_num, s_num, t_num); - delete[] viewgram_buf; + // allocate receive-buffer + const int buffer_size = (viewgram_values[1] - viewgram_values[0] + 1) * (viewgram_values[3] - viewgram_values[2] + 1); + float* viewgram_buf = new float[buffer_size]; + + // receive viewgram array + + MPI_Recv(viewgram_buf, buffer_size, MPI_FLOAT, source, VIEWGRAM_TAG, MPI_COMM_WORLD, &status); + + std::copy(viewgram_buf, viewgram_buf + buffer_size, viewgram_ptr->begin_all()); + + delete[] viewgram_buf; #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave: received viewgram_array after " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave: received viewgram_array after " << t.value() << " seconds" << std::endl; #endif +} - } - - //--------------------------------------Reduce Operations------------------------------------- - - void reduce_received_output_image(stir::DiscretisedDensity<3,float>* output_image_ptr, int destination) - { - #ifdef STIR_MPI_TIMINGS - stir::HighResWallClockTimer fulltimer; - fulltimer.reset(); fulltimer.start(); -#endif - float *output_buf = new float[image_buffer_size]; - float *image_buf = new float[image_buffer_size]; - - //initialize output_buffer to zero. - //contributions from all slaves will be added into it - //KTXXXfor (int i=0; i* output_image_ptr, int destination) { #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + stir::HighResWallClockTimer fulltimer; + fulltimer.reset(); + fulltimer.start(); #endif + float* output_buf = new float[image_buffer_size]; + float* image_buf = new float[image_buffer_size]; - MPI_Reduce(image_buf, output_buf, image_buffer_size, MPI_FLOAT, MPI_SUM, destination, MPI_COMM_WORLD); - delete[] image_buf; + // initialize output_buffer to zero. + // contributions from all slaves will be added into it + // KTXXXfor (int i=0; imin_threshold) std::cout << "Master: reduced output_image after " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) { + t.reset(); + t.start(); + } #endif - std::cout <<"Master: output_image reduced.\n"; - - //get input_image from 1-demnsional array - std::copy(output_buf, output_buf+image_buffer_size, output_image_ptr->begin_all()); - delete[] output_buf; + MPI_Reduce(image_buf, output_buf, image_buffer_size, MPI_FLOAT, MPI_SUM, destination, MPI_COMM_WORLD); + delete[] image_buf; + #ifdef STIR_MPI_TIMINGS - fulltimer.stop(); - if (test_send_receive_times /*&& fulltimer.value()>min_threshold*/) std::cout << "Master: reduced output_image total after " << fulltimer.value() << " seconds" << std::endl; + if (test_send_receive_times) + t.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master: reduced output_image after " << t.value() << " seconds" << std::endl; #endif - } - - void reduce_output_image(stir::shared_ptr > &output_image_ptr, int image_buffer_size, int my_rank_ignored, int destination) - { - float *output_buf = new float[image_buffer_size]; - float *image_buf = new float[image_buffer_size]; - - //serialize input_image into 1-demnsional array - //KTXXXstd::copy(output_image_ptr->begin_all(), output_image_ptr->end_all(), output_buf); - std::copy(output_image_ptr->begin_all(), output_image_ptr->end_all(), image_buf); - - //reduction of output_image at master + + std::cout << "Master: output_image reduced.\n"; + + // get input_image from 1-demnsional array + std::copy(output_buf, output_buf + image_buffer_size, output_image_ptr->begin_all()); + delete[] output_buf; #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} + fulltimer.stop(); + if (test_send_receive_times /*&& fulltimer.value()>min_threshold*/) + std::cout << "Master: reduced output_image total after " << fulltimer.value() << " seconds" << std::endl; #endif +} - MPI_Reduce(image_buf, output_buf, image_buffer_size, MPI_FLOAT, MPI_SUM, destination, MPI_COMM_WORLD); - delete[] image_buf; +void +reduce_output_image(stir::shared_ptr>& output_image_ptr, int image_buffer_size, + int my_rank_ignored, int destination) { + float* output_buf = new float[image_buffer_size]; + float* image_buf = new float[image_buffer_size]; + // serialize input_image into 1-demnsional array + // KTXXXstd::copy(output_image_ptr->begin_all(), output_image_ptr->end_all(), output_buf); + std::copy(output_image_ptr->begin_all(), output_image_ptr->end_all(), image_buf); + + // reduction of output_image at master #ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) t.stop(); - int my_rank=0; - MPI_Comm_rank(MPI_COMM_WORLD, &my_rank) ; /*Gets the rank of the Processor*/ - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Slave " << my_rank << ": reduced output_image after " << t.value() << " seconds" << std::endl; -#endif - delete[] output_buf; + if (test_send_receive_times) { + t.reset(); + t.start(); } - +#endif + + MPI_Reduce(image_buf, output_buf, image_buffer_size, MPI_FLOAT, MPI_SUM, destination, MPI_COMM_WORLD); + delete[] image_buf; + +#ifdef STIR_MPI_TIMINGS + if (test_send_receive_times) + t.stop(); + int my_rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); /*Gets the rank of the Processor*/ + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Slave " << my_rank << ": reduced output_image after " << t.value() << " seconds" << std::endl; +#endif + delete[] output_buf; } + +} // namespace distributed diff --git a/src/recon_buildblock/distributed_test_functions.cxx b/src/recon_buildblock/distributed_test_functions.cxx index a3a3d08ce3..2061b8c216 100644 --- a/src/recon_buildblock/distributed_test_functions.cxx +++ b/src/recon_buildblock/distributed_test_functions.cxx @@ -23,7 +23,7 @@ \brief Implementation of test functions in distributed namespace - \author Tobias Beisel + \author Tobias Beisel */ @@ -31,246 +31,242 @@ #include "stir/recon_buildblock/distributed_functions.h" #include "stir/VoxelsOnCartesianGrid.h" -namespace distributed -{ - void test_viewgram_slave(const stir::shared_ptr& proj_data_info_ptr) - { - printf("\n-----Slave startet Test for sending viewgram----------\n"); - - stir::Viewgram* vg= NULL; - receive_and_construct_viewgram(vg, proj_data_info_ptr, 0); - - send_viewgram(*vg, 0); - vg=NULL; - delete vg; - } - - void test_viewgram_master(stir::Viewgram viewgram, const stir::shared_ptr& proj_data_info_ptr) - { - printf("\n-----Running Test for sending viewgram----------\n"); - - send_viewgram(viewgram, 1); - - stir::Viewgram* vg= NULL; - receive_and_construct_viewgram(vg, proj_data_info_ptr, 1); - - assert(vg!=NULL); - assert(vg->has_same_characteristics(viewgram)); - assert(*vg==viewgram); - - for ( int tang_pos = viewgram.get_min_tangential_pos_num(); tang_pos <= viewgram.get_max_tangential_pos_num() ;++tang_pos) - for ( int ax_pos = viewgram.get_min_axial_pos_num(); ax_pos <= viewgram.get_max_axial_pos_num() ;++ax_pos) - { - assert(viewgram[ax_pos][tang_pos]==(*vg)[ax_pos][tang_pos]); - if (viewgram[ax_pos][tang_pos]!=(*vg)[ax_pos][tang_pos]) printf("-----Test sending viewgram failed!!!!-------------\n"); - } - assert(vg->get_view_num()==viewgram.get_view_num()); - if (vg->get_view_num()!=viewgram.get_view_num()) printf("-----Test sending viewgram failed!!!!-------------\n"); - assert(vg->get_segment_num()==viewgram.get_segment_num()); - if (vg->get_segment_num()!=viewgram.get_segment_num()) printf("-----Test sending viewgram failed!!!!-------------\n"); - - delete vg; - printf("\n-----Test sending viewgram done-----------\n"); - } - - void test_image_estimate_master(const stir::DiscretisedDensity<3,float>* input_image_ptr, int slave) - { - printf("\n-----Running Test for sending image estimate-----\n"); - - int image_buffer_size; - - send_image_parameters(input_image_ptr, 99, slave); - send_image_estimate(input_image_ptr, slave); - - stir::shared_ptr > target_image_sptr; - receive_and_set_image_parameters(target_image_sptr, image_buffer_size, 99, slave); - - receive_image_values_and_fill_image_ptr(target_image_sptr, image_buffer_size, slave); - - assert(target_image_sptr->has_same_characteristics(*input_image_ptr)); - assert(*input_image_ptr==*target_image_sptr); - - stir::DiscretisedDensity<3,float>::const_full_iterator density_iter = input_image_ptr->begin_all(); - stir::DiscretisedDensity<3,float>::const_full_iterator density_end = input_image_ptr->end_all(); - - stir::DiscretisedDensity<3,float>::full_iterator target_density_iter = target_image_sptr->begin_all(); - - while (density_iter!= density_end) - { - assert(*density_iter == *target_density_iter); - - density_iter++; - target_density_iter++; - } - - printf("\n-----Test sending image estimate done-----\n"); - } - - void test_image_estimate_slave() - { - printf("\n-----Slave startet Test for sending image estimate-----\n"); - - int buffer_size; - stir::shared_ptr > received_image_estimate; - - receive_and_set_image_parameters(received_image_estimate, buffer_size, 99, 0); - receive_image_values_and_fill_image_ptr(received_image_estimate, buffer_size, 0); - - send_image_parameters(received_image_estimate.get(), 99, 0); - send_image_estimate(received_image_estimate.get(), 0); +namespace distributed { +void +test_viewgram_slave(const stir::shared_ptr& proj_data_info_ptr) { + printf("\n-----Slave startet Test for sending viewgram----------\n"); + + stir::Viewgram* vg = NULL; + receive_and_construct_viewgram(vg, proj_data_info_ptr, 0); + + send_viewgram(*vg, 0); + vg = NULL; + delete vg; +} + +void +test_viewgram_master(stir::Viewgram viewgram, const stir::shared_ptr& proj_data_info_ptr) { + printf("\n-----Running Test for sending viewgram----------\n"); + + send_viewgram(viewgram, 1); + + stir::Viewgram* vg = NULL; + receive_and_construct_viewgram(vg, proj_data_info_ptr, 1); + + assert(vg != NULL); + assert(vg->has_same_characteristics(viewgram)); + assert(*vg == viewgram); + + for (int tang_pos = viewgram.get_min_tangential_pos_num(); tang_pos <= viewgram.get_max_tangential_pos_num(); ++tang_pos) + for (int ax_pos = viewgram.get_min_axial_pos_num(); ax_pos <= viewgram.get_max_axial_pos_num(); ++ax_pos) { + assert(viewgram[ax_pos][tang_pos] == (*vg)[ax_pos][tang_pos]); + if (viewgram[ax_pos][tang_pos] != (*vg)[ax_pos][tang_pos]) + printf("-----Test sending viewgram failed!!!!-------------\n"); + } + assert(vg->get_view_num() == viewgram.get_view_num()); + if (vg->get_view_num() != viewgram.get_view_num()) + printf("-----Test sending viewgram failed!!!!-------------\n"); + assert(vg->get_segment_num() == viewgram.get_segment_num()); + if (vg->get_segment_num() != viewgram.get_segment_num()) + printf("-----Test sending viewgram failed!!!!-------------\n"); + assert(vg->get_timing_pos_num() == viewgram.get_timing_pos_num()); + if (vg->get_timing_pos_num() != viewgram.get_timing_pos_num()) + printf("-----Test sending viewgram failed!!!!-------------\n"); + + delete vg; + printf("\n-----Test sending viewgram done-----------\n"); +} + +void +test_image_estimate_master(const stir::DiscretisedDensity<3, float>* input_image_ptr, int slave) { + printf("\n-----Running Test for sending image estimate-----\n"); + + int image_buffer_size; + + send_image_parameters(input_image_ptr, 99, slave); + send_image_estimate(input_image_ptr, slave); + + stir::shared_ptr> target_image_sptr; + receive_and_set_image_parameters(target_image_sptr, image_buffer_size, 99, slave); + + receive_image_values_and_fill_image_ptr(target_image_sptr, image_buffer_size, slave); + + assert(target_image_sptr->has_same_characteristics(*input_image_ptr)); + assert(*input_image_ptr == *target_image_sptr); + + stir::DiscretisedDensity<3, float>::const_full_iterator density_iter = input_image_ptr->begin_all(); + stir::DiscretisedDensity<3, float>::const_full_iterator density_end = input_image_ptr->end_all(); + + stir::DiscretisedDensity<3, float>::full_iterator target_density_iter = target_image_sptr->begin_all(); + + while (density_iter != density_end) { + assert(*density_iter == *target_density_iter); + + density_iter++; + target_density_iter++; } - - void test_related_viewgrams_master(const stir::shared_ptr& proj_data_info_ptr, - const stir::shared_ptr symmetries_sptr, - stir::RelatedViewgrams* y, int slave) - { - printf("\n-----Running Test for sending related viewgrams-----\n"); - - send_related_viewgrams(y, 1); - - stir::RelatedViewgrams* received_viewgrams=NULL; - - receive_and_construct_related_viewgrams(received_viewgrams, - proj_data_info_ptr, - symmetries_sptr, 1); - - assert(received_viewgrams!=NULL); - assert(received_viewgrams->has_same_characteristics(*y)); - assert(*received_viewgrams==*y); - - stir::RelatedViewgrams::iterator viewgrams_iter = y->begin(); - stir::RelatedViewgrams::iterator viewgrams_end = y->end(); - stir::RelatedViewgrams::iterator received_viewgrams_iter = received_viewgrams->begin(); - - int pos=0; - while (viewgrams_iter!= viewgrams_end) - { - for ( int tang_pos = (*viewgrams_iter).get_min_tangential_pos_num() ;tang_pos <= (*viewgrams_iter).get_max_tangential_pos_num() ;++tang_pos) - for ( int ax_pos = (*viewgrams_iter).get_min_axial_pos_num(); ax_pos <= (*viewgrams_iter).get_max_axial_pos_num() ;++ax_pos) - { - pos++; - assert(((*viewgrams_iter)[ax_pos][tang_pos])==(*received_viewgrams_iter)[ax_pos][tang_pos]); - } - viewgrams_iter++; - received_viewgrams_iter++; + + printf("\n-----Test sending image estimate done-----\n"); +} + +void +test_image_estimate_slave() { + printf("\n-----Slave startet Test for sending image estimate-----\n"); + + int buffer_size; + stir::shared_ptr> received_image_estimate; + + receive_and_set_image_parameters(received_image_estimate, buffer_size, 99, 0); + receive_image_values_and_fill_image_ptr(received_image_estimate, buffer_size, 0); + + send_image_parameters(received_image_estimate.get(), 99, 0); + send_image_estimate(received_image_estimate.get(), 0); +} + +void +test_related_viewgrams_master(const stir::shared_ptr& proj_data_info_ptr, + const stir::shared_ptr symmetries_sptr, + stir::RelatedViewgrams* y, int slave) { + printf("\n-----Running Test for sending related viewgrams-----\n"); + + send_related_viewgrams(y, 1); + + stir::RelatedViewgrams* received_viewgrams = NULL; + + receive_and_construct_related_viewgrams(received_viewgrams, proj_data_info_ptr, symmetries_sptr, 1); + + assert(received_viewgrams != NULL); + assert(received_viewgrams->has_same_characteristics(*y)); + assert(*received_viewgrams == *y); + + stir::RelatedViewgrams::iterator viewgrams_iter = y->begin(); + stir::RelatedViewgrams::iterator viewgrams_end = y->end(); + stir::RelatedViewgrams::iterator received_viewgrams_iter = received_viewgrams->begin(); + + int pos = 0; + while (viewgrams_iter != viewgrams_end) { + for (int tang_pos = (*viewgrams_iter).get_min_tangential_pos_num(); + tang_pos <= (*viewgrams_iter).get_max_tangential_pos_num(); ++tang_pos) + for (int ax_pos = (*viewgrams_iter).get_min_axial_pos_num(); ax_pos <= (*viewgrams_iter).get_max_axial_pos_num(); + ++ax_pos) { + pos++; + assert(((*viewgrams_iter)[ax_pos][tang_pos]) == (*received_viewgrams_iter)[ax_pos][tang_pos]); } - - received_viewgrams=NULL; - delete received_viewgrams; - printf("\n-----Test sending related viewgrams done-----\n"); - } - - void test_related_viewgrams_slave(const stir::shared_ptr& proj_data_info_ptr, - const stir::shared_ptr symmetries_sptr - ) - { - printf("\n-----Slave startet Test for sending related viewgrams-----\n"); - - stir::RelatedViewgrams* received_viewgrams=NULL; - - receive_and_construct_related_viewgrams(received_viewgrams, - proj_data_info_ptr, - symmetries_sptr, 0); - - assert(received_viewgrams!=NULL); - - send_related_viewgrams(received_viewgrams, 0); - - received_viewgrams=NULL; - delete received_viewgrams; - } - - void test_parameter_info_master(const std::string str, int slave, char const * const text) - { - printf("\n-----Running Test for sending %s-----\n", text); - - std::string slave_string= receive_string(88, slave); - - assert(str.compare(slave_string)==0); - - /*printf("\nReceived Parameter Info:\n"); - cerr<& proj_data_info_ptr, + const stir::shared_ptr symmetries_sptr) { + printf("\n-----Slave startet Test for sending related viewgrams-----\n"); + + stir::RelatedViewgrams* received_viewgrams = NULL; + + receive_and_construct_related_viewgrams(received_viewgrams, proj_data_info_ptr, symmetries_sptr, 0); + + assert(received_viewgrams != NULL); + + send_related_viewgrams(received_viewgrams, 0); + + received_viewgrams = NULL; + delete received_viewgrams; +} + +void +test_parameter_info_master(const std::string str, int slave, char const* const text) { + printf("\n-----Running Test for sending %s-----\n", text); + + std::string slave_string = receive_string(88, slave); + + assert(str.compare(slave_string) == 0); + + /*printf("\nReceived Parameter Info:\n"); + cerr< - find_basic_vs_nums_in_subset(const ProjDataInfo& proj_data_info, - const DataSymmetriesForViewSegmentNumbers& symmetries, - const int min_segment_num, const int max_segment_num, - const int subset_num, const int num_subsets) - { - std::vector vs_nums_to_process; - for (int segment_num = min_segment_num; segment_num <= max_segment_num; segment_num++) - { - for (int view = proj_data_info.get_min_view_num() + subset_num; - view <= proj_data_info.get_max_view_num(); - view += num_subsets) - { - const ViewSegmentNumbers view_segment_num(view, segment_num); +std::vector +find_basic_vs_nums_in_subset(const ProjDataInfo& proj_data_info, const DataSymmetriesForViewSegmentNumbers& symmetries, + const int min_segment_num, const int max_segment_num, const int subset_num, const int num_subsets) { + std::vector vs_nums_to_process; + for (int segment_num = min_segment_num; segment_num <= max_segment_num; segment_num++) { + for (int timing_pos_num = -proj_data_info.get_min_tof_pos_num(); timing_pos_num <= proj_data_info.get_max_tof_pos_num(); + ++timing_pos_num) { + for (int view = proj_data_info.get_min_view_num() + subset_num; view <= proj_data_info.get_max_view_num(); + view += num_subsets) { + const ViewSegmentNumbers view_segment_num(view, segment_num); - if (!symmetries.is_basic(view_segment_num)) - continue; + if (!symmetries.is_basic(view_segment_num)) + continue; + + vs_nums_to_process.push_back(view_segment_num); - vs_nums_to_process.push_back(view_segment_num); - #ifndef NDEBUG - // test if symmetries didn't take us out of the segment range - std::vector rel_vs; - symmetries.get_related_view_segment_numbers(rel_vs, view_segment_num); - for (std::vector::const_iterator iter = rel_vs.begin(); iter!= rel_vs.end(); ++iter) - { - assert(iter->segment_num() >= min_segment_num); - assert(iter->segment_num() <= max_segment_num); - } + // test if symmetries didn't take us out of the segment range + std::vector rel_vs; + symmetries.get_related_view_segment_numbers(rel_vs, view_segment_num); + for (std::vector::const_iterator iter = rel_vs.begin(); iter != rel_vs.end(); ++iter) { + assert(iter->segment_num() >= min_segment_num); + assert(iter->segment_num() <= max_segment_num); + } #endif - } } - return vs_nums_to_process; + } } - + return vs_nums_to_process; } +} // namespace detail + END_NAMESPACE_STIR diff --git a/src/recon_buildblock/recon_buildblock_registries.cxx b/src/recon_buildblock/recon_buildblock_registries.cxx index ed1f212bdc..4fc7b0c1da 100644 --- a/src/recon_buildblock/recon_buildblock_registries.cxx +++ b/src/recon_buildblock/recon_buildblock_registries.cxx @@ -68,31 +68,32 @@ #include "stir/OSSPS/OSSPSReconstruction.h" #ifdef HAVE_LLN_MATRIX -#include "stir/recon_buildblock/BinNormalisationFromECAT7.h" +# include "stir/recon_buildblock/BinNormalisationFromECAT7.h" #endif #include "stir/recon_buildblock/BinNormalisationFromECAT8.h" #ifdef HAVE_HDF5 -#include "stir/recon_buildblock/BinNormalisationFromGEHDF5.h" +# include "stir/recon_buildblock/BinNormalisationFromGEHDF5.h" #endif #include "stir/recon_buildblock/FourierRebinning.h" #ifdef STIR_WITH_NiftyPET_PROJECTOR -#include "stir/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.h" -#include "stir/recon_buildblock/NiftyPET_projector/BackProjectorByBinNiftyPET.h" -#include "stir/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.h" +# include "stir/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.h" +# include "stir/recon_buildblock/NiftyPET_projector/BackProjectorByBinNiftyPET.h" +# include "stir/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.h" #endif //#include "stir/IO/InputFileFormatRegistry.h" START_NAMESPACE_STIR -//static RegisterInputFileFormat idummy0(0); +// static RegisterInputFileFormat idummy0(0); -static PoissonLogLikelihoodWithLinearModelForMeanAndProjData >::RegisterIt dummy1; -static PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin >::RegisterIt dummy2; +static PoissonLogLikelihoodWithLinearModelForMeanAndProjData>::RegisterIt dummy1; +static PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin>::RegisterIt + dummy2; -static FilterRootPrior >::RegisterIt dummy4; +static FilterRootPrior>::RegisterIt dummy4; static QuadraticPrior::RegisterIt dummy5; static PLSPrior::RegisterIt dummyPLS; static RelativeDifferencePrior::RegisterIt dummyRelativeDifference; @@ -120,14 +121,14 @@ static BinNormalisationFromProjData::RegisterIt dummy93; static BinNormalisationFromAttenuationImage::RegisterIt dummy94; static BinNormalisationSPECT::RegisterIt dummy95; static PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::RegisterIt Dummyxxx; -static PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion >::RegisterIt Dummyxxxzz; +static PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion>::RegisterIt Dummyxxxzz; static FBP2DReconstruction::RegisterIt dummy601; static FBP3DRPReconstruction::RegisterIt dummy602; -static OSMAPOSLReconstruction >::RegisterIt dummy603; -static KOSMAPOSLReconstruction >::RegisterIt dummyK ; -static OSSPSReconstruction >::RegisterIt dummy604; +static OSMAPOSLReconstruction>::RegisterIt dummy603; +static KOSMAPOSLReconstruction>::RegisterIt dummyK; +static OSSPSReconstruction>::RegisterIt dummy604; #ifdef STIR_WITH_NiftyPET_PROJECTOR static ForwardProjectorByBinNiftyPET::RegisterIt gpu_fwd; diff --git a/src/recon_test/CMakeLists.txt b/src/recon_test/CMakeLists.txt index c8d6e777db..653efeec20 100644 --- a/src/recon_test/CMakeLists.txt +++ b/src/recon_test/CMakeLists.txt @@ -38,6 +38,19 @@ set(${dir_INVOLVED_TEST_EXE_SOURCES} test_data_processor_projectors ) +#if (HAVE_CERN_ROOT) +# list(APPEND ${dir_INVOLVED_TEST_EXE_SOURCES} test_consistency_root) +# foreach(n RANGE 1 12 1) +# set(test_name test_consistency_root_${n}) +# ADD_TEST(NAME ${test_name} +# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/root_files_generation +# COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_consistency_root +# ${CMAKE_CURRENT_SOURCE_DIR}/root_files_generation/root_header_test${n}.hroot +# ${CMAKE_CURRENT_SOURCE_DIR}/root_files_generation/stir_image${n}.hv +# ) +# endforeach() +#endif() + include(stir_test_exe_targets) # a test that uses MPI diff --git a/src/recon_test/bcktest.cxx b/src/recon_test/bcktest.cxx index 1283be8ac5..5b527c99c3 100644 --- a/src/recon_test/bcktest.cxx +++ b/src/recon_test/bcktest.cxx @@ -31,10 +31,10 @@ bcktest [output-filename [proj_data_file \ [template-image [backprojector-parfile ]]]] \endverbatim - If some command line parameter is not given, the program will ask + If some command line parameter is not given, the program will ask the user interactively. - The format of the parameter file to specifiy the backproejctor is + The format of the parameter file to specifiy the backproejctor is as follows: \verbatim Back Projector parameters:= @@ -80,314 +80,240 @@ using std::cerr; using std::endl; #endif - - - START_NAMESPACE_STIR void -do_segments(DiscretisedDensity<3,float>& image, - ProjData& proj_data_org, - const int start_segment_num, const int end_segment_num, - const int start_axial_pos_num, const int end_axial_pos_num, - const int start_tang_pos_num,const int end_tang_pos_num, - const int start_view, const int end_view, - BackProjectorByBin* back_projector_ptr, - bool fill_with_1) -{ - - shared_ptr - symmetries_sptr(back_projector_ptr->get_symmetries_used()->clone()); - - +do_segments(DiscretisedDensity<3, float>& image, ProjData& proj_data_org, const int start_timing_num, const int end_timing_num, + const int start_segment_num, const int end_segment_num, const int start_axial_pos_num, const int end_axial_pos_num, + const int start_tang_pos_num, const int end_tang_pos_num, const int start_view, const int end_view, + BackProjectorByBin* back_projector_ptr, bool fill_with_1) { + + shared_ptr symmetries_sptr(back_projector_ptr->get_symmetries_used()->clone()); + list already_processed; - back_projector_ptr->start_accumulating_in_new_target(); - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - for (int view= start_view; view<=end_view; view++) - { - ViewSegmentNumbers vs(view, segment_num); - symmetries_sptr->find_basic_view_segment_numbers(vs); - if (find(already_processed.begin(), already_processed.end(), vs) - != already_processed.end()) - continue; - - already_processed.push_back(vs); - - cerr << "Processing view " << vs.view_num() - << " of segment " < viewgrams_empty= - proj_data_org.get_empty_related_viewgrams(vs, symmetries_sptr); - //proj_data_org.get_empty_related_viewgrams(vs.view_num(),vs.segment_num(), symmetries_sptr); - - RelatedViewgrams::iterator r_viewgrams_iter = viewgrams_empty.begin(); - while(r_viewgrams_iter!=viewgrams_empty.end()) - { - Viewgram& single_viewgram = *r_viewgrams_iter; - if (start_view <= single_viewgram.get_view_num() && - single_viewgram.get_view_num() <= end_view && - single_viewgram.get_segment_num() >= start_segment_num && - single_viewgram.get_segment_num() <= end_segment_num) - { - single_viewgram.fill(1.F); - } - r_viewgrams_iter++; - } - - back_projector_ptr->back_project(viewgrams_empty, - std::max(start_axial_pos_num, viewgrams_empty.get_min_axial_pos_num()), - std::min(end_axial_pos_num, viewgrams_empty.get_max_axial_pos_num()), - start_tang_pos_num, end_tang_pos_num); - } - else - { - RelatedViewgrams viewgrams = - proj_data_org.get_related_viewgrams(vs, - //proj_data_org.get_related_viewgrams(vs.view_num(),vs.segment_num(), - symmetries_sptr); - RelatedViewgrams::iterator r_viewgrams_iter = viewgrams.begin(); - - while(r_viewgrams_iter!=viewgrams.end()) - { - Viewgram& single_viewgram = *r_viewgrams_iter; - { - if (start_view <= single_viewgram.get_view_num() && - single_viewgram.get_view_num() <= end_view && - single_viewgram.get_segment_num() >= start_segment_num && - single_viewgram.get_segment_num() <= end_segment_num) - { - // ok - } - else - { - // set to 0 to prevent it being backprojected - single_viewgram.fill(0); - } - } - ++r_viewgrams_iter; - } - - back_projector_ptr->back_project(viewgrams, - std::max(start_axial_pos_num, viewgrams.get_min_axial_pos_num()), - std::min(end_axial_pos_num, viewgrams.get_max_axial_pos_num()), - start_tang_pos_num, end_tang_pos_num); - } // fill - } // for view_num, segment_num - - back_projector_ptr->get_output(image); - + for (int timing_num = start_timing_num; timing_num <= end_timing_num; ++timing_num) { + already_processed.clear(); + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) + for (int view = start_view; view <= end_view; view++) { + ViewSegmentNumbers vs(view, segment_num); + symmetries_sptr->find_basic_view_segment_numbers(vs); + if (find(already_processed.begin(), already_processed.end(), vs) != already_processed.end()) + continue; + + already_processed.push_back(vs); + + cerr << "Processing view " << vs.view_num() << " of segment " << vs.segment_num() << " of timing position index " + << timing_num << endl; + + if (fill_with_1) { + RelatedViewgrams viewgrams_empty = + proj_data_org.get_empty_related_viewgrams(vs, symmetries_sptr, false, timing_num); + // proj_data_org.get_empty_related_viewgrams(vs.view_num(),vs.segment_num(), symmetries_sptr); + + RelatedViewgrams::iterator r_viewgrams_iter = viewgrams_empty.begin(); + while (r_viewgrams_iter != viewgrams_empty.end()) { + Viewgram& single_viewgram = *r_viewgrams_iter; + if (start_view <= single_viewgram.get_view_num() && single_viewgram.get_view_num() <= end_view && + single_viewgram.get_segment_num() >= start_segment_num && single_viewgram.get_segment_num() <= end_segment_num) { + single_viewgram.fill(1.F); + } + r_viewgrams_iter++; + } + + back_projector_ptr->back_project( + viewgrams_empty, std::max(start_axial_pos_num, viewgrams_empty.get_min_axial_pos_num()), + std::min(end_axial_pos_num, viewgrams_empty.get_max_axial_pos_num()), start_tang_pos_num, end_tang_pos_num); + } else { + RelatedViewgrams viewgrams = + proj_data_org.get_related_viewgrams(vs, + // proj_data_org.get_related_viewgrams(vs.view_num(),vs.segment_num(), + symmetries_sptr, false, timing_num); + RelatedViewgrams::iterator r_viewgrams_iter = viewgrams.begin(); + + while (r_viewgrams_iter != viewgrams.end()) { + Viewgram& single_viewgram = *r_viewgrams_iter; + { + if (start_view <= single_viewgram.get_view_num() && single_viewgram.get_view_num() <= end_view && + single_viewgram.get_segment_num() >= start_segment_num && + single_viewgram.get_segment_num() <= end_segment_num) { + // ok + } else { + // set to 0 to prevent it being backprojected + single_viewgram.fill(0); + } + } + ++r_viewgrams_iter; + } + + back_projector_ptr->back_project(viewgrams, std::max(start_axial_pos_num, viewgrams.get_min_axial_pos_num()), + std::min(end_axial_pos_num, viewgrams.get_max_axial_pos_num()), start_tang_pos_num, + end_tang_pos_num); + } // fill + } // for view_num, segment_num + } // for timing_pos_num } END_NAMESPACE_STIR - - USING_NAMESPACE_STIR int -main(int argc, char **argv) -{ - if (argc==1 || argc>7) - { - cerr <<"Usage: " << argv[0] << " \\\n" - << "\t[output-filename [proj_data_file [template-image [backprojector-parfile ]]]]\n"; - exit(EXIT_FAILURE); - } - const std::string output_filename= - argc>1? argv[1] : ask_string("Output filename"); +main(int argc, char** argv) { + if (argc == 1 || argc > 7) { + cerr << "Usage: " << argv[0] << " \\\n" + << "\t[output-filename [proj_data_file [template-image [backprojector-parfile ]]]]\n"; + exit(EXIT_FAILURE); + } + const std::string output_filename = argc > 1 ? argv[1] : ask_string("Output filename"); shared_ptr proj_data_ptr; bool fill; - if (argc>2) - { - proj_data_ptr = ProjData::read_from_file(argv[2]); - fill = ask("Do you want to backproject all 1s (Y) or the data (N) ?", true); - } - else - { - shared_ptr data_info(ProjDataInfo::ask_parameters()); - // create an empty ProjDataFromStream object - // such that we don't have to differentiate between code later on - shared_ptr exam_info_sptr(new ExamInfo); - proj_data_ptr.reset(new ProjDataFromStream (exam_info_sptr, data_info,shared_ptr())); - fill = true; - } + if (argc > 2) { + proj_data_ptr = ProjData::read_from_file(argv[2]); + fill = ask("Do you want to backproject all 1s (Y) or the data (N) ?", true); + } else { + shared_ptr data_info(ProjDataInfo::ask_parameters()); + // create an empty ProjDataFromStream object + // such that we don't have to differentiate between code later on + shared_ptr exam_info_sptr(new ExamInfo); + proj_data_ptr.reset(new ProjDataFromStream(exam_info_sptr, data_info, shared_ptr())); + fill = true; + } shared_ptr back_projector_ptr; const bool disp = ask("Display images ?", false); - + const bool save = ask("Save images ?", true); - + const bool save_profiles = ask("Save horizontal profiles ?", false); - // note: first check 4th parameter for historical reasons + // note: first check 4th parameter for historical reasons // (could be switched with 3rd without problems) - if (argc>4) - { - KeyParser parser; - parser.add_start_key("Back Projector parameters"); - parser.add_parsing_key("type", &back_projector_ptr); - parser.add_stop_key("END"); - parser.parse(argv[4]); - } + if (argc > 4) { + KeyParser parser; + parser.add_start_key("Back Projector parameters"); + parser.add_parsing_key("type", &back_projector_ptr); + parser.add_stop_key("END"); + parser.parse(argv[4]); + } - const shared_ptr proj_data_info_sptr = - proj_data_ptr->get_proj_data_info_sptr(); - - shared_ptr > image_sptr; + const shared_ptr proj_data_info_sptr = proj_data_ptr->get_proj_data_info_sptr(); + + shared_ptr> image_sptr; + + if (argc > 3) { + image_sptr = read_from_file>(argv[3]); + } else { + const float zoom = ask_num("Zoom factor (>1 means smaller voxels)", 0.F, 100.F, 1.F); + int xy_size = static_cast(proj_data_ptr->get_num_tangential_poss() * zoom); + xy_size = ask_num("Number of x,y pixels", 3, xy_size * 2, xy_size); + int z_size = 2 * proj_data_info_sptr->get_scanner_ptr()->get_num_rings() - 1; + z_size = ask_num("Number of z pixels", 1, 1000, z_size); + VoxelsOnCartesianGrid* vox_image_ptr = new VoxelsOnCartesianGrid( + *proj_data_info_sptr, zoom, Coordinate3D(0, 0, 0), Coordinate3D(z_size, xy_size, xy_size)); + const float z_origin = + ask_num("Shift z-origin (in pixels)", -vox_image_ptr->get_length() / 2, vox_image_ptr->get_length() / 2, 0) * + vox_image_ptr->get_voxel_size().z(); + vox_image_ptr->set_origin(Coordinate3D(z_origin, 0, 0)); + + image_sptr.reset(vox_image_ptr); + } - if (argc>3) - { - image_sptr = read_from_file >(argv[3]); - } - else - { - const float zoom = ask_num("Zoom factor (>1 means smaller voxels)",0.F,100.F,1.F); - int xy_size = static_cast(proj_data_ptr->get_num_tangential_poss()*zoom); - xy_size = ask_num("Number of x,y pixels",3,xy_size*2,xy_size); - int z_size = 2*proj_data_info_sptr->get_scanner_ptr()->get_num_rings()-1; - z_size = ask_num("Number of z pixels",1,1000,z_size); - VoxelsOnCartesianGrid * vox_image_ptr = - new VoxelsOnCartesianGrid(*proj_data_info_sptr, - zoom, - Coordinate3D(0,0,0), - Coordinate3D(z_size,xy_size,xy_size)); - const float z_origin = - ask_num("Shift z-origin (in pixels)", - -vox_image_ptr->get_length()/2, - vox_image_ptr->get_length()/2, - 0) - *vox_image_ptr->get_voxel_size().z(); - vox_image_ptr->set_origin(Coordinate3D(z_origin,0,0)); - - image_sptr.reset(vox_image_ptr); - } + while (is_null_ptr(back_projector_ptr)) { + back_projector_ptr.reset(BackProjectorByBin::ask_type_and_parameters()); + } - while (is_null_ptr(back_projector_ptr)) - { - back_projector_ptr.reset(BackProjectorByBin::ask_type_and_parameters()); - } + back_projector_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), image_sptr); + + do { + int min_timing_num = ask_num("Minimum timing position index to backproject", proj_data_info_sptr->get_min_tof_pos_num(), + proj_data_info_sptr->get_max_tof_pos_num(), proj_data_info_sptr->get_min_tof_pos_num()); + int max_timing_num = ask_num("Maximum timing position index to backproject", min_timing_num, + proj_data_info_sptr->get_max_tof_pos_num(), min_timing_num); + int min_segment_num = ask_num("Minimum segment number to backproject", proj_data_info_sptr->get_min_segment_num(), + proj_data_info_sptr->get_max_segment_num(), 0); + int max_segment_num = ask_num("Maximum segment number to backproject", min_segment_num, + proj_data_info_sptr->get_max_segment_num(), min_segment_num); - back_projector_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), - image_sptr); - - do - { - - int min_segment_num = ask_num("Minimum segment number to backproject", - proj_data_info_sptr->get_min_segment_num(), proj_data_info_sptr->get_max_segment_num(), 0); - int max_segment_num = ask_num("Maximum segment number to backproject", - min_segment_num,proj_data_info_sptr->get_max_segment_num(), - min_segment_num); - // find max_axial_pos_num in the range of segments // TODO relies on axial_pos_num starting from 0 assert(proj_data_info_sptr->get_min_axial_pos_num(0) == 0); -#if 1 +#if 1 int max_axial_pos_num; - if (min_segment_num <= 0 && 0 <= max_segment_num) - { + if (min_segment_num <= 0 && 0 <= max_segment_num) { // all axial_poss are addressed for segment 0 max_axial_pos_num = proj_data_info_sptr->get_max_axial_pos_num(0); + } else { + if (min_segment_num > 0) // which implies max_segment_num>0 + max_axial_pos_num = proj_data_info_sptr->get_max_axial_pos_num(min_segment_num); + else // min_segment_num <= max_segment_num < 0 + max_axial_pos_num = proj_data_info_sptr->get_max_axial_pos_num(max_segment_num); } - else - { - if (min_segment_num>0) // which implies max_segment_num>0 - max_axial_pos_num = proj_data_info_sptr->get_max_axial_pos_num(min_segment_num); - else // min_segment_num <= max_segment_num < 0 - max_axial_pos_num = proj_data_info_sptr->get_max_axial_pos_num(max_segment_num); - } - - const int start_axial_pos_num = - ask_num("Start axial_pos", 0, max_axial_pos_num, 0); - const int end_axial_pos_num = - ask_num("End axial_pos", start_axial_pos_num, max_axial_pos_num, max_axial_pos_num); + + const int start_axial_pos_num = ask_num("Start axial_pos", 0, max_axial_pos_num, 0); + const int end_axial_pos_num = ask_num("End axial_pos", start_axial_pos_num, max_axial_pos_num, max_axial_pos_num); #else const int min_axial_pos_num = proj_data_info_sptr->get_min_axial_pos_num(segment_num); const int max_axial_pos_num = proj_data_info_sptr->get_max_axial_pos_num(segment_num); - const int start_axial_pos_num = - ask_num("Start axial_pos", min_axial_pos_num, max_axial_pos_num, min_axial_pos_num); - const int end_axial_pos_num = - ask_num("End axial_pos", start_axial_pos_num, max_axial_pos_num, max_axial_pos_num); + const int start_axial_pos_num = ask_num("Start axial_pos", min_axial_pos_num, max_axial_pos_num, min_axial_pos_num); + const int end_axial_pos_num = ask_num("End axial_pos", start_axial_pos_num, max_axial_pos_num, max_axial_pos_num); #endif - + // TODO this message is symmetry specific const int nviews = proj_data_info_sptr->get_num_views(); - cerr << "Special views are at 0, " - << nviews/4 <<", " << nviews/2 <<", " << nviews/4*3 << endl; - - int start_view = ask_num("Start view", 0, nviews-1, 0); - int end_view = ask_num("End view", 0, nviews-1, nviews-1); - - const int start_tang_pos_num = - ask_num("Start tang_pos", - proj_data_info_sptr->get_min_tangential_pos_num(), - proj_data_info_sptr->get_max_tangential_pos_num(), - proj_data_info_sptr->get_min_tangential_pos_num()); - const int end_tang_pos_num = - ask_num("End tang_pos", - start_tang_pos_num, - proj_data_info_sptr->get_max_tangential_pos_num(), - proj_data_info_sptr->get_max_tangential_pos_num()); - //const int start_tang_pos_num = -end_tang_pos_num; + cerr << "Special views are at 0, " << nviews / 4 << ", " << nviews / 2 << ", " << nviews / 4 * 3 << endl; + + int start_view = ask_num("Start view", 0, nviews - 1, 0); + int end_view = ask_num("End view", 0, nviews - 1, nviews - 1); + + const int start_tang_pos_num = + ask_num("Start tang_pos", proj_data_info_sptr->get_min_tangential_pos_num(), + proj_data_info_sptr->get_max_tangential_pos_num(), proj_data_info_sptr->get_min_tangential_pos_num()); + const int end_tang_pos_num = ask_num("End tang_pos", start_tang_pos_num, proj_data_info_sptr->get_max_tangential_pos_num(), + proj_data_info_sptr->get_max_tangential_pos_num()); + // const int start_tang_pos_num = -end_tang_pos_num; if (!ask("Add this backprojection to image of previous run ?", false)) image_sptr->fill(0); - + CPUTimer timer; timer.reset(); back_projector_ptr->reset_timers(); back_projector_ptr->start_timers(); timer.start(); - do_segments(*image_sptr, - *proj_data_ptr, - min_segment_num, max_segment_num, - start_axial_pos_num,end_axial_pos_num, - start_tang_pos_num,end_tang_pos_num, - start_view, end_view, - back_projector_ptr.get(), - fill); - + do_segments(*image_sptr, *proj_data_ptr, min_timing_num, max_timing_num, min_segment_num, max_segment_num, + start_axial_pos_num, end_axial_pos_num, start_tang_pos_num, end_tang_pos_num, start_view, end_view, + back_projector_ptr.get(), fill); + timer.stop(); cerr << timer.value() << " s total CPU time\n"; - cerr << "of which " << back_projector_ptr->get_CPU_timer_value() - << " s is reported by backprojector\n"; - cerr << "min and max in image " << image_sptr->find_min() - << ", " << image_sptr->find_max() << endl; - + cerr << "of which " << back_projector_ptr->get_CPU_timer_value() << " s is reported by backprojector\n"; + cerr << "min and max in image " << image_sptr->find_min() << ", " << image_sptr->find_max() << endl; + if (disp) display(*image_sptr, image_sptr->find_max()); - - if (save) - { - cerr <<" - Saving " << output_filename << endl; - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, *image_sptr); - + + if (save) { + cerr << " - Saving " << output_filename << endl; + OutputFileFormat>::default_sptr()->write_to_file(output_filename, *image_sptr); } - if (save_profiles) - { - + if (save_profiles) { + cerr << "Writing horizontal profiles to bcktest.prof" << endl; ofstream profile("bcktest.prof"); - if (!profile) - { cerr << "Couldn't open " << "bcktest.prof"; } - - for (int z=image_sptr->get_min_index(); z<= image_sptr->get_max_index(); z++) - profile << (*image_sptr)[z][0] << '\n'; - } - - } - while (ask("One more ?", true)); + if (!profile) { + cerr << "Couldn't open " + << "bcktest.prof"; + } - return EXIT_SUCCESS; -} + for (int z = image_sptr->get_min_index(); z <= image_sptr->get_max_index(); z++) + profile << (*image_sptr)[z][0] << '\n'; + } + } while (ask("One more ?", true)); + return EXIT_SUCCESS; +} diff --git a/src/recon_test/fwdtest.cxx b/src/recon_test/fwdtest.cxx index 51baa13c1b..31a7f09f0d 100644 --- a/src/recon_test/fwdtest.cxx +++ b/src/recon_test/fwdtest.cxx @@ -26,7 +26,7 @@ \author PARAPET project This program allows forward projection of a few segments/views - only, or of the full data set. + only, or of the full data set. \par Usage: \verbatim @@ -34,7 +34,7 @@ \endverbatim The template_proj_data_file will be used to get the scanner, mashing etc. details (its data will \e not be used, nor will it be overwritten). - If some of these parameters are not given, some questions are asked. + If some of these parameters are not given, some questions are asked. \par Example parameter file for specifying the forward projector \verbatim @@ -68,415 +68,303 @@ #include "stir/is_null_ptr.h" #include - using std::cerr; using std::cout; using std::endl; USING_NAMESPACE_STIR -//USING_NAMESPACE_STD - +// USING_NAMESPACE_STD /******************* Declarations local functions *******************/ -static void -do_segments(const VoxelsOnCartesianGrid& image, ProjData& s3d, - const int start_segment_num, const int end_segment_num, - const int start_view, const int end_view, - const int start_tangential_pos_num, const int end_tangential_pos_num, - ForwardProjectorByBin&, - const bool disp); -static void -fill_cuboid(VoxelsOnCartesianGrid& image); -static void -fill_cylinder(VoxelsOnCartesianGrid& image); - - +static void do_segments(const VoxelsOnCartesianGrid& image, ProjData& s3d, const int start_timing_pos_num, + const int end_timing_pos_num, const int start_segment_num, const int end_segment_num, + const int start_view, const int end_view, const int start_tangential_pos_num, + const int end_tangential_pos_num, ForwardProjectorByBin&, const bool disp); +static void fill_cuboid(VoxelsOnCartesianGrid& image); +static void fill_cylinder(VoxelsOnCartesianGrid& image); /*************************** main ***********************************/ -int -main(int argc, char *argv[]) -{ - - if(argc<3 || argc>5) - { - std::cerr <<"Usage:\n" - << argv[0] << " \\\n" - << " output-filename template_proj_data_file [image_to_forward_project [forwardprojector-parfile ]]]\n" - <<"The template_proj_data_file will be used to get the scanner, mashing etc. details.\n"; +int +main(int argc, char* argv[]) { + + if (argc < 3 || argc > 5) { + std::cerr << "Usage:\n" + << argv[0] << " \\\n" + << " output-filename template_proj_data_file [image_to_forward_project [forwardprojector-parfile ]]]\n" + << "The template_proj_data_file will be used to get the scanner, mashing etc. details.\n"; exit(EXIT_FAILURE); } - + const std::string output_file_name = argv[1]; shared_ptr new_data_info_ptr; shared_ptr exam_info_sptr; - if(argc>=3) - { - shared_ptr proj_data_sptr = - ProjData::read_from_file(argv[2]); + if (argc >= 3) { + shared_ptr proj_data_sptr = ProjData::read_from_file(argv[2]); exam_info_sptr = proj_data_sptr->get_exam_info().create_shared_clone(); - new_data_info_ptr= proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); - } - else - { + new_data_info_ptr = proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); + } else { exam_info_sptr.reset(new ExamInfo); new_data_info_ptr.reset(ProjDataInfo::ask_parameters()); } - int limit_segments= - ask_num("Maximum absolute segment number to process: ", 0, - new_data_info_ptr->get_max_segment_num(), - new_data_info_ptr->get_max_segment_num() ); + int limit_segments = ask_num("Maximum absolute segment number to process: ", 0, new_data_info_ptr->get_max_segment_num(), + new_data_info_ptr->get_max_segment_num()); new_data_info_ptr->reduce_segment_range(-limit_segments, limit_segments); shared_ptr proj_data_ptr(new ProjDataInterfile(exam_info_sptr, new_data_info_ptr, output_file_name)); - cerr << "Output will be written to " << output_file_name - << " and its Interfile header\n"; + cerr << "Output will be written to " << output_file_name << " and its Interfile header\n"; - int dispstart = 0; int save = 0; - - shared_ptr > image_sptr; - VoxelsOnCartesianGrid * vox_image_ptr = 0; - - if (argc<4) - { - switch (int choice = ask_num("Start image is cuboid (1) or cylinder (2) or on file (3)",1,3,2)) - { - case 1: - case 2: - { - dispstart = - ask_num("Display start image ? no (0), yes (1)", 0,1,0); - - save = - ask_num("Save start images ? no (0), yes (1)", 0,1,0); - const float zoom = ask_num("Zoom factor (>1 means smaller voxels)",0.F,10.F,1.F); - int xy_size = static_cast(proj_data_ptr->get_num_tangential_poss()*zoom); - xy_size = ask_num("Number of x,y pixels",3,xy_size*2,xy_size); - const float zoom_z = ask_num("Zoom factor in z", 0.F, 10.F, 1.F); - int z_size = - stir::round((2*proj_data_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings()-1)*zoom_z); - z_size = ask_num("Number of z pixels",1,1000,z_size); - vox_image_ptr = - new VoxelsOnCartesianGrid(*(proj_data_ptr->get_proj_data_info_sptr()), - zoom, - CartesianCoordinate3D(0,0,0), - Coordinate3D(z_size,xy_size,xy_size)); - image_sptr.reset(vox_image_ptr); - vox_image_ptr->set_grid_spacing( - vox_image_ptr->get_grid_spacing()/ - CartesianCoordinate3D(zoom_z,1.F,1.F)); - if (choice==1) - fill_cuboid(*vox_image_ptr); - else - fill_cylinder(*vox_image_ptr); - break; - } - case 3: - { - char filename[max_filename_length]; - - ask_filename_with_extension(filename, "Input file name ?", ".hv"); - - image_sptr = - read_from_file >(filename); - vox_image_ptr = dynamic_cast *> (image_sptr.get()); - - break; - } - } + + shared_ptr> image_sptr; + VoxelsOnCartesianGrid* vox_image_ptr = 0; + + if (argc < 4) { + switch (int choice = ask_num("Start image is cuboid (1) or cylinder (2) or on file (3)", 1, 3, 2)) { + case 1: + case 2: { + dispstart = ask_num("Display start image ? no (0), yes (1)", 0, 1, 0); + + save = ask_num("Save start images ? no (0), yes (1)", 0, 1, 0); + const float zoom = ask_num("Zoom factor (>1 means smaller voxels)", 0.F, 10.F, 1.F); + int xy_size = static_cast(proj_data_ptr->get_num_tangential_poss() * zoom); + xy_size = ask_num("Number of x,y pixels", 3, xy_size * 2, xy_size); + const float zoom_z = ask_num("Zoom factor in z", 0.F, 10.F, 1.F); + int z_size = stir::round((2 * proj_data_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings() - 1) * zoom_z); + z_size = ask_num("Number of z pixels", 1, 1000, z_size); + vox_image_ptr = + new VoxelsOnCartesianGrid(*(proj_data_ptr->get_proj_data_info_sptr()), zoom, + CartesianCoordinate3D(0, 0, 0), Coordinate3D(z_size, xy_size, xy_size)); + image_sptr.reset(vox_image_ptr); + vox_image_ptr->set_grid_spacing(vox_image_ptr->get_grid_spacing() / CartesianCoordinate3D(zoom_z, 1.F, 1.F)); + if (choice == 1) + fill_cuboid(*vox_image_ptr); + else + fill_cylinder(*vox_image_ptr); + break; } - else - { - image_sptr = - read_from_file >(argv[3]); - vox_image_ptr = dynamic_cast *> (image_sptr.get()); + case 3: { + char filename[max_filename_length]; + + ask_filename_with_extension(filename, "Input file name ?", ".hv"); + + image_sptr = read_from_file>(filename); + vox_image_ptr = dynamic_cast*>(image_sptr.get()); + + break; } + } + } else { + image_sptr = read_from_file>(argv[3]); + vox_image_ptr = dynamic_cast*>(image_sptr.get()); + } + + const float z_origin = + ask_num("Shift z-origin (in pixels)", -vox_image_ptr->get_length() / 2, vox_image_ptr->get_length() / 2, 0) * + vox_image_ptr->get_voxel_size().z(); - const float z_origin = - ask_num("Shift z-origin (in pixels)", - -vox_image_ptr->get_length()/2, - vox_image_ptr->get_length()/2, - 0) *vox_image_ptr->get_voxel_size().z(); - - vox_image_ptr->set_origin(make_coordinate(z_origin,0.F,0.F) + vox_image_ptr->get_origin()); + vox_image_ptr->set_origin(make_coordinate(z_origin, 0.F, 0.F) + vox_image_ptr->get_origin()); // use shared_ptr such that it cleans up automatically shared_ptr forw_projector_ptr; - if (argc>=5) - { - KeyParser parser; - parser.add_start_key("Forward Projector parameters"); - parser.add_parsing_key("type", &forw_projector_ptr); - parser.add_stop_key("END"); - parser.parse(argv[4]); - } + if (argc >= 5) { + KeyParser parser; + parser.add_start_key("Forward Projector parameters"); + parser.add_parsing_key("type", &forw_projector_ptr); + parser.add_stop_key("END"); + parser.parse(argv[4]); + } - while (is_null_ptr(forw_projector_ptr)) - { - forw_projector_ptr.reset(ForwardProjectorByBin::ask_type_and_parameters()); - } + while (is_null_ptr(forw_projector_ptr)) { + forw_projector_ptr.reset(ForwardProjectorByBin::ask_type_and_parameters()); + } - forw_projector_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), - image_sptr); + forw_projector_ptr->set_up(proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), image_sptr); cerr << forw_projector_ptr->parameter_info(); - if (dispstart) - { - cerr << "Displaying start image"; - display(*image_sptr, image_sptr->find_max()); - } - + if (dispstart) { + cerr << "Displaying start image"; + display(*image_sptr, image_sptr->find_max()); + } - if (save) - { + if (save) { cerr << "Saving start image to 'test_image'" << endl; - OutputFileFormat >::default_sptr()-> - write_to_file("test_image", *image_sptr); + OutputFileFormat>::default_sptr()->write_to_file("test_image", *image_sptr); } - + std::list already_processed; - if (ask("Do full forward projection ?", true)) - { + if (ask("Do full forward projection ?", true)) { CPUTimer timer; timer.reset(); timer.start(); - - do_segments(*vox_image_ptr, *proj_data_ptr, - proj_data_ptr->get_min_segment_num(), proj_data_ptr->get_max_segment_num(), - proj_data_ptr->get_min_view_num(), - proj_data_ptr->get_max_view_num(), - proj_data_ptr->get_min_tangential_pos_num(), - proj_data_ptr->get_max_tangential_pos_num(), - *forw_projector_ptr, - false); - + do_segments(*vox_image_ptr, *proj_data_ptr, proj_data_ptr->get_min_tof_pos_num(), proj_data_ptr->get_max_tof_pos_num(), + proj_data_ptr->get_min_segment_num(), proj_data_ptr->get_max_segment_num(), proj_data_ptr->get_min_view_num(), + proj_data_ptr->get_max_view_num(), proj_data_ptr->get_min_tangential_pos_num(), + proj_data_ptr->get_max_tangential_pos_num(), *forw_projector_ptr, false); + timer.stop(); - cerr << timer.value() << " s CPU time"<get_min_segment_num(); - segment_num <= proj_data_ptr->get_max_segment_num(); - ++segment_num) - { - const SegmentByView segment = - proj_data_ptr->get_empty_segment_by_view(segment_num, false); - if (!(proj_data_ptr->set_segment(segment) == Succeeded::yes)) - warning("Error set_segment %d\n", segment_num); - } - do - { + for (int timing_pos_num = proj_data_ptr->get_min_tof_pos_num(); timing_pos_num <= proj_data_ptr->get_max_tof_pos_num(); + ++timing_pos_num) + for (int segment_num = proj_data_ptr->get_min_segment_num(); segment_num <= proj_data_ptr->get_max_segment_num(); + ++segment_num) { + const SegmentByView segment = proj_data_ptr->get_empty_segment_by_view(segment_num, false, timing_pos_num); + if (!(proj_data_ptr->set_segment(segment) == Succeeded::yes)) + warning("Error set_segment %d of timing position index %d\n", segment_num, timing_pos_num); + } + do { CPUTimer timer; timer.reset(); timer.start(); - - const int segment_num = - ask_num("Segment number to forward project (related segments will be done as well)", - proj_data_ptr->get_min_segment_num(), - proj_data_ptr->get_max_segment_num(), - 0); + + const int timing_pos_num = ask_num("Timing position index to forward project", proj_data_ptr->get_min_tof_pos_num(), + proj_data_ptr->get_max_tof_pos_num(), 0); + const int segment_num = ask_num("Segment number to forward project (related segments will be done as well)", + proj_data_ptr->get_min_segment_num(), proj_data_ptr->get_max_segment_num(), 0); const int min_view = proj_data_ptr->get_min_view_num(); const int max_view = proj_data_ptr->get_max_view_num(); - const int start_view = - ask_num("Start view (related views will be done as well)", min_view, max_view, min_view); - const int end_view = - ask_num("End view (related views will be done as well)", start_view, max_view, max_view); + const int start_view = ask_num("Start view (related views will be done as well)", min_view, max_view, min_view); + const int end_view = ask_num("End view (related views will be done as well)", start_view, max_view, max_view); const int min_tangential_pos_num = proj_data_ptr->get_min_tangential_pos_num(); const int max_tangential_pos_num = proj_data_ptr->get_max_tangential_pos_num(); - const int start_tangential_pos_num = - ask_num("Start tangential_pos_num", min_tangential_pos_num, max_tangential_pos_num, min_tangential_pos_num); - const int end_tangential_pos_num = - ask_num("End tangential_pos_num ", start_tangential_pos_num, max_tangential_pos_num, max_tangential_pos_num); - - do_segments(*vox_image_ptr,*proj_data_ptr, - segment_num,segment_num, - start_view, end_view, - start_tangential_pos_num, end_tangential_pos_num, - *forw_projector_ptr, disp); - + const int start_tangential_pos_num = + ask_num("Start tangential_pos_num", min_tangential_pos_num, max_tangential_pos_num, min_tangential_pos_num); + const int end_tangential_pos_num = + ask_num("End tangential_pos_num ", start_tangential_pos_num, max_tangential_pos_num, max_tangential_pos_num); + + do_segments(*vox_image_ptr, *proj_data_ptr, timing_pos_num, timing_pos_num, segment_num, segment_num, start_view, end_view, + start_tangential_pos_num, end_tangential_pos_num, *forw_projector_ptr, disp); timer.stop(); - cerr << timer.value() << " s CPU time"<& image, - ProjData& proj_data, - const int start_segment_num, const int end_segment_num, - const int start_view, const int end_view, - const int start_tangential_pos_num, const int end_tangential_pos_num, - ForwardProjectorByBin& forw_projector, - const bool disp) -{ - shared_ptr - symmetries_sptr(forw_projector.get_symmetries_used()->clone()); - +do_segments(const VoxelsOnCartesianGrid& image, ProjData& proj_data, const int start_timing_pos_num, + const int end_timing_pos_num, const int start_segment_num, const int end_segment_num, const int start_view, + const int end_view, const int start_tangential_pos_num, const int end_tangential_pos_num, + ForwardProjectorByBin& forw_projector, const bool disp) { + shared_ptr symmetries_sptr(forw_projector.get_symmetries_used()->clone()); + std::list already_processed; - - forw_projector.set_input(image); - - for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) - for (int view= start_view; view<=end_view; view++) - { - ViewSegmentNumbers vs(view, segment_num); - symmetries_sptr->find_basic_view_segment_numbers(vs); - if (find(already_processed.begin(), already_processed.end(), vs) - != already_processed.end()) - continue; - - already_processed.push_back(vs); - - cerr << "Processing view " << vs.view_num() - << " of segment " < viewgrams = - proj_data.get_empty_related_viewgrams(vs, symmetries_sptr,false); - forw_projector.forward_project(viewgrams, - viewgrams.get_min_axial_pos_num(), - viewgrams.get_max_axial_pos_num(), - start_tangential_pos_num, end_tangential_pos_num); - if (disp) - display(viewgrams, viewgrams.find_max()); - if (!(proj_data.set_related_viewgrams(viewgrams) == Succeeded::yes)) - error("Error set_related_viewgrams\n"); - } + for (int timing_pos_num = start_timing_pos_num; timing_pos_num <= end_timing_pos_num; ++timing_pos_num) { + already_processed.clear(); + for (int segment_num = start_segment_num; segment_num <= end_segment_num; ++segment_num) + for (int view = start_view; view <= end_view; view++) { + ViewSegmentNumbers vs(view, segment_num); + symmetries_sptr->find_basic_view_segment_numbers(vs); + if (find(already_processed.begin(), already_processed.end(), vs) != already_processed.end()) + continue; + + already_processed.push_back(vs); + + cerr << "Processing view " << vs.view_num() << " of segment " << vs.segment_num() << " of timing position index " + << timing_pos_num << endl; + + RelatedViewgrams viewgrams = proj_data.get_empty_related_viewgrams(vs, symmetries_sptr, false, timing_pos_num); + forw_projector.forward_project(viewgrams, viewgrams.get_min_axial_pos_num(), viewgrams.get_max_axial_pos_num(), + start_tangential_pos_num, end_tangential_pos_num); + if (disp) + display(viewgrams, viewgrams.find_max()); + if (!(proj_data.set_related_viewgrams(viewgrams) == Succeeded::yes)) + error("Error set_related_viewgrams\n"); + } + } } +void +fill_cuboid(VoxelsOnCartesianGrid& image) { + const float voxel_value = ask_num("Voxel value", -10E10F, 10E10F, 1.F); + const int xs = ask_num("Start X coordinate", image.get_min_x(), image.get_max_x(), (image.get_min_x() + image.get_max_x()) / 2); + const int ys = ask_num("Start Y coordinate", image.get_min_y(), image.get_max_y(), (image.get_min_y() + image.get_max_y()) / 2); + const int zs = ask_num("Start Z coordinate", image.get_min_z(), image.get_max_z(), (image.get_min_z() + image.get_max_z()) / 2); - -void fill_cuboid(VoxelsOnCartesianGrid& image) -{ - const float voxel_value = ask_num("Voxel value",-10E10F, 10E10F,1.F); - const int xs = ask_num("Start X coordinate", - image.get_min_x(), image.get_max_x(), - (image.get_min_x()+ image.get_max_x())/2); - const int ys = ask_num("Start Y coordinate", - image.get_min_y(), image.get_max_y(), - (image.get_min_y()+ image.get_max_y())/2); - const int zs = ask_num("Start Z coordinate", - image.get_min_z(), image.get_max_z(), - (image.get_min_z()+ image.get_max_z())/2); - const int xe = ask_num("End X coordinate", xs, image.get_max_x(), xs); const int ye = ask_num("End Y coordinate", ys, image.get_max_y(), ys); const int ze = ask_num("End Z coordinate", zs, image.get_max_z(), zs); - - - cerr << "Start coordinate: (x,y,z) = (" - << xs << ", " << ys << ", " << zs - << ")" << endl; - cerr << "End coordinate: (x,y,z) = (" - << xe << ", " << ye << ", " << ze - << ")" << endl; - + + cerr << "Start coordinate: (x,y,z) = (" << xs << ", " << ys << ", " << zs << ")" << endl; + cerr << "End coordinate: (x,y,z) = (" << xe << ", " << ye << ", " << ze << ")" << endl; + image.fill(0); - for (int z=zs; z<=ze; z++) - for (int y=ys; y <= ye; y++) - for (int x=xs; x<= xe; x++) - image[z][y][x] = voxel_value; + for (int z = zs; z <= ze; z++) + for (int y = ys; y <= ye; y++) + for (int x = xs; x <= xe; x++) + image[z][y][x] = voxel_value; } -void fill_cylinder(VoxelsOnCartesianGrid& image) -{ - const float voxel_value = ask_num("Voxel value",-10E10F, 10E10F,1.F); - - const double xc = - ask_num("Centre X coordinate", - (double)image.get_min_x(), (double)image.get_max_x(), - (image.get_min_x()+ image.get_max_x())/2.); - - const double yc = - ask_num("Centre Y coordinate", - (double)image.get_min_y(), (double)image.get_max_y(), - (image.get_min_y()+ image.get_max_y())/2.); - - const float zc = - ask_num("Centre Z coordinate", - (float)image.get_min_z(), (float)image.get_max_z(), - (image.get_min_z()+ image.get_max_z())/2.F); - - - const double Rcyl = - ask_num("Radius (pixels)", - .5, (image.get_max_x()- image.get_min_x())/2., - (image.get_max_x()- image.get_min_x())/4.); - +void +fill_cylinder(VoxelsOnCartesianGrid& image) { + const float voxel_value = ask_num("Voxel value", -10E10F, 10E10F, 1.F); + + const double xc = ask_num("Centre X coordinate", (double)image.get_min_x(), (double)image.get_max_x(), + (image.get_min_x() + image.get_max_x()) / 2.); + + const double yc = ask_num("Centre Y coordinate", (double)image.get_min_y(), (double)image.get_max_y(), + (image.get_min_y() + image.get_max_y()) / 2.); + + const float zc = ask_num("Centre Z coordinate", (float)image.get_min_z(), (float)image.get_max_z(), + (image.get_min_z() + image.get_max_z()) / 2.F); + + const double Rcyl = + ask_num("Radius (pixels)", .5, (image.get_max_x() - image.get_min_x()) / 2., (image.get_max_x() - image.get_min_x()) / 4.); + // Max length is num_planes+1 because of edges of voxels - const float Lcyl = - ask_num("Length (planes)", 1.F, (image.get_max_z()- image.get_min_z())+1.F, - (image.get_max_z()- image.get_min_z())+1.F); - - - cerr << "Centre coordinate: (x,y,z) = (" - << xc << ", " << yc << ", " << zc - << ")" << endl; - cerr << "Radius = " << Rcyl << ", Length = " << Lcyl << endl; - - const int num_samples = - ask_num("With how many points (in x,y direction) do I sample each voxel ?", - 1,100,5); - - Array<2,float> plane = image[0]; - - for (int y=image.get_min_y(); y<=image.get_max_y(); y++) - for (int x=image.get_min_x(); x<=image.get_max_x(); x++) - { - double value = 0; - - for (double ysmall=-(num_samples-1.)/num_samples/2.; - ysmall < 0.5; - ysmall+= 1./num_samples) - { - const double ytry = y-ysmall-yc; - - for (double xsmall=-(num_samples-1.)/num_samples/2.; - xsmall < 0.5; - xsmall+= 1./num_samples) - { - const double xtry = x-xsmall-xc; - - if (xtry*xtry + ytry*ytry <= Rcyl*Rcyl) - value++; - } - } - // update plane with normalised value (independent of num_samples) - plane[y][x] = static_cast(voxel_value*value/(num_samples*num_samples)); + const float Lcyl = ask_num("Length (planes)", 1.F, (image.get_max_z() - image.get_min_z()) + 1.F, + (image.get_max_z() - image.get_min_z()) + 1.F); + + cerr << "Centre coordinate: (x,y,z) = (" << xc << ", " << yc << ", " << zc << ")" << endl; + cerr << "Radius = " << Rcyl << ", Length = " << Lcyl << endl; + + const int num_samples = ask_num("With how many points (in x,y direction) do I sample each voxel ?", 1, 100, 5); + + Array<2, float> plane = image[0]; + + for (int y = image.get_min_y(); y <= image.get_max_y(); y++) + for (int x = image.get_min_x(); x <= image.get_max_x(); x++) { + double value = 0; + + for (double ysmall = -(num_samples - 1.) / num_samples / 2.; ysmall < 0.5; ysmall += 1. / num_samples) { + const double ytry = y - ysmall - yc; + + for (double xsmall = -(num_samples - 1.) / num_samples / 2.; xsmall < 0.5; xsmall += 1. / num_samples) { + const double xtry = x - xsmall - xc; + + if (xtry * xtry + ytry * ytry <= Rcyl * Rcyl) + value++; + } } - - for (int z=image.get_min_z(); z<=image.get_max_z(); z++) - { - // use 2. to make both args of min() and max() double - float zfactor = (std::min(z+.5F, zc+Lcyl/2.F) - std::max(z-.5F, zc-Lcyl/2.F)); - if (zfactor<0) zfactor = 0; - image[z] = plane; - image[z] *= zfactor; + // update plane with normalised value (independent of num_samples) + plane[y][x] = static_cast(voxel_value * value / (num_samples * num_samples)); } - -} + for (int z = image.get_min_z(); z <= image.get_max_z(); z++) { + // use 2. to make both args of min() and max() double + float zfactor = (std::min(z + .5F, zc + Lcyl / 2.F) - std::max(z - .5F, zc - Lcyl / 2.F)); + if (zfactor < 0) + zfactor = 0; + image[z] = plane; + image[z] *= zfactor; + } +} diff --git a/src/recon_test/recontest.cxx b/src/recon_test/recontest.cxx index 139d372126..2dc4d40667 100644 --- a/src/recon_test/recontest.cxx +++ b/src/recon_test/recontest.cxx @@ -14,7 +14,6 @@ */ - #include "stir/DiscretisedDensity.h" #include "stir/IO/read_from_file.h" #include "stir/recon_buildblock/Reconstruction.h" @@ -25,70 +24,66 @@ #include "stir/CPUTimer.h" #include "stir/HighResWallClockTimer.h" -static void print_usage_and_exit() -{ - std::cerr<<"This executable is able to reconstruct some data without calling a specific reconstruction method, from the code.\n"; - std::cerr<<"but specifing the method in the par file with the \"econstruction method\". \n"; - std::cerr<<"\nUsage:\nrecontest reconstuction.par\n"; - std::cerr<<"Example parameter file:\n\n" - <<"reconstruction method := OSMAPOSL\n" - <<"OSMAPOSLParameters := \n" - <<"objective function type:= PoissonLogLikelihoodWithLinearModelForMeanAndProjData\n" - <<"PoissonLogLikelihoodWithLinearModelForMeanAndProjData Parameters:=\n" - <<"input file := .hs\n" - <<"maximum absolute segment number to process := -1\n" - <<"projector pair type := Matrix\n" - <<"Projector Pair Using Matrix Parameters :=\n" - <<"Matrix type := Ray Tracing\n" - <<"Ray tracing matrix parameters :=\n" - <<"number of rays in tangential direction to trace for each bin:= 10\n" - <<"End Ray tracing matrix parameters :=\n" - <<"End Projector Pair Using Matrix Parameters :=\n" - <<"recompute sensitivity := 1\n" - <<"zoom := 1\n" - <<"end PoissonLogLikelihoodWithLinearModelForMeanAndProjData Parameters:=\n" - <<"enforce initial positivity condition:= 1 \n" - <<"number of subsets:= 1\n" - <<"number of subiterations:= 1 \n" - <<"save estimates at subiteration intervals:= 1\n" - <<"output filename prefix := output\n" - <<"end OSMAPOSLParameters := \n" - <<"end reconstruction := \n"; - exit(EXIT_FAILURE); +static void +print_usage_and_exit() { + std::cerr + << "This executable is able to reconstruct some data without calling a specific reconstruction method, from the code.\n"; + std::cerr << "but specifing the method in the par file with the \"econstruction method\". \n"; + std::cerr << "\nUsage:\nrecontest reconstuction.par\n"; + std::cerr << "Example parameter file:\n\n" + << "reconstruction method := OSMAPOSL\n" + << "OSMAPOSLParameters := \n" + << "objective function type:= PoissonLogLikelihoodWithLinearModelForMeanAndProjData\n" + << "PoissonLogLikelihoodWithLinearModelForMeanAndProjData Parameters:=\n" + << "input file := .hs\n" + << "maximum absolute segment number to process := -1\n" + << "projector pair type := Matrix\n" + << "Projector Pair Using Matrix Parameters :=\n" + << "Matrix type := Ray Tracing\n" + << "Ray tracing matrix parameters :=\n" + << "number of rays in tangential direction to trace for each bin:= 10\n" + << "End Ray tracing matrix parameters :=\n" + << "End Projector Pair Using Matrix Parameters :=\n" + << "recompute sensitivity := 1\n" + << "zoom := 1\n" + << "end PoissonLogLikelihoodWithLinearModelForMeanAndProjData Parameters:=\n" + << "enforce initial positivity condition:= 1 \n" + << "number of subsets:= 1\n" + << "number of subiterations:= 1 \n" + << "save estimates at subiteration intervals:= 1\n" + << "output filename prefix := output\n" + << "end OSMAPOSLParameters := \n" + << "end reconstruction := \n"; + exit(EXIT_FAILURE); } - /***********************************************************/ -int main(int argc, const char *argv[]) -{ - using namespace stir; +int +main(int argc, const char* argv[]) { + using namespace stir; - if (argc!=2) - print_usage_and_exit(); + if (argc != 2) + print_usage_and_exit(); - shared_ptr < Reconstruction < DiscretisedDensity < 3, float > > > - reconstruction_method_sptr; + shared_ptr>> reconstruction_method_sptr; - KeyParser parser; - parser.add_start_key("Reconstruction"); - parser.add_stop_key("End Reconstruction"); - parser.add_parsing_key("reconstruction method", &reconstruction_method_sptr); - parser.parse(argv[1]); + KeyParser parser; + parser.add_start_key("Reconstruction"); + parser.add_stop_key("End Reconstruction"); + parser.add_parsing_key("reconstruction method", &reconstruction_method_sptr); + parser.parse(argv[1]); - HighResWallClockTimer t; - t.reset(); - t.start(); + HighResWallClockTimer t; + t.reset(); + t.start(); - if (reconstruction_method_sptr->reconstruct() == Succeeded::yes) - { - t.stop(); - std::cout << "Total Wall clock time: " << t.value() << " seconds" << std::endl; - return EXIT_SUCCESS; - } - else - { - t.stop(); - return EXIT_FAILURE; - } + if (reconstruction_method_sptr->reconstruct() == Succeeded::yes) { + t.stop(); + std::cout << "Total Wall clock time: " << t.value() << " seconds" << std::endl; + return EXIT_SUCCESS; + } else { + t.stop(); + return EXIT_FAILURE; + } } diff --git a/src/recon_test/test_DataSymmetriesForBins_PET_CartesianGrid.cxx b/src/recon_test/test_DataSymmetriesForBins_PET_CartesianGrid.cxx index 53556fb922..643af47fee 100644 --- a/src/recon_test/test_DataSymmetriesForBins_PET_CartesianGrid.cxx +++ b/src/recon_test/test_DataSymmetriesForBins_PET_CartesianGrid.cxx @@ -20,13 +20,13 @@ \file \ingroup test - + \brief Test program for stir::DataSymmetriesForBins_PET_CartesianGrid Uses stir::ProjMatrixByBinUsingRayTracing. - + \author Kris Thielemans - + */ #include "stir/VoxelsOnCartesianGrid.h" @@ -52,11 +52,9 @@ using std::cerr; START_NAMESPACE_STIR template -bool -coordinates_less(const BasicCoordinate<3,T>& el1, const BasicCoordinate<3,T>& el2) -{ - return el1[1]& el1, const BasicCoordinate<3, T>& el2) { + return el1[1] < el2[1] || (el1[1] == el2[1] && (el1[2] < el2[2] || (el1[2] == el2[2] && el1[3] < el2[3]))); } /*! @@ -68,39 +66,33 @@ coordinates_less(const BasicCoordinate<3,T>& el1, const BasicCoordinate<3,T>& el symmetries. Checks if results are independent of which symmetries we use. */ -class DataSymmetriesForBins_PET_CartesianGridTests : public RunTests -{ +class DataSymmetriesForBins_PET_CartesianGridTests : public RunTests { public: - DataSymmetriesForBins_PET_CartesianGridTests(char const * template_proj_data_filename = 0); + DataSymmetriesForBins_PET_CartesianGridTests(char const* template_proj_data_filename = 0); void run_tests(); + private: - char const * template_proj_data_filename; + char const* template_proj_data_filename; shared_ptr proj_data_info_sptr; - void run_tests_2_proj_matrices_1_bin(const ProjMatrixByBin& proj_matrix_no_symm, - const ProjMatrixByBin& proj_matrix_with_symm, - const Bin& bin); - void run_tests_2_proj_matrices(const ProjMatrixByBin& proj_matrix_no_symm, - const ProjMatrixByBin& proj_matrix_with_symm); + void run_tests_2_proj_matrices_1_bin(const ProjMatrixByBin& proj_matrix_no_symm, const ProjMatrixByBin& proj_matrix_with_symm, + const Bin& bin); + void run_tests_2_proj_matrices(const ProjMatrixByBin& proj_matrix_no_symm, const ProjMatrixByBin& proj_matrix_with_symm); void run_tests_all_symmetries(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_sptr - ); + const shared_ptr>& density_sptr); void run_tests_for_1_projdata(const shared_ptr& proj_data_info_sptr); }; -DataSymmetriesForBins_PET_CartesianGridTests:: -DataSymmetriesForBins_PET_CartesianGridTests(char const * template_proj_data_filename) - : template_proj_data_filename(template_proj_data_filename) -{} +DataSymmetriesForBins_PET_CartesianGridTests::DataSymmetriesForBins_PET_CartesianGridTests( + char const* template_proj_data_filename) + : template_proj_data_filename(template_proj_data_filename) {} void -DataSymmetriesForBins_PET_CartesianGridTests:: -run_tests_2_proj_matrices_1_bin(const ProjMatrixByBin& proj_matrix_no_symm, - const ProjMatrixByBin& proj_matrix_with_symm, - const Bin& bin) -{ +DataSymmetriesForBins_PET_CartesianGridTests::run_tests_2_proj_matrices_1_bin(const ProjMatrixByBin& proj_matrix_no_symm, + const ProjMatrixByBin& proj_matrix_with_symm, + const Bin& bin) { #if 0 // SYM // assert(proj_matrix_with_symm.get_symmetries_ptr()->is_basic(bin)); // vector related_bins; @@ -122,483 +114,391 @@ run_tests_2_proj_matrices_1_bin(const ProjMatrixByBin& proj_matrix_no_symm, get_proj_matrix_elems_for_one_bin(elems_no_sym, *bin_iter); #else - ProjMatrixElemsForOneBin elems_no_sym; - ProjMatrixElemsForOneBin elems_with_sym; - { - proj_matrix_with_symm. - get_proj_matrix_elems_for_one_bin(elems_with_sym, bin); - proj_matrix_no_symm. - get_proj_matrix_elems_for_one_bin(elems_no_sym, bin); + ProjMatrixElemsForOneBin elems_no_sym; + ProjMatrixElemsForOneBin elems_with_sym; + { + proj_matrix_with_symm.get_proj_matrix_elems_for_one_bin(elems_with_sym, bin); + proj_matrix_no_symm.get_proj_matrix_elems_for_one_bin(elems_no_sym, bin); #endif - elems_no_sym.sort(); - elems_with_sym.sort(); - if (!check(elems_no_sym == elems_with_sym, "comparing lors")) - { - // SYM const Bin bin=*bin_iter; - cerr << "Current bin: segment = " << bin.segment_num() - << ", axial pos " << bin.axial_pos_num() - << ", view = " << bin.view_num() - << ", tangential_pos_num = " << bin.tangential_pos_num() << "\n"; - ProjMatrixElemsForOneBin::const_iterator no_sym_iter= elems_no_sym.begin(); - ProjMatrixElemsForOneBin::const_iterator with_sym_iter = elems_with_sym.begin(); - while (no_sym_iter!= elems_no_sym.end() || with_sym_iter!=elems_with_sym.end()) - { - if (no_sym_iter==elems_no_sym.end() || - with_sym_iter==elems_with_sym.end() || - no_sym_iter->get_coords()!= with_sym_iter->get_coords() || - fabs(no_sym_iter->get_value()/with_sym_iter->get_value() -1) > .0002) - { - bool inc_no_sym_iter = false; - if (no_sym_iter!=elems_no_sym.end() && - (with_sym_iter==elems_with_sym.end() || - coordinates_less(no_sym_iter->get_coords(),with_sym_iter->get_coords()) || - no_sym_iter->get_coords()==with_sym_iter->get_coords())) - { - cerr << no_sym_iter->get_coords() - << ':' << no_sym_iter->get_value() - << " || "; - inc_no_sym_iter = true; - } - else - cerr << " || "; - if (with_sym_iter!=elems_with_sym.end() && - (no_sym_iter==elems_no_sym.end() || - !coordinates_less(no_sym_iter->get_coords(),with_sym_iter->get_coords()))) - { - cerr << with_sym_iter->get_coords() - << ':' << with_sym_iter->get_value(); - ++with_sym_iter; - } - if (inc_no_sym_iter) - ++no_sym_iter; - cerr << "\n"; - } - else - { - if (no_sym_iter!=elems_no_sym.end()) - ++no_sym_iter; - if (with_sym_iter!=elems_with_sym.end()) - ++with_sym_iter; - } - } - } + elems_no_sym.sort(); + elems_with_sym.sort(); + if (!check(elems_no_sym == elems_with_sym, "comparing lors")) { + // SYM const Bin bin=*bin_iter; + cerr << "Current bin: segment = " << bin.segment_num() << ", axial pos " << bin.axial_pos_num() + << ", view = " << bin.view_num() << ", tangential_pos_num = " << bin.tangential_pos_num() + << ", timing position index = " << bin.timing_pos_num() << "\n"; + ProjMatrixElemsForOneBin::const_iterator no_sym_iter = elems_no_sym.begin(); + ProjMatrixElemsForOneBin::const_iterator with_sym_iter = elems_with_sym.begin(); + while (no_sym_iter != elems_no_sym.end() || with_sym_iter != elems_with_sym.end()) { + if (no_sym_iter == elems_no_sym.end() || with_sym_iter == elems_with_sym.end() || + no_sym_iter->get_coords() != with_sym_iter->get_coords() || + fabs(no_sym_iter->get_value() / with_sym_iter->get_value() - 1) > .01) { + bool inc_no_sym_iter = false; + if (no_sym_iter != elems_no_sym.end() && + (with_sym_iter == elems_with_sym.end() || coordinates_less(no_sym_iter->get_coords(), with_sym_iter->get_coords()) || + no_sym_iter->get_coords() == with_sym_iter->get_coords())) { + cerr << no_sym_iter->get_coords() << ':' << no_sym_iter->get_value() << " || "; + inc_no_sym_iter = true; + } else + cerr << " || "; + if (with_sym_iter != elems_with_sym.end() && + (no_sym_iter == elems_no_sym.end() || !coordinates_less(no_sym_iter->get_coords(), with_sym_iter->get_coords()))) { + cerr << with_sym_iter->get_coords() << ':' << with_sym_iter->get_value(); + ++with_sym_iter; + } + if (inc_no_sym_iter) + ++no_sym_iter; + cerr << "\n"; + } else { + if (no_sym_iter != elems_no_sym.end()) + ++no_sym_iter; + if (with_sym_iter != elems_with_sym.end()) + ++with_sym_iter; + } } + } +} } void -DataSymmetriesForBins_PET_CartesianGridTests:: -run_tests_2_proj_matrices(const ProjMatrixByBin& proj_matrix_no_symm, - const ProjMatrixByBin& proj_matrix_with_symm) -{ +DataSymmetriesForBins_PET_CartesianGridTests::run_tests_2_proj_matrices(const ProjMatrixByBin& proj_matrix_no_symm, + const ProjMatrixByBin& proj_matrix_with_symm) { #if 1 - for (int s=-proj_data_info_sptr->get_max_segment_num(); s<=proj_data_info_sptr->get_max_segment_num(); ++s) - for (int v=proj_data_info_sptr->get_min_view_num(); - v <= proj_data_info_sptr->get_max_view_num(); - ++v) - for (int a=proj_data_info_sptr->get_min_axial_pos_num(s); - a <= proj_data_info_sptr->get_max_axial_pos_num(s); - ++a) - for (int t=-6; t<=6; t+=3) - { - const Bin bin(s,v,a,t); - //SYM if (proj_matrix_with_symm.get_symmetries_ptr()->is_basic(bin)) - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); - } + for (int s = -proj_data_info_sptr->get_max_segment_num(); s <= proj_data_info_sptr->get_max_segment_num(); ++s) + for (int v = proj_data_info_sptr->get_min_view_num(); v <= proj_data_info_sptr->get_max_view_num(); ++v) + for (int timing_pos = proj_data_info_sptr->get_min_tof_pos_num(); timing_pos <= proj_data_info_sptr->get_max_tof_pos_num(); + ++timing_pos) + for (int a = proj_data_info_sptr->get_min_axial_pos_num(s); a <= proj_data_info_sptr->get_max_axial_pos_num(s); ++a) + for (int t = -6; t <= 6; t += 3) { + const Bin bin(s, v, a, t, timing_pos); + // SYM if (proj_matrix_with_symm.get_symmetries_ptr()->is_basic(bin)) + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); + } #else const int oblique_seg_num = proj_data_info_sptr->get_max_segment_num(); - const int view45 = - proj_data_info_sptr->get_num_views()/4; - assert(fabs(proj_data_info_sptr-> - get_phi(Bin(0,view45,0,0)) - _PI/4)<.001); - + const int view45 = proj_data_info_sptr->get_num_views() / 4; + assert(fabs(proj_data_info_sptr->get_phi(Bin(0, view45, 0, 0)) - _PI / 4) < .001); + { - const Bin bin(oblique_seg_num,1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,1,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 1, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,1,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 1, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,0,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 0, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,0,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 0, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,0,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 0, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,0,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 0, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,0,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 0, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,0,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 0, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,0,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 0, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,view45,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, view45, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,view45,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, view45, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,view45,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, view45, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,view45,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, view45, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,view45,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, view45, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,view45,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, view45, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,view45,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, view45, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,view45,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, view45, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } - { - const Bin bin(oblique_seg_num,2*view45+1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 2 * view45 + 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,2*view45+1,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 2 * view45 + 1, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,2*view45+1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 2 * view45 + 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,2*view45+1,5,-6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 2 * view45 + 1, 5, -6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(oblique_seg_num,2*view45+1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(oblique_seg_num, 2 * view45 + 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(-oblique_seg_num,2*view45+1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(-oblique_seg_num, 2 * view45 + 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,2*view45+1,5,6); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 2 * view45 + 1, 5, 6); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } { - const Bin bin(0,2*view45+1,5,0); - run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, - proj_matrix_with_symm, bin); + const Bin bin(0, 2 * view45 + 1, 5, 0); + run_tests_2_proj_matrices_1_bin(proj_matrix_no_symm, proj_matrix_with_symm, bin); } #endif } - void -DataSymmetriesForBins_PET_CartesianGridTests:: -run_tests_all_symmetries(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_sptr - ) -{ - - ProjMatrixByBinUsingRayTracing proj_matrix_no_sym; - { - stringstream str; - str << - "Ray Tracing Matrix Parameters :=\n" - "restrict to cylindrical FOV := 1\n" - "number of rays in tangential direction to trace for each bin := 1\n" - "use actual detector boundaries := 0\n" - "do symmetry 90degrees min phi := 0\n" - "do symmetry 180degrees min phi := 0\n" - "do_symmetry_swap_segment := 0\n" - "do_symmetry_swap_s := 0\n" - "do_symmetry_shift_z := 0\n" - "End Ray Tracing Matrix Parameters :=\n"; - if (!check(proj_matrix_no_sym.parse(str), - "parsing projection matrix parameters")) - return; - proj_matrix_no_sym.set_up(proj_data_info_sptr, density_sptr); +DataSymmetriesForBins_PET_CartesianGridTests::run_tests_all_symmetries( + const shared_ptr& proj_data_info_sptr, const shared_ptr>& density_sptr) { + + ProjMatrixByBinUsingRayTracing proj_matrix_no_sym; + { + stringstream str; + str << "Ray Tracing Matrix Parameters :=\n" + "restrict to cylindrical FOV := 1\n" + "number of rays in tangential direction to trace for each bin := 1\n" + "use actual detector boundaries := 0\n" + "do symmetry 90degrees min phi := 0\n" + "do symmetry 180degrees min phi := 0\n" + "do_symmetry_swap_segment := 0\n" + "do_symmetry_swap_s := 0\n" + "do_symmetry_shift_z := 0\n" + "End Ray Tracing Matrix Parameters :=\n"; + if (!check(proj_matrix_no_sym.parse(str), "parsing projection matrix parameters")) + return; + proj_matrix_no_sym.set_up(proj_data_info_sptr, density_sptr); + } + + { + cerr << "\t\tTesting with all symmetries\n"; + ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; + + stringstream str; + str << "Ray Tracing Matrix Parameters :=\n" + "restrict to cylindrical FOV := 1\n" + "number of rays in tangential direction to trace for each bin := 1\n" + "use actual detector boundaries := 0\n" + "do symmetry 90degrees min phi := 1\n" + "do symmetry 180degrees min phi := 1\n" + "do_symmetry_swap_segment := 1\n" + "do_symmetry_swap_s := 1\n" + "do_symmetry_shift_z := 1\n" + "End Ray Tracing Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - - { - cerr << "\t\tTesting with all symmetries\n"; - ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; - - stringstream str; - str << - "Ray Tracing Matrix Parameters :=\n" - "restrict to cylindrical FOV := 1\n" - "number of rays in tangential direction to trace for each bin := 1\n" - "use actual detector boundaries := 0\n" - "do symmetry 90degrees min phi := 1\n" - "do symmetry 180degrees min phi := 1\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 1\n" - "do_symmetry_shift_z := 1\n" - "End Ray Tracing Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } - } - { - cerr << "\t\tTesting with all symmetries except 90-phi\n"; - ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; - - stringstream str; - str << - "Ray Tracing Matrix Parameters :=\n" - "restrict to cylindrical FOV := 1\n" - "number of rays in tangential direction to trace for each bin := 1\n" - "use actual detector boundaries := 0\n" - "do symmetry 90degrees min phi := 0\n" - "do symmetry 180degrees min phi := 1\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 1\n" - "do_symmetry_shift_z := 1\n" - "End Ray Tracing Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with all symmetries except 90-phi\n"; + ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; + + stringstream str; + str << "Ray Tracing Matrix Parameters :=\n" + "restrict to cylindrical FOV := 1\n" + "number of rays in tangential direction to trace for each bin := 1\n" + "use actual detector boundaries := 0\n" + "do symmetry 90degrees min phi := 0\n" + "do symmetry 180degrees min phi := 1\n" + "do_symmetry_swap_segment := 1\n" + "do_symmetry_swap_s := 1\n" + "do_symmetry_shift_z := 1\n" + "End Ray Tracing Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with all symmetries except phi symms\n"; - ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; - - stringstream str; - str << - "Ray Tracing Matrix Parameters :=\n" - "restrict to cylindrical FOV := 1\n" - "number of rays in tangential direction to trace for each bin := 1\n" - "use actual detector boundaries := 0\n" - "do symmetry 90degrees min phi := 0\n" - "do symmetry 180degrees min phi := 0\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 1\n" - "do_symmetry_shift_z := 1\n" - "End Ray Tracing Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with all symmetries except phi symms\n"; + ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; + + stringstream str; + str << "Ray Tracing Matrix Parameters :=\n" + "restrict to cylindrical FOV := 1\n" + "number of rays in tangential direction to trace for each bin := 1\n" + "use actual detector boundaries := 0\n" + "do symmetry 90degrees min phi := 0\n" + "do symmetry 180degrees min phi := 0\n" + "do_symmetry_swap_segment := 1\n" + "do_symmetry_swap_s := 1\n" + "do_symmetry_shift_z := 1\n" + "End Ray Tracing Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with all symmetries except swap_segment\n"; - ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; - - stringstream str; - str << - "Ray Tracing Matrix Parameters :=\n" - "restrict to cylindrical FOV := 1\n" - "number of rays in tangential direction to trace for each bin := 1\n" - "use actual detector boundaries := 0\n" - "do symmetry 90degrees min phi := 1\n" - "do symmetry 180degrees min phi := 1\n" - "do_symmetry_swap_segment := 0\n" - "do_symmetry_swap_s := 1\n" - "do_symmetry_shift_z := 1\n" - "End Ray Tracing Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with all symmetries except swap_segment\n"; + ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; + + stringstream str; + str << "Ray Tracing Matrix Parameters :=\n" + "restrict to cylindrical FOV := 1\n" + "number of rays in tangential direction to trace for each bin := 1\n" + "use actual detector boundaries := 0\n" + "do symmetry 90degrees min phi := 1\n" + "do symmetry 180degrees min phi := 1\n" + "do_symmetry_swap_segment := 0\n" + "do_symmetry_swap_s := 1\n" + "do_symmetry_shift_z := 1\n" + "End Ray Tracing Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with all symmetries except swap_s\n"; - ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; - - stringstream str; - str << - "Ray Tracing Matrix Parameters :=\n" - "restrict to cylindrical FOV := 1\n" - "number of rays in tangential direction to trace for each bin := 1\n" - "use actual detector boundaries := 0\n" - "do symmetry 90degrees min phi := 1\n" - "do symmetry 180degrees min phi := 1\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 0\n" - "do_symmetry_shift_z := 1\n" - "End Ray Tracing Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with all symmetries except swap_s\n"; + ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; + + stringstream str; + str << "Ray Tracing Matrix Parameters :=\n" + "restrict to cylindrical FOV := 1\n" + "number of rays in tangential direction to trace for each bin := 1\n" + "use actual detector boundaries := 0\n" + "do symmetry 90degrees min phi := 1\n" + "do symmetry 180degrees min phi := 1\n" + "do_symmetry_swap_segment := 1\n" + "do_symmetry_swap_s := 0\n" + "do_symmetry_shift_z := 1\n" + "End Ray Tracing Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with all symmetries except shift_z\n"; - ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; - - stringstream str; - str << - "Ray Tracing Matrix Parameters :=\n" - "restrict to cylindrical FOV := 1\n" - "number of rays in tangential direction to trace for each bin := 1\n" - "use actual detector boundaries := 0\n" - "do symmetry 90degrees min phi := 1\n" - "do symmetry 180degrees min phi := 1\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 1\n" - "do_symmetry_shift_z := 0\n" - "End Ray Tracing Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with all symmetries except shift_z\n"; + ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; + + stringstream str; + str << "Ray Tracing Matrix Parameters :=\n" + "restrict to cylindrical FOV := 1\n" + "number of rays in tangential direction to trace for each bin := 1\n" + "use actual detector boundaries := 0\n" + "do symmetry 90degrees min phi := 1\n" + "do symmetry 180degrees min phi := 1\n" + "do_symmetry_swap_segment := 1\n" + "do_symmetry_swap_s := 1\n" + "do_symmetry_shift_z := 0\n" + "End Ray Tracing Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } - { - cerr << "\t\tTesting with only shift_z\n"; - ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; - - stringstream str; - str << - "Ray Tracing Matrix Parameters :=\n" - "restrict to cylindrical FOV := 1\n" - "number of rays in tangential direction to trace for each bin := 1\n" - "use actual detector boundaries := 0\n" - "do symmetry 90degrees min phi := 0\n" - "do symmetry 180degrees min phi := 0\n" - "do_symmetry_swap_segment := 0\n" - "do_symmetry_swap_s := 0\n" - "do_symmetry_shift_z := 1\n" - "End Ray Tracing Matrix Parameters :=\n"; - if (check(proj_matrix_with_sym.parse(str), - "parsing projection matrix parameters")) - { - proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); - run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); - } + } + { + cerr << "\t\tTesting with only shift_z\n"; + ProjMatrixByBinUsingRayTracing proj_matrix_with_sym; + + stringstream str; + str << "Ray Tracing Matrix Parameters :=\n" + "restrict to cylindrical FOV := 1\n" + "number of rays in tangential direction to trace for each bin := 1\n" + "use actual detector boundaries := 0\n" + "do symmetry 90degrees min phi := 0\n" + "do symmetry 180degrees min phi := 0\n" + "do_symmetry_swap_segment := 0\n" + "do_symmetry_swap_s := 0\n" + "do_symmetry_shift_z := 1\n" + "End Ray Tracing Matrix Parameters :=\n"; + if (check(proj_matrix_with_sym.parse(str), "parsing projection matrix parameters")) { + proj_matrix_with_sym.set_up(proj_data_info_sptr, density_sptr); + run_tests_2_proj_matrices(proj_matrix_no_sym, proj_matrix_with_sym); } + } } void -DataSymmetriesForBins_PET_CartesianGridTests:: -run_tests_for_1_projdata(const shared_ptr& proj_data_info_sptr) -{ - CartesianCoordinate3D origin (0,0,0); - const float zoom=1.F; +DataSymmetriesForBins_PET_CartesianGridTests::run_tests_for_1_projdata(const shared_ptr& proj_data_info_sptr) { + CartesianCoordinate3D origin(0, 0, 0); + const float zoom = 1.F; cerr << "\tTests with usual image size\n"; - - shared_ptr > - density_sptr(new VoxelsOnCartesianGrid(*proj_data_info_sptr,zoom,origin)); - VoxelsOnCartesianGrid & image = - dynamic_cast&>(*density_sptr); + shared_ptr> density_sptr(new VoxelsOnCartesianGrid(*proj_data_info_sptr, zoom, origin)); + + VoxelsOnCartesianGrid& image = dynamic_cast&>(*density_sptr); run_tests_all_symmetries(proj_data_info_sptr, density_sptr); cerr << "\tTests with shifted origin\n"; - density_sptr->set_origin(image.get_grid_spacing()* - CartesianCoordinate3D(3,0,0)); + density_sptr->set_origin(image.get_grid_spacing() * CartesianCoordinate3D(3, 0, 0)); run_tests_all_symmetries(proj_data_info_sptr, density_sptr); - const int org_z_length = - density_sptr->get_length(); - const CartesianCoordinate3D org_voxel_size = - image.get_voxel_size(); + const int org_z_length = density_sptr->get_length(); + const CartesianCoordinate3D org_voxel_size = image.get_voxel_size(); - cerr << "\tTests with non-standard range of planes (larger)\n"; - density_sptr->set_origin(CartesianCoordinate3D(0,0,0)); - density_sptr->grow(IndexRange3D(-2, org_z_length+3, - image.get_min_y(), image.get_max_y(), - image.get_min_x(), image.get_max_x())); + cerr << "\tTests with non-standard range of planes (larger)\n"; + density_sptr->set_origin(CartesianCoordinate3D(0, 0, 0)); + density_sptr->grow( + IndexRange3D(-2, org_z_length + 3, image.get_min_y(), image.get_max_y(), image.get_min_x(), image.get_max_x())); run_tests_all_symmetries(proj_data_info_sptr, density_sptr); #if 0 if (org_z_length>2) @@ -610,7 +510,7 @@ run_tests_for_1_projdata(const shared_ptr& proj_data_info_sptr) image.get_min_x(), image.get_max_x())); run_tests_all_symmetries(proj_data_info_sptr, density_sptr); } -#if 1 +# if 1 // this test currently fails with the ray tracing projmatrix // (but not with the interpolation projmatrix) if (org_z_length>1) @@ -636,101 +536,97 @@ run_tests_for_1_projdata(const shared_ptr& proj_data_info_sptr) image.get_min_x(), image.get_max_x())); run_tests_all_symmetries(proj_data_info_sptr, density_sptr); } -#endif +# endif #endif { - cerr << "\tTests with z voxel size 3 times smaller than usual\n"; - density_sptr->set_origin(CartesianCoordinate3D(0,0,0)); - image.set_grid_spacing(org_voxel_size/ - CartesianCoordinate3D(2,1,1)); - density_sptr->grow(IndexRange3D(-2, org_z_length*2, // note: -2 because grow doesn't allow shrinking! - image.get_min_y(), image.get_max_y(), - image.get_min_x(), image.get_max_x())); + cerr << "\tTests with z voxel size 3 times smaller than usual\n"; + density_sptr->set_origin(CartesianCoordinate3D(0, 0, 0)); + image.set_grid_spacing(org_voxel_size / CartesianCoordinate3D(2, 1, 1)); + density_sptr->grow(IndexRange3D(-2, org_z_length * 2, // note: -2 because grow doesn't allow shrinking! + image.get_min_y(), image.get_max_y(), image.get_min_x(), image.get_max_x())); run_tests_all_symmetries(proj_data_info_sptr, density_sptr); } - if (proj_data_info_sptr->get_sampling_in_m(Bin(0,0,0,0))/org_voxel_size.z()>=1.999) + if (proj_data_info_sptr->get_sampling_in_m(Bin(0, 0, 0, 0)) / org_voxel_size.z() >= 1.999) { + // currently symmetries do not work when the voxel size is larger than the ring_spacing + // so we only perform these tests when they can work { - // currently symmetries do not work when the voxel size is larger than the ring_spacing - // so we only perform these tests when they can work - { - cerr << "\tTests with z voxel size 2 times larger than usual\n"; - density_sptr->set_origin(CartesianCoordinate3D(0,0,0)); - image.set_grid_spacing(org_voxel_size* - CartesianCoordinate3D(2,1,1)); - density_sptr->resize(IndexRange3D(0, (org_z_length+1)/2-1, - image.get_min_y(), image.get_max_y(), - image.get_min_x(), image.get_max_x())); - run_tests_all_symmetries(proj_data_info_sptr, density_sptr); - } - { - cerr << "\tTests with usual z voxel size 2 times larger, 1 extra plane\n"; - density_sptr->set_origin(CartesianCoordinate3D(0,0,0)); - image.set_grid_spacing(org_voxel_size* - CartesianCoordinate3D(2,1,1)); - density_sptr->grow(IndexRange3D(0, (org_z_length+1)/2, - image.get_min_y(), image.get_max_y(), - image.get_min_x(), image.get_max_x())); - run_tests_all_symmetries(proj_data_info_sptr, density_sptr); - } + cerr << "\tTests with z voxel size 2 times larger than usual\n"; + density_sptr->set_origin(CartesianCoordinate3D(0, 0, 0)); + image.set_grid_spacing(org_voxel_size * CartesianCoordinate3D(2, 1, 1)); + density_sptr->resize(IndexRange3D(0, (org_z_length + 1) / 2 - 1, image.get_min_y(), image.get_max_y(), image.get_min_x(), + image.get_max_x())); + run_tests_all_symmetries(proj_data_info_sptr, density_sptr); } - + { + cerr << "\tTests with usual z voxel size 2 times larger, 1 extra plane\n"; + density_sptr->set_origin(CartesianCoordinate3D(0, 0, 0)); + image.set_grid_spacing(org_voxel_size * CartesianCoordinate3D(2, 1, 1)); + density_sptr->grow( + IndexRange3D(0, (org_z_length + 1) / 2, image.get_min_y(), image.get_max_y(), image.get_min_x(), image.get_max_x())); + run_tests_all_symmetries(proj_data_info_sptr, density_sptr); + } + } } void -DataSymmetriesForBins_PET_CartesianGridTests::run_tests() -{ +DataSymmetriesForBins_PET_CartesianGridTests::run_tests() { cerr << "Tests for DataSymmetriesForBins_PET_CartesianGrid\n"; - if (template_proj_data_filename == 0) + if (template_proj_data_filename == 0) { { - { - cerr << "Testing span=1\n"; - shared_ptr scanner_sptr(new Scanner(Scanner::E953)); - proj_data_info_sptr.reset( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/1, - /*max_delta=*/5, - /*num_views=*/8, - /*num_tang_poss=*/16)); - - run_tests_for_1_projdata(proj_data_info_sptr); - } - { - cerr << "Testing span=3\n"; - // warning: make sure that parameters are ok such that hard-wired - // bins above are fine (e.g. segment 3 should be allowed) - shared_ptr scanner_sptr(new Scanner(Scanner::E953)); - proj_data_info_sptr.reset( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/3, - /*max_delta=*/12, - /*num_views=*/8, - /*num_tang_poss=*/16)); - - - run_tests_for_1_projdata(proj_data_info_sptr); - } + cerr << "Testing span=1\n"; + shared_ptr scanner_sptr(new Scanner(Scanner::E953)); + proj_data_info_sptr.reset(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/1, + /*max_delta=*/5, + /*num_views=*/8, + /*num_tang_poss=*/16)); + + run_tests_for_1_projdata(proj_data_info_sptr); + } + { + cerr << "Testing span=3\n"; + // warning: make sure that parameters are ok such that hard-wired + // bins above are fine (e.g. segment 3 should be allowed) + shared_ptr scanner_sptr(new Scanner(Scanner::E953)); + proj_data_info_sptr.reset(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/3, + /*max_delta=*/12, + /*num_views=*/8, + /*num_tang_poss=*/16)); + + run_tests_for_1_projdata(proj_data_info_sptr); } - else { - shared_ptr proj_data_sptr = - ProjData::read_from_file(template_proj_data_filename); - proj_data_info_sptr = - proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); + cerr << "Testing with proj_data_info with time-of-flight"; + // warning: make sure that parameters are ok such that hard-wired + // bins above are fine (e.g. segment 3 should be allowed) + shared_ptr scanner_sptr(new Scanner(Scanner::PETMR_Signa)); + proj_data_info_sptr.reset(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/11, + /*max_delta=*/5, + /*num_views=*/scanner_sptr->get_num_detectors_per_ring() / 8, + /*num_tang_poss=*/64, + /*arc_corrected*/ false, + /*tof_mashing*/ 116)); + run_tests_for_1_projdata(proj_data_info_sptr); } + } else { + shared_ptr proj_data_sptr = ProjData::read_from_file(template_proj_data_filename); + proj_data_info_sptr = proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); + run_tests_for_1_projdata(proj_data_info_sptr); + } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main(int argc, char **argv) -{ - DataSymmetriesForBins_PET_CartesianGridTests tests(argc==2? argv[1] : 0); +int +main(int argc, char** argv) { + DataSymmetriesForBins_PET_CartesianGridTests tests(argc == 2 ? argv[1] : 0); tests.run_tests(); return tests.main_return_value(); } diff --git a/src/recon_test/test_FBP2D.cxx b/src/recon_test/test_FBP2D.cxx index b5a1cd4fc6..39c266100e 100644 --- a/src/recon_test/test_FBP2D.cxx +++ b/src/recon_test/test_FBP2D.cxx @@ -24,41 +24,33 @@ START_NAMESPACE_STIR -typedef DiscretisedDensity<3,float> target_type; +typedef DiscretisedDensity<3, float> target_type; /*! \ingroup recon_test \ingroup FBP2D \brief Test class for FBP2D */ -class TestFBP2D : public ReconstructionTests -{ +class TestFBP2D : public ReconstructionTests { private: typedef ReconstructionTests base_type; + public: //! Constructor that can take some input data to run the test with - TestFBP2D(const std::string &proj_data_filename = "", - const std::string & density_filename = "") - : base_type(proj_data_filename, density_filename) - {} + TestFBP2D(const std::string& proj_data_filename = "", const std::string& density_filename = "") + : base_type(proj_data_filename, density_filename) {} virtual ~TestFBP2D() {} - virtual void construct_reconstructor(); void run_tests(); }; - void -TestFBP2D:: -construct_reconstructor() -{ +TestFBP2D::construct_reconstructor() { this->_recon_sptr.reset(new FBP2DReconstruction); } void -TestFBP2D:: -run_tests() -{ +TestFBP2D::run_tests() { std::cerr << "Tests for FBP2D\n"; try { @@ -67,54 +59,45 @@ run_tests() shared_ptr output_sptr(this->_input_density_sptr->get_empty_copy()); this->reconstruct(output_sptr); this->compare(output_sptr); + } catch (const std::exception& error) { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + everything_ok = false; + } catch (...) { + everything_ok = false; } - catch(const std::exception &error) - { - std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; - everything_ok = false; - } - catch(...) - { - everything_ok = false; - } // see if it checks input parameters { FBP2DReconstruction fbp(this->_proj_data_sptr, /*alpha*/ -1.F); - try - { - std::cerr << "\nYou should now see an error about a wrong setting for alpha" << std::endl; - fbp.set_up(this->_input_density_sptr); - // we shouldn't get here - everything_ok = false; - } - catch (...) - { - } + try { + std::cerr << "\nYou should now see an error about a wrong setting for alpha" << std::endl; + fbp.set_up(this->_input_density_sptr); + // we shouldn't get here + everything_ok = false; + } catch (...) { + } } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR +int +main(int argc, char** argv) { + if (argc < 1 || argc > 3) { + std::cerr << "\n\tUsage: " << argv[0] << " [template_proj_data [image]]\n" + << "template_proj_data (optional) will serve as a template, but is otherwise not used.\n" + << "Image (optional) has to be compatible with projection data and currently at zoom=1\n"; + return EXIT_FAILURE; + } -int main(int argc, char **argv) -{ - if (argc < 1 || argc > 3) { - std::cerr << "\n\tUsage: " << argv[0] << " [template_proj_data [image]]\n" - << "template_proj_data (optional) will serve as a template, but is otherwise not used.\n" - << "Image (optional) has to be compatible with projection data and currently at zoom=1\n"; - return EXIT_FAILURE; - } - - //set_default_num_threads(); + // set_default_num_threads(); - TestFBP2D test(argc>1 ? argv[1] : "", argc > 2 ? argv[2] : ""); + TestFBP2D test(argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : ""); - if (test.is_everything_ok()) - test.run_tests(); + if (test.is_everything_ok()) + test.run_tests(); - return test.main_return_value(); + return test.main_return_value(); } diff --git a/src/recon_test/test_FBP3DRP.cxx b/src/recon_test/test_FBP3DRP.cxx index 124ba24543..2c493b7665 100644 --- a/src/recon_test/test_FBP3DRP.cxx +++ b/src/recon_test/test_FBP3DRP.cxx @@ -24,41 +24,33 @@ START_NAMESPACE_STIR -typedef DiscretisedDensity<3,float> target_type; +typedef DiscretisedDensity<3, float> target_type; /*! \ingroup recon_test \ingroup FBP3DRP \brief Test class for FBP3DRP */ -class TestFBP3DRP : public ReconstructionTests -{ +class TestFBP3DRP : public ReconstructionTests { private: typedef ReconstructionTests base_type; + public: //! Constructor that can take some input data to run the test with - TestFBP3DRP(const std::string &proj_data_filename = "", - const std::string & density_filename = "") - : base_type(proj_data_filename, density_filename) - {} + TestFBP3DRP(const std::string& proj_data_filename = "", const std::string& density_filename = "") + : base_type(proj_data_filename, density_filename) {} virtual ~TestFBP3DRP() {} - virtual void construct_reconstructor(); void run_tests(); }; - void -TestFBP3DRP:: -construct_reconstructor() -{ +TestFBP3DRP::construct_reconstructor() { this->_recon_sptr.reset(new FBP3DRPReconstruction); } void -TestFBP3DRP:: -run_tests() -{ +TestFBP3DRP::run_tests() { std::cerr << "Tests for FBP3DRP\n"; try { @@ -67,26 +59,20 @@ run_tests() shared_ptr output_sptr(this->_input_density_sptr->get_empty_copy()); this->reconstruct(output_sptr); this->compare(output_sptr); + } catch (const std::exception& error) { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + everything_ok = false; + } catch (...) { + everything_ok = false; } - catch(const std::exception &error) - { - std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; - everything_ok = false; - } - catch(...) - { - everything_ok = false; - } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main(int argc, char **argv) -{ +int +main(int argc, char** argv) { if (argc < 1 || argc > 3) { std::cerr << "\n\tUsage: " << argv[0] << " [template_proj_data [image]]\n" << "template_proj_data (optional) will serve as a template, but is otherwise not used.\n" @@ -94,9 +80,9 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - //set_default_num_threads(); + // set_default_num_threads(); - TestFBP3DRP test(argc>1 ? argv[1] : "", argc > 2 ? argv[2] : ""); + TestFBP3DRP test(argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : ""); if (test.is_everything_ok()) test.run_tests(); diff --git a/src/recon_test/test_OSMAPOSL.cxx b/src/recon_test/test_OSMAPOSL.cxx index 42080cdb7e..9338ae3b0d 100644 --- a/src/recon_test/test_OSMAPOSL.cxx +++ b/src/recon_test/test_OSMAPOSL.cxx @@ -24,38 +24,30 @@ START_NAMESPACE_STIR -typedef DiscretisedDensity<3,float> target_type; +typedef DiscretisedDensity<3, float> target_type; /*! \ingroup recon_test \ingroup OSMAPOSL \brief Test class for OSMAPOSL */ -class TestOSMAPOSL : public PoissonLLReconstructionTests -{ +class TestOSMAPOSL : public PoissonLLReconstructionTests { private: typedef PoissonLLReconstructionTests base_type; + public: //! Constructor that can take some input data to run the test with - TestOSMAPOSL(const std::string &proj_data_filename = "", - const std::string & density_filename = "") - : base_type(proj_data_filename, density_filename) - {} + TestOSMAPOSL(const std::string& proj_data_filename = "", const std::string& density_filename = "") + : base_type(proj_data_filename, density_filename) {} virtual ~TestOSMAPOSL() {} - virtual void construct_reconstructor(); - OSMAPOSLReconstruction& - recon() - { return dynamic_cast& >(*this->_recon_sptr); } + OSMAPOSLReconstruction& recon() { return dynamic_cast&>(*this->_recon_sptr); } void run_tests(); }; - void -TestOSMAPOSL:: -construct_reconstructor() -{ +TestOSMAPOSL::construct_reconstructor() { this->_recon_sptr.reset(new OSMAPOSLReconstruction); this->construct_log_likelihood(); this->recon().set_objective_function_sptr(this->_objective_function_sptr); @@ -64,9 +56,7 @@ construct_reconstructor() } void -TestOSMAPOSL:: -run_tests() -{ +TestOSMAPOSL::run_tests() { std::cerr << "Tests for OSMAPOSL\n"; try { @@ -76,54 +66,44 @@ run_tests() output_sptr->fill(1.F); this->reconstruct(output_sptr); this->compare(output_sptr); + } catch (const std::exception& error) { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + everything_ok = false; + } catch (...) { + everything_ok = false; } - catch(const std::exception &error) - { - std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; - everything_ok = false; - } - catch(...) - { - everything_ok = false; - } - if (everything_ok) - { - // see if it checks input parameters - try - { - std::cerr << "\nYou should now see an error about a wrong setting for MAP model" << std::endl; - this->recon().set_MAP_model("a_wrong_value"); - // we shouldn't get here - everything_ok = false; - } - catch (...) - { - } + if (everything_ok) { + // see if it checks input parameters + try { + std::cerr << "\nYou should now see an error about a wrong setting for MAP model" << std::endl; + this->recon().set_MAP_model("a_wrong_value"); + // we shouldn't get here + everything_ok = false; + } catch (...) { } + } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR +int +main(int argc, char** argv) { + if (argc < 1 || argc > 3) { + std::cerr << "\n\tUsage: " << argv[0] << " [template_proj_data [image]]\n" + << "template_proj_data (optional) will serve as a template, but is otherwise not used.\n" + << "Image (optional) has to be compatible with projection data and currently at zoom=1\n"; + return EXIT_FAILURE; + } -int main(int argc, char **argv) -{ - if (argc < 1 || argc > 3) { - std::cerr << "\n\tUsage: " << argv[0] << " [template_proj_data [image]]\n" - << "template_proj_data (optional) will serve as a template, but is otherwise not used.\n" - << "Image (optional) has to be compatible with projection data and currently at zoom=1\n"; - return EXIT_FAILURE; - } - - //set_default_num_threads(); + // set_default_num_threads(); - TestOSMAPOSL test(argc>1 ? argv[1] : "", argc > 2 ? argv[2] : ""); + TestOSMAPOSL test(argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : ""); - if (test.is_everything_ok()) - test.run_tests(); + if (test.is_everything_ok()) + test.run_tests(); - return test.main_return_value(); + return test.main_return_value(); } diff --git a/src/recon_test/test_PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx b/src/recon_test/test_PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx index 32898aede9..68de5ac640 100644 --- a/src/recon_test/test_PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx +++ b/src/recon_test/test_PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx @@ -19,7 +19,7 @@ \file \ingroup recon_test - + \brief Test program for stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData \par Usage @@ -64,31 +64,29 @@ #include "stir/recon_buildblock/distributable_main.h" START_NAMESPACE_STIR - /*! \ingroup test \brief Test class for PoissonLogLikelihoodWithLinearModelForMeanAndProjData This is a somewhat preliminary implementation of a test that compares the result - of GeneralisedObjectiveFunction::compute_gradient - with a numerical gradient computed by using the + of GeneralisedObjectiveFunction::compute_gradient + with a numerical gradient computed by using the GeneralisedObjectiveFunction::compute_objective_function() function. - The trouble with this is that compute the gradient voxel by voxel is obviously - terribly slow. A solution (for the test) would be to compute it only in + The trouble with this is that compute the gradient voxel by voxel is obviously + terribly slow. A solution (for the test) would be to compute it only in a subset of voxels or so. We'll leave this for later. Note that the test only works if the objective function is well-defined. For example, if certain projections are non-zero, while the model estimates them to be zero, the Poisson objective function is in theory infinite. - PoissonLogLikelihoodWithLinearModelForMeanAndProjData uses some thresholds to try to + PoissonLogLikelihoodWithLinearModelForMeanAndProjData uses some thresholds to try to avoid overflow, but if there are too many of these bins, the total objective function will become infinite. The numerical gradient then becomes ill-defined (even in voxels that do not contribute to these bins). */ -class PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests : public RunTests -{ +class PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests : public RunTests { public: //! Constructor that can take some input data to run the test with /*! This makes it possible to run the test with your own data. However, beware that @@ -98,61 +96,59 @@ class PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests : public RunTes \todo it would be better to parse an objective function. That would allow us to set all parameters from the command line. */ - PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests(char const * const proj_data_filename = 0, char const * const density_filename = 0); - typedef DiscretisedDensity<3,float> target_type; + PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests(char const* const proj_data_filename = 0, + char const* const density_filename = 0); + typedef DiscretisedDensity<3, float> target_type; void construct_input_data(shared_ptr& density_sptr); void run_tests(); + protected: - char const * proj_data_filename; - char const * density_filename; - shared_ptr > objective_function_sptr; + char const* proj_data_filename; + char const* density_filename; + shared_ptr> objective_function_sptr; //! run the test /*! Note that this function is not specific to PoissonLogLikelihoodWithLinearModelForMeanAndProjData */ - void run_tests_for_objective_function(GeneralisedObjectiveFunction& objective_function, - target_type& target); + void run_tests_for_objective_function(GeneralisedObjectiveFunction& objective_function, target_type& target); }; -PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests:: -PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests(char const * proj_data_filename, char const * const density_filename) - : proj_data_filename(proj_data_filename), density_filename(density_filename) -{} +PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests::PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests( + char const* proj_data_filename, char const* const density_filename) + : proj_data_filename(proj_data_filename), density_filename(density_filename) {} void -PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests:: -run_tests_for_objective_function(GeneralisedObjectiveFunction& objective_function, - PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests::target_type& target) { +PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests::run_tests_for_objective_function( + GeneralisedObjectiveFunction& objective_function, + PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests::target_type& target) { shared_ptr gradient_sptr(target.get_empty_copy()); shared_ptr gradient_2_sptr(target.get_empty_copy()); const int subset_num = 0; info("Computing gradient"); objective_function.compute_sub_gradient(*gradient_sptr, target, subset_num); - this->set_tolerance(std::max(fabs(double(gradient_sptr->find_min())), double(gradient_sptr->find_max()))/1000); + this->set_tolerance(std::max(fabs(double(gradient_sptr->find_min())), double(gradient_sptr->find_max())) / 1000); info("Computing objective function at target"); const double value_at_target = objective_function.compute_objective_function(target, subset_num); - target_type::full_iterator target_iter=target.begin_all(); - target_type::full_iterator gradient_iter=gradient_sptr->begin_all(); - target_type::full_iterator gradient_2_iter=gradient_2_sptr->begin_all(); + target_type::full_iterator target_iter = target.begin_all(); + target_type::full_iterator gradient_iter = gradient_sptr->begin_all(); + target_type::full_iterator gradient_2_iter = gradient_2_sptr->begin_all(); const float eps = 1e-2F; bool testOK = true; info("Computing gradient of objective function by numerical differences (this will take a while)"); - while(target_iter!=target.end_all()) - { - *target_iter += eps; - const double value_at_inc = objective_function.compute_objective_function(target, subset_num); - *target_iter -= eps; - const float gradient_at_iter = static_cast((value_at_inc - value_at_target)/eps); - *gradient_2_iter++ = gradient_at_iter; - testOK = testOK && - this->check_if_equal(gradient_at_iter, *gradient_iter, "gradient"); - ++target_iter; ++ gradient_iter; - } - if (!testOK) - { - info("Writing diagnostic files gradient.hv, numerical_gradient.hv"); - write_to_file("gradient.hv", *gradient_sptr); - write_to_file("numerical_gradient.hv", *gradient_2_sptr); + while (target_iter != target.end_all()) { + *target_iter += eps; + const double value_at_inc = objective_function.compute_objective_function(target, subset_num); + *target_iter -= eps; + const float gradient_at_iter = static_cast((value_at_inc - value_at_target) / eps); + *gradient_2_iter++ = gradient_at_iter; + testOK = testOK && this->check_if_equal(gradient_at_iter, *gradient_iter, "gradient"); + ++target_iter; + ++gradient_iter; + } + if (!testOK) { + info("Writing diagnostic files gradient.hv, numerical_gradient.hv"); + write_to_file("gradient.hv", *gradient_sptr); + write_to_file("numerical_gradient.hv", *gradient_2_sptr); #if 0 write_to_file("subsens.hv", reinterpret_cast &>(objective_function).get_subset_sensitivity(subset_num)); @@ -161,160 +157,134 @@ run_tests_for_objective_function(GeneralisedObjectiveFunction& density_sptr) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests::construct_input_data(shared_ptr& density_sptr) { shared_ptr proj_data_sptr; - if (this->proj_data_filename == 0) - { - // construct a small scanner and sinogram - shared_ptr scanner_sptr(new Scanner(Scanner::E953)); - scanner_sptr->set_num_rings(5); - shared_ptr proj_data_info_sptr( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/3, - /*max_delta=*/4, - /*num_views=*/16, - /*num_tang_poss=*/16)); - shared_ptr exam_info_sptr(new ExamInfo); - proj_data_sptr.reset(new ProjDataInMemory (exam_info_sptr, proj_data_info_sptr)); - for (int seg_num=proj_data_sptr->get_min_segment_num(); - seg_num<=proj_data_sptr->get_max_segment_num(); - ++seg_num) - { - SegmentByView segment = proj_data_sptr->get_empty_segment_by_view(seg_num); - // fill in some crazy values - float value=0; - for (SegmentByView::full_iterator iter = segment.begin_all(); - iter != segment.end_all(); - ++iter) - { - value = float(fabs((seg_num+.1)*value - 5)); // needs to be positive for Poisson - *iter = value; - } - proj_data_sptr->set_segment(segment); + if (this->proj_data_filename == 0) { + // construct a small scanner and sinogram + shared_ptr scanner_sptr(new Scanner(Scanner::E953)); + scanner_sptr->set_num_rings(5); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/3, + /*max_delta=*/4, + /*num_views=*/16, + /*num_tang_poss=*/16)); + shared_ptr exam_info_sptr(new ExamInfo); + proj_data_sptr.reset(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr)); + for (int seg_num = proj_data_sptr->get_min_segment_num(); seg_num <= proj_data_sptr->get_max_segment_num(); ++seg_num) { + for (int timing_pos_num = proj_data_sptr->get_min_tof_pos_num(); timing_pos_num <= proj_data_sptr->get_max_tof_pos_num(); + ++timing_pos_num) { + SegmentByView segment = proj_data_sptr->get_empty_segment_by_view(seg_num, false, timing_pos_num); + // fill in some crazy values + float value = 0; + for (SegmentByView::full_iterator iter = segment.begin_all(); iter != segment.end_all(); ++iter) { + value = float(fabs((seg_num + .1) * value - 5)); // needs to be positive for Poisson + *iter = value; } + proj_data_sptr->set_segment(segment); + } } - else - { - proj_data_sptr = - ProjData::read_from_file(this->proj_data_filename); - } + } else { + proj_data_sptr = ProjData::read_from_file(this->proj_data_filename); + } - if (this->density_filename == 0) - { - // construct a small image - - CartesianCoordinate3D origin (0,0,0); - const float zoom=1.F; - - density_sptr.reset(new VoxelsOnCartesianGrid(*proj_data_sptr->get_proj_data_info_sptr(),zoom,origin)); - // fill with random numbers between 0 and 1 - typedef boost::mt19937 base_generator_type; - // initialize by reproducible seed - static base_generator_type generator(boost::uint32_t(42)); - static boost::uniform_01 random01(generator); - for (target_type::full_iterator iter=density_sptr->begin_all(); iter!=density_sptr->end_all(); ++iter) - *iter = static_cast(random01()); + if (this->density_filename == 0) { + // construct a small image - } - else - { - shared_ptr aptr(read_from_file(this->density_filename)); - density_sptr = aptr; - } + CartesianCoordinate3D origin(0, 0, 0); + const float zoom = 1.F; + + density_sptr.reset(new VoxelsOnCartesianGrid(*proj_data_sptr->get_proj_data_info_sptr(), zoom, origin)); + // fill with random numbers between 0 and 1 + typedef boost::mt19937 base_generator_type; + // initialize by reproducible seed + static base_generator_type generator(boost::uint32_t(42)); + static boost::uniform_01 random01(generator); + for (target_type::full_iterator iter = density_sptr->begin_all(); iter != density_sptr->end_all(); ++iter) + *iter = static_cast(random01()); + + } else { + shared_ptr aptr(read_from_file(this->density_filename)); + density_sptr = aptr; + } // make odd to avoid difficulties with outer-bin that isn't filled-in when using symmetries { - BasicCoordinate<3,int> min_ind, max_ind; - if (density_sptr->get_regular_range(min_ind,max_ind)) - { - for (int d=2; d<=3; ++d) - { - min_ind[d]=std::min(min_ind[d], -max_ind[d]); - max_ind[d]=std::max(-min_ind[d], max_ind[d]); - } - density_sptr->grow(IndexRange<3>(min_ind,max_ind)); - } + BasicCoordinate<3, int> min_ind, max_ind; + if (density_sptr->get_regular_range(min_ind, max_ind)) { + for (int d = 2; d <= 3; ++d) { + min_ind[d] = std::min(min_ind[d], -max_ind[d]); + max_ind[d] = std::max(-min_ind[d], max_ind[d]); + } + density_sptr->grow(IndexRange<3>(min_ind, max_ind)); + } } - // multiplicative term shared_ptr bin_norm_sptr(new TrivialBinNormalisation()); { - shared_ptr - mult_proj_data_sptr(new ProjDataInMemory (proj_data_sptr->get_exam_info_sptr(), - proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone())); - for (int seg_num=proj_data_sptr->get_min_segment_num(); - seg_num<=proj_data_sptr->get_max_segment_num(); - ++seg_num) - { - SegmentByView segment = proj_data_sptr->get_empty_segment_by_view(seg_num); + shared_ptr mult_proj_data_sptr(new ProjDataInMemory( + proj_data_sptr->get_exam_info_sptr(), proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone())); + for (int seg_num = proj_data_sptr->get_min_segment_num(); seg_num <= proj_data_sptr->get_max_segment_num(); ++seg_num) { + for (int timing_pos_num = proj_data_sptr->get_min_tof_pos_num(); timing_pos_num <= proj_data_sptr->get_max_tof_pos_num(); + ++timing_pos_num) { + SegmentByView segment = proj_data_sptr->get_empty_segment_by_view(seg_num, false, timing_pos_num); // fill in some crazy values - float value =0; - for (SegmentByView::full_iterator iter = segment.begin_all(); - iter != segment.end_all(); - ++iter) - { - value = float(fabs(seg_num*value - .2)); // needs to be positive for Poisson - *iter = value; - } + float value = 0; + for (SegmentByView::full_iterator iter = segment.begin_all(); iter != segment.end_all(); ++iter) { + value = float(fabs(seg_num * value - .2)); // needs to be positive for Poisson + *iter = value; + } mult_proj_data_sptr->set_segment(segment); } + } bin_norm_sptr.reset(new BinNormalisationFromProjData(mult_proj_data_sptr)); } // additive term - shared_ptr add_proj_data_sptr(new ProjDataInMemory (proj_data_sptr->get_exam_info_sptr(), - -proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone())); + shared_ptr add_proj_data_sptr(new ProjDataInMemory(proj_data_sptr->get_exam_info_sptr(), + + proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone())); { - for (int seg_num=proj_data_sptr->get_min_segment_num(); - seg_num<=proj_data_sptr->get_max_segment_num(); - ++seg_num) - { - SegmentByView segment = proj_data_sptr->get_empty_segment_by_view(seg_num); + for (int seg_num = proj_data_sptr->get_min_segment_num(); seg_num <= proj_data_sptr->get_max_segment_num(); ++seg_num) { + for (int timing_pos_num = proj_data_sptr->get_min_tof_pos_num(); timing_pos_num <= proj_data_sptr->get_max_tof_pos_num(); + ++timing_pos_num) { + SegmentByView segment = proj_data_sptr->get_empty_segment_by_view(seg_num, false, timing_pos_num); // fill in some crazy values - float value =0; - for (SegmentByView::full_iterator iter = segment.begin_all(); - iter != segment.end_all(); - ++iter) - { - value = float(fabs(seg_num*value - .3)); // needs to be positive for Poisson - *iter = value; - } + float value = 0; + for (SegmentByView::full_iterator iter = segment.begin_all(); iter != segment.end_all(); ++iter) { + value = float(fabs(seg_num * value - .3)); // needs to be positive for Poisson + *iter = value; + } add_proj_data_sptr->set_segment(segment); } + } } objective_function_sptr.reset(new PoissonLogLikelihoodWithLinearModelForMeanAndProjData); PoissonLogLikelihoodWithLinearModelForMeanAndProjData& objective_function = - reinterpret_cast< PoissonLogLikelihoodWithLinearModelForMeanAndProjData& >(*objective_function_sptr); + reinterpret_cast&>(*objective_function_sptr); objective_function.set_proj_data_sptr(proj_data_sptr); objective_function.set_use_subset_sensitivities(true); shared_ptr proj_matrix_sptr(new ProjMatrixByBinUsingRayTracing()); shared_ptr proj_pair_sptr(new ProjectorByBinPairUsingProjMatrixByBin(proj_matrix_sptr)); - objective_function.set_projector_pair_sptr(proj_pair_sptr) ; + objective_function.set_projector_pair_sptr(proj_pair_sptr); /* void set_frame_num(const int); void set_frame_definitions(const TimeFrameDefinitions&); */ objective_function.set_normalisation_sptr(bin_norm_sptr); objective_function.set_additive_proj_data_sptr(add_proj_data_sptr); - objective_function.set_num_subsets(proj_data_sptr->get_num_views()/2); - if (!check(objective_function.set_up(density_sptr)==Succeeded::yes, "set-up of objective function")) + objective_function.set_num_subsets(proj_data_sptr->get_num_views() / 2); + if (!check(objective_function.set_up(density_sptr) == Succeeded::yes, "set-up of objective function")) return; } void -PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests:: -run_tests() -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests::run_tests() { std::cerr << "Tests for PoissonLogLikelihoodWithLinearModelForMeanAndProjData\n"; #if 1 @@ -325,29 +295,28 @@ run_tests() // alternative that gets the objective function from an OSMAPOSL .par file // currently disabled OSMAPOSLReconstruction recon(proj_data_filename); // actually .par - shared_ptr > objective_function_sptr = recon.get_objective_function_sptr(); - if (!check(objective_function_sptr->set_up(recon.get_initial_data_ptr())==Succeeded::yes, "set-up of objective function")) + shared_ptr> objective_function_sptr = recon.get_objective_function_sptr(); + if (!check(objective_function_sptr->set_up(recon.get_initial_data_ptr()) == Succeeded::yes, "set-up of objective function")) return; - this->run_tests_for_objective_function(*objective_function_sptr, - *recon.get_initial_data_ptr()); + this->run_tests_for_objective_function(*objective_function_sptr, *recon.get_initial_data_ptr()); #endif -} +} END_NAMESPACE_STIR - USING_NAMESPACE_STIR #ifdef STIR_MPI -int stir::distributable_main(int argc, char **argv) +int +stir::distributable_main(int argc, char** argv) #else -int main(int argc, char **argv) +int +main(int argc, char** argv) #endif { set_default_num_threads(); - PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests tests(argc>1? argv[1] : 0, - argc>2? argv[2] : 0); + PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests tests(argc > 1 ? argv[1] : 0, argc > 2 ? argv[2] : 0); tests.run_tests(); return tests.main_return_value(); } diff --git a/src/recon_test/test_consistency_root.cxx b/src/recon_test/test_consistency_root.cxx new file mode 100644 index 0000000000..23f3e7d0af --- /dev/null +++ b/src/recon_test/test_consistency_root.cxx @@ -0,0 +1,279 @@ +/* + Copyright (C) 2017, UCL + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details +*/ +/*! + \ingroup recon_test + Implementation of stir::test_consistency_root +*/ +#include "stir/ProjDataInfoCylindricalNoArcCorr.h" +#include "stir/recon_buildblock/ProjMatrixByBin.h" +#include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" +#include "stir/recon_buildblock/ProjMatrixElemsForOneBin.h" +#include "stir/centre_of_gravity.h" +#include "stir/listmode/LmToProjData.h" +#include "stir/listmode/CListModeDataROOT.h" +#include "stir/listmode/CListRecord.h" +#include "stir/IO/read_from_file.h" +#include "stir/HighResWallClockTimer.h" +#include "stir/DiscretisedDensity.h" +#include "stir/VoxelsOnCartesianGrid.h" +#include "stir/Succeeded.h" +#include "stir/shared_ptr.h" +#include "stir/RunTests.h" +#include "boost/lexical_cast.hpp" + +#include "stir/info.h" +#include "stir/warning.h" + +#include + +using std::cerr; +using std::ifstream; + +START_NAMESPACE_STIR + +/*! + * \ingroup recon_test + * \brief Test class to check the consistency between ROOT listmode and STIR backprojection for high resolution TOF + * \author Elise Emond + * + * This test currently uses Root listmodes of single point sources. Scatters are not + * considered. It could be extended to actual scanner data, for which we would need + * to exclude scatter events. A way to do so would be to compute the distance between + * the bin LOR and the (non-TOF?) LOR calculated from the original data and exclude + * the events for which the distance would be more than a chosen threshold. + * + */ + +class ROOTconsistency_Tests : public RunTests { +public: + ROOTconsistency_Tests(const std::string& in, const std::string& image) : root_header_filename(in), image_filename(image) {} + void run_tests(); + + // Class to store the coordinates and weights of the maxima of the Lines-of-Response + // used to calculate the centre of gravity (see below). + class LORMax { + public: + LORMax() : voxel_centre(CartesianCoordinate3D(0.f, 0.f, 0.f)), value(0.f) {} + CartesianCoordinate3D voxel_centre; + float value; + }; + +private: + //! Reads listmode event by event, computes the ProjMatrixElemsForOneBin (probabilities + //! along a bin LOR) and stores in a vector the coordinates and weights of the + //! LOR maxima (vector::LORMax) prior to computing the centre of mass of those. + void construct_list_of_LOR_max(const shared_ptr>& test_discretised_density_sptr); + + //! Selects and stores the highest probability elements of ProjMatrixElemsForOneBin. + void get_LOR_of_max(const ProjMatrixElemsForOneBin& probabilities, + const shared_ptr>& test_discretised_density_sptr); + + //! Given a vector::LORMax, computes the centre of mass. + CartesianCoordinate3D compute_centre_of_mass(); + + //! Checks if original and calculated coordinates are close enough. + void compare_original_and_calculated_coordinates(const CartesianCoordinate3D& original_coords, + const CartesianCoordinate3D& centre_of_mass, + const BasicCoordinate<3, float>& grid_spacing); + + //! Modified version of check_if_equal for this test + bool check_if_almost_equal(const double a, const double b, const std::string& str, const double tolerance); + + std::string root_header_filename; + std::string image_filename; + std::vector max_lor; +}; + +void +ROOTconsistency_Tests::run_tests() { + // DiscretisedDensity for original image + shared_ptr> discretised_density_sptr(DiscretisedDensity<3, float>::read_from_file(image_filename)); + + // needs to be cast to VoxelsOnCartesianGrid to be able to calculate the centre of gravity, + // hence the location of the original source, stored in test_original_coords. + const VoxelsOnCartesianGrid& discretised_cartesian_grid = + dynamic_cast&>(*discretised_density_sptr); + CartesianCoordinate3D original_coords = find_centre_of_gravity_in_mm(discretised_cartesian_grid); + + construct_list_of_LOR_max(discretised_density_sptr); + + CartesianCoordinate3D centreofmass = compute_centre_of_mass(); + + compare_original_and_calculated_coordinates(original_coords, centreofmass, discretised_cartesian_grid.get_grid_spacing()); +} + +void +ROOTconsistency_Tests::construct_list_of_LOR_max(const shared_ptr>& discretised_density_sptr) { + shared_ptr lm_data_sptr(read_from_file(root_header_filename)); + + shared_ptr proj_matrix_sptr(new ProjMatrixByBinUsingRayTracing()); + + proj_matrix_sptr.get()->set_up(lm_data_sptr->get_proj_data_info_sptr(), discretised_density_sptr); + proj_matrix_sptr->enable_tof(lm_data_sptr->get_proj_data_info_sptr()); + + ProjMatrixElemsForOneBin proj_matrix_row; + + { + // loop over all events in the listmode file + shared_ptr record_sptr = lm_data_sptr->get_empty_record_sptr(); + CListRecord& record = *record_sptr; + while (lm_data_sptr->get_next_record(record) == Succeeded::yes) { + // only stores prompts + if (record.is_event() && record.event().is_prompt()) { + Bin bin; + bin.set_bin_value(1.f); + // gets the bin corresponding to the event + record.event().get_bin(bin, *lm_data_sptr->get_proj_data_info_sptr()); + if (bin.get_bin_value() > 0) { + // computes the TOF probabilities along the bin LOR + proj_matrix_sptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, bin); + // adds coordinates and weights of the elements with highest probability along LOR + get_LOR_of_max(proj_matrix_row, discretised_density_sptr); + } + } + } + } +} + +void +ROOTconsistency_Tests::get_LOR_of_max(const ProjMatrixElemsForOneBin& probabilities, + const shared_ptr>& test_discretised_density_sptr) { + std::stack tmp_max_lor; + + CartesianCoordinate3D voxel_centre; + + float maxLOR = 0; + + ProjMatrixElemsForOneBin::const_iterator element_ptr = probabilities.begin(); + // iterative calculation of highest probability and corresponding elements along the LOR + while (element_ptr != probabilities.end()) { + if (element_ptr->get_value() >= maxLOR) { + maxLOR = element_ptr->get_value(); + voxel_centre = test_discretised_density_sptr->get_physical_coordinates_for_indices(element_ptr->get_coords()); + LORMax tmp; + tmp.value = element_ptr->get_value(); + tmp.voxel_centre = voxel_centre; + tmp_max_lor.push(tmp); + } + ++element_ptr; + } + + // only selects the elements on top of the stack, corresponding to the highest probability + if (maxLOR != 0) { + while (!tmp_max_lor.empty()) { + if (tmp_max_lor.top().value == maxLOR) { + max_lor.push_back(tmp_max_lor.top()); + tmp_max_lor.pop(); + } else + break; + } + } +} + +CartesianCoordinate3D +ROOTconsistency_Tests::compute_centre_of_mass() { + + // creation of a file with all LOR maxima, to be able to plot them + std::ofstream myfile; + std::string file_name = image_filename.substr(0, image_filename.size() - 3) + ".txt"; + myfile.open(file_name.c_str()); + + LORMax centreofmass; + + // computes centre of mass + for (std::vector::iterator lor_element_ptr = max_lor.begin(); lor_element_ptr != max_lor.end(); ++lor_element_ptr) { + centreofmass.voxel_centre.x() += lor_element_ptr->voxel_centre.x() * lor_element_ptr->value; + centreofmass.voxel_centre.y() += lor_element_ptr->voxel_centre.y() * lor_element_ptr->value; + centreofmass.voxel_centre.z() += lor_element_ptr->voxel_centre.z() * lor_element_ptr->value; + centreofmass.value += lor_element_ptr->value; + + myfile << lor_element_ptr->voxel_centre.x() << " " << lor_element_ptr->voxel_centre.y() << " " + << lor_element_ptr->voxel_centre.z() << " " << lor_element_ptr->value << std::endl; + } + + // needs to divide by the weights + if (centreofmass.value != 0) { + centreofmass.voxel_centre.x() = centreofmass.voxel_centre.x() / centreofmass.value; + centreofmass.voxel_centre.y() = centreofmass.voxel_centre.y() / centreofmass.value; + centreofmass.voxel_centre.z() = centreofmass.voxel_centre.z() / centreofmass.value; + } else { + warning("Total weight of the centre of mass equal to 0. Please check your data."); + centreofmass.voxel_centre.x() = 0; + centreofmass.voxel_centre.y() = 0; + centreofmass.voxel_centre.z() = 0; + } + + cerr << "Centre of gravity coordinates: " << centreofmass.voxel_centre.x() << " " << centreofmass.voxel_centre.y() << " " + << centreofmass.voxel_centre.z() << std::endl; + + myfile.close(); + + return centreofmass.voxel_centre; +} + +// TODO change this +void +ROOTconsistency_Tests::compare_original_and_calculated_coordinates(const CartesianCoordinate3D& original_coords, + const CartesianCoordinate3D& centre_of_mass, + const BasicCoordinate<3, float>& grid_spacing) { + check_if_almost_equal(static_cast(original_coords.x()), static_cast(centre_of_mass.x()), "x", grid_spacing[1]); + check_if_almost_equal(static_cast(original_coords.y()), static_cast(centre_of_mass.y()), "y", grid_spacing[2]); + check_if_almost_equal(static_cast(original_coords.z()), static_cast(centre_of_mass.z()), "z", grid_spacing[3]); + + cerr << "Original coordinates: " << original_coords.x() << " " << original_coords.y() << " " << original_coords.z() + << std::endl; +} + +bool +ROOTconsistency_Tests::check_if_almost_equal(const double a, const double b, std::string str, const double tolerance) { + if ((fabs(a - b) > tolerance)) { + std::cerr << "Error : unequal values are " << a << " and " << b << ". " << str << std::endl; + everything_ok = false; + return false; + } else + return true; +} + +END_NAMESPACE_STIR + +int +main(int argc, char** argv) { + USING_NAMESPACE_STIR + + if (argc != 3) { + cerr << "Usage : " << argv[1] << " filename " << argv[2] << "original image \n" + << "See source file for the format of this file.\n\n"; + return EXIT_FAILURE; + } + + ifstream in(argv[1]); + if (!in) { + cerr << argv[0] << ": Error opening root file " << argv[1] << "\nExiting.\n"; + + return EXIT_FAILURE; + } + ifstream in2(argv[2]); + if (!in2) { + cerr << argv[0] << ": Error opening original image " << argv[2] << "\nExiting.\n"; + + return EXIT_FAILURE; + } + std::string filename(argv[1]); + std::string image(argv[2]); + ROOTconsistency_Tests tests(filename, image); + tests.run_tests(); + return tests.main_return_value(); +} diff --git a/src/recon_test/test_data_processor_projectors.cxx b/src/recon_test/test_data_processor_projectors.cxx index 52e5afd325..0b135298ec 100644 --- a/src/recon_test/test_data_processor_projectors.cxx +++ b/src/recon_test/test_data_processor_projectors.cxx @@ -33,188 +33,171 @@ START_NAMESPACE_STIR \ingroup test \brief Test class for GPU projectors */ -class TestDataProcessorProjectors : public RunTests -{ +class TestDataProcessorProjectors : public RunTests { public: - //! Constructor that can take some input data to run the test with - TestDataProcessorProjectors(const std::string &sinogram_filename, const float fwhm); + //! Constructor that can take some input data to run the test with + TestDataProcessorProjectors(const std::string& sinogram_filename, const float fwhm); - virtual ~TestDataProcessorProjectors() {} + virtual ~TestDataProcessorProjectors() {} + + void run_tests(); - void run_tests(); protected: - std::string _sinogram_filename; - float _fwhm; - shared_ptr _input_sino_sptr; - const std::vector > > post_data_processor_bck_proj(); - const std::vector > pre_data_processor_fwd_proj(const DiscretisedDensity<3,float> &input_image); + std::string _sinogram_filename; + float _fwhm; + shared_ptr _input_sino_sptr; + const std::vector>> post_data_processor_bck_proj(); + const std::vector> pre_data_processor_fwd_proj(const DiscretisedDensity<3, float>& input_image); }; -TestDataProcessorProjectors::TestDataProcessorProjectors(const std::string &sinogram_filename, const float fwhm) : - _sinogram_filename(sinogram_filename), - _fwhm(fwhm) -{ -} +TestDataProcessorProjectors::TestDataProcessorProjectors(const std::string& sinogram_filename, const float fwhm) + : _sinogram_filename(sinogram_filename), _fwhm(fwhm) {} -static -Succeeded -compare_arrays(const std::vector &vec1, const std::vector &vec2) -{ - // Subtract - std::vector diff = vec1; - std::transform(vec1.begin(), vec1.end(), vec2.begin(), diff.begin(), std::minus()); +static Succeeded +compare_arrays(const std::vector& vec1, const std::vector& vec2) { + // Subtract + std::vector diff = vec1; + std::transform(vec1.begin(), vec1.end(), vec2.begin(), diff.begin(), std::minus()); - // Get max difference - const float max_diff = *std::max_element(diff.begin(), diff.end()); + // Get max difference + const float max_diff = *std::max_element(diff.begin(), diff.end()); - std::cout << "Min array 1 / array 2 = " << *std::min_element(vec1.begin(),vec1.end()) << " / " << *std::min_element(vec2.begin(),vec2.end()) << "\n"; - std::cout << "Max array 1 / array 2 = " << *std::max_element(vec1.begin(),vec1.end()) << " / " << *std::max_element(vec2.begin(),vec2.end()) << "\n"; - std::cout << "Sum array 1 / array 2 = " << std::accumulate(vec1.begin(),vec1.end(),0.f) << " / " << std::accumulate(vec2.begin(),vec2.end(),0.f) << "\n"; - std::cout << "Max diff = " << max_diff << "\n\n"; + std::cout << "Min array 1 / array 2 = " << *std::min_element(vec1.begin(), vec1.end()) << " / " + << *std::min_element(vec2.begin(), vec2.end()) << "\n"; + std::cout << "Max array 1 / array 2 = " << *std::max_element(vec1.begin(), vec1.end()) << " / " + << *std::max_element(vec2.begin(), vec2.end()) << "\n"; + std::cout << "Sum array 1 / array 2 = " << std::accumulate(vec1.begin(), vec1.end(), 0.f) << " / " + << std::accumulate(vec2.begin(), vec2.end(), 0.f) << "\n"; + std::cout << "Max diff = " << max_diff << "\n\n"; - return (std::abs(max_diff) < 1e-3f ? Succeeded::yes : Succeeded::no); + return (std::abs(max_diff) < 1e-3f ? Succeeded::yes : Succeeded::no); } -static -void -compare_images(bool &everything_ok, const DiscretisedDensity<3,float> &im_1, const DiscretisedDensity<3,float> &im_2) -{ - std::cout << "\nComparing images...\n"; - - if (!im_1.has_same_characteristics(im_2)) { - std::cout << "\nImages have different characteristics!\n"; - everything_ok = false; - } - - Coordinate3D min_indices, max_indices; - - im_1.get_regular_range(min_indices, max_indices); - unsigned num_elements = 1; - for (int i=0; i<3; ++i) - num_elements *= unsigned(max_indices[i + 1] - min_indices[i + 1] + 1); - - std::vector arr_1(num_elements), arr_2(num_elements); - - DiscretisedDensity<3,float>::const_full_iterator im_1_iter = im_1.begin_all_const(); - DiscretisedDensity<3,float>::const_full_iterator im_2_iter = im_2.begin_all_const(); - std::vector::iterator arr_1_iter = arr_1.begin(); - std::vector::iterator arr_2_iter = arr_2.begin(); - while (im_1_iter!=im_1.end_all_const()) { - *arr_1_iter = *im_1_iter; - *arr_2_iter = *im_2_iter; - ++im_1_iter; - ++im_2_iter; - ++arr_1_iter; - ++arr_2_iter; - } - - // Compare values - if (compare_arrays(arr_1,arr_2) == Succeeded::yes) - std::cout << "Images match!\n"; - else { - std::cout << "Images don't match!\n"; - everything_ok = false; - } +static void +compare_images(bool& everything_ok, const DiscretisedDensity<3, float>& im_1, const DiscretisedDensity<3, float>& im_2) { + std::cout << "\nComparing images...\n"; + + if (!im_1.has_same_characteristics(im_2)) { + std::cout << "\nImages have different characteristics!\n"; + everything_ok = false; + } + + Coordinate3D min_indices, max_indices; + + im_1.get_regular_range(min_indices, max_indices); + unsigned num_elements = 1; + for (int i = 0; i < 3; ++i) + num_elements *= unsigned(max_indices[i + 1] - min_indices[i + 1] + 1); + + std::vector arr_1(num_elements), arr_2(num_elements); + + DiscretisedDensity<3, float>::const_full_iterator im_1_iter = im_1.begin_all_const(); + DiscretisedDensity<3, float>::const_full_iterator im_2_iter = im_2.begin_all_const(); + std::vector::iterator arr_1_iter = arr_1.begin(); + std::vector::iterator arr_2_iter = arr_2.begin(); + while (im_1_iter != im_1.end_all_const()) { + *arr_1_iter = *im_1_iter; + *arr_2_iter = *im_2_iter; + ++im_1_iter; + ++im_2_iter; + ++arr_1_iter; + ++arr_2_iter; + } + + // Compare values + if (compare_arrays(arr_1, arr_2) == Succeeded::yes) + std::cout << "Images match!\n"; + else { + std::cout << "Images don't match!\n"; + everything_ok = false; + } } -static -void -compare_sinos(bool &everything_ok, const ProjData &proj_data_1, const ProjData &proj_data_2) -{ - std::cout << "\nComparing sinograms...\n"; - - if (*proj_data_1.get_proj_data_info_sptr() != *proj_data_2.get_proj_data_info_sptr()) { - std::cout << "\nSinogram proj data info don't match\n"; - everything_ok = false; - } - - int min_segment_num = proj_data_1.get_min_segment_num(); - int max_segment_num = proj_data_1.get_max_segment_num(); - - // Get number of elements - unsigned num_elements(0); - for (int segment_num = min_segment_num; segment_num<= max_segment_num; ++segment_num) - num_elements += unsigned(proj_data_1.get_max_axial_pos_num(segment_num) - proj_data_1.get_min_axial_pos_num(segment_num)) + 1; - num_elements *= unsigned(proj_data_1.get_max_view_num() - proj_data_1.get_min_view_num()) + 1; - num_elements *= unsigned(proj_data_1.get_max_tangential_pos_num() - proj_data_1.get_min_tangential_pos_num()) + 1; - - // Create arrays - std::vector arr_1(num_elements), arr_2(num_elements); - proj_data_1.copy_to(arr_1.begin()); - proj_data_2.copy_to(arr_2.begin()); - - // Compare values - if (compare_arrays(arr_1,arr_2) == Succeeded::yes) - std::cout << "Sinograms match!\n"; - else { - std::cout << "Sinograms don't match!\n"; - everything_ok = false; - } +static void +compare_sinos(bool& everything_ok, const ProjData& proj_data_1, const ProjData& proj_data_2) { + std::cout << "\nComparing sinograms...\n"; + + if (*proj_data_1.get_proj_data_info_sptr() != *proj_data_2.get_proj_data_info_sptr()) { + std::cout << "\nSinogram proj data info don't match\n"; + everything_ok = false; + } + + int min_segment_num = proj_data_1.get_min_segment_num(); + int max_segment_num = proj_data_1.get_max_segment_num(); + + // Get number of elements + unsigned num_elements(0); + for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) + num_elements += unsigned(proj_data_1.get_max_axial_pos_num(segment_num) - proj_data_1.get_min_axial_pos_num(segment_num)) + 1; + num_elements *= unsigned(proj_data_1.get_max_view_num() - proj_data_1.get_min_view_num()) + 1; + num_elements *= unsigned(proj_data_1.get_max_tangential_pos_num() - proj_data_1.get_min_tangential_pos_num()) + 1; + + // Create arrays + std::vector arr_1(num_elements), arr_2(num_elements); + proj_data_1.copy_to(arr_1.begin()); + proj_data_2.copy_to(arr_2.begin()); + + // Compare values + if (compare_arrays(arr_1, arr_2) == Succeeded::yes) + std::cout << "Sinograms match!\n"; + else { + std::cout << "Sinograms don't match!\n"; + everything_ok = false; + } } void -TestDataProcessorProjectors:: -run_tests() -{ - try { - // Open sinogram - _input_sino_sptr = ProjData::read_from_file(_sinogram_filename); - - // Back project - std::cerr << "Tests for post-data-processor back projection\n"; - const std::vector > > bck_projected_ims = - this->post_data_processor_bck_proj(); - - // Forward project - std::cerr << "Tests for pre-data-processor forward projection\n"; - const std::vector > fwd_projected_sinos = - this->pre_data_processor_fwd_proj(*bck_projected_ims[0]); - - // Compare back projections - compare_images(everything_ok, *bck_projected_ims[0],*bck_projected_ims[1]); - - // Compare forward projections - compare_sinos(everything_ok, *fwd_projected_sinos[0],*fwd_projected_sinos[1]); - } - catch(const std::exception &error) { - std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; - everything_ok = false; - } - catch(...) { - everything_ok = false; - } +TestDataProcessorProjectors::run_tests() { + try { + // Open sinogram + _input_sino_sptr = ProjData::read_from_file(_sinogram_filename); + + // Back project + std::cerr << "Tests for post-data-processor back projection\n"; + const std::vector>> bck_projected_ims = this->post_data_processor_bck_proj(); + + // Forward project + std::cerr << "Tests for pre-data-processor forward projection\n"; + const std::vector> fwd_projected_sinos = this->pre_data_processor_fwd_proj(*bck_projected_ims[0]); + + // Compare back projections + compare_images(everything_ok, *bck_projected_ims[0], *bck_projected_ims[1]); + + // Compare forward projections + compare_sinos(everything_ok, *fwd_projected_sinos[0], *fwd_projected_sinos[1]); + } catch (const std::exception& error) { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + everything_ok = false; + } catch (...) { + everything_ok = false; + } } -static -void -get_data_processor(shared_ptr > > &data_processor_sptr, const float fwhm) -{ - data_processor_sptr.reset(new SeparableCartesianMetzImageFilter); - std::string buffer; - std::stringstream parameterstream(buffer); - - parameterstream << "Separable Cartesian Metz Filter Parameters :=\n" - << "x-dir filter FWHM (in mm):= " << fwhm << "\n" - << "y-dir filter FWHM (in mm):= " << fwhm << "\n" - << "z-dir filter FWHM (in mm):= " << fwhm << "\n" - << "x-dir filter Metz power:= .0\n" - << "y-dir filter Metz power:= .0\n" - << "z-dir filter Metz power:=.0\n" - << "END Separable Cartesian Metz Filter Parameters :=\n"; - data_processor_sptr->parse(parameterstream); +static void +get_data_processor(shared_ptr>>& data_processor_sptr, const float fwhm) { + data_processor_sptr.reset(new SeparableCartesianMetzImageFilter); + std::string buffer; + std::stringstream parameterstream(buffer); + + parameterstream << "Separable Cartesian Metz Filter Parameters :=\n" + << "x-dir filter FWHM (in mm):= " << fwhm << "\n" + << "y-dir filter FWHM (in mm):= " << fwhm << "\n" + << "z-dir filter FWHM (in mm):= " << fwhm << "\n" + << "x-dir filter Metz power:= .0\n" + << "y-dir filter Metz power:= .0\n" + << "z-dir filter Metz power:=.0\n" + << "END Separable Cartesian Metz Filter Parameters :=\n"; + data_processor_sptr->parse(parameterstream); } -static -shared_ptr -get_back_projector_via_parser(const float fwhm = -1.f) -{ - std::string buffer; - std::stringstream parameterstream(buffer); - - parameterstream << "Back Projector parameters:=\n"; - if (fwhm > 0) - parameterstream - << "Post Data Processor := Separable Cartesian Metz\n" +static shared_ptr +get_back_projector_via_parser(const float fwhm = -1.f) { + std::string buffer; + std::stringstream parameterstream(buffer); + + parameterstream << "Back Projector parameters:=\n"; + if (fwhm > 0) + parameterstream << "Post Data Processor := Separable Cartesian Metz\n" << "Separable Cartesian Metz Filter Parameters :=\n" << " x-dir filter FWHM (in mm):= " << fwhm << "\n" << " y-dir filter FWHM (in mm):= " << fwhm << "\n" @@ -223,29 +206,25 @@ get_back_projector_via_parser(const float fwhm = -1.f) << " y-dir filter Metz power:= .0\n" << " z-dir filter Metz power:=.0\n" << "END Separable Cartesian Metz Filter Parameters :=\n"; - parameterstream << "End Back Projector Parameters:=\n"; + parameterstream << "End Back Projector Parameters:=\n"; - shared_ptr PM_sptr(new ProjMatrixByBinUsingRayTracing); + shared_ptr PM_sptr(new ProjMatrixByBinUsingRayTracing); - shared_ptr back_proj_sptr = - MAKE_SHARED(PM_sptr); - back_proj_sptr->parse(parameterstream); + shared_ptr back_proj_sptr = MAKE_SHARED(PM_sptr); + back_proj_sptr->parse(parameterstream); - return back_proj_sptr; + return back_proj_sptr; } -static -shared_ptr -get_forward_projector_via_parser(const float fwhm = -1.f) -{ - shared_ptr fwd_proj; - std::string buffer; - std::stringstream parameterstream(buffer); - - parameterstream << "Forward Projector parameters:=\n"; - if (fwhm > 0) - parameterstream - << "Pre Data Processor := Separable Cartesian Metz\n" +static shared_ptr +get_forward_projector_via_parser(const float fwhm = -1.f) { + shared_ptr fwd_proj; + std::string buffer; + std::stringstream parameterstream(buffer); + + parameterstream << "Forward Projector parameters:=\n"; + if (fwhm > 0) + parameterstream << "Pre Data Processor := Separable Cartesian Metz\n" << "Separable Cartesian Metz Filter Parameters :=\n" << " x-dir filter FWHM (in mm):= " << fwhm << "\n" << " y-dir filter FWHM (in mm):= " << fwhm << "\n" @@ -254,122 +233,114 @@ get_forward_projector_via_parser(const float fwhm = -1.f) << " y-dir filter Metz power:= .0\n" << " z-dir filter Metz power:=.0\n" << "END Separable Cartesian Metz Filter Parameters :=\n"; - parameterstream << "End Forward Projector Parameters:=\n"; + parameterstream << "End Forward Projector Parameters:=\n"; - shared_ptr PM_sptr(new ProjMatrixByBinUsingRayTracing); + shared_ptr PM_sptr(new ProjMatrixByBinUsingRayTracing); - shared_ptr fwd_proj_sptr = - MAKE_SHARED(PM_sptr); - fwd_proj_sptr->parse(parameterstream); + shared_ptr fwd_proj_sptr = MAKE_SHARED(PM_sptr); + fwd_proj_sptr->parse(parameterstream); - return fwd_proj_sptr; + return fwd_proj_sptr; } -const std::vector > -TestDataProcessorProjectors:: -pre_data_processor_fwd_proj(const DiscretisedDensity<3,float> &input_image) -{ - // Create two sinograms, images and forward projectors. - // One for pre-data processor forward projection, - // the other for data processor then forward projection - std::vector > sinos(2); - std::vector > > images(2); - std::vector > projectors(2); +const std::vector> +TestDataProcessorProjectors::pre_data_processor_fwd_proj(const DiscretisedDensity<3, float>& input_image) { + // Create two sinograms, images and forward projectors. + // One for pre-data processor forward projection, + // the other for data processor then forward projection + std::vector> sinos(2); + std::vector>> images(2); + std::vector> projectors(2); - // Loop over twice! - for (unsigned i=0; i(*_input_sino_sptr); - sinos[i]->fill(0.f); + // Copy the sinogram and fill with zeros + sinos[i] = MAKE_SHARED(*_input_sino_sptr); + sinos[i]->fill(0.f); - // Copy input image - images[i].reset(input_image.clone()); + // Copy input image + images[i].reset(input_image.clone()); - // The first time, use the data processor during the forward projection - projectors[i] = get_forward_projector_via_parser(i==0 ? _fwhm : -1); + // The first time, use the data processor during the forward projection + projectors[i] = get_forward_projector_via_parser(i == 0 ? _fwhm : -1); + projectors[i]->set_up(_input_sino_sptr->get_proj_data_info_sptr()->create_shared_clone(), images[i]); - projectors[i]->set_up(_input_sino_sptr->get_proj_data_info_sptr()->create_shared_clone(),images[i]); - - // The second time, use the data processor before the forward projection - if (i!=0) { - // Set up the data processor - shared_ptr > > data_processor_sptr; - get_data_processor(data_processor_sptr, _fwhm); - data_processor_sptr->apply(*images[i]); - } - - // Forward project - projectors[i]->set_input(*images[i]); - projectors[i]->forward_project(*sinos[i]); + // The second time, use the data processor before the forward projection + if (i != 0) { + // Set up the data processor + shared_ptr>> data_processor_sptr; + get_data_processor(data_processor_sptr, _fwhm); + data_processor_sptr->apply(*images[i]); } - return sinos; + // Forward project + projectors[i]->set_input(*images[i]); + projectors[i]->forward_project(*sinos[i]); + } + + return sinos; } -const std::vector > > -TestDataProcessorProjectors:: -post_data_processor_bck_proj() -{ - // Create two images and two back projectors. - // One for pre-data processor back projection, - // the other for data processor then back projection - std::vector > > images(2); - std::vector > projectors(2); - - // Loop over twice! - for (unsigned i=0; i >(*_input_sino_sptr->get_proj_data_info_sptr()); - images[i]->fill(0.f); - - // The first time, use the data processor during the back projection - projectors[i] = get_back_projector_via_parser(i==0 ? _fwhm : -1); - - projectors[i]->set_up(_input_sino_sptr->get_proj_data_info_sptr()->create_shared_clone(),images[i]); - - // Back project - projectors[i]->start_accumulating_in_new_target(); - projectors[i]->back_project(*_input_sino_sptr); - projectors[i]->get_output(*images[i]); - - // The second time, use the data processor after the back projection - if (i!=0) { - // Set up the data processor - shared_ptr > > data_processor_sptr; - get_data_processor(data_processor_sptr, _fwhm); - data_processor_sptr->apply(*images[i]); - } +const std::vector>> +TestDataProcessorProjectors::post_data_processor_bck_proj() { + // Create two images and two back projectors. + // One for pre-data processor back projection, + // the other for data processor then back projection + std::vector>> images(2); + std::vector> projectors(2); + + // Loop over twice! + for (unsigned i = 0; i < images.size(); ++i) { + + // Copy images and fill with zeros + images[i] = MAKE_SHARED>(*_input_sino_sptr->get_proj_data_info_sptr()); + images[i]->fill(0.f); + + // The first time, use the data processor during the back projection + projectors[i] = get_back_projector_via_parser(i == 0 ? _fwhm : -1); + + projectors[i]->set_up(_input_sino_sptr->get_proj_data_info_sptr()->create_shared_clone(), images[i]); + + // Back project + projectors[i]->start_accumulating_in_new_target(); + projectors[i]->back_project(*_input_sino_sptr); + projectors[i]->get_output(*images[i]); + + // The second time, use the data processor after the back projection + if (i != 0) { + // Set up the data processor + shared_ptr>> data_processor_sptr; + get_data_processor(data_processor_sptr, _fwhm); + data_processor_sptr->apply(*images[i]); } + } - return images; + return images; } END_NAMESPACE_STIR - USING_NAMESPACE_STIR +int +main(int argc, char** argv) { + if (argc < 2 || argc > 3) { + std::cerr << "\n\tUsage: " << argv[0] << " sinogram [fwhm]\n"; + return EXIT_FAILURE; + } -int main(int argc, char **argv) -{ - if (argc < 2 || argc > 3) { - std::cerr << "\n\tUsage: " << argv[0] << " sinogram [fwhm]\n"; - return EXIT_FAILURE; - } - - float fwhm = 5.f; - if (argc == 3) - fwhm = float(atof(argv[2])); + float fwhm = 5.f; + if (argc == 3) + fwhm = float(atof(argv[2])); - set_default_num_threads(); + set_default_num_threads(); - TestDataProcessorProjectors test(argv[1], fwhm); + TestDataProcessorProjectors test(argv[1], fwhm); - if (test.is_everything_ok()) - test.run_tests(); + if (test.is_everything_ok()) + test.run_tests(); - return test.main_return_value(); + return test.main_return_value(); } \ No newline at end of file diff --git a/src/recon_test/test_priors.cxx b/src/recon_test/test_priors.cxx index 0abce86eaf..065b63f543 100644 --- a/src/recon_test/test_priors.cxx +++ b/src/recon_test/test_priors.cxx @@ -19,13 +19,13 @@ \file \ingroup recon_test - + \brief Test program for stir::QuadraticPrior, RelativeDifferencePrior, and LogcoshPrior \par Usage
    -  test_priors [ density_filename ] 
    +  test_priors [ density_filename ]
       
    where the argument is optional. See the class documentation for more info. @@ -53,55 +53,48 @@ START_NAMESPACE_STIR - /*! \ingroup test \brief Test class for QuadraticPrior, RelativeDifferencePrior, and LogcoshPrior This test compares the result of GeneralisedPrior::compute_gradient() - with a numerical gradient computed by using the + with a numerical gradient computed by using the GeneralisedPrior::compute_value() function. */ -class GeneralisedPriorTests : public RunTests -{ +class GeneralisedPriorTests : public RunTests { public: //! Constructor that can take some input data to run the test with /*! This makes it possible to run the test with your own data. However, beware that - it is very easy to set up a very long computation. + it is very easy to set up a very long computation. \todo it would be better to parse an objective function. That would allow us to set all parameters from the command line. */ - GeneralisedPriorTests(char const * const density_filename = 0); - typedef DiscretisedDensity<3,float> target_type; + GeneralisedPriorTests(char const* const density_filename = 0); + typedef DiscretisedDensity<3, float> target_type; void construct_input_data(shared_ptr& density_sptr); void run_tests(); + protected: - char const * density_filename; - shared_ptr > objective_function_sptr; + char const* density_filename; + shared_ptr> objective_function_sptr; //! run the test /*! Note that this function is not specific to a particular prior */ - void run_tests_for_objective_function(const std::string& test_name, - GeneralisedPrior& objective_function, + void run_tests_for_objective_function(const std::string& test_name, GeneralisedPrior& objective_function, shared_ptr target_sptr); }; -GeneralisedPriorTests:: -GeneralisedPriorTests(char const * const density_filename) - : density_filename(density_filename) -{} +GeneralisedPriorTests::GeneralisedPriorTests(char const* const density_filename) : density_filename(density_filename) {} void -GeneralisedPriorTests:: -run_tests_for_objective_function(const std::string& test_name, - GeneralisedPrior& objective_function, - shared_ptr target_sptr) -{ +GeneralisedPriorTests::run_tests_for_objective_function(const std::string& test_name, + GeneralisedPrior& objective_function, + shared_ptr target_sptr) { std::cerr << "----- test " << test_name << '\n'; - if (!check(objective_function.set_up(target_sptr)==Succeeded::yes, "set-up of objective function")) + if (!check(objective_function.set_up(target_sptr) == Succeeded::yes, "set-up of objective function")) return; // setup images @@ -109,81 +102,73 @@ run_tests_for_objective_function(const std::string& test_name, shared_ptr gradient_sptr(target.get_empty_copy()); shared_ptr gradient_2_sptr(target.get_empty_copy()); - info("Computing gradient",3); + info("Computing gradient", 3); objective_function.compute_gradient(*gradient_sptr, target); - this->set_tolerance(std::max(fabs(double(gradient_sptr->find_min())), fabs(double(gradient_sptr->find_max()))) /1000); + this->set_tolerance(std::max(fabs(double(gradient_sptr->find_min())), fabs(double(gradient_sptr->find_max()))) / 1000); - info("Computing objective function at target",3); + info("Computing objective function at target", 3); const double value_at_target = objective_function.compute_value(target); - target_type::full_iterator target_iter=target.begin_all(); - target_type::full_iterator gradient_iter=gradient_sptr->begin_all(); - target_type::full_iterator gradient_2_iter=gradient_2_sptr->begin_all(); + target_type::full_iterator target_iter = target.begin_all(); + target_type::full_iterator gradient_iter = gradient_sptr->begin_all(); + target_type::full_iterator gradient_2_iter = gradient_2_sptr->begin_all(); // setup perturbation response const float eps = 1e-3F; bool testOK = true; - info("Computing gradient of objective function by numerical differences (this will take a while)",3); - while(target_iter!=target.end_all())// && testOK) - { - const float org_image_value = *target_iter; - *target_iter += eps; // perturb current voxel - const double value_at_inc = objective_function.compute_value(target); - *target_iter = org_image_value; // restore - const float ngradient_at_iter = static_cast((value_at_inc - value_at_target)/eps); - *gradient_2_iter = ngradient_at_iter; - testOK = testOK && this->check_if_equal(ngradient_at_iter, *gradient_iter, "gradient"); - //for (int i=0; i<5 && target_iter!=target.end_all(); ++i) - { - ++gradient_2_iter; ++target_iter; ++ gradient_iter; - } - } - if (!testOK) + info("Computing gradient of objective function by numerical differences (this will take a while)", 3); + while (target_iter != target.end_all()) // && testOK) + { + const float org_image_value = *target_iter; + *target_iter += eps; // perturb current voxel + const double value_at_inc = objective_function.compute_value(target); + *target_iter = org_image_value; // restore + const float ngradient_at_iter = static_cast((value_at_inc - value_at_target) / eps); + *gradient_2_iter = ngradient_at_iter; + testOK = testOK && this->check_if_equal(ngradient_at_iter, *gradient_iter, "gradient"); + // for (int i=0; i<5 && target_iter!=target.end_all(); ++i) { - info("Writing diagnostic files gradient" + test_name + ".hv, numerical_gradient" + test_name + ".hv"); - write_to_file("gradient" + test_name + ".hv", *gradient_sptr); - write_to_file("numerical_gradient" + test_name + ".hv", *gradient_2_sptr); + ++gradient_2_iter; + ++target_iter; + ++gradient_iter; } - + } + if (!testOK) { + info("Writing diagnostic files gradient" + test_name + ".hv, numerical_gradient" + test_name + ".hv"); + write_to_file("gradient" + test_name + ".hv", *gradient_sptr); + write_to_file("numerical_gradient" + test_name + ".hv", *gradient_2_sptr); + } } void -GeneralisedPriorTests:: -construct_input_data(shared_ptr& density_sptr) -{ - if (this->density_filename == 0) - { - // construct a small image with random voxel values between 0 and 1 - - shared_ptr exam_info_sptr(new ExamInfo); - exam_info_sptr->imaging_modality = ImagingModality::PT; - CartesianCoordinate3D origin (0,0,0); - CartesianCoordinate3D voxel_size(2.F,3.F,3.F); - - density_sptr.reset(new VoxelsOnCartesianGrid(exam_info_sptr, - IndexRange<3>(make_coordinate(10,9,8)), - origin, voxel_size)); - // fill with random numbers between 0 and 1 - typedef boost::mt19937 base_generator_type; - // initialize by reproducible seed - static base_generator_type generator(boost::uint32_t(42)); - static boost::uniform_01 random01(generator); - for (target_type::full_iterator iter=density_sptr->begin_all(); iter!=density_sptr->end_all(); ++iter) - *iter = static_cast(random01()); - - } - else - { - // load image from file - shared_ptr aptr(read_from_file(this->density_filename)); - density_sptr = aptr; - } - return; +GeneralisedPriorTests::construct_input_data(shared_ptr& density_sptr) { + if (this->density_filename == 0) { + // construct a small image with random voxel values between 0 and 1 + + shared_ptr exam_info_sptr(new ExamInfo); + exam_info_sptr->imaging_modality = ImagingModality::PT; + CartesianCoordinate3D origin(0, 0, 0); + CartesianCoordinate3D voxel_size(2.F, 3.F, 3.F); + + density_sptr.reset( + new VoxelsOnCartesianGrid(exam_info_sptr, IndexRange<3>(make_coordinate(10, 9, 8)), origin, voxel_size)); + // fill with random numbers between 0 and 1 + typedef boost::mt19937 base_generator_type; + // initialize by reproducible seed + static base_generator_type generator(boost::uint32_t(42)); + static boost::uniform_01 random01(generator); + for (target_type::full_iterator iter = density_sptr->begin_all(); iter != density_sptr->end_all(); ++iter) + *iter = static_cast(random01()); + + } else { + // load image from file + shared_ptr aptr(read_from_file(this->density_filename)); + density_sptr = aptr; + } + return; } void -GeneralisedPriorTests:: -run_tests() -{ +GeneralisedPriorTests::run_tests() { shared_ptr density_sptr; construct_input_data(density_sptr); @@ -199,32 +184,31 @@ run_tests() this->run_tests_for_objective_function("RDP_no_kappa", objective_function, density_sptr); } // Disabled PLS due to known issue -// std::cerr << "Tests for PLSPrior\n"; -// { -// PLSPrior objective_function(false, 1.F); -// shared_ptr > anatomical_image_sptr(density_sptr->get_empty_copy()); -// anatomical_image_sptr->fill(1.F); -// objective_function.set_anatomical_image_sptr(anatomical_image_sptr); -// this->run_tests_for_objective_function("PLS_no_kappa_flat_anatomical", objective_function, density_sptr); -// } + // std::cerr << "Tests for PLSPrior\n"; + // { + // PLSPrior objective_function(false, 1.F); + // shared_ptr > anatomical_image_sptr(density_sptr->get_empty_copy()); + // anatomical_image_sptr->fill(1.F); + // objective_function.set_anatomical_image_sptr(anatomical_image_sptr); + // this->run_tests_for_objective_function("PLS_no_kappa_flat_anatomical", objective_function, density_sptr); + // } std::cerr << "Tests for Logcosh Prior\n"; { // scalar is off LogcoshPrior objective_function(false, 1.F, 1.F); this->run_tests_for_objective_function("Logcosh_no_kappa", objective_function, density_sptr); } -} +} END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ +int +main(int argc, char** argv) { set_default_num_threads(); - GeneralisedPriorTests tests(argc>1? argv[1] : 0); + GeneralisedPriorTests tests(argc > 1 ? argv[1] : 0); tests.run_tests(); return tests.main_return_value(); } diff --git a/src/scatter_buildblock/CreateTailMaskFromACFs.cxx b/src/scatter_buildblock/CreateTailMaskFromACFs.cxx index 4249f51f99..3abae056b9 100644 --- a/src/scatter_buildblock/CreateTailMaskFromACFs.cxx +++ b/src/scatter_buildblock/CreateTailMaskFromACFs.cxx @@ -23,179 +23,122 @@ START_NAMESPACE_STIR void -CreateTailMaskFromACFs:: -set_input_projdata_sptr(shared_ptr & arg) -{ - this->ACF_sptr = arg; +CreateTailMaskFromACFs::set_input_projdata_sptr(shared_ptr& arg) { + this->ACF_sptr = arg; } void -CreateTailMaskFromACFs:: -set_input_projdata(std::string& arg) -{ - this->ACF_sptr = - ProjData::read_from_file(arg); +CreateTailMaskFromACFs::set_input_projdata(std::string& arg) { + this->ACF_sptr = ProjData::read_from_file(arg); } void -CreateTailMaskFromACFs:: -set_output_projdata_sptr(shared_ptr& arg) -{ - this->mask_proj_data = arg; +CreateTailMaskFromACFs::set_output_projdata_sptr(shared_ptr& arg) { + this->mask_proj_data = arg; } void -CreateTailMaskFromACFs:: -set_output_projdata(std::string& arg) -{ - this->mask_proj_data.reset(new ProjDataInterfile(ACF_sptr->get_exam_info_sptr(), - ACF_sptr->get_proj_data_info_sptr()->create_shared_clone(), - arg)); +CreateTailMaskFromACFs::set_output_projdata(std::string& arg) { + this->mask_proj_data.reset( + new ProjDataInterfile(ACF_sptr->get_exam_info_sptr(), ACF_sptr->get_proj_data_info_sptr()->create_shared_clone(), arg)); } - shared_ptr -CreateTailMaskFromACFs:: -get_output_projdata_sptr() -{ - return this->mask_proj_data; +CreateTailMaskFromACFs::get_output_projdata_sptr() { + return this->mask_proj_data; } void -CreateTailMaskFromACFs:: -set_defaults() -{ - ACF_threshold = 1.1F; - safety_margin = 4; +CreateTailMaskFromACFs::set_defaults() { + ACF_threshold = 1.1F; + safety_margin = 4; } -CreateTailMaskFromACFs:: -CreateTailMaskFromACFs() -{ - this->set_defaults(); -} +CreateTailMaskFromACFs::CreateTailMaskFromACFs() { this->set_defaults(); } void -CreateTailMaskFromACFs:: -initialise_keymap() -{ - this->parser.add_start_key("CreateTailMaskFromACFs"); - this->parser.add_stop_key("END CreateTailMaskFromACFs"); - this->parser.add_key("ACF-filename", - &_input_filename); - this->parser.add_key("output-filename", - &_output_filename); - this->parser.add_key("ACF-threshold", - &ACF_threshold); - this->parser.add_key("safety-margin", - &safety_margin); +CreateTailMaskFromACFs::initialise_keymap() { + this->parser.add_start_key("CreateTailMaskFromACFs"); + this->parser.add_stop_key("END CreateTailMaskFromACFs"); + this->parser.add_key("ACF-filename", &_input_filename); + this->parser.add_key("output-filename", &_output_filename); + this->parser.add_key("ACF-threshold", &ACF_threshold); + this->parser.add_key("safety-margin", &safety_margin); } bool -CreateTailMaskFromACFs:: -post_processing() -{ - if (ACF_threshold<=1) - error("ACF-threshold should be larger than 1"); +CreateTailMaskFromACFs::post_processing() { + if (ACF_threshold <= 1) + error("ACF-threshold should be larger than 1"); - if(this->_input_filename.size() > 0) - this->set_input_projdata(this->_input_filename); + if (this->_input_filename.size() > 0) + this->set_input_projdata(this->_input_filename); + if (this->_output_filename.size() > 0) + this->set_output_projdata(this->_output_filename); - if(this->_output_filename.size() > 0) - this->set_output_projdata(this->_output_filename); - - return false; + return false; } Succeeded -CreateTailMaskFromACFs:: -process_data() -{ - if (is_null_ptr(this->ACF_sptr)) - error("Check the attenuation_correct_factors file"); - - if (is_null_ptr(this->mask_proj_data)) - error("Please set output file"); - - Bin bin; - { - for (bin.segment_num()=this->mask_proj_data->get_min_segment_num(); - bin.segment_num()<=this->mask_proj_data->get_max_segment_num(); - ++bin.segment_num()) - for (bin.axial_pos_num()= - this->mask_proj_data->get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num()<=this->mask_proj_data->get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - { - const Sinogram att_sinogram - (this->ACF_sptr->get_sinogram(bin.axial_pos_num(),bin.segment_num())); - Sinogram mask_sinogram - (this->mask_proj_data->get_empty_sinogram(bin.axial_pos_num(),bin.segment_num())); - - std::size_t count=0; - for (bin.view_num()=this->mask_proj_data->get_min_view_num(); - bin.view_num()<=this->mask_proj_data->get_max_view_num(); - ++bin.view_num()) - { +CreateTailMaskFromACFs::process_data() { + if (is_null_ptr(this->ACF_sptr)) + error("Check the attenuation_correct_factors file"); + + if (is_null_ptr(this->mask_proj_data)) + error("Please set output file"); + + Bin bin; + { + for (bin.segment_num() = this->mask_proj_data->get_min_segment_num(); + bin.segment_num() <= this->mask_proj_data->get_max_segment_num(); ++bin.segment_num()) + for (bin.axial_pos_num() = this->mask_proj_data->get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= this->mask_proj_data->get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) { + const Sinogram att_sinogram(this->ACF_sptr->get_sinogram(bin.axial_pos_num(), bin.segment_num())); + Sinogram mask_sinogram(this->mask_proj_data->get_empty_sinogram(bin.axial_pos_num(), bin.segment_num())); + + std::size_t count = 0; + for (bin.view_num() = this->mask_proj_data->get_min_view_num(); + bin.view_num() <= this->mask_proj_data->get_max_view_num(); ++bin.view_num()) { #ifdef SCFOLD - for (bin.tangential_pos_num()= - mask_proj_data.get_min_tangential_pos_num(); - bin.tangential_pos_num()<= - mask_proj_data.get_max_tangential_pos_num(); - ++bin.tangential_pos_num()) - if (att_sinogram[bin.view_num()][bin.tangential_pos_num()]= std::fabs(scatter_proj_data.get_proj_data_info_sptr()->get_s(bin)))) - { - ++count; - mask_sinogram[bin.view_num()][bin.tangential_pos_num()]=1; - } - else - mask_sinogram[bin.view_num()][bin.tangential_pos_num()]=0; + for (bin.tangential_pos_num() = mask_proj_data.get_min_tangential_pos_num(); + bin.tangential_pos_num() <= mask_proj_data.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + if (att_sinogram[bin.view_num()][bin.tangential_pos_num()] < ACF_threshold && + (mask_radius_in_mm < 0 || + mask_radius_in_mm >= std::fabs(scatter_proj_data.get_proj_data_info_sptr()->get_s(bin)))) { + ++count; + mask_sinogram[bin.view_num()][bin.tangential_pos_num()] = 1; + } else + mask_sinogram[bin.view_num()][bin.tangential_pos_num()] = 0; #else - const Array<1,float>& att_line=att_sinogram[bin.view_num()]; - - using boost::lambda::_1; - - // find left and right mask sizes - // sorry: a load of ugly casting to make sure we allow all datatypes - std::size_t mask_left_size = - static_cast( - std::max(0, - static_cast - (std::find_if(att_line.begin(), att_line.end(), - _1>=ACF_threshold) - - att_line.begin()) - - safety_margin) - ); - std::size_t mask_right_size = - static_cast( - std::max(0, - static_cast - (std::find_if(att_line.rbegin(), att_line.rend() - mask_left_size, - _1>=ACF_threshold) - - att_line.rbegin()) - - safety_margin) - ); -#if 0 + const Array<1, float>& att_line = att_sinogram[bin.view_num()]; + + using boost::lambda::_1; + + // find left and right mask sizes + // sorry: a load of ugly casting to make sure we allow all datatypes + std::size_t mask_left_size = static_cast(std::max( + 0, static_cast(std::find_if(att_line.begin(), att_line.end(), _1 >= ACF_threshold) - att_line.begin()) - + safety_margin)); + std::size_t mask_right_size = static_cast(std::max( + 0, static_cast(std::find_if(att_line.rbegin(), att_line.rend() - mask_left_size, _1 >= ACF_threshold) - + att_line.rbegin()) - + safety_margin)); +# if 0 std::cout << "mask sizes " << mask_left_size << ", " << mask_right_size << '\n'; +# endif + std::fill(mask_sinogram[bin.view_num()].begin(), mask_sinogram[bin.view_num()].begin() + mask_left_size, 1.F); + std::fill(mask_sinogram[bin.view_num()].rbegin(), mask_sinogram[bin.view_num()].rbegin() + mask_right_size, 1.F); + count += mask_left_size + mask_right_size; #endif - std::fill(mask_sinogram[bin.view_num()].begin(), - mask_sinogram[bin.view_num()].begin() + mask_left_size, - 1.F); - std::fill(mask_sinogram[bin.view_num()].rbegin(), - mask_sinogram[bin.view_num()].rbegin() + mask_right_size, - 1.F); - count += mask_left_size + mask_right_size; -#endif - } - std::cout << count << " bins in mask for sinogram at segment " - << bin.segment_num() << ", axial_pos " << bin.axial_pos_num() << "\n"; - if (this->mask_proj_data->set_sinogram(mask_sinogram) != Succeeded::yes) - return Succeeded::no; - } - } - return Succeeded::yes; + } + std::cout << count << " bins in mask for sinogram at segment " << bin.segment_num() << ", axial_pos " + << bin.axial_pos_num() << "\n"; + if (this->mask_proj_data->set_sinogram(mask_sinogram) != Succeeded::yes) + return Succeeded::no; + } + } + return Succeeded::yes; } END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/ScatterEstimation.cxx b/src/scatter_buildblock/ScatterEstimation.cxx index 43ac79c35e..5599a53abb 100644 --- a/src/scatter_buildblock/ScatterEstimation.cxx +++ b/src/scatter_buildblock/ScatterEstimation.cxx @@ -57,273 +57,208 @@ START_NAMESPACE_STIR void -ScatterEstimation:: -set_defaults() -{ - this->_already_setup = false; - this->scatter_simulation_sptr.reset(new SingleScatterSimulation); - this->recompute_atten_projdata = true; - this->recompute_mask_image = true; - { - // image masking - this->masking_parameters.min_threshold = .003F; - shared_ptr > filter_sptr(new SeparableGaussianImageFilter); - filter_sptr->set_fwhms(make_coordinate(15.F, 20.F, 20.F)); - this->masking_parameters.filter_sptr.reset(new PostFiltering >); - this->masking_parameters.filter_sptr->set_filter_sptr(filter_sptr); - } - this->recompute_mask_projdata = true; - this->run_in_2d_projdata = true; - this->do_average_at_2 = true; - this->export_scatter_estimates_of_each_iteration = false; - this->run_debug_mode = false; - this->override_scanner_template = true; - this->override_density_image = true; - this->downsample_scanner_bool = true; - this->remove_interleaving = true; - this->atten_image_filename = ""; - this->atten_coeff_filename = ""; - this->norm_3d_sptr.reset(); - this->multiplicative_binnorm_sptr.reset(); - this->output_scatter_estimate_prefix = ""; - this->output_additive_estimate_prefix = ""; - this->num_scatter_iterations = 5; - this->min_scale_value = 0.4f; - this->max_scale_value = 100.f; - this->half_filter_width = 3; +ScatterEstimation::set_defaults() { + this->_already_setup = false; + this->scatter_simulation_sptr.reset(new SingleScatterSimulation); + this->recompute_atten_projdata = true; + this->recompute_mask_image = true; + { + // image masking + this->masking_parameters.min_threshold = .003F; + shared_ptr> filter_sptr(new SeparableGaussianImageFilter); + filter_sptr->set_fwhms(make_coordinate(15.F, 20.F, 20.F)); + this->masking_parameters.filter_sptr.reset(new PostFiltering>); + this->masking_parameters.filter_sptr->set_filter_sptr(filter_sptr); + } + this->recompute_mask_projdata = true; + this->run_in_2d_projdata = true; + this->do_average_at_2 = true; + this->export_scatter_estimates_of_each_iteration = false; + this->run_debug_mode = false; + this->override_scanner_template = true; + this->override_density_image = true; + this->downsample_scanner_bool = true; + this->remove_interleaving = true; + this->atten_image_filename = ""; + this->atten_coeff_filename = ""; + this->norm_3d_sptr.reset(); + this->multiplicative_binnorm_sptr.reset(); + this->output_scatter_estimate_prefix = ""; + this->output_additive_estimate_prefix = ""; + this->num_scatter_iterations = 5; + this->min_scale_value = 0.4f; + this->max_scale_value = 100.f; + this->half_filter_width = 3; } void -ScatterEstimation:: -initialise_keymap() -{ - this->parser.add_start_key("Scatter Estimation Parameters"); - this->parser.add_stop_key("end Scatter Estimation Parameters"); - - this->parser.add_key("run in debug mode", - &this->run_debug_mode); - this->parser.add_key("input file", - &this->input_projdata_filename); - this->parser.add_key("attenuation image filename", - &this->atten_image_filename); - - // MASK parameters - this->parser.add_key("recompute mask image", - &this->recompute_mask_image); - this->parser.add_key("mask image filename", - &this->mask_image_filename); - this->parser.add_key("mask attenuation image filter filename", - &this->masking_parameters.filter_filename); - this->parser.add_key("mask attenuation image min threshold", - &this->masking_parameters.min_threshold); - this->parser.add_key("recompute mask projdata", - &this->recompute_mask_projdata); - this->parser.add_key("mask projdata filename", - &this->mask_projdata_filename); - this->parser.add_key("tail fitting parameter filename", - &this->tail_mask_par_filename); - // END MASK - this->parser.add_key("background projdata filename", - &this->back_projdata_filename); - this->parser.add_parsing_key("Normalisation type", - &this->norm_3d_sptr); - this->parser.add_key("attenuation correction factors filename", - &this->atten_coeff_filename); - this->parser.add_parsing_key("Bin Normalisation type", - &this->multiplicative_binnorm_sptr); - - // RECONSTRUCTION RELATED - this->parser.add_key("reconstruction parameter filename", - &this->recon_template_par_filename); - this->parser.add_parsing_key("reconstruction type", - &this->reconstruction_template_sptr); - // END RECONSTRUCTION RELATED - - this->parser.add_key("number of scatter iterations", - &this->num_scatter_iterations); - //Scatter simulation - this->parser.add_parsing_key("Scatter Simulation type", - &this->scatter_simulation_sptr); - this->parser.add_key("scatter simulation parameter filename", - &this->scatter_sim_par_filename); - this->parser.add_key("use scanner downsampling in scatter simulation", - &this->downsample_scanner_bool); - - this->parser.add_key("override attenuation image", - &this->override_density_image); - this->parser.add_key("override scanner template", - &this->override_scanner_template); - - // END Scatter simulation - - this->parser.add_key("export scatter estimates of each iteration", - &this->export_scatter_estimates_of_each_iteration); - this->parser.add_key("output scatter estimate name prefix", - &this->output_scatter_estimate_prefix); - this->parser.add_key("output additive estimate name prefix", - &this->output_additive_estimate_prefix); - this->parser.add_key("do average at 2", - &this->do_average_at_2); - this->parser.add_key("maximum scatter scaling factor", - &this->max_scale_value); - this->parser.add_key("minimum scatter scaling factor", - &this->min_scale_value); - this->parser.add_key("upsampling half filter width", - &this->half_filter_width); - this->parser.add_key("remove interleaving before upsampling", - &this->remove_interleaving); - this->parser.add_key("run in 2d projdata", - &this->run_in_2d_projdata); +ScatterEstimation::initialise_keymap() { + this->parser.add_start_key("Scatter Estimation Parameters"); + this->parser.add_stop_key("end Scatter Estimation Parameters"); + + this->parser.add_key("run in debug mode", &this->run_debug_mode); + this->parser.add_key("input file", &this->input_projdata_filename); + this->parser.add_key("attenuation image filename", &this->atten_image_filename); + + // MASK parameters + this->parser.add_key("recompute mask image", &this->recompute_mask_image); + this->parser.add_key("mask image filename", &this->mask_image_filename); + this->parser.add_key("mask attenuation image filter filename", &this->masking_parameters.filter_filename); + this->parser.add_key("mask attenuation image min threshold", &this->masking_parameters.min_threshold); + this->parser.add_key("recompute mask projdata", &this->recompute_mask_projdata); + this->parser.add_key("mask projdata filename", &this->mask_projdata_filename); + this->parser.add_key("tail fitting parameter filename", &this->tail_mask_par_filename); + // END MASK + this->parser.add_key("background projdata filename", &this->back_projdata_filename); + this->parser.add_parsing_key("Normalisation type", &this->norm_3d_sptr); + this->parser.add_key("attenuation correction factors filename", &this->atten_coeff_filename); + this->parser.add_parsing_key("Bin Normalisation type", &this->multiplicative_binnorm_sptr); + + // RECONSTRUCTION RELATED + this->parser.add_key("reconstruction parameter filename", &this->recon_template_par_filename); + this->parser.add_parsing_key("reconstruction type", &this->reconstruction_template_sptr); + // END RECONSTRUCTION RELATED + + this->parser.add_key("number of scatter iterations", &this->num_scatter_iterations); + // Scatter simulation + this->parser.add_parsing_key("Scatter Simulation type", &this->scatter_simulation_sptr); + this->parser.add_key("scatter simulation parameter filename", &this->scatter_sim_par_filename); + this->parser.add_key("use scanner downsampling in scatter simulation", &this->downsample_scanner_bool); + + this->parser.add_key("override attenuation image", &this->override_density_image); + this->parser.add_key("override scanner template", &this->override_scanner_template); + + // END Scatter simulation + + this->parser.add_key("export scatter estimates of each iteration", &this->export_scatter_estimates_of_each_iteration); + this->parser.add_key("output scatter estimate name prefix", &this->output_scatter_estimate_prefix); + this->parser.add_key("output additive estimate name prefix", &this->output_additive_estimate_prefix); + this->parser.add_key("do average at 2", &this->do_average_at_2); + this->parser.add_key("maximum scatter scaling factor", &this->max_scale_value); + this->parser.add_key("minimum scatter scaling factor", &this->min_scale_value); + this->parser.add_key("upsampling half filter width", &this->half_filter_width); + this->parser.add_key("remove interleaving before upsampling", &this->remove_interleaving); + this->parser.add_key("run in 2d projdata", &this->run_in_2d_projdata); } -ScatterEstimation:: -ScatterEstimation() -{ - this->set_defaults(); -} +ScatterEstimation::ScatterEstimation() { this->set_defaults(); } -ScatterEstimation:: -ScatterEstimation(const std::string& parameter_filename) -{ +ScatterEstimation::ScatterEstimation(const std::string& parameter_filename) { this->set_defaults(); - if (!this->parse(parameter_filename.c_str())) - { - error("ScatterEstimation: Error parsing input file %s. Aborting.", parameter_filename.c_str()); - } + if (!this->parse(parameter_filename.c_str())) { + error("ScatterEstimation: Error parsing input file %s. Aborting.", parameter_filename.c_str()); + } } bool -ScatterEstimation:: -post_processing() -{ - if (!this->input_projdata_filename.empty()) - { - info("ScatterEstimation: Loading input projdata...", 3); - this->input_projdata_sptr = - ProjData::read_from_file(this->input_projdata_filename); - } - // If the reconstruction_template_sptr is null then, we need to parse it from another - // file. I prefer this implementation since makes smaller modular files. - if (!this->recon_template_par_filename.empty()) - { - KeyParser local_parser; - local_parser.add_start_key("Reconstruction Parameters"); - local_parser.add_stop_key("End Reconstruction Parameters"); - local_parser.add_parsing_key("reconstruction type", &this->reconstruction_template_sptr); - if (!local_parser.parse(this->recon_template_par_filename.c_str())) - { - warning(boost::format("ScatterEstimation: Error parsing reconstruction parameters file %1%. Aborting.") - %this->recon_template_par_filename); - return true; - } +ScatterEstimation::post_processing() { + if (!this->input_projdata_filename.empty()) { + info("ScatterEstimation: Loading input projdata...", 3); + this->input_projdata_sptr = ProjData::read_from_file(this->input_projdata_filename); + } + // If the reconstruction_template_sptr is null then, we need to parse it from another + // file. I prefer this implementation since makes smaller modular files. + if (!this->recon_template_par_filename.empty()) { + KeyParser local_parser; + local_parser.add_start_key("Reconstruction Parameters"); + local_parser.add_stop_key("End Reconstruction Parameters"); + local_parser.add_parsing_key("reconstruction type", &this->reconstruction_template_sptr); + if (!local_parser.parse(this->recon_template_par_filename.c_str())) { + warning(boost::format("ScatterEstimation: Error parsing reconstruction parameters file %1%. Aborting.") % + this->recon_template_par_filename); + return true; } + } + + if (!this->atten_image_filename.empty()) { + info("ScatterEstimation: Loading attenuation image...", 3); + this->atten_image_sptr = read_from_file>(this->atten_image_filename); + } + if (!this->atten_coeff_filename.empty()) { + info("ScatterEstimation: Loading attenuation coefficients projdata...", 3); + shared_ptr atten_coef_sptr = ProjData::read_from_file(this->atten_coeff_filename); + this->set_attenuation_correction_proj_data_sptr(atten_coef_sptr); + } + if (!is_null_ptr(multiplicative_binnorm_sptr)) { + warning("ScatterEstimation: looks like you set a combined norm via the 'bin normalisation type' keyword\n" + "This is deprecated and will be removed in a future version (5.0?).\n" + "Use 'normalisation type' (for the norm factors) and 'attenuation correction factors filename' instead."); + } + + if (!this->back_projdata_filename.empty()) { + info("ScatterEstimation: Loading background projdata...", 3); + this->back_projdata_sptr = ProjData::read_from_file(this->back_projdata_filename); + } + + // if(!this->recompute_initial_activity_image ) // This image can be used as a template + // { + // info("ScatterEstimation: Loading initial activity image ..."); + // if(this->initial_activity_image_filename.size() > 0 ) + // this->current_activity_image_lowres_sptr = + // read_from_file >(this->initial_activity_image_filename); + // else + // { + // warning("ScatterEstimation: Recompute initial activity image was set to false and" + // "no filename was set. Aborting."); + // return true; + // } + // } + + if (!this->masking_parameters.filter_filename.empty()) { + this->masking_parameters.filter_sptr.reset(new PostFiltering>); + + if (!masking_parameters.filter_sptr->parse(this->masking_parameters.filter_filename.c_str())) { + warning(boost::format("ScatterEstimation: Error parsing post filter parameters file %1%. Aborting.") % + this->masking_parameters.filter_filename); + return true; + } + } - if (!this->atten_image_filename.empty()) - { - info("ScatterEstimation: Loading attenuation image...", 3); - this->atten_image_sptr = - read_from_file >(this->atten_image_filename); - } - if (!this->atten_coeff_filename.empty()) - { - info("ScatterEstimation: Loading attenuation coefficients projdata...", 3); - shared_ptr atten_coef_sptr = - ProjData::read_from_file(this->atten_coeff_filename); - this->set_attenuation_correction_proj_data_sptr(atten_coef_sptr); - } - if(!is_null_ptr(multiplicative_binnorm_sptr)) - { - warning("ScatterEstimation: looks like you set a combined norm via the 'bin normalisation type' keyword\n" - "This is deprecated and will be removed in a future version (5.0?).\n" - "Use 'normalisation type' (for the norm factors) and 'attenuation correction factors filename' instead."); - } - - if (!this->back_projdata_filename.empty()) - { - info("ScatterEstimation: Loading background projdata...", 3); - this->back_projdata_sptr = - ProjData::read_from_file(this->back_projdata_filename); - } - - // if(!this->recompute_initial_activity_image ) // This image can be used as a template - // { - // info("ScatterEstimation: Loading initial activity image ..."); - // if(this->initial_activity_image_filename.size() > 0 ) - // this->current_activity_image_lowres_sptr = - // read_from_file >(this->initial_activity_image_filename); - // else - // { - // warning("ScatterEstimation: Recompute initial activity image was set to false and" - // "no filename was set. Aborting."); - // return true; - // } - // } - - if(!this->masking_parameters.filter_filename.empty()) + if (!this->scatter_sim_par_filename.empty()) { + info("ScatterEstimation: Initialising Scatter Simulation ...", 3); + // Parse locally { - this->masking_parameters.filter_sptr.reset(new PostFiltering >); - - if(!masking_parameters.filter_sptr->parse(this->masking_parameters.filter_filename.c_str())) - { - warning(boost::format("ScatterEstimation: Error parsing post filter parameters file %1%. Aborting.") - %this->masking_parameters.filter_filename); - return true; - } + KeyParser local_parser; + local_parser.add_start_key("Scatter Simulation Parameters"); + local_parser.add_stop_key("End Scatter Simulation Parameters"); + local_parser.add_parsing_key("Scatter Simulation type", &this->scatter_simulation_sptr); + if (!local_parser.parse(this->scatter_sim_par_filename.c_str())) + error("ScatterEstimation: Error parsing scatter simulation parameters."); } - - if (!this->scatter_sim_par_filename.empty()) - { - info ("ScatterEstimation: Initialising Scatter Simulation ...", 3); - // Parse locally - { - KeyParser local_parser; - local_parser.add_start_key("Scatter Simulation Parameters"); - local_parser.add_stop_key("End Scatter Simulation Parameters"); - local_parser.add_parsing_key("Scatter Simulation type", &this->scatter_simulation_sptr); - if (!local_parser.parse(this->scatter_sim_par_filename.c_str())) - error("ScatterEstimation: Error parsing scatter simulation parameters."); - } - } - - // There is no output in this case - if (this->output_scatter_estimate_prefix.empty() && this->output_additive_estimate_prefix.empty()) - { - // This is ok when running from Python or so, but not when running from the command line. - // As we don't know, we just write a warning - warning("ScatterEstimation: no filename prefix set for either the scatter estimate or the additive.\n" - "This is probably not what you want."); - } - - if(!this->recompute_mask_projdata) - { - if (!this->mask_projdata_filename.empty()) - this->mask_projdata_sptr = - ProjData::read_from_file(this->mask_projdata_filename); - } - else - { - if (!this->recompute_mask_image && !this->mask_image_filename.empty()) - this->mask_image_sptr = - read_from_file >(this->mask_image_filename); - } - - return false; + } + + // There is no output in this case + if (this->output_scatter_estimate_prefix.empty() && this->output_additive_estimate_prefix.empty()) { + // This is ok when running from Python or so, but not when running from the command line. + // As we don't know, we just write a warning + warning("ScatterEstimation: no filename prefix set for either the scatter estimate or the additive.\n" + "This is probably not what you want."); + } + + if (!this->recompute_mask_projdata) { + if (!this->mask_projdata_filename.empty()) + this->mask_projdata_sptr = ProjData::read_from_file(this->mask_projdata_filename); + } else { + if (!this->recompute_mask_image && !this->mask_image_filename.empty()) + this->mask_image_sptr = read_from_file>(this->mask_image_filename); + } + + return false; } -shared_ptr -ScatterEstimation::get_output() const -{ - return scatter_estimate_sptr; +shared_ptr +ScatterEstimation::get_output() const { + return scatter_estimate_sptr; } #if STIR_VERSION < 050000 -void ScatterEstimation::set_input_data(const shared_ptr& data) -{ +void +ScatterEstimation::set_input_data(const shared_ptr& data) { this->set_input_proj_data_sptr(data); } #else -void ScatterEstimation::set_input_data(const shared_ptr& data) -{ +void +ScatterEstimation::set_input_data(const shared_ptr& data) { // C++-11 auto sptr = std::dynamic_pointer_cast(data); if (!sptr) @@ -333,1077 +268,881 @@ void ScatterEstimation::set_input_data(const shared_ptr& data) } #endif -shared_ptr ScatterEstimation::get_input_data() const -{ +shared_ptr +ScatterEstimation::get_input_data() const { return this->input_projdata_sptr; } -shared_ptr > -ScatterEstimation::get_estimated_activity_image_sptr() const -{ +shared_ptr> +ScatterEstimation::get_estimated_activity_image_sptr() const { return this->current_activity_image_sptr; } -void ScatterEstimation::set_output_scatter_estimate_prefix(const std::string& arg) -{ +void +ScatterEstimation::set_output_scatter_estimate_prefix(const std::string& arg) { this->output_scatter_estimate_prefix = arg; } -void ScatterEstimation::set_export_scatter_estimates_of_each_iteration(bool arg) -{ +void +ScatterEstimation::set_export_scatter_estimates_of_each_iteration(bool arg) { this->export_scatter_estimates_of_each_iteration = arg; } - void -ScatterEstimation:: -set_attenuation_correction_proj_data_sptr(const shared_ptr arg) -{ +ScatterEstimation::set_attenuation_correction_proj_data_sptr(const shared_ptr arg) { this->_already_setup = false; this->atten_norm_3d_sptr.reset(new BinNormalisationFromProjData(arg)); this->multiplicative_binnorm_sptr.reset(); } void -ScatterEstimation:: -set_normalisation_sptr(const shared_ptr arg) -{ +ScatterEstimation::set_normalisation_sptr(const shared_ptr arg) { this->_already_setup = false; this->norm_3d_sptr = arg; this->multiplicative_binnorm_sptr.reset(); } -bool ScatterEstimation::already_setup() const -{ +bool +ScatterEstimation::already_setup() const { return this->_already_setup; } Succeeded -ScatterEstimation:: -set_up() -{ - if (this->run_debug_mode) - { - info("ScatterEstimation: Debugging mode is activated."); - this->export_scatter_estimates_of_each_iteration = true; +ScatterEstimation::set_up() { + if (this->run_debug_mode) { + info("ScatterEstimation: Debugging mode is activated."); + this->export_scatter_estimates_of_each_iteration = true; - // Create extras folder in this location - FilePath current_full_path(FilePath::get_current_working_directory()); - extras_path = current_full_path.append("extras"); - } + // Create extras folder in this location + FilePath current_full_path(FilePath::get_current_working_directory()); + extras_path = current_full_path.append("extras"); + } - if (is_null_ptr(this->atten_image_sptr)) - error("ScatterEstimation: No attenuation image has been set. Aborting."); + if (is_null_ptr(this->atten_image_sptr)) + error("ScatterEstimation: No attenuation image has been set. Aborting."); - if (is_null_ptr(this->input_projdata_sptr)) - error("ScatterEstimation: No input proj_data have been set. Aborting."); + if (is_null_ptr(this->input_projdata_sptr)) + error("ScatterEstimation: No input proj_data have been set. Aborting."); - if (is_null_ptr(this->scatter_simulation_sptr)) - error("ScatterEstimation: Please define a scatter simulation method. Aborting."); + if (is_null_ptr(this->scatter_simulation_sptr)) + error("ScatterEstimation: Please define a scatter simulation method. Aborting."); - if (!run_in_2d_projdata) - error("ScatterEstimation: Currently, only running the estimation in 2D is supported."); + if (!run_in_2d_projdata) + error("ScatterEstimation: Currently, only running the estimation in 2D is supported."); - if(!this->recompute_mask_projdata) - { - if (is_null_ptr(this->mask_projdata_sptr)) - error("ScatterEstimation: Please set mask proj_data (or enable computing it)"); - } - else if (!this->recompute_mask_image) - { - if (is_null_ptr(this->mask_image_sptr)) - error("ScatterEstimation: Please set a mask image (or enable computing it)"); - } + if (!this->recompute_mask_projdata) { + if (is_null_ptr(this->mask_projdata_sptr)) + error("ScatterEstimation: Please set mask proj_data (or enable computing it)"); + } else if (!this->recompute_mask_image) { + if (is_null_ptr(this->mask_image_sptr)) + error("ScatterEstimation: Please set a mask image (or enable computing it)"); + } - if (this->_already_setup) - return Succeeded::yes; + if (this->_already_setup) + return Succeeded::yes; - info("Scatter Estimation Parameters (objects that are not set by parsing will not be listed correctly)\n" + this->parameter_info() + "\n\n", 1); + info("Scatter Estimation Parameters (objects that are not set by parsing will not be listed correctly)\n" + + this->parameter_info() + "\n\n", + 1); - this->create_multiplicative_binnorm_sptr(); - this->multiplicative_binnorm_sptr->set_up(this->input_projdata_sptr->get_exam_info_sptr(), this->input_projdata_sptr->get_proj_data_info_sptr()); + this->create_multiplicative_binnorm_sptr(); + this->multiplicative_binnorm_sptr->set_up(this->input_projdata_sptr->get_exam_info_sptr(), + this->input_projdata_sptr->get_proj_data_info_sptr()); #if 1 - // Calculate the SSRB - if (input_projdata_sptr->get_num_segments() > 1) - { - info("ScatterEstimation: Running SSRB on input data..."); - shared_ptr proj_data_info_2d_sptr( - SSRB(*this->input_projdata_sptr->get_proj_data_info_sptr(), - this->input_projdata_sptr->get_num_segments(), 1, false)); + // Calculate the SSRB + if (input_projdata_sptr->get_num_segments() > 1) { + info("ScatterEstimation: Running SSRB on input data..."); + shared_ptr proj_data_info_2d_sptr( + SSRB(*this->input_projdata_sptr->get_proj_data_info_sptr(), this->input_projdata_sptr->get_num_segments(), 1, false)); - this->input_projdata_2d_sptr.reset(new ProjDataInMemory(this->input_projdata_sptr->get_exam_info_sptr(), - proj_data_info_2d_sptr)); + this->input_projdata_2d_sptr.reset( + new ProjDataInMemory(this->input_projdata_sptr->get_exam_info_sptr(), proj_data_info_2d_sptr)); - SSRB(*this->input_projdata_2d_sptr, - *input_projdata_sptr,false); - } - else - { - input_projdata_2d_sptr = input_projdata_sptr; - } + SSRB(*this->input_projdata_2d_sptr, *input_projdata_sptr, false); + } else { + input_projdata_2d_sptr = input_projdata_sptr; + } #else - { - std::string tmp_input2D = "./extras/nema_proj_f1g1d0b0.hs_2d.hs"; - this->input_projdata_2d_sptr = - ProjData::read_from_file(tmp_input2D); - } + { + std::string tmp_input2D = "./extras/nema_proj_f1g1d0b0.hs_2d.hs"; + this->input_projdata_2d_sptr = ProjData::read_from_file(tmp_input2D); + } #endif - info("ScatterEstimation: Setting up reconstruction method ..."); - - if(is_null_ptr(this->reconstruction_template_sptr)) - { - warning("ScatterEstimation: Reconstruction method has not been initialised. Aborting."); - return Succeeded::no; + info("ScatterEstimation: Setting up reconstruction method ..."); + + if (is_null_ptr(this->reconstruction_template_sptr)) { + warning("ScatterEstimation: Reconstruction method has not been initialised. Aborting."); + return Succeeded::no; + } + + // We have to check which reconstruction method we are going to use ... + shared_ptr tmp_analytic = + dynamic_pointer_cast(this->reconstruction_template_sptr); + shared_ptr>> tmp_iterative = + dynamic_pointer_cast>>(reconstruction_template_sptr); + + if (!is_null_ptr(tmp_analytic)) { + if (set_up_analytic() == Succeeded::no) { + warning("ScatterEstimation: set_up_analytic reconstruction failed. Aborting."); + return Succeeded::no; } - // We have to check which reconstruction method we are going to use ... - shared_ptr tmp_analytic = - dynamic_pointer_cast(this->reconstruction_template_sptr); - shared_ptr > > tmp_iterative = - dynamic_pointer_cast > >(reconstruction_template_sptr); - - if (!is_null_ptr(tmp_analytic)) - { - if(set_up_analytic() == Succeeded::no) - { - warning("ScatterEstimation: set_up_analytic reconstruction failed. Aborting."); - return Succeeded::no; - } - - this->iterative_method = false; + this->iterative_method = false; + } else if (!is_null_ptr(tmp_iterative)) { + if (set_up_iterative(tmp_iterative) == Succeeded::no) { + warning("ScatterEstimation: set_up_iterative reconstruction failed. Aborting."); + return Succeeded::no; } - else if (!is_null_ptr(tmp_iterative)) - { - if(set_up_iterative(tmp_iterative) == Succeeded::no) - { - warning("ScatterEstimation: set_up_iterative reconstruction failed. Aborting."); - return Succeeded::no; - } - this->iterative_method = true; - } - else - { - warning("ScatterEstimation: Failure to detect a method of reconstruction. Aborting."); - return Succeeded::no; + this->iterative_method = true; + } else { + warning("ScatterEstimation: Failure to detect a method of reconstruction. Aborting."); + return Succeeded::no; + } + + if (iterative_method) + this->current_activity_image_sptr.reset(tmp_iterative->get_initial_data_ptr()); + + this->current_activity_image_sptr->fill(1.0); + + // + // ScatterSimulation + // + + info("ScatterEstimation: Setting up Scatter Simulation method ..."); + // The images are passed to the simulation. + // and it will override anything that the ScatterSimulation.par file has done. + if (this->override_density_image) { + info( + "ScatterEstimation: Over-riding attenuation image! (The file and settings set in the simulation par file are discarded)"); + this->scatter_simulation_sptr->set_density_image_sptr(this->atten_image_sptr); + } + + // if(this->override_initial_activity_image) + // { + // info("ScatterEstimation: Over-riding activity image! (The file and settings set in the simulation par file are + // discarded)"); this->scatter_simulation_sptr->set_activity_image_sptr(this->current_activity_image_sptr); + // } + + if (this->override_scanner_template) { + info("ScatterEstimation: Over-riding the scanner template! (The file and settings set in the simulation par file are " + "discarded)"); + if (run_in_2d_projdata) { + this->scatter_simulation_sptr->set_template_proj_data_info(*this->input_projdata_2d_sptr->get_proj_data_info_sptr()); + this->scatter_simulation_sptr->set_exam_info(this->input_projdata_2d_sptr->get_exam_info()); + } else { + this->scatter_simulation_sptr->set_template_proj_data_info(*this->input_projdata_sptr->get_proj_data_info_sptr()); + this->scatter_simulation_sptr->set_exam_info(this->input_projdata_sptr->get_exam_info()); } - - if(iterative_method) - this->current_activity_image_sptr.reset(tmp_iterative->get_initial_data_ptr()); - - this->current_activity_image_sptr->fill(1.0); - - // - // ScatterSimulation - // - - info("ScatterEstimation: Setting up Scatter Simulation method ..."); - // The images are passed to the simulation. - // and it will override anything that the ScatterSimulation.par file has done. - if(this->override_density_image) - { - info("ScatterEstimation: Over-riding attenuation image! (The file and settings set in the simulation par file are discarded)"); - this->scatter_simulation_sptr->set_density_image_sptr(this->atten_image_sptr); + } + + if (this->downsample_scanner_bool) + this->scatter_simulation_sptr->downsample_scanner(); + + // Check if Load a mask proj_data + + if (is_null_ptr(this->mask_projdata_sptr) || this->recompute_mask_projdata) { + if (is_null_ptr(this->mask_image_sptr) || this->recompute_mask_image) { + // Applying mask + // 1. Clone from the original image. + // 2. Apply to the new clone. + auto mask_image_ptr(this->atten_image_sptr->clone()); + this->apply_mask_in_place(*mask_image_ptr, this->masking_parameters); + this->mask_image_sptr.reset(mask_image_ptr); + if (this->mask_image_filename.size() > 0) + OutputFileFormat>::default_sptr()->write_to_file(this->mask_image_filename, + *this->mask_image_sptr); } - // if(this->override_initial_activity_image) - // { - // info("ScatterEstimation: Over-riding activity image! (The file and settings set in the simulation par file are discarded)"); - // this->scatter_simulation_sptr->set_activity_image_sptr(this->current_activity_image_sptr); - // } - - - if(this->override_scanner_template) - { - info("ScatterEstimation: Over-riding the scanner template! (The file and settings set in the simulation par file are discarded)"); - if (run_in_2d_projdata) - { - this->scatter_simulation_sptr->set_template_proj_data_info(*this->input_projdata_2d_sptr->get_proj_data_info_sptr()); - this->scatter_simulation_sptr->set_exam_info(this->input_projdata_2d_sptr->get_exam_info()); - } - else - { - this->scatter_simulation_sptr->set_template_proj_data_info(*this->input_projdata_sptr->get_proj_data_info_sptr()); - this->scatter_simulation_sptr->set_exam_info(this->input_projdata_sptr->get_exam_info()); - } - + if (project_mask_image() == Succeeded::no) { + warning("ScatterEstimation: Unsuccessful to fwd project the mask image. Aborting."); + return Succeeded::no; } + } - if (this->downsample_scanner_bool) - this->scatter_simulation_sptr->downsample_scanner(); - - // Check if Load a mask proj_data - - if(is_null_ptr(this->mask_projdata_sptr) || this->recompute_mask_projdata) - { - if(is_null_ptr(this->mask_image_sptr) || this->recompute_mask_image) - { - // Applying mask - // 1. Clone from the original image. - // 2. Apply to the new clone. - auto mask_image_ptr(this->atten_image_sptr->clone()); - this->apply_mask_in_place(*mask_image_ptr, this->masking_parameters); - this->mask_image_sptr.reset(mask_image_ptr); - if (this->mask_image_filename.size() > 0 ) - OutputFileFormat >::default_sptr()-> - write_to_file(this->mask_image_filename, *this->mask_image_sptr); - } - - if(project_mask_image() == Succeeded::no) - { - warning("ScatterEstimation: Unsuccessful to fwd project the mask image. Aborting."); - return Succeeded::no; - } - } - - this->_already_setup = true; - info("ScatterEstimation: >>>>Set up finished successfully!!<<<<"); - return Succeeded::yes; + this->_already_setup = true; + info("ScatterEstimation: >>>>Set up finished successfully!!<<<<"); + return Succeeded::yes; } Succeeded -ScatterEstimation:: -set_up_iterative(shared_ptr > > iterative_object) -{ - info("ScatterEstimation: Setting up iterative reconstruction ..."); - - if(run_in_2d_projdata) - { - iterative_object->set_input_data(this->input_projdata_2d_sptr); - } - else - iterative_object->set_input_data(this->input_projdata_sptr); +ScatterEstimation::set_up_iterative(shared_ptr>> iterative_object) { + info("ScatterEstimation: Setting up iterative reconstruction ..."); - const double start_time = this->input_projdata_sptr->get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); - const double end_time =this->input_projdata_sptr->get_exam_info_sptr()->get_time_frame_definitions().get_end_time(); + if (run_in_2d_projdata) { + iterative_object->set_input_data(this->input_projdata_2d_sptr); + } else + iterative_object->set_input_data(this->input_projdata_sptr); + const double start_time = this->input_projdata_sptr->get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); + const double end_time = this->input_projdata_sptr->get_exam_info_sptr()->get_time_frame_definitions().get_end_time(); - // - // Multiplicative projdata - // - shared_ptr tmp_atten_projdata_sptr = - this->get_attenuation_correction_factors_sptr(this->multiplicative_binnorm_sptr); - shared_ptr atten_projdata_2d_sptr; + // + // Multiplicative projdata + // + shared_ptr tmp_atten_projdata_sptr = this->get_attenuation_correction_factors_sptr(this->multiplicative_binnorm_sptr); + shared_ptr atten_projdata_2d_sptr; - info("ScatterEstimation: 3.Calculating the attenuation projection data..."); + info("ScatterEstimation: 3.Calculating the attenuation projection data..."); - if( tmp_atten_projdata_sptr->get_num_segments() > 1) - { - info("ScatterEstimation: Running SSRB on attenuation correction coefficients ..."); + if (tmp_atten_projdata_sptr->get_num_segments() > 1) { + info("ScatterEstimation: Running SSRB on attenuation correction coefficients ..."); - std::string out_filename = "tmp_atten_sino_2d.hs"; + std::string out_filename = "tmp_atten_sino_2d.hs"; - atten_projdata_2d_sptr = create_new_proj_data(out_filename, this->input_projdata_2d_sptr->get_exam_info_sptr(), - this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); + atten_projdata_2d_sptr = create_new_proj_data(out_filename, this->input_projdata_2d_sptr->get_exam_info_sptr(), + this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); - SSRB(*atten_projdata_2d_sptr, - *tmp_atten_projdata_sptr, true); - } - else - { - // TODO: this needs more work. -- Setting directly 2D proj_data is buggy right now. - atten_projdata_2d_sptr = tmp_atten_projdata_sptr; - } - - info("ScatterEstimation: 4.Calculating the normalisation data..."); - { - if (run_in_2d_projdata) - { - shared_ptr norm3d_sptr = - this->get_normalisation_object_sptr(this->multiplicative_binnorm_sptr); - shared_ptr norm_coeff_2d_sptr; + SSRB(*atten_projdata_2d_sptr, *tmp_atten_projdata_sptr, true); + } else { + // TODO: this needs more work. -- Setting directly 2D proj_data is buggy right now. + atten_projdata_2d_sptr = tmp_atten_projdata_sptr; + } - if ( input_projdata_sptr->get_num_segments() > 1) - { - // Some BinNormalisation classes don't know about SSRB. - // we need to get norm2d=1/SSRB(1/norm3d)) + info("ScatterEstimation: 4.Calculating the normalisation data..."); + { + if (run_in_2d_projdata) { + shared_ptr norm3d_sptr = this->get_normalisation_object_sptr(this->multiplicative_binnorm_sptr); + shared_ptr norm_coeff_2d_sptr; - info("ScatterEstimation: Constructing 2D normalisation coefficients ..."); + if (input_projdata_sptr->get_num_segments() > 1) { + // Some BinNormalisation classes don't know about SSRB. + // we need to get norm2d=1/SSRB(1/norm3d)) - std::string out_filename = "tmp_inverted_normdata.hs"; - shared_ptr inv_projdata_3d_sptr = create_new_proj_data(out_filename, - this->input_projdata_sptr->get_exam_info_sptr(), - this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone()); - inv_projdata_3d_sptr->fill(1.f); + info("ScatterEstimation: Constructing 2D normalisation coefficients ..."); - out_filename = "tmp_normdata_2d.hs"; - shared_ptr norm_projdata_2d_sptr = create_new_proj_data(out_filename, - this->input_projdata_2d_sptr->get_exam_info_sptr(), - this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); - norm_projdata_2d_sptr->fill(0.f); + std::string out_filename = "tmp_inverted_normdata.hs"; + shared_ptr inv_projdata_3d_sptr = + create_new_proj_data(out_filename, this->input_projdata_sptr->get_exam_info_sptr(), + this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone()); + inv_projdata_3d_sptr->fill(1.f); - // Essentially since inv_projData_sptr is 1s then this is an inversion. - // inv_projdata_sptr = 1/norm3d - norm3d_sptr->undo(*inv_projdata_3d_sptr, start_time, end_time); + out_filename = "tmp_normdata_2d.hs"; + shared_ptr norm_projdata_2d_sptr = + create_new_proj_data(out_filename, this->input_projdata_2d_sptr->get_exam_info_sptr(), + this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); + norm_projdata_2d_sptr->fill(0.f); - info("ScatterEstimation: Performing SSRB on efficiency factors ..."); + // Essentially since inv_projData_sptr is 1s then this is an inversion. + // inv_projdata_sptr = 1/norm3d + norm3d_sptr->undo(*inv_projdata_3d_sptr, start_time, end_time); - SSRB(*norm_projdata_2d_sptr, - *inv_projdata_3d_sptr,false); + info("ScatterEstimation: Performing SSRB on efficiency factors ..."); - // Crucial: Avoid divisions by zero!! - // This should be resolved after https://github.com/UCL/STIR/issues/348 - pow_times_add min_threshold (0.0f, 1.0f, 1.0f, 1E-20f, NumericInfo().max_value()); - apply_to_proj_data(*norm_projdata_2d_sptr, min_threshold); + SSRB(*norm_projdata_2d_sptr, *inv_projdata_3d_sptr, false); - pow_times_add invert (0.0f, 1.0f, -1.0f, NumericInfo().min_value(), NumericInfo().max_value()); - apply_to_proj_data(*norm_projdata_2d_sptr, invert); + // Crucial: Avoid divisions by zero!! + // This should be resolved after https://github.com/UCL/STIR/issues/348 + pow_times_add min_threshold(0.0f, 1.0f, 1.0f, 1E-20f, NumericInfo().max_value()); + apply_to_proj_data(*norm_projdata_2d_sptr, min_threshold); - norm_coeff_2d_sptr.reset(new BinNormalisationFromProjData(norm_projdata_2d_sptr)); - } - else - { - norm_coeff_2d_sptr = norm3d_sptr; - } + pow_times_add invert(0.0f, 1.0f, -1.0f, NumericInfo().min_value(), NumericInfo().max_value()); + apply_to_proj_data(*norm_projdata_2d_sptr, invert); - shared_ptratten_coeff_2d_sptr(new BinNormalisationFromProjData(atten_projdata_2d_sptr)); - this->multiplicative_binnorm_2d_sptr.reset( - new ChainedBinNormalisation(norm_coeff_2d_sptr, atten_coeff_2d_sptr)); - - this->multiplicative_binnorm_2d_sptr->set_up(this->back_projdata_sptr->get_exam_info_sptr(), this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); - iterative_object->get_objective_function_sptr()->set_normalisation_sptr(multiplicative_binnorm_2d_sptr); - } - else // run_in_2d_projdata - iterative_object->get_objective_function_sptr()->set_normalisation_sptr(multiplicative_binnorm_sptr); - } - info("ScatterEstimation: Done normalisation coefficients."); - - // - // Set background (randoms) projdata - // - info("ScatterEstimation: 5.Calculating the background data and data_to_fit for the scaling..."); - - if (!is_null_ptr(this->back_projdata_sptr)) - { - if( back_projdata_sptr->get_num_segments() > 1) - { - info("ScatterEstimation: Running SSRB on the background data ..."); - - this->back_projdata_2d_sptr.reset(new ProjDataInMemory(this->input_projdata_2d_sptr->get_exam_info_sptr(), - this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone())); + norm_coeff_2d_sptr.reset(new BinNormalisationFromProjData(norm_projdata_2d_sptr)); + } else { + norm_coeff_2d_sptr = norm3d_sptr; + } - SSRB(*this->back_projdata_2d_sptr, - *this->back_projdata_sptr, false); - } - else - { - this->back_projdata_2d_sptr = back_projdata_sptr; - } + shared_ptr atten_coeff_2d_sptr(new BinNormalisationFromProjData(atten_projdata_2d_sptr)); + this->multiplicative_binnorm_2d_sptr.reset(new ChainedBinNormalisation(norm_coeff_2d_sptr, atten_coeff_2d_sptr)); + + this->multiplicative_binnorm_2d_sptr->set_up( + this->back_projdata_sptr->get_exam_info_sptr(), + this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); + iterative_object->get_objective_function_sptr()->set_normalisation_sptr(multiplicative_binnorm_2d_sptr); + } else // run_in_2d_projdata + iterative_object->get_objective_function_sptr()->set_normalisation_sptr(multiplicative_binnorm_sptr); + } + info("ScatterEstimation: Done normalisation coefficients."); + + // + // Set background (randoms) projdata + // + info("ScatterEstimation: 5.Calculating the background data and data_to_fit for the scaling..."); + + if (!is_null_ptr(this->back_projdata_sptr)) { + if (back_projdata_sptr->get_num_segments() > 1) { + info("ScatterEstimation: Running SSRB on the background data ..."); + + this->back_projdata_2d_sptr.reset( + new ProjDataInMemory(this->input_projdata_2d_sptr->get_exam_info_sptr(), + this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone())); + + SSRB(*this->back_projdata_2d_sptr, *this->back_projdata_sptr, false); + } else { + this->back_projdata_2d_sptr = back_projdata_sptr; } - else // We will need a background for the scatter, so let's create a simple empty ProjData - { - if (run_in_2d_projdata) - { - std::string out_filename = "tmp_background_data_2d.hs"; - - this->back_projdata_2d_sptr = create_new_proj_data(out_filename, - this->input_projdata_2d_sptr->get_exam_info_sptr(), - this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); - this->back_projdata_2d_sptr->fill(0.0f); - } - else - { - std::string out_filename = "tmp_background_data.hs"; - - this->back_projdata_sptr = create_new_proj_data(out_filename, - this->input_projdata_sptr->get_exam_info_sptr(), - this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone()); - this->back_projdata_sptr->fill(0.0f); - } + } else // We will need a background for the scatter, so let's create a simple empty ProjData + { + if (run_in_2d_projdata) { + std::string out_filename = "tmp_background_data_2d.hs"; + + this->back_projdata_2d_sptr = + create_new_proj_data(out_filename, this->input_projdata_2d_sptr->get_exam_info_sptr(), + this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); + this->back_projdata_2d_sptr->fill(0.0f); + } else { + std::string out_filename = "tmp_background_data.hs"; + + this->back_projdata_sptr = + create_new_proj_data(out_filename, this->input_projdata_sptr->get_exam_info_sptr(), + this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone()); + this->back_projdata_sptr->fill(0.0f); } + } + if (run_in_2d_projdata) { + // Normalise in order to get the additive component + std::stringstream convert; // stream used for the conversion + convert << output_additive_estimate_prefix << "_0_2d.hs"; + std::string out_filename = convert.str(); // extras_path.get_path() +"/"+ output_background_estimate_prefix + ""; + add_projdata_2d_sptr = create_new_proj_data(out_filename, this->input_projdata_2d_sptr->get_exam_info_sptr(), + this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); + add_projdata_2d_sptr->fill(*back_projdata_2d_sptr); + this->multiplicative_binnorm_2d_sptr->apply(*this->add_projdata_2d_sptr); - if (run_in_2d_projdata) - { - // Normalise in order to get the additive component - std::stringstream convert; // stream used for the conversion - convert << output_additive_estimate_prefix << "_0_2d.hs"; - - std::string out_filename = convert.str(); //extras_path.get_path() +"/"+ output_background_estimate_prefix + ""; - add_projdata_2d_sptr = create_new_proj_data(out_filename, - this->input_projdata_2d_sptr->get_exam_info_sptr(), - this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); - add_projdata_2d_sptr->fill(*back_projdata_2d_sptr); - this->multiplicative_binnorm_2d_sptr->apply(*this->add_projdata_2d_sptr); - - iterative_object->get_objective_function_sptr()->set_additive_proj_data_sptr(this->add_projdata_2d_sptr); - - out_filename ="data_to_fit_2d.hs"; - data_to_fit_projdata_sptr = create_new_proj_data(out_filename, - this->input_projdata_2d_sptr->get_exam_info_sptr(), - this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); - - data_to_fit_projdata_sptr->fill(*input_projdata_2d_sptr); - subtract_proj_data(*data_to_fit_projdata_sptr, *this->back_projdata_2d_sptr); - } - else - { - // Normalise in order to get the additive component - std::string out_filename = output_additive_estimate_prefix + "_0.hs"; - add_projdata_sptr = create_new_proj_data(out_filename, - this->input_projdata_sptr->get_exam_info_sptr(), - this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone()); - add_projdata_sptr->fill(*back_projdata_sptr); - this->multiplicative_binnorm_sptr->apply(*this->add_projdata_sptr); - - iterative_object->get_objective_function_sptr()->set_additive_proj_data_sptr(this->add_projdata_sptr); - - out_filename = "data_to_fit.hs"; - data_to_fit_projdata_sptr = create_new_proj_data(out_filename, - this->input_projdata_sptr->get_exam_info_sptr(), - this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone()); - data_to_fit_projdata_sptr->fill(*input_projdata_sptr); - subtract_proj_data(*data_to_fit_projdata_sptr, *this->back_projdata_sptr); - } + iterative_object->get_objective_function_sptr()->set_additive_proj_data_sptr(this->add_projdata_2d_sptr); - return Succeeded::yes; + out_filename = "data_to_fit_2d.hs"; + data_to_fit_projdata_sptr = + create_new_proj_data(out_filename, this->input_projdata_2d_sptr->get_exam_info_sptr(), + this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); + + data_to_fit_projdata_sptr->fill(*input_projdata_2d_sptr); + subtract_proj_data(*data_to_fit_projdata_sptr, *this->back_projdata_2d_sptr); + } else { + // Normalise in order to get the additive component + std::string out_filename = output_additive_estimate_prefix + "_0.hs"; + add_projdata_sptr = create_new_proj_data(out_filename, this->input_projdata_sptr->get_exam_info_sptr(), + this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone()); + add_projdata_sptr->fill(*back_projdata_sptr); + this->multiplicative_binnorm_sptr->apply(*this->add_projdata_sptr); + + iterative_object->get_objective_function_sptr()->set_additive_proj_data_sptr(this->add_projdata_sptr); + + out_filename = "data_to_fit.hs"; + data_to_fit_projdata_sptr = create_new_proj_data(out_filename, this->input_projdata_sptr->get_exam_info_sptr(), + this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone()); + data_to_fit_projdata_sptr->fill(*input_projdata_sptr); + subtract_proj_data(*data_to_fit_projdata_sptr, *this->back_projdata_sptr); + } + + return Succeeded::yes; } Succeeded -ScatterEstimation:: -set_up_analytic() -{ - //TODO : I have most stuff in tmp. - error("Analytic recon not implemented yet"); - return Succeeded::yes; +ScatterEstimation::set_up_analytic() { + // TODO : I have most stuff in tmp. + error("Analytic recon not implemented yet"); + return Succeeded::yes; } Succeeded -ScatterEstimation:: -process_data() -{ +ScatterEstimation::process_data() { if (!this->_already_setup) error("ScatterEstimation: set_up needs to be called before process_data()"); - float local_min_scale_value = 0.5f; - float local_max_scale_value = 0.5f; - - stir::BSpline::BSplineType spline_type = stir::BSpline::quadratic; - - // This has been set to 2D or 3D in the set_up() - shared_ptr unscaled_est_projdata_sptr(new ProjDataInMemory(this->scatter_simulation_sptr->get_exam_info_sptr(), - this->scatter_simulation_sptr->get_template_proj_data_info_sptr()->create_shared_clone())); - scatter_simulation_sptr->set_output_proj_data_sptr(unscaled_est_projdata_sptr); - - // Here the scaled scatter data will be stored. - // Wether 2D or 3D depends on how the ScatterSimulation was initialised - shared_ptr scaled_est_projdata_sptr; + float local_min_scale_value = 0.5f; + float local_max_scale_value = 0.5f; + + stir::BSpline::BSplineType spline_type = stir::BSpline::quadratic; + + // This has been set to 2D or 3D in the set_up() + shared_ptr unscaled_est_projdata_sptr( + new ProjDataInMemory(this->scatter_simulation_sptr->get_exam_info_sptr(), + this->scatter_simulation_sptr->get_template_proj_data_info_sptr()->create_shared_clone())); + scatter_simulation_sptr->set_output_proj_data_sptr(unscaled_est_projdata_sptr); + + // Here the scaled scatter data will be stored. + // Wether 2D or 3D depends on how the ScatterSimulation was initialised + shared_ptr scaled_est_projdata_sptr; + + shared_ptr normalisation_factors_sptr = this->get_normalisation_object_sptr( + run_in_2d_projdata ? this->multiplicative_binnorm_2d_sptr : this->multiplicative_binnorm_sptr); + if (run_in_2d_projdata) { + scaled_est_projdata_sptr.reset( + new ProjDataInMemory(this->input_projdata_2d_sptr->get_exam_info_sptr(), + this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone())); + scaled_est_projdata_sptr->fill(0.F); + } else { + scaled_est_projdata_sptr.reset( + new ProjDataInMemory(this->input_projdata_sptr->get_exam_info_sptr(), + this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone())); + scaled_est_projdata_sptr->fill(0.F); + } + + info("ScatterEstimation: Start processing..."); + shared_ptr> act_image_for_averaging; + + // Recompute the initial y image if the max is equal to the min. +#if 1 + if (this->current_activity_image_sptr->find_max() == this->current_activity_image_sptr->find_min()) { + info("ScatterEstimation: The max and the min values of the current activity image are equal." + "We deduce that it has been initialised to some value, therefore we will run an initial " + "reconstruction ..."); - shared_ptr normalisation_factors_sptr = - this->get_normalisation_object_sptr(run_in_2d_projdata - ? this->multiplicative_binnorm_2d_sptr - : this->multiplicative_binnorm_sptr); - if(run_in_2d_projdata) - { - scaled_est_projdata_sptr.reset(new ProjDataInMemory(this->input_projdata_2d_sptr->get_exam_info_sptr(), - this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone())); - scaled_est_projdata_sptr->fill(0.F); - } + if (iterative_method) + reconstruct_iterative(0, this->current_activity_image_sptr); else - { - scaled_est_projdata_sptr.reset(new ProjDataInMemory(this->input_projdata_sptr->get_exam_info_sptr(), - this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone())); - scaled_est_projdata_sptr->fill(0.F); - } - - info("ScatterEstimation: Start processing..."); - shared_ptr > act_image_for_averaging; + reconstruct_analytic(0, this->current_activity_image_sptr); - //Recompute the initial y image if the max is equal to the min. -#if 1 - if( this->current_activity_image_sptr->find_max() == this->current_activity_image_sptr->find_min() ) - { - info("ScatterEstimation: The max and the min values of the current activity image are equal." - "We deduce that it has been initialised to some value, therefore we will run an initial " - "reconstruction ..."); - - if (iterative_method) - reconstruct_iterative(0, this->current_activity_image_sptr); - else - reconstruct_analytic(0, this->current_activity_image_sptr); - - if ( run_debug_mode ) - { - std::string out_filename = extras_path.get_path() + "initial_activity_image"; - OutputFileFormat >::default_sptr()-> - write_to_file(out_filename, *this->current_activity_image_sptr); - } + if (run_debug_mode) { + std::string out_filename = extras_path.get_path() + "initial_activity_image"; + OutputFileFormat>::default_sptr()->write_to_file(out_filename, + *this->current_activity_image_sptr); } + } #else - { - std::string filename = extras_path.get_path() + "recon_0.hv"; - current_activity_image_sptr = read_from_file >(filename); - } + { + std::string filename = extras_path.get_path() + "recon_0.hv"; + current_activity_image_sptr = read_from_file>(filename); + } #endif - // Set the first activity image - scatter_simulation_sptr->set_activity_image_sptr(current_activity_image_sptr); + // Set the first activity image + scatter_simulation_sptr->set_activity_image_sptr(current_activity_image_sptr); - if (this->do_average_at_2) - act_image_for_averaging.reset(this->current_activity_image_sptr->clone()); + if (this->do_average_at_2) + act_image_for_averaging.reset(this->current_activity_image_sptr->clone()); - // - // Begin the estimation process... - // - info("ScatterEstimation: Begin the estimation process..."); - for (int i_scat_iter = 1; - i_scat_iter <= this->num_scatter_iterations; - i_scat_iter++) - { + // + // Begin the estimation process... + // + info("ScatterEstimation: Begin the estimation process..."); + for (int i_scat_iter = 1; i_scat_iter <= this->num_scatter_iterations; i_scat_iter++) { + if (this->do_average_at_2) { + if (i_scat_iter == 2) // do average 0 and 1 + { + if (is_null_ptr(act_image_for_averaging)) + error("Storing the first activity estimate has failed at some point."); - if ( this->do_average_at_2) - { - if (i_scat_iter == 2) // do average 0 and 1 - { - if (is_null_ptr(act_image_for_averaging)) - error("Storing the first activity estimate has failed at some point."); + *this->current_activity_image_sptr += *act_image_for_averaging; + *this->current_activity_image_sptr /= 2.f; + } + } - *this->current_activity_image_sptr += *act_image_for_averaging; - *this->current_activity_image_sptr /= 2.f; - } - } + if (!iterative_method) { + // Threshold + } - if (!iterative_method) - { - // Threshold - } + info("ScatterEstimation: Scatter simulation in progress..."); + if (this->scatter_simulation_sptr->set_up() == Succeeded::no) + error("ScatterEstimation: Failure at set_up() of the Scatter Simulation."); - info("ScatterEstimation: Scatter simulation in progress..."); - if (this->scatter_simulation_sptr->set_up() == Succeeded::no) - error("ScatterEstimation: Failure at set_up() of the Scatter Simulation."); - - if (this->scatter_simulation_sptr->process_data() == Succeeded::no) - error("ScatterEstimation: Scatter simulation failed"); - info("ScatterEstimation: Scatter simulation done..."); - - if(this->run_debug_mode) // Write unscaled scatter sinogram - { - std::stringstream convert; // stream used for the conversion - convert << "unscaled_" << i_scat_iter; - FilePath tmp(convert.str(),false); - tmp.prepend_directory_name(extras_path.get_path()); - unscaled_est_projdata_sptr->write_to_file(tmp.get_string()); - } + if (this->scatter_simulation_sptr->process_data() == Succeeded::no) + error("ScatterEstimation: Scatter simulation failed"); + info("ScatterEstimation: Scatter simulation done..."); - // Set the min and max scale factors - // We're going to assume that the first iteration starts from an image without scatter correction, and therefore - // overestimates scatter. This could be inaccurate, but is the case most of the time. - // TODO introduce a variable to control this behaviour - if (i_scat_iter > 0) - { - local_max_scale_value = this->max_scale_value; - local_min_scale_value = this->min_scale_value; - } + if (this->run_debug_mode) // Write unscaled scatter sinogram + { + std::stringstream convert; // stream used for the conversion + convert << "unscaled_" << i_scat_iter; + FilePath tmp(convert.str(), false); + tmp.prepend_directory_name(extras_path.get_path()); + unscaled_est_projdata_sptr->write_to_file(tmp.get_string()); + } - scaled_est_projdata_sptr->fill(0.F); - - upsample_and_fit_scatter_estimate(*scaled_est_projdata_sptr, *data_to_fit_projdata_sptr, - *unscaled_est_projdata_sptr, - *normalisation_factors_sptr, - *this->mask_projdata_sptr, local_min_scale_value, - local_max_scale_value, this->half_filter_width, - spline_type, true); - - if(this->run_debug_mode) - { - std::stringstream convert; // stream used for the conversion - convert << "scaled_" << i_scat_iter; - FilePath tmp(convert.str(),false); - tmp.prepend_directory_name(extras_path.get_path()); - scaled_est_projdata_sptr->write_to_file(tmp.get_string()); - } + // Set the min and max scale factors + // We're going to assume that the first iteration starts from an image without scatter correction, and therefore + // overestimates scatter. This could be inaccurate, but is the case most of the time. + // TODO introduce a variable to control this behaviour + if (i_scat_iter > 0) { + local_max_scale_value = this->max_scale_value; + local_min_scale_value = this->min_scale_value; + } + scaled_est_projdata_sptr->fill(0.F); - // When saving we need to go 3D. - if (this->export_scatter_estimates_of_each_iteration || - i_scat_iter == this->num_scatter_iterations ) - { - - shared_ptr temp_scatter_projdata; - - if(run_in_2d_projdata) - { - info("ScatterEstimation: upsampling scatter to 3D"); - //this is complicated as the 2d scatter estimate was - //"unnormalised" (divided by norm2d), so we need to undo this 2D norm, and put a 3D norm in. - //unfortunately, currently the values in the gaps in the - //scatter estimate are not quite zero (just very small) - //so we have to first make sure that they are zero before - //we do any of this, otherwise the values after normalisation will be garbage - //we do this by min-thresholding and then subtracting the threshold. - //as long as the threshold is tiny, this will be ok - - // At the same time we are going to save to a temp projdata file - - shared_ptr temp_projdata ( new ProjDataInMemory (scaled_est_projdata_sptr->get_exam_info_sptr(), - scaled_est_projdata_sptr->get_proj_data_info_sptr())); - temp_projdata->fill(*scaled_est_projdata_sptr); - pow_times_add min_threshold (0.0f, 1.0f, 1.0f, 1e-9f, NumericInfo().max_value()); - pow_times_add add_scalar (-1e-9f, 1.0f, 1.0f, NumericInfo().min_value(), NumericInfo().max_value()); - apply_to_proj_data(*temp_projdata, min_threshold); - apply_to_proj_data(*temp_projdata, add_scalar); - // threshold back to 0 to avoid getting tiny negatives (due to numerical precision errors) - pow_times_add min_threshold_zero (0.0f, 1.0f, 1.0f, 0.f, NumericInfo().max_value()); - apply_to_proj_data(*temp_projdata, min_threshold_zero); - - // ok, we can multiply with the norm - normalisation_factors_sptr->apply(*temp_projdata); - - // Create proj_data to save the 3d scatter estimate - if(!this->output_scatter_estimate_prefix.empty()) - { - std::stringstream convert; - convert << this->output_scatter_estimate_prefix << "_" << i_scat_iter; - std::string output_scatter_filename = convert.str(); - - scatter_estimate_sptr.reset( - new ProjDataInterfile(this->input_projdata_sptr->get_exam_info_sptr(), - this->input_projdata_sptr->get_proj_data_info_sptr() , - output_scatter_filename, - std::ios::in | std::ios::out | std::ios::trunc)); - } - else - { - // TODO should check if we have one already from previous iteration - scatter_estimate_sptr.reset( - new ProjDataInMemory(this->input_projdata_sptr->get_exam_info_sptr(), - this->input_projdata_sptr->get_proj_data_info_sptr())); - } - scatter_estimate_sptr->fill(0.0); - - // Upsample to 3D - //we're currently not doing the tail fitting in this step, but keeping the same scale as determined in 2D - //Note that most of the arguments here are ignored because we fix the scale to 1 - shared_ptr normalisation_factors_3d_sptr = - this->get_normalisation_object_sptr(this->multiplicative_binnorm_sptr); - - upsample_and_fit_scatter_estimate(*scatter_estimate_sptr, - *this->input_projdata_sptr, - *temp_projdata, - *normalisation_factors_3d_sptr, - *this->input_projdata_sptr, - 1.0f, 1.0f, 1, spline_type, - false); - } - else - { - scatter_estimate_sptr = scaled_est_projdata_sptr; - } - - if(!this->output_additive_estimate_prefix.empty()) - { - info("ScatterEstimation: constructing additive sinogram"); - // Now save the full background term. - std::stringstream convert; - convert << this->output_additive_estimate_prefix << "_" << - i_scat_iter; - std::string output_additive_filename = convert.str(); - - shared_ptr temp_additive_projdata( - new ProjDataInterfile(this->input_projdata_sptr->get_exam_info_sptr(), - this->input_projdata_sptr->get_proj_data_info_sptr() , - output_additive_filename, - std::ios::in | std::ios::out | std::ios::trunc)); - - temp_additive_projdata->fill(*scatter_estimate_sptr); - if (!is_null_ptr(this->back_projdata_sptr)) - { - add_proj_data(*temp_additive_projdata, *this->back_projdata_sptr); - } - - this->multiplicative_binnorm_sptr->apply(*temp_additive_projdata); - } - } + upsample_and_fit_scatter_estimate(*scaled_est_projdata_sptr, *data_to_fit_projdata_sptr, *unscaled_est_projdata_sptr, + *normalisation_factors_sptr, *this->mask_projdata_sptr, local_min_scale_value, + local_max_scale_value, this->half_filter_width, spline_type, true); - // In the additive put the scaled scatter estimate - // If we have randoms, then add them to the scaled scatter estimate - // Then normalise - if(run_in_2d_projdata) - { - this->add_projdata_2d_sptr->fill(*scaled_est_projdata_sptr); - - if (!is_null_ptr(this->back_projdata_2d_sptr)) - { - add_proj_data(*add_projdata_2d_sptr, *this->back_projdata_2d_sptr); - } - this->multiplicative_binnorm_2d_sptr->apply(*add_projdata_2d_sptr); - } - else - { - // TODO restructure code to move additive_projdata code from above - error("ScatterEstimation: You should not be here. This is not 2D."); + if (this->run_debug_mode) { + std::stringstream convert; // stream used for the conversion + convert << "scaled_" << i_scat_iter; + FilePath tmp(convert.str(), false); + tmp.prepend_directory_name(extras_path.get_path()); + scaled_est_projdata_sptr->write_to_file(tmp.get_string()); + } + + // When saving we need to go 3D. + if (this->export_scatter_estimates_of_each_iteration || i_scat_iter == this->num_scatter_iterations) { + + shared_ptr temp_scatter_projdata; + + if (run_in_2d_projdata) { + info("ScatterEstimation: upsampling scatter to 3D"); + // this is complicated as the 2d scatter estimate was + //"unnormalised" (divided by norm2d), so we need to undo this 2D norm, and put a 3D norm in. + // unfortunately, currently the values in the gaps in the + // scatter estimate are not quite zero (just very small) + // so we have to first make sure that they are zero before + // we do any of this, otherwise the values after normalisation will be garbage + // we do this by min-thresholding and then subtracting the threshold. + // as long as the threshold is tiny, this will be ok + + // At the same time we are going to save to a temp projdata file + + shared_ptr temp_projdata(new ProjDataInMemory(scaled_est_projdata_sptr->get_exam_info_sptr(), + scaled_est_projdata_sptr->get_proj_data_info_sptr())); + temp_projdata->fill(*scaled_est_projdata_sptr); + pow_times_add min_threshold(0.0f, 1.0f, 1.0f, 1e-9f, NumericInfo().max_value()); + pow_times_add add_scalar(-1e-9f, 1.0f, 1.0f, NumericInfo().min_value(), NumericInfo().max_value()); + apply_to_proj_data(*temp_projdata, min_threshold); + apply_to_proj_data(*temp_projdata, add_scalar); + // threshold back to 0 to avoid getting tiny negatives (due to numerical precision errors) + pow_times_add min_threshold_zero(0.0f, 1.0f, 1.0f, 0.f, NumericInfo().max_value()); + apply_to_proj_data(*temp_projdata, min_threshold_zero); + + // ok, we can multiply with the norm + normalisation_factors_sptr->apply(*temp_projdata); + + // Create proj_data to save the 3d scatter estimate + if (!this->output_scatter_estimate_prefix.empty()) { + std::stringstream convert; + convert << this->output_scatter_estimate_prefix << "_" << i_scat_iter; + std::string output_scatter_filename = convert.str(); + + scatter_estimate_sptr.reset(new ProjDataInterfile( + this->input_projdata_sptr->get_exam_info_sptr(), this->input_projdata_sptr->get_proj_data_info_sptr(), + output_scatter_filename, std::ios::in | std::ios::out | std::ios::trunc)); + } else { + // TODO should check if we have one already from previous iteration + scatter_estimate_sptr.reset(new ProjDataInMemory(this->input_projdata_sptr->get_exam_info_sptr(), + this->input_projdata_sptr->get_proj_data_info_sptr())); } - current_activity_image_sptr->fill(1.f); + scatter_estimate_sptr->fill(0.0); - iterative_method ? reconstruct_iterative(i_scat_iter, - this->current_activity_image_sptr): - reconstruct_analytic(i_scat_iter, this->current_activity_image_sptr); + // Upsample to 3D + // we're currently not doing the tail fitting in this step, but keeping the same scale as determined in 2D + // Note that most of the arguments here are ignored because we fix the scale to 1 + shared_ptr normalisation_factors_3d_sptr = + this->get_normalisation_object_sptr(this->multiplicative_binnorm_sptr); - scatter_simulation_sptr->set_activity_image_sptr(current_activity_image_sptr); + upsample_and_fit_scatter_estimate(*scatter_estimate_sptr, *this->input_projdata_sptr, *temp_projdata, + *normalisation_factors_3d_sptr, *this->input_projdata_sptr, 1.0f, 1.0f, 1, spline_type, + false); + } else { + scatter_estimate_sptr = scaled_est_projdata_sptr; + } - } + if (!this->output_additive_estimate_prefix.empty()) { + info("ScatterEstimation: constructing additive sinogram"); + // Now save the full background term. + std::stringstream convert; + convert << this->output_additive_estimate_prefix << "_" << i_scat_iter; + std::string output_additive_filename = convert.str(); - info("ScatterEstimation: Scatter Estimation finished !!!"); + shared_ptr temp_additive_projdata(new ProjDataInterfile( + this->input_projdata_sptr->get_exam_info_sptr(), this->input_projdata_sptr->get_proj_data_info_sptr(), + output_additive_filename, std::ios::in | std::ios::out | std::ios::trunc)); - return Succeeded::yes; -} + temp_additive_projdata->fill(*scatter_estimate_sptr); + if (!is_null_ptr(this->back_projdata_sptr)) { + add_proj_data(*temp_additive_projdata, *this->back_projdata_sptr); + } -void -ScatterEstimation:: -reconstruct_iterative(int _current_iter_num, - shared_ptr > & _current_estimate_sptr) -{ + this->multiplicative_binnorm_sptr->apply(*temp_additive_projdata); + } + } - shared_ptr > > tmp_iterative = - dynamic_pointer_cast > >(reconstruction_template_sptr); + // In the additive put the scaled scatter estimate + // If we have randoms, then add them to the scaled scatter estimate + // Then normalise + if (run_in_2d_projdata) { + this->add_projdata_2d_sptr->fill(*scaled_est_projdata_sptr); - // - // Now, we can call Reconstruction::set_up(). - if (tmp_iterative->set_up(this->current_activity_image_sptr) == Succeeded::no) - { - error("ScatterEstimation: Failure at set_up() of the reconstruction method. Aborting."); + if (!is_null_ptr(this->back_projdata_2d_sptr)) { + add_proj_data(*add_projdata_2d_sptr, *this->back_projdata_2d_sptr); + } + this->multiplicative_binnorm_2d_sptr->apply(*add_projdata_2d_sptr); + } else { + // TODO restructure code to move additive_projdata code from above + error("ScatterEstimation: You should not be here. This is not 2D."); } + current_activity_image_sptr->fill(1.f); - // return iterative_object->reconstruct(this->activity_image_lowres_sptr); - tmp_iterative->reconstruct(this->current_activity_image_sptr); + iterative_method ? reconstruct_iterative(i_scat_iter, this->current_activity_image_sptr) + : reconstruct_analytic(i_scat_iter, this->current_activity_image_sptr); - if(this->run_debug_mode) - { - std::stringstream convert; // stream used for the conversion - convert << "recon_" << _current_iter_num; - FilePath tmp(convert.str(),false); - tmp.prepend_directory_name(extras_path.get_path()); - OutputFileFormat >::default_sptr()-> - write_to_file(tmp.get_string(), *_current_estimate_sptr); + scatter_simulation_sptr->set_activity_image_sptr(current_activity_image_sptr); + } - } + info("ScatterEstimation: Scatter Estimation finished !!!"); + + return Succeeded::yes; } void -ScatterEstimation:: -reconstruct_analytic(int _current_iter_num, - shared_ptr > & _current_estimate_sptr) -{ - AnalyticReconstruction* analytic_object = - dynamic_cast (this->reconstruction_template_sptr.get()); - analytic_object->reconstruct(this->current_activity_image_sptr); - - if(this->run_debug_mode) - { - std::stringstream convert; // stream used for the conversion - convert << "recon_analytic_"<< _current_iter_num; - FilePath tmp(convert.str(),false); - tmp.prepend_directory_name(extras_path.get_path()); - OutputFileFormat >::default_sptr()-> - write_to_file(tmp.get_string(), *_current_estimate_sptr); - - } +ScatterEstimation::reconstruct_iterative(int _current_iter_num, + shared_ptr>& _current_estimate_sptr) { + + shared_ptr>> tmp_iterative = + dynamic_pointer_cast>>(reconstruction_template_sptr); + + // + // Now, we can call Reconstruction::set_up(). + if (tmp_iterative->set_up(this->current_activity_image_sptr) == Succeeded::no) { + error("ScatterEstimation: Failure at set_up() of the reconstruction method. Aborting."); + } + + // return iterative_object->reconstruct(this->activity_image_lowres_sptr); + tmp_iterative->reconstruct(this->current_activity_image_sptr); + + if (this->run_debug_mode) { + std::stringstream convert; // stream used for the conversion + convert << "recon_" << _current_iter_num; + FilePath tmp(convert.str(), false); + tmp.prepend_directory_name(extras_path.get_path()); + OutputFileFormat>::default_sptr()->write_to_file(tmp.get_string(), *_current_estimate_sptr); + } +} - //TODO: threshold ... to cut the negative values +void +ScatterEstimation::reconstruct_analytic(int _current_iter_num, shared_ptr>& _current_estimate_sptr) { + AnalyticReconstruction* analytic_object = dynamic_cast(this->reconstruction_template_sptr.get()); + analytic_object->reconstruct(this->current_activity_image_sptr); + + if (this->run_debug_mode) { + std::stringstream convert; // stream used for the conversion + convert << "recon_analytic_" << _current_iter_num; + FilePath tmp(convert.str(), false); + tmp.prepend_directory_name(extras_path.get_path()); + OutputFileFormat>::default_sptr()->write_to_file(tmp.get_string(), *_current_estimate_sptr); + } + + // TODO: threshold ... to cut the negative values } /****************** functions to help **********************/ void -ScatterEstimation:: -add_proj_data(ProjData& first_addend, const ProjData& second_addend) -{ - assert(first_addend.get_min_segment_num() == second_addend.get_min_segment_num()); - assert(first_addend.get_max_segment_num() == second_addend.get_max_segment_num()); - for (int segment_num = first_addend.get_min_segment_num(); - segment_num <= first_addend.get_max_segment_num(); - ++segment_num) - { - SegmentByView first_segment_by_view = - first_addend.get_segment_by_view(segment_num); +ScatterEstimation::add_proj_data(ProjData& first_addend, const ProjData& second_addend) { + assert(first_addend.get_min_segment_num() == second_addend.get_min_segment_num()); + assert(first_addend.get_max_segment_num() == second_addend.get_max_segment_num()); + for (int segment_num = first_addend.get_min_segment_num(); segment_num <= first_addend.get_max_segment_num(); ++segment_num) { + SegmentByView first_segment_by_view = first_addend.get_segment_by_view(segment_num); - SegmentByView sec_segment_by_view = - second_addend.get_segment_by_view(segment_num); + SegmentByView sec_segment_by_view = second_addend.get_segment_by_view(segment_num); - first_segment_by_view += sec_segment_by_view; + first_segment_by_view += sec_segment_by_view; - if (!(first_addend.set_segment(first_segment_by_view) == Succeeded::yes)) - { - error("Error set_segment %d", segment_num); - } + if (!(first_addend.set_segment(first_segment_by_view) == Succeeded::yes)) { + error("Error set_segment %d", segment_num); } + } } void -ScatterEstimation:: -subtract_proj_data(ProjData& minuend, const ProjData& subtracted) -{ - assert(minuend.get_min_segment_num() == subtracted.get_min_segment_num()); - assert(minuend.get_max_segment_num() == subtracted.get_max_segment_num()); - for (int segment_num = minuend.get_min_segment_num(); - segment_num <= minuend.get_max_segment_num(); - ++segment_num) - { - SegmentByView first_segment_by_view = - minuend.get_segment_by_view(segment_num); +ScatterEstimation::subtract_proj_data(ProjData& minuend, const ProjData& subtracted) { + assert(minuend.get_min_segment_num() == subtracted.get_min_segment_num()); + assert(minuend.get_max_segment_num() == subtracted.get_max_segment_num()); + for (int segment_num = minuend.get_min_segment_num(); segment_num <= minuend.get_max_segment_num(); ++segment_num) { + SegmentByView first_segment_by_view = minuend.get_segment_by_view(segment_num); - SegmentByView sec_segment_by_view = - subtracted.get_segment_by_view(segment_num); + SegmentByView sec_segment_by_view = subtracted.get_segment_by_view(segment_num); - first_segment_by_view -= sec_segment_by_view; + first_segment_by_view -= sec_segment_by_view; - if (!(minuend.set_segment(first_segment_by_view) == Succeeded::yes)) - { - error("ScatterEstimation: Error set_segment %d", segment_num); - } + if (!(minuend.set_segment(first_segment_by_view) == Succeeded::yes)) { + error("ScatterEstimation: Error set_segment %d", segment_num); } + } - // Filter negative values: - // pow_times_add zero_threshold (0.0f, 1.0f, 1.0f, 0.0f, NumericInfo().max_value()); - // apply_to_proj_data(minuend, zero_threshold); + // Filter negative values: + // pow_times_add zero_threshold (0.0f, 1.0f, 1.0f, 0.0f, NumericInfo().max_value()); + // apply_to_proj_data(minuend, zero_threshold); } void -ScatterEstimation:: -apply_to_proj_data(ProjData& data, const pow_times_add& func) -{ - for (int segment_num = data.get_min_segment_num(); - segment_num <= data.get_max_segment_num(); - ++segment_num) - { - SegmentByView segment_by_view = - data.get_segment_by_view(segment_num); +ScatterEstimation::apply_to_proj_data(ProjData& data, const pow_times_add& func) { + for (int segment_num = data.get_min_segment_num(); segment_num <= data.get_max_segment_num(); ++segment_num) { + SegmentByView segment_by_view = data.get_segment_by_view(segment_num); - in_place_apply_function(segment_by_view, - func); + in_place_apply_function(segment_by_view, func); - if (!(data.set_segment(segment_by_view) == Succeeded::yes)) - { - error("ScatterEstimation: Error set_segment %d", segment_num); - } + if (!(data.set_segment(segment_by_view) == Succeeded::yes)) { + error("ScatterEstimation: Error set_segment %d", segment_num); } + } } Succeeded -ScatterEstimation::project_mask_image() -{ - if (is_null_ptr(this->mask_image_sptr)) - { - warning("You cannot forward project if you have not set the mask image. Aborting."); - return Succeeded::no; +ScatterEstimation::project_mask_image() { + if (is_null_ptr(this->mask_image_sptr)) { + warning("You cannot forward project if you have not set the mask image. Aborting."); + return Succeeded::no; + } + + if (run_in_2d_projdata) { + if (is_null_ptr(this->input_projdata_2d_sptr)) { + warning("No 2D proj_data have been initialised. Aborting."); + return Succeeded::no; } - - if (run_in_2d_projdata) - { - if (is_null_ptr(this->input_projdata_2d_sptr)) - { - warning("No 2D proj_data have been initialised. Aborting."); - return Succeeded::no; - } - } - else - { - if (is_null_ptr(this->input_projdata_sptr)) - { - warning("No 3D proj_data have been initialised. Aborting."); - return Succeeded::no; - } + } else { + if (is_null_ptr(this->input_projdata_sptr)) { + warning("No 3D proj_data have been initialised. Aborting."); + return Succeeded::no; } + } - shared_ptr forw_projector_sptr; - shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); - forw_projector_sptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); - info(boost::format("ScatterEstimation: Forward projector used for the calculation of " - "the tail mask: %1%") % forw_projector_sptr->parameter_info()); + shared_ptr forw_projector_sptr; + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + forw_projector_sptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); + info(boost::format("ScatterEstimation: Forward projector used for the calculation of " + "the tail mask: %1%") % + forw_projector_sptr->parameter_info()); - shared_ptr mask_projdata; - if(run_in_2d_projdata) - { - forw_projector_sptr->set_up(this->input_projdata_2d_sptr->get_proj_data_info_sptr(), - this->mask_image_sptr ); + shared_ptr mask_projdata; + if (run_in_2d_projdata) { + forw_projector_sptr->set_up(this->input_projdata_2d_sptr->get_proj_data_info_sptr(), this->mask_image_sptr); - mask_projdata.reset(new ProjDataInMemory(this->input_projdata_2d_sptr->get_exam_info_sptr(), - this->input_projdata_2d_sptr->get_proj_data_info_sptr())); - } - else - { - forw_projector_sptr->set_up(this->input_projdata_sptr->get_proj_data_info_sptr(), - this->mask_image_sptr ); + mask_projdata.reset(new ProjDataInMemory(this->input_projdata_2d_sptr->get_exam_info_sptr(), + this->input_projdata_2d_sptr->get_proj_data_info_sptr())); + } else { + forw_projector_sptr->set_up(this->input_projdata_sptr->get_proj_data_info_sptr(), this->mask_image_sptr); - mask_projdata.reset(new ProjDataInMemory(this->input_projdata_sptr->get_exam_info_sptr(), - this->input_projdata_sptr->get_proj_data_info_sptr())); - } + mask_projdata.reset(new ProjDataInMemory(this->input_projdata_sptr->get_exam_info_sptr(), + this->input_projdata_sptr->get_proj_data_info_sptr())); + } - forw_projector_sptr->forward_project(*mask_projdata, *this->mask_image_sptr); + forw_projector_sptr->forward_project(*mask_projdata, *this->mask_image_sptr); - //add 1 to be able to use create_tail_mask_from_ACFs (which expects ACFs, - //so complains if the threshold is too low) + // add 1 to be able to use create_tail_mask_from_ACFs (which expects ACFs, + // so complains if the threshold is too low) - pow_times_add pow_times_add_object(1.0f, 1.0f, 1.0f,NumericInfo().min_value(), - NumericInfo().max_value()); + pow_times_add pow_times_add_object(1.0f, 1.0f, 1.0f, NumericInfo().min_value(), NumericInfo().max_value()); - // I have only one segment I could remove this. - for (int segment_num = mask_projdata->get_min_segment_num(); - segment_num <= mask_projdata->get_max_segment_num(); - ++segment_num) - { - SegmentByView segment_by_view = - mask_projdata->get_segment_by_view(segment_num); + // I have only one segment I could remove this. + for (int segment_num = mask_projdata->get_min_segment_num(); segment_num <= mask_projdata->get_max_segment_num(); + ++segment_num) { + SegmentByView segment_by_view = mask_projdata->get_segment_by_view(segment_num); - in_place_apply_function(segment_by_view, - pow_times_add_object); + in_place_apply_function(segment_by_view, pow_times_add_object); - if (!(mask_projdata->set_segment(segment_by_view) == Succeeded::yes)) - { - warning("ScatterEstimation: Error set_segment %d", segment_num); - return Succeeded::no; - } + if (!(mask_projdata->set_segment(segment_by_view) == Succeeded::yes)) { + warning("ScatterEstimation: Error set_segment %d", segment_num); + return Succeeded::no; } + } - if (this->mask_projdata_filename.size() > 0) - this->mask_projdata_sptr.reset(new ProjDataInterfile(mask_projdata->get_exam_info_sptr(), - mask_projdata->get_proj_data_info_sptr(), - this->mask_projdata_filename, - std::ios::in | std::ios::out | std::ios::trunc)); - else - this->mask_projdata_sptr.reset(new ProjDataInMemory(mask_projdata->get_exam_info_sptr(), - mask_projdata->get_proj_data_info_sptr())); - - CreateTailMaskFromACFs create_tail_mask_from_acfs; - - if(this->tail_mask_par_filename.empty()) - { - create_tail_mask_from_acfs.ACF_threshold = 1.1; - create_tail_mask_from_acfs.safety_margin = 4; - } - else - { - if(!create_tail_mask_from_acfs.parse(this->tail_mask_par_filename.c_str())) - error(boost::format("Error parsing parameters file %1%, for creating mask tails from ACFs.") - %this->tail_mask_par_filename); - } - - create_tail_mask_from_acfs.set_input_projdata_sptr(mask_projdata); - create_tail_mask_from_acfs.set_output_projdata_sptr(this->mask_projdata_sptr); - return create_tail_mask_from_acfs.process_data(); + if (this->mask_projdata_filename.size() > 0) + this->mask_projdata_sptr.reset(new ProjDataInterfile(mask_projdata->get_exam_info_sptr(), + mask_projdata->get_proj_data_info_sptr(), this->mask_projdata_filename, + std::ios::in | std::ios::out | std::ios::trunc)); + else + this->mask_projdata_sptr.reset( + new ProjDataInMemory(mask_projdata->get_exam_info_sptr(), mask_projdata->get_proj_data_info_sptr())); + + CreateTailMaskFromACFs create_tail_mask_from_acfs; + + if (this->tail_mask_par_filename.empty()) { + create_tail_mask_from_acfs.ACF_threshold = 1.1; + create_tail_mask_from_acfs.safety_margin = 4; + } else { + if (!create_tail_mask_from_acfs.parse(this->tail_mask_par_filename.c_str())) + error(boost::format("Error parsing parameters file %1%, for creating mask tails from ACFs.") % + this->tail_mask_par_filename); + } + + create_tail_mask_from_acfs.set_input_projdata_sptr(mask_projdata); + create_tail_mask_from_acfs.set_output_projdata_sptr(this->mask_projdata_sptr); + return create_tail_mask_from_acfs.process_data(); } void -ScatterEstimation:: -apply_mask_in_place(DiscretisedDensity<3, float>& arg, - const MaskingParameters& masking_parameters) -{ - if (!is_null_ptr(masking_parameters.filter_sptr)) - { - masking_parameters.filter_sptr->process_data(arg); - } +ScatterEstimation::apply_mask_in_place(DiscretisedDensity<3, float>& arg, const MaskingParameters& masking_parameters) { + if (!is_null_ptr(masking_parameters.filter_sptr)) { + masking_parameters.filter_sptr->process_data(arg); + } // min threshold - for (DiscretisedDensity<3,float>::full_iterator iter = arg.begin_all(); iter != arg.end_all(); ++iter) - { - if (*iter < masking_parameters.min_threshold) - *iter = 0.F; - else - *iter = 1.F; - } + for (DiscretisedDensity<3, float>::full_iterator iter = arg.begin_all(); iter != arg.end_all(); ++iter) { + if (*iter < masking_parameters.min_threshold) + *iter = 0.F; + else + *iter = 1.F; + } } -int ScatterEstimation::get_num_iterations() const -{ - return num_scatter_iterations; +int +ScatterEstimation::get_num_iterations() const { + return num_scatter_iterations; } // deprecated version -int ScatterEstimation::get_iterations_num() const -{ - return num_scatter_iterations; +int +ScatterEstimation::get_iterations_num() const { + return num_scatter_iterations; } void -ScatterEstimation::create_multiplicative_binnorm_sptr() -{ - if (!is_null_ptr(this->multiplicative_binnorm_sptr)) - { - if (!is_null_ptr(this->norm_3d_sptr)) - error("ScatterEstimation: cannot handle having both norm and 'combined norm' initialised"); - if (!is_null_ptr(this->atten_norm_3d_sptr)) - error("ScatterEstimation: cannot handle having both attenuation and 'combined norm' initialised"); +ScatterEstimation::create_multiplicative_binnorm_sptr() { + if (!is_null_ptr(this->multiplicative_binnorm_sptr)) { + if (!is_null_ptr(this->norm_3d_sptr)) + error("ScatterEstimation: cannot handle having both norm and 'combined norm' initialised"); + if (!is_null_ptr(this->atten_norm_3d_sptr)) + error("ScatterEstimation: cannot handle having both attenuation and 'combined norm' initialised"); + } else { + if (is_null_ptr(this->atten_norm_3d_sptr)) { + error("ScatterEstimation: need attenuation correction factors to be set (sorry)"); } - else - { - if (is_null_ptr(this->atten_norm_3d_sptr)) - { - error("ScatterEstimation: need attenuation correction factors to be set (sorry)"); - } - if (is_null_ptr(this->norm_3d_sptr)) - { - warning("ScatterEstimation: no normalisation data set. This would only be appropriate for simple simulations."); - this->norm_3d_sptr = this->atten_norm_3d_sptr; - } - else - { - this->multiplicative_binnorm_sptr.reset(new ChainedBinNormalisation(norm_3d_sptr, atten_norm_3d_sptr)); - } + if (is_null_ptr(this->norm_3d_sptr)) { + warning("ScatterEstimation: no normalisation data set. This would only be appropriate for simple simulations."); + this->norm_3d_sptr = this->atten_norm_3d_sptr; + } else { + this->multiplicative_binnorm_sptr.reset(new ChainedBinNormalisation(norm_3d_sptr, atten_norm_3d_sptr)); } + } } shared_ptr -ScatterEstimation::get_normalisation_object_sptr(const shared_ptr& combined_norm_sptr) const -{ - const ChainedBinNormalisation* tmp_chain_norm_sptr = - dynamic_cast(combined_norm_sptr.get()); - - if (!is_null_ptr(tmp_chain_norm_sptr )) - { - return tmp_chain_norm_sptr->get_first_norm(); - } - else //Just trivial, then .. - { - shared_ptr normalisation_factors_sptr(new TrivialBinNormalisation()); - normalisation_factors_sptr->set_up(this->input_projdata_sptr->get_exam_info_sptr(), this->input_projdata_sptr->get_proj_data_info_sptr()); - return normalisation_factors_sptr; - } +ScatterEstimation::get_normalisation_object_sptr(const shared_ptr& combined_norm_sptr) const { + const ChainedBinNormalisation* tmp_chain_norm_sptr = dynamic_cast(combined_norm_sptr.get()); + + if (!is_null_ptr(tmp_chain_norm_sptr)) { + return tmp_chain_norm_sptr->get_first_norm(); + } else // Just trivial, then .. + { + shared_ptr normalisation_factors_sptr(new TrivialBinNormalisation()); + normalisation_factors_sptr->set_up(this->input_projdata_sptr->get_exam_info_sptr(), + this->input_projdata_sptr->get_proj_data_info_sptr()); + return normalisation_factors_sptr; + } } shared_ptr -ScatterEstimation::get_attenuation_correction_factors_sptr(const shared_ptr& combined_norm_sptr) const -{ - const ChainedBinNormalisation* tmp_chain_norm_sptr = - dynamic_cast(combined_norm_sptr.get()); +ScatterEstimation::get_attenuation_correction_factors_sptr(const shared_ptr& combined_norm_sptr) const { + const ChainedBinNormalisation* tmp_chain_norm_sptr = dynamic_cast(combined_norm_sptr.get()); shared_ptr atten_norm_sptr; - if (!is_null_ptr(tmp_chain_norm_sptr )) - { - atten_norm_sptr = tmp_chain_norm_sptr->get_second_norm(); - } - else - { - atten_norm_sptr = combined_norm_sptr; - } - - return - dynamic_cast (atten_norm_sptr.get())->get_norm_proj_data_sptr(); + if (!is_null_ptr(tmp_chain_norm_sptr)) { + atten_norm_sptr = tmp_chain_norm_sptr->get_second_norm(); + } else { + atten_norm_sptr = combined_norm_sptr; + } + return dynamic_cast(atten_norm_sptr.get())->get_norm_proj_data_sptr(); } -shared_ptr ScatterEstimation::create_new_proj_data(const std::string& filename, - const shared_ptr exam_info_sptr, - const shared_ptr proj_data_info_sptr) const -{ - shared_ptr pd_sptr; - if (run_debug_mode) - { - FilePath tmp(filename, false); - tmp = tmp.get_filename(); // get rid of any folder info - tmp.prepend_directory_name(extras_path.get_path()); - pd_sptr.reset(new ProjDataInterfile(exam_info_sptr, - proj_data_info_sptr, - tmp.get_string(), - std::ios::in | std::ios::out | std::ios::trunc)); - } - else - { - pd_sptr.reset(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr)); - } - return pd_sptr; +shared_ptr +ScatterEstimation::create_new_proj_data(const std::string& filename, const shared_ptr exam_info_sptr, + const shared_ptr proj_data_info_sptr) const { + shared_ptr pd_sptr; + if (run_debug_mode) { + FilePath tmp(filename, false); + tmp = tmp.get_filename(); // get rid of any folder info + tmp.prepend_directory_name(extras_path.get_path()); + pd_sptr.reset(new ProjDataInterfile(exam_info_sptr, proj_data_info_sptr, tmp.get_string(), + std::ios::in | std::ios::out | std::ios::trunc)); + } else { + pd_sptr.reset(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr)); + } + return pd_sptr; } END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 71bb183cd6..1ef62c204a 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -53,565 +53,472 @@ START_NAMESPACE_STIR -ScatterSimulation:: -ScatterSimulation() -{ - this->set_defaults(); -} +ScatterSimulation::ScatterSimulation() { this->set_defaults(); } -ScatterSimulation:: -~ScatterSimulation() -{ - // Sometimes I get a segfault without this line. - scatt_points_vector.clear(); +ScatterSimulation::~ScatterSimulation() { + // Sometimes I get a segfault without this line. + scatt_points_vector.clear(); } Succeeded -ScatterSimulation:: -process_data() -{ - if (!this->_already_set_up) - error("ScatterSimulation: need to call set_up() first"); - if(is_null_ptr(output_proj_data_sptr)) - error("ScatterSimulation: output projection data not set. Aborting."); - - // this is useful in the scatter estimation process. - this->output_proj_data_sptr->fill(0.f); - // check if output has same info as templates - { - if ((*output_proj_data_sptr->get_proj_data_info_sptr()) != - (*this->get_template_proj_data_info_sptr())) - error("ScatterSimulation: output projection data incompatible with what was used for set_up()"); - // TODO enable check on exam_info but this has no operator== yet - } - info("ScatterSimulator: Running Scatter Simulation ..."); - info("ScatterSimulator: Initialising ..."); - - ViewSegmentNumbers vs_num; - /* ////////////////// SCATTER ESTIMATION TIME //////////////// */ - CPUTimer bin_timer; - bin_timer.start(); - // variables to report (remaining) time - HighResWallClockTimer wall_clock_timer; - double previous_timer = 0 ; - int previous_bin_count = 0 ; - int bin_counter = 0; - int axial_bins = 0 ; - wall_clock_timer.start(); - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); - - const int total_bins = - this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - /* ////////////////// end SCATTER ESTIMATION TIME //////////////// */ - float total_scatter = 0 ; - - info("ScatterSimulator: Initialization finished ..."); - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - { - for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); - vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); - ++vs_num.view_num()) - { - total_scatter += this->process_data_for_view_segment_num(vs_num); - bin_counter += - this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - /* ////////////////// SCATTER ESTIMATION TIME ////////////////*/ - { - wall_clock_timer.stop(); // must be stopped before getting the value - info(boost::format("%1$5u / %2% bins done. Total time elapsed %3$5.2f secs, remaining about %4$5.2f mins (ignoring caching).") - % bin_counter % total_bins - % wall_clock_timer.value() - % ((wall_clock_timer.value() - previous_timer) - * (total_bins - bin_counter) / (bin_counter - previous_bin_count) / 60), - /* verbosity level*/ 3); - previous_timer = wall_clock_timer.value() ; - previous_bin_count = bin_counter ; - wall_clock_timer.start(); - } - /* ////////////////// end SCATTER ESTIMATION TIME //////////////// */ - } +ScatterSimulation::process_data() { + if (!this->_already_set_up) + error("ScatterSimulation: need to call set_up() first"); + if (is_null_ptr(output_proj_data_sptr)) + error("ScatterSimulation: output projection data not set. Aborting."); + + // this is useful in the scatter estimation process. + this->output_proj_data_sptr->fill(0.f); + // check if output has same info as templates + { + if ((*output_proj_data_sptr->get_proj_data_info_sptr()) != (*this->get_template_proj_data_info_sptr())) + error("ScatterSimulation: output projection data incompatible with what was used for set_up()"); + // TODO enable check on exam_info but this has no operator== yet + } + info("ScatterSimulator: Running Scatter Simulation ..."); + info("ScatterSimulator: Initialising ..."); + + ViewSegmentNumbers vs_num; + /* ////////////////// SCATTER ESTIMATION TIME //////////////// */ + CPUTimer bin_timer; + bin_timer.start(); + // variables to report (remaining) time + HighResWallClockTimer wall_clock_timer; + double previous_timer = 0; + int previous_bin_count = 0; + int bin_counter = 0; + int axial_bins = 0; + wall_clock_timer.start(); + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); ++vs_num.segment_num()) + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + + const int total_bins = this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + /* ////////////////// end SCATTER ESTIMATION TIME //////////////// */ + float total_scatter = 0; + + info("ScatterSimulator: Initialization finished ..."); + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); ++vs_num.segment_num()) { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); + vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); ++vs_num.view_num()) { + total_scatter += this->process_data_for_view_segment_num(vs_num); + bin_counter += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + /* ////////////////// SCATTER ESTIMATION TIME ////////////////*/ + { + wall_clock_timer.stop(); // must be stopped before getting the value + info(boost::format( + "%1$5u / %2% bins done. Total time elapsed %3$5.2f secs, remaining about %4$5.2f mins (ignoring caching).") % + bin_counter % total_bins % wall_clock_timer.value() % + ((wall_clock_timer.value() - previous_timer) * (total_bins - bin_counter) / (bin_counter - previous_bin_count) / + 60), + /* verbosity level*/ 3); + previous_timer = wall_clock_timer.value(); + previous_bin_count = bin_counter; + wall_clock_timer.start(); + } + /* ////////////////// end SCATTER ESTIMATION TIME //////////////// */ } + } - bin_timer.stop(); - wall_clock_timer.stop(); + bin_timer.stop(); + wall_clock_timer.stop(); - if (detection_points_vector.size() != static_cast(total_detectors)) - { - warning("Expected num detectors: %d, but found %d\n", - total_detectors, detection_points_vector.size()); - return Succeeded::no; - } + if (detection_points_vector.size() != static_cast(total_detectors)) { + warning("Expected num detectors: %d, but found %d\n", total_detectors, detection_points_vector.size()); + return Succeeded::no; + } - info(boost::format("TOTAL SCATTER counts before upsampling and norm = %g") % total_scatter); - this->write_log(wall_clock_timer.value(), total_scatter); - return Succeeded::yes; + info(boost::format("TOTAL SCATTER counts before upsampling and norm = %g") % total_scatter); + this->write_log(wall_clock_timer.value(), total_scatter); + return Succeeded::yes; } double -ScatterSimulation:: -process_data_for_view_segment_num(const ViewSegmentNumbers& vs_num) -{ - // First construct a vector of all bins that we'll process. - // The reason for making this list before the actual calculation is that we can then parallelise over all bins - // without having to think about double loops. - std::vector all_bins; - { - Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); - - for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - { - for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); - bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); - ++bin.tangential_pos_num()) - { - all_bins.push_back(bin); - } - } +ScatterSimulation::process_data_for_view_segment_num(const ViewSegmentNumbers& vs_num) { + // First construct a vector of all bins that we'll process. + // The reason for making this list before the actual calculation is that we can then parallelise over all bins + // without having to think about double loops. + std::vector all_bins; + { + Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); + + for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); + ++bin.axial_pos_num()) { + for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); + ++bin.tangential_pos_num()) { + all_bins.push_back(bin); + } } + } - // now compute scatter for all bins - double total_scatter = 0.; - Viewgram viewgram = - this->output_proj_data_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); + // now compute scatter for all bins + double total_scatter = 0.; + Viewgram viewgram = this->output_proj_data_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); #ifdef STIR_OPENMP -#pragma omp parallel for reduction(+:total_scatter) schedule(dynamic) +# pragma omp parallel for reduction(+ : total_scatter) schedule(dynamic) #endif - for (int i = 0; i < static_cast(all_bins.size()); ++i) - { - const Bin bin = all_bins[i]; - const double scatter_ratio = scatter_estimate(bin); + for (int i = 0; i < static_cast(all_bins.size()); ++i) { + const Bin bin = all_bins[i]; + const double scatter_ratio = scatter_estimate(bin); -#if defined STIR_OPENMP +#if defined STIR_OPENMP # if _OPENMP >= 201107 # pragma omp atomic write # else # pragma omp critical(ScatterSimulationByBin_process_data_for_view_segment_num) # endif #endif - viewgram[bin.axial_pos_num()][bin.tangential_pos_num()] = - static_cast(scatter_ratio); - total_scatter += static_cast(scatter_ratio); - } // end loop over bins + viewgram[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(scatter_ratio); + total_scatter += static_cast(scatter_ratio); + } // end loop over bins - if (this->output_proj_data_sptr->set_viewgram(viewgram) == Succeeded::no) - error("ScatterSimulation: error writing viewgram"); + if (this->output_proj_data_sptr->set_viewgram(viewgram) == Succeeded::no) + error("ScatterSimulation: error writing viewgram"); - return total_scatter; + return total_scatter; } void -ScatterSimulation::set_defaults() -{ - this->attenuation_threshold = 0.01f ; - this->randomly_place_scatter_points = true; - this->use_cache = true; - this->zoom_xy = -1.f; - this->zoom_z = -1.f; - this->zoom_size_xy = -1; - this->zoom_size_z = -1; - this->downsample_scanner_bool = false; - this->downsample_scanner_dets = 64; - this->downsample_scanner_rings = -1; - this->density_image_filename = ""; - this->activity_image_filename = ""; - this->density_image_for_scatter_points_output_filename =""; - this->density_image_for_scatter_points_filename = ""; - this->template_proj_data_filename = ""; - this->remove_cache_for_integrals_over_activity(); - this->remove_cache_for_integrals_over_attenuation(); - this->_already_set_up = false; +ScatterSimulation::set_defaults() { + this->attenuation_threshold = 0.01f; + this->randomly_place_scatter_points = true; + this->use_cache = true; + this->zoom_xy = -1.f; + this->zoom_z = -1.f; + this->zoom_size_xy = -1; + this->zoom_size_z = -1; + this->downsample_scanner_bool = false; + this->downsample_scanner_dets = 64; + this->downsample_scanner_rings = -1; + this->density_image_filename = ""; + this->activity_image_filename = ""; + this->density_image_for_scatter_points_output_filename = ""; + this->density_image_for_scatter_points_filename = ""; + this->template_proj_data_filename = ""; + this->remove_cache_for_integrals_over_activity(); + this->remove_cache_for_integrals_over_attenuation(); + this->_already_set_up = false; } void -ScatterSimulation:: -ask_parameters() -{ - this->attenuation_threshold = ask_num("attenuation threshold(cm^-1)",0.0f, 5.0f, 0.01f); - this->randomly_place_scatter_points = ask_num("random place scatter points?",0, 1, 1); - this->use_cache = ask_num(" Use cache?",0, 1, 1); - this->density_image_filename = ask_string("density image filename", ""); - this->activity_image_filename = ask_string("activity image filename", ""); - //this->density_image_for_scatter_points_filename = ask_string("density image for scatter points filename", ""); - this->template_proj_data_filename = ask_string("Scanner ProjData filename", ""); +ScatterSimulation::ask_parameters() { + this->attenuation_threshold = ask_num("attenuation threshold(cm^-1)", 0.0f, 5.0f, 0.01f); + this->randomly_place_scatter_points = ask_num("random place scatter points?", 0, 1, 1); + this->use_cache = ask_num(" Use cache?", 0, 1, 1); + this->density_image_filename = ask_string("density image filename", ""); + this->activity_image_filename = ask_string("activity image filename", ""); + // this->density_image_for_scatter_points_filename = ask_string("density image for scatter points filename", ""); + this->template_proj_data_filename = ask_string("Scanner ProjData filename", ""); } void -ScatterSimulation::initialise_keymap() -{ - - // this->parser.add_start_key("Scatter Simulation Parameters"); - // this->parser.add_stop_key("end Scatter Simulation Parameters"); - this->parser.add_key("template projdata filename", - &this->template_proj_data_filename); - this->parser.add_key("attenuation image filename", - &this->density_image_filename); - this->parser.add_key("attenuation image for scatter points filename", - &this->density_image_for_scatter_points_filename); - this->parser.add_key("zoom XY for attenuation image for scatter points", - &this->zoom_xy); - this->parser.add_key("zoom Z for attenuation image for scatter points", - &this->zoom_z); - this->parser.add_key("XY size of downsampled image for scatter points", - &this->zoom_size_xy); - this->parser.add_key("Z size of downsampled image for scatter points", - &this->zoom_size_z); - this->parser.add_key("attenuation image for scatter points output filename", - &this->density_image_for_scatter_points_output_filename); - this->parser.add_key("downsampled scanner number of detectors per ring", - &this->downsample_scanner_dets); - this->parser.add_key("downsampled scanner number of rings", - &this->downsample_scanner_rings); - this->parser.add_key("activity image filename", - &this->activity_image_filename); - this->parser.add_key("attenuation threshold", - &this->attenuation_threshold); - this->parser.add_key("output filename prefix", - &this->output_proj_data_filename); - this->parser.add_key("downsample scanner", - &this->downsample_scanner_bool); - this->parser.add_key("randomly place scatter points", &this->randomly_place_scatter_points); - this->parser.add_key("use cache", &this->use_cache); +ScatterSimulation::initialise_keymap() { + + // this->parser.add_start_key("Scatter Simulation Parameters"); + // this->parser.add_stop_key("end Scatter Simulation Parameters"); + this->parser.add_key("template projdata filename", &this->template_proj_data_filename); + this->parser.add_key("attenuation image filename", &this->density_image_filename); + this->parser.add_key("attenuation image for scatter points filename", &this->density_image_for_scatter_points_filename); + this->parser.add_key("zoom XY for attenuation image for scatter points", &this->zoom_xy); + this->parser.add_key("zoom Z for attenuation image for scatter points", &this->zoom_z); + this->parser.add_key("XY size of downsampled image for scatter points", &this->zoom_size_xy); + this->parser.add_key("Z size of downsampled image for scatter points", &this->zoom_size_z); + this->parser.add_key("attenuation image for scatter points output filename", + &this->density_image_for_scatter_points_output_filename); + this->parser.add_key("downsampled scanner number of detectors per ring", &this->downsample_scanner_dets); + this->parser.add_key("downsampled scanner number of rings", &this->downsample_scanner_rings); + this->parser.add_key("activity image filename", &this->activity_image_filename); + this->parser.add_key("attenuation threshold", &this->attenuation_threshold); + this->parser.add_key("output filename prefix", &this->output_proj_data_filename); + this->parser.add_key("downsample scanner", &this->downsample_scanner_bool); + this->parser.add_key("randomly place scatter points", &this->randomly_place_scatter_points); + this->parser.add_key("use cache", &this->use_cache); } - bool -ScatterSimulation:: -post_processing() -{ +ScatterSimulation::post_processing() { - if (this->template_proj_data_filename.size() > 0) - this->set_template_proj_data_info(this->template_proj_data_filename); + if (this->template_proj_data_filename.size() > 0) + this->set_template_proj_data_info(this->template_proj_data_filename); - if (this->activity_image_filename.size() > 0) - this->set_activity_image(this->activity_image_filename); + if (this->activity_image_filename.size() > 0) + this->set_activity_image(this->activity_image_filename); - if (this->density_image_filename.size() > 0) - this->set_density_image(this->density_image_filename); + if (this->density_image_filename.size() > 0) + this->set_density_image(this->density_image_filename); - if(this->density_image_for_scatter_points_filename.size() > 0) - this->set_density_image_for_scatter_points(this->density_image_for_scatter_points_filename); + if (this->density_image_for_scatter_points_filename.size() > 0) + this->set_density_image_for_scatter_points(this->density_image_for_scatter_points_filename); - if (this->output_proj_data_filename.size() > 0) - this->set_output_proj_data(this->output_proj_data_filename); + if (this->output_proj_data_filename.size() > 0) + this->set_output_proj_data(this->output_proj_data_filename); - return false; + return false; } Succeeded -ScatterSimulation:: -set_up() -{ - if (is_null_ptr(proj_data_info_cyl_noarc_cor_sptr)) - error("ScatterSimulation: projection data info not set. Aborting."); - - if (!proj_data_info_cyl_noarc_cor_sptr->has_energy_information()) - error("ScatterSimulation: scanner energy resolution information not set. Aborting."); - - if (is_null_ptr(template_exam_info_sptr)) - error("ScatterSimulation: projection data info not set. Aborting."); - - if(!template_exam_info_sptr->has_energy_information()) - error("ScatterSimulation: template energy window information not set. Aborting."); - - if(is_null_ptr(activity_image_sptr)) - error("ScatterSimulation: activity image not set. Aborting."); - - if(is_null_ptr(density_image_sptr)) - error("ScatterSimulation: density image not set. Aborting."); - - if(downsample_scanner_bool) - { - if (this->_already_set_up) - error("ScatterSimulation: set_up() called twice. This is currently not supported."); - - downsample_scanner(); - } - - if(is_null_ptr(density_image_for_scatter_points_sptr)) - { - if (this->_already_set_up) - error("ScatterSimulation: set_up() called twice. This is currently not supported."); - downsample_density_image_for_scatter_points(zoom_xy, zoom_z, zoom_size_xy, zoom_size_z); - } - -// { -// this->output_proj_data_sptr.reset(new ProjDataInMemory(this->template_exam_info_sptr, -// this->proj_data_info_cyl_noarc_cor_sptr->create_shared_clone())); -// this->output_proj_data_sptr->fill(0.0); -// info("ScatterSimulation: output projection data created."); -// } - - - // Note: horrible shift used for detection_points_vector - /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns - coordinate in a coordinate system where z=0 in the first ring of the scanner. - We want to shift this to a coordinate system where z=0 in the middle - of the scanner. - We can use get_m() as that uses the 'middle of the scanner' system. - (sorry) - */ +ScatterSimulation::set_up() { + if (is_null_ptr(proj_data_info_cyl_noarc_cor_sptr)) + error("ScatterSimulation: projection data info not set. Aborting."); + + if (!proj_data_info_cyl_noarc_cor_sptr->has_energy_information()) + error("ScatterSimulation: scanner energy resolution information not set. Aborting."); + + if (is_null_ptr(template_exam_info_sptr)) + error("ScatterSimulation: projection data info not set. Aborting."); + + if (!template_exam_info_sptr->has_energy_information()) + error("ScatterSimulation: template energy window information not set. Aborting."); + + if (is_null_ptr(activity_image_sptr)) + error("ScatterSimulation: activity image not set. Aborting."); + + if (is_null_ptr(density_image_sptr)) + error("ScatterSimulation: density image not set. Aborting."); + + if (downsample_scanner_bool) { + if (this->_already_set_up) + error("ScatterSimulation: set_up() called twice. This is currently not supported."); + + downsample_scanner(); + } + + if (is_null_ptr(density_image_for_scatter_points_sptr)) { + if (this->_already_set_up) + error("ScatterSimulation: set_up() called twice. This is currently not supported."); + downsample_density_image_for_scatter_points(zoom_xy, zoom_z, zoom_size_xy, zoom_size_z); + } + + // { + // this->output_proj_data_sptr.reset(new ProjDataInMemory(this->template_exam_info_sptr, + // this->proj_data_info_cyl_noarc_cor_sptr->create_shared_clone())); + // this->output_proj_data_sptr->fill(0.0); + // info("ScatterSimulation: output projection data created."); + // } + + // Note: horrible shift used for detection_points_vector + /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns + coordinate in a coordinate system where z=0 in the first ring of the scanner. + We want to shift this to a coordinate system where z=0 in the middle + of the scanner. + We can use get_m() as that uses the 'middle of the scanner' system. + (sorry) +*/ #ifndef NDEBUG - { - CartesianCoordinate3D detector_coord_A, detector_coord_B; - // check above statement - this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( - detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); - assert(detector_coord_A.z() == 0); - assert(detector_coord_B.z() == 0); - // check that get_m refers to the middle of the scanner - const float m_first = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); - const float m_last = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); - assert(fabs(m_last + m_first) < m_last * 10E-4); - } + { + CartesianCoordinate3D detector_coord_A, detector_coord_B; + // check above statement + this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, + Bin(0, 0, 0, 0)); + assert(detector_coord_A.z() == 0); + assert(detector_coord_B.z() == 0); + // check that get_m refers to the middle of the scanner + const float m_first = this->proj_data_info_cyl_noarc_cor_sptr->get_m( + Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); + const float m_last = this->proj_data_info_cyl_noarc_cor_sptr->get_m( + Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); + assert(fabs(m_last + m_first) < m_last * 10E-4); + } #endif - this->shift_detector_coordinates_to_origin = - CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); + this->shift_detector_coordinates_to_origin = + CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); #if 1 - // checks on image zooming to avvoid getting incorrect results - { - check_z_to_middle_consistent(*this->activity_image_sptr, "activity"); - check_z_to_middle_consistent(*this->density_image_sptr, "attenuation"); - check_z_to_middle_consistent(*this->density_image_for_scatter_points_sptr, "scatter-point"); - } + // checks on image zooming to avvoid getting incorrect results + { + check_z_to_middle_consistent(*this->activity_image_sptr, "activity"); + check_z_to_middle_consistent(*this->density_image_sptr, "attenuation"); + check_z_to_middle_consistent(*this->density_image_for_scatter_points_sptr, "scatter-point"); + } #endif - this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); - this->initialise_cache_for_scattpoint_det_integrals_over_activity(); + this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); + this->initialise_cache_for_scattpoint_det_integrals_over_activity(); - this->_already_set_up = true; + this->_already_set_up = true; - return Succeeded::yes; + return Succeeded::yes; } void -ScatterSimulation:: -check_z_to_middle_consistent(const DiscretisedDensity<3,float>& _image, const std::string& name) const -{ - const VoxelsOnCartesianGrid & image = dynamic_cast const& >(_image); - const float z_to_middle = - (image.get_max_index() + image.get_min_index())*image.get_voxel_size().z()/2.F; - -# if 0 +ScatterSimulation::check_z_to_middle_consistent(const DiscretisedDensity<3, float>& _image, const std::string& name) const { + const VoxelsOnCartesianGrid& image = dynamic_cast const&>(_image); + const float z_to_middle = (image.get_max_index() + image.get_min_index()) * image.get_voxel_size().z() / 2.F; + +#if 0 const Scanner& scanner = *this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr(); const float z_to_middle_standard = (scanner.get_num_rings()-1) * scanner.get_ring_spacing()/2; #endif - const VoxelsOnCartesianGrid & act_image = - dynamic_cast const& >(*this->activity_image_sptr); + const VoxelsOnCartesianGrid& act_image = dynamic_cast const&>(*this->activity_image_sptr); const float z_to_middle_standard = - (act_image.get_max_index() + act_image.get_min_index())*act_image.get_voxel_size().z()/2.F; + (act_image.get_max_index() + act_image.get_min_index()) * act_image.get_voxel_size().z() / 2.F; if (abs(z_to_middle - z_to_middle_standard) > .1) error(boost::format("ScatterSimulation: limitation in #planes and voxel-size for the %1% image.\n" "This would cause a shift of %2%mm w.r.t. the activity image.\n" - "(see https://github.com/UCL/STIR/issues/495.") - % name % (z_to_middle - z_to_middle_standard)); + "(see https://github.com/UCL/STIR/issues/495.") % + name % (z_to_middle - z_to_middle_standard)); } void -ScatterSimulation:: -set_activity_image_sptr(const shared_ptr > arg) -{ - if (is_null_ptr(arg) ) - error("ScatterSimulation: Unable to set the activity image"); +ScatterSimulation::set_activity_image_sptr(const shared_ptr> arg) { + if (is_null_ptr(arg)) + error("ScatterSimulation: Unable to set the activity image"); - this->activity_image_sptr = arg; - this->remove_cache_for_integrals_over_activity(); - this->_already_set_up = false; + this->activity_image_sptr = arg; + this->remove_cache_for_integrals_over_activity(); + this->_already_set_up = false; } void -ScatterSimulation:: -set_activity_image(const std::string& filename) -{ - this->activity_image_filename = filename; - shared_ptr > sptr(read_from_file >(filename)); - this->set_activity_image_sptr(sptr); +ScatterSimulation::set_activity_image(const std::string& filename) { + this->activity_image_filename = filename; + shared_ptr> sptr(read_from_file>(filename)); + this->set_activity_image_sptr(sptr); } void -ScatterSimulation:: -set_density_image_sptr(const shared_ptr > arg) -{ - if (is_null_ptr(arg) ) - error("ScatterSimulation: Unable to set the density image"); - this->density_image_sptr=arg; - // make sure that we're not re-using a previously interpolated image for scatter points - this->density_image_for_scatter_points_sptr.reset(); - this->remove_cache_for_integrals_over_attenuation(); - this->_already_set_up = false; +ScatterSimulation::set_density_image_sptr(const shared_ptr> arg) { + if (is_null_ptr(arg)) + error("ScatterSimulation: Unable to set the density image"); + this->density_image_sptr = arg; + // make sure that we're not re-using a previously interpolated image for scatter points + this->density_image_for_scatter_points_sptr.reset(); + this->remove_cache_for_integrals_over_attenuation(); + this->_already_set_up = false; } void -ScatterSimulation:: -set_density_image(const std::string& filename) -{ - this->density_image_filename=filename; - shared_ptr > sptr(read_from_file >(filename)); - this->set_density_image_sptr(sptr); +ScatterSimulation::set_density_image(const std::string& filename) { + this->density_image_filename = filename; + shared_ptr> sptr(read_from_file>(filename)); + this->set_density_image_sptr(sptr); } void -ScatterSimulation:: -set_density_image_for_scatter_points_sptr(shared_ptr > arg) -{ - if (is_null_ptr(arg) ) - error("ScatterSimulation: Unable to set the density image for scatter points."); - this->density_image_for_scatter_points_sptr.reset( - new VoxelsOnCartesianGrid(*dynamic_cast *>(arg.get()))); - this->sample_scatter_points(); - this->remove_cache_for_integrals_over_attenuation(); - this->_already_set_up = false; +ScatterSimulation::set_density_image_for_scatter_points_sptr(shared_ptr> arg) { + if (is_null_ptr(arg)) + error("ScatterSimulation: Unable to set the density image for scatter points."); + this->density_image_for_scatter_points_sptr.reset( + new VoxelsOnCartesianGrid(*dynamic_cast*>(arg.get()))); + this->sample_scatter_points(); + this->remove_cache_for_integrals_over_attenuation(); + this->_already_set_up = false; } -const DiscretisedDensity<3,float>& -ScatterSimulation:: -get_activity_image() const -{ - return *activity_image_sptr; +const DiscretisedDensity<3, float>& +ScatterSimulation::get_activity_image() const { + return *activity_image_sptr; } -const DiscretisedDensity<3,float>& -ScatterSimulation:: -get_attenuation_image() const -{ - return *density_image_sptr; +const DiscretisedDensity<3, float>& +ScatterSimulation::get_attenuation_image() const { + return *density_image_sptr; } -const DiscretisedDensity<3,float>& -ScatterSimulation:: -get_attenuation_image_for_scatter_points() const -{ - return *density_image_for_scatter_points_sptr; +const DiscretisedDensity<3, float>& +ScatterSimulation::get_attenuation_image_for_scatter_points() const { + return *density_image_for_scatter_points_sptr; } -shared_ptr > -ScatterSimulation:: -get_density_image_for_scatter_points_sptr() const -{ - return density_image_for_scatter_points_sptr; +shared_ptr> +ScatterSimulation::get_density_image_for_scatter_points_sptr() const { + return density_image_for_scatter_points_sptr; } void -ScatterSimulation:: -set_density_image_for_scatter_points(const std::string& filename) -{ - this->density_image_for_scatter_points_filename=filename; - shared_ptr > sptr(read_from_file >(filename)); - this->set_density_image_for_scatter_points_sptr(sptr); - this->_already_set_up = false; +ScatterSimulation::set_density_image_for_scatter_points(const std::string& filename) { + this->density_image_for_scatter_points_filename = filename; + shared_ptr> sptr(read_from_file>(filename)); + this->set_density_image_for_scatter_points_sptr(sptr); + this->_already_set_up = false; } void -ScatterSimulation:: -set_image_downsample_factors(float _zoom_xy, float _zoom_z, - int _size_zoom_xy, int _size_zoom_z) -{ - if (_zoom_xy<0.F || _zoom_z<0.F) - error("ScatterSimulation: at least one zoom factor for the scatter-point image is negative"); - zoom_xy = _zoom_xy; - zoom_z = _zoom_z; - zoom_size_xy = _size_zoom_xy; - zoom_size_z = _size_zoom_z; - _already_set_up = false; +ScatterSimulation::set_image_downsample_factors(float _zoom_xy, float _zoom_z, int _size_zoom_xy, int _size_zoom_z) { + if (_zoom_xy < 0.F || _zoom_z < 0.F) + error("ScatterSimulation: at least one zoom factor for the scatter-point image is negative"); + zoom_xy = _zoom_xy; + zoom_z = _zoom_z; + zoom_size_xy = _size_zoom_xy; + zoom_size_z = _size_zoom_z; + _already_set_up = false; } void -ScatterSimulation:: -downsample_density_image_for_scatter_points(float _zoom_xy, float _zoom_z, - int _size_xy, int _size_z) -{ - if (is_null_ptr(this->density_image_sptr)) - error("ScatterSimulation: downsampling function called before attenuation image is set"); - - const VoxelsOnCartesianGrid & tmp_att = dynamic_cast& >(*this->density_image_sptr); - - const int old_x = tmp_att.get_x_size(); - const int old_y = tmp_att.get_y_size(); - const int old_z = tmp_att.get_z_size(); - - if (_zoom_xy < 0 || _zoom_z < 0) - { - VoxelsOnCartesianGrid tmpl_density(this->density_image_sptr->get_exam_info_sptr(), *proj_data_info_cyl_noarc_cor_sptr); - info(boost::format("ScatterSimulation: template density to find zoom factors: voxel-sizes %1%, size %2%, product %3%") - % tmpl_density.get_voxel_size() - % tmpl_density.get_lengths() - % (tmpl_density.get_voxel_size() * BasicCoordinate<3,float>(tmpl_density.get_lengths())), - 3); - if (_zoom_xy < 0) - _zoom_xy = tmp_att.get_voxel_size().x() / tmpl_density.get_voxel_size().x(); - - const float z_length = - std::max((old_z+1)*tmp_att.get_voxel_size().z(), - (tmpl_density.get_z_size()+1)*tmpl_density.get_voxel_size().z()); - if (_zoom_z < 0) - { - if (_size_z < 0) - _size_z = (tmpl_density.get_z_size()+1)/2; - zoom_z = tmp_att.get_voxel_size().z() / (z_length/_size_z); - } - else - zoom_z = _zoom_z; - } - else +ScatterSimulation::downsample_density_image_for_scatter_points(float _zoom_xy, float _zoom_z, int _size_xy, int _size_z) { + if (is_null_ptr(this->density_image_sptr)) + error("ScatterSimulation: downsampling function called before attenuation image is set"); + + const VoxelsOnCartesianGrid& tmp_att = dynamic_cast&>(*this->density_image_sptr); + + const int old_x = tmp_att.get_x_size(); + const int old_y = tmp_att.get_y_size(); + const int old_z = tmp_att.get_z_size(); + + if (_zoom_xy < 0 || _zoom_z < 0) { + VoxelsOnCartesianGrid tmpl_density(this->density_image_sptr->get_exam_info_sptr(), *proj_data_info_cyl_noarc_cor_sptr); + info(boost::format("ScatterSimulation: template density to find zoom factors: voxel-sizes %1%, size %2%, product %3%") % + tmpl_density.get_voxel_size() % tmpl_density.get_lengths() % + (tmpl_density.get_voxel_size() * BasicCoordinate<3, float>(tmpl_density.get_lengths())), + 3); + if (_zoom_xy < 0) + _zoom_xy = tmp_att.get_voxel_size().x() / tmpl_density.get_voxel_size().x(); + + const float z_length = + std::max((old_z + 1) * tmp_att.get_voxel_size().z(), (tmpl_density.get_z_size() + 1) * tmpl_density.get_voxel_size().z()); + if (_zoom_z < 0) { + if (_size_z < 0) + _size_z = (tmpl_density.get_z_size() + 1) / 2; + zoom_z = tmp_att.get_voxel_size().z() / (z_length / _size_z); + } else zoom_z = _zoom_z; + } else + zoom_z = _zoom_z; - set_image_downsample_factors(_zoom_xy, zoom_z, _size_xy, _size_z); - - int new_x = zoom_size_xy == -1 ? static_cast(old_x * zoom_xy + 1) : zoom_size_xy; - int new_y = zoom_size_xy == -1 ? static_cast(old_y * zoom_xy + 1) : zoom_size_xy; - const int new_z = zoom_size_z == -1 ? static_cast(old_z * zoom_z + 1) : zoom_size_z; - - // make sizes odd to avoid edge effects and half-voxel shifts - if (new_x%2 == 0) - new_x++; - if (new_y%2 == 0) - new_y++; - - // adjust zoom_z to cope with ugly "shift to middle of scanner" problem - { - // see http://github.com/UCL/STIR/issues/495 - zoom_z = static_cast(new_z-1)/(old_z-1); - if (_zoom_z>0 && abs(zoom_z - _zoom_z)>.1) - error(boost::format("Current limitation in ScatterSimulation: use zoom_z==-1 or %1%") - % zoom_z); - } - - const CartesianCoordinate3D new_voxel_size = - tmp_att.get_voxel_size() / make_coordinate(zoom_z, zoom_xy, zoom_xy); - // create new image of appropriate size - shared_ptr > - vox_sptr(new VoxelsOnCartesianGrid(tmp_att.get_exam_info_sptr(), - IndexRange3D(0, new_z-1, - -new_y/2, -new_y/2+new_y-1, - -new_x/2, -new_x/2+new_x-1), - tmp_att.get_origin(), - new_voxel_size - )); - // assign to class member - this->density_image_for_scatter_points_sptr = vox_sptr; - info(boost::format("ScatterSimulation: scatter-point image: voxel-sizes %1%, size %2%, total-length %3%") - % vox_sptr->get_voxel_size() - % vox_sptr->get_lengths() - % (vox_sptr->get_voxel_size() * (BasicCoordinate<3,float>(vox_sptr->get_lengths()+1.F))), - 2); - // fill values from original attenuation image - ZoomOptions scaling(ZoomOptions::preserve_values); - zoom_image( *vox_sptr, tmp_att, scaling); + set_image_downsample_factors(_zoom_xy, zoom_z, _size_xy, _size_z); + + int new_x = zoom_size_xy == -1 ? static_cast(old_x * zoom_xy + 1) : zoom_size_xy; + int new_y = zoom_size_xy == -1 ? static_cast(old_y * zoom_xy + 1) : zoom_size_xy; + const int new_z = zoom_size_z == -1 ? static_cast(old_z * zoom_z + 1) : zoom_size_z; + + // make sizes odd to avoid edge effects and half-voxel shifts + if (new_x % 2 == 0) + new_x++; + if (new_y % 2 == 0) + new_y++; + + // adjust zoom_z to cope with ugly "shift to middle of scanner" problem + { + // see http://github.com/UCL/STIR/issues/495 + zoom_z = static_cast(new_z - 1) / (old_z - 1); + if (_zoom_z > 0 && abs(zoom_z - _zoom_z) > .1) + error(boost::format("Current limitation in ScatterSimulation: use zoom_z==-1 or %1%") % zoom_z); + } + + const CartesianCoordinate3D new_voxel_size = tmp_att.get_voxel_size() / make_coordinate(zoom_z, zoom_xy, zoom_xy); + // create new image of appropriate size + shared_ptr> vox_sptr(new VoxelsOnCartesianGrid( + tmp_att.get_exam_info_sptr(), + IndexRange3D(0, new_z - 1, -new_y / 2, -new_y / 2 + new_y - 1, -new_x / 2, -new_x / 2 + new_x - 1), tmp_att.get_origin(), + new_voxel_size)); + // assign to class member + this->density_image_for_scatter_points_sptr = vox_sptr; + info(boost::format("ScatterSimulation: scatter-point image: voxel-sizes %1%, size %2%, total-length %3%") % + vox_sptr->get_voxel_size() % vox_sptr->get_lengths() % + (vox_sptr->get_voxel_size() * (BasicCoordinate<3, float>(vox_sptr->get_lengths() + 1.F))), + 2); + // fill values from original attenuation image + ZoomOptions scaling(ZoomOptions::preserve_values); + zoom_image(*vox_sptr, tmp_att, scaling); #if 0 // do some checks @@ -631,324 +538,257 @@ downsample_density_image_for_scatter_points(float _zoom_xy, float _zoom_z, } #endif - if(this->density_image_for_scatter_points_output_filename.size()>0) - OutputFileFormat >::default_sptr()-> - write_to_file(density_image_for_scatter_points_output_filename, - *this->density_image_for_scatter_points_sptr); + if (this->density_image_for_scatter_points_output_filename.size() > 0) + OutputFileFormat>::default_sptr()->write_to_file( + density_image_for_scatter_points_output_filename, *this->density_image_for_scatter_points_sptr); - this->sample_scatter_points(); - this->remove_cache_for_integrals_over_attenuation(); - this->_already_set_up = false; + this->sample_scatter_points(); + this->remove_cache_for_integrals_over_attenuation(); + this->_already_set_up = false; } - void -ScatterSimulation:: -set_output_proj_data_sptr(const shared_ptr _exam, - const shared_ptr _info, - const std::string & filename) -{ - if (filename.size() > 0 ) - this->output_proj_data_sptr.reset(new ProjDataInterfile(_exam, - _info, - filename, - std::ios::in | std::ios::out | std::ios::trunc)); - else - this->output_proj_data_sptr.reset( new ProjDataInMemory(_exam, - _info)); +ScatterSimulation::set_output_proj_data_sptr(const shared_ptr _exam, const shared_ptr _info, + const std::string& filename) { + if (filename.size() > 0) + this->output_proj_data_sptr.reset( + new ProjDataInterfile(_exam, _info, filename, std::ios::in | std::ios::out | std::ios::trunc)); + else + this->output_proj_data_sptr.reset(new ProjDataInMemory(_exam, _info)); } shared_ptr -ScatterSimulation:: -get_output_proj_data_sptr() const -{ +ScatterSimulation::get_output_proj_data_sptr() const { - if(is_null_ptr(this->output_proj_data_sptr)) - { - error("ScatterSimulation: No output ProjData set. Aborting."); - } + if (is_null_ptr(this->output_proj_data_sptr)) { + error("ScatterSimulation: No output ProjData set. Aborting."); + } - return this->output_proj_data_sptr; + return this->output_proj_data_sptr; } void -ScatterSimulation:: -set_output_proj_data(const std::string& filename) -{ +ScatterSimulation::set_output_proj_data(const std::string& filename) { - if(is_null_ptr(this->proj_data_info_cyl_noarc_cor_sptr)) - { - error("ScatterSimulation: Template ProjData has not been set. Aborting."); - } + if (is_null_ptr(this->proj_data_info_cyl_noarc_cor_sptr)) { + error("ScatterSimulation: Template ProjData has not been set. Aborting."); + } - this->output_proj_data_filename = filename; - shared_ptr tmp_sptr; + this->output_proj_data_filename = filename; + shared_ptr tmp_sptr; - if (is_null_ptr(this->template_exam_info_sptr)) - { - shared_ptr exam_info_sptr(new ExamInfo); - tmp_sptr.reset(new ProjDataInterfile(exam_info_sptr, - this->proj_data_info_cyl_noarc_cor_sptr->create_shared_clone(), - this->output_proj_data_filename,std::ios::in | std::ios::out | std::ios::trunc)); - } - else - { - tmp_sptr.reset(new ProjDataInterfile(this->template_exam_info_sptr, - this->proj_data_info_cyl_noarc_cor_sptr->create_shared_clone(), - this->output_proj_data_filename,std::ios::in | std::ios::out | std::ios::trunc)); + if (is_null_ptr(this->template_exam_info_sptr)) { + shared_ptr exam_info_sptr(new ExamInfo); + tmp_sptr.reset(new ProjDataInterfile(exam_info_sptr, this->proj_data_info_cyl_noarc_cor_sptr->create_shared_clone(), + this->output_proj_data_filename, std::ios::in | std::ios::out | std::ios::trunc)); + } else { + tmp_sptr.reset(new ProjDataInterfile(this->template_exam_info_sptr, + this->proj_data_info_cyl_noarc_cor_sptr->create_shared_clone(), + this->output_proj_data_filename, std::ios::in | std::ios::out | std::ios::trunc)); + } - } - - set_output_proj_data_sptr(tmp_sptr); + set_output_proj_data_sptr(tmp_sptr); } - void -ScatterSimulation:: -set_output_proj_data_sptr(shared_ptr arg) -{ - this->output_proj_data_sptr = arg; +ScatterSimulation::set_output_proj_data_sptr(shared_ptr arg) { + this->output_proj_data_sptr = arg; } shared_ptr -ScatterSimulation:: -get_template_proj_data_info_sptr() const -{ - return this->proj_data_info_cyl_noarc_cor_sptr; +ScatterSimulation::get_template_proj_data_info_sptr() const { + return this->proj_data_info_cyl_noarc_cor_sptr; } shared_ptr -ScatterSimulation::get_exam_info_sptr() const -{ - return this->template_exam_info_sptr; +ScatterSimulation::get_exam_info_sptr() const { + return this->template_exam_info_sptr; } void -ScatterSimulation:: -set_template_proj_data_info(const std::string& filename) -{ - this->template_proj_data_filename = filename; - shared_ptr template_proj_data_sptr(ProjData::read_from_file(this->template_proj_data_filename)); +ScatterSimulation::set_template_proj_data_info(const std::string& filename) { + this->template_proj_data_filename = filename; + shared_ptr template_proj_data_sptr(ProjData::read_from_file(this->template_proj_data_filename)); - this->set_exam_info(template_proj_data_sptr->get_exam_info()); + this->set_exam_info(template_proj_data_sptr->get_exam_info()); - this->set_template_proj_data_info(*template_proj_data_sptr->get_proj_data_info_sptr()); + this->set_template_proj_data_info(*template_proj_data_sptr->get_proj_data_info_sptr()); } void -ScatterSimulation::set_template_proj_data_info(const ProjDataInfo& arg) -{ - this->_already_set_up = false; - this->proj_data_info_cyl_noarc_cor_sptr.reset(dynamic_cast(arg.clone())); +ScatterSimulation::set_template_proj_data_info(const ProjDataInfo& arg) { + this->_already_set_up = false; + this->proj_data_info_cyl_noarc_cor_sptr.reset(dynamic_cast(arg.clone())); - if (is_null_ptr(this->proj_data_info_cyl_noarc_cor_sptr)) - error("ScatterSimulation: Can only handle non-arccorrected data"); + if (is_null_ptr(this->proj_data_info_cyl_noarc_cor_sptr)) + error("ScatterSimulation: Can only handle non-arccorrected data"); - // find final size of detection_points_vector - this->total_detectors = - this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_num_rings()* - this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_num_detectors_per_ring (); + // find final size of detection_points_vector + this->total_detectors = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_num_rings() * + this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_num_detectors_per_ring(); - // get rid of any previously stored points - this->detection_points_vector.clear(); - // reserve space to avoid reallocation, but the actual size will grow dynamically - this->detection_points_vector.reserve(static_cast(this->total_detectors)); + // get rid of any previously stored points + this->detection_points_vector.clear(); + // reserve space to avoid reallocation, but the actual size will grow dynamically + this->detection_points_vector.reserve(static_cast(this->total_detectors)); - // set to negative value such that this will be recomputed - this->detector_efficiency_no_scatter = -1.F; + // set to negative value such that this will be recomputed + this->detector_efficiency_no_scatter = -1.F; - // remove any cached values as they'd be incorrect if the sizes changes - this->remove_cache_for_integrals_over_attenuation(); - this->remove_cache_for_integrals_over_activity(); + // remove any cached values as they'd be incorrect if the sizes changes + this->remove_cache_for_integrals_over_attenuation(); + this->remove_cache_for_integrals_over_activity(); } void -ScatterSimulation:: -set_exam_info(const ExamInfo& arg) -{ +ScatterSimulation::set_exam_info(const ExamInfo& arg) { this->_already_set_up = false; this->template_exam_info_sptr = arg.create_shared_clone(); } void -ScatterSimulation:: -set_exam_info_sptr(const shared_ptr arg) -{ - this->_already_set_up = false; - this->template_exam_info_sptr = arg->create_shared_clone(); +ScatterSimulation::set_exam_info_sptr(const shared_ptr arg) { + this->_already_set_up = false; + this->template_exam_info_sptr = arg->create_shared_clone(); } Succeeded -ScatterSimulation::downsample_scanner(int new_num_rings, int new_num_dets) -{ - if (new_num_rings <= 0) - { - if(downsample_scanner_rings > 0) - new_num_rings = downsample_scanner_rings; - else if (!is_null_ptr(proj_data_info_cyl_noarc_cor_sptr)) - { - const float total_axial_length = proj_data_info_cyl_noarc_cor_sptr->get_scanner_sptr()->get_num_rings() * - proj_data_info_cyl_noarc_cor_sptr->get_scanner_sptr()->get_ring_spacing(); - - new_num_rings = round(total_axial_length / 20.F + 0.5F); - } - else - return Succeeded::no; - } - if (new_num_dets <= 0) - { - if(downsample_scanner_dets > 0) - new_num_dets = downsample_scanner_dets; - else - return Succeeded::no; - } +ScatterSimulation::downsample_scanner(int new_num_rings, int new_num_dets) { + if (new_num_rings <= 0) { + if (downsample_scanner_rings > 0) + new_num_rings = downsample_scanner_rings; + else if (!is_null_ptr(proj_data_info_cyl_noarc_cor_sptr)) { + const float total_axial_length = proj_data_info_cyl_noarc_cor_sptr->get_scanner_sptr()->get_num_rings() * + proj_data_info_cyl_noarc_cor_sptr->get_scanner_sptr()->get_ring_spacing(); + + new_num_rings = round(total_axial_length / 20.F + 0.5F); + } else + return Succeeded::no; + } + if (new_num_dets <= 0) { + if (downsample_scanner_dets > 0) + new_num_dets = downsample_scanner_dets; + else + return Succeeded::no; + } - const Scanner *const old_scanner_ptr = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr(); - shared_ptr new_scanner_sptr( new Scanner(*old_scanner_ptr)); + const Scanner* const old_scanner_ptr = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr(); + shared_ptr new_scanner_sptr(new Scanner(*old_scanner_ptr)); - // preserve the length of the scanner - float scanner_length = new_scanner_sptr->get_num_rings()* new_scanner_sptr->get_ring_spacing(); + // preserve the length of the scanner + float scanner_length = new_scanner_sptr->get_num_rings() * new_scanner_sptr->get_ring_spacing(); - new_scanner_sptr->set_num_rings(new_num_rings); - new_scanner_sptr->set_num_detectors_per_ring(new_num_dets); - new_scanner_sptr->set_ring_spacing(static_cast(scanner_length/new_scanner_sptr->get_num_rings())); - const float approx_num_non_arccorrected_bins = - old_scanner_ptr->get_max_num_non_arccorrected_bins() * - (float(new_num_dets) / old_scanner_ptr->get_num_detectors_per_ring()) - + 5; // add 5 to avoid strange edge-effects, certainly with B-splines - new_scanner_sptr->set_max_num_non_arccorrected_bins(round(approx_num_non_arccorrected_bins+.5F)); - new_scanner_sptr->set_default_bin_size(new_scanner_sptr->get_effective_ring_radius() * _PI / new_num_dets); // approx new detector size + new_scanner_sptr->set_num_rings(new_num_rings); + new_scanner_sptr->set_num_detectors_per_ring(new_num_dets); + new_scanner_sptr->set_ring_spacing(static_cast(scanner_length / new_scanner_sptr->get_num_rings())); + const float approx_num_non_arccorrected_bins = old_scanner_ptr->get_max_num_non_arccorrected_bins() * + (float(new_num_dets) / old_scanner_ptr->get_num_detectors_per_ring()) + + 5; // add 5 to avoid strange edge-effects, certainly with B-splines + new_scanner_sptr->set_max_num_non_arccorrected_bins(round(approx_num_non_arccorrected_bins + .5F)); + new_scanner_sptr->set_default_bin_size(new_scanner_sptr->get_effective_ring_radius() * _PI / + new_num_dets); // approx new detector size - // Find how much is the delta ring - // If the previous projdatainfo had max segment == 1 then should be from SSRB - // in ScatterEstimation. Otherwise use the max possible. - int delta_ring = proj_data_info_cyl_noarc_cor_sptr->get_num_segments() == 1 ? 0 : - new_scanner_sptr->get_num_rings()-1; + // Find how much is the delta ring + // If the previous projdatainfo had max segment == 1 then should be from SSRB + // in ScatterEstimation. Otherwise use the max possible. + int delta_ring = proj_data_info_cyl_noarc_cor_sptr->get_num_segments() == 1 ? 0 : new_scanner_sptr->get_num_rings() - 1; - shared_ptr templ_proj_data_info_sptr( - ProjDataInfo::ProjDataInfoCTI(new_scanner_sptr, - 1, delta_ring, - new_scanner_sptr->get_num_detectors_per_ring()/2, - new_scanner_sptr->get_max_num_non_arccorrected_bins(), - false)); + shared_ptr templ_proj_data_info_sptr( + ProjDataInfo::ProjDataInfoCTI(new_scanner_sptr, 1, delta_ring, new_scanner_sptr->get_num_detectors_per_ring() / 2, + new_scanner_sptr->get_max_num_non_arccorrected_bins(), false)); - info(boost::format("ScatterSimulation: down-sampled scanner info:\n%1%") - % templ_proj_data_info_sptr->parameter_info(), - 3); - this->set_template_proj_data_info(*templ_proj_data_info_sptr); + info(boost::format("ScatterSimulation: down-sampled scanner info:\n%1%") % templ_proj_data_info_sptr->parameter_info(), 3); + this->set_template_proj_data_info(*templ_proj_data_info_sptr); - return Succeeded::yes; + return Succeeded::yes; } -Succeeded ScatterSimulation::downsample_images_to_scanner_size() -{ - if(is_null_ptr(proj_data_info_cyl_noarc_cor_sptr)) - return Succeeded::no; +Succeeded +ScatterSimulation::downsample_images_to_scanner_size() { + if (is_null_ptr(proj_data_info_cyl_noarc_cor_sptr)) + return Succeeded::no; - // Downsample the activity and attenuation images - shared_ptr > tmpl_image( new VoxelsOnCartesianGrid(*proj_data_info_cyl_noarc_cor_sptr)); + // Downsample the activity and attenuation images + shared_ptr> tmpl_image(new VoxelsOnCartesianGrid(*proj_data_info_cyl_noarc_cor_sptr)); - if(!is_null_ptr(activity_image_sptr)) - { - const VoxelsOnCartesianGrid* tmp_act = dynamic_cast* >(activity_image_sptr.get()); - VoxelsOnCartesianGrid* tmp = tmpl_image->get_empty_copy(); + if (!is_null_ptr(activity_image_sptr)) { + const VoxelsOnCartesianGrid* tmp_act = dynamic_cast*>(activity_image_sptr.get()); + VoxelsOnCartesianGrid* tmp = tmpl_image->get_empty_copy(); - ZoomOptions scaling(ZoomOptions::preserve_projections); - zoom_image(*tmp, *tmp_act, scaling); - activity_image_sptr.reset(tmp); + ZoomOptions scaling(ZoomOptions::preserve_projections); + zoom_image(*tmp, *tmp_act, scaling); + activity_image_sptr.reset(tmp); - this->remove_cache_for_integrals_over_activity(); - this->_already_set_up = false; - } + this->remove_cache_for_integrals_over_activity(); + this->_already_set_up = false; + } - if(!is_null_ptr(density_image_sptr)) - { - const VoxelsOnCartesianGrid* tmp_att = dynamic_cast* >(density_image_sptr.get()); - VoxelsOnCartesianGrid* tmp = tmpl_image->get_empty_copy(); + if (!is_null_ptr(density_image_sptr)) { + const VoxelsOnCartesianGrid* tmp_att = dynamic_cast*>(density_image_sptr.get()); + VoxelsOnCartesianGrid* tmp = tmpl_image->get_empty_copy(); - ZoomOptions scaling(ZoomOptions::preserve_values); - zoom_image(*tmp, *tmp_att, scaling); - density_image_sptr.reset(tmp); + ZoomOptions scaling(ZoomOptions::preserve_values); + zoom_image(*tmp, *tmp_att, scaling); + density_image_sptr.reset(tmp); - this->remove_cache_for_integrals_over_attenuation(); - this->_already_set_up = false; - } + this->remove_cache_for_integrals_over_attenuation(); + this->_already_set_up = false; + } - // zooming of density_image_for_scatter_points_sptr will happen in set_up + // zooming of density_image_for_scatter_points_sptr will happen in set_up - return Succeeded::yes; + return Succeeded::yes; } void -ScatterSimulation:: -set_attenuation_threshold(const float arg) -{ - attenuation_threshold = arg; - this->_already_set_up = false; +ScatterSimulation::set_attenuation_threshold(const float arg) { + attenuation_threshold = arg; + this->_already_set_up = false; } void -ScatterSimulation:: -set_randomly_place_scatter_points(const bool arg) -{ - randomly_place_scatter_points = arg; - this->_already_set_up = false; +ScatterSimulation::set_randomly_place_scatter_points(const bool arg) { + randomly_place_scatter_points = arg; + this->_already_set_up = false; } void -ScatterSimulation:: -set_cache_enabled(const bool arg) -{ - use_cache = arg; +ScatterSimulation::set_cache_enabled(const bool arg) { + use_cache = arg; } void -ScatterSimulation:: -write_log(const double simulation_time, - const float total_scatter) -{ - if (this->output_proj_data_filename.empty()) - return; - - std::string log_filename = - this->output_proj_data_filename + ".log"; - std::ofstream mystream(log_filename.c_str()); - - if (!mystream) - { - warning("Cannot open log file '%s'", log_filename.c_str()) ; - return; - } - - int axial_bins = 0 ; - - for (int segment_num = this->output_proj_data_sptr->get_min_segment_num(); - segment_num <= this->output_proj_data_sptr->get_max_segment_num(); - ++segment_num) - axial_bins += this->output_proj_data_sptr->get_num_axial_poss(segment_num); - - const int total_bins = - this->output_proj_data_sptr->get_num_views() * axial_bins * - this->output_proj_data_sptr->get_num_tangential_poss(); - mystream << this->parameter_info() - << "\nTotal simulation time elapsed: " - << simulation_time / 60 << "min" - << "\nTotal Scatter Points : " << scatt_points_vector.size() - << "\nTotal Scatter Counts (before upsampling and norm) : " << total_scatter - << "\nActivity image SIZE: " - << (*this->activity_image_sptr).size() << " * " - << (*this->activity_image_sptr)[0].size() << " * " // TODO relies on 0 index - << (*this->activity_image_sptr)[0][0].size() - << "\nAttenuation image for scatter points SIZE: " - << (*this->density_image_for_scatter_points_sptr).size() << " * " - << (*this->density_image_for_scatter_points_sptr)[0].size() << " * " - << (*this->density_image_for_scatter_points_sptr)[0][0].size() - << "\nTotal bins : " << total_bins << " = " - << this->output_proj_data_sptr->get_num_views() - << " view_bins * " - << axial_bins << " axial_bins * " - << this->output_proj_data_sptr->get_num_tangential_poss() - << " tangential_bins\n"; +ScatterSimulation::write_log(const double simulation_time, const float total_scatter) { + if (this->output_proj_data_filename.empty()) + return; + + std::string log_filename = this->output_proj_data_filename + ".log"; + std::ofstream mystream(log_filename.c_str()); + + if (!mystream) { + warning("Cannot open log file '%s'", log_filename.c_str()); + return; + } + + int axial_bins = 0; + + for (int segment_num = this->output_proj_data_sptr->get_min_segment_num(); + segment_num <= this->output_proj_data_sptr->get_max_segment_num(); ++segment_num) + axial_bins += this->output_proj_data_sptr->get_num_axial_poss(segment_num); + + const int total_bins = + this->output_proj_data_sptr->get_num_views() * axial_bins * this->output_proj_data_sptr->get_num_tangential_poss(); + mystream << this->parameter_info() << "\nTotal simulation time elapsed: " << simulation_time / 60 << "min" + << "\nTotal Scatter Points : " << scatt_points_vector.size() + << "\nTotal Scatter Counts (before upsampling and norm) : " << total_scatter + << "\nActivity image SIZE: " << (*this->activity_image_sptr).size() << " * " << (*this->activity_image_sptr)[0].size() + << " * " // TODO relies on 0 index + << (*this->activity_image_sptr)[0][0].size() + << "\nAttenuation image for scatter points SIZE: " << (*this->density_image_for_scatter_points_sptr).size() << " * " + << (*this->density_image_for_scatter_points_sptr)[0].size() << " * " + << (*this->density_image_for_scatter_points_sptr)[0][0].size() << "\nTotal bins : " << total_bins << " = " + << this->output_proj_data_sptr->get_num_views() << " view_bins * " << axial_bins << " axial_bins * " + << this->output_proj_data_sptr->get_num_tangential_poss() << " tangential_bins\n"; } END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/SingleScatterSimulation.cxx b/src/scatter_buildblock/SingleScatterSimulation.cxx index 91c81e5feb..867a61118b 100644 --- a/src/scatter_buildblock/SingleScatterSimulation.cxx +++ b/src/scatter_buildblock/SingleScatterSimulation.cxx @@ -18,104 +18,67 @@ START_NAMESPACE_STIR -const char * const -SingleScatterSimulation::registered_name = - "PET Single Scatter Simulation"; +const char* const SingleScatterSimulation::registered_name = "PET Single Scatter Simulation"; +SingleScatterSimulation::SingleScatterSimulation() : base_type() { this->set_defaults(); } -SingleScatterSimulation:: -SingleScatterSimulation() : - base_type() -{ - this->set_defaults(); -} - -SingleScatterSimulation:: -SingleScatterSimulation(const std::string& parameter_filename) -{ - this->initialise(parameter_filename); -} - -SingleScatterSimulation:: -~SingleScatterSimulation() -{} +SingleScatterSimulation::SingleScatterSimulation(const std::string& parameter_filename) { this->initialise(parameter_filename); } +SingleScatterSimulation::~SingleScatterSimulation() {} void -SingleScatterSimulation:: -initialise_keymap() -{ - base_type::initialise_keymap(); - this->parser.add_start_key("PET Single Scatter Simulation Parameters"); - this->parser.add_stop_key("end PET Single Scatter Simulation Parameters"); +SingleScatterSimulation::initialise_keymap() { + base_type::initialise_keymap(); + this->parser.add_start_key("PET Single Scatter Simulation Parameters"); + this->parser.add_stop_key("end PET Single Scatter Simulation Parameters"); } void -SingleScatterSimulation:: -initialise(const std::string& parameter_filename) -{ - if (parameter_filename.size() == 0) - { - this->set_defaults(); - this->ask_parameters(); - } - else - { - this->set_defaults(); - if (!this->parse(parameter_filename.c_str())) - { - error("Error parsing input file %s, exiting", parameter_filename.c_str()); - } +SingleScatterSimulation::initialise(const std::string& parameter_filename) { + if (parameter_filename.size() == 0) { + this->set_defaults(); + this->ask_parameters(); + } else { + this->set_defaults(); + if (!this->parse(parameter_filename.c_str())) { + error("Error parsing input file %s, exiting", parameter_filename.c_str()); } + } } void -SingleScatterSimulation:: -set_defaults() -{ - base_type::set_defaults(); +SingleScatterSimulation::set_defaults() { + base_type::set_defaults(); } Succeeded -SingleScatterSimulation:: -set_up() -{ - // set to negative value such that this will be recomputed - this->max_single_scatter_cos_angle = -1.F; +SingleScatterSimulation::set_up() { + // set to negative value such that this will be recomputed + this->max_single_scatter_cos_angle = -1.F; - return base_type::set_up(); + return base_type::set_up(); } Succeeded -SingleScatterSimulation:: -process_data() -{ - return base_type::process_data(); +SingleScatterSimulation::process_data() { + return base_type::process_data(); } void -SingleScatterSimulation:: -ask_parameters() -{ - base_type::ask_parameters(); +SingleScatterSimulation::ask_parameters() { + base_type::ask_parameters(); } bool -SingleScatterSimulation:: -post_processing() -{ - if (!base_type::post_processing()) - return false; - return true; +SingleScatterSimulation::post_processing() { + if (!base_type::post_processing()) + return false; + return true; } std::string -SingleScatterSimulation:: -method_info() const -{ - return this->registered_name; +SingleScatterSimulation::method_info() const { + return this->registered_name; } - END_NAMESPACE_STIR - diff --git a/src/scatter_buildblock/cached_single_scatter_integrals.cxx b/src/scatter_buildblock/cached_single_scatter_integrals.cxx index 02757aa724..054110b174 100644 --- a/src/scatter_buildblock/cached_single_scatter_integrals.cxx +++ b/src/scatter_buildblock/cached_single_scatter_integrals.cxx @@ -11,7 +11,7 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + GNU Lesser General Public License for more details. See STIR/LICENSE.txt for details */ /*! @@ -19,7 +19,7 @@ \ingroup scatter \brief Implementations of functions defined in stir::ScatterEstimationByBin - Functions calculate the integral along LOR in an image (attenuation or emission). + Functions calculate the integral along LOR in an image (attenuation or emission). (from scatter point to detector coordinate). \author Charalampos Tsoumpas @@ -27,7 +27,7 @@ \author Kris Thielemans */ #include "stir/scatter/ScatterSimulation.h" -#include "stir/IndexRange.h" +#include "stir/IndexRange.h" #include "stir/Coordinate2D.h" START_NAMESPACE_STIR @@ -35,47 +35,36 @@ START_NAMESPACE_STIR const float cache_init_value = -1234567.89E10F; // an arbitrary value that should never occur void -ScatterSimulation:: -remove_cache_for_integrals_over_attenuation() -{ +ScatterSimulation::remove_cache_for_integrals_over_attenuation() { this->cached_attenuation_integral_scattpoint_det.recycle(); } void -ScatterSimulation:: -remove_cache_for_integrals_over_activity() -{ +ScatterSimulation::remove_cache_for_integrals_over_activity() { this->cached_activity_integral_scattpoint_det.recycle(); } - void -ScatterSimulation:: -initialise_cache_for_scattpoint_det_integrals_over_attenuation() -{ +ScatterSimulation::initialise_cache_for_scattpoint_det_integrals_over_attenuation() { if (!this->use_cache) return; - const IndexRange<2> range (Coordinate2D (0,0), - Coordinate2D (static_cast(this->scatt_points_vector.size()-1), - this->total_detectors-1)); + const IndexRange<2> range(Coordinate2D(0, 0), + Coordinate2D(static_cast(this->scatt_points_vector.size() - 1), this->total_detectors - 1)); if (this->cached_attenuation_integral_scattpoint_det.get_index_range() == range) - return; // keep cache if correct size + return; // keep cache if correct size this->cached_attenuation_integral_scattpoint_det.resize(range); this->cached_attenuation_integral_scattpoint_det.fill(cache_init_value); } void -ScatterSimulation:: -initialise_cache_for_scattpoint_det_integrals_over_activity() -{ +ScatterSimulation::initialise_cache_for_scattpoint_det_integrals_over_activity() { if (!this->use_cache) return; - const IndexRange<2> range (Coordinate2D (0,0), - Coordinate2D (static_cast(this->scatt_points_vector.size()-1), - this->total_detectors-1)); + const IndexRange<2> range(Coordinate2D(0, 0), + Coordinate2D(static_cast(this->scatt_points_vector.size() - 1), this->total_detectors - 1)); if (this->cached_activity_integral_scattpoint_det.get_index_range() == range) return; // keep cache if correct size @@ -84,15 +73,10 @@ initialise_cache_for_scattpoint_det_integrals_over_activity() this->cached_activity_integral_scattpoint_det.fill(cache_init_value); } -float -ScatterSimulation:: -cached_integral_over_activity_image_between_scattpoint_det(const unsigned scatter_point_num, - const unsigned det_num) -{ - float * location_in_cache = - this->use_cache - ? &cached_activity_integral_scattpoint_det[scatter_point_num][det_num] - : 0; +float +ScatterSimulation::cached_integral_over_activity_image_between_scattpoint_det(const unsigned scatter_point_num, + const unsigned det_num) { + float* location_in_cache = this->use_cache ? &cached_activity_integral_scattpoint_det[scatter_point_num][det_num] : 0; /* OPENMP note: We use atomic read/write to get at the cache. This should ensure validity. @@ -102,96 +86,79 @@ cached_integral_over_activity_image_between_scattpoint_det(const unsigned scatte */ float value; #if defined(STIR_OPENMP) -# if _OPENMP >=201012 -# pragma omp atomic read -# else -# pragma omp critical(STIRSCATTERESTIMATIONCACHE) +# if _OPENMP >= 201012 +# pragma omp atomic read +# else +# pragma omp critical(STIRSCATTERESTIMATIONCACHE) { -# endif +# endif #endif value = *location_in_cache; -#if defined(STIR_OPENMP) && (_OPENMP <201012) - } +#if defined(STIR_OPENMP) && (_OPENMP < 201012) +} #endif - if (this->use_cache && value!=cache_init_value) - { - return value; - } - else - { - const float result = - integral_over_activity_image_between_scattpoint_det - (scatt_points_vector[scatter_point_num].coord, - detection_points_vector[det_num] - ); - if (this->use_cache) +if (this->use_cache && value != cache_init_value) { + return value; +} else { + const float result = integral_over_activity_image_between_scattpoint_det(scatt_points_vector[scatter_point_num].coord, + detection_points_vector[det_num]); + if (this->use_cache) #ifdef STIR_OPENMP -# if _OPENMP >=201012 -# pragma omp atomic write -# else -# pragma omp critical(STIRSCATTERESTIMATIONCACHE) - { -# endif +# if _OPENMP >= 201012 +# pragma omp atomic write +# else +# pragma omp critical(STIRSCATTERESTIMATIONCACHE) + { +# endif #endif - *location_in_cache=result; -#if defined(STIR_OPENMP) && (_OPENMP <201012) - } + *location_in_cache = result; +#if defined(STIR_OPENMP) && (_OPENMP < 201012) +} #endif - return result; - } +return result; +} } -float -ScatterSimulation:: -cached_exp_integral_over_attenuation_image_between_scattpoint_det(const unsigned scatter_point_num, - const unsigned det_num) -{ - float * location_in_cache = - this->use_cache - ? &cached_attenuation_integral_scattpoint_det[scatter_point_num][det_num] - : 0; +float +ScatterSimulation::cached_exp_integral_over_attenuation_image_between_scattpoint_det(const unsigned scatter_point_num, + const unsigned det_num) { + float* location_in_cache = this->use_cache ? &cached_attenuation_integral_scattpoint_det[scatter_point_num][det_num] : 0; float value; #if defined(STIR_OPENMP) -# if _OPENMP >=201012 -# pragma omp atomic read -# else -# pragma omp critical(STIRSCATTERESTIMATIONREADCACHEATTENINT) +# if _OPENMP >= 201012 +# pragma omp atomic read +# else +# pragma omp critical(STIRSCATTERESTIMATIONREADCACHEATTENINT) { -# endif +# endif #endif value = *location_in_cache; -#if defined(STIR_OPENMP) && (_OPENMP <201012) - } +#if defined(STIR_OPENMP) && (_OPENMP < 201012) +} #endif - if (this->use_cache && value!=cache_init_value) - { - return *location_in_cache; - } - else - { - const float result = - exp_integral_over_attenuation_image_between_scattpoint_det - (scatt_points_vector[scatter_point_num].coord, - detection_points_vector[det_num] - ); - if (this->use_cache) +if (this->use_cache && value != cache_init_value) { + return *location_in_cache; +} else { + const float result = exp_integral_over_attenuation_image_between_scattpoint_det(scatt_points_vector[scatter_point_num].coord, + detection_points_vector[det_num]); + if (this->use_cache) #ifdef STIR_OPENMP -# if _OPENMP >=201012 -# pragma omp atomic write -# else -# pragma omp critical(STIRSCATTERESTIMATIONREADCACHEATTENINT) - { -# endif +# if _OPENMP >= 201012 +# pragma omp atomic write +# else +# pragma omp critical(STIRSCATTERESTIMATIONREADCACHEATTENINT) + { +# endif #endif - *location_in_cache=result; -#if defined(STIR_OPENMP) && (_OPENMP <201012) - } + *location_in_cache = result; +#if defined(STIR_OPENMP) && (_OPENMP < 201012) +} #endif - return result; - } +return result; +} } - + END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/extradebug.cxx b/src/scatter_buildblock/extradebug.cxx index 3672aaa60a..56b1fcfe7e 100644 --- a/src/scatter_buildblock/extradebug.cxx +++ b/src/scatter_buildblock/extradebug.cxx @@ -1,61 +1,55 @@ #ifndef NDEBUGXXX - { - { - const VoxelsOnCartesianGrid& image = dynamic_cast&>(*activity_image_sptr); - const CartesianCoordinate3D voxel_size = image.get_grid_spacing(); - CartesianCoordinate3D origin = - image.get_origin(); - const float z_to_middle = - (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; - origin.z() -= z_to_middle; - /* TODO replace with image.get_index_coordinates_for_physical_coordinates */ - info(boost::format("first/last z for activity image after shift: %1%/%2%") - % (origin.z() + image.get_min_index()*voxel_size.z()) % (origin.z() + image.get_max_index()*voxel_size.z())); - } - { - const VoxelsOnCartesianGrid& image = dynamic_cast&>(*density_image_sptr); - const CartesianCoordinate3D voxel_size = image.get_grid_spacing(); - CartesianCoordinate3D origin = - image.get_origin(); - const float z_to_middle = - (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; - origin.z() -= z_to_middle; - /* TODO replace with image.get_index_coordinates_for_physical_coordinates */ - info(boost::format("first/last z for attenuation image after shift: %1%/%2%") - % (origin.z() + image.get_min_index()*voxel_size.z()) % (origin.z() + image.get_max_index()*voxel_size.z())); - } - { - const VoxelsOnCartesianGrid& image = dynamic_cast&>(*get_density_image_for_scatter_points_sptr()); - const CartesianCoordinate3D voxel_size = image.get_grid_spacing(); - CartesianCoordinate3D origin = - image.get_origin(); - const float z_to_middle = - (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; - origin.z() -= z_to_middle; - /* TODO replace with image.get_index_coordinates_for_physical_coordinates */ - info(boost::format("first/last z for scatter-point image after shift: %1%/%2%") - % (origin.z() + image.get_min_index()*voxel_size.z()) % (origin.z() + image.get_max_index()*voxel_size.z())); - } - { - unsigned det_num_A, det_num_B; - find_detectors(det_num_A, det_num_B, Bin(0,0,this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0),0)); - const float first = detection_points_vector[det_num_A].z(); - find_detectors(det_num_A, det_num_B, Bin(0,0,this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0),0)); - const float last = detection_points_vector[det_num_A].z(); - info(boost::format("first/last z for detectors after shift: %1%/%2%") - % first % last); - } - } +{ + { + const VoxelsOnCartesianGrid& image = dynamic_cast&>(*activity_image_sptr); + const CartesianCoordinate3D voxel_size = image.get_grid_spacing(); + CartesianCoordinate3D origin = image.get_origin(); + const float z_to_middle = (image.get_max_index() + image.get_min_index()) * voxel_size.z() / 2.F; + origin.z() -= z_to_middle; + /* TODO replace with image.get_index_coordinates_for_physical_coordinates */ + info(boost::format("first/last z for activity image after shift: %1%/%2%") % + (origin.z() + image.get_min_index() * voxel_size.z()) % (origin.z() + image.get_max_index() * voxel_size.z())); + } + { + const VoxelsOnCartesianGrid& image = dynamic_cast&>(*density_image_sptr); + const CartesianCoordinate3D voxel_size = image.get_grid_spacing(); + CartesianCoordinate3D origin = image.get_origin(); + const float z_to_middle = (image.get_max_index() + image.get_min_index()) * voxel_size.z() / 2.F; + origin.z() -= z_to_middle; + /* TODO replace with image.get_index_coordinates_for_physical_coordinates */ + info(boost::format("first/last z for attenuation image after shift: %1%/%2%") % + (origin.z() + image.get_min_index() * voxel_size.z()) % (origin.z() + image.get_max_index() * voxel_size.z())); + } + { + const VoxelsOnCartesianGrid& image = + dynamic_cast&>(*get_density_image_for_scatter_points_sptr()); + const CartesianCoordinate3D voxel_size = image.get_grid_spacing(); + CartesianCoordinate3D origin = image.get_origin(); + const float z_to_middle = (image.get_max_index() + image.get_min_index()) * voxel_size.z() / 2.F; + origin.z() -= z_to_middle; + /* TODO replace with image.get_index_coordinates_for_physical_coordinates */ + info(boost::format("first/last z for scatter-point image after shift: %1%/%2%") % + (origin.z() + image.get_min_index() * voxel_size.z()) % (origin.z() + image.get_max_index() * voxel_size.z())); + } + { + unsigned det_num_A, det_num_B; + find_detectors(det_num_A, det_num_B, Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); + const float first = detection_points_vector[det_num_A].z(); + find_detectors(det_num_A, det_num_B, Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); + const float last = detection_points_vector[det_num_A].z(); + info(boost::format("first/last z for detectors after shift: %1%/%2%") % first % last); + } +} #endif - - sample #ifndef NDEBUG - { - const CartesianCoordinate3D first = voxel_size*convert_int_to_float(min_index) + origin; - const CartesianCoordinate3D last = voxel_size*convert_int_to_float(max_index) + origin; - info(boost::format("Coordinates of centre of first and last voxel of scatter-point image after shifting to centre of scanner: %1% / %2% centre %3%") - % first % last % ((first+last)/2)); - } +{ + const CartesianCoordinate3D first = voxel_size * convert_int_to_float(min_index) + origin; + const CartesianCoordinate3D last = voxel_size * convert_int_to_float(max_index) + origin; + info(boost::format("Coordinates of centre of first and last voxel of scatter-point image after shifting to centre of scanner: " + "%1% / %2% centre %3%") % + first % last % ((first + last) / 2)); +} #endif diff --git a/src/scatter_buildblock/sample_scatter_points.cxx b/src/scatter_buildblock/sample_scatter_points.cxx index b27c5c257c..ec5d84154a 100644 --- a/src/scatter_buildblock/sample_scatter_points.cxx +++ b/src/scatter_buildblock/sample_scatter_points.cxx @@ -12,8 +12,8 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! @@ -34,68 +34,58 @@ using namespace std; START_NAMESPACE_STIR -static inline float random_point(const float low, const float high) -{ +static inline float +random_point(const float low, const float high) { /* returns a pseudo random number which holds in the bounds low and high */ - const float result= (rand()*(high-low))/RAND_MAX + low; + const float result = (rand() * (high - low)) / RAND_MAX + low; assert(low <= result); assert(high >= result); return result; } void -ScatterSimulation:: -sample_scatter_points() -{ +ScatterSimulation::sample_scatter_points() { - const DiscretisedDensityOnCartesianGrid<3,float>& attenuation_map = - dynamic_cast& > - (*this->density_image_for_scatter_points_sptr); + const DiscretisedDensityOnCartesianGrid<3, float>& attenuation_map = + dynamic_cast&>(*this->density_image_for_scatter_points_sptr); - BasicCoordinate<3,int> min_index, max_index ; + BasicCoordinate<3, int> min_index, max_index; CartesianCoordinate3D coord; - if(!this->density_image_for_scatter_points_sptr->get_regular_range(min_index, max_index)) - error("scatter points sampling works only on regular ranges, at the moment\n"); - const VoxelsOnCartesianGrid& image = - dynamic_cast&>(attenuation_map); - const CartesianCoordinate3D voxel_size = image.get_voxel_size(); - CartesianCoordinate3D origin = image.get_origin(); + if (!this->density_image_for_scatter_points_sptr->get_regular_range(min_index, max_index)) + error("scatter points sampling works only on regular ranges, at the moment\n"); + const VoxelsOnCartesianGrid& image = dynamic_cast&>(attenuation_map); + const CartesianCoordinate3D voxel_size = image.get_voxel_size(); + CartesianCoordinate3D origin = image.get_origin(); // shift origin such that we refer to the middle of the scanner // this is to be consistent with projector conventions // TODO use class function once it exists - const float z_to_middle = - (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; + const float z_to_middle = (image.get_max_index() + image.get_min_index()) * voxel_size.z() / 2.F; origin.z() -= z_to_middle; - this->scatter_volume = voxel_size[1]*voxel_size[2]*voxel_size[3]; + this->scatter_volume = voxel_size[1] * voxel_size[2] * voxel_size[3]; - if(this->randomly_place_scatter_points) - { // Initialize Pseudo Random Number generator using time - srand((unsigned)time( NULL )); - } + if (this->randomly_place_scatter_points) { // Initialize Pseudo Random Number generator using time + srand((unsigned)time(NULL)); + } this->scatt_points_vector.resize(0); // make sure we don't keep scatter points from a previous run - this->scatt_points_vector.reserve(1000); + this->scatt_points_vector.reserve(1000); - // coord[] is in voxels units - for(coord[1]=min_index[1];coord[1]<=max_index[1];++coord[1]) - for(coord[2]=min_index[2];coord[2]<=max_index[2];++coord[2]) - for(coord[3]=min_index[3];coord[3]<=max_index[3];++coord[3]) - if(attenuation_map[coord] >= this->attenuation_threshold) - { - ScatterPoint scatter_point; - scatter_point.coord = convert_int_to_float(coord); - if (randomly_place_scatter_points) - scatter_point.coord += - CartesianCoordinate3D(random_point(-.5,.5), - random_point(-.5,.5), - random_point(-.5,.5)); - scatter_point.coord = - voxel_size*scatter_point.coord + origin; - scatter_point.mu_value = attenuation_map[coord]; - this->scatt_points_vector.push_back(scatter_point); - } + // coord[] is in voxels units + for (coord[1] = min_index[1]; coord[1] <= max_index[1]; ++coord[1]) + for (coord[2] = min_index[2]; coord[2] <= max_index[2]; ++coord[2]) + for (coord[3] = min_index[3]; coord[3] <= max_index[3]; ++coord[3]) + if (attenuation_map[coord] >= this->attenuation_threshold) { + ScatterPoint scatter_point; + scatter_point.coord = convert_int_to_float(coord); + if (randomly_place_scatter_points) + scatter_point.coord += + CartesianCoordinate3D(random_point(-.5, .5), random_point(-.5, .5), random_point(-.5, .5)); + scatter_point.coord = voxel_size * scatter_point.coord + origin; + scatter_point.mu_value = attenuation_map[coord]; + this->scatt_points_vector.push_back(scatter_point); + } this->remove_cache_for_integrals_over_activity(); this->remove_cache_for_integrals_over_attenuation(); info(boost::format("ScatterSimulation: using %1% scatter points") % this->scatt_points_vector.size(), 2); } -END_NAMESPACE_STIR +END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index ad6124560f..f4f8f10d89 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -12,7 +12,7 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + GNU Lesser General Public License for more details. See STIR/LICENSE.txt for details */ @@ -35,155 +35,112 @@ #include START_NAMESPACE_STIR -unsigned -ScatterSimulation:: -find_in_detection_points_vector(const CartesianCoordinate3D& coord) const -{ +unsigned +ScatterSimulation::find_in_detection_points_vector(const CartesianCoordinate3D& coord) const { #ifndef NDEBUG if (!this->_already_set_up) - error("ScatterSimulation::find_detectors: need to call set_up() first"); + error("ScatterSimulation::find_detectors: need to call set_up() first"); #endif unsigned int ret_value = 0; #pragma omp critical(SCATTERESTIMATIONFINDDETECTIONPOINTS) { - std::vector >::const_iterator iter= - std::find(detection_points_vector.begin(), - detection_points_vector.end(), - coord); - if (iter != detection_points_vector.end()) - { - ret_value = iter-detection_points_vector.begin(); - } - else - { - if (detection_points_vector.size()==static_cast(this->total_detectors)) + std::vector>::const_iterator iter = + std::find(detection_points_vector.begin(), detection_points_vector.end(), coord); + if (iter != detection_points_vector.end()) { + ret_value = iter - detection_points_vector.begin(); + } else { + if (detection_points_vector.size() == static_cast(this->total_detectors)) error("More detection points than we think there are!\n"); detection_points_vector.push_back(coord); - ret_value = detection_points_vector.size()-1; + ret_value = detection_points_vector.size() - 1; } } return ret_value; } void -ScatterSimulation:: -find_detectors(unsigned& det_num_A, unsigned& det_num_B, const Bin& bin) const -{ +ScatterSimulation::find_detectors(unsigned& det_num_A, unsigned& det_num_B, const Bin& bin) const { #ifndef NDEBUG if (!this->_already_set_up) - error("ScatterSimulation::find_detectors: need to call set_up() first"); + error("ScatterSimulation::find_detectors: need to call set_up() first"); #endif CartesianCoordinate3D detector_coord_A, detector_coord_B; - this->proj_data_info_cyl_noarc_cor_sptr-> - find_cartesian_coordinates_of_detection( - detector_coord_A,detector_coord_B,bin); - det_num_A = - this->find_in_detection_points_vector(detector_coord_A + - this->shift_detector_coordinates_to_origin); - det_num_B = - this->find_in_detection_points_vector(detector_coord_B + - this->shift_detector_coordinates_to_origin); + this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, bin); + det_num_A = this->find_in_detection_points_vector(detector_coord_A + this->shift_detector_coordinates_to_origin); + det_num_B = this->find_in_detection_points_vector(detector_coord_B + this->shift_detector_coordinates_to_origin); } float -ScatterSimulation:: -compute_emis_to_det_points_solid_angle_factor( - const CartesianCoordinate3D& emis_point, - const CartesianCoordinate3D& detector_coord) -{ - - const CartesianCoordinate3D dist_vector = emis_point - detector_coord ; - +ScatterSimulation::compute_emis_to_det_points_solid_angle_factor(const CartesianCoordinate3D& emis_point, + const CartesianCoordinate3D& detector_coord) { + + const CartesianCoordinate3D dist_vector = emis_point - detector_coord; const float dist_emis_det_squared = norm_squared(dist_vector); - const float emis_det_solid_angle_factor = 1.F/ dist_emis_det_squared ; + const float emis_det_solid_angle_factor = 1.F / dist_emis_det_squared; - return emis_det_solid_angle_factor ; + return emis_det_solid_angle_factor; } float -ScatterSimulation:: -detection_efficiency(const float energy) const -{ +ScatterSimulation::detection_efficiency(const float energy) const { #ifndef NDEBUG if (!this->_already_set_up) - error("ScatterSimulation::find_detectors: need to call set_up() first"); + error("ScatterSimulation::find_detectors: need to call set_up() first"); #endif // factor 2.35482 is used to convert FWHM to sigma - const float sigma_times_sqrt2= - sqrt(2.*energy*this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_reference_energy())* - this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()/2.35482f; // 2.35482=2 * sqrt( 2 * ( log(2) ) - - // sigma_times_sqrt2= sqrt(2) * sigma // resolution proportional to FWHM - - const float efficiency = - 0.5f*( erf((this->template_exam_info_sptr->get_high_energy_thres()-energy)/sigma_times_sqrt2) - - erf((this->template_exam_info_sptr->get_low_energy_thres()-energy)/sigma_times_sqrt2 )); + const float sigma_times_sqrt2 = + sqrt(2. * energy * this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_reference_energy()) * + this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution() / + 2.35482f; // 2.35482=2 * sqrt( 2 * ( log(2) ) + + // sigma_times_sqrt2= sqrt(2) * sigma // resolution proportional to FWHM + + const float efficiency = 0.5f * (erf((this->template_exam_info_sptr->get_high_energy_thres() - energy) / sigma_times_sqrt2) - + erf((this->template_exam_info_sptr->get_low_energy_thres() - energy) / sigma_times_sqrt2)); /* Maximum efficiency is 1.*/ return efficiency; } float -ScatterSimulation:: -max_cos_angle(const float low, const float approx, const float resolution_at_511keV) -{ - return - 2.f - (8176.*log(2.))/(square(approx*resolution_at_511keV)*(511. + (16.*low*log(2.))/square(approx*resolution_at_511keV) - - sqrt(511.)*sqrt(511. + (32.*low*log(2.))/square(approx*resolution_at_511keV)))) ; +ScatterSimulation::max_cos_angle(const float low, const float approx, const float resolution_at_511keV) { + return 2.f - (8176. * log(2.)) / (square(approx * resolution_at_511keV) * + (511. + (16. * low * log(2.)) / square(approx * resolution_at_511keV) - + sqrt(511.) * sqrt(511. + (32. * low * log(2.)) / square(approx * resolution_at_511keV)))); } - float -ScatterSimulation:: -energy_lower_limit(const float low, const float approx, const float resolution_at_511keV) -{ - return - low + (approx*resolution_at_511keV)*(approx*resolution_at_511keV)*(46.0761 - 2.03829*sqrt(22.1807*low/square(approx*resolution_at_511keV)+511.)); +ScatterSimulation::energy_lower_limit(const float low, const float approx, const float resolution_at_511keV) { + return low + (approx * resolution_at_511keV) * (approx * resolution_at_511keV) * + (46.0761 - 2.03829 * sqrt(22.1807 * low / square(approx * resolution_at_511keV) + 511.)); } double -ScatterSimulation:: -detection_efficiency_no_scatter(const unsigned det_num_A, - const unsigned det_num_B) const -{ +ScatterSimulation::detection_efficiency_no_scatter(const unsigned det_num_A, const unsigned det_num_B) const { #ifndef NDEBUG if (!this->_already_set_up) - error("ScatterSimulation::find_detectors: need to call set_up() first"); + error("ScatterSimulation::find_detectors: need to call set_up() first"); #endif if (detector_efficiency_no_scatter <= 0.F) // set to negative value by set_up(), so recompute - { - detector_efficiency_no_scatter = - detection_efficiency(511.F) > 0 - ? detection_efficiency(511.F) - : (info("Zero detection efficiency for 511. Will normalise to 1"), 1.F); - } - const CartesianCoordinate3D& detector_coord_A = - detection_points_vector[det_num_A]; - const CartesianCoordinate3D& detector_coord_B = - detection_points_vector[det_num_B]; - const CartesianCoordinate3D - detA_to_ring_center(0,-detector_coord_A[2],-detector_coord_A[3]); - const CartesianCoordinate3D - detB_to_ring_center(0,-detector_coord_B[2],-detector_coord_B[3]); - const float rAB_squared=static_cast(norm_squared(detector_coord_A-detector_coord_B)); - const float cos_incident_angle_A = static_cast( - cos_angle(detector_coord_B - detector_coord_A, - detA_to_ring_center)) ; - const float cos_incident_angle_B = static_cast( - cos_angle(detector_coord_A - detector_coord_B, - detB_to_ring_center)) ; - - //0.75 is due to the volume of the pyramid approximation! - return - 1./( 0.75/2./_PI * - rAB_squared - /detector_efficiency_no_scatter/ - (cos_incident_angle_A* - cos_incident_angle_B)); + { + detector_efficiency_no_scatter = detection_efficiency(511.F) > 0 + ? detection_efficiency(511.F) + : (info("Zero detection efficiency for 511. Will normalise to 1"), 1.F); + } + const CartesianCoordinate3D& detector_coord_A = detection_points_vector[det_num_A]; + const CartesianCoordinate3D& detector_coord_B = detection_points_vector[det_num_B]; + const CartesianCoordinate3D detA_to_ring_center(0, -detector_coord_A[2], -detector_coord_A[3]); + const CartesianCoordinate3D detB_to_ring_center(0, -detector_coord_B[2], -detector_coord_B[3]); + const float rAB_squared = static_cast(norm_squared(detector_coord_A - detector_coord_B)); + const float cos_incident_angle_A = static_cast(cos_angle(detector_coord_B - detector_coord_A, detA_to_ring_center)); + const float cos_incident_angle_B = static_cast(cos_angle(detector_coord_A - detector_coord_B, detB_to_ring_center)); + + // 0.75 is due to the volume of the pyramid approximation! + return 1. / (0.75 / 2. / _PI * rAB_squared / detector_efficiency_no_scatter / (cos_incident_angle_A * cos_incident_angle_B)); } END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index 37067ba4df..f6ee335768 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -13,8 +13,8 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! @@ -32,7 +32,7 @@ #include "stir/scatter/ScatterSimulation.h" #ifndef NDEBUG // currently necessary for assert below -#include "stir/VoxelsOnCartesianGrid.h" +# include "stir/VoxelsOnCartesianGrid.h" #endif #include "stir/round.h" @@ -40,116 +40,80 @@ using namespace std; START_NAMESPACE_STIR -static const float total_Compton_cross_section_511keV = -ScatterSimulation:: - total_Compton_cross_section(511.F); +static const float total_Compton_cross_section_511keV = ScatterSimulation::total_Compton_cross_section(511.F); float -SingleScatterSimulation:: - simulate_for_one_scatter_point( - const std::size_t scatter_point_num, - const unsigned det_num_A, - const unsigned det_num_B) -{ +SingleScatterSimulation::simulate_for_one_scatter_point(const std::size_t scatter_point_num, const unsigned det_num_A, + const unsigned det_num_B) { if (this->max_single_scatter_cos_angle <= 0.F) // set to negative value by set_up(), so recompute - { - this->max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(), - 2.f, - this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); - } - - //static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,energy_resolution); - - const CartesianCoordinate3D& scatter_point = - this->scatt_points_vector[scatter_point_num].coord; - const CartesianCoordinate3D& detector_coord_A = - this->detection_points_vector[det_num_A]; - const CartesianCoordinate3D& detector_coord_B = - this->detection_points_vector[det_num_B]; + { + this->max_single_scatter_cos_angle = + max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(), 2.f, + this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); + } + + // static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,energy_resolution); + + const CartesianCoordinate3D& scatter_point = this->scatt_points_vector[scatter_point_num].coord; + const CartesianCoordinate3D& detector_coord_A = this->detection_points_vector[det_num_A]; + const CartesianCoordinate3D& detector_coord_B = this->detection_points_vector[det_num_B]; // note: costheta is -cos_angle such that it is 1 for zero scatter angle - const float costheta = static_cast( - -cos_angle(detector_coord_A - scatter_point, - detector_coord_B - scatter_point)); + const float costheta = static_cast(-cos_angle(detector_coord_A - scatter_point, detector_coord_B - scatter_point)); // note: costheta is identical for scatter to A or scatter to B // Hence, the Compton_cross_section and energy are identical for both cases as well. - if(this->max_single_scatter_cos_angle>costheta) + if (this->max_single_scatter_cos_angle > costheta) return 0; - const float new_energy = - photon_energy_after_Compton_scatter_511keV(costheta); + const float new_energy = photon_energy_after_Compton_scatter_511keV(costheta); - const float detection_efficiency_scatter = - detection_efficiency(new_energy); - if (detection_efficiency_scatter==0) + const float detection_efficiency_scatter = detection_efficiency(new_energy); + if (detection_efficiency_scatter == 0) return 0; const float emiss_to_detA = - cached_integral_over_activity_image_between_scattpoint_det - (static_cast (scatter_point_num), - det_num_A); - const float emiss_to_detB = - cached_integral_over_activity_image_between_scattpoint_det - (static_cast (scatter_point_num), - det_num_B); - if (emiss_to_detA==0 && emiss_to_detB==0) - return 0; - const float atten_to_detA = - cached_exp_integral_over_attenuation_image_between_scattpoint_det - (scatter_point_num, - det_num_A); - const float atten_to_detB = - cached_exp_integral_over_attenuation_image_between_scattpoint_det - (scatter_point_num, - det_num_B); - - const float dif_Compton_cross_section_value = - dif_Compton_cross_section(costheta, 511.F); - - const float rA_squared=static_cast(norm_squared(scatter_point-detector_coord_A)); - const float rB_squared=static_cast(norm_squared(scatter_point-detector_coord_B)); - - const float scatter_point_mu= - scatt_points_vector[scatter_point_num].mu_value; + cached_integral_over_activity_image_between_scattpoint_det(static_cast(scatter_point_num), det_num_A); + const float emiss_to_detB = + cached_integral_over_activity_image_between_scattpoint_det(static_cast(scatter_point_num), det_num_B); + if (emiss_to_detA == 0 && emiss_to_detB == 0) + return 0; + const float atten_to_detA = cached_exp_integral_over_attenuation_image_between_scattpoint_det(scatter_point_num, det_num_A); + const float atten_to_detB = cached_exp_integral_over_attenuation_image_between_scattpoint_det(scatter_point_num, det_num_B); + + const float dif_Compton_cross_section_value = dif_Compton_cross_section(costheta, 511.F); + + const float rA_squared = static_cast(norm_squared(scatter_point - detector_coord_A)); + const float rB_squared = static_cast(norm_squared(scatter_point - detector_coord_B)); + + const float scatter_point_mu = scatt_points_vector[scatter_point_num].mu_value; #ifndef NDEBUG - { + { // check if mu-value ok // currently terribly shift needed as in sample_scatter_points (TODO) const VoxelsOnCartesianGrid& image = - dynamic_cast&>(*this->get_density_image_for_scatter_points_sptr()); - const CartesianCoordinate3D voxel_size = image.get_voxel_size(); - const float z_to_middle = - (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; - CartesianCoordinate3D shifted=scatter_point; + dynamic_cast&>(*this->get_density_image_for_scatter_points_sptr()); + const CartesianCoordinate3D voxel_size = image.get_voxel_size(); + const float z_to_middle = (image.get_max_index() + image.get_min_index()) * voxel_size.z() / 2.F; + CartesianCoordinate3D shifted = scatter_point; shifted.z() += z_to_middle; - assert(scatter_point_mu== - (*this->get_density_image_for_scatter_points_sptr())[this->get_density_image_for_scatter_points_sptr()->get_indices_closest_to_physical_coordinates(shifted)]); + assert(scatter_point_mu == + (*this->get_density_image_for_scatter_points_sptr())[this->get_density_image_for_scatter_points_sptr() + ->get_indices_closest_to_physical_coordinates(shifted)]); } #endif - float scatter_ratio=0 ; - - scatter_ratio= - (emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *detection_efficiency_scatter; - - - const CartesianCoordinate3D - detA_to_ring_center(0,-detector_coord_A[2],-detector_coord_A[3]); - const CartesianCoordinate3D - detB_to_ring_center(0,-detector_coord_B[2],-detector_coord_B[3]); - const float cos_incident_angle_AS = static_cast( - cos_angle(scatter_point - detector_coord_A, - detA_to_ring_center)) ; - const float cos_incident_angle_BS = static_cast( - cos_angle(scatter_point - detector_coord_B, - detB_to_ring_center)) ; - - return scatter_ratio*cos_incident_angle_AS*cos_incident_angle_BS*dif_Compton_cross_section_value; - + float scatter_ratio = 0; + + scatter_ratio = + (emiss_to_detA * (1.F / rB_squared) * pow(atten_to_detB, total_Compton_cross_section_relative_to_511keV(new_energy) - 1) + + emiss_to_detB * (1.F / rA_squared) * pow(atten_to_detA, total_Compton_cross_section_relative_to_511keV(new_energy) - 1)) * + atten_to_detB * atten_to_detA * scatter_point_mu * detection_efficiency_scatter; + + const CartesianCoordinate3D detA_to_ring_center(0, -detector_coord_A[2], -detector_coord_A[3]); + const CartesianCoordinate3D detB_to_ring_center(0, -detector_coord_B[2], -detector_coord_B[3]); + const float cos_incident_angle_AS = static_cast(cos_angle(scatter_point - detector_coord_A, detA_to_ring_center)); + const float cos_incident_angle_BS = static_cast(cos_angle(scatter_point - detector_coord_B, detB_to_ring_center)); + + return scatter_ratio * cos_incident_angle_AS * cos_incident_angle_BS * dif_Compton_cross_section_value; } END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/single_scatter_estimate.cxx b/src/scatter_buildblock/single_scatter_estimate.cxx index 0c5e1f964b..b5276e5ce1 100644 --- a/src/scatter_buildblock/single_scatter_estimate.cxx +++ b/src/scatter_buildblock/single_scatter_estimate.cxx @@ -11,7 +11,7 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + GNU Lesser General Public License for more details. See STIR/LICENSE.txt for details */ @@ -27,47 +27,30 @@ */ #include "stir/scatter/SingleScatterSimulation.h" START_NAMESPACE_STIR -static const float total_Compton_cross_section_511keV = -ScatterSimulation:: - total_Compton_cross_section(511.F); +static const float total_Compton_cross_section_511keV = ScatterSimulation::total_Compton_cross_section(511.F); double -SingleScatterSimulation:: -scatter_estimate(const Bin& bin) -{ +SingleScatterSimulation::scatter_estimate(const Bin& bin) { double scatter_ratio_singles = 0; unsigned det_num_A = 0; // initialise to avoid compiler warnings unsigned det_num_B = 0; this->find_detectors(det_num_A, det_num_B, bin); - this->actual_scatter_estimate(scatter_ratio_singles, - det_num_A, - det_num_B); + this->actual_scatter_estimate(scatter_ratio_singles, det_num_A, det_num_B); - return scatter_ratio_singles; + return scatter_ratio_singles; } - void -SingleScatterSimulation:: -actual_scatter_estimate(double& scatter_ratio_singles, - const unsigned det_num_A, - const unsigned det_num_B) -{ +SingleScatterSimulation::actual_scatter_estimate(double& scatter_ratio_singles, const unsigned det_num_A, + const unsigned det_num_B) { scatter_ratio_singles = 0; - - for(std::size_t scatter_point_num =0; - scatter_point_num < this->scatt_points_vector.size(); - ++scatter_point_num) - { - scatter_ratio_singles += - simulate_for_one_scatter_point( - scatter_point_num, - det_num_A, det_num_B); - - } + + for (std::size_t scatter_point_num = 0; scatter_point_num < this->scatt_points_vector.size(); ++scatter_point_num) { + scatter_ratio_singles += simulate_for_one_scatter_point(scatter_point_num, det_num_A, det_num_B); + } // we will divide by the effiency of the detector pair for unscattered photons // (computed with the same detection model as used in the scatter code) @@ -78,8 +61,7 @@ actual_scatter_estimate(double& scatter_ratio_singles, // the factors total_Compton_cross_section_511keV should probably be moved to the scatter_computation code const double common_factor = - 1/detection_efficiency_no_scatter(det_num_A, det_num_B) * - scatter_volume/total_Compton_cross_section_511keV; + 1 / detection_efficiency_no_scatter(det_num_A, det_num_B) * scatter_volume / total_Compton_cross_section_511keV; scatter_ratio_singles *= common_factor; } diff --git a/src/scatter_buildblock/single_scatter_integrals.cxx b/src/scatter_buildblock/single_scatter_integrals.cxx index 843f692068..54f5ccef43 100644 --- a/src/scatter_buildblock/single_scatter_integrals.cxx +++ b/src/scatter_buildblock/single_scatter_integrals.cxx @@ -13,8 +13,8 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! @@ -22,13 +22,13 @@ \ingroup scatter \brief Implementations of integrating functions in stir::ScatterEstimationByBin - Functions calculates the integral along LOR in an image (attenuation or emission). + Functions calculates the integral along LOR in an image (attenuation or emission). (from scatter point to detector coordinate) - + \author Pablo Aguiar \author Charalampos Tsoumpas \author Kris Thielemans - + */ #include "stir/scatter/ScatterSimulation.h" #include "stir/VoxelsOnCartesianGrid.h" @@ -36,111 +36,79 @@ #include "stir/recon_buildblock/RayTraceVoxelsOnCartesianGrid.h" START_NAMESPACE_STIR -float -ScatterSimulation:: -exp_integral_over_attenuation_image_between_scattpoint_det (const CartesianCoordinate3D& scatter_point, - const CartesianCoordinate3D& detector_coord) -{ -#ifndef NEWSCALE - /* projectors work in pixel units, so convert attenuation data +float +ScatterSimulation::exp_integral_over_attenuation_image_between_scattpoint_det( + const CartesianCoordinate3D& scatter_point, const CartesianCoordinate3D& detector_coord) { +#ifndef NEWSCALE + /* projectors work in pixel units, so convert attenuation data from cm^-1 to pixel_units^-1 */ - const float rescale = - dynamic_cast &>(*density_image_sptr). - get_grid_spacing()[3]/10; + const float rescale = + dynamic_cast&>(*density_image_sptr).get_grid_spacing()[3] / 10; #else - const float rescale = - 0.1F; + const float rescale = 0.1F; #endif - return - exp(-rescale* - integral_between_2_points(*density_image_sptr, - scatter_point, - detector_coord) - ); + return exp(-rescale * integral_between_2_points(*density_image_sptr, scatter_point, detector_coord)); } - float -ScatterSimulation:: -integral_over_activity_image_between_scattpoint_det (const CartesianCoordinate3D& scatter_point, - const CartesianCoordinate3D& detector_coord) -{ +ScatterSimulation::integral_over_activity_image_between_scattpoint_det(const CartesianCoordinate3D& scatter_point, + const CartesianCoordinate3D& detector_coord) { { - const CartesianCoordinate3D dist_vector = scatter_point - detector_coord ; + const CartesianCoordinate3D dist_vector = scatter_point - detector_coord; const float dist_sp1_det_squared = norm_squared(dist_vector); - const float solid_angle_factor = - std::min(static_cast(_PI/2), 1.F / dist_sp1_det_squared) ; - - return - solid_angle_factor * - integral_between_2_points(*activity_image_sptr, - scatter_point, - detector_coord); + const float solid_angle_factor = std::min(static_cast(_PI / 2), 1.F / dist_sp1_det_squared); + + return solid_angle_factor * integral_between_2_points(*activity_image_sptr, scatter_point, detector_coord); } } -float -ScatterSimulation:: -integral_between_2_points(const DiscretisedDensity<3,float>& density, - const CartesianCoordinate3D& scatter_point, - const CartesianCoordinate3D& detector_coord) -{ +float +ScatterSimulation::integral_between_2_points(const DiscretisedDensity<3, float>& density, + const CartesianCoordinate3D& scatter_point, + const CartesianCoordinate3D& detector_coord) { + const VoxelsOnCartesianGrid& image = dynamic_cast&>(density); - const VoxelsOnCartesianGrid& image = - dynamic_cast& > - (density); - const CartesianCoordinate3D voxel_size = image.get_grid_spacing(); - - CartesianCoordinate3D origin = - image.get_origin(); - const float z_to_middle = - (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; + + CartesianCoordinate3D origin = image.get_origin(); + const float z_to_middle = (image.get_max_index() + image.get_min_index()) * voxel_size.z() / 2.F; origin.z() -= z_to_middle; /* TODO replace with image.get_index_coordinates_for_physical_coordinates */ ProjMatrixElemsForOneBin lor; - RayTraceVoxelsOnCartesianGrid(lor, - (scatter_point-origin)/voxel_size, // should be in voxel units - (detector_coord-origin)/voxel_size, // should be in voxel units - voxel_size, //should be in mm + RayTraceVoxelsOnCartesianGrid(lor, + (scatter_point - origin) / voxel_size, // should be in voxel units + (detector_coord - origin) / voxel_size, // should be in voxel units + voxel_size, // should be in mm #ifdef NEWSCALE 1.F // normalise to mm #else - 1/voxel_size.x() // normalise to some kind of 'pixel units' + 1 / voxel_size.x() // normalise to some kind of 'pixel units' #endif - ); + ); lor.sort(); - float sum = 0; // add up values along LOR - { - ProjMatrixElemsForOneBin::iterator element_ptr =lor.begin() ; + float sum = 0; // add up values along LOR + { + ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); bool we_have_been_within_the_image = false; - while (element_ptr != lor.end()) - { - const BasicCoordinate<3,int> coords = element_ptr->get_coords(); - if (coords[1] >= image.get_min_index() && - coords[1] <= image.get_max_index() && - coords[2] >= image[coords[1]].get_min_index() && - coords[2] <= image[coords[1]].get_max_index() && - coords[3] >= image[coords[1]][coords[2]].get_min_index() && - coords[3] <= image[coords[1]][coords[2]].get_max_index()) - { - we_have_been_within_the_image = true; - sum += image[coords] * element_ptr->get_value(); - } - else if (we_have_been_within_the_image) - { - // we jump out of the loop as we are now at the other side of - // the image - // break; - } - ++element_ptr; - } - } - return sum; -} + while (element_ptr != lor.end()) { + const BasicCoordinate<3, int> coords = element_ptr->get_coords(); + if (coords[1] >= image.get_min_index() && coords[1] <= image.get_max_index() && + coords[2] >= image[coords[1]].get_min_index() && coords[2] <= image[coords[1]].get_max_index() && + coords[3] >= image[coords[1]][coords[2]].get_min_index() && coords[3] <= image[coords[1]][coords[2]].get_max_index()) { + we_have_been_within_the_image = true; + sum += image[coords] * element_ptr->get_value(); + } else if (we_have_been_within_the_image) { + // we jump out of the loop as we are now at the other side of + // the image + // break; + } + ++element_ptr; + } + } + return sum; +} END_NAMESPACE_STIR - diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 4560fdb5f9..009bc1fbdc 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -11,8 +11,8 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! @@ -33,7 +33,7 @@ #include "stir/recon_buildblock/BinNormalisation.h" #include "stir/interpolate_projdata.h" #include "stir/utilities.h" -#include "stir/IndexRange2D.h" +#include "stir/IndexRange2D.h" #include "stir/stream.h" #include "stir/Succeeded.h" #include "stir/thresholding.h" @@ -46,106 +46,70 @@ START_NAMESPACE_STIR -void -ScatterEstimation:: -upsample_and_fit_scatter_estimate(ProjData& scaled_scatter_proj_data, - const ProjData& emission_proj_data, - const ProjData& scatter_proj_data, - BinNormalisation& scatter_normalisation, - const ProjData& weights_proj_data, - const float min_scale_factor, - const float max_scale_factor, - const unsigned half_filter_width, - BSpline::BSplineType spline_type, - const bool remove_interleaving) -{ - shared_ptr - interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_sptr()->clone()); - interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); +void +ScatterEstimation::upsample_and_fit_scatter_estimate(ProjData& scaled_scatter_proj_data, const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, BinNormalisation& scatter_normalisation, + const ProjData& weights_proj_data, const float min_scale_factor, + const float max_scale_factor, const unsigned half_filter_width, + BSpline::BSplineType spline_type, const bool remove_interleaving) { + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_sptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0, 0); info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), - interpolated_direct_scatter_proj_data_info_sptr); + interpolated_direct_scatter_proj_data_info_sptr); interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); - const TimeFrameDefinitions& time_frame_defs = - emission_proj_data.get_exam_info_sptr()->time_frame_definitions; - - if (min_scale_factor != 1 || max_scale_factor != 1 || !scatter_normalisation.is_trivial()) - { - ProjDataInMemory interpolated_scatter(emission_proj_data.get_exam_info_sptr(), - emission_proj_data.get_proj_data_info_sptr()->create_shared_clone()); - inverse_SSRB(interpolated_scatter, interpolated_direct_scatter); - - scatter_normalisation.set_up(emission_proj_data.get_exam_info_sptr(), emission_proj_data.get_proj_data_info_sptr()->create_shared_clone()); - scatter_normalisation.undo(interpolated_scatter, - time_frame_defs.get_start_time(), time_frame_defs.get_end_time()); - Array<2,float> scale_factors; - - if (min_scale_factor == max_scale_factor) - { - if (min_scale_factor == 1.F) - { - scaled_scatter_proj_data.fill(interpolated_scatter); - return; // all done - } - - const ProjDataInfo& proj_data_info = *emission_proj_data.get_proj_data_info_sptr(); - IndexRange2D sinogram_range(proj_data_info.get_min_segment_num(),proj_data_info.get_max_segment_num(),0,0); - for (int segment_num=proj_data_info.get_min_segment_num(); - segment_num<=proj_data_info.get_max_segment_num(); - ++segment_num) - { - sinogram_range[segment_num].resize( - proj_data_info.get_min_axial_pos_num(segment_num), - proj_data_info.get_max_axial_pos_num(segment_num) ); - } - scale_factors.grow(sinogram_range); - scale_factors.fill(min_scale_factor); - } - else - { - info("upsample_and_fit_scatter_estimate: Finding scale factors by sinogram", 3); - scale_factors = get_scale_factors_per_sinogram( - emission_proj_data, - interpolated_scatter, - weights_proj_data); - - info(boost::format("upsample_and_fit_scatter_estimate: scale factors before thresholding:\n%1%") % - scale_factors, - 2); - - threshold_lower(scale_factors.begin_all(), - scale_factors.end_all(), - min_scale_factor); - threshold_upper(scale_factors.begin_all(), - scale_factors.end_all(), - max_scale_factor); - info(boost::format("upsample_and_fit_scatter_estimate: scale factors after thresholding:\n%1%") % - scale_factors, - 2); - VectorWithOffset kernel(-static_cast(half_filter_width),half_filter_width); - kernel.fill(1.F/(2*half_filter_width+1)); - ArrayFilter1DUsingConvolution lowpass_filter(kernel, BoundaryConditions::constant); - std::for_each(scale_factors.begin(), - scale_factors.end(), - lowpass_filter); - info(boost::format("upsample_and_fit_scatter_estimate: scale factors after filtering:\n%1%") % - scale_factors, - 2); - } - info("upsample_and_fit_scatter_estimate: applying scale factors", 3); - if (scale_sinograms(scaled_scatter_proj_data, - interpolated_scatter, - scale_factors) != Succeeded::yes) - { - error("upsample_and_fit_scatter_estimate: writing of scaled sinograms failed"); - } + const TimeFrameDefinitions& time_frame_defs = emission_proj_data.get_exam_info_sptr()->time_frame_definitions; + + if (min_scale_factor != 1 || max_scale_factor != 1 || !scatter_normalisation.is_trivial()) { + ProjDataInMemory interpolated_scatter(emission_proj_data.get_exam_info_sptr(), + emission_proj_data.get_proj_data_info_sptr()->create_shared_clone()); + inverse_SSRB(interpolated_scatter, interpolated_direct_scatter); + + scatter_normalisation.set_up(emission_proj_data.get_exam_info_sptr(), + emission_proj_data.get_proj_data_info_sptr()->create_shared_clone()); + scatter_normalisation.undo(interpolated_scatter, time_frame_defs.get_start_time(), time_frame_defs.get_end_time()); + Array<2, float> scale_factors; + + if (min_scale_factor == max_scale_factor) { + if (min_scale_factor == 1.F) { + scaled_scatter_proj_data.fill(interpolated_scatter); + return; // all done + } + + const ProjDataInfo& proj_data_info = *emission_proj_data.get_proj_data_info_sptr(); + IndexRange2D sinogram_range(proj_data_info.get_min_segment_num(), proj_data_info.get_max_segment_num(), 0, 0); + for (int segment_num = proj_data_info.get_min_segment_num(); segment_num <= proj_data_info.get_max_segment_num(); + ++segment_num) { + sinogram_range[segment_num].resize(proj_data_info.get_min_axial_pos_num(segment_num), + proj_data_info.get_max_axial_pos_num(segment_num)); + } + scale_factors.grow(sinogram_range); + scale_factors.fill(min_scale_factor); + } else { + info("upsample_and_fit_scatter_estimate: Finding scale factors by sinogram", 3); + scale_factors = get_scale_factors_per_sinogram(emission_proj_data, interpolated_scatter, weights_proj_data); + + info(boost::format("upsample_and_fit_scatter_estimate: scale factors before thresholding:\n%1%") % scale_factors, 2); + + threshold_lower(scale_factors.begin_all(), scale_factors.end_all(), min_scale_factor); + threshold_upper(scale_factors.begin_all(), scale_factors.end_all(), max_scale_factor); + info(boost::format("upsample_and_fit_scatter_estimate: scale factors after thresholding:\n%1%") % scale_factors, 2); + VectorWithOffset kernel(-static_cast(half_filter_width), half_filter_width); + kernel.fill(1.F / (2 * half_filter_width + 1)); + ArrayFilter1DUsingConvolution lowpass_filter(kernel, BoundaryConditions::constant); + std::for_each(scale_factors.begin(), scale_factors.end(), lowpass_filter); + info(boost::format("upsample_and_fit_scatter_estimate: scale factors after filtering:\n%1%") % scale_factors, 2); } - else // min/max_scale_factor equal to 1 and no norm - { - inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + info("upsample_and_fit_scatter_estimate: applying scale factors", 3); + if (scale_sinograms(scaled_scatter_proj_data, interpolated_scatter, scale_factors) != Succeeded::yes) { + error("upsample_and_fit_scatter_estimate: writing of scaled sinograms failed"); } + } else // min/max_scale_factor equal to 1 and no norm + { + inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + } } END_NAMESPACE_STIR diff --git a/src/scatter_utilities/create_tail_mask_from_ACFs.cxx b/src/scatter_utilities/create_tail_mask_from_ACFs.cxx index 5849f594c1..9ae09f7473 100644 --- a/src/scatter_utilities/create_tail_mask_from_ACFs.cxx +++ b/src/scatter_utilities/create_tail_mask_from_ACFs.cxx @@ -12,7 +12,7 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + GNU Lesser General Public License for more details. See STIR/LICENSE.txt for details */ @@ -28,7 +28,7 @@ \author Nikos Efthimiou \author Kris Thielemans - + \par Usage: \verbatim @@ -62,106 +62,89 @@ #include "stir/scatter/CreateTailMaskFromACFs.h" - -/***********************************************************/ +/***********************************************************/ static void -print_usage_and_exit(const char * const prog_name) -{ - std::cerr << "\nUsage:\n" << prog_name << "\n" - << "\t--ACF-filename \n" - << "\t--output-filename \n" - << "\t[--ACF-threshold ]\n" - << "\t[--safety-margin ]\n" - << "ACF-threshold defaults to 1.1, safety-margin to 4\n" - << "Alternative Usage:\n" - << "Create_tail_mask_from_ACFs parameters.par\n" - << "Example par file:"; - exit(EXIT_FAILURE); +print_usage_and_exit(const char* const prog_name) { + std::cerr << "\nUsage:\n" + << prog_name << "\n" + << "\t--ACF-filename \n" + << "\t--output-filename \n" + << "\t[--ACF-threshold ]\n" + << "\t[--safety-margin ]\n" + << "ACF-threshold defaults to 1.1, safety-margin to 4\n" + << "Alternative Usage:\n" + << "Create_tail_mask_from_ACFs parameters.par\n" + << "Example par file:"; + exit(EXIT_FAILURE); } -int main(int argc, const char *argv[]) -{ - USING_NAMESPACE_STIR; - const char * const prog_name = argv[0]; - - CreateTailMaskFromACFs create_tail_mask_from_ACFs; - - - - // If one arg is supplied and it is a par file - // then use the Create_tail_mask_from_ACFs to parse the - // file. Otherwise continue the old way. - if (argc == 2) - { - std::stringstream hdr_stream(argv[1]); - std::string sargv = hdr_stream.str(); - - size_t lastindex = sargv.find_last_of("."); - std::string extension = sargv.substr(lastindex); - std::string par_ext = ".par"; - if ( extension.compare(par_ext) != 0 ) - error("Please provide a valid par file."); - - if (create_tail_mask_from_ACFs.parse(argv[1]) == false) - { - warning("Create_tail_mask_from_ACFs aborting because error in parsing. Not writing any output"); - return EXIT_FAILURE; - } +int +main(int argc, const char* argv[]) { + USING_NAMESPACE_STIR; + const char* const prog_name = argv[0]; + + CreateTailMaskFromACFs create_tail_mask_from_ACFs; + + // If one arg is supplied and it is a par file + // then use the Create_tail_mask_from_ACFs to parse the + // file. Otherwise continue the old way. + if (argc == 2) { + std::stringstream hdr_stream(argv[1]); + std::string sargv = hdr_stream.str(); + + size_t lastindex = sargv.find_last_of("."); + std::string extension = sargv.substr(lastindex); + std::string par_ext = ".par"; + if (extension.compare(par_ext) != 0) + error("Please provide a valid par file."); + + if (create_tail_mask_from_ACFs.parse(argv[1]) == false) { + warning("Create_tail_mask_from_ACFs aborting because error in parsing. Not writing any output"); + return EXIT_FAILURE; + } + } else { + // option processing + float ACF_threshold = 1.1F; + int safety_margin = 4; + std::string ACF_filename; + std::string output_filename; + + while (argc > 2 && argv[1][1] == '-') { + if (strcmp(argv[1], "--ACF-filename") == 0) { + ACF_filename = (argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--output-filename") == 0) { + output_filename = (argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--ACF-threshold") == 0) { + ACF_threshold = float(atof(argv[2])); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--safety-margin") == 0) { + safety_margin = atoi(argv[2]); + argc -= 2; + argv += 2; + } else { + std::cerr << "\nUnknown option: " << argv[1]; + print_usage_and_exit(prog_name); + } } - else - { - // option processing - float ACF_threshold = 1.1F; - int safety_margin=4; - std::string ACF_filename; - std::string output_filename; - - while (argc>2 && argv[1][1] == '-') - { - if (strcmp(argv[1], "--ACF-filename")==0) - { - ACF_filename = (argv[2]); - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--output-filename")==0) - { - output_filename = (argv[2]); - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--ACF-threshold")==0) - { - ACF_threshold = float(atof(argv[2])); - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--safety-margin")==0) - { - safety_margin = atoi(argv[2]); - argc-=2; argv +=2; - } - else - { - std::cerr << "\nUnknown option: " << argv[1]; - print_usage_and_exit(prog_name); - } - } - - if (argc!=1 || ACF_filename.size()==0 || output_filename.size()==0) - { - print_usage_and_exit(prog_name); - } - - // Use CreateTailMaskFromACFs::set_up to parse the parameters - create_tail_mask_from_ACFs.set_input_projdata(ACF_filename); - create_tail_mask_from_ACFs.set_output_projdata(output_filename); - create_tail_mask_from_ACFs.ACF_threshold = ACF_threshold; - create_tail_mask_from_ACFs.safety_margin = safety_margin; + if (argc != 1 || ACF_filename.size() == 0 || output_filename.size() == 0) { + print_usage_and_exit(prog_name); } - // Onwards the new class will do the job ... + // Use CreateTailMaskFromACFs::set_up to parse the parameters + create_tail_mask_from_ACFs.set_input_projdata(ACF_filename); + create_tail_mask_from_ACFs.set_output_projdata(output_filename); + create_tail_mask_from_ACFs.ACF_threshold = ACF_threshold; + create_tail_mask_from_ACFs.safety_margin = safety_margin; + } - return create_tail_mask_from_ACFs.process_data() == stir::Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; -} - + // Onwards the new class will do the job ... + + return create_tail_mask_from_ACFs.process_data() == stir::Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/scatter_utilities/estimate_scatter.cxx b/src/scatter_utilities/estimate_scatter.cxx index 95418e8043..f471f4ad84 100644 --- a/src/scatter_utilities/estimate_scatter.cxx +++ b/src/scatter_utilities/estimate_scatter.cxx @@ -12,7 +12,7 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + GNU Lesser General Public License for more details. See STIR/LICENSE.txt for details */ @@ -23,8 +23,8 @@ \brief Estimates a coarse scatter sinogram \author Kris Thielemans - - + + \par Usage: \code estimate_scatter parfile @@ -35,33 +35,28 @@ #include "stir/scatter/ScatterEstimation.h" #include "stir/Succeeded.h" -/***********************************************************/ +/***********************************************************/ -static void print_usage_and_exit() -{ - std::cerr<<"This executable runs a Scatter simulation method based on the options " +static void +print_usage_and_exit() { + std::cerr << "This executable runs a Scatter simulation method based on the options " "in a parameter file"; - std::cerr<<"\nUsage:\n simulate_scatter scatter_simulation.par\n"; - std::cerr<<"Example parameter file can be found in the samples folder :\n" - << std::endl; - exit(EXIT_FAILURE); + std::cerr << "\nUsage:\n simulate_scatter scatter_simulation.par\n"; + std::cerr << "Example parameter file can be found in the samples folder :\n" << std::endl; + exit(EXIT_FAILURE); } /***********************************************************/ -int main(int argc, const char *argv[]) -{ - stir::ScatterEstimation scatter_estimation; - - if (argc==2) - { - if (scatter_estimation.parse(argv[1]) == false) - return EXIT_FAILURE; - } - else - print_usage_and_exit(); - - return - (scatter_estimation.set_up() == stir::Succeeded::yes) - && (scatter_estimation.process_data() == stir::Succeeded::yes) ? - EXIT_SUCCESS : EXIT_FAILURE; +int +main(int argc, const char* argv[]) { + stir::ScatterEstimation scatter_estimation; + + if (argc == 2) { + if (scatter_estimation.parse(argv[1]) == false) + return EXIT_FAILURE; + } else + print_usage_and_exit(); + + return (scatter_estimation.set_up() == stir::Succeeded::yes) && (scatter_estimation.process_data() == stir::Succeeded::yes) + ? EXIT_SUCCESS + : EXIT_FAILURE; } - diff --git a/src/scatter_utilities/simulate_scatter.cxx b/src/scatter_utilities/simulate_scatter.cxx index 6f3ba89a27..38c9fb0d40 100644 --- a/src/scatter_utilities/simulate_scatter.cxx +++ b/src/scatter_utilities/simulate_scatter.cxx @@ -41,12 +41,12 @@ using std::cerr; using std::cout; using std::endl; -static void print_usage_and_exit() -{ - std::cerr<<"This executable runs a Scatter simulation method based on the options " +static void +print_usage_and_exit() { + std::cerr << "This executable runs a Scatter simulation method based on the options " "in a parameter file"; - std::cerr<<"\nUsage:\n simulate_scatter scatter_simulation.par\n"; - std::cerr<<"Example minimal parameter file:\n\n" + std::cerr << "\nUsage:\n simulate_scatter scatter_simulation.par\n"; + std::cerr << "Example minimal parameter file:\n\n" "Scatter Simulation Parameters :=\n" "Simulation type := PET Single Scatter Simulation\n" "PET Single Scatter Simulation Parameters :=\n" @@ -55,45 +55,45 @@ static void print_usage_and_exit() "activity image filename :=\n" "output filename prefix := \n" "End PET Single Scatter Simulation Parameters :=\n" - "End Scatter Simulation Parameters:="<< std::endl; - exit(EXIT_FAILURE); + "End Scatter Simulation Parameters:=" + << std::endl; + exit(EXIT_FAILURE); } /***********************************************************/ -int main(int argc, const char *argv[]) -{ - USING_NAMESPACE_STIR - - HighResWallClockTimer t; - t.reset(); - t.start(); - - if (argc!=2) - print_usage_and_exit(); - - shared_ptr < ScatterSimulation > - simulation_method_sptr; - - KeyParser parser; - parser.add_start_key("Scatter Simulation Parameters"); - parser.add_stop_key("End Scatter Simulation Parameters"); - parser.add_parsing_key("Scatter Simulation type", &simulation_method_sptr); - if (!parser.parse(argv[1])) - { t.stop(); return EXIT_FAILURE; } - - if(simulation_method_sptr->set_up() == Succeeded::no) - { t.stop(); return EXIT_FAILURE; } - - if(simulation_method_sptr->process_data() == stir::Succeeded::yes) - { - t.stop(); - cout << "Total Wall clock time: " << t.value() << " seconds" << endl; - return EXIT_SUCCESS; - } - else - { - t.stop(); - return EXIT_FAILURE; - } +int +main(int argc, const char* argv[]) { + USING_NAMESPACE_STIR + + HighResWallClockTimer t; + t.reset(); + t.start(); + + if (argc != 2) + print_usage_and_exit(); + + shared_ptr simulation_method_sptr; + + KeyParser parser; + parser.add_start_key("Scatter Simulation Parameters"); + parser.add_stop_key("End Scatter Simulation Parameters"); + parser.add_parsing_key("Scatter Simulation type", &simulation_method_sptr); + if (!parser.parse(argv[1])) { + t.stop(); + return EXIT_FAILURE; + } + + if (simulation_method_sptr->set_up() == Succeeded::no) { + t.stop(); + return EXIT_FAILURE; + } + + if (simulation_method_sptr->process_data() == stir::Succeeded::yes) { + t.stop(); + cout << "Total Wall clock time: " << t.value() << " seconds" << endl; + return EXIT_SUCCESS; + } else { + t.stop(); + return EXIT_FAILURE; + } } - diff --git a/src/scatter_utilities/upsample_and_fit_single_scatter.cxx b/src/scatter_utilities/upsample_and_fit_single_scatter.cxx index d192ccfe77..7a5ae557dc 100644 --- a/src/scatter_utilities/upsample_and_fit_single_scatter.cxx +++ b/src/scatter_utilities/upsample_and_fit_single_scatter.cxx @@ -11,7 +11,7 @@ This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + GNU Lesser General Public License for more details. See STIR/LICENSE.txt for details */ @@ -25,20 +25,20 @@ \author Charalampos Tsoumpas \author Kris Thielemans - + \par Usage: \code [--min-scale-factor ] [--max-scale-factor ] [--remove-interleaving <1|0>] [--half-filter-width ] - --output-filename + --output-filename --data-to-fit --data-to-scale --norm --weights \endcode - \a remove_interleaving defaults to 1\, \a min-scale-factor to 1e-5, + \a remove_interleaving defaults to 1\, \a min-scale-factor to 1e-5, and \a max-scale-factor to 1e5. The norm parameter expects the filename of a .par file with the following keywords @@ -59,17 +59,17 @@ #include "stir/is_null_ptr.h" #include #include -/***********************************************************/ +/***********************************************************/ static void -print_usage_and_exit(const char * const prog_name) -{ - std::cerr << "\nUsage:\n" << prog_name << "\\\n" +print_usage_and_exit(const char* const prog_name) { + std::cerr << "\nUsage:\n" + << prog_name << "\\\n" << "\t[--min-scale-factor ]\\\n" << "\t[--max-scale-factor ]\\\n" << "\t[--remove-interleaving <1|0>]\\\n" << "\t[--half-filter-width ]\\\n" - << "\t--output-filename \\\n" + << "\t--output-filename \\\n" << "\t--data-to-fit \\\n" << "\t--data-to-scale \\\n" << "\t--norm \\\n" @@ -85,15 +85,15 @@ print_usage_and_exit(const char * const prog_name) exit(EXIT_FAILURE); } -int main(int argc, const char *argv[]) -{ - const char * const prog_name = argv[0]; +int +main(int argc, const char* argv[]) { + const char* const prog_name = argv[0]; float min_scale_factor = 1.E-5F; float max_scale_factor = 1.E5F; bool remove_interleaving = true; unsigned int half_filter_width = 1; - stir::BSpline::BSplineType spline_type = stir::BSpline::linear; + stir::BSpline::BSplineType spline_type = stir::BSpline::linear; std::string data_to_fit_filename; std::string data_to_scale_filename; std::string weights_filename; @@ -101,112 +101,88 @@ int main(int argc, const char *argv[]) stir::shared_ptr normalisation_sptr; // option processing - while (argc>1 && argv[1][1] == '-') - { - if (strcmp(argv[1], "--min-scale-factor")==0) - { - min_scale_factor = static_cast(atof(argv[2])); - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--max-scale-factor")==0) - { - max_scale_factor = static_cast(atof(argv[2])); - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--BSpline-type")==0) - { - spline_type = (stir::BSpline::BSplineType)atoi(argv[2]); - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--half-filter-width")==0) - { - half_filter_width = (unsigned)atoi(argv[2]); - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--remove-interleaving")==0) - { - remove_interleaving = atoi(argv[2])!=0; - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--output-filename")==0) - { - output_filename = (argv[2]); - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--data-to-fit")==0) - { - data_to_fit_filename = argv[2]; - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--data-to-scale")==0) - { - data_to_scale_filename = argv[2]; - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--weights")==0) - { - weights_filename = argv[2]; - argc-=2; argv +=2; - } - else if (strcmp(argv[1], "--norm")==0) - { - stir::KeyParser parser; - parser.add_start_key("Bin Normalisation parameters"); - parser.add_parsing_key("type", &normalisation_sptr); - parser.add_stop_key("END"); - if (!parser.parse(argv[2])) - { return EXIT_FAILURE; } - argc-=2; argv +=2; - } - else - { - std::cerr << "\nUnknown option: " << argv[1]; - print_usage_and_exit(prog_name); - } - } - - if (argc> 1) - { - std::cerr << "Command line should contain only options\n"; - print_usage_and_exit(prog_name); - } - - if (data_to_fit_filename.size()==0 || data_to_scale_filename.size() == 0 || - weights_filename.size()==0 || output_filename.size()==0) - { - std::cerr << "One of the required filenames has not been specified\n"; + while (argc > 1 && argv[1][1] == '-') { + if (strcmp(argv[1], "--min-scale-factor") == 0) { + min_scale_factor = static_cast(atof(argv[2])); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--max-scale-factor") == 0) { + max_scale_factor = static_cast(atof(argv[2])); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--BSpline-type") == 0) { + spline_type = (stir::BSpline::BSplineType)atoi(argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--half-filter-width") == 0) { + half_filter_width = (unsigned)atoi(argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--remove-interleaving") == 0) { + remove_interleaving = atoi(argv[2]) != 0; + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--output-filename") == 0) { + output_filename = (argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--data-to-fit") == 0) { + data_to_fit_filename = argv[2]; + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--data-to-scale") == 0) { + data_to_scale_filename = argv[2]; + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--weights") == 0) { + weights_filename = argv[2]; + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "--norm") == 0) { + stir::KeyParser parser; + parser.add_start_key("Bin Normalisation parameters"); + parser.add_parsing_key("type", &normalisation_sptr); + parser.add_stop_key("END"); + if (!parser.parse(argv[2])) { + return EXIT_FAILURE; + } + argc -= 2; + argv += 2; + } else { + std::cerr << "\nUnknown option: " << argv[1]; print_usage_and_exit(prog_name); } + } + + if (argc > 1) { + std::cerr << "Command line should contain only options\n"; + print_usage_and_exit(prog_name); + } + + if (data_to_fit_filename.size() == 0 || data_to_scale_filename.size() == 0 || weights_filename.size() == 0 || + output_filename.size() == 0) { + std::cerr << "One of the required filenames has not been specified\n"; + print_usage_and_exit(prog_name); + } using stir::ProjData; - const stir::shared_ptr< ProjData > weights_proj_data_sptr = - ProjData::read_from_file(weights_filename); - const stir::shared_ptr data_to_fit_proj_data_sptr = - ProjData::read_from_file(data_to_fit_filename); - const stir::shared_ptr data_to_scale_proj_data_sptr = - ProjData::read_from_file(data_to_scale_filename); - - if (stir::is_null_ptr(normalisation_sptr)) - { - normalisation_sptr.reset(new stir::TrivialBinNormalisation); - normalisation_sptr->set_up(data_to_fit_proj_data_sptr->get_exam_info_sptr(), data_to_fit_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone()); - } + const stir::shared_ptr weights_proj_data_sptr = ProjData::read_from_file(weights_filename); + const stir::shared_ptr data_to_fit_proj_data_sptr = ProjData::read_from_file(data_to_fit_filename); + const stir::shared_ptr data_to_scale_proj_data_sptr = ProjData::read_from_file(data_to_scale_filename); + + if (stir::is_null_ptr(normalisation_sptr)) { + normalisation_sptr.reset(new stir::TrivialBinNormalisation); + normalisation_sptr->set_up(data_to_fit_proj_data_sptr->get_exam_info_sptr(), + data_to_fit_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone()); + } stir::shared_ptr data_to_fit_proj_data_info_sptr = - data_to_fit_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); - - stir::ProjDataInterfile output_proj_data(data_to_fit_proj_data_sptr->get_exam_info_sptr(), - data_to_fit_proj_data_info_sptr, output_filename); - - stir::ScatterEstimation:: - upsample_and_fit_scatter_estimate(output_proj_data, - *data_to_fit_proj_data_sptr, - *data_to_scale_proj_data_sptr, - *normalisation_sptr, - *weights_proj_data_sptr, - min_scale_factor, - max_scale_factor, - half_filter_width, - spline_type, - remove_interleaving); + data_to_fit_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); + + stir::ProjDataInterfile output_proj_data(data_to_fit_proj_data_sptr->get_exam_info_sptr(), data_to_fit_proj_data_info_sptr, + output_filename); + + stir::ScatterEstimation::upsample_and_fit_scatter_estimate( + output_proj_data, *data_to_fit_proj_data_sptr, *data_to_scale_proj_data_sptr, *normalisation_sptr, *weights_proj_data_sptr, + min_scale_factor, max_scale_factor, half_filter_width, spline_type, remove_interleaving); return EXIT_SUCCESS; -} +} diff --git a/src/spatial_transformation_buildblock/GatedSpatialTransformation.cxx b/src/spatial_transformation_buildblock/GatedSpatialTransformation.cxx index 49e3717d74..0524f9313d 100644 --- a/src/spatial_transformation_buildblock/GatedSpatialTransformation.cxx +++ b/src/spatial_transformation_buildblock/GatedSpatialTransformation.cxx @@ -2,20 +2,20 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ -/*! +/*! \file \ingroup spatial_transformation \brief Implementations of inline functions of class stir::GatedSpatialTransformation @@ -32,45 +32,36 @@ START_NAMESPACE_STIR void -GatedSpatialTransformation:: -set_defaults() -{ +GatedSpatialTransformation::set_defaults() { base_type::set_defaults(); - this->_transformation_filename_prefix=""; - this->_spline_type=static_cast (1);; + this->_transformation_filename_prefix = ""; + this->_spline_type = static_cast(1); + ; } -const char * const -GatedSpatialTransformation::registered_name = "Gated Spatial Transformation"; +const char* const GatedSpatialTransformation::registered_name = "Gated Spatial Transformation"; //! default constructor -GatedSpatialTransformation::GatedSpatialTransformation() -{ - this->set_defaults(); -} +GatedSpatialTransformation::GatedSpatialTransformation() { this->set_defaults(); } -GatedSpatialTransformation::~GatedSpatialTransformation() //!< default destructor -{ } +GatedSpatialTransformation::~GatedSpatialTransformation() //!< default destructor +{} -Succeeded -GatedSpatialTransformation::set_up() -{ - if (this->_spatial_transformations_are_stored==true) +Succeeded +GatedSpatialTransformation::set_up() { + if (this->_spatial_transformations_are_stored == true) return Succeeded::yes; else return Succeeded::no; } -const TimeGateDefinitions & -GatedSpatialTransformation::get_time_gate_definitions() const -{ +const TimeGateDefinitions& +GatedSpatialTransformation::get_time_gate_definitions() const { return this->_spatial_transformation_x.get_time_gate_definitions(); } void -GatedSpatialTransformation:: -initialise_keymap() -{ +GatedSpatialTransformation::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Gated Spatial Transformation Parameters"); this->parser.add_key("Gated Spatial Transformation Filenames Prefix", &this->_transformation_filename_prefix); @@ -78,158 +69,158 @@ initialise_keymap() } bool -GatedSpatialTransformation:: -post_processing() -{ +GatedSpatialTransformation::post_processing() { if (base_type::post_processing() == true) return true; - if(this->_transformation_filename_prefix=="0") - { - warning("You need to specify a prefix for three files with transformation information."); - return true; - } - else - { - GatedSpatialTransformation::read_from_files(this->_transformation_filename_prefix); - this->_spatial_transformations_are_stored=true; - } + if (this->_transformation_filename_prefix == "0") { + warning("You need to specify a prefix for three files with transformation information."); + return true; + } else { + GatedSpatialTransformation::read_from_files(this->_transformation_filename_prefix); + this->_spatial_transformations_are_stored = true; + } // Always linear interpolation for the moment - this->_spline_type=static_cast (1); + this->_spline_type = static_cast(1); return false; } -//! Implementation to read the transformation vectors will be moved to the IO directory because it should be general. For example it can be in ECAT7 image formant +//! Implementation to read the transformation vectors will be moved to the IO directory because it should be general. For example +//! it can be in ECAT7 image formant void -GatedSpatialTransformation::read_from_files(const std::string input_string) -{ - const std::string gate_defs_input_string=input_string + ".gdef"; +GatedSpatialTransformation::read_from_files(const std::string input_string) { + const std::string gate_defs_input_string = input_string + ".gdef"; - if (gate_defs_input_string.size()!=0) - this->_gate_defs=TimeGateDefinitions(gate_defs_input_string); + if (gate_defs_input_string.size() != 0) + this->_gate_defs = TimeGateDefinitions(gate_defs_input_string); else { error("No Time Gates Definitions available!!!\n "); } - const shared_ptr spatial_transformation_z_sptr (GatedDiscretisedDensity::read_from_files(input_string,"d1")); - const GatedDiscretisedDensity & spatial_transformation_z(*spatial_transformation_z_sptr); - - const shared_ptr spatial_transformation_y_sptr(GatedDiscretisedDensity::read_from_files(input_string,"d2")); - const GatedDiscretisedDensity & spatial_transformation_y(*spatial_transformation_y_sptr); - - const shared_ptr spatial_transformation_x_sptr (GatedDiscretisedDensity::read_from_files(input_string,"d3")); - const GatedDiscretisedDensity & spatial_transformation_x(*spatial_transformation_x_sptr); - - const TimeGateDefinitions gate_defs(gate_defs_input_string);//This is not necessary as the defs are necessary for all the files and it should be one file... Think how to do this. - - this->_spatial_transformation_z= spatial_transformation_z; this->_spatial_transformation_y= spatial_transformation_y; this->_spatial_transformation_x= spatial_transformation_x; - this->_spatial_transformations_are_stored=true; -} + const shared_ptr spatial_transformation_z_sptr( + GatedDiscretisedDensity::read_from_files(input_string, "d1")); + const GatedDiscretisedDensity& spatial_transformation_z(*spatial_transformation_z_sptr); + + const shared_ptr spatial_transformation_y_sptr( + GatedDiscretisedDensity::read_from_files(input_string, "d2")); + const GatedDiscretisedDensity& spatial_transformation_y(*spatial_transformation_y_sptr); + + const shared_ptr spatial_transformation_x_sptr( + GatedDiscretisedDensity::read_from_files(input_string, "d3")); + const GatedDiscretisedDensity& spatial_transformation_x(*spatial_transformation_x_sptr); + + const TimeGateDefinitions gate_defs(gate_defs_input_string); // This is not necessary as the defs are necessary for all the + // files and it should be one file... Think how to do this. + + this->_spatial_transformation_z = spatial_transformation_z; + this->_spatial_transformation_y = spatial_transformation_y; + this->_spatial_transformation_x = spatial_transformation_x; + this->_spatial_transformations_are_stored = true; +} //! Implementation to write the transformation vectors void -GatedSpatialTransformation::write_to_files(const std::string output_string) -{ - (this->_spatial_transformation_z).write_to_files(output_string,"d1"); - (this->_spatial_transformation_y).write_to_files(output_string,"d2"); - (this->_spatial_transformation_x).write_to_files(output_string,"d3"); +GatedSpatialTransformation::write_to_files(const std::string output_string) { + (this->_spatial_transformation_z).write_to_files(output_string, "d1"); + (this->_spatial_transformation_y).write_to_files(output_string, "d2"); + (this->_spatial_transformation_x).write_to_files(output_string, "d3"); // return Succeeded::yes; // add a no case if you cannot write -} +} -void -GatedSpatialTransformation::warp_image(GatedDiscretisedDensity & new_gated_image, - const GatedDiscretisedDensity & gated_image) const -{ +void +GatedSpatialTransformation::warp_image(GatedDiscretisedDensity& new_gated_image, + const GatedDiscretisedDensity& gated_image) const { std::string explanation; - if (!(gated_image.get_densities()[0])->has_same_characteristics(*(gated_image.get_densities()[0]), explanation)){ - error(boost::format("GatedSpatialTransformation::warp_image needs the same sizes for input and output images: %1%") % explanation); + if (!(gated_image.get_densities()[0])->has_same_characteristics(*(gated_image.get_densities()[0]), explanation)) { + error(boost::format("GatedSpatialTransformation::warp_image needs the same sizes for input and output images: %1%") % + explanation); } new_gated_image.set_time_gate_definitions(this->_gate_defs); - assert(gated_image.get_time_gate_definitions().get_num_gates()==this->_spatial_transformation_x.get_time_gate_definitions().get_num_gates()); + assert(gated_image.get_time_gate_definitions().get_num_gates() == + this->_spatial_transformation_x.get_time_gate_definitions().get_num_gates()); new_gated_image.fill_with_zero(); if (this->_spatial_transformations_are_stored) - for(unsigned int gate_num=1 ; gate_num<=gated_image.get_time_gate_definitions().get_num_gates() ; ++gate_num) - new_gated_image[gate_num]=stir::warp_image((gated_image.get_densities())[gate_num-1], - (this->_spatial_transformation_x.get_densities())[gate_num-1], - (this->_spatial_transformation_y.get_densities())[gate_num-1], - (this->_spatial_transformation_z.get_densities())[gate_num-1], - BSpline::linear, false); + for (unsigned int gate_num = 1; gate_num <= gated_image.get_time_gate_definitions().get_num_gates(); ++gate_num) + new_gated_image[gate_num] = stir::warp_image( + (gated_image.get_densities())[gate_num - 1], (this->_spatial_transformation_x.get_densities())[gate_num - 1], + (this->_spatial_transformation_y.get_densities())[gate_num - 1], + (this->_spatial_transformation_z.get_densities())[gate_num - 1], BSpline::linear, false); else error("The transformation fields haven't been set properly yet.\n"); } void -GatedSpatialTransformation::warp_image(DiscretisedDensity<3, float> & new_reference_image, - const GatedDiscretisedDensity & gated_image) const -{ +GatedSpatialTransformation::warp_image(DiscretisedDensity<3, float>& new_reference_image, + const GatedDiscretisedDensity& gated_image) const { new_reference_image.fill(0.F); this->accumulate_warp_image(new_reference_image, gated_image); } void -GatedSpatialTransformation::accumulate_warp_image(DiscretisedDensity<3, float> & new_reference_image, - const GatedDiscretisedDensity & gated_image) const -{ +GatedSpatialTransformation::accumulate_warp_image(DiscretisedDensity<3, float>& new_reference_image, + const GatedDiscretisedDensity& gated_image) const { GatedDiscretisedDensity new_gated_image(gated_image); new_gated_image.fill_with_zero(); - this->warp_image(new_gated_image,gated_image); - //!todo This is not implemented as sum (or should it be the average?) - for(unsigned int gate_num = 1;gate_num<=gated_image.get_time_gate_definitions().get_num_gates() ; ++gate_num) + this->warp_image(new_gated_image, gated_image); + //! todo This is not implemented as sum (or should it be the average?) + for (unsigned int gate_num = 1; gate_num <= gated_image.get_time_gate_definitions().get_num_gates(); ++gate_num) new_reference_image += new_gated_image[gate_num]; // new_reference_image /= gated_image.get_time_gate_definitions().get_num_gates(); } -void -GatedSpatialTransformation::warp_image(GatedDiscretisedDensity & gated_image, - const DiscretisedDensity<3, float> & reference_image) const -{ - if ((gated_image.get_densities())[0]->size_all()!=reference_image.size_all()){ +void +GatedSpatialTransformation::warp_image(GatedDiscretisedDensity& gated_image, + const DiscretisedDensity<3, float>& reference_image) const { + if ((gated_image.get_densities())[0]->size_all() != reference_image.size_all()) { error("GatedSpatialTransformation::warp_image needs the same sizes for input and output images.\n"); } - if ((gated_image.get_densities())[0]->size_all()!=(this->_spatial_transformation_y.get_densities())[0]->size_all()){ + if ((gated_image.get_densities())[0]->size_all() != (this->_spatial_transformation_y.get_densities())[0]->size_all()) { info(boost::format("Number of voxels in one gated image: %1%") % (gated_image.get_densities())[0]->size_all()); - info(boost::format("Number of voxels in one motion vector gated image: %1%") % (this->_spatial_transformation_y.get_densities())[0]->size_all()); + info(boost::format("Number of voxels in one motion vector gated image: %1%") % + (this->_spatial_transformation_y.get_densities())[0]->size_all()); error("GatedSpatialTransformation::warp_image needs the same sizes for motion vectors and input/output images.\n"); } - const shared_ptr > reference_image_sptr( reference_image.clone()); + const shared_ptr> reference_image_sptr(reference_image.clone()); gated_image.resize_densities(this->_gate_defs); - + if (this->_spatial_transformations_are_stored) - for(unsigned int gate_num = 1 ; gate_num<=gated_image.get_time_gate_definitions().get_num_gates() ; ++gate_num) - { - const VoxelsOnCartesianGrid density = stir::warp_image(reference_image_sptr, - (this->_spatial_transformation_x.get_densities())[gate_num-1], - (this->_spatial_transformation_y.get_densities())[gate_num-1], - (this->_spatial_transformation_z.get_densities())[gate_num-1], - BSpline::linear, false); - const shared_ptr > density_sptr(density.clone()); - gated_image.set_density_sptr(density_sptr,gate_num); - } + for (unsigned int gate_num = 1; gate_num <= gated_image.get_time_gate_definitions().get_num_gates(); ++gate_num) { + const VoxelsOnCartesianGrid density = + stir::warp_image(reference_image_sptr, (this->_spatial_transformation_x.get_densities())[gate_num - 1], + (this->_spatial_transformation_y.get_densities())[gate_num - 1], + (this->_spatial_transformation_z.get_densities())[gate_num - 1], BSpline::linear, false); + const shared_ptr> density_sptr(density.clone()); + gated_image.set_density_sptr(density_sptr, gate_num); + } else - error("The transformation fields haven't been set properly yet."); + error("The transformation fields haven't been set properly yet."); } void -GatedSpatialTransformation:: -set_spatial_transformations(const GatedDiscretisedDensity & transformation_z, - const GatedDiscretisedDensity & transformation_y, - const GatedDiscretisedDensity & transformation_x) -{ - this->_spatial_transformation_z=transformation_z; - this->_spatial_transformation_y=transformation_y; - this->_spatial_transformation_x=transformation_x; - this->_spatial_transformations_are_stored=true; -} - -void -GatedSpatialTransformation::set_gate_defs(const TimeGateDefinitions & gate_defs) -{ this->_gate_defs=gate_defs; } - -GatedDiscretisedDensity GatedSpatialTransformation::get_spatial_transformation_z() const -{ return this->_spatial_transformation_z; } -GatedDiscretisedDensity GatedSpatialTransformation::get_spatial_transformation_y() const -{ return this->_spatial_transformation_y; } -GatedDiscretisedDensity GatedSpatialTransformation::get_spatial_transformation_x() const -{ return this->_spatial_transformation_x; } +GatedSpatialTransformation::set_spatial_transformations(const GatedDiscretisedDensity& transformation_z, + const GatedDiscretisedDensity& transformation_y, + const GatedDiscretisedDensity& transformation_x) { + this->_spatial_transformation_z = transformation_z; + this->_spatial_transformation_y = transformation_y; + this->_spatial_transformation_x = transformation_x; + this->_spatial_transformations_are_stored = true; +} +void +GatedSpatialTransformation::set_gate_defs(const TimeGateDefinitions& gate_defs) { + this->_gate_defs = gate_defs; +} + +GatedDiscretisedDensity +GatedSpatialTransformation::get_spatial_transformation_z() const { + return this->_spatial_transformation_z; +} +GatedDiscretisedDensity +GatedSpatialTransformation::get_spatial_transformation_y() const { + return this->_spatial_transformation_y; +} +GatedDiscretisedDensity +GatedSpatialTransformation::get_spatial_transformation_x() const { + return this->_spatial_transformation_x; +} END_NAMESPACE_STIR diff --git a/src/spatial_transformation_buildblock/InvertAxis.cxx b/src/spatial_transformation_buildblock/InvertAxis.cxx index 5a4b5d99a2..b1124eb260 100644 --- a/src/spatial_transformation_buildblock/InvertAxis.cxx +++ b/src/spatial_transformation_buildblock/InvertAxis.cxx @@ -2,19 +2,19 @@ /* Copyright (C) 2019 National Physical Laboratory This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup buildblock @@ -27,72 +27,64 @@ START_NAMESPACE_STIR void -InvertAxis::invert_axis(DiscretisedDensity<3,float> & inverted_image, - const DiscretisedDensity<3,float> & input_image, - const std::string &axis_name){ -//change all the pointers - const int min_z = input_image.get_min_index(); - const int max_z = input_image.get_max_index(); - - - for (int z=min_z; z<=max_z; z++){ - - const int min_y = input_image[z].get_min_index(); - const int max_y = input_image[z].get_max_index(); - - for (int y=min_y;y<= max_y;y++){ - - const int min_x = input_image[z][y].get_min_index(); - const int max_x = input_image[z][y].get_max_index(); - - for (int x=min_x;x<= max_x;x++){ - - if (axis_name=="x"){ -// checking whether the size is odd - if(((max_x-min_x+1) % 2)==0) - inverted_image[z][y][x]=input_image[z][y][-x-1]; - else - inverted_image[z][y][x]=input_image[z][y][-x]; - } - - else if (axis_name=="y"){ - if(((max_y-min_y+1) % 2)==0) - inverted_image[z][y][x]=input_image[z][-y-1][x]; - else - inverted_image[z][y][x]=input_image[z][-y][x]; - } - - else if (axis_name=="z"){ - inverted_image[z][y][x]=input_image[max_z-z][y][x]; - } - } - } - } - } +InvertAxis::invert_axis(DiscretisedDensity<3, float>& inverted_image, const DiscretisedDensity<3, float>& input_image, + const std::string& axis_name) { + // change all the pointers + const int min_z = input_image.get_min_index(); + const int max_z = input_image.get_max_index(); -int -InvertAxis::invert_axis_index(const int input_index, - const int size, - const std::string& axis_name){ + for (int z = min_z; z <= max_z; z++) { - if (axis_name=="x" || axis_name=="y"){ + const int min_y = input_image[z].get_min_index(); + const int max_y = input_image[z].get_max_index(); -// checking whether the size is odd - if((size % 2)==0) - return -input_index -1; - else - return -input_index; + for (int y = min_y; y <= max_y; y++) { + + const int min_x = input_image[z][y].get_min_index(); + const int max_x = input_image[z][y].get_max_index(); + + for (int x = min_x; x <= max_x; x++) { + + if (axis_name == "x") { + // checking whether the size is odd + if (((max_x - min_x + 1) % 2) == 0) + inverted_image[z][y][x] = input_image[z][y][-x - 1]; + else + inverted_image[z][y][x] = input_image[z][y][-x]; } - else if (axis_name=="z") - return size -1 -input_index; - else - { - error("InvertAxis: invalid axis name: " + axis_name); - return 0; // to avoid compiler warning + else if (axis_name == "y") { + if (((max_y - min_y + 1) % 2) == 0) + inverted_image[z][y][x] = input_image[z][-y - 1][x]; + else + inverted_image[z][y][x] = input_image[z][-y][x]; + } + + else if (axis_name == "z") { + inverted_image[z][y][x] = input_image[max_z - z][y][x]; + } } - + } + } +} +int +InvertAxis::invert_axis_index(const int input_index, const int size, const std::string& axis_name) { + + if (axis_name == "x" || axis_name == "y") { + + // checking whether the size is odd + if ((size % 2) == 0) + return -input_index - 1; + else + return -input_index; + } + + else if (axis_name == "z") + return size - 1 - input_index; + else { + error("InvertAxis: invalid axis name: " + axis_name); + return 0; // to avoid compiler warning + } } END_NAMESPACE_STIR - diff --git a/src/spatial_transformation_buildblock/SpatialTransformation.cxx b/src/spatial_transformation_buildblock/SpatialTransformation.cxx index e1d1f562f3..6997b03a3c 100644 --- a/src/spatial_transformation_buildblock/SpatialTransformation.cxx +++ b/src/spatial_transformation_buildblock/SpatialTransformation.cxx @@ -15,30 +15,27 @@ See STIR/LICENSE.txt for details */ - /*! - \file - \ingroup spatial_transformation - \brief Implementations of inline functions of class stir::SpatialTransformation +/*! + \file + \ingroup spatial_transformation + \brief Implementations of inline functions of class stir::SpatialTransformation - \author Charalampos Tsoumpas + \author Charalampos Tsoumpas - This is the most basic class for including Motion Fields. + This is the most basic class for including Motion Fields. */ - #include "stir/spatial_transformation/SpatialTransformation.h" - START_NAMESPACE_STIR -const char * const -SpatialTransformation::registered_name = "Motion Field Type"; +const char* const SpatialTransformation::registered_name = "Motion Field Type"; -SpatialTransformation::SpatialTransformation() //!< default constructor -{ } +SpatialTransformation::SpatialTransformation() //!< default constructor +{} -SpatialTransformation::~SpatialTransformation() //!< default destructor -{ } +SpatialTransformation::~SpatialTransformation() //!< default destructor +{} END_NAMESPACE_STIR diff --git a/src/spatial_transformation_buildblock/spatial_transformation_registries.cxx b/src/spatial_transformation_buildblock/spatial_transformation_registries.cxx index 5bce94a319..6a5bd23b57 100644 --- a/src/spatial_transformation_buildblock/spatial_transformation_registries.cxx +++ b/src/spatial_transformation_buildblock/spatial_transformation_registries.cxx @@ -1,27 +1,27 @@ // - /* - Copyright (C) 2009 -2013, King's College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.3 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details -*/ +/* + Copyright (C) 2009 -2013, King's College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.3 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ /*! \file \ingroup spatial_transformation \brief File that registers all stir::RegisterObject children in spatial_transformation \author Charalampos Tsoumpas - + */ #include "stir/spatial_transformation/GatedSpatialTransformation.h" @@ -31,4 +31,3 @@ START_NAMESPACE_STIR static GatedSpatialTransformation::RegisterIt dummy1199; END_NAMESPACE_STIR - diff --git a/src/spatial_transformation_buildblock/warp_image.cxx b/src/spatial_transformation_buildblock/warp_image.cxx index ccc55d391c..338b709af5 100644 --- a/src/spatial_transformation_buildblock/warp_image.cxx +++ b/src/spatial_transformation_buildblock/warp_image.cxx @@ -2,50 +2,50 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup buildblock - \brief Implementation of function stir::warp_image + \brief Implementation of function stir::warp_image \author Charalampos Tsoumpas */ #include "stir/spatial_transformation/warp_image.h" START_NAMESPACE_STIR -//using namespace BSpline; +// using namespace BSpline; - -VoxelsOnCartesianGrid -warp_image(const shared_ptr > & density_sptr, - const shared_ptr > & motion_x_sptr, - const shared_ptr > & motion_y_sptr, - const shared_ptr > & motion_z_sptr, - const BSpline::BSplineType spline_type, const bool extend_borders) -{ - const DiscretisedDensityOnCartesianGrid <3,float>* density_cartesian_sptr = - dynamic_cast< DiscretisedDensityOnCartesianGrid<3,float>* > (density_sptr.get()); - const BasicCoordinate<3,float> grid_spacing=density_cartesian_sptr->get_grid_spacing(); - const CartesianCoordinate3D origin=density_cartesian_sptr->get_origin(); +VoxelsOnCartesianGrid +warp_image(const shared_ptr>& density_sptr, + const shared_ptr>& motion_x_sptr, + const shared_ptr>& motion_y_sptr, + const shared_ptr>& motion_z_sptr, const BSpline::BSplineType spline_type, + const bool extend_borders) { + const DiscretisedDensityOnCartesianGrid<3, float>* density_cartesian_sptr = + dynamic_cast*>(density_sptr.get()); + const BasicCoordinate<3, float> grid_spacing = density_cartesian_sptr->get_grid_spacing(); + const CartesianCoordinate3D origin = density_cartesian_sptr->get_origin(); const BSpline::BSplinesRegularGrid<3, float> density_interpolation(*density_sptr, spline_type); - - BasicCoordinate<3,int> min; BasicCoordinate<3,int> max; - const IndexRange<3> range=density_sptr->get_index_range(); - if (!range.get_regular_range(min,max)) + + BasicCoordinate<3, int> min; + BasicCoordinate<3, int> max; + const IndexRange<3> range = density_sptr->get_index_range(); + if (!range.get_regular_range(min, max)) error("image is not in regular grid.\n"); - const BasicCoordinate<3,int> out_min=min; const BasicCoordinate<3,int> out_max=max; + const BasicCoordinate<3, int> out_min = min; + const BasicCoordinate<3, int> out_max = max; #if 0 if (extend_borders==1) { out_min[1]-=abs(voxel_shift_z) ; @@ -56,30 +56,32 @@ warp_image(const shared_ptr > & density_sptr, out_max[3]+=abs(voxel_shift_x) ; } #endif - const IndexRange<3> out_range(out_min,out_max); - VoxelsOnCartesianGrid out_density(out_range,origin,grid_spacing); + const IndexRange<3> out_range(out_min, out_max); + VoxelsOnCartesianGrid out_density(out_range, origin, grid_spacing); - BasicCoordinate<3,int> c; - BasicCoordinate<3,double> d, l; - for (c[1]=min[1]; c[1]<=max[1]; ++c[1]) - for (c[2]=min[2]; c[2]<=max[2]; ++c[2]) - for (c[3]=min[3]; c[3]<=max[3]; ++c[3]) - { - l[1] = static_cast ((*motion_z_sptr)[c]/grid_spacing[1]); - l[2] = static_cast ((*motion_y_sptr)[c]/grid_spacing[2]); - l[3] = static_cast ((*motion_x_sptr)[c]/grid_spacing[3]); - d[1] = static_cast (c[1]) + l[1]; // for the IRTK version I had c-l, but for Christian's it seems to work as c+l - d[2] = static_cast (c[2]) + l[2]; - d[3] = static_cast (c[3]) + l[3]; - // Temporary fix such that when radioactivity comes from outside is set to 0. - // To fix this properly we need to modify the B-Splines interpolation method by changing the periodicity extrapolation. - if ( (d[1]<=static_cast(min[1])) || (d[1]>=static_cast(max[1])) || // I'm not considering the last plane if linear - (d[2]<=static_cast(min[2])) || (d[2]>=static_cast(max[2])) || // because it's going to use extrapolated data - (d[3]<=static_cast(min[3])) || (d[3]>=static_cast(max[3])) ) // I haven't implemented anything for higher order - out_density[c] = 0.F; - else - out_density[c] = density_interpolation(d); - } + BasicCoordinate<3, int> c; + BasicCoordinate<3, double> d, l; + for (c[1] = min[1]; c[1] <= max[1]; ++c[1]) + for (c[2] = min[2]; c[2] <= max[2]; ++c[2]) + for (c[3] = min[3]; c[3] <= max[3]; ++c[3]) { + l[1] = static_cast((*motion_z_sptr)[c] / grid_spacing[1]); + l[2] = static_cast((*motion_y_sptr)[c] / grid_spacing[2]); + l[3] = static_cast((*motion_x_sptr)[c] / grid_spacing[3]); + d[1] = static_cast(c[1]) + l[1]; // for the IRTK version I had c-l, but for Christian's it seems to work as c+l + d[2] = static_cast(c[2]) + l[2]; + d[3] = static_cast(c[3]) + l[3]; + // Temporary fix such that when radioactivity comes from outside is set to 0. + // To fix this properly we need to modify the B-Splines interpolation method by changing the periodicity extrapolation. + if ((d[1] <= static_cast(min[1])) || + (d[1] >= static_cast(max[1])) || // I'm not considering the last plane if linear + (d[2] <= static_cast(min[2])) || + (d[2] >= static_cast(max[2])) || // because it's going to use extrapolated data + (d[3] <= static_cast(min[3])) || + (d[3] >= static_cast(max[3]))) // I haven't implemented anything for higher order + out_density[c] = 0.F; + else + out_density[c] = density_interpolation(d); + } return out_density; } diff --git a/src/swig/stir.i b/src/swig/stir.i index 45faf0e6ec..f16d52d90b 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -65,6 +65,7 @@ #include "stir/CartesianCoordinate3D.h" #include "stir/IndexRange.h" #include "stir/IndexRange3D.h" +#include "stir/IndexRange4D.h" #include "stir/Array.h" #include "stir/DiscretisedDensity.h" #include "stir/DiscretisedDensityOnCartesianGrid.h" @@ -640,27 +641,95 @@ namespace std { #endif - static Array<3,float> create_array_for_proj_data(const ProjData& proj_data) + static Array<4,float> create_array_for_proj_data(const ProjData& proj_data) { - // int num_sinos=proj_data.get_num_axial_poss(0); - // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) + const int num_non_tof_sinos = proj_data.get_num_non_tof_sinograms(); + Array<4,float> array(IndexRange4D(proj_data.get_num_tof_poss(),num_non_tof_sinos, proj_data.get_num_views(), proj_data.get_num_tangential_poss())); + return array; + } + + // a function for converting ProjData to a 4D array as that's what is easy to use + static Array<4,float> projdata_to_4D(const ProjData& proj_data) + { + + Array<4,float> array = create_array_for_proj_data(proj_data); + Array<4,float>::full_iterator array_iter = array.begin_all(); + // for (int s=0; s<= proj_data.get_max_segment_num(); ++s) // { - // num_sinos += 2*proj_data.get_num_axial_poss(s); + // SegmentBySinogram segment=proj_data.get_segment_by_sinogram(s); + // std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); + // std::advance(array_iter, segment.size_all()); + // if (s!=0) + // { + // segment=proj_data.get_segment_by_sinogram(-s); + // std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); + // std::advance(array_iter, segment.size_all()); + // } // } - int num_sinos = proj_data.get_num_sinograms(); - - Array<3,float> array(IndexRange3D(num_sinos, proj_data.get_num_views(), proj_data.get_num_tangential_poss())); + proj_data.copy_to(array_iter); return array; } - // a function for converting ProjData to a 3D array as that's what is easy to use - static Array<3,float> projdata_to_3D(const ProjData& proj_data) + // inverse of the above function + void fill_proj_data_from_4D(ProjData& proj_data, const Array<4,float>& array) { - Array<3,float> array = create_array_for_proj_data(proj_data); - Array<3,float>::full_iterator array_iter = array.begin_all(); - copy_to(proj_data, array_iter); - return array; + // int num_sinos=proj_data.get_num_axial_poss(0); + // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) + // { + // num_sinos += 2*proj_data.get_num_axial_poss(s); + // } + // if (array.size() != static_cast(num_sinos)|| + // array[0].size() != static_cast(proj_data.get_num_views()) || + // array[0][0].size() != static_cast(proj_data.get_num_tangential_poss())) + // { + // throw std::runtime_error("Incorrect size for filling this projection data"); + // } + Array<4,float>::const_full_iterator array_iter = array.begin_all(); + // + // for (int s=0; s<= proj_data.get_max_segment_num(); ++s) + // { + // SegmentBySinogram segment=proj_data.get_empty_segment_by_sinogram(s); + // // cannot use std::copy sadly as needs end-iterator for range + // for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); + // seg_iter != segment.end_all(); + // /*empty*/) + // *seg_iter++ = *array_iter++; + // proj_data.set_segment(segment); + // + // if (s!=0) + // { + // segment=proj_data.get_empty_segment_by_sinogram(-s); + // for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); + // seg_iter != segment.end_all(); + // /*empty*/) + // *seg_iter++ = *array_iter++; + // proj_data.set_segment(segment); + // } + // } + proj_data.fill_from(array_iter); } + +// static Array<3,float> create_array_for_proj_data(const ProjData& proj_data) +// { +// // int num_sinos=proj_data.get_num_axial_poss(0); +// // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) +// // { +// // num_sinos += 2*proj_data.get_num_axial_poss(s); +// // } +// int num_sinos = proj_data.get_num_sinograms(); + +// Array<3,float> array(IndexRange3D(num_sinos, proj_data.get_num_views(), proj_data.get_num_tangential_poss())); +// return array; +// } + +// static Array<3,float> projdata_to_3D(const ProjData& proj_data) +// { +// Array<3,float> array = create_array_for_proj_data(proj_data); +// Array<3,float>::full_iterator array_iter = array.begin_all(); +// copy_to(proj_data, array_iter); +// return array; +// } + } // end of namespace @@ -809,6 +878,7 @@ namespace std { //%shared_ptr(stir::Array<1,float>); %shared_ptr(stir::Array<2,float>); %shared_ptr(stir::Array<3,float>); +%shared_ptr(stir::Array<4,float>); %shared_ptr(stir::DiscretisedDensity<3,float>); %shared_ptr(stir::DiscretisedDensityOnCartesianGrid<3,float>); %shared_ptr(stir::VoxelsOnCartesianGrid); @@ -1092,6 +1162,7 @@ namespace stir { %template(IndexRange2D) IndexRange<2>; //%template(IndexRange2DVectorWithOffset) VectorWithOffset >; %template(IndexRange3D) IndexRange<3>; + %template(IndexRange4D) IndexRange<4>; %ADD_indexaccess(int,T,VectorWithOffset); %template(FloatVectorWithOffset) VectorWithOffset; @@ -1263,6 +1334,7 @@ namespace stir { // TODO name %template (FloatNumericVectorWithOffset3D) stir::NumericVectorWithOffset, float>; %template(FloatArray3D) stir::Array<3,float>; + %template(FloatArray4D) stir::Array<4,float>; #if 0 %ADD_indexaccess(int,%arg(stir::Array<2,float>),%arg(stir::Array<3,float>)); #endif @@ -1310,11 +1382,11 @@ namespace stir { %include "stir/ExamData.h" %include "stir/Verbosity.h" - %attributeref(stir::Bin, int, segment_num); %attributeref(stir::Bin, int, axial_pos_num); %attributeref(stir::Bin, int, view_num); %attributeref(stir::Bin, int, tangential_pos_num); +%attributeref(stir::Bin, int, timing_pos_num); %attribute(stir::Bin, float, bin_value, get_bin_value, set_bin_value); %include "stir/Bin.h" @@ -1364,11 +1436,11 @@ namespace stir { %extend ProjData { #ifdef SWIGPYTHON - %feature("autodoc", "create a stir 3D Array from the projection data (internal)") to_array; + %feature("autodoc", "create a stir 4D Array from the projection data (internal)") to_array; %newobject to_array; - Array<3,float> to_array() + Array<4,float> to_array() { - Array<3,float> array = swigstir::projdata_to_3D(*$self); + Array<4,float> array = swigstir::projdata_to_4D(*$self); return array; } @@ -1377,10 +1449,15 @@ namespace stir { { if (PyIter_Check(arg)) { + // From TOF branch + Array<4,float> array = swigstir::create_array_for_proj_data(*$self); + swigstir::fill_Array_from_Python_iterator(&array, arg); + swigstir::fill_proj_data_from_4D(*$self, array); + // TODO avoid need for copy to Array - Array<3,float> array = swigstir::create_array_for_proj_data(*$self); - swigstir::fill_Array_from_Python_iterator(&array, arg); - fill_from(*$self, array.begin_all(), array.end_all()); +// Array<3,float> array = swigstir::create_array_for_proj_data(*$self); +// swigstir::fill_Array_from_Python_iterator(&array, arg); +// fill_from(*$self, array.begin_all(), array.end_all()); } else { @@ -1395,14 +1472,16 @@ namespace stir { %newobject to_matlab; mxArray * to_matlab() { - Array<3,float> array = swigstir::projdata_to_3D(*$self); + Array<4,float> array = swigstir::projdata_to_4D(*$self); return swigstir::Array_to_matlab(array); } void fill(const mxArray *pm) { - Array<3,float> array; + Array<4,float> array; swigstir::fill_Array_from_matlab(array, pm, true); + + //swigstir::fill_proj_data_from_4D(*$self, array); fill_from(*$self, array.begin_all(), array.end_all()); } #endif @@ -1418,9 +1497,12 @@ namespace stir { { if (PyIter_Check(arg)) { - Array<3,float> array = swigstir::create_array_for_proj_data(*$self); - swigstir::fill_Array_from_Python_iterator(&array, arg); - fill_from(*$self, array.begin_all(), array.end_all()); + Array<4,float> array = swigstir::create_array_for_proj_data(*$self); + swigstir::fill_Array_from_Python_iterator(&array, arg); + swigstir::fill_proj_data_from_4D(*$self, array); +// Array<3,float> array = swigstir::create_array_for_proj_data(*$self); +// swigstir::fill_Array_from_Python_iterator(&array, arg); +// fill_from(*$self, array.begin_all(), array.end_all()); } else { diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 586585ac27..625390a179 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -40,6 +40,7 @@ Set(${dir_INVOLVED_TEST_EXE_SOURCES} IO/test_IO_ITKMulticomponent test_linear_regression test_stir_math + test_time_of_flight # the next 2 are interactive, so we don't add a test for it, but only compile them test_display test_interpolate @@ -95,6 +96,9 @@ ADD_TEST(NAME test_stir_math COMMAND test_stir_math $ ) set_tests_properties(test_stir_math PROPERTIES DEPENDS stir_math) + +ADD_TEST(NAME test_time_of_flight COMMAND test_time_of_flight) + # Final note: we could use TARGET_FILE to avoid the use of ${CMAKE_CURRENT_BINARY_DIR} in the other tests, but both strategies work fine. endif() diff --git a/src/test/IO/test_IO_DiscretisedDensity.cxx b/src/test/IO/test_IO_DiscretisedDensity.cxx index 690968b669..68aac135cf 100644 --- a/src/test/IO/test_IO_DiscretisedDensity.cxx +++ b/src/test/IO/test_IO_DiscretisedDensity.cxx @@ -70,70 +70,63 @@ START_NAMESPACE_STIR \todo Delete STIRtmp.* files, but that's a bit difficult as we don't know which ones are written. */ -class IOTests_DiscretisedDensity : public IOTests > -{ +class IOTests_DiscretisedDensity : public IOTests> { public: - explicit IOTests_DiscretisedDensity(istream& in) : IOTests(in) {} + explicit IOTests_DiscretisedDensity(istream& in) : IOTests(in) {} protected: - - void create_image(); - void read_image(); - void check_result(); + void create_image(); + void read_image(); + void check_result(); }; -void IOTests_DiscretisedDensity::create_image() -{ - _image_to_write_sptr = create_single_image(); +void +IOTests_DiscretisedDensity::create_image() { + _image_to_write_sptr = create_single_image(); } -void IOTests_DiscretisedDensity::read_image() -{ - // now read it back - unique_ptr > - density_ptr = read_from_file >(_filename); +void +IOTests_DiscretisedDensity::read_image() { + // now read it back + unique_ptr> density_ptr = read_from_file>(_filename); - if(!check(!is_null_ptr(density_ptr), "failed reading")) - return; + if (!check(!is_null_ptr(density_ptr), "failed reading")) + return; - _image_to_read_sptr.reset(density_ptr->clone()); + _image_to_read_sptr.reset(density_ptr->clone()); - if(!check(!is_null_ptr(_image_to_read_sptr), "failed reading")) - return; + if (!check(!is_null_ptr(_image_to_read_sptr), "failed reading")) + return; } -void IOTests_DiscretisedDensity::check_result() -{ - // Cast the discretised density to voxels on cartesian grids to check grid spacing - VoxelsOnCartesianGrid *image_to_write_ptr = dynamic_cast *>(_image_to_write_sptr.get()); - VoxelsOnCartesianGrid *image_to_read_ptr = dynamic_cast *>(_image_to_read_sptr.get()); +void +IOTests_DiscretisedDensity::check_result() { + // Cast the discretised density to voxels on cartesian grids to check grid spacing + VoxelsOnCartesianGrid* image_to_write_ptr = dynamic_cast*>(_image_to_write_sptr.get()); + VoxelsOnCartesianGrid* image_to_read_ptr = dynamic_cast*>(_image_to_read_sptr.get()); - compare_images(*image_to_write_ptr, *image_to_read_ptr); + compare_images(*image_to_write_ptr, *image_to_read_ptr); - // Check TimeFrameDefinitions in ExamInfo. Not all formats support this. Skip if ITK - if (_output_file_format_sptr->get_registered_name() != "ITK") - check_exam_info(image_to_write_ptr->get_exam_info(), image_to_read_ptr->get_exam_info()); + // Check TimeFrameDefinitions in ExamInfo. Not all formats support this. Skip if ITK + if (_output_file_format_sptr->get_registered_name() != "ITK") + check_exam_info(image_to_write_ptr->get_exam_info(), image_to_read_ptr->get_exam_info()); } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 2) - { +int +main(int argc, char** argv) { + if (argc != 2) { cerr << "Usage : " << argv[0] << " filename\n" << "See source file for the format of this file.\n\n"; return EXIT_FAILURE; } - ifstream in(argv[1]); - if (!in) - { - cerr << argv[0] - << ": Error opening input file " << argv[1] << "\nExiting.\n"; + if (!in) { + cerr << argv[0] << ": Error opening input file " << argv[1] << "\nExiting.\n"; return EXIT_FAILURE; } diff --git a/src/test/IO/test_IO_DynamicDiscretisedDensity.cxx b/src/test/IO/test_IO_DynamicDiscretisedDensity.cxx index 48bc419e80..6022d1b036 100644 --- a/src/test/IO/test_IO_DynamicDiscretisedDensity.cxx +++ b/src/test/IO/test_IO_DynamicDiscretisedDensity.cxx @@ -71,98 +71,97 @@ START_NAMESPACE_STIR \todo Delete STIRtmp.* files, but that's a bit difficult as we don't know which ones are written. */ -class IOTests_DynamicDiscretisedDensity : public IOTests -{ +class IOTests_DynamicDiscretisedDensity : public IOTests { public: - explicit IOTests_DynamicDiscretisedDensity(istream& in) : IOTests(in) {} + explicit IOTests_DynamicDiscretisedDensity(istream& in) : IOTests(in) {} protected: - - void create_image(); - void check_result(); + void create_image(); + void check_result(); }; -void IOTests_DynamicDiscretisedDensity::create_image() -{ - double im_1_start = 20; - double im_1_end = 45; - double im_2_start = 50; - double im_2_end = 93; - - shared_ptr > dyn_im_1_sptr = create_single_image(); - shared_ptr > dyn_im_2_sptr = create_single_image(); - shared_ptr > dummy_im_sptr = create_single_image(); - - dyn_im_1_sptr->fill(2.); - dyn_im_2_sptr->fill(1.); - ExamInfo exam_info = dyn_im_1_sptr->get_exam_info(); - exam_info.time_frame_definitions.set_time_frame(1,im_1_start, im_1_end); - dyn_im_1_sptr->set_exam_info(exam_info); - exam_info.time_frame_definitions.set_time_frame(1,im_2_start, im_2_end); - dyn_im_2_sptr->set_exam_info(exam_info); - - // Create a scanner (any will do) - shared_ptr scanner_sptr(new Scanner(Scanner::Advance)); - - TimeFrameDefinitions tdefs; - tdefs.set_num_time_frames(2); - tdefs.set_time_frame(1,im_1_start,im_1_end); - tdefs.set_time_frame(2,im_2_start,im_2_end); - - _image_to_write_sptr.reset(new DynamicDiscretisedDensity(tdefs,dummy_im_sptr->get_exam_info().start_time_in_secs_since_1970,scanner_sptr,dummy_im_sptr)); - _image_to_write_sptr->set_density(*dyn_im_1_sptr,1); - _image_to_write_sptr->set_density(*dyn_im_2_sptr,2); - exam_info = _image_to_write_sptr->get_exam_info(); - exam_info.set_high_energy_thres(dummy_im_sptr->get_exam_info().get_high_energy_thres()); - exam_info.set_low_energy_thres(dummy_im_sptr->get_exam_info().get_low_energy_thres()); - _image_to_write_sptr->set_exam_info(exam_info); +void +IOTests_DynamicDiscretisedDensity::create_image() { + double im_1_start = 20; + double im_1_end = 45; + double im_2_start = 50; + double im_2_end = 93; + + shared_ptr> dyn_im_1_sptr = create_single_image(); + shared_ptr> dyn_im_2_sptr = create_single_image(); + shared_ptr> dummy_im_sptr = create_single_image(); + + dyn_im_1_sptr->fill(2.); + dyn_im_2_sptr->fill(1.); + ExamInfo exam_info = dyn_im_1_sptr->get_exam_info(); + exam_info.time_frame_definitions.set_time_frame(1, im_1_start, im_1_end); + dyn_im_1_sptr->set_exam_info(exam_info); + exam_info.time_frame_definitions.set_time_frame(1, im_2_start, im_2_end); + dyn_im_2_sptr->set_exam_info(exam_info); + + // Create a scanner (any will do) + shared_ptr scanner_sptr(new Scanner(Scanner::Advance)); + + TimeFrameDefinitions tdefs; + tdefs.set_num_time_frames(2); + tdefs.set_time_frame(1, im_1_start, im_1_end); + tdefs.set_time_frame(2, im_2_start, im_2_end); + + _image_to_write_sptr.reset(new DynamicDiscretisedDensity(tdefs, dummy_im_sptr->get_exam_info().start_time_in_secs_since_1970, + scanner_sptr, dummy_im_sptr)); + _image_to_write_sptr->set_density(*dyn_im_1_sptr, 1); + _image_to_write_sptr->set_density(*dyn_im_2_sptr, 2); + exam_info = _image_to_write_sptr->get_exam_info(); + exam_info.set_high_energy_thres(dummy_im_sptr->get_exam_info().get_high_energy_thres()); + exam_info.set_low_energy_thres(dummy_im_sptr->get_exam_info().get_low_energy_thres()); + _image_to_write_sptr->set_exam_info(exam_info); } -void IOTests_DynamicDiscretisedDensity::check_result() -{ - set_tolerance(.00001); +void +IOTests_DynamicDiscretisedDensity::check_result() { + set_tolerance(.00001); + + check_if_equal(_image_to_read_sptr->get_densities().size(), _image_to_write_sptr->get_densities().size(), + "test number of dynamic images"); - check_if_equal(_image_to_read_sptr->get_densities().size(),_image_to_write_sptr->get_densities().size(), "test number of dynamic images"); - - // Check the exam info - std::cerr << "\tChecking the exam info...\n"; - check_exam_info(_image_to_write_sptr->get_exam_info(),_image_to_read_sptr->get_exam_info()); + // Check the exam info + std::cerr << "\tChecking the exam info...\n"; + check_exam_info(_image_to_write_sptr->get_exam_info(), _image_to_read_sptr->get_exam_info()); - for (int i=1; i<=_image_to_read_sptr->get_densities().size(); ++i) { + for (int i = 1; i <= _image_to_read_sptr->get_densities().size(); ++i) { - std::cerr << "\t\tChecking dynamic image " << i << "...\n"; - - // Cast the discretised density to voxels on cartesian grids to check grid spacing - VoxelsOnCartesianGrid *image_to_write_ptr = dynamic_cast *>(&_image_to_write_sptr->get_density(i)); - VoxelsOnCartesianGrid *image_to_read_ptr = dynamic_cast *>(&_image_to_read_sptr->get_density(i)); + std::cerr << "\t\tChecking dynamic image " << i << "...\n"; - if (is_null_ptr(image_to_write_ptr) || is_null_ptr(image_to_read_ptr)) { - everything_ok = false; - return; - } + // Cast the discretised density to voxels on cartesian grids to check grid spacing + VoxelsOnCartesianGrid* image_to_write_ptr = + dynamic_cast*>(&_image_to_write_sptr->get_density(i)); + VoxelsOnCartesianGrid* image_to_read_ptr = + dynamic_cast*>(&_image_to_read_sptr->get_density(i)); - compare_images(*image_to_write_ptr, *image_to_read_ptr); + if (is_null_ptr(image_to_write_ptr) || is_null_ptr(image_to_read_ptr)) { + everything_ok = false; + return; } + + compare_images(*image_to_write_ptr, *image_to_read_ptr); + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 2) - { +int +main(int argc, char** argv) { + if (argc != 2) { cerr << "Usage : " << argv[0] << " filename\n" << "See source file for the format of this file.\n\n"; return EXIT_FAILURE; } ifstream in(argv[1]); - if (!in) - { - cerr << argv[0] - << ": Error opening input file " << argv[1] << "\nExiting.\n"; + if (!in) { + cerr << argv[0] << ": Error opening input file " << argv[1] << "\nExiting.\n"; return EXIT_FAILURE; } diff --git a/src/test/IO/test_IO_ITKMulticomponent.cxx b/src/test/IO/test_IO_ITKMulticomponent.cxx index 0f4d3c4a93..0fb8740c3d 100644 --- a/src/test/IO/test_IO_ITKMulticomponent.cxx +++ b/src/test/IO/test_IO_ITKMulticomponent.cxx @@ -40,60 +40,57 @@ START_NAMESPACE_STIR \ingroup test \brief A simple class to test the reading of multicomponent ITK images. */ -class IOTests_ITKMulticomponent : public RunTests -{ +class IOTests_ITKMulticomponent : public RunTests { public: - explicit IOTests_ITKMulticomponent(const std::string &multi) : - _multi(multi) {} + explicit IOTests_ITKMulticomponent(const std::string& multi) : _multi(multi) {} - void run_tests(); + void run_tests(); protected: - - std::string _multi; + std::string _multi; }; -void IOTests_ITKMulticomponent::run_tests() -{ - typedef VoxelsOnCartesianGrid > VoxelsCoords; +void +IOTests_ITKMulticomponent::run_tests() { + typedef VoxelsOnCartesianGrid> VoxelsCoords; - // Read the files - std::cerr << "\nReading: " << _multi << "\n"; + // Read the files + std::cerr << "\nReading: " << _multi << "\n"; - try { - shared_ptr voxels_coords(read_from_file(_multi)); + try { + shared_ptr voxels_coords(read_from_file(_multi)); - check(!is_null_ptr(voxels_coords), "failed reading %s"); + check(!is_null_ptr(voxels_coords), "failed reading %s"); - // Check sizes - check_if_equal(voxels_coords->size(), 64); - check_if_equal(voxels_coords->at(0).size(), 62); - check_if_equal(voxels_coords->at(0).at(0).size(), 63); - check_if_equal(voxels_coords->at(0).at(0).at(0).size(), 3); + // Check sizes + check_if_equal(voxels_coords->size(), 64); + check_if_equal(voxels_coords->at(0).size(), 62); + check_if_equal(voxels_coords->at(0).at(0).size(), 63); + check_if_equal(voxels_coords->at(0).at(0).at(0).size(), 3); - // Check voxel sizes - check_if_equal(voxels_coords->get_voxel_size()[1], 4.0625F); - check_if_equal(voxels_coords->get_voxel_size()[2], 4.0625F); - check_if_equal(voxels_coords->get_voxel_size()[3], 4.0625F); + // Check voxel sizes + check_if_equal(voxels_coords->get_voxel_size()[1], 4.0625F); + check_if_equal(voxels_coords->get_voxel_size()[2], 4.0625F); + check_if_equal(voxels_coords->get_voxel_size()[3], 4.0625F); - } catch(...) { - everything_ok = false; - } + } catch (...) { + everything_ok = false; + } } END_NAMESPACE_STD USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 2) { - std::cerr << "Usage : " << argv[0] << " filename\n"; - return EXIT_FAILURE; - } +int +main(int argc, char** argv) { + if (argc != 2) { + std::cerr << "Usage : " << argv[0] << " filename\n"; + return EXIT_FAILURE; + } - IOTests_ITKMulticomponent tests(argv[1]); + IOTests_ITKMulticomponent tests(argv[1]); - tests.run_tests(); + tests.run_tests(); - return tests.main_return_value(); + return tests.main_return_value(); } diff --git a/src/test/IO/test_IO_ParametricDiscretisedDensity.cxx b/src/test/IO/test_IO_ParametricDiscretisedDensity.cxx index ba4a42775c..86b0f7df8f 100644 --- a/src/test/IO/test_IO_ParametricDiscretisedDensity.cxx +++ b/src/test/IO/test_IO_ParametricDiscretisedDensity.cxx @@ -72,102 +72,105 @@ START_NAMESPACE_STIR \todo Delete STIRtmp.* files, but that's a bit difficult as we don't know which ones are written. */ -class IOTests_ParametricDiscretisedDensity : public IOTests -{ +class IOTests_ParametricDiscretisedDensity : public IOTests { public: - explicit IOTests_ParametricDiscretisedDensity(istream& in) : IOTests(in) {} + explicit IOTests_ParametricDiscretisedDensity(istream& in) : IOTests(in) {} protected: - void create_image(); - void check_result(); + void create_image(); + void check_result(); }; -void IOTests_ParametricDiscretisedDensity::create_image() -{ - shared_ptr > param_1_sptr = create_single_image(); - shared_ptr > param_2_sptr = create_single_image(); - shared_ptr > dummy_im_sptr = create_single_image(); - - //! Setup the scanner details first - const Scanner::Type test_scanner=Scanner::E966; - const shared_ptr scanner_sptr(new Scanner(test_scanner)); - VectorWithOffset num_axial_pos_per_segment; num_axial_pos_per_segment.resize(0,0); num_axial_pos_per_segment[0]=48; - VectorWithOffset min_ring_diff; min_ring_diff.resize(0,0); min_ring_diff[0]=0; - VectorWithOffset max_ring_diff; max_ring_diff.resize(0,0); max_ring_diff[0]=0; - const int num_views=144; const int num_tangential_poss=144; - - const float zoom=1.F; - - const CartesianCoordinate3D sizes ( - dummy_im_sptr->get_z_size(), - dummy_im_sptr->get_y_size(), - dummy_im_sptr->get_x_size()); - - ProjDataInfoCylindricalNoArcCorr proj_data_info(scanner_sptr,num_axial_pos_per_segment,min_ring_diff,max_ring_diff,num_views,num_tangential_poss); - - _image_to_write_sptr.reset(new ParametricVoxelsOnCartesianGrid(ParametricVoxelsOnCartesianGridBaseType(proj_data_info,zoom,dummy_im_sptr->get_grid_spacing(),sizes))); - - // Fill the first param - param_2_sptr->fill(2.F); - _image_to_write_sptr->update_parametric_image(*param_1_sptr,1); - - // Fill the second param with 1's - param_2_sptr->fill(1.F); - _image_to_write_sptr->update_parametric_image(*param_2_sptr,2); - - // Set the time definitions - ExamInfo exam_info = _image_to_write_sptr->get_exam_info(); - exam_info.set_time_frame_definitions(dummy_im_sptr->get_exam_info().get_time_frame_definitions()); - _image_to_write_sptr->set_exam_info(exam_info); +void +IOTests_ParametricDiscretisedDensity::create_image() { + shared_ptr> param_1_sptr = create_single_image(); + shared_ptr> param_2_sptr = create_single_image(); + shared_ptr> dummy_im_sptr = create_single_image(); + + //! Setup the scanner details first + const Scanner::Type test_scanner = Scanner::E966; + const shared_ptr scanner_sptr(new Scanner(test_scanner)); + VectorWithOffset num_axial_pos_per_segment; + num_axial_pos_per_segment.resize(0, 0); + num_axial_pos_per_segment[0] = 48; + VectorWithOffset min_ring_diff; + min_ring_diff.resize(0, 0); + min_ring_diff[0] = 0; + VectorWithOffset max_ring_diff; + max_ring_diff.resize(0, 0); + max_ring_diff[0] = 0; + const int num_views = 144; + const int num_tangential_poss = 144; + + const float zoom = 1.F; + + const CartesianCoordinate3D sizes(dummy_im_sptr->get_z_size(), dummy_im_sptr->get_y_size(), dummy_im_sptr->get_x_size()); + + ProjDataInfoCylindricalNoArcCorr proj_data_info(scanner_sptr, num_axial_pos_per_segment, min_ring_diff, max_ring_diff, + num_views, num_tangential_poss); + + _image_to_write_sptr.reset(new ParametricVoxelsOnCartesianGrid( + ParametricVoxelsOnCartesianGridBaseType(proj_data_info, zoom, dummy_im_sptr->get_grid_spacing(), sizes))); + + // Fill the first param + param_2_sptr->fill(2.F); + _image_to_write_sptr->update_parametric_image(*param_1_sptr, 1); + + // Fill the second param with 1's + param_2_sptr->fill(1.F); + _image_to_write_sptr->update_parametric_image(*param_2_sptr, 2); + + // Set the time definitions + ExamInfo exam_info = _image_to_write_sptr->get_exam_info(); + exam_info.set_time_frame_definitions(dummy_im_sptr->get_exam_info().get_time_frame_definitions()); + _image_to_write_sptr->set_exam_info(exam_info); } -void IOTests_ParametricDiscretisedDensity::check_result() -{ - set_tolerance(.00001); +void +IOTests_ParametricDiscretisedDensity::check_result() { + set_tolerance(.00001); - if(!check_if_equal(_image_to_read_sptr->get_num_params(),_image_to_write_sptr->get_num_params(), "test number of dynamic images")) - return; + if (!check_if_equal(_image_to_read_sptr->get_num_params(), _image_to_write_sptr->get_num_params(), + "test number of dynamic images")) + return; - // Check the exam info - std::cerr << "\tChecking the exam info...\n"; - check_exam_info(_image_to_write_sptr->get_exam_info(),_image_to_read_sptr->get_exam_info()); + // Check the exam info + std::cerr << "\tChecking the exam info...\n"; + check_exam_info(_image_to_write_sptr->get_exam_info(), _image_to_read_sptr->get_exam_info()); - for (int i=1; i<=_image_to_read_sptr->get_num_params(); ++i) { + for (int i = 1; i <= _image_to_read_sptr->get_num_params(); ++i) { - std::cerr << "\t\tChecking kinetic parameter " << i << "...\n"; + std::cerr << "\t\tChecking kinetic parameter " << i << "...\n"; - const VoxelsOnCartesianGrid &image_to_write = - _image_to_write_sptr->construct_single_density(i); + const VoxelsOnCartesianGrid& image_to_write = _image_to_write_sptr->construct_single_density(i); - const VoxelsOnCartesianGrid &image_to_read = - _image_to_read_sptr->construct_single_density(i); + const VoxelsOnCartesianGrid& image_to_read = _image_to_read_sptr->construct_single_density(i); - compare_images(image_to_write, image_to_read); - } + compare_images(image_to_write, image_to_read); + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 2) { - cerr << "Usage : " << argv[0] << " filename\n" - << "See source file for the format of this file.\n\n"; - return EXIT_FAILURE; - } +int +main(int argc, char** argv) { + if (argc != 2) { + cerr << "Usage : " << argv[0] << " filename\n" + << "See source file for the format of this file.\n\n"; + return EXIT_FAILURE; + } - ifstream in(argv[1]); - if (!in) { - cerr << argv[0] - << ": Error opening input file " << argv[1] << "\nExiting.\n"; - return EXIT_FAILURE; - } + ifstream in(argv[1]); + if (!in) { + cerr << argv[0] << ": Error opening input file " << argv[1] << "\nExiting.\n"; + return EXIT_FAILURE; + } - IOTests_ParametricDiscretisedDensity tests(in); + IOTests_ParametricDiscretisedDensity tests(in); - if (tests.is_everything_ok()) - tests.run_tests(); + if (tests.is_everything_ok()) + tests.run_tests(); - return tests.main_return_value(); + return tests.main_return_value(); } diff --git a/src/test/NiftyPET_projector/test_ProjectorNiftyPET_adjoint.cxx b/src/test/NiftyPET_projector/test_ProjectorNiftyPET_adjoint.cxx index f18bfb1482..6620643e89 100644 --- a/src/test/NiftyPET_projector/test_ProjectorNiftyPET_adjoint.cxx +++ b/src/test/NiftyPET_projector/test_ProjectorNiftyPET_adjoint.cxx @@ -42,411 +42,364 @@ using namespace std; \ingroup test \brief Test class for GPU projectors */ -class TestGPUProjectors : public RunTests -{ +class TestGPUProjectors : public RunTests { public: - //! Constructor - explicit TestGPUProjectors(const unsigned num_attempts) - : _num_attempts(num_attempts), - _time_fwrd(0), _time_back(0) {} + //! Constructor + explicit TestGPUProjectors(const unsigned num_attempts) : _num_attempts(num_attempts), _time_fwrd(0), _time_back(0) {} - /// Destructor - virtual ~TestGPUProjectors() {} + /// Destructor + virtual ~TestGPUProjectors() {} - /// Run tests - void run_tests(); + /// Run tests + void run_tests(); protected: - - /// Set up - void set_up(); - /// Set up the image - void set_up_image(); - /// Set up the sinogram - void set_up_sino(); - /// test the adjoint multiple times - void test_adjoints(); - - const unsigned _num_attempts; - ForwardProjectorByBinNiftyPET _projector_fwrd; - BackProjectorByBinNiftyPET _projector_back; - shared_ptr > _image_sptr; - shared_ptr _sino_sptr; - shared_ptr > _projected_image_sptr; - shared_ptr _projected_sino_sptr; - double _time_fwrd, _time_back; - std::vector _results; + /// Set up + void set_up(); + /// Set up the image + void set_up_image(); + /// Set up the sinogram + void set_up_sino(); + /// test the adjoint multiple times + void test_adjoints(); + + const unsigned _num_attempts; + ForwardProjectorByBinNiftyPET _projector_fwrd; + BackProjectorByBinNiftyPET _projector_back; + shared_ptr> _image_sptr; + shared_ptr _sino_sptr; + shared_ptr> _projected_image_sptr; + shared_ptr _projected_sino_sptr; + double _time_fwrd, _time_back; + std::vector _results; }; -static int get_rand(const int lower, const int upper) -{ - return rand() % upper + lower; +static int +get_rand(const int lower, const int upper) { + return rand() % upper + lower; } -static float get_rand(const float lower, const float upper) -{ - return lower + static_cast(rand()) / (static_cast(RAND_MAX/(upper-lower))); +static float +get_rand(const float lower, const float upper) { + return lower + static_cast(rand()) / (static_cast(RAND_MAX / (upper - lower))); } -static -CartesianCoordinate3D -get_rand_point(const CartesianCoordinate3D &min, const CartesianCoordinate3D &max) -{ - return CartesianCoordinate3D( - get_rand(min.at(1), max.at(1)), - get_rand(min.at(2), max.at(2)), - get_rand(min.at(3), max.at(3))); +static CartesianCoordinate3D +get_rand_point(const CartesianCoordinate3D& min, const CartesianCoordinate3D& max) { + return CartesianCoordinate3D(get_rand(min.at(1), max.at(1)), get_rand(min.at(2), max.at(2)), + get_rand(min.at(3), max.at(3))); } -static -CartesianCoordinate3D -get_rand_point(const float min, const float max) -{ - return CartesianCoordinate3D( - get_rand(min, max), - get_rand(min, max), - get_rand(min, max)); +static CartesianCoordinate3D +get_rand_point(const float min, const float max) { + return CartesianCoordinate3D(get_rand(min, max), get_rand(min, max), get_rand(min, max)); } -static float find_max(const ProjDataInMemory &prj) -{ - // Get number of elements - unsigned num_elements = prj.size_all(); +static float +find_max(const ProjDataInMemory& prj) { + // Get number of elements + unsigned num_elements = prj.size_all(); - // Create arrays - std::vector arr(num_elements); - prj.copy_to(arr.begin()); - return *std::max_element(arr.begin(),arr.end()); + // Create arrays + std::vector arr(num_elements); + prj.copy_to(arr.begin()); + return *std::max_element(arr.begin(), arr.end()); } void -TestGPUProjectors:: -set_up() -{ - std::cerr << "Setting up...\n"; - - // random seed - srand(time(NULL)); - - set_up_sino(); - set_up_image(); - - std::cerr << "\tSetting up projectors...\n"; - _projector_fwrd.set_verbosity(false); - _projector_fwrd.set_up(_sino_sptr->get_proj_data_info_sptr(),_image_sptr); - _projector_back.set_verbosity(false); - _projector_back.set_up(_sino_sptr->get_proj_data_info_sptr(),_image_sptr); +TestGPUProjectors::set_up() { + std::cerr << "Setting up...\n"; + + // random seed + srand(time(NULL)); + + set_up_sino(); + set_up_image(); + + std::cerr << "\tSetting up projectors...\n"; + _projector_fwrd.set_verbosity(false); + _projector_fwrd.set_up(_sino_sptr->get_proj_data_info_sptr(), _image_sptr); + _projector_back.set_verbosity(false); + _projector_back.set_up(_sino_sptr->get_proj_data_info_sptr(), _image_sptr); } void -TestGPUProjectors:: -set_up_image() -{ - std::cerr << "\tSetting up images...\n"; - - BasicCoordinate<3, int> min_image_indices(make_coordinate(0, -160, -160)); - BasicCoordinate<3, int> max_image_indices(make_coordinate(126, 159, 159)); - IndexRange<3> range = IndexRange<3>(min_image_indices,max_image_indices); - - _image_sptr = MAKE_SHARED >( - _sino_sptr->get_exam_info_sptr(), - range, - CartesianCoordinate3D(0.f,0.f,0.f), - CartesianCoordinate3D(2.03125f, 2.08626f, 2.08626f)); - - // Fill - _image_sptr->fill(0.f); - - // Make projected image a copy - _projected_image_sptr.reset(_image_sptr->clone()); +TestGPUProjectors::set_up_image() { + std::cerr << "\tSetting up images...\n"; + + BasicCoordinate<3, int> min_image_indices(make_coordinate(0, -160, -160)); + BasicCoordinate<3, int> max_image_indices(make_coordinate(126, 159, 159)); + IndexRange<3> range = IndexRange<3>(min_image_indices, max_image_indices); + + _image_sptr = MAKE_SHARED>(_sino_sptr->get_exam_info_sptr(), range, + CartesianCoordinate3D(0.f, 0.f, 0.f), + CartesianCoordinate3D(2.03125f, 2.08626f, 2.08626f)); + + // Fill + _image_sptr->fill(0.f); + + // Make projected image a copy + _projected_image_sptr.reset(_image_sptr->clone()); } void -TestGPUProjectors:: -set_up_sino() -{ - std::cerr << "\tSetting up sinograms...\n"; - // Create scanner - shared_ptr scanner_sptr(new Scanner(Scanner::Siemens_mMR)); - - // ExamInfo - shared_ptr exam_info_sptr(new ExamInfo); - exam_info_sptr->imaging_modality = ImagingModality::PT; - - shared_ptr proj_data_info_sptr( - ProjDataInfo::construct_proj_data_info( - scanner_sptr, - 11, // span - /* mMR needs maxDelta of */60, - scanner_sptr->get_num_detectors_per_ring()/2, - scanner_sptr->get_max_num_non_arccorrected_bins(), - /* arc_correction*/false)); - - _sino_sptr = MAKE_SHARED(exam_info_sptr,proj_data_info_sptr); - - // Create vector to be able to fill sinogram - const size_t num_elements = _sino_sptr->size_all(); - std::vector arr(num_elements); - for (unsigned i=0; ifill_from(arr.begin()); - - _projected_sino_sptr = MAKE_SHARED(*_sino_sptr); +TestGPUProjectors::set_up_sino() { + std::cerr << "\tSetting up sinograms...\n"; + // Create scanner + shared_ptr scanner_sptr(new Scanner(Scanner::Siemens_mMR)); + + // ExamInfo + shared_ptr exam_info_sptr(new ExamInfo); + exam_info_sptr->imaging_modality = ImagingModality::PT; + + shared_ptr proj_data_info_sptr( + ProjDataInfo::construct_proj_data_info(scanner_sptr, + 11, // span + /* mMR needs maxDelta of */ 60, scanner_sptr->get_num_detectors_per_ring() / 2, + scanner_sptr->get_max_num_non_arccorrected_bins(), + /* arc_correction*/ false)); + + _sino_sptr = MAKE_SHARED(exam_info_sptr, proj_data_info_sptr); + + // Create vector to be able to fill sinogram + const size_t num_elements = _sino_sptr->size_all(); + std::vector arr(num_elements); + for (unsigned i = 0; i < num_elements; ++i) + arr[i] = float(i); + _sino_sptr->fill_from(arr.begin()); + + _projected_sino_sptr = MAKE_SHARED(*_sino_sptr); } -static -void -get_random_sino(ProjData &sino) -{ - std::cerr << "Getting random sinogram...\n"; - - const size_t num_elements = sino.size_all(); - std::vector arr(num_elements,0.f); - - // Number of voxels to fill - const unsigned num_rand_voxels = get_rand(100,2000); - for (unsigned j=0; j arr(num_elements, 0.f); + + // Number of voxels to fill + const unsigned num_rand_voxels = get_rand(100, 2000); + for (unsigned j = 0; j < num_rand_voxels; ++j) { + // Get random index + const unsigned idx = get_rand(0, num_elements - 1); + const float val = get_rand(1.f, 100.f); + arr[idx] = val; + } + sino.fill_from(arr.begin()); } -static -void -get_random_image(VoxelsOnCartesianGrid &im) -{ - std::cerr << "Getting random image...\n"; - - im.fill(0.f); - auto temp = *im.clone(); - - CartesianCoordinate3D min = im.get_physical_coordinates_for_indices(im.get_min_indices()); - CartesianCoordinate3D max = im.get_physical_coordinates_for_indices(im.get_max_indices()); - CartesianCoordinate3D num_samles = {10,10,10}; - const float min_radius = 20.f; - const float max_radius = 100.f; - const float min_intensity = 10.f; - const float max_intensity = 100.f; - - // Keep looping until random image contains non-zeroes - // (in case all ellipsoids were in part that got truncated) - while (true) { - - const unsigned num_ellipsoids = get_rand(1,5); - - for (unsigned j=0; j 1e-4f) - break; - else - std::cout << "\nRandom image contains all zeroes, regenerating...\n"; +static void +get_random_image(VoxelsOnCartesianGrid& im) { + std::cerr << "Getting random image...\n"; + + im.fill(0.f); + auto temp = *im.clone(); + + CartesianCoordinate3D min = im.get_physical_coordinates_for_indices(im.get_min_indices()); + CartesianCoordinate3D max = im.get_physical_coordinates_for_indices(im.get_max_indices()); + CartesianCoordinate3D num_samles = {10, 10, 10}; + const float min_radius = 20.f; + const float max_radius = 100.f; + const float min_intensity = 10.f; + const float max_intensity = 100.f; + + // Keep looping until random image contains non-zeroes + // (in case all ellipsoids were in part that got truncated) + while (true) { + + const unsigned num_ellipsoids = get_rand(1, 5); + + for (unsigned j = 0; j < num_ellipsoids; ++j) { + + // Get radii, centre and intensity of ellipsoid + const auto radii = get_rand_point(min_radius, max_radius); + const auto centre = get_rand_point(min, max); + const float intensity = get_rand(min_intensity, max_intensity); + // Create shape + Ellipsoid ellipsoid(radii, centre); + // Get shape as image + temp.fill(0.f); + ellipsoid.construct_volume(temp, num_samles); + temp *= intensity; + // Add to output image + im += temp; } + + // Truncate it to a small cylinder + truncate_rim(im, 17); + + // Check that image contains non-zeros. + if (im.find_max() > 1e-4f) + break; + else + std::cout << "\nRandom image contains all zeroes, regenerating...\n"; + } } -static -void -forward_project(ProjData &sino, const VoxelsOnCartesianGrid &im, ForwardProjectorByBinNiftyPET &projector, double &time) -{ - std::cerr << "Forward projecting...\n"; - sino.fill(0.f); +static void +forward_project(ProjData& sino, const VoxelsOnCartesianGrid& im, ForwardProjectorByBinNiftyPET& projector, double& time) { + std::cerr << "Forward projecting...\n"; + sino.fill(0.f); - CPUTimer timer; - timer.start(); + CPUTimer timer; + timer.start(); - projector.set_input(im); - projector.forward_project(sino); + projector.set_input(im); + projector.forward_project(sino); - timer.stop(); - time += timer.value(); + timer.stop(); + time += timer.value(); } -static -void -back_project(VoxelsOnCartesianGrid &im, const ProjData &sino, BackProjectorByBinNiftyPET &projector, double &time) -{ - std::cerr << "Back projecting...\n"; - im.fill(0.f); +static void +back_project(VoxelsOnCartesianGrid& im, const ProjData& sino, BackProjectorByBinNiftyPET& projector, double& time) { + std::cerr << "Back projecting...\n"; + im.fill(0.f); - CPUTimer timer; - timer.start(); + CPUTimer timer; + timer.start(); - projector.start_accumulating_in_new_target(); - projector.back_project(sino); - projector.get_output(im); + projector.start_accumulating_in_new_target(); + projector.back_project(sino); + projector.get_output(im); - timer.stop(); - time += timer.value(); + timer.stop(); + time += timer.value(); } -static float get_inner_product( - const VoxelsOnCartesianGrid &im1, - const VoxelsOnCartesianGrid &im2) -{ - return std::inner_product(im1.begin_all(),im1.end_all(),im2.begin_all(),0.f); +static float +get_inner_product(const VoxelsOnCartesianGrid& im1, const VoxelsOnCartesianGrid& im2) { + return std::inner_product(im1.begin_all(), im1.end_all(), im2.begin_all(), 0.f); } -static float get_inner_product( - const ProjDataInMemory &proj1, - const ProjDataInMemory &proj2) -{ - // Get number of elements - const size_t num_elements = proj1.size_all(); +static float +get_inner_product(const ProjDataInMemory& proj1, const ProjDataInMemory& proj2) { + // Get number of elements + const size_t num_elements = proj1.size_all(); - // Create arrays - std::vector arr1(num_elements), arr2(num_elements); - proj1.copy_to(arr1.begin()); - proj2.copy_to(arr2.begin()); + // Create arrays + std::vector arr1(num_elements), arr2(num_elements); + proj1.copy_to(arr1.begin()); + proj2.copy_to(arr2.begin()); - return std::inner_product(arr1.begin(),arr1.end(),arr2.begin(),0.f); + return std::inner_product(arr1.begin(), arr1.end(), arr2.begin(), 0.f); } -static -float -test_inner_product(const VoxelsOnCartesianGrid &im, const ProjData &sino, - const VoxelsOnCartesianGrid &im_proj, const ProjData &sino_proj) -{ - std::cerr << "Checking inner products...\n"; - const float inner_product_images = get_inner_product(im,im_proj); - const float inner_product_sinos = get_inner_product(sino, sino_proj); - - std::cout << "\tinner product between images = " << inner_product_images << "\n"; - std::cout << "\tinner product between sinograms = " << inner_product_sinos << "\n"; - - if (std::abs(inner_product_images) + std::abs(inner_product_sinos) < 1e-4f) { - std::cout << "\n\t\tCan't perform adjoint test as both equal zero...\n"; - std::cout << "\t\tmax in input image = " << im.find_max() << "\n"; - std::cout << "\t\tmax in projected image = " << im_proj.find_max() << "\n"; - std::cout << "\t\tmax in input image = " << find_max(sino) << "\n"; - std::cout << "\t\tmax in projected image = " << find_max(sino_proj) << "\n"; - return -1.f; - } - - float adjoint_test = - std::abs(inner_product_images - inner_product_sinos) / - (0.5f * (std::abs(inner_product_images) + std::abs(inner_product_sinos))); - std::cout << "\t| - | / 0.5*(||+||) = " << adjoint_test << "\n"; - return adjoint_test; +static float +test_inner_product(const VoxelsOnCartesianGrid& im, const ProjData& sino, const VoxelsOnCartesianGrid& im_proj, + const ProjData& sino_proj) { + std::cerr << "Checking inner products...\n"; + const float inner_product_images = get_inner_product(im, im_proj); + const float inner_product_sinos = get_inner_product(sino, sino_proj); + + std::cout << "\tinner product between images = " << inner_product_images << "\n"; + std::cout << "\tinner product between sinograms = " << inner_product_sinos << "\n"; + + if (std::abs(inner_product_images) + std::abs(inner_product_sinos) < 1e-4f) { + std::cout << "\n\t\tCan't perform adjoint test as both equal zero...\n"; + std::cout << "\t\tmax in input image = " << im.find_max() << "\n"; + std::cout << "\t\tmax in projected image = " << im_proj.find_max() << "\n"; + std::cout << "\t\tmax in input image = " << find_max(sino) << "\n"; + std::cout << "\t\tmax in projected image = " << find_max(sino_proj) << "\n"; + return -1.f; + } + + float adjoint_test = std::abs(inner_product_images - inner_product_sinos) / + (0.5f * (std::abs(inner_product_images) + std::abs(inner_product_sinos))); + std::cout << "\t| - | / 0.5*(||+||) = " << adjoint_test << "\n"; + return adjoint_test; } void -TestGPUProjectors:: -test_adjoints() -{ - set_up(); - - unsigned num_unsuccessful(0); - - while(_results.size() < _num_attempts) { - - unsigned i = _results.size(); - - std::cout << "\nPerforming test " << i+1 << " of " << _num_attempts << "\n"; - - // Even iterations, modify the image - if (i%2==0) { - get_random_image(*_image_sptr); - forward_project(*_projected_sino_sptr, *_image_sptr, _projector_fwrd, _time_fwrd); - } - // Odd iterations (and first), modify the sinogram - if (i==0 || i%2==1) { - get_random_sino(*_sino_sptr); - back_project(*_projected_image_sptr, *_sino_sptr, _projector_back, _time_back); - } - - const float adjoint_test = - test_inner_product(*_image_sptr, *_sino_sptr, *_projected_image_sptr, *_projected_sino_sptr); - if (adjoint_test > 0.f) { - _results.push_back(adjoint_test); - std::cout << "\tAvg. test result = " << std::accumulate(_results.begin(), _results.end(), 0.0) /double(i+1) << - " (number of tests = " << i+1 << "), avg. time forward projecting = " << _time_fwrd/double(i+1) << " s, " << - "avg. time back projecting = " << _time_back/double(i+1) << " s.\n\n"; - - // Check the result - if (adjoint_test > 1e-4f) - error("Adjoint test greater than threshold, failed!"); - - // Reset unsuccessful counter - num_unsuccessful = 0; - } - else { - ++num_unsuccessful; - if (num_unsuccessful==5) - error("Too many (5) unsuccessful comparisons"); - } - } -} +TestGPUProjectors::test_adjoints() { + set_up(); -void -TestGPUProjectors:: -run_tests() -{ - try { - cerr << "Testing whether forward and back projectors are adjoint...\n"; - this->test_adjoints(); + unsigned num_unsuccessful(0); + + while (_results.size() < _num_attempts) { + + unsigned i = _results.size(); + + std::cout << "\nPerforming test " << i + 1 << " of " << _num_attempts << "\n"; + + // Even iterations, modify the image + if (i % 2 == 0) { + get_random_image(*_image_sptr); + forward_project(*_projected_sino_sptr, *_image_sptr, _projector_fwrd, _time_fwrd); } - catch(const std::exception &error) { - std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; - everything_ok = false; + // Odd iterations (and first), modify the sinogram + if (i == 0 || i % 2 == 1) { + get_random_sino(*_sino_sptr); + back_project(*_projected_image_sptr, *_sino_sptr, _projector_back, _time_back); } - catch(...) { - everything_ok = false; + + const float adjoint_test = test_inner_product(*_image_sptr, *_sino_sptr, *_projected_image_sptr, *_projected_sino_sptr); + if (adjoint_test > 0.f) { + _results.push_back(adjoint_test); + std::cout << "\tAvg. test result = " << std::accumulate(_results.begin(), _results.end(), 0.0) / double(i + 1) + << " (number of tests = " << i + 1 << "), avg. time forward projecting = " << _time_fwrd / double(i + 1) << " s, " + << "avg. time back projecting = " << _time_back / double(i + 1) << " s.\n\n"; + + // Check the result + if (adjoint_test > 1e-4f) + error("Adjoint test greater than threshold, failed!"); + + // Reset unsuccessful counter + num_unsuccessful = 0; + } else { + ++num_unsuccessful; + if (num_unsuccessful == 5) + error("Too many (5) unsuccessful comparisons"); } + } } -END_NAMESPACE_STIR +void +TestGPUProjectors::run_tests() { + try { + cerr << "Testing whether forward and back projectors are adjoint...\n"; + this->test_adjoints(); + } catch (const std::exception& error) { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + everything_ok = false; + } catch (...) { + everything_ok = false; + } +} +END_NAMESPACE_STIR USING_NAMESPACE_STIR -void print_usage() -{ - std::cerr << "\n\tUsage: test_ProjectorNiftyPET_adjoint [-h] \n"; +void +print_usage() { + std::cerr << "\n\tUsage: test_ProjectorNiftyPET_adjoint [-h] \n"; } -int main(int argc, char **argv) -{ - set_default_num_threads(); - Verbosity::set(0); +int +main(int argc, char** argv) { + set_default_num_threads(); + Verbosity::set(0); - // Require a single argument - if (argc != 2) { - print_usage(); - return EXIT_SUCCESS; - } + // Require a single argument + if (argc != 2) { + print_usage(); + return EXIT_SUCCESS; + } - // If help desired - if (strcmp(argv[1],"-h") ==0) { - print_usage(); - return EXIT_SUCCESS; - } + // If help desired + if (strcmp(argv[1], "-h") == 0) { + print_usage(); + return EXIT_SUCCESS; + } - const unsigned num_attempts = std::stoi(argv[1]); + const unsigned num_attempts = std::stoi(argv[1]); - TestGPUProjectors test(num_attempts); + TestGPUProjectors test(num_attempts); - if (test.is_everything_ok()) - test.run_tests(); + if (test.is_everything_ok()) + test.run_tests(); - return test.main_return_value(); + return test.main_return_value(); } diff --git a/src/test/modelling/test_ParametricDiscretisedDensity.cxx b/src/test/modelling/test_ParametricDiscretisedDensity.cxx index 9c0955cc4c..4d4da7cad1 100644 --- a/src/test/modelling/test_ParametricDiscretisedDensity.cxx +++ b/src/test/modelling/test_ParametricDiscretisedDensity.cxx @@ -1,31 +1,31 @@ /* Copyright (C) 2006- 2011, Hammersmith Imanet Ltd This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ -/*! - +/*! + \file \ingroup test - + \brief testing stir::ParametricDiscretisedDensity class - + \author T. Borgeaud -\author Charalampos Tsoumpas - - - +\author Charalampos Tsoumpas + + + */ #include @@ -60,112 +60,111 @@ using std::endl; START_NAMESPACE_STIR -class ParametricDiscretisedDensityTests : public RunTests -{ +class ParametricDiscretisedDensityTests : public RunTests { public: - ParametricDiscretisedDensityTests() - {} + ParametricDiscretisedDensityTests() {} void run_tests(); - //private: + // private: }; -void ParametricDiscretisedDensityTests::run_tests() -{ +void +ParametricDiscretisedDensityTests::run_tests() { set_tolerance(0.000000000000001); const unsigned num_params = ParametricVoxelsOnCartesianGrid::get_num_params(); //! Setup the scanner details first - const Scanner::Type test_scanner=Scanner::E966; + const Scanner::Type test_scanner = Scanner::E966; const shared_ptr scanner_sptr(new Scanner(test_scanner)); - VectorWithOffset num_axial_pos_per_segment; num_axial_pos_per_segment.resize(0,0); num_axial_pos_per_segment[0]=48; - VectorWithOffset min_ring_diff; min_ring_diff.resize(0,0); min_ring_diff[0]=0; - VectorWithOffset max_ring_diff; max_ring_diff.resize(0,0); max_ring_diff[0]=0; - const int num_views=144; const int num_tangential_poss=144; - ProjDataInfoCylindricalNoArcCorr proj_data_info(scanner_sptr,num_axial_pos_per_segment,min_ring_diff,max_ring_diff,num_views,num_tangential_poss); + VectorWithOffset num_axial_pos_per_segment; + num_axial_pos_per_segment.resize(0, 0); + num_axial_pos_per_segment[0] = 48; + VectorWithOffset min_ring_diff; + min_ring_diff.resize(0, 0); + min_ring_diff[0] = 0; + VectorWithOffset max_ring_diff; + max_ring_diff.resize(0, 0); + max_ring_diff[0] = 0; + const int num_views = 144; + const int num_tangential_poss = 144; + ProjDataInfoCylindricalNoArcCorr proj_data_info(scanner_sptr, num_axial_pos_per_segment, min_ring_diff, max_ring_diff, + num_views, num_tangential_poss); //! Setup some of the image details - const CartesianCoordinate3D< float > origin (0.F,0.F,0.F); - const CartesianCoordinate3D grid_spacing (1.F,1.F,1.F); - const float zoom=1.F; + const CartesianCoordinate3D origin(0.F, 0.F, 0.F); + const CartesianCoordinate3D grid_spacing(1.F, 1.F, 1.F); + const float zoom = 1.F; { cerr << "Testing ParametricDiscretisedDensity class for one voxel..." << endl; - const CartesianCoordinate3D sizes (1,1,1); - - const shared_ptr parametric_image_sptr - ( - new ParametricVoxelsOnCartesianGrid( - ParametricVoxelsOnCartesianGridBaseType(proj_data_info, - zoom,grid_spacing,sizes))); - ParametricVoxelsOnCartesianGrid & parametric_image = *parametric_image_sptr; - parametric_image[0][0][0][1]=1.F; parametric_image[0][0][0][2]=2.F; - - check_if_equal(parametric_image[0][0][0][1],1.F,"check ParametricVoxelsOnCartesianGrid class implementation"); - check_if_equal(parametric_image[0][0][0][2],2.F,"check ParametricVoxelsOnCartesianGrid class implementation"); + const CartesianCoordinate3D sizes(1, 1, 1); + + const shared_ptr parametric_image_sptr( + new ParametricVoxelsOnCartesianGrid(ParametricVoxelsOnCartesianGridBaseType(proj_data_info, zoom, grid_spacing, sizes))); + ParametricVoxelsOnCartesianGrid& parametric_image = *parametric_image_sptr; + parametric_image[0][0][0][1] = 1.F; + parametric_image[0][0][0][2] = 2.F; + + check_if_equal(parametric_image[0][0][0][1], 1.F, "check ParametricVoxelsOnCartesianGrid class implementation"); + check_if_equal(parametric_image[0][0][0][2], 2.F, "check ParametricVoxelsOnCartesianGrid class implementation"); } { - // Test of two frame images, read voxel + // Test of two frame images, read voxel cerr << "Testing ParametricDiscretisedDensity class for more voxels: 63x128x128..." << endl; - const CartesianCoordinate3D sizes (63,128,128); - - //const shared_ptr parametric_image_sptr = + const CartesianCoordinate3D sizes(63, 128, 128); + + // const shared_ptr parametric_image_sptr = // new ParametricVoxelsOnCartesianGrid(ParametricVoxelsOnCartesianGridBaseType(proj_data_info,zoom,grid_spacing,sizes)); - //ParametricVoxelsOnCartesianGrid & parametric_image = *parametric_image_sptr; + // ParametricVoxelsOnCartesianGrid & parametric_image = *parametric_image_sptr; - //ParametricVoxelsOnCartesianGrid & parametric_image = *parametric_image_sptr; - ParametricVoxelsOnCartesianGrid parametric_image(ParametricVoxelsOnCartesianGridBaseType(proj_data_info,zoom,grid_spacing,sizes)); - for(int k=0;k<63;++k) - for(int j=-64;j<63;++j) - for(int i=-64;i<63;++i) - for(unsigned int par_num=1; par_num<=num_params; ++par_num) - parametric_image[k][j][i][par_num] = static_cast (par_num*(i*1.F+j*5.F-k*10.F)); + // ParametricVoxelsOnCartesianGrid & parametric_image = *parametric_image_sptr; + ParametricVoxelsOnCartesianGrid parametric_image( + ParametricVoxelsOnCartesianGridBaseType(proj_data_info, zoom, grid_spacing, sizes)); + for (int k = 0; k < 63; ++k) + for (int j = -64; j < 63; ++j) + for (int i = -64; i < 63; ++i) + for (unsigned int par_num = 1; par_num <= num_params; ++par_num) + parametric_image[k][j][i][par_num] = static_cast(par_num * (i * 1.F + j * 5.F - k * 10.F)); cerr << "- Checking the [] operator. " << endl; - for(int k=0;k<63;++k) - for(int j=-64;j<63;++j) - for(int i=-64;i<63;++i) - for(unsigned int par_num=1; par_num<=num_params; ++par_num) - check_if_equal(parametric_image[k][j][i][par_num],static_cast (par_num*(i*1.F+j*5.F-k*10.F)), - "Please, check the [] operator implementation"); - + for (int k = 0; k < 63; ++k) + for (int j = -64; j < 63; ++j) + for (int i = -64; i < 63; ++i) + for (unsigned int par_num = 1; par_num <= num_params; ++par_num) + check_if_equal(parametric_image[k][j][i][par_num], static_cast(par_num * (i * 1.F + j * 5.F - k * 10.F)), + "Please, check the [] operator implementation"); cerr << "- Checking construct_single_density(param_num) implementation." << endl; // TODO tests need to be rewritten to accomodate for other num_params!=2 - if (num_params!=2) - { - warning("test_ParametricDiscretisedDensity test only tests first 2 maps"); - } + if (num_params != 2) { + warning("test_ParametricDiscretisedDensity test only tests first 2 maps"); + } ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType single_density_1 = parametric_image.construct_single_density(1); ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType single_density_2 = parametric_image.construct_single_density(2); - for(int k=0;k<63;++k) - for(int j=-64;j<63;++j) - for(int i=-64;i<63;++i) - { - check_if_equal(parametric_image[k][j][i][1],single_density_1[k][j][i], - "Please, check construct_single_density(param_num) implementation"); - check_if_equal(parametric_image[k][j][i][2],single_density_2[k][j][i], - "Please, check construct_single_density(param_num) implementation"); - for(unsigned int par_num=1; par_num<=num_params; ++par_num) - check_if_equal(parametric_image[k][j][i][par_num],static_cast (par_num*(i*1.F+j*5.F-k*10.F)), - "Please, check the construct_single_density(param_num) implementation"); - } - - ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType::full_iterator cur_iter_1 = - single_density_1.begin_all(); - ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType::full_iterator cur_iter_2 = - single_density_2.begin_all(); - for (; cur_iter_1!=single_density_1.end_all() && - cur_iter_2!=single_density_2.end_all(); - ++cur_iter_1, ++cur_iter_2) - check_if_equal(*cur_iter_1*2.F, *cur_iter_2, - "Please, check construct_single_density(param_num) implementation"); + for (int k = 0; k < 63; ++k) + for (int j = -64; j < 63; ++j) + for (int i = -64; i < 63; ++i) { + check_if_equal(parametric_image[k][j][i][1], single_density_1[k][j][i], + "Please, check construct_single_density(param_num) implementation"); + check_if_equal(parametric_image[k][j][i][2], single_density_2[k][j][i], + "Please, check construct_single_density(param_num) implementation"); + for (unsigned int par_num = 1; par_num <= num_params; ++par_num) + check_if_equal(parametric_image[k][j][i][par_num], static_cast(par_num * (i * 1.F + j * 5.F - k * 10.F)), + "Please, check the construct_single_density(param_num) implementation"); + } + + ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType::full_iterator cur_iter_1 = single_density_1.begin_all(); + ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType::full_iterator cur_iter_2 = single_density_2.begin_all(); + for (; cur_iter_1 != single_density_1.end_all() && cur_iter_2 != single_density_2.end_all(); ++cur_iter_1, ++cur_iter_2) + check_if_equal(*cur_iter_1 * 2.F, *cur_iter_2, "Please, check construct_single_density(param_num) implementation"); std::fill(single_density_1.begin_all(), single_density_1.end_all(), 1.F); std::fill(single_density_2.begin_all(), single_density_2.end_all(), 2.F); - VectorWithOffset > v_test; - v_test.resize(1,2); v_test[1].reset(single_density_1.clone()); v_test[2].reset(single_density_2.clone()); + VectorWithOffset> v_test; + v_test.resize(1, 2); + v_test[1].reset(single_density_1.clone()); + v_test[2].reset(single_density_2.clone()); #if 0 // test disabled as function currently removed from class cerr << "- Checking constructor from(VectorWithOffset single_densities) implementation." << endl; @@ -213,19 +212,19 @@ void ParametricDiscretisedDensityTests::run_tests() } #endif cerr << "- Checking update_parametric_image(single_density,param_num) implementation." << endl; - parametric_image.update_parametric_image(single_density_1,2); + parametric_image.update_parametric_image(single_density_1, 2); #if 1 - parametric_image.update_parametric_image(single_density_2,1); + parametric_image.update_parametric_image(single_density_2, 1); // Check if the result has been reversed. { bool still_equal = true; - for(int k=0;still_equal && k<63;++k) - for(int j=-64;still_equal && j<63;++j) - for(int i=-64;still_equal && i<63;++i) - for(unsigned int par_num=1;still_equal && par_num<=num_params;++par_num) - still_equal = check_if_equal(parametric_image[k][j][i][par_num],static_cast (2+1-par_num), - "Please, check update_parametric_image(VectorWithOffset) implementation"); + for (int k = 0; still_equal && k < 63; ++k) + for (int j = -64; still_equal && j < 63; ++j) + for (int i = -64; still_equal && i < 63; ++i) + for (unsigned int par_num = 1; still_equal && par_num <= num_params; ++par_num) + still_equal = check_if_equal(parametric_image[k][j][i][par_num], static_cast(2 + 1 - par_num), + "Please, check update_parametric_image(VectorWithOffset) implementation"); } #endif } @@ -234,13 +233,12 @@ void ParametricDiscretisedDensityTests::run_tests() END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 1) - { - cerr << "Usage : " << argv[0] << " \n"; - return EXIT_FAILURE; - } +int +main(int argc, char** argv) { + if (argc != 1) { + cerr << "Usage : " << argv[0] << " \n"; + return EXIT_FAILURE; + } ParametricDiscretisedDensityTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/modelling/test_modelling.cxx b/src/test/modelling/test_modelling.cxx index 77ab5c07fa..54054f364a 100644 --- a/src/test/modelling/test_modelling.cxx +++ b/src/test/modelling/test_modelling.cxx @@ -1,7 +1,7 @@ // // /*! - \file + \file \ingroup test \brief tests parts of the modelling implementation @@ -25,7 +25,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/RunTests.h" #include "stir/modelling/PatlakPlot.h" #include "stir/modelling/ModelMatrix.h" @@ -41,173 +40,194 @@ START_NAMESPACE_STIR \ingroup test \brief A simple class to test modelling functions. */ -class modellingTests : public RunTests -{ +class modellingTests : public RunTests { public: explicit modellingTests(const std::string& directory); void run_tests(); + private: - //istream& in; + // istream& in; std::string directory; boost::shared_array full_filename_sptr; std::string add_directory(const std::string& filename); }; -modellingTests:: -modellingTests(const std::string& directory_v) - : directory(directory_v), - full_filename_sptr(new char[directory_v.length() + 100]) -{} +modellingTests::modellingTests(const std::string& directory_v) + : directory(directory_v), full_filename_sptr(new char[directory_v.length() + 100]) {} -std::string -modellingTests:: -add_directory(const std::string& filename) -{ +std::string +modellingTests::add_directory(const std::string& filename) { strcpy(this->full_filename_sptr.get(), filename.c_str()); - prepend_directory_name(this->full_filename_sptr.get(),this->directory.c_str()); + prepend_directory_name(this->full_filename_sptr.get(), this->directory.c_str()); return std::string(this->full_filename_sptr.get()); } -void modellingTests::run_tests() -{ +void +modellingTests::run_tests() { std::cerr << "Testing basic modelling functions..." << std::endl; set_tolerance(0.004); - + { - std::cerr << "Testing the reading of PlasmaData ..." << std::endl; - - PlasmaData file_plasma_data, testing_plasma_data; - file_plasma_data.read_plasma_data(this->add_directory("triple_plasma.if")); - std::vector this_plasma_blood_plot; - const PlasmaSample sample_1(0.5F,.999947F,.0999947F); - const PlasmaSample sample_2(7573.3F,.450739F,.0450739F); - const PlasmaSample sample_3(30292.2F,.0412893F,.00412893F); - this_plasma_blood_plot.push_back(sample_1); - this_plasma_blood_plot.push_back(sample_2); - this_plasma_blood_plot.push_back(sample_3); - testing_plasma_data.set_plot(this_plasma_blood_plot); - - - PlasmaData::const_iterator cur_iter_1, cur_iter_2; - - for (cur_iter_1=file_plasma_data.begin(), cur_iter_2=testing_plasma_data.begin(); - cur_iter_1!=file_plasma_data.end() && cur_iter_2!=testing_plasma_data.end(); - ++cur_iter_1, ++cur_iter_2) - { - check_if_equal((*cur_iter_1).get_time_in_s(),(*cur_iter_2).get_time_in_s(), "Check Reading Time of PlasmaData "); - check_if_equal((*cur_iter_1).get_plasma_counts_in_kBq(),(*cur_iter_2).get_plasma_counts_in_kBq(), "Check Reading Plasma of PlasmaData "); - check_if_equal((*cur_iter_1).get_blood_counts_in_kBq(),(*cur_iter_2).get_blood_counts_in_kBq(), "Check Reading Blood of PlasmaData "); - } + std::cerr << "Testing the reading of PlasmaData ..." << std::endl; + + PlasmaData file_plasma_data, testing_plasma_data; + file_plasma_data.read_plasma_data(this->add_directory("triple_plasma.if")); + std::vector this_plasma_blood_plot; + const PlasmaSample sample_1(0.5F, .999947F, .0999947F); + const PlasmaSample sample_2(7573.3F, .450739F, .0450739F); + const PlasmaSample sample_3(30292.2F, .0412893F, .00412893F); + this_plasma_blood_plot.push_back(sample_1); + this_plasma_blood_plot.push_back(sample_2); + this_plasma_blood_plot.push_back(sample_3); + testing_plasma_data.set_plot(this_plasma_blood_plot); + + PlasmaData::const_iterator cur_iter_1, cur_iter_2; + + for (cur_iter_1 = file_plasma_data.begin(), cur_iter_2 = testing_plasma_data.begin(); + cur_iter_1 != file_plasma_data.end() && cur_iter_2 != testing_plasma_data.end(); ++cur_iter_1, ++cur_iter_2) { + check_if_equal((*cur_iter_1).get_time_in_s(), (*cur_iter_2).get_time_in_s(), "Check Reading Time of PlasmaData "); + check_if_equal((*cur_iter_1).get_plasma_counts_in_kBq(), (*cur_iter_2).get_plasma_counts_in_kBq(), + "Check Reading Plasma of PlasmaData "); + check_if_equal((*cur_iter_1).get_blood_counts_in_kBq(), (*cur_iter_2).get_blood_counts_in_kBq(), + "Check Reading Blood of PlasmaData "); + } } { - std::cerr << "Testing the reading and writing of the ModelMatrix ..." << std::endl; - - ModelMatrix<2> file_model_matrix, correct_model_matrix; - file_model_matrix.read_from_file(this->add_directory("model_array.in")); - file_model_matrix.write_to_file(this->add_directory("model_array.out")); - - BasicCoordinate<2,int> min_range; - BasicCoordinate<2,int> max_range; - min_range[1]=1; min_range[2]=23; - max_range[1]=2; max_range[2]=28; - IndexRange<2> data_range(min_range,max_range); - Array<2,float> correct_model_array(data_range); - correct_model_array[1][23]=1; correct_model_array[2][23]=2; - correct_model_array[1][24]=11; correct_model_array[2][24]=22; - correct_model_array[1][25]=111; correct_model_array[2][25]=222; - correct_model_array[1][26]=1111; correct_model_array[2][26]=2222; - correct_model_array[1][27]=11111; correct_model_array[2][27]=22222; - correct_model_array[1][28]=111111; correct_model_array[2][28]=222222; - - correct_model_matrix.set_model_array(correct_model_array); - - Array<2,float> file_model_array=file_model_matrix.get_model_array(); - Array<2,float> get_correct_model_array=correct_model_matrix.get_model_array(); - - for (unsigned int param_num=1;param_num<=2;++param_num) - for(unsigned int frame_num=23;frame_num<=28;++frame_num) - { - check_if_equal(file_model_array[param_num][frame_num],get_correct_model_array[param_num][frame_num],"Check ModelMatrix reading. "); - check_if_equal(file_model_array[param_num][frame_num],correct_model_array[param_num][frame_num],"Check ModelMatrix reading. "); - } + std::cerr << "Testing the reading and writing of the ModelMatrix ..." << std::endl; + + ModelMatrix<2> file_model_matrix, correct_model_matrix; + file_model_matrix.read_from_file(this->add_directory("model_array.in")); + file_model_matrix.write_to_file(this->add_directory("model_array.out")); + + BasicCoordinate<2, int> min_range; + BasicCoordinate<2, int> max_range; + min_range[1] = 1; + min_range[2] = 23; + max_range[1] = 2; + max_range[2] = 28; + IndexRange<2> data_range(min_range, max_range); + Array<2, float> correct_model_array(data_range); + correct_model_array[1][23] = 1; + correct_model_array[2][23] = 2; + correct_model_array[1][24] = 11; + correct_model_array[2][24] = 22; + correct_model_array[1][25] = 111; + correct_model_array[2][25] = 222; + correct_model_array[1][26] = 1111; + correct_model_array[2][26] = 2222; + correct_model_array[1][27] = 11111; + correct_model_array[2][27] = 22222; + correct_model_array[1][28] = 111111; + correct_model_array[2][28] = 222222; + + correct_model_matrix.set_model_array(correct_model_array); + + Array<2, float> file_model_array = file_model_matrix.get_model_array(); + Array<2, float> get_correct_model_array = correct_model_matrix.get_model_array(); + + for (unsigned int param_num = 1; param_num <= 2; ++param_num) + for (unsigned int frame_num = 23; frame_num <= 28; ++frame_num) { + check_if_equal(file_model_array[param_num][frame_num], get_correct_model_array[param_num][frame_num], + "Check ModelMatrix reading. "); + check_if_equal(file_model_array[param_num][frame_num], correct_model_array[param_num][frame_num], + "Check ModelMatrix reading. "); + } } { // This tests uses the results from the Mathematica. The used plasma and frame files are parts of the t00196 scan. - std::cerr << "\nTesting the sampling of PlasmaData into frames ..." << std::endl; + std::cerr << "\nTesting the sampling of PlasmaData into frames ..." << std::endl; PlasmaData file_plasma_data, testing_plasma_data; file_plasma_data.read_plasma_data(this->add_directory("plasma.if")); std::vector this_plasma_blood_plot; - TimeFrameDefinitions time_frame_def(this->add_directory("time.fdef")); + TimeFrameDefinitions time_frame_def(this->add_directory("time.fdef")); file_plasma_data.set_isotope_halflife(6586.2F); PlasmaData sample_plasma_data_in_frames = file_plasma_data.get_sample_data_in_frames(time_frame_def); - const PlasmaSample sample_17(1, 11.4776, 10.7832); const PlasmaSample sample_18(1, 10.7523, 10.1135); const PlasmaSample sample_19(1, 10.0841, 9.50239); - const PlasmaSample sample_20(1, 9.24207, 8.7949); const PlasmaSample sample_21(1, 8.39741, 8.04141); const PlasmaSample sample_22(1, 7.74369, 7.36121); - const PlasmaSample sample_23(1, 7.18224, 6.78764); const PlasmaSample sample_24(1, 6.67699, 6.3266); const PlasmaSample sample_25(1, 6.23402, 5.93635); - const PlasmaSample sample_26(1, 5.8495, 5.593); const PlasmaSample sample_27(1, 5.50858, 5.29071); const PlasmaSample sample_28(1, 5.19509, 5.02458); - - TimeFrameDefinitions plasma_fdef=sample_plasma_data_in_frames.get_time_frame_definitions(); - - this_plasma_blood_plot.push_back(sample_17); this_plasma_blood_plot.push_back(sample_18); this_plasma_blood_plot.push_back(sample_19); - this_plasma_blood_plot.push_back(sample_20); this_plasma_blood_plot.push_back(sample_21); this_plasma_blood_plot.push_back(sample_22); - this_plasma_blood_plot.push_back(sample_23); this_plasma_blood_plot.push_back(sample_24); this_plasma_blood_plot.push_back(sample_25); - this_plasma_blood_plot.push_back(sample_26); this_plasma_blood_plot.push_back(sample_27); this_plasma_blood_plot.push_back(sample_28); + const PlasmaSample sample_17(1, 11.4776, 10.7832); + const PlasmaSample sample_18(1, 10.7523, 10.1135); + const PlasmaSample sample_19(1, 10.0841, 9.50239); + const PlasmaSample sample_20(1, 9.24207, 8.7949); + const PlasmaSample sample_21(1, 8.39741, 8.04141); + const PlasmaSample sample_22(1, 7.74369, 7.36121); + const PlasmaSample sample_23(1, 7.18224, 6.78764); + const PlasmaSample sample_24(1, 6.67699, 6.3266); + const PlasmaSample sample_25(1, 6.23402, 5.93635); + const PlasmaSample sample_26(1, 5.8495, 5.593); + const PlasmaSample sample_27(1, 5.50858, 5.29071); + const PlasmaSample sample_28(1, 5.19509, 5.02458); + + TimeFrameDefinitions plasma_fdef = sample_plasma_data_in_frames.get_time_frame_definitions(); + + this_plasma_blood_plot.push_back(sample_17); + this_plasma_blood_plot.push_back(sample_18); + this_plasma_blood_plot.push_back(sample_19); + this_plasma_blood_plot.push_back(sample_20); + this_plasma_blood_plot.push_back(sample_21); + this_plasma_blood_plot.push_back(sample_22); + this_plasma_blood_plot.push_back(sample_23); + this_plasma_blood_plot.push_back(sample_24); + this_plasma_blood_plot.push_back(sample_25); + this_plasma_blood_plot.push_back(sample_26); + this_plasma_blood_plot.push_back(sample_27); + this_plasma_blood_plot.push_back(sample_28); testing_plasma_data.set_plot(this_plasma_blood_plot); testing_plasma_data.set_isotope_halflife(6586.2F); testing_plasma_data.decay_correct_PlasmaData(); PlasmaData::const_iterator cur_iter_1, cur_iter_2; - - for (cur_iter_1=sample_plasma_data_in_frames.begin()+16, cur_iter_2=testing_plasma_data.begin(); - cur_iter_1!=sample_plasma_data_in_frames.end() && cur_iter_2!=testing_plasma_data.end(); - ++cur_iter_1, ++cur_iter_2) - { - check_if_equal((*cur_iter_1).get_plasma_counts_in_kBq(),(*cur_iter_2).get_plasma_counts_in_kBq(),"Check Plasma when sampling PlasmaData into frames"); - check_if_equal((*cur_iter_1).get_blood_counts_in_kBq(),(*cur_iter_2).get_blood_counts_in_kBq(),"Check Blood when sampling PlasmaData into frames"); - } - assert(time_frame_def.get_num_frames()==plasma_fdef.get_num_frames()); - for (unsigned int frame_num=17 ; frame_num<=time_frame_def.get_num_frames() && frame_num<=plasma_fdef.get_num_frames(); ++frame_num) - { - check_if_equal(time_frame_def.get_start_time(frame_num),plasma_fdef.get_start_time(frame_num),"Check start time when sampling PlasmaData into frames"); - check_if_equal(time_frame_def.get_duration(frame_num),plasma_fdef.get_duration(frame_num),"Check duration when sampling PlasmaData into frames"); - check_if_equal(time_frame_def.get_end_time(frame_num),plasma_fdef.get_end_time(frame_num),"Check duration when sampling PlasmaData into frames"); - } - std::cerr << "\nTesting the creation of Model Matrix based on Plasma Data..." << std::endl; - PatlakPlot patlak_plot; - const unsigned int starting_frame=23; - patlak_plot._plasma_frame_data=sample_plasma_data_in_frames; - patlak_plot._frame_defs=time_frame_def; - patlak_plot._starting_frame=starting_frame; - patlak_plot._cal_factor=10.0F; - patlak_plot.set_up(); - ModelMatrix<2> stir_model_matrix=(patlak_plot.get_model_matrix()); - ModelMatrix<2> mathematica_model_matrix; - mathematica_model_matrix.read_from_file(this->add_directory("math_model_matrix.in")); - // stir_model_matrix.convert_to_total_frame_counts(time_frame_def); - Array<2,float> stir_model_array=stir_model_matrix.get_model_array(); - Array<2,float> mathematica_model_array=mathematica_model_matrix.get_model_array(); - - for(unsigned int frame_num=23;frame_num<=28;++frame_num) - { - check_if_equal(mathematica_model_array[1][frame_num]/patlak_plot._cal_factor,stir_model_array[1][frame_num],"Check _model_array-1st column in ModelMatrix"); - check_if_equal(mathematica_model_array[2][frame_num]/patlak_plot._cal_factor,stir_model_array[2][frame_num],"Check _model_array-2nd column in ModelMatrix"); - } - } + for (cur_iter_1 = sample_plasma_data_in_frames.begin() + 16, cur_iter_2 = testing_plasma_data.begin(); + cur_iter_1 != sample_plasma_data_in_frames.end() && cur_iter_2 != testing_plasma_data.end(); + ++cur_iter_1, ++cur_iter_2) { + check_if_equal((*cur_iter_1).get_plasma_counts_in_kBq(), (*cur_iter_2).get_plasma_counts_in_kBq(), + "Check Plasma when sampling PlasmaData into frames"); + check_if_equal((*cur_iter_1).get_blood_counts_in_kBq(), (*cur_iter_2).get_blood_counts_in_kBq(), + "Check Blood when sampling PlasmaData into frames"); + } + assert(time_frame_def.get_num_frames() == plasma_fdef.get_num_frames()); + for (unsigned int frame_num = 17; frame_num <= time_frame_def.get_num_frames() && frame_num <= plasma_fdef.get_num_frames(); + ++frame_num) { + check_if_equal(time_frame_def.get_start_time(frame_num), plasma_fdef.get_start_time(frame_num), + "Check start time when sampling PlasmaData into frames"); + check_if_equal(time_frame_def.get_duration(frame_num), plasma_fdef.get_duration(frame_num), + "Check duration when sampling PlasmaData into frames"); + check_if_equal(time_frame_def.get_end_time(frame_num), plasma_fdef.get_end_time(frame_num), + "Check duration when sampling PlasmaData into frames"); + } + std::cerr << "\nTesting the creation of Model Matrix based on Plasma Data..." << std::endl; + PatlakPlot patlak_plot; + const unsigned int starting_frame = 23; + patlak_plot._plasma_frame_data = sample_plasma_data_in_frames; + patlak_plot._frame_defs = time_frame_def; + patlak_plot._starting_frame = starting_frame; + patlak_plot._cal_factor = 10.0F; + patlak_plot.set_up(); + ModelMatrix<2> stir_model_matrix = (patlak_plot.get_model_matrix()); + ModelMatrix<2> mathematica_model_matrix; + mathematica_model_matrix.read_from_file(this->add_directory("math_model_matrix.in")); + // stir_model_matrix.convert_to_total_frame_counts(time_frame_def); + Array<2, float> stir_model_array = stir_model_matrix.get_model_array(); + Array<2, float> mathematica_model_array = mathematica_model_matrix.get_model_array(); + + for (unsigned int frame_num = 23; frame_num <= 28; ++frame_num) { + check_if_equal(mathematica_model_array[1][frame_num] / patlak_plot._cal_factor, stir_model_array[1][frame_num], + "Check _model_array-1st column in ModelMatrix"); + check_if_equal(mathematica_model_array[2][frame_num] / patlak_plot._cal_factor, stir_model_array[2][frame_num], + "Check _model_array-2nd column in ModelMatrix"); + } + } } - END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 2) - { +int +main(int argc, char** argv) { + if (argc != 2) { std::cerr << "Usage : " << argv[0] << " \n"; return EXIT_FAILURE; } diff --git a/src/test/numerics/BSplines_timing.cxx b/src/test/numerics/BSplines_timing.cxx index 7ed4efcb66..005565d815 100644 --- a/src/test/numerics/BSplines_timing.cxx +++ b/src/test/numerics/BSplines_timing.cxx @@ -8,23 +8,23 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! -\file +\file \ingroup numerics_test \brief Allows executing timing tests for the stir::BSpline::BSplinesRegularGrid class \author Tim Borgeaud \author Kris Thielemans - -*/ + +*/ //#define MYLINEAR #include "stir/Array.h" @@ -37,7 +37,6 @@ #include "stir/numerics/BSplines.h" #include "stir/numerics/BSplinesRegularGrid.h" - #include #include #include @@ -48,12 +47,9 @@ using std::cerr; using namespace stir; using namespace BSpline; - - const int MAX_DIMS = 4; const int DEF_DIMS = 1; - const int MAX_NUM = 10000000; const int MIN_SIZE = 5; const int MAX_TOTAL_GRID_ELEMENTS = 10000000; @@ -61,115 +57,103 @@ const int MAX_TOTAL_GRID_ELEMENTS = 10000000; const int DEF_NUM = 1000; const int DEF_SIZE = 10; +void +usage(char* name) { -void usage(char *name) { - cerr << "A program to test the BSplines interpolation implementation\n\n"; - + cerr << "Usage: " << name << " [-n number of interpolations] [-s grid size]\n"; cerr << " [-i interpolator] [-d 2]\n\n"; - + cerr << " interpolator: near, linear, quadratic, cubic, omoms\n\n"; - } +template +double +interpolate(int num, int size, BSplineType bs_type, Array grid) { - -template -double interpolate(int num, int size, BSplineType bs_type, Array grid) { - // Create interpolator. - + struct timeval start; - gettimeofday(&start, NULL); + gettimeofday(&start, NULL); BSplinesRegularGrid bsi(grid, bs_type); - + struct timeval end; gettimeofday(&end, NULL); - - double total = (end.tv_sec - start.tv_sec) + ((end.tv_usec - start.tv_usec)/1000000.0); - + + double total = (end.tv_sec - start.tv_sec) + ((end.tv_usec - start.tv_usec) / 1000000.0); + cout << "Constructed " << dims << " dimensional, " << size; - for (int d = 1 ; d < dims ; d++ ) { + for (int d = 1; d < dims; d++) { cout << " x " << size; } cout << " element grid.\n"; cout << "Time: " << total << " seconds\n"; cout << "\n"; - BasicCoordinate pos; - - gettimeofday(&start, NULL); double foo = 0.0; // Now try some interpolation. - for (int i = 0 ; i < num ; i++ ) { + for (int i = 0; i < num; i++) { // Set position - for (int d = 1 ; d < dims + 1 ; d++ ) { - pos[d] = (static_cast(size - 1)/(RAND_MAX)) * random(); - //cout << pos[d] << "\n"; + for (int d = 1; d < dims + 1; d++) { + pos[d] = (static_cast(size - 1) / (RAND_MAX)) * random(); + // cout << pos[d] << "\n"; } // Get interpolation. foo += bsi(pos); - } - + } gettimeofday(&end, NULL); - total = (end.tv_sec - start.tv_sec) + ((end.tv_usec - start.tv_usec)/1000000.0); - + total = (end.tv_sec - start.tv_sec) + ((end.tv_usec - start.tv_usec) / 1000000.0); cout << "Interpolations: " << num << "\n"; cout << "Time: " << total << " seconds\n"; cout << "\n"; ////////////// -#ifdef MYLINEAR +#ifdef MYLINEAR gettimeofday(&start, NULL); foo = 0.0; // Now try some interpolation. - for (int i = 0 ; i < num ; i++ ) { + for (int i = 0; i < num; i++) { // Set position - for (int d = 1 ; d < dims + 1 ; d++ ) { - pos[d] = (static_cast(size - 1)/(RAND_MAX)) * random(); - //cout << pos[d] << "\n"; + for (int d = 1; d < dims + 1; d++) { + pos[d] = (static_cast(size - 1) / (RAND_MAX)) * random(); + // cout << pos[d] << "\n"; } // Get interpolation. - foo += pull_linear_interpolate(grid,pos); - } + foo += pull_linear_interpolate(grid, pos); + } gettimeofday(&end, NULL); - total = (end.tv_sec - start.tv_sec) + ((end.tv_usec - start.tv_usec)/1000000.0); - + total = (end.tv_sec - start.tv_sec) + ((end.tv_usec - start.tv_usec) / 1000000.0); cout << "linear Time: " << total << " seconds\n"; cout << "\n"; -#endif //MYLINEAR +#endif // MYLINEAR ////////////// cout << "foo: " << foo << "\n\n"; - return(total); + return (total); } - - - - - -int main(int argc, char **argv) { +int +main(int argc, char** argv) { int grid_size = DEF_SIZE; BSplineType bs_type = near_n; @@ -180,146 +164,133 @@ int main(int argc, char **argv) { // Options. while ((opt_ch = getopt(argc, argv, "n:s:i:d:h")) != -1) - - switch (opt_ch) { - case 'h': - usage(basename(argv[0])); - exit(EXIT_SUCCESS); - - case 'n': - // Number of interpolations. - num = atoi(optarg); - break; - - case 's': - // Grid_Size - grid_size = atoi(optarg); - break; - - case 'i': - // Interpolation. - - if ( strcasecmp(optarg, "near") == 0 ) { - bs_type = near_n; - } else if ( strcasecmp(optarg, "linear") == 0 ) { - bs_type = linear; - } else if ( strcasecmp(optarg, "quadratic") == 0 ) { - bs_type = quadratic; - } else if ( strcasecmp(optarg, "cubic") == 0 ) { - bs_type = cubic; - } else if ( strcasecmp(optarg, "quartic") == 0 ) { - bs_type = quartic; - } else if ( strcasecmp(optarg, "quintic") == 0 ) { - bs_type = quintic; - } else if ( strcasecmp(optarg, "omoms") == 0 ) { - bs_type = oMoms; - } - - break; - - case 'd': - dimensions = atoi(optarg); - break; - - case '?': - default: - usage(basename(argv[0])); - exit(0); - break; - } - + + switch (opt_ch) { + case 'h': + usage(basename(argv[0])); + exit(EXIT_SUCCESS); + + case 'n': + // Number of interpolations. + num = atoi(optarg); + break; + + case 's': + // Grid_Size + grid_size = atoi(optarg); + break; + + case 'i': + // Interpolation. + + if (strcasecmp(optarg, "near") == 0) { + bs_type = near_n; + } else if (strcasecmp(optarg, "linear") == 0) { + bs_type = linear; + } else if (strcasecmp(optarg, "quadratic") == 0) { + bs_type = quadratic; + } else if (strcasecmp(optarg, "cubic") == 0) { + bs_type = cubic; + } else if (strcasecmp(optarg, "quartic") == 0) { + bs_type = quartic; + } else if (strcasecmp(optarg, "quintic") == 0) { + bs_type = quintic; + } else if (strcasecmp(optarg, "omoms") == 0) { + bs_type = oMoms; + } + + break; + + case 'd': + dimensions = atoi(optarg); + break; + + case '?': + default: + usage(basename(argv[0])); + exit(0); + break; + } + argc -= optind; - - if ( argc > 0 ) { + + if (argc > 0) { usage(basename(argv[0])); exit(EXIT_FAILURE); } - - // Sanity check on grid dimensions and number of interpolations to carry out. - if ( num < 1 || num > MAX_NUM ) { + if (num < 1 || num > MAX_NUM) { num = DEF_NUM; cerr << "Number of interpolations out of range. Reset to: " << num << "\n"; } - - - if ( grid_size < MIN_SIZE ) { + if (grid_size < MIN_SIZE) { grid_size = DEF_SIZE; cerr << "Grid size too small. Reset to: " << grid_size << "\n"; } else { - + int total_elements = grid_size; - - for (int d = 1 ; d < dimensions ; d++) { + + for (int d = 1; d < dimensions; d++) { total_elements *= grid_size; } - - if ( total_elements > MAX_TOTAL_GRID_ELEMENTS ) { + + if (total_elements > MAX_TOTAL_GRID_ELEMENTS) { grid_size = DEF_SIZE; - cerr << "Grid size too large for " << dimensions << " dimensions. Reset to: " - << grid_size << "\n"; + cerr << "Grid size too large for " << dimensions << " dimensions. Reset to: " << grid_size << "\n"; } } - - - if ( dimensions < 1 || dimensions > MAX_DIMS ) { + if (dimensions < 1 || dimensions > MAX_DIMS) { dimensions = DEF_DIMS; cerr << "Dimensions out of range. Reset to: " << dimensions << "\n"; } - int size[4] = {0, 0, 0, 0}; - for (int d = 0 ; d < dimensions ; d++) { + for (int d = 0; d < dimensions; d++) { size[d] = grid_size; } - + // Test arrays - Double precision. Array<1, float> data_1(size[0]); IndexRange2D range2(size[1], size[1]); Array<2, float> data_2(range2); - + IndexRange3D range3(size[2], size[2], size[2]); Array<3, float> data_3(range3); IndexRange4D range4(size[3], size[3], size[3], size[3]); Array<4, float> data_4(range4); - - + // Fill test arrays. - for (int i = 0 ; i < size[0] ; i++ ) { + for (int i = 0; i < size[0]; i++) { data_1[i] = i; - - for (int j = 0 ; j < size[1] ; j++ ) { + + for (int j = 0; j < size[1]; j++) { data_2[i][j] = i * j; - - - for (int k = 0 ; k < size[2] ; k++) { + + for (int k = 0; k < size[2]; k++) { data_3[i][j][k] = i * j * k; - - for (int l = 0 ; l < size[3] ; l++) { + + for (int l = 0; l < size[3]; l++) { data_4[i][j][k][l] = i * j * k * l; } } } } - - - - switch ( dimensions ) { + switch (dimensions) { #ifndef MYLINEAR case 1: interpolate(num, size[0], bs_type, data_1); break; - + case 2: interpolate(num, size[1], bs_type, data_2); break; -#endif +#endif case 3: interpolate(num, size[2], bs_type, data_3); break; @@ -331,10 +302,8 @@ int main(int argc, char **argv) { default: // Do nothing. break; - } - - return(0); -} /* End of Main */ + return (0); +} /* End of Main */ diff --git a/src/test/numerics/test_BSplines.cxx b/src/test/numerics/test_BSplines.cxx index ab87bff4ae..cabcf525d3 100644 --- a/src/test/numerics/test_BSplines.cxx +++ b/src/test/numerics/test_BSplines.cxx @@ -17,13 +17,13 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics_test - \brief tests the BSplines + \brief tests the BSplines \author Charalampos Tsoumpas \author Kris Thielemans -*/ +*/ #include "stir/RunTests.h" #include "stir/Array.h" #include "stir/IndexRange2D.h" @@ -45,410 +45,385 @@ using std::endl; #endif START_NAMESPACE_STIR namespace BSpline { - /*! - \ingroup test - \brief A simple class to test the BSplines function. - */ - class BSplines_Tests : public RunTests +/*! + \ingroup test + \brief A simple class to test the BSplines function. +*/ +class BSplines_Tests : public RunTests { +public: + BSplines_Tests() {} + void run_tests(); + +private: + template + bool check_at_sample_points(const std::vector& v, BSplines1DRegularGrid& interpolator, + const char* const message) { + std::vector out; + for (std::size_t i = 0, imax = v.size(); i < imax; ++i) + out.push_back(interpolator.BSplines(static_cast(i))); + std::cout << "IN: " << v << "OUT: " << out; + return check_if_equal(v, out, message); + } +}; +void +BSplines_Tests::run_tests() { + cerr << "Testing BSplines set of functions..." << endl; + set_tolerance(0.001); + typedef double elemT; + static std::vector pre_input_sample; + // pre_input_sample.push_back(-5); + pre_input_sample.push_back(-14); + pre_input_sample.push_back(8); + pre_input_sample.push_back(-1); + pre_input_sample.push_back(13); + pre_input_sample.push_back(-1); + pre_input_sample.push_back(-2); + pre_input_sample.push_back(11); + pre_input_sample.push_back(1); + pre_input_sample.push_back(-8); + pre_input_sample.push_back(6); + pre_input_sample.push_back(11); + pre_input_sample.push_back(-14); + pre_input_sample.push_back(6); + pre_input_sample.push_back(-3); + pre_input_sample.push_back(10); + pre_input_sample.push_back(1); + pre_input_sample.push_back(7); + pre_input_sample.push_back(-2); + pre_input_sample.push_back(-5); + pre_input_sample.push_back(-9); + pre_input_sample.push_back(-9); + pre_input_sample.push_back(6); + pre_input_sample.push_back(-5); + pre_input_sample.push_back(2); + pre_input_sample.push_back(-10); + pre_input_sample.push_back(6); + pre_input_sample.push_back(-3); + pre_input_sample.push_back(11); + pre_input_sample.push_back(11); + pre_input_sample.push_back(3); + { + cerr << "Testing BSplines_weights cubic function..." << endl; + std::vector BSplines_weights_STIR_vector_3, BSplines_weights_correct_vector_3; + BSplines1DRegularGrid BSplines1DRegularGridTests; + for (elemT i = 0.3; i <= 3; ++i) + BSplines_weights_STIR_vector_3.push_back(BSplines_weights(i, cubic)); + BSplines_weights_STIR_vector_3.push_back(BSplines_weights(0., cubic)); + + BSplines_weights_correct_vector_3.push_back(0.590167); // 1 + BSplines_weights_correct_vector_3.push_back(0.0571667); // 2 + BSplines_weights_correct_vector_3.push_back(0.); // 3 + BSplines_weights_correct_vector_3.push_back(0.666667); // 4 + + std::vector::iterator cur_iter_stir_out_3 = BSplines_weights_STIR_vector_3.begin(), + cur_iter_test_3 = BSplines_weights_correct_vector_3.begin(); + for (; cur_iter_stir_out_3 != BSplines_weights_STIR_vector_3.end() && + cur_iter_test_3 != BSplines_weights_correct_vector_3.end(); + ++cur_iter_stir_out_3, ++cur_iter_test_3) + check_if_equal(*cur_iter_stir_out_3, *cur_iter_test_3, "check cubic BSplines_weights implementation"); + } + { + cerr << "Testing BSplines_weights quadratic function..." << endl; + std::vector BSplines_weights_STIR_vector_2, BSplines_weights_correct_vector_2; + BSplines1DRegularGrid BSplines1DRegularGridTests; + for (elemT i = 0.3; i <= 3; ++i) + BSplines_weights_STIR_vector_2.push_back(BSplines_weights(i, quadratic)); + BSplines_weights_STIR_vector_2.push_back(BSplines_weights(0., quadratic)); + BSplines_weights_correct_vector_2.push_back(0.66); // 1 + BSplines_weights_correct_vector_2.push_back(0.02); // 2 + BSplines_weights_correct_vector_2.push_back(0.00); // 3 + BSplines_weights_correct_vector_2.push_back(0.75); // 4 + + std::vector::iterator cur_iter_stir_out_2 = BSplines_weights_STIR_vector_2.begin(), + cur_iter_test_2 = BSplines_weights_correct_vector_2.begin(); + for (; cur_iter_stir_out_2 != BSplines_weights_STIR_vector_2.end() && + cur_iter_test_2 != BSplines_weights_correct_vector_2.end(); + ++cur_iter_stir_out_2, ++cur_iter_test_2) + check_if_equal(*cur_iter_stir_out_2, *cur_iter_test_2, "check BSplines_weights quadratic implementation"); + } + { + cerr << "Testing BSplines_weights quintic function..." << endl; + std::vector BSplines_weights_STIR_vector_5, BSplines_weights_correct_vector_5; + BSplines1DRegularGrid BSplines1DRegularGridTests; + for (elemT i = 0.3; i <= 3; ++i) + BSplines_weights_STIR_vector_5.push_back(BSplines_weights(i, quintic)); + BSplines_weights_STIR_vector_5.push_back(BSplines_weights(0., quintic)); + BSplines_weights_correct_vector_5.push_back(0.506823); // 1 + BSplines_weights_correct_vector_5.push_back(0.109918); // 2 + BSplines_weights_correct_vector_5.push_back(0.00140058); // 3 + BSplines_weights_correct_vector_5.push_back(0.55); // 4 + std::vector::iterator cur_iter_stir_out = BSplines_weights_STIR_vector_5.begin(), + cur_iter_test = BSplines_weights_correct_vector_5.begin(); + for (; cur_iter_stir_out != BSplines_weights_STIR_vector_5.end() && cur_iter_test != BSplines_weights_correct_vector_5.end(); + ++cur_iter_stir_out, ++cur_iter_test) + check_if_equal(*cur_iter_stir_out, *cur_iter_test, "check BSplines_weights quintic implementation"); + } + { + BSplines1DRegularGrid BSplines1DRegularGridTests; + cerr << "Testing oMoms_weight function..." << endl; + std::vector oMoms_weight_STIR_vector, oMoms_weight_correct_vector; + oMoms_weight_STIR_vector.push_back(oMoms_weight(0.)); + for (elemT i = 0.3; i <= 3; ++i) + oMoms_weight_STIR_vector.push_back(oMoms_weight(i)); + oMoms_weight_correct_vector.push_back(0.619048); // 1 + oMoms_weight_correct_vector.push_back(0.563976); // 2 + oMoms_weight_correct_vector.push_back(0.0738333); // 3 + oMoms_weight_correct_vector.push_back(0.); // 4 + std::vector::iterator cur_iter_stir_out = oMoms_weight_STIR_vector.begin(), + cur_iter_test = oMoms_weight_correct_vector.begin(); + for (; cur_iter_stir_out != oMoms_weight_STIR_vector.end() && cur_iter_test != oMoms_weight_correct_vector.end(); + ++cur_iter_stir_out, ++cur_iter_test) + check_if_equal(*cur_iter_stir_out, *cur_iter_test, "check oMoms_weight implementation"); + } + { + cerr << "Testing BSplines_1st_der_weight function..." << endl; + BSplines1DRegularGrid BSplines1DRegularGridTests; + std::vector BSplines_1st_der_weight_STIR_vector, BSplines_1st_der_weight_correct_vector, + BSplines_1st_der_weight_est_vector; + + BSplines_1st_der_weight_STIR_vector.push_back(BSplines_1st_der_weight(0., cubic)); + + for (elemT i = 0.3; i <= 3; ++i) + BSplines_1st_der_weight_STIR_vector.push_back(BSplines_1st_der_weight(i, cubic)); + BSplines_1st_der_weight_correct_vector.push_back(0.); // 1 + BSplines_1st_der_weight_correct_vector.push_back(-0.465); // 2 + BSplines_1st_der_weight_correct_vector.push_back(-0.245); // 3 + BSplines_1st_der_weight_correct_vector.push_back(0.); // 4 + for (std::vector::iterator cur_iter_stir_out = BSplines_1st_der_weight_STIR_vector.begin(), + cur_iter_test = BSplines_1st_der_weight_correct_vector.begin(); + cur_iter_stir_out != BSplines_1st_der_weight_STIR_vector.end() && + cur_iter_test != BSplines_1st_der_weight_correct_vector.end(); + ++cur_iter_stir_out, ++cur_iter_test) + check_if_equal(*cur_iter_stir_out, *cur_iter_test, "check BSplines_1st_der_weight implementation"); + } + { + cerr << "Testing BSplines 1st Derivative analytically..." << endl; + std::vector BSplines_1st_der_STIR_vector, BSplines_1st_der_est_vector, new_input_sample(15, 1); + new_input_sample[5] = 7.; + new_input_sample[6] = 9.; + new_input_sample[10] = 91.; + BSplines1DRegularGrid BSplines1DRegularGridTest(new_input_sample, cubic); + const double epsilon = .0001; + for (double i = 0; i <= new_input_sample.size() + 3; ++i) { + BSplines_1st_der_STIR_vector.push_back(BSplines1DRegularGridTest.BSplines_1st_der(i)); + BSplines_1st_der_est_vector.push_back((BSplines1DRegularGridTest(i + epsilon) - BSplines1DRegularGridTest(i - epsilon)) / + (2 * epsilon)); + } + for (std::vector::iterator cur_iter_stir_out = BSplines_1st_der_est_vector.begin(), + cur_iter_test = BSplines_1st_der_STIR_vector.begin(); + cur_iter_test != BSplines_1st_der_STIR_vector.end(); ++cur_iter_stir_out, ++cur_iter_test) + check_if_equal(*cur_iter_stir_out, *cur_iter_test, "check cubic BSplines_1st_der_est or cubic BSplines implementation"); + } { - public: - BSplines_Tests() - {} - void run_tests(); - private: - template - bool check_at_sample_points(const std::vector& v, - BSplines1DRegularGrid& interpolator, - const char * const message) + cerr << "Testing BSplines: Nearest Neighbour values and constructor using a vector as input..." << endl; { - std::vector out; - for (std::size_t i=0, imax=v.size(); i(i))); - std::cout << "IN: " << v << "OUT: " << out; - return - check_if_equal(v, out, message); + const std::vector const_input_sample(10, 1); + BSplines1DRegularGrid BSplines1DRegularGridTest1(const_input_sample.begin(), const_input_sample.end(), + near_n); + check_at_sample_points(const_input_sample, BSplines1DRegularGridTest1, + "check BSplines implementation for nearest interpolation"); } - }; - void BSplines_Tests::run_tests() - { - cerr << "Testing BSplines set of functions..." << endl; - set_tolerance(0.001); - typedef double elemT; - static std::vector pre_input_sample; - //pre_input_sample.push_back(-5); - pre_input_sample.push_back(-14); pre_input_sample.push_back(8); pre_input_sample.push_back(-1); - pre_input_sample.push_back(13); pre_input_sample.push_back(-1); pre_input_sample.push_back(-2); - pre_input_sample.push_back(11); pre_input_sample.push_back(1); pre_input_sample.push_back(-8); - pre_input_sample.push_back(6); pre_input_sample.push_back(11); pre_input_sample.push_back(-14); - pre_input_sample.push_back(6); pre_input_sample.push_back(-3); pre_input_sample.push_back(10); - pre_input_sample.push_back(1); pre_input_sample.push_back(7); pre_input_sample.push_back(-2); - pre_input_sample.push_back(-5); pre_input_sample.push_back(-9); pre_input_sample.push_back(-9); - pre_input_sample.push_back(6); pre_input_sample.push_back(-5); pre_input_sample.push_back(2); - pre_input_sample.push_back(-10); pre_input_sample.push_back(6); pre_input_sample.push_back(-3); - pre_input_sample.push_back(11); pre_input_sample.push_back(11); pre_input_sample.push_back(3); { - cerr << "Testing BSplines_weights cubic function..." << endl; - std::vector BSplines_weights_STIR_vector_3, BSplines_weights_correct_vector_3; - BSplines1DRegularGrid BSplines1DRegularGridTests; - for(elemT i=0.3; i<=3 ;++i) - BSplines_weights_STIR_vector_3.push_back(BSplines_weights(i,cubic)); - BSplines_weights_STIR_vector_3.push_back(BSplines_weights(0.,cubic)); + std::vector linear_input; + for (elemT i = 0, imax = 10; i < imax; ++i) + linear_input.push_back(i); + BSplines1DRegularGrid BSplines1DRegularGridTesti(linear_input, near_n); - BSplines_weights_correct_vector_3.push_back(0.590167); //1 - BSplines_weights_correct_vector_3.push_back(0.0571667); //2 - BSplines_weights_correct_vector_3.push_back(0.); //3 - BSplines_weights_correct_vector_3.push_back(0.666667); //4 - - std::vector:: iterator cur_iter_stir_out_3= BSplines_weights_STIR_vector_3.begin() - , cur_iter_test_3= BSplines_weights_correct_vector_3.begin() ; - for (; cur_iter_stir_out_3!=BSplines_weights_STIR_vector_3.end() && - cur_iter_test_3!=BSplines_weights_correct_vector_3.end(); - ++cur_iter_stir_out_3, ++cur_iter_test_3) - check_if_equal(*cur_iter_stir_out_3, *cur_iter_test_3, - "check cubic BSplines_weights implementation"); + check_at_sample_points(linear_input, BSplines1DRegularGridTesti, "check BSplines implementation for nearest interpolation"); } { - cerr << "Testing BSplines_weights quadratic function..." << endl; - std::vector BSplines_weights_STIR_vector_2, BSplines_weights_correct_vector_2; - BSplines1DRegularGrid BSplines1DRegularGridTests; - for(elemT i=0.3; i<=3 ;++i) - BSplines_weights_STIR_vector_2.push_back(BSplines_weights(i,quadratic)); - BSplines_weights_STIR_vector_2.push_back(BSplines_weights(0.,quadratic)); - BSplines_weights_correct_vector_2.push_back(0.66); //1 - BSplines_weights_correct_vector_2.push_back(0.02); //2 - BSplines_weights_correct_vector_2.push_back(0.00); //3 - BSplines_weights_correct_vector_2.push_back(0.75); //4 - - std::vector:: iterator cur_iter_stir_out_2= BSplines_weights_STIR_vector_2.begin() - , cur_iter_test_2= BSplines_weights_correct_vector_2.begin() ; - for (; cur_iter_stir_out_2!=BSplines_weights_STIR_vector_2.end() && - cur_iter_test_2!=BSplines_weights_correct_vector_2.end(); - ++cur_iter_stir_out_2, ++cur_iter_test_2) - check_if_equal(*cur_iter_stir_out_2, *cur_iter_test_2, - "check BSplines_weights quadratic implementation"); + BSplines1DRegularGrid BSplines1DRegularGridTest(pre_input_sample, near_n); + check_at_sample_points(pre_input_sample, BSplines1DRegularGridTest, + "check BSplines implementation for nearest interpolation"); } + } + { + cerr << "Testing BSplines: Linear Interpolation values and constructor using a vector as input..." << endl; { - cerr << "Testing BSplines_weights quintic function..." << endl; - std::vector BSplines_weights_STIR_vector_5, BSplines_weights_correct_vector_5; - BSplines1DRegularGrid BSplines1DRegularGridTests; - for(elemT i=0.3; i<=3 ;++i) - BSplines_weights_STIR_vector_5.push_back(BSplines_weights(i,quintic)); - BSplines_weights_STIR_vector_5.push_back(BSplines_weights(0.,quintic)); - BSplines_weights_correct_vector_5.push_back(0.506823); //1 - BSplines_weights_correct_vector_5.push_back(0.109918); //2 - BSplines_weights_correct_vector_5.push_back(0.00140058); //3 - BSplines_weights_correct_vector_5.push_back(0.55); //4 - std::vector:: iterator cur_iter_stir_out= BSplines_weights_STIR_vector_5.begin() - , cur_iter_test= BSplines_weights_correct_vector_5.begin() ; - for (; cur_iter_stir_out!=BSplines_weights_STIR_vector_5.end() && - cur_iter_test!=BSplines_weights_correct_vector_5.end(); - ++cur_iter_stir_out, ++cur_iter_test) - check_if_equal(*cur_iter_stir_out, *cur_iter_test, - "check BSplines_weights quintic implementation"); + const std::vector const_input_sample(10, 1); + BSplines1DRegularGrid BSplines1DRegularGridTest1(const_input_sample.begin(), const_input_sample.end(), + linear); + check_at_sample_points(const_input_sample, BSplines1DRegularGridTest1, + "check BSplines implementation for linear interpolation"); } { - BSplines1DRegularGrid BSplines1DRegularGridTests; - cerr << "Testing oMoms_weight function..." << endl; - std::vector oMoms_weight_STIR_vector, oMoms_weight_correct_vector; - oMoms_weight_STIR_vector.push_back(oMoms_weight(0.)); - for(elemT i=0.3; i<=3 ;++i) - oMoms_weight_STIR_vector.push_back(oMoms_weight(i)); - oMoms_weight_correct_vector.push_back(0.619048);//1 - oMoms_weight_correct_vector.push_back(0.563976);//2 - oMoms_weight_correct_vector.push_back(0.0738333);//3 - oMoms_weight_correct_vector.push_back(0.); //4 - std::vector:: iterator cur_iter_stir_out= oMoms_weight_STIR_vector.begin() - , cur_iter_test= oMoms_weight_correct_vector.begin() ; - for (; cur_iter_stir_out!= oMoms_weight_STIR_vector.end() && - cur_iter_test!= oMoms_weight_correct_vector.end(); - ++cur_iter_stir_out, ++cur_iter_test) - check_if_equal(*cur_iter_stir_out, *cur_iter_test, - "check oMoms_weight implementation"); - } - { - cerr << "Testing BSplines_1st_der_weight function..." << endl; - BSplines1DRegularGrid BSplines1DRegularGridTests; - std::vector BSplines_1st_der_weight_STIR_vector, BSplines_1st_der_weight_correct_vector, - BSplines_1st_der_weight_est_vector; - - BSplines_1st_der_weight_STIR_vector.push_back(BSplines_1st_der_weight(0.,cubic)); + std::vector linear_input; + for (elemT i = 0, imax = 10; i < imax; ++i) + linear_input.push_back(i); + BSplines1DRegularGrid BSplines1DRegularGridTesti(linear_input, linear); - for(elemT i=0.3; i<=3 ;++i) - BSplines_1st_der_weight_STIR_vector.push_back(BSplines_1st_der_weight(i,cubic)); - BSplines_1st_der_weight_correct_vector.push_back(0.); //1 - BSplines_1st_der_weight_correct_vector.push_back(-0.465); //2 - BSplines_1st_der_weight_correct_vector.push_back(-0.245); //3 - BSplines_1st_der_weight_correct_vector.push_back(0.); //4 - for ( std::vector:: iterator cur_iter_stir_out= BSplines_1st_der_weight_STIR_vector.begin() - , cur_iter_test= BSplines_1st_der_weight_correct_vector.begin(); - cur_iter_stir_out!=BSplines_1st_der_weight_STIR_vector.end() && - cur_iter_test!=BSplines_1st_der_weight_correct_vector.end(); - ++cur_iter_stir_out, ++cur_iter_test) - check_if_equal(*cur_iter_stir_out, *cur_iter_test, - "check BSplines_1st_der_weight implementation"); + check_at_sample_points(linear_input, BSplines1DRegularGridTesti, "check BSplines implementation for linear interpolation"); } - { - cerr << "Testing BSplines 1st Derivative analytically..." << endl; - std::vector BSplines_1st_der_STIR_vector, - BSplines_1st_der_est_vector, new_input_sample(15,1); - new_input_sample[5]=7.; - new_input_sample[6]=9.; - new_input_sample[10]=91.; - BSplines1DRegularGrid BSplines1DRegularGridTest(new_input_sample,cubic); - const double epsilon = .0001; - for(double i=0; i<=new_input_sample.size()+3 ;++i) - { - BSplines_1st_der_STIR_vector.push_back(BSplines1DRegularGridTest.BSplines_1st_der(i)); - BSplines_1st_der_est_vector.push_back( - (BSplines1DRegularGridTest(i+epsilon) - - BSplines1DRegularGridTest(i-epsilon)) /(2*epsilon)); - } - for ( std::vector:: iterator cur_iter_stir_out= BSplines_1st_der_est_vector.begin() - , cur_iter_test=BSplines_1st_der_STIR_vector.begin(); - cur_iter_test!=BSplines_1st_der_STIR_vector.end(); - ++cur_iter_stir_out, ++cur_iter_test) - check_if_equal(*cur_iter_stir_out, *cur_iter_test, - "check cubic BSplines_1st_der_est or cubic BSplines implementation"); - } { - cerr << "Testing BSplines: Nearest Neighbour values and constructor using a vector as input..." << endl; - { - const std::vector const_input_sample(10,1); - BSplines1DRegularGrid BSplines1DRegularGridTest1( - const_input_sample.begin(), const_input_sample.end(), near_n); - check_at_sample_points(const_input_sample, BSplines1DRegularGridTest1, - "check BSplines implementation for nearest interpolation"); - } - { - std::vector linear_input; - for (elemT i=0, imax=10; i - BSplines1DRegularGridTesti(linear_input, near_n); - - check_at_sample_points(linear_input, BSplines1DRegularGridTesti, - "check BSplines implementation for nearest interpolation"); - } - { - BSplines1DRegularGrid - BSplines1DRegularGridTest(pre_input_sample, near_n); - check_at_sample_points(pre_input_sample, BSplines1DRegularGridTest, - "check BSplines implementation for nearest interpolation"); - } + BSplines1DRegularGrid BSplines1DRegularGridTest(pre_input_sample, linear); + check_at_sample_points(pre_input_sample, BSplines1DRegularGridTest, + "check BSplines implementation for linear interpolation"); } + } + { + cerr << "Testing BSplines: Quadratic Interpolation values and constructor using a vector as input..." << endl; { - cerr << "Testing BSplines: Linear Interpolation values and constructor using a vector as input..." << endl; - { - const std::vector const_input_sample(10,1); - BSplines1DRegularGrid BSplines1DRegularGridTest1( - const_input_sample.begin(), const_input_sample.end(), linear); - check_at_sample_points(const_input_sample, BSplines1DRegularGridTest1, - "check BSplines implementation for linear interpolation"); - } - { - std::vector linear_input; - for (elemT i=0, imax=10; i - BSplines1DRegularGridTesti(linear_input, linear); - - check_at_sample_points(linear_input, BSplines1DRegularGridTesti, - "check BSplines implementation for linear interpolation"); - } - { - BSplines1DRegularGrid - BSplines1DRegularGridTest(pre_input_sample, linear); - check_at_sample_points(pre_input_sample, BSplines1DRegularGridTest, - "check BSplines implementation for linear interpolation"); - } + const std::vector const_input_sample(10, 1); + BSplines1DRegularGrid BSplines1DRegularGridTest1(const_input_sample.begin(), const_input_sample.end(), + quadratic); + check_at_sample_points(const_input_sample, BSplines1DRegularGridTest1, + "check BSplines implementation for quadratic interpolation"); } { - cerr << "Testing BSplines: Quadratic Interpolation values and constructor using a vector as input..." << endl; - { - const std::vector const_input_sample(10,1); - BSplines1DRegularGrid BSplines1DRegularGridTest1( - const_input_sample.begin(), const_input_sample.end(), quadratic); - check_at_sample_points(const_input_sample, BSplines1DRegularGridTest1, - "check BSplines implementation for quadratic interpolation"); - } - { - std::vector linear_input; - for (elemT i=0, imax=10; i - BSplines1DRegularGridTesti(linear_input, quadratic); - - check_at_sample_points(linear_input, BSplines1DRegularGridTesti, - "check BSplines implementation for quadratic interpolation"); - } - { - BSplines1DRegularGrid - BSplines1DRegularGridTest(pre_input_sample, quadratic); - check_at_sample_points(pre_input_sample, BSplines1DRegularGridTest, - "check BSplines implementation for quadratic interpolation"); - } - } - { - cerr << "Testing BSplines: Cubic Interpolation values and constructor using a vector as input..." << endl; - { - const std::vector const_input_sample(10,1); - BSplines1DRegularGrid BSplines1DRegularGridTest1( - const_input_sample.begin(), const_input_sample.end(), cubic); - check_at_sample_points(const_input_sample, BSplines1DRegularGridTest1, - "check BSplines implementation for cubic interpolation"); - } - { - std::vector linear_input; - for (elemT i=0, imax=10; i - BSplines1DRegularGridTesti(linear_input, cubic); - - check_at_sample_points(linear_input, BSplines1DRegularGridTesti, - "check BSplines implementation for cubic interpolation"); - } - { - BSplines1DRegularGrid - BSplines1DRegularGridTest(pre_input_sample, cubic); - check_at_sample_points(pre_input_sample, BSplines1DRegularGridTest, - "check BSplines implementation for cubic interpolation"); - } - } + std::vector linear_input; + for (elemT i = 0, imax = 10; i < imax; ++i) + linear_input.push_back(i); + BSplines1DRegularGrid BSplines1DRegularGridTesti(linear_input, quadratic); + + check_at_sample_points(linear_input, BSplines1DRegularGridTesti, + "check BSplines implementation for quadratic interpolation"); + } { - cerr << "Testing BSplines: o-Moms Interpolation values and constructor using a vector as input..." << endl; - { - const std::vector const_input_sample(10,1); - BSplines1DRegularGrid BSplines1DRegularGridTest1( - const_input_sample.begin(), const_input_sample.end(), oMoms); - check_at_sample_points(const_input_sample, BSplines1DRegularGridTest1, - "check BSplines implementation for o-Moms interpolation"); - } - { - std::vector linear_input; - for (elemT i=0, imax=10; i - BSplines1DRegularGridTesti(linear_input, oMoms); - - check_at_sample_points(linear_input, BSplines1DRegularGridTesti, - "check BSplines implementation for o-Moms interpolation"); - } - } + BSplines1DRegularGrid BSplines1DRegularGridTest(pre_input_sample, quadratic); + check_at_sample_points(pre_input_sample, BSplines1DRegularGridTest, + "check BSplines implementation for quadratic interpolation"); + } + } + { + cerr << "Testing BSplines: Cubic Interpolation values and constructor using a vector as input..." << endl; { - cerr << "Testing BSplines Continuity..." << endl; - std::vector new_input_sample(12,1) , STIR_right_output_sample, - STIR_left_output_sample; - BSplines1DRegularGrid BSplines1DRegularGridTests( - new_input_sample.begin(), new_input_sample.end()); - // test if shifted copy of the B-spline functions add to 1 - for (double inc=0; inc<1; inc+=.1) - check_if_equal( - BSplines_weights(+inc,cubic)+ - BSplines_weights(+inc+1,cubic)+ - BSplines_weights(+inc+2,cubic)+ - BSplines_weights(+inc-1,cubic)+ - BSplines_weights(+inc-2,cubic), - 1., "test on cubic B-spline function"); - std::cerr << '\n'; - const elemT epsilon = 0.01; - for (elemT i=1, imax=10; i:: iterator cur_iter_stir_left_out= STIR_left_output_sample.begin(), - cur_iter_stir_right_out= STIR_right_output_sample.begin(); - for (; cur_iter_stir_left_out!=STIR_left_output_sample.end() && - cur_iter_stir_right_out!=STIR_right_output_sample.end(); - ++cur_iter_stir_left_out, ++cur_iter_stir_right_out) - check_if_equal(*cur_iter_stir_left_out, *cur_iter_stir_right_out, - "check BSplines implementation"); + const std::vector const_input_sample(10, 1); + BSplines1DRegularGrid BSplines1DRegularGridTest1(const_input_sample.begin(), const_input_sample.end(), cubic); + check_at_sample_points(const_input_sample, BSplines1DRegularGridTest1, + "check BSplines implementation for cubic interpolation"); } { - cerr << "Testing BSplines 1st Derivative Continuity..." << endl; - std::vector new_input_sample, STIR_right_output_sample, STIR_left_output_sample; + std::vector linear_input; + for (elemT i = 0, imax = 10; i < imax; ++i) + linear_input.push_back(i); + BSplines1DRegularGrid BSplines1DRegularGridTesti(linear_input, cubic); - for (elemT i=0, imax=14; i BSplines1DRegularGridTests( - new_input_sample.begin(), new_input_sample.end()); - - std::cerr << '\n'; - const elemT epsilon = 0.0001; - for (elemT i=1, imax=13; i:: iterator cur_iter_stir_left_out= STIR_left_output_sample.begin(), - cur_iter_stir_right_out= STIR_right_output_sample.begin(); - for (; cur_iter_stir_left_out!=STIR_left_output_sample.end() && - cur_iter_stir_right_out!=STIR_right_output_sample.end(); - ++cur_iter_stir_left_out, ++cur_iter_stir_right_out) - check_if_equal(*cur_iter_stir_left_out, *cur_iter_stir_right_out, - "check BSplines implementation"); + check_at_sample_points(linear_input, BSplines1DRegularGridTesti, "check BSplines implementation for cubic interpolation"); } { - cerr << "Testing BSplines values giving a vector as input..." << endl; - std::vector input_sample(10,1), output_sample_position, STIR_output_sample; - - BSplines1DRegularGrid BSplines1DRegularGridTests(input_sample); - for (elemT i=0, imax=23; i BSplines1DRegularGridTest(pre_input_sample, cubic); + check_at_sample_points(pre_input_sample, BSplines1DRegularGridTest, + "check BSplines implementation for cubic interpolation"); + } + } + { + cerr << "Testing BSplines: o-Moms Interpolation values and constructor using a vector as input..." << endl; + { + const std::vector const_input_sample(10, 1); + BSplines1DRegularGrid BSplines1DRegularGridTest1(const_input_sample.begin(), const_input_sample.end(), oMoms); + check_at_sample_points(const_input_sample, BSplines1DRegularGridTest1, + "check BSplines implementation for o-Moms interpolation"); + } + { + std::vector linear_input; + for (elemT i = 0, imax = 10; i < imax; ++i) + linear_input.push_back(i); + BSplines1DRegularGrid BSplines1DRegularGridTesti(linear_input, oMoms); - std::vector:: iterator cur_iter_stir_out = STIR_output_sample.begin(); + check_at_sample_points(linear_input, BSplines1DRegularGridTesti, "check BSplines implementation for o-Moms interpolation"); + } + } + { + cerr << "Testing BSplines Continuity..." << endl; + std::vector new_input_sample(12, 1), STIR_right_output_sample, STIR_left_output_sample; + BSplines1DRegularGrid BSplines1DRegularGridTests(new_input_sample.begin(), new_input_sample.end()); + // test if shifted copy of the B-spline functions add to 1 + for (double inc = 0; inc < 1; inc += .1) + check_if_equal(BSplines_weights(+inc, cubic) + BSplines_weights(+inc + 1, cubic) + BSplines_weights(+inc + 2, cubic) + + BSplines_weights(+inc - 1, cubic) + BSplines_weights(+inc - 2, cubic), + 1., "test on cubic B-spline function"); + std::cerr << '\n'; + const elemT epsilon = 0.01; + for (elemT i = 1, imax = 10; i < imax; ++i) { + STIR_left_output_sample.push_back(BSplines1DRegularGridTests(i - epsilon)); + STIR_right_output_sample.push_back(BSplines1DRegularGridTests(i + epsilon)); + } + std::vector::iterator cur_iter_stir_left_out = STIR_left_output_sample.begin(), + cur_iter_stir_right_out = STIR_right_output_sample.begin(); + for (; cur_iter_stir_left_out != STIR_left_output_sample.end() && cur_iter_stir_right_out != STIR_right_output_sample.end(); + ++cur_iter_stir_left_out, ++cur_iter_stir_right_out) + check_if_equal(*cur_iter_stir_left_out, *cur_iter_stir_right_out, "check BSplines implementation"); + } + { + cerr << "Testing BSplines 1st Derivative Continuity..." << endl; + std::vector new_input_sample, STIR_right_output_sample, STIR_left_output_sample; + + for (elemT i = 0, imax = 14; i < imax; ++i) + new_input_sample.push_back(i); + + BSplines1DRegularGrid BSplines1DRegularGridTests(new_input_sample.begin(), new_input_sample.end()); + + std::cerr << '\n'; + const elemT epsilon = 0.0001; + for (elemT i = 1, imax = 13; i < imax; ++i) { + STIR_left_output_sample.push_back(BSplines1DRegularGridTests.BSplines_1st_der(i - epsilon)); + STIR_right_output_sample.push_back(BSplines1DRegularGridTests.BSplines_1st_der(i + epsilon)); + } + std::vector::iterator cur_iter_stir_left_out = STIR_left_output_sample.begin(), + cur_iter_stir_right_out = STIR_right_output_sample.begin(); + for (; cur_iter_stir_left_out != STIR_left_output_sample.end() && cur_iter_stir_right_out != STIR_right_output_sample.end(); + ++cur_iter_stir_left_out, ++cur_iter_stir_right_out) + check_if_equal(*cur_iter_stir_left_out, *cur_iter_stir_right_out, "check BSplines implementation"); + } + { + cerr << "Testing BSplines values giving a vector as input..." << endl; + std::vector input_sample(10, 1), output_sample_position, STIR_output_sample; + + BSplines1DRegularGrid BSplines1DRegularGridTests(input_sample); + for (elemT i = 0, imax = 23; i < imax; ++i) + output_sample_position.push_back((i + 0.5) / 2.4); - for (; cur_iter_stir_out!=STIR_output_sample.end(); ++cur_iter_stir_out) - check_if_equal(*cur_iter_stir_out, (elemT)1, - "check BSplines implementation"); - } - /* { - cerr << "Testing interpolation results. Look at the text files!" << endl; - std::vector exp_input_sample; - std::vector STIR_output_sample; - int imax =30; - for(int i=0; i:: iterator cur_iter_stir_out= STIR_output_sample.begin(); - BSplines1DRegularGrid BSplines1DRegularGridTest( - pre_input_sample.begin(), pre_input_sample.end(), linear); - string output_string; - output_string += "gaussian"; //"noisy_inter" ; - ofstream out(output_string.c_str()); //output file // - - if(!out) - { - cout << "Cannot open text file.\n" ; - //return EXIT_FAILURE; - } - - - // STIR_output_sample.push_back(BSplines1DRegularGridTest(i)); - // cout << STIR_output_sample; - out << BSplines1DRegularGridTest.spline_type <<". B-Spline \n"; - out << "Position " << "\t" << " Value \n" ; - for (elemT i=0; i::iterator cur_iter_stir_out = STIR_output_sample.begin(); + + for (; cur_iter_stir_out != STIR_output_sample.end(); ++cur_iter_stir_out) + check_if_equal(*cur_iter_stir_out, (elemT)1, "check BSplines implementation"); } + /* { + cerr << "Testing interpolation results. Look at the text files!" << endl; + std::vector exp_input_sample; + std::vector STIR_output_sample; + int imax =30; + for(int i=0; i:: iterator cur_iter_stir_out= STIR_output_sample.begin(); + BSplines1DRegularGrid BSplines1DRegularGridTest( + pre_input_sample.begin(), pre_input_sample.end(), linear); + string output_string; + output_string += "gaussian"; //"noisy_inter" ; + ofstream out(output_string.c_str()); //output file // + + if(!out) + { + cout << "Cannot open text file.\n" ; + //return EXIT_FAILURE; + } + + + // STIR_output_sample.push_back(BSplines1DRegularGridTest(i)); + // cout << STIR_output_sample; + out << BSplines1DRegularGridTest.spline_type <<". B-Spline \n"; + out << "Position " << "\t" << " Value \n" ; + for (elemT i=0; i - bool check_at_sample_points(const Array<2,elemT>& v, - const BSplinesRegularGrid<2, elemT, elemT>& interpolator, - const char * const message) - { - Array<2,elemT> out(v.get_index_range()); - BasicCoordinate<2, elemT> relative_positions; - for (int j=out.get_min_index() ; j<=out.get_max_index() ; ++j) - for (int i=out[j].get_min_index() ; i<=out[j].get_max_index() ; ++i) - { - relative_positions[1]=j; - relative_positions[2]=i; - out[j][i]=interpolator(relative_positions); - } - // cout << "IN: \n" << v << "OUT: \n" << out; - return - check_if_equal(v, out, message); - } - template - bool check_near_sample_points(const Array<2,elemT>& v, - const BSplinesRegularGrid<2, elemT, elemT>& interpolator, - const BasicCoordinate<2, elemT>& epsilon, - const char * const message) - { - Array<2,elemT> out_near(v.get_index_range()); - BasicCoordinate<2, elemT> relative_positions; - for (int j=out_near.get_min_index() ; j<=out_near.get_max_index() ; ++j) - for (int i=out_near[j].get_min_index() ; i<=out_near[j].get_max_index() ; ++i) - { - relative_positions[1]=j+epsilon[1]; - relative_positions[2]=i+epsilon[2]; - out_near[j][i]=interpolator(relative_positions); - } - // cout << "IN: \n" << v << "out_near: \n" << out_near; - return - check_if_equal(v, out_near, message); - } - - template - bool check_at_half_way(const Array<2,elemT>& v, - const Array<2,elemT>& v_at_half, - const BSplinesRegularGrid<2, elemT, elemT>& interpolator, - const char * const message) - { - Array<2,elemT> out_at_half(v_at_half.get_index_range()), dv(v_at_half.get_index_range()); - BasicCoordinate<2, elemT> relative_positions; - for (int j=out_at_half.get_min_index() ; j<=out_at_half.get_max_index() ; ++j) - for (int i=out_at_half[j].get_min_index() ; i<=out_at_half[j].get_max_index() ; ++i) - { - relative_positions[1]=j+0.5; - relative_positions[2]=i+0.5; - out_at_half[j][i]=interpolator(relative_positions); - } - dv = (out_at_half - v_at_half)/v_at_half.sum(); - dv *= dv; - - // cout << "Checking BSplines implementation at half way:\n" ; - // cout << "IN: \n" << v_at_half << "OUT: \n" << out_at_half; - std::cout << "The mean deviation from the correct value is: " - << sqrt(dv.sum()/dv.size_all()) << endl; - return - check_if_zero(sqrt(dv.sum()/dv.size_all()), message); - } +/*! + \ingroup numerics_test + \brief A simple class to BSplinesRegularGrid for 2D arrays. +*/ +class BSplinesRegularGrid_Tests : public RunTests { +public: + BSplinesRegularGrid_Tests() {} + void run_tests(); - template - bool check_at_half_way(const Array<2,elemT>& v, - const BSplinesRegularGrid<2, elemT, elemT>& interpolator) - { - Array<2,elemT> out(v.get_index_range()); - BasicCoordinate<2, elemT> relative_positions; - for (int j=out.get_min_index() ; j<=out.get_max_index() ; ++j) - for (int i=out[j].get_min_index() ; i<=out[j].get_max_index() ; ++i) - { - relative_positions[1]=j+0.5; - relative_positions[2]=i+0.5; - out[j][i]=interpolator(relative_positions); - } - std::cout << "BSplines implementation at half way:\n" ; - std::cout << "IN: \n" << v << "OUT: \n" << out; - return true; - } +private: + template + bool check_at_sample_points(const Array<2, elemT>& v, const BSplinesRegularGrid<2, elemT, elemT>& interpolator, + const char* const message) { + Array<2, elemT> out(v.get_index_range()); + BasicCoordinate<2, elemT> relative_positions; + for (int j = out.get_min_index(); j <= out.get_max_index(); ++j) + for (int i = out[j].get_min_index(); i <= out[j].get_max_index(); ++i) { + relative_positions[1] = j; + relative_positions[2] = i; + out[j][i] = interpolator(relative_positions); + } + // cout << "IN: \n" << v << "OUT: \n" << out; + return check_if_equal(v, out, message); + } + template + bool check_near_sample_points(const Array<2, elemT>& v, const BSplinesRegularGrid<2, elemT, elemT>& interpolator, + const BasicCoordinate<2, elemT>& epsilon, const char* const message) { + Array<2, elemT> out_near(v.get_index_range()); + BasicCoordinate<2, elemT> relative_positions; + for (int j = out_near.get_min_index(); j <= out_near.get_max_index(); ++j) + for (int i = out_near[j].get_min_index(); i <= out_near[j].get_max_index(); ++i) { + relative_positions[1] = j + epsilon[1]; + relative_positions[2] = i + epsilon[2]; + out_near[j][i] = interpolator(relative_positions); + } + // cout << "IN: \n" << v << "out_near: \n" << out_near; + return check_if_equal(v, out_near, message); + } - - template - bool check_coefficients(const Array<2,elemT>& v, - const BSplinesRegularGrid<2, elemT, elemT>& interpolator, - const char * const message) - { - const Array<2,elemT> out=interpolator.get_coefficients(); - // cout << "IN: \n" << v << "Coefficients: \n" << out; - return - check_if_equal(v, out, message); - } + template + bool check_at_half_way(const Array<2, elemT>& v, const Array<2, elemT>& v_at_half, + const BSplinesRegularGrid<2, elemT, elemT>& interpolator, const char* const message) { + Array<2, elemT> out_at_half(v_at_half.get_index_range()), dv(v_at_half.get_index_range()); + BasicCoordinate<2, elemT> relative_positions; + for (int j = out_at_half.get_min_index(); j <= out_at_half.get_max_index(); ++j) + for (int i = out_at_half[j].get_min_index(); i <= out_at_half[j].get_max_index(); ++i) { + relative_positions[1] = j + 0.5; + relative_positions[2] = i + 0.5; + out_at_half[j][i] = interpolator(relative_positions); + } + dv = (out_at_half - v_at_half) / v_at_half.sum(); + dv *= dv; + + // cout << "Checking BSplines implementation at half way:\n" ; + // cout << "IN: \n" << v_at_half << "OUT: \n" << out_at_half; + std::cout << "The mean deviation from the correct value is: " << sqrt(dv.sum() / dv.size_all()) << endl; + return check_if_zero(sqrt(dv.sum() / dv.size_all()), message); + } - template - bool check_gradient(const BSplinesRegularGrid& interpolator, - const BasicCoordinate& p, - const char * const message) - { - const elemT epsilon = static_cast(1.E-4); - BasicCoordinate gradient = - interpolator.gradient(p); - const elemT value = - interpolator(p); - BasicCoordinate numerical_gradient; - BasicCoordinate multidim_epsilon; - for (int d=1; d<=num_dimensions; ++d) - { - assign(multidim_epsilon,0); - multidim_epsilon[d]=epsilon; - numerical_gradient[d] = - (interpolator( p+multidim_epsilon) - value) / epsilon; - } - return - this->check_if_equal(gradient, numerical_gradient, message); + template + bool check_at_half_way(const Array<2, elemT>& v, const BSplinesRegularGrid<2, elemT, elemT>& interpolator) { + Array<2, elemT> out(v.get_index_range()); + BasicCoordinate<2, elemT> relative_positions; + for (int j = out.get_min_index(); j <= out.get_max_index(); ++j) + for (int i = out[j].get_min_index(); i <= out[j].get_max_index(); ++i) { + relative_positions[1] = j + 0.5; + relative_positions[2] = i + 0.5; + out[j][i] = interpolator(relative_positions); + } + std::cout << "BSplines implementation at half way:\n"; + std::cout << "IN: \n" << v << "OUT: \n" << out; + return true; + } + + template + bool check_coefficients(const Array<2, elemT>& v, const BSplinesRegularGrid<2, elemT, elemT>& interpolator, + const char* const message) { + const Array<2, elemT> out = interpolator.get_coefficients(); + // cout << "IN: \n" << v << "Coefficients: \n" << out; + return check_if_equal(v, out, message); + } + + template + bool check_gradient(const BSplinesRegularGrid& interpolator, + const BasicCoordinate& p, const char* const message) { + const elemT epsilon = static_cast(1.E-4); + BasicCoordinate gradient = interpolator.gradient(p); + const elemT value = interpolator(p); + BasicCoordinate numerical_gradient; + BasicCoordinate multidim_epsilon; + for (int d = 1; d <= num_dimensions; ++d) { + assign(multidim_epsilon, 0); + multidim_epsilon[d] = epsilon; + numerical_gradient[d] = (interpolator(p + multidim_epsilon) - value) / epsilon; } + return this->check_if_equal(gradient, numerical_gradient, message); + } + template + bool check_continuity_of_gradient(const BSplinesRegularGrid& interpolator, + const BasicCoordinate& p, const char* const message) { + // TODO + return true; + } +}; - template - bool check_continuity_of_gradient(const BSplinesRegularGrid& interpolator, - const BasicCoordinate& p, - const char * const message) - { - // TODO - return true; +void +BSplinesRegularGrid_Tests::run_tests() { + cerr << "\nTesting BSplinesRegularGrid class..." << endl; + double test_tolerance = 0.001; + set_tolerance(test_tolerance); + typedef double elemT; + BasicCoordinate<2, elemT> epsilon_1; + epsilon_1[1] = -test_tolerance / 50; + epsilon_1[2] = test_tolerance / 50; + BasicCoordinate<2, elemT> epsilon_2; + epsilon_2[1] = -test_tolerance / 50; + epsilon_2[2] = -test_tolerance / 50; + BasicCoordinate<2, elemT> epsilon_3; + epsilon_3[1] = test_tolerance / 50; + epsilon_3[2] = -test_tolerance / 50; + BasicCoordinate<2, elemT> epsilon_4; + epsilon_4[1] = test_tolerance / 50; + epsilon_4[2] = test_tolerance / 50; + + Array<1, elemT> const_1D = make_1d_array(1., 1., 1., 1., 1., 1.); + Array<1, elemT> linear_1D = make_1d_array(1., 2., 3., 4., 5., 6., 7., 8., 9., 10.); + Array<1, elemT> random_1D_1 = make_1d_array(-14., 8., -1., 13., -1., -2., 11., 1., -8.); + Array<1, elemT> random_1D_2 = make_1d_array(6., 11., -14., 6., -3., 10., 1., 7., -2.); + Array<1, elemT> random_1D_3 = make_1d_array(-5., -9., -9., 6., -5., 2., -10., 6., -3.); + Array<1, elemT> random_1D_4 = make_1d_array(11., 8., -1., -1., 12., 11., 11., 3., 1.); + Array<1, elemT> random_1D_5 = make_1d_array(8., -1., 13., -1., -2., 11., 1., -8., -14.); + Array<1, elemT> random_1D_6 = make_1d_array(-14., 8., -1., 13., -1., -2., 1., -8., 11.); + Array<1, elemT> random_1D_7 = make_1d_array(13., -1., -2., -14., 11., 1., -8., 8., -1.); + + Array<2, elemT> const_input_sample = make_array(const_1D, const_1D, const_1D, const_1D, const_1D, const_1D); + Array<2, elemT> linear_const_input_sample = make_array(linear_1D, linear_1D, linear_1D, linear_1D, linear_1D, linear_1D); + Array<2, elemT> random_input_sample = + make_array(random_1D_1, random_1D_2, random_1D_3, random_1D_4, random_1D_5, random_1D_6, random_1D_7); + + const int jmax = 30, imax = 30; + BasicCoordinate<2, int> gauss_min, gauss_max, gauss_min_less, gauss_max_less; + gauss_min[1] = 0; + gauss_max[1] = jmax; + gauss_min[2] = 0; + gauss_max[2] = imax; + gauss_min_less[1] = 0; + gauss_max_less[1] = jmax - 1; + gauss_min_less[2] = 0; + gauss_max_less[2] = imax - 1; + + IndexRange<2> gaussian_input_sample_range(gauss_min, gauss_max); + Array<2, elemT> gaussian_input_sample(gaussian_input_sample_range); + + IndexRange<2> gaussian_input_sample_range_less(gauss_min_less, gauss_max_less); + Array<2, elemT> gaussian_check_sample(gaussian_input_sample_range_less); + + for (int j = gauss_min[1]; j <= gauss_max[1]; ++j) + for (int i = gauss_min[2]; i <= gauss_max[2]; ++i) { + gaussian_input_sample[j][i] = exp(-((static_cast(i) - 10.) * (static_cast(i) - 10.) + + (static_cast(j) - 10.) * (static_cast(j) - 10.)) / + 400.); + if (j > gauss_max_less[1] || i > gauss_max_less[2]) + continue; + else + gaussian_check_sample[j][i] = exp(-((static_cast(i) + 0.5 - 10.) * (static_cast(i) + 0.5 - 10.) + + (static_cast(j) + 0.5 - 10.) * (static_cast(j) + 0.5 - 10.)) / + 400.); } - }; - - - void BSplinesRegularGrid_Tests::run_tests() - { - cerr << "\nTesting BSplinesRegularGrid class..." << endl; - double test_tolerance = 0.001; - set_tolerance(test_tolerance); - typedef double elemT; - BasicCoordinate<2, elemT> epsilon_1; epsilon_1[1]=-test_tolerance/50; epsilon_1[2]=test_tolerance/50; - BasicCoordinate<2, elemT> epsilon_2; epsilon_2[1]=-test_tolerance/50; epsilon_2[2]=-test_tolerance/50; - BasicCoordinate<2, elemT> epsilon_3; epsilon_3[1]=test_tolerance/50; epsilon_3[2]=-test_tolerance/50; - BasicCoordinate<2, elemT> epsilon_4; epsilon_4[1]=test_tolerance/50; epsilon_4[2]=test_tolerance/50; - - Array<1,elemT> const_1D = make_1d_array(1., 1., 1., 1., 1., 1.); - Array<1,elemT> linear_1D = make_1d_array(1., 2., 3., 4., 5., 6.,7.,8.,9.,10.); - Array<1,elemT> random_1D_1 = make_1d_array(-14., 8., -1., 13., -1., -2., 11., 1., -8.); - Array<1,elemT> random_1D_2 = make_1d_array(6., 11., -14., 6., -3., 10., 1., 7., -2.); - Array<1,elemT> random_1D_3 = make_1d_array(-5., -9., -9., 6., -5., 2., -10., 6., -3.); - Array<1,elemT> random_1D_4 = make_1d_array(11., 8., -1., -1., 12., 11., 11., 3., 1.); - Array<1,elemT> random_1D_5 = make_1d_array(8., -1., 13., -1., -2., 11., 1., -8., -14.); - Array<1,elemT> random_1D_6 = make_1d_array(-14., 8., -1., 13., -1., -2., 1., -8., 11.); - Array<1,elemT> random_1D_7 = make_1d_array(13., -1., -2., -14., 11., 1., -8., 8., -1.); - - Array<2,elemT> const_input_sample = make_array(const_1D, - const_1D, - const_1D, - const_1D, - const_1D, - const_1D); - Array<2,elemT> linear_const_input_sample = make_array(linear_1D, - linear_1D, - linear_1D, - linear_1D, - linear_1D, - linear_1D); - Array<2,elemT> random_input_sample = make_array(random_1D_1, - random_1D_2, - random_1D_3, - random_1D_4, - random_1D_5, - random_1D_6, - random_1D_7); - - - - const int jmax=30, imax=30; - BasicCoordinate<2,int> gauss_min, gauss_max, gauss_min_less, gauss_max_less ; - gauss_min[1]=0; gauss_max[1]=jmax; gauss_min[2]=0; gauss_max[2]=imax; - gauss_min_less[1]=0; gauss_max_less[1]=jmax-1; gauss_min_less[2]=0; gauss_max_less[2]=imax-1; - - IndexRange<2> gaussian_input_sample_range(gauss_min,gauss_max); - Array<2,elemT> gaussian_input_sample(gaussian_input_sample_range); - - IndexRange<2> gaussian_input_sample_range_less(gauss_min_less,gauss_max_less); - Array<2,elemT> gaussian_check_sample(gaussian_input_sample_range_less); - - for (int j=gauss_min[1] ; j<=gauss_max[1] ; ++j) - for (int i=gauss_min[2] ; i<=gauss_max[2] ; ++i) - { - gaussian_input_sample[j][i]= - exp(-((static_cast(i)-10.)*(static_cast(i)-10.)+ - (static_cast(j)-10.)*(static_cast(j)-10.))/400.); - if (j>gauss_max_less[1] || i>gauss_max_less[2]) - continue; - else - gaussian_check_sample[j][i]= - exp(-((static_cast(i)+0.5-10.)*(static_cast(i)+0.5-10.)+ - (static_cast(j)+0.5-10.)*(static_cast(j)+0.5-10.))/400.); - - } + { + BSplinesRegularGrid<1, elemT> BSplinesRegularGridTest_const(const_1D, cubic); + BSplinesRegularGrid<1, elemT> BSplinesRegularGridTest_linear(linear_1D, cubic); + BSplinesRegularGrid<1, elemT> BSplinesRegularGridTest_random(random_1D_1, cubic); + BSplinesRegularGrid<1, elemT> BSplinesRegularGridTest_gaussian(gaussian_input_sample[14], cubic); + //////// gradient { - BSplinesRegularGrid<1, elemT> BSplinesRegularGridTest_const(const_1D, cubic); - BSplinesRegularGrid<1, elemT> BSplinesRegularGridTest_linear(linear_1D, cubic); - BSplinesRegularGrid<1, elemT> BSplinesRegularGridTest_random(random_1D_1, cubic); - BSplinesRegularGrid<1, elemT> BSplinesRegularGridTest_gaussian(gaussian_input_sample[14], cubic); - //////// gradient - { - BasicCoordinate<1,pos_type> p; - p[1] = 8.4; check_gradient(BSplinesRegularGridTest_gaussian, p, "gradient of cubic B-spline with Gaussian input"); - p[1] = 4.4; check_gradient(BSplinesRegularGridTest_gaussian, p, "gradient of cubic B-spline with Gaussian input"); - p[1] = 3.4; check_gradient(BSplinesRegularGridTest_linear, p, "gradient of cubic B-spline with linear input"); - p[1] = 2.4; check_gradient(BSplinesRegularGridTest_const, p, "gradient of cubic B-spline with const input"); - } - + BasicCoordinate<1, pos_type> p; + p[1] = 8.4; + check_gradient(BSplinesRegularGridTest_gaussian, p, "gradient of cubic B-spline with Gaussian input"); + p[1] = 4.4; + check_gradient(BSplinesRegularGridTest_gaussian, p, "gradient of cubic B-spline with Gaussian input"); + p[1] = 3.4; + check_gradient(BSplinesRegularGridTest_linear, p, "gradient of cubic B-spline with linear input"); + p[1] = 2.4; + check_gradient(BSplinesRegularGridTest_const, p, "gradient of cubic B-spline with const input"); } + } + { + cerr << "\nTesting BSplinesRegularGrid: Nearest Neighbour values and constructor using a 2D array as input..." << endl; { - cerr << "\nTesting BSplinesRegularGrid: Nearest Neighbour values and constructor using a 2D array as input..." << endl; - { - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, near_n); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const( - linear_const_input_sample, near_n); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, near_n); - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for nearest interpolation"); - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for nearest interpolation"); - // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); - check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, - "check BSplines implementation for nearest interpolation"); - // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); - check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, - "check BSplines implementation for nearest interpolation"); - // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); - check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, - epsilon_1, "Check BSplines implementation for nearest neighbour interpolation near samples: random test case 1"); - check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, - epsilon_2, "Check BSplines implementation for nearest neighbour interpolation near samples: random test case 2"); - check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, - epsilon_3, "Check BSplines implementation for nearest neighbour interpolation near samples: random test case 3"); - check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, - epsilon_4, "Check BSplines implementation for nearest neighbour interpolation near samples: random test case 4"); - } + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const(const_input_sample, near_n); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const(linear_const_input_sample, near_n); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, near_n); + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for nearest interpolation"); + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for nearest interpolation"); + // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); + check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, + "check BSplines implementation for nearest interpolation"); + // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for nearest interpolation"); + // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); + check_near_sample_points( + random_input_sample, BSplinesRegularGridTest_random, epsilon_1, + "Check BSplines implementation for nearest neighbour interpolation near samples: random test case 1"); + check_near_sample_points( + random_input_sample, BSplinesRegularGridTest_random, epsilon_2, + "Check BSplines implementation for nearest neighbour interpolation near samples: random test case 2"); + check_near_sample_points( + random_input_sample, BSplinesRegularGridTest_random, epsilon_3, + "Check BSplines implementation for nearest neighbour interpolation near samples: random test case 3"); + check_near_sample_points( + random_input_sample, BSplinesRegularGridTest_random, epsilon_4, + "Check BSplines implementation for nearest neighbour interpolation near samples: random test case 4"); } + } + { + cerr << "\nTesting BSplinesRegularGrid: linear interpolation values and constructor using a 2D array as input..." << endl; { - cerr << "\nTesting BSplinesRegularGrid: linear interpolation values and constructor using a 2D array as input..." << endl; - { - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, linear); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const( - linear_const_input_sample, linear); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, linear); - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for linear interpolation"); - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for linear interpolation"); - // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); - check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, - "check BSplines implementation for linear interpolation"); - // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); - check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, - "check BSplines implementation for linear interpolation"); - // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); - check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, - epsilon_1, "Check BSplines implementation for linear interpolation near samples: random test case 1"); - check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, - epsilon_2, "Check BSplines implementation for linear interpolation near samples: random test case 2"); - check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, - epsilon_3, "Check BSplines implementation for linear interpolation near samples: random test case 3"); - check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, - epsilon_4, "Check BSplines implementation for linear interpolation near samples: random test case 4"); - } + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const(const_input_sample, linear); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const(linear_const_input_sample, linear); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, linear); + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for linear interpolation"); + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for linear interpolation"); + // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); + check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, + "check BSplines implementation for linear interpolation"); + // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for linear interpolation"); + // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); + check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, epsilon_1, + "Check BSplines implementation for linear interpolation near samples: random test case 1"); + check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, epsilon_2, + "Check BSplines implementation for linear interpolation near samples: random test case 2"); + check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, epsilon_3, + "Check BSplines implementation for linear interpolation near samples: random test case 3"); + check_near_sample_points(random_input_sample, BSplinesRegularGridTest_random, epsilon_4, + "Check BSplines implementation for linear interpolation near samples: random test case 4"); } + } + { + cerr << "\nTesting BSplinesRegularGrid: quadratic interpolation values and constructor using a 2D array as input..." << endl; { - cerr << "\nTesting BSplinesRegularGrid: quadratic interpolation values and constructor using a 2D array as input..." << endl; - { - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, quadratic); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const( - linear_const_input_sample, quadratic); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, quadratic); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_gaussian( - gaussian_input_sample, quadratic); - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for quadratic interpolation"); - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for quadratic interpolation"); - // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); - check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, - "check BSplines implementation for quadratic interpolation"); - // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); - check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, - "check BSplines implementation for quadratic interpolation"); - // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); - check_at_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - "check BSplines implementation for quadratic interpolation"); - - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_1, "Check BSplines implementation for quadratic interpolation near samples"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_2, "Check BSplines implementation for quadratic interpolation near samples"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_3, "Check BSplines implementation for quadratic interpolation near samples"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_4, "Check BSplines implementation for quadratic interpolation near samples"); - check_at_half_way(gaussian_input_sample, gaussian_check_sample, - BSplinesRegularGridTest_gaussian, - "check BSplines implementation for quadratic interpolation.\nProblems at half way!"); - } + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const(const_input_sample, quadratic); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const(linear_const_input_sample, quadratic); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, quadratic); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_gaussian(gaussian_input_sample, quadratic); + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for quadratic interpolation"); + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for quadratic interpolation"); + // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); + check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, + "check BSplines implementation for quadratic interpolation"); + // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for quadratic interpolation"); + // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); + check_at_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, + "check BSplines implementation for quadratic interpolation"); + + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_1, + "Check BSplines implementation for quadratic interpolation near samples"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_2, + "Check BSplines implementation for quadratic interpolation near samples"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_3, + "Check BSplines implementation for quadratic interpolation near samples"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_4, + "Check BSplines implementation for quadratic interpolation near samples"); + check_at_half_way(gaussian_input_sample, gaussian_check_sample, BSplinesRegularGridTest_gaussian, + "check BSplines implementation for quadratic interpolation.\nProblems at half way!"); } + } + { + cerr << "\nTesting BSplinesRegularGrid: Cubic interpolation values and constructor using a 2D array as input..." << endl; { - cerr << "\nTesting BSplinesRegularGrid: Cubic interpolation values and constructor using a 2D array as input..." << endl; - { - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, cubic); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const( - linear_const_input_sample, cubic); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, cubic); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_gaussian( - gaussian_input_sample, cubic); - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for cubic interpolation"); - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for cubic interpolation"); - // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); - check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, - "check BSplines implementation for cubic interpolation"); - // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); - check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, - "check BSplines implementation for cubic interpolation"); - // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); - - check_at_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - "check BSplines implementation for cubic interpolation"); - - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_1, "Check BSplines implementation for cubic interpolation near samples"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_2, "Check BSplines implementation for cubic interpolation near samples"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_3, "Check BSplines implementation for cubic interpolation near samples"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_4, "Check BSplines implementation for cubic interpolation near samples"); - - check_at_half_way(gaussian_input_sample, gaussian_check_sample, - BSplinesRegularGridTest_gaussian, - "check BSplines implementation for cubic interpolation.\nProblems at half way!"); - - - //////// gradient - { - - check_gradient(BSplinesRegularGridTest_gaussian, Coordinate2D(1.1,2.2), "cubic-spline gradient: Gaussian test-case 1"); - check_gradient(BSplinesRegularGridTest_gaussian, Coordinate2D(3.1,4.2), "cubic-spline gradient: Gaussian test-case 2"); - check_gradient(BSplinesRegularGridTest_linear_const, Coordinate2D(3.1,4.2), "cubic-spline gradient: test-case linear const"); - } - - } + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const(const_input_sample, cubic); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const(linear_const_input_sample, cubic); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, cubic); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_gaussian(gaussian_input_sample, cubic); + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for cubic interpolation"); + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for cubic interpolation"); + // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); + check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, + "check BSplines implementation for cubic interpolation"); + // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for cubic interpolation"); + // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); + + check_at_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, + "check BSplines implementation for cubic interpolation"); + + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_1, + "Check BSplines implementation for cubic interpolation near samples"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_2, + "Check BSplines implementation for cubic interpolation near samples"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_3, + "Check BSplines implementation for cubic interpolation near samples"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_4, + "Check BSplines implementation for cubic interpolation near samples"); + + check_at_half_way(gaussian_input_sample, gaussian_check_sample, BSplinesRegularGridTest_gaussian, + "check BSplines implementation for cubic interpolation.\nProblems at half way!"); + + //////// gradient + { + + check_gradient(BSplinesRegularGridTest_gaussian, Coordinate2D(1.1, 2.2), + "cubic-spline gradient: Gaussian test-case 1"); + check_gradient(BSplinesRegularGridTest_gaussian, Coordinate2D(3.1, 4.2), + "cubic-spline gradient: Gaussian test-case 2"); + check_gradient(BSplinesRegularGridTest_linear_const, Coordinate2D(3.1, 4.2), + "cubic-spline gradient: test-case linear const"); + } } + } + { + cerr << "\nTesting BSplinesRegularGrid: oMoms interpolation values and constructor using a 2D array as input..." << endl; { - cerr << "\nTesting BSplinesRegularGrid: oMoms interpolation values and constructor using a 2D array as input..." << endl; - { - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, oMoms); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const( - linear_const_input_sample, oMoms); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, oMoms); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_gaussian( - gaussian_input_sample, oMoms); - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for oMoms interpolation"); - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for oMoms interpolation"); - // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); - check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, - "check BSplines implementation for oMoms interpolation"); - // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); - check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, - "check BSplines implementation for oMoms interpolation"); - // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); - - check_at_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - "check BSplines implementation for oMoms interpolation"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_1, "Check BSplines implementation for oMoms interpolation near samples"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_2, "Check BSplines implementation for oMoms interpolation near samples"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_3, "Check BSplines implementation for oMoms interpolation near samples"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_4, "Check BSplines implementation for oMoms interpolation near samples"); - - check_at_half_way(gaussian_input_sample, gaussian_check_sample, - BSplinesRegularGridTest_gaussian, - "check BSplines implementation for oMoms interpolation.\nProblems at half way!"); - } + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const(const_input_sample, oMoms); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const(linear_const_input_sample, oMoms); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, oMoms); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_gaussian(gaussian_input_sample, oMoms); + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for oMoms interpolation"); + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for oMoms interpolation"); + // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); + check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, + "check BSplines implementation for oMoms interpolation"); + // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for oMoms interpolation"); + // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); + + check_at_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, + "check BSplines implementation for oMoms interpolation"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_1, + "Check BSplines implementation for oMoms interpolation near samples"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_2, + "Check BSplines implementation for oMoms interpolation near samples"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_3, + "Check BSplines implementation for oMoms interpolation near samples"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_4, + "Check BSplines implementation for oMoms interpolation near samples"); + + check_at_half_way(gaussian_input_sample, gaussian_check_sample, BSplinesRegularGridTest_gaussian, + "check BSplines implementation for oMoms interpolation.\nProblems at half way!"); } + } + { + cerr << "\nTesting BSplinesRegularGrid: Linear-Cubic interpolation values and constructor using a 2D array as input..." + << endl; { - cerr << "\nTesting BSplinesRegularGrid: Linear-Cubic interpolation values and constructor using a 2D array as input..." << endl; - { - BasicCoordinate<2,BSpline::BSplineType> linear_cubic; - - linear_cubic[1]=linear; - linear_cubic[2]=cubic; - - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, linear_cubic); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const( - linear_const_input_sample, linear_cubic); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, linear_cubic); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_gaussian( - gaussian_input_sample, linear_cubic); - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for linear_cubic interpolation"); - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for linear_cubic interpolation"); - // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); - check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, - "check BSplines implementation for linear_cubic interpolation"); - // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); - check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, - "check BSplines implementation for linear_cubic interpolation"); - // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); - - check_at_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - "check BSplines implementation for linear_cubic interpolation"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_1, "Check BSplines implementation for linear-cubic interpolation near samples: gaussian test 1"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_2, "Check BSplines implementation for linear-cubic interpolation near samples: gaussian test 2"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_3, "Check BSplines implementation for linear-cubic interpolation near samples: gaussian test 3"); - check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, - epsilon_4, "Check BSplines implementation for linear-cubic interpolation near samples: gaussian test 4"); - - check_at_half_way(gaussian_input_sample, gaussian_check_sample, - BSplinesRegularGridTest_gaussian, - "check BSplines implementation for linear_cubic interpolation.\nProblems at half way!"); - } - } - /* { - cerr << "\nTesting BSplinesRegularGrid: Linear interpolation values and constructor using a 2D diamond array as input..." << endl; - Array<1,elemT> random_1D_1 = make_1d_array(-14., 8., -1., 13., -1., -2., 11., 1., -8.); - Array<1,elemT> random_1D_2 = make_1d_array(6., 11., -14., 6., -3., 10., 1.); - Array<1,elemT> random_1D_3 = make_1d_array(-5., -9., -9., 6., -5.); - Array<2,elemT> nonsquare = make_array(random_1D_1,random_1D_2,random_1D_3); - BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest( - nonsquare, linear); - - check_at_sample_points(const_input_sample, BSplinesRegularGridTest, - "check BSplines implementation for cubic interpolation no square"); - }*/ - } + BasicCoordinate<2, BSpline::BSplineType> linear_cubic; + + linear_cubic[1] = linear; + linear_cubic[2] = cubic; + + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_const(const_input_sample, linear_cubic); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_linear_const(linear_const_input_sample, linear_cubic); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, linear_cubic); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest_gaussian(gaussian_input_sample, linear_cubic); + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for linear_cubic interpolation"); + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for linear_cubic interpolation"); + // check_at_half_way(const_input_sample, BSplinesRegularGridTest_const); + check_at_sample_points(linear_const_input_sample, BSplinesRegularGridTest_linear_const, + "check BSplines implementation for linear_cubic interpolation"); + // check_at_half_way(linear_const_input_sample, BSplinesRegularGridTest_linear_const); + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for linear_cubic interpolation"); + // check_at_half_way(random_input_sample, BSplinesRegularGridTest_random); + + check_at_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, + "check BSplines implementation for linear_cubic interpolation"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_1, + "Check BSplines implementation for linear-cubic interpolation near samples: gaussian test 1"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_2, + "Check BSplines implementation for linear-cubic interpolation near samples: gaussian test 2"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_3, + "Check BSplines implementation for linear-cubic interpolation near samples: gaussian test 3"); + check_near_sample_points(gaussian_input_sample, BSplinesRegularGridTest_gaussian, epsilon_4, + "Check BSplines implementation for linear-cubic interpolation near samples: gaussian test 4"); + + check_at_half_way(gaussian_input_sample, gaussian_check_sample, BSplinesRegularGridTest_gaussian, + "check BSplines implementation for linear_cubic interpolation.\nProblems at half way!"); + } + } + /* { + cerr << "\nTesting BSplinesRegularGrid: Linear interpolation values and constructor using a 2D diamond array as input..." << + endl; Array<1,elemT> random_1D_1 = make_1d_array(-14., 8., -1., 13., -1., -2., 11., 1., -8.); Array<1,elemT> random_1D_2 = + make_1d_array(6., 11., -14., 6., -3., 10., 1.); Array<1,elemT> random_1D_3 = make_1d_array(-5., -9., -9., 6., -5.); + Array<2,elemT> nonsquare = make_array(random_1D_1,random_1D_2,random_1D_3); + BSplinesRegularGrid<2, elemT, elemT> BSplinesRegularGridTest( + nonsquare, linear); + + check_at_sample_points(const_input_sample, BSplinesRegularGridTest, + "check BSplines implementation for cubic interpolation no square"); + }*/ +} } // end namespace BSpline @@ -523,14 +466,13 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 1) - { - cerr << "Usage : " << argv[0] << " \n"; - return EXIT_FAILURE; - } - BSpline::BSplinesRegularGrid_Tests tests; - tests.run_tests(); - return tests.main_return_value(); +int +main(int argc, char** argv) { + if (argc != 1) { + cerr << "Usage : " << argv[0] << " \n"; + return EXIT_FAILURE; + } + BSpline::BSplinesRegularGrid_Tests tests; + tests.run_tests(); + return tests.main_return_value(); } diff --git a/src/test/numerics/test_BSplinesRegularGrid1D.cxx b/src/test/numerics/test_BSplinesRegularGrid1D.cxx index e06f5914cf..7d0615588c 100644 --- a/src/test/numerics/test_BSplinesRegularGrid1D.cxx +++ b/src/test/numerics/test_BSplinesRegularGrid1D.cxx @@ -6,22 +6,22 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics_test \brief tests the stir::BSplinesRegularGrid class for the stir::Array 1D case \author Charalampos Tsoumpas \author Kris Thielemans -*/ +*/ #include "stir/RunTests.h" #include "stir/Array.h" #include "stir/make_array.h" @@ -36,251 +36,217 @@ using std::endl; #endif START_NAMESPACE_STIR namespace BSpline { - /*! - \ingroup numerics_test - \brief A simple class to test the BSplinesRegularGrid class for 1D arrays - */ - class BSplinesRegularGrid1D_Tests : public RunTests - { - public: - BSplinesRegularGrid1D_Tests() - {} - void run_tests(); - private: - template - bool check_at_sample_points(const Array<1,elemT>& v, - BSplinesRegularGrid<1, elemT, elemT>& interpolator, - const char * const message) - { - IndexRange<1> out_range(static_cast(v.size())); - Array<1,elemT> out(out_range); - BasicCoordinate<1, elemT> relative_positions; - for (int i=0, imax=static_cast(v.size()); i + bool check_at_sample_points(const Array<1, elemT>& v, BSplinesRegularGrid<1, elemT, elemT>& interpolator, + const char* const message) { + IndexRange<1> out_range(static_cast(v.size())); + Array<1, elemT> out(out_range); + BasicCoordinate<1, elemT> relative_positions; + for (int i = 0, imax = static_cast(v.size()); i < imax; ++i) { + relative_positions[1] = i; + out[i] = interpolator(relative_positions); } - - template - bool check_coefficients(const Array<1,elemT>& v, - BSplinesRegularGrid<1, elemT, elemT>& interpolator, - const char * const message) - { - IndexRange<1> out_range(static_cast(v.size())); - Array<1,elemT> out(out_range); - out=interpolator.get_coefficients(); - std::cout << "IN: " << v << "Coefficients: " << out; - return - check_if_equal(v, out, message); - } - }; + std::cout << "IN: " << v << "OUT: " << out; + return check_if_equal(v, out, message); + } + + template + bool check_coefficients(const Array<1, elemT>& v, BSplinesRegularGrid<1, elemT, elemT>& interpolator, + const char* const message) { + IndexRange<1> out_range(static_cast(v.size())); + Array<1, elemT> out(out_range); + out = interpolator.get_coefficients(); + std::cout << "IN: " << v << "Coefficients: " << out; + return check_if_equal(v, out, message); + } +}; - void BSplinesRegularGrid1D_Tests::run_tests() - { - cerr << "\nTesting BSplinesRegularGrid class..." << endl; - set_tolerance(0.001); - typedef double elemT; - Array<1,elemT> const_input_sample = make_1d_array(1., 1., 1., 1., 1., 1.); - Array<1,elemT> linear_input_sample = make_1d_array(1., 2., 3., 4., 5., 6.); - Array<1,elemT> random_input_sample = make_1d_array(-14., 8., -1., 13., -1., -2., 11., 1., -8.); +void +BSplinesRegularGrid1D_Tests::run_tests() { + cerr << "\nTesting BSplinesRegularGrid class..." << endl; + set_tolerance(0.001); + typedef double elemT; + Array<1, elemT> const_input_sample = make_1d_array(1., 1., 1., 1., 1., 1.); + Array<1, elemT> linear_input_sample = make_1d_array(1., 2., 3., 4., 5., 6.); + Array<1, elemT> random_input_sample = make_1d_array(-14., 8., -1., 13., -1., -2., 11., 1., -8.); + { + cerr << "\nTesting BSplinesRegularGrid: Nearest Neighbour values and constructor using an 1D array as input..." << endl; { - cerr << "\nTesting BSplinesRegularGrid: Nearest Neighbour values and constructor using an 1D array as input..." << endl; - { - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, near_n); - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_linear( - linear_input_sample, near_n); - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, near_n); - BasicCoordinate<1,elemT> relative_positions; - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for nearest interpolation"); - - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for nearest interpolation"); - cerr << "At half points: " ; - for (int i=0, imax=static_cast(const_input_sample.size()); i(linear_input_sample.size()); i BSplinesRegularGridTest_const(const_input_sample, near_n); + BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_linear(linear_input_sample, near_n); + BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, near_n); + BasicCoordinate<1, elemT> relative_positions; + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for nearest interpolation"); + + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for nearest interpolation"); + cerr << "At half points: "; + for (int i = 0, imax = static_cast(const_input_sample.size()); i < imax; ++i) { + relative_positions[1] = i - 0.5; + cerr << BSplinesRegularGridTest_const(relative_positions) << " "; + } + cerr << "\n\n"; + check_at_sample_points(linear_input_sample, BSplinesRegularGridTest_linear, + "check BSplines implementation for nearest interpolation"); + cerr << "At half points: "; + for (int i = 0, imax = static_cast(linear_input_sample.size()); i < imax; ++i) { + relative_positions[1] = i - 0.5; + cerr << BSplinesRegularGridTest_linear(relative_positions) << " "; } - } + cerr << "\n\n"; + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for nearest interpolation"); + } + } + { + cerr << "\nTesting BSplinesRegularGrid: Linear interpolation values and constructor using an 1D array as input..." << endl; { - cerr << "\nTesting BSplinesRegularGrid: Linear interpolation values and constructor using an 1D array as input..." << endl; - { - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, linear); - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_linear( - linear_input_sample, linear); - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, linear); - BasicCoordinate<1,elemT> relative_positions; - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for linear interpolation"); - - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for linear interpolation"); - cerr << "At half points: " ; - for (int i=0, imax=static_cast(const_input_sample.size()); i(linear_input_sample.size()); i BSplinesRegularGridTest_const(const_input_sample, linear); + BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_linear(linear_input_sample, linear); + BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, linear); + BasicCoordinate<1, elemT> relative_positions; + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for linear interpolation"); + + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for linear interpolation"); + cerr << "At half points: "; + for (int i = 0, imax = static_cast(const_input_sample.size()); i < imax; ++i) { + relative_positions[1] = i - 0.5; + cerr << BSplinesRegularGridTest_const(relative_positions) << " "; } + cerr << "\n\n"; + check_at_sample_points(linear_input_sample, BSplinesRegularGridTest_linear, + "check BSplines implementation for linear interpolation"); + cerr << "At half points: "; + for (int i = 0, imax = static_cast(linear_input_sample.size()); i < imax; ++i) { + relative_positions[1] = i - 0.5; + cerr << BSplinesRegularGridTest_linear(relative_positions) << " "; + } + cerr << "\n\n"; + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for linear interpolation"); } + } + { + cerr << "\nTesting BSplinesRegularGrid: Quadratic interpolation values and constructor using an 1D array as input..." << endl; { - cerr << "\nTesting BSplinesRegularGrid: Quadratic interpolation values and constructor using an 1D array as input..." << endl; - { - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, quadratic); - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_linear( - linear_input_sample, quadratic); - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, quadratic); - BasicCoordinate<1,elemT> relative_positions; - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for quadratic interpolation"); - - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for quadratic interpolation"); - cerr << "At half points: " ; - for (std::size_t i=0, imax=const_input_sample.size(); i BSplinesRegularGridTest_const(const_input_sample, quadratic); + BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_linear(linear_input_sample, quadratic); + BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, quadratic); + BasicCoordinate<1, elemT> relative_positions; + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for quadratic interpolation"); + + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for quadratic interpolation"); + cerr << "At half points: "; + for (std::size_t i = 0, imax = const_input_sample.size(); i < imax; ++i) { + relative_positions[1] = i - 0.5; + cerr << BSplinesRegularGridTest_const(relative_positions) << " "; } + cerr << "\n\n"; + check_at_sample_points(linear_input_sample, BSplinesRegularGridTest_linear, + "check BSplines implementation for quadratic interpolation"); + cerr << "At half points: "; + for (std::size_t i = 0, imax = linear_input_sample.size(); i < imax; ++i) { + relative_positions[1] = i - 0.5; + cerr << BSplinesRegularGridTest_linear(relative_positions) << " "; + } + cerr << "\n\n"; + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for quadratic interpolation"); } + } + { + cerr << "\nTesting BSplinesRegularGrid: Cubic interpolation values and constructor using an 1D array as input..." << endl; { - cerr << "\nTesting BSplinesRegularGrid: Cubic interpolation values and constructor using an 1D array as input..." << endl; - { - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, cubic); - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_linear( - linear_input_sample, cubic); - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, cubic); - BasicCoordinate<1,elemT> relative_positions; - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for cubic interpolation"); - - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for cubic interpolation"); - cerr << "At half points: " ; - for (std::size_t i=0, imax=const_input_sample.size(); i BSplinesRegularGridTest_const(const_input_sample, cubic); + BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_linear(linear_input_sample, cubic); + BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, cubic); + BasicCoordinate<1, elemT> relative_positions; + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for cubic interpolation"); + + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for cubic interpolation"); + cerr << "At half points: "; + for (std::size_t i = 0, imax = const_input_sample.size(); i < imax; ++i) { + relative_positions[1] = i - 0.5; + cerr << BSplinesRegularGridTest_const(relative_positions) << " "; } + cerr << "\n\n"; + check_at_sample_points(linear_input_sample, BSplinesRegularGridTest_linear, + "check BSplines implementation for cubic interpolation"); + cerr << "At half points: "; + for (std::size_t i = 0, imax = linear_input_sample.size(); i < imax; ++i) { + relative_positions[1] = i - 0.5; + cerr << BSplinesRegularGridTest_linear(relative_positions) << " "; + } + cerr << "\n\n"; + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for cubic interpolation"); } + } + { + cerr << "\nTesting BSplinesRegularGrid: oMoms interpolation values and constructor using an 1D array as input..." << endl; { - cerr << "\nTesting BSplinesRegularGrid: oMoms interpolation values and constructor using an 1D array as input..." << endl; - { - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_const( - const_input_sample, oMoms); - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_linear( - linear_input_sample, oMoms); - BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_random( - random_input_sample, oMoms); - BasicCoordinate<1,elemT> relative_positions; - - check_coefficients(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for oMoms interpolation"); - - check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, - "check BSplines implementation for oMoms interpolation"); - cerr << "At half points: " ; - for (std::size_t i=0, imax=const_input_sample.size(); i BSplinesRegularGridTest_const(const_input_sample, oMoms); + BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_linear(linear_input_sample, oMoms); + BSplinesRegularGrid<1, elemT, elemT> BSplinesRegularGridTest_random(random_input_sample, oMoms); + BasicCoordinate<1, elemT> relative_positions; + + check_coefficients(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for oMoms interpolation"); + + check_at_sample_points(const_input_sample, BSplinesRegularGridTest_const, + "check BSplines implementation for oMoms interpolation"); + cerr << "At half points: "; + for (std::size_t i = 0, imax = const_input_sample.size(); i < imax; ++i) { + relative_positions[1] = i - 0.5; + cerr << BSplinesRegularGridTest_const(relative_positions) << " "; } + cerr << "\n\n"; + check_at_sample_points(linear_input_sample, BSplinesRegularGridTest_linear, + "check BSplines implementation for oMoms interpolation"); + cerr << "At half points: "; + for (std::size_t i = 0, imax = linear_input_sample.size(); i < imax; ++i) { + relative_positions[1] = i - 0.5; + cerr << BSplinesRegularGridTest_linear(relative_positions) << " "; + } + cerr << "\n\n"; + check_at_sample_points(random_input_sample, BSplinesRegularGridTest_random, + "check BSplines implementation for oMoms interpolation"); } } +} } // end namespace BSpline END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 1) - { - cerr << "Usage : " << argv[0] << " \n"; - return EXIT_FAILURE; - } +int +main(int argc, char** argv) { + if (argc != 1) { + cerr << "Usage : " << argv[0] << " \n"; + return EXIT_FAILURE; + } BSpline::BSplinesRegularGrid1D_Tests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/numerics/test_Fourier.cxx b/src/test/numerics/test_Fourier.cxx index 9e86853200..2fc286e229 100644 --- a/src/test/numerics/test_Fourier.cxx +++ b/src/test/numerics/test_Fourier.cxx @@ -2,7 +2,7 @@ // /*! - \file + \file \ingroup tests \ingroup DFT \brief Tests for function in the DFT group @@ -28,7 +28,6 @@ #include #include - using std::cin; using std::cout; using std::endl; @@ -37,115 +36,103 @@ START_NAMESPACE_STIR #define DOARRAY #ifdef DOARRAY - typedef Array<1,std::complex > ArrayC1; - typedef Array<1,float> ArrayF1; - typedef Array<2,float> ArrayF2; - typedef Array<2,std::complex > ArrayC2; - typedef Array<3,float> ArrayF3; - typedef Array<3,std::complex > ArrayC3; +typedef Array<1, std::complex> ArrayC1; +typedef Array<1, float> ArrayF1; +typedef Array<2, float> ArrayF2; +typedef Array<2, std::complex> ArrayC2; +typedef Array<3, float> ArrayF3; +typedef Array<3, std::complex> ArrayC3; #else - typedef VectorWithOffset > ArrayC1; - typedef VectorWithOffset ArrayF1; - typedef VectorWithOffset ArrayC2; +typedef VectorWithOffset> ArrayC1; +typedef VectorWithOffset ArrayF1; +typedef VectorWithOffset ArrayC2; #endif - - - -inline float rand1() -{ - return 2*(rand()-RAND_MAX/2.F)/RAND_MAX; +inline float +rand1() { + return 2 * (rand() - RAND_MAX / 2.F) / RAND_MAX; } /*! \ingroup numerics_test \brief A simple class to test the erf and erfc functions. */ -class FourierTests : public RunTests -{ +class FourierTests : public RunTests { public: - FourierTests() - {} + FourierTests() {} void run_tests(); + private: template void test_single_dimension(const IndexRange& index_range); }; template -void FourierTests::test_single_dimension(const IndexRange& index_range) -{ - typedef Array > complex_type; +void +FourierTests::test_single_dimension(const IndexRange& index_range) { + typedef Array> complex_type; typedef Array real_type; complex_type complex_array(index_range); real_type real_array(index_range); // fill { - for (typename real_type::full_iterator iter= real_array.begin_all(); - iter!=real_array.end_all(); - ++iter) - *iter= rand1(); + for (typename real_type::full_iterator iter = real_array.begin_all(); iter != real_array.end_all(); ++iter) + *iter = rand1(); std::copy(real_array.begin_all(), real_array.end_all(), complex_array.begin_all()); } - const int sign=1; - - complex_type pos_frequencies = - fourier_for_real_data(real_array, sign); - const complex_type all_frequencies = - pos_frequencies_to_all(pos_frequencies); - - fourier(complex_array,sign); - //cout << pos_frequencies; - //cout << all_frequencies << complex_array; - //cout << '\n' << complex_array-all_frequencies; + const int sign = 1; + + complex_type pos_frequencies = fourier_for_real_data(real_array, sign); + const complex_type all_frequencies = pos_frequencies_to_all(pos_frequencies); + + fourier(complex_array, sign); + // cout << pos_frequencies; + // cout << all_frequencies << complex_array; + // cout << '\n' << complex_array-all_frequencies; complex_array -= all_frequencies; - cout << "\nReal FT Residual norm " << - norm(complex_array.begin_all(), complex_array.end_all())/norm(real_array.begin_all(), real_array.end_all()); + cout << "\nReal FT Residual norm " + << norm(complex_array.begin_all(), complex_array.end_all()) / norm(real_array.begin_all(), real_array.end_all()); - real_type test_inverse_real = - inverse_fourier_for_real_data(pos_frequencies,sign); - //cout <<"\nv,test "<< v << test_inverse_real << test_inverse_real/v; + real_type test_inverse_real = inverse_fourier_for_real_data(pos_frequencies, sign); + // cout <<"\nv,test "<< v << test_inverse_real << test_inverse_real/v; test_inverse_real -= real_array; - cout << "\ninverse Real FT Residual norm " << - norm(test_inverse_real.begin_all(), test_inverse_real.end_all())/norm(real_array.begin_all(), real_array.end_all()); + cout << "\ninverse Real FT Residual norm " + << norm(test_inverse_real.begin_all(), test_inverse_real.end_all()) / norm(real_array.begin_all(), real_array.end_all()); // fill { - for (typename complex_type::full_iterator iter= complex_array.begin_all(); - iter!=complex_array.end_all(); - ++iter) + for (typename complex_type::full_iterator iter = complex_array.begin_all(); iter != complex_array.end_all(); ++iter) *iter = std::complex(rand1(), rand1()); } const complex_type array_copy(complex_array); - fourier(complex_array,sign); - inverse_fourier(complex_array,sign); + fourier(complex_array, sign); + inverse_fourier(complex_array, sign); complex_array -= array_copy; - cout << "\ninverse FT Residual norm " << - norm(complex_array.begin_all(), complex_array.end_all())/norm(array_copy.begin_all(), array_copy.end_all()); + cout << "\ninverse FT Residual norm " + << norm(complex_array.begin_all(), complex_array.end_all()) / norm(array_copy.begin_all(), array_copy.end_all()); } -void FourierTests::run_tests() -{ +void +FourierTests::run_tests() { std::cerr << "Testing Fourier Functions..." << std::endl; std::cerr << "... Testing 1D\n"; test_single_dimension(IndexRange<1>(128)); std::cerr << "... Testing 2D\n"; - test_single_dimension(IndexRange2D(128,256)); + test_single_dimension(IndexRange2D(128, 256)); std::cerr << "... Testing 3D\n"; - test_single_dimension(IndexRange3D(128,256,16)); + test_single_dimension(IndexRange3D(128, 256, 16)); } END_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 1) - { +int +main(int argc, char** argv) { + if (argc != 1) { std::cerr << "Usage : " << argv[0] << " \n"; return EXIT_FAILURE; } diff --git a/src/test/numerics/test_IR_filters.cxx b/src/test/numerics/test_IR_filters.cxx index 97f345fd89..cbe6f1543a 100644 --- a/src/test/numerics/test_IR_filters.cxx +++ b/src/test/numerics/test_IR_filters.cxx @@ -1,7 +1,7 @@ // // /*! - \file + \file \ingroup numerics_test \brief tests the implementation of the IR_filters @@ -25,13 +25,11 @@ See STIR/LICENSE.txt for details */ - #include "stir/RunTests.h" #include "stir/numerics/IR_filters.h" #include #include - #ifndef STIR_NO_NAMESPACES using std::cerr; using std::endl; @@ -43,118 +41,98 @@ START_NAMESPACE_STIR \ingroup numerics_test \brief A simple class to test the IIR_filter and FIR_filter function. */ -class IR_filterTests : public RunTests -{ +class IR_filterTests : public RunTests { public: - IR_filterTests() - {} + IR_filterTests() {} void run_tests(); + private: - //istream& in; + // istream& in; }; - -void IR_filterTests::run_tests() -{ +void +IR_filterTests::run_tests() { cerr << "Testing IR_filter function..." << endl; set_tolerance(0.001); - - std::vector input_test_signal, input_factors, poles, - output_FIR_test_value, output_IIR_test_value, - stir_FIR_output, stir_IIR_output; - - for (int i=1, imax=11; i input_test_signal, input_factors, poles, output_FIR_test_value, output_IIR_test_value, stir_FIR_output, + stir_IIR_output; + + for (int i = 1, imax = 11; i < imax; ++i) { + input_test_signal.push_back(i); + + stir_FIR_output.push_back(0); + stir_IIR_output.push_back(0); + + input_factors.push_back(imax - i); + if (i == 10) + break; + + if (i <= 5) poles.push_back(1); - input_factors.push_back(9); - } - if (i==3) - input_factors.push_back(8); - */ + else + poles.push_back(-1); + + /* For Checking different sizes of the poles and input_factors + + if (i==1) + { + poles.push_back(1); + input_factors.push_back(10); + } + if (i==2) + { + poles.push_back(1); + input_factors.push_back(9); } + if (i==3) + input_factors.push_back(8); + */ + } + + output_FIR_test_value.push_back(10); // 1 + output_FIR_test_value.push_back(29); // 2 + output_FIR_test_value.push_back(56); // 3 + output_FIR_test_value.push_back(90); // 4 + output_FIR_test_value.push_back(130); // 5 + output_FIR_test_value.push_back(175); // 6 + output_FIR_test_value.push_back(224); // 7 + output_FIR_test_value.push_back(276); // 8 + output_FIR_test_value.push_back(330); // 9 + output_FIR_test_value.push_back(385); // 10 + + output_IIR_test_value.push_back(10); // 1 + output_IIR_test_value.push_back(19); // 2 + output_IIR_test_value.push_back(27); // 3 + output_IIR_test_value.push_back(34); // 4 + output_IIR_test_value.push_back(40); // 5 + output_IIR_test_value.push_back(45); // 6 + output_IIR_test_value.push_back(69); // 7 + output_IIR_test_value.push_back(90); // 8 + output_IIR_test_value.push_back(108); // 9 + output_IIR_test_value.push_back(123); // 10 + + { + cerr << "Testing FIR_filter function..." << endl; + + FIR_filter(stir_FIR_output.begin(), stir_FIR_output.end(), input_test_signal.begin(), input_test_signal.end(), + input_factors.begin(), input_factors.end(), 0); + + std::vector::iterator cur_iter_stir_out = stir_FIR_output.begin(), cur_iter_FIR_out = output_FIR_test_value.begin(); - output_FIR_test_value.push_back(10); //1 - output_FIR_test_value.push_back(29); //2 - output_FIR_test_value.push_back(56); //3 - output_FIR_test_value.push_back(90); //4 - output_FIR_test_value.push_back(130); //5 - output_FIR_test_value.push_back(175); //6 - output_FIR_test_value.push_back(224); //7 - output_FIR_test_value.push_back(276); //8 - output_FIR_test_value.push_back(330); //9 - output_FIR_test_value.push_back(385); //10 - - output_IIR_test_value.push_back(10); //1 - output_IIR_test_value.push_back(19); //2 - output_IIR_test_value.push_back(27); //3 - output_IIR_test_value.push_back(34); //4 - output_IIR_test_value.push_back(40); //5 - output_IIR_test_value.push_back(45); //6 - output_IIR_test_value.push_back(69); //7 - output_IIR_test_value.push_back(90); //8 - output_IIR_test_value.push_back(108); //9 - output_IIR_test_value.push_back(123); //10 - - - { - cerr << "Testing FIR_filter function..." << endl; - - FIR_filter(stir_FIR_output.begin(), stir_FIR_output.end(), - input_test_signal.begin(), input_test_signal.end(), - input_factors.begin(), input_factors.end(),0); - - std::vector:: iterator cur_iter_stir_out= stir_FIR_output.begin(), - cur_iter_FIR_out= output_FIR_test_value.begin(); - - for (; - cur_iter_stir_out!=stir_FIR_output.end() - && - cur_iter_FIR_out!=output_FIR_test_value.end(); - ++cur_iter_stir_out, ++cur_iter_FIR_out) - check_if_equal(*cur_iter_stir_out, *cur_iter_FIR_out, - "check FIR filter implementation"); - } - { - cerr << "Testing IIR_filter function..." << endl; - IIR_filter(stir_IIR_output.begin(), stir_IIR_output.end(), - input_test_signal.begin(), input_test_signal.end(), - input_factors.begin(), input_factors.end(), - poles.begin(), poles.end(),0); - std::vector:: iterator cur_iter_stir_IIR_out= - stir_IIR_output.begin(), - cur_iter_IIR_out= output_IIR_test_value.begin(); - for (; - cur_iter_stir_IIR_out!=stir_IIR_output.end() - && - cur_iter_IIR_out!=output_IIR_test_value.end(); - ++cur_iter_stir_IIR_out, ++cur_iter_IIR_out) - check_if_equal(*cur_iter_stir_IIR_out, *cur_iter_IIR_out, - "check IIR filter implementation"); + for (; cur_iter_stir_out != stir_FIR_output.end() && cur_iter_FIR_out != output_FIR_test_value.end(); + ++cur_iter_stir_out, ++cur_iter_FIR_out) + check_if_equal(*cur_iter_stir_out, *cur_iter_FIR_out, "check FIR filter implementation"); + } + { + cerr << "Testing IIR_filter function..." << endl; + IIR_filter(stir_IIR_output.begin(), stir_IIR_output.end(), input_test_signal.begin(), input_test_signal.end(), + input_factors.begin(), input_factors.end(), poles.begin(), poles.end(), 0); + std::vector::iterator cur_iter_stir_IIR_out = stir_IIR_output.begin(), cur_iter_IIR_out = output_IIR_test_value.begin(); + for (; cur_iter_stir_IIR_out != stir_IIR_output.end() && cur_iter_IIR_out != output_IIR_test_value.end(); + ++cur_iter_stir_IIR_out, ++cur_iter_IIR_out) + check_if_equal(*cur_iter_stir_IIR_out, *cur_iter_IIR_out, "check IIR filter implementation"); } } @@ -162,10 +140,9 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 1) - { +int +main(int argc, char** argv) { + if (argc != 1) { cerr << "Usage : " << argv[0] << " \n"; return EXIT_FAILURE; } diff --git a/src/test/numerics/test_erf.cxx b/src/test/numerics/test_erf.cxx index f7ca4f2a78..f461c6f110 100644 --- a/src/test/numerics/test_erf.cxx +++ b/src/test/numerics/test_erf.cxx @@ -17,14 +17,14 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics_test \brief tests the error function stir::erf and its complementary \author Charalampos Tsoumpas */ - + #include "stir/RunTests.h" #include "stir/numerics/erf.h" #include @@ -35,31 +35,28 @@ START_NAMESPACE_STIR \ingroup numerics_test \brief A simple class to test the erf and erfc functions. */ -class erfTests : public RunTests -{ +class erfTests : public RunTests { public: - erfTests() - {} + erfTests() {} void run_tests(); + private: - //istream& in; + // istream& in; }; - -void erfTests::run_tests() -{ +void +erfTests::run_tests() { std::cerr << "Testing Error Functions..." << std::endl; set_tolerance(0.000000000000001); - - //std::vector input, mathematica_results, STIR_results; - - { - - std::vector input_vector(10), - output_correct_vector(10), output_correct_vector_c(10), - STIR_vector(10), STIR_vector_c(10); - + + // std::vector input, mathematica_results, STIR_results; + + { + + std::vector input_vector(10), output_correct_vector(10), output_correct_vector_c(10), STIR_vector(10), + STIR_vector_c(10); + output_correct_vector[0] = 0.0000000000000000000000000000000; output_correct_vector[1] = 0.0112834155558496169159095235481; output_correct_vector[2] = 0.0225645746918449442243658616474; @@ -69,7 +66,7 @@ void erfTests::run_tests() output_correct_vector[6] = 0.0676215943933084420794314523912; output_correct_vector[7] = 0.0788577197708907433569970386680; output_correct_vector[8] = 0.0900781258410181607233921876161; - output_correct_vector[9] = 0.101280593914626883352498163244; + output_correct_vector[9] = 0.101280593914626883352498163244; output_correct_vector_c[0] = 1.00000000000000000000000000000; output_correct_vector_c[1] = 0.988716584444150383084090476452; @@ -80,47 +77,35 @@ void erfTests::run_tests() output_correct_vector_c[6] = 0.932378405606691557920568547609; output_correct_vector_c[7] = 0.921142280229109256643002961332; output_correct_vector_c[8] = 0.909921874158981839276607812384; - output_correct_vector_c[9] = 0.898719406085373116647501836756; - - - for (int i=0 ; i<10 ; ++i) - { - input_vector[i] = 0.01*(static_cast(i)); - STIR_vector[i] = erf(input_vector[i]); - STIR_vector_c[i] = erfc(input_vector[i]); - } - std::vector:: iterator cur_iter_cor = output_correct_vector.begin(), - cur_iter_cor_c = output_correct_vector_c.begin(), - cur_iter_STIR = STIR_vector.begin(), - cur_iter_STIR_c = STIR_vector_c.begin(); - - for (cur_iter_STIR = STIR_vector.begin(); - cur_iter_STIR!=STIR_vector.end() && cur_iter_cor!=output_correct_vector.end(); - ++cur_iter_STIR, ++cur_iter_cor) - check_if_equal(*cur_iter_cor, *cur_iter_STIR, - "check erf() implementation"); - for (; - cur_iter_STIR_c!=STIR_vector_c.end() && cur_iter_cor_c!=output_correct_vector_c.end(); - ++cur_iter_STIR_c, ++cur_iter_cor_c) - check_if_equal(*cur_iter_cor_c, *cur_iter_STIR_c, - "check erfc() implementation"); + output_correct_vector_c[9] = 0.898719406085373116647501836756; + + for (int i = 0; i < 10; ++i) { + input_vector[i] = 0.01 * (static_cast(i)); + STIR_vector[i] = erf(input_vector[i]); + STIR_vector_c[i] = erfc(input_vector[i]); + } + std::vector::iterator cur_iter_cor = output_correct_vector.begin(), cur_iter_cor_c = output_correct_vector_c.begin(), + cur_iter_STIR = STIR_vector.begin(), cur_iter_STIR_c = STIR_vector_c.begin(); + + for (cur_iter_STIR = STIR_vector.begin(); cur_iter_STIR != STIR_vector.end() && cur_iter_cor != output_correct_vector.end(); + ++cur_iter_STIR, ++cur_iter_cor) + check_if_equal(*cur_iter_cor, *cur_iter_STIR, "check erf() implementation"); + for (; cur_iter_STIR_c != STIR_vector_c.end() && cur_iter_cor_c != output_correct_vector_c.end(); + ++cur_iter_STIR_c, ++cur_iter_cor_c) + check_if_equal(*cur_iter_cor_c, *cur_iter_STIR_c, "check erfc() implementation"); for (cur_iter_STIR_c = STIR_vector_c.begin(), cur_iter_STIR = STIR_vector.begin(); - cur_iter_STIR!=STIR_vector.end() && - cur_iter_STIR_c!=STIR_vector_c.end(); - ++cur_iter_STIR, ++cur_iter_STIR_c) - check_if_equal(1.0, (*cur_iter_STIR_c) + (*cur_iter_STIR), - "check erfc() and erf() results"); - } + cur_iter_STIR != STIR_vector.end() && cur_iter_STIR_c != STIR_vector_c.end(); ++cur_iter_STIR, ++cur_iter_STIR_c) + check_if_equal(1.0, (*cur_iter_STIR_c) + (*cur_iter_STIR), "check erfc() and erf() results"); + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 1) - { +int +main(int argc, char** argv) { + if (argc != 1) { std::cerr << "Usage : " << argv[0] << " \n"; return EXIT_FAILURE; } diff --git a/src/test/numerics/test_integrate_discrete_function.cxx b/src/test/numerics/test_integrate_discrete_function.cxx index 1ddb5d9e44..0fd915c785 100644 --- a/src/test/numerics/test_integrate_discrete_function.cxx +++ b/src/test/numerics/test_integrate_discrete_function.cxx @@ -23,9 +23,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics_test - \brief tests the integrate_discrete_function function + \brief tests the integrate_discrete_function function */ #include "stir/RunTests.h" @@ -38,44 +38,40 @@ START_NAMESPACE_STIR \ingroup numerics_test \brief A simple class to test the integrate_discrete_function function. */ -class integrate_discrete_functionTests : public RunTests -{ +class integrate_discrete_functionTests : public RunTests { public: - integrate_discrete_functionTests() - {} + integrate_discrete_functionTests() {} void run_tests(); }; - -void integrate_discrete_functionTests::run_tests() -{ +void +integrate_discrete_functionTests::run_tests() { std::cerr << "Testing integrate_discrete_function..." << std::endl; - { + { set_tolerance(0.000001); - + // Give a simple linear function. The analytical estimation of the integral is E=(tmax-tmin)*(fmax+fmin)/2 - const int Nmin=2; - const int Nmax=333; - - const float tmin=12; - const float tmax=123; - const float fmin=113; - const float fmax=1113; - - const float cor_integral_value=(tmax-tmin)*(fmax+fmin)*0.5; - std::vector input_vector_f(Nmax-Nmin+1), input_vector_t(Nmax-Nmin+1); - - for (int i=0;i<=Nmax-Nmin;++i) - { - input_vector_t[i]=tmin+i*(tmax-tmin)/(Nmax-Nmin); - input_vector_f[i]=fmin+i*(fmax-fmin)/(Nmax-Nmin); - } - - check_if_equal(integrate_discrete_function(input_vector_t,input_vector_f,0),cor_integral_value, - "check integrate_discrete_function implementation for linear function using rectangular approximation"); - check_if_equal(integrate_discrete_function(input_vector_t,input_vector_f), cor_integral_value, - "check integrate_discrete_function implementation for linear function using trapezoidal approximation"); + const int Nmin = 2; + const int Nmax = 333; + + const float tmin = 12; + const float tmax = 123; + const float fmin = 113; + const float fmax = 1113; + + const float cor_integral_value = (tmax - tmin) * (fmax + fmin) * 0.5; + std::vector input_vector_f(Nmax - Nmin + 1), input_vector_t(Nmax - Nmin + 1); + + for (int i = 0; i <= Nmax - Nmin; ++i) { + input_vector_t[i] = tmin + i * (tmax - tmin) / (Nmax - Nmin); + input_vector_f[i] = fmin + i * (fmax - fmin) / (Nmax - Nmin); + } + + check_if_equal(integrate_discrete_function(input_vector_t, input_vector_f, 0), cor_integral_value, + "check integrate_discrete_function implementation for linear function using rectangular approximation"); + check_if_equal(integrate_discrete_function(input_vector_t, input_vector_f), cor_integral_value, + "check integrate_discrete_function implementation for linear function using trapezoidal approximation"); } // quadratic @@ -84,37 +80,38 @@ void integrate_discrete_functionTests::run_tests() std::vector values(100); // make non-uniform sampling - int i=0; - for (i=0; i<=50; ++i) - coords[i]=2*(i-50); - for (; i<=70; ++i) - coords[i]=coords[i-1]+1; - for (; i<100; ++i) - coords[i]=coords[i-1]+1.5; + int i = 0; + for (i = 0; i <= 50; ++i) + coords[i] = 2 * (i - 50); + for (; i <= 70; ++i) + coords[i] = coords[i - 1] + 1; + for (; i < 100; ++i) + coords[i] = coords[i - 1] + 1.5; // fill values - for (i=0; i<100; ++i) - values[i]=2*coords[i]*coords[i]- 5*coords[i]+7; + for (i = 0; i < 100; ++i) + values[i] = 2 * coords[i] * coords[i] - 5 * coords[i] + 7; const double analytic_result = - (2*coords[99]*coords[99]*coords[99]/3 - 5*coords[0]*coords[99]/2+7*coords[99]) - - (2*coords[0]*coords[0]*coords[0]/3 - 5*coords[0]*coords[0]/2+7*coords[0]); - double stir_result=integrate_discrete_function(coords, values,1); + (2 * coords[99] * coords[99] * coords[99] / 3 - 5 * coords[0] * coords[99] / 2 + 7 * coords[99]) - + (2 * coords[0] * coords[0] * coords[0] / 3 - 5 * coords[0] * coords[0] / 2 + 7 * coords[0]); + double stir_result = integrate_discrete_function(coords, values, 1); set_tolerance(.03); // expected accuracy is 3% - check_if_equal(stir_result, analytic_result, "check integrate_discrete_function implementation for quadratic function using trapezoidal approximation"); - stir_result=integrate_discrete_function(coords, values, 0); + check_if_equal(stir_result, analytic_result, + "check integrate_discrete_function implementation for quadratic function using trapezoidal approximation"); + stir_result = integrate_discrete_function(coords, values, 0); set_tolerance(.03); - check_if_equal(stir_result, analytic_result, "check integrate_discrete_function implementation for linear function using rectangular approximation"); + check_if_equal(stir_result, analytic_result, + "check integrate_discrete_function implementation for linear function using rectangular approximation"); } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 1) - { +int +main(int argc, char** argv) { + if (argc != 1) { std::cerr << "Usage : " << argv[0] << " \n"; return EXIT_FAILURE; } diff --git a/src/test/numerics/test_matrices.cxx b/src/test/numerics/test_matrices.cxx index a5fd1396e7..cc295c6ac2 100644 --- a/src/test/numerics/test_matrices.cxx +++ b/src/test/numerics/test_matrices.cxx @@ -16,9 +16,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics_test - + \brief tests for functions in MatrixFunction.h etc. \author Kris Thielemans @@ -35,22 +35,25 @@ #include "stir/stream.h" #include #include -# ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::sqrt; using ::sin; using ::cos} -# endif +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::sqrt; +using ::sin; +using ::cos +} // namespace std +#endif START_NAMESPACE_STIR - /*! \brief Tests MatrixFunction.h functionality \ingroup test_numerics */ -class MatrixTests : public RunTests -{ +class MatrixTests : public RunTests { public: void run_tests(); + private: void run_tests_1D(); void run_tests_2D(); @@ -60,30 +63,19 @@ class MatrixTests : public RunTests // local function, copied from the Shape library // takes Euler angles and make an orthogonal matrix // note that because of STIR conventions, this matrix has determinant -1. -static -Array<2,float> -make_orthogonal_matrix(const float alpha, const float beta, const float gamma) -{ - return - make_array(make_1d_array( - std::sin(beta)*std::sin(gamma), - std::cos(gamma)*std::sin(alpha) + std::cos(alpha)*std::cos(beta)*std::sin(gamma), - std::cos(alpha)*std::cos(gamma) - std::cos(beta)*std::sin(alpha)*std::sin(gamma)), - make_1d_array( - std::cos(gamma)*std::sin(beta), - std::cos(alpha)*std::cos(beta)*std::cos(gamma) - std::sin(alpha)*std::sin(gamma), - -(std::cos(beta)*std::cos(gamma)*std::sin(alpha)) - std::cos(alpha)*std::sin(gamma)), - make_1d_array( - std::cos(beta), - -(std::cos(alpha)*std::sin(beta)), - std::sin(alpha)*std::sin(beta)) - ); +static Array<2, float> +make_orthogonal_matrix(const float alpha, const float beta, const float gamma) { + return make_array(make_1d_array(std::sin(beta) * std::sin(gamma), + std::cos(gamma) * std::sin(alpha) + std::cos(alpha) * std::cos(beta) * std::sin(gamma), + std::cos(alpha) * std::cos(gamma) - std::cos(beta) * std::sin(alpha) * std::sin(gamma)), + make_1d_array(std::cos(gamma) * std::sin(beta), + std::cos(alpha) * std::cos(beta) * std::cos(gamma) - std::sin(alpha) * std::sin(gamma), + -(std::cos(beta) * std::cos(gamma) * std::sin(alpha)) - std::cos(alpha) * std::sin(gamma)), + make_1d_array(std::cos(beta), -(std::cos(alpha) * std::sin(beta)), std::sin(alpha) * std::sin(beta))); } void -MatrixTests:: -run_tests() -{ +MatrixTests::run_tests() { std::cerr << "Testing numerics/MatrixFunction.h functions\n"; run_tests_1D(); run_tests_2D(); @@ -91,283 +83,176 @@ run_tests() } void -MatrixTests:: -run_tests_1D() -{ +MatrixTests::run_tests_1D() { std::cerr << "Testing 1D stuff" << std::endl; { - const Array<1,float> v = make_1d_array(1.F,2.F,3.F,-5.F); - check_if_equal(norm(v),static_cast(std::sqrt(square(1.F)+square(2)+square(3)+square(5))), - "norm of float array"); - check_if_equal(inner_product(v,v),square(1.F)+square(2)+square(3)+square(5), - "inner_product of float array with itself"); - const Array<1,float> v2 = make_1d_array(7.F,8.F,3.3F,-5.F); - check_if_equal(inner_product(v,v2),1.F*7+2*8+3*3.3F+25, - "inner_product of float arrays"); + const Array<1, float> v = make_1d_array(1.F, 2.F, 3.F, -5.F); + check_if_equal(norm(v), static_cast(std::sqrt(square(1.F) + square(2) + square(3) + square(5))), + "norm of float array"); + check_if_equal(inner_product(v, v), square(1.F) + square(2) + square(3) + square(5), + "inner_product of float array with itself"); + const Array<1, float> v2 = make_1d_array(7.F, 8.F, 3.3F, -5.F); + check_if_equal(inner_product(v, v2), 1.F * 7 + 2 * 8 + 3 * 3.3F + 25, "inner_product of float arrays"); } { - typedef std::complex complex_t; - const Array<1,complex_t > v = make_1d_array(complex_t(1.F,0.F), - complex_t(2.F,-3.F)); - check_if_equal(norm(v),static_cast(std::sqrt(square(1.F)+square(2)+square(3))), - "norm of complex array"); - check_if_equal(inner_product(v,v), - complex_t(square(1.F)+square(2)+square(3),0.F), - "inner_product of complex array with itself"); - const Array<1,complex_t > v2 = make_1d_array(complex_t(1.F,1.F), - complex_t(4.F,5.F)); - check_if_equal(inner_product(v,v2), - std::conj(v[0])*v2[0]+std::conj(v[1])*v2[1], - "inner_product of complex arrays"); + typedef std::complex complex_t; + const Array<1, complex_t> v = make_1d_array(complex_t(1.F, 0.F), complex_t(2.F, -3.F)); + check_if_equal(norm(v), static_cast(std::sqrt(square(1.F) + square(2) + square(3))), "norm of complex array"); + check_if_equal(inner_product(v, v), complex_t(square(1.F) + square(2) + square(3), 0.F), + "inner_product of complex array with itself"); + const Array<1, complex_t> v2 = make_1d_array(complex_t(1.F, 1.F), complex_t(4.F, 5.F)); + check_if_equal(inner_product(v, v2), std::conj(v[0]) * v2[0] + std::conj(v[1]) * v2[1], "inner_product of complex arrays"); } } void -MatrixTests:: -run_tests_2D() -{ +MatrixTests::run_tests_2D() { std::cerr << "Testing 2D stuff" << std::endl; - const Array<2,float> m1 = - make_array(make_1d_array(3.F,4.F), - make_1d_array(5.F,6.F), - make_1d_array(1.5F,-4.6F)); + const Array<2, float> m1 = make_array(make_1d_array(3.F, 4.F), make_1d_array(5.F, 6.F), make_1d_array(1.5F, -4.6F)); // matrix*vector { - const Array<1,float> v = make_1d_array(1.F,2.F); - check_if_equal(matrix_multiply(m1,v), - make_1d_array(m1[0][0]*v[0]+m1[0][1]*v[1], - m1[1][0]*v[0]+m1[1][1]*v[1], - m1[2][0]*v[0]+m1[2][1]*v[1]), - "matrix times vector"); + const Array<1, float> v = make_1d_array(1.F, 2.F); + check_if_equal( + matrix_multiply(m1, v), + make_1d_array(m1[0][0] * v[0] + m1[0][1] * v[1], m1[1][0] * v[0] + m1[1][1] * v[1], m1[2][0] * v[0] + m1[2][1] * v[1]), + "matrix times vector"); } // matrix*matrix { - const Array<2,float> m2 = - make_array(make_1d_array(1.F,4.3F,6.F,8.F), - make_1d_array(-5.F,6.5F,2.F,5.F)); - check_if_equal(matrix_multiply(m1,m2), - make_array(make_1d_array(m1[0][0]*m2[0][0]+m1[0][1]*m2[1][0], - m1[0][0]*m2[0][1]+m1[0][1]*m2[1][1], - m1[0][0]*m2[0][2]+m1[0][1]*m2[1][2], - m1[0][0]*m2[0][3]+m1[0][1]*m2[1][3]), - make_1d_array(m1[1][0]*m2[0][0]+m1[1][1]*m2[1][0], - m1[1][0]*m2[0][1]+m1[1][1]*m2[1][1], - m1[1][0]*m2[0][2]+m1[1][1]*m2[1][2], - m1[1][0]*m2[0][3]+m1[1][1]*m2[1][3]), - make_1d_array(m1[2][0]*m2[0][0]+m1[2][1]*m2[1][0], - m1[2][0]*m2[0][1]+m1[2][1]*m2[1][1], - m1[2][0]*m2[0][2]+m1[2][1]*m2[1][2], - m1[2][0]*m2[0][3]+m1[2][1]*m2[1][3])), - "matrix times matrix"); + const Array<2, float> m2 = make_array(make_1d_array(1.F, 4.3F, 6.F, 8.F), make_1d_array(-5.F, 6.5F, 2.F, 5.F)); + check_if_equal( + matrix_multiply(m1, m2), + make_array(make_1d_array(m1[0][0] * m2[0][0] + m1[0][1] * m2[1][0], m1[0][0] * m2[0][1] + m1[0][1] * m2[1][1], + m1[0][0] * m2[0][2] + m1[0][1] * m2[1][2], m1[0][0] * m2[0][3] + m1[0][1] * m2[1][3]), + make_1d_array(m1[1][0] * m2[0][0] + m1[1][1] * m2[1][0], m1[1][0] * m2[0][1] + m1[1][1] * m2[1][1], + m1[1][0] * m2[0][2] + m1[1][1] * m2[1][2], m1[1][0] * m2[0][3] + m1[1][1] * m2[1][3]), + make_1d_array(m1[2][0] * m2[0][0] + m1[2][1] * m2[1][0], m1[2][0] * m2[0][1] + m1[2][1] * m2[1][1], + m1[2][0] * m2[0][2] + m1[2][1] * m2[1][2], m1[2][0] * m2[0][3] + m1[2][1] * m2[1][3])), + "matrix times matrix"); } // transpose { - const Array<2,float> m1_trans = - make_array(make_1d_array(m1[0][0],m1[1][0],m1[2][0]), - make_1d_array(m1[0][1],m1[1][1],m1[2][1])); - check_if_equal(matrix_transpose(m1), m1_trans, - "matrix transposition"); + const Array<2, float> m1_trans = + make_array(make_1d_array(m1[0][0], m1[1][0], m1[2][0]), make_1d_array(m1[0][1], m1[1][1], m1[2][1])); + check_if_equal(matrix_transpose(m1), m1_trans, "matrix transposition"); } // diagonal_matrix { - const Array<2,float> d = - diagonal_matrix(2, 3.F); - check_if_equal(d, - make_array(make_1d_array(3.F,0.F), - make_1d_array(0.F,3.F)), - "diagonal_matrix with all diag-elems equal"); - const Array<2,float> d2 = - diagonal_matrix(Coordinate2D(3.F,4.F)); - check_if_equal(d2, - make_array(make_1d_array(3.F,0.F), - make_1d_array(0.F,4.F)), - "diagonal_matrix with differing diag-elems"); + const Array<2, float> d = diagonal_matrix(2, 3.F); + check_if_equal(d, make_array(make_1d_array(3.F, 0.F), make_1d_array(0.F, 3.F)), "diagonal_matrix with all diag-elems equal"); + const Array<2, float> d2 = diagonal_matrix(Coordinate2D(3.F, 4.F)); + check_if_equal(d2, make_array(make_1d_array(3.F, 0.F), make_1d_array(0.F, 4.F)), "diagonal_matrix with differing diag-elems"); } - } - void -MatrixTests:: -run_tests_max_eigenvector() -{ +MatrixTests::run_tests_max_eigenvector() { std::cerr << "Testing max_eigenvector stuff" << std::endl; set_tolerance(.01); float max_eigenvalue; - Array<1,float> max_eigenvector; - { - { - const Array<2,float> d = - diagonal_matrix(Coordinate3D(3.F,4.F,-2.F)); - Succeeded success = - absolute_max_eigenvector_using_power_method(max_eigenvalue, - max_eigenvector, - d, - make_1d_array(1.F,2.F,3.F), - /*tolerance=*/ .001, - 1000UL); - check(success == Succeeded::yes, - "abs_max_using_power: succeeded (float diagonal matrix)"); - - check_if_equal(max_eigenvalue, 4.F, - "abs_max_using_power: eigenvalue (float diagonal matrix)"); - check_if_equal(max_eigenvector, make_1d_array(0.F,1.F,0.F), - "abs_max_using_power: eigenvector (float diagonal matrix)"); - success = - absolute_max_eigenvector_using_shifted_power_method(max_eigenvalue, - max_eigenvector, - d, - make_1d_array(1.F,2.F,3.F), - .5F, // note: shift should be small enough that it doesn't make the most negative eigenvalue 'larger' - /*tolerance=*/ .001, - 1000UL); - check(success == Succeeded::yes, - "abs_max_using_shifted_power: succeeded (float diagonal matrix)"); - - check_if_equal(max_eigenvalue, 4.F, - "abs_max_using_shifted_power: eigenvalue (float diagonal matrix)"); - check_if_equal(max_eigenvector, make_1d_array(0.F,1.F,0.F), - "abs_max_using_shifted_power: eigenvector (float diagonal matrix)"); - - success = - max_eigenvector_using_power_method(max_eigenvalue, - max_eigenvector, - d, - make_1d_array(1.F,-2.F,-3.F), - /*tolerance=*/ .001, - 1000UL); - check(success == Succeeded::yes, - "max_using_power: succeeded (float diagonal matrix)"); - - check_if_equal(max_eigenvalue, 4.F, - "max_using_power: eigenvalue (float diagonal matrix)"); - check_if_equal(max_eigenvector, make_1d_array(0.F,1.F,0.F), - "max_using_power: eigenvector (float diagonal matrix)"); - - success = - max_eigenvector_using_power_method(max_eigenvalue, - max_eigenvector, - Array<2,float>(d*(-1.F)), - make_1d_array(1.F,2.F,3.F), - /*tolerance=*/ .001, - 1000UL); - check(success == Succeeded::yes, - "max_using_power: succeeded (float diagonal matrix with large negative value)"); - - check_if_equal(max_eigenvalue, 2.F, - "max_using_power: eigenvalue (float diagonal matrix with large negative value)"); - check_if_equal(max_eigenvector, make_1d_array(0.F,0.F,1.F), - "max_using_power: eigenvector (float diagonal matrix with large negative value)"); - } - } + Array<1, float> max_eigenvector; + {{const Array<2, float> d = diagonal_matrix(Coordinate3D(3.F, 4.F, -2.F)); + Succeeded success = + absolute_max_eigenvector_using_power_method(max_eigenvalue, max_eigenvector, d, make_1d_array(1.F, 2.F, 3.F), + /*tolerance=*/.001, 1000UL); + check(success == Succeeded::yes, "abs_max_using_power: succeeded (float diagonal matrix)"); - { - const float pi2=static_cast(_PI/2); - const Array<2,float> rotation = - // make_orthogonal_matrix(.2F,.4F,-1.F); - make_orthogonal_matrix(pi2,pi2,pi2); - std::cerr << rotation; - check_if_equal(matrix_multiply(rotation, matrix_transpose(rotation)), - diagonal_matrix(3,1.F), - "construct orthogonal matrix O.O^t"); - check_if_equal(matrix_multiply(matrix_transpose(rotation), rotation), - diagonal_matrix(3,1.F), - "construct orthogonal matrix O^t.O"); - - const Array<2,float> d = - diagonal_matrix(Coordinate3D(3.F,4.F,-2.F)); - - const Array<2,float> m = - matrix_multiply(rotation, matrix_multiply(d, matrix_transpose(rotation))); - Array<1,float> the_max_eigenvector = - matrix_multiply(rotation,make_1d_array(0.F,1.F,0.F)); - the_max_eigenvector /= (*abs_max_element(the_max_eigenvector.begin(), the_max_eigenvector.end())); - - // now repetition of tests with diagonal matrix - Succeeded success = - absolute_max_eigenvector_using_power_method(max_eigenvalue, - max_eigenvector, - m, - make_1d_array(1.F,2.F,3.F), - /*tolerance=*/ .001, - 1000UL); - check(success == Succeeded::yes, - "abs_max_using_power: succeeded (float non-diagonal matrix)"); - - check_if_equal(max_eigenvalue, 4.F, - "abs_max_using_power: eigenvalue (float non-diagonal matrix)"); - check_if_equal(max_eigenvector, the_max_eigenvector, - "abs_max_using_power: eigenvector (float non-diagonal matrix)"); - success = - absolute_max_eigenvector_using_shifted_power_method(max_eigenvalue, - max_eigenvector, - m, - make_1d_array(1.F,2.F,3.F), - .5F, // note: shift should be small enough that it doesn't make the most negative eigenvalue 'larger' - /*tolerance=*/ .001, - 1000UL); - check(success == Succeeded::yes, - "abs_max_using_shifted_power: succeeded (float non-diagonal matrix)"); - - check_if_equal(max_eigenvalue, 4.F, - "abs_max_using_shifted_power: eigenvalue (float non-diagonal matrix)"); - check_if_equal(max_eigenvector, the_max_eigenvector, - "abs_max_using_shifted_power: eigenvector (float non-diagonal matrix)"); - - success = - max_eigenvector_using_power_method(max_eigenvalue, - max_eigenvector, - m, - make_1d_array(1.F,-2.F,-3.F), - /*tolerance=*/ .001, - 1000UL); - check(success == Succeeded::yes, - "max_using_power: succeeded (float non-diagonal matrix)"); - - check_if_equal(max_eigenvalue, 4.F, - "max_using_power: eigenvalue (float non-diagonal matrix)"); - check_if_equal(max_eigenvector, the_max_eigenvector, - "max_using_power: eigenvector (float non-diagonal matrix)"); - - success = - max_eigenvector_using_power_method(max_eigenvalue, - max_eigenvector, - Array<2,float>(m*(-1.F)), - make_1d_array(1.F,2.F,3.F), - /*tolerance=*/ .001, - 1000UL); - check(success == Succeeded::yes, - "max_using_power: succeeded (float non-diagonal matrix with large negative value)"); - - check_if_equal(max_eigenvalue, 2.F, - "max_using_power: eigenvalue (float non-diagonal matrix with large negative value)"); - check_if_equal(max_eigenvector, matrix_multiply(rotation,make_1d_array(0.F,0.F,1.F)), - "max_using_power: eigenvector (float non-diagonal matrix with large negative value)"); - } + check_if_equal(max_eigenvalue, 4.F, "abs_max_using_power: eigenvalue (float diagonal matrix)"); + check_if_equal(max_eigenvector, make_1d_array(0.F, 1.F, 0.F), "abs_max_using_power: eigenvector (float diagonal matrix)"); + success = absolute_max_eigenvector_using_shifted_power_method( + max_eigenvalue, max_eigenvector, d, make_1d_array(1.F, 2.F, 3.F), + .5F, // note: shift should be small enough that it doesn't make the most negative eigenvalue 'larger' + /*tolerance=*/.001, 1000UL); + check(success == Succeeded::yes, "abs_max_using_shifted_power: succeeded (float diagonal matrix)"); - { - // now test for a case where the power-method fails - const Array<2,float> d = - diagonal_matrix(Coordinate2D(3.F,-3.F)); - Succeeded success = - absolute_max_eigenvector_using_power_method(max_eigenvalue, - max_eigenvector, - d, - make_1d_array(1.F,2.F), - /*tolerance=*/ .001, - 100UL); - check(success == Succeeded::no, - "abs_max_using_power should have failed (float diagonal matrix with opposite max eigenvalues)"); - } + check_if_equal(max_eigenvalue, 4.F, "abs_max_using_shifted_power: eigenvalue (float diagonal matrix)"); + check_if_equal(max_eigenvector, make_1d_array(0.F, 1.F, 0.F), + "abs_max_using_shifted_power: eigenvector (float diagonal matrix)"); + + success = max_eigenvector_using_power_method(max_eigenvalue, max_eigenvector, d, make_1d_array(1.F, -2.F, -3.F), + /*tolerance=*/.001, 1000UL); + check(success == Succeeded::yes, "max_using_power: succeeded (float diagonal matrix)"); + + check_if_equal(max_eigenvalue, 4.F, "max_using_power: eigenvalue (float diagonal matrix)"); + check_if_equal(max_eigenvector, make_1d_array(0.F, 1.F, 0.F), "max_using_power: eigenvector (float diagonal matrix)"); + + success = max_eigenvector_using_power_method(max_eigenvalue, max_eigenvector, Array<2, float>(d * (-1.F)), + make_1d_array(1.F, 2.F, 3.F), + /*tolerance=*/.001, 1000UL); + check(success == Succeeded::yes, "max_using_power: succeeded (float diagonal matrix with large negative value)"); + + check_if_equal(max_eigenvalue, 2.F, "max_using_power: eigenvalue (float diagonal matrix with large negative value)"); + check_if_equal(max_eigenvector, make_1d_array(0.F, 0.F, 1.F), + "max_using_power: eigenvector (float diagonal matrix with large negative value)"); +} } -END_NAMESPACE_STIR +{ + const float pi2 = static_cast(_PI / 2); + const Array<2, float> rotation = + // make_orthogonal_matrix(.2F,.4F,-1.F); + make_orthogonal_matrix(pi2, pi2, pi2); + std::cerr << rotation; + check_if_equal(matrix_multiply(rotation, matrix_transpose(rotation)), diagonal_matrix(3, 1.F), + "construct orthogonal matrix O.O^t"); + check_if_equal(matrix_multiply(matrix_transpose(rotation), rotation), diagonal_matrix(3, 1.F), + "construct orthogonal matrix O^t.O"); + + const Array<2, float> d = diagonal_matrix(Coordinate3D(3.F, 4.F, -2.F)); + + const Array<2, float> m = matrix_multiply(rotation, matrix_multiply(d, matrix_transpose(rotation))); + Array<1, float> the_max_eigenvector = matrix_multiply(rotation, make_1d_array(0.F, 1.F, 0.F)); + the_max_eigenvector /= (*abs_max_element(the_max_eigenvector.begin(), the_max_eigenvector.end())); + + // now repetition of tests with diagonal matrix + Succeeded success = + absolute_max_eigenvector_using_power_method(max_eigenvalue, max_eigenvector, m, make_1d_array(1.F, 2.F, 3.F), + /*tolerance=*/.001, 1000UL); + check(success == Succeeded::yes, "abs_max_using_power: succeeded (float non-diagonal matrix)"); + + check_if_equal(max_eigenvalue, 4.F, "abs_max_using_power: eigenvalue (float non-diagonal matrix)"); + check_if_equal(max_eigenvector, the_max_eigenvector, "abs_max_using_power: eigenvector (float non-diagonal matrix)"); + success = absolute_max_eigenvector_using_shifted_power_method( + max_eigenvalue, max_eigenvector, m, make_1d_array(1.F, 2.F, 3.F), + .5F, // note: shift should be small enough that it doesn't make the most negative eigenvalue 'larger' + /*tolerance=*/.001, 1000UL); + check(success == Succeeded::yes, "abs_max_using_shifted_power: succeeded (float non-diagonal matrix)"); + check_if_equal(max_eigenvalue, 4.F, "abs_max_using_shifted_power: eigenvalue (float non-diagonal matrix)"); + check_if_equal(max_eigenvector, the_max_eigenvector, "abs_max_using_shifted_power: eigenvector (float non-diagonal matrix)"); + + success = max_eigenvector_using_power_method(max_eigenvalue, max_eigenvector, m, make_1d_array(1.F, -2.F, -3.F), + /*tolerance=*/.001, 1000UL); + check(success == Succeeded::yes, "max_using_power: succeeded (float non-diagonal matrix)"); + + check_if_equal(max_eigenvalue, 4.F, "max_using_power: eigenvalue (float non-diagonal matrix)"); + check_if_equal(max_eigenvector, the_max_eigenvector, "max_using_power: eigenvector (float non-diagonal matrix)"); + + success = max_eigenvector_using_power_method(max_eigenvalue, max_eigenvector, Array<2, float>(m * (-1.F)), + make_1d_array(1.F, 2.F, 3.F), + /*tolerance=*/.001, 1000UL); + check(success == Succeeded::yes, "max_using_power: succeeded (float non-diagonal matrix with large negative value)"); + + check_if_equal(max_eigenvalue, 2.F, "max_using_power: eigenvalue (float non-diagonal matrix with large negative value)"); + check_if_equal(max_eigenvector, matrix_multiply(rotation, make_1d_array(0.F, 0.F, 1.F)), + "max_using_power: eigenvector (float non-diagonal matrix with large negative value)"); +} -int main() { + // now test for a case where the power-method fails + const Array<2, float> d = diagonal_matrix(Coordinate2D(3.F, -3.F)); + Succeeded success = absolute_max_eigenvector_using_power_method(max_eigenvalue, max_eigenvector, d, make_1d_array(1.F, 2.F), + /*tolerance=*/.001, 100UL); + check(success == Succeeded::no, "abs_max_using_power should have failed (float diagonal matrix with opposite max eigenvalues)"); +} +} + +END_NAMESPACE_STIR + +int +main() { stir::MatrixTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/numerics/test_overlap_interpolate.cxx b/src/test/numerics/test_overlap_interpolate.cxx index e9438de93d..a9122fb614 100644 --- a/src/test/numerics/test_overlap_interpolate.cxx +++ b/src/test/numerics/test_overlap_interpolate.cxx @@ -35,116 +35,85 @@ START_NAMESPACE_STIR - /*! \brief Test class for stir::overlap_interpolate \ingroup numerics_test */ -class overlap_interpolateTests : public RunTests -{ +class overlap_interpolateTests : public RunTests { public: void run_tests(); + private: #ifndef STIR_OVERLAP_NORMALISATION template - static - void - divide_by_out_size( - ValueT& outvalues, - const BoundaryT& outboundaries) - { + static void divide_by_out_size(ValueT& outvalues, const BoundaryT& outboundaries) { typename ValueT::iterator iter = outvalues.begin(); typename BoundaryT::const_iterator bound_iter = outboundaries.begin(); - for (; iter != outvalues.end(); ++iter, ++bound_iter) - { - *iter /= (*(bound_iter+1)) - (*bound_iter); - } + for (; iter != outvalues.end(); ++iter, ++bound_iter) { + *iter /= (*(bound_iter + 1)) - (*bound_iter); + } } #endif template - Succeeded - test_case(const ValueT& invalues, - const BoundaryT& inboundaries, - const ValueT& outvalues, - const BoundaryT& outboundaries, - const char * const description) - { + Succeeded test_case(const ValueT& invalues, const BoundaryT& inboundaries, const ValueT& outvalues, + const BoundaryT& outboundaries, const char* const description) { ValueT my_outvalues = outvalues; - overlap_interpolate(my_outvalues.begin(), my_outvalues.end(), - outboundaries.begin(), outboundaries.end(), - invalues.begin(), invalues.end(), - inboundaries.begin(), inboundaries.end()); + overlap_interpolate(my_outvalues.begin(), my_outvalues.end(), outboundaries.begin(), outboundaries.end(), invalues.begin(), + invalues.end(), inboundaries.begin(), inboundaries.end()); #ifndef STIR_OVERLAP_NORMALISATION divide_by_out_size(my_outvalues, outboundaries); #endif - const bool ret = check_if_equal(my_outvalues, outvalues,description); + const bool ret = check_if_equal(my_outvalues, outvalues, description); if (!ret) std::cerr << "\nres: " << my_outvalues << "should be " << outvalues; - return - ret ? Succeeded::yes : Succeeded::no; + return ret ? Succeeded::yes : Succeeded::no; } template - Succeeded - uniform_test_case(const ValueT& invalues, - const float zoom, const float offset, - const ValueT& outvalues, - const char * const description) - { + Succeeded uniform_test_case(const ValueT& invalues, const float zoom, const float offset, const ValueT& outvalues, + const char* const description) { using namespace boost::lambda; ValueT my_outvalues = outvalues; - overlap_interpolate(my_outvalues, - invalues, zoom, offset); + overlap_interpolate(my_outvalues, invalues, zoom, offset); #ifndef STIR_OVERLAP_NORMALISATION std::for_each(my_outvalues.begin(), my_outvalues.end(), _1 *= zoom); #endif - const bool ret = check_if_equal(my_outvalues, outvalues,description); + const bool ret = check_if_equal(my_outvalues, outvalues, description); if (!ret) std::cerr << "\nres: " << my_outvalues << "should be " << outvalues << '\n'; - return - ret ? Succeeded::yes : Succeeded::no; + return ret ? Succeeded::yes : Succeeded::no; } - Succeeded - test_case_1d(const char * const input, - const char * const description) - { + Succeeded test_case_1d(const char* const input, const char* const description) { std::istringstream s(input); VectorWithOffset invalues, inboundaries, outvalues, outboundaries; s >> invalues >> inboundaries >> outvalues >> outboundaries; return test_case(invalues, inboundaries, outvalues, outboundaries, description); } - - Succeeded - uniform_test_case_1d(const char * const input, - const char * const description) - { + Succeeded uniform_test_case_1d(const char* const input, const char* const description) { std::istringstream s(input); VectorWithOffset invalues, outvalues; int instartindex, outstartindex, outendindex; float zoom, offset; char out[10000]; - s >> invalues - >> instartindex >> outstartindex >> outendindex - >> zoom >> offset - >> outvalues; + s >> invalues >> instartindex >> outstartindex >> outendindex >> zoom >> offset >> outvalues; invalues.set_min_index(instartindex); - VectorWithOffset inboundaries(invalues.get_min_index(), invalues.get_max_index()+1); - for (int i=inboundaries.get_min_index(); i<=inboundaries.get_max_index(); ++i) - inboundaries[i]=i-.5F; + VectorWithOffset inboundaries(invalues.get_min_index(), invalues.get_max_index() + 1); + for (int i = inboundaries.get_min_index(); i <= inboundaries.get_max_index(); ++i) + inboundaries[i] = i - .5F; outvalues.set_min_index(outstartindex); sprintf(out, "%s: inconsistent index sizes. Check test program", description); - if (!check_if_equal(outvalues.get_max_index(), outendindex-1, out)) - return Succeeded::no; + if (!check_if_equal(outvalues.get_max_index(), outendindex - 1, out)) + return Succeeded::no; VectorWithOffset outboundaries(outstartindex, outendindex); - for (int i=outboundaries.get_min_index(); i<=outboundaries.get_max_index(); ++i) - outboundaries[i]=(i-.5F)/zoom+offset; + for (int i = outboundaries.get_min_index(); i <= outboundaries.get_max_index(); ++i) + outboundaries[i] = (i - .5F) / zoom + offset; sprintf(out, "%s: test general overlap_interpolate", description); if (test_case(invalues, inboundaries, outvalues, outboundaries, out) == Succeeded::no) @@ -155,149 +124,146 @@ class overlap_interpolateTests : public RunTests return Succeeded::no; return Succeeded::yes; } - }; void -overlap_interpolateTests::run_tests() -{ +overlap_interpolateTests::run_tests() { std::cerr << "Tests for overlap_interpolate\n" - << "Everythings is fine if the program runs without any output." << std::endl; - + << "Everythings is fine if the program runs without any output." << std::endl; + set_tolerance(.0005); test_case_1d("{1,2.1,-3,4}" - "{2,3,4,5,6}" - "{1,2.1,-3,4}" - "{2,3,4,5,6}", - "equal boundaries"); + "{2,3,4,5,6}" + "{1,2.1,-3,4}" + "{2,3,4,5,6}", + "equal boundaries"); test_case_1d("{1.1,2,3,4.5}" - "{2,3,4,5,7}" - "{0,1.1,2,3,4.5}" - "{-1,2,3,4,5,7}", - "equal boundaries, but longer at start"); + "{2,3,4,5,7}" + "{0,1.1,2,3,4.5}" + "{-1,2,3,4,5,7}", + "equal boundaries, but longer at start"); test_case_1d("{1.1,2,3,4.5}" - "{2,3,4,5,7}" - "{1.1,2,3,4.5,0}" - "{2,3,4,5,7,10}", - "equal boundaries, but longer at end"); + "{2,3,4,5,7}" + "{1.1,2,3,4.5,0}" + "{2,3,4,5,7,10}", + "equal boundaries, but longer at end"); test_case_1d("{1.1,2,3,4.5}" - "{2,3,4,5,7}" - "{0,1.1,1.1,2,2,3,3,4.5,4.5,4.5,4.5}" - "{-1,2,2.5,3,3.3,4,4.8,5,5.1,5.2,5.6,7}", - "multiple out boxes in each in box"); + "{2,3,4,5,7}" + "{0,1.1,1.1,2,2,3,3,4.5,4.5,4.5,4.5}" + "{-1,2,2.5,3,3.3,4,4.8,5,5.1,5.2,5.6,7}", + "multiple out boxes in each in box"); test_case_1d("{1,5,2,16,7,4,2,4}" - "{-2,5,6,6.5,7,86,101,110,130}" - "{0.,0.2,1.,1.,1.,5.8,7.,7.,7.,6.53448,1.28421,0.,0.}" - "{-30,-4,-1.5,1,1.5,4,9,13,18,37,95,190,210,250}", - "arbitrary sizes case 1"); + "{-2,5,6,6.5,7,86,101,110,130}" + "{0.,0.2,1.,1.,1.,5.8,7.,7.,7.,6.53448,1.28421,0.,0.}" + "{-30,-4,-1.5,1,1.5,4,9,13,18,37,95,190,210,250}", + "arbitrary sizes case 1"); test_case_1d("{-1,2.5,2,1.6,7,-4,4}" - "{-2.1,5.2,6.3,6.5,7.6,7.8,11,11.7}" - "{-0.516667,-0.0416667,1.6,1.55556}" - "{-5,1,7,7.1,8}", - "arbitrary sizes case 2"); + "{-2.1,5.2,6.3,6.5,7.6,7.8,11,11.7}" + "{-0.516667,-0.0416667,1.6,1.55556}" + "{-5,1,7,7.1,8}", + "arbitrary sizes case 2"); test_case_1d("{-1,2.56,2,11.6,7.3,-4,4}" - "{-2.1,5.2,6.3,6.5,7.6,7.8,11,11.7}" - "{-0.0333333,-1.,-1.,-1.,-0.4304,4.10182,9.58333,-4.,-4.,-2.,0.,0.}" - "{-5,-2,0,1,3.1,5.6,6.7,7.9,8.3,8.9,11.7,13,15}", - "arbitrary sizes case 3"); + "{-2.1,5.2,6.3,6.5,7.6,7.8,11,11.7}" + "{-0.0333333,-1.,-1.,-1.,-0.4304,4.10182,9.58333,-4.,-4.,-2.,0.,0.}" + "{-5,-2,0,1,3.1,5.6,6.7,7.9,8.3,8.9,11.7,13,15}", + "arbitrary sizes case 3"); test_case_1d("{0.594221,0.932554,0.930552,0.479434,0.44984,0.426074,0.574378,\ 0.893291}" - "{0,0.0253037,0.889616,1.52744,2.47386,3.11161,3.56033,4.02598,4.94703}" - "{0.923744,0.930552,0.509265,0.457499,0.44984}" - "{0,0.995915,1.46923,2.34955,2.82987,2.96136}", - "random case 1"); + "{0,0.0253037,0.889616,1.52744,2.47386,3.11161,3.56033,4.02598,4.94703}" + "{0.923744,0.930552,0.509265,0.457499,0.44984}" + "{0,0.995915,1.46923,2.34955,2.82987,2.96136}", + "random case 1"); test_case_1d("{0.43649,0.236381,0.978282,0.537264,0.503936,0.305829,0.498848,\ 0.0874235}" - "{0,0.0778616,0.809312,1.41487,1.47699,1.69054,1.78416,2.4433,2.86767}" - "{0.256752,0.925738,0.493403,0.387417,0.0874235,0.00196432,0.,0.,0.}" - "{0,0.764837,1.3928,2.13089,2.55935,2.85087,3.59851,3.85628,4.15325,5.00828}",\ + "{0,0.0778616,0.809312,1.41487,1.47699,1.69054,1.78416,2.4433,2.86767}" + "{0.256752,0.925738,0.493403,0.387417,0.0874235,0.00196432,0.,0.,0.}" + "{0,0.764837,1.3928,2.13089,2.55935,2.85087,3.59851,3.85628,4.15325,5.00828}", - "random case 2"); + "random case 2"); test_case_1d("{0.511261,0.27949,0.759702,0.351098,0.205432,0.780642,0.672278,\ 0.273237}" - "{0,0.473981,0.649066,1.25922,1.31891,1.69927,2.21521,2.40101,2.69586}" - "{0.491445,0.577761,0.641911,0.672278,0.672278,0.29108,0.}" - "{0,0.75239,1.53024,2.28759,2.29091,2.29566,2.81574,3.27612}", - "random case 3"); + "{0,0.473981,0.649066,1.25922,1.31891,1.69927,2.21521,2.40101,2.69586}" + "{0.491445,0.577761,0.641911,0.672278,0.672278,0.29108,0.}" + "{0,0.75239,1.53024,2.28759,2.29091,2.29566,2.81574,3.27612}", + "random case 3"); test_case_1d("{0.148291,0.493487,0.240592,0.700675,0.797193,0.288055,0.459951,\ 0.0283963,0.523956}" - "{0,0.814074,1.09894,1.51718,1.98145,2.41516,3.18408,3.41653,3.58595,4.26728}\ + "{0,0.814074,1.09894,1.51718,1.98145,2.41516,3.18408,3.41653,3.58595,4.26728}\ " - "{0.209939,0.298013,0.559381,0.74738,0.40299,0.288055,0.288055}" - "{0,0.991066,1.46617,1.63226,2.30884,2.77983,2.79455,2.81236}", - "random case 4"); + "{0.209939,0.298013,0.559381,0.74738,0.40299,0.288055,0.288055}" + "{0,0.991066,1.46617,1.63226,2.30884,2.77983,2.79455,2.81236}", + "random case 4"); test_case_1d("{0.183092,0.230392,0.314051,0.220611,0.895037}" - "{0,0.770442,1.0561,1.75275,1.83371,2.31929}" - "{0.18838,0.246126,0.314051,0.633862,0.}" - "{0,0.867418,1.0998,1.74705,2.4637,3.09868}", - "random case 5"); + "{0,0.770442,1.0561,1.75275,1.83371,2.31929}" + "{0.18838,0.246126,0.314051,0.633862,0.}" + "{0,0.867418,1.0998,1.74705,2.4637,3.09868}", + "random case 5"); test_case_1d("{0.0629649,0.965917,0.72559,0.15987,0.89687,0.289338,0.254605,0.\ 145144}" - "{0,0.879067,0.985312,1.00953,1.84062,2.49907,2.71028,2.96405,3.50949}" - "{0.140638,0.410539,0.178698,0.861756,0.217232,0.0726656,0.,0.}" - "{0,0.961802,1.09205,1.86024,2.53826,3.26768,3.75068,3.80222,3.84527}", - "random case 6"); + "{0,0.879067,0.985312,1.00953,1.84062,2.49907,2.71028,2.96405,3.50949}" + "{0.140638,0.410539,0.178698,0.861756,0.217232,0.0726656,0.,0.}" + "{0,0.961802,1.09205,1.86024,2.53826,3.26768,3.75068,3.80222,3.84527}", + "random case 6"); test_case_1d("{0.666452,0.517083,0.32595,0.883177,0.769582,0.227745,0.0713446,\ 0.738033}" - "{0,0.890515,1.01201,1.05915,1.96609,2.19815,3.10844,3.9018,4.2633}" - "{0.666452,0.626473,0.687369}" - "{0,0.270258,1.0503,1.07547}", - "random case 7"); + "{0,0.890515,1.01201,1.05915,1.96609,2.19815,3.10844,3.9018,4.2633}" + "{0.666452,0.626473,0.687369}" + "{0,0.270258,1.0503,1.07547}", + "random case 7"); test_case_1d("{0.683484,0.540841,0.297046,0.973624,0.640437,0.874389,0.779963,\ 0.647674}" - "{0,0.75726,0.862067,1.41428,1.99061,2.00984,2.22413,2.65485,3.18405}" - "{0.683484,0.57681,0.557915,0.902686,0.701251,0.075033,0.,0.,0.}" - "{0,0.112286,1.09452,1.61495,2.35078,3.10157,3.81354,4.55392,5.2646,5.3319}", - "random case 8"); + "{0,0.75726,0.862067,1.41428,1.99061,2.00984,2.22413,2.65485,3.18405}" + "{0.683484,0.57681,0.557915,0.902686,0.701251,0.075033,0.,0.,0.}" + "{0,0.112286,1.09452,1.61495,2.35078,3.10157,3.81354,4.55392,5.2646,5.3319}", + "random case 8"); uniform_test_case_1d("{1,5,2,16,7,4,2,4}" - "-2 -2 6 1 0" - "{1.,5.,2.,16.,7.,4.,2.,4.}", - "uniform equal in and out"); + "-2 -2 6 1 0" + "{1.,5.,2.,16.,7.,4.,2.,4.}", + "uniform equal in and out"); uniform_test_case_1d("{1,5,2,16,7,4,2,4}" - "-2 -2 3 1 0" - "{1.,5.,2.,16.,7.}", - "uniform equal in and out, but short on right"); + "-2 -2 3 1 0" + "{1.,5.,2.,16.,7.}", + "uniform equal in and out, but short on right"); uniform_test_case_1d("{1,5,2,16,7,4,2,4}" - "-2 0 6 1 0" - "{2.,16.,7.,4.,2.,4.}", - "uniform equal in and out, but short on left"); + "-2 0 6 1 0" + "{2.,16.,7.,4.,2.,4.}", + "uniform equal in and out, but short on left"); uniform_test_case_1d("{1,5,2,16,7,4,2,4}" - "-2 0 10 1 0" - "{2.,16.,7.,4.,2.,4.,0.,0.,0.,0.}", - "uniform equal in and out, but short on left and long on right"); + "-2 0 10 1 0" + "{2.,16.,7.,4.,2.,4.,0.,0.,0.,0.}", + "uniform equal in and out, but short on left and long on right"); uniform_test_case_1d("{1,5,2,16,7,4,2,4}" - "-1 -3 5 1 0" - "{0.,0.,1.,5.,2.,16.,7.,4.}", - "uniform equal in and out, but long on left and short on right"); + "-1 -3 5 1 0" + "{0.,0.,1.,5.,2.,16.,7.,4.}", + "uniform equal in and out, but long on left and short on right"); uniform_test_case_1d("{1,5,2,16,7,4,2,4}" - "-2 0 10 1 -2" - "{1.,5.,2.,16.,7.,4.,2.,4.,0.,0.}", - "uniform equal in and out, offset only"); + "-2 0 10 1 -2" + "{1.,5.,2.,16.,7.,4.,2.,4.,0.,0.}", + "uniform equal in and out, offset only"); uniform_test_case_1d("{1,5,2,16,7,4,2,4}" - "-2 -1 10 0.3 -1" - "{0.,3.2,7.6,1.5,0.,0.,0.,0.,0.,0.,0.}", - "uniform test case 1"); + "-2 -1 10 0.3 -1" + "{0.,3.2,7.6,1.5,0.,0.,0.,0.,0.,0.,0.}", + "uniform test case 1"); uniform_test_case_1d("{1,5,2,16,7,4,2,4}" - "2 1 10 0.3 1.3" - "{7.88,3.42,0.,0.,0.,0.,0.,0.,0.}", - "uniform test case 2"); + "2 1 10 0.3 1.3" + "{7.88,3.42,0.,0.,0.,0.,0.,0.,0.}", + "uniform test case 2"); uniform_test_case_1d("{1,5,2,16,7,4,2,4}" - "-2 -3 10 2.5 -2.2" - "{0.,0.,0.25,1.,1.,4.,5.,4.25,2.,2.,12.5,16.,13.75}", - "uniform test case 3"); + "-2 -3 10 2.5 -2.2" + "{0.,0.,0.25,1.,1.,4.,5.,4.25,2.,2.,12.5,16.,13.75}", + "uniform test case 3"); } - END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { overlap_interpolateTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_ArcCorrection.cxx b/src/test/test_ArcCorrection.cxx index 17ef8e33c5..d747c06559 100644 --- a/src/test/test_ArcCorrection.cxx +++ b/src/test/test_ArcCorrection.cxx @@ -49,119 +49,100 @@ START_NAMESPACE_STIR - a geometry test to see that a point in a sinogram is arc-corrected to the correct location. - - a uniformity test that checks that uniform data are arc-corrected to + - a uniformity test that checks that uniform data are arc-corrected to uniform data with the same value. This is currently only done on sinograms and viewgrams. - The tests are performed both at the default arc-corrected bin-size, + The tests are performed both at the default arc-corrected bin-size, but also at twice as large bin-size. */ -class ArcCorrectionTests: public RunTests -{ +class ArcCorrectionTests : public RunTests { public: void run_tests(); + void run_tests_tof(); + protected: void run_tests_for_specific_proj_data_info(const ArcCorrection&); }; void -ArcCorrectionTests:: -run_tests_for_specific_proj_data_info(const ArcCorrection& arc_correction) -{ - const ProjDataInfoCylindricalArcCorr& proj_data_info_arc_corr = - arc_correction.get_arc_corrected_proj_data_info(); - const ProjDataInfoCylindricalNoArcCorr& proj_data_info_noarc_corr = - arc_correction.get_not_arc_corrected_proj_data_info(); +ArcCorrectionTests::run_tests_for_specific_proj_data_info(const ArcCorrection& arc_correction) { + const ProjDataInfoCylindricalArcCorr& proj_data_info_arc_corr = arc_correction.get_arc_corrected_proj_data_info(); + const ProjDataInfoCylindricalNoArcCorr& proj_data_info_noarc_corr = arc_correction.get_not_arc_corrected_proj_data_info(); const float sampling_in_s = proj_data_info_arc_corr.get_tangential_sampling(); - for (int segment_num=proj_data_info_noarc_corr.get_min_segment_num(); - segment_num<=proj_data_info_noarc_corr.get_max_segment_num(); - ++segment_num) - { - const int axial_pos_num = 0; - Sinogram noarccorr_sinogram = - proj_data_info_noarc_corr.get_empty_sinogram(axial_pos_num, segment_num); - Sinogram arccorr_sinogram = - proj_data_info_arc_corr.get_empty_sinogram(axial_pos_num, segment_num); - - for (int view_num=proj_data_info_noarc_corr.get_min_view_num(); - view_num<=proj_data_info_noarc_corr.get_max_view_num(); - view_num+=3) - { - Viewgram noarccorr_viewgram = - proj_data_info_noarc_corr.get_empty_viewgram(view_num, segment_num); - Viewgram arccorr_viewgram = - proj_data_info_arc_corr.get_empty_viewgram(view_num, segment_num); - // test geometry by checking if single non-zero value gets put in the right bin - { - for (int tangential_pos_num=proj_data_info_noarc_corr.get_min_tangential_pos_num(); - tangential_pos_num<=proj_data_info_noarc_corr.get_max_tangential_pos_num(); - tangential_pos_num+=4) - { - noarccorr_sinogram.fill(0); - noarccorr_viewgram.fill(0); - noarccorr_viewgram[axial_pos_num][tangential_pos_num]=1; - noarccorr_sinogram[view_num][tangential_pos_num]=1; - arc_correction.do_arc_correction(arccorr_sinogram, noarccorr_sinogram); - arc_correction.do_arc_correction(arccorr_viewgram, noarccorr_viewgram); - check_if_equal(noarccorr_sinogram[view_num], noarccorr_viewgram[axial_pos_num], - "1 line in sinogram and viewgram (geometric test)"); - const int arccorr_tangential_pos_num_at_max= - index_at_maximum(arccorr_viewgram[axial_pos_num]); - - const float noarccorr_s = - proj_data_info_noarc_corr. - get_s(Bin(segment_num,view_num,axial_pos_num,tangential_pos_num)); - const float arccorr_s = - proj_data_info_arc_corr. - get_s(Bin(segment_num,view_num,axial_pos_num,arccorr_tangential_pos_num_at_max)); - check((arccorr_s - noarccorr_s)/sampling_in_s < 1.1, - "correspondence in location of maximum after arc-correction"); - } - } - // test if uniformity and counts are preserved - { - /* We set a viewgram to 1, and check if the transformed viewgram is also 1 - (except at the boundary). - */ - noarccorr_sinogram.fill(1); - noarccorr_viewgram.fill(1); - arc_correction.do_arc_correction(arccorr_sinogram, noarccorr_sinogram); - arc_correction.do_arc_correction(arccorr_viewgram, noarccorr_viewgram); - check_if_equal(noarccorr_sinogram[view_num], noarccorr_viewgram[axial_pos_num], - "1 line in sinogram and viewgram (uniformity test)"); - - const float max_s = - proj_data_info_noarc_corr. - get_s(Bin(segment_num,view_num,axial_pos_num, - proj_data_info_noarc_corr.get_max_tangential_pos_num())); - const float min_s = - proj_data_info_noarc_corr. - get_s(Bin(segment_num,view_num,axial_pos_num, - proj_data_info_noarc_corr.get_min_tangential_pos_num())); - for (int tangential_pos_num= round(min_s/sampling_in_s)+2; - tangential_pos_num<=round(max_s/sampling_in_s)-2; - ++tangential_pos_num) - check_if_equal(arccorr_viewgram[axial_pos_num][tangential_pos_num], 1.F, - "uniformity"); - } - } + for (int timing_pos_num = proj_data_info_noarc_corr.get_min_tof_pos_num(); + timing_pos_num <= proj_data_info_noarc_corr.get_max_tof_pos_num(); ++timing_pos_num) + for (int segment_num = proj_data_info_noarc_corr.get_min_segment_num(); + segment_num <= proj_data_info_noarc_corr.get_max_segment_num(); ++segment_num) { + const int axial_pos_num = 0; + Sinogram noarccorr_sinogram = + proj_data_info_noarc_corr.get_empty_sinogram(axial_pos_num, segment_num, false, timing_pos_num); + Sinogram arccorr_sinogram = + proj_data_info_arc_corr.get_empty_sinogram(axial_pos_num, segment_num, false, timing_pos_num); + + for (int view_num = proj_data_info_noarc_corr.get_min_view_num(); view_num <= proj_data_info_noarc_corr.get_max_view_num(); + view_num += 3) { + Viewgram noarccorr_viewgram = + proj_data_info_noarc_corr.get_empty_viewgram(view_num, segment_num, false, timing_pos_num); + Viewgram arccorr_viewgram = + proj_data_info_arc_corr.get_empty_viewgram(view_num, segment_num, false, timing_pos_num); + // test geometry by checking if single non-zero value gets put in the right bin + { + for (int tangential_pos_num = proj_data_info_noarc_corr.get_min_tangential_pos_num(); + tangential_pos_num <= proj_data_info_noarc_corr.get_max_tangential_pos_num(); tangential_pos_num += 4) { + noarccorr_sinogram.fill(0); + noarccorr_viewgram.fill(0); + noarccorr_viewgram[axial_pos_num][tangential_pos_num] = 1; + noarccorr_sinogram[view_num][tangential_pos_num] = 1; + arc_correction.do_arc_correction(arccorr_sinogram, noarccorr_sinogram); + arc_correction.do_arc_correction(arccorr_viewgram, noarccorr_viewgram); + check_if_equal(noarccorr_sinogram[view_num], noarccorr_viewgram[axial_pos_num], + "1 line in sinogram and viewgram (geometric test)"); + const int arccorr_tangential_pos_num_at_max = index_at_maximum(arccorr_viewgram[axial_pos_num]); + + const float noarccorr_s = + proj_data_info_noarc_corr.get_s(Bin(segment_num, view_num, axial_pos_num, tangential_pos_num, timing_pos_num)); + const float arccorr_s = proj_data_info_arc_corr.get_s( + Bin(segment_num, view_num, axial_pos_num, arccorr_tangential_pos_num_at_max, timing_pos_num)); + check((arccorr_s - noarccorr_s) / sampling_in_s < 1.1, "correspondence in location of maximum after arc-correction"); + } + } + // test if uniformity and counts are preserved + { + /* We set a viewgram to 1, and check if the transformed viewgram is also 1 + (except at the boundary). + */ + noarccorr_sinogram.fill(1); + noarccorr_viewgram.fill(1); + arc_correction.do_arc_correction(arccorr_sinogram, noarccorr_sinogram); + arc_correction.do_arc_correction(arccorr_viewgram, noarccorr_viewgram); + check_if_equal(noarccorr_sinogram[view_num], noarccorr_viewgram[axial_pos_num], + "1 line in sinogram and viewgram (uniformity test)"); + + const float max_s = proj_data_info_noarc_corr.get_s( + Bin(segment_num, view_num, axial_pos_num, proj_data_info_noarc_corr.get_max_tangential_pos_num())); + const float min_s = proj_data_info_noarc_corr.get_s( + Bin(segment_num, view_num, axial_pos_num, proj_data_info_noarc_corr.get_min_tangential_pos_num())); + for (int tangential_pos_num = round(min_s / sampling_in_s) + 2; tangential_pos_num <= round(max_s / sampling_in_s) - 2; + ++tangential_pos_num) + check_if_equal(arccorr_viewgram[axial_pos_num][tangential_pos_num], 1.F, "uniformity"); + } } + } } - void -ArcCorrectionTests::run_tests() -{ +ArcCorrectionTests::run_tests() { cerr << "-------- Testing ArcCorrection --------\n"; ArcCorrection arc_correction; shared_ptr scanner_ptr(new Scanner(Scanner::E962)); - - shared_ptr proj_data_info_ptr( - ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - /*span*/7, 10,/*views*/ 96, /*tang_pos*/128, /*arc_corrected*/ false)); + + shared_ptr proj_data_info_ptr(ProjDataInfo::ProjDataInfoCTI(scanner_ptr, + /*span*/ 7, 10, /*views*/ 96, /*tang_pos*/ 128, + /*arc_corrected*/ false)); cerr << "Using default range and bin-size\n"; { arc_correction.set_up(proj_data_info_ptr); @@ -169,21 +150,41 @@ ArcCorrectionTests::run_tests() } cerr << "Using non-default range and bin-size\n"; { - arc_correction.set_up(proj_data_info_ptr, - 128, - scanner_ptr->get_default_bin_size()*2); + arc_correction.set_up(proj_data_info_ptr, 128, scanner_ptr->get_default_bin_size() * 2); run_tests_for_specific_proj_data_info(arc_correction); } } -END_NAMESPACE_STIR +void +ArcCorrectionTests::run_tests_tof() { + cerr << "-------- Testing ArcCorrection for TOF scanner --------\n"; + ArcCorrection arc_correction; + shared_ptr scanner_ptr(new Scanner(Scanner::PETMR_Signa)); + + shared_ptr proj_data_info_ptr(ProjDataInfo::ProjDataInfoGE(scanner_ptr, + /*max_delta*/ 5, /*views*/ 112, /*tang_pos*/ 357, + /*arc_corrected*/ false, /*tof_mashing_factor*/ 116)); + cerr << "Using default range and bin-size\n"; + { + arc_correction.set_up(proj_data_info_ptr); + run_tests_for_specific_proj_data_info(arc_correction); + } + cerr << "Using non-default range and bin-size\n"; + { + arc_correction.set_up(proj_data_info_ptr, 357, scanner_ptr->get_default_bin_size() * 2); + run_tests_for_specific_proj_data_info(arc_correction); + } +} + +END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { ArcCorrectionTests tests; tests.run_tests(); + tests.run_tests_tof(); return tests.main_return_value(); } diff --git a/src/test/test_Array.cxx b/src/test/test_Array.cxx index b738173bd1..80c6ed1905 100644 --- a/src/test/test_Array.cxx +++ b/src/test/test_Array.cxx @@ -19,10 +19,10 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup test \ingroup Array - + \brief tests for the stir::Array class \author Kris Thielemans @@ -31,10 +31,10 @@ #ifndef NDEBUG // set to high level of debugging -#ifdef _DEBUG -#undef _DEBUG -#endif -#define _DEBUG 2 +# ifdef _DEBUG +# undef _DEBUG +# endif +# define _DEBUG 2 #endif #include "stir/Array.h" @@ -73,211 +73,195 @@ START_NAMESPACE_STIR namespace detail { - static Array<2,float> test_make_array() - { - return - make_array(make_1d_array(1.F,0.F,0.F), - make_1d_array(0.F,1.F,1.F), - make_1d_array(0.F,-2.F,2.F)); - } +static Array<2, float> +test_make_array() { + return make_array(make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, 1.F, 1.F), make_1d_array(0.F, -2.F, 2.F)); } +} // namespace detail /*! \brief Tests Array functionality \ingroup test - \warning Running this will create and delete 2 files with names + \warning Running this will create and delete 2 files with names output.flt and output.other. Existing files with these names will be overwritten. */ -class ArrayTests : public RunTests -{ +class ArrayTests : public RunTests { private: // this function tests the next() function and compare it to using full_iterators // sadly needs to be declared in the class for VC 6.0 template - void - run_tests_on_next(const Array& test) - { + void run_tests_on_next(const Array& test) { // exit if empty array (as do..while() loop would fail) if (test.size() == 0) return; - BasicCoordinate index = get_min_indices(test); + BasicCoordinate index = get_min_indices(test); typename Array::const_full_iterator iter = test.begin_all(); - do - { - check(*iter == test[index], "test on next(): element out of sequence?"); - ++iter; - } - while (next(index, test) && (iter != test.end_all())); - check (iter == test.end_all(), "test on next() : did we cover all elements?"); + do { + check(*iter == test[index], "test on next(): element out of sequence?"); + ++iter; + } while (next(index, test) && (iter != test.end_all())); + check(iter == test.end_all(), "test on next() : did we cover all elements?"); } // functions that runs IO tests for an array of arbitrary dimension // sadly needs to be declared in the class for VC 6.0 template - void run_IO_tests(const Array&t1) - { + void run_IO_tests(const Array& t1) { std::fstream os; std::fstream is; - run_IO_tests_with_file_args(os, is, t1); + run_IO_tests_with_file_args(os, is, t1); FILE* ofptr; FILE* ifptr; - run_IO_tests_with_file_args(ofptr, is, t1); - run_IO_tests_with_file_args(ofptr, ifptr, t1); + run_IO_tests_with_file_args(ofptr, is, t1); + run_IO_tests_with_file_args(ofptr, ifptr, t1); } - template - void run_IO_tests_with_file_args(OFSTREAM& os, IFSTREAM& is, const Array&t1) - { + template + void run_IO_tests_with_file_args(OFSTREAM& os, IFSTREAM& is, const Array& t1) { { open_write_binary(os, "output.flt"); - check(write_data(os,t1)==Succeeded::yes, "write_data could not write array"); + check(write_data(os, t1) == Succeeded::yes, "write_data could not write array"); close_file(os); } - Array t2(t1.get_index_range()); + Array t2(t1.get_index_range()); { open_read_binary(is, "output.flt"); - check(read_data(is,t2)==Succeeded::yes, "read_data could not read from output.flt"); + check(read_data(is, t2) == Succeeded::yes, "read_data could not read from output.flt"); close_file(is); } - check_if_equal(t1 ,t2, "test out/in" ); + check_if_equal(t1, t2, "test out/in"); remove("output.flt"); { open_write_binary(os, "output.flt"); - const Array copy=t1; - check(write_data(os,t1,ByteOrder::swapped)==Succeeded::yes, "write_data could not write array with swapped byte order"); - check_if_equal(t1 ,copy, "test out with byte-swapping didn't change the array" ); + const Array copy = t1; + check(write_data(os, t1, ByteOrder::swapped) == Succeeded::yes, "write_data could not write array with swapped byte order"); + check_if_equal(t1, copy, "test out with byte-swapping didn't change the array"); close_file(os); } { open_read_binary(is, "output.flt"); - check(read_data(is,t2,ByteOrder::swapped)==Succeeded::yes, "read_data could not read from output.flt"); + check(read_data(is, t2, ByteOrder::swapped) == Succeeded::yes, "read_data could not read from output.flt"); close_file(is); } - check_if_equal(t1 ,t2, "test out/in (swapped byte order)" ); + check_if_equal(t1, t2, "test out/in (swapped byte order)"); remove("output.flt"); - cerr <<"\tTests writing as shorts\n"; + cerr << "\tTests writing as shorts\n"; run_IO_tests_mixed(os, is, t1, NumericInfo()); - cerr <<"\tTests writing as floats\n"; + cerr << "\tTests writing as floats\n"; run_IO_tests_mixed(os, is, t1, NumericInfo()); - cerr <<"\tTests writing as signed chars\n"; + cerr << "\tTests writing as signed chars\n"; run_IO_tests_mixed(os, is, t1, NumericInfo()); - /* check on failed IO. Note: needs to be after the others, as we would have to call os.clear() for ostream to be able to write again, but that's not defined for FILE*. */ { - const Array copy=t1; + const Array copy = t1; cerr << "\n\tYou should now see a warning that writing failed. That's by intention.\n"; - check(write_data(os,t1,ByteOrder::swapped)!=Succeeded::yes, "write_data with swapped byte order should have failed"); - check_if_equal(t1 ,copy, "test out with byte-swapping didn't change the array even with failed IO" ); + check(write_data(os, t1, ByteOrder::swapped) != Succeeded::yes, "write_data with swapped byte order should have failed"); + check_if_equal(t1, copy, "test out with byte-swapping didn't change the array even with failed IO"); } - } //! function that runs IO tests with mixed types for array of arbitrary dimension // sadly needs to be implemented in the class for VC 6.0 template - void run_IO_tests_mixed(OFSTREAM& os, IFSTREAM& is, const Array&orig, NumericInfo output_type_info) + void run_IO_tests_mixed(OFSTREAM& os, IFSTREAM& is, const Array& orig, + NumericInfo output_type_info) { { - { - open_write_binary(os, "output.orig"); - elemT scale(1); - check(write_data(os, orig, NumericInfo(), scale)==Succeeded::yes, "write_data could not write array in original data type"); - close_file(os); - check_if_equal(scale ,static_cast(1), "test out/in: data written in original data type: scale factor should be 1" ); - } + open_write_binary(os, "output.orig"); elemT scale(1); - bool write_data_ok; + check(write_data(os, orig, NumericInfo(), scale) == Succeeded::yes, + "write_data could not write array in original data type"); + close_file(os); + check_if_equal(scale, static_cast(1), "test out/in: data written in original data type: scale factor should be 1"); + } + elemT scale(1); + bool write_data_ok; + { + ofstream os; + open_write_binary(os, "output.other"); + write_data_ok = check(write_data(os, orig, output_type_info, scale) == Succeeded::yes, + "write_data could not write array as other_type"); + close_file(os); + } + + if (write_data_ok) { + // only do reading test if data was written + Array data_read_back(orig.get_index_range()); { - ofstream os; - open_write_binary(os, "output.other"); - write_data_ok=check(write_data(os,orig, output_type_info, scale)==Succeeded::yes, "write_data could not write array as other_type"); - close_file(os); + open_read_binary(is, "output.other"); + check(read_data(is, data_read_back) == Succeeded::yes, "read_data could not read from output.other"); + close_file(is); + remove("output.other"); } - if (write_data_ok) - { - // only do reading test if data was written - Array data_read_back(orig.get_index_range()); - { - open_read_binary(is, "output.other"); - check(read_data(is, data_read_back)==Succeeded::yes, "read_data could not read from output.other"); - close_file(is); - remove("output.other"); - } - - // compare with convert() - { - float newscale = static_cast(scale); - Array origconverted = - convert_array(newscale, orig, NumericInfo()); - check_if_equal(newscale ,scale, "test read_data <-> convert : scale factor "); - check_if_equal(origconverted ,data_read_back, "test read_data <-> convert : data"); - } + // compare with convert() + { + float newscale = static_cast(scale); + Array origconverted = convert_array(newscale, orig, NumericInfo()); + check_if_equal(newscale, scale, "test read_data <-> convert : scale factor "); + check_if_equal(origconverted, data_read_back, "test read_data <-> convert : data"); + } - // compare orig/scale with data_read_back - { - const Array orig_scaled(orig/scale); - this->check_array_equality_with_rounding(orig_scaled, data_read_back, - "test out/in: data written as other_type, read as other_type"); - } + // compare orig/scale with data_read_back + { + const Array orig_scaled(orig / scale); + this->check_array_equality_with_rounding(orig_scaled, data_read_back, + "test out/in: data written as other_type, read as other_type"); + } - // compare data written as original, but read as other_type - { - Array data_read_back2(orig.get_index_range()); - - ifstream is; - open_read_binary(is, "output.orig"); - - elemT in_scale = 0; - check(read_data(is, data_read_back2, NumericInfo(), in_scale)==Succeeded::yes, "read_data could not read from output.orig"); - // compare orig/in_scale with data_read_back2 - const Array orig_scaled(orig/in_scale); - this->check_array_equality_with_rounding(orig_scaled, data_read_back2, - "test out/in: data written as original_type, read as other_type"); - } - } // end of if(write_data_ok) - remove("output.orig"); - } + // compare data written as original, but read as other_type + { + Array data_read_back2(orig.get_index_range()); + + ifstream is; + open_read_binary(is, "output.orig"); + + elemT in_scale = 0; + check(read_data(is, data_read_back2, NumericInfo(), in_scale) == Succeeded::yes, + "read_data could not read from output.orig"); + // compare orig/in_scale with data_read_back2 + const Array orig_scaled(orig / in_scale); + this->check_array_equality_with_rounding(orig_scaled, data_read_back2, + "test out/in: data written as original_type, read as other_type"); + } + } // end of if(write_data_ok) + remove("output.orig"); + } //! a special version of check_if_equal just for this class /*! we check up to .5 if output_type is integer, and up to tolerance otherwise */ template - bool check_array_equality_with_rounding(const Array& orig, const Array& data_read_back, const char*const message) - { + bool check_array_equality_with_rounding(const Array& orig, + const Array& data_read_back, const char* const message) { NumericInfo output_type_info; - bool test_failed=false; - typename Array::const_full_iterator diff_iter = orig.begin_all(); - typename Array::const_full_iterator data_read_back_iter = data_read_back.begin_all_const(); - while(diff_iter!=orig.end_all()) - { - if (output_type_info.integer_type()) - { - std::stringstream full_message; - // construct useful error message even though we use a boolean check - full_message << boost::format("unequal values are %2% and %3%. %1%: difference larger than .5") - % message % static_cast(*data_read_back_iter) % *diff_iter; - // difference should be maximum .5 (but we test with slightly larger tolerance to accomodate numerical precision) - test_failed = check(fabs(*diff_iter - *data_read_back_iter)<=.502, - full_message.str().c_str()); - } - else - { - std::string full_message = message; - full_message += ": difference larger than tolerance"; - test_failed = check_if_equal(static_cast(*data_read_back_iter), *diff_iter, - full_message.c_str()); - } - if (test_failed) - break; - diff_iter++; data_read_back_iter++; + bool test_failed = false; + typename Array::const_full_iterator diff_iter = orig.begin_all(); + typename Array::const_full_iterator data_read_back_iter = data_read_back.begin_all_const(); + while (diff_iter != orig.end_all()) { + if (output_type_info.integer_type()) { + std::stringstream full_message; + // construct useful error message even though we use a boolean check + full_message << boost::format("unequal values are %2% and %3%. %1%: difference larger than .5") % message % + static_cast(*data_read_back_iter) % *diff_iter; + // difference should be maximum .5 (but we test with slightly larger tolerance to accomodate numerical precision) + test_failed = check(fabs(*diff_iter - *data_read_back_iter) <= .502, full_message.str().c_str()); + } else { + std::string full_message = message; + full_message += ": difference larger than tolerance"; + test_failed = check_if_equal(static_cast(*data_read_back_iter), *diff_iter, full_message.c_str()); } + if (test_failed) + break; + diff_iter++; + data_read_back_iter++; + } return test_failed; } @@ -285,105 +269,107 @@ class ArrayTests : public RunTests void run_tests(); }; - void -ArrayTests::run_tests() -{ +ArrayTests::run_tests() { cerr << "Testing Array classes\n"; { cerr << "Testing 1D stuff" << endl; { - - Array<1,int> testint(IndexRange<1>(5)); + + Array<1, int> testint(IndexRange<1>(5)); testint[0] = 2; check_if_equal(testint.size(), size_t(5), "test size()"); check_if_equal(testint.size_all(), size_t(5), "test size_all()"); - Array<1,float> test(IndexRange<1>(10)); + Array<1, float> test(IndexRange<1>(10)); check_if_zero(test, "Array1D not initialised to 0"); test[1] = (float)10.5; test.set_offset(-1); check_if_equal(test.size(), size_t(10), "test size() with non-zero offset"); check_if_equal(test.size_all(), size_t(10), "test size_all() with non-zero offset"); - check_if_equal( test[0], 10.5F, "test indexing of Array1D"); + check_if_equal(test[0], 10.5F, "test indexing of Array1D"); test += 1; - check_if_equal( test[0] , 11.5F, "test operator+=(float)"); - check_if_equal( test.sum(), 20.5F, "test operator+=(float) and sum()"); - check_if_zero( test - test, "test operator-(Array1D)"); + check_if_equal(test[0], 11.5F, "test operator+=(float)"); + check_if_equal(test.sum(), 20.5F, "test operator+=(float) and sum()"); + check_if_zero(test - test, "test operator-(Array1D)"); - BasicCoordinate<1,int> c; - c[1]=0; - check_if_equal(test[c] , 11.5F , "test operator[](BasicCoordinate)"); + BasicCoordinate<1, int> c; + c[1] = 0; + check_if_equal(test[c], 11.5F, "test operator[](BasicCoordinate)"); test[c] = 12.5; - check_if_equal(test[c] , 12.5F , "test operator[](BasicCoordinate)"); + check_if_equal(test[c], 12.5F, "test operator[](BasicCoordinate)"); { - Array<1,float> ref(-1,2); - ref[-1]=1.F;ref[0]=3.F;ref[1]=3.14F; - Array<1,float> test = ref; + Array<1, float> ref(-1, 2); + ref[-1] = 1.F; + ref[0] = 3.F; + ref[1] = 3.14F; + Array<1, float> test = ref; test += 1; - for (int i=ref.get_min_index(); i<= ref.get_max_index(); ++i) - check_if_equal( test[i] , ref[i]+1, "test operator+=(float)"); - test = ref; test -= 4; - for (int i=ref.get_min_index(); i<= ref.get_max_index(); ++i) - check_if_equal( test[i] , ref[i]-4, "test operator-=(float)"); - test = ref; test *= 3; - for (int i=ref.get_min_index(); i<= ref.get_max_index(); ++i) - check_if_equal( test[i] , ref[i]*3, "test operator*=(float)"); - test = ref; test /= 3; - for (int i=ref.get_min_index(); i<= ref.get_max_index(); ++i) - check_if_equal( test[i] , ref[i]/3, "test operator/=(float)"); + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], ref[i] + 1, "test operator+=(float)"); + test = ref; + test -= 4; + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], ref[i] - 4, "test operator-=(float)"); + test = ref; + test *= 3; + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], ref[i] * 3, "test operator*=(float)"); + test = ref; + test /= 3; + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], ref[i] / 3, "test operator/=(float)"); } { - Array<1,float> test2; + Array<1, float> test2; test2 = test * 2; - check_if_equal( 2*test[0] , test2[0], "test operator*(float)"); + check_if_equal(2 * test[0], test2[0], "test operator*(float)"); } { - Array<1,float> test2 = test; - test.grow(-2,test.get_max_index()); - Array<1,float> test3 = test2 + test; + Array<1, float> test2 = test; + test.grow(-2, test.get_max_index()); + Array<1, float> test3 = test2 + test; check_if_zero(test3[-2], "test growing during operator+"); } - } -#if 1 +#if 1 { // tests on log/exp - Array<1,float> test(-3,10); + Array<1, float> test(-3, 10); test.fill(1.F); in_place_log(test); { - Array<1,float> testeq(-3,10); - check_if_equal(test , testeq, "test in_place_log of Array1D"); + Array<1, float> testeq(-3, 10); + check_if_equal(test, testeq, "test in_place_log of Array1D"); } { - for (int i=test.get_min_index(); i<= test.get_max_index(); i++) - test[i] = 3.5F*i + 100; + for (int i = test.get_min_index(); i <= test.get_max_index(); i++) + test[i] = 3.5F * i + 100; } - Array<1,float> test_copy = test; + Array<1, float> test_copy = test; in_place_log(test); in_place_exp(test); - check_if_equal(test , test_copy, "test log/exp of Array1D"); + check_if_equal(test, test_copy, "test log/exp of Array1D"); } #endif } - + { cerr << "Testing 2D stuff" << endl; { - const IndexRange<2> range(Coordinate2D(0,0),Coordinate2D(9,9)); - Array<2,float> test2(range); + const IndexRange<2> range(Coordinate2D(0, 0), Coordinate2D(9, 9)); + Array<2, float> test2(range); check_if_equal(test2.size(), size_t(10), "test size()"); check_if_equal(test2.size_all(), size_t(100), "test size_all()"); // KT 17/03/98 added check on initialisation - check_if_zero(test2, "test Array<2,float> not initialised to 0" ); + check_if_zero(test2, "test Array<2,float> not initialised to 0"); #if 0 // KT 06/04/98 removed operator() @@ -391,15 +377,14 @@ ArrayTests::run_tests() #else test2[3][4] = (float)23.3; #endif - //test2.set_offsets(-1,-4); - //check_if_equal( test2[2][0] , 23.3, "test indexing of Array2D"); + // test2.set_offsets(-1,-4); + // check_if_equal( test2[2][0] , 23.3, "test indexing of Array2D"); } - { - IndexRange<2> range(Coordinate2D(0,0),Coordinate2D(3,3)); - Array<2,float> testfp(range); - Array<2,float> t2fp(range); + IndexRange<2> range(Coordinate2D(0, 0), Coordinate2D(3, 3)); + Array<2, float> testfp(range); + Array<2, float> t2fp(range); #if 0 // KT 06/04/98 removed operator() testfp(3,2) = 3.3F; @@ -409,123 +394,117 @@ ArrayTests::run_tests() t2fp[3][2] = 2.2F; #endif - Array<2,float> t2 = t2fp + testfp; - check_if_equal( t2[3][2] , 5.5F, "test operator +(Array2D)"); + Array<2, float> t2 = t2fp + testfp; + check_if_equal(t2[3][2], 5.5F, "test operator +(Array2D)"); t2fp += testfp; - check_if_equal( t2fp[3][2] , 5.5F, "test operator +=(Array2D)"); - check_if_equal(t2 , t2fp, "test comparing Array2D+= and +" ); + check_if_equal(t2fp[3][2], 5.5F, "test operator +=(Array2D)"); + check_if_equal(t2, t2fp, "test comparing Array2D+= and +"); - { - BasicCoordinate<2,int> c; - c[1]=3; c[2]=2; - check_if_equal(t2[c], 5.5F, "test on operator[](BasicCoordinate)"); + { + BasicCoordinate<2, int> c; + c[1] = 3; + c[2] = 2; + check_if_equal(t2[c], 5.5F, "test on operator[](BasicCoordinate)"); t2[c] = 6.; - check_if_equal(t2[c], 6.F, "test on operator[](BasicCoordinate)"); + check_if_equal(t2[c], 6.F, "test on operator[](BasicCoordinate)"); } // assert should break on next line (in Debug build) if uncommented - //t2[-4][3]=1.F; + // t2[-4][3]=1.F; // at() should throw error { - bool exception_thrown=false; - try - { - t2.at(-4).at(3); - } - catch (...) - { - exception_thrown=true; - } + bool exception_thrown = false; + try { + t2.at(-4).at(3); + } catch (...) { + exception_thrown = true; + } check(exception_thrown, "out-of-range index should throw an exception"); } - - //t2.grow_height(-5,5); - IndexRange<2> larger_range(Coordinate2D(-5,0),Coordinate2D(5,3)); + + // t2.grow_height(-5,5); + IndexRange<2> larger_range(Coordinate2D(-5, 0), Coordinate2D(5, 3)); t2.grow(larger_range); - t2[-4][3]=1.F; - check_if_equal( t2[3][2] , 6.F, "test on grow"); - + t2[-4][3] = 1.F; + check_if_equal(t2[3][2], 6.F, "test on grow"); + // test assignment t2fp = t2; - check_if_equal(t2 , t2fp, "test operator=(Array2D)" ); + check_if_equal(t2, t2fp, "test operator=(Array2D)"); { - Array<2,float> tmp; + Array<2, float> tmp; tmp = t2 / 2; - check_if_equal( t2.sum()/2 , tmp.sum(), "test operator/(float)"); + check_if_equal(t2.sum() / 2, tmp.sum(), "test operator/(float)"); } { // copy constructor; - Array<2,float> t21(t2); - check_if_equal(t21 , t2, "test Array2D copy constructor" ); + Array<2, float> t21(t2); + check_if_equal(t21, t2, "test Array2D copy constructor"); // 'assignment constructor' (this simply calls copy constructor) - Array<2,float> t22 = t2; - check_if_equal(t22 , t2, "test Array2D copy constructor" ); + Array<2, float> t22 = t2; + check_if_equal(t22, t2, "test Array2D copy constructor"); } } // size_all with irregular range { - const IndexRange<2> range(Coordinate2D(-1,1),Coordinate2D(1,2)); - Array<2,float> test2(range); + const IndexRange<2> range(Coordinate2D(-1, 1), Coordinate2D(1, 2)); + Array<2, float> test2(range); check(test2.is_regular(), "test is_regular() with regular"); check_if_equal(test2.size(), size_t(3), "test size() with non-zero offset"); - check_if_equal(test2.size_all(), size_t(6), "test size_all() with non-zero offset"); - test2[0].resize(-1,2); + check_if_equal(test2.size_all(), size_t(6), "test size_all() with non-zero offset"); + test2[0].resize(-1, 2); check(!test2.is_regular(), "test is_regular() with irregular"); check_if_equal(test2.size(), size_t(3), "test size() with irregular range"); - check_if_equal(test2.size_all(), size_t(6+2), "test size_all() with irregular range"); + check_if_equal(test2.size_all(), size_t(6 + 2), "test size_all() with irregular range"); } // full iterator { - IndexRange<2> range(Coordinate2D(0,0),Coordinate2D(2,2)); - Array<2,float> test2(range); + IndexRange<2> range(Coordinate2D(0, 0), Coordinate2D(2, 2)); + Array<2, float> test2(range); { float value = 1.2F; - for (Array<2,float>::full_iterator iter = test2.begin_all(); - iter != test2.end_all(); - ) + for (Array<2, float>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) *iter++ = value++; } { float value = 1.2F; - Array<2,float>::const_full_iterator iter = test2.begin_all_const(); - for (int i=test2.get_min_index(); i<= test2.get_max_index(); ++i) - for (int j=test2[i].get_min_index(); j<= test2[i].get_max_index(); ++j) - { - check(iter != test2.end_all_const(), "test on 2D full iterator"); - check_if_equal(*iter++, test2[i][j], "test on 2D full iterator vs. index"); - check_if_equal(test2[i][j], value++, "test on 2D full iterator value"); - } + Array<2, float>::const_full_iterator iter = test2.begin_all_const(); + for (int i = test2.get_min_index(); i <= test2.get_max_index(); ++i) + for (int j = test2[i].get_min_index(); j <= test2[i].get_max_index(); ++j) { + check(iter != test2.end_all_const(), "test on 2D full iterator"); + check_if_equal(*iter++, test2[i][j], "test on 2D full iterator vs. index"); + check_if_equal(test2[i][j], value++, "test on 2D full iterator value"); + } } - const Array<2,float> empty; + const Array<2, float> empty; check(empty.begin_all() == empty.end_all(), "test on 2D full iterator for empty range"); } // tests for next() { - const IndexRange<2> range(Coordinate2D(-1,1),Coordinate2D(1,2)); - Array<2,int> test(range); + const IndexRange<2> range(Coordinate2D(-1, 1), Coordinate2D(1, 2)); + Array<2, int> test(range); // fill array with numbers in sequence { - Array<2,int>::full_iterator iter = test.begin_all(); - for (int i=0; iter!= test.end_all(); ++iter, ++i) - { - *iter = i; - } + Array<2, int>::full_iterator iter = test.begin_all(); + for (int i = 0; iter != test.end_all(); ++iter, ++i) { + *iter = i; + } } std::cerr << "\tTest on next() with regular array\n"; this->run_tests_on_next(test); // now do test with irregular array - test[0].resize(0,2); + test[0].resize(0, 2); test[0][2] = 10; std::cerr << "\tTest on next() with irregular array, case 1\n"; this->run_tests_on_next(test); - test[1].resize(-2,2); + test[1].resize(-2, 2); test[1][-2] = 20; std::cerr << "\tTest on next() with irregular array, case 2\n"; this->run_tests_on_next(test); - test[-1].resize(-2,0); + test[-1].resize(-2, 0); test[-1][-2] = 30; std::cerr << "\tTest on next() with irregular array, case 3\n"; this->run_tests_on_next(test); @@ -535,8 +514,8 @@ ArrayTests::run_tests() { cerr << "Testing 3D stuff" << endl; - IndexRange<3> range(Coordinate3D(0,-1,1),Coordinate3D(3,3,3)); - Array<3,float> test3(range); + IndexRange<3> range(Coordinate3D(0, -1, 1), Coordinate3D(3, 3, 3)); + Array<3, float> test3(range); check_if_equal(test3.size(), size_t(4), "test size()"); check_if_equal(test3.size_all(), size_t(60), "test size_all() with non-zero offset"); // KT 06/04/98 removed operator() @@ -548,76 +527,73 @@ ArrayTests::run_tests() test3[1][0][2] = (float)7.3; test3[1][0][1] = -1; - - check_if_equal( test3.sum() , 12.9F, "test on sum"); - check_if_equal( test3.find_max() , 7.3F, "test on find_max"); - check_if_equal( test3.find_min() , -1.F, "test on find_min"); + check_if_equal(test3.sum(), 12.9F, "test on sum"); + check_if_equal(test3.find_max(), 7.3F, "test on find_max"); + check_if_equal(test3.find_min(), -1.F, "test on find_min"); { - Array<3,float> test3copy(test3); - BasicCoordinate<3,int> c; - c[1]=1; c[2]=0; c[3]=2; - check_if_equal(test3[c], 7.3F, "test on operator[](BasicCoordinate)"); - test3copy[c]=8.; - check_if_equal(test3copy[1][0][2], 8.F, "test on operator[](BasicCoordinate)"); + Array<3, float> test3copy(test3); + BasicCoordinate<3, int> c; + c[1] = 1; + c[2] = 0; + c[3] = 2; + check_if_equal(test3[c], 7.3F, "test on operator[](BasicCoordinate)"); + test3copy[c] = 8.; + check_if_equal(test3copy[1][0][2], 8.F, "test on operator[](BasicCoordinate)"); } - Array<3,float> test3bis(range); + Array<3, float> test3bis(range); test3bis[1][2][1] = (float)6.6; test3bis[1][0][1] = (float)1.3; - Array<3,float> test3ter = test3bis; + Array<3, float> test3ter = test3bis; test3ter += test3; - check_if_equal(test3ter[1][0][1] , .3F, "test on operator+=(Array3D)"); + check_if_equal(test3ter[1][0][1], .3F, "test on operator+=(Array3D)"); - Array<3,float> test3quat = test3 + test3bis; - check_if_equal(test3quat , test3ter, "test summing Array3D"); + Array<3, float> test3quat = test3 + test3bis; + check_if_equal(test3quat, test3ter, "test summing Array3D"); { - Array<3,float> tmp= test3 - 2; - Array<3,float> tmp2 = test3; + Array<3, float> tmp = test3 - 2; + Array<3, float> tmp2 = test3; tmp2.fill(1.F); - - check_if_zero( test3.sum() - 2*tmp2.sum() - tmp.sum(), "test operator-(float)"); + + check_if_zero(test3.sum() - 2 * tmp2.sum() - tmp.sum(), "test operator-(float)"); } -#if !defined(_MSC_VER) || _MSC_VER>1300 +#if !defined(_MSC_VER) || _MSC_VER > 1300 // VC 6.0 cannot compile this in_place_apply_function(test3ter, bind2nd(plus(), 4.F)); test3quat += 4.F; - check_if_equal(test3quat , test3ter, - "test in_place_apply_function and operator+=(NUMBER)"); + check_if_equal(test3quat, test3ter, "test in_place_apply_function and operator+=(NUMBER)"); #endif // size_all with irregular range { - const IndexRange<3> range(Coordinate3D(-1,1,4),Coordinate3D(1,2,6)); - Array<3,float> test(range); + const IndexRange<3> range(Coordinate3D(-1, 1, 4), Coordinate3D(1, 2, 6)); + Array<3, float> test(range); check(test.is_regular(), "test is_regular() with regular"); check_if_equal(test.size(), size_t(3), "test size() with non-zero offset"); - check_if_equal(test.size_all(), size_t(3*2*3), "test size_all() with non-zero offset"); - test[0][1].resize(-1,2); + check_if_equal(test.size_all(), size_t(3 * 2 * 3), "test size_all() with non-zero offset"); + test[0][1].resize(-1, 2); check(!test.is_regular(), "test is_regular() with irregular"); check_if_equal(test.size(), size_t(3), "test size() with irregular range"); - check_if_equal(test.size_all(), size_t(3*2*3+4-3), "test size_all() with irregular range"); + check_if_equal(test.size_all(), size_t(3 * 2 * 3 + 4 - 3), "test size_all() with irregular range"); } // full iterator { - IndexRange<3> range(Coordinate3D(0,0,1),Coordinate3D(2,2,3)); - Array<3,float> test(range); + IndexRange<3> range(Coordinate3D(0, 0, 1), Coordinate3D(2, 2, 3)); + Array<3, float> test(range); { float value = 1.2F; - for (Array<3,float>::full_iterator iter = test.begin_all(); - iter != test.end_all(); - ) + for (Array<3, float>::full_iterator iter = test.begin_all(); iter != test.end_all();) *iter++ = value++; } { float value = 1.2F; - Array<3,float>::const_full_iterator iter = test.begin_all_const(); - for (int i=test.get_min_index(); i<= test.get_max_index(); ++i) - for (int j=test[i].get_min_index(); j<= test[i].get_max_index(); ++j) - for (int k=test[i][j].get_min_index(); k<= test[i][j].get_max_index(); ++k) - { + Array<3, float>::const_full_iterator iter = test.begin_all_const(); + for (int i = test.get_min_index(); i <= test.get_max_index(); ++i) + for (int j = test[i].get_min_index(); j <= test[i].get_max_index(); ++j) + for (int k = test[i][j].get_min_index(); k <= test[i][j].get_max_index(); ++k) { check(iter != test.end_all_const(), "test on 3D full iterator"); check_if_equal(*iter++, test[i][j][k], "test on 3D full iterator vs. index"); check_if_equal(test[i][j][k], value++, "test on 3D full iterator value"); @@ -625,22 +601,21 @@ ArrayTests::run_tests() } // test empty container { - const Array<3,float> empty; + const Array<3, float> empty; check(empty.begin_all() == empty.end_all(), "test on 3D full iterator for empty range"); } // test conversion from full_iterator to const_full_iterator { - Array<3,float>::full_iterator titer= test.begin_all(); - Array<3,float>::const_full_iterator ctiter= titer; // this should compile + Array<3, float>::full_iterator titer = test.begin_all(); + Array<3, float>::const_full_iterator ctiter = titer; // this should compile } } } - { cerr << "Testing 4D stuff" << endl; - const IndexRange<4> range(Coordinate4D(-3,0,-1,1),Coordinate4D(-2,3,3,3)); - Array<4,float> test4(range); + const IndexRange<4> range(Coordinate4D(-3, 0, -1, 1), Coordinate4D(-2, 3, 3, 3)); + Array<4, float> test4(range); test4.fill(1.); test4[-3][1][2][1] = (float)6.6; #if 0 @@ -649,67 +624,70 @@ ArrayTests::run_tests() test4[-2][1][0][2] = (float)7.3; #endif { - float sum = test4.sum(); - check_if_equal( sum , 131.9F, "test on sum()"); + float sum = test4.sum(); + check_if_equal(sum, 131.9F, "test on sum()"); } - const IndexRange<4> larger_range(Coordinate4D(-3,0,-1,1),Coordinate4D(-1,3,3,5)); + const IndexRange<4> larger_range(Coordinate4D(-3, 0, -1, 1), Coordinate4D(-1, 3, 3, 5)); test4.grow(larger_range); check_if_equal(test4.get_index_range(), larger_range, "test Array4D grow index range"); - check_if_equal(test4.sum(), 131.9F , "test Array4D grow sum"); + check_if_equal(test4.sum(), 131.9F, "test Array4D grow sum"); { - const Array<4,float> test41 = test4; - check_if_equal(test4 , test41, "test Array4D copy constructor" ); - check_if_equal( test41[-3][1][2][1] , 6.6F, "test on indexing after grow"); + const Array<4, float> test41 = test4; + check_if_equal(test4, test41, "test Array4D copy constructor"); + check_if_equal(test41[-3][1][2][1], 6.6F, "test on indexing after grow"); } { - Array<4,float> test41 = test4; - const IndexRange<4> mixed_range(Coordinate4D(-4,1,0,1),Coordinate4D(-2,3,3,6)); + Array<4, float> test41 = test4; + const IndexRange<4> mixed_range(Coordinate4D(-4, 1, 0, 1), Coordinate4D(-2, 3, 3, 6)); test41.resize(mixed_range); check_if_equal(test41.get_index_range(), mixed_range, "test Array4D resize index range"); - check_if_equal( test41[-3][1][2][1] , 6.6F, "test on indexing after resize"); + check_if_equal(test41[-3][1][2][1], 6.6F, "test on indexing after resize"); } - { - BasicCoordinate<4,int> c; - c[1]=-2;c[2]=1;c[3]=0;c[4]=2; - check_if_equal(test4[c] , 7.3F , "test on operator[](BasicCoordinate)"); - test4[c]=1.; - check_if_equal(test4[c] , 1.F , "test on operator[](BasicCoordinate)"); + { + BasicCoordinate<4, int> c; + c[1] = -2; + c[2] = 1; + c[3] = 0; + c[4] = 2; + check_if_equal(test4[c], 7.3F, "test on operator[](BasicCoordinate)"); + test4[c] = 1.; + check_if_equal(test4[c], 1.F, "test on operator[](BasicCoordinate)"); } { - Array<4,float> test4bis(range); + Array<4, float> test4bis(range); test4bis[-2][1][2][1] = (float)6.6; test4bis[-3][1][0][1] = (float)1.3; - Array<4,float> test4ter = test4bis; + Array<4, float> test4ter = test4bis; test4ter += test4; - check_if_equal(test4ter[-3][1][0][1] ,2.3F, "test on operator+=(Array4D)"); + check_if_equal(test4ter[-3][1][0][1], 2.3F, "test on operator+=(Array4D)"); check(test4ter.get_index_range() == larger_range, "test range for operator+=(Array4D) with grow"); - + // Note that test4 is bigger in size than test4bis. - Array<4,float> test4quat = test4bis + test4; - check_if_equal(test4quat ,test4ter, "test summing Array4D with grow"); + Array<4, float> test4quat = test4bis + test4; + check_if_equal(test4quat, test4ter, "test summing Array4D with grow"); check(test4quat.get_index_range() == larger_range, "test range for operator+=(Array4D)"); } // test on scalar multiplication, division { - Array<4,float> test4bis = test4; + Array<4, float> test4bis = test4; test4bis *= 6.F; - check_if_equal(test4bis.sum() ,test4.sum()*6, "test operator *=(float)"); + check_if_equal(test4bis.sum(), test4.sum() * 6, "test operator *=(float)"); test4bis /= 5.F; - check_if_equal(test4bis.sum() ,test4.sum()*6.F/5, "test operator /=(float)"); - } + check_if_equal(test4bis.sum(), test4.sum() * 6.F / 5, "test operator /=(float)"); + } // test on element-wise multiplication, division { - Array<4,float> test4bis(range); + Array<4, float> test4bis(range); { - for (int i=test4bis.get_min_index(); i<= test4bis.get_max_index(); i++) - test4bis[i].fill(i+10.F); + for (int i = test4bis.get_min_index(); i <= test4bis.get_max_index(); i++) + test4bis[i].fill(i + 10.F); } // save for comparison later on - Array<4,float> test4ter = test4bis; - + Array<4, float> test4ter = test4bis; + // Note that test4 is bigger than test4bis, so it will grow with the *= // new elements in test4bis will remain 0 because we're using multiplication test4[-1].fill(666); @@ -717,64 +695,63 @@ ArrayTests::run_tests() check_if_zero(test4bis[-1], "test operator *=(Array4D) grows ok"); check(test4.get_index_range() == test4bis.get_index_range(), "test operator *=(Array4D) grows ok: range"); - // compute the new sum. + // compute the new sum. { - float sum_check = 0; - for (int i=test4.get_min_index(); i<= -2; i++) - sum_check += test4[i].sum()*(i+10.F); - check_if_equal(test4bis.sum() ,sum_check, "test operator *=(Array4D)"); + float sum_check = 0; + for (int i = test4.get_min_index(); i <= -2; i++) + sum_check += test4[i].sum() * (i + 10.F); + check_if_equal(test4bis.sum(), sum_check, "test operator *=(Array4D)"); } // divide test4, but add a tiny number to avoid division by zero - const Array<4,float> test4quat = test4bis / (test4+.00001F); + const Array<4, float> test4quat = test4bis / (test4 + .00001F); test4ter.grow(test4.get_index_range()); - check_if_equal(test4ter ,test4quat, "test operator /(Array4D)"); - } - + check_if_equal(test4ter, test4quat, "test operator /(Array4D)"); + } + // test operator+(float) { // KT 31/01/2000 new - Array<4,float> tmp= test4 + 2; - Array<4,float> tmp2 = test4; + Array<4, float> tmp = test4 + 2; + Array<4, float> tmp2 = test4; tmp2.fill(1.F); - + // KT 20/12/2001 made check_if_zero compare relative to 1 by dividing - check_if_zero( (test4.sum() + 2*tmp2.sum() - tmp.sum())/test4.sum(), - "test operator+(float)"); + check_if_zero((test4.sum() + 2 * tmp2.sum() - tmp.sum()) / test4.sum(), "test operator+(float)"); } // test axpby { - Array<4,float> tmp(test4.get_index_range()); - Array<4,float> tmp2(test4+2); + Array<4, float> tmp(test4.get_index_range()); + Array<4, float> tmp2(test4 + 2); tmp.axpby(2.F, test4, 3.3F, tmp2); - const Array<4,float> by_hand = test4*2.F + (test4+2)*3.3F; + const Array<4, float> by_hand = test4 * 2.F + (test4 + 2) * 3.3F; check_if_equal(tmp, by_hand, "test axpby (Array4D)"); } - + // test xapyb, a and b scalar { - Array<4,float> tmp(test4.get_index_range()); - tmp.xapyb(test4, 2.F, test4+2, 3.3F); + Array<4, float> tmp(test4.get_index_range()); + tmp.xapyb(test4, 2.F, test4 + 2, 3.3F); - const Array<4,float> by_hand = test4*2.F + (test4+2)*3.3F; + const Array<4, float> by_hand = test4 * 2.F + (test4 + 2) * 3.3F; check_if_equal(tmp, by_hand, "test xapyb scalar (Array4D)"); tmp = test4; - tmp.sapyb(2.F, test4+2, 3.3F); - check_if_equal(tmp, by_hand, "test sapyb scalar (Array4D)"); + tmp.sapyb(2.F, test4 + 2, 3.3F); + check_if_equal(tmp, by_hand, "test sapyb scalar (Array4D)"); } - // test xapyb, a and b vector + // test xapyb, a and b vector { - Array<4,float> tmp(test4.get_index_range()); - tmp.xapyb(test4, test4+4, test4+2, test4+6); + Array<4, float> tmp(test4.get_index_range()); + tmp.xapyb(test4, test4 + 4, test4 + 2, test4 + 6); const Array<4, float> by_hand = test4 * (test4 + 4) + (test4 + 2) * (test4 + 6); check_if_equal(tmp, by_hand, "test xapyb vector (Array4D)"); tmp = test4; - tmp.sapyb(test4+4, test4+2, test4+6); - check_if_equal(tmp, by_hand, "test sapyb vector (Array4D)"); + tmp.sapyb(test4 + 4, test4 + 2, test4 + 6); + check_if_equal(tmp, by_hand, "test sapyb vector (Array4D)"); } { @@ -792,11 +769,10 @@ ArrayTests::run_tests() NVecArrIter iter_by_hand = by_hand.begin(); int i = 0; - while (iter_tmp != tmp.end()) - { - *iter_x = test4+i; - *iter_y = (test4 +i+ 2); - *iter_by_hand = ((test4 +i)* 2.0F + (test4+i + 2) * 3.3F); + while (iter_tmp != tmp.end()) { + *iter_x = test4 + i; + *iter_y = (test4 + i + 2); + *iter_by_hand = ((test4 + i) * 2.0F + (test4 + i + 2) * 3.3F); iter_tmp++; iter_x++; @@ -808,7 +784,7 @@ ArrayTests::run_tests() check_if_equal(tmp, by_hand, "test xapyb scalar (NumericVectorWithOffset)"); x.sapyb(2.0F, y, 3.3F); - check_if_equal(x, by_hand, "test sapyb scalar (NumericVectorWithOffset)"); + check_if_equal(x, by_hand, "test sapyb scalar (NumericVectorWithOffset)"); } { typedef NumericVectorWithOffset, float> NVecArr; @@ -829,13 +805,12 @@ ArrayTests::run_tests() NVecArrIter iter_by_hand = by_hand.begin(); int i = 0; - while (iter_tmp != tmp.end()) - { - *iter_x = test4+i; - *iter_y = (test4+i + 2); - *iter_a = (test4+i + 4); - *iter_b = (test4+i + 6); - *iter_by_hand = ((test4+i) * (test4+i + 4) + (test4+i + 2) * (test4+i + 6)); + while (iter_tmp != tmp.end()) { + *iter_x = test4 + i; + *iter_y = (test4 + i + 2); + *iter_a = (test4 + i + 4); + *iter_b = (test4 + i + 6); + *iter_by_hand = ((test4 + i) * (test4 + i + 4) + (test4 + i + 2) * (test4 + i + 6)); iter_tmp++; iter_x++; @@ -849,25 +824,25 @@ ArrayTests::run_tests() check_if_equal(tmp, by_hand, "test xapyb vector (NumericVectorWithOffset)"); x.sapyb(a, y, b); - check_if_equal(x, by_hand, "test sapyb vector (NumericVectorWithOffset)"); + check_if_equal(x, by_hand, "test sapyb vector (NumericVectorWithOffset)"); } } #if 1 { cerr << "Testing 1D float IO" << endl; - Array<1,float> t1(IndexRange<1>(-1,10)); - for (int i=-1; i<=10; i++) - t1[i] = static_cast(sin(i* _PI/ 15.)); - run_IO_tests(t1); + Array<1, float> t1(IndexRange<1>(-1, 10)); + for (int i = -1; i <= 10; i++) + t1[i] = static_cast(sin(i * _PI / 15.)); + run_IO_tests(t1); } { cerr << "Testing 2D double IO" << endl; - IndexRange<2> range(Coordinate2D(-1,11),Coordinate2D(10,20)); - Array<2,double> t1(range); - for (int i=-1; i<=10; i++) - for (int j=11; j<=20; j++) - t1[i][j] = static_cast(sin(i*j* _PI/ 15.)); + IndexRange<2> range(Coordinate2D(-1, 11), Coordinate2D(10, 20)); + Array<2, double> t1(range); + for (int i = -1; i <= 10; i++) + for (int j = 11; j <= 20; j++) + t1[i][j] = static_cast(sin(i * j * _PI / 15.)); run_IO_tests(t1); } { @@ -875,44 +850,40 @@ ArrayTests::run_tests() // construct test array which has rows of very different magnitudes, // numbers in last rows do not fit into short integers - IndexRange<3> range(Coordinate3D(-1,11,21),Coordinate3D(10,20,30)); - Array<3,float> t1(range); - for (int i=-1; i<=10; i++) - for (int j=11; j<=20; j++) - for (int k=21; k<=30; k++) - t1[i][j][k] = static_cast(20000.*k*sin(i*j*k* _PI/ 3000.)); + IndexRange<3> range(Coordinate3D(-1, 11, 21), Coordinate3D(10, 20, 30)); + Array<3, float> t1(range); + for (int i = -1; i <= 10; i++) + for (int j = 11; j <= 20; j++) + for (int k = 21; k <= 30; k++) + t1[i][j][k] = static_cast(20000. * k * sin(i * j * k * _PI / 3000.)); run_IO_tests(t1); } #endif { - cerr << "Testing make_array" << endl; + cerr << "Testing make_array" << endl; - const Array<2,float> arr1 = - make_array(make_1d_array(1.F,0.F,0.F), - make_1d_array(0.F,1.F,1.F), - make_1d_array(0.F,-2.F,2.F)); + const Array<2, float> arr1 = + make_array(make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, 1.F, 1.F), make_1d_array(0.F, -2.F, 2.F)); - const Array<2,float> arr2( - make_array(make_1d_array(1.F,0.F,0.F), - make_1d_array(0.F,1.F,1.F), - make_1d_array(0.F,-2.F,2.F))); + const Array<2, float> arr2( + make_array(make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, 1.F, 1.F), make_1d_array(0.F, -2.F, 2.F))); - const Array<2,float> arr3 = detail::test_make_array(); - const Array<2,float> arr4(detail::test_make_array()); + const Array<2, float> arr3 = detail::test_make_array(); + const Array<2, float> arr4(detail::test_make_array()); check_if_equal(arr1[2][1], -2.F, "make_array element comparison"); check_if_equal(arr1, arr2, "make_array inline assignment vs constructor"); check_if_equal(arr1, arr3, "make_array inline vs function with assignment"); check_if_equal(arr1, arr4, "make_array inline constructor from function"); - } + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { ArrayTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_ArrayFilter.cxx b/src/test/test_ArrayFilter.cxx index 2801bbb849..0a831b733c 100644 --- a/src/test/test_ArrayFilter.cxx +++ b/src/test/test_ArrayFilter.cxx @@ -1,8 +1,8 @@ /*! - \file + \file \ingroup test - + \brief tests for the stir::ArrayFilter classes \author Kris Thielemans @@ -38,343 +38,320 @@ #include "stir/modulo.h" #include "stir/RunTests.h" -#include "stir/stream.h"//XXX +#include "stir/stream.h" //XXX #include #include #include #ifdef DO_TIMINGS -#include "stir/CPUTimer.h" +# include "stir/CPUTimer.h" #endif START_NAMESPACE_STIR - /*! \brief Tests Array functionality \ingroup test */ -class ArrayFilterTests : public RunTests -{ +class ArrayFilterTests : public RunTests { public: void run_tests(); -private: - +private: + template + void compare_results_1arg(const ArrayFunctionObject& filter1, + const ArrayFunctionObject& filter2, const Array& test) { + { + Array out1(test); + Array out2(out1); + filter1(out1); + filter2(out2); -template -void -compare_results_1arg(const ArrayFunctionObject& filter1, - const ArrayFunctionObject& filter2, - const Array& test) -{ - { - Array out1(test); - Array out2(out1); - filter1(out1); - filter2(out2); - - check_if_equal( out1, out2, "test comparing output of filters, equal length"); - //std::cerr << out1 << out2; + check_if_equal(out1, out2, "test comparing output of filters, equal length"); + // std::cerr << out1 << out2; + } + { + Array out1(test); + BasicCoordinate min_indices, max_indices; + check(test.get_regular_range(min_indices, max_indices), "test only works for Arrays of regular range"); + const IndexRange larger_range(min_indices - 2, max_indices + 1); + out1.resize(larger_range); + + Array out2(out1); + filter1(out1); + filter2(out2); + + if (!check_if_equal(out1, out2, "test comparing output of filters, larger length")) { + } // std::cerr << out1 << out2; + } } - { - Array out1(test); + + template + void compare_results_2arg(const ArrayFunctionObject& filter1, + const ArrayFunctionObject& filter2, const Array& test) { BasicCoordinate min_indices, max_indices; check(test.get_regular_range(min_indices, max_indices), "test only works for Arrays of regular range"); - const IndexRange larger_range(min_indices-2, max_indices+1); - out1.resize(larger_range); - - Array out2(out1); - filter1(out1); - filter2(out2); - - if (!check_if_equal( out1, out2, "test comparing output of filters, larger length")) - {}//std::cerr << out1 << out2; - } -} + { + Array out1(test.get_index_range()); + Array out2(out1.get_index_range()); + filter1(out1, test); + filter2(out2, test); -template -void -compare_results_2arg(const ArrayFunctionObject& filter1, - const ArrayFunctionObject& filter2, - const Array& test) -{ - BasicCoordinate min_indices, max_indices; - check(test.get_regular_range(min_indices, max_indices), "test only works for Arrays of regular range"); - { - Array out1(test.get_index_range()); - Array out2(out1.get_index_range()); - filter1(out1, test); - filter2(out2, test); - - check_if_equal( out1, out2, "test comparing output of filter2, equal length"); - //std::cerr << out1 << out2; - } - { - const IndexRange larger_range(min_indices-2, max_indices+1); - Array out1(larger_range); - Array out2(larger_range); - filter1(out1, test); - filter2(out2, test); - - check_if_equal( out1, out2, "test comparing output of filter2, larger length"); - //std::cerr << out1 << out2; - } - { - const IndexRange smaller_range(min_indices+2, max_indices-1); - Array out1(smaller_range); - Array out2(smaller_range); - filter1(out1, test); - filter2(out2, test); - - check_if_equal( out1, out2, "test comparing output of filters, smaller length"); - } - if (num_dimensions==1) - { - IndexRange influenced_range; - if (filter2.get_influenced_indices(influenced_range, test.get_index_range())==Succeeded::yes) - { - BasicCoordinate min_indices, max_indices; - check(influenced_range.get_regular_range(min_indices, max_indices), "test only works for Arrays of regular range"); - const IndexRange larger_range(min_indices-3, max_indices+4);// WARNING ALIASING +7 - //Array out1(IndexRange(influenced_range.get_min_index()-3, influenced_range.get_max_index()+4)); - Array out1(larger_range); - Array out2(out1.get_index_range()); - filter1(out1, test); - filter2(out2, test); - - check_if_equal( out1, out2, "test comparing output of filters, out range is in range+ kernel + extra"); - check_if_zero( out2[out2.get_min_index()], "test conv 0 beyond kernel length"); - check_if_zero( out2[out2.get_min_index()+1], "test conv 0 beyond kernel length"); - check_if_zero( out2[out2.get_min_index()+2], "test conv 0 beyond kernel length"); - check_if_zero( out2[out2.get_max_index()], "test conv 0 beyond kernel length"); - check_if_zero( out2[out2.get_max_index()-1], "test conv 0 beyond kernel length"); - check_if_zero( out2[out2.get_max_index()-2], "test conv 0 beyond kernel length"); - check_if_zero( out2[out2.get_max_index()-3], "test conv 0 beyond kernel length"); - - // really not necessary if above tests were ok, - // but in case they failed, this gives some extra info - check_if_zero( out1[out1.get_min_index()], "test DFT 0 beyond kernel length"); - check_if_zero( out1[out1.get_min_index()+1], "test DFT 0 beyond kernel length"); - check_if_zero( out1[out1.get_min_index()+2], "test DFT 0 beyond kernel length"); - check_if_zero( out1[out1.get_max_index()], "test DFT 0 beyond kernel length"); - check_if_zero( out1[out1.get_max_index()-1], "test DFT 0 beyond kernel length"); - check_if_zero( out1[out1.get_max_index()-2], "test DFT 0 beyond kernel length"); - check_if_zero( out1[out1.get_max_index()-3], "test DFT 0 beyond kernel length"); - //std::cerr << out1 << out2; + check_if_equal(out1, out2, "test comparing output of filter2, equal length"); + // std::cerr << out1 << out2; + } + { + const IndexRange larger_range(min_indices - 2, max_indices + 1); + Array out1(larger_range); + Array out2(larger_range); + filter1(out1, test); + filter2(out2, test); + + check_if_equal(out1, out2, "test comparing output of filter2, larger length"); + // std::cerr << out1 << out2; + } + { + const IndexRange smaller_range(min_indices + 2, max_indices - 1); + Array out1(smaller_range); + Array out2(smaller_range); + filter1(out1, test); + filter2(out2, test); + + check_if_equal(out1, out2, "test comparing output of filters, smaller length"); + } + if (num_dimensions == 1) { + IndexRange influenced_range; + if (filter2.get_influenced_indices(influenced_range, test.get_index_range()) == Succeeded::yes) { + BasicCoordinate min_indices, max_indices; + check(influenced_range.get_regular_range(min_indices, max_indices), "test only works for Arrays of regular range"); + const IndexRange larger_range(min_indices - 3, max_indices + 4); // WARNING ALIASING +7 + // Array out1(IndexRange(influenced_range.get_min_index()-3, + // influenced_range.get_max_index()+4)); + Array out1(larger_range); + Array out2(out1.get_index_range()); + filter1(out1, test); + filter2(out2, test); + + check_if_equal(out1, out2, "test comparing output of filters, out range is in range+ kernel + extra"); + check_if_zero(out2[out2.get_min_index()], "test conv 0 beyond kernel length"); + check_if_zero(out2[out2.get_min_index() + 1], "test conv 0 beyond kernel length"); + check_if_zero(out2[out2.get_min_index() + 2], "test conv 0 beyond kernel length"); + check_if_zero(out2[out2.get_max_index()], "test conv 0 beyond kernel length"); + check_if_zero(out2[out2.get_max_index() - 1], "test conv 0 beyond kernel length"); + check_if_zero(out2[out2.get_max_index() - 2], "test conv 0 beyond kernel length"); + check_if_zero(out2[out2.get_max_index() - 3], "test conv 0 beyond kernel length"); + + // really not necessary if above tests were ok, + // but in case they failed, this gives some extra info + check_if_zero(out1[out1.get_min_index()], "test DFT 0 beyond kernel length"); + check_if_zero(out1[out1.get_min_index() + 1], "test DFT 0 beyond kernel length"); + check_if_zero(out1[out1.get_min_index() + 2], "test DFT 0 beyond kernel length"); + check_if_zero(out1[out1.get_max_index()], "test DFT 0 beyond kernel length"); + check_if_zero(out1[out1.get_max_index() - 1], "test DFT 0 beyond kernel length"); + check_if_zero(out1[out1.get_max_index() - 2], "test DFT 0 beyond kernel length"); + check_if_zero(out1[out1.get_max_index() - 3], "test DFT 0 beyond kernel length"); + // std::cerr << out1 << out2; } + } } -} - }; void -ArrayFilterTests::run_tests() -{ +ArrayFilterTests::run_tests() { std::cerr << "\nTesting 1D\n"; { const int size1 = 100; - Array<1,float> test(IndexRange<1>(100));// warning: not using 'size1' here. gcc 3.3 fails to compile it otherwise - Array<1,float> test_neg_offset(IndexRange<1>(-10,size1-11)); - Array<1,float> test_pos_offset(IndexRange<1>(10,size1+9)); + Array<1, float> test(IndexRange<1>(100)); // warning: not using 'size1' here. gcc 3.3 fails to compile it otherwise + Array<1, float> test_neg_offset(IndexRange<1>(-10, size1 - 11)); + Array<1, float> test_pos_offset(IndexRange<1>(10, size1 + 9)); // initialise to some arbitrary values - for (int i=test.get_min_index(); i<=test.get_max_index(); ++i) - test[i]=i*i*2-i-100.F; + for (int i = test.get_min_index(); i <= test.get_max_index(); ++i) + test[i] = i * i * 2 - i - 100.F; std::copy(test.begin(), test.end(), test_neg_offset.begin()); std::copy(test.begin(), test.end(), test_pos_offset.begin()); { - const int kernel_half_length=30; - const int DFT_kernel_size=256; + const int kernel_half_length = 30; + const int DFT_kernel_size = 256; // necessary to avoid aliasing in DFT - BOOST_STATIC_ASSERT(DFT_kernel_size>=(kernel_half_length*2+1)*2); - BOOST_STATIC_ASSERT(DFT_kernel_size>=2*size1+3);// note +3 as test grows the array - Array<1,float> kernel_for_DFT(IndexRange<1>(0,DFT_kernel_size-1)); - Array<1,float> kernel_for_conv(IndexRange<1>(-kernel_half_length,kernel_half_length)); - for (int i=-kernel_half_length; i DFT_filter; - check(DFT_filter.set_kernel(kernel_for_DFT)==Succeeded::yes, "initialisation DFT filter"); + BOOST_STATIC_ASSERT(DFT_kernel_size >= (kernel_half_length * 2 + 1) * 2); + BOOST_STATIC_ASSERT(DFT_kernel_size >= 2 * size1 + 3); // note +3 as test grows the array + Array<1, float> kernel_for_DFT(IndexRange<1>(0, DFT_kernel_size - 1)); + Array<1, float> kernel_for_conv(IndexRange<1>(-kernel_half_length, kernel_half_length)); + for (int i = -kernel_half_length; i < kernel_half_length; ++i) { + kernel_for_conv[i] = i * i - 3 * i + 1.F; + kernel_for_DFT[modulo(i, DFT_kernel_size)] = kernel_for_conv[i]; + } + + ArrayFilterUsingRealDFTWithPadding<1, float> DFT_filter; + check(DFT_filter.set_kernel(kernel_for_DFT) == Succeeded::yes, "initialisation DFT filter"); ArrayFilter1DUsingConvolution conv_filter(kernel_for_conv); check(!DFT_filter.is_trivial(), "DFT is_trivial"); check(!conv_filter.is_trivial(), "conv is_trivial"); - set_tolerance(test.find_max()*kernel_for_conv.sum()*1.E-6); - //std::cerr << get_tolerance(); + set_tolerance(test.find_max() * kernel_for_conv.sum() * 1.E-6); + // std::cerr << get_tolerance(); - std::cerr <<"Comparing DFT and Convolution with input offset 0\n"; + std::cerr << "Comparing DFT and Convolution with input offset 0\n"; compare_results_2arg(DFT_filter, conv_filter, test); compare_results_1arg(DFT_filter, conv_filter, test); - std::cerr <<"Comparing DFT and Convolution with input negative offset\n"; + std::cerr << "Comparing DFT and Convolution with input negative offset\n"; compare_results_2arg(DFT_filter, conv_filter, test_neg_offset); compare_results_1arg(DFT_filter, conv_filter, test_neg_offset); - std::cerr <<"Comparing DFT and Convolution with input positive offset\n"; + std::cerr << "Comparing DFT and Convolution with input positive offset\n"; compare_results_2arg(DFT_filter, conv_filter, test_pos_offset); compare_results_1arg(DFT_filter, conv_filter, test_pos_offset); } { - const int kernel_half_length=30; - Array<1,float> kernel_for_symconv(IndexRange<1>(0,kernel_half_length)); - Array<1,float> kernel_for_conv(IndexRange<1>(-kernel_half_length,kernel_half_length)); - for (int i=0; i kernel_for_symconv(IndexRange<1>(0, kernel_half_length)); + Array<1, float> kernel_for_conv(IndexRange<1>(-kernel_half_length, kernel_half_length)); + for (int i = 0; i < kernel_half_length; ++i) { + kernel_for_symconv[i] = kernel_for_conv[i] = kernel_for_conv[-i] = i * i - 3 * i + 1.F; + } // symmetric convolution currently requires equal in and out range - Array<1,float> test(IndexRange<1>(100)); + Array<1, float> test(IndexRange<1>(100)); // initialise to some arbitrary values - for (int i=test.get_min_index(); i<=test.get_max_index(); ++i) - test[i]=i*i*2-i-100.F; - - - + for (int i = test.get_min_index(); i <= test.get_max_index(); ++i) + test[i] = i * i * 2 - i - 100.F; + ArrayFilter1DUsingConvolution conv_filter(kernel_for_conv); ArrayFilter1DUsingConvolutionSymmetricKernel symconv_filter(kernel_for_symconv); check(!symconv_filter.is_trivial(), "symconv is_trivial"); check(!conv_filter.is_trivial(), "conv is_trivial"); - set_tolerance(test.find_max()*kernel_for_conv.sum()*1.E-6); - std::cerr <<"Comparing SymmetricConvolution and Convolution\n"; + set_tolerance(test.find_max() * kernel_for_conv.sum() * 1.E-6); + std::cerr << "Comparing SymmetricConvolution and Convolution\n"; // note: SymmetricConvolution cannot handle different input and output ranges compare_results_1arg(symconv_filter, conv_filter, test); } std::cerr << "Testing boundary conditions\n"; { - Array<1,float> kernel(IndexRange<1>(-1,2)); + Array<1, float> kernel(IndexRange<1>(-1, 2)); kernel[-1] = 1; kernel[0] = 2; kernel[1] = 3; kernel[2] = .5; const ArrayFilter1DUsingConvolution conv_filter_zero_BC(kernel); const ArrayFilter1DUsingConvolution conv_filter_cst_BC(kernel, BoundaryConditions::constant); - { - Array<1,float> test(IndexRange<1>(101)); - // initialise to some arbitrary values - for (int i=test.get_min_index(); i<=test.get_max_index(); ++i) - test[i]=i*i*2-i-100.F; - set_tolerance(test.find_max()*kernel.sum()*1.E-6); - - Array<1,float> out_zero_BCs = test; - Array<1,float> out_cst_BCs = test; - conv_filter_zero_BC(out_zero_BCs); - conv_filter_cst_BC(out_cst_BCs); - // test if internal array elements are the same - { - Array<1,float> out_zero_BCs_small=out_zero_BCs; - out_zero_BCs_small.resize(out_zero_BCs.get_min_index() + kernel.get_max_index(), - out_zero_BCs.get_max_index() + kernel.get_min_index()); - Array<1,float> out_cst_BCs_small=out_cst_BCs; - out_cst_BCs_small.resize(out_cst_BCs.get_min_index() + kernel.get_max_index(), - out_cst_BCs.get_max_index() + kernel.get_min_index()); - check_if_equal(out_cst_BCs_small, out_zero_BCs_small, "comparing 1D with different boundary conditions: internal values"); - } - // edge - float left_boundary=test[0]*kernel[2] + test[0]*kernel[1] + test[0]*kernel[0] + test[1]*kernel[-1]; - check_if_equal(out_cst_BCs[0], left_boundary, "1D with cst BC: left edge"); - left_boundary=test[0]*kernel[0] + test[1]*kernel[-1]; - check_if_equal(out_zero_BCs[0], left_boundary, "1D with zero BC: left edge"); - float right_boundary=test[98]*kernel[2] + test[99]*kernel[1] + test[100]*kernel[0] + test[100]*kernel[-1]; - check_if_equal(out_cst_BCs[100], right_boundary, "1D with cst BC: right edge"); - right_boundary=test[98]*kernel[2] + test[99]*kernel[1] + test[100]*kernel[0]; - check_if_equal(out_zero_BCs[100], right_boundary, "1D with zero BC: right edge"); + { + Array<1, float> test(IndexRange<1>(101)); + // initialise to some arbitrary values + for (int i = test.get_min_index(); i <= test.get_max_index(); ++i) + test[i] = i * i * 2 - i - 100.F; + set_tolerance(test.find_max() * kernel.sum() * 1.E-6); + + Array<1, float> out_zero_BCs = test; + Array<1, float> out_cst_BCs = test; + conv_filter_zero_BC(out_zero_BCs); + conv_filter_cst_BC(out_cst_BCs); + // test if internal array elements are the same + { + Array<1, float> out_zero_BCs_small = out_zero_BCs; + out_zero_BCs_small.resize(out_zero_BCs.get_min_index() + kernel.get_max_index(), + out_zero_BCs.get_max_index() + kernel.get_min_index()); + Array<1, float> out_cst_BCs_small = out_cst_BCs; + out_cst_BCs_small.resize(out_cst_BCs.get_min_index() + kernel.get_max_index(), + out_cst_BCs.get_max_index() + kernel.get_min_index()); + check_if_equal(out_cst_BCs_small, out_zero_BCs_small, + "comparing 1D with different boundary conditions: internal values"); + } + // edge + float left_boundary = test[0] * kernel[2] + test[0] * kernel[1] + test[0] * kernel[0] + test[1] * kernel[-1]; + check_if_equal(out_cst_BCs[0], left_boundary, "1D with cst BC: left edge"); + left_boundary = test[0] * kernel[0] + test[1] * kernel[-1]; + check_if_equal(out_zero_BCs[0], left_boundary, "1D with zero BC: left edge"); + float right_boundary = test[98] * kernel[2] + test[99] * kernel[1] + test[100] * kernel[0] + test[100] * kernel[-1]; + check_if_equal(out_cst_BCs[100], right_boundary, "1D with cst BC: right edge"); + right_boundary = test[98] * kernel[2] + test[99] * kernel[1] + test[100] * kernel[0]; + check_if_equal(out_zero_BCs[100], right_boundary, "1D with zero BC: right edge"); } { - Array<1,float> test(-2,5), test_out(-5,8); - test.fill(1.F); - set_tolerance(test.find_max()*kernel.sum()*1.E-6); - conv_filter_zero_BC(test_out, test); - check_if_equal(test_out[-5],0.F,"1D with zero BC: element -5"); - check_if_equal(test_out[-4],0.F,"1D with zero BC: element -4"); - check_if_equal(test_out[-3],kernel[-1],"1D with zero BC: element -3"); - check_if_equal(test_out[-2],kernel[-1]+kernel[0],"1D with zero BC: element -2"); - check_if_equal(test_out[-1],kernel[-1]+kernel[0]+kernel[1],"1D with zero BC: element -1"); - check_if_equal(test_out[0],kernel[2]+kernel[1]+kernel[0]+kernel[-1],"1D with zero BC: element 0"); - check_if_equal(test_out[4],kernel[2]+kernel[1]+kernel[0]+kernel[-1],"1D with zero BC: element 4"); - check_if_equal(test_out[5],kernel[2]+kernel[1]+kernel[0],"1D with zero BC: element 5"); - check_if_equal(test_out[6],kernel[2]+kernel[1],"1D with zero BC: element 6"); - check_if_equal(test_out[7],kernel[2],"1D with zero BC: element 7"); - check_if_equal(test_out[8],0.F,"1D with zero BC: element 8"); - conv_filter_cst_BC(test_out, test); - const float sum=kernel.sum(); - check_if_equal(test_out[-5],sum,"1D with cst BC: element -5"); - check_if_equal(test_out[-4],sum,"1D with cst BC: element -4"); - check_if_equal(test_out[-3],sum,"1D with cst BC: element -3"); - check_if_equal(test_out[-2],sum,"1D with cst BC: element -2"); - check_if_equal(test_out[-1],sum,"1D with cst BC: element -1"); - check_if_equal(test_out[0],sum,"1D with cst BC: element 0"); - check_if_equal(test_out[4],sum,"1D with cst BC: element 4"); - check_if_equal(test_out[5],sum,"1D with cst BC: element 5"); - check_if_equal(test_out[6],sum,"1D with cst BC: element 6"); - check_if_equal(test_out[7],sum,"1D with cst BC: element 7"); - check_if_equal(test_out[8],sum,"1D with cst BC: element 8"); + Array<1, float> test(-2, 5), test_out(-5, 8); + test.fill(1.F); + set_tolerance(test.find_max() * kernel.sum() * 1.E-6); + conv_filter_zero_BC(test_out, test); + check_if_equal(test_out[-5], 0.F, "1D with zero BC: element -5"); + check_if_equal(test_out[-4], 0.F, "1D with zero BC: element -4"); + check_if_equal(test_out[-3], kernel[-1], "1D with zero BC: element -3"); + check_if_equal(test_out[-2], kernel[-1] + kernel[0], "1D with zero BC: element -2"); + check_if_equal(test_out[-1], kernel[-1] + kernel[0] + kernel[1], "1D with zero BC: element -1"); + check_if_equal(test_out[0], kernel[2] + kernel[1] + kernel[0] + kernel[-1], "1D with zero BC: element 0"); + check_if_equal(test_out[4], kernel[2] + kernel[1] + kernel[0] + kernel[-1], "1D with zero BC: element 4"); + check_if_equal(test_out[5], kernel[2] + kernel[1] + kernel[0], "1D with zero BC: element 5"); + check_if_equal(test_out[6], kernel[2] + kernel[1], "1D with zero BC: element 6"); + check_if_equal(test_out[7], kernel[2], "1D with zero BC: element 7"); + check_if_equal(test_out[8], 0.F, "1D with zero BC: element 8"); + conv_filter_cst_BC(test_out, test); + const float sum = kernel.sum(); + check_if_equal(test_out[-5], sum, "1D with cst BC: element -5"); + check_if_equal(test_out[-4], sum, "1D with cst BC: element -4"); + check_if_equal(test_out[-3], sum, "1D with cst BC: element -3"); + check_if_equal(test_out[-2], sum, "1D with cst BC: element -2"); + check_if_equal(test_out[-1], sum, "1D with cst BC: element -1"); + check_if_equal(test_out[0], sum, "1D with cst BC: element 0"); + check_if_equal(test_out[4], sum, "1D with cst BC: element 4"); + check_if_equal(test_out[5], sum, "1D with cst BC: element 5"); + check_if_equal(test_out[6], sum, "1D with cst BC: element 6"); + check_if_equal(test_out[7], sum, "1D with cst BC: element 7"); + check_if_equal(test_out[8], sum, "1D with cst BC: element 8"); } } // boundary conditions - } // 1D std::cerr << "\nTesting 2D\n"; { set_tolerance(.001F); - const int size1=6;const int size2=20; - Array<2,float> test(IndexRange2D(size1,size2)); - Array<2,float> test_neg_offset(IndexRange2D(-5,size1-6,-10,size2-11)); - Array<2,float> test_pos_offset(IndexRange2D(1,size1,2,size2+1)); + const int size1 = 6; + const int size2 = 20; + Array<2, float> test(IndexRange2D(size1, size2)); + Array<2, float> test_neg_offset(IndexRange2D(-5, size1 - 6, -10, size2 - 11)); + Array<2, float> test_pos_offset(IndexRange2D(1, size1, 2, size2 + 1)); // initialise to some arbitrary values { - Array<2,float>::full_iterator iter = test.begin_all(); + Array<2, float>::full_iterator iter = test.begin_all(); /*for (int i=-100; iter != test.end_all(); ++i, ++iter) *iter = 1;//i*i*2.F-i-100.F;*/ - test[0][0]=1; + test[0][0] = 1; std::copy(test.begin_all(), test.end_all(), test_neg_offset.begin_all()); std::copy(test.begin_all(), test.end_all(), test_pos_offset.begin_all()); } { - const int kernel_half_length=14; - const int DFT_kernel_size=64; + const int kernel_half_length = 14; + const int DFT_kernel_size = 64; // necessary to avoid aliasing in DFT - BOOST_STATIC_ASSERT(DFT_kernel_size>=(kernel_half_length*2+1)*2); - BOOST_STATIC_ASSERT(DFT_kernel_size>=2*size2+3);// note +3 as test grows the array - BOOST_STATIC_ASSERT(DFT_kernel_size>=2*size1+3);// note +3 as test grows the array - const Coordinate2D sizes(DFT_kernel_size/2,DFT_kernel_size); - Array<2,float> kernel_for_DFT(IndexRange2D(DFT_kernel_size/2,DFT_kernel_size)); - Array<2,float> kernel_for_conv(IndexRange2D(-(kernel_half_length/2),kernel_half_length/2, - -kernel_half_length,kernel_half_length)); - for (int i=-(kernel_half_length/2); i index(i,j); - kernel_for_conv[index] = i*i-3*i+1.F+j*i/20.F; - kernel_for_DFT[modulo(index,sizes)] = - kernel_for_conv[index]; - } - - - ArrayFilterUsingRealDFTWithPadding<2,float> DFT_filter; - check(DFT_filter.set_kernel(kernel_for_DFT)==Succeeded::yes, "initialisation DFT filter"); + BOOST_STATIC_ASSERT(DFT_kernel_size >= (kernel_half_length * 2 + 1) * 2); + BOOST_STATIC_ASSERT(DFT_kernel_size >= 2 * size2 + 3); // note +3 as test grows the array + BOOST_STATIC_ASSERT(DFT_kernel_size >= 2 * size1 + 3); // note +3 as test grows the array + const Coordinate2D sizes(DFT_kernel_size / 2, DFT_kernel_size); + Array<2, float> kernel_for_DFT(IndexRange2D(DFT_kernel_size / 2, DFT_kernel_size)); + Array<2, float> kernel_for_conv( + IndexRange2D(-(kernel_half_length / 2), kernel_half_length / 2, -kernel_half_length, kernel_half_length)); + for (int i = -(kernel_half_length / 2); i < kernel_half_length / 2; ++i) + for (int j = -kernel_half_length; j < kernel_half_length; ++j) { + const Coordinate2D index(i, j); + kernel_for_conv[index] = i * i - 3 * i + 1.F + j * i / 20.F; + kernel_for_DFT[modulo(index, sizes)] = kernel_for_conv[index]; + } + + ArrayFilterUsingRealDFTWithPadding<2, float> DFT_filter; + check(DFT_filter.set_kernel(kernel_for_DFT) == Succeeded::yes, "initialisation DFT filter"); ArrayFilter2DUsingConvolution conv_filter(kernel_for_conv); check(!DFT_filter.is_trivial(), "DFT is_trivial"); check(!conv_filter.is_trivial(), "conv is_trivial"); - set_tolerance(test.find_max()*kernel_for_conv.sum()*1.E-6); - //std::cerr << get_tolerance(); + set_tolerance(test.find_max() * kernel_for_conv.sum() * 1.E-6); + // std::cerr << get_tolerance(); - std::cerr <<"Comparing DFT and Convolution with input offset 0\n"; + std::cerr << "Comparing DFT and Convolution with input offset 0\n"; compare_results_2arg(DFT_filter, conv_filter, test); compare_results_1arg(DFT_filter, conv_filter, test); - std::cerr <<"Comparing DFT and Convolution with input negative offset\n"; + std::cerr << "Comparing DFT and Convolution with input negative offset\n"; compare_results_2arg(DFT_filter, conv_filter, test_neg_offset); compare_results_1arg(DFT_filter, conv_filter, test_neg_offset); - std::cerr <<"Comparing DFT and Convolution with input positive offset\n"; + std::cerr << "Comparing DFT and Convolution with input positive offset\n"; compare_results_2arg(DFT_filter, conv_filter, test_pos_offset); compare_results_1arg(DFT_filter, conv_filter, test_pos_offset); } @@ -382,71 +359,68 @@ ArrayFilterTests::run_tests() std::cerr << "\nTesting 3D\n"; { set_tolerance(.001F); - const int size1=5;const int size2=7; const int size3=6; - Array<3,float> test(IndexRange3D(size1,size2,size3)); - Array<3,float> test_neg_offset(IndexRange3D(-5,size1-6,-10,size2-11,-4,size3-5)); - Array<3,float> test_pos_offset(IndexRange3D(1,size1,2,size2+1,3,size3+4)); + const int size1 = 5; + const int size2 = 7; + const int size3 = 6; + Array<3, float> test(IndexRange3D(size1, size2, size3)); + Array<3, float> test_neg_offset(IndexRange3D(-5, size1 - 6, -10, size2 - 11, -4, size3 - 5)); + Array<3, float> test_pos_offset(IndexRange3D(1, size1, 2, size2 + 1, 3, size3 + 4)); // initialise to some arbitrary values { - Array<3,float>::full_iterator iter = test.begin_all(); - for (int i=-100; iter != test.end_all(); ++i, ++iter) - *iter = 1;//i*i*2.F-i-100.F; + Array<3, float>::full_iterator iter = test.begin_all(); + for (int i = -100; iter != test.end_all(); ++i, ++iter) + *iter = 1; // i*i*2.F-i-100.F; std::copy(test.begin_all(), test.end_all(), test_neg_offset.begin_all()); std::copy(test.begin_all(), test.end_all(), test_pos_offset.begin_all()); } { - const int kernel_half_length=7; - const int DFT_kernel_size=32; + const int kernel_half_length = 7; + const int DFT_kernel_size = 32; // necessary to avoid aliasing in DFT - BOOST_STATIC_ASSERT(DFT_kernel_size>=(kernel_half_length*2+1)*2); - BOOST_STATIC_ASSERT(DFT_kernel_size/2>=2*size1+3);// note +3 as test grows the array - BOOST_STATIC_ASSERT(DFT_kernel_size>=2*size2+3);// note +3 as test grows the array - BOOST_STATIC_ASSERT(DFT_kernel_size>=2*size3+3);// note +3 as test grows the array - const Coordinate3D sizes(DFT_kernel_size/2,DFT_kernel_size,DFT_kernel_size); - Array<3,float> kernel_for_DFT(IndexRange3D(DFT_kernel_size/2,DFT_kernel_size,DFT_kernel_size)); - Array<3,float> kernel_for_conv(IndexRange3D(-(kernel_half_length/2),kernel_half_length/2, - -kernel_half_length,kernel_half_length, - -kernel_half_length,kernel_half_length)); - for (int i=-(kernel_half_length/2); i index(i,j,k); - kernel_for_conv[index] = i*i-3*i+1.F+j*i/20.F+k; - kernel_for_DFT[modulo(index,sizes)] = - kernel_for_conv[index]; - } - - - ArrayFilterUsingRealDFTWithPadding<3,float> DFT_filter; - check(DFT_filter.set_kernel(kernel_for_DFT)==Succeeded::yes, "initialisation DFT filter"); + BOOST_STATIC_ASSERT(DFT_kernel_size >= (kernel_half_length * 2 + 1) * 2); + BOOST_STATIC_ASSERT(DFT_kernel_size / 2 >= 2 * size1 + 3); // note +3 as test grows the array + BOOST_STATIC_ASSERT(DFT_kernel_size >= 2 * size2 + 3); // note +3 as test grows the array + BOOST_STATIC_ASSERT(DFT_kernel_size >= 2 * size3 + 3); // note +3 as test grows the array + const Coordinate3D sizes(DFT_kernel_size / 2, DFT_kernel_size, DFT_kernel_size); + Array<3, float> kernel_for_DFT(IndexRange3D(DFT_kernel_size / 2, DFT_kernel_size, DFT_kernel_size)); + Array<3, float> kernel_for_conv(IndexRange3D(-(kernel_half_length / 2), kernel_half_length / 2, -kernel_half_length, + kernel_half_length, -kernel_half_length, kernel_half_length)); + for (int i = -(kernel_half_length / 2); i < kernel_half_length / 2; ++i) + for (int j = -kernel_half_length; j < kernel_half_length; ++j) + for (int k = -kernel_half_length; k < kernel_half_length; ++k) { + Coordinate3D index(i, j, k); + kernel_for_conv[index] = i * i - 3 * i + 1.F + j * i / 20.F + k; + kernel_for_DFT[modulo(index, sizes)] = kernel_for_conv[index]; + } + + ArrayFilterUsingRealDFTWithPadding<3, float> DFT_filter; + check(DFT_filter.set_kernel(kernel_for_DFT) == Succeeded::yes, "initialisation DFT filter"); ArrayFilter3DUsingConvolution conv_filter(kernel_for_conv); check(!DFT_filter.is_trivial(), "DFT is_trivial"); check(!conv_filter.is_trivial(), "conv is_trivial"); - set_tolerance(test.find_max()*kernel_for_conv.sum()*1.E-6); - //std::cerr << get_tolerance(); + set_tolerance(test.find_max() * kernel_for_conv.sum() * 1.E-6); + // std::cerr << get_tolerance(); - std::cerr <<"Comparing DFT and Convolution with input offset 0\n"; + std::cerr << "Comparing DFT and Convolution with input offset 0\n"; compare_results_2arg(DFT_filter, conv_filter, test); compare_results_1arg(DFT_filter, conv_filter, test); - std::cerr <<"Comparing DFT and Convolution with input negative offset\n"; + std::cerr << "Comparing DFT and Convolution with input negative offset\n"; compare_results_2arg(DFT_filter, conv_filter, test_neg_offset); compare_results_1arg(DFT_filter, conv_filter, test_neg_offset); - std::cerr <<"Comparing DFT and Convolution with input positive offset\n"; + std::cerr << "Comparing DFT and Convolution with input positive offset\n"; compare_results_2arg(DFT_filter, conv_filter, test_pos_offset); compare_results_1arg(DFT_filter, conv_filter, test_pos_offset); } } - } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { ArrayFilterTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_ByteOrder.cxx b/src/test/test_ByteOrder.cxx index a8a82cbc36..9c81d589a2 100644 --- a/src/test/test_ByteOrder.cxx +++ b/src/test/test_ByteOrder.cxx @@ -40,50 +40,45 @@ using std::endl; START_NAMESPACE_STIR - /*! \brief Test class for ByteOrder and the preprocessor defines from ByteOrderDefine.h \ingroup test */ -class ByteOrderTests : public RunTests -{ +class ByteOrderTests : public RunTests { public: void run_tests(); }; void -ByteOrderTests::run_tests() -{ +ByteOrderTests::run_tests() { cerr << "Tests for ByteOrder\n" << "Everythings is fine if the program runs without any output." << endl; // if any of these is wrong, check ByteOrderDefine.h #if STIRIsNativeByteOrderBigEndian check(ByteOrder::get_native_order() == ByteOrder::big_endian, - "STIRIsNativeByteOrderBigEndian preprocessor define is determined incorrectly."); + "STIRIsNativeByteOrderBigEndian preprocessor define is determined incorrectly."); #else check(ByteOrder::get_native_order() == ByteOrder::little_endian, - "STIRIsNativeByteOrderBigEndian preprocessor define is determined incorrectly."); + "STIRIsNativeByteOrderBigEndian preprocessor define is determined incorrectly."); #endif #if STIRIsNativeByteOrderLittleEndian check(ByteOrder::get_native_order() == ByteOrder::little_endian, - "STIRIsNativeByteOrderBigEndian preprocessor define is determined incorrectly."); + "STIRIsNativeByteOrderBigEndian preprocessor define is determined incorrectly."); #else check(ByteOrder::get_native_order() == ByteOrder::big_endian, - "STIRIsNativeByteOrderBigEndian preprocessor define is determined incorrectly."); + "STIRIsNativeByteOrderBigEndian preprocessor define is determined incorrectly."); #endif - } - END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { ByteOrderTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_DateTime.cxx b/src/test/test_DateTime.cxx index 986a07c59c..b86586f699 100644 --- a/src/test/test_DateTime.cxx +++ b/src/test/test_DateTime.cxx @@ -18,7 +18,7 @@ */ /*! - \file + \file \ingroup test \ingroup date_time \brief A simple program to test the date-time conversions @@ -30,7 +30,6 @@ #include - START_NAMESPACE_STIR /*! @@ -38,81 +37,80 @@ START_NAMESPACE_STIR \ingroup test \ingroup date_time */ -class DateTimeTest : public RunTests -{ +class DateTimeTest : public RunTests { void check_round_trip(const double secs, const double tz_offset, const std::string& str); + public: void run_tests(); }; - void -DateTimeTest::run_tests() -{ +DateTimeTest::run_tests() { // just do a consistency check first: mktime and local time should be "inverse" of eachother { time_t current_time = time(0); - struct tm * local_time = localtime(¤t_time); + struct tm* local_time = localtime(¤t_time); if (difftime(current_time, mktime(local_time)) != 0) error("CTIME internal error"); } std::cerr << "Testing DICOM DateTime to epoch functionality\n"; { - check_if_zero(DICOM_datetime_to_secs_since_Unix_epoch("19700101000000.00+0000") - - 0., "test 1 Jan 1970 is 0"); + check_if_zero(DICOM_datetime_to_secs_since_Unix_epoch("19700101000000.00+0000") - 0., "test 1 Jan 1970 is 0"); check_if_zero(DICOM_datetime_to_secs_since_Unix_epoch("19710202000000+0000") - - (((((365 + 31 + 1)*24) + 0)*60. + 0)*60 + 0), "test 2 Feb 1971 0:0:"); + (((((365 + 31 + 1) * 24) + 0) * 60. + 0) * 60 + 0), + "test 2 Feb 1971 0:0:"); check_if_zero(DICOM_datetime_to_secs_since_Unix_epoch("19710202230001.80+0000") - - (((((365 + 31 + 1)*24) + 23)*60. + 0)*60 + 1.80), "test 2 Feb 1971 23:0:1.8"); + (((((365 + 31 + 1) * 24) + 23) * 60. + 0) * 60 + 1.80), + "test 2 Feb 1971 23:0:1.8"); check_if_zero(DICOM_datetime_to_secs_since_Unix_epoch("19710202230301+0230") - - (((((365 + 31 + 1)*24) + 23 - 2.5)*60. + 3)*60 + 1), "test 2 Feb 1971 23:03:01 +02:30"); + (((((365 + 31 + 1) * 24) + 23 - 2.5) * 60. + 3) * 60 + 1), + "test 2 Feb 1971 23:03:01 +02:30"); check_if_zero(DICOM_datetime_to_secs_since_Unix_epoch("19710202230301-0500") - - (((((365 + 31 + 1)*24) + 23 + 5)*60. + 3)*60 + 1), "test 2 Feb 1971 23:03:01 -05:00"); + (((((365 + 31 + 1) * 24) + 23 + 5) * 60. + 3) * 60 + 1), + "test 2 Feb 1971 23:03:01 -05:00"); check_if_zero(DICOM_datetime_to_secs_since_Unix_epoch(DICOM_date_time_to_DT("19710202", "230301", "-0500")) - - (((((365 + 31 + 1)*24) + 23 + 5)*60. + 3)*60 + 1), "test 2 Feb 1971 23:03:01 -05:00 (split)"); + (((((365 + 31 + 1) * 24) + 23 + 5) * 60. + 3) * 60 + 1), + "test 2 Feb 1971 23:03:01 -05:00 (split)"); std::cerr << "\nThe next test should throw an error\n"; - try - { - DICOM_datetime_to_secs_since_Unix_epoch("19710202230301+020"); - check(false, "test ill-formed TZ"); - } - catch (...) - { - std::cerr << "Test was ok\n"; - } + try { + DICOM_datetime_to_secs_since_Unix_epoch("19710202230301+020"); + check(false, "test ill-formed TZ"); + } catch (...) { + std::cerr << "Test was ok\n"; + } // test difference, disabling warnings check_if_zero(DICOM_datetime_to_secs_since_Unix_epoch("20700104000000.4", true) - - DICOM_datetime_to_secs_since_Unix_epoch("20700101000000", true) - - (3*24*60.*60 + 0.4), "test difference without TZ"); + DICOM_datetime_to_secs_since_Unix_epoch("20700101000000", true) - (3 * 24 * 60. * 60 + 0.4), + "test difference without TZ"); } std::cerr << "\nTesting Interfile DateTime to epoch functionality\n"; { - check_if_zero(Interfile_datetime_to_secs_since_Unix_epoch(DateTimeStrings("1970:01:01", "00:00:00.00+0000")) - - 0., "test 1 Jan 1970 is 0"); + check_if_zero(Interfile_datetime_to_secs_since_Unix_epoch(DateTimeStrings("1970:01:01", "00:00:00.00+0000")) - 0., + "test 1 Jan 1970 is 0"); check_if_zero(Interfile_datetime_to_secs_since_Unix_epoch(DateTimeStrings("1971:02:02", "00:00:00+0000")) - - (((((365 + 31 + 1)*24) + 0)*60. + 0)*60 + 0), "test 2 Feb 1971 0:0:"); + (((((365 + 31 + 1) * 24) + 0) * 60. + 0) * 60 + 0), + "test 2 Feb 1971 0:0:"); check_if_zero(Interfile_datetime_to_secs_since_Unix_epoch(DateTimeStrings("1971:02:02", "23:00:01.80+0000")) - - (((((365 + 31 + 1)*24) + 23)*60. + 0)*60 + 1.80), "test 2 Feb 1971 23:0:1.8"); + (((((365 + 31 + 1) * 24) + 23) * 60. + 0) * 60 + 1.80), + "test 2 Feb 1971 23:0:1.8"); check_if_zero(Interfile_datetime_to_secs_since_Unix_epoch(DateTimeStrings("1971:02:02", "23:03:01+0230")) - - (((((365 + 31 + 1)*24) + 23 - 2.5)*60. + 3)*60 + 1), "test 2 Feb 1971 23:03:01 +02:30"); + (((((365 + 31 + 1) * 24) + 23 - 2.5) * 60. + 3) * 60 + 1), + "test 2 Feb 1971 23:03:01 +02:30"); check_if_zero(Interfile_datetime_to_secs_since_Unix_epoch(DateTimeStrings("1971:02:02", "23:03:01-0500")) - - (((((365 + 31 + 1)*24) + 23 + 5)*60. + 3)*60 + 1), "test 2 Feb 1971 23:03:01 -05:00"); + (((((365 + 31 + 1) * 24) + 23 + 5) * 60. + 3) * 60 + 1), + "test 2 Feb 1971 23:03:01 -05:00"); std::cerr << "\nThe next test should throw an error\n"; - try - { - Interfile_datetime_to_secs_since_Unix_epoch(DateTimeStrings("1971:02:2", "23:03:01")); - check(false, "test ill-formed date"); - } - catch (...) - { - std::cerr << "Test was ok\n"; - } - + try { + Interfile_datetime_to_secs_since_Unix_epoch(DateTimeStrings("1971:02:2", "23:03:01")); + check(false, "test ill-formed date"); + } catch (...) { + std::cerr << "Test was ok\n"; + } } std::cerr << "\nTesting round-trip\n"; @@ -122,59 +120,47 @@ DateTimeTest::run_tests() secs = DICOM_datetime_to_secs_since_Unix_epoch("20201120223001.5+0000"); check_round_trip(secs, 0., "round-trip 1 tz+0"); - check_round_trip(secs, 5.5*3600., "round-trip 1 tz+5.5"); - check_round_trip(secs, 12*3600., "round-trip 1 tz+12"); - check_round_trip(secs, -12*3600., "round-trip 1 tz-12"); + check_round_trip(secs, 5.5 * 3600., "round-trip 1 tz+5.5"); + check_round_trip(secs, 12 * 3600., "round-trip 1 tz+12"); + check_round_trip(secs, -12 * 3600., "round-trip 1 tz-12"); // a time in July (opposite DST situation) secs = DICOM_datetime_to_secs_since_Unix_epoch("20200720235901.5+0000"); check_round_trip(secs, 0., "round-trip 2 tz+0"); - check_round_trip(secs, 5.5*3600., "round-trip 2 tz+5.5"); - check_round_trip(secs, 12*3600., "round-trip 2 tz+12"); - check_round_trip(secs, -12*3600., "round-trip 2 tz-12"); + check_round_trip(secs, 5.5 * 3600., "round-trip 2 tz+5.5"); + check_round_trip(secs, 12 * 3600., "round-trip 2 tz+12"); + check_round_trip(secs, -12 * 3600., "round-trip 2 tz-12"); } std::cerr << "\nCurrent timezone offset in hours (I cannot check this though):\n" - << " without DST: " << time_zone_offset_in_secs()/3600. - << " with DST: " << current_time_zone_and_DST_offset_in_secs()/3600. - << "\n"; - + << " without DST: " << time_zone_offset_in_secs() / 3600. + << " with DST: " << current_time_zone_and_DST_offset_in_secs() / 3600. << "\n"; } void -DateTimeTest:: -check_round_trip(const double secs, const double tz_offset, const std::string& str) -{ - try +DateTimeTest::check_round_trip(const double secs, const double tz_offset, const std::string& str) { + try { { - { - const std::string time = secs_since_Unix_epoch_to_DICOM_datetime(secs, tz_offset); - const double new_secs = DICOM_datetime_to_secs_since_Unix_epoch(time); - check_if_zero(new_secs - secs, str + " : " +time); - } - { - const DateTimeStrings dt = secs_since_Unix_epoch_to_Interfile_datetime(secs, tz_offset); - const double new_secs = Interfile_datetime_to_secs_since_Unix_epoch(dt); - check_if_zero(new_secs - secs, str + " : " + dt.date + ", " + dt.time); - } + const std::string time = secs_since_Unix_epoch_to_DICOM_datetime(secs, tz_offset); + const double new_secs = DICOM_datetime_to_secs_since_Unix_epoch(time); + check_if_zero(new_secs - secs, str + " : " + time); } - catch (...) { - check(false, str); + const DateTimeStrings dt = secs_since_Unix_epoch_to_Interfile_datetime(secs, tz_offset); + const double new_secs = Interfile_datetime_to_secs_since_Unix_epoch(dt); + check_if_zero(new_secs - secs, str + " : " + dt.date + ", " + dt.time); } + } catch (...) { + check(false, str); + } } - END_NAMESPACE_STIR - - USING_NAMESPACE_STIR - - -int main() -{ +int +main() { DateTimeTest tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_DynamicDiscretisedDensity.cxx b/src/test/test_DynamicDiscretisedDensity.cxx index 2519637963..09d8036da0 100644 --- a/src/test/test_DynamicDiscretisedDensity.cxx +++ b/src/test/test_DynamicDiscretisedDensity.cxx @@ -50,255 +50,263 @@ using std::string; #endif START_NAMESPACE_STIR - - class DynamicDiscretisedDensityTests : public RunTests - { - public: - DynamicDiscretisedDensityTests() - {} - void run_tests(); - //private: - }; - - void DynamicDiscretisedDensityTests::run_tests() -{ + +class DynamicDiscretisedDensityTests : public RunTests { +public: + DynamicDiscretisedDensityTests() {} + void run_tests(); + // private: +}; + +void +DynamicDiscretisedDensityTests::run_tests() { { - // Simple Test of one voxel - cerr << "Testing DynamicDiscretisedDensity class for one voxel..." << endl; - - set_tolerance(0.000000000000001); - const CartesianCoordinate3D< float > origin (0.F,0.F,0.F); - BasicCoordinate<3, float > grid_spacing ; - grid_spacing[1] = 1.F; - grid_spacing[2] = 1.F; - grid_spacing[3] = 1.F; - BasicCoordinate<3,int> sizes ; - sizes[1]=1; - sizes[2]=1; - sizes[3]=1; - IndexRange<3> range(sizes); - - const shared_ptr > - frame1_sptr(new VoxelsOnCartesianGrid (range, origin, grid_spacing)); - (*frame1_sptr)[0][0][0] = 1.F; - - std::vector< std::pair< double, double > > time_frame_definitions_vector(1) ; - std::pair< double, double > time_frame_pair(1.,2.5); - time_frame_definitions_vector[0]=time_frame_pair; - const TimeFrameDefinitions time_frame_definitions(time_frame_definitions_vector); - const double scan_start_time_in_secs_since_1970 = double(1277478034); // somewhere in June 2010... - - Scanner::Type test_scanner=Scanner::E966; - shared_ptr scanner_sptr(new Scanner(test_scanner)); - DynamicDiscretisedDensity dynamic_image(time_frame_definitions, scan_start_time_in_secs_since_1970, scanner_sptr); - ExamInfo exam_info = frame1_sptr->get_exam_info(); - exam_info.set_time_frame_definitions(time_frame_definitions); - exam_info.start_time_in_secs_since_1970 = scan_start_time_in_secs_since_1970; - frame1_sptr->set_exam_info(exam_info); - dynamic_image.set_density(*frame1_sptr, 1); - check_if_equal(dynamic_image[1][0][0][0],1.F,"check DynamicDiscretisedDensity class implementation"); + // Simple Test of one voxel + cerr << "Testing DynamicDiscretisedDensity class for one voxel..." << endl; + + set_tolerance(0.000000000000001); + const CartesianCoordinate3D origin(0.F, 0.F, 0.F); + BasicCoordinate<3, float> grid_spacing; + grid_spacing[1] = 1.F; + grid_spacing[2] = 1.F; + grid_spacing[3] = 1.F; + BasicCoordinate<3, int> sizes; + sizes[1] = 1; + sizes[2] = 1; + sizes[3] = 1; + IndexRange<3> range(sizes); + + const shared_ptr> frame1_sptr(new VoxelsOnCartesianGrid(range, origin, grid_spacing)); + (*frame1_sptr)[0][0][0] = 1.F; + + std::vector> time_frame_definitions_vector(1); + std::pair time_frame_pair(1., 2.5); + time_frame_definitions_vector[0] = time_frame_pair; + const TimeFrameDefinitions time_frame_definitions(time_frame_definitions_vector); + const double scan_start_time_in_secs_since_1970 = double(1277478034); // somewhere in June 2010... + + Scanner::Type test_scanner = Scanner::E966; + shared_ptr scanner_sptr(new Scanner(test_scanner)); + DynamicDiscretisedDensity dynamic_image(time_frame_definitions, scan_start_time_in_secs_since_1970, scanner_sptr); + ExamInfo exam_info = frame1_sptr->get_exam_info(); + exam_info.set_time_frame_definitions(time_frame_definitions); + exam_info.start_time_in_secs_since_1970 = scan_start_time_in_secs_since_1970; + frame1_sptr->set_exam_info(exam_info); + dynamic_image.set_density(*frame1_sptr, 1); + check_if_equal(dynamic_image[1][0][0][0], 1.F, "check DynamicDiscretisedDensity class implementation"); } { - // Test of two frame images, read voxel - cerr << "Writing DynamicDiscretisedDensity class for two frames 63x128x128..." << endl; - - set_tolerance(0.001); - const CartesianCoordinate3D< float > origin (0.F,0.F,0.F); - BasicCoordinate<3, float > grid_spacing ; - grid_spacing[1] = 2.425F; - grid_spacing[2] = 2.0594F; - grid_spacing[3] = 2.0594F; - BasicCoordinate<3,int> min_size, max_size; - min_size[1]=0; min_size[2]=-64; min_size[3]=-64; - max_size[1]=63; max_size[2]=63; max_size[3]=63; - - IndexRange<3> range(min_size,max_size); - const shared_ptr > - frame1_2_sptr(new VoxelsOnCartesianGrid (range, origin, grid_spacing)); - const shared_ptr > - frame2_2_sptr(new VoxelsOnCartesianGrid (range, origin, grid_spacing)); - - for(int k=min_size[3];k > time_frame_definitions_vector(2) ; - std::pair< double, double > first_time_frame_pair(1.,3.) ; - std::pair< double, double > second_time_frame_pair(3.,6.) ; - - time_frame_definitions_vector[0]=first_time_frame_pair; - time_frame_definitions_vector[1]=second_time_frame_pair; - - const TimeFrameDefinitions time_frame_definitions(time_frame_definitions_vector); - const double scan_start_time_in_secs_since_1970 = double(1277478034); // somewhere in June 2010... - Scanner::Type test_scanner=Scanner::E966; - shared_ptr scanner_sptr(new Scanner(test_scanner)); - - DynamicDiscretisedDensity empty_dynamic_image(time_frame_definitions, - scan_start_time_in_secs_since_1970, - scanner_sptr,frame1_2_sptr); - - DynamicDiscretisedDensity dynamic_image(time_frame_definitions, - scan_start_time_in_secs_since_1970, - scanner_sptr); - ExamInfo exam_info = frame1_2_sptr->get_exam_info(); - exam_info.set_time_frame_definitions(TimeFrameDefinitions(time_frame_definitions,1)); - exam_info.start_time_in_secs_since_1970 = scan_start_time_in_secs_since_1970; - frame1_2_sptr->set_exam_info(exam_info); - exam_info.set_time_frame_definitions(TimeFrameDefinitions(time_frame_definitions,2)); - frame2_2_sptr->set_exam_info(exam_info); - dynamic_image.set_density(*frame1_2_sptr, 1); - dynamic_image.set_density(*frame2_2_sptr, 2); - - string string_test("STIRtmp_dyn2f.img"); - string string_empty_test("STIRtmp_dyn2f_empty.img"); + // Test of two frame images, read voxel + cerr << "Writing DynamicDiscretisedDensity class for two frames 63x128x128..." << endl; + + set_tolerance(0.001); + const CartesianCoordinate3D origin(0.F, 0.F, 0.F); + BasicCoordinate<3, float> grid_spacing; + grid_spacing[1] = 2.425F; + grid_spacing[2] = 2.0594F; + grid_spacing[3] = 2.0594F; + BasicCoordinate<3, int> min_size, max_size; + min_size[1] = 0; + min_size[2] = -64; + min_size[3] = -64; + max_size[1] = 63; + max_size[2] = 63; + max_size[3] = 63; + + IndexRange<3> range(min_size, max_size); + const shared_ptr> frame1_2_sptr(new VoxelsOnCartesianGrid(range, origin, grid_spacing)); + const shared_ptr> frame2_2_sptr(new VoxelsOnCartesianGrid(range, origin, grid_spacing)); + + for (int k = min_size[3]; k < min_size[3]; ++k) + for (int j = max_size[2]; j < max_size[2]; ++j) + for (int i = min_size[1]; i < min_size[1]; ++i) { + (*frame1_2_sptr)[k][j][i] = 1 * (i + j * 5.F - k * 10.F); + (*frame2_2_sptr)[k][j][i] = 2 * (i + j * 5.F - k * 10.F); + } + + std::vector> time_frame_definitions_vector(2); + std::pair first_time_frame_pair(1., 3.); + std::pair second_time_frame_pair(3., 6.); + + time_frame_definitions_vector[0] = first_time_frame_pair; + time_frame_definitions_vector[1] = second_time_frame_pair; + + const TimeFrameDefinitions time_frame_definitions(time_frame_definitions_vector); + const double scan_start_time_in_secs_since_1970 = double(1277478034); // somewhere in June 2010... + Scanner::Type test_scanner = Scanner::E966; + shared_ptr scanner_sptr(new Scanner(test_scanner)); + + DynamicDiscretisedDensity empty_dynamic_image(time_frame_definitions, scan_start_time_in_secs_since_1970, scanner_sptr, + frame1_2_sptr); + + DynamicDiscretisedDensity dynamic_image(time_frame_definitions, scan_start_time_in_secs_since_1970, scanner_sptr); + ExamInfo exam_info = frame1_2_sptr->get_exam_info(); + exam_info.set_time_frame_definitions(TimeFrameDefinitions(time_frame_definitions, 1)); + exam_info.start_time_in_secs_since_1970 = scan_start_time_in_secs_since_1970; + frame1_2_sptr->set_exam_info(exam_info); + exam_info.set_time_frame_definitions(TimeFrameDefinitions(time_frame_definitions, 2)); + frame2_2_sptr->set_exam_info(exam_info); + dynamic_image.set_density(*frame1_2_sptr, 1); + dynamic_image.set_density(*frame2_2_sptr, 2); + + string string_test("STIRtmp_dyn2f.img"); + string string_empty_test("STIRtmp_dyn2f_empty.img"); #ifdef HAVE_LLN_MATRIX - check(dynamic_image.write_to_ecat7(string_test)==Succeeded::yes,"check DynamicDiscretisedDensity::write_to_ecat7 implementation"); + check(dynamic_image.write_to_ecat7(string_test) == Succeeded::yes, + "check DynamicDiscretisedDensity::write_to_ecat7 implementation"); #endif - check_if_zero((empty_dynamic_image.get_density(1)).find_min(),"check DynamicDiscretisedDensity constructor implementation"); - check_if_zero((empty_dynamic_image.get_density(1)).find_max(),"check DynamicDiscretisedDensity constructor implementation"); - check_if_zero((empty_dynamic_image.get_density(2)).find_min(),"check DynamicDiscretisedDensity constructor implementation"); - check_if_zero((empty_dynamic_image.get_density(2)).find_max(),"check DynamicDiscretisedDensity constructor implementation"); -} - { - // Test of three frame images, read voxel - cerr << "Testing DynamicDiscretisedDensity class for three frames..." << endl; - - set_tolerance(0.001); - const CartesianCoordinate3D< float > origin (0.F,0.F,0.F); - BasicCoordinate<3, float > grid_spacing ; - grid_spacing[1] = 2.425F; - grid_spacing[2] = 2.0594F; - grid_spacing[3] = 2.0594F; - BasicCoordinate<3,int> min_size, max_size; - min_size[1]=0; min_size[2]=-64; min_size[3]=-64; - max_size[1]=63; max_size[2]=63; max_size[3]=63; - IndexRange<3> range(min_size,max_size); - const shared_ptr > - frame1_3_sptr(new VoxelsOnCartesianGrid (range, origin, grid_spacing)); - const shared_ptr > - frame2_3_sptr(new VoxelsOnCartesianGrid (range, origin, grid_spacing)); - const shared_ptr > - frame3_3_sptr(new VoxelsOnCartesianGrid (range, origin, grid_spacing)); - - for(int k=min_size[3];k > time_frame_definitions_vector(3) ; - std::pair< double, double > first_time_frame_pair(1.,3.) ; - std::pair< double, double > second_time_frame_pair(3.,6.) ; - std::pair< double, double > third_time_frame_pair(6.5,7.) ; - - time_frame_definitions_vector[0]=first_time_frame_pair; - time_frame_definitions_vector[1]=second_time_frame_pair; - time_frame_definitions_vector[2]=third_time_frame_pair; - - const TimeFrameDefinitions time_frame_definitions(time_frame_definitions_vector); - const double scan_start_time_in_secs_since_1970 = double(1277478034); // somewhere in June 2010... - Scanner::Type test_scanner=Scanner::E966; - shared_ptr scanner_sptr(new Scanner(test_scanner)); - DynamicDiscretisedDensity dynamic_image(time_frame_definitions, - scan_start_time_in_secs_since_1970, - scanner_sptr); - ExamInfo exam_info = dynamic_image.get_exam_info(); - exam_info.set_time_frame_definitions(TimeFrameDefinitions(time_frame_definitions,1)); - exam_info.start_time_in_secs_since_1970 = scan_start_time_in_secs_since_1970; - frame1_3_sptr->set_exam_info(exam_info); - - exam_info.set_time_frame_definitions(TimeFrameDefinitions(time_frame_definitions,2)); - exam_info.start_time_in_secs_since_1970 = scan_start_time_in_secs_since_1970; - frame2_3_sptr->set_exam_info(exam_info); - - exam_info.set_time_frame_definitions(TimeFrameDefinitions(time_frame_definitions,3)); - exam_info.start_time_in_secs_since_1970 = scan_start_time_in_secs_since_1970; - frame3_3_sptr->set_exam_info(exam_info); - - dynamic_image.set_density(*frame1_3_sptr, 1); - dynamic_image.set_density(*frame2_3_sptr, 2); - dynamic_image.set_density(*frame3_3_sptr, 3); - - // testing full iterators + check_if_zero((empty_dynamic_image.get_density(1)).find_min(), "check DynamicDiscretisedDensity constructor implementation"); + check_if_zero((empty_dynamic_image.get_density(1)).find_max(), "check DynamicDiscretisedDensity constructor implementation"); + check_if_zero((empty_dynamic_image.get_density(2)).find_min(), "check DynamicDiscretisedDensity constructor implementation"); + check_if_zero((empty_dynamic_image.get_density(2)).find_max(), "check DynamicDiscretisedDensity constructor implementation"); + } { - DiscretisedDensity<3,float>::const_full_iterator dens_iter; - DynamicDiscretisedDensity::const_full_iterator dyn_dens_iter = dynamic_image.begin_all_const(); - bool ok_upto_now = true; - // check frame 1 - dens_iter = frame1_3_sptr->begin_all_const(); - while (ok_upto_now && dens_iter != frame1_3_sptr->end_all_const()) - { + // Test of three frame images, read voxel + cerr << "Testing DynamicDiscretisedDensity class for three frames..." << endl; + + set_tolerance(0.001); + const CartesianCoordinate3D origin(0.F, 0.F, 0.F); + BasicCoordinate<3, float> grid_spacing; + grid_spacing[1] = 2.425F; + grid_spacing[2] = 2.0594F; + grid_spacing[3] = 2.0594F; + BasicCoordinate<3, int> min_size, max_size; + min_size[1] = 0; + min_size[2] = -64; + min_size[3] = -64; + max_size[1] = 63; + max_size[2] = 63; + max_size[3] = 63; + IndexRange<3> range(min_size, max_size); + const shared_ptr> frame1_3_sptr(new VoxelsOnCartesianGrid(range, origin, grid_spacing)); + const shared_ptr> frame2_3_sptr(new VoxelsOnCartesianGrid(range, origin, grid_spacing)); + const shared_ptr> frame3_3_sptr(new VoxelsOnCartesianGrid(range, origin, grid_spacing)); + + for (int k = min_size[3]; k < min_size[3]; ++k) + for (int j = max_size[2]; j < max_size[2]; ++j) + for (int i = min_size[1]; i < min_size[1]; ++i) { + (*frame1_3_sptr)[k][j][i] = 1 * (i + j * 5.F - k * 10.F); + (*frame2_3_sptr)[k][j][i] = 2 * (i + j * 5.F - k * 10.F); + (*frame3_3_sptr)[k][j][i] = 3 * (i + j * 5.F - k * 10.F); + } + + std::vector> time_frame_definitions_vector(3); + std::pair first_time_frame_pair(1., 3.); + std::pair second_time_frame_pair(3., 6.); + std::pair third_time_frame_pair(6.5, 7.); + + time_frame_definitions_vector[0] = first_time_frame_pair; + time_frame_definitions_vector[1] = second_time_frame_pair; + time_frame_definitions_vector[2] = third_time_frame_pair; + + const TimeFrameDefinitions time_frame_definitions(time_frame_definitions_vector); + const double scan_start_time_in_secs_since_1970 = double(1277478034); // somewhere in June 2010... + Scanner::Type test_scanner = Scanner::E966; + shared_ptr scanner_sptr(new Scanner(test_scanner)); + DynamicDiscretisedDensity dynamic_image(time_frame_definitions, scan_start_time_in_secs_since_1970, scanner_sptr); + ExamInfo exam_info = dynamic_image.get_exam_info(); + exam_info.set_time_frame_definitions(TimeFrameDefinitions(time_frame_definitions, 1)); + exam_info.start_time_in_secs_since_1970 = scan_start_time_in_secs_since_1970; + frame1_3_sptr->set_exam_info(exam_info); + + exam_info.set_time_frame_definitions(TimeFrameDefinitions(time_frame_definitions, 2)); + exam_info.start_time_in_secs_since_1970 = scan_start_time_in_secs_since_1970; + frame2_3_sptr->set_exam_info(exam_info); + + exam_info.set_time_frame_definitions(TimeFrameDefinitions(time_frame_definitions, 3)); + exam_info.start_time_in_secs_since_1970 = scan_start_time_in_secs_since_1970; + frame3_3_sptr->set_exam_info(exam_info); + + dynamic_image.set_density(*frame1_3_sptr, 1); + dynamic_image.set_density(*frame2_3_sptr, 2); + dynamic_image.set_density(*frame3_3_sptr, 3); + + // testing full iterators + { + DiscretisedDensity<3, float>::const_full_iterator dens_iter; + DynamicDiscretisedDensity::const_full_iterator dyn_dens_iter = dynamic_image.begin_all_const(); + bool ok_upto_now = true; + // check frame 1 + dens_iter = frame1_3_sptr->begin_all_const(); + while (ok_upto_now && dens_iter != frame1_3_sptr->end_all_const()) { ok_upto_now = check_if_equal(*dyn_dens_iter++, *dens_iter++, "check full-iterator: frame 1"); } - // check frame 2 - dens_iter = frame2_3_sptr->begin_all_const(); - while (ok_upto_now && dens_iter != frame2_3_sptr->end_all_const()) - { + // check frame 2 + dens_iter = frame2_3_sptr->begin_all_const(); + while (ok_upto_now && dens_iter != frame2_3_sptr->end_all_const()) { ok_upto_now = check_if_equal(*dyn_dens_iter++, *dens_iter++, "check full-iterator: frame 1"); } - // check frame 3 - dens_iter = frame3_3_sptr->begin_all_const(); - while (ok_upto_now && dens_iter != frame3_3_sptr->end_all_const()) - { + // check frame 3 + dens_iter = frame3_3_sptr->begin_all_const(); + while (ok_upto_now && dens_iter != frame3_3_sptr->end_all_const()) { ok_upto_now = check_if_equal(*dyn_dens_iter++, *dens_iter++, "check full-iterator: frame 1"); - } - } + } + } #ifndef HAVE_LLN_MATRIX - warning("write_to_ecat7 not tested as LLN library not present"); + warning("write_to_ecat7 not tested as LLN library not present"); #else - string string_test("STIRtmp_dyn3f.img");//TODO: Use the path info!!! - // string string_test2("./local/samples/dyn_image_write_to_ecat7_test2.img"); - // dynamic_image.write_to_ecat7(string_test); - check(dynamic_image.write_to_ecat7(string_test)==Succeeded::yes,"check DynamicDiscretisedDensity::write_to_ecat7 implementation"); - shared_ptr< DynamicDiscretisedDensity > - dyn_image_read_test_sptr(read_from_file(string_test)); - const DynamicDiscretisedDensity & dyn_image_read_test = *dyn_image_read_test_sptr; - // dyn_image_read_test.write_to_ecat7(string_test2); - - for(int k=min_size[3];k dyn_image_read_test_sptr(read_from_file(string_test)); + const DynamicDiscretisedDensity& dyn_image_read_test = *dyn_image_read_test_sptr; + // dyn_image_read_test.write_to_ecat7(string_test2); + + for (int k = min_size[3]; k < min_size[3]; ++k) + for (int j = max_size[2]; j < max_size[2]; ++j) + for (int i = min_size[1]; i < min_size[1]; ++i) { + check_if_equal(dynamic_image[1][k][j][i], (*frame1_3_sptr)[k][j][i], + "check DynamicDiscretisedDensity class implementation"); + check_if_equal(dynamic_image[2][k][j][i], (*frame2_3_sptr)[k][j][i], + "check DynamicDiscretisedDensity class implementation"); + check_if_equal(dynamic_image[3][k][j][i], (*frame3_3_sptr)[k][j][i], + "check DynamicDiscretisedDensity class implementation"); + check_if_equal(dyn_image_read_test[1][k][j - 64][i - 64], (*frame1_3_sptr)[k][j][i], + "check DynamicDiscretisedDensity::read_from_file implementation"); // The written image is read in + // respect to its center as origin!!! + check_if_equal(dyn_image_read_test[2][k][j - 64][i - 64], (*frame2_3_sptr)[k][j][i], + "check DynamicDiscretisedDensity::read_from_file implementation"); + check_if_equal(dyn_image_read_test[3][k][j - 64][i - 64], (*frame3_3_sptr)[k][j][i], + "check DynamicDiscretisedDensity::read_from_file implementation"); } - check_if_equal((dynamic_image.get_time_frame_definitions()).get_end_time(1),3.,"check DynamicDiscretisedDensity class implementation"); - check_if_equal((dynamic_image.get_time_frame_definitions()).get_start_time(1),1.,"check DynamicDiscretisedDensity class implementation"); - check_if_equal((dynamic_image.get_time_frame_definitions()).get_end_time(2),6.,"check DynamicDiscretisedDensity class implementation"); - check_if_equal((dynamic_image.get_time_frame_definitions()).get_start_time(2),3.,"check DynamicDiscretisedDensity class implementation"); - check_if_equal((dynamic_image.get_time_frame_definitions()).get_end_time(3),7.,"check DynamicDiscretisedDensity class implementation"); - check_if_equal((dynamic_image.get_time_frame_definitions()).get_start_time(3),6.5,"check DynamicDiscretisedDensity class implementation"); + check_if_equal((dynamic_image.get_time_frame_definitions()).get_end_time(1), 3., + "check DynamicDiscretisedDensity class implementation"); + check_if_equal((dynamic_image.get_time_frame_definitions()).get_start_time(1), 1., + "check DynamicDiscretisedDensity class implementation"); + check_if_equal((dynamic_image.get_time_frame_definitions()).get_end_time(2), 6., + "check DynamicDiscretisedDensity class implementation"); + check_if_equal((dynamic_image.get_time_frame_definitions()).get_start_time(2), 3., + "check DynamicDiscretisedDensity class implementation"); + check_if_equal((dynamic_image.get_time_frame_definitions()).get_end_time(3), 7., + "check DynamicDiscretisedDensity class implementation"); + check_if_equal((dynamic_image.get_time_frame_definitions()).get_start_time(3), 6.5, + "check DynamicDiscretisedDensity class implementation"); // test if info read is ok - check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_end_time(1),3.,"check DynamicDiscretisedDensity class implementation"); - check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_start_time(1),1.,"check DynamicDiscretisedDensity class implementation"); - check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_end_time(2),6.,"check DynamicDiscretisedDensity class implementation"); - check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_start_time(2),3.,"check DynamicDiscretisedDensity class implementation"); - check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_end_time(3),7.,"check DynamicDiscretisedDensity class implementation"); - check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_start_time(3),6.5,"check DynamicDiscretisedDensity class implementation"); + check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_end_time(1), 3., + "check DynamicDiscretisedDensity class implementation"); + check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_start_time(1), 1., + "check DynamicDiscretisedDensity class implementation"); + check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_end_time(2), 6., + "check DynamicDiscretisedDensity class implementation"); + check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_start_time(2), 3., + "check DynamicDiscretisedDensity class implementation"); + check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_end_time(3), 7., + "check DynamicDiscretisedDensity class implementation"); + check_if_equal((dyn_image_read_test.get_time_frame_definitions()).get_start_time(3), 6.5, + "check DynamicDiscretisedDensity class implementation"); #endif - } + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 1) - { +int +main(int argc, char** argv) { + if (argc != 1) { cerr << "Usage : " << argv[0] << " \n"; return EXIT_FAILURE; } diff --git a/src/test/test_GeneralisedPoissonNoiseGenerator.cxx b/src/test/test_GeneralisedPoissonNoiseGenerator.cxx index 6fd38c5281..acaed1be4d 100644 --- a/src/test/test_GeneralisedPoissonNoiseGenerator.cxx +++ b/src/test/test_GeneralisedPoissonNoiseGenerator.cxx @@ -16,10 +16,10 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup test \ingroup buildblock - + \brief tests for the stir::GeneralisedPoissonNoiseGenerator class \author Kris Thielemans @@ -36,56 +36,51 @@ START_NAMESPACE_STIR - /*! \brief Tests GeneralisedPoissonNoiseGenerator functionality \ingroup test Currently contains only simple tests to check mean and variance. */ -class GeneralisedPoissonNoiseGeneratorTests : public RunTests -{ +class GeneralisedPoissonNoiseGeneratorTests : public RunTests { private: - void - run_one_test(const int size, const float mu, const float scaling_factor, const bool preserve_mean); - + void run_one_test(const int size, const float mu, const float scaling_factor, const bool preserve_mean); + public: void run_tests(); }; void -GeneralisedPoissonNoiseGeneratorTests:: -run_one_test(const int size, const float mu, const float scaling_factor, const bool preserve_mean) -{ - Array<1,float> input(size); - Array<1,float> output(size); +GeneralisedPoissonNoiseGeneratorTests::run_one_test(const int size, const float mu, const float scaling_factor, + const bool preserve_mean) { + Array<1, float> input(size); + Array<1, float> output(size); input.fill(mu); GeneralisedPoissonNoiseGenerator generator(scaling_factor, preserve_mean); generator.generate_random(output, input); - + using namespace boost::accumulators; - - // The accumulator set which will calculate the properties for us: - accumulator_set< float, features< tag::variance, tag::mean > > acc; + + // The accumulator set which will calculate the properties for us: + accumulator_set> acc; // Use std::for_each to accumulate the statistical properties: - acc = std::for_each( output.begin(), output.end(), acc ); + acc = std::for_each(output.begin(), output.end(), acc); set_tolerance(.1); - const float actual_mean = preserve_mean? mu : mu*scaling_factor; - const float actual_variance = preserve_mean? mu/scaling_factor : actual_mean; + const float actual_mean = preserve_mean ? mu : mu * scaling_factor; + const float actual_variance = preserve_mean ? mu / scaling_factor : actual_mean; boost::format formatter("size %1%, mu %2%, scaling_factor %3%, preserve_mean %4%"); formatter % size % mu % scaling_factor % preserve_mean; - + check_if_equal(mean(acc), actual_mean, "test mean with " + formatter.str()); check_if_equal(variance(acc), actual_variance, "test variance with " + formatter.str()); } void -GeneralisedPoissonNoiseGeneratorTests::run_tests() -{ +GeneralisedPoissonNoiseGeneratorTests::run_tests() { std::cerr << "Testing GeneralisedPoissonNoiseGenerator\n"; @@ -102,8 +97,8 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { GeneralisedPoissonNoiseGeneratorTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_IndexRange.cxx b/src/test/test_IndexRange.cxx index 1a3945ed7e..bfd9c7cbdc 100644 --- a/src/test/test_IndexRange.cxx +++ b/src/test/test_IndexRange.cxx @@ -2,8 +2,8 @@ // /*! - \file - + \file + \brief A simple program to test the stir::IndexRange class \author Kris Thielemans @@ -44,109 +44,87 @@ START_NAMESPACE_STIR /*! \brief Class with tests for IndexRange, IndexRange3D. */ -class IndexRange_Tests : public RunTests -{ +class IndexRange_Tests : public RunTests { public: void run_tests(); }; - void -IndexRange_Tests::run_tests() -{ +IndexRange_Tests::run_tests() { cerr << "Testing IndexRange classes" << endl - <<" (There should be only informative messages here starting with 'Testing')" << endl; + << " (There should be only informative messages here starting with 'Testing')" << endl; // make an irregular range { - IndexRange<1> range1(1,3); - IndexRange<1> range2(2,4); - VectorWithOffset< IndexRange<1> > range2d(3,4); - range2d[3]=range1; - range2d[4]=range2; + IndexRange<1> range1(1, 3); + IndexRange<1> range2(2, 4); + VectorWithOffset> range2d(3, 4); + range2d[3] = range1; + range2d[4] = range2; IndexRange<2> idx_range2d = range2d; - - check(idx_range2d[3].get_min_index() == range1.get_min_index(), - "testing constructor from base_type"); - check(idx_range2d[3].get_max_index() == range1.get_max_index(), - "testing constructor from base_type"); - check(idx_range2d.is_regular()==false, - "testing is_regular on irregular range"); + + check(idx_range2d[3].get_min_index() == range1.get_min_index(), "testing constructor from base_type"); + check(idx_range2d[3].get_max_index() == range1.get_max_index(), "testing constructor from base_type"); + check(idx_range2d.is_regular() == false, "testing is_regular on irregular range"); } // make a regular range { - IndexRange<1> range1(1,3); - VectorWithOffset< IndexRange<1> > range2d(3,4); - range2d[3]=range1; - range2d[4]=range1; + IndexRange<1> range1(1, 3); + VectorWithOffset> range2d(3, 4); + range2d[3] = range1; + range2d[4] = range1; IndexRange<2> idx_range2d = range2d; - - check(idx_range2d[3].get_min_index() == range1.get_min_index(), - "testing constructor from base_type"); - check(idx_range2d[3].get_max_index() == range1.get_max_index(), - "testing constructor from base_type"); - check(idx_range2d.is_regular()==true, - "testing is_regular on irregular range"); - - IndexRange2D another_idx_range2d(3,4, 1,3); + + check(idx_range2d[3].get_min_index() == range1.get_min_index(), "testing constructor from base_type"); + check(idx_range2d[3].get_max_index() == range1.get_max_index(), "testing constructor from base_type"); + check(idx_range2d.is_regular() == true, "testing is_regular on irregular range"); + + IndexRange2D another_idx_range2d(3, 4, 1, 3); check(another_idx_range2d == idx_range2d, "test IndexRange2D"); } { - Coordinate3D low(1,2,3); - Coordinate3D high(3,4,5); + Coordinate3D low(1, 2, 3); + Coordinate3D high(3, 4, 5); IndexRange<3> idx_range3d(low, high); - - check(idx_range3d[3].get_max_index() == 4, - "testing constructor from 2 Coordinate objects"); - check(idx_range3d.is_regular()==true, - "testing is_regular on regular range"); + + check(idx_range3d[3].get_max_index() == 4, "testing constructor from 2 Coordinate objects"); + check(idx_range3d.is_regular() == true, "testing is_regular on regular range"); Coordinate3D low_test, high_test; - if (idx_range3d.get_regular_range(low_test, high_test)) - { + if (idx_range3d.get_regular_range(low_test, high_test)) { check_if_equal(low, low_test, "testing is_regular on regular range: lower indices"); check_if_equal(high, high_test, "testing is_regular on regular range: higher indices"); } - IndexRange3D another_idx_range3d(low[1],high[1], low[2], high[2], low[3], high[3]); + IndexRange3D another_idx_range3d(low[1], high[1], low[2], high[2], low[3], high[3]); check(another_idx_range3d == idx_range3d, "test IndexRange3D"); } { - const Coordinate3D sizes(3,4,5); + const Coordinate3D sizes(3, 4, 5); const IndexRange<3> idx_range3d(sizes); - - check(idx_range3d.get_max_index() == 2, - "testing constructor from 1 Coordinate object"); - check(idx_range3d[0].get_max_index() == 3, - "testing constructor from 1 Coordinate object"); - check(idx_range3d[0][0].get_max_index() == 4, - "testing constructor from 1 Coordinate object"); - check(idx_range3d.is_regular()==true, - "testing is_regular on regular range"); + + check(idx_range3d.get_max_index() == 2, "testing constructor from 1 Coordinate object"); + check(idx_range3d[0].get_max_index() == 3, "testing constructor from 1 Coordinate object"); + check(idx_range3d[0][0].get_max_index() == 4, "testing constructor from 1 Coordinate object"); + check(idx_range3d.is_regular() == true, "testing is_regular on regular range"); Coordinate3D low_test, high_test; - if (idx_range3d.get_regular_range(low_test, high_test)) - { - check_if_equal(Coordinate3D(0,0,0), low_test, "testing is_regular on regular range: lower indices"); - check_if_equal(sizes-1, high_test, "testing is_regular on regular range: higher indices"); + if (idx_range3d.get_regular_range(low_test, high_test)) { + check_if_equal(Coordinate3D(0, 0, 0), low_test, "testing is_regular on regular range: lower indices"); + check_if_equal(sizes - 1, high_test, "testing is_regular on regular range: higher indices"); } const IndexRange3D another_idx_range3d(sizes[1], sizes[2], sizes[3]); check(another_idx_range3d == idx_range3d, "test IndexRange3D"); } - } END_NAMESPACE_STIR - - USING_NAMESPACE_STIR - -int main() -{ +int +main() { IndexRange_Tests tests; tests.run_tests(); return tests.main_return_value(); - } diff --git a/src/test/test_KeyParser.cxx b/src/test/test_KeyParser.cxx index 6116934d6c..5ed8e45075 100644 --- a/src/test/test_KeyParser.cxx +++ b/src/test/test_KeyParser.cxx @@ -3,8 +3,8 @@ /* Copyright (C) 2020, University College London This file is part of STIR. - - This file is free software; you can redistribute it and/or modify + + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. @@ -34,14 +34,9 @@ START_NAMESPACE_STIR template -class TestKP : public KeyParser -{ +class TestKP : public KeyParser { public: - TestKP() - : - scalar_v(0), - vector_v(2,0) - { + TestKP() : scalar_v(0), vector_v(2, 0) { add_start_key("start"); add_stop_key("stop"); add_key("scalar", &scalar_v); @@ -56,16 +51,15 @@ class TestKP : public KeyParser \brief Test class for KeyParser */ -class KeyParserTests : public RunTests -{ +class KeyParserTests : public RunTests { public: - template void run_tests_one_type(); + template + void run_tests_one_type(); void run_tests(); }; void -KeyParserTests::run_tests() -{ +KeyParserTests::run_tests() { std::cerr << "Tests for KeyParser\n"; std::cerr << "... int parsing\n"; run_tests_one_type(); @@ -79,10 +73,9 @@ KeyParserTests::run_tests() template void -KeyParserTests::run_tests_one_type() -{ +KeyParserTests::run_tests_one_type() { - TestKP parser; + TestKP parser; // basic test if parsing ok { std::stringstream str; @@ -101,16 +94,13 @@ KeyParserTests::run_tests_one_type() << "scalar[1]:=2\n" << "vector[1] := 3\n" << "stop :=\n"; - try - { - std::cerr << "Next test should write an error (but not crash!)" << std::endl; - parser.parse(str); - check(false, "parsing non-vectorised key with vector should have failed"); - } - catch (...) - { - // ok - } + try { + std::cerr << "Next test should write an error (but not crash!)" << std::endl; + parser.parse(str); + check(false, "parsing non-vectorised key with vector should have failed"); + } catch (...) { + // ok + } } // test 2 if parsing catches errors { @@ -119,28 +109,22 @@ KeyParserTests::run_tests_one_type() << "scalar:=2\n" << "vector := 3\n" << "stop :=\n"; - try - { - std::cerr << "Next test should write an error (but not crash!)" << std::endl; - parser.parse(str); - check(false, "parsing vectorised key with non-vector should have failed"); - } - catch (...) - { - // ok - } + try { + std::cerr << "Next test should write an error (but not crash!)" << std::endl; + parser.parse(str); + check(false, "parsing vectorised key with non-vector should have failed"); + } catch (...) { + // ok + } } - } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main() -{ +int +main() { KeyParserTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_NestedIterator.cxx b/src/test/test_NestedIterator.cxx index 39bfcbde78..1a36c74d2f 100644 --- a/src/test/test_NestedIterator.cxx +++ b/src/test/test_NestedIterator.cxx @@ -16,9 +16,9 @@ */ /*! - \file + \file \ingroup test - + \brief tests for the stir::NestedIterator class \author Kris Thielemans @@ -44,334 +44,288 @@ START_NAMESPACE_STIR \todo Code is ugly. Copy-paste with tiny modifications. */ -class NestedIteratorTests : public RunTests -{ +class NestedIteratorTests : public RunTests { private: - public: void run_tests(); }; - void -NestedIteratorTests::run_tests() -{ +NestedIteratorTests::run_tests() { std::cerr << "Testing NestedIterator\n"; { std::cerr << "Compare with full iterator\n"; { - IndexRange<2> range(make_coordinate(0,0),make_coordinate(2,2)); - Array<2,float> test2(range); + IndexRange<2> range(make_coordinate(0, 0), make_coordinate(2, 2)); + Array<2, float> test2(range); { float value = 1.2F; - for (Array<2,float>::full_iterator iter = test2.begin_all(); - iter != test2.end_all(); - ) + for (Array<2, float>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) *iter++ = value++; } - check(test2.begin()->begin() == BeginEndFunction::iterator>().begin(test2.begin()), "begin"); - check((test2.begin()+1)->begin() == BeginEndFunction::iterator>().begin(test2.begin()+1), "begin"); - typedef NestedIterator::iterator> FullIter; + check(test2.begin()->begin() == BeginEndFunction::iterator>().begin(test2.begin()), "begin"); + check((test2.begin() + 1)->begin() == BeginEndFunction::iterator>().begin(test2.begin() + 1), "begin"); + typedef NestedIterator::iterator> FullIter; FullIter fiter1; - FullIter fiter(test2.begin(),test2.end()); - //fiter1=fiter; - const FullIter fiter_end(test2.end(),test2.end()); - for (Array<2,float>::full_iterator iter = test2.begin_all(); - iter != test2.end_all(); - ) - { - check(fiter!=fiter_end, "fiter"); - check(*fiter++ == *iter++,"fiter=="); - } - - check(fiter==fiter_end,"fiter end"); + FullIter fiter(test2.begin(), test2.end()); + // fiter1=fiter; + const FullIter fiter_end(test2.end(), test2.end()); + for (Array<2, float>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) { + check(fiter != fiter_end, "fiter"); + check(*fiter++ == *iter++, "fiter=="); + } + + check(fiter == fiter_end, "fiter end"); // check(test2.begin()->begin() == make_begin_function(test2.begin())(), "begin"); - const Array<2,float> empty; + const Array<2, float> empty; check(empty.begin_all() == empty.end_all(), "test on 2D full iterator for empty range"); } } - std::cerr<< " full iterator coord\n"; + std::cerr << " full iterator coord\n"; { - IndexRange<2> range(make_coordinate(0,0),make_coordinate(2,2)); - typedef BasicCoordinate<2,float> elemT; - Array<2,elemT > test2(range); + IndexRange<2> range(make_coordinate(0, 0), make_coordinate(2, 2)); + typedef BasicCoordinate<2, float> elemT; + Array<2, elemT> test2(range); { float value = 1.2F; - for (Array<2,elemT>::full_iterator iter = test2.begin_all(); - iter != test2.end_all(); - ) - { - *iter++ = make_coordinate(value,value+.3F); - ++value; - } + for (Array<2, elemT>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) { + *iter++ = make_coordinate(value, value + .3F); + ++value; + } } - check(test2.begin()->begin() == BeginEndFunction::iterator>().begin(test2.begin()), "begin"); - check((test2.begin()+1)->begin() == BeginEndFunction::iterator>().begin(test2.begin()+1), "begin"); - typedef NestedIterator::iterator> - FullIter; + check(test2.begin()->begin() == BeginEndFunction::iterator>().begin(test2.begin()), "begin"); + check((test2.begin() + 1)->begin() == BeginEndFunction::iterator>().begin(test2.begin() + 1), "begin"); + typedef NestedIterator::iterator> FullIter; FullIter fiter1; - FullIter fiter(test2.begin(),test2.end()); - //fiter1=fiter; - const FullIter fiter_end(test2.end(),test2.end()); + FullIter fiter(test2.begin(), test2.end()); + // fiter1=fiter; + const FullIter fiter_end(test2.end(), test2.end()); { - for (Array<2,elemT>::full_iterator iter = test2.begin_all(); - iter != test2.end_all(); - ) - { - check(fiter!=fiter_end, "fiter"); - check(*fiter++ == *iter++,"fiter=="); - } + for (Array<2, elemT>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) { + check(fiter != fiter_end, "fiter"); + check(*fiter++ == *iter++, "fiter=="); + } } - check(fiter==fiter_end,"fiter end"); + check(fiter == fiter_end, "fiter end"); } - std::cerr<< " full iterator coord\n"; + std::cerr << " full iterator coord\n"; { - IndexRange<2> range(make_coordinate(0,0),make_coordinate(2,2)); - typedef BasicCoordinate<2,float> elemT; - Array<2,elemT > test(range); + IndexRange<2> range(make_coordinate(0, 0), make_coordinate(2, 2)); + typedef BasicCoordinate<2, float> elemT; + Array<2, elemT> test(range); { float value = 1.2F; - for (Array<2,elemT>::full_iterator iter = test.begin_all(); - iter != test.end_all(); - ) - { - *iter++ = make_coordinate(value,value+.3F); - ++value; - } + for (Array<2, elemT>::full_iterator iter = test.begin_all(); iter != test.end_all();) { + *iter++ = make_coordinate(value, value + .3F); + ++value; + } } - const Array<2,elemT> test2 = test; -# if defined __GNUC__ && __GNUC__ < 3 + const Array<2, elemT> test2 = test; +#if defined __GNUC__ && __GNUC__ < 3 // at some point, it seemed we needed a work-around for gcc 3 or earlier, but that is no longer the case - typedef BeginEndFunction::const_iterator> constbeginendfunction_type; + typedef BeginEndFunction::const_iterator> constbeginendfunction_type; #else - typedef ConstBeginEndFunction::const_iterator> constbeginendfunction_type; + typedef ConstBeginEndFunction::const_iterator> constbeginendfunction_type; #endif check(test2.begin()->begin() == constbeginendfunction_type().begin(test2.begin()), "begin"); - check((test2.begin()+1)->begin() == constbeginendfunction_type().begin(test2.begin()+1), "begin"); - typedef NestedIterator::const_iterator, constbeginendfunction_type> - FullIter; + check((test2.begin() + 1)->begin() == constbeginendfunction_type().begin(test2.begin() + 1), "begin"); + typedef NestedIterator::const_iterator, constbeginendfunction_type> FullIter; FullIter fiter1; - FullIter fiter(test2.begin(),test2.end()); - //fiter1=fiter; - FullIter fiter_end(test2.end(),test2.end()); - + FullIter fiter(test2.begin(), test2.end()); + // fiter1=fiter; + FullIter fiter_end(test2.end(), test2.end()); + { - for (Array<2,elemT>::const_full_iterator iter = test2.begin_all_const(); - iter != test2.end_all_const(); - ) - { - check(fiter!=fiter_end, "fiter"); - check(*fiter++ == *iter++,"fiter=="); - } + for (Array<2, elemT>::const_full_iterator iter = test2.begin_all_const(); iter != test2.end_all_const();) { + check(fiter != fiter_end, "fiter"); + check(*fiter++ == *iter++, "fiter=="); + } } - check(fiter==fiter_end,"fiter end"); + check(fiter == fiter_end, "fiter end"); } - std::cerr<< " full iterator coord full\n"; + std::cerr << " full iterator coord full\n"; { - IndexRange<2> range(make_coordinate(0,0),make_coordinate(2,2)); - typedef BasicCoordinate<2,float> elemT; - Array<2,elemT > test2(range); + IndexRange<2> range(make_coordinate(0, 0), make_coordinate(2, 2)); + typedef BasicCoordinate<2, float> elemT; + Array<2, elemT> test2(range); { float value = 1.2F; - for (Array<2,elemT>::full_iterator iter = test2.begin_all(); - iter != test2.end_all(); - ) - { - *iter++ = make_coordinate(value,value+.3F); - ++value; - } + for (Array<2, elemT>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) { + *iter++ = make_coordinate(value, value + .3F); + ++value; + } } - check(test2.begin()->begin() == BeginEndFunction::iterator>().begin(test2.begin()), "begin"); - check((test2.begin()+1)->begin() == BeginEndFunction::iterator>().begin(test2.begin()+1), "begin"); - typedef - NestedIterator::full_iterator, - BeginEndFunction::full_iterator> > - FullIter; + check(test2.begin()->begin() == BeginEndFunction::iterator>().begin(test2.begin()), "begin"); + check((test2.begin() + 1)->begin() == BeginEndFunction::iterator>().begin(test2.begin() + 1), "begin"); + typedef NestedIterator::full_iterator, BeginEndFunction::full_iterator>> FullIter; FullIter fiter1; - FullIter fiter(test2.begin_all(),test2.end_all()); - //fiter1=fiter; - FullIter fiter_end(test2.end_all(),test2.end_all()); - + FullIter fiter(test2.begin_all(), test2.end_all()); + // fiter1=fiter; + FullIter fiter_end(test2.end_all(), test2.end_all()); + { - for (Array<2,elemT>::full_iterator iter = test2.begin_all(); - iter != test2.end_all(); - ) - { - check(fiter!=fiter_end, "fiter"); - check_if_equal(*fiter++, *iter->begin(),"fiter== 0"); - check_if_equal(*fiter++,*(iter->begin()+1),"fiter== 1"); - ++iter; - } + for (Array<2, elemT>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) { + check(fiter != fiter_end, "fiter"); + check_if_equal(*fiter++, *iter->begin(), "fiter== 0"); + check_if_equal(*fiter++, *(iter->begin() + 1), "fiter== 1"); + ++iter; + } } - check(fiter==fiter_end,"fiter end"); + check(fiter == fiter_end, "fiter end"); } - std::cerr<< " full iterator coord full const\n"; + std::cerr << " full iterator coord full const\n"; { - IndexRange<2> range(make_coordinate(0,0),make_coordinate(2,2)); - typedef BasicCoordinate<2,float> elemT; - Array<2,elemT > test(range); + IndexRange<2> range(make_coordinate(0, 0), make_coordinate(2, 2)); + typedef BasicCoordinate<2, float> elemT; + Array<2, elemT> test(range); { float value = 1.2F; - for (Array<2,elemT>::full_iterator iter = test.begin_all(); - iter != test.end_all(); - ) - { - *iter++ = make_coordinate(value,value+.3F); - ++value; - } - + for (Array<2, elemT>::full_iterator iter = test.begin_all(); iter != test.end_all();) { + *iter++ = make_coordinate(value, value + .3F); + ++value; + } } - const Array<2,elemT> test2 = test; + const Array<2, elemT> test2 = test; - check(test2.begin_all_const()->begin() == ConstBeginEndFunction::const_full_iterator>().begin(test2.begin_all_const()), "begin"); - typedef - NestedIterator::const_full_iterator, - ConstBeginEndFunction::const_full_iterator> > - FullIter; + check(test2.begin_all_const()->begin() == + ConstBeginEndFunction::const_full_iterator>().begin(test2.begin_all_const()), + "begin"); + typedef NestedIterator::const_full_iterator, ConstBeginEndFunction::const_full_iterator>> + FullIter; FullIter fiter1; - FullIter fiter(test2.begin_all_const(),test2.end_all_const()); - //fiter1=fiter; - FullIter fiter_end(test2.end_all_const(),test2.end_all_const()); - + FullIter fiter(test2.begin_all_const(), test2.end_all_const()); + // fiter1=fiter; + FullIter fiter_end(test2.end_all_const(), test2.end_all_const()); + { - for (Array<2,elemT>::const_full_iterator iter = test2.begin_all_const(); - iter != test2.end_all_const(); - ) - { - check(fiter!=fiter_end, "fiter"); - check_if_equal(*fiter++, *iter->begin(),"fiter== 0"); - check_if_equal(*fiter++,*(iter->begin()+1),"fiter== 1"); - ++iter; - } + for (Array<2, elemT>::const_full_iterator iter = test2.begin_all_const(); iter != test2.end_all_const();) { + check(fiter != fiter_end, "fiter"); + check_if_equal(*fiter++, *iter->begin(), "fiter== 0"); + check_if_equal(*fiter++, *(iter->begin() + 1), "fiter== 1"); + ++iter; + } } - check(fiter==fiter_end,"fiter end"); + check(fiter == fiter_end, "fiter end"); } - std::cerr<< " full iterator coord full\n"; + std::cerr << " full iterator coord full\n"; { - IndexRange<2> range(make_coordinate(0,0),make_coordinate(2,2)); - typedef BasicCoordinate<2,float> elemT; - Array<2,elemT > test2(range); + IndexRange<2> range(make_coordinate(0, 0), make_coordinate(2, 2)); + typedef BasicCoordinate<2, float> elemT; + Array<2, elemT> test2(range); { float value = 1.2F; - for (Array<2,elemT>::full_iterator iter = test2.begin_all(); - iter != test2.end_all(); - ) - { - *iter++ = make_coordinate(value,value+.3F); - ++value; - } + for (Array<2, elemT>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) { + *iter++ = make_coordinate(value, value + .3F); + ++value; + } } - check(test2.begin()->begin() == BeginEndFunction::iterator>().begin(test2.begin()), "begin"); - check((test2.begin()+1)->begin() == BeginEndFunction::iterator>().begin(test2.begin()+1), "begin"); - typedef - NestedIterator::full_iterator, - BeginEndFunction::full_iterator> > - FullIter; + check(test2.begin()->begin() == BeginEndFunction::iterator>().begin(test2.begin()), "begin"); + check((test2.begin() + 1)->begin() == BeginEndFunction::iterator>().begin(test2.begin() + 1), "begin"); + typedef NestedIterator::full_iterator, BeginEndFunction::full_iterator>> FullIter; FullIter fiter1; - FullIter fiter(test2.begin_all(),test2.end_all()); - //fiter1=fiter; - FullIter fiter_end(test2.end_all(),test2.end_all()); - + FullIter fiter(test2.begin_all(), test2.end_all()); + // fiter1=fiter; + FullIter fiter_end(test2.end_all(), test2.end_all()); + { - for (Array<2,elemT>::full_iterator iter = test2.begin_all(); - iter != test2.end_all(); - ) - { - check(fiter!=fiter_end, "fiter"); - check_if_equal(*fiter++, *iter->begin(),"fiter== 0"); - check_if_equal(*fiter++,*(iter->begin()+1),"fiter== 1"); - ++iter; - } + for (Array<2, elemT>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) { + check(fiter != fiter_end, "fiter"); + check_if_equal(*fiter++, *iter->begin(), "fiter== 0"); + check_if_equal(*fiter++, *(iter->begin() + 1), "fiter== 1"); + ++iter; + } } - check(fiter==fiter_end,"fiter end"); + check(fiter == fiter_end, "fiter end"); } - std::cerr<< " NestedIterator vector\n"; + std::cerr << " NestedIterator vector\n"; { typedef std::list C2; typedef std::vector C1; C1 c(2); - c[0].push_back(1); c[0].push_back(2); - c[1].push_back(3); c[1].push_back(4); c[1].push_back(5); + c[0].push_back(1); + c[0].push_back(2); + c[1].push_back(3); + c[1].push_back(4); + c[1].push_back(5); // normal iterator { typedef NestedIterator FullIter; - FullIter fiter(c.begin(),c.end()); - const FullIter fiter_end(c.end(),c.end()); - int count=1; - while (fiter != fiter_end) - { + FullIter fiter(c.begin(), c.end()); + const FullIter fiter_end(c.end(), c.end()); + int count = 1; + while (fiter != fiter_end) { check_if_equal(*fiter++, count++, "nestiterator of vector"); } check_if_equal(count, 6, "nestiterator of vector: num elements"); } // const iterator { - typedef NestedIterator > FullIter; - FullIter fiter(c.begin(),c.end()); - const FullIter fiter_end(c.end(),c.end()); - int count=1; - while (fiter != fiter_end) - { + typedef NestedIterator> FullIter; + FullIter fiter(c.begin(), c.end()); + const FullIter fiter_end(c.end(), c.end()); + int count = 1; + while (fiter != fiter_end) { check_if_equal(*fiter++, count++, "nestiterator of vector"); } check_if_equal(count, 6, "nestiterator of vector: num elements"); } // test conversion from full_iterator to const_full_iterator { - typedef NestedIterator > CFullIter; + typedef NestedIterator> CFullIter; typedef NestedIterator FullIter; - FullIter fiter(c.begin(),c.end()); - CFullIter cfiter= fiter; // this should compile + FullIter fiter(c.begin(), c.end()); + CFullIter cfiter = fiter; // this should compile } } - std::cerr<< " NestedIterator vector\n"; + std::cerr << " NestedIterator vector\n"; { typedef std::list C2; - typedef std::vector C1; + typedef std::vector C1; C1 c(2); c[0] = new C2; c[1] = new C2; - c[0]->push_back(1); c[0]->push_back(2); - c[1]->push_back(3); c[1]->push_back(4); c[1]->push_back(5); + c[0]->push_back(1); + c[0]->push_back(2); + c[1]->push_back(3); + c[1]->push_back(4); + c[1]->push_back(5); // normal iterator { - typedef NestedIterator > FullIter; - FullIter fiter(c.begin(),c.end()); - const FullIter fiter_end(c.end(),c.end()); - int count=1; - while (fiter != fiter_end) - { + typedef NestedIterator> FullIter; + FullIter fiter(c.begin(), c.end()); + const FullIter fiter_end(c.end(), c.end()); + int count = 1; + while (fiter != fiter_end) { check_if_equal(*fiter++, count++, "nestiterator of vector< list *>"); } check_if_equal(count, 6, "nestiterator of vector: num elements"); } // const iterator { - typedef NestedIterator > FullIter; - FullIter fiter(c.begin(),c.end()); - const FullIter fiter_end(c.end(),c.end()); - int count=1; - while (fiter != fiter_end) - { + typedef NestedIterator> FullIter; + FullIter fiter(c.begin(), c.end()); + const FullIter fiter_end(c.end(), c.end()); + int count = 1; + while (fiter != fiter_end) { check_if_equal(*fiter++, count++, "nestiterator of vector< list *>"); } check_if_equal(count, 6, "nestiterator of vector: num elements"); @@ -380,60 +334,55 @@ NestedIteratorTests::run_tests() delete c[1]; } - std::cerr<< " NestedIterator vector< shared_ptr >\n"; + std::cerr << " NestedIterator vector< shared_ptr >\n"; { - IndexRange<2> range1(make_coordinate(0,0),make_coordinate(1,2)); - IndexRange<2> range2(make_coordinate(0,0),make_coordinate(1,3)); + IndexRange<2> range1(make_coordinate(0, 0), make_coordinate(1, 2)); + IndexRange<2> range2(make_coordinate(0, 0), make_coordinate(1, 3)); typedef int elemT; - typedef Array<2,int> C2; - typedef std::vector > C1; + typedef Array<2, int> C2; + typedef std::vector> C1; C1 c(2); c[0].reset(new C2(range1)); c[1].reset(new C2(range2)); int count = 1; - for (C2::full_iterator fullarrayiter = c[0]->begin_all(); fullarrayiter != c[0]->end_all(); - ++fullarrayiter, ++count) + for (C2::full_iterator fullarrayiter = c[0]->begin_all(); fullarrayiter != c[0]->end_all(); ++fullarrayiter, ++count) *fullarrayiter = count; - for (C2::full_iterator fullarrayiter = c[1]->begin_all(); fullarrayiter != c[1]->end_all(); - ++fullarrayiter, ++count) + for (C2::full_iterator fullarrayiter = c[1]->begin_all(); fullarrayiter != c[1]->end_all(); ++fullarrayiter, ++count) *fullarrayiter = count; // normal iterator { - typedef NestedIterator > FullIter; - FullIter fiter(c.begin(),c.end()); - const FullIter fiter_end(c.end(),c.end()); - count=1; - while (fiter != fiter_end) - { + typedef NestedIterator> FullIter; + FullIter fiter(c.begin(), c.end()); + const FullIter fiter_end(c.end(), c.end()); + count = 1; + while (fiter != fiter_end) { check_if_equal(*fiter++, count++, "nestiterator of vector>>"); } - check_if_equal(count, static_cast(c[0]->size_all() + c[1]->size_all() + 1), - "nestiterator of vector>>: num elements"); + check_if_equal(count, static_cast(c[0]->size_all() + c[1]->size_all() + 1), + "nestiterator of vector>>: num elements"); } // const iterator { - typedef NestedIterator > FullIter; - FullIter fiter(c.begin(),c.end()); - const FullIter fiter_end(c.end(),c.end()); - count=1; - while (fiter != fiter_end) - { + typedef NestedIterator> FullIter; + FullIter fiter(c.begin(), c.end()); + const FullIter fiter_end(c.end(), c.end()); + count = 1; + while (fiter != fiter_end) { check_if_equal(*fiter++, count++, "nestiterator of vector>>"); } - check_if_equal(count, static_cast(c[0]->size_all() + c[1]->size_all() + 1), - "nestiterator of vector>>: num elements"); + check_if_equal(count, static_cast(c[0]->size_all() + c[1]->size_all() + 1), + "nestiterator of vector>>: num elements"); } } - } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { NestedIteratorTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_OutputFileFormat.cxx b/src/test/test_OutputFileFormat.cxx index 17eca35f4d..b5b92e493f 100644 --- a/src/test/test_OutputFileFormat.cxx +++ b/src/test/test_OutputFileFormat.cxx @@ -10,7 +10,7 @@ \author Kris Thielemans - + To run the test, you should use a command line argument with the name of a file. This should contain a test par file. See stir::OutputFileFormatTests class documentation for file contents. @@ -38,11 +38,11 @@ See STIR/LICENSE.txt for details */ - + #include "stir/IO/OutputFileFormat.h" #include "stir/IO/read_from_file.h" #ifdef HAVE_LLN_MATRIX -#include "stir/IO/ECAT6OutputFileFormat.h" // need this for test on pixel_size +# include "stir/IO/ECAT6OutputFileFormat.h" // need this for test on pixel_size #endif #include "stir/RunTests.h" #include "stir/KeyParser.h" @@ -76,47 +76,43 @@ START_NAMESPACE_STIR \verbatim Test OutputFileFormat Parameters:= - output file format type := + output file format type := ; here are parameters specific for the file format End:= \endverbatim \warning Overwrites files STIRtmp.* in the current directory - \todo Delete STIRtmp.* files, but that's a bit difficult as we don't know which ones + \todo Delete STIRtmp.* files, but that's a bit difficult as we don't know which ones are written. */ -class OutputFileFormatTests : public RunTests -{ +class OutputFileFormatTests : public RunTests { public: - OutputFileFormatTests(istream& in) ; + OutputFileFormatTests(istream& in); void run_tests(); + private: istream& in; - shared_ptr > > output_file_format_ptr; + shared_ptr>> output_file_format_ptr; KeyParser parser; }; -OutputFileFormatTests:: -OutputFileFormatTests(istream& in) : - in(in) -{ +OutputFileFormatTests::OutputFileFormatTests(istream& in) : in(in) { output_file_format_ptr.reset(); parser.add_start_key("Test OutputFileFormat Parameters"); parser.add_parsing_key("output file format type", &output_file_format_ptr); parser.add_stop_key("END"); } -void OutputFileFormatTests::run_tests() -{ +void +OutputFileFormatTests::run_tests() { cerr << "Testing OutputFileFormat parsing function..." << endl; cerr << "WARNING: will overwite files called STIRtmp*\n"; if (!check(parser.parse(in), "parsing failed")) return; - if (!check(!is_null_ptr(output_file_format_ptr), - "parsing failed to set output_file_format_ptr")) + if (!check(!is_null_ptr(output_file_format_ptr), "parsing failed to set output_file_format_ptr")) return; #if 0 cerr << "Output parameters after reading from input file:\n" @@ -125,7 +121,7 @@ void OutputFileFormatTests::run_tests() cerr << "-------------------------------------------\n\n"; #endif - cerr << "Now writing to file and reading it back." << endl; + cerr << "Now writing to file and reading it back." << endl; // construct density and write to file { #ifdef HAVE_LLN_MATRIX @@ -134,112 +130,90 @@ void OutputFileFormatTests::run_tests() // TODO get next info from OutputFileFormat class instead of hard-wiring // this in here const bool supports_different_xy_pixel_sizes = - dynamic_cast(output_file_format_ptr.get()) == 0 - ? true : false; + dynamic_cast(output_file_format_ptr.get()) == 0 ? true : false; const bool supports_origin_z_shift = - dynamic_cast(output_file_format_ptr.get()) == 0 - ? true : false; - const bool supports_origin_xy_shift = - true; + dynamic_cast(output_file_format_ptr.get()) == 0 ? true : false; + const bool supports_origin_xy_shift = true; #else const bool supports_different_xy_pixel_sizes = true; const bool supports_origin_z_shift = true; - const bool supports_origin_xy_shift = - true; + const bool supports_origin_xy_shift = true; #endif - CartesianCoordinate3D origin (0.F,0.F,0.F); - if (supports_origin_xy_shift) - { origin.x()=2.4F; origin.y() = -3.5F; } - if (supports_origin_z_shift) - { origin.z()=6.4F; } - - CartesianCoordinate3D grid_spacing (3.F,4.F,supports_different_xy_pixel_sizes?5.F:4.F); - - IndexRange<3> - range(CartesianCoordinate3D(0,-15,-14), - CartesianCoordinate3D(4,14,14)); - - VoxelsOnCartesianGrid image(range,origin, grid_spacing); + CartesianCoordinate3D origin(0.F, 0.F, 0.F); + if (supports_origin_xy_shift) { + origin.x() = 2.4F; + origin.y() = -3.5F; + } + if (supports_origin_z_shift) { + origin.z() = 6.4F; + } + + CartesianCoordinate3D grid_spacing(3.F, 4.F, supports_different_xy_pixel_sizes ? 5.F : 4.F); + + IndexRange<3> range(CartesianCoordinate3D(0, -15, -14), CartesianCoordinate3D(4, 14, 14)); + + VoxelsOnCartesianGrid image(range, origin, grid_spacing); { // fill with some data - for (int z=image.get_min_z(); z<=image.get_max_z(); ++z) - for (int y=image.get_min_y(); y<=image.get_max_y(); ++y) - for (int x=image.get_min_x(); x<=image.get_max_x(); ++x) - image[z][y][x]= - 300*sin(static_cast(x*_PI)/image.get_max_x()) - *sin(static_cast(y+10*_PI)/image.get_max_y()) - *cos(static_cast(z*_PI/3)/image.get_max_z()); + for (int z = image.get_min_z(); z <= image.get_max_z(); ++z) + for (int y = image.get_min_y(); y <= image.get_max_y(); ++y) + for (int x = image.get_min_x(); x <= image.get_max_x(); ++x) + image[z][y][x] = 300 * sin(static_cast(x * _PI) / image.get_max_x()) * + sin(static_cast(y + 10 * _PI) / image.get_max_y()) * + cos(static_cast(z * _PI / 3) / image.get_max_z()); } // write to file std::string filename = "STIRtmp"; - const Succeeded success = - output_file_format_ptr->write_to_file(filename,image); - - if (check( success==Succeeded::yes, "test writing to file")) - { - - // now read it back - - unique_ptr > - density_ptr = read_from_file >(filename); - - const VoxelsOnCartesianGrid * image_as_read_ptr = - dynamic_cast< VoxelsOnCartesianGrid const *> - (density_ptr.get()); - - set_tolerance(.00001); - if (check(!is_null_ptr(image_as_read_ptr), "test on image type read back from file")) - { - check_if_equal(image_as_read_ptr->get_grid_spacing(), grid_spacing, "test on grid spacing read back from file"); - - - if (output_file_format_ptr->get_type_of_numbers().integer_type()) - { - set_tolerance(image.find_max()/ - pow(2.,static_cast(output_file_format_ptr->get_type_of_numbers().size_in_bits()))); - } - - check_if_equal(image, *density_ptr, "test on data read back from file"); - set_tolerance(.00001); - check_if_equal(density_ptr->get_origin(), origin, "test on origin read back from file"); - } - } - if (is_everything_ok()) - { - - } - else - cerr << "You can check what was written in STIRtmp.*\n"; + const Succeeded success = output_file_format_ptr->write_to_file(filename, image); - } - + if (check(success == Succeeded::yes, "test writing to file")) { + // now read it back -} + unique_ptr> density_ptr = read_from_file>(filename); + const VoxelsOnCartesianGrid* image_as_read_ptr = + dynamic_cast const*>(density_ptr.get()); + + set_tolerance(.00001); + if (check(!is_null_ptr(image_as_read_ptr), "test on image type read back from file")) { + check_if_equal(image_as_read_ptr->get_grid_spacing(), grid_spacing, "test on grid spacing read back from file"); + + if (output_file_format_ptr->get_type_of_numbers().integer_type()) { + set_tolerance(image.find_max() / + pow(2., static_cast(output_file_format_ptr->get_type_of_numbers().size_in_bits()))); + } + + check_if_equal(image, *density_ptr, "test on data read back from file"); + set_tolerance(.00001); + check_if_equal(density_ptr->get_origin(), origin, "test on origin read back from file"); + } + } + if (is_everything_ok()) { + + } else + cerr << "You can check what was written in STIRtmp.*\n"; + } +} END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 2) - { +int +main(int argc, char** argv) { + if (argc != 2) { cerr << "Usage : " << argv[0] << " filename\n" << "See source file for the format of this file.\n\n"; return EXIT_FAILURE; } - ifstream in(argv[1]); - if (!in) - { - cerr << argv[0] - << ": Error opening input file " << argv[1] << "\nExiting.\n"; + if (!in) { + cerr << argv[0] << ": Error opening input file " << argv[1] << "\nExiting.\n"; return EXIT_FAILURE; } diff --git a/src/test/test_ROIs.cxx b/src/test/test_ROIs.cxx index 1e8081a45d..ab3ef489a4 100644 --- a/src/test/test_ROIs.cxx +++ b/src/test/test_ROIs.cxx @@ -20,15 +20,15 @@ \file \ingroup test - + \brief Test program for ROI functionality (and a bit of stir::Shape3D hierarchy) - + \author Kris Thielemans \author C. Ross Schmidtlein (added stir::Box3D test) - + */ -/*! +/*! \def test_ROIs_DISPLAY Enable visual display of the ROIs */ @@ -52,7 +52,7 @@ #include "stir/make_array.h" #include "stir/numerics/determinant.h" #ifdef test_ROIs_DISPLAY -#include "stir/display.h" +# include "stir/display.h" #endif #include @@ -65,246 +65,218 @@ START_NAMESPACE_STIR Visual tests can be enabled by setting the compiler define test_ROIs_DISPLAY. \todo Tests are currently somewhat simplistic - + */ -class ROITests : public RunTests -{ +class ROITests : public RunTests { public: void run_tests(); + private: //! Run a series of tests for a shape /*! - This function tests ROI values and Shape3D::geometric_volume before and after + This function tests ROI values and Shape3D::geometric_volume before and after translating and scaling the shape. \warning fills /changes image and shape \warning - If you want to add new tests, the "scale" and "set_direction_vectors" test-code + If you want to add new tests, the "scale" and "set_direction_vectors" test-code does not work for all shapes as it assumes that the transformed shape is inside the original one. You can disable the "set_direction_vectors" test by setting the do_rotated_ROI_test to false. */ - void run_tests_one_shape(Shape3D& shape, - VoxelsOnCartesianGrid& image, - const bool do_rotated_ROI_test=true); + void run_tests_one_shape(Shape3D& shape, VoxelsOnCartesianGrid& image, const bool do_rotated_ROI_test = true); }; void -ROITests::run_tests_one_shape(Shape3D& shape, - VoxelsOnCartesianGrid& image, - const bool do_rotated_ROI_test) -{ - shape.construct_volume(image, Coordinate3D(1,1,1)); +ROITests::run_tests_one_shape(Shape3D& shape, VoxelsOnCartesianGrid& image, const bool do_rotated_ROI_test) { + shape.construct_volume(image, Coordinate3D(1, 1, 1)); - if (dynamic_cast(&shape) != 0) - { + if (dynamic_cast(&shape) != 0) { #ifdef test_ROIs_DISPLAY - shared_ptr > copy_sptr = - static_cast(shape).get_discretised_density().clone(); + shared_ptr> copy_sptr = + static_cast(shape).get_discretised_density().clone(); #endif - MinimalImageFilter3D erosion_filter(make_coordinate(2,2,2)); - erosion_filter.apply(static_cast(shape).get_discretised_density()); + MinimalImageFilter3D erosion_filter(make_coordinate(2, 2, 2)); + erosion_filter.apply(static_cast(shape).get_discretised_density()); #ifdef test_ROIs_DISPLAY - const float max = copy_sptr->find_max(); - *copy_sptr -= static_cast(shape).get_discretised_density(); - *copy_sptr += max/2; - display(*copy_sptr, - max, - "Original - erosion"); -#endif - } - const CartesianCoordinate3D voxel_size = image.get_voxel_size(); - const float voxel_volume = voxel_size.x() * voxel_size.y() * voxel_size.z(); + const float max = copy_sptr->find_max(); + *copy_sptr -= static_cast(shape).get_discretised_density(); + *copy_sptr += max / 2; + display(*copy_sptr, max, "Original - erosion"); +#endif + } + const CartesianCoordinate3D voxel_size = image.get_voxel_size(); + const float voxel_volume = voxel_size.x() * voxel_size.y() * voxel_size.z(); - image *= 2; + image *= 2; #ifdef test_ROIs_DISPLAY - display(image, image.find_max(), "image corresponding to shape (before erosion in the discretised case)"); + display(image, image.find_max(), "image corresponding to shape (before erosion in the discretised case)"); #endif + { + const ROIValues ROI_values = compute_total_ROI_values(image, shape, Coordinate3D(1, 1, 1)); + + check_if_equal(ROI_values.get_mean(), 2.F, "ROI mean"); + check_if_equal(ROI_values.get_stddev(), 0.F, "ROI stddev"); + check_if_equal(ROI_values.get_max(), 2.F, "ROI max"); + check_if_equal(ROI_values.get_min(), 2.F, "ROI min"); + // check volume + // test supposes that shape is entirely within the volume + const float volume = shape.get_geometric_volume(); + if (volume >= 0) // only test it if it's implemented { - const ROIValues ROI_values = - compute_total_ROI_values(image, shape, Coordinate3D(1,1,1)); - - check_if_equal(ROI_values.get_mean(), 2.F, "ROI mean"); - check_if_equal(ROI_values.get_stddev(), 0.F, "ROI stddev"); - check_if_equal(ROI_values.get_max(), 2.F, "ROI max"); - check_if_equal(ROI_values.get_min(), 2.F, "ROI min"); - // check volume - // test supposes that shape is entirely within the volume - const float volume = shape.get_geometric_volume(); - if (volume>=0) // only test it if it's implemented - { - const double old_tolerance = get_tolerance(); - set_tolerance(pow(volume/voxel_volume,1.F/3)*.1); - check_if_equal(ROI_values.get_roi_volume(), volume, "ROI volume"); - set_tolerance(old_tolerance); - } + const double old_tolerance = get_tolerance(); + set_tolerance(pow(volume / voxel_volume, 1.F / 3) * .1); + check_if_equal(ROI_values.get_roi_volume(), volume, "ROI volume"); + set_tolerance(old_tolerance); } - // test on translation (image and shape translate same way) + } + // test on translation (image and shape translate same way) + { + const CartesianCoordinate3D translation(3, 1, 20); + image.set_origin(image.get_origin() + translation); + shape.translate(translation); + const ROIValues ROI_values = compute_total_ROI_values(image, shape, Coordinate3D(1, 1, 1)); + + check_if_equal(ROI_values.get_mean(), 2.F, "ROI mean after translation"); + check_if_equal(ROI_values.get_stddev(), 0.F, "ROI stddev after translation"); + check_if_equal(ROI_values.get_max(), 2.F, "ROI max after translation"); + check_if_equal(ROI_values.get_min(), 2.F, "ROI min after translation"); + // check volume + // test supposes that shape is entirely within the volume + const float volume = shape.get_geometric_volume(); + if (volume >= 0) // only test it if it's implemented { - const CartesianCoordinate3D translation (3,1,20); - image.set_origin(image.get_origin()+translation); - shape.translate(translation); - const ROIValues ROI_values = - compute_total_ROI_values(image, shape, Coordinate3D(1,1,1)); - - check_if_equal(ROI_values.get_mean(), 2.F, "ROI mean after translation"); - check_if_equal(ROI_values.get_stddev(), 0.F, "ROI stddev after translation"); - check_if_equal(ROI_values.get_max(), 2.F, "ROI max after translation"); - check_if_equal(ROI_values.get_min(), 2.F, "ROI min after translation"); - // check volume - // test supposes that shape is entirely within the volume - const float volume = shape.get_geometric_volume(); - if (volume>=0) // only test it if it's implemented - { - const double old_tolerance = get_tolerance(); - set_tolerance(pow(volume/voxel_volume,1.F/3)*.1); - check_if_equal(ROI_values.get_roi_volume(), volume, "ROI volume after translation"); - set_tolerance(old_tolerance); - } - image.set_origin(image.get_origin()-translation); - shape.translate(translation*-1); + const double old_tolerance = get_tolerance(); + set_tolerance(pow(volume / voxel_volume, 1.F / 3) * .1); + check_if_equal(ROI_values.get_roi_volume(), volume, "ROI volume after translation"); + set_tolerance(old_tolerance); } - // test on translation (image and shape translate separately) + image.set_origin(image.get_origin() - translation); + shape.translate(translation * -1); + } + // test on translation (image and shape translate separately) + { + const CartesianCoordinate3D translation(3, 1, 10); + image.set_origin(image.get_origin() + translation); + const ROIValues ROI_values = compute_total_ROI_values(image, shape, Coordinate3D(1, 1, 1)); + image.set_origin(image.get_origin() - translation); + shape.translate(translation * -1); + const ROIValues ROI_values2 = compute_total_ROI_values(image, shape, Coordinate3D(1, 1, 1)); + shape.translate(translation); + + check_if_equal(ROI_values.get_mean(), ROI_values2.get_mean(), "ROI mean after translation shape vs. image"); + check_if_equal(ROI_values.get_stddev(), ROI_values2.get_stddev(), "ROI stddev after translation shape vs. image"); + check_if_equal(ROI_values.get_max(), ROI_values2.get_max(), "ROI max after translation shape vs. image"); + check_if_equal(ROI_values.get_min(), ROI_values2.get_min(), "ROI min after translation shape vs. image"); + } + // test on scaling (test only works if all scale factors < 1) + if (dynamic_cast(&shape) == 0) { + const float volume_before_scale = shape.get_geometric_volume(); + const CartesianCoordinate3D scale(.5F, .9F, .8F); + const float total_scale = scale[1] * scale[2] * scale[3]; + shared_ptr new_shape_sptr(shape.clone()); + new_shape_sptr->scale_around_origin(scale); + + const ROIValues ROI_values = compute_total_ROI_values(image, *new_shape_sptr, Coordinate3D(1, 1, 1)); + + check_if_equal(ROI_values.get_mean(), 2.F, "ROI mean after scale"); + check_if_equal(ROI_values.get_stddev(), 0.F, "ROI stddev after scale"); + check_if_equal(ROI_values.get_max(), 2.F, "ROI max after scale"); + check_if_equal(ROI_values.get_min(), 2.F, "ROI min after scale"); + // check volume + // test supposes that shape is entirely within the volume + const float volume = new_shape_sptr->get_geometric_volume(); + if (volume >= 0) // only test it if it's implemented { - const CartesianCoordinate3D translation (3,1,10); - image.set_origin(image.get_origin()+translation); - const ROIValues ROI_values = - compute_total_ROI_values(image, shape, Coordinate3D(1,1,1)); - image.set_origin(image.get_origin()-translation); - shape.translate(translation*-1); - const ROIValues ROI_values2 = - compute_total_ROI_values(image, shape, Coordinate3D(1,1,1)); - shape.translate(translation); - - check_if_equal(ROI_values.get_mean(), ROI_values2.get_mean(), "ROI mean after translation shape vs. image"); - check_if_equal(ROI_values.get_stddev(), ROI_values2.get_stddev(), "ROI stddev after translation shape vs. image"); - check_if_equal(ROI_values.get_max(), ROI_values2.get_max(), "ROI max after translation shape vs. image"); - check_if_equal(ROI_values.get_min(), ROI_values2.get_min(), "ROI min after translation shape vs. image"); + check_if_equal(volume_before_scale * total_scale, volume, "shape volume after scale"); + const double old_tolerance = get_tolerance(); + set_tolerance(pow(volume / voxel_volume, 1.F / 3) * .1); + check_if_equal(ROI_values.get_roi_volume(), volume, "ROI volume after scale"); + set_tolerance(old_tolerance); } - // test on scaling (test only works if all scale factors < 1) - if (dynamic_cast(&shape) == 0) - { - const float volume_before_scale = shape.get_geometric_volume(); - const CartesianCoordinate3D scale(.5F,.9F,.8F); - const float total_scale = scale[1]*scale[2]*scale[3]; - shared_ptr new_shape_sptr(shape.clone()); - new_shape_sptr->scale_around_origin(scale); - - const ROIValues ROI_values = - compute_total_ROI_values(image, *new_shape_sptr, Coordinate3D(1,1,1)); - - check_if_equal(ROI_values.get_mean(), 2.F, "ROI mean after scale"); - check_if_equal(ROI_values.get_stddev(), 0.F, "ROI stddev after scale"); - check_if_equal(ROI_values.get_max(), 2.F, "ROI max after scale"); - check_if_equal(ROI_values.get_min(), 2.F, "ROI min after scale"); - // check volume - // test supposes that shape is entirely within the volume - const float volume = new_shape_sptr->get_geometric_volume(); - if (volume>=0) // only test it if it's implemented - { - check_if_equal(volume_before_scale*total_scale, volume, "shape volume after scale"); - const double old_tolerance = get_tolerance(); - set_tolerance(pow(volume/voxel_volume,1.F/3)*.1); - check_if_equal(ROI_values.get_roi_volume(), volume, "ROI volume after scale"); - set_tolerance(old_tolerance); - } #ifdef test_ROIs_DISPLAY - VoxelsOnCartesianGrid image2 = image; - new_shape_sptr->construct_volume(image2, Coordinate3D(1,1,1)); - image2 *= 4; - image2 -= image; - image2 += 2; - display(image2, image2.find_max(), "(image corresponding to scaled (.5,.9,.8) shape)*2 - (original shape) + 1"); + VoxelsOnCartesianGrid image2 = image; + new_shape_sptr->construct_volume(image2, Coordinate3D(1, 1, 1)); + image2 *= 4; + image2 -= image; + image2 += 2; + display(image2, image2.find_max(), "(image corresponding to scaled (.5,.9,.8) shape)*2 - (original shape) + 1"); #endif - } + } - // test on setting direction vectors (test only works if new shape is smaller than original) - if (dynamic_cast(&shape) != 0) + // test on setting direction vectors (test only works if new shape is smaller than original) + if (dynamic_cast(&shape) != 0) { + const float volume_before_scale = shape.get_geometric_volume(); + // rotate over 45 degrees around 1 and scale + const Array<2, float> direction_vectors = + make_array(make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, 1.F, 1.F), make_1d_array(0.F, -2.F, 2.F)); + const float total_scale = 1 / determinant(direction_vectors); + shared_ptr new_shape_sptr(dynamic_cast(shape.clone())); + check(new_shape_sptr->set_direction_vectors(direction_vectors) == Succeeded::yes, "set_direction_vectors"); + // std::cerr << new_shape_sptr->parameter_info(); + + const ROIValues ROI_values = compute_total_ROI_values(image, *new_shape_sptr, Coordinate3D(1, 1, 1)); + + if (do_rotated_ROI_test) { + check_if_equal(ROI_values.get_mean(), 2.F, "ROI mean after changing direction vectors"); + check_if_equal(ROI_values.get_stddev(), 0.F, "ROI stddev after changing direction vectors"); + check_if_equal(ROI_values.get_min(), 2.F, "ROI min after changing direction vectors"); + } + check_if_equal(ROI_values.get_max(), 2.F, "ROI max after changing direction vectors"); + // check volume + // test supposes that shape is entirely within the volume + const float volume = new_shape_sptr->get_geometric_volume(); + if (volume >= 0) // only test it if it's implemented { - const float volume_before_scale = shape.get_geometric_volume(); - // rotate over 45 degrees around 1 and scale - const Array<2,float> direction_vectors= - make_array(make_1d_array(1.F,0.F,0.F), - make_1d_array(0.F,1.F,1.F), - make_1d_array(0.F,-2.F,2.F)); - const float total_scale = 1/determinant(direction_vectors); - shared_ptr - new_shape_sptr(dynamic_cast(shape.clone())); - check(new_shape_sptr->set_direction_vectors(direction_vectors) == Succeeded::yes, "set_direction_vectors"); - //std::cerr << new_shape_sptr->parameter_info(); - - const ROIValues ROI_values = - compute_total_ROI_values(image, *new_shape_sptr, Coordinate3D(1,1,1)); - - if (do_rotated_ROI_test) - { - check_if_equal(ROI_values.get_mean(), 2.F, "ROI mean after changing direction vectors"); - check_if_equal(ROI_values.get_stddev(), 0.F, "ROI stddev after changing direction vectors"); - check_if_equal(ROI_values.get_min(), 2.F, "ROI min after changing direction vectors"); - } - check_if_equal(ROI_values.get_max(), 2.F, "ROI max after changing direction vectors"); - // check volume - // test supposes that shape is entirely within the volume - const float volume = new_shape_sptr->get_geometric_volume(); - if (volume>=0) // only test it if it's implemented - { - check_if_equal(volume_before_scale*total_scale, volume, "shape volume after changing direction vectors"); - const double old_tolerance = get_tolerance(); - set_tolerance(pow(volume/voxel_volume,1.F/3)*.1); - check_if_equal(ROI_values.get_roi_volume(), volume, "ROI volume after changing direction vectors"); - set_tolerance(old_tolerance); - } + check_if_equal(volume_before_scale * total_scale, volume, "shape volume after changing direction vectors"); + const double old_tolerance = get_tolerance(); + set_tolerance(pow(volume / voxel_volume, 1.F / 3) * .1); + check_if_equal(ROI_values.get_roi_volume(), volume, "ROI volume after changing direction vectors"); + set_tolerance(old_tolerance); + } #ifdef test_ROIs_DISPLAY - VoxelsOnCartesianGrid image2 = image; - new_shape_sptr->construct_volume(image2, Coordinate3D(1,1,1)); - image2 *= 4; - image2 -= image; - image2 += 2; - display(image2, image2.find_max(), "(image corresponding to rotated and scaled (x,y) shape)*2 - (original shape) + 1"); + VoxelsOnCartesianGrid image2 = image; + new_shape_sptr->construct_volume(image2, Coordinate3D(1, 1, 1)); + image2 *= 4; + image2 -= image; + image2 += 2; + display(image2, image2.find_max(), "(image corresponding to rotated and scaled (x,y) shape)*2 - (original shape) + 1"); #endif - } - // test on parsing - if (dynamic_cast(&shape) == 0) - { - shared_ptr shape_sptr(shape.clone()); - KeyParser parser; - parser.add_start_key("start"); - parser.add_stop_key("stop"); - parser.add_parsing_key("shape type", &shape_sptr); - // construct stream with all info - std::stringstream str; - str << parser.parameter_info(); - // now read it back in and check - if (check(parser.parse(str) && !is_null_ptr(shape_sptr), - "parsing parameters failed")) - { - // check if it's what we expect - if(!check(*shape_sptr == shape, - "parsed shape not equal to original")) - { - std::cerr << "Original: \n" << shape.parameter_info() - << "\nParsed: \n" << shape_sptr->parameter_info(); - } + } + // test on parsing + if (dynamic_cast(&shape) == 0) { + shared_ptr shape_sptr(shape.clone()); + KeyParser parser; + parser.add_start_key("start"); + parser.add_stop_key("stop"); + parser.add_parsing_key("shape type", &shape_sptr); + // construct stream with all info + std::stringstream str; + str << parser.parameter_info(); + // now read it back in and check + if (check(parser.parse(str) && !is_null_ptr(shape_sptr), "parsing parameters failed")) { + // check if it's what we expect + if (!check(*shape_sptr == shape, "parsed shape not equal to original")) { + std::cerr << "Original: \n" << shape.parameter_info() << "\nParsed: \n" << shape_sptr->parameter_info(); } + } } } void ROITests::run_tests() -{ +{ std::cerr << "Tests for compute_ROI_values and Shape3D hierarchy\n"; - - CartesianCoordinate3D origin (0,0,0); - CartesianCoordinate3D grid_spacing (3,4,5); - - const IndexRange<3> - range(Coordinate3D(0,-45,-44), - Coordinate3D(24,44,45)); - VoxelsOnCartesianGrid image(range,origin, grid_spacing); + + CartesianCoordinate3D origin(0, 0, 0); + CartesianCoordinate3D grid_spacing(3, 4, 5); + + const IndexRange<3> range(Coordinate3D(0, -45, -44), Coordinate3D(24, 44, 45)); + VoxelsOnCartesianGrid image(range, origin, grid_spacing); /* WARNING: - If you want to add new tests, the "scale" and "set_direction_vectors" test-code + If you want to add new tests, the "scale" and "set_direction_vectors" test-code in run_tests_one_shape() does not work for all shapes as it assumes that the transformed shape is inside the original one. You can disable the "set_direction_vectors" test by setting the do_rotated_ROI_test to false. @@ -312,91 +284,85 @@ ROITests::run_tests() { std::cerr << "\tTests with ellipsoidal cylinder.\n"; // object at centre of image - EllipsoidalCylinder - cylinder(/*length*/image.size()*grid_spacing.z()/3, - /*radius_x*/image[0][0].size()*grid_spacing.x()/4, - /*radius_y*/image[0].size()*grid_spacing.y()/4, - /*centre*/CartesianCoordinate3D((image.get_min_index()+image.get_max_index())/2*grid_spacing.z(), 0,0)); + EllipsoidalCylinder cylinder( + /*length*/ image.size() * grid_spacing.z() / 3, + /*radius_x*/ image[0][0].size() * grid_spacing.x() / 4, + /*radius_y*/ image[0].size() * grid_spacing.y() / 4, + /*centre*/ CartesianCoordinate3D((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), 0, 0)); this->run_tests_one_shape(cylinder, image); } image.set_origin(origin); { std::cerr << "\tTests with ellipsoidal cylinder and wedge.\n"; // object at centre of image - EllipsoidalCylinder - cylinder(/*length*/image.size()*grid_spacing.z()/3, - /*radius_x*/image[0][0].size()*grid_spacing.x()/4, - /*radius_y*/image[0].size()*grid_spacing.y()/4, - /* theta_1 */ 10.F, - /* theta_2 */ 280.F, - /*centre*/CartesianCoordinate3D((image.get_min_index()+image.get_max_index())/2*grid_spacing.z(), 0,0)); - this->run_tests_one_shape(cylinder, image, /*do_rotated_ROI_test=*/ false); + EllipsoidalCylinder cylinder( + /*length*/ image.size() * grid_spacing.z() / 3, + /*radius_x*/ image[0][0].size() * grid_spacing.x() / 4, + /*radius_y*/ image[0].size() * grid_spacing.y() / 4, + /* theta_1 */ 10.F, + /* theta_2 */ 280.F, + /*centre*/ CartesianCoordinate3D((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), 0, 0)); + this->run_tests_one_shape(cylinder, image, /*do_rotated_ROI_test=*/false); } image.set_origin(origin); { std::cerr << "\tTests with ellipsoid.\n"; // object at centre of image - Ellipsoid - ellipsoid(CartesianCoordinate3D(/*radius_z*/image.size()*grid_spacing.z()/3, - /*radius_y*/image[0].size()*grid_spacing.y()/5, - /*radius_x*/image[0][0].size()*grid_spacing.x()/4), - /*centre*/CartesianCoordinate3D((image.get_min_index()+image.get_max_index())/2*grid_spacing.z(), 0,0)); + Ellipsoid ellipsoid( + CartesianCoordinate3D(/*radius_z*/ image.size() * grid_spacing.z() / 3, + /*radius_y*/ image[0].size() * grid_spacing.y() / 5, + /*radius_x*/ image[0][0].size() * grid_spacing.x() / 4), + /*centre*/ CartesianCoordinate3D((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), 0, 0)); this->run_tests_one_shape(ellipsoid, image); } { std::cerr << "\tTests with Box3D.\n"; // object at centre of image - Box3D - box(/*length_x*/image[0][0].size()*grid_spacing.x()/4, - /*length_y*/image[0].size()*grid_spacing.y()/5, - /*length_z*/image.size()*grid_spacing.z()/3, - /*centre*/CartesianCoordinate3D((image.get_min_index()+image.get_max_index())/2*grid_spacing.z(), 0,0)); + Box3D box( + /*length_x*/ image[0][0].size() * grid_spacing.x() / 4, + /*length_y*/ image[0].size() * grid_spacing.y() / 5, + /*length_z*/ image.size() * grid_spacing.z() / 3, + /*centre*/ CartesianCoordinate3D((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), 0, 0)); this->run_tests_one_shape(box, image); - } + } { std::cerr << "\tTests with DiscretisedShape3D.\n"; // object at centre of image - Ellipsoid - ellipsoid(CartesianCoordinate3D(/*radius_z*/image.size()*grid_spacing.z()/3, - /*radius_y*/image[0].size()*grid_spacing.y()/5, - /*radius_x*/image[0][0].size()*grid_spacing.x()/4), - /*centre*/CartesianCoordinate3D((image.get_min_index()+image.get_max_index())/2*grid_spacing.z(), 0,0)); + Ellipsoid ellipsoid( + CartesianCoordinate3D(/*radius_z*/ image.size() * grid_spacing.z() / 3, + /*radius_y*/ image[0].size() * grid_spacing.y() / 5, + /*radius_x*/ image[0][0].size() * grid_spacing.x() / 4), + /*centre*/ CartesianCoordinate3D((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), 0, 0)); // note: it is important to use num_samples=(1,1,1) here, otherwise tests will fail - // this is because the shape would have smooth edges, and the tests do not take + // this is because the shape would have smooth edges, and the tests do not take // that into account - ellipsoid.construct_volume(image, make_coordinate(1,1,1)); + ellipsoid.construct_volume(image, make_coordinate(1, 1, 1)); { DiscretisedShape3D discretised_shape(image); std::cerr << "\t\tidentical image\n"; this->run_tests_one_shape(discretised_shape, image); } // need to fill in image again, as the tests change it - ellipsoid.construct_volume(image, make_coordinate(1,1,1)); + ellipsoid.construct_volume(image, make_coordinate(1, 1, 1)); { std::cerr << "\t\tNot-identical image\n"; DiscretisedShape3D discretised_shape(image); - CartesianCoordinate3D other_origin (2,4,9); - CartesianCoordinate3D other_grid_spacing (3.3,4.4,5.5); - - const IndexRange<3> - other_range(Coordinate3D(-1,-40,-43), - Coordinate3D(25,45,47)); - VoxelsOnCartesianGrid other_image(other_range,other_origin, other_grid_spacing); + CartesianCoordinate3D other_origin(2, 4, 9); + CartesianCoordinate3D other_grid_spacing(3.3, 4.4, 5.5); + + const IndexRange<3> other_range(Coordinate3D(-1, -40, -43), Coordinate3D(25, 45, 47)); + VoxelsOnCartesianGrid other_image(other_range, other_origin, other_grid_spacing); this->run_tests_one_shape(discretised_shape, other_image); } - } - } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main() -{ +int +main() { ROITests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_Scanner.cxx b/src/test/test_Scanner.cxx index e01b427c9b..42bf736e65 100644 --- a/src/test/test_Scanner.cxx +++ b/src/test/test_Scanner.cxx @@ -31,12 +31,12 @@ #include "stir/Succeeded.h" #include "stir/shared_ptr.h" #ifdef HAVE_LLN_MATRIX -#include "ecat_model.h" +# include "ecat_model.h" extern "C" { - EcatModel *ecat_model(int); +EcatModel* ecat_model(int); } -#include "stir/IO/stir_ecat_common.h" +# include "stir/IO/stir_ecat_common.h" #endif #include #include @@ -51,23 +51,19 @@ START_NAMESPACE_STIR \ingroup test \brief Test class for Scanner */ -class ScannerTests: public RunTests -{ -public: +class ScannerTests : public RunTests { +public: void run_tests(); + private: void test_scanner(const Scanner&); }; - void -ScannerTests:: -run_tests() -{ - Scanner::Type type= Scanner::E931; - while (type != Scanner::Unknown_scanner) - { - if (type!=Scanner::User_defined_scanner) +ScannerTests::run_tests() { + Scanner::Type type = Scanner::E931; + while (type != Scanner::Unknown_scanner) { + if (type != Scanner::User_defined_scanner) test_scanner(Scanner(type)); // tricky business to find next type int int_type = type; @@ -77,20 +73,18 @@ run_tests() } void -ScannerTests:: -test_scanner(const Scanner& scanner) -{ +ScannerTests::test_scanner(const Scanner& scanner) { set_tolerance(.00001); - cerr << "Tests for scanner model " << scanner.get_name()<<'\n'; + cerr << "Tests for scanner model " << scanner.get_name() << '\n'; check(scanner.check_consistency() == Succeeded::yes, "check_consistency"); /* check if number of non-arccorrected tangential positions is smaller than the maximum - allowed for a full-ring tomograph + allowed for a full-ring tomograph */ { check(scanner.get_max_num_non_arccorrected_bins() <= scanner.get_num_detectors_per_ring(), - "too large max_num_non_arccorrected_bins compared to num_detectors_per_ring"); + "too large max_num_non_arccorrected_bins compared to num_detectors_per_ring"); } /* check if default_bin_size is close to the central bin size. This is especially true for CTI scanners. @@ -104,22 +98,20 @@ test_scanner(const Scanner& scanner) scanner.get_type() != Scanner::DiscoveryRX/* && scanner.get_type() != Scanner::HZLR*/) { - const float natural_bin_size = - scanner.get_inner_ring_radius()*float(_PI)/scanner.get_num_detectors_per_ring(); - if (fabs(natural_bin_size - scanner.get_default_bin_size())> .03) + const float natural_bin_size = scanner.get_inner_ring_radius() * float(_PI) / scanner.get_num_detectors_per_ring(); + if (fabs(natural_bin_size - scanner.get_default_bin_size()) > .03) warning("central bin size (derived from inner ring radius and num detectors) %g\n" - "differs from given default bin size %g\n" - "(unequal values do not necessarily mean there's an error as " - "it's a convention used by the scanner manufacturer)\n", - natural_bin_size, scanner.get_default_bin_size()); + "differs from given default bin size %g\n" + "(unequal values do not necessarily mean there's an error as " + "it's a convention used by the scanner manufacturer)\n", + natural_bin_size, scanner.get_default_bin_size()); } // (weak) test on get_scanner_from_name { string name = scanner.get_name(); name += " "; shared_ptr scanner_from_name_sptr(Scanner::get_scanner_from_name(name)); - check_if_equal(scanner.get_type(), scanner_from_name_sptr->get_type(), - "get_scanner_from_name"); + check_if_equal(scanner.get_type(), scanner_from_name_sptr->get_type(), "get_scanner_from_name"); } #ifdef HAVE_LLN_MATRIX if (scanner.get_type() <= Scanner::E966) // TODO relies on ordering of enum @@ -128,45 +120,37 @@ test_scanner(const Scanner& scanner) cerr << "Comparing STIR scanner info with LLN matrix\n"; short ecat_type = ecat::find_ECAT_system_type(scanner); - if (ecat_type==0) + if (ecat_type == 0) return; - EcatModel * ecat_scanner_info = ecat_model(static_cast(ecat_type)); - if (ecat_scanner_info==0) + EcatModel* ecat_scanner_info = ecat_model(static_cast(ecat_type)); + if (ecat_scanner_info == 0) return; - check_if_equal(scanner.get_num_axial_buckets(), ecat_scanner_info->rings, - "number of rings of buckets"); + check_if_equal(scanner.get_num_axial_buckets(), ecat_scanner_info->rings, "number of rings of buckets"); if (scanner.get_type() != Scanner::E925) // ART is a partial ring tomograph - check_if_equal(scanner.get_num_axial_buckets()*scanner.get_num_transaxial_buckets(), - ecat_scanner_info->nbuckets, - "total number of buckets"); + check_if_equal(scanner.get_num_axial_buckets() * scanner.get_num_transaxial_buckets(), ecat_scanner_info->nbuckets, + "total number of buckets"); check_if_equal(scanner.get_num_transaxial_blocks_per_bucket(), ecat_scanner_info->transBlocksPerBucket, - "transaxial blocks per bucket"); - check_if_equal(scanner.get_num_axial_blocks_per_bucket(), ecat_scanner_info->axialBlocksPerBucket, - "axial blocks per bucket"); - check_if_equal(scanner.get_num_transaxial_blocks_per_bucket() * scanner.get_num_axial_blocks_per_bucket(), - ecat_scanner_info->blocks, - "total number of blocks"); + "transaxial blocks per bucket"); + check_if_equal(scanner.get_num_axial_blocks_per_bucket(), ecat_scanner_info->axialBlocksPerBucket, "axial blocks per bucket"); + check_if_equal(scanner.get_num_transaxial_blocks_per_bucket() * scanner.get_num_axial_blocks_per_bucket(), + ecat_scanner_info->blocks, "total number of blocks"); check_if_equal(scanner.get_num_axial_crystals_per_block(), ecat_scanner_info->axialCrystalsPerBlock, - "number of crystals in the axial direction"); + "number of crystals in the axial direction"); check_if_equal(scanner.get_num_transaxial_crystals_per_block(), ecat_scanner_info->angularCrystalsPerBlock, - "number of transaxial crystals"); - check_if_equal(scanner.get_inner_ring_radius(), ecat_scanner_info->crystalRad*10, - "detector radius"); - check_if_equal(scanner.get_ring_spacing()/2, ecat_scanner_info->planesep*10, - "plane separation"); - check_if_equal(scanner.get_default_bin_size(), ecat_scanner_info->binsize*10, - "bin size (spacing of transaxial elements)"); + "number of transaxial crystals"); + check_if_equal(scanner.get_inner_ring_radius(), ecat_scanner_info->crystalRad * 10, "detector radius"); + check_if_equal(scanner.get_ring_spacing() / 2, ecat_scanner_info->planesep * 10, "plane separation"); + check_if_equal(scanner.get_default_bin_size(), ecat_scanner_info->binsize * 10, "bin size (spacing of transaxial elements)"); } #endif -} +} END_NAMESPACE_STIR - -int main() -{ -USING_NAMESPACE_STIR +int +main() { + USING_NAMESPACE_STIR ScannerTests tests; tests.run_tests(); diff --git a/src/test/test_ScatterSimulation.cxx b/src/test/test_ScatterSimulation.cxx index 5110178d64..5048737f53 100644 --- a/src/test/test_ScatterSimulation.cxx +++ b/src/test/test_ScatterSimulation.cxx @@ -37,11 +37,11 @@ #include "stir/zoom.h" #include "stir/round.h" #if 0 -#include "stir/recon_buildblock/ForwardProjectorByBin.h" -#include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" -#include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" -#include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" -#include "stir/recon_buildblock/BinNormalisationFromAttenuationImage.h" +# include "stir/recon_buildblock/ForwardProjectorByBin.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" +# include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" +# include "stir/recon_buildblock/BinNormalisationFromAttenuationImage.h" #endif #include "stir/Shape/EllipsoidalCylinder.h" #include "stir/Shape/Box3D.h" @@ -62,195 +62,180 @@ START_NAMESPACE_STIR \ingroup scatter \brief Test class for ScatterSimulation */ -class ScatterSimulationTests: public RunTests -{ -public: - bool write_output; - void run_tests(); -private: +class ScatterSimulationTests : public RunTests { +public: + bool write_output; + void run_tests(); - //! Load a ProjDataInfo downsample and perform some consistency checks. - void test_downsampling_ProjDataInfo(); - //! Load an attenuation image for scatter points, downsample and check if - //! the mean value is approximately the same. - void test_downsampling_DiscretisedDensity(); +private: + //! Load a ProjDataInfo downsample and perform some consistency checks. + void test_downsampling_ProjDataInfo(); + //! Load an attenuation image for scatter points, downsample and check if + //! the mean value is approximately the same. + void test_downsampling_DiscretisedDensity(); - //! Do simulation of object in the centre, check if symmetric - void test_scatter_simulation(); + //! Do simulation of object in the centre, check if symmetric + void test_scatter_simulation(); - void test_symmetric(ScatterSimulation& sss, const std::string& name); - void test_output_is_symmetric(const ProjData& proj_data, const std::string& name); + void test_symmetric(ScatterSimulation& sss, const std::string& name); + void test_output_is_symmetric(const ProjData& proj_data, const std::string& name); }; +void +ScatterSimulationTests::test_downsampling_ProjDataInfo() { -void ScatterSimulationTests:: -test_downsampling_ProjDataInfo() -{ - - Scanner::Type type= Scanner::E931; - shared_ptr test_scanner(new Scanner(type)); + Scanner::Type type = Scanner::E931; + shared_ptr test_scanner(new Scanner(type)); - // Create the original projdata - shared_ptr original_projdata( dynamic_cast( - ProjDataInfo::ProjDataInfoCTI(test_scanner, - 1, test_scanner->get_num_rings()-1, - test_scanner->get_num_detectors_per_ring()/2, - test_scanner->get_max_num_non_arccorrected_bins(), - false))); + // Create the original projdata + shared_ptr original_projdata(dynamic_cast( + ProjDataInfo::ProjDataInfoCTI(test_scanner, 1, test_scanner->get_num_rings() - 1, + test_scanner->get_num_detectors_per_ring() / 2, + test_scanner->get_max_num_non_arccorrected_bins(), false))); + unique_ptr sss(new SingleScatterSimulation()); + sss->set_template_proj_data_info(*original_projdata); - unique_ptr sss(new SingleScatterSimulation()); - sss->set_template_proj_data_info(*original_projdata); + { + auto sss_projdata(sss->get_template_proj_data_info_sptr()); + check(*original_projdata == *sss_projdata, "Check the ProjDataInfo has been set correctly."); + } - { - auto sss_projdata(sss->get_template_proj_data_info_sptr()); - check(*original_projdata == *sss_projdata, "Check the ProjDataInfo has been set correctly."); - } + // Downsample the scanner 50% + { + int down_rings = static_cast(test_scanner->get_num_rings() * 0.5 + 0.5); + int down_dets = static_cast(test_scanner->get_num_detectors_per_ring() * 0.5); - // Downsample the scanner 50% - { - int down_rings = static_cast(test_scanner->get_num_rings()*0.5 + 0.5); - int down_dets = static_cast(test_scanner->get_num_detectors_per_ring() * 0.5); - - sss->downsample_scanner(down_rings, down_dets); - auto sss_projdata(sss->get_template_proj_data_info_sptr()); - check_if_equal(original_projdata->get_scanner_ptr()->get_num_rings(), 2*sss_projdata->get_scanner_ptr()->get_num_rings(), "Check the number of rings is correct"); - check_if_equal(original_projdata->get_scanner_ptr()->get_num_detectors_per_ring(), - 2*sss_projdata->get_scanner_ptr()->get_num_detectors_per_ring(), "Check number of detectors per ring."); - - set_tolerance(0.01); - check_if_equal(2.f*original_projdata->get_ring_spacing(), sss_projdata->get_ring_spacing(), "Check the ring spacing."); - check_if_equal(2.f*original_projdata->get_axial_sampling(0), sss_projdata->get_axial_sampling(0), "Check axial samping. Seg 0"); - - check_if_equal(2.f*original_projdata->get_axial_sampling(original_projdata->get_min_segment_num()), - sss_projdata->get_axial_sampling(sss_projdata->get_min_segment_num()), "Check axial samping. Min. Seg"); - check_if_equal(2.f*original_projdata->get_axial_sampling(original_projdata->get_max_segment_num()), - sss_projdata->get_axial_sampling(sss_projdata->get_max_segment_num()), "Check axial samping. Max Seg."); - - Bin b1(original_projdata->get_min_segment_num(),0, - original_projdata->get_max_axial_pos_num(original_projdata->get_min_segment_num())/2,0); - Bin b2(sss_projdata->get_min_segment_num(),0, - sss_projdata->get_max_axial_pos_num(sss_projdata->get_min_segment_num())/2,0); - check_if_equal(original_projdata->get_m(b1), sss_projdata->get_m(b2), "Check center of Bin (min_seg, 0, mid_axial, 0, 0)"); - } + sss->downsample_scanner(down_rings, down_dets); + auto sss_projdata(sss->get_template_proj_data_info_sptr()); + check_if_equal(original_projdata->get_scanner_ptr()->get_num_rings(), 2 * sss_projdata->get_scanner_ptr()->get_num_rings(), + "Check the number of rings is correct"); + check_if_equal(original_projdata->get_scanner_ptr()->get_num_detectors_per_ring(), + 2 * sss_projdata->get_scanner_ptr()->get_num_detectors_per_ring(), "Check number of detectors per ring."); + set_tolerance(0.01); + check_if_equal(2.f * original_projdata->get_ring_spacing(), sss_projdata->get_ring_spacing(), "Check the ring spacing."); + check_if_equal(2.f * original_projdata->get_axial_sampling(0), sss_projdata->get_axial_sampling(0), + "Check axial samping. Seg 0"); + + check_if_equal(2.f * original_projdata->get_axial_sampling(original_projdata->get_min_segment_num()), + sss_projdata->get_axial_sampling(sss_projdata->get_min_segment_num()), "Check axial samping. Min. Seg"); + check_if_equal(2.f * original_projdata->get_axial_sampling(original_projdata->get_max_segment_num()), + sss_projdata->get_axial_sampling(sss_projdata->get_max_segment_num()), "Check axial samping. Max Seg."); + + Bin b1(original_projdata->get_min_segment_num(), 0, + original_projdata->get_max_axial_pos_num(original_projdata->get_min_segment_num()) / 2, 0); + Bin b2(sss_projdata->get_min_segment_num(), 0, sss_projdata->get_max_axial_pos_num(sss_projdata->get_min_segment_num()) / 2, + 0); + check_if_equal(original_projdata->get_m(b1), sss_projdata->get_m(b2), "Check center of Bin (min_seg, 0, mid_axial, 0, 0)"); + } } -void ScatterSimulationTests:: -test_downsampling_DiscretisedDensity() -{ - Scanner::Type type= Scanner::E931; - shared_ptr test_scanner(new Scanner(type)); - - // Create the original projdata - shared_ptr original_projdata( dynamic_cast( - ProjDataInfo::ProjDataInfoCTI(test_scanner, - 1, test_scanner->get_num_rings()-1, - test_scanner->get_num_detectors_per_ring()/2, - test_scanner->get_max_num_non_arccorrected_bins(), - false))); - - // Create an appropriate image for the projdata. - shared_ptr > tmpl_density( new VoxelsOnCartesianGrid(*original_projdata)); - +void +ScatterSimulationTests::test_downsampling_DiscretisedDensity() { + Scanner::Type type = Scanner::E931; + shared_ptr test_scanner(new Scanner(type)); - Box3D phantom(tmpl_density->get_x_size()*tmpl_density->get_voxel_size().x()*0.25, - tmpl_density->get_y_size()*tmpl_density->get_voxel_size().y()*0.25, - tmpl_density->get_z_size()*tmpl_density->get_voxel_size().z()*2, - tmpl_density->get_origin()); + // Create the original projdata + shared_ptr original_projdata(dynamic_cast( + ProjDataInfo::ProjDataInfoCTI(test_scanner, 1, test_scanner->get_num_rings() - 1, + test_scanner->get_num_detectors_per_ring() / 2, + test_scanner->get_max_num_non_arccorrected_bins(), false))); + // Create an appropriate image for the projdata. + shared_ptr> tmpl_density(new VoxelsOnCartesianGrid(*original_projdata)); - CartesianCoordinate3D num_samples(3,3,3); - shared_ptr > water_density(tmpl_density->clone()); + Box3D phantom(tmpl_density->get_x_size() * tmpl_density->get_voxel_size().x() * 0.25, + tmpl_density->get_y_size() * tmpl_density->get_voxel_size().y() * 0.25, + tmpl_density->get_z_size() * tmpl_density->get_voxel_size().z() * 2, tmpl_density->get_origin()); - phantom.construct_volume(*water_density, num_samples); - // Water attenuation coefficient. - *water_density *= 9.687E-02; + CartesianCoordinate3D num_samples(3, 3, 3); + shared_ptr> water_density(tmpl_density->clone()); -// EllipsoidalCylinder cyl2(tmpl_density->get_z_size()*tmpl_density->get_voxel_size().z()*2, -// tmpl_density->get_y_size()*tmpl_density->get_voxel_size().y()*0.125, -// tmpl_density->get_x_size()*tmpl_density->get_voxel_size().x()*0.125, -// tmpl_density->get_origin()); + phantom.construct_volume(*water_density, num_samples); + // Water attenuation coefficient. + *water_density *= 9.687E-02; -// shared_ptr > bone_density(tmpl_density->clone()); + // EllipsoidalCylinder cyl2(tmpl_density->get_z_size()*tmpl_density->get_voxel_size().z()*2, + // tmpl_density->get_y_size()*tmpl_density->get_voxel_size().y()*0.125, + // tmpl_density->get_x_size()*tmpl_density->get_voxel_size().x()*0.125, + // tmpl_density->get_origin()); -// cyl2.construct_volume(*bone_density, num_samples); + // shared_ptr > bone_density(tmpl_density->clone()); -// // Watter attenuation coefficient. -// *bone_density *= 9.687E-02 - 9.696E-02; + // cyl2.construct_volume(*bone_density, num_samples); - shared_ptr > atten_density(new VoxelsOnCartesianGrid(*tmpl_density)); + // // Watter attenuation coefficient. + // *bone_density *= 9.687E-02 - 9.696E-02; -// *atten_density = *bone_density; - *atten_density += *water_density; + shared_ptr> atten_density(new VoxelsOnCartesianGrid(*tmpl_density)); - unique_ptr sss(new SingleScatterSimulation()); + // *atten_density = *bone_density; + *atten_density += *water_density; - sss->set_template_proj_data_info(*original_projdata); - sss->set_density_image_sptr(atten_density); + unique_ptr sss(new SingleScatterSimulation()); -// int total_scatter_points_orig = sss.get_num_scatter_points(); + sss->set_template_proj_data_info(*original_projdata); + sss->set_density_image_sptr(atten_density); - sss->downsample_density_image_for_scatter_points(0.5f, 0.5f, 1); - - auto downed_image = sss->get_density_image_for_scatter_points_sptr(); + // int total_scatter_points_orig = sss.get_num_scatter_points(); + sss->downsample_density_image_for_scatter_points(0.5f, 0.5f, 1); - float mean_value_atten = 0.0f; - int atten_counter = 0; + auto downed_image = sss->get_density_image_for_scatter_points_sptr(); - BasicCoordinate<3,int> min_index, max_index ; - CartesianCoordinate3D coord; + float mean_value_atten = 0.0f; + int atten_counter = 0; - atten_density->get_regular_range(min_index, max_index); + BasicCoordinate<3, int> min_index, max_index; + CartesianCoordinate3D coord; - for(coord[1]=min_index[1];coord[1]<=max_index[1];++coord[1]) - for(coord[2]=min_index[2];coord[2]<=max_index[2];++coord[2]) - for(coord[3]=min_index[3];coord[3]<=max_index[3];++coord[3]) - if((*atten_density)[coord] > 0.02f) - { - atten_counter++; - mean_value_atten += (*atten_density)[coord]; - } + atten_density->get_regular_range(min_index, max_index); - mean_value_atten /= atten_counter; + for (coord[1] = min_index[1]; coord[1] <= max_index[1]; ++coord[1]) + for (coord[2] = min_index[2]; coord[2] <= max_index[2]; ++coord[2]) + for (coord[3] = min_index[3]; coord[3] <= max_index[3]; ++coord[3]) + if ((*atten_density)[coord] > 0.02f) { + atten_counter++; + mean_value_atten += (*atten_density)[coord]; + } - float mean_value_downed = 0.0f; - int downed_counter = 0; + mean_value_atten /= atten_counter; - downed_image->get_regular_range(min_index, max_index); + float mean_value_downed = 0.0f; + int downed_counter = 0; - for(coord[1]=min_index[1]+1;coord[1]<=max_index[1]-1;++coord[1]) - for(coord[2]=min_index[2];coord[2]<=max_index[2];++coord[2]) - for(coord[3]=min_index[3];coord[3]<=max_index[3];++coord[3]) - if((*downed_image)[coord] > 0.02f) - { - downed_counter++; - mean_value_downed += (*downed_image)[coord]; - } + downed_image->get_regular_range(min_index, max_index); - mean_value_downed /= downed_counter; + for (coord[1] = min_index[1] + 1; coord[1] <= max_index[1] - 1; ++coord[1]) + for (coord[2] = min_index[2]; coord[2] <= max_index[2]; ++coord[2]) + for (coord[3] = min_index[3]; coord[3] <= max_index[3]; ++coord[3]) + if ((*downed_image)[coord] > 0.02f) { + downed_counter++; + mean_value_downed += (*downed_image)[coord]; + } - set_tolerance(0.1); - check_if_equal(mean_value_atten, mean_value_downed, "Check the mean value of downsampled image."); - set_tolerance(0.01); + mean_value_downed /= downed_counter; - CartesianCoordinate3D cog_atten = find_centre_of_gravity_in_mm(*atten_density); - CartesianCoordinate3D cog_downed = find_centre_of_gravity_in_mm(*dynamic_cast*>(downed_image.get())); + set_tolerance(0.1); + check_if_equal(mean_value_atten, mean_value_downed, "Check the mean value of downsampled image."); + set_tolerance(0.01); + CartesianCoordinate3D cog_atten = find_centre_of_gravity_in_mm(*atten_density); + CartesianCoordinate3D cog_downed = + find_centre_of_gravity_in_mm(*dynamic_cast*>(downed_image.get())); - check_if_equal(cog_atten, cog_downed, "Check centre of gravity of the original image is the same as the downsampled."); -// int total_scatter_points_down = sss.get_num_scatter_points(); + check_if_equal(cog_atten, cog_downed, "Check centre of gravity of the original image is the same as the downsampled."); + // int total_scatter_points_down = sss.get_num_scatter_points(); -// std::string density_image_for_scatter_points_output_filename("./output_image"); -// write_to_file(density_image_for_scatter_points_output_filename, -// *downed_image); -//int debug_stop = 0; + // std::string density_image_for_scatter_points_output_filename("./output_image"); + // write_to_file(density_image_for_scatter_points_output_filename, + // *downed_image); + // int debug_stop = 0; } void -ScatterSimulationTests::test_symmetric(ScatterSimulation& ss, const std::string& name) -{ +ScatterSimulationTests::test_symmetric(ScatterSimulation& ss, const std::string& name) { auto output_projdata_info(ss.get_template_proj_data_info_sptr()); shared_ptr sss_output(new ProjDataInMemory(ss.get_exam_info_sptr(), output_projdata_info)); ss.set_output_proj_data_sptr(sss_output); @@ -258,12 +243,11 @@ ScatterSimulationTests::test_symmetric(ScatterSimulation& ss, const std::string& std::cerr << "\nSetting up for test " << name << "\n"; check(ss.set_up() == Succeeded::yes ? true : false, "Check Scatter Simulation set_up. test " + name); - if (this->write_output) - { - write_to_file("my_sss_activity__"+name+".hv", ss.get_activity_image()); - write_to_file("my_sss_attenuation_"+name+".hv", ss.get_attenuation_image()); - write_to_file("my_sss_scatter-points_"+name+".hv", ss.get_attenuation_image_for_scatter_points()); - } + if (this->write_output) { + write_to_file("my_sss_activity__" + name + ".hv", ss.get_activity_image()); + write_to_file("my_sss_attenuation_" + name + ".hv", ss.get_attenuation_image()); + write_to_file("my_sss_scatter-points_" + name + ".hv", ss.get_attenuation_image_for_scatter_points()); + } std::cerr << "Starting processing\n"; check(ss.process_data() == Succeeded::yes ? true : false, "Check Scatter Simulation process. test " + name); @@ -272,12 +256,12 @@ ScatterSimulationTests::test_symmetric(ScatterSimulation& ss, const std::string& // check if max within 5% const SegmentByView seg = sss_output->get_segment_by_view(0); - //check(seg.find_max()>0.F, "Check Scatter Simulation output not zero. test " + name); + // check(seg.find_max()>0.F, "Check Scatter Simulation output not zero. test " + name); { const float approx_max = 0.195F; const double old_tolerance = get_tolerance(); set_tolerance(.5); - check_if_equal(seg.find_max()*1000, approx_max*1000, + check_if_equal(seg.find_max() * 1000, approx_max * 1000, "Check Scatter Simulation output maximum value is approximately ok. test " + name); set_tolerance(old_tolerance); } @@ -289,40 +273,33 @@ ScatterSimulationTests::test_symmetric(ScatterSimulation& ss, const std::string& } void -ScatterSimulationTests::test_output_is_symmetric(const ProjData& proj_data, const std::string& name) -{ +ScatterSimulationTests::test_output_is_symmetric(const ProjData& proj_data, const std::string& name) { SegmentBySinogram seg = proj_data.get_segment_by_sinogram(0); - seg *=1000; // work-around problem in RunTests::check_if_equal for floats that it can fail for small numbers + seg *= 1000; // work-around problem in RunTests::check_if_equal for floats that it can fail for small numbers // values have to be symmetric around the middle of the scanner - for (int first=seg.get_min_axial_pos_num(), last=seg.get_max_axial_pos_num(); - first=seg.get_min_tangential_pos_num() && last<=seg.get_max_tangential_pos_num(); + for (int first = -1, last = +1; first >= seg.get_min_tangential_pos_num() && last <= seg.get_max_tangential_pos_num(); --first, ++last) check_if_equal(seg[3][0][first], seg[3][0][last], "check if symmetric along the tangential_pos direction. test " + name); - // test views. Need to reduce tolerance due to discretisation artefacts { const double old_tolerance = get_tolerance(); set_tolerance(.1); - const int mid_axial_pos_num = (seg.get_min_axial_pos_num()+seg.get_max_axial_pos_num())/2; + const int mid_axial_pos_num = (seg.get_min_axial_pos_num() + seg.get_max_axial_pos_num()) / 2; const int first_view = seg.get_min_view_num(); // we will compare the middle 11 entries // (the profile goes down a lot, and we want to avoid errors for very small numbers) - Array<1,float> row_first = seg[mid_axial_pos_num][first_view]; - row_first.resize(-5,5); - for (int view=seg.get_min_view_num() + 1; view<=seg.get_max_view_num(); ++view) - { - Array<1,float> row = seg[mid_axial_pos_num][view]; - row.resize(-5,5); - check_if_equal(row_first, row, - "check if symmetric along views. test " + name); - } + Array<1, float> row_first = seg[mid_axial_pos_num][first_view]; + row_first.resize(-5, 5); + for (int view = seg.get_min_view_num() + 1; view <= seg.get_max_view_num(); ++view) { + Array<1, float> row = seg[mid_axial_pos_num][view]; + row.resize(-5, 5); + check_if_equal(row_first, row, "check if symmetric along views. test " + name); + } set_tolerance(old_tolerance); } #if 0 @@ -333,229 +310,212 @@ ScatterSimulationTests::test_output_is_symmetric(const ProjData& proj_data, cons } void -ScatterSimulationTests::test_scatter_simulation() -{ - unique_ptr sss(new SingleScatterSimulation()); - - Scanner::Type type= Scanner::E931; - shared_ptr test_scanner(new Scanner(type)); - const float scanner_length = test_scanner->get_num_rings() * test_scanner->get_ring_spacing(); - - std::cerr << "Testing scatter simulation for the following scanner:\n" - << test_scanner->parameter_info() - << "\nAxial length = " << scanner_length << " mm" << std::endl; - - if(!test_scanner->has_energy_information()) - { - test_scanner->set_reference_energy(511); - test_scanner->set_energy_resolution(0.34f); - } +ScatterSimulationTests::test_scatter_simulation() { + unique_ptr sss(new SingleScatterSimulation()); - check(test_scanner->has_energy_information() == true, "Check the scanner has energy information."); + Scanner::Type type = Scanner::E931; + shared_ptr test_scanner(new Scanner(type)); + const float scanner_length = test_scanner->get_num_rings() * test_scanner->get_ring_spacing(); - shared_ptr exam(new ExamInfo); - exam->set_low_energy_thres(450); - exam->set_high_energy_thres(650); - exam->imaging_modality = ImagingModality::PT; + std::cerr << "Testing scatter simulation for the following scanner:\n" + << test_scanner->parameter_info() << "\nAxial length = " << scanner_length << " mm" << std::endl; - check(exam->has_energy_information() == true, "Check the ExamInfo has energy information."); + if (!test_scanner->has_energy_information()) { + test_scanner->set_reference_energy(511); + test_scanner->set_energy_resolution(0.34f); + } - sss->set_exam_info(*exam); + check(test_scanner->has_energy_information() == true, "Check the scanner has energy information."); - // Create the original projdata - shared_ptr original_projdata_info( dynamic_cast( - ProjDataInfo::ProjDataInfoCTI(test_scanner, - 1, 0, - test_scanner->get_num_detectors_per_ring()/2, - test_scanner->get_max_num_non_arccorrected_bins(), - false))); + shared_ptr exam(new ExamInfo); + exam->set_low_energy_thres(450); + exam->set_high_energy_thres(650); + exam->imaging_modality = ImagingModality::PT; - check(original_projdata_info->has_energy_information() == true, "Check the ProjDataInfo has energy information."); + check(exam->has_energy_information() == true, "Check the ExamInfo has energy information."); - shared_ptr > tmpl_density( new VoxelsOnCartesianGrid(exam, *original_projdata_info)); + sss->set_exam_info(*exam); - //// Create an object in the middle of the image (which will be in the middle of the scanner - CartesianCoordinate3D min_ind, max_ind; - tmpl_density->get_regular_range(min_ind, max_ind); - CartesianCoordinate3D centre((tmpl_density->get_physical_coordinates_for_indices(min_ind) + - tmpl_density->get_physical_coordinates_for_indices(max_ind))/2.F); + // Create the original projdata + shared_ptr original_projdata_info(dynamic_cast( + ProjDataInfo::ProjDataInfoCTI(test_scanner, 1, 0, test_scanner->get_num_detectors_per_ring() / 2, + test_scanner->get_max_num_non_arccorrected_bins(), false))); - EllipsoidalCylinder phantom(50.F, 50.F, 50.F, centre); - CartesianCoordinate3D num_samples(2,2,2); + check(original_projdata_info->has_energy_information() == true, "Check the ProjDataInfo has energy information."); - //// attenuation image - shared_ptr > water_density(tmpl_density->clone()); - phantom.construct_volume(*water_density, num_samples); - // Water attenuation coefficient. - *water_density *= 9.687E-02; - sss->set_density_image_sptr(water_density); + shared_ptr> tmpl_density(new VoxelsOnCartesianGrid(exam, *original_projdata_info)); - ////activity image (same object) - shared_ptr > act_density(tmpl_density->clone()); - phantom.construct_volume(*act_density, num_samples); - sss->set_activity_image_sptr(act_density); + //// Create an object in the middle of the image (which will be in the middle of the scanner + CartesianCoordinate3D min_ind, max_ind; + tmpl_density->get_regular_range(min_ind, max_ind); + CartesianCoordinate3D centre((tmpl_density->get_physical_coordinates_for_indices(min_ind) + + tmpl_density->get_physical_coordinates_for_indices(max_ind)) / + 2.F); + + EllipsoidalCylinder phantom(50.F, 50.F, 50.F, centre); + CartesianCoordinate3D num_samples(2, 2, 2); + + //// attenuation image + shared_ptr> water_density(tmpl_density->clone()); + phantom.construct_volume(*water_density, num_samples); + // Water attenuation coefficient. + *water_density *= 9.687E-02; + sss->set_density_image_sptr(water_density); - //// sss settings - sss->set_randomly_place_scatter_points(false); + ////activity image (same object) + shared_ptr> act_density(tmpl_density->clone()); + phantom.construct_volume(*act_density, num_samples); + sss->set_activity_image_sptr(act_density); - sss->set_template_proj_data_info(*original_projdata_info); - sss->downsample_scanner(original_projdata_info->get_scanner_sptr()->get_num_rings(), -1); + //// sss settings + sss->set_randomly_place_scatter_points(false); + + sss->set_template_proj_data_info(*original_projdata_info); + sss->downsample_scanner(original_projdata_info->get_scanner_sptr()->get_num_rings(), -1); #if 1 - set_tolerance(.02); - { - const int new_size_z = 14; // original_projdata_info->get_scanner_sptr()->get_num_rings() - const float zoom_z = static_cast(new_size_z-1)/(water_density->size()-1); - sss->downsample_density_image_for_scatter_points(.2F, zoom_z, -1, new_size_z); - test_symmetric(*sss, "rings_size14"); - } - { - const int new_size_z = 14; // original_projdata_info->get_scanner_sptr()->get_num_rings() - sss->downsample_density_image_for_scatter_points(.2F, -1.F, -1, new_size_z); - test_symmetric(*sss, "rings_size14_def_zoom"); - } - { - sss->downsample_density_image_for_scatter_points(.3F, .4F, -1, -1); - test_symmetric(*sss, "rings_zoomxy.3_zoomz.4"); - } - // reduce for smaller number of rings - set_tolerance(.03); - { - const int new_size_z = 5; - sss->downsample_density_image_for_scatter_points(.2F, -1.F, -1, new_size_z); - test_symmetric(*sss, "rings_size5"); - } - { - sss->downsample_density_image_for_scatter_points(.2F, .3F, -1, -1); - test_symmetric(*sss, "rings_zoomz.3"); - } + set_tolerance(.02); + { + const int new_size_z = 14; // original_projdata_info->get_scanner_sptr()->get_num_rings() + const float zoom_z = static_cast(new_size_z - 1) / (water_density->size() - 1); + sss->downsample_density_image_for_scatter_points(.2F, zoom_z, -1, new_size_z); + test_symmetric(*sss, "rings_size14"); + } + { + const int new_size_z = 14; // original_projdata_info->get_scanner_sptr()->get_num_rings() + sss->downsample_density_image_for_scatter_points(.2F, -1.F, -1, new_size_z); + test_symmetric(*sss, "rings_size14_def_zoom"); + } + { + sss->downsample_density_image_for_scatter_points(.3F, .4F, -1, -1); + test_symmetric(*sss, "rings_zoomxy.3_zoomz.4"); + } + // reduce for smaller number of rings + set_tolerance(.03); + { + const int new_size_z = 5; + sss->downsample_density_image_for_scatter_points(.2F, -1.F, -1, new_size_z); + test_symmetric(*sss, "rings_size5"); + } + { + sss->downsample_density_image_for_scatter_points(.2F, .3F, -1, -1); + test_symmetric(*sss, "rings_zoomz.3"); + } - // testing with zooming (but currently fails) - { - const CartesianCoordinate3D zooms(.5F, .3F, .3F); - shared_ptr > - zoomed_act_sptr(new VoxelsOnCartesianGrid - (zoom_image(*act_density, - zooms, - CartesianCoordinate3D(0.F,0.F,0.F) /* offset */, - round(BasicCoordinate<3,float>(act_density->get_lengths())*zooms)+1 /* sizes */, - ZoomOptions::preserve_projections) - ) - ); - //std::cerr << "new origin : " << zoomed_act_sptr->get_origin(); - sss->set_activity_image_sptr(zoomed_act_sptr); - std::cerr << "\nThis test should currently throw an error. You'll see some error messages therefore.\n"; - try - { - test_symmetric(*sss, "act_zoom_rings_zoomxy.3_zoomz.4"); - check(false, "Test on zooming of activity image should have thrown."); - } - catch(...) - { - // ok - } - // restore to original activity - sss->set_activity_image_sptr(act_density); + // testing with zooming (but currently fails) + { + const CartesianCoordinate3D zooms(.5F, .3F, .3F); + shared_ptr> zoomed_act_sptr(new VoxelsOnCartesianGrid( + zoom_image(*act_density, zooms, CartesianCoordinate3D(0.F, 0.F, 0.F) /* offset */, + round(BasicCoordinate<3, float>(act_density->get_lengths()) * zooms) + 1 /* sizes */, + ZoomOptions::preserve_projections))); + // std::cerr << "new origin : " << zoomed_act_sptr->get_origin(); + sss->set_activity_image_sptr(zoomed_act_sptr); + std::cerr << "\nThis test should currently throw an error. You'll see some error messages therefore.\n"; + try { + test_symmetric(*sss, "act_zoom_rings_zoomxy.3_zoomz.4"); + check(false, "Test on zooming of activity image should have thrown."); + } catch (...) { + // ok } + // restore to original activity + sss->set_activity_image_sptr(act_density); + } - // a few tests with more downsampled scanner - sss->set_template_proj_data_info(*original_projdata_info); - sss->downsample_scanner(original_projdata_info->get_scanner_sptr()->get_num_rings()/2, -1); - { - const int new_size_z = 14; - const float zoom_z = static_cast(new_size_z-1)/(water_density->size()-1); - sss->downsample_density_image_for_scatter_points(.2F, zoom_z, -1, new_size_z); - test_symmetric(*sss, "halfrings_size14"); - } - // reduce for smaller number of rings - set_tolerance(.03); - { - const int new_size_z = 5; - sss->downsample_density_image_for_scatter_points(.2F, -1.F, -1, new_size_z); - test_symmetric(*sss, "halfrings_size5"); - } - { - sss->downsample_density_image_for_scatter_points(.2F, .3F, -1, -1); - test_symmetric(*sss, "halfrings_zoomz.3"); - } + // a few tests with more downsampled scanner + sss->set_template_proj_data_info(*original_projdata_info); + sss->downsample_scanner(original_projdata_info->get_scanner_sptr()->get_num_rings() / 2, -1); + { + const int new_size_z = 14; + const float zoom_z = static_cast(new_size_z - 1) / (water_density->size() - 1); + sss->downsample_density_image_for_scatter_points(.2F, zoom_z, -1, new_size_z); + test_symmetric(*sss, "halfrings_size14"); + } + // reduce for smaller number of rings + set_tolerance(.03); + { + const int new_size_z = 5; + sss->downsample_density_image_for_scatter_points(.2F, -1.F, -1, new_size_z); + test_symmetric(*sss, "halfrings_size5"); + } + { + sss->downsample_density_image_for_scatter_points(.2F, .3F, -1, -1); + test_symmetric(*sss, "halfrings_zoomz.3"); + } #endif - // shared_ptr atten_sino(new ProjDataInMemory(exam, output_projdata_info)); - // atten_sino->fill(1.F); - // shared_ptr act_sino(new ProjDataInMemory(exam, output_projdata_info)); - // { - // info("ScatterSimulationTests: Calculate the Attenuation coefficients."); - // shared_ptr forw_projector_ptr; - // shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); - // forw_projector_ptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); - - // shared_ptr normalisation_ptr - // (new BinNormalisationFromAttenuationImage(water_density, - // forw_projector_ptr)); - - // { - // normalisation_ptr->set_up(output_projdata_info->create_shared_clone()); - // const double start_frame = 0; - // const double end_frame = 0; - // shared_ptr symmetries_sptr(forw_projector_ptr->get_symmetries_used()->clone()); - // normalisation_ptr->undo(*atten_sino,start_frame,end_frame, symmetries_sptr); - // } - - //// atten_sino->write_to_file("_sino"); - //// std::string density_image_for_scatter_points_output_filename("./image"); - //// write_to_file(density_image_for_scatter_points_output_filename, - //// *act_density); - - // { - // forw_projector_ptr->set_up(output_projdata_info->create_shared_clone(), act_density); - // forw_projector_ptr->forward_project(*act_sino, *act_density); - // } - - // for (int i = output_projdata_info->get_min_view_num(); - // i < output_projdata_info->get_max_view_num(); ++i) - // { - // Viewgram view_att = atten_sino->get_viewgram(i, 0); - // Viewgram view_act = act_sino->get_viewgram(i,0); - // Viewgram view_sct = sss_output->get_viewgram(i,0); - - // view_act *= view_att; - // view_act += view_sct; - - // act_sino->set_viewgram(view_act); - // } - // } + // shared_ptr atten_sino(new ProjDataInMemory(exam, output_projdata_info)); + // atten_sino->fill(1.F); + // shared_ptr act_sino(new ProjDataInMemory(exam, output_projdata_info)); + // { + // info("ScatterSimulationTests: Calculate the Attenuation coefficients."); + // shared_ptr forw_projector_ptr; + // shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + // forw_projector_ptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); + + // shared_ptr normalisation_ptr + // (new BinNormalisationFromAttenuationImage(water_density, + // forw_projector_ptr)); + + // { + // normalisation_ptr->set_up(output_projdata_info->create_shared_clone()); + // const double start_frame = 0; + // const double end_frame = 0; + // shared_ptr + // symmetries_sptr(forw_projector_ptr->get_symmetries_used()->clone()); + // normalisation_ptr->undo(*atten_sino,start_frame,end_frame, symmetries_sptr); + // } + + //// atten_sino->write_to_file("_sino"); + //// std::string density_image_for_scatter_points_output_filename("./image"); + //// write_to_file(density_image_for_scatter_points_output_filename, + //// *act_density); + + // { + // forw_projector_ptr->set_up(output_projdata_info->create_shared_clone(), act_density); + // forw_projector_ptr->forward_project(*act_sino, *act_density); + // } + + // for (int i = output_projdata_info->get_min_view_num(); + // i < output_projdata_info->get_max_view_num(); ++i) + // { + // Viewgram view_att = atten_sino->get_viewgram(i, 0); + // Viewgram view_act = act_sino->get_viewgram(i,0); + // Viewgram view_sct = sss_output->get_viewgram(i,0); + + // view_act *= view_att; + // view_act += view_sct; + + // act_sino->set_viewgram(view_act); + // } + // } } - -//void -//ScatterSimulationTests::simulate_scatter_for_one_point(shared_ptr) +// void +// ScatterSimulationTests::simulate_scatter_for_one_point(shared_ptr) //{ //} void -ScatterSimulationTests:: -run_tests() -{ +ScatterSimulationTests::run_tests() { - // test the downsampling functions. - test_downsampling_ProjDataInfo(); - test_downsampling_DiscretisedDensity(); + // test the downsampling functions. + test_downsampling_ProjDataInfo(); + test_downsampling_DiscretisedDensity(); - test_scatter_simulation(); + test_scatter_simulation(); } - END_NAMESPACE_STIR +int +main() { + USING_NAMESPACE_STIR + // decrease verbosity a bit to avoid too much output + Verbosity::set(0); -int main() -{ - USING_NAMESPACE_STIR - // decrease verbosity a bit to avoid too much output - Verbosity::set(0); - - ScatterSimulationTests tests; - tests.write_output = true; // TODO get this from the command line args - tests.run_tests(); - return tests.main_return_value(); + ScatterSimulationTests tests; + tests.write_output = true; // TODO get this from the command line args + tests.run_tests(); + return tests.main_return_value(); } diff --git a/src/test/test_SeparableGaussianArrayFilter.cxx b/src/test/test_SeparableGaussianArrayFilter.cxx index 13823eb1cf..83a3f1af1d 100644 --- a/src/test/test_SeparableGaussianArrayFilter.cxx +++ b/src/test/test_SeparableGaussianArrayFilter.cxx @@ -1,8 +1,8 @@ /*! - \file + \file \ingroup test - + \brief tests for the stir::SeparableGaussianArrayFilter class \author Ludovica Brusaferri @@ -41,7 +41,6 @@ START_NAMESPACE_STIR - /*! \brief Tests SeparableGaussianArrayFilter functionality \ingroup test @@ -52,31 +51,27 @@ START_NAMESPACE_STIR #define num_dimensions 3 -class SeparableGaussianArrayFilterTests : public RunTests -{ +class SeparableGaussianArrayFilterTests : public RunTests { public: void run_tests(); + private: //! test one case (overwrites contents of \c test) - void test_one(Array&, - const BasicCoordinate< num_dimensions,float>& fwhms, - const BasicCoordinate< num_dimensions,int>& max_kernel_sizes); - + void test_one(Array&, const BasicCoordinate& fwhms, + const BasicCoordinate& max_kernel_sizes); }; void -SeparableGaussianArrayFilterTests:: -test_one(Array& test, - const BasicCoordinate< num_dimensions,float>& fwhms, - const BasicCoordinate< num_dimensions,int>& max_kernel_sizes) -{ +SeparableGaussianArrayFilterTests::test_one(Array& test, + const BasicCoordinate& fwhms, + const BasicCoordinate& max_kernel_sizes) { test.fill(0.F); - BasicCoordinate<3,int> min_ind, max_ind; + BasicCoordinate<3, int> min_ind, max_ind; test.get_regular_range(min_ind, max_ind); - BasicCoordinate<3,int> centre = (max_ind+min_ind)/2; + BasicCoordinate<3, int> centre = (max_ind + min_ind) / 2; test[centre] = 1.F; - SeparableGaussianArrayFilter<3,float> filter(fwhms,max_kernel_sizes,true); + SeparableGaussianArrayFilter<3, float> filter(fwhms, max_kernel_sizes, true); filter(test); double old_tol = get_tolerance(); set_tolerance(.01); @@ -85,50 +80,54 @@ test_one(Array& test, check(test.find_min() >= 0, "test if Gaussian kernel is non-negative"); set_tolerance(.1); - for (int d=1; d<=3; ++d) - { - std::cerr << "testing FWHM along dim " << d << '\n'; - const Array<1,float> line = extract_line(test, centre, d); - const float fwhm = find_level_width(line.begin(), line.end(), .5*test[centre]); - check_if_equal(fwhm, fwhms[d], "FWHM of kernel"); - } + for (int d = 1; d <= 3; ++d) { + std::cerr << "testing FWHM along dim " << d << '\n'; + const Array<1, float> line = extract_line(test, centre, d); + const float fwhm = find_level_width(line.begin(), line.end(), .5 * test[centre]); + check_if_equal(fwhm, fwhms[d], "FWHM of kernel"); + } set_tolerance(old_tol); } void -SeparableGaussianArrayFilterTests::run_tests() -{ +SeparableGaussianArrayFilterTests::run_tests() { std::cerr << "\nTesting 3D\n"; { set_tolerance(.001F); - const int size1=69; - const int size2=200; - const int size3=130; - Array<3,float> test(IndexRange3D(size1,size2,size3)); + const int size1 = 69; + const int size2 = 200; + const int size3 = 130; + Array<3, float> test(IndexRange3D(size1, size2, size3)); { - BasicCoordinate< num_dimensions,float> fwhms; - fwhms[1]=9.F; fwhms[2]=7.4F; fwhms[3]=5.4F; - BasicCoordinate< num_dimensions,int> max_kernel_sizes; + BasicCoordinate fwhms; + fwhms[1] = 9.F; + fwhms[2] = 7.4F; + fwhms[3] = 5.4F; + BasicCoordinate max_kernel_sizes; std::cerr << "Fixed kernel size\n"; { - max_kernel_sizes[1]=19; max_kernel_sizes[2]=19; max_kernel_sizes[3]=29; - test_one(test, fwhms, max_kernel_sizes); + max_kernel_sizes[1] = 19; + max_kernel_sizes[2] = 19; + max_kernel_sizes[3] = 29; + test_one(test, fwhms, max_kernel_sizes); } std::cerr << "Automatic kernel size\n"; { - max_kernel_sizes[1]=-1; max_kernel_sizes[2]=-1; max_kernel_sizes[3]=-1; - test_one(test, fwhms, max_kernel_sizes); + max_kernel_sizes[1] = -1; + max_kernel_sizes[2] = -1; + max_kernel_sizes[3] = -1; + test_one(test, fwhms, max_kernel_sizes); } } - } + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { SeparableGaussianArrayFilterTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_SeparableMetzArrayFilter.cxx b/src/test/test_SeparableMetzArrayFilter.cxx index 4deaf46fa7..2fc1d0c3b1 100644 --- a/src/test/test_SeparableMetzArrayFilter.cxx +++ b/src/test/test_SeparableMetzArrayFilter.cxx @@ -1,8 +1,8 @@ /*! - \file + \file \ingroup test - + \brief tests for the stir::SeparableMetzArrayFilter class \author Kris Thielemans @@ -39,7 +39,6 @@ START_NAMESPACE_STIR - /*! \brief Tests SeparableMetzArrayFilter functionality \ingroup test @@ -47,57 +46,61 @@ START_NAMESPACE_STIR Currently only very basic tests on normalisation */ -class SeparableMetzArrayFilterTests : public RunTests -{ +class SeparableMetzArrayFilterTests : public RunTests { public: void run_tests(); -private: - - +private: }; void -SeparableMetzArrayFilterTests::run_tests() -{ +SeparableMetzArrayFilterTests::run_tests() { std::cerr << "\nTesting 3D\n"; { set_tolerance(.001F); - const int size1=69; - const int size2=200; - const int size3=130; - Array<3,float> test(IndexRange3D(size1,size2,size3)); + const int size1 = 69; + const int size2 = 200; + const int size3 = 130; + Array<3, float> test(IndexRange3D(size1, size2, size3)); #if 1 test.fill(0.F); - test[size1/2][size2/2][size3/2] = 1.F; -#else + test[size1 / 2][size2 / 2][size3 / 2] = 1.F; +#else // initialise to some arbitrary values { - Array<3,float>::full_iterator iter = test.begin_all(); + Array<3, float>::full_iterator iter = test.begin_all(); /*for (int i=-100; iter != test.end_all(); ++i, ++iter) *iter = 1;//i*i*2.F-i-100.F;*/ - test[0][0[0]]=1; + test[0][0 [0]] = 1; } #endif { - VectorWithOffset fwhms(1,3); - fwhms[1]=9.F; fwhms[2]=7.4F; fwhms[3]=5.4F; - VectorWithOffset metz_powers(1,3); - BasicCoordinate<3,float> sampling_distances = make_coordinate(3.1F, 2.F, 2.5F); - VectorWithOffset max_kernel_sizes(1,3); - max_kernel_sizes[1]=19; max_kernel_sizes[2]=19; max_kernel_sizes[3]=29; - + VectorWithOffset fwhms(1, 3); + fwhms[1] = 9.F; + fwhms[2] = 7.4F; + fwhms[3] = 5.4F; + VectorWithOffset metz_powers(1, 3); + BasicCoordinate<3, float> sampling_distances = make_coordinate(3.1F, 2.F, 2.5F); + VectorWithOffset max_kernel_sizes(1, 3); + max_kernel_sizes[1] = 19; + max_kernel_sizes[2] = 19; + max_kernel_sizes[3] = 29; + { - metz_powers[1]=0.F; metz_powers[2]=0.F; metz_powers[3]=0.F; - SeparableMetzArrayFilter<3,float> filter(fwhms, metz_powers, sampling_distances, max_kernel_sizes); + metz_powers[1] = 0.F; + metz_powers[2] = 0.F; + metz_powers[3] = 0.F; + SeparableMetzArrayFilter<3, float> filter(fwhms, metz_powers, sampling_distances, max_kernel_sizes); filter(test); check_if_equal(1.F, test.sum(), "test if Gaussian kernel is normalised to 1"); check(test.find_min() >= -0.005F, "test if Gaussian kernel is almost non-negative"); } { - metz_powers[1]=1.F; metz_powers[2]=2.F; metz_powers[3]=1.F; - SeparableMetzArrayFilter<3,float> filter(fwhms, metz_powers, sampling_distances, max_kernel_sizes); + metz_powers[1] = 1.F; + metz_powers[2] = 2.F; + metz_powers[3] = 1.F; + SeparableMetzArrayFilter<3, float> filter(fwhms, metz_powers, sampling_distances, max_kernel_sizes); filter(test); double old_tol = get_tolerance(); @@ -106,15 +109,15 @@ SeparableMetzArrayFilterTests::run_tests() set_tolerance(old_tol); } } - } + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { SeparableMetzArrayFilterTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_VectorWithOffset.cxx b/src/test/test_VectorWithOffset.cxx index 39fd55ea49..22dab9e5ea 100644 --- a/src/test/test_VectorWithOffset.cxx +++ b/src/test/test_VectorWithOffset.cxx @@ -29,10 +29,10 @@ */ #ifndef NDEBUG // set to high level of debugging -#ifdef _DEBUG -#undef _DEBUG -#endif -#define _DEBUG 2 +# ifdef _DEBUG +# undef _DEBUG +# endif +# define _DEBUG 2 #endif #include "stir/VectorWithOffset.h" @@ -53,74 +53,68 @@ using std::size_t; START_NAMESPACE_STIR - /*! \brief Test class for VectorWithOffset \ingroup test */ -class VectorWithOffsetTests : public RunTests -{ +class VectorWithOffsetTests : public RunTests { public: void run_tests(); }; void -VectorWithOffsetTests::run_tests() -{ +VectorWithOffsetTests::run_tests() { cerr << "Tests for VectorWithOffset\n" << "Everythings is fine if the program runs without any output." << endl; - + VectorWithOffset v(-3, 40); check_if_equal(v.get_min_index(), -3, "test basic constructor and get_min_index"); check_if_equal(v.get_max_index(), 40, "test basic constructor and get_max_index"); - check(v.size()== 40+3+1, "test basic constructor and size"); - check(v.capacity()== 40+3+1, "test basic constructor and capacity"); + check(v.size() == 40 + 3 + 1, "test basic constructor and size"); + check(v.capacity() == 40 + 3 + 1, "test basic constructor and capacity"); - for (int i=v.get_min_index(); i<=v.get_max_index(); i++) - v[i] = 2*i; + for (int i = v.get_min_index(); i <= v.get_max_index(); i++) + v[i] = 2 * i; check_if_equal(v[4], 8, "test operator[]"); - int *ptr = v.get_data_ptr(); - ptr[4+3] = 5; + int* ptr = v.get_data_ptr(); + ptr[4 + 3] = 5; v.release_data_ptr(); check_if_equal(v[4], 5, "test get_data_tr/release_data_ptr"); // iterator tests { - { + { int value = -3; - for (VectorWithOffset::iterator iter = v.begin(); - iter != v.end(); - iter++, value++) - *iter = value; + for (VectorWithOffset::iterator iter = v.begin(); iter != v.end(); iter++, value++) + *iter = value; check_if_equal(v[4], 4, "test iterators operator++ and *"); } { VectorWithOffset::const_iterator iter = v.begin(); - check_if_equal(*(iter+4-v.get_min_index()), 4, "test iterators operator+ and *"); - iter += 4-v.get_min_index(); + check_if_equal(*(iter + 4 - v.get_min_index()), 4, "test iterators operator+ and *"); + iter += 4 - v.get_min_index(); check_if_equal(*iter, 4, "test iterators operator+= and *"); ++iter; - check_if_equal(*(iter-1), 4, "test iterators operator+= and *"); + check_if_equal(*(iter - 1), 4, "test iterators operator+= and *"); --iter; check_if_equal(*iter, 4, "test iterators operator+= and *"); } { const VectorWithOffset& const_v = v; VectorWithOffset::const_iterator iter = const_v.begin(); - check_if_equal(*(iter+4-v.get_min_index()), 4, "test iterators operator+ and *"); - iter += 4-v.get_min_index(); + check_if_equal(*(iter + 4 - v.get_min_index()), 4, "test iterators operator+ and *"); + iter += 4 - v.get_min_index(); check_if_equal(*iter, 4, "test iterators operator+= and *"); ++iter; - check_if_equal(*(iter-1), 4, "test iterators operator+= and *"); + check_if_equal(*(iter - 1), 4, "test iterators operator+= and *"); --iter; check_if_equal(*iter, 4, "test iterators operator+= and *"); } - { - VectorWithOffset::iterator p=find(v.begin(), v.end(), 6); + VectorWithOffset::iterator p = find(v.begin(), v.end(), 6); check_if_zero(p - v.begin() - 9, "test iterators: find"); check_if_equal(*p, 6, "test iterators: find"); } @@ -132,7 +126,7 @@ VectorWithOffsetTests::run_tests() { VectorWithOffset::reverse_iterator pr = v.rbegin(); check_if_equal(*pr++, -3, "test reverse iterator operator++ and *"); - check_if_equal(*(pr+2), 0, "test reverse iterator operator++ and *"); + check_if_equal(*(pr + 2), 0, "test reverse iterator operator++ and *"); } sort(v.rbegin(), v.rend(), greater()); @@ -141,515 +135,420 @@ VectorWithOffsetTests::run_tests() } // end test iterators - { VectorWithOffset test = v; test.set_min_index(-1); - check( test.size()==v.size(), "test set_min_index (size)"); - check( test.capacity()==v.capacity(), "test set_min_index (capacity)"); - check_if_equal( test[-1], v[v.get_min_index()], "test set_min_index (operator[])"); + check(test.size() == v.size(), "test set_min_index (size)"); + check(test.capacity() == v.capacity(), "test set_min_index (capacity)"); + check_if_equal(test[-1], v[v.get_min_index()], "test set_min_index (operator[])"); } /**********************************************************************/ // tests on reserve() /**********************************************************************/ - { - // tests on reserve() with 0 length - { - // check reserve 0,max - { - VectorWithOffset test; - check_if_equal(test.capacity(), size_t(0), - "check capacity after default constructor"); - test.reserve(2); - check_if_equal(test.size(), size_t(0), - "check reserve of empty vector (0,max) (size)"); - check_if_equal(test.capacity(), size_t(2), - "check reserve of empty vector (0,max) (capacity)"); - check_if_equal(test.get_capacity_min_index(), 0, - "check reserve of empty vector (0,max) (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), 1, - "check reserve of empty vector (0,max) (capacity_max_index)"); - } - // check reserve -1,2 - { - VectorWithOffset test; - test.reserve(-1,2); - check_if_equal(test.size(), size_t(0), - "check reserve of empty vector (-1,2) (size)"); - check_if_equal(test.capacity(), size_t(4), - "check reserve of empty vector (-1,2) (capacity)"); - // note: for length 0 vectors, get_capacity_min_index() is always 0 - check_if_equal(test.get_capacity_min_index(), 0, - "check reserve of empty vector (-1,2) (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), 3, - "check reserve of empty vector (-1,2) (capacity_max_index)"); - } - // check reserve -1,2 and then 1,6 - { - VectorWithOffset test; - test.reserve(-1,2); - test.reserve(1,6); - check_if_equal(test.size(), size_t(0), - "check reserve of empty vector (-1,2 and then 1,6) (size)"); - check_if_equal(test.capacity(), size_t(6), - "check reserve of empty vector (-1,2 and then 1,6) (capacity)"); - // note: for length 0 vectors, get_capacity_min_index() is always 0 - check_if_equal(test.get_capacity_min_index(), 0, - "check reserve of empty vector (-1,2 and then 1,6) (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), 5, - "check reserve of empty vector (-1,2 and then 1,6) (capacity_max_index)"); - } - } // end of tests length 0 - - // tests of reserve() with non-zero length - { - const VectorWithOffset ref = v; - VectorWithOffset test = ref; - // check reserve within range (should have no effect) - test.reserve(0,1); - check_if_equal(test.size(), ref.size(), - "check reserve within range (size)"); - check_if_equal(test.get_min_index(), ref.get_min_index(), - "check reserve within range (get_min_index)"); - check_if_equal(test, ref, - "check reserve within range (values)"); - check_if_equal(test.capacity(), ref.size(), - "check reserve within range (capacity)"); - check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), - "check reserve within range (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), ref.get_max_index(), - "check reserve within range (capacity_max_index)"); - // check reserve within range on low index (should reserve space at higher indices only) - test.reserve(0,test.get_max_index()+5); - check_if_equal(test.size(), ref.size(), - "check reserve within range on low index (size)"); - check_if_equal(test.get_min_index(), ref.get_min_index(), - "check reserve within range on low index (get_min_index)"); - check_if_equal(test, ref, - "check reserve within range on low index (values)"); - check_if_equal(test.capacity(), ref.size()+5, - "check reserve within range on low index (capacity)"); - check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), - "check reserve within range on low index (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), ref.get_max_index()+5, - "check reserve within range on low index (capacity_max_index)"); - // check reserve within range on high index (should reserve space at low indices only) - test.recycle(); - check_if_equal(test.capacity(), size_t(0), "test recycle"); - test = ref; - test.reserve(test.get_min_index()-5,0); - check_if_equal(test.size(), ref.size(), - "check reserve within range on high index (size)"); - check_if_equal(test.get_min_index(), ref.get_min_index(), - "check reserve within range on high index (get_min_index)"); - check_if_equal(test, ref, - "check reserve within range on high index (values)"); - check_if_equal(test.capacity(), ref.size()+5, - "check reserve within range on high index (capacity)"); - check_if_equal(test.get_capacity_min_index(), ref.get_min_index()-5, - "check reserve within range on high index (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), ref.get_max_index(), - "check reserve within range on high index (capacity_max_index)"); - // check reserve for both ranges - test.recycle(); - check_if_equal(test.capacity(), size_t(0), "test recycle"); - test = ref; - test.reserve(test.get_min_index()-5,test.get_max_index()+4); - check_if_equal(test.size(), ref.size(), - "check reserve (size)"); - check_if_equal(test.get_min_index(), ref.get_min_index(), - "check reserve (get_min_index)"); - check_if_equal(test, ref, - "check reserve (values)"); - check_if_equal(test.capacity(), ref.size()+9, - "check reserve (capacity)"); - check_if_equal(test.get_capacity_min_index(), ref.get_min_index()-5, - "check reserve (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), ref.get_max_index()+4, - "check reserve (capacity_max_index)"); - } - } - /**********************************************************************/ - // tests on resize() - /**********************************************************************/ - { - // tests on resize() with 0 length - { - // check resize 0,max - { - VectorWithOffset test; - check_if_equal(test.capacity(), size_t(0), - "check capacity after default constructor"); - test.resize(2); - check_if_equal(test.size(), size_t(2), - "check resize of empty vector (0,max) (size)"); - check_if_equal(test.capacity(), size_t(2), - "check resize of empty vector (0,max) (capacity)"); - check_if_equal(test.get_min_index(), 0, - "check resize of empty vector (0,max) (min_index)"); - check_if_equal(test.get_max_index(), 1, - "check resize of empty vector (0,max) (max_index)"); - } - // check resize -1,2 - { - VectorWithOffset test; - test.resize(-1,2); - check_if_equal(test.size(), size_t(4), - "check resize of empty vector (-1,2) (size)"); - check_if_equal(test.capacity(), size_t(4), - "check resize of empty vector (-1,2) (capacity)"); - check_if_equal(test.get_min_index(), -1, - "check resize of empty vector (-1,2) (min_index)"); - check_if_equal(test.get_max_index(), 2, - "check resize of empty vector (-1,2) (max_index)"); - } - // check resize -1,2 and then 1,6 - { - VectorWithOffset test; - test.resize(-1,2); - test.resize(1,6); - check_if_equal(test.size(), size_t(6), - "check resize of empty vector (-1,2 and then 1,6) (size)"); - check_if_equal(test.capacity(), size_t(8), - "check resize of empty vector (-1,2 and then 1,6) (capacity)"); - // note: for length 0 vectors, get_min_index() is always 0 - check_if_equal(test.get_min_index(), 1, - "check resize of empty vector (-1,2 and then 1,6) (min_index)"); - check_if_equal(test.get_max_index(), 6, - "check resize of empty vector (-1,2 and then 1,6) (max_index)"); - } - } // end of tests length 0 - - // tests of resize() with non-zero length - { - const VectorWithOffset ref = v; - VectorWithOffset test = ref; - // check resize with identical range (should have no effect) - test.resize(ref.get_min_index(), ref.get_max_index()); - check_if_equal(test.size(), ref.size(), - "check resize with identical range (size)"); - check_if_equal(test.get_min_index(), ref.get_min_index(), - "check resize with identical range (get_min_index)"); - check_if_equal(test, ref, - "check resize with identical range (values)"); - check_if_equal(test.capacity(), ref.size(), - "check resize with identical range (capacity)"); - check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), - "check resize with identical range (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), ref.get_max_index(), - "check resize with identical range (capacity_max_index)"); - // check resize with grow on high index (should resize space at higher indices only) - test.resize(ref.get_min_index(),test.get_max_index()+5); - check_if_equal(test.size(), ref.size()+5, - "check resize with grow on high index (size)"); - check_if_equal(test.get_min_index(), ref.get_min_index(), - "check resize with grow on high index (get_min_index)"); - for (int i=ref.get_min_index(); i<=ref.get_max_index(); ++i) - check_if_equal(test[i], ref[i], - "check resize with grow on high index (values)"); - check_if_equal(test.capacity(), ref.size()+5, - "check resize with grow on high index (capacity)"); - check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), - "check resize with grow on high index (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), ref.get_max_index()+5, - "check resize with grow on high index (capacity_max_index)"); - // check resize with grow on low index (should resize space at low indices only) - test.recycle(); - check_if_equal(test.capacity(), size_t(0), "test recycle"); - test = ref; - test.resize(test.get_min_index()-5,ref.get_max_index()); - check_if_equal(test.size(), ref.size()+5, - "check resize with grow on low index (size)"); - check_if_equal(test.get_min_index(), ref.get_min_index()-5, - "check resize with grow on low index (get_min_index)"); - for (int i=ref.get_min_index(); i<=ref.get_max_index(); ++i) - check_if_equal(test[i], ref[i], - "check resize with grow on low index (values)"); - check_if_equal(test.capacity(), ref.size()+5, - "check resize with grow on low index (capacity)"); - check_if_equal(test.get_capacity_min_index(), ref.get_min_index()-5, - "check resize with grow on low index (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), ref.get_max_index(), - "check resize with grow on low index (capacity_max_index)"); - // check grow for both ranges - test.recycle(); - check_if_equal(test.capacity(), size_t(0), "test recycle"); - test = ref; - test.resize(test.get_min_index()-5,test.get_max_index()+4); - check_if_equal(test.size(), ref.size()+9, - "check resize with grow at both ends (size)"); - check_if_equal(test.get_min_index(), ref.get_min_index()-5, - "check resize with grow at both ends (get_min_index)"); - for (int i=ref.get_min_index(); i<=ref.get_max_index(); ++i) - check_if_equal(test[i], ref[i], - "check resize with grow at both ends (values)"); - check_if_equal(test.capacity(), ref.size()+9, - "check resize with grow at both ends (capacity)"); - check_if_equal(test.get_capacity_min_index(), ref.get_min_index()-5, - "check resize with grow at both ends (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), ref.get_max_index()+4, - "check resize with grow at both ends (capacity_max_index)"); - // check resize with shrink for both ranges - test.recycle(); - check_if_equal(test.capacity(), size_t(0), "test recycle"); - test = ref; - test.resize(test.get_min_index()+5,test.get_max_index()-4); - check_if_equal(test.size(), ref.size()-9, - "check resize with shrink at both ends(size)"); - check_if_equal(test.get_min_index(), ref.get_min_index()+5, - "check resize with shrink at both ends(get_min_index)"); - for (int i=test.get_min_index(); i<=test.get_max_index(); ++i) - check_if_equal(test[i], ref[i], - "check resize with shrink at both ends (values)"); - check_if_equal(test.capacity(), ref.size(), - "check resize with shrink at both ends(capacity)"); - check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), - "check resize with shrink at both ends(capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), ref.get_max_index(), - "check resize with shrink at both ends(capacity_max_index)"); - // check resize with shrink at left and grow at right - test.recycle(); - check_if_equal(test.capacity(), size_t(0), "test recycle"); - test = ref; - test.resize(test.get_min_index()+5,test.get_max_index()+4); - check_if_equal(test.size(), ref.size()-1, - "check resize with shrink at left and grow at right (size)"); - check_if_equal(test.get_min_index(), ref.get_min_index()+5, - "check resize with shrink at left and grow at right (get_min_index)"); - for (int i=test.get_min_index(); i<=ref.get_max_index(); ++i) - check_if_equal(test[i], ref[i], - "check resize with shrink at left and grow at right (values)"); - check_if_equal(test.capacity(), ref.size()+4, - "check resize with shrink at left and grow at right (capacity)"); - check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), - "check resize with shrink at left and grow at right (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), ref.get_max_index()+4, - "check resize with shrink at left and grow at right (capacity_max_index)"); - // check resize with resize non-overlapping to right - test.recycle(); - check_if_equal(test.capacity(), size_t(0), "test recycle"); - test = ref; - // note: test new size is smaller than original size, so no reallocation should occur - test.resize(test.get_max_index()+20, static_cast(test.get_max_index()+20+ref.size()-3)); - check_if_equal(test.size(), size_t(ref.size()-2), - "check resize with resize non-overlapping to right (size)"); - check_if_equal(test.get_min_index(), ref.get_max_index()+20, - "check resize with resize non-overlapping to right (get_min_index)"); - check_if_equal(test.capacity(), ref.size(), - "check resize with resize non-overlapping to right (capacity)"); - check_if_equal(test.get_capacity_min_index(), test.get_min_index(), - "check resize with resize non-overlapping to right (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), test.get_min_index()+static_cast(test.capacity())-1, - "check resize with resize non-overlapping to right (capacity_max_index)"); - // check resize with resize non-overlapping to left - test.recycle(); - check_if_equal(test.capacity(), size_t(0), "test recycle"); - test = ref; - // not: test new size is larger than original size, so reallocation should occur - test.resize(test.get_min_index()-300, static_cast(test.get_min_index()-300+ref.size()+4)); - check_if_equal(test.size(), size_t(ref.size()+5), - "check resize with resize non-overlapping to left (size)"); - check_if_equal(test.get_min_index(), ref.get_min_index()-300, - "check resize with resize non-overlapping to left (get_min_index)"); - check_if_equal(test.capacity(), test.size(), - "check resize with resize non-overlapping to left (capacity)"); - check_if_equal(test.get_capacity_min_index(), test.get_min_index(), - "check resize with resize non-overlapping to left (capacity_min_index)"); - check_if_equal(test.get_capacity_max_index(), test.get_max_index(), - "check resize with resize non-overlapping to left (capacity_max_index)"); - } - } + { // tests on reserve() with 0 length + {// check reserve 0,max + {VectorWithOffset test; + check_if_equal(test.capacity(), size_t(0), "check capacity after default constructor"); + test.reserve(2); + check_if_equal(test.size(), size_t(0), "check reserve of empty vector (0,max) (size)"); + check_if_equal(test.capacity(), size_t(2), "check reserve of empty vector (0,max) (capacity)"); + check_if_equal(test.get_capacity_min_index(), 0, "check reserve of empty vector (0,max) (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), 1, "check reserve of empty vector (0,max) (capacity_max_index)"); +} +// check reserve -1,2 +{ + VectorWithOffset test; + test.reserve(-1, 2); + check_if_equal(test.size(), size_t(0), "check reserve of empty vector (-1,2) (size)"); + check_if_equal(test.capacity(), size_t(4), "check reserve of empty vector (-1,2) (capacity)"); + // note: for length 0 vectors, get_capacity_min_index() is always 0 + check_if_equal(test.get_capacity_min_index(), 0, "check reserve of empty vector (-1,2) (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), 3, "check reserve of empty vector (-1,2) (capacity_max_index)"); +} +// check reserve -1,2 and then 1,6 +{ + VectorWithOffset test; + test.reserve(-1, 2); + test.reserve(1, 6); + check_if_equal(test.size(), size_t(0), "check reserve of empty vector (-1,2 and then 1,6) (size)"); + check_if_equal(test.capacity(), size_t(6), "check reserve of empty vector (-1,2 and then 1,6) (capacity)"); + // note: for length 0 vectors, get_capacity_min_index() is always 0 + check_if_equal(test.get_capacity_min_index(), 0, "check reserve of empty vector (-1,2 and then 1,6) (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), 5, "check reserve of empty vector (-1,2 and then 1,6) (capacity_max_index)"); +} +} // end of tests length 0 - /**********************************************************************/ - // tests on operator += etc - /**********************************************************************/ - { - const VectorWithOffset ref = v; - VectorWithOffset test = ref; - - test = ref; test += ref; - for (int i=ref.get_min_index(); i<= ref.get_max_index(); ++i) - check_if_equal( test[i] , ref[i]*2, "test operator+=(VectorWithOffset)"); - test = ref; test -= ref; - for (int i=ref.get_min_index(); i<= ref.get_max_index(); ++i) - check_if_equal( test[i] , 0, "test operator-=(VectorWithOffset)"); - test = ref; test *= ref; - for (int i=ref.get_min_index(); i<= ref.get_max_index(); ++i) - check_if_equal( test[i] , ref[i]*ref[i], "test operator*=(VectorWithOffset)"); - - const int minimum = *std::min_element(ref.begin(), ref.end()); - const int ensure_non_zero = - minimum<= 0 ? -minimum+1 : 0; - VectorWithOffset denominator = ref; - test = ref; - for (int i=ref.get_min_index(); i<= ref.get_max_index(); ++i) - { - denominator[i] += ensure_non_zero; - test[i]+=10000; - } - test /= denominator; - for (int i=ref.get_min_index(); i<= ref.get_max_index(); ++i) - check_if_equal( test[i] , (ref[i]+10000)/(ref[i]+ensure_non_zero), "test operator/=(VectorWithOffset)"); +// tests of reserve() with non-zero length +{ + const VectorWithOffset ref = v; + VectorWithOffset test = ref; + // check reserve within range (should have no effect) + test.reserve(0, 1); + check_if_equal(test.size(), ref.size(), "check reserve within range (size)"); + check_if_equal(test.get_min_index(), ref.get_min_index(), "check reserve within range (get_min_index)"); + check_if_equal(test, ref, "check reserve within range (values)"); + check_if_equal(test.capacity(), ref.size(), "check reserve within range (capacity)"); + check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), "check reserve within range (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), ref.get_max_index(), "check reserve within range (capacity_max_index)"); + // check reserve within range on low index (should reserve space at higher indices only) + test.reserve(0, test.get_max_index() + 5); + check_if_equal(test.size(), ref.size(), "check reserve within range on low index (size)"); + check_if_equal(test.get_min_index(), ref.get_min_index(), "check reserve within range on low index (get_min_index)"); + check_if_equal(test, ref, "check reserve within range on low index (values)"); + check_if_equal(test.capacity(), ref.size() + 5, "check reserve within range on low index (capacity)"); + check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), + "check reserve within range on low index (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), ref.get_max_index() + 5, + "check reserve within range on low index (capacity_max_index)"); + // check reserve within range on high index (should reserve space at low indices only) + test.recycle(); + check_if_equal(test.capacity(), size_t(0), "test recycle"); + test = ref; + test.reserve(test.get_min_index() - 5, 0); + check_if_equal(test.size(), ref.size(), "check reserve within range on high index (size)"); + check_if_equal(test.get_min_index(), ref.get_min_index(), "check reserve within range on high index (get_min_index)"); + check_if_equal(test, ref, "check reserve within range on high index (values)"); + check_if_equal(test.capacity(), ref.size() + 5, "check reserve within range on high index (capacity)"); + check_if_equal(test.get_capacity_min_index(), ref.get_min_index() - 5, + "check reserve within range on high index (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), ref.get_max_index(), + "check reserve within range on high index (capacity_max_index)"); + // check reserve for both ranges + test.recycle(); + check_if_equal(test.capacity(), size_t(0), "test recycle"); + test = ref; + test.reserve(test.get_min_index() - 5, test.get_max_index() + 4); + check_if_equal(test.size(), ref.size(), "check reserve (size)"); + check_if_equal(test.get_min_index(), ref.get_min_index(), "check reserve (get_min_index)"); + check_if_equal(test, ref, "check reserve (values)"); + check_if_equal(test.capacity(), ref.size() + 9, "check reserve (capacity)"); + check_if_equal(test.get_capacity_min_index(), ref.get_min_index() - 5, "check reserve (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), ref.get_max_index() + 4, "check reserve (capacity_max_index)"); +} +} +/**********************************************************************/ +// tests on resize() +/**********************************************************************/ +{ // tests on resize() with 0 length + {// check resize 0,max + {VectorWithOffset test; +check_if_equal(test.capacity(), size_t(0), "check capacity after default constructor"); +test.resize(2); +check_if_equal(test.size(), size_t(2), "check resize of empty vector (0,max) (size)"); +check_if_equal(test.capacity(), size_t(2), "check resize of empty vector (0,max) (capacity)"); +check_if_equal(test.get_min_index(), 0, "check resize of empty vector (0,max) (min_index)"); +check_if_equal(test.get_max_index(), 1, "check resize of empty vector (0,max) (max_index)"); +} +// check resize -1,2 +{ + VectorWithOffset test; + test.resize(-1, 2); + check_if_equal(test.size(), size_t(4), "check resize of empty vector (-1,2) (size)"); + check_if_equal(test.capacity(), size_t(4), "check resize of empty vector (-1,2) (capacity)"); + check_if_equal(test.get_min_index(), -1, "check resize of empty vector (-1,2) (min_index)"); + check_if_equal(test.get_max_index(), 2, "check resize of empty vector (-1,2) (max_index)"); +} +// check resize -1,2 and then 1,6 +{ + VectorWithOffset test; + test.resize(-1, 2); + test.resize(1, 6); + check_if_equal(test.size(), size_t(6), "check resize of empty vector (-1,2 and then 1,6) (size)"); + check_if_equal(test.capacity(), size_t(8), "check resize of empty vector (-1,2 and then 1,6) (capacity)"); + // note: for length 0 vectors, get_min_index() is always 0 + check_if_equal(test.get_min_index(), 1, "check resize of empty vector (-1,2 and then 1,6) (min_index)"); + check_if_equal(test.get_max_index(), 6, "check resize of empty vector (-1,2 and then 1,6) (max_index)"); +} +} // end of tests length 0 - } +// tests of resize() with non-zero length +{ + const VectorWithOffset ref = v; + VectorWithOffset test = ref; + // check resize with identical range (should have no effect) + test.resize(ref.get_min_index(), ref.get_max_index()); + check_if_equal(test.size(), ref.size(), "check resize with identical range (size)"); + check_if_equal(test.get_min_index(), ref.get_min_index(), "check resize with identical range (get_min_index)"); + check_if_equal(test, ref, "check resize with identical range (values)"); + check_if_equal(test.capacity(), ref.size(), "check resize with identical range (capacity)"); + check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), "check resize with identical range (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), ref.get_max_index(), "check resize with identical range (capacity_max_index)"); + // check resize with grow on high index (should resize space at higher indices only) + test.resize(ref.get_min_index(), test.get_max_index() + 5); + check_if_equal(test.size(), ref.size() + 5, "check resize with grow on high index (size)"); + check_if_equal(test.get_min_index(), ref.get_min_index(), "check resize with grow on high index (get_min_index)"); + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], ref[i], "check resize with grow on high index (values)"); + check_if_equal(test.capacity(), ref.size() + 5, "check resize with grow on high index (capacity)"); + check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), "check resize with grow on high index (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), ref.get_max_index() + 5, + "check resize with grow on high index (capacity_max_index)"); + // check resize with grow on low index (should resize space at low indices only) + test.recycle(); + check_if_equal(test.capacity(), size_t(0), "test recycle"); + test = ref; + test.resize(test.get_min_index() - 5, ref.get_max_index()); + check_if_equal(test.size(), ref.size() + 5, "check resize with grow on low index (size)"); + check_if_equal(test.get_min_index(), ref.get_min_index() - 5, "check resize with grow on low index (get_min_index)"); + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], ref[i], "check resize with grow on low index (values)"); + check_if_equal(test.capacity(), ref.size() + 5, "check resize with grow on low index (capacity)"); + check_if_equal(test.get_capacity_min_index(), ref.get_min_index() - 5, + "check resize with grow on low index (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), ref.get_max_index(), "check resize with grow on low index (capacity_max_index)"); + // check grow for both ranges + test.recycle(); + check_if_equal(test.capacity(), size_t(0), "test recycle"); + test = ref; + test.resize(test.get_min_index() - 5, test.get_max_index() + 4); + check_if_equal(test.size(), ref.size() + 9, "check resize with grow at both ends (size)"); + check_if_equal(test.get_min_index(), ref.get_min_index() - 5, "check resize with grow at both ends (get_min_index)"); + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], ref[i], "check resize with grow at both ends (values)"); + check_if_equal(test.capacity(), ref.size() + 9, "check resize with grow at both ends (capacity)"); + check_if_equal(test.get_capacity_min_index(), ref.get_min_index() - 5, + "check resize with grow at both ends (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), ref.get_max_index() + 4, + "check resize with grow at both ends (capacity_max_index)"); + // check resize with shrink for both ranges + test.recycle(); + check_if_equal(test.capacity(), size_t(0), "test recycle"); + test = ref; + test.resize(test.get_min_index() + 5, test.get_max_index() - 4); + check_if_equal(test.size(), ref.size() - 9, "check resize with shrink at both ends(size)"); + check_if_equal(test.get_min_index(), ref.get_min_index() + 5, "check resize with shrink at both ends(get_min_index)"); + for (int i = test.get_min_index(); i <= test.get_max_index(); ++i) + check_if_equal(test[i], ref[i], "check resize with shrink at both ends (values)"); + check_if_equal(test.capacity(), ref.size(), "check resize with shrink at both ends(capacity)"); + check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), "check resize with shrink at both ends(capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), ref.get_max_index(), "check resize with shrink at both ends(capacity_max_index)"); + // check resize with shrink at left and grow at right + test.recycle(); + check_if_equal(test.capacity(), size_t(0), "test recycle"); + test = ref; + test.resize(test.get_min_index() + 5, test.get_max_index() + 4); + check_if_equal(test.size(), ref.size() - 1, "check resize with shrink at left and grow at right (size)"); + check_if_equal(test.get_min_index(), ref.get_min_index() + 5, + "check resize with shrink at left and grow at right (get_min_index)"); + for (int i = test.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], ref[i], "check resize with shrink at left and grow at right (values)"); + check_if_equal(test.capacity(), ref.size() + 4, "check resize with shrink at left and grow at right (capacity)"); + check_if_equal(test.get_capacity_min_index(), ref.get_min_index(), + "check resize with shrink at left and grow at right (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), ref.get_max_index() + 4, + "check resize with shrink at left and grow at right (capacity_max_index)"); + // check resize with resize non-overlapping to right + test.recycle(); + check_if_equal(test.capacity(), size_t(0), "test recycle"); + test = ref; + // note: test new size is smaller than original size, so no reallocation should occur + test.resize(test.get_max_index() + 20, static_cast(test.get_max_index() + 20 + ref.size() - 3)); + check_if_equal(test.size(), size_t(ref.size() - 2), "check resize with resize non-overlapping to right (size)"); + check_if_equal(test.get_min_index(), ref.get_max_index() + 20, + "check resize with resize non-overlapping to right (get_min_index)"); + check_if_equal(test.capacity(), ref.size(), "check resize with resize non-overlapping to right (capacity)"); + check_if_equal(test.get_capacity_min_index(), test.get_min_index(), + "check resize with resize non-overlapping to right (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), test.get_min_index() + static_cast(test.capacity()) - 1, + "check resize with resize non-overlapping to right (capacity_max_index)"); + // check resize with resize non-overlapping to left + test.recycle(); + check_if_equal(test.capacity(), size_t(0), "test recycle"); + test = ref; + // not: test new size is larger than original size, so reallocation should occur + test.resize(test.get_min_index() - 300, static_cast(test.get_min_index() - 300 + ref.size() + 4)); + check_if_equal(test.size(), size_t(ref.size() + 5), "check resize with resize non-overlapping to left (size)"); + check_if_equal(test.get_min_index(), ref.get_min_index() - 300, + "check resize with resize non-overlapping to left (get_min_index)"); + check_if_equal(test.capacity(), test.size(), "check resize with resize non-overlapping to left (capacity)"); + check_if_equal(test.get_capacity_min_index(), test.get_min_index(), + "check resize with resize non-overlapping to left (capacity_min_index)"); + check_if_equal(test.get_capacity_max_index(), test.get_max_index(), + "check resize with resize non-overlapping to left (capacity_max_index)"); +} +} - // some checks with min_index==0 - { - VectorWithOffset v0(40); - check_if_equal(v0.get_min_index(), 0, "test 1-arg constructor and get_min_index"); - check_if_equal(v0.get_max_index(), 40-1, "test 1-arg constructor and get_max_index"); - check_if_equal(v0.size(), size_t(40), "test 1-arg constructor and size"); - check_if_equal(v0.capacity(), size_t(40), "test 1-arg constructor and capacity"); +/**********************************************************************/ +// tests on operator += etc +/**********************************************************************/ +{ + const VectorWithOffset ref = v; + VectorWithOffset test = ref; + + test = ref; + test += ref; + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], ref[i] * 2, "test operator+=(VectorWithOffset)"); + test = ref; + test -= ref; + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], 0, "test operator-=(VectorWithOffset)"); + test = ref; + test *= ref; + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], ref[i] * ref[i], "test operator*=(VectorWithOffset)"); + + const int minimum = *std::min_element(ref.begin(), ref.end()); + const int ensure_non_zero = minimum <= 0 ? -minimum + 1 : 0; + VectorWithOffset denominator = ref; + test = ref; + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) { + denominator[i] += ensure_non_zero; + test[i] += 10000; } + test /= denominator; + for (int i = ref.get_min_index(); i <= ref.get_max_index(); ++i) + check_if_equal(test[i], (ref[i] + 10000) / (ref[i] + ensure_non_zero), "test operator/=(VectorWithOffset)"); +} - // tests on empty - { - { - VectorWithOffset test; - check(test.empty(), "test default constructor gives empty vector"); - } - { - VectorWithOffset test(1,-1); - check(test.empty(), "test reverse range gives empty vector"); - } - { - VectorWithOffset test(3,6); - check(!test.empty(), "test vector says !empty()"); - test.resize(0); - check(test.empty(), "test vector resized to size 0 is empty()"); - } - } +// some checks with min_index==0 +{ + VectorWithOffset v0(40); + check_if_equal(v0.get_min_index(), 0, "test 1-arg constructor and get_min_index"); + check_if_equal(v0.get_max_index(), 40 - 1, "test 1-arg constructor and get_max_index"); + check_if_equal(v0.size(), size_t(40), "test 1-arg constructor and size"); + check_if_equal(v0.capacity(), size_t(40), "test 1-arg constructor and capacity"); +} - // tests on at() with out-of-range - { - { - VectorWithOffset test; - try - { - int a=test.at(5); - // if we get here, there's a problem, so we report that by failing the next test. - check(false, "test out-of-range on empty vector"); - } - catch (std::out_of_range& ) - { - } - } - { - VectorWithOffset test(1,54); - try - { - test[4]=1; - check_if_equal(test.at(4),1, "test using at() to read content"); - test.at(3)=2; - check_if_equal(test[3],2, "test using at() to set content"); - - int a=test.at(55); - // if we get here, there's a problem, so we report that by failing the next test. - check(false, "test out-of-range on vector"); - } - catch (std::out_of_range& ) - { - } - } - } +// tests on empty +{{VectorWithOffset test; +check(test.empty(), "test default constructor gives empty vector"); +} +{ + VectorWithOffset test(1, -1); + check(test.empty(), "test reverse range gives empty vector"); +} +{ + VectorWithOffset test(3, 6); + check(!test.empty(), "test vector says !empty()"); + test.resize(0); + check(test.empty(), "test vector resized to size 0 is empty()"); +} +} - // checks on using existing data_ptr with constructor indices starting at 0 - { - const int size=100; - int data[size]; - std::fill(data, data+size, 12345); - check_if_equal(data[0], 12345, "test filling data block at 0"); - check_if_equal(data[size-1], 12345, "test filling data block at end"); - // set data_ptr to somewhere in the block to check overrun - int * data_ptr = data+10; - - const int vsize = size-20; - VectorWithOffset v(vsize, data_ptr, data + size); - check(!v.owns_memory_for_data(), "test vector using data_ptr: should not allocate new memory"); - check(data_ptr == v.get_data_ptr(), "test vector using data_ptr: get_data_ptr()"); - v.release_data_ptr(); - check_if_equal(v[1], 12345, "test vector using data_ptr: vector at 1 after construction"); - v[1]=1; - check_if_equal(data_ptr[1], 1, "test filling vector using data_ptr: data at 1 after setting"); - check_if_equal(v[1], 1, "test filling vector using data_ptr: vector at 1 after setting"); - v.fill(2); - check_if_equal(std::accumulate(v.begin(), v.end(), 0), 2*vsize , "test filling vector using data_ptr"); - check_if_equal(data_ptr[0], 2, "test filling vector using data_ptr: data at 0"); - check_if_equal(data_ptr[-1], 12345, "test filling vector using data_ptr: data block before vector"); - check_if_equal(data_ptr[vsize], 12345, "test filling vector using data_ptr: data block after vector"); - - // test resize using existing memory - v[1]=5; - v.resize(1,vsize-5); - check(!v.owns_memory_for_data(), "test vector using data_ptr: resize should not allocate new memory"); - check(data_ptr+1 == v.get_data_ptr(), "test vector using data_ptr: get_data_ptr() after resize"); - v.release_data_ptr(); - check_if_equal(v[1], 5 , "test resizing vector using data_ptr: data at 1"); - v[1]=6; - check_if_equal(data_ptr[1], 6, "test resizing vector using data_ptr: data should still be refered to"); - check_if_equal(std::accumulate(v.begin(), v.end(), 0), 6+v[2]*(v.get_length()-1) , "test resizing vector using data_ptr"); - - // test resize that should allocate new memory - v.resize(-1,vsize-2); - check(v.owns_memory_for_data(), "test vector using data_ptr: resize should allocate new memory"); - v.fill(7); - check_if_equal(data[9], 12345, "test vector using data_ptr: after resize data block at 9"); - check_if_equal(data[size-9], 12345, "test vector using data_ptr: after resize data block at end-9"); - check_if_equal(data_ptr[1], 6, "test vector using data_ptr: after resize data 1"); +// tests on at() with out-of-range +{{VectorWithOffset test; +try { + int a = test.at(5); + // if we get here, there's a problem, so we report that by failing the next test. + check(false, "test out-of-range on empty vector"); +} catch (std::out_of_range&) { +} +} +{ + VectorWithOffset test(1, 54); + try { + test[4] = 1; + check_if_equal(test.at(4), 1, "test using at() to read content"); + test.at(3) = 2; + check_if_equal(test[3], 2, "test using at() to set content"); + + int a = test.at(55); + // if we get here, there's a problem, so we report that by failing the next test. + check(false, "test out-of-range on vector"); + } catch (std::out_of_range&) { } +} +} - // checks on using existing data_ptr with constructor indices starting at -3 - { - const int size=100; - int data[size]; - std::fill(data, data+size, 12345); - check_if_equal(data[0], 12345, "test filling data block at 0"); - check_if_equal(data[size-1], 12345, "test filling data block at end"); - // set data_ptr to somewhere in the block to check overrun - int * data_ptr = data+10; - - const int vsize = size-20; - VectorWithOffset v(-3, vsize-4, data_ptr, data + size); - check_if_equal(v.get_length(), vsize, "test vector using data_ptr (negative min_index):size"); - // first essentially same tests as above - check(!v.owns_memory_for_data(), "test vector using data_ptr (negative min_index): should not allocate new memory"); - check(data_ptr == v.get_data_ptr(), "test vector using data_ptr (negative min_index): get_data_ptr()"); - v.release_data_ptr(); - check_if_equal(v[1], 12345, "test vector using data_ptr (negative min_index): vector at 1 after construction"); - check_if_equal(v[-3], 12345, "test vector using data_ptr (negative min_index): vector at -3 after construction"); - v[-3]=1; - check_if_equal(data_ptr[0], 1, "test filling vector using data_ptr (negative min_index) data at -3 after setting"); - check_if_equal(v[-3], 1, "test filling vector using data_ptr (negative min_index) vector at -3 after setting"); - v.fill(2); - check_if_equal(std::accumulate(v.begin(), v.end(), 0), 2*vsize , "test filling vector using data_ptr (negative min_index)"); - check_if_equal(data_ptr[0], 2, "test filling vector using data_ptr (negative min_index) data at 0"); - check_if_equal(data_ptr[-1], 12345, "test filling vector using data_ptr (negative min_index) data block before vector"); - check_if_equal(data_ptr[vsize], 12345, "test filling vector using data_ptr (negative min_index) data block after vector"); - - // assignment that doesn't reallocate - v = VectorWithOffset(2,6); - check(!v.owns_memory_for_data(), "test vector using data_ptr (negative min_index): assignment should not allocate new memory"); - v[4]=4; - check_if_equal(v[4], 4, "test vector using data_ptr (negative min_index): vector at 4 after assignment and setting"); - // vector will again start at data_ptr - check_if_equal(data_ptr[4-v.get_min_index()], 4, "test vector using data_ptr (negative min_index): data at 4-min_index after assignment and setting"); - // another assignment that does not reallocate - v = VectorWithOffset(static_cast(size-(data_ptr-data) )); - check(!v.owns_memory_for_data(), "test vector using data_ptr (negative min_index): 2nd assignment should not allocate new memory"); - // assignment that does reallocate - v = VectorWithOffset(static_cast(size-(data_ptr-data)+1 )); - check(v.owns_memory_for_data(), "test vector using data_ptr (negative min_index): 3rd assignment should allocate new memory"); - } +// checks on using existing data_ptr with constructor indices starting at 0 +{ + const int size = 100; + int data[size]; + std::fill(data, data + size, 12345); + check_if_equal(data[0], 12345, "test filling data block at 0"); + check_if_equal(data[size - 1], 12345, "test filling data block at end"); + // set data_ptr to somewhere in the block to check overrun + int* data_ptr = data + 10; + + const int vsize = size - 20; + VectorWithOffset v(vsize, data_ptr, data + size); + check(!v.owns_memory_for_data(), "test vector using data_ptr: should not allocate new memory"); + check(data_ptr == v.get_data_ptr(), "test vector using data_ptr: get_data_ptr()"); + v.release_data_ptr(); + check_if_equal(v[1], 12345, "test vector using data_ptr: vector at 1 after construction"); + v[1] = 1; + check_if_equal(data_ptr[1], 1, "test filling vector using data_ptr: data at 1 after setting"); + check_if_equal(v[1], 1, "test filling vector using data_ptr: vector at 1 after setting"); + v.fill(2); + check_if_equal(std::accumulate(v.begin(), v.end(), 0), 2 * vsize, "test filling vector using data_ptr"); + check_if_equal(data_ptr[0], 2, "test filling vector using data_ptr: data at 0"); + check_if_equal(data_ptr[-1], 12345, "test filling vector using data_ptr: data block before vector"); + check_if_equal(data_ptr[vsize], 12345, "test filling vector using data_ptr: data block after vector"); + + // test resize using existing memory + v[1] = 5; + v.resize(1, vsize - 5); + check(!v.owns_memory_for_data(), "test vector using data_ptr: resize should not allocate new memory"); + check(data_ptr + 1 == v.get_data_ptr(), "test vector using data_ptr: get_data_ptr() after resize"); + v.release_data_ptr(); + check_if_equal(v[1], 5, "test resizing vector using data_ptr: data at 1"); + v[1] = 6; + check_if_equal(data_ptr[1], 6, "test resizing vector using data_ptr: data should still be refered to"); + check_if_equal(std::accumulate(v.begin(), v.end(), 0), 6 + v[2] * (v.get_length() - 1), "test resizing vector using data_ptr"); + + // test resize that should allocate new memory + v.resize(-1, vsize - 2); + check(v.owns_memory_for_data(), "test vector using data_ptr: resize should allocate new memory"); + v.fill(7); + check_if_equal(data[9], 12345, "test vector using data_ptr: after resize data block at 9"); + check_if_equal(data[size - 9], 12345, "test vector using data_ptr: after resize data block at end-9"); + check_if_equal(data_ptr[1], 6, "test vector using data_ptr: after resize data 1"); } +// checks on using existing data_ptr with constructor indices starting at -3 +{ + const int size = 100; + int data[size]; + std::fill(data, data + size, 12345); + check_if_equal(data[0], 12345, "test filling data block at 0"); + check_if_equal(data[size - 1], 12345, "test filling data block at end"); + // set data_ptr to somewhere in the block to check overrun + int* data_ptr = data + 10; + + const int vsize = size - 20; + VectorWithOffset v(-3, vsize - 4, data_ptr, data + size); + check_if_equal(v.get_length(), vsize, "test vector using data_ptr (negative min_index):size"); + // first essentially same tests as above + check(!v.owns_memory_for_data(), "test vector using data_ptr (negative min_index): should not allocate new memory"); + check(data_ptr == v.get_data_ptr(), "test vector using data_ptr (negative min_index): get_data_ptr()"); + v.release_data_ptr(); + check_if_equal(v[1], 12345, "test vector using data_ptr (negative min_index): vector at 1 after construction"); + check_if_equal(v[-3], 12345, "test vector using data_ptr (negative min_index): vector at -3 after construction"); + v[-3] = 1; + check_if_equal(data_ptr[0], 1, "test filling vector using data_ptr (negative min_index) data at -3 after setting"); + check_if_equal(v[-3], 1, "test filling vector using data_ptr (negative min_index) vector at -3 after setting"); + v.fill(2); + check_if_equal(std::accumulate(v.begin(), v.end(), 0), 2 * vsize, "test filling vector using data_ptr (negative min_index)"); + check_if_equal(data_ptr[0], 2, "test filling vector using data_ptr (negative min_index) data at 0"); + check_if_equal(data_ptr[-1], 12345, "test filling vector using data_ptr (negative min_index) data block before vector"); + check_if_equal(data_ptr[vsize], 12345, "test filling vector using data_ptr (negative min_index) data block after vector"); + + // assignment that doesn't reallocate + v = VectorWithOffset(2, 6); + check(!v.owns_memory_for_data(), "test vector using data_ptr (negative min_index): assignment should not allocate new memory"); + v[4] = 4; + check_if_equal(v[4], 4, "test vector using data_ptr (negative min_index): vector at 4 after assignment and setting"); + // vector will again start at data_ptr + check_if_equal(data_ptr[4 - v.get_min_index()], 4, + "test vector using data_ptr (negative min_index): data at 4-min_index after assignment and setting"); + // another assignment that does not reallocate + v = VectorWithOffset(static_cast(size - (data_ptr - data))); + check(!v.owns_memory_for_data(), + "test vector using data_ptr (negative min_index): 2nd assignment should not allocate new memory"); + // assignment that does reallocate + v = VectorWithOffset(static_cast(size - (data_ptr - data) + 1)); + check(v.owns_memory_for_data(), "test vector using data_ptr (negative min_index): 3rd assignment should allocate new memory"); +} +} END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { VectorWithOffsetTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_VoxelsOnCartesianGrid.cxx b/src/test/test_VoxelsOnCartesianGrid.cxx index 8f4025ddc6..6a7d550790 100644 --- a/src/test/test_VoxelsOnCartesianGrid.cxx +++ b/src/test/test_VoxelsOnCartesianGrid.cxx @@ -2,35 +2,35 @@ // /* Copyright (C) 2000 PARAPET partners - Copyright (C) 2000- 2011, Hammersmith Imanet Ltd + Copyright (C) 2000- 2011, Hammersmith Imanet Ltd Copyright (C) 2018, Commonwealth Scientific and Industrial Research Organisation Australian eHealth Research Centre Copyright (C) 2019, University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! \file \ingroup test - + \brief Test program for stir::VoxelsOnCartesianGrid and image hierarchy - + \author Ashley Gillman \author Sanida Mustafovic \author Kris Thielemans \author PARAPET project - + */ #include "stir/VoxelsOnCartesianGrid.h" @@ -55,221 +55,197 @@ START_NAMESPACE_STIR \brief Test class for VoxelsOnCartesianGrid and image hierarchy */ -class VoxelsOnCartesianGridTests : public RunTests -{ +class VoxelsOnCartesianGridTests : public RunTests { public: void run_tests(); }; - void VoxelsOnCartesianGridTests::run_tests() -{ +{ cerr << "Tests for VoxelsOnCartesianGrid and the image hierarchy\n"; - - CartesianCoordinate3D origin (0,1,2); - CartesianCoordinate3D grid_spacing (3,4,5); - - IndexRange<3> - range(CartesianCoordinate3D(0,-15,-14), - CartesianCoordinate3D(4,14,15)); - - Array<3,float> test1(range); - + + CartesianCoordinate3D origin(0, 1, 2); + CartesianCoordinate3D grid_spacing(3, 4, 5); + + IndexRange<3> range(CartesianCoordinate3D(0, -15, -14), CartesianCoordinate3D(4, 14, 15)); + + Array<3, float> test1(range); + { cerr << "Tests with default constructor\n"; - - VoxelsOnCartesianGrid ob1; - + + VoxelsOnCartesianGrid ob1; + // Check set.* & constructor - + ob1.set_origin(origin); - ob1.set_grid_spacing (grid_spacing); - - check_if_equal( ob1.get_grid_spacing(), grid_spacing,"test on grid_spacing"); - check_if_equal( ob1.get_origin(), origin, "test on origin"); + ob1.set_grid_spacing(grid_spacing); + + check_if_equal(ob1.get_grid_spacing(), grid_spacing, "test on grid_spacing"); + check_if_equal(ob1.get_origin(), origin, "test on origin"); } - + { cerr << "Tests with 2nd constructor (array, origin, grid_spacing)\n"; - - VoxelsOnCartesianGrid ob2(test1,origin, grid_spacing); + + VoxelsOnCartesianGrid ob2(test1, origin, grid_spacing); test1[1][12][5] = float(5.5); test1[4][5][-5] = float(4.5); - - check_if_equal( ob2.get_grid_spacing(),grid_spacing, "test on grid_spacing"); - check_if_equal( ob2.get_origin(), origin, "test on origin"); - check_if_equal( test1.sum(), 10.F, "test on arrays"); + + check_if_equal(ob2.get_grid_spacing(), grid_spacing, "test on grid_spacing"); + check_if_equal(ob2.get_origin(), origin, "test on origin"); + check_if_equal(test1.sum(), 10.F, "test on arrays"); } { - + cerr << "Tests with 3rd constructor(index_range, origin, grid_spacing)\n"; - VoxelsOnCartesianGrid ob3(range,origin, grid_spacing); - - check( ob3.get_index_range() == range, "test on range"); - check_if_equal( ob3.get_grid_spacing(),grid_spacing, "test on grid_spacing"); - check_if_equal( ob3.get_origin(), origin, "test on origin"); - - const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); - const CartesianCoordinate3D coord = - ob3.get_physical_coordinates_for_indices(indices); - const CartesianCoordinate3D rel_coord = - ob3.get_relative_coordinates_for_indices(indices); - - check_if_equal(coord, rel_coord + origin, - "test on get_physical_coordinates_for_indices"); - check_if_equal(rel_coord, grid_spacing*BasicCoordinate<3,float>(indices), - "test on get_relative_coordinates_for_indices"); - check_if_equal(indices, ob3.get_indices_closest_to_relative_coordinates(rel_coord), - "test on get_indices_closest_to_relative_coordinates"); - check_if_equal(indices, ob3.get_indices_closest_to_physical_coordinates(coord), - "test on get_indices_closest_to_relative_coordinates"); - check_if_equal(indices,ob3.get_indices_closest_to_relative_coordinates(rel_coord + grid_spacing/3), - "test on get_indices_closest_to_relative_coordinates (not on grid point)"); + VoxelsOnCartesianGrid ob3(range, origin, grid_spacing); + + check(ob3.get_index_range() == range, "test on range"); + check_if_equal(ob3.get_grid_spacing(), grid_spacing, "test on grid_spacing"); + check_if_equal(ob3.get_origin(), origin, "test on origin"); + const BasicCoordinate<3, int> indices = make_coordinate(1, 2, 3); + const CartesianCoordinate3D coord = ob3.get_physical_coordinates_for_indices(indices); + const CartesianCoordinate3D rel_coord = ob3.get_relative_coordinates_for_indices(indices); + check_if_equal(coord, rel_coord + origin, "test on get_physical_coordinates_for_indices"); + check_if_equal(rel_coord, grid_spacing * BasicCoordinate<3, float>(indices), "test on get_relative_coordinates_for_indices"); + check_if_equal(indices, ob3.get_indices_closest_to_relative_coordinates(rel_coord), + "test on get_indices_closest_to_relative_coordinates"); + check_if_equal(indices, ob3.get_indices_closest_to_physical_coordinates(coord), + "test on get_indices_closest_to_relative_coordinates"); + check_if_equal(indices, ob3.get_indices_closest_to_relative_coordinates(rel_coord + grid_spacing / 3), + "test on get_indices_closest_to_relative_coordinates (not on grid point)"); } - + shared_ptr scanner_ptr(new Scanner(Scanner::E953)); - shared_ptr proj_data_info_ptr( - ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - /*span=*/1, - /*max_delta=*/5, - /*num_views=*/8, - /*num_tang_poss=*/16)); - + shared_ptr proj_data_info_ptr(ProjDataInfo::ProjDataInfoCTI(scanner_ptr, + /*span=*/1, + /*max_delta=*/5, + /*num_views=*/8, + /*num_tang_poss=*/16)); + { cerr << "Tests with constructor with ProjDataInfo with default sizes\n"; - - const float zoom=2.3F; - //KT 10/12/2001 removed make_xy_size_odd things - - VoxelsOnCartesianGrid - ob4(*proj_data_info_ptr,zoom,origin); - + + const float zoom = 2.3F; + // KT 10/12/2001 removed make_xy_size_odd things + + VoxelsOnCartesianGrid ob4(*proj_data_info_ptr, zoom, origin); + IndexRange<3> obtained_range = ob4.get_index_range(); CartesianCoordinate3D low_bound, high_bound; check(obtained_range.get_regular_range(low_bound, high_bound), "test regular range"); - + // KT 11/09/2001 adapted as this constructor now takes zoom into account - const bool is_arccorrected = - dynamic_cast(proj_data_info_ptr.get()) != 0; + const bool is_arccorrected = dynamic_cast(proj_data_info_ptr.get()) != 0; check(is_arccorrected, "ProjDataInfoCTI should have returned arc-corrected data"); - if (is_arccorrected) - { - const int FOVradius_in_bins = - max(proj_data_info_ptr->get_max_tangential_pos_num(), - -proj_data_info_ptr->get_min_tangential_pos_num()); - const int diameter_int = - 2*static_cast(ceil(FOVradius_in_bins * zoom)) + 1; - - check_if_equal(low_bound, CartesianCoordinate3D(0,-(diameter_int/2),-(diameter_int/2)), - "test on index range: lower bounds"); - check_if_equal(high_bound, CartesianCoordinate3D(30,+(diameter_int/2),+(diameter_int/2)), - "test on index range: higher bounds"); + if (is_arccorrected) { + const int FOVradius_in_bins = + max(proj_data_info_ptr->get_max_tangential_pos_num(), -proj_data_info_ptr->get_min_tangential_pos_num()); + const int diameter_int = 2 * static_cast(ceil(FOVradius_in_bins * zoom)) + 1; + + check_if_equal(low_bound, CartesianCoordinate3D(0, -(diameter_int / 2), -(diameter_int / 2)), + "test on index range: lower bounds"); + check_if_equal(high_bound, CartesianCoordinate3D(30, +(diameter_int / 2), +(diameter_int / 2)), + "test on index range: higher bounds"); } - check_if_equal(ob4.get_grid_spacing(), - CartesianCoordinate3D(scanner_ptr->get_ring_spacing()/2, - scanner_ptr->get_default_bin_size()/zoom, - scanner_ptr->get_default_bin_size()/zoom), + check_if_equal(ob4.get_grid_spacing(), + CartesianCoordinate3D(scanner_ptr->get_ring_spacing() / 2, scanner_ptr->get_default_bin_size() / zoom, + scanner_ptr->get_default_bin_size() / zoom), "test on grid spacing"); check_if_equal(ob4.get_origin(), origin); } { - + cerr << "Tests with constructor with ProjDataInfo with non-default sizes\n"; // KT 10/12/2001 changed to allow for new format of constructor, and add z_size const int xy_size = 100; - const float zoom=3.1F; - const int min_xy = -(xy_size/2); - const int max_xy = -(xy_size/2)+xy_size-1; + const float zoom = 3.1F; + const int min_xy = -(xy_size / 2); + const int max_xy = -(xy_size / 2) + xy_size - 1; const int z_size = 9; - VoxelsOnCartesianGrid - ob5(*proj_data_info_ptr,zoom,origin,CartesianCoordinate3D(z_size,xy_size,xy_size)); + VoxelsOnCartesianGrid ob5(*proj_data_info_ptr, zoom, origin, CartesianCoordinate3D(z_size, xy_size, xy_size)); // put in some data for further testing ob5.fill(1.F); - ob5[1][1][1]=5.F; + ob5[1][1][1] = 5.F; IndexRange<3> obtained_range = ob5.get_index_range(); CartesianCoordinate3D low_bound, high_bound; check(obtained_range.get_regular_range(low_bound, high_bound), "test regular range"); - - check_if_equal(low_bound, CartesianCoordinate3D(0,min_xy,min_xy),"test on index range: lower bounds"); - check_if_equal(high_bound, CartesianCoordinate3D(z_size-1,max_xy,max_xy),"test on index range: higher bounds"); - check_if_equal(ob5.get_grid_spacing(), - CartesianCoordinate3D(scanner_ptr->get_ring_spacing()/2, - scanner_ptr->get_default_bin_size()/zoom, - scanner_ptr->get_default_bin_size()/zoom), + + check_if_equal(low_bound, CartesianCoordinate3D(0, min_xy, min_xy), "test on index range: lower bounds"); + check_if_equal(high_bound, CartesianCoordinate3D(z_size - 1, max_xy, max_xy), "test on index range: higher bounds"); + check_if_equal(ob5.get_grid_spacing(), + CartesianCoordinate3D(scanner_ptr->get_ring_spacing() / 2, scanner_ptr->get_default_bin_size() / zoom, + scanner_ptr->get_default_bin_size() / zoom), "test on grid spacing"); check_if_equal(ob5.get_origin(), origin); { // with different zooms shared_ptr exam_info_sptr(new ExamInfo()); - CartesianCoordinate3D zooms(1.1F,1.2F,1.3F); - VoxelsOnCartesianGrid - ob6(exam_info_sptr, *proj_data_info_ptr,zooms,origin,CartesianCoordinate3D(z_size,xy_size,xy_size)); + CartesianCoordinate3D zooms(1.1F, 1.2F, 1.3F); + VoxelsOnCartesianGrid ob6(exam_info_sptr, *proj_data_info_ptr, zooms, origin, + CartesianCoordinate3D(z_size, xy_size, xy_size)); check_if_equal(ob6.get_grid_spacing(), - CartesianCoordinate3D(scanner_ptr->get_ring_spacing()/2/zooms[1], - scanner_ptr->get_default_bin_size()/zooms[2], - scanner_ptr->get_default_bin_size()/zooms[3]), + CartesianCoordinate3D(scanner_ptr->get_ring_spacing() / 2 / zooms[1], + scanner_ptr->get_default_bin_size() / zooms[2], + scanner_ptr->get_default_bin_size() / zooms[3]), "test on grid spacing (3 different zooms)"); check_if_equal(ob6.get_origin(), origin); } { cerr << "Tests get_empty_voxels_on_cartesian_grid\n"; - - shared_ptr< VoxelsOnCartesianGrid > emp(ob5.get_empty_voxels_on_cartesian_grid()); - + + shared_ptr> emp(ob5.get_empty_voxels_on_cartesian_grid()); + IndexRange<3> obtained_range2 = emp->get_index_range(); - check_if_equal( emp->get_origin(), ob5.get_origin(), "test on origin"); - check_if_equal( emp->get_grid_spacing(), ob5.get_grid_spacing(),"test on grid_spacing"); - check(emp->get_index_range() == ob5.get_index_range(),"test on index range"); - + check_if_equal(emp->get_origin(), ob5.get_origin(), "test on origin"); + check_if_equal(emp->get_grid_spacing(), ob5.get_grid_spacing(), "test on grid_spacing"); + check(emp->get_index_range() == ob5.get_index_range(), "test on index range"); } - + { cerr << "Tests get_empty_copy()\n"; - - shared_ptr > emp(ob5.get_empty_copy()); - - VoxelsOnCartesianGrid* emp1 = - dynamic_cast* >(emp.get()); + + shared_ptr> emp(ob5.get_empty_copy()); + + VoxelsOnCartesianGrid* emp1 = dynamic_cast*>(emp.get()); check(emp1 != 0, "test on pointer conversion from get_empty_copy"); - + IndexRange<3> obtained_range3 = emp1->get_index_range(); - check_if_equal( emp->get_origin(), ob5.get_origin(), "test on origin"); - check_if_equal( emp1->get_grid_spacing(), ob5.get_grid_spacing(),"test on grid_spacing"); - check(emp->get_index_range() == ob5.get_index_range(),"test on index range"); + check_if_equal(emp->get_origin(), ob5.get_origin(), "test on origin"); + check_if_equal(emp1->get_grid_spacing(), ob5.get_grid_spacing(), "test on grid_spacing"); + check(emp->get_index_range() == ob5.get_index_range(), "test on index range"); } { cerr << "Tests has_same_characteristics()\n"; - shared_ptr > emp (ob5.get_empty_copy()); + shared_ptr> emp(ob5.get_empty_copy()); check(ob5.has_same_characteristics(*emp), "test on has_same_characteristics after get_empty_copy"); check(ob5 != *emp, "test on operator!= after get_empty_copy"); *emp += ob5; check(ob5 == *emp, "test on operator== after get_empty_copy and operator+="); - emp->set_origin(ob5.get_origin()+1.F); + emp->set_origin(ob5.get_origin() + 1.F); check(ob5 != *emp, "test on operator!= after shifting origin"); emp->set_origin(ob5.get_origin()); check(ob5 == *emp, "test on operator== after shifting origin back to original"); - dynamic_cast& >(*emp). - set_grid_spacing(ob5.get_grid_spacing()+.3F); + dynamic_cast&>(*emp).set_grid_spacing(ob5.get_grid_spacing() + .3F); check(ob5 != *emp, "test on operator!= after changing voxel size"); - dynamic_cast& >(*emp). - set_grid_spacing(ob5.get_grid_spacing()); + dynamic_cast&>(*emp).set_grid_spacing(ob5.get_grid_spacing()); check(ob5 == *emp, "test on operator== after changing voxel size back to original"); { - IndexRange<3> range = emp->get_index_range(); - range.resize(0,0); - emp->resize(range); - check(!ob5.has_same_characteristics(*emp), "test on has_same_characteristics after resize"); + IndexRange<3> range = emp->get_index_range(); + range.resize(0, 0); + emp->resize(range); + check(!ob5.has_same_characteristics(*emp), "test on has_same_characteristics after resize"); } } - } { @@ -278,98 +254,72 @@ VoxelsOnCartesianGridTests::run_tests() shared_ptr hfs_exam_info_sptr(new ExamInfo()); hfs_exam_info_sptr->patient_position.set_orientation(PatientPosition::head_in); hfs_exam_info_sptr->patient_position.set_rotation(PatientPosition::supine); - VoxelsOnCartesianGrid hfs_image(hfs_exam_info_sptr, - range, origin, grid_spacing); + VoxelsOnCartesianGrid hfs_image(hfs_exam_info_sptr, range, origin, grid_spacing); shared_ptr ffs_exam_info_sptr(new ExamInfo()); ffs_exam_info_sptr->patient_position.set_orientation(PatientPosition::feet_in); ffs_exam_info_sptr->patient_position.set_rotation(PatientPosition::supine); - VoxelsOnCartesianGrid ffs_image(ffs_exam_info_sptr, - range, origin, grid_spacing); + VoxelsOnCartesianGrid ffs_image(ffs_exam_info_sptr, range, origin, grid_spacing); shared_ptr hfp_exam_info_sptr(new ExamInfo()); hfp_exam_info_sptr->patient_position.set_orientation(PatientPosition::head_in); hfp_exam_info_sptr->patient_position.set_rotation(PatientPosition::prone); - VoxelsOnCartesianGrid hfp_image(hfp_exam_info_sptr, - range, origin, grid_spacing); + VoxelsOnCartesianGrid hfp_image(hfp_exam_info_sptr, range, origin, grid_spacing); shared_ptr ffp_exam_info_sptr(new ExamInfo()); ffp_exam_info_sptr->patient_position.set_orientation(PatientPosition::feet_in); ffp_exam_info_sptr->patient_position.set_rotation(PatientPosition::prone); - VoxelsOnCartesianGrid ffp_image(ffp_exam_info_sptr, - range, origin, grid_spacing); + VoxelsOnCartesianGrid ffp_image(ffp_exam_info_sptr, range, origin, grid_spacing); - const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); + const BasicCoordinate<3, int> indices = make_coordinate(1, 2, 3); // Check some known relations check_if_equal(hfs_image.get_LPS_coordinates_for_indices(indices).x(), - -hfp_image.get_LPS_coordinates_for_indices(indices).x(), - "head in (suppine/prone) have opposite x"); + -hfp_image.get_LPS_coordinates_for_indices(indices).x(), "head in (suppine/prone) have opposite x"); check_if_equal(hfs_image.get_LPS_coordinates_for_indices(indices).y(), - -hfp_image.get_LPS_coordinates_for_indices(indices).y(), - "head in (suppine/prone) have opposite y"); - check_if_equal(hfs_image.get_LPS_coordinates_for_indices(indices).z(), - hfp_image.get_LPS_coordinates_for_indices(indices).z(), + -hfp_image.get_LPS_coordinates_for_indices(indices).y(), "head in (suppine/prone) have opposite y"); + check_if_equal(hfs_image.get_LPS_coordinates_for_indices(indices).z(), hfp_image.get_LPS_coordinates_for_indices(indices).z(), "head in (suppine/prone) have same z"); check_if_equal(ffs_image.get_LPS_coordinates_for_indices(indices).x(), - -ffp_image.get_LPS_coordinates_for_indices(indices).x(), - "feet in (suppine/prone) have opposite x"); + -ffp_image.get_LPS_coordinates_for_indices(indices).x(), "feet in (suppine/prone) have opposite x"); check_if_equal(ffs_image.get_LPS_coordinates_for_indices(indices).y(), - -ffp_image.get_LPS_coordinates_for_indices(indices).y(), - "feet in (suppine/prone) have opposite y"); - check_if_equal(ffs_image.get_LPS_coordinates_for_indices(indices).z(), - ffp_image.get_LPS_coordinates_for_indices(indices).z(), + -ffp_image.get_LPS_coordinates_for_indices(indices).y(), "feet in (suppine/prone) have opposite y"); + check_if_equal(ffs_image.get_LPS_coordinates_for_indices(indices).z(), ffp_image.get_LPS_coordinates_for_indices(indices).z(), "feet in (suppine/prone) have same z"); check_if_equal(hfs_image.get_LPS_coordinates_for_indices(indices).x(), - -ffs_image.get_LPS_coordinates_for_indices(indices).x(), - "(head/feet) in suppine have opposite x"); - check_if_equal(hfs_image.get_LPS_coordinates_for_indices(indices).y(), - ffs_image.get_LPS_coordinates_for_indices(indices).y(), + -ffs_image.get_LPS_coordinates_for_indices(indices).x(), "(head/feet) in suppine have opposite x"); + check_if_equal(hfs_image.get_LPS_coordinates_for_indices(indices).y(), ffs_image.get_LPS_coordinates_for_indices(indices).y(), "(head/feet) in suppine have same y"); check_if_equal(hfs_image.get_LPS_coordinates_for_indices(indices).z(), - -ffs_image.get_LPS_coordinates_for_indices(indices).z(), - "(head/feet) in suppine have opposite z"); + -ffs_image.get_LPS_coordinates_for_indices(indices).z(), "(head/feet) in suppine have opposite z"); check_if_equal(hfp_image.get_LPS_coordinates_for_indices(indices).x(), - -ffp_image.get_LPS_coordinates_for_indices(indices).x(), - "(head/feet) in prone have opposite x"); - check_if_equal(hfp_image.get_LPS_coordinates_for_indices(indices).y(), - ffp_image.get_LPS_coordinates_for_indices(indices).y(), + -ffp_image.get_LPS_coordinates_for_indices(indices).x(), "(head/feet) in prone have opposite x"); + check_if_equal(hfp_image.get_LPS_coordinates_for_indices(indices).y(), ffp_image.get_LPS_coordinates_for_indices(indices).y(), "(head/feet) in prone have same y"); check_if_equal(hfp_image.get_LPS_coordinates_for_indices(indices).z(), - -ffp_image.get_LPS_coordinates_for_indices(indices).z(), - "(head/feet) in prone have opposite z"); + -ffp_image.get_LPS_coordinates_for_indices(indices).z(), "(head/feet) in prone have opposite z"); // Check inverse consistency - check_if_equal(indices, - hfs_image.get_indices_closest_to_LPS_coordinates( - hfs_image.get_LPS_coordinates_for_indices(indices)), + check_if_equal(indices, hfs_image.get_indices_closest_to_LPS_coordinates(hfs_image.get_LPS_coordinates_for_indices(indices)), "HFS inverse consistency"); - check_if_equal(indices, - ffs_image.get_indices_closest_to_LPS_coordinates( - ffs_image.get_LPS_coordinates_for_indices(indices)), + check_if_equal(indices, ffs_image.get_indices_closest_to_LPS_coordinates(ffs_image.get_LPS_coordinates_for_indices(indices)), "FFS inverse consistency"); - check_if_equal(indices, - hfp_image.get_indices_closest_to_LPS_coordinates( - hfp_image.get_LPS_coordinates_for_indices(indices)), + check_if_equal(indices, hfp_image.get_indices_closest_to_LPS_coordinates(hfp_image.get_LPS_coordinates_for_indices(indices)), "HFP inverse consistency"); - check_if_equal(indices, - ffp_image.get_indices_closest_to_LPS_coordinates( - ffp_image.get_LPS_coordinates_for_indices(indices)), + check_if_equal(indices, ffp_image.get_indices_closest_to_LPS_coordinates(ffp_image.get_LPS_coordinates_for_indices(indices)), "FFP inverse consistency"); } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main() -{ +int +main() { VoxelsOnCartesianGridTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_convert_array.cxx b/src/test/test_convert_array.cxx index 5d6274206a..97360a4d06 100644 --- a/src/test/test_convert_array.cxx +++ b/src/test/test_convert_array.cxx @@ -18,8 +18,8 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup test + \file + \ingroup test \brief tests for the stir::convert_array functions \author Kris Thielemans @@ -41,108 +41,100 @@ using std::endl; START_NAMESPACE_STIR //! tests convert_array functionality -class convert_array_Tests : public RunTests -{ +class convert_array_Tests : public RunTests { public: void run_tests(); }; - void -convert_array_Tests::run_tests() -{ +convert_array_Tests::run_tests() { + + cerr << "Test program for 'convert_array'." << endl << "Everything is fine when there is no output below." << endl; - cerr << "Test program for 'convert_array'." << endl - << "Everything is fine when there is no output below." << endl; - // 1D { - Array<1,float> tf1(1,20); + Array<1, float> tf1(1, 20); tf1.fill(100.F); - - Array<1,short> ti1(1,20); + + Array<1, short> ti1(1, 20); ti1.fill(100); - + { // float -> short with a preferred scale factor float scale_factor = float(1); - Array<1,short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); - - check(scale_factor == float(1),"test convert_array float->short 1D"); + Array<1, short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); + + check(scale_factor == float(1), "test convert_array float->short 1D"); check_if_equal(ti1, ti2, "test convert_array float->short 1D"); } - - + { // float -> short with automatic scale factor float scale_factor = 0; - Array<1,short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); - - check(fabs(NumericInfo().max_value()/1.01 / ti2[1] -1) < 1E-4); - for (int i=1; i<= 20; i++) - ti2[i] = short( double(ti2[i]) *scale_factor); + Array<1, short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); + + check(fabs(NumericInfo().max_value() / 1.01 / ti2[1] - 1) < 1E-4); + for (int i = 1; i <= 20; i++) + ti2[i] = short(double(ti2[i]) * scale_factor); check(ti1 == ti2); } - + tf1 *= 1E20F; { // float -> short with a preferred scale factor that needs to be adjusted float scale_factor = 1; - Array<1,short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); - - check(fabs(NumericInfo().max_value()/1.01 / ti2[1] -1) < 1E-4); - for (int i=1; i<= 20; i++) - check(fabs(double(ti2[i]) *scale_factor / tf1[i] - 1) < 1E-4) ; - + Array<1, short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); + + check(fabs(NumericInfo().max_value() / 1.01 / ti2[1] - 1) < 1E-4); + for (int i = 1; i <= 20; i++) + check(fabs(double(ti2[i]) * scale_factor / tf1[i] - 1) < 1E-4); } - + { // short -> float with a scale factor = 1 float scale_factor = 1; - Array<1,float> tf2 = convert_array(scale_factor, ti1, NumericInfo()); - Array<1,short> ti2(1,20); - - + Array<1, float> tf2 = convert_array(scale_factor, ti1, NumericInfo()); + Array<1, short> ti2(1, 20); + check(scale_factor == float(1)); check(tf2[1] == 100.F); - for (int i=1; i<= 20; i++) - ti2[i] = short(double(tf2[i]) *scale_factor) ; + for (int i = 1; i <= 20; i++) + ti2[i] = short(double(tf2[i]) * scale_factor); check(ti1 == ti2); } - + { // short -> float with a preferred scale factor = .01 float scale_factor = .01F; - Array<1,float> tf2 = convert_array(scale_factor, ti1, NumericInfo()); - Array<1,short> ti2(1,20); - + Array<1, float> tf2 = convert_array(scale_factor, ti1, NumericInfo()); + Array<1, short> ti2(1, 20); + check(scale_factor == float(.01)); - //TODO double->short - for (int i=1; i<= 20; i++) - ti2[i] = short(double(tf2[i]) *scale_factor + 0.5) ; + // TODO double->short + for (int i = 1; i <= 20; i++) + ti2[i] = short(double(tf2[i]) * scale_factor + 0.5); check(ti1 == ti2); } - + tf1.fill(-3.2F); ti1.fill(-3); { // positive float -> unsigned short with a preferred scale factor float scale_factor = 1; - Array<1,short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); - + Array<1, short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); + check(scale_factor == float(1)); check(ti1 == ti2); } - + { - Array<1,unsigned short> ti3(1,20); + Array<1, unsigned short> ti3(1, 20); ti3.fill(0); - + // negative float -> unsigned short with a preferred scale factor float scale_factor = 1; - Array<1,unsigned short> ti2 = - convert_array(scale_factor, tf1, NumericInfo()); - + Array<1, unsigned short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); + check(scale_factor == float(1)); check(ti3 == ti2); } @@ -150,99 +142,85 @@ convert_array_Tests::run_tests() // 3D { - Array<3,float> tf1(IndexRange3D(1,30,1,182,-2,182)); + Array<3, float> tf1(IndexRange3D(1, 30, 1, 182, -2, 182)); tf1.fill(100.F); - - Array<3,short> ti1(tf1.get_index_range()); + + Array<3, short> ti1(tf1.get_index_range()); ti1.fill(100); - + { // float -> short with a preferred scale factor float scale_factor = float(1); - Array<3,short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); - + Array<3, short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); + check(scale_factor == float(1)); check(ti1 == ti2); } - + { // float -> short with automatic scale factor float scale_factor = 0; - Array<3,short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); -#ifndef DO_TIMING_ONLY - check(fabs(NumericInfo().max_value()/1.01 / (*ti2.begin_all()) -1) < 1E-4); - const Array<3,short>::full_iterator iter_end= ti2.end_all(); - for (Array<3,short>::full_iterator iter= ti2.begin_all(); - iter != iter_end; - ++iter) - *iter = short( double((*iter)) *scale_factor); + Array<3, short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); +#ifndef DO_TIMING_ONLY + check(fabs(NumericInfo().max_value() / 1.01 / (*ti2.begin_all()) - 1) < 1E-4); + const Array<3, short>::full_iterator iter_end = ti2.end_all(); + for (Array<3, short>::full_iterator iter = ti2.begin_all(); iter != iter_end; ++iter) + *iter = short(double((*iter)) * scale_factor); check(ti1 == ti2); #endif } - + tf1 *= 1E20F; { // float -> short with a preferred scale factor that needs to be adjusted float scale_factor = 1; - Array<3,short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); + Array<3, short> ti2 = convert_array(scale_factor, tf1, NumericInfo()); #ifndef DO_TIMING_ONLY - check(fabs(NumericInfo().max_value()/1.01 / (*ti2.begin_all()) -1) < 1E-4); - Array<3,short>::full_iterator iter_ti2= ti2.begin_all(); - const Array<3,short>::full_iterator iter_ti2_end= ti2.end_all(); - Array<3,float>::full_iterator iter_tf1= tf1.begin_all(); - for (; - iter_ti2 != iter_ti2_end; - ++iter_ti2, ++iter_tf1) - check(fabs(double(*iter_ti2) *scale_factor / *iter_tf1 - 1) < 1E-4) ; -#endif + check(fabs(NumericInfo().max_value() / 1.01 / (*ti2.begin_all()) - 1) < 1E-4); + Array<3, short>::full_iterator iter_ti2 = ti2.begin_all(); + const Array<3, short>::full_iterator iter_ti2_end = ti2.end_all(); + Array<3, float>::full_iterator iter_tf1 = tf1.begin_all(); + for (; iter_ti2 != iter_ti2_end; ++iter_ti2, ++iter_tf1) + check(fabs(double(*iter_ti2) * scale_factor / *iter_tf1 - 1) < 1E-4); +#endif } } // tests on convert_range { - std::vector vin(10,2); + std::vector vin(10, 2); std::vector vout(10); - float scale_factor=0; + float scale_factor = 0; convert_range(vout.begin(), scale_factor, vin.begin(), vin.end()); { - std::vector::const_iterator iter_out= vout.begin(); - std::vector::const_iterator iter_in= vin.begin(); - for (; - iter_out != vout.end(); - ++iter_in, ++iter_out) - check(fabs(double(*iter_out) *scale_factor / *iter_in - 1) < 1E-4, - "convert_range signed char->int") ; + std::vector::const_iterator iter_out = vout.begin(); + std::vector::const_iterator iter_in = vin.begin(); + for (; iter_out != vout.end(); ++iter_in, ++iter_out) + check(fabs(double(*iter_out) * scale_factor / *iter_in - 1) < 1E-4, "convert_range signed char->int"); } } // equal type { - std::vector vin(10,2); + std::vector vin(10, 2); std::vector vout(10); - float scale_factor=3; + float scale_factor = 3; convert_range(vout.begin(), scale_factor, vin.begin(), vin.end()); { check_if_equal(scale_factor, 1.F, "scale_factor should be 1 when using equal types"); - std::vector::const_iterator iter_out= vout.begin(); - std::vector::const_iterator iter_in= vin.begin(); - for (; - iter_out != vout.end(); - ++iter_in, ++iter_out) - check(fabs(double(*iter_out) *scale_factor / *iter_in - 1) < 1E-4, - "convert_range equal types") ; + std::vector::const_iterator iter_out = vout.begin(); + std::vector::const_iterator iter_in = vin.begin(); + for (; iter_out != vout.end(); ++iter_in, ++iter_out) + check(fabs(double(*iter_out) * scale_factor / *iter_in - 1) < 1E-4, "convert_range equal types"); } } } END_NAMESPACE_STIR - - USING_NAMESPACE_STIR - - -int main() -{ +int +main() { convert_array_Tests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_coordinates.cxx b/src/test/test_coordinates.cxx index 341279989a..672e1cf4bb 100644 --- a/src/test/test_coordinates.cxx +++ b/src/test/test_coordinates.cxx @@ -19,9 +19,9 @@ */ /*! - \file + \file \ingroup test - + \brief A simple program to test the Coordinate classes \author Kris Thielemans @@ -44,68 +44,71 @@ using std::cerr; using std::endl; #endif - START_NAMESPACE_STIR /*! \brief Class with tests for BasicCoordinate, Coordinate3D et al. \ingroup test */ -class coordinateTests : public RunTests -{ +class coordinateTests : public RunTests { public: void run_tests(); }; - void -coordinateTests::run_tests() -{ +coordinateTests::run_tests() { cerr << "Testing Coordinate classes" << endl - <<" (There should be only informative messages here starting with 'Testing')" << endl; + << " (There should be only informative messages here starting with 'Testing')" << endl; { cerr << "Testing BasicCoordinate<3,float>" << endl; BasicCoordinate<3, float> a; - a[1]=1;a[2]=2;a[3]=3; + a[1] = 1; + a[2] = 2; + a[3] = 3; BasicCoordinate<3, float> copy_of_a; - copy_of_a[1]=1;copy_of_a[2]=2;copy_of_a[3]=3; + copy_of_a[1] = 1; + copy_of_a[2] = 2; + copy_of_a[3] = 3; BasicCoordinate<3, float> b; - b[1]=-1;b[2]=-3;b[3]=5; + b[1] = -1; + b[2] = -3; + b[3] = 5; BasicCoordinate<3, float> a_plus_b; - a_plus_b[1]=0;a_plus_b[2]=-1;a_plus_b[3]=8; + a_plus_b[1] = 0; + a_plus_b[2] = -1; + a_plus_b[3] = 8; - - check(a[3]==3, "testing operator[]"); - check_if_equal(inner_product(a,b), 8.F, "testing inner_product"); + check(a[3] == 3, "testing operator[]"); + check_if_equal(inner_product(a, b), 8.F, "testing inner_product"); check_if_equal(norm(a), 3.74166, "testing norm"); a += b; - check_if_zero(a- a_plus_b, "testing operator+=(BasicCoordinate)"); + check_if_zero(a - a_plus_b, "testing operator+=(BasicCoordinate)"); a -= b; check_if_equal(a, copy_of_a, "testing operator-=(BasicCoordinate)"); { BasicCoordinate<3, float> b2(3.F); - check_if_zero(norm(b2-3.F), "testing constructor with single element, and operator-"); + check_if_zero(norm(b2 - 3.F), "testing constructor with single element, and operator-"); b2.fill(4.F); - check_if_zero(norm(b2-4.F), "testing fill, and operator-"); - } + check_if_zero(norm(b2 - 4.F), "testing fill, and operator-"); + } { BasicCoordinate<3, float> b1 = b; - check_if_zero(norm(b1-b), "testing copy constructor, and operator-"); - + check_if_zero(norm(b1 - b), "testing copy constructor, and operator-"); + b1 = a; - check_if_zero(norm(a-b1), "testing assignment"); + check_if_zero(norm(a - b1), "testing assignment"); } a *= 4; - check(a[1] == copy_of_a[1]*4, "testing operator*=(float)"); - check_if_equal(norm(a), norm(copy_of_a)*4, "testing operator*=(float)"); + check(a[1] == copy_of_a[1] * 4, "testing operator*=(float)"); + check_if_equal(norm(a), norm(copy_of_a) * 4, "testing operator*=(float)"); a /= 4; - check_if_zero(norm(a-copy_of_a), "testing operator/=(float)"); + check_if_zero(norm(a - copy_of_a), "testing operator/=(float)"); { BasicCoordinate<3, float> a1; @@ -119,54 +122,60 @@ coordinateTests::run_tests() a1 *= 3; a1 += a; a1 -= 4; - BasicCoordinate<3, float> a2 = (b*3+a)-4; - check_if_zero(norm(a1-a2), "testing various numerical operators"); + BasicCoordinate<3, float> a2 = (b * 3 + a) - 4; + check_if_zero(norm(a1 - a2), "testing various numerical operators"); } // basic iterator tests - { + { #ifndef STIR_NO_NAMESPACES - float *p=std::find(b.begin(), b.end(), -3); + float* p = std::find(b.begin(), b.end(), -3); #else - float *p=find(b.begin(), b.end(), -3); + float* p = find(b.begin(), b.end(), -3); #endif check_if_zero(p - b.begin() - 1, "iterator test"); BasicCoordinate<3, float> b_sorted; - b_sorted[1]=-3;b_sorted[2]=-1;b_sorted[3]=5; + b_sorted[1] = -3; + b_sorted[2] = -1; + b_sorted[3] = 5; #ifndef STIR_NO_NAMESPACES - std::sort(b.begin(), b.end()); + std::sort(b.begin(), b.end()); #else - sort(b.begin(), b.end()); + sort(b.begin(), b.end()); #endif - check_if_zero(norm(b-b_sorted), "testing iterators via STL sort"); + check_if_zero(norm(b - b_sorted), "testing iterators via STL sort"); } } { cerr << "Testing join/cut_first_dimension/comparisons on BasicCoordinate" << endl; - + // join { BasicCoordinate<3, int> a; - a[1]=1;a[2]=2;a[3]=3; + a[1] = 1; + a[2] = 2; + a[3] = 3; { - BasicCoordinate<4, int> a4 = join(0, a); - check_if_equal(a4[1], 0, "testing join of float with BasicCoordinate"); - check_if_equal(a4[2], 1, "testing join of float with BasicCoordinate"); - check_if_equal(a4[3], 2, "testing join of float with BasicCoordinate"); - check_if_equal(a4[4], 3, "testing join of float with BasicCoordinate"); + BasicCoordinate<4, int> a4 = join(0, a); + check_if_equal(a4[1], 0, "testing join of float with BasicCoordinate"); + check_if_equal(a4[2], 1, "testing join of float with BasicCoordinate"); + check_if_equal(a4[3], 2, "testing join of float with BasicCoordinate"); + check_if_equal(a4[4], 3, "testing join of float with BasicCoordinate"); } { - BasicCoordinate<4, int> a4 = join(a, 0); - check_if_equal(a4[1], 1, "testing join of BasicCoordinate with float"); - check_if_equal(a4[2], 2, "testing join of BasicCoordinate with float"); - check_if_equal(a4[3], 3, "testing join of BasicCoordinate with float"); - check_if_equal(a4[4], 0, "testing join of BasicCoordinate with float"); + BasicCoordinate<4, int> a4 = join(a, 0); + check_if_equal(a4[1], 1, "testing join of BasicCoordinate with float"); + check_if_equal(a4[2], 2, "testing join of BasicCoordinate with float"); + check_if_equal(a4[3], 3, "testing join of BasicCoordinate with float"); + check_if_equal(a4[4], 0, "testing join of BasicCoordinate with float"); } } // cut*dimension { BasicCoordinate<3, int> a; - a[1]=1;a[2]=2;a[3]=3; + a[1] = 1; + a[2] = 2; + a[3] = 3; const BasicCoordinate<2, int> start = cut_last_dimension(a); check_if_equal(start[1], 1, "testing cut_last_dimension"); check_if_equal(start[2], 2, "testing cut_last_dimension"); @@ -177,47 +186,59 @@ coordinateTests::run_tests() // comparison 2D { BasicCoordinate<2, int> a; - a[1]=1;a[2]=2; + a[1] = 1; + a[2] = 2; BasicCoordinate<2, int> b; - b[1]=1;b[2]=1; - check(a==a, "2D operator=="); - check(a<=a, "2D operator<= (when equal)"); - check(a>=a, "2D operator>= (when equal)"); - check(a>b, "2D operator>"); - check(b=b, "2D operator>= (when not equal)"); - check(b<=a, "2D operator<= (when not equal)"); - check(a!=b, "2D operator!="); + b[1] = 1; + b[2] = 1; + check(a == a, "2D operator=="); + check(a <= a, "2D operator<= (when equal)"); + check(a >= a, "2D operator>= (when equal)"); + check(a > b, "2D operator>"); + check(b < a, "2D operator<"); + check(a >= b, "2D operator>= (when not equal)"); + check(b <= a, "2D operator<= (when not equal)"); + check(a != b, "2D operator!="); } // comparison 3D { BasicCoordinate<3, int> a; - a[1]=1;a[2]=2;a[3]=3; + a[1] = 1; + a[2] = 2; + a[3] = 3; BasicCoordinate<3, int> b; - b[1]=1;b[2]=1;b[3]=3; - check(a==a, "3D operator=="); - check(a<=a, "3D operator<= (when equal)"); - check(a>=a, "3D operator>= (when equal)"); - check(a>b, "3D operator>"); - check(b=b, "3D operator>= (when not equal)"); - check(b<=a, "3D operator<= (when not equal)"); - check(a!=b, "3D operator!="); + b[1] = 1; + b[2] = 1; + b[3] = 3; + check(a == a, "3D operator=="); + check(a <= a, "3D operator<= (when equal)"); + check(a >= a, "3D operator>= (when equal)"); + check(a > b, "3D operator>"); + check(b < a, "3D operator<"); + check(a >= b, "3D operator>= (when not equal)"); + check(b <= a, "3D operator<= (when not equal)"); + check(a != b, "3D operator!="); } // comparison 4D { BasicCoordinate<4, int> a; - a[1]=1;a[2]=2;a[3]=3; a[4]=1; + a[1] = 1; + a[2] = 2; + a[3] = 3; + a[4] = 1; BasicCoordinate<4, int> b; - b[1]=1;b[2]=1;b[3]=3; b[4]=2; - check(a==a, "4D operator=="); - check(a<=a, "4D operator<= (when equal)"); - check(a>=a, "4D operator>= (when equal)"); - check(a>b, "4D operator>"); - check(b=b, "4D operator>= (when not equal)"); - check(b<=a, "4D operator<= (when not equal)"); - check(a!=b, "4D operator!="); + b[1] = 1; + b[2] = 1; + b[3] = 3; + b[4] = 2; + check(a == a, "4D operator=="); + check(a <= a, "4D operator<= (when equal)"); + check(a >= a, "4D operator>= (when equal)"); + check(a > b, "4D operator>"); + check(b < a, "4D operator<"); + check(a >= b, "4D operator>= (when not equal)"); + check(b <= a, "4D operator<= (when not equal)"); + check(a != b, "4D operator!="); } } @@ -227,36 +248,42 @@ coordinateTests::run_tests() cerr << "Testing Coordinate3D" << endl; Coordinate3D a; - a[1]=1;a[2]=2;a[3]=3; + a[1] = 1; + a[2] = 2; + a[3] = 3; // use new constructor - Coordinate3D copy_of_a(1,2,3); + Coordinate3D copy_of_a(1, 2, 3); Coordinate3D b; - b[1]=-1;b[2]=-3;b[3]=5; + b[1] = -1; + b[2] = -3; + b[3] = 5; Coordinate3D a_plus_b; - a_plus_b[1]=0;a_plus_b[2]=-1;a_plus_b[3]=8; - - check(a[3]==3, "testing operator[]"); - check_if_equal(inner_product(a,b), 8.F, "testing inner_product"); + a_plus_b[1] = 0; + a_plus_b[2] = -1; + a_plus_b[3] = 8; + + check(a[3] == 3, "testing operator[]"); + check_if_equal(inner_product(a, b), 8.F, "testing inner_product"); check_if_equal(norm(a), 3.74166, "testing norm"); a += b; check_if_zero(norm(a - a_plus_b), "testing operator+=(BasicCoordinate)"); a -= b; check_if_zero(norm(a - copy_of_a), "testing operator-=(BasicCoordinate)"); - + { Coordinate3D b1 = b; - check_if_zero(norm(b1-b), "testing copy constructor, and operator-"); - + check_if_zero(norm(b1 - b), "testing copy constructor, and operator-"); + b1 = a; - check_if_zero(norm(a-b1), "testing assignment"); + check_if_zero(norm(a - b1), "testing assignment"); } a *= 4; - check_if_zero(norm(a)- norm(copy_of_a)*4, "testing operator*=(float)"); - check_if_zero(a[1]- copy_of_a[1]*4, "testing operator*=(float)"); + check_if_zero(norm(a) - norm(copy_of_a) * 4, "testing operator*=(float)"); + check_if_zero(a[1] - copy_of_a[1] * 4, "testing operator*=(float)"); a /= 4; - check_if_zero(norm(a-copy_of_a), "testing operator/=(float)"); + check_if_zero(norm(a - copy_of_a), "testing operator/=(float)"); { Coordinate3D a1; @@ -264,17 +291,16 @@ coordinateTests::run_tests() a1 *= 3; a1 += a; a1 -= 4; - Coordinate3D a2 = (b*3+a)-4; - check_if_zero(norm(a1-a2), "testing various numerical operators"); + Coordinate3D a2 = (b * 3 + a) - 4; + check_if_zero(norm(a1 - a2), "testing various numerical operators"); } { - BasicCoordinate<3,float> gen_a(a); + BasicCoordinate<3, float> gen_a(a); a = gen_a; - check_if_zero(norm(a-copy_of_a), "testing conversions"); - check_if_zero(norm(gen_a-copy_of_a), "testing conversions"); + check_if_zero(norm(a - copy_of_a), "testing conversions"); + check_if_zero(norm(gen_a - copy_of_a), "testing conversions"); } - } // essentially the same as above, but now with CartesianCoordinate3D @@ -282,36 +308,42 @@ coordinateTests::run_tests() cerr << "Testing CartesianCoordinate3D" << endl; CartesianCoordinate3D a; - a[1]=1;a[2]=2;a[3]=3; + a[1] = 1; + a[2] = 2; + a[3] = 3; // use new constructor - CartesianCoordinate3D copy_of_a(1,2,3); + CartesianCoordinate3D copy_of_a(1, 2, 3); CartesianCoordinate3D b; - b[1]=-1;b[2]=-3;b[3]=5; + b[1] = -1; + b[2] = -3; + b[3] = 5; CartesianCoordinate3D a_plus_b; - a_plus_b[1]=0;a_plus_b[2]=-1;a_plus_b[3]=8; - - check(a[3]==3, "testing operator[]"); - check_if_equal(inner_product(a,b), 8.F, "testing inner_product"); + a_plus_b[1] = 0; + a_plus_b[2] = -1; + a_plus_b[3] = 8; + + check(a[3] == 3, "testing operator[]"); + check_if_equal(inner_product(a, b), 8.F, "testing inner_product"); check_if_equal(norm(a), 3.74166, "testing norm"); a += b; check_if_zero(norm(a - a_plus_b), "testing operator+=(BasicCoordinate)"); a -= b; check_if_zero(norm(a - copy_of_a), "testing operator-=(BasicCoordinate)"); - + { CartesianCoordinate3D b1 = b; - check_if_zero(norm(b1-b), "testing copy constructor, and operator-"); - + check_if_zero(norm(b1 - b), "testing copy constructor, and operator-"); + b1 = a; - check_if_zero(norm(a-b1), "testing assignment"); + check_if_zero(norm(a - b1), "testing assignment"); } a *= 4; - check_if_zero(norm(a)- norm(copy_of_a)*4, "testing operator*=(float)"); - check_if_zero(a[1]- copy_of_a[1]*4, "testing operator*=(float)"); + check_if_zero(norm(a) - norm(copy_of_a) * 4, "testing operator*=(float)"); + check_if_zero(a[1] - copy_of_a[1] * 4, "testing operator*=(float)"); a /= 4; - check_if_zero(norm(a-copy_of_a), "testing operator/=(float)"); + check_if_zero(norm(a - copy_of_a), "testing operator/=(float)"); { CartesianCoordinate3D a1; @@ -319,24 +351,23 @@ coordinateTests::run_tests() a1 *= 3; a1 += a; a1 -= 4; - CartesianCoordinate3D a2 = (b*3+a)-4; - check_if_zero(norm(a1-a2), "testing various numerical operators"); + CartesianCoordinate3D a2 = (b * 3 + a) - 4; + check_if_zero(norm(a1 - a2), "testing various numerical operators"); } { - BasicCoordinate<3,float> gen_a(a); + BasicCoordinate<3, float> gen_a(a); a = gen_a; - check_if_zero(norm(a-copy_of_a), "testing conversions"); - check_if_zero(norm(gen_a-copy_of_a), "testing conversions"); + check_if_zero(norm(a - copy_of_a), "testing conversions"); + check_if_zero(norm(gen_a - copy_of_a), "testing conversions"); } - } { cerr << "Testing round with coordinates" << endl; - const Coordinate3D af(1.1F,-1.1F,3.6F); + const Coordinate3D af(1.1F, -1.1F, 3.6F); const Coordinate3D aint = round(af); - check_if_equal(aint, Coordinate3D (1,-1,4)); + check_if_equal(aint, Coordinate3D(1, -1, 4)); } { cerr << "Testing constructor with different types of coordinates" << endl; @@ -344,40 +375,31 @@ coordinateTests::run_tests() would not work if 'af' is defined as const Coordinate3D af(1.1F,-1.1F,3.6F); */ - const BasicCoordinate<3,float> af = Coordinate3D (1.1F,-1.1F,3.6F); - const BasicCoordinate<3,int> aint(af); - check_if_equal(aint, Coordinate3D (1,-1,3)); - const BasicCoordinate<3,float> af2(aint); - check_if_equal(af2, Coordinate3D (1.F,-1.F,3.F)); + const BasicCoordinate<3, float> af = Coordinate3D(1.1F, -1.1F, 3.6F); + const BasicCoordinate<3, int> aint(af); + check_if_equal(aint, Coordinate3D(1, -1, 3)); + const BasicCoordinate<3, float> af2(aint); + check_if_equal(af2, Coordinate3D(1.F, -1.F, 3.F)); } { cerr << "Testing make_coordinate" << endl; - check_if_equal(make_coordinate(1.F)[1],1.F, "test make_coordinate with 1 arg"); - check_if_equal(make_coordinate(1.F,3.4F),Coordinate2D(1.F,3.4F), - "test make_coordinate with 2 args"); - check_if_equal(make_coordinate(1.,3.4,-4.8),Coordinate3D(1.,3.4,-4.8), - "test make_coordinate with 3 args"); - check_if_equal(make_coordinate(1,2,3,4),Coordinate4D(1,2,3,4), - "test make_coordinate with 4 args"); - check_if_equal(make_coordinate(1,2,3,4,5),join(Coordinate4D(1,2,3,4),5), - "test make_coordinate with 5 args"); - check_if_equal(make_coordinate(1,2,3,4,5,6),join(join(Coordinate4D(1,2,3,4),5),6), - "test make_coordinate with 6 args"); + check_if_equal(make_coordinate(1.F)[1], 1.F, "test make_coordinate with 1 arg"); + check_if_equal(make_coordinate(1.F, 3.4F), Coordinate2D(1.F, 3.4F), "test make_coordinate with 2 args"); + check_if_equal(make_coordinate(1., 3.4, -4.8), Coordinate3D(1., 3.4, -4.8), "test make_coordinate with 3 args"); + check_if_equal(make_coordinate(1, 2, 3, 4), Coordinate4D(1, 2, 3, 4), "test make_coordinate with 4 args"); + check_if_equal(make_coordinate(1, 2, 3, 4, 5), join(Coordinate4D(1, 2, 3, 4), 5), "test make_coordinate with 5 args"); + check_if_equal(make_coordinate(1, 2, 3, 4, 5, 6), join(join(Coordinate4D(1, 2, 3, 4), 5), 6), + "test make_coordinate with 6 args"); } } - END_NAMESPACE_STIR - - USING_NAMESPACE_STIR - - -int main() -{ +int +main() { coordinateTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_display.cxx b/src/test/test_display.cxx index 9de7a3968c..71887a85a6 100644 --- a/src/test/test_display.cxx +++ b/src/test/test_display.cxx @@ -35,75 +35,68 @@ USING_NAMESPACE_STIR int -main() -{ +main() { std::cerr << "Tests display with a few very simple bitmaps.\n" - << "You should see 10 bitmaps (4th and 5th brighter) twice, and then a single bitmap\n"; + << "You should see 10 bitmaps (4th and 5th brighter) twice, and then a single bitmap\n"; typedef float test_type; - // provide a test example. This could easily be changed in reading + // provide a test example. This could easily be changed in reading // something from file - // note: sizes are prime numbers to avoid having accidental matches - // with 'word-boundaries' etc. This is especailly an issue + // note: sizes are prime numbers to avoid having accidental matches + // with 'word-boundaries' etc. This is especailly an issue // when using X windows. - Array<3,test_type> t(IndexRange3D(10,87,123)); + Array<3, test_type> t(IndexRange3D(10, 87, 123)); VectorWithOffset scale_factors(10); scale_factors.fill(1.F); // make images 3 and 4 stand out scale_factors[3] = 1.3F; scale_factors[4] = 1.5F; - for (int i=0; i text(t.get_min_index(), t.get_max_index()); - for (int i=t.get_min_index(); i<= t.get_max_index(); i++) - { - text[i] = new char [15]; - sprintf(text[i], "image %d", i); - } + VectorWithOffset text(t.get_min_index(), t.get_max_index()); + for (int i = t.get_min_index(); i <= t.get_max_index(); i++) { + text[i] = new char[15]; + sprintf(text[i], "image %d", i); + } display(t, scale_factors, text, maxi, "Test display 3D all args", scale); - display(t,t.find_max()/2,"Test display 3D 3 args, half the colour scale" ); + display(t, t.find_max() / 2, "Test display 3D 3 args, half the colour scale"); - for (int i=t.get_min_index(); i<= t.get_max_index(); i++) + for (int i = t.get_min_index(); i <= t.get_max_index(); i++) delete[] text[i]; - display(*t.begin(), "Test display 2D, 2 args"); return EXIT_SUCCESS; diff --git a/src/test/test_export_array.cxx b/src/test/test_export_array.cxx index 6732a8fa3e..dd74d6be94 100644 --- a/src/test/test_export_array.cxx +++ b/src/test/test_export_array.cxx @@ -45,63 +45,45 @@ START_NAMESPACE_STIR -class ExportArrayTests : public RunTests -{ +class ExportArrayTests : public RunTests { public: - void run_tests(); + void run_tests(); protected: - void test_static_data(); - void test_dynamic_data(); - void run_static_test(ProjData& test_proj_data, - ProjData& check_proj_data, - const std::string& test_name); - void check_if_equal_projdata(const ProjData& test_proj_data, - const ProjData& check_proj_data, - const std::string& test_name); + void test_static_data(); + void test_dynamic_data(); + void run_static_test(ProjData& test_proj_data, ProjData& check_proj_data, const std::string& test_name); + void check_if_equal_projdata(const ProjData& test_proj_data, const ProjData& check_proj_data, const std::string& test_name); }; -void ExportArrayTests :: run_tests() -{ - test_static_data(); - test_dynamic_data(); +void +ExportArrayTests ::run_tests() { + test_static_data(); + test_dynamic_data(); } -void ExportArrayTests :: check_if_equal_projdata(const ProjData& test_proj_data, - const ProjData& check_proj_data, - const std::string& test_name) -{ - for (int segment_num = test_proj_data.get_min_segment_num(); - segment_num <= test_proj_data.get_max_segment_num(); - ++segment_num) - { - const SegmentByView test_segment_by_view_data = - test_proj_data.get_segment_by_view(segment_num); - - const SegmentByView check_segment_by_view_data = - check_proj_data.get_segment_by_view(segment_num); - - for (int view_num = test_segment_by_view_data.get_min_view_num(); - view_num<=test_segment_by_view_data.get_max_view_num(); - ++view_num) - { - Viewgram test_view = test_segment_by_view_data.get_viewgram(view_num); - Viewgram check_view = check_segment_by_view_data.get_viewgram(view_num); - - for (int axial = test_view.get_min_axial_pos_num(); - axial <= test_view.get_max_axial_pos_num(); - ++axial) - { - for (int s = test_view.get_min_tangential_pos_num(); - s <= test_view.get_max_tangential_pos_num(); - ++s) - { - check_if_equal(test_view[axial][s], check_view[axial][s], test_name + ": test ProjData different from check ProjData."); - check_if_equal(check_view[axial][s], (float)segment_num, test_name + ": check ProjData different from segment number."); - } - } +void +ExportArrayTests ::check_if_equal_projdata(const ProjData& test_proj_data, const ProjData& check_proj_data, + const std::string& test_name) { + for (int segment_num = test_proj_data.get_min_segment_num(); segment_num <= test_proj_data.get_max_segment_num(); + ++segment_num) { + const SegmentByView test_segment_by_view_data = test_proj_data.get_segment_by_view(segment_num); + + const SegmentByView check_segment_by_view_data = check_proj_data.get_segment_by_view(segment_num); + + for (int view_num = test_segment_by_view_data.get_min_view_num(); view_num <= test_segment_by_view_data.get_max_view_num(); + ++view_num) { + Viewgram test_view = test_segment_by_view_data.get_viewgram(view_num); + Viewgram check_view = check_segment_by_view_data.get_viewgram(view_num); + + for (int axial = test_view.get_min_axial_pos_num(); axial <= test_view.get_max_axial_pos_num(); ++axial) { + for (int s = test_view.get_min_tangential_pos_num(); s <= test_view.get_max_tangential_pos_num(); ++s) { + check_if_equal(test_view[axial][s], check_view[axial][s], test_name + ": test ProjData different from check ProjData."); + check_if_equal(check_view[axial][s], (float)segment_num, test_name + ": check ProjData different from segment number."); } + } } + } } //! @@ -111,201 +93,167 @@ void ExportArrayTests :: check_if_equal_projdata(const ProjData& test_proj_data, //! written and retrieved from the disk, resorted in DynamicProjData and //! compared with the original. The test will fails if the array retrieved //! from the disk is of different size from the original. -void ExportArrayTests::test_dynamic_data() -{ - info("Initialising..."); - //. Create ProjData - - //- ProjDataInfo - //-- Scanner - shared_ptr test_scanner_sptr( new Scanner(Scanner::Siemens_mMR)); - - //-- ExamInfo - shared_ptr test_exam_info_sptr(new ExamInfo()); - // TODO, Currently all stir::Scanner types are PET. - test_exam_info_sptr->imaging_modality = ImagingModality::PT; - - info("Creating test DynamicProjData..."); - shared_ptr test_dynamic_projData_sptr (new DynamicProjData(test_exam_info_sptr)); - - shared_ptr tmp_proj_data_info_sptr( - ProjDataInfo::ProjDataInfoCTI(test_scanner_sptr, - 1, - 1, /* Reduce the number of segments */ - test_scanner_sptr->get_max_num_views(), - test_scanner_sptr->get_max_num_non_arccorrected_bins(), - false)); - - const int num_of_gates = 3; - info(boost::format("Resizing the DynamicProjData for %1% gates... ") % num_of_gates); - test_dynamic_projData_sptr->resize( num_of_gates); - - for (int i_gate = 1; i_gate <= num_of_gates; i_gate++) - { - info(boost::format("Allocating and filling the %1% gate... ") % i_gate); +void +ExportArrayTests::test_dynamic_data() { + info("Initialising..."); + //. Create ProjData - shared_ptr test_proj_data_gate_ptr( - new ProjDataInMemory(test_exam_info_sptr, - tmp_proj_data_info_sptr)); + //- ProjDataInfo + //-- Scanner + shared_ptr test_scanner_sptr(new Scanner(Scanner::Siemens_mMR)); - for (int segment_num = test_proj_data_gate_ptr->get_min_segment_num(); - segment_num <= test_proj_data_gate_ptr->get_max_segment_num(); - ++segment_num) - { - SegmentByView segment_by_view_data = - test_proj_data_gate_ptr->get_segment_by_view(segment_num); + //-- ExamInfo + shared_ptr test_exam_info_sptr(new ExamInfo()); + // TODO, Currently all stir::Scanner types are PET. + test_exam_info_sptr->imaging_modality = ImagingModality::PT; - // 1000 is an arbitary number to distiguish data in different gates. - segment_by_view_data.fill(static_cast(segment_num + (i_gate * 1000))); + info("Creating test DynamicProjData..."); + shared_ptr test_dynamic_projData_sptr(new DynamicProjData(test_exam_info_sptr)); - if (!(test_proj_data_gate_ptr->set_segment(segment_by_view_data) == Succeeded::yes)) - warning("Error set_segment %d\n", segment_num); - } + shared_ptr tmp_proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI( + test_scanner_sptr, 1, 1, /* Reduce the number of segments */ + test_scanner_sptr->get_max_num_views(), test_scanner_sptr->get_max_num_non_arccorrected_bins(), false)); - info("Populating the Dynamic ProjData... "); - test_dynamic_projData_sptr->set_proj_data_sptr(test_proj_data_gate_ptr, i_gate); - } + const int num_of_gates = 3; + info(boost::format("Resizing the DynamicProjData for %1% gates... ") % num_of_gates); + test_dynamic_projData_sptr->resize(num_of_gates); - const std::size_t total_size = test_dynamic_projData_sptr->size_all(); - const int total_gates = static_cast(test_dynamic_projData_sptr->get_num_proj_data()); - const int projdata_size = static_cast(test_dynamic_projData_sptr->get_proj_data_size()); + for (int i_gate = 1; i_gate <= num_of_gates; i_gate++) { + info(boost::format("Allocating and filling the %1% gate... ") % i_gate); - info(boost::format("Total size: %1%, number of gates: %2%, size of projdata %3%") % total_size % total_gates % - projdata_size); - // Allocate 2D array to store the data. - info("Allocating test array..."); - Array<2, float> test_array (IndexRange2D(0, total_gates, 0, projdata_size)); - test_array.fill(-1); - Array<2, float>::full_iterator test_array_iter = test_array.begin_all(); + shared_ptr test_proj_data_gate_ptr(new ProjDataInMemory(test_exam_info_sptr, tmp_proj_data_info_sptr)); - // Copy data to array. - info("Copying test dynamic projdata to array ..."); - copy_to(*test_dynamic_projData_sptr, test_array_iter); + for (int segment_num = test_proj_data_gate_ptr->get_min_segment_num(); + segment_num <= test_proj_data_gate_ptr->get_max_segment_num(); ++segment_num) { + SegmentByView segment_by_view_data = test_proj_data_gate_ptr->get_segment_by_view(segment_num); - // Convert it to ProjData - info("Copying data from array to check dynamic projdata ..."); + // 1000 is an arbitary number to distiguish data in different gates. + segment_by_view_data.fill(static_cast(segment_num + (i_gate * 1000))); - shared_ptr check_dynamic_projData_sptr (new DynamicProjData(test_exam_info_sptr, - num_of_gates)); + if (!(test_proj_data_gate_ptr->set_segment(segment_by_view_data) == Succeeded::yes)) + warning("Error set_segment %d\n", segment_num); + } - for (int i_gate = 0; i_gate < num_of_gates; i_gate++) - { - info(boost::format("Allocating and filling the %1% gate... ") % (i_gate+1)); + info("Populating the Dynamic ProjData... "); + test_dynamic_projData_sptr->set_proj_data_sptr(test_proj_data_gate_ptr, i_gate); + } - shared_ptr test_proj_data_gate_ptr( - new ProjDataInMemory(test_exam_info_sptr, - tmp_proj_data_info_sptr)); + const std::size_t total_size = test_dynamic_projData_sptr->size_all(); + const int total_gates = static_cast(test_dynamic_projData_sptr->get_num_proj_data()); + const int projdata_size = static_cast(test_dynamic_projData_sptr->get_proj_data_size()); - info("Populating the Dynamic ProjData... "); - check_dynamic_projData_sptr->set_proj_data_sptr(test_proj_data_gate_ptr, (i_gate+1)); - } + info(boost::format("Total size: %1%, number of gates: %2%, size of projdata %3%") % total_size % total_gates % projdata_size); + // Allocate 2D array to store the data. + info("Allocating test array..."); + Array<2, float> test_array(IndexRange2D(0, total_gates, 0, projdata_size)); + test_array.fill(-1); + Array<2, float>::full_iterator test_array_iter = test_array.begin_all(); - fill_from(*check_dynamic_projData_sptr, test_array.begin_all_const(), test_array.end_all_const()); + // Copy data to array. + info("Copying test dynamic projdata to array ..."); + copy_to(*test_dynamic_projData_sptr, test_array_iter); - info ("Checking if data are the same..."); - for(int i_gate = 1; i_gate <= num_of_gates; i_gate++) - { - shared_ptr _test_projdata_sptr (test_dynamic_projData_sptr->get_proj_data_sptr(i_gate)); - shared_ptr _check_projdata_sptr(check_dynamic_projData_sptr->get_proj_data_sptr(i_gate)); - - for (int segment_num = _test_projdata_sptr->get_min_segment_num(); - segment_num <= _test_projdata_sptr->get_max_segment_num(); - ++segment_num) - { - SegmentByView _test_segment_by_view_data = - _test_projdata_sptr->get_segment_by_view(segment_num); - - SegmentByView _check_segment_by_view_data = - _check_projdata_sptr->get_segment_by_view(segment_num); - - for (int view_num = _test_segment_by_view_data.get_min_view_num(); - view_num <= _test_segment_by_view_data.get_max_view_num(); - ++view_num) - { - Viewgram _test_view = _test_segment_by_view_data.get_viewgram(view_num); - Viewgram _check_view = _check_segment_by_view_data.get_viewgram(view_num); - - for (int axial = _test_view.get_min_axial_pos_num(); - axial <= _test_view.get_max_axial_pos_num(); - ++axial) - { - for (int s = _test_view.get_min_tangential_pos_num(); - s <= _test_view.get_max_tangential_pos_num(); - ++s) - { - check_if_equal(_test_view[axial][s], _check_view[axial][s], "Test ProjData different from check ProjData."); - check_if_equal(_check_view[axial][s], (float) (segment_num + (i_gate * 1000)), "Check ProjData different from segment number."); - } - } - } - } - } + // Convert it to ProjData + info("Copying data from array to check dynamic projdata ..."); -} + shared_ptr check_dynamic_projData_sptr(new DynamicProjData(test_exam_info_sptr, num_of_gates)); -void ExportArrayTests :: run_static_test(ProjData& test_proj_data, - ProjData& check_proj_data, - const std::string& test_name) -{ - std::cerr << "Running " << test_name << '\n'; + for (int i_gate = 0; i_gate < num_of_gates; i_gate++) { + info(boost::format("Allocating and filling the %1% gate... ") % (i_gate + 1)); - //. Fill ProjData with the number of the segment - info("Filling test ProjData with the segment number ... "); + shared_ptr test_proj_data_gate_ptr(new ProjDataInMemory(test_exam_info_sptr, tmp_proj_data_info_sptr)); - for (int segment_num = test_proj_data.get_min_segment_num(); - segment_num <= test_proj_data.get_max_segment_num(); - ++segment_num) - { - info(boost::format("Segment: %1% ") % segment_num); - SegmentByView segment_by_view_data = - test_proj_data.get_empty_segment_by_view(segment_num); + info("Populating the Dynamic ProjData... "); + check_dynamic_projData_sptr->set_proj_data_sptr(test_proj_data_gate_ptr, (i_gate + 1)); + } - segment_by_view_data.fill(static_cast(segment_num)); + fill_from(*check_dynamic_projData_sptr, test_array.begin_all_const(), test_array.end_all_const()); - if (!(test_proj_data.set_segment(segment_by_view_data) == Succeeded::yes)) - error("Error set_segment %d\n", segment_num); - } + info("Checking if data are the same..."); + for (int i_gate = 1; i_gate <= num_of_gates; i_gate++) { + shared_ptr _test_projdata_sptr(test_dynamic_projData_sptr->get_proj_data_sptr(i_gate)); + shared_ptr _check_projdata_sptr(check_dynamic_projData_sptr->get_proj_data_sptr(i_gate)); - //- Get the total size of the ProjData + for (int segment_num = _test_projdata_sptr->get_min_segment_num(); segment_num <= _test_projdata_sptr->get_max_segment_num(); + ++segment_num) { + SegmentByView _test_segment_by_view_data = _test_projdata_sptr->get_segment_by_view(segment_num); - const unsigned int total_size = test_proj_data.size_all(); + SegmentByView _check_segment_by_view_data = _check_projdata_sptr->get_segment_by_view(segment_num); - //- Allocate 1D array and get iterator + for (int view_num = _test_segment_by_view_data.get_min_view_num(); + view_num <= _test_segment_by_view_data.get_max_view_num(); ++view_num) { + Viewgram _test_view = _test_segment_by_view_data.get_viewgram(view_num); + Viewgram _check_view = _check_segment_by_view_data.get_viewgram(view_num); - info("Allocating array ..."); - Array<3,float> test_array(IndexRange3D(test_proj_data.get_num_sinograms(), test_proj_data.get_num_views(), test_proj_data.get_num_tangential_poss())); - check (test_array.size_all() == total_size, "check on size of array"); - Array<3,float>::full_iterator test_array_iter = test_array.begin_all(); - - //- - info("Copying from ProjData to array ..."); - copy_to(test_proj_data, test_array_iter); + for (int axial = _test_view.get_min_axial_pos_num(); axial <= _test_view.get_max_axial_pos_num(); ++axial) { + for (int s = _test_view.get_min_tangential_pos_num(); s <= _test_view.get_max_tangential_pos_num(); ++s) { + check_if_equal(_test_view[axial][s], _check_view[axial][s], "Test ProjData different from check ProjData."); + check_if_equal(_check_view[axial][s], (float)(segment_num + (i_gate * 1000)), + "Check ProjData different from segment number."); + } + } + } + } + } +} - //- Check if segment order is as expected - { - const std::vector segment_sequence = ProjData::standard_segment_sequence(*test_proj_data.get_proj_data_info_sptr()); - test_array_iter = test_array.begin_all(); - for (std::vector::const_iterator iter = segment_sequence.begin(); iter != segment_sequence.end(); ++iter) - { - const int seg = *iter; - const SegmentBySinogram segment = test_proj_data.get_segment_by_sinogram(seg); - for (SegmentBySinogram::const_full_iterator seg_iter = segment.begin_all(); seg_iter != segment.end_all(); ++seg_iter, ++test_array_iter) - { - if (!check_if_equal(*seg_iter, *test_array_iter, "check if array in correct order")) - { - // one failed, so many others will as well. we just stop checking. - // make sure we get out of the outer loop as well - iter = segment_sequence.end() - 1; - break; - } - } +void +ExportArrayTests ::run_static_test(ProjData& test_proj_data, ProjData& check_proj_data, const std::string& test_name) { + std::cerr << "Running " << test_name << '\n'; + + //. Fill ProjData with the number of the segment + info("Filling test ProjData with the segment number ... "); + + for (int segment_num = test_proj_data.get_min_segment_num(); segment_num <= test_proj_data.get_max_segment_num(); + ++segment_num) { + info(boost::format("Segment: %1% ") % segment_num); + SegmentByView segment_by_view_data = test_proj_data.get_empty_segment_by_view(segment_num); + + segment_by_view_data.fill(static_cast(segment_num)); + + if (!(test_proj_data.set_segment(segment_by_view_data) == Succeeded::yes)) + error("Error set_segment %d\n", segment_num); + } + + //- Get the total size of the ProjData + + const unsigned int total_size = test_proj_data.size_all(); + + //- Allocate 1D array and get iterator + + info("Allocating array ..."); + Array<3, float> test_array( + IndexRange3D(test_proj_data.get_num_sinograms(), test_proj_data.get_num_views(), test_proj_data.get_num_tangential_poss())); + check(test_array.size_all() == total_size, "check on size of array"); + Array<3, float>::full_iterator test_array_iter = test_array.begin_all(); + + //- + info("Copying from ProjData to array ..."); + copy_to(test_proj_data, test_array_iter); + + //- Check if segment order is as expected + { + const std::vector segment_sequence = ProjData::standard_segment_sequence(*test_proj_data.get_proj_data_info_sptr()); + test_array_iter = test_array.begin_all(); + for (std::vector::const_iterator iter = segment_sequence.begin(); iter != segment_sequence.end(); ++iter) { + const int seg = *iter; + const SegmentBySinogram segment = test_proj_data.get_segment_by_sinogram(seg); + for (SegmentBySinogram::const_full_iterator seg_iter = segment.begin_all(); seg_iter != segment.end_all(); + ++seg_iter, ++test_array_iter) { + if (!check_if_equal(*seg_iter, *test_array_iter, "check if array in correct order")) { + // one failed, so many others will as well. we just stop checking. + // make sure we get out of the outer loop as well + iter = segment_sequence.end() - 1; + break; } + } } + } - // Convert it back to ProjData - info("Copying from array to a new ProjData ..."); - fill_from(check_proj_data, test_array.begin_all_const(), test_array.end_all_const()); - this->check_if_equal_projdata(test_proj_data, check_proj_data, test_name); + // Convert it back to ProjData + info("Copying from array to a new ProjData ..."); + fill_from(check_proj_data, test_array.begin_all_const(), test_array.end_all_const()); + this->check_if_equal_projdata(test_proj_data, check_proj_data, test_name); } //! @@ -313,64 +261,58 @@ void ExportArrayTests :: run_static_test(ProjData& test_proj_data, //! \details This test will chech if projection data copied to arrays are the //! same when copied back to projdata. //! -void ExportArrayTests :: test_static_data() -{ - info("Initialising..."); - //. Create ProjData - - //- ProjDataInfo - //-- Scanner - shared_ptr test_scanner_sptr( new Scanner(Scanner::Siemens_mMR)); - - //-- ExamInfo - shared_ptr test_exam_info_sptr(new ExamInfo()); - // TODO, Currently all stir::Scanner types are PET. - test_exam_info_sptr->imaging_modality = ImagingModality::PT; - - //- - shared_ptr tmp_proj_data_info_sptr( - ProjDataInfo::ProjDataInfoCTI(test_scanner_sptr, - 1, - 1, - test_scanner_sptr->get_max_num_views(), - test_scanner_sptr->get_max_num_non_arccorrected_bins(), - false)); - +void +ExportArrayTests ::test_static_data() { + info("Initialising..."); + //. Create ProjData + + //- ProjDataInfo + //-- Scanner + shared_ptr test_scanner_sptr(new Scanner(Scanner::Siemens_mMR)); + + //-- ExamInfo + shared_ptr test_exam_info_sptr(new ExamInfo()); + // TODO, Currently all stir::Scanner types are PET. + test_exam_info_sptr->imaging_modality = ImagingModality::PT; + + //- + shared_ptr tmp_proj_data_info_sptr( + ProjDataInfo::ProjDataInfoCTI(test_scanner_sptr, 1, 1, test_scanner_sptr->get_max_num_views(), + test_scanner_sptr->get_max_num_non_arccorrected_bins(), false)); + + { + ProjDataInMemory test_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr); { - ProjDataInMemory test_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr); - { - ProjDataInMemory check_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr); - run_static_test(test_proj_data, check_proj_data, "static test in-memory"); - } - { - ProjDataInterfile check_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr, - "test_proj_data_export_check.hs", std::ios::out | std::ios::trunc | std::ios::in); - run_static_test(test_proj_data, check_proj_data, "static test in-memory/interfile"); - } + ProjDataInMemory check_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr); + run_static_test(test_proj_data, check_proj_data, "static test in-memory"); } { - ProjDataInterfile test_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr, - "test_proj_data_export.hs", std::ios::out | std::ios::trunc | std::ios::in); - { - ProjDataInMemory check_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr); - run_static_test(test_proj_data, check_proj_data, "static test in-memory"); - } - { - ProjDataInterfile check_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr, - "test_proj_data_export_check.hs", std::ios::out | std::ios::trunc | std::ios::in); - run_static_test(test_proj_data, check_proj_data, "static test in-memory/interfile"); - } + ProjDataInterfile check_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr, "test_proj_data_export_check.hs", + std::ios::out | std::ios::trunc | std::ios::in); + run_static_test(test_proj_data, check_proj_data, "static test in-memory/interfile"); } - - + } + { + ProjDataInterfile test_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr, "test_proj_data_export.hs", + std::ios::out | std::ios::trunc | std::ios::in); + { + ProjDataInMemory check_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr); + run_static_test(test_proj_data, check_proj_data, "static test in-memory"); + } + { + ProjDataInterfile check_proj_data(test_exam_info_sptr, tmp_proj_data_info_sptr, "test_proj_data_export_check.hs", + std::ios::out | std::ios::trunc | std::ios::in); + run_static_test(test_proj_data, check_proj_data, "static test in-memory/interfile"); + } + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - ExportArrayTests tests; - tests.run_tests(); - return tests.main_return_value(); +int +main(int argc, char** argv) { + ExportArrayTests tests; + tests.run_tests(); + return tests.main_return_value(); } diff --git a/src/test/test_filename_functions.cxx b/src/test/test_filename_functions.cxx index e258231723..638ceee283 100644 --- a/src/test/test_filename_functions.cxx +++ b/src/test/test_filename_functions.cxx @@ -43,23 +43,22 @@ START_NAMESPACE_STIR \brief Test class for filename functions defined in utility.h \ingroup test */ -class FilenameTests : public RunTests -{ +class FilenameTests : public RunTests { public: void run_tests(); }; -void FilenameTests::run_tests() -{ +void +FilenameTests::run_tests() { char filename_with_directory[max_filename_length]; cerr << "Testing various filename utilities "; #if defined(__OS_VAX__) cerr << "(using VAX-VMS filesystem conventions)" << endl; - + // relative names either contain no '[', or have '[.' -#if 0 +# if 0 // tests disabled as add_extension is disabled strcpy(filename_with_directory, "[dir.name]filename"); add_extension(filename_with_directory, ".img"); @@ -67,13 +66,13 @@ void FilenameTests::run_tests() strcpy(filename_with_directory, "[dir.name]filename.v"); add_extension(filename_with_directory, ".img"); check(strcmp(filename_with_directory, "[dir.name]filename.v") == 0); -#endif +# endif strcpy(filename_with_directory, "[dir.name]filename.v"); check(strcmp(find_filename(filename_with_directory), "filename.v") == 0); strcpy(filename_with_directory, "filename.v"); check(strcmp(find_filename(filename_with_directory), "filename.v") == 0); - + { // same checks but with string versions string filename_with_directory = "[dir.name]filename"; @@ -82,39 +81,30 @@ void FilenameTests::run_tests() filename_with_directory = "[dir.name]filename.v"; add_extension(filename_with_directory, ".img"); check(filename_with_directory == "[dir.name]filename.v"); - + filename_with_directory = "[dir.name]filename.v"; - check(filename_with_directory.substr( - find_pos_of_filename(filename_with_directory), - string::npos) - == "filename.v"); + check(filename_with_directory.substr(find_pos_of_filename(filename_with_directory), string::npos) == "filename.v"); filename_with_directory = "filename.v"; - check(filename_with_directory.substr( - find_pos_of_filename(filename_with_directory), - string::npos) - == "filename.v"); + check(filename_with_directory.substr(find_pos_of_filename(filename_with_directory), string::npos) == "filename.v"); } check(is_absolute_pathname("da0:[bladi.b]bla.v") == true); check(is_absolute_pathname("[.bladi]bla.v") == false); check(is_absolute_pathname("bla.v") == false); strcpy(filename_with_directory, "[.b]c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "da0:[a]"), - "da0:[a.b]c.v") == 0); + check(strcmp(prepend_directory_name(filename_with_directory, "da0:[a]"), "da0:[a.b]c.v") == 0); strcpy(filename_with_directory, "c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "da0:[a.b]"), - "da0:[a.b]c.v") == 0); + check(strcmp(prepend_directory_name(filename_with_directory, "da0:[a.b]"), "da0:[a.b]c.v") == 0); strcpy(filename_with_directory, "da0:[b]c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a"), - "da0:[b]c.v") == 0); + check(strcmp(prepend_directory_name(filename_with_directory, "a"), "da0:[b]c.v") == 0); #elif defined(__OS_WIN__) cerr << "(using Windows filesystem conventions)" << endl; - + // relative names do not start with '\' or '?:\' // but we allow forward slashes as well -#if 0 +# if 0 // tests disabled as add_extension is disabled strcpy(filename_with_directory, "dir.name\\filename"); add_extension(filename_with_directory, ".img"); @@ -128,7 +118,7 @@ void FilenameTests::run_tests() strcpy(filename_with_directory, "dir.name/filename.v"); add_extension(filename_with_directory, ".img"); check(strcmp(filename_with_directory, "dir.name/filename.v") == 0); -#endif +# endif strcpy(filename_with_directory, "dir.name\\filename.v"); check(strcmp(find_filename(filename_with_directory), "filename.v") == 0); strcpy(filename_with_directory, "dir.name/filename.v"); @@ -137,193 +127,170 @@ void FilenameTests::run_tests() check(strcmp(find_filename(filename_with_directory), "filename.v") == 0); strcpy(filename_with_directory, "filename.v"); check(strcmp(find_filename(filename_with_directory), "filename.v") == 0); - { // The same with the new FilePath class. - FilePath filename_with_directory("dir.name\\filename.v", false); + { // The same with the new FilePath class. + FilePath filename_with_directory("dir.name\\filename.v", false); - check(filename_with_directory.get_filename() == "filename.v"); + check(filename_with_directory.get_filename() == "filename.v"); - filename_with_directory = "dir.name/filename.v"; - check(filename_with_directory.get_filename() == "filename.v"); + filename_with_directory = "dir.name/filename.v"; + check(filename_with_directory.get_filename() == "filename.v"); - filename_with_directory = "a:filename.v"; - check(filename_with_directory.get_filename() == "filename.v"); + filename_with_directory = "a:filename.v"; + check(filename_with_directory.get_filename() == "filename.v"); - filename_with_directory = "filename.v"; - check(filename_with_directory.get_filename() == "filename.v"); + filename_with_directory = "filename.v"; + check(filename_with_directory.get_filename() == "filename.v"); } { // same checks with string versions - string filename_with_directory = "dir.name\\filename"; + string filename_with_directory = "dir.name\\filename"; check(get_directory_name(filename_with_directory) == "dir.name\\"); add_extension(filename_with_directory, ".img"); - check(filename_with_directory == "dir.name\\filename.img"); - filename_with_directory = "dir.name\\filename.v"; + check(filename_with_directory == "dir.name\\filename.img"); + filename_with_directory = "dir.name\\filename.v"; add_extension(filename_with_directory, ".img"); - check(filename_with_directory == "dir.name\\filename.v"); - filename_with_directory = "dir.name/filename"; + check(filename_with_directory == "dir.name\\filename.v"); + filename_with_directory = "dir.name/filename"; add_extension(filename_with_directory, ".img"); - check(filename_with_directory == "dir.name/filename.img"); - filename_with_directory = "dir.name/filename.v"; + check(filename_with_directory == "dir.name/filename.img"); + filename_with_directory = "dir.name/filename.v"; add_extension(filename_with_directory, ".img"); - check(filename_with_directory == "dir.name/filename.v"); + check(filename_with_directory == "dir.name/filename.v"); - filename_with_directory = "dir.name\\filename.v"; - check(filename_with_directory.substr( - find_pos_of_filename(filename_with_directory), - string::npos) - == "filename.v"); - filename_with_directory = "dir.name/filename.v"; + filename_with_directory = "dir.name\\filename.v"; + check(filename_with_directory.substr(find_pos_of_filename(filename_with_directory), string::npos) == "filename.v"); + filename_with_directory = "dir.name/filename.v"; check(get_directory_name(filename_with_directory) == "dir.name/"); - check(filename_with_directory.substr( - find_pos_of_filename(filename_with_directory), - string::npos) - == "filename.v"); - filename_with_directory = "a:filename.v"; - check(filename_with_directory.substr( - find_pos_of_filename(filename_with_directory), - string::npos) - == "filename.v"); - filename_with_directory = "filename.v"; - check(filename_with_directory.substr( - find_pos_of_filename(filename_with_directory), - string::npos) - == "filename.v"); + check(filename_with_directory.substr(find_pos_of_filename(filename_with_directory), string::npos) == "filename.v"); + filename_with_directory = "a:filename.v"; + check(filename_with_directory.substr(find_pos_of_filename(filename_with_directory), string::npos) == "filename.v"); + filename_with_directory = "filename.v"; + check(filename_with_directory.substr(find_pos_of_filename(filename_with_directory), string::npos) == "filename.v"); } - { - check(is_absolute_pathname("\\bladi\\bla.v") == true); - check(is_absolute_pathname("a:\\bladi\\bla.v") == true); - check(is_absolute_pathname("bladi\\bla.v") == false); - check(is_absolute_pathname("/bladi/bla.v") == true); - check(is_absolute_pathname("a:/bladi/bla.v") == true); - check(is_absolute_pathname("bladi/bla.v") == false); - check(is_absolute_pathname("bla.v") == false); - - strcpy(filename_with_directory, "b\\c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a"), - "a\\b\\c.v") == 0); - strcpy(filename_with_directory, "b\\c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a\\"), - "a\\b\\c.v") == 0); - strcpy(filename_with_directory, "b\\c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a:"), - "a:b\\c.v") == 0); - strcpy(filename_with_directory, "c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a\\b"), - "a\\b\\c.v") == 0); - strcpy(filename_with_directory, "\\b\\c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a"), - "\\b\\c.v") == 0); - strcpy(filename_with_directory, "b/c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a"), - "a\\b/c.v") == 0); - strcpy(filename_with_directory, "b/c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a/"), - "a/b/c.v") == 0); - strcpy(filename_with_directory, "b/c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a:"), - "a:b/c.v") == 0); - strcpy(filename_with_directory, "c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a/b"), - "a/b\\c.v") == 0); - strcpy(filename_with_directory, "/b/c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a"), - "/b/c.v") == 0); + { + check(is_absolute_pathname("\\bladi\\bla.v") == true); + check(is_absolute_pathname("a:\\bladi\\bla.v") == true); + check(is_absolute_pathname("bladi\\bla.v") == false); + check(is_absolute_pathname("/bladi/bla.v") == true); + check(is_absolute_pathname("a:/bladi/bla.v") == true); + check(is_absolute_pathname("bladi/bla.v") == false); + check(is_absolute_pathname("bla.v") == false); + + strcpy(filename_with_directory, "b\\c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a"), "a\\b\\c.v") == 0); + strcpy(filename_with_directory, "b\\c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a\\"), "a\\b\\c.v") == 0); + strcpy(filename_with_directory, "b\\c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a:"), "a:b\\c.v") == 0); + strcpy(filename_with_directory, "c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a\\b"), "a\\b\\c.v") == 0); + strcpy(filename_with_directory, "\\b\\c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a"), "\\b\\c.v") == 0); + strcpy(filename_with_directory, "b/c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a"), "a\\b/c.v") == 0); + strcpy(filename_with_directory, "b/c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a/"), "a/b/c.v") == 0); + strcpy(filename_with_directory, "b/c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a:"), "a:b/c.v") == 0); + strcpy(filename_with_directory, "c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a/b"), "a/b\\c.v") == 0); + strcpy(filename_with_directory, "/b/c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a"), "/b/c.v") == 0); } - // Directory tests new tests + // Directory tests new tests { - check(FilePath::is_absolute("\\bladi\\bla.v") == true); - check(FilePath::is_absolute("bladi\\bla.v") == false); - check(FilePath::is_absolute("/bladi/bla.v") == true); - check(FilePath::is_absolute("a:/bladi/bla.v") == true); - check(FilePath::is_absolute("bladi/bla.v") == false); - check(FilePath::is_absolute("bla.v") == false); + check(FilePath::is_absolute("\\bladi\\bla.v") == true); + check(FilePath::is_absolute("bladi\\bla.v") == false); + check(FilePath::is_absolute("/bladi/bla.v") == true); + check(FilePath::is_absolute("a:/bladi/bla.v") == true); + check(FilePath::is_absolute("bladi/bla.v") == false); + check(FilePath::is_absolute("bla.v") == false); - FilePath filename_with_directory("b\\c.v", false); + FilePath filename_with_directory("b\\c.v", false); - filename_with_directory.prepend_directory_name("a"); - check( filename_with_directory == "a\\b\\c.v"); + filename_with_directory.prepend_directory_name("a"); + check(filename_with_directory == "a\\b\\c.v"); - filename_with_directory = "b\\c.v"; - filename_with_directory.prepend_directory_name("a\\"); - check( filename_with_directory == "a\\b\\c.v"); + filename_with_directory = "b\\c.v"; + filename_with_directory.prepend_directory_name("a\\"); + check(filename_with_directory == "a\\b\\c.v"); - filename_with_directory = "b\\c.v"; - filename_with_directory.prepend_directory_name("a:"); - check( filename_with_directory == "a:b\\c.v"); + filename_with_directory = "b\\c.v"; + filename_with_directory.prepend_directory_name("a:"); + check(filename_with_directory == "a:b\\c.v"); - filename_with_directory = "c.v"; - filename_with_directory.prepend_directory_name("a\\b"); - check( filename_with_directory == "a\\b\\c.v"); + filename_with_directory = "c.v"; + filename_with_directory.prepend_directory_name("a\\b"); + check(filename_with_directory == "a\\b\\c.v"); - filename_with_directory = "\\b\\c.v"; - filename_with_directory.prepend_directory_name("a"); - check( filename_with_directory == "\\b\\c.v"); + filename_with_directory = "\\b\\c.v"; + filename_with_directory.prepend_directory_name("a"); + check(filename_with_directory == "\\b\\c.v"); - filename_with_directory = "b/c.v"; - filename_with_directory.prepend_directory_name("a/"); - check( filename_with_directory == "a/b/c.v"); + filename_with_directory = "b/c.v"; + filename_with_directory.prepend_directory_name("a/"); + check(filename_with_directory == "a/b/c.v"); - filename_with_directory = "b\\c.v"; - filename_with_directory.prepend_directory_name("a:"); - check( filename_with_directory == "a:b\\c.v"); + filename_with_directory = "b\\c.v"; + filename_with_directory.prepend_directory_name("a:"); + check(filename_with_directory == "a:b\\c.v"); - filename_with_directory = "c.v"; - filename_with_directory.prepend_directory_name("a/b"); - check( filename_with_directory == "a/b\\c.v"); - - filename_with_directory = "/b/c.v"; - filename_with_directory.prepend_directory_name("a"); - check( filename_with_directory == "/b/c.v"); + filename_with_directory = "c.v"; + filename_with_directory.prepend_directory_name("a/b"); + check(filename_with_directory == "a/b\\c.v"); + filename_with_directory = "/b/c.v"; + filename_with_directory.prepend_directory_name("a"); + check(filename_with_directory == "/b/c.v"); } - //N.E: New directory tests. + // N.E: New directory tests. { - // No checks again because it will throw error. - FilePath fake_directory("dir.name\\filename", false); - check(FilePath::exists(fake_directory.get_path()) == false); + // No checks again because it will throw error. + FilePath fake_directory("dir.name\\filename", false); + check(FilePath::exists(fake_directory.get_path()) == false); - FilePath current_directory(FilePath::get_current_working_directory()); - check(FilePath::exists(current_directory.get_path()) == true); - check(current_directory.is_directory() == true); - check(current_directory.is_writable() == true); + FilePath current_directory(FilePath::get_current_working_directory()); + check(FilePath::exists(current_directory.get_path()) == true); + check(current_directory.is_directory() == true); + check(current_directory.is_writable() == true); - { - // Test create Path from Path. - // This is a bit of paradox so we have to set the first the - // checks to false. - // False, because not yet created. - FilePath path_to_append("my_test_folder_a", false); + { + // Test create Path from Path. + // This is a bit of paradox so we have to set the first the + // checks to false. + // False, because not yet created. + FilePath path_to_append("my_test_folder_a", false); - FilePath newly_created_path = current_directory.append(path_to_append); + FilePath newly_created_path = current_directory.append(path_to_append); - check(newly_created_path.is_directory() == true); - check(newly_created_path.is_writable() == true); + check(newly_created_path.is_directory() == true); + check(newly_created_path.is_writable() == true); - check(FilePath::exists(path_to_append.get_path()) == true); - } + check(FilePath::exists(path_to_append.get_path()) == true); + } - { - // Test create Path from String. - string path_to_append("my_test_folder_b"); + { + // Test create Path from String. + string path_to_append("my_test_folder_b"); - FilePath newly_created_path = current_directory.append(path_to_append); + FilePath newly_created_path = current_directory.append(path_to_append); - check(newly_created_path.is_directory() == true); - check(newly_created_path.is_writable() == true); + check(newly_created_path.is_directory() == true); + check(newly_created_path.is_writable() == true); - // test for recrussive creation - string paths_to_append("my_test_folder_c\\my_test_folder_d"); - FilePath newly_created_subfolder = newly_created_path.append(paths_to_append); + // test for recrussive creation + string paths_to_append("my_test_folder_c\\my_test_folder_d"); + FilePath newly_created_subfolder = newly_created_path.append(paths_to_append); - check(newly_created_subfolder.is_directory() == true); - check(newly_created_subfolder.is_writable() == true); - } + check(newly_created_subfolder.is_directory() == true); + check(newly_created_subfolder.is_writable() == true); + } } #elif defined(__OS_MAC__) @@ -331,7 +298,7 @@ void FilenameTests::run_tests() cerr << "(using MacOS filesystem conventions)" << endl; // relative names either have no ':' or do not start with ':' -#if 0 +# if 0 // tests disabled as add_extension is disabled strcpy(filename_with_directory, "dir.name:filename"); add_extension(filename_with_directory, ".img"); @@ -344,134 +311,122 @@ void FilenameTests::run_tests() check(strcmp(find_filename(filename_with_directory), "filename.v") == 0); strcpy(filename_with_directory, "filename.v"); check(strcmp(find_filename(filename_with_directory), "filename.v") == 0); -#endif +# endif { // same checks with string versions - string filename_with_directory = "dir.name:filename"; + string filename_with_directory = "dir.name:filename"; check(get_directory_name(filename_with_directory) == "dir.name:"); - + add_extension(filename_with_directory, ".img"); - check(filename_with_directory == "dir.name:filename.img"); - filename_with_directory = "dir.name:filename.v"; + check(filename_with_directory == "dir.name:filename.img"); + filename_with_directory = "dir.name:filename.v"; add_extension(filename_with_directory, ".img"); - check(filename_with_directory == "dir.name:filename.v"); - - filename_with_directory = "dir.name:filename.v"; - check(filename_with_directory.substr( - find_pos_of_filename(filename_with_directory), - string::npos) - == "filename.v"); - filename_with_directory = "filename.v"; - check(filename_with_directory.substr( - find_pos_of_filename(filename_with_directory), - string::npos) - == "filename.v"); - } - // N.E: same checks with Path class -{ + check(filename_with_directory == "dir.name:filename.v"); - FilePath filename_with_directory("dir.name:filename", false); + filename_with_directory = "dir.name:filename.v"; + check(filename_with_directory.substr(find_pos_of_filename(filename_with_directory), string::npos) == "filename.v"); + filename_with_directory = "filename.v"; + check(filename_with_directory.substr(find_pos_of_filename(filename_with_directory), string::npos) == "filename.v"); + } + // N.E: same checks with Path class + { - check( filename_with_directory.get_path() == "dir.name:"); + FilePath filename_with_directory("dir.name:filename", false); - filename_with_directory.add_extension(".img"); - check(filename_with_directory == "dir.name:filename.img"); + check(filename_with_directory.get_path() == "dir.name:"); - filename_with_directory = "dir.name:filename.v"; - check(filename_with_directory == "dir.name:filename.v"); + filename_with_directory.add_extension(".img"); + check(filename_with_directory == "dir.name:filename.img"); - filename_with_directory.add_extension(".img"); + filename_with_directory = "dir.name:filename.v"; + check(filename_with_directory == "dir.name:filename.v"); - // check no change made - check(filename_with_directory == "dir.name:filename.v"); + filename_with_directory.add_extension(".img"); - // Replace is the proper action - filename_with_directory.replace_extension(".img"); - check(filename_with_directory == "dir.name:filename.img"); + // check no change made + check(filename_with_directory == "dir.name:filename.v"); - // N.E: Not sure about this. Set again in case of failure of the - // previous test? - filename_with_directory = "dir.name:filename.v"; - check(filename_with_directory.get_filename() == "filename.v"); + // Replace is the proper action + filename_with_directory.replace_extension(".img"); + check(filename_with_directory == "dir.name:filename.img"); - filename_with_directory = "filename.v"; - check(filename_with_directory.get_filename() == "filename.v"); + // N.E: Not sure about this. Set again in case of failure of the + // previous test? + filename_with_directory = "dir.name:filename.v"; + check(filename_with_directory.get_filename() == "filename.v"); -} + filename_with_directory = "filename.v"; + check(filename_with_directory.get_filename() == "filename.v"); + } { - check(is_absolute_pathname("bladi:bla.v") == true); - check(is_absolute_pathname(":bladi:bla.v") == false); - check(is_absolute_pathname("bla.v") == false); - - strcpy(filename_with_directory, ":b:c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a"), - "a:b:c.v") == 0); - strcpy(filename_with_directory, ":b:c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a:"), - "a:b:c.v") == 0); - strcpy(filename_with_directory, "c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a:b:"), - "a:b:c.v") == 0); - strcpy(filename_with_directory, "c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a:b"), - "a:b:c.v") == 0); - strcpy(filename_with_directory, "b:c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a"), - "b:c.v") == 0); -} + check(is_absolute_pathname("bladi:bla.v") == true); + check(is_absolute_pathname(":bladi:bla.v") == false); + check(is_absolute_pathname("bla.v") == false); + + strcpy(filename_with_directory, ":b:c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a"), "a:b:c.v") == 0); + strcpy(filename_with_directory, ":b:c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a:"), "a:b:c.v") == 0); + strcpy(filename_with_directory, "c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a:b:"), "a:b:c.v") == 0); + strcpy(filename_with_directory, "c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a:b"), "a:b:c.v") == 0); + strcpy(filename_with_directory, "b:c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a"), "b:c.v") == 0); + } // Directory tests new tests { - check(FilePath::is_absolute(":bladi:bla.v") == true); - check(FilePath::is_absolute("bladi:bla.v") == false); - check(FilePath::is_absolute("bla.v") == false); + check(FilePath::is_absolute(":bladi:bla.v") == true); + check(FilePath::is_absolute("bladi:bla.v") == false); + check(FilePath::is_absolute("bla.v") == false); - FilePath filename_with_directory("b:c.v", false); + FilePath filename_with_directory("b:c.v", false); - filename_with_directory.prepend_directory_name("a"); - check( filename_with_directory == "a:b:c.v"); + filename_with_directory.prepend_directory_name("a"); + check(filename_with_directory == "a:b:c.v"); - filename_with_directory = "b:c.v"; - filename_with_directory.prepend_directory_name("a:"); - check( filename_with_directory == "a:b:c.v"); + filename_with_directory = "b:c.v"; + filename_with_directory.prepend_directory_name("a:"); + check(filename_with_directory == "a:b:c.v"); - filename_with_directory = "c.v"; - filename_with_directory.prepend_directory_name("a:b"); - check( filename_with_directory == "a:b:c.v"); + filename_with_directory = "c.v"; + filename_with_directory.prepend_directory_name("a:b"); + check(filename_with_directory == "a:b:c.v"); - filename_with_directory = ":b:c.v"; - filename_with_directory.prepend_directory_name("a"); - check( filename_with_directory == ":b:c.v"); + filename_with_directory = ":b:c.v"; + filename_with_directory.prepend_directory_name("a"); + check(filename_with_directory == ":b:c.v"); } - //N.E: New directory tests. + // N.E: New directory tests. { - // No checks again because it will throw error. - FilePath fake_directory("dir.name:filename", false); + // No checks again because it will throw error. + FilePath fake_directory("dir.name:filename", false); - check (FilePath::exists(fake_directory.get_path()) == false); + check(FilePath::exists(fake_directory.get_path()) == false); - FilePath current_directory(FilePath::get_current_working_directory()); - check (FilePath::exists(current_directory.get_path()) == true); - check(current_directory.is_directory() == true); - check(current_directory.is_writable() == true); + FilePath current_directory(FilePath::get_current_working_directory()); + check(FilePath::exists(current_directory.get_path()) == true); + check(current_directory.is_directory() == true); + check(current_directory.is_writable() == true); - { - // Test create Path from Path. - // This is a bit of paradox so we have to set the first the - // checks to false. - // False, because not yet created. - FilePath path_to_append("my_test_folder_a", false); + { + // Test create Path from Path. + // This is a bit of paradox so we have to set the first the + // checks to false. + // False, because not yet created. + FilePath path_to_append("my_test_folder_a", false); - FilePath newly_created_path = current_directory.append(path_to_append); + FilePath newly_created_path = current_directory.append(path_to_append); - check(newly_created_path.is_directory() == true); - check(newly_created_path.is_writable() == true); + check(newly_created_path.is_directory() == true); + check(newly_created_path.is_writable() == true); - check (FilePath::exists(path_to_append.get_path()) == true); - } + check(FilePath::exists(path_to_append.get_path()) == true); + } - { + { // Test create Path from String. string path_to_append("my_test_folder_b"); @@ -486,13 +441,13 @@ void FilenameTests::run_tests() check(newly_created_subfolder.is_directory() == true); check(newly_created_subfolder.is_writable() == true); - } + } } #else // defined(__OS_UNIX__) cerr << "(using Unix filesystem conventions)" << endl; -#if 0 +# if 0 // tests disabled as add_extension is disabled strcpy(filename_with_directory, "dir.name/filename"); add_extension(filename_with_directory, ".img"); @@ -505,136 +460,123 @@ void FilenameTests::run_tests() check(strcmp(find_filename(filename_with_directory), "filename.v") == 0); strcpy(filename_with_directory, "filename.v"); check(strcmp(find_filename(filename_with_directory), "filename.v") == 0); -#endif +# endif { // same checks with string versions - string filename_with_directory = "dir.name/filename"; + string filename_with_directory = "dir.name/filename"; check(get_directory_name(filename_with_directory) == "dir.name/"); add_extension(filename_with_directory, ".img"); - check(filename_with_directory == "dir.name/filename.img"); - filename_with_directory = "dir.name/filename.v"; + check(filename_with_directory == "dir.name/filename.img"); + filename_with_directory = "dir.name/filename.v"; add_extension(filename_with_directory, ".img"); - check(filename_with_directory == "dir.name/filename.v"); - - filename_with_directory = "dir.name/filename.v"; - check(filename_with_directory.substr( - find_pos_of_filename(filename_with_directory), - string::npos) - == "filename.v"); - filename_with_directory = "filename.v"; - check(filename_with_directory.substr( - find_pos_of_filename(filename_with_directory), - string::npos) - == "filename.v"); + check(filename_with_directory == "dir.name/filename.v"); + filename_with_directory = "dir.name/filename.v"; + check(filename_with_directory.substr(find_pos_of_filename(filename_with_directory), string::npos) == "filename.v"); + filename_with_directory = "filename.v"; + check(filename_with_directory.substr(find_pos_of_filename(filename_with_directory), string::npos) == "filename.v"); } - // N.E: same checks with Path class + // N.E: same checks with Path class { FilePath filename_with_directory("dir.name/filename", false); - check( filename_with_directory.get_path() == "dir.name/"); + check(filename_with_directory.get_path() == "dir.name/"); filename_with_directory.add_extension(".img"); - check(filename_with_directory == "dir.name/filename.img"); + check(filename_with_directory == "dir.name/filename.img"); - filename_with_directory = "dir.name/filename.v"; + filename_with_directory = "dir.name/filename.v"; check(filename_with_directory == "dir.name/filename.v"); filename_with_directory.add_extension(".img"); // check no change made - check(filename_with_directory == "dir.name/filename.v"); + check(filename_with_directory == "dir.name/filename.v"); // Replace is the proper action filename_with_directory.replace_extension(".img"); - check(filename_with_directory == "dir.name/filename.img"); + check(filename_with_directory == "dir.name/filename.img"); // N.E: Not sure about this. Set again in case of failure of the // previous test? - filename_with_directory = "dir.name/filename.v"; + filename_with_directory = "dir.name/filename.v"; check(filename_with_directory.get_filename() == "filename.v"); - filename_with_directory = "filename.v"; + filename_with_directory = "filename.v"; check(filename_with_directory.get_filename() == "filename.v"); - } - // N.E: Finished the old tests with the new FilePath; + // N.E: Finished the old tests with the new FilePath; // Directory tests old tests { - check(is_absolute_pathname("/bladi/bla.v") == true); - check(is_absolute_pathname("bladi/bla.v") == false); - check(is_absolute_pathname("bla.v") == false); - - strcpy(filename_with_directory, "b/c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a"), - "a/b/c.v") == 0); - strcpy(filename_with_directory, "b/c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a/"), - "a/b/c.v") == 0); - strcpy(filename_with_directory, "c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a/b"), - "a/b/c.v") == 0); - strcpy(filename_with_directory, "/b/c.v"); - check(strcmp(prepend_directory_name(filename_with_directory, "a"), - "/b/c.v") == 0); + check(is_absolute_pathname("/bladi/bla.v") == true); + check(is_absolute_pathname("bladi/bla.v") == false); + check(is_absolute_pathname("bla.v") == false); + + strcpy(filename_with_directory, "b/c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a"), "a/b/c.v") == 0); + strcpy(filename_with_directory, "b/c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a/"), "a/b/c.v") == 0); + strcpy(filename_with_directory, "c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a/b"), "a/b/c.v") == 0); + strcpy(filename_with_directory, "/b/c.v"); + check(strcmp(prepend_directory_name(filename_with_directory, "a"), "/b/c.v") == 0); } // Directory tests new tests { - check(FilePath::is_absolute("/bladi/bla.v") == true); - check(FilePath::is_absolute("bladi/bla.v") == false); - check(FilePath::is_absolute("bla.v") == false); + check(FilePath::is_absolute("/bladi/bla.v") == true); + check(FilePath::is_absolute("bladi/bla.v") == false); + check(FilePath::is_absolute("bla.v") == false); - FilePath filename_with_directory("b/c.v", false); + FilePath filename_with_directory("b/c.v", false); - filename_with_directory.prepend_directory_name("a"); - check( filename_with_directory == "a/b/c.v"); + filename_with_directory.prepend_directory_name("a"); + check(filename_with_directory == "a/b/c.v"); - filename_with_directory = "b/c.v"; - filename_with_directory.prepend_directory_name("a/"); - check( filename_with_directory == "a/b/c.v"); + filename_with_directory = "b/c.v"; + filename_with_directory.prepend_directory_name("a/"); + check(filename_with_directory == "a/b/c.v"); - filename_with_directory = "c.v"; - filename_with_directory.prepend_directory_name("a/b"); - check( filename_with_directory == "a/b/c.v"); + filename_with_directory = "c.v"; + filename_with_directory.prepend_directory_name("a/b"); + check(filename_with_directory == "a/b/c.v"); - filename_with_directory = "/b/c.v"; - filename_with_directory.prepend_directory_name("a"); - check( filename_with_directory == "/b/c.v"); + filename_with_directory = "/b/c.v"; + filename_with_directory.prepend_directory_name("a"); + check(filename_with_directory == "/b/c.v"); } - - //N.E: New directory tests. + // N.E: New directory tests. { - // No checks again because it will throw error. - FilePath fake_directory("dir.name/filename", false); - check (FilePath::exists(fake_directory.get_path()) == false); + // No checks again because it will throw error. + FilePath fake_directory("dir.name/filename", false); + check(FilePath::exists(fake_directory.get_path()) == false); - FilePath current_directory(FilePath::get_current_working_directory()); - check (FilePath::exists(current_directory.get_path()) == true); - check(current_directory.is_directory() == true); - check(current_directory.is_writable() == true); + FilePath current_directory(FilePath::get_current_working_directory()); + check(FilePath::exists(current_directory.get_path()) == true); + check(current_directory.is_directory() == true); + check(current_directory.is_writable() == true); - { - // Test create Path from Path. - // This is a bit of paradox so we have to set the first the - // checks to false. - // False, because not yet created. - FilePath path_to_append("my_test_folder_a", false); + { + // Test create Path from Path. + // This is a bit of paradox so we have to set the first the + // checks to false. + // False, because not yet created. + FilePath path_to_append("my_test_folder_a", false); - FilePath newly_created_path = current_directory.append(path_to_append); + FilePath newly_created_path = current_directory.append(path_to_append); - check(newly_created_path.is_directory() == true); - check(newly_created_path.is_writable() == true); + check(newly_created_path.is_directory() == true); + check(newly_created_path.is_writable() == true); - check (FilePath::exists(path_to_append.get_path()) == true); - } + check(FilePath::exists(path_to_append.get_path()) == true); + } - { + { // Test create Path from String. string path_to_append("my_test_folder_b"); @@ -649,17 +591,17 @@ void FilenameTests::run_tests() check(newly_created_subfolder.is_directory() == true); check(newly_created_subfolder.is_writable() == true); - } + } } -#endif /* Unix */ +#endif /* Unix */ } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { FilenameTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_find_fwhm_in_image.cxx b/src/test/test_find_fwhm_in_image.cxx index 742d73d018..8086f946bc 100644 --- a/src/test/test_find_fwhm_in_image.cxx +++ b/src/test/test_find_fwhm_in_image.cxx @@ -6,12 +6,12 @@ it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! @@ -23,17 +23,17 @@ \author Pablo Aguiar \author Kris Thielemans - - To run the test, simply run the executable. + + To run the test, simply run the executable. */ - + #include "stir/RunTests.h" #include "stir/VoxelsOnCartesianGrid.h" #include "stir/SeparableCartesianMetzImageFilter.h" #define DO_DISPLAY 0 #if DO_DISPLAY -#include "stir/display.h" +# include "stir/display.h" #endif #include "stir/find_fwhm_in_image.h" #include "stir/Coordinate3D.h" @@ -55,259 +55,220 @@ START_NAMESPACE_STIR \ingroup test \brief A simple class to test the find_fwhm_in_image function. */ -class find_fwhm_in_imageTests : public RunTests -{ +class find_fwhm_in_imageTests : public RunTests { public: - find_fwhm_in_imageTests() - {} + find_fwhm_in_imageTests() {} void run_tests(); + private: - //istream& in; + // istream& in; }; -void set_Gaussian_filter_fwhm(SeparableCartesianMetzImageFilter& filter, - const float fwhm_z, - const float fwhm_y, - const float fwhm_x) -{ +void +set_Gaussian_filter_fwhm(SeparableCartesianMetzImageFilter& filter, const float fwhm_z, const float fwhm_y, + const float fwhm_x) { std::string buffer; std::stringstream parameterstream(buffer); parameterstream << "Separable Cartesian Metz Filter Parameters :=\n" - << "x-dir filter FWHM (in mm):= " << fwhm_x << "\n" - << "y-dir filter FWHM (in mm):= " << fwhm_y << "\n" - << "z-dir filter FWHM (in mm):= " << fwhm_z << "\n" - << "x-dir filter Metz power:= .0\n" - << "y-dir filter Metz power:= .0\n" - << "z-dir filter Metz power:=.0\n" - << "END Separable Cartesian Metz Filter Parameters :=\n"; - filter.parse(parameterstream); + << "x-dir filter FWHM (in mm):= " << fwhm_x << "\n" + << "y-dir filter FWHM (in mm):= " << fwhm_y << "\n" + << "z-dir filter FWHM (in mm):= " << fwhm_z << "\n" + << "x-dir filter Metz power:= .0\n" + << "y-dir filter Metz power:= .0\n" + << "z-dir filter Metz power:=.0\n" + << "END Separable Cartesian Metz Filter Parameters :=\n"; + filter.parse(parameterstream); } - -void find_fwhm_in_imageTests::run_tests() -{ +void +find_fwhm_in_imageTests::run_tests() { cerr << "Testing find_fwhm_in_image function..." << endl; set_tolerance(1.0); - - CartesianCoordinate3D origin (0,1,2); - CartesianCoordinate3D grid_spacing (2,1.4F,2.5F); - - IndexRange<3> - range(CartesianCoordinate3D(0,-65,-64), - CartesianCoordinate3D(24,64,65)); - + CartesianCoordinate3D origin(0, 1, 2); + CartesianCoordinate3D grid_spacing(2, 1.4F, 2.5F); + + IndexRange<3> range(CartesianCoordinate3D(0, -65, -64), CartesianCoordinate3D(24, 64, 65)); - VoxelsOnCartesianGrid image(range,origin, grid_spacing); + VoxelsOnCartesianGrid image(range, origin, grid_spacing); SeparableCartesianMetzImageFilter filter; - set_Gaussian_filter_fwhm(filter, 12,14,12); + set_Gaussian_filter_fwhm(filter, 12, 14, 12); { // point source image.fill(0); - Coordinate3D location_of_maximum(12,0,0); + Coordinate3D location_of_maximum(12, 0, 0); image[location_of_maximum] = 1; - check_if_equal(image[location_of_maximum], 1.F, - "for parameter constant, should be equal"); + check_if_equal(image[location_of_maximum], 1.F, "for parameter constant, should be equal"); filter.apply(image); #if DO_DISPLAY - std::cerr << "min, max: " << image.find_min() <<", " << image.find_max() << '\n'; - display(image,image.find_max()); + std::cerr << "min, max: " << image.find_min() << ", " << image.find_max() << '\n'; + display(image, image.find_max()); #endif - const std::list > result = - find_fwhm_in_image(image, 1, 2, 0, true); + const std::list> result = find_fwhm_in_image(image, 1, 2, 0, true); check(result.size() == 1, "check only 1 maximum for single point source case"); - std::list >::const_iterator current_result_iter = - result.begin(); - - check_if_equal(current_result_iter->voxel_location, location_of_maximum, - "check location of maximum for single point source case"); - check_if_equal(current_result_iter->resolution, - Coordinate3D(12,14,12), - "check resolution for single point source case"); + std::list>::const_iterator current_result_iter = result.begin(); - - } + check_if_equal(current_result_iter->voxel_location, location_of_maximum, + "check location of maximum for single point source case"); + check_if_equal(current_result_iter->resolution, Coordinate3D(12, 14, 12), + "check resolution for single point source case"); + } { // two spheres in a slice image.fill(0); - Coordinate3D location_of_maximum(12,0,0); - image[location_of_maximum]=2; - image[12][0][18]=1; - set_Gaussian_filter_fwhm(filter, 12,14,12); + Coordinate3D location_of_maximum(12, 0, 0); + image[location_of_maximum] = 2; + image[12][0][18] = 1; + set_Gaussian_filter_fwhm(filter, 12, 14, 12); filter.apply(image); #if DO_DISPLAY - display(image, image.find_max()); + display(image, image.find_max()); #endif - const std::list > result = - find_fwhm_in_image(image, 1, 2, 0, true); + const std::list> result = find_fwhm_in_image(image, 1, 2, 0, true); check(result.size() == 1, "check only 1 maximum for 2 point sources in 1 slice"); - std::list >::const_iterator current_result_iter = - result.begin(); - + std::list>::const_iterator current_result_iter = result.begin(); + check_if_equal(current_result_iter->voxel_location, location_of_maximum, - "check location of maximum for 2 point sources in 1 slice"); - check_if_equal(current_result_iter->resolution, - Coordinate3D(12,14,12), - "check resolution for 2 point sources in 1 slice"); + "check location of maximum for 2 point sources in 1 slice"); + check_if_equal(current_result_iter->resolution, Coordinate3D(12, 14, 12), + "check resolution for 2 point sources in 1 slice"); } { SeparableCartesianMetzImageFilter filter2; - set_Gaussian_filter_fwhm(filter2, 13,14,11); + set_Gaussian_filter_fwhm(filter2, 13, 14, 11); // two spheres in different slices image.fill(0); - Coordinate3D location_of_maximum(14,0,0); - image[location_of_maximum]=2; - image[3][0][0]=1; + Coordinate3D location_of_maximum(14, 0, 0); + image[location_of_maximum] = 2; + image[3][0][0] = 1; filter2.apply(image); #if DO_DISPLAY - display(image, image.find_max()); + display(image, image.find_max()); #endif - const std::list > result = - find_fwhm_in_image(image, 1, 2, 0, true); + const std::list> result = find_fwhm_in_image(image, 1, 2, 0, true); check(result.size() == 1, "check only 1 maximum for 2 point sources in different slices"); - std::list >::const_iterator current_result_iter = - result.begin(); - + std::list>::const_iterator current_result_iter = result.begin(); + check_if_equal(current_result_iter->voxel_location, location_of_maximum, - "check location of maximum for 2 point sources in different slices"); - check_if_equal(current_result_iter->resolution, - Coordinate3D(13,14,11), - "check resolution for 2 point sources in different slices"); + "check location of maximum for 2 point sources in different slices"); + check_if_equal(current_result_iter->resolution, Coordinate3D(13, 14, 11), + "check resolution for 2 point sources in different slices"); } { // 3 spheres source image.fill(0.0005F); - Coordinate3D location_of_maximum1(12,0,0); + Coordinate3D location_of_maximum1(12, 0, 0); image[location_of_maximum1] = 5; - - Coordinate3D location_of_maximum2(19,32,36); - Coordinate3D location_of_maximum3(3,-32,-32); - image[location_of_maximum2]=3.F; - image[location_of_maximum3]=1.2F; + + Coordinate3D location_of_maximum2(19, 32, 36); + Coordinate3D location_of_maximum3(3, -32, -32); + image[location_of_maximum2] = 3.F; + image[location_of_maximum3] = 1.2F; // other_image[24][10][0]=1; - //other_image[0][0][10]=1; - //other_image[14][64][0]=1; - //other_image[8][0][65]=1; + // other_image[0][0][10]=1; + // other_image[14][64][0]=1; + // other_image[8][0][65]=1; - set_Gaussian_filter_fwhm(filter, 12,14,12); + set_Gaussian_filter_fwhm(filter, 12, 14, 12); filter.apply(image); - + #if DO_DISPLAY - display(image, image.find_max()); + display(image, image.find_max()); #endif - const std::list > result = - find_fwhm_in_image(image, 2, 2, 0, true); + const std::list> result = find_fwhm_in_image(image, 2, 2, 0, true); check(result.size() == 2, "check only 2 maxima from 3 point source case"); - std::list >::const_iterator current_result_iter = - result.begin(); - + std::list>::const_iterator current_result_iter = result.begin(); + check_if_equal(current_result_iter->voxel_location, location_of_maximum1, - "check location of 1st maximum for 3 point source case"); - check_if_equal(current_result_iter->resolution, - Coordinate3D(12,14,12), - "check resolution for 1st maximum 3 point source case"); + "check location of 1st maximum for 3 point source case"); + check_if_equal(current_result_iter->resolution, Coordinate3D(12, 14, 12), + "check resolution for 1st maximum 3 point source case"); ++current_result_iter; check_if_equal(current_result_iter->voxel_location, location_of_maximum2, - "check location of 2nd maximum for 3 point source case"); - check_if_equal(current_result_iter->resolution, - Coordinate3D(12,14,12), - "check resolution for 2nd maximum 3 point source case"); + "check location of 2nd maximum for 3 point source case"); + check_if_equal(current_result_iter->resolution, Coordinate3D(12, 14, 12), + "check resolution for 2nd maximum 3 point source case"); //++current_result_iter; - //check_if_equal(current_result_iter->voxel_location, location_of_maximum3, + // check_if_equal(current_result_iter->voxel_location, location_of_maximum3, // "check location of 3rd maximum for 3 point source case"); - //check_if_equal(current_result_iter->resolution, + // check_if_equal(current_result_iter->resolution, // Coordinate3D(4,4,4), // "check resolution for 3rd maximum 3 point source case"); - } - + { // test line source in y-direction image.fill(0); const int z_location = 12; const int x_location = 0; - for (int y=image[z_location].get_min_index(); - y<=image[z_location].get_max_index();++y) - image[z_location][y][x_location] = 1; - set_Gaussian_filter_fwhm(filter, 12,0,10); - filter.apply(image); - const std::list > result = - find_fwhm_in_image(image, image[z_location].get_length(), 2, 2, true); - #if DO_DISPLAY - display(image, image.find_max()); + for (int y = image[z_location].get_min_index(); y <= image[z_location].get_max_index(); ++y) + image[z_location][y][x_location] = 1; + set_Gaussian_filter_fwhm(filter, 12, 0, 10); + filter.apply(image); + const std::list> result = find_fwhm_in_image(image, image[z_location].get_length(), 2, 2, true); +#if DO_DISPLAY + display(image, image.find_max()); #endif - check(result.size() == static_cast(image[z_location].get_length()) , - "check number of maxima in line source along y axis"); - int y=image[z_location].get_min_index(); - for(std::list >::const_iterator current_result_iter = - result.begin(); - current_result_iter != result.end(); - ++current_result_iter) - { - Coordinate3D location_of_maximum(z_location,y,x_location); - check_if_equal(current_result_iter->voxel_location, location_of_maximum, - "check location of maximum in line source along y axis"); - check_if_equal(current_result_iter->resolution, - Coordinate3D(12,0,10), - "check resolution in line source along y axisXXX"); - ++y; - } - + check(result.size() == static_cast(image[z_location].get_length()), + "check number of maxima in line source along y axis"); + int y = image[z_location].get_min_index(); + for (std::list>::const_iterator current_result_iter = result.begin(); + current_result_iter != result.end(); ++current_result_iter) { + Coordinate3D location_of_maximum(z_location, y, x_location); + check_if_equal(current_result_iter->voxel_location, location_of_maximum, + "check location of maximum in line source along y axis"); + check_if_equal(current_result_iter->resolution, Coordinate3D(12, 0, 10), + "check resolution in line source along y axisXXX"); + ++y; + } } { // test line source in x-direction - image.fill(0); - const int z_location = 9; - const int y_location = 0; - for (int x=image[z_location][y_location].get_min_index(); - x<=image[z_location][y_location].get_max_index();++x) - { - image[z_location][y_location][x] = 1; - } - set_Gaussian_filter_fwhm(filter, 12,10,0); - filter.apply(image); - const std::list > result = - find_fwhm_in_image(image, image[z_location].get_length(), 2, 3, true); - #if DO_DISPLAY - display(image, image.find_max()); + image.fill(0); + const int z_location = 9; + const int y_location = 0; + for (int x = image[z_location][y_location].get_min_index(); x <= image[z_location][y_location].get_max_index(); ++x) { + image[z_location][y_location][x] = 1; + } + set_Gaussian_filter_fwhm(filter, 12, 10, 0); + filter.apply(image); + const std::list> result = find_fwhm_in_image(image, image[z_location].get_length(), 2, 3, true); +#if DO_DISPLAY + display(image, image.find_max()); #endif - check(result.size() == static_cast(image[z_location][y_location].get_length()) , - "check number of maxima in line source along x axis"); - int x=image[z_location][y_location].get_min_index(); - for(std::list >::const_iterator current_result_iter = - result.begin(); - current_result_iter != result.end(); - ++current_result_iter) - { - Coordinate3D location_of_maximum(z_location,y_location,x); - check_if_equal(current_result_iter->voxel_location, location_of_maximum, - "check location of maximum in line source along x axis"); - check_if_equal(current_result_iter->resolution, - Coordinate3D(12,10,0), - "check resolution in line source along x axis"); - ++x; - } + check(result.size() == static_cast(image[z_location][y_location].get_length()), + "check number of maxima in line source along x axis"); + int x = image[z_location][y_location].get_min_index(); + for (std::list>::const_iterator current_result_iter = result.begin(); + current_result_iter != result.end(); ++current_result_iter) { + Coordinate3D location_of_maximum(z_location, y_location, x); + check_if_equal(current_result_iter->voxel_location, location_of_maximum, + "check location of maximum in line source along x axis"); + check_if_equal(current_result_iter->resolution, Coordinate3D(12, 10, 0), + "check resolution in line source along x axis"); + ++x; + } } { @@ -316,53 +277,43 @@ void find_fwhm_in_imageTests::run_tests() const int y_location = 0; const int x_location = 0; - for (int z=image.get_min_index(); z<=image.get_max_index();++z) - { - image[z][y_location][x_location] = 1; - } - set_Gaussian_filter_fwhm(filter, 12,11,10); - filter.apply(image); - const std::list > result = - find_fwhm_in_image(image, image.get_length(), 2, 1, true); + for (int z = image.get_min_index(); z <= image.get_max_index(); ++z) { + image[z][y_location][x_location] = 1; + } + set_Gaussian_filter_fwhm(filter, 12, 11, 10); + filter.apply(image); + const std::list> result = find_fwhm_in_image(image, image.get_length(), 2, 1, true); #if DO_DISPLAY - display(image, image.find_max()); + display(image, image.find_max()); #endif - check(result.size() == static_cast(image.get_length()) , - "check number of maxima in line source along z axis"); - int z=image.get_min_index(); - for(std::list >::const_iterator current_result_iter = - result.begin(); - current_result_iter != result.end(); - ++current_result_iter) - { - Coordinate3D location_of_maximum(z, y_location,x_location); - check_if_equal(current_result_iter->voxel_location, location_of_maximum, - "check location of maximum in line source along z axis"); - check_if_equal(current_result_iter->resolution, - Coordinate3D(0,11,10), - "check resolution in line source along z axis"); - ++z; - } + check(result.size() == static_cast(image.get_length()), "check number of maxima in line source along z axis"); + int z = image.get_min_index(); + for (std::list>::const_iterator current_result_iter = result.begin(); + current_result_iter != result.end(); ++current_result_iter) { + Coordinate3D location_of_maximum(z, y_location, x_location); + check_if_equal(current_result_iter->voxel_location, location_of_maximum, + "check location of maximum in line source along z axis"); + check_if_equal(current_result_iter->resolution, Coordinate3D(0, 11, 10), + "check resolution in line source along z axis"); + ++z; + } } - /* - const double old_tolerance = get_tolerance(); - set_tolerance(error_on_chi_square); - check_if_equal(expected_chi_square, chi_square, - "for parameter chi_square, should be equal"); - */ + /* + const double old_tolerance = get_tolerance(); + set_tolerance(error_on_chi_square); + check_if_equal(expected_chi_square, chi_square, + "for parameter chi_square, should be equal"); + */ } - END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc != 1) - { +int +main(int argc, char** argv) { + if (argc != 1) { cerr << "Usage : " << argv[0] << " \n"; return EXIT_FAILURE; } diff --git a/src/test/test_interpolate.cxx b/src/test/test_interpolate.cxx index 1800b28d65..ded2cf954a 100644 --- a/src/test/test_interpolate.cxx +++ b/src/test/test_interpolate.cxx @@ -42,38 +42,29 @@ using std::endl; USING_NAMESPACE_STIR -int -main(int argc, char *argv[]) -{ - if (ask ("1D", false)) - { - typedef Array<1,float> array; - - array in(-9,9); +int +main(int argc, char* argv[]) { + if (ask("1D", false)) { + typedef Array<1, float> array; + + array in(-9, 9); // initialise with some data - for (int i=-9; i<=9; i++) - in[i] = .5*square(i-6)+3.*i-30; - - - do - { - const float zoom = - ask_num("Zoom ", 0., 100., 1.); - const float offset = - ask_num("Offset ", -100., 100., 0.); - const float min2 = (in.get_min_index()-.5 - offset)*zoom; - const float max2 = (in.get_max_index()+.5 - offset)*zoom; - cout << "Range of non-zero 'out' coordinates : (" - << min2 << ", " << max2 << ")" << endl; - const int out_min = - ask_num("Start index ", (int)(min2-20), (int)(max2+20), (int)min2); - const int out_max = - ask_num("End index ", out_min, (int)(max2+20), (int)max2); - + for (int i = -9; i <= 9; i++) + in[i] = .5 * square(i - 6) + 3. * i - 30; + + do { + const float zoom = ask_num("Zoom ", 0., 100., 1.); + const float offset = ask_num("Offset ", -100., 100., 0.); + const float min2 = (in.get_min_index() - .5 - offset) * zoom; + const float max2 = (in.get_max_index() + .5 - offset) * zoom; + cout << "Range of non-zero 'out' coordinates : (" << min2 << ", " << max2 << ")" << endl; + const int out_min = ask_num("Start index ", (int)(min2 - 20), (int)(max2 + 20), (int)min2); + const int out_max = ask_num("End index ", out_min, (int)(max2 + 20), (int)max2); + array out(out_min, out_max); // fill with some junk to see if it sets it to 0 out.fill(111111111.F); - + overlap_interpolate(out, in, zoom, offset, true); cout << "in:" << in; cout << "out:" << out; @@ -81,83 +72,67 @@ main(int argc, char *argv[]) cout << "old sum : " << in.sum() << ", new sum : " << out.sum() << endl; { - Array<1,float> in_coords(in.get_min_index(), in.get_max_index()+1); - for (int i=in_coords.get_min_index(); i<=in_coords.get_max_index(); ++i) - in_coords[i]=i-.5F; - Array<1,float> out_coords(out.get_min_index(), out.get_max_index()+1); - for (int i=out_coords.get_min_index(); i<=out_coords.get_max_index(); ++i) - out_coords[i]=(i-.5F)/zoom+offset; - array new_out(out.get_index_range()); - overlap_interpolate(new_out.begin(), new_out.end(), - out_coords.begin(), out_coords.end(), - in.begin(), in.end(), - in_coords.begin(), in_coords.end() - ); - cout << new_out; - new_out -= out; - cout << "diff:\n" << new_out; + Array<1, float> in_coords(in.get_min_index(), in.get_max_index() + 1); + for (int i = in_coords.get_min_index(); i <= in_coords.get_max_index(); ++i) + in_coords[i] = i - .5F; + Array<1, float> out_coords(out.get_min_index(), out.get_max_index() + 1); + for (int i = out_coords.get_min_index(); i <= out_coords.get_max_index(); ++i) + out_coords[i] = (i - .5F) / zoom + offset; + array new_out(out.get_index_range()); + overlap_interpolate(new_out.begin(), new_out.end(), out_coords.begin(), out_coords.end(), in.begin(), in.end(), + in_coords.begin(), in_coords.end()); + cout << new_out; + new_out -= out; + cout << "diff:\n" << new_out; } } while (ask("More ?", true)); } - - - if (ask ("2D", true)) - { - - typedef Array<2,float> array; - - array in(IndexRange2D(-4,4,3,6)); + + if (ask("2D", true)) { + + typedef Array<2, float> array; + + array in(IndexRange2D(-4, 4, 3, 6)); // initialise with arbitrary data - for (int i=-4; i<=4; i++) - for (int j=3; j<=6; j++) - in[i][j] = .5*square(i-6)+3.*i-30+j; - - do - { - const float zoom = - ask_num("Zoom ", 0., 100., 1.); - const float offset = - ask_num("Offset ", -100., 100., 0.); - const float min2 = (in.get_min_index()-.5 - offset)*zoom; - const float max2 = (in.get_max_index()+.5 - offset)*zoom; - cout << "Range of non-zero 'out' coordinates : (" - << min2 << ", " << max2 << ")" << endl; - const int out_min = - ask_num("Start index ", (int)(min2-20), (int)(max2+20), (int)min2); - const int out_max = - ask_num("End index ", out_min, (int)(max2+20), (int)max2); - - array out(IndexRange2D(out_min, out_max, 3,6)); - - - // fill with some junk to see if it sets it to 0 - out.fill(111111111.F); - - overlap_interpolate(out, in, zoom, offset, true); - cout << out; - - cout << "old sum : " << in.sum() << ", new sum : " << out.sum() << endl; + for (int i = -4; i <= 4; i++) + for (int j = 3; j <= 6; j++) + in[i][j] = .5 * square(i - 6) + 3. * i - 30 + j; + + do { + const float zoom = ask_num("Zoom ", 0., 100., 1.); + const float offset = ask_num("Offset ", -100., 100., 0.); + const float min2 = (in.get_min_index() - .5 - offset) * zoom; + const float max2 = (in.get_max_index() + .5 - offset) * zoom; + cout << "Range of non-zero 'out' coordinates : (" << min2 << ", " << max2 << ")" << endl; + const int out_min = ask_num("Start index ", (int)(min2 - 20), (int)(max2 + 20), (int)min2); + const int out_max = ask_num("End index ", out_min, (int)(max2 + 20), (int)max2); + + array out(IndexRange2D(out_min, out_max, 3, 6)); + + // fill with some junk to see if it sets it to 0 + out.fill(111111111.F); + + overlap_interpolate(out, in, zoom, offset, true); + cout << out; + + cout << "old sum : " << in.sum() << ", new sum : " << out.sum() << endl; { - Array<1,float> in_coords(in.get_min_index(), in.get_max_index()+1); - for (int i=in_coords.get_min_index(); i<=in_coords.get_max_index(); ++i) - in_coords[i]=i-.5F; - Array<1,float> out_coords(out.get_min_index(), out.get_max_index()+1); - for (int i=out_coords.get_min_index(); i<=out_coords.get_max_index(); ++i) - out_coords[i]=(i-.5F)/zoom+offset; - array new_out(out.get_index_range()); - overlap_interpolate(new_out.begin(), new_out.end(), - out_coords.begin(), out_coords.end(), - in.begin(), in.end(), - in_coords.begin(), in_coords.end() - ); - cout << new_out; - new_out -= out; - cout << "diff:\n" << new_out; + Array<1, float> in_coords(in.get_min_index(), in.get_max_index() + 1); + for (int i = in_coords.get_min_index(); i <= in_coords.get_max_index(); ++i) + in_coords[i] = i - .5F; + Array<1, float> out_coords(out.get_min_index(), out.get_max_index() + 1); + for (int i = out_coords.get_min_index(); i <= out_coords.get_max_index(); ++i) + out_coords[i] = (i - .5F) / zoom + offset; + array new_out(out.get_index_range()); + overlap_interpolate(new_out.begin(), new_out.end(), out_coords.begin(), out_coords.end(), in.begin(), in.end(), + in_coords.begin(), in_coords.end()); + cout << new_out; + new_out -= out; + cout << "diff:\n" << new_out; } - - } while (ask("More ?", true)); + + } while (ask("More ?", true)); } - - + return EXIT_SUCCESS; } diff --git a/src/test/test_linear_regression.cxx b/src/test/test_linear_regression.cxx index ba1415e257..e79f14097b 100644 --- a/src/test/test_linear_regression.cxx +++ b/src/test/test_linear_regression.cxx @@ -12,7 +12,7 @@ - + To run the test, you should use a command line argument with the name of a file. This should contain a number of test cases for the fit. See linear_regressionTests for file contents. @@ -34,7 +34,7 @@ See STIR/LICENSE.txt for details */ - + #include "stir/linear_regression.h" #include "stir/RunTests.h" #include "stir/ArrayFunction.h" @@ -64,8 +64,8 @@ START_NAMESPACE_STIR list_of_numbers
    ... - - where list_of_numbers is the following list of numbers + + where list_of_numbers is the following list of numbers (white space is ignored) number_of_points
    @@ -73,170 +73,145 @@ START_NAMESPACE_STIR data
    weights
    expected_constant expected_scale
    - expected_chi_square
    + expected_chi_square
    expected_variance_of_constant expected_variance_of_scale
    expected_covariance_of_constant_with_scale
    */ -class linear_regressionTests : public RunTests -{ +class linear_regressionTests : public RunTests { public: - linear_regressionTests(istream& in) - : in(in) - {} + linear_regressionTests(istream& in) : in(in) {} void run_tests(); + private: istream& in; }; - -void linear_regressionTests::run_tests() -{ +void +linear_regressionTests::run_tests() { cerr << "Testing linear_regression function..." << endl; char text[200]; - in.get(text,200); + in.get(text, 200); cerr << text << endl; int test_case = 0; - - while (in) - { + + while (in) { // first get rid of EOL - in.getline(text,200); + in.getline(text, 200); // now get real text - in.get(text,200); - test_case ++; - + in.get(text, 200); + test_case++; + int size = 0; in >> size; - if (size<=0) + if (size <= 0) break; cerr << text << endl; - Array<1,float> coordinates(size); - Array<1,float> measured_data(size); - Array<1,float> weights(size); - for (int i=0; i coordinates(size); + Array<1, float> measured_data(size); + Array<1, float> weights(size); + for (int i = 0; i < size; i++) in >> coordinates[i]; - for (int i=0; i> measured_data[i]; - for (int i=0; i> weights[i]; - + double expected_scale; double expected_constant; double expected_variance_of_scale; double expected_variance_of_constant; double expected_covariance_of_constant_with_scale; double expected_chi_square; - - in >> expected_constant >> expected_scale - >> expected_chi_square - >> expected_variance_of_constant >> expected_variance_of_scale - >> expected_covariance_of_constant_with_scale; - - - double scale=0; - double constant=0; - double variance_of_scale=0; - double variance_of_constant=0; - double covariance_of_constant_with_scale=0; + + in >> expected_constant >> expected_scale >> expected_chi_square >> expected_variance_of_constant >> + expected_variance_of_scale >> expected_covariance_of_constant_with_scale; + + double scale = 0; + double constant = 0; + double variance_of_scale = 0; + double variance_of_constant = 0; + double covariance_of_constant_with_scale = 0; double chi_square = 0; - - linear_regression( - constant, scale, - chi_square, - variance_of_constant, - variance_of_scale, - covariance_of_constant_with_scale, - measured_data, - coordinates, - weights); - - check_if_equal(expected_constant, constant, - "for parameter constant, should be equal"); - check_if_equal(expected_scale, scale, - "for parameter scale, should be equal"); + + linear_regression(constant, scale, chi_square, variance_of_constant, variance_of_scale, covariance_of_constant_with_scale, + measured_data, coordinates, weights); + + check_if_equal(expected_constant, constant, "for parameter constant, should be equal"); + check_if_equal(expected_scale, scale, "for parameter scale, should be equal"); // KT 24/01/2001 changed tolerance for this comparisons - /* chi_square is computed as a + /* chi_square is computed as a chi^2 = weights.(data - (constant + scale coordinates))^2 - + There's a subtraction of nearly matching floating - point numbers. This means there's a lot of potential for + point numbers. This means there's a lot of potential for numerical error. Float computations have a precision of about 10^-5. Which means you can really trust numbers upto 10^-5 times some value related to the size of the numbers you're adding/subtracing. So, we're really computing - chi^2 +- 10^-5*(weights.data) + chi^2 +- 10^-5*(weights.data) */ double error_on_chi_square = 0; { - for (int i=0; i - +#include #ifndef STIR_NO_NAMESPACES using std::cerr; using std::setw; @@ -58,72 +58,67 @@ START_NAMESPACE_STIR \brief Test class for MultipleProjData */ -class MultipleProjDataTests: public RunTests -{ +class MultipleProjDataTests : public RunTests { public: void run_tests(); - void set_multi_file(const std::string &multi_file) { _multi_file = multi_file; } + void set_multi_file(const std::string& multi_file) { _multi_file = multi_file; } + private: std::string _multi_file; }; void -MultipleProjDataTests::run_tests() -{ - std::cout << "-------- Testing MultipleProjData --------\n"; - - // Create single proj data - shared_ptr scanner_sptr(new Scanner(Scanner::E953)); - shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, 1, 10, 96, 128, true)); - shared_ptr exam_info_sptr(new ExamInfo); - - // Create and write proj data 1 - shared_ptr proj_data_1_sptr(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr)); - float fill_value = 5.F; - proj_data_1_sptr->fill(fill_value); - proj_data_1_sptr->write_to_file("test_proj_data1"); - - // Create and write proj data 2 - shared_ptr proj_data_2_sptr(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr)); - proj_data_2_sptr->fill(fill_value*2.F); - proj_data_2_sptr->write_to_file("test_proj_data2"); - - // Create a multi header file - std::ofstream myfile("test_multi_file.txt"); - if (myfile.is_open()) { - myfile << "Multi :=\n"; - myfile << "\ttotal number of data sets := 2\n"; - myfile << "\tdata set[1] := test_proj_data1.hs\n"; - myfile << "\tdata set[2] := test_proj_data2.hs\n"; - myfile << "end :=\n"; - myfile.close(); - } - else { - everything_ok = false; - return; - } - - // Read back in - shared_ptr read_in_multi_proj_data; - read_in_multi_proj_data = MultipleProjData::read_from_file("test_multi_file.txt"); - - // Compare results - check_if_equal(read_in_multi_proj_data->get_proj_data(1).get_viewgram(0,0).find_max(), - proj_data_1_sptr->get_viewgram(0,0).find_max(), - "test between maxes of first sinogram"); - - check_if_equal(read_in_multi_proj_data->get_proj_data(2).get_viewgram(0,0).find_min(), - proj_data_2_sptr->get_viewgram(1,1).find_min(), - "test between mins of second sinogram"); +MultipleProjDataTests::run_tests() { + std::cout << "-------- Testing MultipleProjData --------\n"; + + // Create single proj data + shared_ptr scanner_sptr(new Scanner(Scanner::E953)); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, 1, 10, 96, 128, true)); + shared_ptr exam_info_sptr(new ExamInfo); + + // Create and write proj data 1 + shared_ptr proj_data_1_sptr(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr)); + float fill_value = 5.F; + proj_data_1_sptr->fill(fill_value); + proj_data_1_sptr->write_to_file("test_proj_data1"); + + // Create and write proj data 2 + shared_ptr proj_data_2_sptr(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr)); + proj_data_2_sptr->fill(fill_value * 2.F); + proj_data_2_sptr->write_to_file("test_proj_data2"); + + // Create a multi header file + std::ofstream myfile("test_multi_file.txt"); + if (myfile.is_open()) { + myfile << "Multi :=\n"; + myfile << "\ttotal number of data sets := 2\n"; + myfile << "\tdata set[1] := test_proj_data1.hs\n"; + myfile << "\tdata set[2] := test_proj_data2.hs\n"; + myfile << "end :=\n"; + myfile.close(); + } else { + everything_ok = false; + return; + } + + // Read back in + shared_ptr read_in_multi_proj_data; + read_in_multi_proj_data = MultipleProjData::read_from_file("test_multi_file.txt"); + + // Compare results + check_if_equal(read_in_multi_proj_data->get_proj_data(1).get_viewgram(0, 0).find_max(), + proj_data_1_sptr->get_viewgram(0, 0).find_max(), "test between maxes of first sinogram"); + + check_if_equal(read_in_multi_proj_data->get_proj_data(2).get_viewgram(0, 0).find_min(), + proj_data_2_sptr->get_viewgram(1, 1).find_min(), "test between mins of second sinogram"); } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main() -{ +int +main() { set_default_num_threads(); diff --git a/src/test/test_proj_data.cxx b/src/test/test_proj_data.cxx index 21bb8d82d0..bb6881a9fc 100644 --- a/src/test/test_proj_data.cxx +++ b/src/test/test_proj_data.cxx @@ -42,211 +42,192 @@ START_NAMESPACE_STIR - /*! \ingroup test \brief Test class for ProjData and ProjDataInMemory */ -class ProjDataTests: public RunTests -{ +class ProjDataTests : public RunTests { public: void run_tests(); + private: void run_tests_on_proj_data(ProjData&); void run_tests_in_memory_only(ProjDataInMemory&); }; void -ProjDataTests:: -run_tests_on_proj_data(ProjData& proj_data) -{ +ProjDataTests::run_tests_on_proj_data(ProjData& proj_data) { CPUTimer timer; const float value = 1.2F; std::cerr << "test fill(float)\n"; - timer.reset(); timer.start(); + timer.reset(); + timer.start(); { proj_data.fill(value); - Viewgram viewgram = proj_data.get_viewgram(0,0); - check_if_equal(viewgram.find_min(), - value, - "test fill(float) and get_viewgram"); + Viewgram viewgram = proj_data.get_viewgram(0, 0); + check_if_equal(viewgram.find_min(), value, "test fill(float) and get_viewgram"); } - - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; std::cerr << "\ntest set_viewgram\n"; - timer.reset(); timer.start(); + timer.reset(); + timer.start(); { - Viewgram viewgram = proj_data.get_empty_viewgram(1,1); - viewgram.fill(value*2); - check(proj_data.set_viewgram(viewgram) == Succeeded::yes, - "test set_viewgram succeeded"); - - Viewgram viewgram2 = proj_data.get_viewgram(1,1); - check_if_equal(viewgram2.find_min(), - viewgram.find_min(), - "test set/get_viewgram"); + Viewgram viewgram = proj_data.get_empty_viewgram(1, 1); + viewgram.fill(value * 2); + check(proj_data.set_viewgram(viewgram) == Succeeded::yes, "test set_viewgram succeeded"); + + Viewgram viewgram2 = proj_data.get_viewgram(1, 1); + check_if_equal(viewgram2.find_min(), viewgram.find_min(), "test set/get_viewgram"); } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; std::cerr << "\ntest making a copy\n"; - timer.reset(); timer.start(); + timer.reset(); + timer.start(); { ProjDataInMemory proj_data2(proj_data); - check_if_equal(proj_data2.get_viewgram(0,0).find_max(), - proj_data.get_viewgram(0,0).find_max(), + check_if_equal(proj_data2.get_viewgram(0, 0).find_max(), proj_data.get_viewgram(0, 0).find_max(), "test 1 for copy-constructor and get_viewgram"); - check_if_equal(proj_data2.get_viewgram(1,1).find_max(), - proj_data.get_viewgram(1,1).find_max(), + check_if_equal(proj_data2.get_viewgram(1, 1).find_max(), proj_data.get_viewgram(1, 1).find_max(), "test 1 for copy-constructor and get_viewgram"); // check this was a deep-copy by filling and check if the original is not affected proj_data2.fill(1e4f); - check(std::abs(proj_data2.get_viewgram(0,0).find_max() - - proj_data.get_viewgram(0,0).find_max()) > 1.f, + check(std::abs(proj_data2.get_viewgram(0, 0).find_max() - proj_data.get_viewgram(0, 0).find_max()) > 1.f, "test 1 for deep copy and get_viewgram"); } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; std::cerr << "\ntest making a copy using stir::copy_to\n"; - timer.reset(); timer.start(); + timer.reset(); + timer.start(); { ProjDataInMemory proj_data2(proj_data.get_exam_info_sptr(), proj_data.get_proj_data_info_sptr()); - ProjData const& p=proj_data; + ProjData const& p = proj_data; copy_to(p, proj_data2.begin_all()); - check_if_equal(proj_data2.get_viewgram(0,0).find_max(), - proj_data.get_viewgram(0,0).find_max(), + check_if_equal(proj_data2.get_viewgram(0, 0).find_max(), proj_data.get_viewgram(0, 0).find_max(), "test 1 for templated-copy and get_viewgram(0,0)"); - check_if_equal(proj_data2.get_viewgram(1,1).find_max(), - proj_data.get_viewgram(1,1).find_max(), + check_if_equal(proj_data2.get_viewgram(1, 1).find_max(), proj_data.get_viewgram(1, 1).find_max(), "test 1 for templated-copy and get_viewgram(1,1)"); } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; std::cerr << "\ntest making a copy using stir::copy_to with reference to ProjData\n"; - timer.reset(); timer.start(); + timer.reset(); + timer.start(); { ProjDataInMemory proj_data2(proj_data.get_exam_info_sptr(), proj_data.get_proj_data_info_sptr()); ProjData& p_ref(proj_data); copy_to(p_ref, proj_data2.begin_all()); - check_if_equal(proj_data2.get_viewgram(0,0).find_max(), - proj_data.get_viewgram(0,0).find_max(), + check_if_equal(proj_data2.get_viewgram(0, 0).find_max(), proj_data.get_viewgram(0, 0).find_max(), "test 1 for templated-copy ProjData& and get_viewgram(0,0)"); - check_if_equal(proj_data2.get_viewgram(1,1).find_max(), - proj_data.get_viewgram(1,1).find_max(), + check_if_equal(proj_data2.get_viewgram(1, 1).find_max(), proj_data.get_viewgram(1, 1).find_max(), "test 1 for templated-copy ProjData& and get_viewgram(1,1)"); } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; std::cerr << "\ntest fill with larger input\n"; - timer.reset(); timer.start(); - { - shared_ptr proj_data_info_sptr2 - (ProjDataInfo::ProjDataInfoCTI(proj_data.get_proj_data_info_sptr()->get_scanner_sptr(), - /*span*/1, 8, - proj_data.get_num_views(), proj_data.get_num_tangential_poss(), - /*arc_corrected*/ true) - ); - - + timer.reset(); + timer.start(); + { + shared_ptr proj_data_info_sptr2( + ProjDataInfo::ProjDataInfoCTI(proj_data.get_proj_data_info_sptr()->get_scanner_sptr(), + /*span*/ 1, 8, proj_data.get_num_views(), proj_data.get_num_tangential_poss(), + /*arc_corrected*/ true)); + // construct without filling ProjDataInMemory proj_data2(proj_data.get_exam_info_sptr(), proj_data_info_sptr2, false); proj_data2.fill(proj_data); - check_if_equal(proj_data2.get_viewgram(0,0).find_max(), - proj_data.get_viewgram(0,0).find_max(), + check_if_equal(proj_data2.get_viewgram(0, 0).find_max(), proj_data.get_viewgram(0, 0).find_max(), "test 1 for copy-constructor and get_viewgram"); - check_if_equal(proj_data2.get_viewgram(1,1).find_max(), - proj_data.get_viewgram(1,1).find_max(), + check_if_equal(proj_data2.get_viewgram(1, 1).find_max(), proj_data.get_viewgram(1, 1).find_max(), "test 1 for copy-constructor and get_viewgram"); } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; std::cerr << "\ntest fill with smaller input\n"; - timer.reset(); timer.start(); - { - shared_ptr proj_data_info_sptr2 - (ProjDataInfo::ProjDataInfoCTI(proj_data.get_proj_data_info_sptr()->get_scanner_sptr(), - /*span*/1, 12, - proj_data.get_num_views(), proj_data.get_num_tangential_poss(), - /*arc_corrected*/ true) - ); - - + timer.reset(); + timer.start(); + { + shared_ptr proj_data_info_sptr2( + ProjDataInfo::ProjDataInfoCTI(proj_data.get_proj_data_info_sptr()->get_scanner_sptr(), + /*span*/ 1, 12, proj_data.get_num_views(), proj_data.get_num_tangential_poss(), + /*arc_corrected*/ true)); + // construct without filling ProjDataInMemory proj_data2(proj_data.get_exam_info_sptr(), proj_data_info_sptr2, false); // this should call error, so we'll catch it - try - { - std::cout << "\nthis test should intentionally throw an error\n"; - proj_data2.fill(proj_data); - check(false, "test fill wtih too small proj_data should have thrown"); - } - catch (...) - { - // ok - } + try { + std::cout << "\nthis test should intentionally throw an error\n"; + proj_data2.fill(proj_data); + check(false, "test fill wtih too small proj_data should have thrown"); + } catch (...) { + // ok + } } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; } void -ProjDataTests::run_tests_in_memory_only(ProjDataInMemory& proj_data) -{ +ProjDataTests::run_tests_in_memory_only(ProjDataInMemory& proj_data) { std::cerr << "\ntest set_bin_value() and get_bin_value\n"; { - std::vector test; - test.resize(proj_data.size_all()); - - for(unsigned int i=0;i viewgram=proj_data.get_viewgram(bin.view_num(), bin.segment_num()); - check_if_equal(bin.get_bin_value(),viewgram[bin.axial_pos_num()][bin.tangential_pos_num()], - "ProjDataInMemory::set_bin_value/get_viewgram not consistent"); + std::vector test; + test.resize(proj_data.size_all()); + + for (unsigned int i = 0; i < test.size(); i++) + test[i] = i; + + fill_from(proj_data, test.begin(), test.end()); + + Bin bin(0, proj_data.get_max_view_num() / 2, proj_data.get_max_axial_pos_num(0) / 2, 0); + + bin.set_bin_value(42); + proj_data.set_bin_value(bin); + check_if_equal(bin.get_bin_value(), proj_data.get_bin_value(bin), + "ProjDataInMemory::set_bin_value/get_bin_value not consistent"); + // also check via get_viewgram + const Viewgram viewgram = proj_data.get_viewgram(bin.view_num(), bin.segment_num()); + check_if_equal(bin.get_bin_value(), viewgram[bin.axial_pos_num()][bin.tangential_pos_num()], + "ProjDataInMemory::set_bin_value/get_viewgram not consistent"); } std::cerr << "test if copy_to is consistent with iterators\n"; { - Array<3,float> test_array(IndexRange3D(proj_data.get_num_sinograms(), proj_data.get_num_views(), proj_data.get_num_tangential_poss())); + Array<3, float> test_array( + IndexRange3D(proj_data.get_num_sinograms(), proj_data.get_num_views(), proj_data.get_num_tangential_poss())); // copy to the array copy_to(proj_data, test_array.begin_all()); { - Array<3,float>::const_full_iterator test_array_iter = test_array.begin_all_const(); + Array<3, float>::const_full_iterator test_array_iter = test_array.begin_all_const(); ProjDataInMemory::full_iterator proj_data_iter = proj_data.begin_all(); - while (test_array_iter != test_array.end_all_const()) - { - if (!check_if_equal(*proj_data_iter, *test_array_iter, "check if array iterator in correct order")) - { - // get out as there will be lots of other failures - break; - } - ++test_array_iter; - ++proj_data_iter; + while (test_array_iter != test_array.end_all_const()) { + if (!check_if_equal(*proj_data_iter, *test_array_iter, "check if array iterator in correct order")) { + // get out as there will be lots of other failures + break; } + ++test_array_iter; + ++proj_data_iter; + } } } } void -ProjDataTests:: -run_tests() -{ +ProjDataTests::run_tests() { std::cerr << "-------- Testing ProjData --------\n"; shared_ptr scanner_sptr(new Scanner(Scanner::E953)); - shared_ptr proj_data_info_sptr - (ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span*/1, 10,/*views*/ 2096, /*tang_pos*/132, /*arc_corrected*/ true) - ); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span*/ 1, 10, /*views*/ 2096, /*tang_pos*/ 132, + /*arc_corrected*/ true)); shared_ptr exam_info_sptr(new ExamInfo); exam_info_sptr->imaging_modality = ImagingModality::PT; @@ -254,29 +235,24 @@ run_tests() // construct with filling to 0 ProjDataInMemory proj_data_in_memory(exam_info_sptr, proj_data_info_sptr); { - Sinogram sinogram = proj_data_in_memory.get_sinogram(0,0); - check_if_equal(sinogram.find_min(), - 0.F, - "test constructor and get_sinogram"); + Sinogram sinogram = proj_data_in_memory.get_sinogram(0, 0); + check_if_equal(sinogram.find_min(), 0.F, "test constructor and get_sinogram"); } run_tests_on_proj_data(proj_data_in_memory); run_tests_in_memory_only(proj_data_in_memory); - std::cerr<< "\n-----------------Repeating tests but now with interfile input\n"; + std::cerr << "\n-----------------Repeating tests but now with interfile input\n"; - ProjDataInterfile(exam_info_sptr, proj_data_info_sptr, - "test_proj_data.hs", std::ios::in|std::ios::out|std::ios::trunc); + ProjDataInterfile(exam_info_sptr, proj_data_info_sptr, "test_proj_data.hs", std::ios::in | std::ios::out | std::ios::trunc); run_tests_on_proj_data(proj_data_in_memory); - } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main() -{ +int +main() { ProjDataTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_proj_data_in_memory.cxx b/src/test/test_proj_data_in_memory.cxx new file mode 100644 index 0000000000..cb058947d4 --- /dev/null +++ b/src/test/test_proj_data_in_memory.cxx @@ -0,0 +1,241 @@ +// +// +/*! + + \file + \ingroup test + + \brief Test program for stir::ProjDataInMemory + + \author Kris Thielemans + +*/ +/* + Copyright (C) 2015, University College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ + +#include "stir/ProjDataInMemory.h" +#include "stir/ExamInfo.h" +#include "stir/ProjDataInfo.h" +#include "stir/Sinogram.h" +#include "stir/Viewgram.h" +#include "stir/Succeeded.h" +#include "stir/RunTests.h" +#include "stir/Scanner.h" + +START_NAMESPACE_STIR + +/*! + \ingroup test + \brief Test class for ProjDataInMemory +*/ +class ProjDataInMemoryTests : public RunTests { +public: + void run_tests(); + void run_tests_no_tof(); + void run_tests_tof(); +}; + +void +ProjDataInMemoryTests::run_tests() { + this->run_tests_no_tof(); + this->run_tests_tof(); +} + +void +ProjDataInMemoryTests::run_tests_no_tof() { + std::cerr << "-------- Testing ProjDataInMemory without TOF --------\n"; + shared_ptr scanner_sptr(new Scanner(Scanner::E953)); + + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span*/ 1, 10, /*views*/ 96, /*tang_pos*/ 128, + /*arc_corrected*/ true)); + shared_ptr exam_info_sptr(new ExamInfo); + + // construct with filling to 0 + ProjDataInMemory proj_data(exam_info_sptr, proj_data_info_sptr); + { + Sinogram sinogram = proj_data.get_sinogram(0, 0); + check_if_equal(sinogram.find_min(), 0.F, "test constructor and get_sinogram"); + } + + const float value = 1.2F; + // test fill(float) + { + proj_data.fill(value); + Viewgram viewgram = proj_data.get_viewgram(0, 0); + check_if_equal(viewgram.find_min(), value, "test fill(float) and get_viewgram"); + } + + // test set_viewgram + { + Viewgram viewgram = proj_data.get_empty_viewgram(1, 1); + viewgram.fill(value * 2); + check(proj_data.set_viewgram(viewgram) == Succeeded::yes, "test set_viewgram succeeded"); + + Viewgram viewgram2 = proj_data.get_viewgram(1, 1); + check_if_equal(viewgram2.find_min(), viewgram.find_min(), "test set/get_viewgram"); + } + + // test making a copy + { + ProjDataInMemory proj_data2(proj_data); + check_if_equal(proj_data2.get_viewgram(0, 0).find_max(), proj_data.get_viewgram(0, 0).find_max(), + "test 1 for copy-constructor and get_viewgram"); + check_if_equal(proj_data2.get_viewgram(1, 1).find_max(), proj_data.get_viewgram(1, 1).find_max(), + "test 1 for copy-constructor and get_viewgram"); + proj_data2.fill(1e4f); + check(std::abs(proj_data2.get_viewgram(0, 0).find_max() - proj_data.get_viewgram(0, 0).find_max()) > 1.f, + "test 1 for deep copy and get_viewgram"); + } + + // test fill with larger input + { + shared_ptr proj_data_info_sptr2(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span*/ 1, 8, /*views*/ 96, /*tang_pos*/ 128, + /*arc_corrected*/ true)); + + // construct without filling + ProjDataInMemory proj_data2(exam_info_sptr, proj_data_info_sptr2, false); + proj_data2.fill(proj_data); + check_if_equal(proj_data2.get_viewgram(0, 0).find_max(), proj_data.get_viewgram(0, 0).find_max(), + "test 1 for constructor, fill and get_viewgram(0,0)"); + check_if_equal(proj_data2.get_viewgram(1, 1).find_max(), proj_data.get_viewgram(1, 1).find_max(), + "test 1 for constructor, fill and get_viewgram(1,1)"); + } + + // test fill with smaller input + { + shared_ptr proj_data_info_sptr2(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span*/ 1, 12, /*views*/ 96, /*tang_pos*/ 128, + /*arc_corrected*/ true)); + + // construct without filling + ProjDataInMemory proj_data2(exam_info_sptr, proj_data_info_sptr2, false); + // this should call error, so we'll catch it + try { + std::cout << "\nthis test should throw an error (which we will catch)\n"; + proj_data2.fill(proj_data); + check(false, "test fill with too small proj_data should have thrown"); + } catch (...) { + // ok + } + } +} + +void +ProjDataInMemoryTests::run_tests_tof() { + std::cerr << "-------- Testing ProjDataInMemory with TOF --------\n"; + shared_ptr scanner_sptr(new Scanner(Scanner::PETMR_Signa)); + + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span*/ 1, 10, /*views*/ 96, /*tang_pos*/ 64, + /*arc_corrected*/ true, 70)); + shared_ptr exam_info_sptr(new ExamInfo); + + // construct with filling to 0 + ProjDataInMemory proj_data(exam_info_sptr, proj_data_info_sptr); + { + check_if_equal(proj_data.get_sinogram(0, 0, false, -2).get_timing_pos_num(), -2, "test get_sinogram timing position index"); + Sinogram sinogram = proj_data.get_sinogram(0, 0, false, -2); + check_if_equal(sinogram.get_timing_pos_num(), -2, "test constructor and get_sinogram timing position index"); + check_if_equal(sinogram.find_min(), 0.F, "test constructor and get_sinogram"); + } + + const float value = 1.2F; + // test fill(float) + { + proj_data.fill(value); + Viewgram viewgram = proj_data.get_viewgram(0, 0, false, -2); + check_if_equal(viewgram.get_timing_pos_num(), -2, "test constructor and get_viewgram timing position index"); + check_if_equal(viewgram.find_min(), value, "test fill(float) and get_viewgram"); + } + + // test set_viewgram + { + Viewgram viewgram = proj_data.get_empty_viewgram(1, 1, false, -2); + viewgram.fill(value * 2); + check(proj_data.set_viewgram(viewgram) == Succeeded::yes, "test set_viewgram succeeded"); + + Viewgram viewgram2 = proj_data.get_viewgram(1, 1, false, -2); + check_if_equal(viewgram2.get_timing_pos_num(), -2, "test set/get_viewgram timing position index"); + check_if_equal(viewgram2.find_min(), viewgram.find_min(), "test set/get_viewgram"); + } + // test set_segment_by_view + { + SegmentByView segment = proj_data.get_empty_segment_by_view(1, false, -2); + segment.fill(value * 2); + check(proj_data.set_segment(segment) == Succeeded::yes, "test set_segment succeeded"); + + SegmentByView segment2 = proj_data.get_segment_by_view(1, -2); + check_if_equal(segment2.get_timing_pos_num(), -2, "test set/get_segment_by_view timing position index"); + check_if_equal(segment2.find_min(), segment.find_min(), "test set/get_segment_by_view"); + } + // test making a copy + { + ProjDataInMemory proj_data2(proj_data); + check_if_equal(proj_data2.get_viewgram(0, 0, false, -2).find_max(), proj_data.get_viewgram(0, 0, false, -2).find_max(), + "test 1 for copy-constructor and get_viewgram"); + check_if_equal(proj_data2.get_viewgram(1, 1, false, -2).find_max(), proj_data.get_viewgram(1, 1, false, -2).find_max(), + "test 1 for copy-constructor and get_viewgram"); + check_if_equal(proj_data2.get_viewgram(1, 1, false, -2).get_timing_pos_num(), -2, + "test 2 for copy-constructor and get_viewgram"); + } + + // test fill with larger input + { + shared_ptr proj_data_info_sptr2(ProjDataInfo::ProjDataInfoCTI( + scanner_sptr, + /*span*/ 1, 8, /*views*/ 96, /*tang_pos*/ 64, /*arc_corrected*/ true, proj_data.get_tof_mash_factor())); + + // construct without filling + ProjDataInMemory proj_data2(exam_info_sptr, proj_data_info_sptr2, false); + proj_data2.fill(proj_data); + check_if_equal(proj_data2.get_viewgram(0, 0, false, -2).find_max(), proj_data.get_viewgram(0, 0, false, -2).find_max(), + "test 1 for constructor, fill and get_viewgram(0,0,-2)"); + check_if_equal(proj_data2.get_viewgram(1, 1, false, 2).find_max(), proj_data.get_viewgram(1, 1, false, 2).find_max(), + "test 1 for constructor, fill and get_viewgram(1,1,2)"); + } + + // test fill with smaller input + { + shared_ptr proj_data_info_sptr2(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span*/ 1, 20, /*views*/ 96, /*tang_pos*/ 64, + /*arc_corrected*/ true, 70)); + + // construct without filling + ProjDataInMemory proj_data2(exam_info_sptr, proj_data_info_sptr2, false); + // this should call error, so we'll catch it + try { + std::cout << "\nthis test should throw an error (which we will catch)\n"; + proj_data2.fill(proj_data); + check(false, "test fill with too small proj_data should have thrown"); + } catch (...) { + // ok + } + } +} + +END_NAMESPACE_STIR + +USING_NAMESPACE_STIR + +int +main() { + ProjDataInMemoryTests tests; + tests.run_tests(); + return tests.main_return_value(); +} diff --git a/src/test/test_proj_data_info.cxx b/src/test/test_proj_data_info.cxx index c2a0fce764..8afe8f52e5 100644 --- a/src/test/test_proj_data_info.cxx +++ b/src/test/test_proj_data_info.cxx @@ -53,37 +53,36 @@ using std::max; using std::size_t; #endif +//#define STIR_TOF_DEBUG 1 + START_NAMESPACE_STIR -static inline -int intabs(const int x) -{ return x>=0?x:-x; } +static inline int +intabs(const int x) { + return x >= 0 ? x : -x; +} // prints a michelogram to the screen #if 1 // TODO move somewhere else -void michelogram(const ProjDataInfoCylindrical& proj_data_info) -{ +void +michelogram(const ProjDataInfoCylindrical& proj_data_info) { cerr << '{'; - for (int ring1=0; ring1get_num_rings(); ++ring1) - { + for (int ring1 = 0; ring1 < proj_data_info.get_scanner_ptr()->get_num_rings(); ++ring1) { cerr << '{'; - for (int ring2=0; ring2get_num_rings(); ++ring2) - { - int segment_num=0; + for (int ring2 = 0; ring2 < proj_data_info.get_scanner_ptr()->get_num_rings(); ++ring2) { + int segment_num = 0; int ax_pos_num = 0; - if (proj_data_info.get_segment_axial_pos_num_for_ring_pair(segment_num, ax_pos_num, ring1, ring2) - == Succeeded::yes) + if (proj_data_info.get_segment_axial_pos_num_for_ring_pair(segment_num, ax_pos_num, ring1, ring2) == Succeeded::yes) cerr << '{' << setw(3) << segment_num << ',' << setw(2) << ax_pos_num << "}"; else cerr << "{} "; - if (ring2 != proj_data_info.get_scanner_ptr()->get_num_rings()-1) + if (ring2 != proj_data_info.get_scanner_ptr()->get_num_rings() - 1) cerr << ','; - } cerr << '}'; - if (ring1 != proj_data_info.get_scanner_ptr()->get_num_rings()-1) - cerr << ','; + if (ring1 != proj_data_info.get_scanner_ptr()->get_num_rings() - 1) + cerr << ','; cerr << endl; } cerr << '}' << endl; @@ -94,209 +93,216 @@ void michelogram(const ProjDataInfoCylindrical& proj_data_info) \ingroup test \brief Test class for ProjDataInfo */ -class ProjDataInfoTests: public RunTests -{ -protected: +class ProjDataInfoTests : public RunTests { +protected: void test_generic_proj_data_info(ProjDataInfo& proj_data_info); }; void -ProjDataInfoTests:: -test_generic_proj_data_info(ProjDataInfo& proj_data_info) -{ +ProjDataInfoTests::test_generic_proj_data_info(ProjDataInfo& proj_data_info) { + cerr << "\tTests on get_min/max_num\n"; + check_if_equal(proj_data_info.get_max_tangential_pos_num() - proj_data_info.get_min_tangential_pos_num() + 1, + proj_data_info.get_num_tangential_poss(), "basic check on min/max/num_tangential_pos_num"); + check(abs(proj_data_info.get_max_tangential_pos_num() + proj_data_info.get_min_tangential_pos_num()) <= 1, + "check on min/max_tangential_pos_num being (almost) centred"); + check_if_equal(proj_data_info.get_max_tof_pos_num() - proj_data_info.get_min_tof_pos_num() + 1, + proj_data_info.get_num_tof_poss(), "basic check on min/max/num_tof_pos_num"); + check_if_equal(proj_data_info.get_max_tof_pos_num() + proj_data_info.get_min_tof_pos_num(), 0, + "check on min/max_tof_pos_num being (almost) centred"); + check_if_equal(proj_data_info.get_max_view_num() - proj_data_info.get_min_view_num() + 1, proj_data_info.get_num_views(), + "basic check on min/max/num_view_num"); + check_if_equal(proj_data_info.get_max_segment_num() - proj_data_info.get_min_segment_num() + 1, + proj_data_info.get_num_segments(), "basic check on min/max/num_segment_num"); + // not strictly necessary in most of the code, but most likely required in some of it + check_if_equal(proj_data_info.get_max_segment_num() + proj_data_info.get_min_segment_num(), 0, + "check on min/max_segment_num being centred"); + check_if_equal(proj_data_info.get_max_axial_pos_num(0) - proj_data_info.get_min_axial_pos_num(0) + 1, + proj_data_info.get_num_axial_poss(0), "basic check on min/max/num_axial_pos_num"); + cerr << "\tTests on get_LOR/get_bin\n"; - int max_diff_segment_num=0; - int max_diff_view_num=0; - int max_diff_axial_pos_num=0; - int max_diff_tangential_pos_num=0; + int max_diff_segment_num = 0; + int max_diff_view_num = 0; + int max_diff_axial_pos_num = 0; + int max_diff_tangential_pos_num = 0; + int max_diff_timing_pos_num = 0; #ifdef STIR_OPENMP -#pragma omp parallel for schedule(dynamic) +# pragma omp parallel for schedule(dynamic) +#endif + for (int segment_num = proj_data_info.get_min_segment_num(); segment_num <= proj_data_info.get_max_segment_num(); + ++segment_num) { + for (int view_num = proj_data_info.get_min_view_num(); view_num <= proj_data_info.get_max_view_num(); view_num += 3) { + // loop over axial_positions. Avoid using first and last positions, as + // if there is axial compression, the central LOR of a bin might actually not + // fall within the scanner. In this case, the get_bin(get_LOR(org_bin)) code + // will return an out-of-range bin (i.e. value<0). + int axial_pos_num_margin = 0; + const ProjDataInfoCylindrical* const proj_data_info_cyl_ptr = + dynamic_cast(&proj_data_info); + if (proj_data_info_cyl_ptr != 0) { + axial_pos_num_margin = std::max(round(ceil(proj_data_info_cyl_ptr->get_average_ring_difference(segment_num) - + proj_data_info_cyl_ptr->get_min_ring_difference(segment_num))), + round(ceil(proj_data_info_cyl_ptr->get_max_ring_difference(segment_num) - + proj_data_info_cyl_ptr->get_average_ring_difference(segment_num)))); + } + for (int axial_pos_num = proj_data_info.get_min_axial_pos_num(segment_num) + axial_pos_num_margin; + axial_pos_num <= proj_data_info.get_max_axial_pos_num(segment_num) - axial_pos_num_margin; axial_pos_num += 3) { + for (int tangential_pos_num = proj_data_info.get_min_tangential_pos_num() + 1; + tangential_pos_num <= proj_data_info.get_max_tangential_pos_num() - 1; tangential_pos_num += 1) { + for (int timing_pos_num = proj_data_info.get_min_tof_pos_num(); timing_pos_num <= proj_data_info.get_max_tof_pos_num(); + timing_pos_num += std::max(1, (proj_data_info.get_max_tof_pos_num() - proj_data_info.get_min_tof_pos_num()) / + 2)) // take 3 or 1 steps, always going through 0 + { + const Bin org_bin(segment_num, view_num, axial_pos_num, tangential_pos_num, timing_pos_num, /* value*/ 1.f); + const double delta_time = proj_data_info.get_tof_delta_time(org_bin); + LORInAxialAndNoArcCorrSinogramCoordinates lor; + proj_data_info.get_LOR(lor, org_bin); + { + const Bin new_bin = proj_data_info.get_bin(lor, delta_time); +#if STIR_TOF_DEBUG > 1 + std::cerr << "T:" << org_bin.timing_pos_num() << ", swapped=" << lor.is_swapped() << ", z1=" << lor.z1() + << ", z2=" << lor.z2() << ", phi=" << lor.phi() << ", beta=" << lor.beta() << std::endl; #endif - for (int segment_num=proj_data_info.get_min_segment_num(); - segment_num<=proj_data_info.get_max_segment_num(); - ++segment_num) - { - for (int view_num=proj_data_info.get_min_view_num(); - view_num<=proj_data_info.get_max_view_num(); - view_num+=3) - { - // loop over axial_positions. Avoid using first and last positions, as - // if there is axial compression, the central LOR of a bin might actually not - // fall within the scanner. In this case, the get_bin(get_LOR(org_bin)) code - // will return an out-of-range bin (i.e. value<0). - int axial_pos_num_margin=0; - const ProjDataInfoCylindrical* const proj_data_info_cyl_ptr = - dynamic_cast(&proj_data_info); - if (proj_data_info_cyl_ptr!=0) - { - axial_pos_num_margin = - std::max( - round(ceil(proj_data_info_cyl_ptr->get_average_ring_difference(segment_num) - - proj_data_info_cyl_ptr->get_min_ring_difference(segment_num))), - round(ceil(proj_data_info_cyl_ptr->get_max_ring_difference(segment_num) - - proj_data_info_cyl_ptr->get_average_ring_difference(segment_num)))); - } - for (int axial_pos_num=proj_data_info.get_min_axial_pos_num(segment_num)+axial_pos_num_margin ; - axial_pos_num<=proj_data_info.get_max_axial_pos_num(segment_num)-axial_pos_num_margin; - axial_pos_num+=3) - { - for (int tangential_pos_num=proj_data_info.get_min_tangential_pos_num()+1; - tangential_pos_num<=proj_data_info.get_max_tangential_pos_num()-1; - tangential_pos_num+=1) - { - const Bin org_bin(segment_num,view_num,axial_pos_num,tangential_pos_num, /* value*/1); - LORInAxialAndNoArcCorrSinogramCoordinates lor; - proj_data_info.get_LOR(lor, org_bin); - { - const Bin new_bin = proj_data_info.get_bin(lor); #if 1 - const int diff_segment_num = - intabs(org_bin.segment_num() - new_bin.segment_num()); - const int diff_view_num = - intabs(org_bin.view_num() - new_bin.view_num()); - const int diff_axial_pos_num = - intabs(org_bin.axial_pos_num() - new_bin.axial_pos_num()); - const int diff_tangential_pos_num = - intabs(org_bin.tangential_pos_num() - new_bin.tangential_pos_num()); - if (new_bin.get_bin_value()>0) - { - if (diff_segment_num>max_diff_segment_num) - max_diff_segment_num=diff_segment_num; - if (diff_view_num>max_diff_view_num) - max_diff_view_num=diff_view_num; - if (diff_axial_pos_num>max_diff_axial_pos_num) - max_diff_axial_pos_num=diff_axial_pos_num; - if (diff_tangential_pos_num>max_diff_tangential_pos_num) - max_diff_tangential_pos_num=diff_tangential_pos_num; - } - if (!check(org_bin.get_bin_value() == new_bin.get_bin_value(), "round-trip get_LOR then get_bin: value") || - !check(diff_segment_num<=0, "round-trip get_LOR then get_bin: segment") || - !check(diff_view_num<=1, "round-trip get_LOR then get_bin: view") || - !check(diff_axial_pos_num<=1, "round-trip get_LOR then get_bin: axial_pos") || - !check(diff_tangential_pos_num<=1, "round-trip get_LOR then get_bin: tangential_pos")) + const int diff_segment_num = intabs(org_bin.segment_num() - new_bin.segment_num()); + const int diff_view_num = intabs(org_bin.view_num() - new_bin.view_num()); + const int diff_axial_pos_num = intabs(org_bin.axial_pos_num() - new_bin.axial_pos_num()); + const int diff_tangential_pos_num = intabs(org_bin.tangential_pos_num() - new_bin.tangential_pos_num()); + const int diff_timing_pos_num = intabs(org_bin.timing_pos_num() - new_bin.timing_pos_num()); + if (new_bin.get_bin_value() > 0) { + if (diff_segment_num > max_diff_segment_num) + max_diff_segment_num = diff_segment_num; + if (diff_view_num > max_diff_view_num) + max_diff_view_num = diff_view_num; + if (diff_axial_pos_num > max_diff_axial_pos_num) + max_diff_axial_pos_num = diff_axial_pos_num; + if (diff_tangential_pos_num > max_diff_tangential_pos_num) + max_diff_tangential_pos_num = diff_tangential_pos_num; + if (diff_timing_pos_num > max_diff_timing_pos_num) + max_diff_timing_pos_num = diff_timing_pos_num; + } + if (!check(org_bin.get_bin_value() == new_bin.get_bin_value(), "round-trip get_LOR then get_bin: value") || + !check(diff_segment_num <= 0, "round-trip get_LOR then get_bin: segment") || + !check(diff_view_num <= 1, "round-trip get_LOR then get_bin: view") || + !check(diff_axial_pos_num <= 1, "round-trip get_LOR then get_bin: axial_pos") || + !check(diff_tangential_pos_num <= 1, "round-trip get_LOR then get_bin: tangential_pos") || + !check(diff_timing_pos_num == 0, "round-trip get_LOR then get_bin: timing_pos")) #else - if (!check(org_bin == new_bin, "round-trip get_LOR then get_bin")) + if (!check(org_bin == new_bin, "round-trip get_LOR then get_bin")) +#endif + { + cerr << "\tProblem at segment = " << org_bin.segment_num() << ", axial pos " << org_bin.axial_pos_num() + << ", view = " << org_bin.view_num() << ", tangential_pos = " << org_bin.tangential_pos_num() + << ", timing_pos = " << org_bin.timing_pos_num() << "\n"; + if (new_bin.get_bin_value() > 0) + cerr << "\tround-trip to segment = " << new_bin.segment_num() << ", axial pos " << new_bin.axial_pos_num() + << ", view = " << new_bin.view_num() << ", tangential_pos = " << new_bin.tangential_pos_num() + << ", timing_pos = " << new_bin.timing_pos_num() << '\n'; + } + } + // repeat test but with different type of LOR + { + LORAs2Points lor_as_points; + lor.get_intersections_with_cylinder(lor_as_points, lor.radius()); +#if STIR_TOF_DEBUG > 1 + std::cerr << " z1=" << lor_as_points.p1().z() << ", y1=" << lor_as_points.p1().y() + << ", x1=" << lor_as_points.p1().x() << "\n z2=" << lor_as_points.p2().z() + << ", y2=" << lor_as_points.p2().y() << ", x2=" << lor_as_points.p2().x() << std::endl; #endif - { - cerr << "\tProblem at segment = " << org_bin.segment_num() - << ", axial pos " << org_bin.axial_pos_num() - << ", view = " << org_bin.view_num() - << ", tangential_pos_num = " << org_bin.tangential_pos_num() << "\n"; - if (new_bin.get_bin_value()>0) - cerr << "\tround-trip to segment = " << new_bin.segment_num() - << ", axial pos " << new_bin.axial_pos_num() - << ", view = " << new_bin.view_num() - << ", tangential_pos_num = " << new_bin.tangential_pos_num() - <<'\n'; - } - } - // repeat test but with different type of LOR - { - LORAs2Points lor_as_points; - lor.get_intersections_with_cylinder(lor_as_points, lor.radius()); - const Bin new_bin = proj_data_info.get_bin(lor_as_points); + const Bin new_bin = proj_data_info.get_bin(lor_as_points, proj_data_info.get_tof_delta_time(org_bin)); #if 1 - const int diff_segment_num = - intabs(org_bin.segment_num() - new_bin.segment_num()); - const int diff_view_num = - intabs(org_bin.view_num() - new_bin.view_num()); - const int diff_axial_pos_num = - intabs(org_bin.axial_pos_num() - new_bin.axial_pos_num()); - const int diff_tangential_pos_num = - intabs(org_bin.tangential_pos_num() - new_bin.tangential_pos_num()); - if (new_bin.get_bin_value()>0) - { - if (diff_segment_num>max_diff_segment_num) - max_diff_segment_num=diff_segment_num; - if (diff_view_num>max_diff_view_num) - max_diff_view_num=diff_view_num; - if (diff_axial_pos_num>max_diff_axial_pos_num) - max_diff_axial_pos_num=diff_axial_pos_num; - if (diff_tangential_pos_num>max_diff_tangential_pos_num) - max_diff_tangential_pos_num=diff_tangential_pos_num; - } - if (!check(org_bin.get_bin_value() == new_bin.get_bin_value(), "round-trip get_LOR then get_bin (LORAs2Points): value") || - !check(diff_segment_num<=0, "round-trip get_LOR then get_bin (LORAs2Points): segment") || - !check(diff_view_num<=1, "round-trip get_LOR then get_bin (LORAs2Points): view") || - !check(diff_axial_pos_num<=1, "round-trip get_LOR then get_bin (LORAs2Points): axial_pos") || - !check(diff_tangential_pos_num<=1, "round-trip get_LOR then get_bin (LORAs2Points): tangential_pos")) - + const int diff_segment_num = intabs(org_bin.segment_num() - new_bin.segment_num()); + const int diff_view_num = intabs(org_bin.view_num() - new_bin.view_num()); + const int diff_axial_pos_num = intabs(org_bin.axial_pos_num() - new_bin.axial_pos_num()); + const int diff_tangential_pos_num = intabs(org_bin.tangential_pos_num() - new_bin.tangential_pos_num()); + const int diff_timing_pos_num = intabs(org_bin.timing_pos_num() - new_bin.timing_pos_num()); + if (new_bin.get_bin_value() > 0) { + if (diff_segment_num > max_diff_segment_num) + max_diff_segment_num = diff_segment_num; + if (diff_view_num > max_diff_view_num) + max_diff_view_num = diff_view_num; + if (diff_axial_pos_num > max_diff_axial_pos_num) + max_diff_axial_pos_num = diff_axial_pos_num; + if (diff_tangential_pos_num > max_diff_tangential_pos_num) + max_diff_tangential_pos_num = diff_tangential_pos_num; + if (diff_timing_pos_num > max_diff_timing_pos_num) + max_diff_timing_pos_num = diff_timing_pos_num; + } + if (!check(org_bin.get_bin_value() == new_bin.get_bin_value(), + "round-trip get_LOR then get_bin (LORAs2Points): value") || + !check(diff_segment_num <= 0, "round-trip get_LOR then get_bin (LORAs2Points): segment") || + !check(diff_view_num <= 1, "round-trip get_LOR then get_bin (LORAs2Points): view") || + !check(diff_axial_pos_num <= 1, "round-trip get_LOR then get_bin (LORAs2Points): axial_pos") || + !check(diff_tangential_pos_num <= 1, "round-trip get_LOR then get_bin (LORAs2Points): tangential_pos") || + !check(diff_timing_pos_num == 0, "round-trip get_LOR then get_bin (LORAs2Points): timing_pos")) + #else - if (!check(org_bin == new_bin, "round-trip get_LOR then get_bin")) + if (!check(org_bin == new_bin, "round-trip get_LOR then get_bin")) #endif - { - cerr << "\tProblem at segment = " << org_bin.segment_num() - << ", axial pos " << org_bin.axial_pos_num() - << ", view = " << org_bin.view_num() - << ", tangential_pos_num = " << org_bin.tangential_pos_num() << "\n"; - if (new_bin.get_bin_value()>0) - cerr << "\tround-trip to segment = " << new_bin.segment_num() - << ", axial pos " << new_bin.axial_pos_num() - << ", view = " << new_bin.view_num() - << ", tangential_pos_num = " << new_bin.tangential_pos_num() - <<'\n'; - } - } - } - } - } + { + cerr << "\tProblem at segment = " << org_bin.segment_num() << ", axial pos " << org_bin.axial_pos_num() + << ", view = " << org_bin.view_num() << ", tangential_pos_num = " << org_bin.tangential_pos_num() + << ", timing_pos = " << org_bin.timing_pos_num() << "\n"; + if (new_bin.get_bin_value() > 0) + cerr << "\tround-trip to segment = " << new_bin.segment_num() << ", axial pos " << new_bin.axial_pos_num() + << ", view = " << new_bin.view_num() << ", tangential_pos_num = " << new_bin.tangential_pos_num() + << ", timing_pos = " << new_bin.timing_pos_num() << '\n'; + } + } + } + } } - cerr << "Max Deviation: segment = " << max_diff_segment_num - << ", axial pos " << max_diff_axial_pos_num - << ", view = " << max_diff_view_num - << ", tangential_pos_num = " << max_diff_tangential_pos_num << "\n"; - - // test on reduce_segment_range and operator>= - { - shared_ptr smaller(proj_data_info.clone()); - check(proj_data_info >= *smaller, "check on operator>= and equal objects"); - smaller->set_min_tangential_pos_num(0); - check(proj_data_info >= *smaller, "check on tangential_pos and operator>="); - smaller->set_min_axial_pos_num(4, 0); - check(proj_data_info >= *smaller, "check on axial_pos and operator>="); - - smaller->reduce_segment_range(0,0); - check(proj_data_info >= *smaller, "check on reduce_segment_range and operator>="); - // make one range larger, so should now fail - smaller->set_min_tangential_pos_num(proj_data_info.get_min_tangential_pos_num() - 4); - check(!(proj_data_info >= *smaller), "check on mixed case with tangential_pos_num and operator>="); - // reset and do the same for axial pos - smaller->set_min_tangential_pos_num(proj_data_info.get_min_tangential_pos_num() + 4); - check(proj_data_info >= *smaller, "check on reduced segments and tangential_pos and operator>="); - smaller->set_max_axial_pos_num(proj_data_info.get_max_axial_pos_num(0)+4, 0); - check(!(proj_data_info >= *smaller), "check on mixed case with axial_pos_num and operator>="); } -} + } + cerr << "Max Deviation: segment = " << max_diff_segment_num << ", axial pos " << max_diff_axial_pos_num + << ", view = " << max_diff_view_num << ", tangential_pos_num = " << max_diff_tangential_pos_num + << ", timing_pos_num = " << max_diff_timing_pos_num << "\n"; + // test on reduce_segment_range and operator>= + { + shared_ptr smaller(proj_data_info.clone()); + check(proj_data_info >= *smaller, "check on operator>= and equal objects"); + smaller->set_min_tangential_pos_num(0); + check(proj_data_info >= *smaller, "check on tangential_pos and operator>="); + smaller->set_min_axial_pos_num(4, 0); + check(proj_data_info >= *smaller, "check on axial_pos and operator>="); + // if (proj_data_info.is_tof_data()) + // { + // smaller->set_min_timing_pos_num(0); + // check(proj_data_info >= *smaller, "check on timing_pos and operator>="); + // } + smaller->reduce_segment_range(0, 0); + check(proj_data_info >= *smaller, "check on reduce_segment_range and operator>="); + // make one range larger, so should now fail + smaller->set_min_tangential_pos_num(proj_data_info.get_min_tangential_pos_num() - 4); + check(!(proj_data_info >= *smaller), "check on mixed case with tangential_pos_num and operator>="); + // reset and do the same for axial pos + smaller->set_min_tangential_pos_num(proj_data_info.get_min_tangential_pos_num() + 4); + check(proj_data_info >= *smaller, "check on reduced segments and tangential_pos and operator>="); + smaller->set_max_axial_pos_num(proj_data_info.get_max_axial_pos_num(0) + 4, 0); + check(!(proj_data_info >= *smaller), "check on mixed case with axial_pos_num and operator>="); + } +} /*! \ingroup test \brief Test class for ProjDataInfoCylindrical */ -class ProjDataInfoCylindricalTests: public ProjDataInfoTests -{ -protected: +class ProjDataInfoCylindricalTests : public ProjDataInfoTests { +protected: void test_cylindrical_proj_data_info(ProjDataInfoCylindrical& proj_data_info); }; - void -ProjDataInfoCylindricalTests:: -test_cylindrical_proj_data_info(ProjDataInfoCylindrical& proj_data_info) -{ +ProjDataInfoCylindricalTests::test_cylindrical_proj_data_info(ProjDataInfoCylindrical& proj_data_info) { cerr << "\tTesting consistency between different implementations of geometric info\n"; { - const Bin bin(proj_data_info.get_max_segment_num(), - 1, - proj_data_info.get_max_axial_pos_num(proj_data_info.get_max_segment_num())/2, - 1); - check_if_equal(proj_data_info.get_sampling_in_m(bin), - proj_data_info.ProjDataInfo::get_sampling_in_m(bin), - "test consistency get_sampling_in_m"); - check_if_equal(proj_data_info.get_sampling_in_t(bin), - proj_data_info.ProjDataInfo::get_sampling_in_t(bin), - "test consistency get_sampling_in_t"); + const Bin bin(proj_data_info.get_max_segment_num(), 1, + proj_data_info.get_max_axial_pos_num(proj_data_info.get_max_segment_num()) / 2, 1); + check_if_equal(proj_data_info.get_sampling_in_m(bin), proj_data_info.ProjDataInfo::get_sampling_in_m(bin), + "test consistency get_sampling_in_m"); + check_if_equal(proj_data_info.get_sampling_in_t(bin), proj_data_info.ProjDataInfo::get_sampling_in_t(bin), + "test consistency get_sampling_in_t"); #if 0 // ProjDataInfo has no default implementation for get_tantheta // I just leave the code here to make this explicit @@ -304,125 +310,87 @@ test_cylindrical_proj_data_info(ProjDataInfoCylindrical& proj_data_info) proj_data_info.ProjDataInfo::get_tantheta(bin), "test consistency get_tantheta"); #endif - check_if_equal(proj_data_info.get_costheta(bin), - proj_data_info.ProjDataInfo::get_costheta(bin), - "test consistency get_costheta"); + check_if_equal(proj_data_info.get_costheta(bin), proj_data_info.ProjDataInfo::get_costheta(bin), + "test consistency get_costheta"); - check_if_equal(proj_data_info.get_costheta(bin), - cos(atan(proj_data_info.get_tantheta(bin))), - "cross check get_costheta and get_tantheta"); + check_if_equal(proj_data_info.get_costheta(bin), cos(atan(proj_data_info.get_tantheta(bin))), + "cross check get_costheta and get_tantheta"); // try the same with a non-standard ring spacing const float old_ring_spacing = proj_data_info.get_ring_spacing(); proj_data_info.set_ring_spacing(2.1F); - check_if_equal(proj_data_info.get_sampling_in_m(bin), - proj_data_info.ProjDataInfo::get_sampling_in_m(bin), - "test consistency get_sampling_in_m"); - check_if_equal(proj_data_info.get_sampling_in_t(bin), - proj_data_info.ProjDataInfo::get_sampling_in_t(bin), - "test consistency get_sampling_in_t"); + check_if_equal(proj_data_info.get_sampling_in_m(bin), proj_data_info.ProjDataInfo::get_sampling_in_m(bin), + "test consistency get_sampling_in_m"); + check_if_equal(proj_data_info.get_sampling_in_t(bin), proj_data_info.ProjDataInfo::get_sampling_in_t(bin), + "test consistency get_sampling_in_t"); #if 0 check_if_equal(proj_data_info.get_tantheta(bin), proj_data_info.ProjDataInfo::get_tantheta(bin), "test consistency get_tantheta"); #endif - check_if_equal(proj_data_info.get_costheta(bin), - proj_data_info.ProjDataInfo::get_costheta(bin), - "test consistency get_costheta"); + check_if_equal(proj_data_info.get_costheta(bin), proj_data_info.ProjDataInfo::get_costheta(bin), + "test consistency get_costheta"); - check_if_equal(proj_data_info.get_costheta(bin), - cos(atan(proj_data_info.get_tantheta(bin))), - "cross check get_costheta and get_tantheta"); + check_if_equal(proj_data_info.get_costheta(bin), cos(atan(proj_data_info.get_tantheta(bin))), + "cross check get_costheta and get_tantheta"); // set back to usual value proj_data_info.set_ring_spacing(old_ring_spacing); } - if (proj_data_info.get_max_ring_difference(0) == proj_data_info.get_min_ring_difference(0) - && proj_data_info.get_max_ring_difference(1) == proj_data_info.get_min_ring_difference(1) - && proj_data_info.get_max_ring_difference(2) == proj_data_info.get_min_ring_difference(2) - ) - { - // these tests work only without axial compression - cerr << "\tTest ring pair to segment,ax_pos (span 1)\n"; + if (proj_data_info.get_max_ring_difference(0) == proj_data_info.get_min_ring_difference(0) && + proj_data_info.get_max_ring_difference(1) == proj_data_info.get_min_ring_difference(1) && + proj_data_info.get_max_ring_difference(2) == proj_data_info.get_min_ring_difference(2)) { + // these tests work only without axial compression + cerr << "\tTest ring pair to segment,ax_pos (span 1)\n"; #ifdef STIR_OPENMP -#pragma omp parallel for schedule(dynamic) +# pragma omp parallel for schedule(dynamic) #endif - for (int ring1=0; ring1get_num_rings(); ++ring1) - for (int ring2=0; ring2get_num_rings(); ++ring2) - { - int segment_num = 0, axial_pos_num = 0; - check(proj_data_info. - get_segment_axial_pos_num_for_ring_pair(segment_num, - axial_pos_num, - ring1, - ring2) == - Succeeded::yes, - "test if segment,ax_pos_num found for a ring pair"); - check_if_equal(segment_num, ring2-ring1, - "test if segment_num is equal to ring difference\n"); - check_if_equal(axial_pos_num, min(ring2,ring1), - "test if segment_num is equal to ring difference\n"); - - int check_ring1 = 0, check_ring2 = 0; - proj_data_info. - get_ring_pair_for_segment_axial_pos_num(check_ring1, - check_ring2, - segment_num, - axial_pos_num); - check_if_equal(ring1, check_ring1, - "test ring1 equal after going to segment/ax_pos and returning\n"); - check_if_equal(ring2, check_ring2, - "test ring2 equal after going to segment/ax_pos and returning\n"); - - const ProjDataInfoCylindrical::RingNumPairs& ring_pairs = - proj_data_info. - get_all_ring_pairs_for_segment_axial_pos_num(segment_num, - axial_pos_num); - - check_if_equal(ring_pairs.size(), static_cast(1), - "test total number of ring-pairs for 1 segment/ax_pos should be 1 for span=1\n"); - check_if_equal(ring1, ring_pairs[0].first, - "test ring1 equal after going to segment/ax_pos and returning (version with all ring_pairs)\n"); - check_if_equal(ring2, ring_pairs[0].second, - "test ring2 equal after going to segment/ax_pos and returning (version with all ring_pairs)\n"); - } + for (int ring1 = 0; ring1 < proj_data_info.get_scanner_ptr()->get_num_rings(); ++ring1) + for (int ring2 = 0; ring2 < proj_data_info.get_scanner_ptr()->get_num_rings(); ++ring2) { + int segment_num = 0, axial_pos_num = 0; + check(proj_data_info.get_segment_axial_pos_num_for_ring_pair(segment_num, axial_pos_num, ring1, ring2) == Succeeded::yes, + "test if segment,ax_pos_num found for a ring pair"); + check_if_equal(segment_num, ring2 - ring1, "test if segment_num is equal to ring difference\n"); + check_if_equal(axial_pos_num, min(ring2, ring1), "test if segment_num is equal to ring difference\n"); + + int check_ring1 = 0, check_ring2 = 0; + proj_data_info.get_ring_pair_for_segment_axial_pos_num(check_ring1, check_ring2, segment_num, axial_pos_num); + check_if_equal(ring1, check_ring1, "test ring1 equal after going to segment/ax_pos and returning\n"); + check_if_equal(ring2, check_ring2, "test ring2 equal after going to segment/ax_pos and returning\n"); + + const ProjDataInfoCylindrical::RingNumPairs& ring_pairs = + proj_data_info.get_all_ring_pairs_for_segment_axial_pos_num(segment_num, axial_pos_num); + + check_if_equal(ring_pairs.size(), static_cast(1), + "test total number of ring-pairs for 1 segment/ax_pos should be 1 for span=1\n"); + check_if_equal(ring1, ring_pairs[0].first, + "test ring1 equal after going to segment/ax_pos and returning (version with all ring_pairs)\n"); + check_if_equal(ring2, ring_pairs[0].second, + "test ring2 equal after going to segment/ax_pos and returning (version with all ring_pairs)\n"); + } } cerr << "\tTest ring pair to segment,ax_pos and vice versa (for any axial compression)\n"; { #ifdef STIR_OPENMP -#pragma omp parallel for schedule(dynamic) +# pragma omp parallel for schedule(dynamic) #endif - for (int segment_num=proj_data_info.get_min_segment_num(); - segment_num<=proj_data_info.get_max_segment_num(); - ++segment_num) - for (int axial_pos_num=proj_data_info.get_min_axial_pos_num(segment_num); - axial_pos_num<=proj_data_info.get_max_axial_pos_num(segment_num); - ++axial_pos_num) - { - const ProjDataInfoCylindrical::RingNumPairs& ring_pairs = - proj_data_info. - get_all_ring_pairs_for_segment_axial_pos_num(segment_num, - axial_pos_num); - for (ProjDataInfoCylindrical::RingNumPairs::const_iterator iter = ring_pairs.begin(); - iter != ring_pairs.end(); - ++iter) - { - int check_segment_num = 0, check_axial_pos_num = 0; - check(proj_data_info. - get_segment_axial_pos_num_for_ring_pair(check_segment_num, - check_axial_pos_num, - iter->first, - iter->second) == - Succeeded::yes, - "test if segment,ax_pos_num found for a ring pair"); - check_if_equal(check_segment_num, segment_num, - "test if segment_num is consistent\n"); - check_if_equal(check_axial_pos_num, axial_pos_num, - "test if axial_pos_num is consistent\n"); - } - } + for (int segment_num = proj_data_info.get_min_segment_num(); segment_num <= proj_data_info.get_max_segment_num(); + ++segment_num) + for (int axial_pos_num = proj_data_info.get_min_axial_pos_num(segment_num); + axial_pos_num <= proj_data_info.get_max_axial_pos_num(segment_num); ++axial_pos_num) { + const ProjDataInfoCylindrical::RingNumPairs& ring_pairs = + proj_data_info.get_all_ring_pairs_for_segment_axial_pos_num(segment_num, axial_pos_num); + for (ProjDataInfoCylindrical::RingNumPairs::const_iterator iter = ring_pairs.begin(); iter != ring_pairs.end(); ++iter) { + int check_segment_num = 0, check_axial_pos_num = 0; + check(proj_data_info.get_segment_axial_pos_num_for_ring_pair(check_segment_num, check_axial_pos_num, iter->first, + iter->second) == Succeeded::yes, + "test if segment,ax_pos_num found for a ring pair"); + check_if_equal(check_segment_num, segment_num, "test if segment_num is consistent\n"); + check_if_equal(check_axial_pos_num, axial_pos_num, "test if axial_pos_num is consistent\n"); + } + } } test_generic_proj_data_info(proj_data_info); @@ -433,104 +401,96 @@ test_cylindrical_proj_data_info(ProjDataInfoCylindrical& proj_data_info) \brief Test class for ProjDataInfoCylindricalArcCorr */ -class ProjDataInfoCylindricalArcCorrTests: public ProjDataInfoCylindricalTests -{ -public: +class ProjDataInfoCylindricalArcCorrTests : public ProjDataInfoCylindricalTests { +public: void run_tests(); }; - void ProjDataInfoCylindricalArcCorrTests::run_tests() -{ +{ cerr << "-------- Testing ProjDataInfoCylindricalArcCorr --------\n"; { // Test on the empty constructor - + ProjDataInfoCylindricalArcCorr ob1; - + // Test on set.* & get.* + constructor const float test_tangential_sampling = 1.5; - //const float test_azimuthal_angle_sampling = 10.1; - + // const float test_azimuthal_angle_sampling = 10.1; + ob1.set_tangential_sampling(test_tangential_sampling); // Set_azimuthal_angle_sampling // ob1.set_azimuthal_angle_sampling(test_azimuthal_angle_sampling); - - - check_if_equal( ob1.get_tangential_sampling(), test_tangential_sampling,"test on tangential_sampling"); - //check_if_zero( ob1.get_azimuthal_angle_sampling() - test_azimuthal_angle_sampling, " test on azimuthal_angle_sampling"); - + + check_if_equal(ob1.get_tangential_sampling(), test_tangential_sampling, "test on tangential_sampling"); + // check_if_zero( ob1.get_azimuthal_angle_sampling() - test_azimuthal_angle_sampling, " test on azimuthal_angle_sampling"); } { shared_ptr scanner_ptr(new Scanner(Scanner::E953)); - - VectorWithOffset num_axial_pos_per_segment(-1,1); - VectorWithOffset min_ring_diff(-1,1); - VectorWithOffset max_ring_diff(-1,1); + + VectorWithOffset num_axial_pos_per_segment(-1, 1); + VectorWithOffset min_ring_diff(-1, 1); + VectorWithOffset max_ring_diff(-1, 1); // simulate span=3 for segment 0, span=1 for segment 2 - num_axial_pos_per_segment[-1]=14; - num_axial_pos_per_segment[0]=31; - num_axial_pos_per_segment[1]=14; + num_axial_pos_per_segment[-1] = 14; + num_axial_pos_per_segment[0] = 31; + num_axial_pos_per_segment[1] = 14; // KT 28/11/2001 corrected typo (bug): min_ring_diff[-1] was initialised twice, and max_ring_diff[-1] wasn't min_ring_diff[-1] = max_ring_diff[-1] = -2; - min_ring_diff[ 0] = -1; max_ring_diff[ 0] = 1; + min_ring_diff[0] = -1; + max_ring_diff[0] = 1; min_ring_diff[+1] = max_ring_diff[+1] = +2; const int num_views = 96; const int num_tangential_poss = 128; - + const float bin_size = 1.2F; - - - //Test on the constructor - ProjDataInfoCylindricalArcCorr - ob2(scanner_ptr, bin_size, - num_axial_pos_per_segment, min_ring_diff, max_ring_diff, - num_views,num_tangential_poss); - - check_if_equal( ob2.get_tangential_sampling(), bin_size,"test on tangential_sampling"); - check_if_equal( ob2.get_azimuthal_angle_sampling() , _PI/num_views, " test on azimuthal_angle_sampling"); - check_if_equal( ob2.get_axial_sampling(1), scanner_ptr->get_ring_spacing(), "test on axial_sampling"); - check_if_equal( ob2.get_axial_sampling(0), scanner_ptr->get_ring_spacing()/2, "test on axial_sampling for segment0"); - + + // Test on the constructor + ProjDataInfoCylindricalArcCorr ob2(scanner_ptr, bin_size, num_axial_pos_per_segment, min_ring_diff, max_ring_diff, num_views, + num_tangential_poss); + + check_if_equal(ob2.get_tangential_sampling(), bin_size, "test on tangential_sampling"); + check_if_equal(ob2.get_azimuthal_angle_sampling(), _PI / num_views, " test on azimuthal_angle_sampling"); + check_if_equal(ob2.get_axial_sampling(1), scanner_ptr->get_ring_spacing(), "test on axial_sampling"); + check_if_equal(ob2.get_axial_sampling(0), scanner_ptr->get_ring_spacing() / 2, "test on axial_sampling for segment0"); + { // segment 0 - Bin bin(0,10,10,20); + Bin bin(0, 10, 10, 20); float theta = ob2.get_tantheta(bin); - float phi = ob2.get_phi(bin); + float phi = ob2.get_phi(bin); // Get t float t = ob2.get_t(bin); //! Get s float s = ob2.get_s(bin); - - check_if_equal( theta, 0.F,"test on get_tantheta, seg 0"); - check_if_equal( phi, 10*ob2.get_azimuthal_angle_sampling(), " get_phi , seg 0"); + + check_if_equal(theta, 0.F, "test on get_tantheta, seg 0"); + check_if_equal(phi, 10 * ob2.get_azimuthal_angle_sampling(), " get_phi , seg 0"); // KT 25/10/2000 adjust to new convention - const float ax_pos_origin = - (ob2.get_min_axial_pos_num(0) + ob2.get_max_axial_pos_num(0))/2.F; - check_if_equal( t, (10-ax_pos_origin)*ob2.get_axial_sampling(0) , "get_t, seg 0"); - check_if_equal( s, 20*ob2.get_tangential_sampling() , "get_s, seg 0"); + const float ax_pos_origin = (ob2.get_min_axial_pos_num(0) + ob2.get_max_axial_pos_num(0)) / 2.F; + check_if_equal(t, (10 - ax_pos_origin) * ob2.get_axial_sampling(0), "get_t, seg 0"); + check_if_equal(s, 20 * ob2.get_tangential_sampling(), "get_s, seg 0"); } { // Segment 1 - Bin bin (1,10,10,20); + Bin bin(1, 10, 10, 20); float theta = ob2.get_tantheta(bin); - float phi = ob2.get_phi(bin); + float phi = ob2.get_phi(bin); // Get t float t = ob2.get_t(bin); // Get s float s = ob2.get_s(bin); - - float thetatest = 2*ob2.get_axial_sampling(1)/(2*sqrt(square(scanner_ptr->get_effective_ring_radius())-square(s))); - - check_if_equal( theta, thetatest,"test on get_tantheta, seg 1"); - check_if_equal( phi, 10*ob2.get_azimuthal_angle_sampling(), " get_phi , seg 1"); + + float thetatest = 2 * ob2.get_axial_sampling(1) / (2 * sqrt(square(scanner_ptr->get_effective_ring_radius()) - square(s))); + + check_if_equal(theta, thetatest, "test on get_tantheta, seg 1"); + check_if_equal(phi, 10 * ob2.get_azimuthal_angle_sampling(), " get_phi , seg 1"); // KT 25/10/2000 adjust to new convention - const float ax_pos_origin = - (ob2.get_min_axial_pos_num(1) + ob2.get_max_axial_pos_num(1))/2.F; - check_if_equal( t, (10-ax_pos_origin)/sqrt(1+square(thetatest))*ob2.get_axial_sampling(1) , "get_t, seg 1"); - check_if_equal( s, 20*ob2.get_tangential_sampling() , "get_s, seg 1"); + const float ax_pos_origin = (ob2.get_min_axial_pos_num(1) + ob2.get_max_axial_pos_num(1)) / 2.F; + check_if_equal(t, (10 - ax_pos_origin) / sqrt(1 + square(thetatest)) * ob2.get_axial_sampling(1), "get_t, seg 1"); + check_if_equal(s, 20 * ob2.get_tangential_sampling(), "get_s, seg 1"); } #if 0 @@ -563,417 +523,373 @@ ProjDataInfoCylindricalArcCorrTests::run_tests() } #endif - - shared_ptr scanner_ptr(new Scanner(Scanner::E953)); + shared_ptr scanner_ptr(new Scanner(Scanner::E953)); cerr << "Tests with proj_data_info without mashing and axial compression\n\n"; - // Note: test without axial compression requires that all ring differences + // Note: test without axial compression requires that all ring differences // are in some segment, so use maximum ring difference shared_ptr proj_data_info_ptr( - ProjDataInfo::construct_proj_data_info(scanner_ptr, - /*span*/1, scanner_ptr->get_num_rings()-1, - /*views*/ scanner_ptr->get_num_detectors_per_ring()/2, - /*tang_pos*/64, - /*arc_corrected*/ true)); - test_cylindrical_proj_data_info(dynamic_cast(*proj_data_info_ptr)); + ProjDataInfo::construct_proj_data_info(scanner_ptr, + /*span*/ 1, scanner_ptr->get_num_rings() - 1, + /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2, + /*tang_pos*/ 64, + /*arc_corrected*/ true)); + test_cylindrical_proj_data_info(dynamic_cast(*proj_data_info_ptr)); cerr << "\nTests with proj_data_info with mashing and axial compression (span 5)\n\n"; - proj_data_info_ptr = - ProjDataInfo::construct_proj_data_info(scanner_ptr, - /*span*/5, scanner_ptr->get_num_rings()-1, - /*views*/ scanner_ptr->get_num_detectors_per_ring()/2/8, - /*tang_pos*/64, - /*arc_corrected*/ true); - test_cylindrical_proj_data_info(dynamic_cast(*proj_data_info_ptr)); + proj_data_info_ptr = ProjDataInfo::construct_proj_data_info(scanner_ptr, + /*span*/ 5, scanner_ptr->get_num_rings() - 1, + /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2 / 8, + /*tang_pos*/ 64, + /*arc_corrected*/ true); + test_cylindrical_proj_data_info(dynamic_cast(*proj_data_info_ptr)); cerr << "\nTests with proj_data_info with mashing and axial compression (span 4)\n\n"; - proj_data_info_ptr = - ProjDataInfo::construct_proj_data_info(scanner_ptr, - /*span*/4, scanner_ptr->get_num_rings() - 1, - /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2 / 8, - /*tang_pos*/64, - /*arc_corrected*/ true); + proj_data_info_ptr = ProjDataInfo::construct_proj_data_info(scanner_ptr, + /*span*/ 4, scanner_ptr->get_num_rings() - 1, + /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2 / 8, + /*tang_pos*/ 64, + /*arc_corrected*/ true); #if 0 // disabled to get noninteractive test michelogram(dynamic_cast(*proj_data_info_ptr)); cerr << endl; #endif - test_cylindrical_proj_data_info(dynamic_cast(*proj_data_info_ptr)); + test_cylindrical_proj_data_info(dynamic_cast(*proj_data_info_ptr)); } - /*! \ingroup test \brief Test class for ProjDataInfoCylindricalNoArcCorr */ -class ProjDataInfoCylindricalNoArcCorrTests: public ProjDataInfoCylindricalTests -{ -public: +class ProjDataInfoCylindricalNoArcCorrTests : public ProjDataInfoCylindricalTests { +public: void run_tests(); + private: void test_proj_data_info(ProjDataInfoCylindricalNoArcCorr& proj_data_info); }; - void -ProjDataInfoCylindricalNoArcCorrTests:: -run_tests() -{ +ProjDataInfoCylindricalNoArcCorrTests::run_tests() { cerr << "\n-------- Testing ProjDataInfoCylindricalNoArcCorr --------\n"; shared_ptr scanner_ptr(new Scanner(Scanner::E953)); cerr << "Tests with proj_data_info without mashing and axial compression\n\n"; - // Note: test without axial compression requires that all ring differences + // Note: test without axial compression requires that all ring differences // are in some segment, so use maximum ring difference shared_ptr proj_data_info_ptr( - ProjDataInfo::construct_proj_data_info(scanner_ptr, - /*span*/1, scanner_ptr->get_num_rings()-1, - /*views*/ scanner_ptr->get_num_detectors_per_ring()/2, - /*tang_pos*/64, - /*arc_corrected*/ false)); - test_proj_data_info(dynamic_cast(*proj_data_info_ptr)); + ProjDataInfo::construct_proj_data_info(scanner_ptr, + /*span*/ 1, scanner_ptr->get_num_rings() - 1, + /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2, + /*tang_pos*/ 64, + /*arc_corrected*/ false)); +#ifndef STIR_TOF_DEBUG // disable these for speed of testing + test_proj_data_info(dynamic_cast(*proj_data_info_ptr)); cerr << "\nTests with proj_data_info with mashing and axial compression (span 5)\n\n"; - proj_data_info_ptr = - ProjDataInfo::construct_proj_data_info(scanner_ptr, - /*span*/5, scanner_ptr->get_num_rings()-1, - /*views*/ scanner_ptr->get_num_detectors_per_ring()/2/8, - /*tang_pos*/64, - /*arc_corrected*/ false); - test_proj_data_info(dynamic_cast(*proj_data_info_ptr)); + proj_data_info_ptr = ProjDataInfo::construct_proj_data_info(scanner_ptr, + /*span*/ 5, scanner_ptr->get_num_rings() - 1, + /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2 / 8, + /*tang_pos*/ 64, + /*arc_corrected*/ false); + test_proj_data_info(dynamic_cast(*proj_data_info_ptr)); cerr << "\nTests with proj_data_info with mashing and axial compression (span 2)\n\n"; - proj_data_info_ptr = - ProjDataInfo::construct_proj_data_info(scanner_ptr, - /*span*/2, scanner_ptr->get_num_rings() - 7, - /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2 / 8, - /*tang_pos*/64, - /*arc_corrected*/ false); - test_proj_data_info(dynamic_cast(*proj_data_info_ptr)); + proj_data_info_ptr = ProjDataInfo::construct_proj_data_info(scanner_ptr, + /*span*/ 2, scanner_ptr->get_num_rings() - 7, + /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2 / 8, + /*tang_pos*/ 64, + /*arc_corrected*/ false); + test_proj_data_info(dynamic_cast(*proj_data_info_ptr)); +#endif // STIR_TOF_DEBUG + cerr << "\nTests with proj_data_info with time-of-flight\n\n"; + shared_ptr scanner_tof_ptr(new Scanner(Scanner::Discovery690)); + proj_data_info_ptr = ProjDataInfo::construct_proj_data_info(scanner_tof_ptr, + /*span*/ 11, scanner_tof_ptr->get_num_rings() - 1, + /*views*/ scanner_tof_ptr->get_num_detectors_per_ring() / 2, + /*tang_pos*/ 64, + /*arc_corrected*/ false, + /*tof_mashing*/ 5); + test_proj_data_info(dynamic_cast(*proj_data_info_ptr)); } void -ProjDataInfoCylindricalNoArcCorrTests:: -test_proj_data_info(ProjDataInfoCylindricalNoArcCorr& proj_data_info) -{ +ProjDataInfoCylindricalNoArcCorrTests::test_proj_data_info(ProjDataInfoCylindricalNoArcCorr& proj_data_info) { test_cylindrical_proj_data_info(proj_data_info); const int num_detectors = proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); #ifndef TEST_ONLY_GET_BIN - if (proj_data_info.get_view_mashing_factor()==1) - { - // these tests work only without mashing - - cerr << "\n\tTest code for sinogram <-> detector conversions."; - -#ifdef STIR_OPENMP - #pragma omp parallel for schedule(dynamic) -#endif - for (int det_num_a = 0; det_num_a < num_detectors; det_num_a++) - for (int det_num_b = 0; det_num_b < num_detectors; det_num_b++) - { - int det1, det2; - bool positive_segment; - int tang_pos_num; - int view; - - // skip case of equal detectors (as this is a singular LOR) - if (det_num_a == det_num_b) - continue; - - positive_segment = - proj_data_info.get_view_tangential_pos_num_for_det_num_pair(view, tang_pos_num, det_num_a, det_num_b); - proj_data_info.get_det_num_pair_for_view_tangential_pos_num(det1, det2, view, tang_pos_num); - - if (!check((det_num_a == det1 && det_num_b == det2 && positive_segment) || - (det_num_a == det2 && det_num_b == det1 && !positive_segment))) - { - cerr << "Problem at det1 = " << det_num_a << ", det2 = " << det_num_b - << "\n dets -> sino -> dets gives new detector numbers " - << det1 << ", " << det2 << endl; - continue; - } - if (!check(view < num_detectors/2)) - { - cerr << "Problem at det1 = " << det_num_a << ", det2 = " << det_num_b - << ":\n view is too big : " << view << endl; - } - if (!check(tang_pos_num < num_detectors/2 && tang_pos_num >= -(num_detectors/2))) - { - cerr << "Problem at det1 = " << det_num_a << ", det2 = " << det_num_b - << ":\n tang_pos_num is out of range : " << tang_pos_num << endl; - } - } // end of detectors_to_sinogram, sinogram_to_detector test - - -#ifdef STIR_OPENMP -#pragma omp parallel for -#endif - for (int view = 0; view < num_detectors/2; ++view) - for (int tang_pos_num = -(num_detectors/2)+1; tang_pos_num < num_detectors/2; ++tang_pos_num) - { - int new_tang_pos_num, new_view; - bool positive_segment; - int det_num_a; - int det_num_b; - - proj_data_info.get_det_num_pair_for_view_tangential_pos_num(det_num_a, det_num_b, view, tang_pos_num); - positive_segment = - proj_data_info.get_view_tangential_pos_num_for_det_num_pair(new_view, new_tang_pos_num, det_num_a, det_num_b); - - if (tang_pos_num != new_tang_pos_num || view != new_view || !positive_segment) - { - cerr << "Problem at view = " << view << ", tang_pos_num = " << tang_pos_num - << "\n sino -> dets -> sino gives new view, tang_pos_num :" - << new_view << ", " << new_tang_pos_num - << " with detector swapping " << positive_segment - << endl; - } - } // end of sinogram_to_detector, detectors_to_sinogram test - - } // end of tests that work only without mashing - - if (proj_data_info.get_view_mashing_factor()==1 - && proj_data_info.get_max_ring_difference(0) == proj_data_info.get_min_ring_difference(0) - && proj_data_info.get_max_ring_difference(1) == proj_data_info.get_min_ring_difference(1) - && proj_data_info.get_max_ring_difference(2) == proj_data_info.get_min_ring_difference(2) - ) + if (proj_data_info.get_view_mashing_factor() == 1) { + // these tests work only without mashing + + cerr << "\n\tTest code for sinogram <-> detector conversions."; + +# ifdef STIR_OPENMP +# pragma omp parallel for schedule(dynamic) +# endif + for (int det_num_a = 0; det_num_a < num_detectors; det_num_a++) + for (int det_num_b = 0; det_num_b < num_detectors; det_num_b++) { + int det1, det2; + bool positive_segment; + int tang_pos_num; + int view; + + // skip case of equal detectors (as this is a singular LOR) + if (det_num_a == det_num_b) + continue; + + positive_segment = proj_data_info.get_view_tangential_pos_num_for_det_num_pair(view, tang_pos_num, det_num_a, det_num_b); + proj_data_info.get_det_num_pair_for_view_tangential_pos_num(det1, det2, view, tang_pos_num); + + if (!check((det_num_a == det1 && det_num_b == det2 && positive_segment) || + (det_num_a == det2 && det_num_b == det1 && !positive_segment))) { + cerr << "Problem at det1 = " << det_num_a << ", det2 = " << det_num_b + << "\n dets -> sino -> dets gives new detector numbers " << det1 << ", " << det2 << endl; + continue; + } + if (!check(view < num_detectors / 2)) { + cerr << "Problem at det1 = " << det_num_a << ", det2 = " << det_num_b << ":\n view is too big : " << view << endl; + } + if (!check(tang_pos_num < num_detectors / 2 && tang_pos_num >= -(num_detectors / 2))) { + cerr << "Problem at det1 = " << det_num_a << ", det2 = " << det_num_b + << ":\n tang_pos_num is out of range : " << tang_pos_num << endl; + } + } // end of detectors_to_sinogram, sinogram_to_detector test + +# ifdef STIR_OPENMP +# pragma omp parallel for +# endif + for (int view = 0; view < num_detectors / 2; ++view) + for (int tang_pos_num = -(num_detectors / 2) + 1; tang_pos_num < num_detectors / 2; ++tang_pos_num) { + int new_tang_pos_num, new_view; + bool positive_segment; + int det_num_a; + int det_num_b; + + proj_data_info.get_det_num_pair_for_view_tangential_pos_num(det_num_a, det_num_b, view, tang_pos_num); + positive_segment = + proj_data_info.get_view_tangential_pos_num_for_det_num_pair(new_view, new_tang_pos_num, det_num_a, det_num_b); + + if (tang_pos_num != new_tang_pos_num || view != new_view || !positive_segment) { + cerr << "Problem at view = " << view << ", tang_pos_num = " << tang_pos_num + << "\n sino -> dets -> sino gives new view, tang_pos_num :" << new_view << ", " << new_tang_pos_num + << " with detector swapping " << positive_segment << endl; + } + } // end of sinogram_to_detector, detectors_to_sinogram test + + } // end of tests that work only without mashing + + if (proj_data_info.get_view_mashing_factor() == 1 && + proj_data_info.get_max_ring_difference(0) == proj_data_info.get_min_ring_difference(0) && + proj_data_info.get_max_ring_difference(1) == proj_data_info.get_min_ring_difference(1) && + proj_data_info.get_max_ring_difference(2) == proj_data_info.get_min_ring_difference(2)) { + // these tests work only without mashing and axial compression + + cerr << "\n\tTest code for detector,ring -> bin and back conversions."; + + DetectionPositionPair<> det_pos_pair; + for (det_pos_pair.pos1().axial_coord() = 0; det_pos_pair.pos1().axial_coord() <= 2; det_pos_pair.pos1().axial_coord()++) + for (det_pos_pair.pos2().axial_coord() = 0; det_pos_pair.pos2().axial_coord() <= 2; det_pos_pair.pos2().axial_coord()++) +# ifdef STIR_OPENMP + // insert a parallel for here for testing. + // we do it at this level to avoid too much overhead for the thread creation, while still having enough jobs to do + // note: for-loop writing somewhat awkwardly as openmp needs int variables for the loop +# pragma omp parallel for firstprivate(det_pos_pair) +# endif + for (int tangential_coord1 = 0; tangential_coord1 < num_detectors; tangential_coord1++) + for (det_pos_pair.pos2().tangential_coord() = 0; det_pos_pair.pos2().tangential_coord() < (unsigned)num_detectors; + det_pos_pair.pos2().tangential_coord()++) + for (det_pos_pair.timing_pos() = 0; // currently unsigned so start from 0 + det_pos_pair.timing_pos() <= (unsigned)proj_data_info.get_max_tof_pos_num(); + det_pos_pair.timing_pos() += (unsigned)std::max(1, proj_data_info.get_max_tof_pos_num())) { + + // set from for-loop variable + det_pos_pair.pos1().tangential_coord() = (unsigned)tangential_coord1; + // skip case of equal detector numbers (as this is either a singular LOR) + // or an LOR parallel to the scanner axis + if (det_pos_pair.pos1().tangential_coord() == det_pos_pair.pos2().tangential_coord()) + continue; + Bin bin(0, 0, 0, 0, 0, 0.0f); + DetectionPositionPair<> new_det_pos_pair; + const bool there_is_a_bin = proj_data_info.get_bin_for_det_pos_pair(bin, det_pos_pair) == Succeeded::yes; + if (there_is_a_bin) + proj_data_info.get_det_pos_pair_for_bin(new_det_pos_pair, bin); + if (!check(there_is_a_bin, "checking if there is a bin for this det_pos_pair") || + !check(det_pos_pair == new_det_pos_pair, "checking if we round-trip to the same detection positions")) { + cerr << "Problem at det1 = " << det_pos_pair.pos1().tangential_coord() + << ", det2 = " << det_pos_pair.pos2().tangential_coord() << ", ring1 = " << det_pos_pair.pos1().axial_coord() + << ", ring2 = " << det_pos_pair.pos2().axial_coord() << ", timing_pos = " << det_pos_pair.timing_pos() + << endl; + if (there_is_a_bin) + cerr << " dets,rings -> bin -> dets,rings, gives new numbers:\n\t" + << "det1 = " << new_det_pos_pair.pos1().tangential_coord() + + << ", det2 = " << new_det_pos_pair.pos2().tangential_coord() + << ", ring1 = " << new_det_pos_pair.pos1().axial_coord() + << ", ring2 = " << new_det_pos_pair.pos2().axial_coord() << ", timing_pos = " << det_pos_pair.timing_pos() + << endl; + } + + } // end of get_bin_for_det_pos_pair and vice versa code + + cerr << "\n\tTest code for bin -> detector,ring and back conversions. (This might take a while...)"; { - // these tests work only without mashing and axial compression - - cerr << "\n\tTest code for detector,ring -> bin and back conversions."; - - DetectionPositionPair<> det_pos_pair; - for (det_pos_pair.pos1().axial_coord() = 0; - det_pos_pair.pos1().axial_coord() <= 2; - det_pos_pair.pos1().axial_coord()++) - for (det_pos_pair.pos2().axial_coord() = 0; - det_pos_pair.pos2().axial_coord() <= 2; - det_pos_pair.pos2().axial_coord()++) -#ifdef STIR_OPENMP - // insert a parallel for here for testing. - // we do it at this level to avoid too much overhead for the thread creation, while still having enough jobs to do - // note: for-loop writing somewhat awkwardly as openmp needs int variables for the loop -#pragma omp parallel for firstprivate(det_pos_pair) -#endif - for (int tangential_coord1 = 0; - tangential_coord1 < num_detectors; - tangential_coord1++) - for (det_pos_pair.pos2().tangential_coord() = 0; - det_pos_pair.pos2().tangential_coord() < (unsigned)num_detectors; - det_pos_pair.pos2().tangential_coord()++) - { + Bin bin(0, 0, 0, 0, 0, 0.0f); + // set value for comparison later on + bin.set_bin_value(0.f); + for (bin.timing_pos_num() = proj_data_info.get_min_tof_pos_num(); + bin.timing_pos_num() <= proj_data_info.get_max_tof_pos_num(); + bin.timing_pos_num() += std::max(1, (proj_data_info.get_max_tof_pos_num() - proj_data_info.get_min_tof_pos_num()) / + 2)) // take 3 or 1 steps, always going through 0) + for (bin.segment_num() = max(-5, proj_data_info.get_min_segment_num()); + bin.segment_num() <= min(5, proj_data_info.get_max_segment_num()); ++bin.segment_num()) + for (bin.axial_pos_num() = proj_data_info.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= proj_data_info.get_max_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() += std::min(3, proj_data_info.get_num_axial_poss(bin.segment_num()))) +# ifdef STIR_OPENMP + // insert a parallel for here for testing. + // we do it at this level to avoid too much overhead for the thread creation, while still having enough jobs to do // + // Note that the omp construct needs an int loop variable +# pragma omp parallel for firstprivate(bin) +# endif + for (int tangential_pos_num = -(num_detectors / 2) + 1; tangential_pos_num < num_detectors / 2; ++tangential_pos_num) + for (bin.view_num() = 0; bin.view_num() < num_detectors / 2; ++bin.view_num()) { // set from for-loop variable - det_pos_pair.pos1().tangential_coord() = (unsigned)tangential_coord1; - // skip case of equal detector numbers (as this is either a singular LOR) - // or an LOR parallel to the scanner axis - if (det_pos_pair.pos1().tangential_coord() == det_pos_pair.pos2().tangential_coord()) - continue; - Bin bin; - DetectionPositionPair<> new_det_pos_pair; - const bool there_is_a_bin = - proj_data_info.get_bin_for_det_pos_pair(bin, det_pos_pair) == - Succeeded::yes; - if (there_is_a_bin) - proj_data_info.get_det_pos_pair_for_bin(new_det_pos_pair, bin); - if (!check(there_is_a_bin, "checking if there is a bin for this det_pos_pair") || - !check(det_pos_pair == new_det_pos_pair, "checking if we round-trip to the same detection positions")) - { - cerr << "Problem at det1 = " << det_pos_pair.pos1().tangential_coord() - << ", det2 = " << det_pos_pair.pos2().tangential_coord() - << ", ring1 = " << det_pos_pair.pos1().axial_coord() - << ", ring2 = " << det_pos_pair.pos2().axial_coord() - << endl; - if (there_is_a_bin) - cerr << " dets,rings -> bin -> dets,rings, gives new numbers:\n\t" - << "det1 = " << new_det_pos_pair.pos1().tangential_coord() - - << ", det2 = " << new_det_pos_pair.pos2().tangential_coord() - << ", ring1 = " << new_det_pos_pair.pos1().axial_coord() - << ", ring2 = " << new_det_pos_pair.pos2().axial_coord() - << endl; - } - - } // end of get_bin_for_det_pos_pair and vice versa code - - cerr << "\n\tTest code for bin -> detector,ring and back conversions. (This might take a while...)"; - - { - Bin bin; - // set value for comparison later on - bin.set_bin_value(0); - for (bin.segment_num() = max(-5,proj_data_info.get_min_segment_num()); - bin.segment_num() <= min(5,proj_data_info.get_max_segment_num()); - ++bin.segment_num()) - for (bin.axial_pos_num() = proj_data_info.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= proj_data_info.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) -#ifdef STIR_OPENMP - // insert a parallel for here for testing. - // we do it at this level to avoid too much overhead for the thread creation, while still having enough jobs to do - // Note that the omp construct needs an int loop variable -#pragma omp parallel for firstprivate(bin) -#endif - for (int tangential_pos_num = -(num_detectors/2)+1; - tangential_pos_num < num_detectors/2; - ++tangential_pos_num) - for (bin.view_num() = 0; bin.view_num() < num_detectors/2; ++bin.view_num()) - { - // set from for-loop variable - bin.tangential_pos_num() = tangential_pos_num; - Bin new_bin; - // set value for comparison with bin - new_bin.set_bin_value(0); - DetectionPositionPair<> det_pos_pair; - proj_data_info.get_det_pos_pair_for_bin(det_pos_pair, bin); - - const bool there_is_a_bin = - proj_data_info.get_bin_for_det_pos_pair(new_bin, - det_pos_pair) == - Succeeded::yes; - if (!check(there_is_a_bin, "checking if there is a bin for this det_pos_pair") || - !check(bin == new_bin, "checking if we round-trip to the same bin")) - { - cerr << "Problem at segment = " << bin.segment_num() - << ", axial pos " << bin.axial_pos_num() - << ", view = " << bin.view_num() - << ", tangential_pos_num = " << bin.tangential_pos_num() << "\n"; - if (there_is_a_bin) - cerr << " bin -> dets -> bin, gives new numbers:\n\t" - << "segment = " << new_bin.segment_num() - << ", axial pos " << new_bin.axial_pos_num() - << ", view = " << new_bin.view_num() - << ", tangential_pos_num = " << new_bin.tangential_pos_num() - << endl; - } - - } // end of get_det_pos_pair_for_bin and back code - } - } // end of tests which require no mashing nor axial compression + bin.tangential_pos_num() = tangential_pos_num; + Bin new_bin(0, 0, 0, 0, 0, 0.0f); + // set value for comparison with bin + new_bin.set_bin_value(0); + DetectionPositionPair<> det_pos_pair; + proj_data_info.get_det_pos_pair_for_bin(det_pos_pair, bin); + + const bool there_is_a_bin = proj_data_info.get_bin_for_det_pos_pair(new_bin, det_pos_pair) == Succeeded::yes; + if (!check(there_is_a_bin, "checking if there is a bin for this det_pos_pair") || + !check(bin == new_bin, "checking if we round-trip to the same bin")) { + cerr << "Problem at segment = " << bin.segment_num() << ", axial pos " << bin.axial_pos_num() + << ", view = " << bin.view_num() << ", tangential_pos_num = " << bin.tangential_pos_num() + << ", timing pos num = " << bin.timing_pos_num() << "\n"; + if (there_is_a_bin) + cerr << " bin -> dets -> bin, gives new numbers:\n\t" + << "segment = " << new_bin.segment_num() << ", axial pos " << new_bin.axial_pos_num() + << ", view = " << new_bin.view_num() << ", tangential_pos_num = " << new_bin.tangential_pos_num() + << ", timing pos num = " << new_bin.timing_pos_num() << endl; + } + + } // end of get_det_pos_pair_for_bin and back code + } + } // end of tests which require no mashing nor axial compression { cerr << "\n\tTest code for bins <-> detectors routines that work with any mashing and axial compression"; - Bin bin; + Bin bin(0, 0, 0, 0, 0, 0.0f); // set value for comparison later on bin.set_bin_value(0); - std::vector > det_pos_pairs; -#ifdef STIR_OPENMP + std::vector> det_pos_pairs; +# ifdef STIR_OPENMP //#pragma omp parallel for schedule(dynamic) -#endif - for (bin.segment_num() = proj_data_info.get_min_segment_num(); - bin.segment_num() <= proj_data_info.get_max_segment_num(); - ++bin.segment_num()) +# endif + for (bin.segment_num() = proj_data_info.get_min_segment_num(); bin.segment_num() <= proj_data_info.get_max_segment_num(); + bin.segment_num() += std::max(1, proj_data_info.get_num_segments() / 2)) for (bin.axial_pos_num() = proj_data_info.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= proj_data_info.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - for (bin.view_num() = proj_data_info.get_min_view_num(); - bin.view_num() <= proj_data_info.get_max_view_num(); - ++bin.view_num()) - for (bin.tangential_pos_num() = proj_data_info.get_min_tangential_pos_num(); - bin.tangential_pos_num() <= proj_data_info.get_max_tangential_pos_num(); - ++bin.tangential_pos_num()) - { - proj_data_info.get_all_det_pos_pairs_for_bin(det_pos_pairs, bin); - Bin new_bin; - // set value for comparison with bin - new_bin.set_bin_value(0); - for (std::vector >::const_iterator det_pos_pair_iter = det_pos_pairs.begin(); - det_pos_pair_iter != det_pos_pairs.end(); - ++det_pos_pair_iter) - { - const bool there_is_a_bin = - proj_data_info.get_bin_for_det_pos_pair(new_bin, - *det_pos_pair_iter) == - Succeeded::yes; - if (!check(there_is_a_bin, "checking if there is a bin for this det_pos_pair") || - !check(bin == new_bin, "checking if we round-trip to the same bin")) - { - cerr << "Problem at segment = " << bin.segment_num() - << ", axial pos " << bin.axial_pos_num() - << ", view = " << bin.view_num() - << ", tangential_pos_num = " << bin.tangential_pos_num() << "\n"; - if (there_is_a_bin) - cerr << " bin -> dets -> bin, gives new numbers:\n\t" - << "segment = " << new_bin.segment_num() - << ", axial pos " << new_bin.axial_pos_num() - << ", view = " << new_bin.view_num() - << ", tangential_pos_num = " << new_bin.tangential_pos_num() - << endl; - } - } // end of iteration of det_pos_pairs - } // end of loop over all bins - } // end of get_all_det_pairs_for_bin and back code -#endif //TEST_ONLY_GET_BIN + bin.axial_pos_num() <= proj_data_info.get_max_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() += std::min(3, proj_data_info.get_num_axial_poss(bin.segment_num()))) + for (bin.view_num() = proj_data_info.get_min_view_num(); bin.view_num() <= proj_data_info.get_max_view_num(); + bin.view_num() += std::min(5, proj_data_info.get_num_views())) + for (bin.tangential_pos_num() = proj_data_info.get_min_tangential_pos_num(); + bin.tangential_pos_num() <= proj_data_info.get_max_tangential_pos_num(); + bin.tangential_pos_num() += std::min(7, proj_data_info.get_num_tangential_poss())) + for (bin.timing_pos_num() = proj_data_info.get_min_tof_pos_num(); + bin.timing_pos_num() <= proj_data_info.get_max_tof_pos_num(); + bin.timing_pos_num() += + std::max(1, (proj_data_info.get_max_tof_pos_num() - proj_data_info.get_min_tof_pos_num()) / + 2)) // take 3 or 1 steps, always going through 0) + { + proj_data_info.get_all_det_pos_pairs_for_bin(det_pos_pairs, bin); + Bin new_bin(0, 0, 0, 0, 0, 0.0f); + // set value for comparison with bin + new_bin.set_bin_value(0); + for (std::vector>::const_iterator det_pos_pair_iter = det_pos_pairs.begin(); + det_pos_pair_iter != det_pos_pairs.end(); ++det_pos_pair_iter) { + const bool there_is_a_bin = + proj_data_info.get_bin_for_det_pos_pair(new_bin, *det_pos_pair_iter) == Succeeded::yes; + if (!check(there_is_a_bin, "checking if there is a bin for this det_pos_pair") || + !check(bin == new_bin, "checking if we round-trip to the same bin")) { + cerr << "Problem at segment = " << bin.segment_num() << ", axial pos " << bin.axial_pos_num() + << ", view = " << bin.view_num() << ", tangential_pos = " << bin.tangential_pos_num() << ", timing_pos - " + << bin.timing_pos_num() << "\n"; + if (there_is_a_bin) + cerr << " bin -> dets -> bin, gives new numbers:\n\t" + << "segment = " << new_bin.segment_num() << ", axial pos " << new_bin.axial_pos_num() + << ", view = " << new_bin.view_num() << ", tangential_pos_num = " << new_bin.tangential_pos_num() + << ", timing_pos - " << new_bin.timing_pos_num() << endl; + } + } // end of iteration of det_pos_pairs + } // end of loop over all bins + } // end of get_all_det_pairs_for_bin and back code +#endif // TEST_ONLY_GET_BIN { cerr << endl; cerr << "\tTesting find scanner coordinates given cartesian and vice versa." << endl; - { - const int num_detectors_per_ring = - proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); - const int num_rings = - proj_data_info.get_scanner_ptr()->get_num_rings(); + { + const int num_detectors_per_ring = proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_rings = proj_data_info.get_scanner_ptr()->get_num_rings(); #ifdef STIR_OPENMP -#pragma omp parallel for schedule(dynamic) +# pragma omp parallel for schedule(dynamic) #endif - for ( int Ring_A = 0; Ring_A < num_rings; Ring_A+=num_rings/3) - for ( int Ring_B = 0; Ring_B < num_rings; Ring_B+=num_rings/3) - for ( int det1 =0; det1 < num_detectors_per_ring; ++det1) - for ( int det2 =0; det2 < num_detectors_per_ring; ++det2) - { - if (det1==det2) - continue; - CartesianCoordinate3D coord_1; - CartesianCoordinate3D coord_2; - - proj_data_info.find_cartesian_coordinates_given_scanner_coordinates (coord_1,coord_2, - Ring_A,Ring_B, - det1,det2); - - const CartesianCoordinate3D coord_1_new = coord_1 + (coord_2-coord_1)*5; - const CartesianCoordinate3D coord_2_new = coord_1 + (coord_2-coord_1)*2; - - int det1_f, det2_f,ring1_f, ring2_f; - - check(proj_data_info.find_scanner_coordinates_given_cartesian_coordinates(det1_f, det2_f, ring1_f, ring2_f, - coord_1_new, coord_2_new) == - Succeeded::yes); - if (det1_f == det1 && Ring_A == ring1_f) - { - check_if_equal( det1_f, det1, "test on det1"); - check_if_equal( Ring_A, ring1_f, "test on ring1"); - check_if_equal( det2_f, det2, "test on det2"); - check_if_equal( Ring_B, ring2_f, "test on ring1"); - } - else - { - check_if_equal( det2_f, det1, "test on det1"); - check_if_equal( Ring_B, ring1_f, "test on ring1"); - check_if_equal( det1_f, det2, "test on det2"); - check_if_equal( Ring_A, ring2_f, "test on ring1"); - } - } + for (int Ring_A = 0; Ring_A < num_rings; Ring_A += num_rings / 3) + for (int Ring_B = 0; Ring_B < num_rings; Ring_B += num_rings / 3) + for (int det1 = 0; det1 < num_detectors_per_ring; ++det1) + for (int det2 = 0; det2 < num_detectors_per_ring; ++det2) { + if (det1 == det2) + continue; + CartesianCoordinate3D coord_1; + CartesianCoordinate3D coord_2; + + proj_data_info.find_cartesian_coordinates_given_scanner_coordinates(coord_1, coord_2, Ring_A, Ring_B, det1, det2); + + const CartesianCoordinate3D coord_1_new = coord_1 + (coord_2 - coord_1) * 5; + const CartesianCoordinate3D coord_2_new = coord_1 + (coord_2 - coord_1) * 2; + + int det1_f, det2_f, ring1_f, ring2_f; + + check(proj_data_info.find_scanner_coordinates_given_cartesian_coordinates( + det1_f, det2_f, ring1_f, ring2_f, coord_1_new, coord_2_new) == Succeeded::yes); + if (det1_f == det1 && Ring_A == ring1_f) { + check_if_equal(det1_f, det1, "test on det1"); + check_if_equal(Ring_A, ring1_f, "test on ring1"); + check_if_equal(det2_f, det2, "test on det2"); + check_if_equal(Ring_B, ring2_f, "test on ring1"); + } else { + check_if_equal(det2_f, det1, "test on det1"); + check_if_equal(Ring_B, ring1_f, "test on ring1"); + check_if_equal(det1_f, det2, "test on det2"); + check_if_equal(Ring_A, ring2_f, "test on ring1"); + } + } } } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main() -{ +int +main() { set_default_num_threads(); +#ifndef STIR_TOF_DEBUG // disable for speed of testing { ProjDataInfoCylindricalArcCorrTests tests; tests.run_tests(); if (!tests.is_everything_ok()) return tests.main_return_value(); } +#endif { ProjDataInfoCylindricalNoArcCorrTests tests1; tests1.run_tests(); diff --git a/src/test/test_proj_data_maths.cxx b/src/test/test_proj_data_maths.cxx index b33bfb4ce7..fcfec82c0a 100644 --- a/src/test/test_proj_data_maths.cxx +++ b/src/test/test_proj_data_maths.cxx @@ -38,104 +38,94 @@ #include "stir/copy_fill.h" START_NAMESPACE_STIR - /*! \ingroup test \brief Test class for ProjDataInMemory */ -class ProjDataInMemoryTests: public RunTests -{ +class ProjDataInMemoryTests : public RunTests { public: void run_tests(); }; -static -void check_proj_data_are_equal_and_non_zero(const ProjData& x, const ProjData& y) -{ - const size_t n = x.size_all(); - const size_t ny = y.size_all(); - if (n!=ny) - error("ProjData::xapyb and ProjDataInMemory::xapyb mismatch"); - - // Create arrays - std::vector arr1(n), arr2(n); - copy_to(x, arr1.begin()); - copy_to(y, arr2.begin()); - - // Check for mismatch - for (unsigned i=0; i 1e-4f) - error("ProjData::xapyb and ProjDataInMemory::xapyb mismatch"); - - // Check for non-zero - if (std::abs(*std::max_element(arr1.begin(),arr1.end())) < 1e-4f) - error("ProjData::xapyb and ProjDataInMemory::xapyb mismatch"); +static void +check_proj_data_are_equal_and_non_zero(const ProjData& x, const ProjData& y) { + const size_t n = x.size_all(); + const size_t ny = y.size_all(); + if (n != ny) + error("ProjData::xapyb and ProjDataInMemory::xapyb mismatch"); + + // Create arrays + std::vector arr1(n), arr2(n); + copy_to(x, arr1.begin()); + copy_to(y, arr2.begin()); + + // Check for mismatch + for (unsigned i = 0; i < n; ++i) + if (std::abs(arr1[i] - arr2[i]) > 1e-4f) + error("ProjData::xapyb and ProjDataInMemory::xapyb mismatch"); + + // Check for non-zero + if (std::abs(*std::max_element(arr1.begin(), arr1.end())) < 1e-4f) + error("ProjData::xapyb and ProjDataInMemory::xapyb mismatch"); } void -ProjDataInMemoryTests:: -run_tests() -{ - // Create scanner and proj data info - shared_ptr scanner_sptr(new Scanner(Scanner::E953)); - shared_ptr - proj_data_info_sptr( - ProjDataInfo::construct_proj_data_info - (scanner_sptr, - /*span*/1, 10,/*views*/ 96, /*tang_pos*/128, /*arc_corrected*/ true) - ); - - // Create pd1 and pd2 - shared_ptr exam_info_sptr(new ExamInfo); - ProjDataInMemory pd1(exam_info_sptr, proj_data_info_sptr); - ProjDataInMemory pd2(pd1); - - // Create x1 and x2 - ProjDataInMemory x1(pd1); - x1.fill(100.f); - ProjDataInMemory x2(x1); - - // Create y1 and y2 - ProjDataInMemory y1(pd1); - y1.fill(1000.f); - ProjDataInMemory y2(y1); - - - // Check xapby with general and ProjDataInMemory methods - const float a = 2.f; - const float b = 3.f; - pd1.xapyb(x1,a,y1,b); - pd2.ProjData::xapyb(x2,a,y2,b); - check_proj_data_are_equal_and_non_zero(pd1,pd2); - - // Check sapby with general and ProjDataInMemory methods - ProjDataInMemory out1(x1); - out1.sapyb(a, y1, b); - check_proj_data_are_equal_and_non_zero(pd1,out1); - - ProjDataInMemory out2(x1); - out2.ProjData::sapyb(a, y1, b); - check_proj_data_are_equal_and_non_zero(pd1,out2); - - // Check using iterators - ProjDataInMemory pd3(pd1); - pd3.fill(0.f); - ProjDataInMemory::iterator pd_iter = pd3.begin(); - ProjDataInMemory::const_iterator x_iter = x1.begin(); - ProjDataInMemory::const_iterator y_iter = y1.begin(); - while (pd_iter != pd3.end()) - *pd_iter++ = a*(*x_iter++) + b*(*y_iter++); - - check_proj_data_are_equal_and_non_zero(pd1,pd3); +ProjDataInMemoryTests::run_tests() { + // Create scanner and proj data info + shared_ptr scanner_sptr(new Scanner(Scanner::E953)); + shared_ptr proj_data_info_sptr(ProjDataInfo::construct_proj_data_info(scanner_sptr, + /*span*/ 1, 10, /*views*/ 96, + /*tang_pos*/ 128, /*arc_corrected*/ true)); + + // Create pd1 and pd2 + shared_ptr exam_info_sptr(new ExamInfo); + ProjDataInMemory pd1(exam_info_sptr, proj_data_info_sptr); + ProjDataInMemory pd2(pd1); + + // Create x1 and x2 + ProjDataInMemory x1(pd1); + x1.fill(100.f); + ProjDataInMemory x2(x1); + + // Create y1 and y2 + ProjDataInMemory y1(pd1); + y1.fill(1000.f); + ProjDataInMemory y2(y1); + + // Check xapby with general and ProjDataInMemory methods + const float a = 2.f; + const float b = 3.f; + pd1.xapyb(x1, a, y1, b); + pd2.ProjData::xapyb(x2, a, y2, b); + check_proj_data_are_equal_and_non_zero(pd1, pd2); + + // Check sapby with general and ProjDataInMemory methods + ProjDataInMemory out1(x1); + out1.sapyb(a, y1, b); + check_proj_data_are_equal_and_non_zero(pd1, out1); + + ProjDataInMemory out2(x1); + out2.ProjData::sapyb(a, y1, b); + check_proj_data_are_equal_and_non_zero(pd1, out2); + + // Check using iterators + ProjDataInMemory pd3(pd1); + pd3.fill(0.f); + ProjDataInMemory::iterator pd_iter = pd3.begin(); + ProjDataInMemory::const_iterator x_iter = x1.begin(); + ProjDataInMemory::const_iterator y_iter = y1.begin(); + while (pd_iter != pd3.end()) + *pd_iter++ = a * (*x_iter++) + b * (*y_iter++); + + check_proj_data_are_equal_and_non_zero(pd1, pd3); } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main() -{ +int +main() { ProjDataInMemoryTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_stir_math.cxx b/src/test/test_stir_math.cxx index 2fef311744..351405db2c 100644 --- a/src/test/test_stir_math.cxx +++ b/src/test/test_stir_math.cxx @@ -2,10 +2,10 @@ \file \ingroup test - + \brief Test program for the stir_math utility - - Takes as single command line argument the filename of the stir_math executable + + Takes as single command line argument the filename of the stir_math executable (with a relative or absolute path). If no argument is given, the executable im the path is used. \warning will overwite (and then delete) files called STIR$$*. @@ -61,146 +61,131 @@ START_NAMESPACE_STIR \warning will overwite (and then delete) files called STIR$$*. */ -class stir_mathTests : public RunTests -{ +class stir_mathTests : public RunTests { public: - stir_mathTests(const string& stir_math_executable) - : stir_math_executable(stir_math_executable) - {} - + stir_mathTests(const string& stir_math_executable) : stir_math_executable(stir_math_executable) {} + void run_tests(); + private: string stir_math_executable; //! returns true if it ran it successfully - bool run_stir_math(const char * const arguments); - + bool run_stir_math(const char* const arguments); }; - bool -stir_mathTests:: -run_stir_math(const char * const arguments) -{ +stir_mathTests::run_stir_math(const char* const arguments) { static string cmdline; static string error_string; // note: add extra quotes around executable name to cope with spaces in the filename cmdline = "\"" + stir_math_executable + "\""; - cmdline += ' ' ; + cmdline += ' '; cmdline += arguments; error_string = "error executing command '"; error_string += cmdline; error_string += "'"; cerr << "\nExecuting '" << cmdline << "'\n"; - return check(system(cmdline.c_str())==EXIT_SUCCESS, - "executing previous command returned non-zero status\n."); + return check(system(cmdline.c_str()) == EXIT_SUCCESS, "executing previous command returned non-zero status\n."); } void stir_mathTests::run_tests() -{ +{ cerr << "Tests for the stir_math utility\n"; cerr << "WARNING: will overwite (and then delete) files called STIRtmp*\n"; - + // images { - CartesianCoordinate3D origin (0,0,0); - CartesianCoordinate3D grid_spacing (3,4,5); - IndexRange<3> - range(CartesianCoordinate3D(0,-2,-3), - CartesianCoordinate3D(1,2,3)); - VoxelsOnCartesianGrid data1(range,origin, grid_spacing); - VoxelsOnCartesianGrid data2(range,origin, grid_spacing); - VoxelsOnCartesianGrid data3(range,origin, grid_spacing); + CartesianCoordinate3D origin(0, 0, 0); + CartesianCoordinate3D grid_spacing(3, 4, 5); + IndexRange<3> range(CartesianCoordinate3D(0, -2, -3), CartesianCoordinate3D(1, 2, 3)); + VoxelsOnCartesianGrid data1(range, origin, grid_spacing); + VoxelsOnCartesianGrid data2(range, origin, grid_spacing); + VoxelsOnCartesianGrid data3(range, origin, grid_spacing); VoxelsOnCartesianGrid calc_data; - shared_ptr > out_data_ptr; - + shared_ptr> out_data_ptr; + // fill with some random numbers srand(1); generate(data1.begin_all(), data1.end_all(), rand); generate(data2.begin_all(), data2.end_all(), rand); generate(data3.begin_all(), data3.end_all(), rand); - + InterfileOutputFileFormat output_file_format; - check(output_file_format.write_to_file("STIRtmp1.v", data1)== Succeeded::yes, - "test writing Interfile image STIRtmp1"); - check(output_file_format.write_to_file("STIRtmp2.v", data2)== Succeeded::yes, - "test writing Interfile image STIRtmp2"); - check(output_file_format.write_to_file("STIRtmp3.v", data3)== Succeeded::yes, - "test writing Interfile image STIRtmp3"); - - set_tolerance(data1.find_max()/10000); - + check(output_file_format.write_to_file("STIRtmp1.v", data1) == Succeeded::yes, "test writing Interfile image STIRtmp1"); + check(output_file_format.write_to_file("STIRtmp2.v", data2) == Succeeded::yes, "test writing Interfile image STIRtmp2"); + check(output_file_format.write_to_file("STIRtmp3.v", data3) == Succeeded::yes, "test writing Interfile image STIRtmp3"); + + set_tolerance(data1.find_max() / 10000); + // add - if (run_stir_math("STIRtmpout.v STIRtmp1.hv STIRtmp2.hv STIRtmp3.hv")) - { - out_data_ptr = read_from_file >("STIRtmpout.hv"); + if (run_stir_math("STIRtmpout.v STIRtmp1.hv STIRtmp2.hv STIRtmp3.hv")) { + out_data_ptr = read_from_file>("STIRtmpout.hv"); calc_data = data1; calc_data += data2 + data3; - - check_if_equal( calc_data, *out_data_ptr,"test on adding"); + + check_if_equal(calc_data, *out_data_ptr, "test on adding"); } // mult - if (run_stir_math("--mult STIRtmpout.v STIRtmp1.hv STIRtmp2.hv STIRtmp3.hv")) - { - out_data_ptr = read_from_file >("STIRtmpout.hv"); + if (run_stir_math("--mult STIRtmpout.v STIRtmp1.hv STIRtmp2.hv STIRtmp3.hv")) { + out_data_ptr = read_from_file>("STIRtmpout.hv"); calc_data = data1; calc_data *= data2 * data3; - - check_if_equal( calc_data, *out_data_ptr,"test on multiplying"); + + check_if_equal(calc_data, *out_data_ptr, "test on multiplying"); } // add with power etc // range for rand() is 0 to RAND_MAX - const float min_threshold = RAND_MAX/5.F; - const float max_threshold = RAND_MAX/2.F; + const float min_threshold = RAND_MAX / 5.F; + const float max_threshold = RAND_MAX / 2.F; { char cmd_args[1000]; - sprintf(cmd_args, "--add-scalar 3.1 --power 2 --times-scalar 3.2 --min-threshold %g --max-threshold %g " - "STIRtmpout.v STIRtmp1.hv STIRtmp2.hv STIRtmp3.hv", - min_threshold, max_threshold); - if (run_stir_math(cmd_args)) - { - out_data_ptr = read_from_file >("STIRtmpout.hv"); - calc_data.fill(0); - VoxelsOnCartesianGrid data2_thresholded(data2); - VoxelsOnCartesianGrid data3_thresholded(data3); - threshold_upper_lower( data2_thresholded.begin_all(), data2_thresholded.end_all(), - min_threshold, max_threshold); - threshold_upper_lower( data3_thresholded.begin_all(), data3_thresholded.end_all(), - min_threshold, max_threshold); - calc_data += data1 + (data2_thresholded*data2_thresholded)*3.2F + 3.1F + (data3_thresholded*data3_thresholded)*3.2F + 3.1F; - - check_if_equal( calc_data, *out_data_ptr,"test with thresholding, power and scalar multiplication and addition"); - } + sprintf(cmd_args, + "--add-scalar 3.1 --power 2 --times-scalar 3.2 --min-threshold %g --max-threshold %g " + "STIRtmpout.v STIRtmp1.hv STIRtmp2.hv STIRtmp3.hv", + min_threshold, max_threshold); + if (run_stir_math(cmd_args)) { + out_data_ptr = read_from_file>("STIRtmpout.hv"); + calc_data.fill(0); + VoxelsOnCartesianGrid data2_thresholded(data2); + VoxelsOnCartesianGrid data3_thresholded(data3); + threshold_upper_lower(data2_thresholded.begin_all(), data2_thresholded.end_all(), min_threshold, max_threshold); + threshold_upper_lower(data3_thresholded.begin_all(), data3_thresholded.end_all(), min_threshold, max_threshold); + calc_data += + data1 + (data2_thresholded * data2_thresholded) * 3.2F + 3.1F + (data3_thresholded * data3_thresholded) * 3.2F + 3.1F; + + check_if_equal(calc_data, *out_data_ptr, "test with thresholding, power and scalar multiplication and addition"); + } } // add with power etc and including-first - if (run_stir_math("--power 2 --times-scalar 3.2 --including-first STIRtmpout.v STIRtmp1.hv STIRtmp2.hv STIRtmp3.hv")) - { - out_data_ptr = read_from_file >("STIRtmpout.hv"); + if (run_stir_math("--power 2 --times-scalar 3.2 --including-first STIRtmpout.v STIRtmp1.hv STIRtmp2.hv STIRtmp3.hv")) { + out_data_ptr = read_from_file>("STIRtmpout.hv"); calc_data.fill(0); - calc_data += (data1*data1 + data2*data2 + data3*data3)*3.2F; - check_if_equal( calc_data, *out_data_ptr,"test with power and scalar multiplication with --including-first"); + calc_data += (data1 * data1 + data2 * data2 + data3 * data3) * 3.2F; + check_if_equal(calc_data, *out_data_ptr, "test with power and scalar multiplication with --including-first"); } - // add with power etc and accumulate - if (run_stir_math("--accumulate --power 2 --times-scalar 3.2 --add-scalar 3.1 --divide-scalar 2.1 --mult STIRtmp1.hv STIRtmp3.hv")) - { + // add with power etc and accumulate + if (run_stir_math( + "--accumulate --power 2 --times-scalar 3.2 --add-scalar 3.1 --divide-scalar 2.1 --mult STIRtmp1.hv STIRtmp3.hv")) { calc_data.fill(0); calc_data += data1; - calc_data += (data3*data3)*3.2F/2.1F + 3.1F; - out_data_ptr = read_from_file >("STIRtmp1.hv"); - check_if_equal( calc_data, *out_data_ptr,"test with power and scalar multiplication, division and addition with --accumulate"); + calc_data += (data3 * data3) * 3.2F / 2.1F + 3.1F; + out_data_ptr = read_from_file>("STIRtmp1.hv"); + check_if_equal(calc_data, *out_data_ptr, + "test with power and scalar multiplication, division and addition with --accumulate"); } // add with power etc and accumulate and including-first - if (run_stir_math("--accumulate --power 2 --times-scalar 3.2 --including-first STIRtmp2.hv STIRtmp3.hv")) - { + if (run_stir_math("--accumulate --power 2 --times-scalar 3.2 --including-first STIRtmp2.hv STIRtmp3.hv")) { calc_data.fill(0); calc_data += data2; calc_data *= calc_data * 3.2F; - calc_data += (data3*data3)*3.2F; - out_data_ptr = read_from_file >("STIRtmp2.hv"); - check_if_equal( calc_data, *out_data_ptr,"test with power and scalar multiplication with --including-first and --accumulate"); - } + calc_data += (data3 * data3) * 3.2F; + out_data_ptr = read_from_file>("STIRtmp2.hv"); + check_if_equal(calc_data, *out_data_ptr, + "test with power and scalar multiplication with --including-first and --accumulate"); + } remove("STIRtmp1.ahv"); remove("STIRtmp1.hv"); @@ -218,16 +203,15 @@ stir_mathTests::run_tests() // projdata { - // to keep testing code below as close as possible to the image case, we'll just + // to keep testing code below as close as possible to the image case, we'll just // take a single segment in the data. shared_ptr scanner_ptr(new Scanner(Scanner::E953)); - shared_ptr proj_data_info_ptr( - ProjDataInfo::ProjDataInfoCTI(scanner_ptr, - /*span=*/1, - /*max_delta=*/0, - /*num_views=*/8, - /*num_tang_poss=*/16)); + shared_ptr proj_data_info_ptr(ProjDataInfo::ProjDataInfoCTI(scanner_ptr, + /*span=*/1, + /*max_delta=*/0, + /*num_views=*/8, + /*num_tang_poss=*/16)); SegmentByView data1 = proj_data_info_ptr->get_empty_segment_by_view(0); SegmentByView data2 = proj_data_info_ptr->get_empty_segment_by_view(0); SegmentByView data3 = proj_data_info_ptr->get_empty_segment_by_view(0); @@ -239,98 +223,91 @@ stir_mathTests::run_tests() generate(data1.begin_all(), data1.end_all(), rand); generate(data2.begin_all(), data2.end_all(), rand); generate(data3.begin_all(), data3.end_all(), rand); - + // first create files and close them afterwards // This is necessary because system() requires all streams to be flushed. { shared_ptr exam_info_sptr(new ExamInfo); - + ProjDataInterfile proj_data1(exam_info_sptr, proj_data_info_ptr, "STIRtmp1"); ProjDataInterfile proj_data2(exam_info_sptr, proj_data_info_ptr, "STIRtmp2"); ProjDataInterfile proj_data3(exam_info_sptr, proj_data_info_ptr, "STIRtmp3"); - + proj_data1.set_segment(data1); proj_data2.set_segment(data2); proj_data3.set_segment(data3); - - set_tolerance(data1.find_max()/10000); + + set_tolerance(data1.find_max() / 10000); } - + // add - if (run_stir_math("-s STIRtmpout.hs STIRtmp1.hs STIRtmp2.hs STIRtmp3.hs")) - { + if (run_stir_math("-s STIRtmpout.hs STIRtmp1.hs STIRtmp2.hs STIRtmp3.hs")) { out_data_ptr = ProjData::read_from_file("STIRtmpout.hs"); calc_data = data1; calc_data += data2 + data3; - - check_if_equal( calc_data, out_data_ptr->get_segment_by_view(0), - "test on adding"); + + check_if_equal(calc_data, out_data_ptr->get_segment_by_view(0), "test on adding"); } // mult - if (run_stir_math("-s --mult STIRtmpout.hs STIRtmp1.hs STIRtmp2.hs STIRtmp3.hs")) - { + if (run_stir_math("-s --mult STIRtmpout.hs STIRtmp1.hs STIRtmp2.hs STIRtmp3.hs")) { out_data_ptr = ProjData::read_from_file("STIRtmpout.hs"); calc_data = data1; calc_data *= data2 * data3; - - check_if_equal( calc_data, out_data_ptr->get_segment_by_view(0), - "test on multiplying"); + + check_if_equal(calc_data, out_data_ptr->get_segment_by_view(0), "test on multiplying"); } // add with power etc // range for rand() is 0 to RAND_MAX - const float min_threshold = RAND_MAX/5.F; - const float max_threshold = RAND_MAX/2.F; + const float min_threshold = RAND_MAX / 5.F; + const float max_threshold = RAND_MAX / 2.F; { char cmd_args[1000]; - sprintf(cmd_args, "-s --add-scalar 3.1 --power 2 --times-scalar 3.2 --min-threshold %g --max-threshold %g " - "STIRtmpout.hs STIRtmp1.hs STIRtmp2.hs STIRtmp3.hs", - min_threshold, max_threshold); - if (run_stir_math(cmd_args)) - { - out_data_ptr = ProjData::read_from_file("STIRtmpout.hs"); - calc_data.fill(0); - SegmentByView data2_thresholded(data2); - SegmentByView data3_thresholded(data3); - threshold_upper_lower( data2_thresholded.begin_all(), data2_thresholded.end_all(), - min_threshold, max_threshold); - threshold_upper_lower( data3_thresholded.begin_all(), data3_thresholded.end_all(), - min_threshold, max_threshold); - calc_data += data1 + (data2_thresholded*data2_thresholded)*3.2F + 3.1F + (data3_thresholded*data3_thresholded)*3.2F + 3.1F; - - check_if_equal( calc_data, out_data_ptr->get_segment_by_view(0), - "test with thresholding, power and scalar multiplication and addition"); - } + sprintf(cmd_args, + "-s --add-scalar 3.1 --power 2 --times-scalar 3.2 --min-threshold %g --max-threshold %g " + "STIRtmpout.hs STIRtmp1.hs STIRtmp2.hs STIRtmp3.hs", + min_threshold, max_threshold); + if (run_stir_math(cmd_args)) { + out_data_ptr = ProjData::read_from_file("STIRtmpout.hs"); + calc_data.fill(0); + SegmentByView data2_thresholded(data2); + SegmentByView data3_thresholded(data3); + threshold_upper_lower(data2_thresholded.begin_all(), data2_thresholded.end_all(), min_threshold, max_threshold); + threshold_upper_lower(data3_thresholded.begin_all(), data3_thresholded.end_all(), min_threshold, max_threshold); + calc_data += + data1 + (data2_thresholded * data2_thresholded) * 3.2F + 3.1F + (data3_thresholded * data3_thresholded) * 3.2F + 3.1F; + + check_if_equal(calc_data, out_data_ptr->get_segment_by_view(0), + "test with thresholding, power and scalar multiplication and addition"); + } } // add with power etc and including-first - if (run_stir_math("-s --power 2 --times-scalar 3.2 --including-first STIRtmpout.hs STIRtmp1.hs STIRtmp2.hs STIRtmp3.hs")) - { + if (run_stir_math("-s --power 2 --times-scalar 3.2 --including-first STIRtmpout.hs STIRtmp1.hs STIRtmp2.hs STIRtmp3.hs")) { out_data_ptr = ProjData::read_from_file("STIRtmpout.hs"); calc_data.fill(0); - calc_data += (data1*data1 + data2*data2 + data3*data3)*3.2F; - check_if_equal( calc_data, out_data_ptr->get_segment_by_view(0), - "test with power and scalar multiplication with --including-first"); + calc_data += (data1 * data1 + data2 * data2 + data3 * data3) * 3.2F; + check_if_equal(calc_data, out_data_ptr->get_segment_by_view(0), + "test with power and scalar multiplication with --including-first"); } - // add with power etc and accumulate - if (run_stir_math("-s --accumulate --power 2 --times-scalar 3.2 --divide-scalar 1.9 --add-scalar 3.1 --mult STIRtmp1.hs STIRtmp3.hs")) - { + // add with power etc and accumulate + if (run_stir_math( + "-s --accumulate --power 2 --times-scalar 3.2 --divide-scalar 1.9 --add-scalar 3.1 --mult STIRtmp1.hs STIRtmp3.hs")) { calc_data.fill(0); calc_data += data1; - calc_data += (data3*data3)*3.2F/1.9F+3.1F; + calc_data += (data3 * data3) * 3.2F / 1.9F + 3.1F; out_data_ptr = ProjData::read_from_file("STIRtmp1.hs"); - check_if_equal( calc_data, out_data_ptr->get_segment_by_view(0), - "test with power and scalar multiplication, division and addition with --accumulate"); + check_if_equal(calc_data, out_data_ptr->get_segment_by_view(0), + "test with power and scalar multiplication, division and addition with --accumulate"); } // add with power etc and accumulate and including-first - if (run_stir_math("-s --accumulate --power 2 --times-scalar 3.2 --including-first STIRtmp2.hs STIRtmp3.hs")) - { + if (run_stir_math("-s --accumulate --power 2 --times-scalar 3.2 --including-first STIRtmp2.hs STIRtmp3.hs")) { calc_data.fill(0); calc_data += data2; calc_data *= calc_data * 3.2F; - calc_data += (data3*data3)*3.2F; + calc_data += (data3 * data3) * 3.2F; out_data_ptr = ProjData::read_from_file("STIRtmp2.hs"); - check_if_equal( calc_data, out_data_ptr->get_segment_by_view(0), - "test with power and scalar multiplication with --including-first and --accumulate"); + check_if_equal(calc_data, out_data_ptr->get_segment_by_view(0), + "test with power and scalar multiplication with --including-first and --accumulate"); } remove("STIRtmp1.hs"); @@ -342,18 +319,15 @@ stir_mathTests::run_tests() remove("STIRtmpout.hs"); remove("STIRtmpout.s"); } - } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main(int argc, char** argv) -{ - stir_mathTests tests(argc==2?argv[1] : "stir_math"); +int +main(int argc, char** argv) { + stir_mathTests tests(argc == 2 ? argv[1] : "stir_math"); tests.run_tests(); return tests.main_return_value(); } diff --git a/src/test/test_time_of_flight.cxx b/src/test/test_time_of_flight.cxx new file mode 100644 index 0000000000..ae56468b82 --- /dev/null +++ b/src/test/test_time_of_flight.cxx @@ -0,0 +1,443 @@ +/* + Copyright (C) 2016, UCL + Copyright (C) 2016, University of Hull + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details +*/ + +#include "stir/ProjDataInfoCylindricalNoArcCorr.h" +#include "stir/recon_buildblock/ProjMatrixByBin.h" +#include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" +#include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" +#include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" +#include "stir/recon_buildblock/ProjMatrixElemsForOneBin.h" +#include "stir/recon_buildblock/ProjectorByBinPair.h" +#include "stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h" +#include "stir/HighResWallClockTimer.h" +#include "stir/DiscretisedDensity.h" +#include "stir/VoxelsOnCartesianGrid.h" +#include "stir/recon_buildblock/ProjMatrixElemsForOneBin.h" +#include "stir/ViewSegmentNumbers.h" +#include "stir/RelatedViewgrams.h" +//#include "stir/geometry/line_distances.h" +#include "stir/Succeeded.h" +#include "stir/shared_ptr.h" +#include "stir/RunTests.h" +#include "stir/Scanner.h" +#include "boost/lexical_cast.hpp" + +#include "stir/info.h" +#include "stir/warning.h" + +START_NAMESPACE_STIR + +//! A helper class to keep the combination of a view, a segment and +//! a key tight. +//! \author Nikos Efthimiou +//! +class cache_index { +public: + cache_index() : key(0) { + view_num = 0; + seg_num = 0; + } + + inline bool operator==(const cache_index& Y) const { return view_num == Y.view_num && seg_num == Y.seg_num && key == Y.key; } + + inline bool operator!=(const cache_index& Y) const { return !(*this == Y); } + + inline bool operator<(const cache_index& Y) const { return view_num < Y.view_num && seg_num < Y.seg_num && key < Y.key; } + + int view_num; + int seg_num; + boost::uint32_t key; +}; + +// Helper class. +class FloatFloat { +public: + FloatFloat() { + float1 = 0.f; + float2 = 0.f; + } + float float1; + float float2; +}; + +/*! + \ingroup test + \brief Test class for Time Of Flight + \author Nikos Efthimiou + + + The following 2 tests are performed: + + *. Compare the ProjDataInfo of the GE Signa scanner to known values. + + *. Check that the sum of the TOF LOR is the same as the non TOF. + + \warning If you change the mashing factor the test_tof_proj_data_info() will fail. + \warning The execution time strongly depends on the value of the TOF mashing factor +*/ +class TOF_Tests : public RunTests { +public: + void run_tests(); + +private: + void test_tof_proj_data_info(); + + //! This checks peaks a specific bin, finds the LOR and applies all the + //! kernels of all available timing positions. Then check if the sum + //! of the TOF bins is equal to the non-TOF LOR. + void test_tof_kernel_application(bool export_to_file); + + //! Exports the nonTOF LOR to a file indicated by the current_id value + //! in the filename. + void export_lor(ProjMatrixElemsForOneBin& probabilities, const CartesianCoordinate3D& point1, + const CartesianCoordinate3D& point2, int current_id); + + //! Exports the TOF LOR. The TOFid is indicated in the fileName. + //! Only the common elements with the nonTOF LOR will be written in the file. + //! Although changing that is straight forward. + void export_lor(ProjMatrixElemsForOneBin& probabilities, const CartesianCoordinate3D& point1, + const CartesianCoordinate3D& point2, int current_id, ProjMatrixElemsForOneBin& template_probabilities); + + shared_ptr test_scanner_sptr; + shared_ptr test_proj_data_info_sptr; + + shared_ptr test_nonTOF_scanner_sptr; + shared_ptr test_nonTOF_proj_data_info_sptr; + + shared_ptr> test_discretised_density_sptr; + shared_ptr test_proj_matrix_sptr; + shared_ptr test_nonTOF_proj_matrix_sptr; + + shared_ptr projector_pair_sptr; + shared_ptr symmetries_used_sptr; +}; + +void +TOF_Tests::run_tests() { + // New Scanner + test_scanner_sptr.reset(new Scanner(Scanner::PETMR_Signa)); + test_nonTOF_scanner_sptr.reset(new Scanner(Scanner::PETMR_Signa_nonTOF)); + + // New Proj_Data_Info + const int test_tof_mashing_factor = 39; // to have 9 TOF bins (381/39=9) + test_proj_data_info_sptr.reset(ProjDataInfo::ProjDataInfoCTI(test_scanner_sptr, 1, test_scanner_sptr->get_num_rings() - 1, + test_scanner_sptr->get_num_detectors_per_ring() / 2, + test_scanner_sptr->get_max_num_non_arccorrected_bins(), + /* arc_correction*/ false)); + test_proj_data_info_sptr->set_tof_mash_factor(test_tof_mashing_factor); + + test_nonTOF_proj_data_info_sptr.reset(ProjDataInfo::ProjDataInfoCTI( + test_nonTOF_scanner_sptr, 1, test_scanner_sptr->get_num_rings() - 1, test_scanner_sptr->get_num_detectors_per_ring() / 2, + test_scanner_sptr->get_max_num_non_arccorrected_bins(), + /* arc_correction*/ false)); + + test_tof_proj_data_info(); + // test_tof_geometry_1(); + + // New Discretised Density + test_discretised_density_sptr.reset(new VoxelsOnCartesianGrid( + *test_proj_data_info_sptr, 1.f, CartesianCoordinate3D(0.f, 0.f, 0.f), CartesianCoordinate3D(-1, -1, -1))); + // New ProjMatrix + test_proj_matrix_sptr.reset(new ProjMatrixByBinUsingRayTracing()); + dynamic_cast(test_proj_matrix_sptr.get())->set_num_tangential_LORs(1); + dynamic_cast(test_proj_matrix_sptr.get()) + ->set_up(test_proj_data_info_sptr, test_discretised_density_sptr); + + test_nonTOF_proj_matrix_sptr.reset(new ProjMatrixByBinUsingRayTracing()); + dynamic_cast(test_nonTOF_proj_matrix_sptr.get())->set_num_tangential_LORs(1); + dynamic_cast(test_nonTOF_proj_matrix_sptr.get()) + ->set_up(test_nonTOF_proj_data_info_sptr, test_discretised_density_sptr); + + // Switch to true in order to export the LORs at files in the current directory + test_tof_kernel_application(false); +} + +void +TOF_Tests::test_tof_proj_data_info() { + const int correct_tof_mashing_factor = 39; + const int num_timing_positions = 9; + float correct_width_of_tof_bin = + test_scanner_sptr->get_size_of_timing_pos() * test_proj_data_info_sptr->get_tof_mash_factor() * 0.299792458f / 2; + float correct_timing_locations[num_timing_positions] = {-360.201f / 2 + correct_width_of_tof_bin / 2, + -280.156f / 2 + correct_width_of_tof_bin / 2, + -200.111f / 2 + correct_width_of_tof_bin / 2, + -120.067f / 2 + correct_width_of_tof_bin / 2, + 0.0f, + 40.022f / 2 + correct_width_of_tof_bin / 2, + 120.067f / 2 + correct_width_of_tof_bin / 2, + 200.111f / 2 + correct_width_of_tof_bin / 2, + 280.156f / 2 + correct_width_of_tof_bin / 2}; + + check_if_equal(correct_tof_mashing_factor, test_proj_data_info_sptr->get_tof_mash_factor(), "Different TOF mashing factor."); + + check_if_equal(num_timing_positions, test_proj_data_info_sptr->get_num_tof_poss(), "Different number of timing positions."); + + for (int timing_num = test_proj_data_info_sptr->get_min_tof_pos_num(), counter = 0; + timing_num <= test_proj_data_info_sptr->get_max_tof_pos_num(); ++timing_num, counter++) { + Bin bin(0, 0, 0, 0, timing_num, 1.f); + + check_if_equal(static_cast(correct_width_of_tof_bin), + static_cast(test_proj_data_info_sptr->get_sampling_in_k(bin)), "Error in get_sampling_in_k()"); + check_if_equal(static_cast(correct_timing_locations[counter]), + static_cast(test_proj_data_info_sptr->get_k(bin)), "Error in get_sampling_in_k()"); + } + + float total_width = test_proj_data_info_sptr->get_k(Bin(0, 0, 0, 0, test_proj_data_info_sptr->get_max_tof_pos_num(), 1.f)) - + test_proj_data_info_sptr->get_k(Bin(0, 0, 0, 0, test_proj_data_info_sptr->get_min_tof_pos_num(), 1.f)) + + test_proj_data_info_sptr->get_sampling_in_k(Bin(0, 0, 0, 0, 0, 1.f)); + + set_tolerance(static_cast(0.005)); + check_if_equal(static_cast(total_width), static_cast(test_proj_data_info_sptr->get_coincidence_window_width()), + "Coincidence widths don't match."); +} + +void +TOF_Tests::test_tof_kernel_application(bool print_to_file) { + int seg_num = 0; + int view_num = 0; + int axial_num = 0; + int tang_num = 0; + + float nonTOF_val = 0.0; + float TOF_val = 0.0; + + ProjMatrixElemsForOneBin proj_matrix_row; + ProjMatrixElemsForOneBin sum_tof_proj_matrix_row; + + HighResWallClockTimer t; + std::vector times_of_tofing; + + ProjDataInfoCylindrical* proj_data_ptr = dynamic_cast(test_proj_data_info_sptr.get()); + + // ProjDataInfoCylindrical* proj_data_nonTOF_ptr = + // dynamic_cast (test_nonTOF_proj_data_info_sptr.get()); + + LORInAxialAndNoArcCorrSinogramCoordinates lor; + + Bin this_bin(seg_num, view_num, axial_num, tang_num, 1.f); + + t.reset(); + t.start(); + test_nonTOF_proj_matrix_sptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, this_bin); + t.stop(); + + std::cerr << "Execution time for nonTOF: " << t.value() << std::endl; + proj_data_ptr->get_LOR(lor, this_bin); + LORAs2Points lor2(lor); + + if (print_to_file) + export_lor(proj_matrix_row, lor2.p1(), lor2.p2(), 500000000); + + for (int timing_num = test_proj_data_info_sptr->get_min_tof_pos_num(); + timing_num <= test_proj_data_info_sptr->get_max_tof_pos_num(); ++timing_num) { + ProjMatrixElemsForOneBin new_proj_matrix_row; + Bin bin(seg_num, view_num, axial_num, tang_num, timing_num, 1.f); + + t.reset(); + t.start(); + test_proj_matrix_sptr->get_proj_matrix_elems_for_one_bin(new_proj_matrix_row, bin); + t.stop(); + times_of_tofing.push_back(t.value()); + + if (print_to_file) + export_lor(new_proj_matrix_row, lor2.p1(), lor2.p2(), timing_num, proj_matrix_row); + + if (sum_tof_proj_matrix_row.size() > 0) { + ProjMatrixElemsForOneBin::iterator element_ptr = new_proj_matrix_row.begin(); + while (element_ptr != new_proj_matrix_row.end()) { + ProjMatrixElemsForOneBin::iterator sum_element_ptr = sum_tof_proj_matrix_row.begin(); + bool found = false; + while (sum_element_ptr != sum_tof_proj_matrix_row.end()) { + if (element_ptr->get_coords() == sum_element_ptr->get_coords()) { + float new_value = element_ptr->get_value() + sum_element_ptr->get_value(); + *sum_element_ptr = ProjMatrixElemsForOneBin::value_type(element_ptr->get_coords(), new_value); + found = true; + break; + } + ++sum_element_ptr; + } + if (!found) { + sum_tof_proj_matrix_row.push_back( + ProjMatrixElemsForOneBin::value_type(element_ptr->get_coords(), element_ptr->get_value())); + break; + } + ++element_ptr; + } + + } else { + ProjMatrixElemsForOneBin::iterator element_ptr = new_proj_matrix_row.begin(); + while (element_ptr != new_proj_matrix_row.end()) { + sum_tof_proj_matrix_row.push_back( + ProjMatrixElemsForOneBin::value_type(element_ptr->get_coords(), element_ptr->get_value())); + ++element_ptr; + } + } + } + + // Get value of nonTOF LOR, for central voxels only + + { + ProjMatrixElemsForOneBin::iterator element_ptr = proj_matrix_row.begin(); + while (element_ptr != proj_matrix_row.end()) { + if (element_ptr->get_value() > nonTOF_val) + nonTOF_val = element_ptr->get_value(); + ++element_ptr; + } + } + + // Get value of TOF LOR, for central voxels only + + { + ProjMatrixElemsForOneBin::iterator element_ptr = sum_tof_proj_matrix_row.begin(); + while (element_ptr != sum_tof_proj_matrix_row.end()) { + if (element_ptr->get_value() > TOF_val) + TOF_val = element_ptr->get_value(); + ++element_ptr; + } + } + + check_if_equal(static_cast(nonTOF_val), static_cast(TOF_val), + "Sum over nonTOF LOR does not match sum over TOF LOR."); + + { + double mean = 0.0; + for (unsigned i = 0; i < times_of_tofing.size(); i++) + mean += times_of_tofing.at(i); + + mean /= (times_of_tofing.size()); + + double s = 0.0; + for (unsigned i = 0; i < times_of_tofing.size(); i++) + s += (times_of_tofing.at(i) - mean) * (times_of_tofing.at(i) - mean) / (times_of_tofing.size() - 1); + + s = std::sqrt(s); + std::cerr << "Execution time for TOF: " << mean << " ±" << s; + } + + std::cerr << std::endl; +} + +void +TOF_Tests::export_lor(ProjMatrixElemsForOneBin& probabilities, const CartesianCoordinate3D& point1, + const CartesianCoordinate3D& point2, int current_id) { + std::ofstream myfile; + std::string file_name = "glor_" + boost::lexical_cast(current_id) + ".txt"; + myfile.open(file_name.c_str()); + + CartesianCoordinate3D voxel_center; + + std::vector lor_to_export; + lor_to_export.reserve(probabilities.size()); + + const CartesianCoordinate3D middle = (point1 + point2) * 0.5f; + const CartesianCoordinate3D diff = point2 - middle; + + const float lor_length = 1.f / (std::sqrt(diff.x() * diff.x() + diff.y() * diff.y() + diff.z() * diff.z())); + + ProjMatrixElemsForOneBin::iterator element_ptr = probabilities.begin(); + while (element_ptr != probabilities.end()) { + voxel_center = test_discretised_density_sptr->get_physical_coordinates_for_indices(element_ptr->get_coords()); + + // if(voxel_center.z() == 0.f) + { + project_point_on_a_line(point1, point2, voxel_center); + + const CartesianCoordinate3D x = voxel_center - middle; + + const float d2 = -inner_product(x, diff) * lor_length; + + FloatFloat tmp; + tmp.float1 = d2; + + // std::cerr<< voxel_center.x() << " " << voxel_center.y() << " " << voxel_center.z() << " " << + // d1 << " " << d2 << " " << d12 << " " << element_ptr->get_value() <get_value(); + lor_to_export.push_back(tmp); + } + ++element_ptr; + } + + for (unsigned int i = 0; i < lor_to_export.size(); i++) + myfile << lor_to_export.at(i).float1 << " " << lor_to_export.at(i).float2 << std::endl; + + myfile << std::endl; + myfile.close(); +} + +void +TOF_Tests::export_lor(ProjMatrixElemsForOneBin& probabilities, const CartesianCoordinate3D& point1, + const CartesianCoordinate3D& point2, int current_id, + ProjMatrixElemsForOneBin& template_probabilities) { + std::ofstream myfile; + std::string file_name = "glor_" + boost::lexical_cast(current_id) + ".txt"; + myfile.open(file_name.c_str()); + + const CartesianCoordinate3D middle = (point1 + point2) * 0.5f; + const CartesianCoordinate3D diff = point2 - middle; + + const float lor_length = 1.f / (std::sqrt(diff.x() * diff.x() + diff.y() * diff.y() + diff.z() * diff.z())); + + CartesianCoordinate3D voxel_center; + + std::vector lor_to_export; + lor_to_export.reserve(template_probabilities.size()); + + ProjMatrixElemsForOneBin::iterator tmpl_element_ptr = template_probabilities.begin(); + while (tmpl_element_ptr != template_probabilities.end()) { + voxel_center = test_discretised_density_sptr->get_physical_coordinates_for_indices(tmpl_element_ptr->get_coords()); + // if(voxel_center.z() == 0.f) + { + project_point_on_a_line(point1, point2, voxel_center); + + const CartesianCoordinate3D x = voxel_center - middle; + + const float d2 = -inner_product(x, diff) * lor_length; + + FloatFloat tmp; + tmp.float1 = d2; + + ProjMatrixElemsForOneBin::iterator element_ptr = probabilities.begin(); + + while (element_ptr != probabilities.end()) { + if (element_ptr->get_coords() == tmpl_element_ptr->get_coords()) { + tmp.float2 = element_ptr->get_value(); + lor_to_export.push_back(tmp); + break; + } + ++element_ptr; + } + } + ++tmpl_element_ptr; + } + + for (unsigned int i = 0; i < lor_to_export.size(); i++) + myfile << lor_to_export.at(i).float1 << " " << lor_to_export.at(i).float2 << std::endl; + + myfile << std::endl; + myfile.close(); +} + +END_NAMESPACE_STIR + +int +main() { + USING_NAMESPACE_STIR + TOF_Tests tests; + tests.run_tests(); + return tests.main_return_value(); +} diff --git a/src/test/test_warp_image.cxx b/src/test/test_warp_image.cxx index d442e683ac..65a09f7fa6 100644 --- a/src/test/test_warp_image.cxx +++ b/src/test/test_warp_image.cxx @@ -3,12 +3,12 @@ /* Copyright (C) 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -17,10 +17,10 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup test \ingroup spatial_transformation - + \brief A simple program to test the warp image functions \author Charalampos Tsoumpas */ @@ -46,135 +46,140 @@ START_NAMESPACE_STIR \brief Class with tests for warp_image functions. \ingroup test */ -class warp_imageTests : public RunTests -{ +class warp_imageTests : public RunTests { public: void run_tests(); }; void -warp_imageTests::run_tests() -{ +warp_imageTests::run_tests() { std::cerr << "Tests for warp_image" << std::endl; - CartesianCoordinate3D origin (0,1,2); - CartesianCoordinate3D grid_spacing (3,4,5); - - IndexRange<3> - range(CartesianCoordinate3D(0,-15,-14), - CartesianCoordinate3D(40,44,45)); - - VoxelsOnCartesianGrid image(range, origin, grid_spacing); + CartesianCoordinate3D origin(0, 1, 2); + CartesianCoordinate3D grid_spacing(3, 4, 5); + + IndexRange<3> range(CartesianCoordinate3D(0, -15, -14), CartesianCoordinate3D(40, 44, 45)); + + VoxelsOnCartesianGrid image(range, origin, grid_spacing); image.fill(0.F); - const BasicCoordinate<3,int> indices = make_coordinate(10,22,23); + const BasicCoordinate<3, int> indices = make_coordinate(10, 22, 23); image[indices] = 1.F; - VoxelsOnCartesianGrid motion_x(range, origin, grid_spacing); - VoxelsOnCartesianGrid motion_y(range, origin, grid_spacing); - VoxelsOnCartesianGrid motion_z(range, origin, grid_spacing); + VoxelsOnCartesianGrid motion_x(range, origin, grid_spacing); + VoxelsOnCartesianGrid motion_y(range, origin, grid_spacing); + VoxelsOnCartesianGrid motion_z(range, origin, grid_spacing); - motion_x.fill(3*grid_spacing[3]); - motion_y.fill(2*grid_spacing[2]); + motion_x.fill(3 * grid_spacing[3]); + motion_y.fill(2 * grid_spacing[2]); motion_z.fill(grid_spacing[1]); - // horrible way - but it works. I need to make it simpler. - const shared_ptr > image_sptr(image.clone()) ; - const shared_ptr > motion_x_sptr(motion_x.clone()) ; - const shared_ptr > motion_y_sptr(motion_y.clone()) ; - const shared_ptr > motion_z_sptr(motion_z.clone()) ; - std::vector > gate_sequence; + // horrible way - but it works. I need to make it simpler. + const shared_ptr> image_sptr(image.clone()); + const shared_ptr> motion_x_sptr(motion_x.clone()); + const shared_ptr> motion_y_sptr(motion_y.clone()); + const shared_ptr> motion_z_sptr(motion_z.clone()); + std::vector> gate_sequence; gate_sequence.resize(2); - for (unsigned int current_gate = 1; - current_gate <= 2; - ++current_gate) - { - gate_sequence[current_gate-1].first = current_gate; - gate_sequence[current_gate-1].second = 1; - } + for (unsigned int current_gate = 1; current_gate <= 2; ++current_gate) { + gate_sequence[current_gate - 1].first = current_gate; + gate_sequence[current_gate - 1].second = 1; + } TimeGateDefinitions gate_defs(gate_sequence); - const VoxelsOnCartesianGrid new_image=warp_image(image_sptr,motion_x_sptr,motion_y_sptr,motion_z_sptr,BSpline::BSplineType(1),0); - const BasicCoordinate<3,int> new_indices = make_coordinate(indices[1]-1,indices[2]-2,indices[3]-3); + const VoxelsOnCartesianGrid new_image = + warp_image(image_sptr, motion_x_sptr, motion_y_sptr, motion_z_sptr, BSpline::BSplineType(1), 0); + const BasicCoordinate<3, int> new_indices = make_coordinate(indices[1] - 1, indices[2] - 2, indices[3] - 3); { - check_if_equal(image[indices],1.F, "testing original image at non-zero point"); - check_if_equal(image[new_indices],0.F, "testing original image at new location"); - check_if_equal(new_image[indices],0.F, "testing warped image at original location"); - check_if_equal(new_image[new_indices],1.F, "testing warped image at new location"); + check_if_equal(image[indices], 1.F, "testing original image at non-zero point"); + check_if_equal(image[new_indices], 0.F, "testing original image at new location"); + check_if_equal(new_image[indices], 0.F, "testing warped image at original location"); + check_if_equal(new_image[new_indices], 1.F, "testing warped image at new location"); } std::cerr << "Tests for class GatedSpatialTransformation::warp_image etc" << std::endl; - const shared_ptr > new_image_sptr(new_image.clone()) ; - GatedDiscretisedDensity gated_image(image_sptr,2); - gated_image.set_density_sptr(image_sptr,1); - gated_image.set_density_sptr(new_image_sptr,2); + const shared_ptr> new_image_sptr(new_image.clone()); + GatedDiscretisedDensity gated_image(image_sptr, 2); + gated_image.set_density_sptr(image_sptr, 1); + gated_image.set_density_sptr(new_image_sptr, 2); gated_image.set_time_gate_definitions(gate_defs); - VoxelsOnCartesianGrid reverse_motion_x(range, origin, grid_spacing); - VoxelsOnCartesianGrid reverse_motion_y(range, origin, grid_spacing); - VoxelsOnCartesianGrid reverse_motion_z(range, origin, grid_spacing); - reverse_motion_x.fill(-3*grid_spacing[3]); - reverse_motion_y.fill(-2*grid_spacing[2]); - reverse_motion_z.fill(-1*grid_spacing[1]); - - // horrible way - but it works. I need to make it simpler. - const shared_ptr > reverse_motion1_x_sptr(motion_x.get_empty_copy()) ; - const shared_ptr > reverse_motion1_y_sptr(motion_y.get_empty_copy()) ; - const shared_ptr > reverse_motion1_z_sptr(motion_z.get_empty_copy()) ; - const shared_ptr > reverse_motion2_x_sptr(reverse_motion_x.clone()) ; - const shared_ptr > reverse_motion2_y_sptr(reverse_motion_y.clone()) ; - const shared_ptr > reverse_motion2_z_sptr(reverse_motion_z.clone()) ; - - GatedDiscretisedDensity reverse_gated_motion_x(image_sptr,2); - reverse_gated_motion_x.set_density_sptr(reverse_motion1_x_sptr,1); - reverse_gated_motion_x.set_density_sptr(reverse_motion2_x_sptr,2); + VoxelsOnCartesianGrid reverse_motion_x(range, origin, grid_spacing); + VoxelsOnCartesianGrid reverse_motion_y(range, origin, grid_spacing); + VoxelsOnCartesianGrid reverse_motion_z(range, origin, grid_spacing); + reverse_motion_x.fill(-3 * grid_spacing[3]); + reverse_motion_y.fill(-2 * grid_spacing[2]); + reverse_motion_z.fill(-1 * grid_spacing[1]); + + // horrible way - but it works. I need to make it simpler. + const shared_ptr> reverse_motion1_x_sptr(motion_x.get_empty_copy()); + const shared_ptr> reverse_motion1_y_sptr(motion_y.get_empty_copy()); + const shared_ptr> reverse_motion1_z_sptr(motion_z.get_empty_copy()); + const shared_ptr> reverse_motion2_x_sptr(reverse_motion_x.clone()); + const shared_ptr> reverse_motion2_y_sptr(reverse_motion_y.clone()); + const shared_ptr> reverse_motion2_z_sptr(reverse_motion_z.clone()); + + GatedDiscretisedDensity reverse_gated_motion_x(image_sptr, 2); + reverse_gated_motion_x.set_density_sptr(reverse_motion1_x_sptr, 1); + reverse_gated_motion_x.set_density_sptr(reverse_motion2_x_sptr, 2); reverse_gated_motion_x.set_time_gate_definitions(gate_defs); - GatedDiscretisedDensity reverse_gated_motion_y(image_sptr,2); - reverse_gated_motion_y.set_density_sptr(reverse_motion1_y_sptr,1); - reverse_gated_motion_y.set_density_sptr(reverse_motion2_y_sptr,2); + GatedDiscretisedDensity reverse_gated_motion_y(image_sptr, 2); + reverse_gated_motion_y.set_density_sptr(reverse_motion1_y_sptr, 1); + reverse_gated_motion_y.set_density_sptr(reverse_motion2_y_sptr, 2); reverse_gated_motion_y.set_time_gate_definitions(gate_defs); - GatedDiscretisedDensity reverse_gated_motion_z(image_sptr,2); - reverse_gated_motion_z.set_density_sptr(reverse_motion1_z_sptr,1); - reverse_gated_motion_z.set_density_sptr(reverse_motion2_z_sptr,2); + GatedDiscretisedDensity reverse_gated_motion_z(image_sptr, 2); + reverse_gated_motion_z.set_density_sptr(reverse_motion1_z_sptr, 1); + reverse_gated_motion_z.set_density_sptr(reverse_motion2_z_sptr, 2); reverse_gated_motion_z.set_time_gate_definitions(gate_defs); - + GatedSpatialTransformation mvtest; mvtest.set_gate_defs(gate_defs); - mvtest.set_spatial_transformations(reverse_gated_motion_z,reverse_gated_motion_y,reverse_gated_motion_x); + mvtest.set_spatial_transformations(reverse_gated_motion_z, reverse_gated_motion_y, reverse_gated_motion_x); VoxelsOnCartesianGrid accumulated_image(range, origin, grid_spacing); - mvtest.warp_image(accumulated_image,gated_image); + mvtest.warp_image(accumulated_image, gated_image); { // simple test for gated_image values - check_if_equal((gated_image.get_density(1))[indices],1.F, "testing 1st gate (i.e. original image) at non-zero point"); - check_if_equal((gated_image.get_density(1))[new_indices],0.F, "testing 1st gate at new location of the non-zero point"); - check_if_equal((gated_image.get_density(2))[indices],0.F, "testing 2nd gate at the original location of non-zero point"); - check_if_equal((gated_image.get_density(2))[new_indices],1.F, "testing 2nd gate at the new location of the non-zero point"); - check_if_equal((int)gated_image.get_time_gate_definitions().get_num_gates(),2, "testing gate_defs of gated_image are set correctly"); + check_if_equal((gated_image.get_density(1))[indices], 1.F, "testing 1st gate (i.e. original image) at non-zero point"); + check_if_equal((gated_image.get_density(1))[new_indices], 0.F, "testing 1st gate at new location of the non-zero point"); + check_if_equal((gated_image.get_density(2))[indices], 0.F, "testing 2nd gate at the original location of non-zero point"); + check_if_equal((gated_image.get_density(2))[new_indices], 1.F, "testing 2nd gate at the new location of the non-zero point"); + check_if_equal((int)gated_image.get_time_gate_definitions().get_num_gates(), 2, + "testing gate_defs of gated_image are set correctly"); // test if motion vectors have been set correctly - check_if_equal((reverse_gated_motion_z.get_density(2))[indices],-1*grid_spacing[1], "testing the input to set the motion in z"); - check_if_equal((mvtest.get_spatial_transformation_z().get_density(2))[indices],-1*grid_spacing[1], "testing GatedSpatialTransformation class get the motion vector z correctly"); - check_if_equal((mvtest.get_spatial_transformation_z().get_density(2))[new_indices],-1*grid_spacing[1], "testing GatedSpatialTransformation class get the motion vector z correctly"); - check_if_equal((mvtest.get_spatial_transformation_y().get_density(2))[indices],-2*grid_spacing[2], "testing GatedSpatialTransformation class get the motion vector y correctly"); - check_if_equal((mvtest.get_spatial_transformation_y().get_density(2))[new_indices],-2*grid_spacing[2], "testing GatedSpatialTransformation class get the motion vector y correctly"); - check_if_equal((mvtest.get_spatial_transformation_x().get_density(2))[indices],-3*grid_spacing[3], "testing GatedSpatialTransformation class get the motion vector x correctly"); - check_if_equal((mvtest.get_spatial_transformation_x().get_density(2))[new_indices],-3*grid_spacing[3], "testing GatedSpatialTransformation class get the motion vector x correctly"); - check_if_equal((int)gate_defs.get_num_gates(),2, "testing gate_defs are set correctly"); - check_if_equal((int)reverse_gated_motion_z.get_time_gate_definitions().get_num_gates(),2, "testing GatedSpatialTransformation class get the motion vector x correctly"); - check_if_equal((int)(mvtest.get_time_gate_definitions()).get_num_gates(),2, "testing GatedSpatialTransformation class time_gate_difinitions"); + check_if_equal((reverse_gated_motion_z.get_density(2))[indices], -1 * grid_spacing[1], + "testing the input to set the motion in z"); + check_if_equal((mvtest.get_spatial_transformation_z().get_density(2))[indices], -1 * grid_spacing[1], + "testing GatedSpatialTransformation class get the motion vector z correctly"); + check_if_equal((mvtest.get_spatial_transformation_z().get_density(2))[new_indices], -1 * grid_spacing[1], + "testing GatedSpatialTransformation class get the motion vector z correctly"); + check_if_equal((mvtest.get_spatial_transformation_y().get_density(2))[indices], -2 * grid_spacing[2], + "testing GatedSpatialTransformation class get the motion vector y correctly"); + check_if_equal((mvtest.get_spatial_transformation_y().get_density(2))[new_indices], -2 * grid_spacing[2], + "testing GatedSpatialTransformation class get the motion vector y correctly"); + check_if_equal((mvtest.get_spatial_transformation_x().get_density(2))[indices], -3 * grid_spacing[3], + "testing GatedSpatialTransformation class get the motion vector x correctly"); + check_if_equal((mvtest.get_spatial_transformation_x().get_density(2))[new_indices], -3 * grid_spacing[3], + "testing GatedSpatialTransformation class get the motion vector x correctly"); + check_if_equal((int)gate_defs.get_num_gates(), 2, "testing gate_defs are set correctly"); + check_if_equal((int)reverse_gated_motion_z.get_time_gate_definitions().get_num_gates(), 2, + "testing GatedSpatialTransformation class get the motion vector x correctly"); + check_if_equal((int)(mvtest.get_time_gate_definitions()).get_num_gates(), 2, + "testing GatedSpatialTransformation class time_gate_difinitions"); // actual test for accumulate_warp_image check_if_equal(accumulated_image[indices], 2.F, "testing the accumulated image at the original location of non-zero point"); - check_if_equal(accumulated_image[new_indices], 0.F, "testing the accumulated image at the location where the non-zero point had moved"); + check_if_equal(accumulated_image[new_indices], 0.F, + "testing the accumulated image at the location where the non-zero point had moved"); } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() -{ +int +main() { warp_imageTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_zoom_image.cxx b/src/test/test_zoom_image.cxx index 6e8857e778..6c74510c22 100644 --- a/src/test/test_zoom_image.cxx +++ b/src/test/test_zoom_image.cxx @@ -1,29 +1,29 @@ // // /* - Copyright (C) 2006- 2007, Hammersmith Imanet Ltd - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - + Copyright (C) 2006- 2007, Hammersmith Imanet Ltd + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details */ /*! \file \ingroup test - + \brief Test program for stir::zoom_image (and stir::centre_of_gravity) - + \author Kris Thielemans - + */ #include "stir/VoxelsOnCartesianGrid.h" @@ -45,39 +45,33 @@ START_NAMESPACE_STIR after zooming. This is done by checking the centre of gravity of the zoomed image. */ -class zoom_imageTests : public RunTests -{ +class zoom_imageTests : public RunTests { public: void run_tests(); }; - void zoom_imageTests::run_tests() -{ +{ std::cerr << "Tests for zoom_image\n"; - - CartesianCoordinate3D origin (0,1,2); - CartesianCoordinate3D grid_spacing (3,4,5); - - IndexRange<3> - range(CartesianCoordinate3D(0,-15,-14), - CartesianCoordinate3D(4,14,15)); - - VoxelsOnCartesianGrid image(range,origin, grid_spacing); + + CartesianCoordinate3D origin(0, 1, 2); + CartesianCoordinate3D grid_spacing(3, 4, 5); + + IndexRange<3> range(CartesianCoordinate3D(0, -15, -14), CartesianCoordinate3D(4, 14, 15)); + + VoxelsOnCartesianGrid image(range, origin, grid_spacing); image.fill(0.F); - const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); + const BasicCoordinate<3, int> indices = make_coordinate(1, 2, 3); image[indices] = 1.F; - const CartesianCoordinate3D coord = - image.get_physical_coordinates_for_indices(indices); + const CartesianCoordinate3D coord = image.get_physical_coordinates_for_indices(indices); { // check if centre_of_gravity_in_mm returns same point - check_if_equal(coord, - find_centre_of_gravity_in_mm(image), - "test on get_physical_coordinates_for_indices and find_centre_of_gravity_in_mm"); + check_if_equal(coord, find_centre_of_gravity_in_mm(image), + "test on get_physical_coordinates_for_indices and find_centre_of_gravity_in_mm"); } // we cannot have very good accuracy in the centre of gravity @@ -88,94 +82,69 @@ zoom_imageTests::run_tests() // test 2 arg zoom_image { - CartesianCoordinate3D new_origin (4.F,5.F,6.F); - CartesianCoordinate3D new_grid_spacing (2.2F,3.1F,4.3F); - - IndexRange<3> - new_range(CartesianCoordinate3D(-1,-16,-17), - CartesianCoordinate3D(5,15,20)); - - VoxelsOnCartesianGrid new_image(new_range,new_origin, new_grid_spacing); + CartesianCoordinate3D new_origin(4.F, 5.F, 6.F); + CartesianCoordinate3D new_grid_spacing(2.2F, 3.1F, 4.3F); + + IndexRange<3> new_range(CartesianCoordinate3D(-1, -16, -17), CartesianCoordinate3D(5, 15, 20)); + + VoxelsOnCartesianGrid new_image(new_range, new_origin, new_grid_spacing); zoom_image(new_image, image); { // check if centre_of_gravity_in_mm returns same point this->set_tolerance(tolerance_for_distance); - check_if_equal(coord, - find_centre_of_gravity_in_mm(new_image), - "test on 2-argument zoom_image"); + check_if_equal(coord, find_centre_of_gravity_in_mm(new_image), "test on 2-argument zoom_image"); this->set_tolerance(old_tolerance); - check_if_equal(new_range, new_image.get_index_range(), - "test on 2-argument argument zoom_image: index range"); - check_if_equal(new_grid_spacing, new_image.get_voxel_size(), - "test on 2-argument argument zoom_image: voxel size"); - check_if_equal(new_origin, new_image.get_origin(), - "test on 2-argument argument zoom_image: origin"); - + check_if_equal(new_range, new_image.get_index_range(), "test on 2-argument argument zoom_image: index range"); + check_if_equal(new_grid_spacing, new_image.get_voxel_size(), "test on 2-argument argument zoom_image: voxel size"); + check_if_equal(new_origin, new_image.get_origin(), "test on 2-argument argument zoom_image: origin"); } } - // test multiple argument zoom_image { - const CartesianCoordinate3D zooms(1.3F,1.2F,1.5F); - const CartesianCoordinate3D offsets_in_mm(3.F,4.F,5.5F); - const Coordinate3D new_sizes(30,40,50); - const VoxelsOnCartesianGrid new_image = - zoom_image(image, zooms, offsets_in_mm, new_sizes); + const CartesianCoordinate3D zooms(1.3F, 1.2F, 1.5F); + const CartesianCoordinate3D offsets_in_mm(3.F, 4.F, 5.5F); + const Coordinate3D new_sizes(30, 40, 50); + const VoxelsOnCartesianGrid new_image = zoom_image(image, zooms, offsets_in_mm, new_sizes); { // check if centre_of_gravity_in_mm returns same point this->set_tolerance(tolerance_for_distance); - check_if_equal(coord, - find_centre_of_gravity_in_mm(new_image), - "test on multiple argument zoom_image"); + check_if_equal(coord, find_centre_of_gravity_in_mm(new_image), "test on multiple argument zoom_image"); this->set_tolerance(old_tolerance); - check_if_equal(new_sizes, new_image.get_lengths(), - "test on multiple argument zoom_image: index range"); - check_if_equal(new_image.get_voxel_size(), image.get_voxel_size()/zooms, - "test on multiple argument zoom_image: voxel size"); - + check_if_equal(new_sizes, new_image.get_lengths(), "test on multiple argument zoom_image: index range"); + check_if_equal(new_image.get_voxel_size(), image.get_voxel_size() / zooms, + "test on multiple argument zoom_image: voxel size"); } } // test multiple argument zoom_image in 2D { const float zoom = 1.3F; - const CartesianCoordinate3D zooms(1.F,zoom,zoom); - const CartesianCoordinate3D offsets_in_mm(0.F,4.F,5.5F); + const CartesianCoordinate3D zooms(1.F, zoom, zoom); + const CartesianCoordinate3D offsets_in_mm(0.F, 4.F, 5.5F); const int new_size = 30; - const VoxelsOnCartesianGrid new_image = - zoom_image(image, zoom, offsets_in_mm.x(), offsets_in_mm.y(), new_size); + const VoxelsOnCartesianGrid new_image = zoom_image(image, zoom, offsets_in_mm.x(), offsets_in_mm.y(), new_size); { // check if centre_of_gravity_in_mm returns same point this->set_tolerance(tolerance_for_distance); - check_if_equal(coord, - find_centre_of_gravity_in_mm(new_image), - "test on multiple argument (2d) zoom_image"); + check_if_equal(coord, find_centre_of_gravity_in_mm(new_image), "test on multiple argument (2d) zoom_image"); this->set_tolerance(old_tolerance); - check_if_equal(image.get_min_z(), new_image.get_min_z(), - "test on multiple argument (2d) zoom_image: min_z"); - check_if_equal(image.get_max_z(), new_image.get_max_z(), - "test on multiple argument (2d) zoom_image: max_z"); - check_if_equal(new_size, new_image.get_x_size(), - "test on multiple argument (2d) zoom_image: x_size"); - check_if_equal(new_size, new_image.get_y_size(), - "test on multiple argument (2d) zoom_image: y_size"); - check_if_equal(new_image.get_voxel_size(), image.get_voxel_size()/zooms, - "test on multiple argument (2d) zoom_image: voxel size"); - + check_if_equal(image.get_min_z(), new_image.get_min_z(), "test on multiple argument (2d) zoom_image: min_z"); + check_if_equal(image.get_max_z(), new_image.get_max_z(), "test on multiple argument (2d) zoom_image: max_z"); + check_if_equal(new_size, new_image.get_x_size(), "test on multiple argument (2d) zoom_image: x_size"); + check_if_equal(new_size, new_image.get_y_size(), "test on multiple argument (2d) zoom_image: y_size"); + check_if_equal(new_image.get_voxel_size(), image.get_voxel_size() / zooms, + "test on multiple argument (2d) zoom_image: voxel size"); } } - } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main() -{ +int +main() { zoom_imageTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/utilities/SSRB.cxx b/src/utilities/SSRB.cxx index 643f45c467..1d08ffa1a0 100644 --- a/src/utilities/SSRB.cxx +++ b/src/utilities/SSRB.cxx @@ -36,7 +36,7 @@ \endcode \param num_segments_to_combine has to be odd. It is used as the number of segments in the original data to combine. - \param num_views_to_combine has to be at least 1 (which is the default). + \param num_views_to_combine has to be at least 1 (which is the default). It is used as the number of views in the original data to combine. \param num_tangential_poss_to_trim has to be smaller than the available number of tangential positions. @@ -53,14 +53,14 @@ output would correspond to a span=3 file with mashing factor 2, and would be normalised (at least as far as SSRB concerns). \a num_segments_to_combine=3 results in ring differences -1,0,1 to be combined all into segment 0, etc. - \see + \see stir::SSRB(const std::string& output_filename, const stir::ProjData& in_projdata, - const int num_segments_to_combine, - const int num_views_to_combine, - const int num_tang_poss_to_trim, - const bool do_normalisation, - const int max_in_segment_num_to_process + const int num_segments_to_combine, + const int num_views_to_combine, + const int num_tang_poss_to_trim, + const bool do_normalisation, + const int max_in_segment_num_to_process ) for info on parameters and restrictions. \code @@ -82,16 +82,15 @@ using std::cerr; USING_NAMESPACE_STIR - -static void print_usage_and_exit(const std::string& prog_name) -{ +static void +print_usage_and_exit(const std::string& prog_name) { cerr << "Usage:\n\n" << "Two options:\n" << "\t - Classical STIR SSRB method\n" << prog_name << " [-t num_tangential_poss_to_trim] \\\n" << "\toutput_filename input_projdata_name \\\n" << "\t[num_segments_to_combine \\\n" - <<"\t[ num_views_to_combine [do_norm [max_in_segment_num_to_process ]]]]\n" + << "\t[ num_views_to_combine [do_norm [max_in_segment_num_to_process ]]]]\n" << "num_segments_to_combine has to be odd. It is used as the number of segments\n" << " in the original data to combine.\n" << "num_views_to_combine has to be at least 1 (which is the default)\n" @@ -107,53 +106,45 @@ static void print_usage_and_exit(const std::string& prog_name) exit(EXIT_FAILURE); } -void classic_SSRB(int argc, char **argv) -{ +void +classic_SSRB(int argc, char** argv) { // Does the standard method of SSRB based upon numerical inputs int num_tangential_poss_to_trim = 0; - if (argc>1 && strcmp(argv[1], "-t")==0) - { + if (argc > 1 && strcmp(argv[1], "-t") == 0) { num_tangential_poss_to_trim = atoi(argv[2]); - argc -= 2; argv += 2; + argc -= 2; + argv += 2; } const string output_filename = argv[1]; shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[2]); const int num_segments_to_combine = argc <= 3 ? 1 : atoi(argv[3]); - const int num_views_to_combine = argc<=4 ? 1 : atoi(argv[4]); - const bool do_norm = argc<=5 ? true : atoi(argv[5]) != 0; - const int max_segment_num_to_process = argc <=6 ? -1 : atoi(argv[6]); + const int num_views_to_combine = argc <= 4 ? 1 : atoi(argv[4]); + const bool do_norm = argc <= 5 ? true : atoi(argv[5]) != 0; + const int max_segment_num_to_process = argc <= 6 ? -1 : atoi(argv[6]); // do standard SSRB - SSRB(output_filename, - *in_projdata_ptr, - num_segments_to_combine, - num_views_to_combine, - num_tangential_poss_to_trim, - do_norm, - max_segment_num_to_process - ); + SSRB(output_filename, *in_projdata_ptr, num_segments_to_combine, num_views_to_combine, num_tangential_poss_to_trim, do_norm, + max_segment_num_to_process); } -void template_based_SSRB(int argc, char **argv) -{ +void +template_based_SSRB(int argc, char** argv) { // Does the template based SSRB whereby the target template is given as an argument shared_ptr template_projdata_ptr = ProjData::read_from_file(argv[2]); const string output_filename = argv[3]; shared_ptr in_projdata_ptr = ProjData::read_from_file(argv[4]); - ProjDataInterfile out_proj_data(in_projdata_ptr->get_exam_info_sptr(), - template_projdata_ptr->get_proj_data_info_sptr(), output_filename, std::ios::out); - const bool do_norm = argc<=5 ? true : atoi(argv[5]) != 0; + ProjDataInterfile out_proj_data(in_projdata_ptr->get_exam_info_sptr(), template_projdata_ptr->get_proj_data_info_sptr(), + output_filename, std::ios::out); + const bool do_norm = argc <= 5 ? true : atoi(argv[5]) != 0; SSRB(out_proj_data, *in_projdata_ptr, do_norm); } -int main(int argc, char **argv) -{ - if (argc > 7 || argc < 3 ) - { +int +main(int argc, char** argv) { + if (argc > 7 || argc < 3) { print_usage_and_exit(argv[0]); } - if (strcmp(argv[1], "--template")==0) - { + if (strcmp(argv[1], "--template") == 0) { template_based_SSRB(argc, argv); } else { classic_SSRB(argc, argv); diff --git a/src/utilities/abs_image.cxx b/src/utilities/abs_image.cxx index a5ae5259e6..d98bca4f78 100644 --- a/src/utilities/abs_image.cxx +++ b/src/utilities/abs_image.cxx @@ -19,7 +19,7 @@ /*! \file \ingroup utilities - \brief It produces the absolute value image of an image. + \brief It produces the absolute value image of an image. \author Kris Thielemans \author Charalampos Tsoumpas @@ -28,7 +28,7 @@ \par Usage: \code - abs_image [-p || -d] -o output_filename -i input_filename + abs_image [-p || -d] -o output_filename -i input_filename \endcode Use -p switch for parametric images, or the -d switch for dynamic images. */ @@ -41,111 +41,97 @@ #include #include "stir/getopt.h" -int main(int argc, char * argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR; - const char * output_filename = 0; - const char * input_filename = 0; - bool do_parametric=0; - bool do_dynamic=0; + const char* output_filename = 0; + const char* input_filename = 0; + bool do_parametric = 0; + bool do_dynamic = 0; - const char * const usage = "abs_image [ -p | -d ] -o output_filename -i input_filename\n"; + const char* const usage = "abs_image [ -p | -d ] -o output_filename -i input_filename\n"; opterr = 0; { char c; - while ((c = getopt (argc, argv, "i:o:(p||d)")) != -1) - switch (c) - { - case 'i': - input_filename = optarg; - break; - case 'o': - output_filename = optarg; - break; - case 'p': - do_parametric=true; - break; - case 'd': - do_dynamic=true; - break; - case '?': - std::cerr << usage; - return EXIT_FAILURE; - default: - if (isprint (optopt)) - fprintf (stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf (stderr, - "Unknown option character `\\x%x'.\n", - optopt); - std::cerr << usage; - return EXIT_FAILURE; - } + while ((c = getopt(argc, argv, "i:o:(p||d)")) != -1) + switch (c) { + case 'i': + input_filename = optarg; + break; + case 'o': + output_filename = optarg; + break; + case 'p': + do_parametric = true; + break; + case 'd': + do_dynamic = true; + break; + case '?': + std::cerr << usage; + return EXIT_FAILURE; + default: + if (isprint(optopt)) + fprintf(stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); + std::cerr << usage; + return EXIT_FAILURE; + } } - if (output_filename==0 || input_filename==0) - { - std::cerr << usage; - return EXIT_FAILURE; - } + if (output_filename == 0 || input_filename == 0) { + std::cerr << usage; + return EXIT_FAILURE; + } - if(do_parametric)// A better way will be to template it... - { - shared_ptr - input_image_sptr(ParametricVoxelsOnCartesianGrid::read_from_file(input_filename)); - shared_ptr output_image_sptr(input_image_sptr->clone()); - ParametricVoxelsOnCartesianGrid::full_iterator out_iter = output_image_sptr->begin_all(); - ParametricVoxelsOnCartesianGrid::const_full_iterator in_iter = input_image_sptr->begin_all_const(); - while( in_iter != input_image_sptr->end_all_const()) - { - if (*in_iter<0.F) - *out_iter = -(*in_iter); - ++in_iter; ++out_iter; - } - Succeeded success = - OutputFileFormat::default_sptr()-> - write_to_file(output_filename, *output_image_sptr); - return success==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; - } - else if(do_dynamic)// A better way will be to template it... - { - const shared_ptr - input_image_sptr(read_from_file(input_filename)); - const DynamicDiscretisedDensity input_image = *input_image_sptr; - DynamicDiscretisedDensity output_image = input_image; - for(unsigned int frame_num=1;frame_num<=(input_image.get_time_frame_definitions()).get_num_frames();++frame_num) - { - DiscretisedDensity<3,float>::full_iterator out_iter = output_image[frame_num].begin_all(); - DiscretisedDensity<3,float>::const_full_iterator in_iter = input_image[frame_num].begin_all_const(); - while( in_iter != input_image[frame_num].end_all_const()) - { - if (*in_iter<0.F) - *out_iter = -(*in_iter); - ++in_iter; ++out_iter; - } - } - Succeeded success = - output_image.write_to_ecat7(output_filename); - return success==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + if (do_parametric) // A better way will be to template it... + { + shared_ptr input_image_sptr(ParametricVoxelsOnCartesianGrid::read_from_file(input_filename)); + shared_ptr output_image_sptr(input_image_sptr->clone()); + ParametricVoxelsOnCartesianGrid::full_iterator out_iter = output_image_sptr->begin_all(); + ParametricVoxelsOnCartesianGrid::const_full_iterator in_iter = input_image_sptr->begin_all_const(); + while (in_iter != input_image_sptr->end_all_const()) { + if (*in_iter < 0.F) + *out_iter = -(*in_iter); + ++in_iter; + ++out_iter; } - else - { - shared_ptr > - input_image_sptr(read_from_file >(input_filename)); + Succeeded success = + OutputFileFormat::default_sptr()->write_to_file(output_filename, *output_image_sptr); + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + } else if (do_dynamic) // A better way will be to template it... + { + const shared_ptr input_image_sptr(read_from_file(input_filename)); + const DynamicDiscretisedDensity input_image = *input_image_sptr; + DynamicDiscretisedDensity output_image = input_image; + for (unsigned int frame_num = 1; frame_num <= (input_image.get_time_frame_definitions()).get_num_frames(); ++frame_num) { + DiscretisedDensity<3, float>::full_iterator out_iter = output_image[frame_num].begin_all(); + DiscretisedDensity<3, float>::const_full_iterator in_iter = input_image[frame_num].begin_all_const(); + while (in_iter != input_image[frame_num].end_all_const()) { + if (*in_iter < 0.F) + *out_iter = -(*in_iter); + ++in_iter; + ++out_iter; + } + } + Succeeded success = output_image.write_to_ecat7(output_filename); + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + } else { + shared_ptr> input_image_sptr(read_from_file>(input_filename)); - shared_ptr > output_image_sptr(input_image_sptr->clone()); - DiscretisedDensity<3,float>::full_iterator out_iter = output_image_sptr->begin_all(); - DiscretisedDensity<3,float>::const_full_iterator in_iter = input_image_sptr->begin_all_const(); - while( in_iter != input_image_sptr->end_all_const()) - { - if (*in_iter<0.F) - *out_iter = -(*in_iter); - ++in_iter; ++out_iter; - } - Succeeded success = - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, *output_image_sptr); - return success==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + shared_ptr> output_image_sptr(input_image_sptr->clone()); + DiscretisedDensity<3, float>::full_iterator out_iter = output_image_sptr->begin_all(); + DiscretisedDensity<3, float>::const_full_iterator in_iter = input_image_sptr->begin_all_const(); + while (in_iter != input_image_sptr->end_all_const()) { + if (*in_iter < 0.F) + *out_iter = -(*in_iter); + ++in_iter; + ++out_iter; } + Succeeded success = + OutputFileFormat>::default_sptr()->write_to_file(output_filename, *output_image_sptr); + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + } } diff --git a/src/utilities/apply_normfactors.cxx b/src/utilities/apply_normfactors.cxx index e88b6b8e08..edeccb8cbb 100644 --- a/src/utilities/apply_normfactors.cxx +++ b/src/utilities/apply_normfactors.cxx @@ -40,124 +40,103 @@ #include #include - USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc<7 || argc>10) - { - std::cerr << "Usage: " << argv[0] - << " out_filename in_norm_filename_prefix measured_data apply_or_undo iter_num eff_iter_num [do_eff [ do_geo [ do_block]]]\n" - << "apply_or_undo is 1 (multiply) or 0 (divide)\n" - << "do_eff, do_geo, do_block are 1 or 0 and all default to 1\n"; - return EXIT_FAILURE; - } - - const bool do_block = argc>=10?atoi(argv[9])!=0: true; - const bool do_geo = argc>=9?atoi(argv[8])!=0: true; - const bool do_eff = argc>=8?atoi(argv[7])!=0: true; +int +main(int argc, char** argv) { + if (argc < 7 || argc > 10) { + std::cerr << "Usage: " << argv[0] + << " out_filename in_norm_filename_prefix measured_data apply_or_undo iter_num eff_iter_num [do_eff [ do_geo [ " + "do_block]]]\n" + << "apply_or_undo is 1 (multiply) or 0 (divide)\n" + << "do_eff, do_geo, do_block are 1 or 0 and all default to 1\n"; + return EXIT_FAILURE; + } + + const bool do_block = argc >= 10 ? atoi(argv[9]) != 0 : true; + const bool do_geo = argc >= 9 ? atoi(argv[8]) != 0 : true; + const bool do_eff = argc >= 8 ? atoi(argv[7]) != 0 : true; const int eff_iter_num = atoi(argv[6]); const int iter_num = atoi(argv[5]); - const bool apply_or_undo = atoi(argv[4])!=0; + const bool apply_or_undo = atoi(argv[4]) != 0; shared_ptr measured_data = ProjData::read_from_file(argv[3]); const std::string in_filename_prefix = argv[2]; const std::string output_file_name = argv[1]; const std::string program_name = argv[0]; - shared_ptr out_proj_data_ptr - (new ProjDataInterfile(measured_data->get_exam_info_sptr(), - measured_data->get_proj_data_info_sptr()->create_shared_clone(), - output_file_name)); + shared_ptr out_proj_data_ptr(new ProjDataInterfile( + measured_data->get_exam_info_sptr(), measured_data->get_proj_data_info_sptr()->create_shared_clone(), output_file_name)); - const int num_detectors = - measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); - const int num_crystals_per_block = - measured_data->get_proj_data_info_sptr()->get_scanner_ptr()-> - get_num_transaxial_crystals_per_block(); - const int num_blocks = - measured_data->get_proj_data_info_sptr()->get_scanner_ptr()-> - get_num_transaxial_blocks(); + const int num_detectors = measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_crystals_per_block = + measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_transaxial_crystals_per_block(); + const int num_blocks = measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_transaxial_blocks(); const int segment_num = 0; - Array<1,float> efficiencies(num_detectors); - assert(num_crystals_per_block%2 == 0); - GeoData norm_geo_data(IndexRange2D(num_crystals_per_block/2, num_detectors)); + Array<1, float> efficiencies(num_detectors); + assert(num_crystals_per_block % 2 == 0); + GeoData norm_geo_data(IndexRange2D(num_crystals_per_block / 2, num_detectors)); BlockData norm_block_data(IndexRange2D(num_blocks, num_blocks)); DetPairData det_pair_data; for (int ax_pos_num = measured_data->get_min_axial_pos_num(segment_num); - ax_pos_num <= measured_data->get_max_axial_pos_num(segment_num); - ++ax_pos_num) - { + ax_pos_num <= measured_data->get_max_axial_pos_num(segment_num); ++ax_pos_num) { + + // efficiencies + if (do_eff) { + char* in_filename = new char[in_filename_prefix.size() + 30]; + sprintf(in_filename, "%s_%s_%d_%d_%d.out", in_filename_prefix.c_str(), "eff", ax_pos_num, iter_num, eff_iter_num); + std::ifstream in(in_filename); + in >> efficiencies; + if (!in) { + warning("Error reading %s, using all 1s instead\n", in_filename); + efficiencies = Array<1, float>(num_detectors); + efficiencies.fill(1); + } - // efficiencies + delete[] in_filename; + } + // geo norm + if (do_geo) { + { + char* in_filename = new char[in_filename_prefix.size() + 30]; + sprintf(in_filename, "%s_%s_%d_%d.out", in_filename_prefix.c_str(), "geo", ax_pos_num, iter_num); + std::ifstream in(in_filename); + in >> norm_geo_data; + if (!in) { + warning("Error reading %s, using all 1s instead\n", in_filename); + norm_geo_data = GeoData(IndexRange2D(num_crystals_per_block / 2, num_detectors)); + norm_geo_data.fill(1); + } + delete[] in_filename; + } + } + // block norm + if (do_block) { + { + char* in_filename = new char[in_filename_prefix.size() + 30]; + sprintf(in_filename, "%s_%s_%d_%d.out", in_filename_prefix.c_str(), "block", ax_pos_num, iter_num); + std::ifstream in(in_filename); + in >> norm_block_data; + if (!in) { + warning("Error reading %s, using all 1s instead\n", in_filename); + norm_block_data = BlockData(IndexRange2D(num_blocks, num_blocks)); + norm_block_data.fill(1); + } + delete[] in_filename; + } + } + { + make_det_pair_data(det_pair_data, *measured_data, segment_num, ax_pos_num); if (do_eff) - { - char *in_filename = new char[in_filename_prefix.size() + 30]; - sprintf(in_filename, "%s_%s_%d_%d_%d.out", - in_filename_prefix.c_str(), "eff", ax_pos_num, iter_num, eff_iter_num); - std::ifstream in(in_filename); - in >> efficiencies; - if (!in) - { - warning("Error reading %s, using all 1s instead\n", in_filename); - efficiencies = Array<1,float>(num_detectors); - efficiencies.fill(1); - } - - delete[] in_filename; - } - // geo norm + apply_efficiencies(det_pair_data, efficiencies, apply_or_undo); if (do_geo) - { - { - char *in_filename = new char[in_filename_prefix.size() + 30]; - sprintf(in_filename, "%s_%s_%d_%d.out", - in_filename_prefix.c_str(), "geo", ax_pos_num, iter_num); - std::ifstream in(in_filename); - in >> norm_geo_data; - if (!in) - { - warning("Error reading %s, using all 1s instead\n", in_filename); - norm_geo_data= GeoData(IndexRange2D(num_crystals_per_block/2, num_detectors)); - norm_geo_data.fill(1); - } - delete[] in_filename; - } - } - // block norm + apply_geo_norm(det_pair_data, norm_geo_data, apply_or_undo); if (do_block) - { - { - char *in_filename = new char[in_filename_prefix.size() + 30]; - sprintf(in_filename, "%s_%s_%d_%d.out", - in_filename_prefix.c_str(), "block", ax_pos_num, iter_num); - std::ifstream in(in_filename); - in >> norm_block_data; - if (!in) - { - warning("Error reading %s, using all 1s instead\n", in_filename); - norm_block_data = BlockData(IndexRange2D(num_blocks, num_blocks)); - norm_block_data.fill(1); - } - delete[] in_filename; - } - } - { - make_det_pair_data(det_pair_data, *measured_data, segment_num, ax_pos_num); - if (do_eff) - apply_efficiencies(det_pair_data, efficiencies, apply_or_undo); - if (do_geo) - apply_geo_norm(det_pair_data, norm_geo_data, apply_or_undo); - if (do_block) - apply_block_norm(det_pair_data, norm_block_data, apply_or_undo); - set_det_pair_data(*out_proj_data_ptr, - det_pair_data, - segment_num, - ax_pos_num); - } + apply_block_norm(det_pair_data, norm_block_data, apply_or_undo); + set_det_pair_data(*out_proj_data_ptr, det_pair_data, segment_num, ax_pos_num); } + } return EXIT_SUCCESS; } diff --git a/src/utilities/apply_normfactors3D.cxx b/src/utilities/apply_normfactors3D.cxx index ff858845d0..6f82933f0a 100644 --- a/src/utilities/apply_normfactors3D.cxx +++ b/src/utilities/apply_normfactors3D.cxx @@ -41,139 +41,114 @@ #include #include - USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc<7 || argc>12) - { - std::cerr << "Usage: " << argv[0] - << " out_filename in_norm_filename_prefix measured_data apply_or_undo iter_num eff_iter_num [do_eff [ do_geo [ do_block [do_display]]]]\n" - << "apply_or_undo is 1 (multiply) or 0 (divide)\n" - << "do_eff, do_geo, do_block are 1 or 0 and all default to 1\n" - << "do_display is 1 or 0 (defaults to 0)\n"; - return EXIT_FAILURE; - } - - const bool do_display = argc>=11?atoi(argv[10])!=0 : false; - bool do_block = argc>=10?atoi(argv[9])!=0: true; - bool do_geo = argc>=9?atoi(argv[8])!=0: true; - bool do_eff = argc>=8?atoi(argv[7])!=0: true; - - // if (do_geo) - // error("Cannot do geometric factors in 3D yet"); +int +main(int argc, char** argv) { + if (argc < 7 || argc > 12) { + std::cerr << "Usage: " << argv[0] + << " out_filename in_norm_filename_prefix measured_data apply_or_undo iter_num eff_iter_num [do_eff [ do_geo [ " + "do_block [do_display]]]]\n" + << "apply_or_undo is 1 (multiply) or 0 (divide)\n" + << "do_eff, do_geo, do_block are 1 or 0 and all default to 1\n" + << "do_display is 1 or 0 (defaults to 0)\n"; + return EXIT_FAILURE; + } + + const bool do_display = argc >= 11 ? atoi(argv[10]) != 0 : false; + bool do_block = argc >= 10 ? atoi(argv[9]) != 0 : true; + bool do_geo = argc >= 9 ? atoi(argv[8]) != 0 : true; + bool do_eff = argc >= 8 ? atoi(argv[7]) != 0 : true; + + // if (do_geo) + // error("Cannot do geometric factors in 3D yet"); const int eff_iter_num = atoi(argv[6]); const int iter_num = atoi(argv[5]); - const bool apply_or_undo = atoi(argv[4])!=0; + const bool apply_or_undo = atoi(argv[4]) != 0; shared_ptr measured_data = ProjData::read_from_file(argv[3]); const std::string in_filename_prefix = argv[2]; const std::string output_file_name = argv[1]; const std::string program_name = argv[0]; - shared_ptr out_proj_data_ptr - (new ProjDataInterfile(measured_data->get_exam_info_sptr(), - measured_data->get_proj_data_info_sptr()->create_shared_clone(), - output_file_name)); - - const int num_rings = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_rings(); - const int num_detectors_per_ring = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_detectors_per_ring(); - const int num_transaxial_blocks = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_transaxial_blocks(); - const int num_axial_blocks = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_axial_blocks(); + shared_ptr out_proj_data_ptr(new ProjDataInterfile( + measured_data->get_exam_info_sptr(), measured_data->get_proj_data_info_sptr()->create_shared_clone(), output_file_name)); + + const int num_rings = measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_rings(); + const int num_detectors_per_ring = measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_detectors_per_ring(); + const int num_transaxial_blocks = measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_transaxial_blocks(); + const int num_axial_blocks = measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_axial_blocks(); const int num_transaxial_crystals_per_block = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_transaxial_crystals_per_block(); + measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_transaxial_crystals_per_block(); const int num_axial_crystals_per_block = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_axial_crystals_per_block(); - - GeoData3D norm_geo_data(num_axial_crystals_per_block, num_transaxial_crystals_per_block/2, num_rings, num_detectors_per_ring); + measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_axial_crystals_per_block(); - BlockData3D norm_block_data(num_axial_blocks, num_transaxial_blocks, - num_axial_blocks-1, num_transaxial_blocks-1); - DetectorEfficiencies efficiencies(IndexRange2D(num_rings, num_detectors_per_ring)); + GeoData3D norm_geo_data(num_axial_crystals_per_block, num_transaxial_crystals_per_block / 2, num_rings, num_detectors_per_ring); - { + BlockData3D norm_block_data(num_axial_blocks, num_transaxial_blocks, num_axial_blocks - 1, num_transaxial_blocks - 1); + DetectorEfficiencies efficiencies(IndexRange2D(num_rings, num_detectors_per_ring)); - // efficiencies - if (do_eff) - { - char *in_filename = new char[in_filename_prefix.size() + 30]; - sprintf(in_filename, "%s_%s_%d_%d.out", - in_filename_prefix.c_str(), "eff", iter_num, eff_iter_num); - std::ifstream in(in_filename); - in >> efficiencies; - if (!in) - { - warning("Error reading %s, using all 1s instead\n", in_filename); - do_eff = false; - } - delete[] in_filename; - } + { + + // efficiencies + if (do_eff) { + char* in_filename = new char[in_filename_prefix.size() + 30]; + sprintf(in_filename, "%s_%s_%d_%d.out", in_filename_prefix.c_str(), "eff", iter_num, eff_iter_num); + std::ifstream in(in_filename); + in >> efficiencies; + if (!in) { + warning("Error reading %s, using all 1s instead\n", in_filename); + do_eff = false; + } + delete[] in_filename; + } // geo norm - if (do_geo) - { - { - char *in_filename = new char[in_filename_prefix.size() + 30]; - sprintf(in_filename, "%s_%s_%d.out", - in_filename_prefix.c_str(), "geo", iter_num); - std::ifstream in(in_filename); - in >> norm_geo_data; - if (!in) - { - warning("Error reading %s, using all 1s instead\n", in_filename); - do_geo = false; - } - delete[] in_filename; - } + if (do_geo) { + { + char* in_filename = new char[in_filename_prefix.size() + 30]; + sprintf(in_filename, "%s_%s_%d.out", in_filename_prefix.c_str(), "geo", iter_num); + std::ifstream in(in_filename); + in >> norm_geo_data; + if (!in) { + warning("Error reading %s, using all 1s instead\n", in_filename); + do_geo = false; } - - // block norm - if (do_block) - { - { - char *in_filename = new char[in_filename_prefix.size() + 30]; - sprintf(in_filename, "%s_%s_%d.out", - in_filename_prefix.c_str(), "block", iter_num); - std::ifstream in(in_filename); - in >> norm_block_data; - if (!in) - { - warning("Error reading %s, using all 1s instead\n", in_filename); - do_block = false; - } - delete[] in_filename; - } - } + delete[] in_filename; + } + } + // block norm + if (do_block) { { - FanProjData fan_data; - make_fan_data(fan_data, *measured_data); -// make_fan_data_remove_gaps(fan_data, *measured_data); - - if (do_eff) - apply_efficiencies(fan_data, efficiencies, apply_or_undo); - if (do_geo) - apply_geo_norm(fan_data, norm_geo_data, apply_or_undo); - if (do_block) - apply_block_norm(fan_data, norm_block_data, apply_or_undo); - - if (do_display) - display(fan_data, "input*norm"); - set_fan_data(*out_proj_data_ptr, fan_data); -// set_fan_data_add_gaps(*out_proj_data_ptr, fan_data); - - + char* in_filename = new char[in_filename_prefix.size() + 30]; + sprintf(in_filename, "%s_%s_%d.out", in_filename_prefix.c_str(), "block", iter_num); + std::ifstream in(in_filename); + in >> norm_block_data; + if (!in) { + warning("Error reading %s, using all 1s instead\n", in_filename); + do_block = false; + } + delete[] in_filename; } } + { + FanProjData fan_data; + make_fan_data(fan_data, *measured_data); + // make_fan_data_remove_gaps(fan_data, *measured_data); + + if (do_eff) + apply_efficiencies(fan_data, efficiencies, apply_or_undo); + if (do_geo) + apply_geo_norm(fan_data, norm_geo_data, apply_or_undo); + if (do_block) + apply_block_norm(fan_data, norm_block_data, apply_or_undo); + + if (do_display) + display(fan_data, "input*norm"); + set_fan_data(*out_proj_data_ptr, fan_data); + // set_fan_data_add_gaps(*out_proj_data_ptr, fan_data); + } + } + return EXIT_SUCCESS; } diff --git a/src/utilities/attenuation_coefficients_to_projections.cxx b/src/utilities/attenuation_coefficients_to_projections.cxx index 522eb7eb87..220c33a687 100644 --- a/src/utilities/attenuation_coefficients_to_projections.cxx +++ b/src/utilities/attenuation_coefficients_to_projections.cxx @@ -26,7 +26,7 @@ attenuation_coefficients_to_projections \ --AF|--ACF \endverbatim - Use --AF if input are attenuation factors, --ACF for + Use --AF if input are attenuation factors, --ACF for attenuation correction factors (i.e. the inverse of the former). \warning Currently thresholds ACF values to maximum 150 (and AF to minimum 1/150) @@ -36,7 +36,6 @@ \author Kris Thielemans */ - #include "stir/ProjData.h" #include "stir/ProjDataInterfile.h" #include "stir/Viewgram.h" @@ -46,75 +45,63 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit() -{ - std::cerr<<"\nUsage:\nattenuation_coefficients_to_projections\n\t" - << " --AF|--ACF \n"; +static void +print_usage_and_exit() { + std::cerr << "\nUsage:\nattenuation_coefficients_to_projections\n\t" + << " --AF|--ACF \n"; exit(EXIT_FAILURE); } -int -main (int argc, char * argv[]) -{ +int +main(int argc, char* argv[]) { // TODO get this from cmdline - const float acf_threshold=150.F; - - if (argc!=4) + const float acf_threshold = 150.F; + + if (argc != 4) print_usage_and_exit(); - bool doACF=true;// initialise to avoid compiler warning - if (strcmp(argv[1],"--ACF")==0) - doACF=true; - else if (strcmp(argv[1],"--AF")==0) - doACF=false; + bool doACF = true; // initialise to avoid compiler warning + if (strcmp(argv[1], "--ACF") == 0) + doACF = true; + else if (strcmp(argv[1], "--AF") == 0) + doACF = false; else print_usage_and_exit(); - ++argv; --argc; - - shared_ptr attenuation_proj_data_ptr = - ProjData::read_from_file(argv[2]); + ++argv; + --argc; + + shared_ptr attenuation_proj_data_ptr = ProjData::read_from_file(argv[2]); const std::string output_file_name = argv[1]; - shared_ptr - out_proj_data_ptr(new ProjDataInterfile(attenuation_proj_data_ptr->get_exam_info_sptr(), - attenuation_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), - output_file_name)); - - for (int segment_num = attenuation_proj_data_ptr->get_min_segment_num(); - segment_num<= attenuation_proj_data_ptr->get_max_segment_num(); - ++segment_num) - for ( int view_num = attenuation_proj_data_ptr->get_min_view_num(); - view_num<=attenuation_proj_data_ptr->get_max_view_num(); - ++view_num) - { - Viewgram viewgram = attenuation_proj_data_ptr->get_viewgram(view_num,segment_num); - - if (doACF) - { - // threshold minimum to arbitrary value as log will otherwise explode) - threshold_lower(viewgram.begin_all(), viewgram.end_all(), 1/acf_threshold); - in_place_log(viewgram); - } - else - { - // threshold maximum to arbitrary value as log will otherwise explode) - threshold_upper(viewgram.begin_all(), viewgram.end_all(), acf_threshold); - in_place_log(viewgram); - viewgram *= -1.F; - } - - if (out_proj_data_ptr->set_viewgram(viewgram) != Succeeded::yes) - { - warning("Error setting output viewgram at segment %d view %d. Exiting", - segment_num, view_num); - return EXIT_FAILURE; - } + shared_ptr out_proj_data_ptr( + new ProjDataInterfile(attenuation_proj_data_ptr->get_exam_info_sptr(), + attenuation_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), output_file_name)); + + for (int segment_num = attenuation_proj_data_ptr->get_min_segment_num(); + segment_num <= attenuation_proj_data_ptr->get_max_segment_num(); ++segment_num) + for (int view_num = attenuation_proj_data_ptr->get_min_view_num(); view_num <= attenuation_proj_data_ptr->get_max_view_num(); + ++view_num) { + Viewgram viewgram = attenuation_proj_data_ptr->get_viewgram(view_num, segment_num); + + if (doACF) { + // threshold minimum to arbitrary value as log will otherwise explode) + threshold_lower(viewgram.begin_all(), viewgram.end_all(), 1 / acf_threshold); + in_place_log(viewgram); + } else { + // threshold maximum to arbitrary value as log will otherwise explode) + threshold_upper(viewgram.begin_all(), viewgram.end_all(), acf_threshold); + in_place_log(viewgram); + viewgram *= -1.F; + } + + if (out_proj_data_ptr->set_viewgram(viewgram) != Succeeded::yes) { + warning("Error setting output viewgram at segment %d view %d. Exiting", segment_num, view_num); + return EXIT_FAILURE; + } } - - + return EXIT_SUCCESS; } - diff --git a/src/utilities/back_project.cxx b/src/utilities/back_project.cxx index c296e559af..5e06a9c09c 100644 --- a/src/utilities/back_project.cxx +++ b/src/utilities/back_project.cxx @@ -53,60 +53,52 @@ #include #include -static void print_usage_and_exit() -{ - std::cerr<<"\nUsage:\nback_project output-filename proj_data_to_back_project template_image [backprojector-parfile ]\n"; - std::cerr<<"The default projector uses the ray-tracing matrix.\n\n"; - std::cerr<<"Example parameter file:\n\n" - <<"Back Projector parameters:=\n" - <<" type := Matrix\n" - <<" Back projector Using Matrix Parameters :=\n" - <<" Matrix type := Ray Tracing\n" - <<" Ray tracing matrix parameters :=\n" - <<" End Ray tracing matrix parameters :=\n" - <<" End Back Projector Using Matrix Parameters :=\n" - <<"End:=\n"; +static void +print_usage_and_exit() { + std::cerr << "\nUsage:\nback_project output-filename proj_data_to_back_project template_image [backprojector-parfile ]\n"; + std::cerr << "The default projector uses the ray-tracing matrix.\n\n"; + std::cerr << "Example parameter file:\n\n" + << "Back Projector parameters:=\n" + << " type := Matrix\n" + << " Back projector Using Matrix Parameters :=\n" + << " Matrix type := Ray Tracing\n" + << " Ray tracing matrix parameters :=\n" + << " End Ray tracing matrix parameters :=\n" + << " End Back Projector Using Matrix Parameters :=\n" + << "End:=\n"; exit(EXIT_FAILURE); } - -int -main (int argc, char * argv[]) -{ +int +main(int argc, char* argv[]) { using namespace stir; - if (argc!=4 && argc!=5 ) + if (argc != 4 && argc != 5) print_usage_and_exit(); - + const std::string output_filename = argv[1]; - shared_ptr proj_data_sptr = - ProjData::read_from_file(argv[2]); + shared_ptr proj_data_sptr = ProjData::read_from_file(argv[2]); - shared_ptr > - image_density_sptr(read_from_file >(argv[3])); + shared_ptr> image_density_sptr(read_from_file>(argv[3])); image_density_sptr->set_exam_info(proj_data_sptr->get_exam_info()); shared_ptr back_projector_sptr; - if (argc>=5) - { - KeyParser parser; - parser.add_start_key("Back Projector parameters"); - parser.add_parsing_key("type", &back_projector_sptr); - parser.add_stop_key("END"); - parser.parse(argv[4]); - } - else - { - shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); - back_projector_sptr.reset(new BackProjectorByBinUsingProjMatrixByBin(PM)); - } + if (argc >= 5) { + KeyParser parser; + parser.add_start_key("Back Projector parameters"); + parser.add_parsing_key("type", &back_projector_sptr); + parser.add_stop_key("END"); + parser.parse(argv[4]); + } else { + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + back_projector_sptr.reset(new BackProjectorByBinUsingProjMatrixByBin(PM)); + } image_density_sptr->fill(0.F); - back_projector_sptr->set_up(proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(), - image_density_sptr ); + back_projector_sptr->set_up(proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(), image_density_sptr); #if 0 back_projector_sptr->back_project(*image_density_sptr, *proj_data_sptr); @@ -115,9 +107,7 @@ main (int argc, char * argv[]) back_projector_sptr->back_project(*proj_data_sptr); back_projector_sptr->get_output(*image_density_sptr); #endif - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, *image_density_sptr); + OutputFileFormat>::default_sptr()->write_to_file(output_filename, *image_density_sptr); return EXIT_SUCCESS; } - diff --git a/src/utilities/calculate_attenuation_coefficients.cxx b/src/utilities/calculate_attenuation_coefficients.cxx index a863d8038a..9d25d749a6 100644 --- a/src/utilities/calculate_attenuation_coefficients.cxx +++ b/src/utilities/calculate_attenuation_coefficients.cxx @@ -31,7 +31,7 @@ --ACF calculates the attenuation correction factors, --AF calculates the attenuation factor (i.e. the inverse of the ACFs). - The option --PMRT forces forward projection using the Probability Matrix Using Ray Tracing + The option --PMRT forces forward projection using the Probability Matrix Using Ray Tracing (stir::ProjMatrixByBinUsingRayTracing). The attenuation_image has to contain an estimate of the mu-map for the image. It will be used @@ -66,108 +66,98 @@ using std::endl; using std::cerr; #endif - START_NAMESPACE_STIR - -static void print_usage_and_exit() -{ - std::cerr<<"\nUsage: calculate_attenuation_coefficients [--PMRT --NOPMRT] --AF|--ACF \n" - <<"\t--ACF calculates the attenuation correction factors\n" - <<"\t--AF calculates the attenuation factor (i.e. the inverse of the ACFs)\n" - <<"\t--PMRT uses the Ray Tracing Projection Matrix (default)\n" - <<"\t--NOPMRT uses the (old) Ray Tracing forward projector\n" - <<"The input image has to give the attenuation (or mu) values at 511 keV, and be in units of cm^-1.\n"; - exit(EXIT_FAILURE); +static void +print_usage_and_exit() { + std::cerr << "\nUsage: calculate_attenuation_coefficients [--PMRT --NOPMRT] --AF|--ACF \n" + << "\t--ACF calculates the attenuation correction factors\n" + << "\t--AF calculates the attenuation factor (i.e. the inverse of the ACFs)\n" + << "\t--PMRT uses the Ray Tracing Projection Matrix (default)\n" + << "\t--NOPMRT uses the (old) Ray Tracing forward projector\n" + << "The input image has to give the attenuation (or mu) values at 511 keV, and be in units of cm^-1.\n"; + exit(EXIT_FAILURE); } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int -main (int argc, char * argv[]) -{ +int +main(int argc, char* argv[]) { // variable to decide to use the ray-tracing projection matrix or not - bool use_PMRT=true; - - if (argc>1 && strcmp(argv[1],"--PMRT")==0) - { - use_PMRT=true; - --argc; ++argv; - } - if (argc!=5 ) + bool use_PMRT = true; + + if (argc > 1 && strcmp(argv[1], "--PMRT") == 0) { + use_PMRT = true; + --argc; + ++argv; + } + if (argc != 5) print_usage_and_exit(); - bool doACF=true;// initialise to avoid compiler warning - if (strcmp(argv[1],"--ACF")==0) - doACF=true; - else if (strcmp(argv[1],"--AF")==0) - doACF=false; + bool doACF = true; // initialise to avoid compiler warning + if (strcmp(argv[1], "--ACF") == 0) + doACF = true; + else if (strcmp(argv[1], "--AF") == 0) + doACF = false; else print_usage_and_exit(); - ++argv; --argc; - + ++argv; + --argc; + const std::string atten_image_filename(argv[2]); // read it to get ExamInfo - shared_ptr > - atten_image_sptr(read_from_file >(atten_image_filename)); + shared_ptr> atten_image_sptr(read_from_file>(atten_image_filename)); - shared_ptr template_proj_data_ptr = - ProjData::read_from_file(argv[3]); + shared_ptr template_proj_data_ptr = ProjData::read_from_file(argv[3]); shared_ptr forw_projector_ptr; - if (use_PMRT) - { - shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); - forw_projector_ptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); - } - else - { + if (use_PMRT) { + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + forw_projector_ptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); + } else { forw_projector_ptr.reset(new ForwardProjectorByBinUsingRayTracing()); } - cerr << "\n\nForward projector used:\n" << forw_projector_ptr->parameter_info(); + cerr << "\n\nForward projector used:\n" << forw_projector_ptr->parameter_info(); + + if (template_proj_data_ptr->get_proj_data_info_sptr()->is_tof_data()) { + warning("The scanner template provided contains timing information. The calculation of the attenuation coefficients will not " + "take them into consideration.\n"); + } const std::string output_file_name = argv[1]; - shared_ptr - out_proj_data_ptr( - new ProjDataInterfile(template_proj_data_ptr->get_exam_info_sptr(),// TODO this should say it's an ACF File - template_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), - output_file_name, - std::ios::in|std::ios::out|std::ios::trunc)); + shared_ptr out_proj_data_ptr( + new ProjDataInterfile(template_proj_data_ptr->get_exam_info_sptr(), // TODO this should say it's an ACF File + template_proj_data_ptr->get_proj_data_info_sptr()->create_non_tof_clone(), output_file_name, + std::ios::in | std::ios::out | std::ios::trunc)); // fill with 1s as we will "normalise" this sinogram. out_proj_data_ptr->fill(1.F); // construct a normalisation object that does all the work for us. - shared_ptr normalisation_ptr - (new BinNormalisationFromAttenuationImage(atten_image_filename, - forw_projector_ptr)); - - if ( - normalisation_ptr->set_up(template_proj_data_ptr->get_exam_info_sptr(), template_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone()) - != Succeeded::yes) - { - warning("calculate_attenuation_coefficients: set-up of normalisation failed\n"); - return EXIT_FAILURE; - } + shared_ptr normalisation_ptr( + new BinNormalisationFromAttenuationImage(atten_image_filename, forw_projector_ptr)); + + if (normalisation_ptr->set_up(template_proj_data_ptr->get_exam_info_sptr(), + template_proj_data_ptr->get_proj_data_info_sptr()->create_non_tof_clone()) != Succeeded::yes) { + warning("calculate_attenuation_coefficients: set-up of normalisation failed\n"); + return EXIT_FAILURE; + } // dummy values currently necessary for BinNormalisation, but they will be ignored const double start_frame = 0; const double end_frame = 0; shared_ptr symmetries_sptr(forw_projector_ptr->get_symmetries_used()->clone()); - if (doACF) - { - normalisation_ptr->apply(*out_proj_data_ptr, symmetries_sptr); - } - else - { - normalisation_ptr->undo(*out_proj_data_ptr,start_frame,end_frame, symmetries_sptr); - } + if (doACF) { + normalisation_ptr->apply(*out_proj_data_ptr, symmetries_sptr); + } else { + normalisation_ptr->undo(*out_proj_data_ptr, start_frame, end_frame, symmetries_sptr); + } return EXIT_SUCCESS; } - diff --git a/src/utilities/compare_image.cxx b/src/utilities/compare_image.cxx index b0dd2bd8a5..1ceded01cb 100644 --- a/src/utilities/compare_image.cxx +++ b/src/utilities/compare_image.cxx @@ -3,7 +3,7 @@ /*! \file -\ingroup utilities +\ingroup utilities \brief compare images to see if they are identical, allowing for small differences \author Matthew Jacobson @@ -12,7 +12,7 @@ \author Charalampos Tsoumpas: Add the tolerance as input This utility compares two images. They are deemed identical if -their maximum absolute relative difference is less than a hard-coded tolerance +their maximum absolute relative difference is less than a hard-coded tolerance value. Diagnostic output is written to stdout, and the return value indicates if the files are identical or not. @@ -36,7 +36,7 @@ if the files are identical or not. See STIR/LICENSE.txt for details */ /* Modification History: - + KT 12/09/2001 added rim_truncation option */ @@ -54,115 +54,105 @@ using std::cout; using std::endl; #endif - - //********************** main - - USING_NAMESPACE_STIR - -int main(int argc, char *argv[]) -{ - if(argc<3 || argc>7) - { - cerr << "Usage: \n" << argv[0] << "\n\t" - << "[-r rimsize] \n\t" - << "[-t tolerance] \n\t" - << "old_image new_image \n\t" - << "'rimsize' has to be a nonnegative integer.\n\t" - << "'tolerance' is by default .0005 \n\t" - << "When the -r option is used, the (radial) rim of the\n\t" - << "images will be set to 0, for 'rimsize' pixels.\n"; - return(EXIT_FAILURE); +int +main(int argc, char* argv[]) { + if (argc < 3 || argc > 7) { + cerr << "Usage: \n" + << argv[0] << "\n\t" + << "[-r rimsize] \n\t" + << "[-t tolerance] \n\t" + << "old_image new_image \n\t" + << "'rimsize' has to be a nonnegative integer.\n\t" + << "'tolerance' is by default .0005 \n\t" + << "When the -r option is used, the (radial) rim of the\n\t" + << "images will be set to 0, for 'rimsize' pixels.\n"; + return (EXIT_FAILURE); } // skip program name --argc; ++argv; int rim_truncation_image = -1; - float tolerance = .0005F ; + float tolerance = .0005F; // first process command line options - while (argc>0 && argv[0][0]=='-') - { - if (strcmp(argv[0], "-r")==0) - { - if (argc<2) - { cerr << "Option '-r' expects a nonnegative (integer) argument\n"; exit(EXIT_FAILURE); } - rim_truncation_image = atoi(argv[1]); - argc-=2; argv+=2; - } - if (strcmp(argv[0], "-t")==0) - { - if (argc<2) - { cerr << "Option '-t' expects a (float) argument\n"; exit(EXIT_FAILURE); } - tolerance = static_cast(atof(argv[1])); - argc-=2; argv+=2; - } + while (argc > 0 && argv[0][0] == '-') { + if (strcmp(argv[0], "-r") == 0) { + if (argc < 2) { + cerr << "Option '-r' expects a nonnegative (integer) argument\n"; + exit(EXIT_FAILURE); + } + rim_truncation_image = atoi(argv[1]); + argc -= 2; + argv += 2; + } + if (strcmp(argv[0], "-t") == 0) { + if (argc < 2) { + cerr << "Option '-t' expects a (float) argument\n"; + exit(EXIT_FAILURE); + } + tolerance = static_cast(atof(argv[1])); + argc -= 2; + argv += 2; } + } - shared_ptr< DiscretisedDensity<3,float> > - first_operand(read_from_file >(argv[0])); + shared_ptr> first_operand(read_from_file>(argv[0])); - if (is_null_ptr(first_operand)) - { cerr << "Could not read first file\n"; exit(EXIT_FAILURE); } + if (is_null_ptr(first_operand)) { + cerr << "Could not read first file\n"; + exit(EXIT_FAILURE); + } - shared_ptr< DiscretisedDensity<3,float> > - second_operand(read_from_file >(argv[1])); - if (is_null_ptr(second_operand)) - { cerr << "Could not read 2nd file\n"; exit(EXIT_FAILURE); } + shared_ptr> second_operand(read_from_file>(argv[1])); + if (is_null_ptr(second_operand)) { + cerr << "Could not read 2nd file\n"; + exit(EXIT_FAILURE); + } // check if images are compatible { std::string explanation; - if (!first_operand->has_same_characteristics(*second_operand, - explanation)) - { - warning("input images do not have the same characteristics.\n%s", - explanation.c_str()); - return EXIT_FAILURE; - } + if (!first_operand->has_same_characteristics(*second_operand, explanation)) { + warning("input images do not have the same characteristics.\n%s", explanation.c_str()); + return EXIT_FAILURE; + } } - if (rim_truncation_image>=0) - { + if (rim_truncation_image >= 0) { truncate_rim(*first_operand, rim_truncation_image); truncate_rim(*second_operand, rim_truncation_image); } - float reference_max=first_operand->find_max(); - float reference_min=first_operand->find_min(); + float reference_max = first_operand->find_max(); + float reference_min = first_operand->find_min(); - float amplitude=fabs(reference_max)>fabs(reference_min)? - fabs(reference_max):fabs(reference_min); + float amplitude = fabs(reference_max) > fabs(reference_min) ? fabs(reference_max) : fabs(reference_min); *first_operand -= *second_operand; - const float max_error=first_operand->find_max(); - const float min_error=first_operand->find_min(); + const float max_error = first_operand->find_max(); + const float min_error = first_operand->find_min(); in_place_abs(*first_operand); - const float max_abs_error=first_operand->find_max(); + const float max_abs_error = first_operand->find_max(); - const bool same=(max_abs_error/amplitude<=tolerance); + const bool same = (max_abs_error / amplitude <= tolerance); - cout << "\nMaximum absolute error = "<& input1, const SegmentByView &input2, - float &max_pos_error, float& max_neg_error, float &litude) -{ - const float reference_max=input1.find_max(); - const float reference_min=input1.find_min(); - - const float local_amplitude= - fabs(reference_max)>fabs(reference_min)? - fabs(reference_max):fabs(reference_min); - - amplitude=local_amplitude>amplitude?local_amplitude:amplitude; - - input1-=input2; - const float max_local_pos_error=input1.find_max(); - const float max_local_neg_error=input1.find_min(); - - max_pos_error=max_local_pos_error>max_pos_error? max_local_pos_error:max_pos_error; - max_neg_error=max_local_neg_error& input1, const SegmentByView& input2, float& max_pos_error, float& max_neg_error, + float& amplitude) { + const float reference_max = input1.find_max(); + const float reference_min = input1.find_min(); + + const float local_amplitude = fabs(reference_max) > fabs(reference_min) ? fabs(reference_max) : fabs(reference_min); + amplitude = local_amplitude > amplitude ? local_amplitude : amplitude; + input1 -= input2; + const float max_local_pos_error = input1.find_max(); + const float max_local_neg_error = input1.find_min(); + max_pos_error = max_local_pos_error > max_pos_error ? max_local_pos_error : max_pos_error; + max_neg_error = max_local_neg_error < max_neg_error ? max_local_neg_error : max_neg_error; +} END_NAMESPACE_STIR //********************** main - - - - -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR; // defaults - float tolerance=0.0001F; - + float tolerance = 0.0001F; // first process command line options - const char * const progname = argv[0]; + const char* const progname = argv[0]; // skip program name --argc; ++argv; - while (argc>0 && argv[0][0]=='-') - { - if (strcmp(argv[0], "-t")==0) - { - if (argc<2) - { cerr << "Option '-t' expects a (float) argument\n"; exit(EXIT_FAILURE); } - tolerance = static_cast(atof(argv[1])); - argc-=2; argv+=2; - } - else - { - std::cerr << "Unknown option '" << argv[0] <<"'\n"; exit(EXIT_FAILURE); - } + while (argc > 0 && argv[0][0] == '-') { + if (strcmp(argv[0], "-t") == 0) { + if (argc < 2) { + cerr << "Option '-t' expects a (float) argument\n"; + exit(EXIT_FAILURE); + } + tolerance = static_cast(atof(argv[1])); + argc -= 2; + argv += 2; + } else { + std::cerr << "Unknown option '" << argv[0] << "'\n"; + exit(EXIT_FAILURE); } + } - if(argc<2) - { - cerr<< "Usage:" << progname << " [-t tolerance] old_projdata new_projdata [max_segment_num]\n"; + if (argc < 2) { + cerr << "Usage:" << progname << " [-t tolerance] old_projdata new_projdata [max_segment_num]\n"; exit(EXIT_FAILURE); } - - - shared_ptr first_operand=ProjData::read_from_file(argv[0]); - shared_ptr second_operand=ProjData::read_from_file(argv[1]); + shared_ptr first_operand = ProjData::read_from_file(argv[0]); + shared_ptr second_operand = ProjData::read_from_file(argv[1]); - int max_segment=first_operand->get_max_segment_num(); - if(argc==3 && atoi(argv[2])>=0 && atoi(argv[2])get_max_segment_num(); + if (argc == 3 && atoi(argv[2]) >= 0 && atoi(argv[2]) < max_segment) + max_segment = atoi(argv[2]); // compare proj_data_info { shared_ptr first_sptr(first_operand->get_proj_data_info_sptr()->clone()); shared_ptr second_sptr(second_operand->get_proj_data_info_sptr()->clone()); - if (argc==4) - { - first_sptr->reduce_segment_range(-max_segment, max_segment); - second_sptr->reduce_segment_range(-max_segment, max_segment); - } - if (*first_sptr != *second_sptr) - { - cout << "\nProjection data sizes or other data characteristics are not identical. \n" - << "Use list_projdata_info to investigate.\n"; - return EXIT_FAILURE; } + if (argc == 4) { + first_sptr->reduce_segment_range(-max_segment, max_segment); + second_sptr->reduce_segment_range(-max_segment, max_segment); + } + if (*first_sptr != *second_sptr) { + cout << "\nProjection data sizes or other data characteristics are not identical. \n" + << "Use list_projdata_info to investigate.\n"; + return EXIT_FAILURE; + } } - float max_pos_error=0.F, max_neg_error=0.F, amplitude=0.F; - for (int segment_num = -max_segment; segment_num <= max_segment ; segment_num++) - { - SegmentByView input1=first_operand->get_segment_by_view(segment_num); - const SegmentByView input2=second_operand->get_segment_by_view(segment_num); + float max_pos_error = 0.F, max_neg_error = 0.F, amplitude = 0.F; + for (int segment_num = -max_segment; segment_num <= max_segment; segment_num++) { + SegmentByView input1 = first_operand->get_segment_by_view(segment_num); + const SegmentByView input2 = second_operand->get_segment_by_view(segment_num); - update_comparison(input1,input2,max_pos_error,max_neg_error, amplitude); - } + update_comparison(input1, input2, max_pos_error, max_neg_error, amplitude); + } - const float max_abs_error=max(max_pos_error, -max_neg_error); - bool same=(max_abs_error/amplitude<=tolerance)?true:false; + const float max_abs_error = max(max_pos_error, -max_neg_error); + bool same = (max_abs_error / amplitude <= tolerance) ? true : false; - cout << "\nMaximum absolute error = "< START_NAMESPACE_STIR -static void print_usage_and_exit() -{ - std::cerr<<"\nThis executable computes the square root of the Hessian row sum of the objective function." - "\n\nUsage: compute_sqrt_Hessian_row_sum compute_sqrt_Hessian_row_sum.par" - "\n\n (The example parameter file can be found in the samples folder.)" << std::endl; +static void +print_usage_and_exit() { + std::cerr << "\nThis executable computes the square root of the Hessian row sum of the objective function." + "\n\nUsage: compute_sqrt_Hessian_row_sum compute_sqrt_Hessian_row_sum.par" + "\n\n (The example parameter file can be found in the samples folder.)" + << std::endl; exit(EXIT_FAILURE); } END_NAMESPACE_STIR USING_NAMESPACE_STIR int -main(int argc, char *argv[]) -{ - if (argc!=2) +main(int argc, char* argv[]) { + if (argc != 2) print_usage_and_exit(); - SqrtHessianRowSum> SqrtHessianRowSumObject(argv[1]); + SqrtHessianRowSum> SqrtHessianRowSumObject(argv[1]); SqrtHessianRowSumObject.set_up(); SqrtHessianRowSumObject.process_data(); return EXIT_SUCCESS; diff --git a/src/utilities/construct_randoms_from_GEsingles.cxx b/src/utilities/construct_randoms_from_GEsingles.cxx old mode 100755 new mode 100644 index f060fd852b..3fafcd382a --- a/src/utilities/construct_randoms_from_GEsingles.cxx +++ b/src/utilities/construct_randoms_from_GEsingles.cxx @@ -64,20 +64,17 @@ using std::ios; USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc!=4 && argc!=3) - { - cerr << "Usage: " << argv[0] - << " out_filename GE_RDF_filename [template_projdata]\n" - << "The template is used for size- and time-frame-info, but actual counts are ignored.\n" - << "If no template is specified, we will use the normal GE sizes and the time frame information of the RDF.\n"; - return EXIT_FAILURE; - } +int +main(int argc, char** argv) { + if (argc != 4 && argc != 3) { + cerr << "Usage: " << argv[0] << " out_filename GE_RDF_filename [template_projdata]\n" + << "The template is used for size- and time-frame-info, but actual counts are ignored.\n" + << "If no template is specified, we will use the normal GE sizes and the time frame information of the RDF.\n"; + return EXIT_FAILURE; + } // const int eff_iter_num = atoi(argv[4]); - const int iter_num = 1;//atoi(argv[5]); + const int iter_num = 1; // atoi(argv[5]); - const string input_filename = argv[2]; const string output_file_name = argv[1]; const string program_name = argv[0]; @@ -86,82 +83,66 @@ int main(int argc, char **argv) GE::RDF_HDF5::GEHDF5Wrapper input_file(input_filename); std::string template_filename; - if (argc==4) - { - template_filename = argv[3]; - shared_ptr template_projdata_sptr = ProjData::read_from_file(template_filename); - proj_data_info_sptr = template_projdata_sptr->get_proj_data_info_sptr(); - exam_info_sptr = template_projdata_sptr->get_exam_info_sptr(); - } - else - { - template_filename = input_filename; - proj_data_info_sptr = input_file.get_proj_data_info_sptr(); - exam_info_sptr = input_file.get_exam_info_sptr(); - } - - if (exam_info_sptr->get_time_frame_definitions().get_num_time_frames()==0 || + if (argc == 4) { + template_filename = argv[3]; + shared_ptr template_projdata_sptr = ProjData::read_from_file(template_filename); + proj_data_info_sptr = template_projdata_sptr->get_proj_data_info_sptr(); + exam_info_sptr = template_projdata_sptr->get_exam_info_sptr(); + } else { + template_filename = input_filename; + proj_data_info_sptr = input_file.get_proj_data_info_sptr(); + exam_info_sptr = input_file.get_exam_info_sptr(); + } + + if (exam_info_sptr->get_time_frame_definitions().get_num_time_frames() == 0 || exam_info_sptr->get_time_frame_definitions().get_duration(1) < .0001) - error("Missing time-frame information in \"" + template_filename +'\"'); + error("Missing time-frame information in \"" + template_filename + '\"'); - ProjDataInterfile - proj_data(exam_info_sptr, - proj_data_info_sptr->create_shared_clone(), - output_file_name); + ProjDataInterfile proj_data(exam_info_sptr, proj_data_info_sptr->create_shared_clone(), output_file_name); - const int num_rings = - proj_data_info_sptr->get_scanner_ptr()->get_num_rings(); - const int num_detectors_per_ring = - proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_rings = proj_data_info_sptr->get_scanner_ptr()->get_num_rings(); + const int num_detectors_per_ring = proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring(); // this uses the wrong naming currently. It so happens that the formulas are the same // as when multiplying efficiencies DetectorEfficiencies efficiencies(IndexRange2D(num_rings, num_detectors_per_ring)); { - GE::RDF_HDF5::SinglesRatesFromGEHDF5 singles; + GE::RDF_HDF5::SinglesRatesFromGEHDF5 singles; singles.read_singles_from_listmode_file(input_filename); // efficiencies - if (true) - { - for (int r=0; r pos(c,r,0); - efficiencies[r][c]=singles.get_singles_rate(pos, - exam_info_sptr->get_time_frame_definitions().get_start_time(1), - exam_info_sptr->get_time_frame_definitions().get_end_time(1)); + if (true) { + for (int r = 0; r < num_rings; ++r) + for (int c = 0; c < num_detectors_per_ring; ++c) { + DetectionPosition<> pos(c, r, 0); + efficiencies[r][c] = singles.get_singles_rate(pos, exam_info_sptr->get_time_frame_definitions().get_start_time(1), + exam_info_sptr->get_time_frame_definitions().get_end_time(1)); } } - }// nothing + } // nothing { - const ProjDataInfoCylindricalNoArcCorr * const proj_data_info_ptr = - dynamic_cast - (proj_data.get_proj_data_info_sptr().get()); - if (proj_data_info_ptr == 0) - { + const ProjDataInfoCylindricalNoArcCorr* const proj_data_info_ptr = + dynamic_cast(proj_data.get_proj_data_info_sptr().get()); + if (proj_data_info_ptr == 0) { error("Can only process not arc-corrected data\n"); } const int half_fan_size = - std::min(proj_data_info_ptr->get_max_tangential_pos_num(), - -proj_data_info_ptr->get_min_tangential_pos_num()); - const int fan_size = 2*half_fan_size+1; + std::min(proj_data_info_ptr->get_max_tangential_pos_num(), -proj_data_info_ptr->get_min_tangential_pos_num()); + const int fan_size = 2 * half_fan_size + 1; - const int max_ring_diff = - proj_data_info_ptr->get_max_ring_difference(proj_data_info_ptr->get_max_segment_num()); + const int max_ring_diff = proj_data_info_ptr->get_max_ring_difference(proj_data_info_ptr->get_max_segment_num()); - const int mashing_factor = - proj_data_info_ptr->get_view_mashing_factor(); + const int mashing_factor = proj_data_info_ptr->get_view_mashing_factor(); shared_ptr scanner_sptr(new Scanner(*proj_data_info_ptr->get_scanner_ptr())); - const ProjDataInfoCylindricalNoArcCorr * const uncompressed_proj_data_info_ptr = - dynamic_cast(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/1, max_ring_diff, - /*num_views=*/num_detectors_per_ring/2, - fan_size, - /*arccorrection=*/false)); + const ProjDataInfoCylindricalNoArcCorr* const uncompressed_proj_data_info_ptr = + dynamic_cast( + ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/1, max_ring_diff, + /*num_views=*/num_detectors_per_ring / 2, fan_size, + /*arccorrection=*/false)); const float coincidence_time_window = input_file.get_coincidence_time_window(); @@ -181,83 +162,68 @@ int main(int argc, char **argv) const double isotope_halflife = 6586.2; const double decay_corr_factor = decay_correction_factor(isotope_halflife, 0., duration); const double total_to_activity = decay_corr_factor / duration; - info(boost::format("decay correction factor: %1%, time frame duration: %2%. total correction factor from activity to counts: %3%") - % decay_corr_factor % duration % (1/total_to_activity), + info(boost::format( + "decay correction factor: %1%, time frame duration: %2%. total correction factor from activity to counts: %3%") % + decay_corr_factor % duration % (1 / total_to_activity), 2); Bin bin; Bin uncompressed_bin; - for (bin.segment_num() = proj_data.get_min_segment_num(); - bin.segment_num() <= proj_data.get_max_segment_num(); - ++ bin.segment_num()) - { + for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); + ++bin.segment_num()) { for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - { - Sinogram sinogram = - proj_data_info_ptr->get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); + bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) { + Sinogram sinogram = proj_data_info_ptr->get_empty_sinogram(bin.axial_pos_num(), bin.segment_num()); const float out_m = proj_data_info_ptr->get_m(bin); - const int in_min_segment_num = - proj_data_info_ptr->get_min_ring_difference(bin.segment_num()); - const int in_max_segment_num = - proj_data_info_ptr->get_max_ring_difference(bin.segment_num()); + const int in_min_segment_num = proj_data_info_ptr->get_min_ring_difference(bin.segment_num()); + const int in_max_segment_num = proj_data_info_ptr->get_max_ring_difference(bin.segment_num()); // now loop over uncompressed detector-pairs { - for (uncompressed_bin.segment_num() = in_min_segment_num; - uncompressed_bin.segment_num() <= in_max_segment_num; - ++uncompressed_bin.segment_num()) - { - for (uncompressed_bin.axial_pos_num() = uncompressed_proj_data_info_ptr->get_min_axial_pos_num(uncompressed_bin.segment_num()); - uncompressed_bin.axial_pos_num() <= uncompressed_proj_data_info_ptr->get_max_axial_pos_num(uncompressed_bin.segment_num()); - ++uncompressed_bin.axial_pos_num() ) - { + for (uncompressed_bin.segment_num() = in_min_segment_num; uncompressed_bin.segment_num() <= in_max_segment_num; + ++uncompressed_bin.segment_num()) { + for (uncompressed_bin.axial_pos_num() = + uncompressed_proj_data_info_ptr->get_min_axial_pos_num(uncompressed_bin.segment_num()); + uncompressed_bin.axial_pos_num() <= + uncompressed_proj_data_info_ptr->get_max_axial_pos_num(uncompressed_bin.segment_num()); + ++uncompressed_bin.axial_pos_num()) { const float in_m = uncompressed_proj_data_info_ptr->get_m(uncompressed_bin); if (fabs(out_m - in_m) > 1E-4) continue; - // views etc - if (proj_data.get_min_view_num()!=0) + if (proj_data.get_min_view_num() != 0) error("Can only handle min_view_num==0\n"); - for (bin.view_num() = proj_data.get_min_view_num(); - bin.view_num() <= proj_data.get_max_view_num(); - ++ bin.view_num()) - { - - for (bin.tangential_pos_num() = -half_fan_size; - bin.tangential_pos_num() <= half_fan_size; - ++bin.tangential_pos_num()) - { + for (bin.view_num() = proj_data.get_min_view_num(); bin.view_num() <= proj_data.get_max_view_num(); + ++bin.view_num()) { + + for (bin.tangential_pos_num() = -half_fan_size; bin.tangential_pos_num() <= half_fan_size; + ++bin.tangential_pos_num()) { uncompressed_bin.tangential_pos_num() = bin.tangential_pos_num(); - for (uncompressed_bin.view_num() = bin.view_num()*mashing_factor; - uncompressed_bin.view_num() < (bin.view_num()+1)*mashing_factor; - ++ uncompressed_bin.view_num()) - { + for (uncompressed_bin.view_num() = bin.view_num() * mashing_factor; + uncompressed_bin.view_num() < (bin.view_num() + 1) * mashing_factor; ++uncompressed_bin.view_num()) { int ra = 0, a = 0; int rb = 0, b = 0; - uncompressed_proj_data_info_ptr->get_det_pair_for_bin(a, ra, b, rb, - uncompressed_bin); - - sinogram[bin.view_num()][bin.tangential_pos_num()] += - coincidence_time_window*efficiencies[ra][a]*efficiencies[rb][(b%num_detectors_per_ring)]*total_to_activity; - }// endfor uncompresed view num - }//endfor tangeial pos num - }// endfor view num - }//endfor uncompresed axial pos - }//endfor uncompresed segment num - }// nothing + uncompressed_proj_data_info_ptr->get_det_pair_for_bin(a, ra, b, rb, uncompressed_bin); + + sinogram[bin.view_num()][bin.tangential_pos_num()] += coincidence_time_window * efficiencies[ra][a] * + efficiencies[rb][(b % num_detectors_per_ring)] * + total_to_activity; + } // endfor uncompresed view num + } // endfor tangeial pos num + } // endfor view num + } // endfor uncompresed axial pos + } // endfor uncompresed segment num + } // nothing proj_data.set_sinogram(sinogram); - }//endfor axial pos num - - }//endfor segment num - }//nothing + } // endfor axial pos num + } // endfor segment num + } // nothing return EXIT_SUCCESS; } diff --git a/src/utilities/construct_randoms_from_singles.cxx b/src/utilities/construct_randoms_from_singles.cxx index dfb34bb3f6..2d2db4c1a9 100644 --- a/src/utilities/construct_randoms_from_singles.cxx +++ b/src/utilities/construct_randoms_from_singles.cxx @@ -29,7 +29,6 @@ #include "stir/ProjDataInterfile.h" - #include "stir/ProjDataInfoCylindricalNoArcCorr.h" #include "stir/Scanner.h" #include "stir/Bin.h" @@ -54,38 +53,33 @@ using std::ios; USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (argc!=5) - { - cerr << "Usage: " << argv[0] - << " out_filename in_norm_filename_prefix template_projdata eff_iter_num\n"; - return EXIT_FAILURE; - } +int +main(int argc, char** argv) { + if (argc != 5) { + cerr << "Usage: " << argv[0] << " out_filename in_norm_filename_prefix template_projdata eff_iter_num\n"; + return EXIT_FAILURE; + } #if 0 bool do_block = argc>=10?atoi(argv[9])!=0: true; bool do_geo = argc>=9?atoi(argv[8])!=0: true; - bool do_eff = argc>=8?atoi(argv[7])!=0: true; + bool do_eff = argc>=8?atoi(argv[7])!=0: true; #else bool do_eff = true; #endif const int eff_iter_num = atoi(argv[4]); - const int iter_num = 1;//atoi(argv[5]); - //const bool apply_or_undo = atoi(argv[4])!=0; + const int iter_num = 1; // atoi(argv[5]); + // const bool apply_or_undo = atoi(argv[4])!=0; shared_ptr template_projdata_ptr = ProjData::read_from_file(argv[3]); const string in_filename_prefix = argv[2]; const string output_file_name = argv[1]; const string program_name = argv[0]; - ProjDataInterfile - proj_data(template_projdata_ptr->get_exam_info_sptr(), - template_projdata_ptr->get_proj_data_info_sptr()->create_shared_clone(), - output_file_name); + ProjDataInterfile proj_data(template_projdata_ptr->get_exam_info_sptr(), + template_projdata_ptr->get_proj_data_info_sptr()->create_shared_clone(), output_file_name); - const int num_rings = - template_projdata_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings(); - const int num_detectors_per_ring = - template_projdata_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_rings = template_projdata_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings(); + const int num_detectors_per_ring = + template_projdata_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); #if 0 const int num_tangential_crystals_per_block = 8; const int num_tangential_blocks = num_detectors_per_ring/num_tangential_crystals_per_block; @@ -101,20 +95,17 @@ int main(int argc, char **argv) { // efficiencies - if (do_eff) - { - char *in_filename = new char[in_filename_prefix.size() + 30]; - sprintf(in_filename, "%s_%s_%d_%d.out", - in_filename_prefix.c_str(), "eff", iter_num, eff_iter_num); - ifstream in(in_filename); - in >> efficiencies; - if (!in) - { - warning("Error reading %s, using all 1s instead\n", in_filename); - do_eff = false; - } - delete[] in_filename; + if (do_eff) { + char* in_filename = new char[in_filename_prefix.size() + 30]; + sprintf(in_filename, "%s_%s_%d_%d.out", in_filename_prefix.c_str(), "eff", iter_num, eff_iter_num); + ifstream in(in_filename); + in >> efficiencies; + if (!in) { + warning("Error reading %s, using all 1s instead\n", in_filename); + do_eff = false; } + delete[] in_filename; + } #if 0 // block norm if (do_block) @@ -138,108 +129,79 @@ int main(int argc, char **argv) { const shared_ptr proj_data_info_sptr = - dynamic_pointer_cast - (proj_data.get_proj_data_info_sptr()); - if (is_null_ptr(proj_data_info_sptr)) - { - error("Can only process not arc-corrected data\n"); - } - const int max_ring_diff = - proj_data_info_sptr->get_max_ring_difference - (proj_data_info_sptr->get_max_segment_num()); + dynamic_pointer_cast(proj_data.get_proj_data_info_sptr()); + if (is_null_ptr(proj_data_info_sptr)) { + error("Can only process not arc-corrected data\n"); + } + const int max_ring_diff = proj_data_info_sptr->get_max_ring_difference(proj_data_info_sptr->get_max_segment_num()); - const int mashing_factor = - proj_data_info_sptr->get_view_mashing_factor(); + const int mashing_factor = proj_data_info_sptr->get_view_mashing_factor(); shared_ptr scanner_sptr(new Scanner(*proj_data_info_sptr->get_scanner_ptr())); - unique_ptr uncompressed_proj_data_info_uptr - (ProjDataInfo::construct_proj_data_info(scanner_sptr, - /*span=*/1, max_ring_diff, - /*num_views=*/num_detectors_per_ring / 2, - scanner_sptr->get_max_num_non_arccorrected_bins(), - /*arccorrection=*/false)); - const ProjDataInfoCylindricalNoArcCorr * const - uncompressed_proj_data_info_sptr = - dynamic_cast - (uncompressed_proj_data_info_uptr.get()); - - + unique_ptr uncompressed_proj_data_info_uptr(ProjDataInfo::construct_proj_data_info( + scanner_sptr, + /*span=*/1, max_ring_diff, + /*num_views=*/num_detectors_per_ring / 2, scanner_sptr->get_max_num_non_arccorrected_bins(), + /*arccorrection=*/false)); + const ProjDataInfoCylindricalNoArcCorr* const uncompressed_proj_data_info_sptr = + dynamic_cast(uncompressed_proj_data_info_uptr.get()); + Bin bin; Bin uncompressed_bin; - for (bin.segment_num() = proj_data.get_min_segment_num(); - bin.segment_num() <= proj_data.get_max_segment_num(); - ++ bin.segment_num()) - { - - for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - { - Sinogram sinogram = - proj_data_info_sptr->get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); - const float out_m = proj_data_info_sptr->get_m(bin); - const int in_min_segment_num = - proj_data_info_sptr->get_min_ring_difference(bin.segment_num()); - const int in_max_segment_num = - proj_data_info_sptr->get_max_ring_difference(bin.segment_num()); - - // now loop over uncompressed detector-pairs - - { - for (uncompressed_bin.segment_num() = in_min_segment_num; - uncompressed_bin.segment_num() <= in_max_segment_num; - ++uncompressed_bin.segment_num()) - for (uncompressed_bin.axial_pos_num() = uncompressed_proj_data_info_sptr->get_min_axial_pos_num(uncompressed_bin.segment_num()); - uncompressed_bin.axial_pos_num() <= uncompressed_proj_data_info_sptr->get_max_axial_pos_num(uncompressed_bin.segment_num()); - ++uncompressed_bin.axial_pos_num() ) - { - const float in_m = uncompressed_proj_data_info_sptr->get_m(uncompressed_bin); - if (fabs(out_m - in_m) > 1E-4) - continue; - - - // views etc - if (proj_data.get_min_view_num()!=0) - error("Can only handle min_view_num==0\n"); - for (bin.view_num() = proj_data.get_min_view_num(); - bin.view_num() <= proj_data.get_max_view_num(); - ++ bin.view_num()) - { - - for (bin.tangential_pos_num() = proj_data_info_sptr->get_min_tangential_pos_num(); - bin.tangential_pos_num() <= proj_data_info_sptr->get_max_tangential_pos_num(); - ++bin.tangential_pos_num()) - { - uncompressed_bin.tangential_pos_num() = - bin.tangential_pos_num(); - for (uncompressed_bin.view_num() = bin.view_num()*mashing_factor; - uncompressed_bin.view_num() < (bin.view_num()+1)*mashing_factor; - ++ uncompressed_bin.view_num()) - { - - int ra = 0, a = 0; - int rb = 0, b = 0; - - uncompressed_proj_data_info_sptr->get_det_pair_for_bin(a, ra, b, rb, - uncompressed_bin); - - /*(*segment_ptr)[bin.axial_pos_num()]*/ - sinogram[bin.view_num()][bin.tangential_pos_num()] += - efficiencies[ra][a]*efficiencies[rb][b%num_detectors_per_ring]; - } - } - } - - - } - } - proj_data.set_sinogram(sinogram); - } - + for (bin.segment_num() = proj_data.get_min_segment_num(); bin.segment_num() <= proj_data.get_max_segment_num(); + ++bin.segment_num()) { + + for (bin.axial_pos_num() = proj_data.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= proj_data.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) { + Sinogram sinogram = proj_data_info_sptr->get_empty_sinogram(bin.axial_pos_num(), bin.segment_num()); + const float out_m = proj_data_info_sptr->get_m(bin); + const int in_min_segment_num = proj_data_info_sptr->get_min_ring_difference(bin.segment_num()); + const int in_max_segment_num = proj_data_info_sptr->get_max_ring_difference(bin.segment_num()); + + // now loop over uncompressed detector-pairs + + { + for (uncompressed_bin.segment_num() = in_min_segment_num; uncompressed_bin.segment_num() <= in_max_segment_num; + ++uncompressed_bin.segment_num()) + for (uncompressed_bin.axial_pos_num() = + uncompressed_proj_data_info_sptr->get_min_axial_pos_num(uncompressed_bin.segment_num()); + uncompressed_bin.axial_pos_num() <= + uncompressed_proj_data_info_sptr->get_max_axial_pos_num(uncompressed_bin.segment_num()); + ++uncompressed_bin.axial_pos_num()) { + const float in_m = uncompressed_proj_data_info_sptr->get_m(uncompressed_bin); + if (fabs(out_m - in_m) > 1E-4) + continue; + + // views etc + if (proj_data.get_min_view_num() != 0) + error("Can only handle min_view_num==0\n"); + for (bin.view_num() = proj_data.get_min_view_num(); bin.view_num() <= proj_data.get_max_view_num(); + ++bin.view_num()) { + + for (bin.tangential_pos_num() = proj_data_info_sptr->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= proj_data_info_sptr->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) { + uncompressed_bin.tangential_pos_num() = bin.tangential_pos_num(); + for (uncompressed_bin.view_num() = bin.view_num() * mashing_factor; + uncompressed_bin.view_num() < (bin.view_num() + 1) * mashing_factor; ++uncompressed_bin.view_num()) { + + int ra = 0, a = 0; + int rb = 0, b = 0; + + uncompressed_proj_data_info_sptr->get_det_pair_for_bin(a, ra, b, rb, uncompressed_bin); + + /*(*segment_ptr)[bin.axial_pos_num()]*/ + sinogram[bin.view_num()][bin.tangential_pos_num()] += + efficiencies[ra][a] * efficiencies[rb][b % num_detectors_per_ring]; + } + } + } + } + } + proj_data.set_sinogram(sinogram); } + } } - return EXIT_SUCCESS; } diff --git a/src/utilities/conv_AVW.cxx b/src/utilities/conv_AVW.cxx index 0c246acde4..f3e12fdf19 100644 --- a/src/utilities/conv_AVW.cxx +++ b/src/utilities/conv_AVW.cxx @@ -20,7 +20,7 @@ \file \ingroup utilities \brief convert image files to different file format. Images are read using the AVW library. -\author Kris Thielemans +\author Kris Thielemans */ @@ -36,25 +36,23 @@ #include #include -void print_usage_and_exit( const char * const program_name) -{ +void +print_usage_and_exit(const char* const program_name) { { std::cerr << "Usage : " << program_name << " [ --flip_z ] imagefile\n"; AVW_List* list = AVW_ListFormats(AVW_SUPPORT_READ); std::cerr << "Supported file formats for reading by AVW:\n "; - for (int i=0; iNumberOfEntries; ++i) - { - std::cerr << list->Entry[i] << '\n'; + for (int i = 0; i < list->NumberOfEntries; ++i) { + std::cerr << list->Entry[i] << '\n'; } exit(EXIT_FAILURE); } } int -main(int argc, char **argv) -{ - const char * const program_name = argv[0]; +main(int argc, char** argv) { + const char* const program_name = argv[0]; // skip program name --argc; ++argv; @@ -62,100 +60,82 @@ main(int argc, char **argv) bool flip_z = false; // first process command line options - while (argc>0 && argv[0][0]=='-') - { - if (strcmp(argv[0], "--flip_z")==0) - { - flip_z = true; - argc-=1; argv+=1; - } - else - { - std::cerr << "Unknown option '" << argv[0] <<"'\n"; - print_usage_and_exit(program_name); + while (argc > 0 && argv[0][0] == '-') { + if (strcmp(argv[0], "--flip_z") == 0) { + flip_z = true; + argc -= 1; + argv += 1; + } else { + std::cerr << "Unknown option '" << argv[0] << "'\n"; + print_usage_and_exit(program_name); } } if (argc != 1) - print_usage_and_exit(program_name); + print_usage_and_exit(program_name); - char *imagefile = argv[0]; - stir::shared_ptr > > - output_file_format_sptr = - stir::OutputFileFormat >::default_sptr(); + char* imagefile = argv[0]; + stir::shared_ptr>> output_file_format_sptr = + stir::OutputFileFormat>::default_sptr(); { // open non-existent file first // this is necessary to get AVW_LoadObjectMap to work - AVW_ImageFile *avw_file= AVW_OpenImageFile("xxx non-existent I hope","r"); + AVW_ImageFile* avw_file = AVW_OpenImageFile("xxx non-existent I hope", "r"); } - + std::cout << "Reading ImageMap " << imagefile << '\n'; - AVW_ImageFile*avw_file = AVW_OpenImageFile(imagefile,"r"); - if(!avw_file) - { - AVW_Error("AVW_OpenImageFile"); - std::cout << std::flush; - exit(EXIT_FAILURE); - } - + AVW_ImageFile* avw_file = AVW_OpenImageFile(imagefile, "r"); + if (!avw_file) { + AVW_Error("AVW_OpenImageFile"); + std::cout << std::flush; + exit(EXIT_FAILURE); + } + std::cout << "Number of volumes: " << avw_file->NumVols << '\n'; unsigned int min_volume_num = 0; - unsigned int max_volume_num = avw_file->NumVols-1; - if (!stir::ask("Attempt all data-sets (Y) or single data-set (N)", true)) - { - min_volume_num = max_volume_num = - stir::ask_num("Volume number ? ", 1U, avw_file->NumVols, 1U) - - 1; // subtract 1 as AVW numbering starts from 0 - } + unsigned int max_volume_num = avw_file->NumVols - 1; + if (!stir::ask("Attempt all data-sets (Y) or single data-set (N)", true)) { + min_volume_num = max_volume_num = + stir::ask_num("Volume number ? ", 1U, avw_file->NumVols, 1U) - 1; // subtract 1 as AVW numbering starts from 0 + } { - AVW_Volume *volume = NULL; - for (unsigned int volume_num=min_volume_num; volume_num<=max_volume_num; ++volume_num) - { + AVW_Volume* volume = NULL; + for (unsigned int volume_num = min_volume_num; volume_num <= max_volume_num; ++volume_num) { { - volume = AVW_ReadVolume(avw_file, volume_num, volume); - if(!volume) - { - AVW_Error("AVW_ReadVolume"); - stir::warning("Error in volume %d. Skipping...", volume_num+1);//, AVW_ErrorMessage); - continue; - } - stir::shared_ptr > stir_volume_sptr = - stir::AVW::AVW_Volume_to_VoxelsOnCartesianGrid(volume, flip_z); - if (stir::is_null_ptr(stir_volume_sptr)) - { - stir::warning("Error converting volume to STIR format. Skipping...", volume_num); - continue; - } - char *header_filename = new char[strlen(imagefile) + 100]; - { - strcpy(header_filename, imagefile); - // keep extension, just in case we would have conflicts otherwise - // but replace the . with a _ - char * dot_ptr = strchr(stir::find_filename(header_filename),'.'); - if (dot_ptr != NULL) - *dot_ptr = '_'; - // now add stuff to say which frame, gate, bed, data this was - sprintf(header_filename+strlen(header_filename), "_f%ug%dd%db%d", - volume_num+1, 1, 0, 0); - } - if (output_file_format_sptr->write_to_file(header_filename, *stir_volume_sptr) - == stir::Succeeded::no) - { - stir::warning("Error writing %s", header_filename); - } - else - { - std::cout << "Wrote " << header_filename << '\n'; - } - delete[] header_filename; + volume = AVW_ReadVolume(avw_file, volume_num, volume); + if (!volume) { + AVW_Error("AVW_ReadVolume"); + stir::warning("Error in volume %d. Skipping...", volume_num + 1); //, AVW_ErrorMessage); + continue; + } + stir::shared_ptr> stir_volume_sptr = + stir::AVW::AVW_Volume_to_VoxelsOnCartesianGrid(volume, flip_z); + if (stir::is_null_ptr(stir_volume_sptr)) { + stir::warning("Error converting volume to STIR format. Skipping...", volume_num); + continue; + } + char* header_filename = new char[strlen(imagefile) + 100]; + { + strcpy(header_filename, imagefile); + // keep extension, just in case we would have conflicts otherwise + // but replace the . with a _ + char* dot_ptr = strchr(stir::find_filename(header_filename), '.'); + if (dot_ptr != NULL) + *dot_ptr = '_'; + // now add stuff to say which frame, gate, bed, data this was + sprintf(header_filename + strlen(header_filename), "_f%ug%dd%db%d", volume_num + 1, 1, 0, 0); + } + if (output_file_format_sptr->write_to_file(header_filename, *stir_volume_sptr) == stir::Succeeded::no) { + stir::warning("Error writing %s", header_filename); + } else { + std::cout << "Wrote " << header_filename << '\n'; + } + delete[] header_filename; } } AVW_DestroyVolume(volume); } AVW_CloseImageFile(avw_file); - - return(EXIT_SUCCESS); + return (EXIT_SUCCESS); } - - diff --git a/src/utilities/conv_GATE_raw_ECAT_projdata_to_interfile.cxx b/src/utilities/conv_GATE_raw_ECAT_projdata_to_interfile.cxx index fd0fc3102b..1c2fabc697 100644 --- a/src/utilities/conv_GATE_raw_ECAT_projdata_to_interfile.cxx +++ b/src/utilities/conv_GATE_raw_ECAT_projdata_to_interfile.cxx @@ -3,27 +3,27 @@ Copyright (C) 2010- 2013, King's College London Copyright (C) 2013, University College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! - \file - \ingroup utilities + \file + \ingroup utilities \brief This program converts GATE ECAT output (.ima) into STIR interfile format - + \author Charalampos Tsoumpas \author Pablo Aguiar - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/ProjDataInterfile.h" @@ -37,94 +37,82 @@ #define NUMARG 8 -int main(int argc,char **argv) -{ +int +main(int argc, char** argv) { using namespace stir; - - static const char * const options[]={ - "argv[1] GATE file\n", - "argv[2] Angles in GATE file\n", - "argv[3] Bins in GATE file\n", - "argv[4] Rings in GATE file\n", - "argv[5] STIR scanner name\n", - "argv[6] maximum ring difference to use for writing\n", - "argv[7] STIR file name\n" - }; - if (argc!=NUMARG){ + + static const char* const options[] = {"argv[1] GATE file\n", "argv[2] Angles in GATE file\n", + "argv[3] Bins in GATE file\n", "argv[4] Rings in GATE file\n", + "argv[5] STIR scanner name\n", "argv[6] maximum ring difference to use for writing\n", + "argv[7] STIR file name\n"}; + if (argc != NUMARG) { std::cerr << "\n\nConvert GATE ECAT format to STIR\n\n"; std::cerr << "Not enough arguments !!! ..\n"; - for (int i=1;i=num_rings) - error("Cannot have max ring difference larger than the number of rings"); - if( sizeof(short int)!=2 ) - error("Expected Input Data should be in UINT16 format\nand size of short int is should be 2\n") ; - shared_ptr scanner_sptr( Scanner::get_scanner_from_name(scanner_name)); + const char* const STIR_output_filename = argv[7]; + const long num_bins_per_sino = num_views * num_tangential_poss; + + if (max_ring_difference >= num_rings) + error("Cannot have max ring difference larger than the number of rings"); + if (sizeof(short int) != 2) + error("Expected Input Data should be in UINT16 format\nand size of short int is should be 2\n"); + shared_ptr scanner_sptr(Scanner::get_scanner_from_name(scanner_name)); if (is_null_ptr(scanner_sptr)) error("Scanner '%s' is not a valid name", scanner_name); - - FILE *GATE_file ; - if( (GATE_file=fopen(GATE_filename,"rb"))==NULL) + + FILE* GATE_file; + if ((GATE_file = fopen(GATE_filename, "rb")) == NULL) error("Cannot open GATE file %s", GATE_filename); else { - long GATE_file_size=fseek(GATE_file, 0, SEEK_END); - GATE_file_size=ftell(GATE_file); + long GATE_file_size = fseek(GATE_file, 0, SEEK_END); + GATE_file_size = ftell(GATE_file); rewind(GATE_file); - std::cerr << GATE_file_size << " size of file" << std::endl; - std::cerr << num_bins_per_sino << " bins per sino" << std::endl; - - if( GATE_file_size%num_bins_per_sino!=0 ) - error("Expected Input Data should be multiple of the number of bins per sinogram. Check input for bins and angles or GATE file.\n") ; + std::cerr << GATE_file_size << " size of file" << std::endl; + std::cerr << num_bins_per_sino << " bins per sino" << std::endl; + + if (GATE_file_size % num_bins_per_sino != 0) + error("Expected Input Data should be multiple of the number of bins per sinogram. Check input for bins and angles or GATE " + "file.\n"); } - const float STIR_scanner_length = - scanner_sptr->get_num_rings() * scanner_sptr->get_ring_spacing(); + const float STIR_scanner_length = scanner_sptr->get_num_rings() * scanner_sptr->get_ring_spacing(); scanner_sptr->set_num_rings(num_rings); - scanner_sptr->set_ring_spacing(STIR_scanner_length/num_rings); - scanner_sptr->set_num_detectors_per_ring(num_views*2); - shared_ptr proj_data_info_sptr( - ProjDataInfo::ProjDataInfoCTI( scanner_sptr, - /*span=*/1, - /*max_delta=*/max_ring_difference, - num_views, - num_tangential_poss, - /*arc_corrected =*/ false)); + scanner_sptr->set_ring_spacing(STIR_scanner_length / num_rings); + scanner_sptr->set_num_detectors_per_ring(num_views * 2); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/1, + /*max_delta=*/max_ring_difference, num_views, + num_tangential_poss, + /*arc_corrected =*/false)); shared_ptr exam_info_sptr(new ExamInfo); - ProjDataInterfile proj_data(exam_info_sptr, proj_data_info_sptr, - STIR_output_filename, std::ios::out); - + ProjDataInterfile proj_data(exam_info_sptr, proj_data_info_sptr, STIR_output_filename, std::ios::out); + // loop over segments in the GATE ECAT output in a fancy way - for (int seg_num=0; seg_num<=max_ring_difference; seg_num = (seg_num<=0) ? 1+seg_num*-1 : -1*seg_num) - { - // correct sign - const int segment_num = -seg_num; - for (int axial_pos_num = proj_data.get_min_axial_pos_num(segment_num); - axial_pos_num <= proj_data.get_max_axial_pos_num(segment_num); - axial_pos_num++) - { - Sinogram sino = proj_data.get_empty_sinogram(axial_pos_num,segment_num); - float scale=1; - if (read_data(GATE_file, sino, NumericType::SHORT, scale) != - Succeeded::yes) - { - warning("error reading from GATE sino"); - fclose(GATE_file); - return EXIT_FAILURE; - } - proj_data.set_sinogram(sino); - } + for (int seg_num = 0; seg_num <= max_ring_difference; seg_num = (seg_num <= 0) ? 1 + seg_num * -1 : -1 * seg_num) { + // correct sign + const int segment_num = -seg_num; + for (int axial_pos_num = proj_data.get_min_axial_pos_num(segment_num); + axial_pos_num <= proj_data.get_max_axial_pos_num(segment_num); axial_pos_num++) { + Sinogram sino = proj_data.get_empty_sinogram(axial_pos_num, segment_num); + float scale = 1; + if (read_data(GATE_file, sino, NumericType::SHORT, scale) != Succeeded::yes) { + warning("error reading from GATE sino"); + fclose(GATE_file); + return EXIT_FAILURE; + } + proj_data.set_sinogram(sino); } + } fclose(GATE_file); - + return EXIT_SUCCESS; } diff --git a/src/utilities/conv_gipl_to_interfile.cxx b/src/utilities/conv_gipl_to_interfile.cxx index a272810779..7feb1c93cb 100644 --- a/src/utilities/conv_gipl_to_interfile.cxx +++ b/src/utilities/conv_gipl_to_interfile.cxx @@ -2,12 +2,12 @@ Copyright (C) 2009 - 2013, King's College London Copyright (C) 2013, University College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -16,9 +16,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities - + \brief This program converts Images from GIPL (Guy's Imaging Processing Lab) format to Interfile Format. \author Charalampos Tsoumpas */ @@ -45,130 +45,129 @@ using std::cerr; using std::endl; #endif - USING_NAMESPACE_STIR // ------------------------------------------------------------------------- // Main function // ------------------------------------------------------------------------- -int main(int argc, char* argv[]) -{ - if(argc>3 || argc<2) { - std::cerr<<"Usage: " << argv[0] << " \n" - << "\nConversion of an image from gipl format to interfile.\n" - << "Orientation flag can be: 1, 2 or 3\n" - << " For Transverse set to: 1 \n" - << " For Coronal set to: 2 \n" - << " For Sagittal set to: 3 \n" - << "\t Orientation defaults to Transverse \n" - << "output file will change only extension\n"; +int +main(int argc, char* argv[]) { + if (argc > 3 || argc < 2) { + std::cerr << "Usage: " << argv[0] << " \n" + << "\nConversion of an image from gipl format to interfile.\n" + << "Orientation flag can be: 1, 2 or 3\n" + << " For Transverse set to: 1 \n" + << " For Coronal set to: 2 \n" + << " For Sagittal set to: 3 \n" + << "\t Orientation defaults to Transverse \n" + << "output file will change only extension\n"; exit(EXIT_FAILURE); - } + } - Image * image= new Image; + Image* image = new Image; image->GiplRead(argv[1]); string filename(argv[1]); string output_filename; string::iterator string_iter; - for(string_iter=filename.begin(); - string_iter!=filename.end() && *string_iter!='.' ; - ++string_iter) - output_filename.push_back(*string_iter); - const int orientation = (argc==2) ? 1 : atoi(argv[2]) ; - - if (orientation==1) { - BasicCoordinate<3,int> min_range; BasicCoordinate<3,int> max_range; - min_range[1]=0; max_range[1]=image->m_dim[2]-1; - min_range[2]=-static_cast(floor(image->m_dim[1]/2.F)); max_range[2]=min_range[2] + image->m_dim[1]-1; - min_range[3]=-static_cast(floor(image->m_dim[0]/2.F)); max_range[3]=min_range[3] + image->m_dim[0]-1; - IndexRange<3> data_range(min_range,max_range); - Array<3,float> v_array(data_range); - - for (int k_out=min_range[1]; k_out<=max_range[1]; ++k_out) - for (int j_out=min_range[2]; j_out<=max_range[2]; ++j_out) - for (int i_out=min_range[3]; i_out<=max_range[3]; ++i_out) - { - int index = i_out-min_range[3] + image->ImageOffset[0]*(j_out-min_range[2]) + image->ImageOffset[1]*(k_out-min_range[1]); - if (image->m_image_type==15) - v_array[k_out][j_out][i_out]=(float)image->vData[index]; - else if (image->m_image_type==64) - v_array[k_out][j_out][i_out]=image->vData_f[index]; - } - const CartesianCoordinate3D - grid_spacing(image->m_pixdim[2],image->m_pixdim[1],image->m_pixdim[0]); - CartesianCoordinate3D origin(0.F,0.F,0.F); - // TODO not sure if this is correct for even/odd-sized data. - origin[1]=static_cast(image->m_origin[2]+image->m_pixdim[2]*image->m_dim[2]/2.F); - origin[2]=static_cast(image->m_origin[1]+image->m_pixdim[1]*image->m_dim[1]/2.F); - origin[3]=static_cast(image->m_origin[0]+image->m_pixdim[0]*image->m_dim[0]/2.F); - const VoxelsOnCartesianGrid new_image(v_array,origin,grid_spacing); - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, new_image); - } - else if (orientation==2) { - BasicCoordinate<3,int> min_range; BasicCoordinate<3,int> max_range; - min_range[1]=0; max_range[1]=image->m_dim[1]-1; - min_range[2]=-static_cast(floor(image->m_dim[2]/2.F)); max_range[2]=min_range[2] + image->m_dim[2]-1; - min_range[3]=-static_cast(floor(image->m_dim[0]/2.F)); max_range[3]=min_range[3] + image->m_dim[0]-1; - - IndexRange<3> data_range(min_range,max_range); - Array<3,float> v_array(data_range); - - for (int k_out=min_range[1]; k_out<=max_range[1]; ++k_out) - for (int j_out=min_range[2]; j_out<=max_range[2]; ++j_out) - for (int i_out=min_range[3]; i_out<=max_range[3]; ++i_out) - { - int index = i_out-min_range[3] + image->ImageOffset[0]*(k_out-min_range[1]) + image->ImageOffset[1]*(j_out-min_range[2]); - if (image->m_image_type==15) - v_array[k_out][j_out][i_out]=(float)image->vData[index]; - else if (image->m_image_type==64) - v_array[k_out][j_out][i_out]=image->vData_f[index]; - } - const CartesianCoordinate3D - grid_spacing(image->m_pixdim[1],image->m_pixdim[2],image->m_pixdim[0]); - CartesianCoordinate3D origin(0.F,0.F,0.F); - origin[2]=static_cast(image->m_origin[2]+image->m_pixdim[2]*image->m_dim[2]/2.F); - origin[1]=static_cast(image->m_origin[1]+image->m_pixdim[1]*image->m_dim[1]/2.F); - origin[3]=static_cast(image->m_origin[0]+image->m_pixdim[0]*image->m_dim[0]/2.F); - const VoxelsOnCartesianGrid new_image(v_array,origin,grid_spacing); - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, new_image); - } - else if (orientation==3) { - BasicCoordinate<3,int> min_range; BasicCoordinate<3,int> max_range; - min_range[1]=0; max_range[1]=image->m_dim[1]-1; - min_range[2]=-static_cast(floor(image->m_dim[0]/2.F)); max_range[2]=min_range[2] + image->m_dim[0]-1; - min_range[3]=-static_cast(floor(image->m_dim[2]/2.F)); max_range[3]=max_range[3] + image->m_dim[2]-1; - - IndexRange<3> data_range(min_range,max_range); - Array<3,float> v_array(data_range); - - for (int k_out=min_range[1]; k_out<=max_range[1]; ++k_out) - for (int j_out=min_range[2]; j_out<=max_range[2]; ++j_out) - for (int i_out=min_range[3]; i_out<=max_range[3]; ++i_out) - { - int index = j_out-min_range[2] + image->ImageOffset[0]*(k_out-min_range[1]) + image->ImageOffset[1]*(max_range[3]-i_out); - if (image->m_image_type==15) - v_array[k_out][j_out][i_out]=(float)image->vData[index]; - else if (image->m_image_type==64) - v_array[k_out][j_out][i_out]=image->vData_f[index]; - } - const CartesianCoordinate3D - grid_spacing(image->m_pixdim[1],image->m_pixdim[0],image->m_pixdim[2]); - CartesianCoordinate3D origin(0.F,0.F,0.F); - origin[3]=static_cast(image->m_origin[2]+image->m_pixdim[2]*image->m_dim[2]/2.F); - origin[1]=static_cast(image->m_origin[1]+image->m_pixdim[1]*image->m_dim[1]/2.F); - origin[2]=static_cast(image->m_origin[0]+image->m_pixdim[0]*image->m_dim[0]/2.F); - - const VoxelsOnCartesianGrid new_image(v_array,origin,grid_spacing); - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, new_image); + for (string_iter = filename.begin(); string_iter != filename.end() && *string_iter != '.'; ++string_iter) + output_filename.push_back(*string_iter); + const int orientation = (argc == 2) ? 1 : atoi(argv[2]); + + if (orientation == 1) { + BasicCoordinate<3, int> min_range; + BasicCoordinate<3, int> max_range; + min_range[1] = 0; + max_range[1] = image->m_dim[2] - 1; + min_range[2] = -static_cast(floor(image->m_dim[1] / 2.F)); + max_range[2] = min_range[2] + image->m_dim[1] - 1; + min_range[3] = -static_cast(floor(image->m_dim[0] / 2.F)); + max_range[3] = min_range[3] + image->m_dim[0] - 1; + IndexRange<3> data_range(min_range, max_range); + Array<3, float> v_array(data_range); + + for (int k_out = min_range[1]; k_out <= max_range[1]; ++k_out) + for (int j_out = min_range[2]; j_out <= max_range[2]; ++j_out) + for (int i_out = min_range[3]; i_out <= max_range[3]; ++i_out) { + int index = i_out - min_range[3] + image->ImageOffset[0] * (j_out - min_range[2]) + + image->ImageOffset[1] * (k_out - min_range[1]); + if (image->m_image_type == 15) + v_array[k_out][j_out][i_out] = (float)image->vData[index]; + else if (image->m_image_type == 64) + v_array[k_out][j_out][i_out] = image->vData_f[index]; + } + const CartesianCoordinate3D grid_spacing(image->m_pixdim[2], image->m_pixdim[1], image->m_pixdim[0]); + CartesianCoordinate3D origin(0.F, 0.F, 0.F); + // TODO not sure if this is correct for even/odd-sized data. + origin[1] = static_cast(image->m_origin[2] + image->m_pixdim[2] * image->m_dim[2] / 2.F); + origin[2] = static_cast(image->m_origin[1] + image->m_pixdim[1] * image->m_dim[1] / 2.F); + origin[3] = static_cast(image->m_origin[0] + image->m_pixdim[0] * image->m_dim[0] / 2.F); + const VoxelsOnCartesianGrid new_image(v_array, origin, grid_spacing); + OutputFileFormat>::default_sptr()->write_to_file(output_filename, new_image); + } else if (orientation == 2) { + BasicCoordinate<3, int> min_range; + BasicCoordinate<3, int> max_range; + min_range[1] = 0; + max_range[1] = image->m_dim[1] - 1; + min_range[2] = -static_cast(floor(image->m_dim[2] / 2.F)); + max_range[2] = min_range[2] + image->m_dim[2] - 1; + min_range[3] = -static_cast(floor(image->m_dim[0] / 2.F)); + max_range[3] = min_range[3] + image->m_dim[0] - 1; + + IndexRange<3> data_range(min_range, max_range); + Array<3, float> v_array(data_range); + + for (int k_out = min_range[1]; k_out <= max_range[1]; ++k_out) + for (int j_out = min_range[2]; j_out <= max_range[2]; ++j_out) + for (int i_out = min_range[3]; i_out <= max_range[3]; ++i_out) { + int index = i_out - min_range[3] + image->ImageOffset[0] * (k_out - min_range[1]) + + image->ImageOffset[1] * (j_out - min_range[2]); + if (image->m_image_type == 15) + v_array[k_out][j_out][i_out] = (float)image->vData[index]; + else if (image->m_image_type == 64) + v_array[k_out][j_out][i_out] = image->vData_f[index]; + } + const CartesianCoordinate3D grid_spacing(image->m_pixdim[1], image->m_pixdim[2], image->m_pixdim[0]); + CartesianCoordinate3D origin(0.F, 0.F, 0.F); + origin[2] = static_cast(image->m_origin[2] + image->m_pixdim[2] * image->m_dim[2] / 2.F); + origin[1] = static_cast(image->m_origin[1] + image->m_pixdim[1] * image->m_dim[1] / 2.F); + origin[3] = static_cast(image->m_origin[0] + image->m_pixdim[0] * image->m_dim[0] / 2.F); + const VoxelsOnCartesianGrid new_image(v_array, origin, grid_spacing); + OutputFileFormat>::default_sptr()->write_to_file(output_filename, new_image); + } else if (orientation == 3) { + BasicCoordinate<3, int> min_range; + BasicCoordinate<3, int> max_range; + min_range[1] = 0; + max_range[1] = image->m_dim[1] - 1; + min_range[2] = -static_cast(floor(image->m_dim[0] / 2.F)); + max_range[2] = min_range[2] + image->m_dim[0] - 1; + min_range[3] = -static_cast(floor(image->m_dim[2] / 2.F)); + max_range[3] = max_range[3] + image->m_dim[2] - 1; + + IndexRange<3> data_range(min_range, max_range); + Array<3, float> v_array(data_range); + + for (int k_out = min_range[1]; k_out <= max_range[1]; ++k_out) + for (int j_out = min_range[2]; j_out <= max_range[2]; ++j_out) + for (int i_out = min_range[3]; i_out <= max_range[3]; ++i_out) { + int index = j_out - min_range[2] + image->ImageOffset[0] * (k_out - min_range[1]) + + image->ImageOffset[1] * (max_range[3] - i_out); + if (image->m_image_type == 15) + v_array[k_out][j_out][i_out] = (float)image->vData[index]; + else if (image->m_image_type == 64) + v_array[k_out][j_out][i_out] = image->vData_f[index]; + } + const CartesianCoordinate3D grid_spacing(image->m_pixdim[1], image->m_pixdim[0], image->m_pixdim[2]); + CartesianCoordinate3D origin(0.F, 0.F, 0.F); + origin[3] = static_cast(image->m_origin[2] + image->m_pixdim[2] * image->m_dim[2] / 2.F); + origin[1] = static_cast(image->m_origin[1] + image->m_pixdim[1] * image->m_dim[1] / 2.F); + origin[2] = static_cast(image->m_origin[0] + image->m_pixdim[0] * image->m_dim[0] / 2.F); + + const VoxelsOnCartesianGrid new_image(v_array, origin, grid_spacing); + OutputFileFormat>::default_sptr()->write_to_file(output_filename, new_image); + } else { + std::cerr << "Orientation flag is not recognised." << std::endl; + exit(EXIT_FAILURE); } - else - { - std::cerr << "Orientation flag is not recognised." << std::endl; - exit(EXIT_FAILURE); - } return EXIT_SUCCESS; } diff --git a/src/utilities/conv_interfile_to_gipl.cxx b/src/utilities/conv_interfile_to_gipl.cxx index 9df04dbbeb..2eb217b53b 100644 --- a/src/utilities/conv_interfile_to_gipl.cxx +++ b/src/utilities/conv_interfile_to_gipl.cxx @@ -1,12 +1,12 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -15,10 +15,10 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities - \brief This program converts Images from Interfile Format to GIPL (Guy's Imaging Processing Lab) format. + \brief This program converts Images from Interfile Format to GIPL (Guy's Imaging Processing Lab) format. \author Charalampos Tsoumpas */ @@ -45,114 +45,109 @@ using std::cerr; using std::endl; #endif - USING_NAMESPACE_STIR // ------------------------------------------------------------------------- // Main function // ------------------------------------------------------------------------- -int main(int argc, char* argv[]) -{ - if(argc>3 || argc<2) { - std::cerr<<"Usage: " << argv[0] << " \n" - << "\nConversion of an image from image file format to giplfile.\n" - << "Orientation flag can be: 1, 2 or 3\n" - << " For Transverse set to: 1 \n" - << " For Coronal set to: 2 \n" - << " For Sagittal set to: 3 \n" - << "\t Orientation defaults to Coronal \n" - << "output file will change only extension\n"; +int +main(int argc, char* argv[]) { + if (argc > 3 || argc < 2) { + std::cerr << "Usage: " << argv[0] << " \n" + << "\nConversion of an image from image file format to giplfile.\n" + << "Orientation flag can be: 1, 2 or 3\n" + << " For Transverse set to: 1 \n" + << " For Coronal set to: 2 \n" + << " For Sagittal set to: 3 \n" + << "\t Orientation defaults to Coronal \n" + << "output file will change only extension\n"; exit(EXIT_FAILURE); } string filename(argv[1]); - const shared_ptr > image_sptr(DiscretisedDensity<3,float>::read_from_file(filename)); + const shared_ptr> image_sptr(DiscretisedDensity<3, float>::read_from_file(filename)); string output_filename; string::iterator string_iter; - for(string_iter=filename.begin(); - string_iter!=filename.end() && *string_iter!='.' ; - ++string_iter) - output_filename.push_back(*string_iter); - output_filename+=".gipl"; - const int orientation = (argc==2) ? 2 : atoi(argv[2]) ; + for (string_iter = filename.begin(); string_iter != filename.end() && *string_iter != '.'; ++string_iter) + output_filename.push_back(*string_iter); + output_filename += ".gipl"; + const int orientation = (argc == 2) ? 2 : atoi(argv[2]); - const DiscretisedDensity<3,float>& input_image = *image_sptr; - const DiscretisedDensityOnCartesianGrid <3,float>* image_cartesian_ptr = - dynamic_cast< DiscretisedDensityOnCartesianGrid<3,float>* > (image_sptr.get()); - - const IndexRange<3> data_range=image_sptr->get_index_range(); - BasicCoordinate<3,int> min_range; BasicCoordinate<3,int> max_range; - data_range.get_regular_range(min_range,max_range); - - const int num_voxels=(max_range[3]-min_range[3]+1)*(max_range[2]-min_range[2]+1)*(max_range[1]-min_range[1]+1); - Image image(num_voxels,64); - const Coordinate3D origin=input_image.get_origin(); - const Coordinate3D grid_spacing=image_cartesian_ptr->get_grid_spacing(); - if (orientation==1){ - image.m_dim[2]=max_range[1]-min_range[1]+1; - image.m_dim[1]=max_range[2]-min_range[2]+1; - image.m_dim[0]=max_range[3]-min_range[3]+1; - image.m_pixdim[2]=grid_spacing[1]; - image.m_pixdim[1]=grid_spacing[2]; - image.m_pixdim[0]=grid_spacing[3]; - image.m_origin[2]=origin[1]-image.m_pixdim[2]*image.m_dim[2]/2.F; - image.m_origin[1]=origin[2]-image.m_pixdim[1]*image.m_dim[1]/2.F; - image.m_origin[0]=origin[3]-image.m_pixdim[0]*image.m_dim[0]/2.F; - image.ImageOffset[1]=image.m_dim[0]*image.m_dim[1]; - image.ImageOffset[0]=image.m_dim[0]; - for (int k_out=min_range[1]; k_out<=max_range[1]; k_out++) - for (int j_out=min_range[2]; j_out<=max_range[2]; j_out++) - for (int i_out=min_range[3]; i_out<=max_range[3]; i_out++) - { - int index = i_out-min_range[3] + image.ImageOffset[0]*(j_out-min_range[2]) + image.ImageOffset[1]*(k_out-min_range[1]); - image.vData_f[index]=input_image[k_out][j_out][i_out]; - } - } - else if (orientation==2) { - image.m_dim[2]=max_range[2]-min_range[2]+1; - image.m_dim[1]=max_range[1]-min_range[1]+1; - image.m_dim[0]=max_range[3]-min_range[3]+1; - image.m_pixdim[2]=grid_spacing[2]; - image.m_pixdim[1]=grid_spacing[1]; - image.m_pixdim[0]=grid_spacing[3]; - image.m_origin[2]=origin[2]-image.m_pixdim[2]*image.m_dim[2]/2.F; - image.m_origin[1]=origin[1]-image.m_pixdim[1]*image.m_dim[1]/2.F; - image.m_origin[0]=origin[3]-image.m_pixdim[0]*image.m_dim[0]/2.F; - image.ImageOffset[1]=image.m_dim[0]*image.m_dim[1]; - image.ImageOffset[0]=image.m_dim[0]; - for (int k_out=min_range[1]; k_out<=max_range[1]; k_out++) - for (int j_out=min_range[2]; j_out<=max_range[2]; j_out++) - for (int i_out=min_range[3]; i_out<=max_range[3]; i_out++) - { - int index = i_out-min_range[3] + image.ImageOffset[0]*(k_out-min_range[1]) + image.ImageOffset[1]*(j_out-min_range[2]); - image.vData_f[index]=input_image[k_out][j_out][i_out]; - } - } - else if (orientation==3) { - image.m_dim[0]=max_range[2]-min_range[2]+1; - image.m_dim[1]=max_range[1]-min_range[1]+1; - image.m_dim[2]=max_range[3]-min_range[3]+1; - image.m_pixdim[0]=grid_spacing[2]; - image.m_pixdim[1]=grid_spacing[1]; - image.m_pixdim[2]=grid_spacing[3]; - image.m_origin[2]=origin[3]-image.m_pixdim[2]*image.m_dim[2]/2.F; - image.m_origin[1]=origin[1]-image.m_pixdim[1]*image.m_dim[1]/2.F; - image.m_origin[0]=origin[2]-image.m_pixdim[0]*image.m_dim[0]/2.F; - image.ImageOffset[1]=image.m_dim[0]*image.m_dim[1]; - image.ImageOffset[0]=image.m_dim[0]; - for (int k_out=min_range[1]; k_out<=max_range[1]; k_out++) - for (int j_out=min_range[2]; j_out<=max_range[2]; j_out++) - for (int i_out=min_range[3]; i_out<=max_range[3]; i_out++) - { - int index = j_out-min_range[2] + image.ImageOffset[0]*(k_out-min_range[1]) + image.ImageOffset[1]*(max_range[3]-i_out); - image.vData_f[index]=input_image[k_out][j_out][i_out]; - } + const DiscretisedDensity<3, float>& input_image = *image_sptr; + const DiscretisedDensityOnCartesianGrid<3, float>* image_cartesian_ptr = + dynamic_cast*>(image_sptr.get()); + + const IndexRange<3> data_range = image_sptr->get_index_range(); + BasicCoordinate<3, int> min_range; + BasicCoordinate<3, int> max_range; + data_range.get_regular_range(min_range, max_range); + + const int num_voxels = + (max_range[3] - min_range[3] + 1) * (max_range[2] - min_range[2] + 1) * (max_range[1] - min_range[1] + 1); + Image image(num_voxels, 64); + const Coordinate3D origin = input_image.get_origin(); + const Coordinate3D grid_spacing = image_cartesian_ptr->get_grid_spacing(); + if (orientation == 1) { + image.m_dim[2] = max_range[1] - min_range[1] + 1; + image.m_dim[1] = max_range[2] - min_range[2] + 1; + image.m_dim[0] = max_range[3] - min_range[3] + 1; + image.m_pixdim[2] = grid_spacing[1]; + image.m_pixdim[1] = grid_spacing[2]; + image.m_pixdim[0] = grid_spacing[3]; + image.m_origin[2] = origin[1] - image.m_pixdim[2] * image.m_dim[2] / 2.F; + image.m_origin[1] = origin[2] - image.m_pixdim[1] * image.m_dim[1] / 2.F; + image.m_origin[0] = origin[3] - image.m_pixdim[0] * image.m_dim[0] / 2.F; + image.ImageOffset[1] = image.m_dim[0] * image.m_dim[1]; + image.ImageOffset[0] = image.m_dim[0]; + for (int k_out = min_range[1]; k_out <= max_range[1]; k_out++) + for (int j_out = min_range[2]; j_out <= max_range[2]; j_out++) + for (int i_out = min_range[3]; i_out <= max_range[3]; i_out++) { + int index = i_out - min_range[3] + image.ImageOffset[0] * (j_out - min_range[2]) + + image.ImageOffset[1] * (k_out - min_range[1]); + image.vData_f[index] = input_image[k_out][j_out][i_out]; + } + } else if (orientation == 2) { + image.m_dim[2] = max_range[2] - min_range[2] + 1; + image.m_dim[1] = max_range[1] - min_range[1] + 1; + image.m_dim[0] = max_range[3] - min_range[3] + 1; + image.m_pixdim[2] = grid_spacing[2]; + image.m_pixdim[1] = grid_spacing[1]; + image.m_pixdim[0] = grid_spacing[3]; + image.m_origin[2] = origin[2] - image.m_pixdim[2] * image.m_dim[2] / 2.F; + image.m_origin[1] = origin[1] - image.m_pixdim[1] * image.m_dim[1] / 2.F; + image.m_origin[0] = origin[3] - image.m_pixdim[0] * image.m_dim[0] / 2.F; + image.ImageOffset[1] = image.m_dim[0] * image.m_dim[1]; + image.ImageOffset[0] = image.m_dim[0]; + for (int k_out = min_range[1]; k_out <= max_range[1]; k_out++) + for (int j_out = min_range[2]; j_out <= max_range[2]; j_out++) + for (int i_out = min_range[3]; i_out <= max_range[3]; i_out++) { + int index = i_out - min_range[3] + image.ImageOffset[0] * (k_out - min_range[1]) + + image.ImageOffset[1] * (j_out - min_range[2]); + image.vData_f[index] = input_image[k_out][j_out][i_out]; + } + } else if (orientation == 3) { + image.m_dim[0] = max_range[2] - min_range[2] + 1; + image.m_dim[1] = max_range[1] - min_range[1] + 1; + image.m_dim[2] = max_range[3] - min_range[3] + 1; + image.m_pixdim[0] = grid_spacing[2]; + image.m_pixdim[1] = grid_spacing[1]; + image.m_pixdim[2] = grid_spacing[3]; + image.m_origin[2] = origin[3] - image.m_pixdim[2] * image.m_dim[2] / 2.F; + image.m_origin[1] = origin[1] - image.m_pixdim[1] * image.m_dim[1] / 2.F; + image.m_origin[0] = origin[2] - image.m_pixdim[0] * image.m_dim[0] / 2.F; + image.ImageOffset[1] = image.m_dim[0] * image.m_dim[1]; + image.ImageOffset[0] = image.m_dim[0]; + for (int k_out = min_range[1]; k_out <= max_range[1]; k_out++) + for (int j_out = min_range[2]; j_out <= max_range[2]; j_out++) + for (int i_out = min_range[3]; i_out <= max_range[3]; i_out++) { + int index = j_out - min_range[2] + image.ImageOffset[0] * (k_out - min_range[1]) + + image.ImageOffset[1] * (max_range[3] - i_out); + image.vData_f[index] = input_image[k_out][j_out][i_out]; + } + } else { + std::cerr << "Orientation flag is not recognised." << std::endl; + exit(EXIT_FAILURE); } - else - { - std::cerr << "Orientation flag is not recognised." << std::endl; - exit(EXIT_FAILURE); - } std::cerr << "Now writing image in gipl format" << std::endl; image.GiplWrite(output_filename.c_str()); diff --git a/src/utilities/convert_to_binary_image.cxx b/src/utilities/convert_to_binary_image.cxx index 7bb7981876..185ea309e6 100644 --- a/src/utilities/convert_to_binary_image.cxx +++ b/src/utilities/convert_to_binary_image.cxx @@ -17,10 +17,10 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities - - \brief This program outputs a binary image (voxel values 0 or 1) where all values + + \brief This program outputs a binary image (voxel values 0 or 1) where all values strictly below a threshold are set to 0, and others to 1. \author Kris Thielemans @@ -33,40 +33,33 @@ USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if(argc!=4) { - std::cerr<<"Usage: " << argv[0] << " threshold\n"; +int +main(int argc, char** argv) { + if (argc != 4) { + std::cerr << "Usage: " << argv[0] << " threshold\n"; exit(EXIT_FAILURE); } - + // get parameters from command line std::string output_filename = argv[1]; - char const * const input_filename = argv[2]; + char const* const input_filename = argv[2]; const float threshold = atof(argv[3]); - // read image + // read image - shared_ptr > - density_ptr(read_from_file >(input_filename)); + shared_ptr> density_ptr(read_from_file>(input_filename)); // binarise - for (DiscretisedDensity<3,float>::full_iterator iter = density_ptr->begin_all(); - iter != density_ptr->end_all(); - ++iter) - { - if (*iter < threshold) - *iter = 0.F; - else - *iter = 1.F; - } - shared_ptr > > output_file_format_sptr = - OutputFileFormat >::default_sptr(); + for (DiscretisedDensity<3, float>::full_iterator iter = density_ptr->begin_all(); iter != density_ptr->end_all(); ++iter) { + if (*iter < threshold) + *iter = 0.F; + else + *iter = 1.F; + } + shared_ptr>> output_file_format_sptr = + OutputFileFormat>::default_sptr(); output_file_format_sptr->set_type_of_numbers(NumericType::SCHAR); output_file_format_sptr->set_scale_to_write_data(1); - return - output_file_format_sptr->write_to_file(output_filename, *density_ptr) == Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; - + return output_file_format_sptr->write_to_file(output_filename, *density_ptr) == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/utilities/correct_projdata.cxx b/src/utilities/correct_projdata.cxx index eb52e811ec..812014fb5d 100644 --- a/src/utilities/correct_projdata.cxx +++ b/src/utilities/correct_projdata.cxx @@ -28,7 +28,7 @@ Here's a sample .par file \verbatim -correct_projdata Parameters := +correct_projdata Parameters := input file := trues.hs ; Current way of specifying time frames, pending modifications to @@ -41,24 +41,24 @@ correct_projdata Parameters := ; the number should be between 1 and num_frames and defaults to 1 ; this is currently only used to pass the relevant time to the normalisation ; time frame number := 1 - + ; output file - ; for future compatibility, do not use an extension in the name of + ; for future compatibility, do not use an extension in the name of ; the output file. It will be added automatically output filename := precorrected ; default value for next is -1, meaning 'all segments' - ; maximum absolute segment number to process := - + ; maximum absolute segment number to process := + ; use data in the input file, or substitute data with all 1's ; (useful to get correction factors only) ; default is '1' - ; use data (1) or set to one (0) := + ; use data (1) or set to one (0) := ; precorrect data, or undo precorrection ; default is '1' - ; apply (1) or undo (0) correction := + ; apply (1) or undo (0) correction := ; parameters specifying correction factors ; if no value is given, the corresponding correction will not be performed @@ -74,7 +74,7 @@ correct_projdata Parameters := ; attenuation image, will be forward projected to get attenuation factors ; OBSOLETE ;attenuation image filename := attenuation_image.hv - + ; forward projector used to estimate attenuation factors, defaults to Ray Tracing ; OBSOLETE ;forward_projector type := Ray Tracing @@ -85,7 +85,7 @@ correct_projdata Parameters := ; to interpolate to uniform sampling in 's', set value to 1 ; arc correction := 1 -END:= +END:= \endverbatim Time frame definition is only necessary when the normalisation type uses @@ -93,11 +93,12 @@ this time info for dead-time correction. \warning arc-correction can currently not be undone. -The following gives a brief explanation of the non-obvious parameters. +The following gives a brief explanation of the non-obvious parameters.
    • use data (1) or set to one (0):
      -Use the data in the input file, or substitute data with all 1's. This is useful to get correction factors only. Its value defaults to 1. +Use the data in the input file, or substitute data with all 1's. This is useful to get correction factors only. Its value defaults +to 1.
    • apply (1) or undo (0) correction:
      @@ -105,21 +106,21 @@ Precorrect data, or undo precorrection. Its value defaults to 1.
    • Bin Normalisation type:
      -Normalisation (or binwise multiplication, so can contain attenuation factors +Normalisation (or binwise multiplication, so can contain attenuation factors as well). \see stir::BinNormalisation
    • attenuation image filename: obsolete
      -Specify the attenuation image, which will be forward projected to get +Specify the attenuation image, which will be forward projected to get attenuation factors. Has to be in units cm^-1. -This parameter will be removed. Use instead a "chained" bin normalisation -with a bin normalisation "from attenuation image" +This parameter will be removed. Use instead a "chained" bin normalisation +with a bin normalisation "from attenuation image" \see stir::ChainedBinNormalisation \see stir::BinNormalisationFromAttenuationImage
    • forward_projector type: obsolete
      -Forward projector used to estimate attenuation factors, defaults to +Forward projector used to estimate attenuation factors, defaults to Ray Tracing. \see stir::ForwardProjectorUsingRayTracing This parameter will be removed.
    • @@ -144,14 +145,14 @@ This parameter will be removed. #include "stir/ArrayFunction.h" #include "stir/TimeFrameDefinitions.h" #ifndef USE_PMRT -#include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" #else -#include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" -#include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" +# include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" #endif #include "stir/is_null_ptr.h" #include -#include +#include #include #include @@ -167,8 +168,6 @@ using std::vector; START_NAMESPACE_STIR - - // TODO most of this is identical to ReconstructionParameters, so make a common class /*! \ingroup utilities \brief class to do precorrections @@ -176,38 +175,36 @@ START_NAMESPACE_STIR \todo Preliminary class interface. At some point, this class should move to the library, instead of being in correct_projdata.cxx. */ -class CorrectProjDataApplication : public ParsingObject -{ +class CorrectProjDataApplication : public ParsingObject { public: - - CorrectProjDataApplication(const char * const par_filename); + CorrectProjDataApplication(const char* const par_filename); //! set-up variables before processing Succeeded set_up(); //! do precorrection - /*! set_up() has to be run first */ + /*! set_up() has to be run first */ Succeeded run() const; - + // shared_ptrs such that they clean up automatically at exit shared_ptr input_projdata_ptr; shared_ptr scatter_projdata_ptr; shared_ptr randoms_projdata_ptr; shared_ptr output_projdata_ptr; shared_ptr normalisation_ptr; - shared_ptr > attenuation_image_ptr; + shared_ptr> attenuation_image_ptr; shared_ptr forward_projector_ptr; //! apply_or_undo_correction==true means: apply it bool apply_or_undo_correction; //! use input data, or replace it with all 1's /*! use_data_or_set_to_1 == true means: use the data*/ - bool use_data_or_set_to_1; + bool use_data_or_set_to_1; int max_segment_num_to_process; int frame_num; TimeFrameDefinitions frame_defs; bool do_arc_correction; -private: +private: virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); @@ -215,170 +212,135 @@ class CorrectProjDataApplication : public ParsingObject string output_filename; string scatter_projdata_filename; string atten_image_filename; - string norm_filename; - string randoms_projdata_filename; + string norm_filename; + string randoms_projdata_filename; string frame_definition_filename; - - shared_ptr arc_correction_sptr; + shared_ptr arc_correction_sptr; }; - Succeeded -CorrectProjDataApplication:: -run() const -{ +CorrectProjDataApplication::run() const { ProjData& output_projdata = *output_projdata_ptr; const ProjData& input_projdata = *input_projdata_ptr; const bool do_scatter = !is_null_ptr(scatter_projdata_ptr); const bool do_randoms = !is_null_ptr(randoms_projdata_ptr); - // TODO - shared_ptr - symmetries_ptr( - is_null_ptr(forward_projector_ptr) ? - new TrivialDataSymmetriesForViewSegmentNumbers - : - forward_projector_ptr->get_symmetries_used()->clone() - ); - - for (int segment_num = output_projdata.get_min_segment_num(); segment_num <= output_projdata.get_max_segment_num() ; segment_num++) - { - cerr<is_basic(view_seg_nums)) - continue; - - // ** first fill in the data ** - RelatedViewgrams - viewgrams = input_projdata.get_empty_related_viewgrams(view_seg_nums, - symmetries_ptr); - if (use_data_or_set_to_1) - { - viewgrams += - input_projdata.get_related_viewgrams(view_seg_nums, - symmetries_ptr); - } - else - { - viewgrams.fill(1.F); - } - - if (do_arc_correction && !apply_or_undo_correction) - { - error("Cannot undo arc-correction yet. Sorry."); - // TODO - //arc_correction_sptr->undo_arc_correction(output_viewgrams, viewgrams); - } - - if (do_scatter && !apply_or_undo_correction) - { - viewgrams += - scatter_projdata_ptr->get_related_viewgrams(view_seg_nums, - symmetries_ptr); - } + shared_ptr symmetries_ptr(is_null_ptr(forward_projector_ptr) + ? new TrivialDataSymmetriesForViewSegmentNumbers + : forward_projector_ptr->get_symmetries_used()->clone()); + for (int timing_pos_num = output_projdata.get_min_tof_pos_num(); timing_pos_num <= output_projdata.get_max_tof_pos_num(); + timing_pos_num++) + for (int segment_num = output_projdata.get_min_segment_num(); segment_num <= output_projdata.get_max_segment_num(); + segment_num++) { + cerr << endl + << "Processing segment # " << segment_num << "(and any related segments) of timing position index # " << timing_pos_num + << endl; + for (int view_num = input_projdata.get_min_view_num(); view_num <= input_projdata.get_max_view_num(); ++view_num) { + const ViewSegmentNumbers view_seg_nums(view_num, segment_num); + if (!symmetries_ptr->is_basic(view_seg_nums)) + continue; + + // ** first fill in the data ** + RelatedViewgrams viewgrams = + input_projdata.get_empty_related_viewgrams(view_seg_nums, symmetries_ptr, false, timing_pos_num); + if (use_data_or_set_to_1) { + viewgrams += input_projdata.get_related_viewgrams(view_seg_nums, symmetries_ptr, false, timing_pos_num); + } else { + viewgrams.fill(1.F); + } - if (do_randoms && apply_or_undo_correction) - { - viewgrams -= - randoms_projdata_ptr->get_related_viewgrams(view_seg_nums, - symmetries_ptr); - } -#if 0 - if (frame_num==-1) - { - int num_frames = frame_def.get_num_frames(); - for ( int i = 1; i<=num_frames; i++) - { - //cerr << "Doing frame " << i << endl; - const double start_frame = frame_def.get_start_time(i); - const double end_frame = frame_def.get_end_time(i); - //cerr << "Start time " << start_frame << endl; - //cerr << " End time " << end_frame << endl; - // ** normalisation ** - if (apply_or_undo_correction) - { - normalisation_ptr->apply(viewgrams,start_frame,end_frame); - } - else - { - normalisation_ptr->undo(viewgrams,start_frame,end_frame); - } + if (do_arc_correction && !apply_or_undo_correction) { + error("Cannot undo arc-correction yet. Sorry."); + // TODO + // arc_correction_sptr->undo_arc_correction(output_viewgrams, viewgrams); } - } - else + + if (do_scatter && !apply_or_undo_correction) { + viewgrams += scatter_projdata_ptr->get_related_viewgrams(view_seg_nums, symmetries_ptr, false, timing_pos_num); + } + + if (do_randoms && apply_or_undo_correction) { + viewgrams -= randoms_projdata_ptr->get_related_viewgrams(view_seg_nums, symmetries_ptr, false, timing_pos_num); + } +#if 0 + if (frame_num==-1) + { + int num_frames = frame_def.get_num_frames(); + for ( int i = 1; i<=num_frames; i++) + { + //cerr << "Doing frame " << i << endl; + const double start_frame = frame_def.get_start_time(i); + const double end_frame = frame_def.get_end_time(i); + //cerr << "Start time " << start_frame << endl; + //cerr << " End time " << end_frame << endl; + // ** normalisation ** + if (apply_or_undo_correction) + { + normalisation_ptr->apply(viewgrams,start_frame,end_frame); + } + else + { + normalisation_ptr->undo(viewgrams,start_frame,end_frame); + } + } + } + + + + else #endif - { - const double start_frame = frame_defs.get_start_time(frame_num); - const double end_frame = frame_defs.get_end_time(frame_num); - if (apply_or_undo_correction) { - normalisation_ptr->apply(viewgrams,start_frame,end_frame); + const double start_frame = frame_defs.get_start_time(frame_num); + const double end_frame = frame_defs.get_end_time(frame_num); + if (apply_or_undo_correction) { + normalisation_ptr->apply(viewgrams, start_frame, end_frame); + } else { + normalisation_ptr->undo(viewgrams, start_frame, end_frame); + } + } + if (do_scatter && apply_or_undo_correction) { + viewgrams -= scatter_projdata_ptr->get_related_viewgrams(view_seg_nums, symmetries_ptr, false, timing_pos_num); } - else - { - normalisation_ptr->undo(viewgrams,start_frame,end_frame); - } - } - if (do_scatter && apply_or_undo_correction) - { - viewgrams -= - scatter_projdata_ptr->get_related_viewgrams(view_seg_nums, - symmetries_ptr); - } - if (do_randoms && !apply_or_undo_correction) - { - viewgrams += - randoms_projdata_ptr->get_related_viewgrams(view_seg_nums, - symmetries_ptr); - } + if (do_randoms && !apply_or_undo_correction) { + viewgrams += randoms_projdata_ptr->get_related_viewgrams(view_seg_nums, symmetries_ptr, false, timing_pos_num); + } - if (do_arc_correction && apply_or_undo_correction) - { - viewgrams = arc_correction_sptr->do_arc_correction(viewgrams); - } - - // output - { - // Unfortunately, segment range in output_projdata and input_projdata can be - // different. - // Hence, output_projdata.set_related_viewgrams(viewgrams) would not work. - // So, we need an extra viewgrams object to take this into account. - // The trick relies on calling Array::operator+= instead of - // RelatedViewgrams::operator= - RelatedViewgrams - output_viewgrams = - output_projdata.get_empty_related_viewgrams(view_seg_nums, - symmetries_ptr); - output_viewgrams += viewgrams; - - if (!(output_projdata.set_related_viewgrams(viewgrams) == Succeeded::yes)) - { - warning("CorrectProjData: Error set_related_viewgrams\n"); - return Succeeded::no; - } + if (do_arc_correction && apply_or_undo_correction) { + viewgrams = arc_correction_sptr->do_arc_correction(viewgrams); + } + + // output + { + // Unfortunately, segment range in output_projdata and input_projdata can be + // different. + // Hence, output_projdata.set_related_viewgrams(viewgrams) would not work. + // So, we need an extra viewgrams object to take this into account. + // The trick relies on calling Array::operator+= instead of + // RelatedViewgrams::operator= + RelatedViewgrams output_viewgrams = + output_projdata.get_empty_related_viewgrams(view_seg_nums, symmetries_ptr, false, timing_pos_num); + output_viewgrams += viewgrams; + + if (!(output_projdata.set_related_viewgrams(viewgrams) == Succeeded::yes)) { + warning("CorrectProjData: Error set_related_viewgrams\n"); + return Succeeded::no; + } + } } - } - - } return Succeeded::yes; -} - +} -void -CorrectProjDataApplication:: -set_defaults() -{ +void +CorrectProjDataApplication::set_defaults() { input_projdata_ptr.reset(); max_segment_num_to_process = -1; normalisation_ptr.reset(); - use_data_or_set_to_1= true; + use_data_or_set_to_1 = true; apply_or_undo_correction = true; scatter_projdata_filename = ""; atten_image_filename = ""; @@ -392,25 +354,23 @@ set_defaults() #ifndef USE_PMRT forward_projector_ptr.reset(new ForwardProjectorByBinUsingRayTracing); #else - shared_ptr PM(new ProjMatrixByBinUsingRayTracing); - forward_projector_ptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr PM(new ProjMatrixByBinUsingRayTracing); + forward_projector_ptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); #endif - do_arc_correction= false; + do_arc_correction = false; } -void -CorrectProjDataApplication:: -initialise_keymap() -{ +void +CorrectProjDataApplication::initialise_keymap() { parser.add_start_key("correct_projdata Parameters"); - parser.add_key("input file",&input_filename); - parser.add_key("time frame definition filename", &frame_definition_filename); + parser.add_key("input file", &input_filename); + parser.add_key("time frame definition filename", &frame_definition_filename); parser.add_key("time frame number", &frame_num); - parser.add_key("output filename",&output_filename); + parser.add_key("output filename", &output_filename); parser.add_key("maximum absolute segment number to process", &max_segment_num_to_process); - + parser.add_key("use data (1) or set to one (0)", &use_data_or_set_to_1); parser.add_key("apply (1) or undo (0) correction", &apply_or_undo_correction); parser.add_parsing_key("Bin Normalisation type", &normalisation_ptr); @@ -422,76 +382,59 @@ initialise_keymap() parser.add_stop_key("END"); } - bool -CorrectProjDataApplication:: -post_processing() -{ - if (is_null_ptr(normalisation_ptr)) - { +CorrectProjDataApplication::post_processing() { + if (is_null_ptr(normalisation_ptr)) { warning("Invalid normalisation object\n"); return true; } - // read time frame def - if (frame_definition_filename.size()!=0) + // read time frame def + if (frame_definition_filename.size() != 0) frame_defs = TimeFrameDefinitions(frame_definition_filename); - else - { - // make a single frame starting from 0 to 1. - std::vector > frame_times(1, std::pair(0,1)); - frame_defs = TimeFrameDefinitions(frame_times); - } + else { + // make a single frame starting from 0 to 1. + std::vector> frame_times(1, std::pair(0, 1)); + frame_defs = TimeFrameDefinitions(frame_times); + } - if (frame_num<=0) - { - warning("frame_num should be >= 1 \n"); - return true; - } + if (frame_num <= 0) { + warning("frame_num should be >= 1 \n"); + return true; + } - if (static_cast(frame_num)> frame_defs.get_num_frames()) - { - warning("frame_num is %d, but should be less than the number of frames %d.\n", - frame_num, frame_defs.get_num_frames()); - return true; - } + if (static_cast(frame_num) > frame_defs.get_num_frames()) { + warning("frame_num is %d, but should be less than the number of frames %d.\n", frame_num, frame_defs.get_num_frames()); + return true; + } input_projdata_ptr = ProjData::read_from_file(input_filename); - if (scatter_projdata_filename!="" && scatter_projdata_filename != "0") + if (scatter_projdata_filename != "" && scatter_projdata_filename != "0") scatter_projdata_ptr = ProjData::read_from_file(scatter_projdata_filename); - if (randoms_projdata_filename!="" && randoms_projdata_filename != "0") + if (randoms_projdata_filename != "" && randoms_projdata_filename != "0") randoms_projdata_ptr = ProjData::read_from_file(randoms_projdata_filename); return false; } Succeeded -CorrectProjDataApplication:: -set_up() -{ - const int max_segment_num_available = - input_projdata_ptr->get_max_segment_num(); +CorrectProjDataApplication::set_up() { + const int max_segment_num_available = input_projdata_ptr->get_max_segment_num(); // Set default or upper bound of data to process (if out of bounds) - if (max_segment_num_to_process<0 || - max_segment_num_to_process > max_segment_num_available) + if (max_segment_num_to_process < 0 || max_segment_num_to_process > max_segment_num_available) max_segment_num_to_process = max_segment_num_available; - shared_ptr - input_proj_data_info_sptr(input_projdata_ptr->get_proj_data_info_sptr()->clone()); + shared_ptr input_proj_data_info_sptr(input_projdata_ptr->get_proj_data_info_sptr()->clone()); shared_ptr output_proj_data_info_sptr; if (!do_arc_correction) output_proj_data_info_sptr = input_proj_data_info_sptr; - else - { - arc_correction_sptr = - shared_ptr(new ArcCorrection); - arc_correction_sptr->set_up(input_proj_data_info_sptr); - output_proj_data_info_sptr = - arc_correction_sptr->get_arc_corrected_proj_data_info_sptr()->create_shared_clone(); - } - output_proj_data_info_sptr->reduce_segment_range(-max_segment_num_to_process, - max_segment_num_to_process); + else { + arc_correction_sptr = shared_ptr(new ArcCorrection); + arc_correction_sptr->set_up(input_proj_data_info_sptr); + output_proj_data_info_sptr = arc_correction_sptr->get_arc_corrected_proj_data_info_sptr()->create_shared_clone(); + } + output_proj_data_info_sptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); // construct output_projdata { @@ -512,7 +455,7 @@ set_up() else #endif { - string output_filename_with_ext = output_filename; + string output_filename_with_ext = output_filename; #if 0 if (frame_definition_filename.size()!=0) { @@ -521,26 +464,20 @@ set_up() output_filename_with_ext += ext; } #endif - output_projdata_ptr.reset(new ProjDataInterfile(input_projdata_ptr->get_exam_info_sptr(), - output_proj_data_info_sptr,output_filename_with_ext)); - }// output_projdata block + output_projdata_ptr.reset( + new ProjDataInterfile(input_projdata_ptr->get_exam_info_sptr(), output_proj_data_info_sptr, output_filename_with_ext)); + } // output_projdata block + + } // output_projdata block - }// output_projdata block - // read attenuation image and add it to the normalisation object - if(atten_image_filename!="0" && atten_image_filename!="") - { - - shared_ptr atten_sptr - (new BinNormalisationFromAttenuationImage(atten_image_filename, - forward_projector_ptr)); - - normalisation_ptr = - shared_ptr - ( new ChainedBinNormalisation(normalisation_ptr, atten_sptr)); - } - else - { + if (atten_image_filename != "0" && atten_image_filename != "") { + + shared_ptr atten_sptr( + new BinNormalisationFromAttenuationImage(atten_image_filename, forward_projector_ptr)); + + normalisation_ptr = shared_ptr(new ChainedBinNormalisation(normalisation_ptr, atten_sptr)); + } else { // get rid of this object for now // this is currently checked to find the symmetries: bad // TODO @@ -548,49 +485,37 @@ set_up() } // set up normalisation object - if ( - normalisation_ptr->set_up(input_projdata_ptr->get_exam_info_sptr(),input_proj_data_info_sptr) - != Succeeded::yes) - { - warning("correct_projdata: set-up of normalisation failed\n"); - return Succeeded::no; - } + if (normalisation_ptr->set_up(input_projdata_ptr->get_exam_info_sptr(), input_proj_data_info_sptr) != Succeeded::yes) { + warning("correct_projdata: set-up of normalisation failed\n"); + return Succeeded::no; + } return Succeeded::yes; - } -CorrectProjDataApplication:: -CorrectProjDataApplication(const char * const par_filename) -{ +CorrectProjDataApplication::CorrectProjDataApplication(const char* const par_filename) { set_defaults(); - if (par_filename!=0) - parse(par_filename) ; + if (par_filename != 0) + parse(par_filename); else ask_parameters(); - } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char *argv[]) -{ - - if(argc!=2) - { - cerr<<"Usage: " << argv[0] << " par_file\n" - << endl; +int +main(int argc, char* argv[]) { + + if (argc != 2) { + cerr << "Usage: " << argv[0] << " par_file\n" << endl; + } + CorrectProjDataApplication correct_proj_data_application(argc == 2 ? argv[1] : 0); + + if (argc != 2) { + cerr << "Corresponding .par file input \n" << correct_proj_data_application.parameter_info() << endl; } - CorrectProjDataApplication correct_proj_data_application( argc==2 ? argv[1] : 0); - - if (argc!=2) - { - cerr << "Corresponding .par file input \n" - << correct_proj_data_application.parameter_info() << endl; - } - CPUTimer timer; timer.start(); @@ -598,11 +523,8 @@ int main(int argc, char *argv[]) if (correct_proj_data_application.set_up() == Succeeded::no) return EXIT_FAILURE; - Succeeded success = - correct_proj_data_application.run(); + Succeeded success = correct_proj_data_application.run(); timer.stop(); cerr << "CPU time : " << timer.value() << "secs" << endl; - return success==Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; - + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/utilities/create_multi_header.cxx b/src/utilities/create_multi_header.cxx index e397d29589..5dff3f74cb 100644 --- a/src/utilities/create_multi_header.cxx +++ b/src/utilities/create_multi_header.cxx @@ -33,44 +33,46 @@ \warning There is no check that the data sizes and other info are compatible. Hence, lots of funny effects can happen if data are not compatible. - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/MultipleDataSetHeader.h" #include -#include -#include +#include +#include USING_NAMESPACE_STIR -int -main(int argc, char **argv) -{ - if(argc<3) - { - std::cerr<< "Usage: " << argv[0] << "\n\t" - << "output_filename_with_extension in_data1 [in_data2 [in_data3...]]\n\n"; - exit(EXIT_FAILURE); - } +int +main(int argc, char** argv) { + if (argc < 3) { + std::cerr << "Usage: " << argv[0] << "\n\t" + << "output_filename_with_extension in_data1 [in_data2 [in_data3...]]\n\n"; + exit(EXIT_FAILURE); + } // skip program name --argc; ++argv; - - if (argc==0) - { std::cerr << "No output file (nor input files) on command line\n"; exit(EXIT_FAILURE); } + if (argc == 0) { + std::cerr << "No output file (nor input files) on command line\n"; + exit(EXIT_FAILURE); + } // find output filename const std::string output_file_name = *argv; - { - --argc; ++argv; - } + { + --argc; + ++argv; + } const int num_files = argc; - if (num_files==0) - { std::cerr << "No input files on command line\n"; exit(EXIT_FAILURE); } + if (num_files == 0) { + std::cerr << "No input files on command line\n"; + exit(EXIT_FAILURE); + } - MultipleDataSetHeader::write_header(output_file_name, std::vector(argv, argv+argc)); + MultipleDataSetHeader::write_header(output_file_name, std::vector(argv, argv + argc)); return EXIT_SUCCESS; } diff --git a/src/utilities/create_projdata_template.cxx b/src/utilities/create_projdata_template.cxx index 0364d13682..220266843f 100644 --- a/src/utilities/create_projdata_template.cxx +++ b/src/utilities/create_projdata_template.cxx @@ -18,7 +18,7 @@ */ /* Copyright (C) 2004, Hammersmith Imanet Ltd - Copyright (C) 2014, University College London + Copyright (C) 2014, University College London This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -43,26 +43,29 @@ using std::cerr; #endif - USING_NAMESPACE_STIR -int main(int argc, char *argv[]) -{ - - if(argc!=2) - { - cerr<<"Usage: " << argv[0] << " output_filename\n"; +int +main(int argc, char* argv[]) { + + if (argc != 2) { + cerr << "Usage: " << argv[0] << " output_filename\n"; return EXIT_FAILURE; } + shared_ptr proj_data_info_sptr(ProjDataInfo::ask_parameters()); - shared_ptr proj_data_info_ptr(ProjDataInfo::ask_parameters()); - const std::string output_file_name = argv[1]; shared_ptr exam_info_sptr(new ExamInfo); // TODO, Currently all stir::Scanner types are PET. exam_info_sptr->imaging_modality = ImagingModality::PT; - shared_ptr proj_data_ptr(new ProjDataInterfile(exam_info_sptr, proj_data_info_ptr, output_file_name)); + // If TOF activated -- No mashing factor will produce surrealistic sinograms + // if ( proj_data_info_sptr->get_num_tof_poss() >1) + // shared_ptr proj_data_sptr(new ProjDataInterfile(exam_info_sptr, proj_data_info_sptr, output_file_name, + // std::ios::out, + // ProjDataFromStream::Timing_Segment_View_AxialPos_TangPos)); + // else + shared_ptr proj_data_sptr(new ProjDataInterfile(exam_info_sptr, proj_data_info_sptr, output_file_name)); return EXIT_SUCCESS; } diff --git a/src/utilities/ctac_to_mu_values.cxx b/src/utilities/ctac_to_mu_values.cxx index 86128c5754..0d73ced55f 100644 --- a/src/utilities/ctac_to_mu_values.cxx +++ b/src/utilities/ctac_to_mu_values.cxx @@ -25,10 +25,8 @@ \par Usage: \code - ctac_to_mu_values -o output_filename -i input_volume -j slope_filename -m manufacturer_name [-v kilovoltage_peak] -k target_photon_energy - \endcode - Default value for tube voltage is 120 kV. For PET, the \c target_photon_energy - has to be 511. + ctac_to_mu_values -o output_filename -i input_volume -j slope_filename -m manufacturer_name [-v kilovoltage_peak] -k + target_photon_energy \endcode Default value for tube voltage is 120 kV. For PET, the \c target_photon_energy has to be 511. This convert HU to mu-values using a piece-wise linear curve. \see HUToMuImageProcessor for details on file format etc @@ -36,7 +34,6 @@ */ - #include "stir/info.h" #include "stir/Succeeded.h" #include "stir/HUToMuImageProcessor.h" @@ -49,107 +46,95 @@ USING_NAMESPACE_STIR -typedef DiscretisedDensity<3,float> FloatImageType; - +typedef DiscretisedDensity<3, float> FloatImageType; -int main(int argc, char * argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR; - const char * output_filename = 0; - const char * input_filename = 0; - const char * slope_filename = 0; - const char * manufacturer_name = 0; - const char * kVp_str = 0; - const char * keV_str = 0; - - const char * const usage = "ctac_to_mu_values -o output_filename -i input_volume -j slope_filename -m manufacturer_name [-v kilovoltage_peak] -k target_photon_energy\n" - "Default value for tube voltage is 120 kV.\n"; + const char* output_filename = 0; + const char* input_filename = 0; + const char* slope_filename = 0; + const char* manufacturer_name = 0; + const char* kVp_str = 0; + const char* keV_str = 0; + + const char* const usage = "ctac_to_mu_values -o output_filename -i input_volume -j slope_filename -m manufacturer_name [-v " + "kilovoltage_peak] -k target_photon_energy\n" + "Default value for tube voltage is 120 kV.\n"; opterr = 0; { char c; - while ((c = getopt (argc, argv, "i:o:j:m:v:k:?")) != -1) - switch (c) - { - case 'i': - input_filename = optarg; - break; - case 'o': - output_filename = optarg; - break; - case 'j': - slope_filename = optarg; - break; - case 'm': - manufacturer_name = optarg; - break; - case 'v': - kVp_str = optarg; - break; - case 'k': - keV_str = optarg; - break; - case '?': - std::cerr << usage; - return EXIT_FAILURE; - default: - if (isprint (optopt)) - fprintf (stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf (stderr, - "Unknown option character `\\x%x'.\n", - optopt); - std::cerr << usage; - return EXIT_FAILURE; - } + while ((c = getopt(argc, argv, "i:o:j:m:v:k:?")) != -1) + switch (c) { + case 'i': + input_filename = optarg; + break; + case 'o': + output_filename = optarg; + break; + case 'j': + slope_filename = optarg; + break; + case 'm': + manufacturer_name = optarg; + break; + case 'v': + kVp_str = optarg; + break; + case 'k': + keV_str = optarg; + break; + case '?': + std::cerr << usage; + return EXIT_FAILURE; + default: + if (isprint(optopt)) + fprintf(stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); + std::cerr << usage; + return EXIT_FAILURE; + } } - if (output_filename==0 || input_filename==0 || slope_filename==0 || manufacturer_name==0 || keV_str==0 ) - { - std::cerr << usage; - return EXIT_FAILURE; - } + if (output_filename == 0 || input_filename == 0 || slope_filename == 0 || manufacturer_name == 0 || keV_str == 0) { + std::cerr << usage; + return EXIT_FAILURE; + } - if (kVp_str == 0){ - //If the user does not specify a value for kVP, assume 120 kVp. + if (kVp_str == 0) { + // If the user does not specify a value for kVP, assume 120 kVp. kVp_str = "120"; stir::info(boost::format("No value for kVp given, assuming %s") % kVp_str); } - try - { - HUToMuImageProcessor > hu_to_mu; - hu_to_mu.set_manufacturer_name(manufacturer_name); - hu_to_mu.set_slope_filename(slope_filename); - hu_to_mu.set_target_photon_energy(std::stof(keV_str)); - hu_to_mu.set_kilovoltage_peak(std::stof(kVp_str)); - //Read DICOM data - stir::info(boost::format("ctac_to_mu_values: opening file %1%") % input_filename); - unique_ptr< FloatImageType > input_image_sptr(stir::read_from_file( input_filename )); - hu_to_mu.set_up(*input_image_sptr); - - //Create output image from input image. - shared_ptr< FloatImageType > output_image_sptr(input_image_sptr->clone()); - //Apply scaling. - hu_to_mu.apply(*output_image_sptr, *input_image_sptr); - //Write output file. - write_to_file(output_filename, *output_image_sptr); - } - catch (std::string& error_string) - { - // don't print yet, as error() already does that at the moment - // std::cerr << error_string << std::endl; - return EXIT_FAILURE; - } - catch (std::exception& e) - { - stir::warning(e.what()); - return EXIT_FAILURE; - } - catch (...) - { - return EXIT_FAILURE; - } + try { + HUToMuImageProcessor> hu_to_mu; + hu_to_mu.set_manufacturer_name(manufacturer_name); + hu_to_mu.set_slope_filename(slope_filename); + hu_to_mu.set_target_photon_energy(std::stof(keV_str)); + hu_to_mu.set_kilovoltage_peak(std::stof(kVp_str)); + // Read DICOM data + stir::info(boost::format("ctac_to_mu_values: opening file %1%") % input_filename); + unique_ptr input_image_sptr(stir::read_from_file(input_filename)); + hu_to_mu.set_up(*input_image_sptr); + + // Create output image from input image. + shared_ptr output_image_sptr(input_image_sptr->clone()); + // Apply scaling. + hu_to_mu.apply(*output_image_sptr, *input_image_sptr); + // Write output file. + write_to_file(output_filename, *output_image_sptr); + } catch (std::string& error_string) { + // don't print yet, as error() already does that at the moment + // std::cerr << error_string << std::endl; + return EXIT_FAILURE; + } catch (std::exception& e) { + stir::warning(e.what()); + return EXIT_FAILURE; + } catch (...) { + return EXIT_FAILURE; + } return EXIT_SUCCESS; - } diff --git a/src/utilities/display_projdata.cxx b/src/utilities/display_projdata.cxx index f7f378f03f..fdad4485b5 100644 --- a/src/utilities/display_projdata.cxx +++ b/src/utilities/display_projdata.cxx @@ -1,9 +1,9 @@ // // /*! - \file + \file \ingroup utilities - + \brief This program displays projection data by segment \author Kris Thielemans @@ -35,45 +35,40 @@ #include "stir/display.h" #include "stir/utilities.h" - #ifndef STIR_NO_NAMESPACES using std::cout; #endif USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) { + if (argc < 2) { + cout << "Usage: display_projdata
      (*.hs)\n"; + exit(EXIT_FAILURE); + } -int main(int argc, char *argv[]) -{ - if(argc<2) { - cout<<"Usage: display_projdata
      (*.hs)\n"; - exit(EXIT_FAILURE); - } + shared_ptr s3d = ProjData::read_from_file(argv[1]); - - - shared_ptr s3d = ProjData::read_from_file(argv[1]); + do { + int segment_num = + ask_num("Which segment number do you want to display", s3d->get_min_segment_num(), s3d->get_max_segment_num(), 0); - do { - int segment_num = ask_num("Which segment number do you want to display", - s3d->get_min_segment_num(), s3d->get_max_segment_num(), 0); + int tof_num = + ask_num("Which timing pos number do you want to display", s3d->get_min_tof_pos_num(), s3d->get_max_tof_pos_num(), 0); - if(ask_num("Display as SegmentByView (0) or BySinogram (1)?", 0,1,0)==0) - { - SegmentByView segment= s3d->get_segment_by_view(segment_num); - const float maxi = - ask_num("Maximum in color scale (default is actual max)",0.F,2*segment.find_max(),segment.find_max()); - display(segment,maxi); - } - else - { - SegmentBySinogram segment = s3d->get_segment_by_sinogram(segment_num); - const float maxi = - ask_num("Maximum in color scale (default is actual max)",0.F,2*segment.find_max(),segment.find_max()); - display(segment,maxi); - } + if (ask_num("Display as SegmentByView (0) or BySinogram (1)?", 0, 1, 0) == 0) { + SegmentByView segment = s3d->get_segment_by_view(segment_num, tof_num); + const float maxi = + ask_num("Maximum in color scale (default is actual max)", 0.F, 2 * segment.find_max(), segment.find_max()); + display(segment, maxi); + } else { + SegmentBySinogram segment = s3d->get_segment_by_sinogram(segment_num, tof_num); + const float maxi = + ask_num("Maximum in color scale (default is actual max)", 0.F, 2 * segment.find_max(), segment.find_max()); + display(segment, maxi); } - while (ask("Display another segment ?",true)); + } while (ask("Display another segment ?", true)); - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/src/utilities/do_linear_regression.cxx b/src/utilities/do_linear_regression.cxx index d21f9f523c..27e5d47bfe 100644 --- a/src/utilities/do_linear_regression.cxx +++ b/src/utilities/do_linear_regression.cxx @@ -1,10 +1,10 @@ // // /*! - \file + \file \ingroup utilities - - \brief + + \brief A simple programme to perform weighted least squares. \author Kris Thielemans @@ -12,7 +12,7 @@ This performs a weighted least squares fit.
      - stdev and covariance are computed using the estimated + stdev and covariance are computed using the estimated variance chi_square/(n-2). The file should contain data in the following format:
      @@ -54,32 +54,26 @@ using std::ifstream; USING_NAMESPACE_STIR +int +main(int argc, char** argv) { -int main(int argc, char **argv) -{ - - if (argc != 2) - { + if (argc != 2) { cerr << "Usage : " << argv[0] << " filename\n" << "This performs a weighted least squares fit.\n" - << "stdev and covariance are computed using the estimated " - << "variance chi_square/(n-2).\n\n" - << "The file should contain data in the following format:\n\n" - << "number_of_points\n" - << "coordinates\n" - << "data\n" - << "weights\n" << endl; + << "stdev and covariance are computed using the estimated " + << "variance chi_square/(n-2).\n\n" + << "The file should contain data in the following format:\n\n" + << "number_of_points\n" + << "coordinates\n" + << "data\n" + << "weights\n" + << endl; return EXIT_FAILURE; } - - ifstream in(argv[1]); - if (!in) - { - cerr << argv[0] - << ": Error opening input file " << argv[1] << "\nExiting." - << endl; + if (!in) { + cerr << argv[0] << ": Error opening input file " << argv[1] << "\nExiting." << endl; return EXIT_FAILURE; } @@ -89,50 +83,34 @@ int main(int argc, char **argv) VectorWithOffset coordinates(size); VectorWithOffset measured_data(size); VectorWithOffset weights(size); - for (int i=0; i> coordinates[i]; - if (!in) - error("%s: error reading input file %s after the %d-th coordinate\n", - argv[0], argv[1], i); - } - for (int i=0; i> measured_data[i]; - if (!in) - error("%s: error reading input file %s after the %d-th measured_data\n", - argv[0], argv[1], i); - } - for (int i=0; i> weights[i]; - if (!in) - error("%s: error reading input file %s after the %d-th weight\n", - argv[0], argv[1], i); - } - - double scale=0; - double constant=0; - double variance_of_scale=0; - double variance_of_constant=0; - double covariance_of_constant_with_scale=0; + for (int i = 0; i < size; i++) { + in >> coordinates[i]; + if (!in) + error("%s: error reading input file %s after the %d-th coordinate\n", argv[0], argv[1], i); + } + for (int i = 0; i < size; i++) { + in >> measured_data[i]; + if (!in) + error("%s: error reading input file %s after the %d-th measured_data\n", argv[0], argv[1], i); + } + for (int i = 0; i < size; i++) { + in >> weights[i]; + if (!in) + error("%s: error reading input file %s after the %d-th weight\n", argv[0], argv[1], i); + } + + double scale = 0; + double constant = 0; + double variance_of_scale = 0; + double variance_of_constant = 0; + double covariance_of_constant_with_scale = 0; double chi_square = 0; - linear_regression( - constant, scale, - chi_square, - variance_of_constant, - variance_of_scale, - covariance_of_constant_with_scale, - measured_data, - coordinates, - weights); - - cout << "scale = " << scale << " +- " << sqrt(variance_of_scale) - << ", cst = " << constant << " +- " << sqrt(variance_of_constant) - << "\nchi_square = " << chi_square - << "\ncovariance = " << covariance_of_constant_with_scale + linear_regression(constant, scale, chi_square, variance_of_constant, variance_of_scale, covariance_of_constant_with_scale, + measured_data, coordinates, weights); + + cout << "scale = " << scale << " +- " << sqrt(variance_of_scale) << ", cst = " << constant << " +- " + << sqrt(variance_of_constant) << "\nchi_square = " << chi_square << "\ncovariance = " << covariance_of_constant_with_scale << endl; return EXIT_SUCCESS; } - diff --git a/src/utilities/ecat/conv_to_ecat6.cxx b/src/utilities/ecat/conv_to_ecat6.cxx index 5b88bbe5a8..5bc2b0dc8e 100644 --- a/src/utilities/ecat/conv_to_ecat6.cxx +++ b/src/utilities/ecat/conv_to_ecat6.cxx @@ -17,16 +17,16 @@ See STIR/LICENSE.txt for details */ -/*! +/*! \file \ingroup ECAT_utilities -\brief Conversion from interfile (or any format that we can read) +\brief Conversion from interfile (or any format that we can read) to ECAT 6 cti (image and sinogram data) \author Kris Thielemans \author PARAPET project -This programme is used to convert image or projection data into CTI ECAT 6 data (input -can be any format currently supported by the library). It normally should be run as +This programme is used to convert image or projection data into CTI ECAT 6 data (input +can be any format currently supported by the library). It normally should be run as follows
      conv_to_ecat6 [-k] [-i]  outputfilename.img input_filename1 [input_filename2 ...] scanner_name
       
      @@ -34,27 +34,26 @@ follows
      conv_to_ecat6 -s[2] [-k] [-i] outputfilename.scn input_filename1 [input_filename2 ...]
       
      (for projection data)
      -If there are no command line parameters, the user is asked for the filenames and options -instead. Unless the -i option is used, the data will be assigned a frame number in the +If there are no command line parameters, the user is asked for the filenames and options +instead. Unless the -i option is used, the data will be assigned a frame number in the order that they occur on the command line.
      -See buildblock/Scanner.cxx for supported scanner names, but examples are ECAT 953, -ART, Advance. ECAT HR+, etc. If the scanner_name contains a space, the scanner name has to +See buildblock/Scanner.cxx for supported scanner names, but examples are ECAT 953, +ART, Advance. ECAT HR+, etc. If the scanner_name contains a space, the scanner name has to be surrounded by double quotes (") when used as a command line argument. \par Command line options:
      • -s2: This option forces output to 2D sinograms (ignoring higher segments).
      • -
      • -k: the existing ECAT6 file will NOT be overwritten, but added to. Any existing -data in the ECAT6 file with the same <frame,gate,data,bed> specification will be +
      • -k: the existing ECAT6 file will NOT be overwritten, but added to. Any existing +data in the ECAT6 file with the same <frame,gate,data,bed> specification will be overwritten.
      • -i: ask for <frame,gate,data,bed> for each dataset
      -Note that to store projection data in ECAT6, a 3D sinogram cannot be axially compressed +Note that to store projection data in ECAT6, a 3D sinogram cannot be axially compressed (CTI span=1). */ - #include "stir/DiscretisedDensity.h" #include "stir/ProjData.h" #include "stir/shared_ptr.h" @@ -80,240 +79,191 @@ USING_NAMESPACE_STIR USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT6 - -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { char cti_name[1000], scanner_name[1000] = ""; vector filenames; bool its_an_image = true; bool its_a_2D_sinogram = false; bool add_to_existing = false; bool interactive = false; - - if(argc>=4) - { - if (strncmp(argv[1],"-s",2)==0) - { - its_an_image = false; - its_a_2D_sinogram = strlen(argv[1])==3 && argv[1][2]=='2'; - if (its_a_2D_sinogram) - cout << "I will write 2D sinograms\n"; - while (argv[2][0] == '-') - { - if (strcmp(argv[2],"-k")==0) - add_to_existing = true; - else if (strcmp(argv[2],"-i")==0) - interactive = true; - else - warning("Ignored unrecognised option: %s.", argv[2]); - - argv++; argc--; - } - strcpy(cti_name,argv[2]); - int num_files = argc-3; - argv+=3; - filenames.reserve(num_files); - for (; num_files>0; --num_files, ++argv) - filenames.push_back(*argv); - } - else - { - its_an_image = true; - strcpy(cti_name,argv[1]); - int num_files = argc-3; - argv+=2; - filenames.reserve(num_files); - for (; num_files>0; --num_files, ++argv) - filenames.push_back(*argv); - strcpy(scanner_name,*argv); + if (argc >= 4) { + if (strncmp(argv[1], "-s", 2) == 0) { + its_an_image = false; + its_a_2D_sinogram = strlen(argv[1]) == 3 && argv[1][2] == '2'; + if (its_a_2D_sinogram) + cout << "I will write 2D sinograms\n"; + + while (argv[2][0] == '-') { + if (strcmp(argv[2], "-k") == 0) + add_to_existing = true; + else if (strcmp(argv[2], "-i") == 0) + interactive = true; + else + warning("Ignored unrecognised option: %s.", argv[2]); + + argv++; + argc--; } - } - else - { - cerr<< "\nConversion from data to ECAT6 CTI.\n" - << "Multiples files can be written to a single ECAT 6 file.\n" - << "Unless the -i option is used, the data will be assigned a frame number in \n" - << "the order that they occur on the command line.\n\n" - << "Usage: 2 possible forms depending on data type\n" - << "For sinogram data:\n" - << "\tconv_to_ecat6 -s[2] [-k] [-i] output_ECAT6_name orig_filename1 [orig_filename2 ...]\n" - << "\tThe -s2 option forces output to 2D sinograms (ignoring higher segments).\n" - << "For image data:\n" - << "\tconv_to_ecat6 [-k] [-i] output_ECAT6_name orig_filename1 [orig_filename2 ...] scanner_name\n" - << "scanner_name has to be recognised by the Scanner class\n" - << "Examples are : \"ECAT 953\", \"RPT\" etc.\n" - << "(the quotes are required when used as a command line argument)\n\n" - << "Options:\n" - << " -k: the existing ECAT6 file will NOT be overwritten,\n" - << "\tbut added to. Any existing data in the ECAT6 file with the same \n" - << "\tspecification will be overwritten.\n" - << " -i: ask for for each dataset\n\n" - << "I will now ask you the same info interactively...\n\n"; - - its_an_image = ask("Converting images?",true); + strcpy(cti_name, argv[2]); + int num_files = argc - 3; + argv += 3; + filenames.reserve(num_files); + for (; num_files > 0; --num_files, ++argv) + filenames.push_back(*argv); + } else { + its_an_image = true; + strcpy(cti_name, argv[1]); + int num_files = argc - 3; + argv += 2; + filenames.reserve(num_files); + for (; num_files > 0; --num_files, ++argv) + filenames.push_back(*argv); + strcpy(scanner_name, *argv); + } + } else { + cerr << "\nConversion from data to ECAT6 CTI.\n" + << "Multiples files can be written to a single ECAT 6 file.\n" + << "Unless the -i option is used, the data will be assigned a frame number in \n" + << "the order that they occur on the command line.\n\n" + << "Usage: 2 possible forms depending on data type\n" + << "For sinogram data:\n" + << "\tconv_to_ecat6 -s[2] [-k] [-i] output_ECAT6_name orig_filename1 [orig_filename2 ...]\n" + << "\tThe -s2 option forces output to 2D sinograms (ignoring higher segments).\n" + << "For image data:\n" + << "\tconv_to_ecat6 [-k] [-i] output_ECAT6_name orig_filename1 [orig_filename2 ...] scanner_name\n" + << "scanner_name has to be recognised by the Scanner class\n" + << "Examples are : \"ECAT 953\", \"RPT\" etc.\n" + << "(the quotes are required when used as a command line argument)\n\n" + << "Options:\n" + << " -k: the existing ECAT6 file will NOT be overwritten,\n" + << "\tbut added to. Any existing data in the ECAT6 file with the same \n" + << "\tspecification will be overwritten.\n" + << " -i: ask for for each dataset\n\n" + << "I will now ask you the same info interactively...\n\n"; + + its_an_image = ask("Converting images?", true); if (!its_an_image) - its_a_2D_sinogram = ask("Write as 2D sinogram?",false); + its_a_2D_sinogram = ask("Write as 2D sinogram?", false); - int num_files = ask_num("Number of files",1,10000,1); + int num_files = ask_num("Number of files", 1, 10000, 1); filenames.reserve(num_files); char cur_name[max_filename_length]; - for (; num_files>0; --num_files) - { - ask_filename_with_extension(cur_name,"Name of the input file? ",its_an_image?".hv":".hs"); + for (; num_files > 0; --num_files) { + ask_filename_with_extension(cur_name, "Name of the input file? ", its_an_image ? ".hv" : ".hs"); filenames.push_back(cur_name); } - - ask_filename_with_extension(cti_name,"Name of the ECAT6 file? ", - its_an_image ? ".img" : ".scn"); + + ask_filename_with_extension(cti_name, "Name of the ECAT6 file? ", its_an_image ? ".img" : ".scn"); } size_t num_frames, num_gates, num_bed_poss, num_data; - if (interactive) - { - num_frames = ask_num("Num frames?",static_cast(1),filenames.size(), filenames.size()); - num_gates = ask_num("Num gates?",static_cast(1),filenames.size()/num_frames, filenames.size()/num_frames); - num_bed_poss = ask_num("Num bed positions?",static_cast(1),filenames.size(), filenames.size()); - num_data = ask_num("Num data?",static_cast(1),filenames.size()/num_frames, filenames.size()/num_frames); - } - else - { - num_frames = filenames.size(); - num_gates=1; - num_bed_poss=1; - num_data=1; - } + if (interactive) { + num_frames = ask_num("Num frames?", static_cast(1), filenames.size(), filenames.size()); + num_gates = ask_num("Num gates?", static_cast(1), filenames.size() / num_frames, filenames.size() / num_frames); + num_bed_poss = ask_num("Num bed positions?", static_cast(1), filenames.size(), filenames.size()); + num_data = ask_num("Num data?", static_cast(1), filenames.size() / num_frames, filenames.size() / num_frames); + } else { + num_frames = filenames.size(); + num_gates = 1; + num_bed_poss = 1; + num_data = 1; + } size_t min_frame_num = 1; size_t max_frame_num = num_frames; size_t min_bed_num = 0; - size_t max_bed_num = num_bed_poss-1; + size_t max_bed_num = num_bed_poss - 1; size_t min_gate_num = 1; size_t max_gate_num = num_gates; size_t min_data_num = 0; - if (its_an_image) - { + if (its_an_image) { - shared_ptr scanner_ptr( - strlen(scanner_name)==0 ? - Scanner::ask_parameters() : - Scanner::get_scanner_from_name(scanner_name)); + shared_ptr scanner_ptr(strlen(scanner_name) == 0 ? Scanner::ask_parameters() + : Scanner::get_scanner_from_name(scanner_name)); // read first image cerr << "Reading " << filenames[0] << endl; - shared_ptr > - density_ptr(read_from_file >(filenames[0])); - + shared_ptr> density_ptr(read_from_file>(filenames[0])); + ECAT6_Main_header mhead; make_ECAT6_Main_header(mhead, *scanner_ptr, filenames[0], *density_ptr); mhead.num_frames = filenames.size(); - FILE *fptr= cti_create (cti_name, &mhead); - if (fptr == NULL) - { + FILE* fptr = cti_create(cti_name, &mhead); + if (fptr == NULL) { warning("conv_to_ecat6: error opening output file %s\n", cti_name); return EXIT_FAILURE; } size_t frame_num = 1; - while (1) - { - if (DiscretisedDensity_to_ECAT6(fptr, - *density_ptr, - mhead, - frame_num) - == Succeeded::no) - { + while (1) { + if (DiscretisedDensity_to_ECAT6(fptr, *density_ptr, mhead, frame_num) == Succeeded::no) { fclose(fptr); return EXIT_FAILURE; } - if (++frame_num > filenames.size()) - { + if (++frame_num > filenames.size()) { fclose(fptr); return EXIT_SUCCESS; } - cerr << "Reading " << filenames[frame_num-1] << endl; - density_ptr = - read_from_file >(filenames[frame_num-1]); + cerr << "Reading " << filenames[frame_num - 1] << endl; + density_ptr = read_from_file>(filenames[frame_num - 1]); } - } - else - { - + } else { + // read first data set cerr << "Reading " << filenames[0] << endl; - shared_ptr proj_data_ptr = - ProjData::read_from_file(filenames[0]); - + shared_ptr proj_data_ptr = ProjData::read_from_file(filenames[0]); + ECAT6_Main_header mhead; - FILE *fptr; + FILE* fptr; - if (add_to_existing) - { - fptr = fopen(cti_name,"wb+"); - if (!fptr) - error("Error opening cti file %s\n", cti_name); - if (cti_read_ECAT6_Main_header (fptr, &mhead) == EXIT_FAILURE) - error("Error reading main header from cti file %s\n", cti_name); - } - else - { - make_ECAT6_Main_header(mhead, filenames[0], *proj_data_ptr->get_proj_data_info_sptr()); - mhead.num_frames = num_frames; - mhead.num_gates = num_gates; - mhead.num_bed_pos = num_bed_poss-1; - //mhead.num_data = num_data; - - fptr = cti_create (cti_name, &mhead); - if (fptr == NULL) - { - warning("conv_to_ecat6: error opening output file %s\n", cti_name); - return EXIT_FAILURE; - } + if (add_to_existing) { + fptr = fopen(cti_name, "wb+"); + if (!fptr) + error("Error opening cti file %s\n", cti_name); + if (cti_read_ECAT6_Main_header(fptr, &mhead) == EXIT_FAILURE) + error("Error reading main header from cti file %s\n", cti_name); + } else { + make_ECAT6_Main_header(mhead, filenames[0], *proj_data_ptr->get_proj_data_info_sptr()); + mhead.num_frames = num_frames; + mhead.num_gates = num_gates; + mhead.num_bed_pos = num_bed_poss - 1; + // mhead.num_data = num_data; + + fptr = cti_create(cti_name, &mhead); + if (fptr == NULL) { + warning("conv_to_ecat6: error opening output file %s\n", cti_name); + return EXIT_FAILURE; } + } size_t frame_num = 1; - while (1) - { + while (1) { size_t current_frame_num, current_bed_num, current_gate_num, current_data_num; - if (interactive) - { - current_frame_num= - ask_num("Frame number ? ", min_frame_num, max_frame_num, min_frame_num); - current_bed_num= - ask_num("Bed number ? ", min_bed_num, max_bed_num, min_bed_num); - current_gate_num= - ask_num("Gate number ? ", min_gate_num, max_gate_num, min_gate_num); - current_data_num= - ask_num("Data number ? ",0,7, 0); - } - else - { - current_frame_num = frame_num; - current_bed_num = min_bed_num; - current_gate_num = min_gate_num; - current_data_num = min_data_num; - } - if (ProjData_to_ECAT6(fptr, - *proj_data_ptr, - mhead, - current_frame_num, current_gate_num, current_data_num, current_bed_num, - its_a_2D_sinogram) - == Succeeded::no) - { + if (interactive) { + current_frame_num = ask_num("Frame number ? ", min_frame_num, max_frame_num, min_frame_num); + current_bed_num = ask_num("Bed number ? ", min_bed_num, max_bed_num, min_bed_num); + current_gate_num = ask_num("Gate number ? ", min_gate_num, max_gate_num, min_gate_num); + current_data_num = ask_num("Data number ? ", 0, 7, 0); + } else { + current_frame_num = frame_num; + current_bed_num = min_bed_num; + current_gate_num = min_gate_num; + current_data_num = min_data_num; + } + if (ProjData_to_ECAT6(fptr, *proj_data_ptr, mhead, current_frame_num, current_gate_num, current_data_num, current_bed_num, + its_a_2D_sinogram) == Succeeded::no) { fclose(fptr); return EXIT_FAILURE; } - if (++frame_num > filenames.size()) - { + if (++frame_num > filenames.size()) { fclose(fptr); return EXIT_SUCCESS; } - cerr << "Reading " << filenames[frame_num-1] << endl; - proj_data_ptr = - ProjData::read_from_file(filenames[frame_num-1]); + cerr << "Reading " << filenames[frame_num - 1] << endl; + proj_data_ptr = ProjData::read_from_file(filenames[frame_num - 1]); } - } + } } - - diff --git a/src/utilities/ecat/conv_to_ecat7.cxx b/src/utilities/ecat/conv_to_ecat7.cxx index 24ae587a4a..2b0e950d48 100644 --- a/src/utilities/ecat/conv_to_ecat7.cxx +++ b/src/utilities/ecat/conv_to_ecat7.cxx @@ -1,14 +1,14 @@ -/*! +/*! \file \ingroup ECAT_utilities -\brief Conversion from interfile (or any format that we can read) +\brief Conversion from interfile (or any format that we can read) to ECAT 7 cti (image and sinogram data) \author Kris Thielemans \author PARAPET project -This programme is used to convert image or projection data into CTI ECAT 7 data (input -can be any format currently supported by the library). It normally should be run as +This programme is used to convert image or projection data into CTI ECAT 7 data (input +can be any format currently supported by the library). It normally should be run as follows
      conv_to_ecat7 output_ECAT7_name input_filename1 [input_filename2 ...] scanner_name
       
      @@ -19,11 +19,11 @@ follows
      conv_to_ecat7 -a output_ECAT7_name  input_filename1 [input_filename2 ...]
       
      (for sinogram-attenuation data)
      -If there are no command line parameters, the user is asked for the filenames and options -instead. The data will be assigned a frame number in the +If there are no command line parameters, the user is asked for the filenames and options +instead. The data will be assigned a frame number in the order that they occur on the command line.
      -See buildblock/Scanner.cxx for supported scanner names, but examples are ECAT 953, -ART, Advance. ECAT HR+, etc. If the scanner_name contains a space, the scanner name has to +See buildblock/Scanner.cxx for supported scanner names, but examples are ECAT 953, +ART, Advance. ECAT HR+, etc. If the scanner_name contains a space, the scanner name has to be surrounded by double quotes (") when used as a command line argument. */ /* @@ -68,242 +68,195 @@ USING_NAMESPACE_STIR USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 - - - -void usage() { - - cerr << "\nConversion from data to ECAT7 CTI.\n" - << "Multiples files can be written to a single ECAT 7 file.\n" - << "The data will be assigned a frame number in the " - << "order that they occur on the command line.\n\n" - << "Usage: 3 possible forms depending on data type\n" - << "For sinogram data:\n" - << "\tconv_to_ecat7 -s [-n] output_ECAT7_name orig_filename1 [orig_filename2 ...]\n" - << "For sinogram-attenuation data:\n" - << "\tconv_to_ecat7 -a [-n] output_ECAT7_name orig_filename1 [orig_filename2 ...]\n" - << "For image data:\n" - << "\tconv_to_ecat7 output_ECAT7_name orig_filename1 [orig_filename2 ...] scanner_name\n" - << "scanner_name has to be recognised by the Scanner class\n" - << "Examples are : \"ECAT 953\", \"RPT\" etc.\n" - << "(the quotes are required when used as a command line argument)\n\n"; +void +usage() { + + cerr << "\nConversion from data to ECAT7 CTI.\n" + << "Multiples files can be written to a single ECAT 7 file.\n" + << "The data will be assigned a frame number in the " + << "order that they occur on the command line.\n\n" + << "Usage: 3 possible forms depending on data type\n" + << "For sinogram data:\n" + << "\tconv_to_ecat7 -s [-n] output_ECAT7_name orig_filename1 [orig_filename2 ...]\n" + << "For sinogram-attenuation data:\n" + << "\tconv_to_ecat7 -a [-n] output_ECAT7_name orig_filename1 [orig_filename2 ...]\n" + << "For image data:\n" + << "\tconv_to_ecat7 output_ECAT7_name orig_filename1 [orig_filename2 ...] scanner_name\n" + << "scanner_name has to be recognised by the Scanner class\n" + << "Examples are : \"ECAT 953\", \"RPT\" etc.\n" + << "(the quotes are required when used as a command line argument)\n\n"; } - - - - - -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { char cti_name[1000], scanner_name[1000] = ""; vector filenames; bool its_an_image = true; bool write_as_attenuation = false; float scale_factor = 0.0; - - + int arg_index = 1; - + /* Check options - single letters only */ - while ( arg_index < argc && argv[arg_index][0] == '-' ) { - + while (arg_index < argc && argv[arg_index][0] == '-') { + int i = 1; char c; - - while ( (c = argv[arg_index][i]) != '\0' ) { - - switch ( c ) { - + + while ((c = argv[arg_index][i]) != '\0') { + + switch (c) { + case 's': its_an_image = false; break; - + case 'a': its_an_image = false; write_as_attenuation = true; break; - + case 'n': scale_factor = 1.0F; break; - + default: cerr << "Error: Unknown option " << c << " \n\n"; usage(); exit(0); break; - } - + i++; } - + arg_index++; } - - - /* Check number of remaining arguments */ - if ( (its_an_image == false && argc - arg_index >= 1) || argc - arg_index >= 2) { - + if ((its_an_image == false && argc - arg_index >= 1) || argc - arg_index >= 2) { + // Warn about scaling option on it's own. - if ( its_an_image == true && scale_factor != 0.0F ) { + if (its_an_image == true && scale_factor != 0.0F) { cerr << "Warning: option -n has no effect when converting images.\n\n"; } - - + /* Parse remaining arguments */ strcpy(cti_name, argv[arg_index]); arg_index++; - int num_files; - if ( its_an_image ) { - + if (its_an_image) { + for (num_files = argc - arg_index - 1; num_files > 0; --num_files, arg_index++) { filenames.push_back(argv[arg_index]); } - + strcpy(scanner_name, argv[arg_index]); - + } else { - - for (num_files = argc - arg_index; num_files>0; --num_files, arg_index++) { + + for (num_files = argc - arg_index; num_files > 0; --num_files, arg_index++) { filenames.push_back(argv[arg_index]); } } } else { - + usage(); cerr << "I will now ask you the same info interactively...\n\n"; - - its_an_image = ask("Converting images?",true); - + + its_an_image = ask("Converting images?", true); + if (!its_an_image) { - write_as_attenuation = ask("Write as attenuation data?",false); + write_as_attenuation = ask("Write as attenuation data?", false); } else { - if ( ask("Fix scale factor to 1.0?", false) ) { + if (ask("Fix scale factor to 1.0?", false)) { scale_factor = 1.0F; } } - int num_files = ask_num("Number of files",1,10000,1); + int num_files = ask_num("Number of files", 1, 10000, 1); filenames.reserve(num_files); char cur_name[max_filename_length]; - for (; num_files>0; --num_files) - { - ask_filename_with_extension(cur_name,"Name of the input file? ",its_an_image?".hv":".hs"); + for (; num_files > 0; --num_files) { + ask_filename_with_extension(cur_name, "Name of the input file? ", its_an_image ? ".hv" : ".hs"); filenames.push_back(cur_name); } - - ask_filename_with_extension(cti_name,"Name of the ECAT7 file? ", - its_an_image ? ".img" : ".scn"); - - } - + ask_filename_with_extension(cti_name, "Name of the ECAT7 file? ", its_an_image ? ".img" : ".scn"); + } - if (its_an_image) - { + if (its_an_image) { - shared_ptr scanner_ptr( - strlen(scanner_name)==0 ? - Scanner::ask_parameters() : - Scanner::get_scanner_from_name(scanner_name)); + shared_ptr scanner_ptr(strlen(scanner_name) == 0 ? Scanner::ask_parameters() + : Scanner::get_scanner_from_name(scanner_name)); // read first image cerr << "Reading " << filenames[0] << endl; - shared_ptr > density_ptr( - read_from_file >(filenames[0])); - + shared_ptr> density_ptr(read_from_file>(filenames[0])); + Main_header mhead; make_ECAT7_main_header(mhead, *scanner_ptr, filenames[0], *density_ptr); mhead.num_frames = filenames.size(); - mhead.acquisition_type = - mhead.num_frames>1 ? DynamicEmission : StaticEmission; + mhead.acquisition_type = mhead.num_frames > 1 ? DynamicEmission : StaticEmission; - MatrixFile* mptr= matrix_create (cti_name, MAT_CREATE, &mhead); - if (mptr == 0) - { + MatrixFile* mptr = matrix_create(cti_name, MAT_CREATE, &mhead); + if (mptr == 0) { warning(boost::format("conv_to_ecat7: error opening output file %s. Remove first if it exists already") % cti_name); return EXIT_FAILURE; } unsigned int frame_num = 1; - while (1) - { - if (DiscretisedDensity_to_ECAT7(mptr, - *density_ptr, - frame_num) - == Succeeded::no) - { + while (1) { + if (DiscretisedDensity_to_ECAT7(mptr, *density_ptr, frame_num) == Succeeded::no) { matrix_close(mptr); return EXIT_FAILURE; } - if (++frame_num > filenames.size()) - { + if (++frame_num > filenames.size()) { matrix_close(mptr); return EXIT_SUCCESS; } - cerr << "Reading " << filenames[frame_num-1] << endl; - density_ptr = - read_from_file >(filenames[frame_num-1]); + cerr << "Reading " << filenames[frame_num - 1] << endl; + density_ptr = read_from_file>(filenames[frame_num - 1]); } - } - else - { - + } else { + // read first data set cerr << "Reading " << filenames[0] << endl; - shared_ptr proj_data_ptr = - ProjData::read_from_file(filenames[0]); - + shared_ptr proj_data_ptr = ProjData::read_from_file(filenames[0]); + Main_header mhead; // TODO exam_info currently used from the first frame, which means that time frame info is incorrect // better to use DynamicProjData etc. - make_ECAT7_main_header(mhead, filenames[0], - proj_data_ptr->get_exam_info(), - *proj_data_ptr->get_proj_data_info_sptr(), - write_as_attenuation, - NumericType::SHORT); + make_ECAT7_main_header(mhead, filenames[0], proj_data_ptr->get_exam_info(), *proj_data_ptr->get_proj_data_info_sptr(), + write_as_attenuation, NumericType::SHORT); // fix time frame info mhead.num_frames = filenames.size(); - if (!write_as_attenuation) - { - mhead.acquisition_type = - mhead.num_frames>1 ? DynamicEmission : StaticEmission; - } - MatrixFile* mptr= matrix_create (cti_name, MAT_CREATE, &mhead); - if (mptr == 0) - { + if (!write_as_attenuation) { + mhead.acquisition_type = mhead.num_frames > 1 ? DynamicEmission : StaticEmission; + } + MatrixFile* mptr = matrix_create(cti_name, MAT_CREATE, &mhead); + if (mptr == 0) { warning(boost::format("conv_to_ecat7: error opening output file %s. Remove first if it exists already") % cti_name); return EXIT_FAILURE; } unsigned int frame_num = 1; - while (1) - { - if (ProjData_to_ECAT7(mptr, *proj_data_ptr, - frame_num, 1, 0, 0, scale_factor) == Succeeded::no) - { + while (1) { + if (ProjData_to_ECAT7(mptr, *proj_data_ptr, frame_num, 1, 0, 0, scale_factor) == Succeeded::no) { matrix_close(mptr); return EXIT_FAILURE; } - if (++frame_num > filenames.size()) - { + if (++frame_num > filenames.size()) { matrix_close(mptr); return EXIT_SUCCESS; } - cerr << "Reading " << filenames[frame_num-1] << endl; - proj_data_ptr = - ProjData::read_from_file(filenames[frame_num-1]); + cerr << "Reading " << filenames[frame_num - 1] << endl; + proj_data_ptr = ProjData::read_from_file(filenames[frame_num - 1]); } - } + } } - diff --git a/src/utilities/ecat/convecat6_if.cxx b/src/utilities/ecat/convecat6_if.cxx index 417bc4b464..902db1baa2 100644 --- a/src/utilities/ecat/convecat6_if.cxx +++ b/src/utilities/ecat/convecat6_if.cxx @@ -19,7 +19,7 @@ See STIR/LICENSE.txt for details */ -/*! +/*! \file \ingroup ECAT_utilities \brief Conversion from ECAT 6 cti to interfile (image and sinogram data) @@ -28,22 +28,22 @@ \author Sanida Mustafovic \author PARAPET project - \par Usage: + \par Usage:
      convecat6_if [output_file_name_without_extension cti_data_file_name [scanner_name]]
         
      The optional \a scanner_name can be used to force to a particular scanner (ignoring the system_type in the main header). \a scanner_name has to be recognised by the Scanner class. - Examples are : ECAT 953, RPT, ECAT HR+, Advance etc. If the \a scanner_name - contains a space, the scanner name has to be surrounded by double quotes + Examples are : ECAT 953, RPT, ECAT HR+, Advance etc. If the \a scanner_name + contains a space, the scanner name has to be surrounded by double quotes (") when used as a command line argument.
      - The program asks if all frames should be written or not. If so, all + The program asks if all frames should be written or not. If so, all sinograms/images are converted for a fixed 'data' number. For each data set, - a suffix is added to the output_filename of the form "_f#g#b#d#" where the # + a suffix is added to the output_filename of the form "_f#g#b#d#" where the # are replaced by the corresponding number of the frame, gate, bed, data. - \warning CTI ECAT files seem to have a peculiarity that frames and gates are + \warning CTI ECAT files seem to have a peculiarity that frames and gates are numbered from 1, while bed positions are numbered from 0. Similarly, the number of bed positions in the main header seems to be 1 less than the actual number present. This is at least the case for single bed studies. If this is not true @@ -59,7 +59,6 @@ we would have to extend OutputFileFormat to handle projection data. */ - #include "stir/utilities.h" #include "stir/IO/InterfileOutputFileFormat.h" #include "stir/shared_ptr.h" @@ -81,160 +80,127 @@ using std::min; using std::max; #endif - - USING_NAMESPACE_STIR USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT6 int -main(int argc, char *argv[]) -{ +main(int argc, char* argv[]) { std::string cti_name; std::string out_name; - char * scanner_name_ptr = 0; - FILE *cti_fptr; - - if(argc==3 || argc==4) - { - cti_name = argv[2]; - out_name = argv[1]; - if (argc>3) - scanner_name_ptr = argv[3]; - } - else - { - cerr<<"\nConversion from ECAT6 CTI data to interfile.\n"; - cerr<<"Usage: convecat6_if [output_file_name_without_extension cti_data_file_name [scanner_name]]\n" - <<"The optional scanner_name can be used to force to a particular scanner" - <<" (ignoring the system_type in the main header).\n" - << "scanner_name has to be recognised by the Scanner class\n" - << "Examples are : \"ECAT 953\", \"RPT\" etc.\n" - << "(the quotes are required when used as a command line argument)\n" - << endl; - - if (argc!=1) - exit(EXIT_FAILURE); - - out_name = ask_filename_with_extension("Name of the output file? (.hv/.hs and .v/.s will be added)",""); - cti_name = ask_filename_with_extension("Name of the input data file? ",".scn"); - - } - + char* scanner_name_ptr = 0; + FILE* cti_fptr; + + if (argc == 3 || argc == 4) { + cti_name = argv[2]; + out_name = argv[1]; + if (argc > 3) + scanner_name_ptr = argv[3]; + } else { + cerr << "\nConversion from ECAT6 CTI data to interfile.\n"; + cerr << "Usage: convecat6_if [output_file_name_without_extension cti_data_file_name [scanner_name]]\n" + << "The optional scanner_name can be used to force to a particular scanner" + << " (ignoring the system_type in the main header).\n" + << "scanner_name has to be recognised by the Scanner class\n" + << "Examples are : \"ECAT 953\", \"RPT\" etc.\n" + << "(the quotes are required when used as a command line argument)\n" + << endl; + + if (argc != 1) + exit(EXIT_FAILURE); + + out_name = ask_filename_with_extension("Name of the output file? (.hv/.hs and .v/.s will be added)", ""); + cti_name = ask_filename_with_extension("Name of the input data file? ", ".scn"); + } // open input file, read main header - cti_fptr=fopen(cti_name.c_str(), "rb"); - if(!cti_fptr) { - error("Error opening input file: %s",cti_name.c_str()); + cti_fptr = fopen(cti_name.c_str(), "rb"); + if (!cti_fptr) { + error("Error opening input file: %s", cti_name.c_str()); } ECAT6_Main_header mhead; - if(cti_read_ECAT6_Main_header(cti_fptr, &mhead)!=EXIT_SUCCESS) { - error("Unable to read main header in file: %s",cti_name.c_str()); + if (cti_read_ECAT6_Main_header(cti_fptr, &mhead) != EXIT_SUCCESS) { + error("Unable to read main header in file: %s", cti_name.c_str()); } - if (scanner_name_ptr != 0) - { + if (scanner_name_ptr != 0) { // force scanner - shared_ptr scanner_ptr( - Scanner::get_scanner_from_name(scanner_name_ptr)); + shared_ptr scanner_ptr(Scanner::get_scanner_from_name(scanner_name_ptr)); mhead.system_type = find_ECAT_system_type(*scanner_ptr); } // funnily enough, num_bed_pos seems to be offset with 1 - // (That's to say, in a singled bed study, num_bed_pos==0) + // (That's to say, in a singled bed study, num_bed_pos==0) // TODO maybe not true for multi-bed studies - const int num_frames = max(static_cast( mhead.num_frames),1); - const int num_bed_poss = max(static_cast( mhead.num_bed_pos) + 1,1); - const int num_gates = max(static_cast( mhead.num_gates),1); - + const int num_frames = max(static_cast(mhead.num_frames), 1); + const int num_bed_poss = max(static_cast(mhead.num_bed_pos) + 1, 1); + const int num_gates = max(static_cast(mhead.num_gates), 1); int min_frame_num = 1; int max_frame_num = num_frames; int min_bed_num = 0; - int max_bed_num = num_bed_poss-1; + int max_bed_num = num_bed_poss - 1; int min_gate_num = 1; int max_gate_num = num_gates; int data_num = 0; bool do_all = true; - - if (ask("Attempt all data-sets (Y) or single data-set (N)", true)) - { - data_num=ask_num("Data number ? ",0,8, 0); - - cout << "Processing frames " << min_frame_num << '-' << max_frame_num - << ", gates " << min_gate_num << '-' << max_gate_num - << ", bed positions " << min_bed_num << '-' << max_bed_num - << endl; - } - else - { - do_all = false; - min_frame_num= max_frame_num= - ask_num("Frame number ? ", min_frame_num, max_frame_num, min_frame_num); - min_bed_num= max_bed_num= - ask_num("Bed number ? ", min_bed_num, max_bed_num, min_bed_num); - min_gate_num= max_gate_num= - ask_num("Gate number ? ", min_gate_num, max_gate_num, min_gate_num); - data_num= - ask_num("Data number ? ",0,7, 0); - } - - switch(mhead.file_type) - { - case matImageFile: - { - char *new_out_filename = new char[out_name.size()+100]; - for (int frame_num=min_frame_num; frame_num<=max_frame_num;++frame_num) - for (int bed_num=min_bed_num; bed_num<=max_bed_num;++bed_num) - for (int gate_num=min_gate_num; gate_num<=max_gate_num;++gate_num) - { - strcpy(new_out_filename, out_name.c_str()); - if (do_all) - sprintf(new_out_filename+strlen(new_out_filename), "_f%dg%db%dd%d", - frame_num, gate_num, bed_num, data_num); - cout << "Writing " << new_out_filename << endl; - shared_ptr > image_ptr( - ECAT6_to_VoxelsOnCartesianGrid(frame_num, gate_num, data_num, bed_num, - cti_fptr, mhead)); - InterfileOutputFileFormat output_file_format; - output_file_format.write_to_file(new_out_filename,*image_ptr); - } - delete[] new_out_filename; - break; - } - case matScanFile: - case matAttenFile: - case matNormFile: - { - const int max_ring_diff= - ask_num("Max ring diff to store (-1 == num_rings-1)",-1,100,-1); - - const bool arccorrected = - ask("Consider the data to be arc-corrected?",false); - - char *new_out_filename = new char[out_name.size()+100]; - for (int frame_num=min_frame_num; frame_num<=max_frame_num;++frame_num) - for (int bed_num=min_bed_num; bed_num<=max_bed_num;++bed_num) - for (int gate_num=min_gate_num; gate_num<=max_gate_num;++gate_num) - { - strcpy(new_out_filename, out_name.c_str()); - if (do_all) - sprintf(new_out_filename+strlen(new_out_filename), "_f%dg%db%dd%d", - frame_num, gate_num, bed_num, data_num); - cout << "Writing " << new_out_filename << endl; - ECAT6_to_PDFS(frame_num, gate_num, data_num, bed_num, - max_ring_diff, arccorrected, - new_out_filename, cti_fptr, mhead); - } - delete[] new_out_filename; - break; - } - default: - { - error("\nSupporting only image, scan, atten or norm file type at the moment. Sorry.\n"); - } - } + + if (ask("Attempt all data-sets (Y) or single data-set (N)", true)) { + data_num = ask_num("Data number ? ", 0, 8, 0); + + cout << "Processing frames " << min_frame_num << '-' << max_frame_num << ", gates " << min_gate_num << '-' << max_gate_num + << ", bed positions " << min_bed_num << '-' << max_bed_num << endl; + } else { + do_all = false; + min_frame_num = max_frame_num = ask_num("Frame number ? ", min_frame_num, max_frame_num, min_frame_num); + min_bed_num = max_bed_num = ask_num("Bed number ? ", min_bed_num, max_bed_num, min_bed_num); + min_gate_num = max_gate_num = ask_num("Gate number ? ", min_gate_num, max_gate_num, min_gate_num); + data_num = ask_num("Data number ? ", 0, 7, 0); + } + + switch (mhead.file_type) { + case matImageFile: { + char* new_out_filename = new char[out_name.size() + 100]; + for (int frame_num = min_frame_num; frame_num <= max_frame_num; ++frame_num) + for (int bed_num = min_bed_num; bed_num <= max_bed_num; ++bed_num) + for (int gate_num = min_gate_num; gate_num <= max_gate_num; ++gate_num) { + strcpy(new_out_filename, out_name.c_str()); + if (do_all) + sprintf(new_out_filename + strlen(new_out_filename), "_f%dg%db%dd%d", frame_num, gate_num, bed_num, data_num); + cout << "Writing " << new_out_filename << endl; + shared_ptr> image_ptr( + ECAT6_to_VoxelsOnCartesianGrid(frame_num, gate_num, data_num, bed_num, cti_fptr, mhead)); + InterfileOutputFileFormat output_file_format; + output_file_format.write_to_file(new_out_filename, *image_ptr); + } + delete[] new_out_filename; + break; + } + case matScanFile: + case matAttenFile: + case matNormFile: { + const int max_ring_diff = ask_num("Max ring diff to store (-1 == num_rings-1)", -1, 100, -1); + + const bool arccorrected = ask("Consider the data to be arc-corrected?", false); + + char* new_out_filename = new char[out_name.size() + 100]; + for (int frame_num = min_frame_num; frame_num <= max_frame_num; ++frame_num) + for (int bed_num = min_bed_num; bed_num <= max_bed_num; ++bed_num) + for (int gate_num = min_gate_num; gate_num <= max_gate_num; ++gate_num) { + strcpy(new_out_filename, out_name.c_str()); + if (do_all) + sprintf(new_out_filename + strlen(new_out_filename), "_f%dg%db%dd%d", frame_num, gate_num, bed_num, data_num); + cout << "Writing " << new_out_filename << endl; + ECAT6_to_PDFS(frame_num, gate_num, data_num, bed_num, max_ring_diff, arccorrected, new_out_filename, cti_fptr, mhead); + } + delete[] new_out_filename; + break; + } + default: { + error("\nSupporting only image, scan, atten or norm file type at the moment. Sorry.\n"); + } + } fclose(cti_fptr); - + return EXIT_SUCCESS; } diff --git a/src/utilities/ecat/copy_ecat7_header.cxx b/src/utilities/ecat/copy_ecat7_header.cxx index b1099b79d9..132400a773 100644 --- a/src/utilities/ecat/copy_ecat7_header.cxx +++ b/src/utilities/ecat/copy_ecat7_header.cxx @@ -18,7 +18,7 @@ See STIR/LICENSE.txt for details */ -/*! +/*! \file \ingroup utilities \ingroup ECAT @@ -40,7 +40,6 @@ To copy a subheader (but keeping essential info) \author Kris Thielemans */ - #include "stir/Succeeded.h" #include "stir/utilities.h" #include "stir/IO/stir_ecat7.h" @@ -61,42 +60,39 @@ using std::ostream; USING_NAMESPACE_STIR USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 -#define STIR_DO_IT(x) out_sh.x =in_sh.x; +#define STIR_DO_IT(x) out_sh.x = in_sh.x; -void copy_subheader(Image_subheader& out_sh, const Image_subheader& in_sh) -{ +void +copy_subheader(Image_subheader& out_sh, const Image_subheader& in_sh) { /* - short data_type; - short num_dimensions; - short x_dimension; - short y_dimension; - short z_dimension; - short align_0; - float z_offset; - float x_offset; - float y_offset; - float scale_factor; - short image_min; - short image_max; - float x_pixel_size; - float y_pixel_size; - float z_pixel_size; - short align_1; - short align_2; - short align_3; + short data_type; + short num_dimensions; + short x_dimension; + short y_dimension; + short z_dimension; + short align_0; + float z_offset; + float x_offset; + float y_offset; + float scale_factor; + short image_min; + short image_max; + float x_pixel_size; + float y_pixel_size; + float z_pixel_size; + short align_1; + short align_2; + short align_3; */ - if (out_sh.recon_zoom==0) - { - warning("Copying recon_zoom from template as original zoom is 0. I didn't check the pixel sizes though"); - STIR_DO_IT(recon_zoom); - } - else - { - if (fabs(in_sh.recon_zoom - out_sh.recon_zoom)<.05) - warning("recon_zoom field in template (%g) and output (%g) is different.\n" - "Keeping original value for zoom (%g) (also keeping the original voxel sizes)", - out_sh.recon_zoom, in_sh.recon_zoom, in_sh.recon_zoom); - } + if (out_sh.recon_zoom == 0) { + warning("Copying recon_zoom from template as original zoom is 0. I didn't check the pixel sizes though"); + STIR_DO_IT(recon_zoom); + } else { + if (fabs(in_sh.recon_zoom - out_sh.recon_zoom) < .05) + warning("recon_zoom field in template (%g) and output (%g) is different.\n" + "Keeping original value for zoom (%g) (also keeping the original voxel sizes)", + out_sh.recon_zoom, in_sh.recon_zoom, in_sh.recon_zoom); + } STIR_DO_IT(frame_duration); STIR_DO_IT(frame_start_time); @@ -115,10 +111,10 @@ void copy_subheader(Image_subheader& out_sh, const Image_subheader& in_sh) STIR_DO_IT(filter_order); STIR_DO_IT(filter_scatter_fraction); STIR_DO_IT(filter_scatter_slope); - //STIR_DO_IT(x_resolution); - //STIR_DO_IT(y_resolution); - //STIR_DO_IT(z_resolution); - for (int i=0; i<40; ++i) + // STIR_DO_IT(x_resolution); + // STIR_DO_IT(y_resolution); + // STIR_DO_IT(z_resolution); + for (int i = 0; i < 40; ++i) STIR_DO_IT(annotation[i]); STIR_DO_IT(mt_1_1); STIR_DO_IT(mt_1_2); @@ -145,32 +141,31 @@ void copy_subheader(Image_subheader& out_sh, const Image_subheader& in_sh) STIR_DO_IT(recon_views); } - -void copy_subheader(Image_subheader& out_sh, const Scan3D_subheader& in_sh) -{ +void +copy_subheader(Image_subheader& out_sh, const Scan3D_subheader& in_sh) { warning("Copying only timing and gating info from scan to image subheader\n"); /* - short data_type; - short num_dimensions; - short x_dimension; - short y_dimension; - short z_dimension; - short align_0; - float z_offset; - float x_offset; - float y_offset; - float scale_factor; - short image_min; - short image_max; - float x_pixel_size; - float y_pixel_size; - float z_pixel_size; - short align_1; - float x_resolution; - float y_resolution; - float z_resolution; - short align_2; - short align_3; + short data_type; + short num_dimensions; + short x_dimension; + short y_dimension; + short z_dimension; + short align_0; + float z_offset; + float x_offset; + float y_offset; + float scale_factor; + short image_min; + short image_max; + float x_pixel_size; + float y_pixel_size; + float z_pixel_size; + short align_1; + float x_resolution; + float y_resolution; + float z_resolution; + short align_2; + short align_3; // if (out_sh.recon_zoom==0) { @@ -228,24 +223,24 @@ void copy_subheader(Image_subheader& out_sh, const Scan3D_subheader& in_sh) STIR_DO_IT(num_accepted_beats); } -void copy_subheader(Scan3D_subheader& out_sh, const Scan3D_subheader& in_sh) -{ +void +copy_subheader(Scan3D_subheader& out_sh, const Scan3D_subheader& in_sh) { /* - short data_type; - short num_dimensions; - short num_r_elements; - short num_angles; - short num_z_elements[64]; - short ring_difference; - short storage_order; - short axial_compression; - float x_resolution; - float v_resolution; - float z_resolution; - float w_resolution; + short data_type; + short num_dimensions; + short num_r_elements; + short num_angles; + short num_z_elements[64]; + short ring_difference; + short storage_order; + short axial_compression; + float x_resolution; + float v_resolution; + float z_resolution; + float w_resolution; float scale_factor; - short scan_min; - short scan_max; + short scan_min; + short scan_max; */ STIR_DO_IT(frame_start_time); @@ -262,26 +257,26 @@ void copy_subheader(Scan3D_subheader& out_sh, const Scan3D_subheader& in_sh) STIR_DO_IT(r_wave_offset); STIR_DO_IT(num_accepted_beats); STIR_DO_IT(total_coin_rate); - for (int i=0; i<128; ++i) + for (int i = 0; i < 128; ++i) STIR_DO_IT(uncor_singles[i]); } -void copy_subheader(Attn_subheader& out_sh, const Attn_subheader& in_sh) -{ +void +copy_subheader(Attn_subheader& out_sh, const Attn_subheader& in_sh) { /* - short data_type; - short num_dimensions; - short num_r_elements; - short num_angles; - short num_z_elements; - short ring_difference; - float scale_factor; - short z_elements[64]; + short data_type; + short num_dimensions; + short num_r_elements; + short num_angles; + short num_z_elements; + short ring_difference; + float scale_factor; + short z_elements[64]; */ - //STIR_DO_IT(x_resolution); - //STIR_DO_IT(y_resolution); - //STIR_DO_IT(z_resolution); - //STIR_DO_IT(w_resolution); + // STIR_DO_IT(x_resolution); + // STIR_DO_IT(y_resolution); + // STIR_DO_IT(z_resolution); + // STIR_DO_IT(w_resolution); STIR_DO_IT(x_offset); STIR_DO_IT(y_offset); STIR_DO_IT(x_radius); @@ -294,16 +289,14 @@ void copy_subheader(Attn_subheader& out_sh, const Attn_subheader& in_sh) STIR_DO_IT(skull_thickness); STIR_DO_IT(num_additional_atten_coeff); STIR_DO_IT(edge_finding_threshold); - for (int i=0; i<8; ++i) + for (int i = 0; i < 8; ++i) STIR_DO_IT(additional_atten_coeff[i]); } -void copy_subheader(MatrixData * data_out, - const MatrixData * data_in) -{ - MatrixFile *mptr = data_out->matfile; - switch (mptr->mhptr->file_type) - { +void +copy_subheader(MatrixData* data_out, const MatrixData* data_in) { + MatrixFile* mptr = data_out->matfile; + switch (mptr->mhptr->file_type) { #if 0 case CTISinogram: copy_subheader( @@ -316,334 +309,269 @@ void copy_subheader(MatrixData * data_out, *reinterpret_cast(data_in->shptr)); break; #endif + case PetImage: + case ByteVolume: + case PetVolume: { + switch (data_in->matfile->mhptr->file_type) { + case Byte3dSinogram: + case Short3dSinogram: + case Float3dSinogram: + copy_subheader(*reinterpret_cast(data_out->shptr), *reinterpret_cast(data_in->shptr)); + break; case PetImage: case ByteVolume: case PetVolume: - { - switch(data_in->matfile->mhptr->file_type) - { - case Byte3dSinogram: - case Short3dSinogram: - case Float3dSinogram : - copy_subheader( - *reinterpret_cast(data_out->shptr), - *reinterpret_cast(data_in->shptr)); - break; - case PetImage: - case ByteVolume: - case PetVolume: - copy_subheader( - *reinterpret_cast(data_out->shptr), - *reinterpret_cast(data_in->shptr)); - break; - default: - error("\ncopy_subheader: cannot copy input subheader to subheader of type image\n"); - } - break; - } - case AttenCor: - copy_subheader( - *reinterpret_cast(data_out->shptr), - *reinterpret_cast(data_in->shptr)); - break; - case Byte3dSinogram: - case Short3dSinogram: - case Float3dSinogram : - copy_subheader( - *reinterpret_cast(data_out->shptr), - *reinterpret_cast(data_in->shptr)); + copy_subheader(*reinterpret_cast(data_out->shptr), *reinterpret_cast(data_in->shptr)); break; default: - case ByteProjection: - case PetProjection: - error("copy_subheader: file_type not supported yet\n"); + error("\ncopy_subheader: cannot copy input subheader to subheader of type image\n"); } + break; + } + case AttenCor: + copy_subheader(*reinterpret_cast(data_out->shptr), *reinterpret_cast(data_in->shptr)); + break; + case Byte3dSinogram: + case Short3dSinogram: + case Float3dSinogram: + copy_subheader(*reinterpret_cast(data_out->shptr), *reinterpret_cast(data_in->shptr)); + break; + default: + case ByteProjection: + case PetProjection: + error("copy_subheader: file_type not supported yet\n"); + } } -void update_main_header(Main_header& mh_out, const Main_header& mh_in) - { - Main_header mh = mh_in; - mh.num_planes = mh_out.num_planes; - mh.num_frames = mh_out.num_frames; - mh.num_gates = mh_out.num_gates; - mh.num_bed_pos = mh_out.num_bed_pos; - mh.file_type = mh_out.file_type; - - mh_out = mh; - } +void +update_main_header(Main_header& mh_out, const Main_header& mh_in) { + Main_header mh = mh_in; + mh.num_planes = mh_out.num_planes; + mh.num_frames = mh_out.num_frames; + mh.num_gates = mh_out.num_gates; + mh.num_bed_pos = mh_out.num_bed_pos; + mh.file_type = mh_out.file_type; + + mh_out = mh; +} Succeeded -copy_main_header(MatrixFile * mout_ptr, MatrixFile *min_ptr) - { - update_main_header(*mout_ptr->mhptr, *min_ptr->mhptr); - - if (mat_write_main_header(mout_ptr->fptr, mout_ptr->mhptr)) - return Succeeded::no; - else - return Succeeded::yes; - } +copy_main_header(MatrixFile* mout_ptr, MatrixFile* min_ptr) { + update_main_header(*mout_ptr->mhptr, *min_ptr->mhptr); + + if (mat_write_main_header(mout_ptr->fptr, mout_ptr->mhptr)) + return Succeeded::no; + else + return Succeeded::yes; +} -class ECAT_dataset_spec -{ +class ECAT_dataset_spec { public: -ECAT_dataset_spec(); -ECAT_dataset_spec(const char *const spec); -ECAT_dataset_spec(const string&); -int matnum() const; -int frame_num; -int plane_num; -int gate_num; -int data_num; -int bed_pos_num; -private: + ECAT_dataset_spec(); + ECAT_dataset_spec(const char* const spec); + ECAT_dataset_spec(const string&); + int matnum() const; + int frame_num; + int plane_num; + int gate_num; + int data_num; + int bed_pos_num; -void decode_spec(const char * const spec); -void set_defaults(); +private: + void decode_spec(const char* const spec); + void set_defaults(); }; void -ECAT_dataset_spec:: -set_defaults() -{ - frame_num=1; - gate_num=1; - data_num=0; - bed_pos_num=0; - plane_num=0; +ECAT_dataset_spec::set_defaults() { + frame_num = 1; + gate_num = 1; + data_num = 0; + bed_pos_num = 0; + plane_num = 0; } void -ECAT_dataset_spec:: -decode_spec(const char * const spec) -{ +ECAT_dataset_spec::decode_spec(const char* const spec) { set_defaults(); - sscanf(spec, "%d,%d,%d,%d", - &frame_num, &gate_num, &data_num, &bed_pos_num); + sscanf(spec, "%d,%d,%d,%d", &frame_num, &gate_num, &data_num, &bed_pos_num); } -ECAT_dataset_spec:: -ECAT_dataset_spec() -{ - set_defaults(); -} +ECAT_dataset_spec::ECAT_dataset_spec() { set_defaults(); } -ECAT_dataset_spec:: -ECAT_dataset_spec(const char * const spec) -{ - decode_spec(spec); -} +ECAT_dataset_spec::ECAT_dataset_spec(const char* const spec) { decode_spec(spec); } -ECAT_dataset_spec:: -ECAT_dataset_spec(const string& spec) -{ - decode_spec(spec.c_str()); -} +ECAT_dataset_spec::ECAT_dataset_spec(const string& spec) { decode_spec(spec.c_str()); } -int -ECAT_dataset_spec:: -matnum() const -{ - return mat_numcod (frame_num, 1, gate_num, data_num, bed_pos_num); +int +ECAT_dataset_spec::matnum() const { + return mat_numcod(frame_num, 1, gate_num, data_num, bed_pos_num); } -ostream& operator<<(ostream& s, const ECAT_dataset_spec& spec) -{ - s << spec.frame_num << ',' - << spec.gate_num << ',' - << spec.data_num << ',' - << spec.bed_pos_num; +ostream& +operator<<(ostream& s, const ECAT_dataset_spec& spec) { + s << spec.frame_num << ',' << spec.gate_num << ',' << spec.data_num << ',' << spec.bed_pos_num; return s; } - + Succeeded -mat_write_any_subheader( - MatrixData * data) -{ +mat_write_any_subheader(MatrixData* data) { struct MatDir matdir; - + matrix_errno = MAT_OK; matrix_errtxt[0] = '\0'; - if (data==NULL) - { - matrix_errno = MAT_READ_FROM_NILFPTR; - return Succeeded::no; - } + if (data == NULL) { + matrix_errno = MAT_READ_FROM_NILFPTR; + return Succeeded::no; + } - MatrixFile *mptr = data->matfile; - if (mptr == NULL) - { - matrix_errno = MAT_READ_FROM_NILFPTR ; - return Succeeded::no; - } - else if (mptr->mhptr == NULL) matrix_errno = MAT_NOMHD_FILE_OBJECT ; - else if (data->shptr == NULL) matrix_errno = MAT_NIL_SHPTR ; - if (matrix_errno != MAT_OK) return Succeeded::no ; - - if (matrix_find (mptr, data->matnum, &matdir) != 0) + MatrixFile* mptr = data->matfile; + if (mptr == NULL) { + matrix_errno = MAT_READ_FROM_NILFPTR; + return Succeeded::no; + } else if (mptr->mhptr == NULL) + matrix_errno = MAT_NOMHD_FILE_OBJECT; + else if (data->shptr == NULL) + matrix_errno = MAT_NIL_SHPTR; + if (matrix_errno != MAT_OK) return Succeeded::no; - - const int strtblk = matdir.strtblk; - int return_value=0; - switch (mptr->mhptr->file_type) - { - case CTISinogram: - return_value = mat_write_scan_subheader (mptr->fptr, mptr->mhptr, strtblk, - reinterpret_cast(data->shptr)); - break; - case PetImage: - case ByteVolume: - case PetVolume: - return_value = mat_write_image_subheader (mptr->fptr, mptr->mhptr, strtblk, - reinterpret_cast(data->shptr)); - break; - case AttenCor: - return_value = mat_write_attn_subheader (mptr->fptr, mptr->mhptr, strtblk, - reinterpret_cast(data->shptr)); - break; - case Normalization: - return_value = mat_write_norm_subheader (mptr->fptr, mptr->mhptr, strtblk, - reinterpret_cast(data->shptr)); - break; - case Byte3dSinogram: - case Short3dSinogram: - case Float3dSinogram : - return_value = mat_write_Scan3D_subheader (mptr->fptr, mptr->mhptr, strtblk, - reinterpret_cast(data->shptr)); - - break; - default: - case ByteProjection: - case PetProjection: - case PolarMap: - case Norm3d: - fprintf (stderr, "Not implemented yet\n"); - matrix_errno = MAT_WRITE_ERROR; - } - if (return_value) - { - matrix_perror("error in writing subheader"); - return Succeeded::no; - } - else - return Succeeded::yes; + if (matrix_find(mptr, data->matnum, &matdir) != 0) + return Succeeded::no; + const int strtblk = matdir.strtblk; + + int return_value = 0; + switch (mptr->mhptr->file_type) { + case CTISinogram: + return_value = mat_write_scan_subheader(mptr->fptr, mptr->mhptr, strtblk, reinterpret_cast(data->shptr)); + break; + case PetImage: + case ByteVolume: + case PetVolume: + return_value = mat_write_image_subheader(mptr->fptr, mptr->mhptr, strtblk, reinterpret_cast(data->shptr)); + break; + case AttenCor: + return_value = mat_write_attn_subheader(mptr->fptr, mptr->mhptr, strtblk, reinterpret_cast(data->shptr)); + break; + case Normalization: + return_value = mat_write_norm_subheader(mptr->fptr, mptr->mhptr, strtblk, reinterpret_cast(data->shptr)); + break; + case Byte3dSinogram: + case Short3dSinogram: + case Float3dSinogram: + return_value = mat_write_Scan3D_subheader(mptr->fptr, mptr->mhptr, strtblk, reinterpret_cast(data->shptr)); + + break; + default: + case ByteProjection: + case PetProjection: + case PolarMap: + case Norm3d: + fprintf(stderr, "Not implemented yet\n"); + matrix_errno = MAT_WRITE_ERROR; + } + if (return_value) { + matrix_perror("error in writing subheader"); + return Succeeded::no; + } else + return Succeeded::yes; } +int +main(int argc, char* argv[]) { + bool update = true; // switch between update and straight copy + if (argc > 1 && strcmp(argv[1], "--copy") == 0) { + update = false; + --argc; + ++argv; + } - -int main(int argc, char *argv[]) -{ - - bool update=true; // switch between update and straight copy - if (argc>1 && strcmp(argv[1], "--copy")==0) - { - update=false; - --argc; ++ argv; - } - - if(argc!=3 && argc!=5) - { - cerr<< "\nCopy contents of ECAT7 headers.\n" - << "Usage: \n" - << "To copy the main header:\n" - << "\t" << argv[0] << " [--copy] output_ECAT7_name input_ECAT7_name\n" - << " without --copy, num_planes etc are preserved.\n" - << "or to copy a subheader (but keeping essential info)\n" - << "\t" << argv[0] << " output_ECAT7_name f,g,d,b input_ECAT7_name f,g,d,b\n\n"; - return EXIT_FAILURE; + if (argc != 3 && argc != 5) { + cerr << "\nCopy contents of ECAT7 headers.\n" + << "Usage: \n" + << "To copy the main header:\n" + << "\t" << argv[0] << " [--copy] output_ECAT7_name input_ECAT7_name\n" + << " without --copy, num_planes etc are preserved.\n" + << "or to copy a subheader (but keeping essential info)\n" + << "\t" << argv[0] << " output_ECAT7_name f,g,d,b input_ECAT7_name f,g,d,b\n\n"; + return EXIT_FAILURE; } const string output_name = argv[1]; - const string input_name = argc==3? argv[2] :argv[3]; - - const bool write_main_header = argc==3; + const string input_name = argc == 3 ? argv[2] : argv[3]; + + const bool write_main_header = argc == 3; #ifndef USE_MATRIX_LIB_FOR_MAINHEADER - if (write_main_header) - { - FILE * in_fptr = fopen(input_name.c_str(), "rb"); - if (!in_fptr) - { - error("Error opening '%s' for reading: %s", - input_name.c_str(), strerror(errno)); - } - FILE * out_fptr = fopen(output_name.c_str(), "rb+"); - if (!out_fptr) - { - error("Error opening '%s' for reading and writing: %s", - output_name.c_str(), strerror(errno)); - } - Main_header mh_in; - if (mat_read_main_header(in_fptr, &mh_in)!=0) - error("Error reading main header from %s", input_name.c_str()); - if (update) - { - Main_header mh_out; - if (mat_read_main_header(out_fptr, &mh_out)!=0) - error("Error reading main header from %s", output_name.c_str()); - update_main_header(mh_out, mh_in); - if (mat_write_main_header(out_fptr, &mh_out)) - error("Error writing main header to %s", output_name.c_str()); - } - else - { - if (mat_write_main_header(out_fptr, &mh_in)) - error("Error writing main header to %s", output_name.c_str()); - } - fclose(in_fptr); - fclose(out_fptr); - return EXIT_SUCCESS; + if (write_main_header) { + FILE* in_fptr = fopen(input_name.c_str(), "rb"); + if (!in_fptr) { + error("Error opening '%s' for reading: %s", input_name.c_str(), strerror(errno)); + } + FILE* out_fptr = fopen(output_name.c_str(), "rb+"); + if (!out_fptr) { + error("Error opening '%s' for reading and writing: %s", output_name.c_str(), strerror(errno)); } + Main_header mh_in; + if (mat_read_main_header(in_fptr, &mh_in) != 0) + error("Error reading main header from %s", input_name.c_str()); + if (update) { + Main_header mh_out; + if (mat_read_main_header(out_fptr, &mh_out) != 0) + error("Error reading main header from %s", output_name.c_str()); + update_main_header(mh_out, mh_in); + if (mat_write_main_header(out_fptr, &mh_out)) + error("Error writing main header to %s", output_name.c_str()); + } else { + if (mat_write_main_header(out_fptr, &mh_in)) + error("Error writing main header to %s", output_name.c_str()); + } + fclose(in_fptr); + fclose(out_fptr); + return EXIT_SUCCESS; + } #endif - MatrixFile *min_ptr= - matrix_open( input_name.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); + MatrixFile* min_ptr = matrix_open(input_name.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); if (!min_ptr) { matrix_perror(input_name.c_str()); exit(EXIT_FAILURE); } - MatrixFile *mout_ptr= - matrix_open( output_name.c_str(), MAT_OPEN_EXISTING, MAT_UNKNOWN_FTYPE); + MatrixFile* mout_ptr = matrix_open(output_name.c_str(), MAT_OPEN_EXISTING, MAT_UNKNOWN_FTYPE); if (!mout_ptr) { matrix_perror(output_name.c_str()); exit(EXIT_FAILURE); } #ifdef USE_MATRIX_LIB_FOR_MAINHEADER - if (write_main_header) - { - if (copy_main_header(mout_ptr, min_ptr) == Succeeded::no) - return EXIT_FAILURE; - else - return EXIT_SUCCESS; - } + if (write_main_header) { + if (copy_main_header(mout_ptr, min_ptr) == Succeeded::no) + return EXIT_FAILURE; + else + return EXIT_SUCCESS; + } #endif assert(!write_main_header); const ECAT_dataset_spec out_spec(argv[2]); const ECAT_dataset_spec in_spec(argv[4]); - cerr << "Attempting to read in '" << in_spec <<"' and out '" - << out_spec << "'" << endl; - MatrixData * mindata_ptr = - matrix_read(min_ptr, in_spec.matnum(), MAT_SUB_HEADER); - if (mindata_ptr == NULL) - { + cerr << "Attempting to read in '" << in_spec << "' and out '" << out_spec << "'" << endl; + MatrixData* mindata_ptr = matrix_read(min_ptr, in_spec.matnum(), MAT_SUB_HEADER); + if (mindata_ptr == NULL) { matrix_perror("Error reading input subheader"); return EXIT_FAILURE; } - MatrixData * moutdata_ptr = - matrix_read(mout_ptr, out_spec.matnum(), MAT_SUB_HEADER); - if (moutdata_ptr == NULL) - { + MatrixData* moutdata_ptr = matrix_read(mout_ptr, out_spec.matnum(), MAT_SUB_HEADER); + if (moutdata_ptr == NULL) { matrix_perror("Error reading output subheader"); return EXIT_FAILURE; } copy_subheader(moutdata_ptr, mindata_ptr); if (mat_write_any_subheader(moutdata_ptr) == Succeeded::no) - return EXIT_FAILURE; + return EXIT_FAILURE; free_matrix_data(moutdata_ptr); free_matrix_data(mindata_ptr); diff --git a/src/utilities/ecat/ecat_swap_corners.cxx b/src/utilities/ecat/ecat_swap_corners.cxx index 6ad3d1b5a2..14ad701410 100644 --- a/src/utilities/ecat/ecat_swap_corners.cxx +++ b/src/utilities/ecat/ecat_swap_corners.cxx @@ -16,7 +16,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! @@ -32,12 +32,12 @@ \par Usage \code - ecat_swap_corners out_name in_name + ecat_swap_corners out_name in_name \endcode \par What does it do? - For some historical reason, CTI scanners store 3D sinograms + For some historical reason, CTI scanners store 3D sinograms sometimes in a 'corner-swapped' mode. What happens is that some corners of the positive and negative segments are interchanged. (As a consequence, segment 0 is never affected).

      @@ -53,15 +53,15 @@ that allows you to find out which mode it is in. For ECAT7 data, the situation is even more confusing. Data acquired - directly in projection data have to be corner-swapped when the + directly in projection data have to be corner-swapped when the acquisition was in 'volume-mode' (i.e. stored by sinograms), but NOT when acquired in 'view-mode' (i.e. stored by view). It seems that bkproj_3D_sun follows this convention by assuming that any ECAT7 projection data stored in 'volume-mode' has to be corner swapped, and when it writes projection data in 'view-mode', it does the corner swapping - for you. - So, although there is strictly speaking no field in the ECAT7 header - concerning corner swapping, it seems that the storage mode field + for you. + So, although there is strictly speaking no field in the ECAT7 header + concerning corner swapping, it seems that the storage mode field determines the corner swapping as well.
      When the data is acquired in listmode, this changes somewhat. @@ -71,26 +71,26 @@ corner-swapping or without. After the acquisition, the listmode data has then to be binned into projection data. It is then up to the binning program to take this corner-swapping into account. This is - easiest to do by generating 'volume-mode' projection data when a - 'volume-mode' when the listmode setup was in 'volume-mode', and + easiest to do by generating 'volume-mode' projection data when a + 'volume-mode' when the listmode setup was in 'volume-mode', and similar for 'view-mode'.
      - If this sounds confusing to you, KT would agree. + If this sounds confusing to you, KT would agree. Here seems to be the best thing to do:

      Do all acquisitions in 'view-mode', set-up your listmode scan - in 'view-mode', bin the data in 'view-mode'. Forget about + in 'view-mode', bin the data in 'view-mode'. Forget about corner-swapping.

      - If you cannot do this, then this utility will corner-swap the - projection data for you. + If you cannot do this, then this utility will corner-swap the + projection data for you. \par Who implemented this and how was it tested? The actual corner swapping code was supplied by Christian Michel, based on code by Larry Byars.
      - KT has tested it by performing a very long cylinder scan in + KT has tested it by performing a very long cylinder scan in 'volume-mode' on the ECAT 966, and looking at the delayeds. The oblique segments had obvious discontinuities in the efficiency patterns. After applyying this utility, these discontinuities appeared. - + \warning This utility does not (and cannot) check for you if the data has to be corner-swapped or not. So, it can do the wrong thing. @@ -111,143 +111,128 @@ using std::swap; USING_NAMESPACE_STIR -static void dets_to_ve( int da, int db, int *v, int *e, int ndets) -{ - int h,x,y,a,b,te; - - h=ndets/2; - x=max(da,db); - y=min(da,db); - a=((x+y+h+1)%ndets)/2; - b=a+h; - te=abs(x-y-h); - if ((ynviews*nmash/2) continue; - nodup = 1; - for (j=0; j0) && (e nviews * nmash / 2) + continue; + nodup = 1; + for (j = 0; j < n; j++) + if (off == list[j]) + nodup = 0; + if (nodup && (e + 1 > 0) && (e < nprojs)) + list[n++] = off; + } + } + *nptr = n; + return (list); } -int main(int argc, char **argv) -{ - - if (argc!=3) - { +int +main(int argc, char** argv) { + + if (argc != 3) { cerr << "Usage: " << argv[0] << " out_name in_name \n"; return EXIT_FAILURE; } - - shared_ptr org_proj_data_ptr = - ProjData::read_from_file(argv[2]); - ProjDataInterfile - new_proj_data(org_proj_data_ptr->get_exam_info_sptr(), - org_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), - argv[1]); - - + + shared_ptr org_proj_data_ptr = ProjData::read_from_file(argv[2]); + ProjDataInterfile new_proj_data(org_proj_data_ptr->get_exam_info_sptr(), + org_proj_data_ptr->get_proj_data_info_sptr()->create_shared_clone(), argv[1]); + const int num_tang_poss = org_proj_data_ptr->get_num_tangential_poss(); const int min_tang_pos_num = org_proj_data_ptr->get_min_tangential_pos_num(); const int min_view_num = org_proj_data_ptr->get_min_view_num(); - const int mash = - org_proj_data_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring() / - org_proj_data_ptr->get_num_views() / 2; + const int mash = org_proj_data_ptr->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring() / + org_proj_data_ptr->get_num_views() / 2; cerr << "Mash factor determined from data is " << mash << endl; - int num_swapped = 0; - int *swap_lors = - compute_swap_lors_mashed(org_proj_data_ptr->get_num_tangential_poss(), - org_proj_data_ptr->get_num_views(), - mash, - &num_swapped); + int* swap_lors = compute_swap_lors_mashed(org_proj_data_ptr->get_num_tangential_poss(), org_proj_data_ptr->get_num_views(), + mash, &num_swapped); // first do segment 0 (no swapping) new_proj_data.set_segment(org_proj_data_ptr->get_segment_by_sinogram(0)); // now the rest - for (int segment_num=1; segment_num<=org_proj_data_ptr->get_max_segment_num(); ++segment_num) - { - for (int axial_pos_num=org_proj_data_ptr->get_min_axial_pos_num(segment_num); - axial_pos_num<=org_proj_data_ptr->get_max_axial_pos_num(segment_num); - ++axial_pos_num) - { - Sinogram sino1= - org_proj_data_ptr->get_sinogram(axial_pos_num, segment_num, false); - Sinogram sino2= - org_proj_data_ptr->get_sinogram(axial_pos_num, -segment_num, false); - - for (int i=0; iget_max_segment_num(); ++segment_num) { + for (int axial_pos_num = org_proj_data_ptr->get_min_axial_pos_num(segment_num); + axial_pos_num <= org_proj_data_ptr->get_max_axial_pos_num(segment_num); ++axial_pos_num) { + Sinogram sino1 = org_proj_data_ptr->get_sinogram(axial_pos_num, segment_num, false); + Sinogram sino2 = org_proj_data_ptr->get_sinogram(axial_pos_num, -segment_num, false); + + for (int i = 0; i < num_swapped; i++) { + int offset = swap_lors[i]; + const int tang_pos_num = offset % num_tang_poss + min_tang_pos_num; + const int view_num = offset / num_tang_poss + min_view_num; swap(sino1[view_num][tang_pos_num], sino2[view_num][tang_pos_num]); } - + new_proj_data.set_sinogram(sino1); new_proj_data.set_sinogram(sino2); } } - free (swap_lors); + free(swap_lors); return EXIT_SUCCESS; } diff --git a/src/utilities/ecat/ifheaders_for_ecat7.cxx b/src/utilities/ecat/ifheaders_for_ecat7.cxx index bcebee668f..f4c83be138 100644 --- a/src/utilities/ecat/ifheaders_for_ecat7.cxx +++ b/src/utilities/ecat/ifheaders_for_ecat7.cxx @@ -1,7 +1,7 @@ // // -/*! +/*! \file \ingroup ECAT_utilities \brief Utility to make Interfile headers for ECAT7 data @@ -11,8 +11,8 @@ Usage: $File$ ecat7_filename. - This will attempt to write interfile headers 'pointing into' the ECAT7 file. - + This will attempt to write interfile headers 'pointing into' the ECAT7 file. + A question will be asked if all data sets should be processed, or only a single one. @@ -22,7 +22,7 @@ \see write_basic_interfile_header_for_ecat7() \warning This only works with some CTI file_types. In particular, it does NOT -work with the ECAT6-like files_types, as then there are subheaders 'in' the +work with the ECAT6-like files_types, as then there are subheaders 'in' the datasets. \warning Implementation uses the Louvain la Neuve Ecat library. So, it will @@ -46,8 +46,6 @@ only work on systems where this library works properly. See STIR/LICENSE.txt for details */ - - #include "stir/ProjDataInfo.h" #include "stir/ProjDataFromStream.h" #include "stir/IO/interfile.h" @@ -72,60 +70,50 @@ using std::cerr; using std::endl; #endif - USING_NAMESPACE_STIR USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 -int -main( int argc, char **argv) -{ - MatrixFile *mptr; - - if (argc<2) - { - cerr << "usage : "<< argv[0] << " filename\n"; +int +main(int argc, char** argv) { + MatrixFile* mptr; + + if (argc < 2) { + cerr << "usage : " << argv[0] << " filename\n"; exit(EXIT_FAILURE); } - mptr = matrix_open( argv[1], MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); + mptr = matrix_open(argv[1], MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); if (!mptr) { matrix_perror(argv[1]); exit(EXIT_FAILURE); } - - const int num_frames = std::max(static_cast( mptr->mhptr->num_frames),1); + + const int num_frames = std::max(static_cast(mptr->mhptr->num_frames), 1); // funnily enough, num_bed_pos seems to be offset with 1 - // (That's to say, in a singled bed study, num_bed_pos==0) + // (That's to say, in a singled bed study, num_bed_pos==0) // TODO maybe not true for multi-bed studies - const int num_bed_poss = static_cast( mptr->mhptr->num_bed_pos) + 1; - const int num_gates = std::max(static_cast( mptr->mhptr->num_gates),1); + const int num_bed_poss = static_cast(mptr->mhptr->num_bed_pos) + 1; + const int num_gates = std::max(static_cast(mptr->mhptr->num_gates), 1); fclose(mptr->fptr); delete mptr; string interfile_header_filename; - if (ask("Attempt all data-sets (Y) or single data-set (N)", true)) - { - const int data_num=ask_num("Data number ? ",0,8, 0); - - for (int frame_num=1; frame_num<=num_frames;++frame_num) - for (int bed_num=0; bed_num1 && argv[1][0] == '-') - { - if (strcmp(argv[1], "--image") == 0) - { - option = opt_image; --argc; ++argv; break; - } - if (strcmp(argv[1], "--emission") == 0) - { - option = opt_emission; --argc; ++argv; break; - } - if (strcmp(argv[1], "--ACF") == 0) - { - option = opt_ACF; --argc; ++argv; break; - } - else - print_usage_and_exit(prog_name); + while (argc > 1 && argv[1][0] == '-') { + if (strcmp(argv[1], "--image") == 0) { + option = opt_image; + --argc; + ++argv; + break; + } + if (strcmp(argv[1], "--emission") == 0) { + option = opt_emission; + --argc; + ++argv; + break; } - if (argc!=2) + if (strcmp(argv[1], "--ACF") == 0) { + option = opt_ACF; + --argc; + ++argv; + break; + } else + print_usage_and_exit(prog_name); + } + if (argc != 2) print_usage_and_exit(prog_name); - const char * filename = argv[1]; + const char* filename = argv[1]; bool value; - switch (option) - { - case opt_none: value = stir::ecat::ecat7::is_ECAT7_file(filename); break; - case opt_image: value = stir::ecat::ecat7::is_ECAT7_image_file(filename); break; - case opt_emission: value = stir::ecat::ecat7::is_ECAT7_emission_file(filename); break; - case opt_ACF: value = stir::ecat::ecat7::is_ECAT7_attenuation_file(filename); break; - default: value=false; - } + switch (option) { + case opt_none: + value = stir::ecat::ecat7::is_ECAT7_file(filename); + break; + case opt_image: + value = stir::ecat::ecat7::is_ECAT7_image_file(filename); + break; + case opt_emission: + value = stir::ecat::ecat7::is_ECAT7_emission_file(filename); + break; + case opt_ACF: + value = stir::ecat::ecat7::is_ECAT7_attenuation_file(filename); + break; + default: + value = false; + } if (value) std::cout << "yes\n"; diff --git a/src/utilities/ecat/print_ecat_singles_values.cxx b/src/utilities/ecat/print_ecat_singles_values.cxx index e0594fec04..d652df806d 100644 --- a/src/utilities/ecat/print_ecat_singles_values.cxx +++ b/src/utilities/ecat/print_ecat_singles_values.cxx @@ -23,16 +23,13 @@ \author Tim Borgeaud */ - #include "stir/data/SinglesRatesFromECAT7.h" - #include #include #include #include - #ifndef STIR_NO_NAMESPACES using std::cout; using std::cerr; @@ -44,16 +41,12 @@ using std::vector; USING_NAMESPACE_STIR - - - -int -main (int argc, char **argv) -{ +int +main(int argc, char** argv) { vector columns; - // Check arguments. + // Check arguments. // Singles filename + optional bin indices. if (argc < 2) { cerr << "Program to print out values from a singles file.\n\n"; @@ -64,66 +57,56 @@ main (int argc, char **argv) const string ecat7_filename = argv[1]; - for (int arg = 2 ; arg < argc ; ++arg) { + for (int arg = 2; arg < argc; ++arg) { columns.push_back(atoi(argv[arg])); - } - - + } + // Singles file object. ecat::ecat7::SinglesRatesFromECAT7 singles_from_ecat7; - // Read the singles file. singles_from_ecat7.read_singles_from_file(ecat7_filename); - // Get total number of frames int num_frames = singles_from_ecat7.get_num_frames(); - + // Get scanner details and, from these, the number of singles units. - const Scanner *scanner = singles_from_ecat7.get_scanner_ptr(); + const Scanner* scanner = singles_from_ecat7.get_scanner_ptr(); int total_singles_units = scanner->get_num_singles_units(); - - + // If no columns are set. Create a vector with all columns. - if ( columns.size() == 0 ) { - for (int singles_bin = 0 ; singles_bin < total_singles_units ; ++singles_bin) { - columns.push_back(singles_bin); + if (columns.size() == 0) { + for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { + columns.push_back(singles_bin); } } - // Print columns cout << "# Frame Frame time "; - for (vector::iterator col = columns.begin() ; col < columns.end() ; ++col) { + for (vector::iterator col = columns.begin(); col < columns.end(); ++col) { cout << setw(9) << *col << " "; } cout << "\n"; - // Loop over all frames. - for (int frame = 1 ; frame <= num_frames ; ++frame) { - + for (int frame = 1; frame <= num_frames; ++frame) { + // Ouput frame number, start and end times. - cout << setw(2) << frame << " " - << setw(8) << singles_from_ecat7.get_time_frame_definitions().get_start_time(frame) << " to " - << setw(8) << singles_from_ecat7.get_time_frame_definitions().get_end_time(frame) << " "; + cout << setw(2) << frame << " " << setw(8) << singles_from_ecat7.get_time_frame_definitions().get_start_time(frame) + << " to " << setw(8) << singles_from_ecat7.get_time_frame_definitions().get_end_time(frame) << " "; - for (vector::iterator col = columns.begin() ; col < columns.end() ; ++col) { - - if ( *col >= 0 && *col < total_singles_units ) { + for (vector::iterator col = columns.begin(); col < columns.end(); ++col) { + + if (*col >= 0 && *col < total_singles_units) { float val = singles_from_ecat7.get_singles_rate(*col, frame); - + cout << setw(9) << val << " "; } } - + // Output the end of line. cout << endl; - } - - return EXIT_SUCCESS; } diff --git a/src/utilities/estimate_triple_energy_window_scatter_sinogram.cxx b/src/utilities/estimate_triple_energy_window_scatter_sinogram.cxx index 41efeb5584..2b5bc38266 100644 --- a/src/utilities/estimate_triple_energy_window_scatter_sinogram.cxx +++ b/src/utilities/estimate_triple_energy_window_scatter_sinogram.cxx @@ -24,7 +24,6 @@ \author Daniel Deidda */ - #include "stir/SegmentByView.h" #include "stir/IO/OutputFileFormat.h" #include "stir/IO/read_from_file.h" @@ -41,9 +40,8 @@ #include "stir/IndexRange3D.h" #include "stir/ArrayFilter3DUsingConvolution.h" - -#include -#include +#include +#include #include #include #include @@ -60,165 +58,139 @@ using std::string; using std::vector; #endif - USING_NAMESPACE_STIR -class estimate_TEW_scatter : public KeyParser, ArrayFilter3DUsingConvolution -{ +class estimate_TEW_scatter : public KeyParser, ArrayFilter3DUsingConvolution { public: - estimate_TEW_scatter(); std::string scatter_filename; - std::string lower_filename,upper_filename; + std::string lower_filename, upper_filename; double lower_width, peak_width, upper_width; bool do_smooth; Succeeded compute(); -private: - -// virtual void set_defaults(); +private: + // virtual void set_defaults(); virtual void initialise_keymap(); -// virtual bool post_processing(); + // virtual bool post_processing(); }; void - estimate_TEW_scatter:: -initialise_keymap() -{ +estimate_TEW_scatter::initialise_keymap() { add_start_key(" Estimate_TEW_scatter Parameters"); - add_key("output scatter filename",&scatter_filename); - add_key("lower filename",&lower_filename); - add_key("upper filename",&upper_filename); - add_key("lower width",&lower_width); - add_key("peak width",&peak_width); - add_key("upper width",&upper_width); - add_key("do smooth",&do_smooth); + add_key("output scatter filename", &scatter_filename); + add_key("lower filename", &lower_filename); + add_key("upper filename", &upper_filename); + add_key("lower width", &lower_width); + add_key("peak width", &peak_width); + add_key("upper width", &upper_width); + add_key("do smooth", &do_smooth); add_stop_key("END"); - -} - -estimate_TEW_scatter::estimate_TEW_scatter() -{ - initialise_keymap(); } -int -main(int argc, char **argv) -{ - if(argc<2) - { - cerr<< "Usage: " << argv[0] << "\n\t" - << "[par_file]\n\t" - << " Should contain the following:\n" - << "Estimate_TEW_scatter Parameters:= \n" - << "output scatter filename :=\n" - << "lower filename :=\n" - << "upper filename :=\n" - << "lower width :=\n" - << "peak width :=\n" - << "upper width :=\n" - << "do smooth :=\n" - << "END :=\n"; - exit(EXIT_FAILURE); - } +estimate_TEW_scatter::estimate_TEW_scatter() { initialise_keymap(); } + +int +main(int argc, char** argv) { + if (argc < 2) { + cerr << "Usage: " << argv[0] << "\n\t" + << "[par_file]\n\t" + << " Should contain the following:\n" + << "Estimate_TEW_scatter Parameters:= \n" + << "output scatter filename :=\n" + << "lower filename :=\n" + << "upper filename :=\n" + << "lower width :=\n" + << "peak width :=\n" + << "upper width :=\n" + << "do smooth :=\n" + << "END :=\n"; + exit(EXIT_FAILURE); + } // first process command line options - estimate_TEW_scatter estimate; - - if (argc==0) - { cerr << "No par file on command line\n"; exit(EXIT_FAILURE); } - else{ - if (argv[1]!=0) - { - if (estimate.parse(argv[1]) == false) - exit(EXIT_FAILURE); - } - else - estimate.ask_parameters();} + estimate_TEW_scatter estimate; + + if (argc == 0) { + cerr << "No par file on command line\n"; + exit(EXIT_FAILURE); + } else { + if (argv[1] != 0) { + if (estimate.parse(argv[1]) == false) + exit(EXIT_FAILURE); + } else + estimate.ask_parameters(); + } // find output filename const string output_file_name = estimate.scatter_filename; -// start the main processing -// read windows data - shared_ptr lower_sptr; - shared_ptr upper_sptr; - shared_ptr out_scatter_proj_data_ptr; - - lower_sptr = ProjData::read_from_file(estimate.lower_filename); - upper_sptr = ProjData::read_from_file(estimate.upper_filename); - - - shared_ptr - output_proj_data_info_sptr((*lower_sptr).get_proj_data_info_sptr()->clone()); - - out_scatter_proj_data_ptr.reset(new ProjDataInterfile((*lower_sptr).get_exam_info_sptr(), - output_proj_data_info_sptr, - output_file_name)); - -// if (num_files>1) -// { -// // reset time-frames as we don't really know what's happening with all this -// ExamInfo new_exam_info(out_scatter_proj_data_ptr->get_exam_info()); -// new_exam_info.set_time_frame_definitions(TimeFrameDefinitions()); -// out_scatter_proj_data_ptr->set_exam_info(new_exam_info); -// } - - - // do reading/writing in a loop over segments - for (int segment_num = out_scatter_proj_data_ptr->get_min_segment_num(); - segment_num <= out_scatter_proj_data_ptr->get_max_segment_num(); - ++segment_num) - { - - SegmentByView lower_segment_by_view = - (*lower_sptr).get_segment_by_view(segment_num); - SegmentByView upper_segment_by_view = - (*upper_sptr).get_segment_by_view(segment_num); - SegmentByView scatter_segment_by_view= - (*lower_sptr).get_segment_by_view(segment_num); - SegmentByView filter_lower_segment_by_view = - (*lower_sptr).get_segment_by_view(segment_num); - SegmentByView filter_upper_segment_by_view = - (*upper_sptr).get_segment_by_view(segment_num); - - if(estimate.do_smooth){ - IndexRange3D kernel_size(0,0,-2,2,-2,2); - Array<3,float> kernel(kernel_size); - kernel.fill(1/25.F); - ArrayFilter3DUsingConvolution filter3d(kernel); - filter3d(filter_lower_segment_by_view,lower_segment_by_view); - filter3d(filter_upper_segment_by_view,upper_segment_by_view); - } - - - // construct function object that does the manipulations on each data - float power=1 ; - float add_scalar=0; - float min_threshold = NumericInfo().min_value(); - float max_threshold = NumericInfo().max_value(); - -// The following apply the the TEW method C_{scatter}=(C_{lower}/W_{lower}+C_{upper}/W_{upper})*W_{peak}/2 + // start the main processing + // read windows data + shared_ptr lower_sptr; + shared_ptr upper_sptr; + shared_ptr out_scatter_proj_data_ptr; + + lower_sptr = ProjData::read_from_file(estimate.lower_filename); + upper_sptr = ProjData::read_from_file(estimate.upper_filename); + + shared_ptr output_proj_data_info_sptr((*lower_sptr).get_proj_data_info_sptr()->clone()); + + out_scatter_proj_data_ptr.reset( + new ProjDataInterfile((*lower_sptr).get_exam_info_sptr(), output_proj_data_info_sptr, output_file_name)); + + // if (num_files>1) + // { + // // reset time-frames as we don't really know what's happening with all this + // ExamInfo new_exam_info(out_scatter_proj_data_ptr->get_exam_info()); + // new_exam_info.set_time_frame_definitions(TimeFrameDefinitions()); + // out_scatter_proj_data_ptr->set_exam_info(new_exam_info); + // } + + // do reading/writing in a loop over segments + for (int segment_num = out_scatter_proj_data_ptr->get_min_segment_num(); + segment_num <= out_scatter_proj_data_ptr->get_max_segment_num(); ++segment_num) { + + SegmentByView lower_segment_by_view = (*lower_sptr).get_segment_by_view(segment_num); + SegmentByView upper_segment_by_view = (*upper_sptr).get_segment_by_view(segment_num); + SegmentByView scatter_segment_by_view = (*lower_sptr).get_segment_by_view(segment_num); + SegmentByView filter_lower_segment_by_view = (*lower_sptr).get_segment_by_view(segment_num); + SegmentByView filter_upper_segment_by_view = (*upper_sptr).get_segment_by_view(segment_num); + + if (estimate.do_smooth) { + IndexRange3D kernel_size(0, 0, -2, 2, -2, 2); + Array<3, float> kernel(kernel_size); + kernel.fill(1 / 25.F); + ArrayFilter3DUsingConvolution filter3d(kernel); + filter3d(filter_lower_segment_by_view, lower_segment_by_view); + filter3d(filter_upper_segment_by_view, upper_segment_by_view); + } - pow_times_add divide_by_lower_width(add_scalar, 1/estimate.lower_width,power ,min_threshold ,max_threshold ); - pow_times_add divide_by_upper_width(add_scalar, 1/estimate.upper_width,power ,min_threshold ,max_threshold ); - pow_times_add mult_by_half_peak_width(add_scalar, estimate.peak_width/2,power ,min_threshold ,max_threshold ); + // construct function object that does the manipulations on each data + float power = 1; + float add_scalar = 0; + float min_threshold = NumericInfo().min_value(); + float max_threshold = NumericInfo().max_value(); - in_place_apply_function(filter_lower_segment_by_view, divide_by_lower_width); - in_place_apply_function(filter_upper_segment_by_view, divide_by_upper_width); + // The following apply the the TEW method C_{scatter}=(C_{lower}/W_{lower}+C_{upper}/W_{upper})*W_{peak}/2 - scatter_segment_by_view=filter_lower_segment_by_view; - scatter_segment_by_view+=filter_upper_segment_by_view; + pow_times_add divide_by_lower_width(add_scalar, 1 / estimate.lower_width, power, min_threshold, max_threshold); + pow_times_add divide_by_upper_width(add_scalar, 1 / estimate.upper_width, power, min_threshold, max_threshold); + pow_times_add mult_by_half_peak_width(add_scalar, estimate.peak_width / 2, power, min_threshold, max_threshold); + in_place_apply_function(filter_lower_segment_by_view, divide_by_lower_width); + in_place_apply_function(filter_upper_segment_by_view, divide_by_upper_width); - in_place_apply_function(scatter_segment_by_view, mult_by_half_peak_width); + scatter_segment_by_view = filter_lower_segment_by_view; + scatter_segment_by_view += filter_upper_segment_by_view; + in_place_apply_function(scatter_segment_by_view, mult_by_half_peak_width); - if (!(out_scatter_proj_data_ptr->set_segment(scatter_segment_by_view) == Succeeded::yes)) - warning("Error set_segment %d\n", segment_num); - } + if (!(out_scatter_proj_data_ptr->set_segment(scatter_segment_by_view) == Succeeded::yes)) + warning("Error set_segment %d\n", segment_num); + } - std::cout<<"TEW scatter estimated "< (*.hs)\n"; - exit(EXIT_FAILURE); - } - - char const * const filename = argv[1]; - - shared_ptr s3d = ProjData::read_from_file(filename); - - const bool extract_by_view = - ask_num("Extract as SegmentByView (0) or BySinogram (1)?", 0,1,0)==0; - - for (int segment_num = s3d->get_min_segment_num(); - segment_num <= s3d->get_max_segment_num(); - ++segment_num) - { - std::string output_filename=filename; - replace_extension(output_filename, ""); - output_filename+="seg"; - output_filename+=boost::str(boost::format("%d") % segment_num); - - Bin central_bin(segment_num,0,0,0); - const float m_spacing = s3d->get_proj_data_info_sptr()->get_sampling_in_m(central_bin); - const float s_spacing = s3d->get_proj_data_info_sptr()->get_sampling_in_s(central_bin); - const float m = s3d->get_proj_data_info_sptr()->get_m(central_bin); - const float s = s3d->get_proj_data_info_sptr()->get_s(central_bin); - - if (extract_by_view) - { - SegmentByView segment= s3d->get_segment_by_view(segment_num); - write_basic_interfile(output_filename + "_by_view.hv", - segment, - CartesianCoordinate3D(1.F, m_spacing, s_spacing), - CartesianCoordinate3D(0.F, m, s)); - } - else { - SegmentBySinogram segment = s3d->get_segment_by_sinogram(segment_num); - write_basic_interfile(output_filename + "_by_sino.hv", - segment, - CartesianCoordinate3D(m_spacing, 1.F, s_spacing), - CartesianCoordinate3D(m, 0.F, s)); - } +int +main(int argc, char* argv[]) { + if (argc < 2) { + cerr << "Usage: " << argv[0] << " (*.hs)\n"; + exit(EXIT_FAILURE); + } + + char const* const filename = argv[1]; + + shared_ptr s3d = ProjData::read_from_file(filename); + + const bool extract_by_view = ask_num("Extract as SegmentByView (0) or BySinogram (1)?", 0, 1, 0) == 0; + + for (int segment_num = s3d->get_min_segment_num(); segment_num <= s3d->get_max_segment_num(); ++segment_num) { + std::string output_filename = filename; + replace_extension(output_filename, ""); + output_filename += "seg"; + output_filename += boost::str(boost::format("%d") % segment_num); + + Bin central_bin(segment_num, 0, 0, 0); + const float m_spacing = s3d->get_proj_data_info_sptr()->get_sampling_in_m(central_bin); + const float s_spacing = s3d->get_proj_data_info_sptr()->get_sampling_in_s(central_bin); + const float m = s3d->get_proj_data_info_sptr()->get_m(central_bin); + const float s = s3d->get_proj_data_info_sptr()->get_s(central_bin); + + if (extract_by_view) { + SegmentByView segment = s3d->get_segment_by_view(segment_num); + write_basic_interfile(output_filename + "_by_view.hv", segment, CartesianCoordinate3D(1.F, m_spacing, s_spacing), + CartesianCoordinate3D(0.F, m, s)); + } else { + SegmentBySinogram segment = s3d->get_segment_by_sinogram(segment_num); + write_basic_interfile(output_filename + "_by_sino.hv", segment, CartesianCoordinate3D(m_spacing, 1.F, s_spacing), + CartesianCoordinate3D(m, 0.F, s)); } + } - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/src/utilities/extract_single_images_from_dynamic_image.cxx b/src/utilities/extract_single_images_from_dynamic_image.cxx index 531688f8fe..147841b10c 100644 --- a/src/utilities/extract_single_images_from_dynamic_image.cxx +++ b/src/utilities/extract_single_images_from_dynamic_image.cxx @@ -24,7 +24,7 @@ \author Richard Brown \par Usage: - \code + \code extract_single_images_from_dynamic_image output_filename_pattern input_header_filename output_format_parameter_file The output filename should look something like this: dyn_im_%d_output.file_extension, @@ -51,68 +51,68 @@ #include "stir/IO/OutputFileFormat.h" #include "stir/Succeeded.h" -int main(int argc, char *argv[]) -{ - USING_NAMESPACE_STIR - - if (argc != 3 && argc != 4) { - std::cerr << "\nUsage: extract_single_images_from_dynamic_image output_filename_pattern input_header_filename [output_format_parameter_file]\n\n"; - return EXIT_FAILURE; +int +main(int argc, char* argv[]) { + USING_NAMESPACE_STIR + + if (argc != 3 && argc != 4) { + std::cerr << "\nUsage: extract_single_images_from_dynamic_image output_filename_pattern input_header_filename " + "[output_format_parameter_file]\n\n"; + return EXIT_FAILURE; + } + + try { + + // Read images + shared_ptr dyn_im_sptr(read_from_file(argv[2])); + + // Check + if (is_null_ptr(dyn_im_sptr)) + throw std::runtime_error("Failed to read dynamic image (" + std::string(argv[2]) + ")."); + + // Set up the output type + shared_ptr>> output_file_format_sptr; + if (argc == 3) + output_file_format_sptr = OutputFileFormat>::default_sptr(); + else { + KeyParser parser; + parser.add_start_key("OutputFileFormat Parameters"); + parser.add_parsing_key("output file format type", &output_file_format_sptr); + parser.add_stop_key("END"); + std::ifstream in(argv[3]); + if (!parser.parse(in) || is_null_ptr(output_file_format_sptr)) + throw std::runtime_error("Failed to parse output format file (" + std::string(argv[3]) + ")."); } - try { - - // Read images - shared_ptr dyn_im_sptr(read_from_file(argv[2])); - - // Check - if (is_null_ptr(dyn_im_sptr)) - throw std::runtime_error("Failed to read dynamic image (" + std::string(argv[2]) + ")."); - - // Set up the output type - shared_ptr > > output_file_format_sptr; - if (argc == 3) - output_file_format_sptr = OutputFileFormat >::default_sptr(); - else { - KeyParser parser; - parser.add_start_key("OutputFileFormat Parameters"); - parser.add_parsing_key("output file format type", &output_file_format_sptr); - parser.add_stop_key("END"); - std::ifstream in(argv[3]); - if (!parser.parse(in) || is_null_ptr(output_file_format_sptr)) - throw std::runtime_error("Failed to parse output format file (" + std::string(argv[3]) + ")."); - } - - // Loop over each image - for (unsigned i=1; i<=dyn_im_sptr->get_num_time_frames(); ++i) { - - DiscretisedDensity<3,float> &disc = dyn_im_sptr->get_density(i); - - std::string current_filename; - try { - current_filename = boost::str(boost::format(argv[1]) % i); - } catch (std::exception& e) { - error(boost::format("Error using 'output_filename' pattern (which is set to '%1%'). " - "Check syntax for boost::format. Error is:\n%2%") % argv[1] % e.what()); - return EXIT_FAILURE; - } - - // Write to file - const Succeeded success = output_file_format_sptr->write_to_file(current_filename,disc); - if (success == Succeeded::no) - throw std::runtime_error("Failed writing."); - } - - // If all is good, exit - return EXIT_SUCCESS; + // Loop over each image + for (unsigned i = 1; i <= dyn_im_sptr->get_num_time_frames(); ++i) { - // If there was an error - } catch(const std::exception &error) { - std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; - return EXIT_FAILURE; - } catch(...) { + DiscretisedDensity<3, float>& disc = dyn_im_sptr->get_density(i); + + std::string current_filename; + try { + current_filename = boost::str(boost::format(argv[1]) % i); + } catch (std::exception& e) { + error(boost::format("Error using 'output_filename' pattern (which is set to '%1%'). " + "Check syntax for boost::format. Error is:\n%2%") % + argv[1] % e.what()); return EXIT_FAILURE; + } + + // Write to file + const Succeeded success = output_file_format_sptr->write_to_file(current_filename, disc); + if (success == Succeeded::no) + throw std::runtime_error("Failed writing."); } -} + // If all is good, exit + return EXIT_SUCCESS; + // If there was an error + } catch (const std::exception& error) { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + return EXIT_FAILURE; + } catch (...) { + return EXIT_FAILURE; + } +} diff --git a/src/utilities/find_ML_normfactors.cxx b/src/utilities/find_ML_normfactors.cxx index bd15dcfcad..4db836ab36 100644 --- a/src/utilities/find_ML_normfactors.cxx +++ b/src/utilities/find_ML_normfactors.cxx @@ -42,7 +42,6 @@ START_NAMESPACE_STIR - #if 0 // this is a test routine for the code // should really be in a test class @@ -104,77 +103,66 @@ void check_geo_data() #endif - - END_NAMESPACE_STIR -static void print_usage_and_exit(const std::string& program_name) -{ - std::cerr<<"Usage: " << program_name << " [--display | --print-KL | --include-block-timing-model] \\\n" - << " out_filename_prefix measured_data model num_iterations num_eff_iterations\n" - << " set num_iterations to 0 to do only efficiencies\n"; +static void +print_usage_and_exit(const std::string& program_name) { + std::cerr << "Usage: " << program_name << " [--display | --print-KL | --include-block-timing-model] \\\n" + << " out_filename_prefix measured_data model num_iterations num_eff_iterations\n" + << " set num_iterations to 0 to do only efficiencies\n"; exit(EXIT_FAILURE); } - USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - const char * const program_name = argv[0]; +int +main(int argc, char** argv) { + const char* const program_name = argv[0]; // skip program name --argc; ++argv; - //check_geo_data(); + // check_geo_data(); bool do_display = false; bool do_KL = false; bool do_block = false; // first process command line options - while (argc>0 && argv[0][0]=='-' && argc>=1) - { - if (strcmp(argv[0], "--display")==0) - { - do_display = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--print-KL")==0) - { - do_KL = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--include-block-timing-model")==0) - { - do_block = true; - --argc; ++argv; - } - else - print_usage_and_exit(program_name); - } - // go back to previous counts such that we don't have to change code below - ++argc; --argv; - - if (argc!=6) - { + while (argc > 0 && argv[0][0] == '-' && argc >= 1) { + if (strcmp(argv[0], "--display") == 0) { + do_display = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--print-KL") == 0) { + do_KL = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--include-block-timing-model") == 0) { + do_block = true; + --argc; + ++argv; + } else print_usage_and_exit(program_name); - } + } + // go back to previous counts such that we don't have to change code below + ++argc; + --argv; + + if (argc != 6) { + print_usage_and_exit(program_name); + } const int num_eff_iterations = atoi(argv[5]); const int num_iterations = atoi(argv[4]); shared_ptr model_data = ProjData::read_from_file(argv[3]); shared_ptr measured_data = ProjData::read_from_file(argv[2]); const std::string out_filename_prefix = argv[1]; - /* const int num_rings = + /* const int num_rings = measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_rings(); */ - const int num_detectors = - measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); - const int num_crystals_per_block = - measured_data->get_proj_data_info_sptr()->get_scanner_ptr()-> - get_num_transaxial_crystals_per_block(); - const int num_blocks = - measured_data->get_proj_data_info_sptr()->get_scanner_ptr()-> - get_num_transaxial_blocks(); + const int num_detectors = measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_crystals_per_block = + measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_transaxial_crystals_per_block(); + const int num_blocks = measured_data->get_proj_data_info_sptr()->get_scanner_ptr()->get_num_transaxial_blocks(); CPUTimer timer; timer.start(); @@ -182,174 +170,156 @@ int main(int argc, char **argv) const int segment_num = 0; DetPairData det_pair_data; DetPairData model_det_pair_data; - Array<1,float> data_fan_sums(num_detectors); - Array<1,float> efficiencies(num_detectors); - assert(num_crystals_per_block%2 == 0); - GeoData measured_geo_data(IndexRange2D(num_crystals_per_block/2, num_detectors)); - GeoData norm_geo_data(IndexRange2D(num_crystals_per_block/2, num_detectors)); + Array<1, float> data_fan_sums(num_detectors); + Array<1, float> efficiencies(num_detectors); + assert(num_crystals_per_block % 2 == 0); + GeoData measured_geo_data(IndexRange2D(num_crystals_per_block / 2, num_detectors)); + GeoData norm_geo_data(IndexRange2D(num_crystals_per_block / 2, num_detectors)); BlockData measured_block_data(IndexRange2D(num_blocks, num_blocks)); BlockData norm_block_data(IndexRange2D(num_blocks, num_blocks)); for (int ax_pos_num = measured_data->get_min_axial_pos_num(segment_num); - ax_pos_num <= measured_data->get_max_axial_pos_num(segment_num); - ++ax_pos_num) + ax_pos_num <= measured_data->get_max_axial_pos_num(segment_num); ++ax_pos_num) { + // next could be local if KL is not computed below + DetPairData measured_det_pair_data; + float threshold_for_KL; + // compute factors dependent on the data { - // next could be local if KL is not computed below - DetPairData measured_det_pair_data; - float threshold_for_KL; - // compute factors dependent on the data - { - make_det_pair_data(measured_det_pair_data, *measured_data, segment_num, ax_pos_num); - threshold_for_KL = measured_det_pair_data.find_max()/100000.F; - std::cerr << "ax_pos " << ax_pos_num << std::endl; - //display(measured_det_pair_data, "measured data"); - - make_fan_sum_data(data_fan_sums, measured_det_pair_data); - make_geo_data(measured_geo_data, measured_det_pair_data); - make_block_data(measured_block_data, measured_det_pair_data); - if (do_display) - display(measured_block_data, "raw block data from measurements"); - /*{ - char *out_filename = new char[20]; - sprintf(out_filename, "%s_%d.out", - "fan", ax_pos_num); - std::ofstream out(out_filename); - out << data_fan_sums; - delete[] out_filename; - } - */ - } + make_det_pair_data(measured_det_pair_data, *measured_data, segment_num, ax_pos_num); + threshold_for_KL = measured_det_pair_data.find_max() / 100000.F; + std::cerr << "ax_pos " << ax_pos_num << std::endl; + // display(measured_det_pair_data, "measured data"); - make_det_pair_data(model_det_pair_data, *model_data, segment_num, ax_pos_num); - //display(model_det_pair_data, "model"); + make_fan_sum_data(data_fan_sums, measured_det_pair_data); + make_geo_data(measured_geo_data, measured_det_pair_data); + make_block_data(measured_block_data, measured_det_pair_data); + if (do_display) + display(measured_block_data, "raw block data from measurements"); + /*{ + char *out_filename = new char[20]; + sprintf(out_filename, "%s_%d.out", + "fan", ax_pos_num); + std::ofstream out(out_filename); + out << data_fan_sums; + delete[] out_filename; + } + */ + } - for (int iter_num = 1; iter_num<=std::max(num_iterations, 1); ++iter_num) - { - if (iter_num== 1) - { - efficiencies.fill(sqrt(data_fan_sums.sum()/model_det_pair_data.sum())); - norm_geo_data.fill(1); - norm_block_data.fill(1); - } - // efficiencies - { - det_pair_data = model_det_pair_data; - apply_geo_norm(det_pair_data, norm_geo_data); - apply_block_norm(det_pair_data, norm_block_data); - if (do_display) - display(det_pair_data, "model*geo*block"); - for (int eff_iter_num = 1; eff_iter_num<=num_eff_iterations; ++eff_iter_num) - { - iterate_efficiencies(efficiencies, data_fan_sums, det_pair_data); - { - char *out_filename = new char[out_filename_prefix.size() + 30]; - sprintf(out_filename, "%s_%s_%d_%d_%d.out", - out_filename_prefix.c_str(), "eff", ax_pos_num, iter_num, eff_iter_num); - std::ofstream out(out_filename); - out << efficiencies; - delete[] out_filename; - } - if (do_KL) - { - DetPairData model_times_norm = det_pair_data; - apply_efficiencies(model_times_norm, efficiencies); - if (do_display) - display( model_times_norm, "model_times_norm"); - //std::cerr << "model_times_norm min max: " << model_times_norm.find_min() << ',' << model_times_norm.find_max() << std::endl; + make_det_pair_data(model_det_pair_data, *model_data, segment_num, ax_pos_num); + // display(model_det_pair_data, "model"); - std::cerr << "KL " << KL(measured_det_pair_data, model_times_norm, threshold_for_KL) << std::endl; - } - if (do_display) - { - DetPairData norm = det_pair_data; - norm.fill(1); - apply_efficiencies(norm, efficiencies); - display(norm, "eff norm"); - } - - } - } - if (num_iterations==0) - break; - // geo norm - { - det_pair_data = model_det_pair_data; - apply_efficiencies(det_pair_data, efficiencies); - apply_block_norm(det_pair_data, norm_block_data); - iterate_geo_norm(norm_geo_data, measured_geo_data, det_pair_data); - { // check - for (int a=0; a0 && argv[0][0]=='-' && argc>=1) - { - if (strcmp(argv[0], "--display")==0) - { - do_display = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--print-KL")==0) - { - do_KL = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--include-geometric-model")==0) - { - do_geo = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--include-block-timing-model")==0) - { - do_block = true; - --argc; ++argv; - } - else - print_usage_and_exit(program_name); - } - // go back to previous counts such that we don't have to change code below - ++argc; --argv; - - //check_geo_data(); - if (argc!=6) - { + while (argc > 0 && argv[0][0] == '-' && argc >= 1) { + if (strcmp(argv[0], "--display") == 0) { + do_display = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--print-KL") == 0) { + do_KL = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--include-geometric-model") == 0) { + do_geo = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--include-block-timing-model") == 0) { + do_block = true; + --argc; + ++argv; + } else print_usage_and_exit(program_name); - } + } + // go back to previous counts such that we don't have to change code below + ++argc; + --argv; + + // check_geo_data(); + if (argc != 6) { + print_usage_and_exit(program_name); + } const int num_eff_iterations = atoi(argv[5]); const int num_iterations = atoi(argv[4]); shared_ptr model_data = ProjData::read_from_file(argv[3]); shared_ptr measured_data = ProjData::read_from_file(argv[2]); const std::string out_filename_prefix = argv[1]; - const int num_rings = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_rings(); - const int num_detectors_per_ring = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_detectors_per_ring(); - const int num_transaxial_blocks = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_transaxial_blocks(); - const int num_axial_blocks = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_axial_blocks(); - const int num_transaxial_crystals_per_block = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_transaxial_crystals_per_block(); - const int num_axial_crystals_per_block = - measured_data->get_proj_data_info_sptr()->get_scanner_sptr()-> - get_num_axial_crystals_per_block(); - - - - CPUTimer timer; - timer.start(); - - FanProjData model_fan_data; - FanProjData fan_data; - Array<2,float> data_fan_sums(IndexRange2D(num_rings, num_detectors_per_ring)); - DetectorEfficiencies efficiencies(IndexRange2D(num_rings, num_detectors_per_ring)); - - GeoData3D measured_geo_data(num_axial_crystals_per_block, num_transaxial_crystals_per_block/2, num_rings, num_detectors_per_ring ); //inputes have to be modified - GeoData3D norm_geo_data(num_axial_crystals_per_block, num_transaxial_crystals_per_block/2, num_rings, num_detectors_per_ring ); //inputes have to be modified - - BlockData3D measured_block_data(num_axial_blocks, num_transaxial_blocks, num_axial_blocks-1, num_transaxial_blocks-1); - BlockData3D norm_block_data(num_axial_blocks, num_transaxial_blocks, num_axial_blocks-1, num_transaxial_blocks-1); - - - make_fan_data(model_fan_data, *model_data); - { - // next could be local if KL is not computed below - FanProjData measured_fan_data; - float threshold_for_KL; - // compute factors dependent on the data - { - make_fan_data(measured_fan_data, *measured_data); - -/* TEMP FIX */ - for (int ra = model_fan_data.get_min_ra(); ra <= model_fan_data.get_max_ra(); ++ra) + const int num_rings = measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_rings(); + const int num_detectors_per_ring = measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_detectors_per_ring(); + const int num_transaxial_blocks = measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_transaxial_blocks(); + const int num_axial_blocks = measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_axial_blocks(); + const int num_transaxial_crystals_per_block = + measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_transaxial_crystals_per_block(); + const int num_axial_crystals_per_block = + measured_data->get_proj_data_info_sptr()->get_scanner_sptr()->get_num_axial_crystals_per_block(); + + CPUTimer timer; + timer.start(); + + FanProjData model_fan_data; + FanProjData fan_data; + Array<2, float> data_fan_sums(IndexRange2D(num_rings, num_detectors_per_ring)); + DetectorEfficiencies efficiencies(IndexRange2D(num_rings, num_detectors_per_ring)); + + GeoData3D measured_geo_data(num_axial_crystals_per_block, num_transaxial_crystals_per_block / 2, num_rings, + num_detectors_per_ring); // inputes have to be modified + GeoData3D norm_geo_data(num_axial_crystals_per_block, num_transaxial_crystals_per_block / 2, num_rings, + num_detectors_per_ring); // inputes have to be modified + + BlockData3D measured_block_data(num_axial_blocks, num_transaxial_blocks, num_axial_blocks - 1, num_transaxial_blocks - 1); + BlockData3D norm_block_data(num_axial_blocks, num_transaxial_blocks, num_axial_blocks - 1, num_transaxial_blocks - 1); + + make_fan_data(model_fan_data, *model_data); + { + // next could be local if KL is not computed below + FanProjData measured_fan_data; + float threshold_for_KL; + // compute factors dependent on the data { - for (int a = model_fan_data.get_min_a(); a <= model_fan_data.get_max_a(); ++a) - { - for (int rb = std::max(ra,model_fan_data.get_min_rb(ra)); rb <= model_fan_data.get_max_rb(ra); ++rb) - { - for (int b = model_fan_data.get_min_b(a); b <= model_fan_data.get_max_b(a); ++b) - if (model_fan_data(ra,a,rb,b) == 0) - measured_fan_data(ra,a,rb,b) = 0; - } + make_fan_data(measured_fan_data, *measured_data); + + /* TEMP FIX */ + for (int ra = model_fan_data.get_min_ra(); ra <= model_fan_data.get_max_ra(); ++ra) { + for (int a = model_fan_data.get_min_a(); a <= model_fan_data.get_max_a(); ++a) { + for (int rb = std::max(ra, model_fan_data.get_min_rb(ra)); rb <= model_fan_data.get_max_rb(ra); ++rb) { + for (int b = model_fan_data.get_min_b(a); b <= model_fan_data.get_max_b(a); ++b) + if (model_fan_data(ra, a, rb, b) == 0) + measured_fan_data(ra, a, rb, b) = 0; + } } - } + } - threshold_for_KL = measured_fan_data.find_max()/100000.F; - //display(measured_fan_data, "measured data"); - - make_fan_sum_data(data_fan_sums, measured_fan_data); - make_geo_data(measured_geo_data, measured_fan_data); - make_block_data(measured_block_data, measured_fan_data); - if (do_display) - display(measured_block_data, "raw block data from measurements"); - - /* { - char *out_filename = new char[20]; - sprintf(out_filename, "%s_%d.out", - "fan", ax_pos_num); - std::ofstream out(out_filename); - out << data_fan_sums; - delete[] out_filename; - } - */ + threshold_for_KL = measured_fan_data.find_max() / 100000.F; + // display(measured_fan_data, "measured data"); + + make_fan_sum_data(data_fan_sums, measured_fan_data); + make_geo_data(measured_geo_data, measured_fan_data); + make_block_data(measured_block_data, measured_fan_data); + if (do_display) + display(measured_block_data, "raw block data from measurements"); + + /* { + char *out_filename = new char[20]; + sprintf(out_filename, "%s_%d.out", + "fan", ax_pos_num); + std::ofstream out(out_filename); + out << data_fan_sums; + delete[] out_filename; } - - //std::cerr << "model min " << model_fan_data.find_min() << " ,max " << model_fan_data.find_max() << std::endl; - if (do_display) - display(model_fan_data, "model"); + */ + } + + // std::cerr << "model min " << model_fan_data.find_min() << " ,max " << model_fan_data.find_max() << std::endl; + if (do_display) + display(model_fan_data, "model"); #if 0 { shared_ptr out_proj_data_ptr = @@ -196,71 +176,64 @@ int main(int argc, char **argv) set_fan_data(*out_proj_data_ptr, model_fan_data); } #endif - - for (int iter_num = 1; iter_num<=std::max(num_iterations, 1); ++iter_num) - { - if (iter_num== 1) - { - efficiencies.fill(sqrt(data_fan_sums.sum()/model_fan_data.sum())); - norm_geo_data.fill(1); - norm_block_data.fill(1); - } - // efficiencies - { - fan_data = model_fan_data; - apply_geo_norm(fan_data, norm_geo_data); - apply_block_norm(fan_data, norm_block_data); - if (do_display) - display(fan_data, "model*geo*block"); - for (int eff_iter_num = 1; eff_iter_num<=num_eff_iterations; ++eff_iter_num) - { - iterate_efficiencies(efficiencies, data_fan_sums, fan_data); - { - char *out_filename = new char[out_filename_prefix.size() + 30]; - sprintf(out_filename, "%s_%s_%d_%d.out", - out_filename_prefix.c_str(), "eff", iter_num, eff_iter_num); - std::ofstream out(out_filename); - out << efficiencies; - delete[] out_filename; - } - if (do_KL) - { - apply_efficiencies(fan_data, efficiencies); - std::cerr << "measured*norm min " << measured_fan_data.find_min() << " ,max " << measured_fan_data.find_max() << std::endl; - std::cerr << "model*norm min " << fan_data.find_min() << " ,max " << fan_data.find_max() << std::endl; - if (do_display) - display( fan_data, "model_times_norm"); - info(boost::format("KL %1%") % KL(measured_fan_data, fan_data, threshold_for_KL)); - // now restore for further iterations - fan_data = model_fan_data; - apply_geo_norm(fan_data, norm_geo_data); - apply_block_norm(fan_data, norm_block_data); - } - if (do_display) - { - fan_data.fill(1); - apply_efficiencies(fan_data, efficiencies); - display(fan_data, "eff norm"); - // now restore for further iterations - fan_data = model_fan_data; - apply_geo_norm(fan_data, norm_geo_data); - apply_block_norm(fan_data, norm_block_data); - } - - } - } // end efficiencies - - - // geo norm - + + for (int iter_num = 1; iter_num <= std::max(num_iterations, 1); ++iter_num) { + if (iter_num == 1) { + efficiencies.fill(sqrt(data_fan_sums.sum() / model_fan_data.sum())); + norm_geo_data.fill(1); + norm_block_data.fill(1); + } + // efficiencies + { + fan_data = model_fan_data; + apply_geo_norm(fan_data, norm_geo_data); + apply_block_norm(fan_data, norm_block_data); + if (do_display) + display(fan_data, "model*geo*block"); + for (int eff_iter_num = 1; eff_iter_num <= num_eff_iterations; ++eff_iter_num) { + iterate_efficiencies(efficiencies, data_fan_sums, fan_data); + { + char* out_filename = new char[out_filename_prefix.size() + 30]; + sprintf(out_filename, "%s_%s_%d_%d.out", out_filename_prefix.c_str(), "eff", iter_num, eff_iter_num); + std::ofstream out(out_filename); + out << efficiencies; + delete[] out_filename; + } + if (do_KL) { + apply_efficiencies(fan_data, efficiencies); + std::cerr << "measured*norm min " << measured_fan_data.find_min() << " ,max " << measured_fan_data.find_max() + << std::endl; + std::cerr << "model*norm min " << fan_data.find_min() << " ,max " << fan_data.find_max() << std::endl; + if (do_display) + display(fan_data, "model_times_norm"); + info(boost::format("KL %1%") % KL(measured_fan_data, fan_data, threshold_for_KL)); + // now restore for further iterations fan_data = model_fan_data; + apply_geo_norm(fan_data, norm_geo_data); + apply_block_norm(fan_data, norm_block_data); + } + if (do_display) { + fan_data.fill(1); apply_efficiencies(fan_data, efficiencies); + display(fan_data, "eff norm"); + // now restore for further iterations + fan_data = model_fan_data; + apply_geo_norm(fan_data, norm_geo_data); apply_block_norm(fan_data, norm_block_data); - - if (do_geo) - iterate_geo_norm(norm_geo_data, measured_geo_data, fan_data); - - #if 0 + } + } + } // end efficiencies + + // geo norm + + fan_data = model_fan_data; + apply_efficiencies(fan_data, efficiencies); + apply_block_norm(fan_data, norm_block_data); + + if (do_geo) + iterate_geo_norm(norm_geo_data, measured_geo_data, fan_data); + +#if 0 { // check for (int a=0; a fan_sums(IndexRange2D(num_rings, num_detectors_per_ring)); - GeoData3D geo_data(num_axial_crystals_per_block, num_transaxial_crystals_per_block/2, num_rings, num_detectors_per_ring ); //inputes have to be modified - BlockData3D block_data(num_axial_blocks, num_transaxial_blocks, num_axial_blocks-1, num_transaxial_blocks-1); - - make_fan_sum_data(fan_sums, fan_data); - make_geo_data(geo_data, fan_data); - make_block_data(block_data, measured_fan_data); - -std::cerr << "KL on fans: " << KL(measured_fan_data, fan_data,0) << ", " << KL(measured_geo_data,geo_data,0) << std::endl; -} +#endif + { + char* out_filename = new char[out_filename_prefix.size() + 30]; + sprintf(out_filename, "%s_%s_%d.out", out_filename_prefix.c_str(), "block", iter_num); + std::ofstream out(out_filename); + out << norm_block_data; + delete[] out_filename; + } + if (do_KL) { + apply_block_norm(fan_data, norm_block_data); + info(boost::format("KL %1%") % KL(measured_fan_data, fan_data, threshold_for_KL)); } + if (do_display) { + fan_data.fill(1); + apply_block_norm(fan_data, norm_block_data); + display(norm_block_data, "raw block norm"); + display(fan_data, "block norm"); + } + } // end block + + //// print KL for fansums + if (do_KL) { + Array<2, float> fan_sums(IndexRange2D(num_rings, num_detectors_per_ring)); + GeoData3D geo_data(num_axial_crystals_per_block, num_transaxial_crystals_per_block / 2, num_rings, + num_detectors_per_ring); // inputes have to be modified + BlockData3D block_data(num_axial_blocks, num_transaxial_blocks, num_axial_blocks - 1, num_transaxial_blocks - 1); + + make_fan_sum_data(fan_sums, fan_data); + make_geo_data(geo_data, fan_data); + make_block_data(block_data, measured_fan_data); + + std::cerr << "KL on fans: " << KL(measured_fan_data, fan_data, 0) << ", " << KL(measured_geo_data, geo_data, 0) + << std::endl; + } } - timer.stop(); - info(boost::format("CPU time %1% secs") % timer.value()); - return EXIT_SUCCESS; + } + timer.stop(); + info(boost::format("CPU time %1% secs") % timer.value()); + return EXIT_SUCCESS; } diff --git a/src/utilities/find_ML_singles_from_delayed.cxx b/src/utilities/find_ML_singles_from_delayed.cxx index d6498d0528..0977717eb5 100644 --- a/src/utilities/find_ML_singles_from_delayed.cxx +++ b/src/utilities/find_ML_singles_from_delayed.cxx @@ -37,191 +37,160 @@ START_NAMESPACE_STIR -static unsigned long compute_num_bins(const int num_rings, const int num_detectors_per_ring, - const int max_ring_diff, const int half_fan_size) -{ +static unsigned long +compute_num_bins(const int num_rings, const int num_detectors_per_ring, const int max_ring_diff, const int half_fan_size) { unsigned long num = 0; for (int ra = 0; ra < num_rings; ++ra) - for (int a =0; a < num_detectors_per_ring; ++a) - { - for (int rb = std::max(ra-max_ring_diff, 0); rb <= std::min(ra+max_ring_diff, num_rings-1); ++rb) - for (int b = a+num_detectors_per_ring/2-half_fan_size; b <= a+num_detectors_per_ring/2+half_fan_size; ++b) - ++num; + for (int a = 0; a < num_detectors_per_ring; ++a) { + for (int rb = std::max(ra - max_ring_diff, 0); rb <= std::min(ra + max_ring_diff, num_rings - 1); ++rb) + for (int b = a + num_detectors_per_ring / 2 - half_fan_size; b <= a + num_detectors_per_ring / 2 + half_fan_size; ++b) + ++num; } return num; } - END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if (!(argc==4 || (argc==7 && strcmp(argv[1],"-f")==0))) - { - std::cerr << "Usage: \n" - << '\t' << argv[0] << " -f out_filename_prefix measured_fan_sum_data num_iterations max_ring_diff fan_size\n" - << "or\n" - << '\t' << argv[0] << " out_filename_prefix measured_projdata num_iterations\n" - << "If the -f option is used, the 2nd arg should be a file with fan_sums. " - << "Otherwise, it has to be projection data.\n"; - - return EXIT_FAILURE; - } - const int num_eff_iterations = atoi(argv[argc==4?3:4]); - const std::string out_filename_prefix = argv[argc==4?1:2]; - - const int do_display_interval = - ask_num("Display iterations which are a multiple of ",0,num_eff_iterations,0); - const int do_KL_interval = - ask_num("Compute KL distance between fan-sums at iterations which are a multiple of ",0,num_eff_iterations,0); - const int do_save_interval = - ask_num("Write output at iterations which are a multiple of ",0,num_eff_iterations,num_eff_iterations); +int +main(int argc, char** argv) { + if (!(argc == 4 || (argc == 7 && strcmp(argv[1], "-f") == 0))) { + std::cerr << "Usage: \n" + << '\t' << argv[0] << " -f out_filename_prefix measured_fan_sum_data num_iterations max_ring_diff fan_size\n" + << "or\n" + << '\t' << argv[0] << " out_filename_prefix measured_projdata num_iterations\n" + << "If the -f option is used, the 2nd arg should be a file with fan_sums. " + << "Otherwise, it has to be projection data.\n"; + + return EXIT_FAILURE; + } + const int num_eff_iterations = atoi(argv[argc == 4 ? 3 : 4]); + const std::string out_filename_prefix = argv[argc == 4 ? 1 : 2]; + + const int do_display_interval = ask_num("Display iterations which are a multiple of ", 0, num_eff_iterations, 0); + const int do_KL_interval = + ask_num("Compute KL distance between fan-sums at iterations which are a multiple of ", 0, num_eff_iterations, 0); + const int do_save_interval = + ask_num("Write output at iterations which are a multiple of ", 0, num_eff_iterations, num_eff_iterations); - - int num_rings; int num_detectors_per_ring; int fan_size; int max_ring_diff; - Array<2,float> data_fan_sums; + Array<2, float> data_fan_sums; - if (argc==4) - { - shared_ptr measured_data = ProjData::read_from_file(argv[2]); - get_fan_info(num_rings, num_detectors_per_ring, max_ring_diff, fan_size, - *measured_data->get_proj_data_info_sptr()); - data_fan_sums.grow(IndexRange2D(num_rings, num_detectors_per_ring)); + if (argc == 4) { + shared_ptr measured_data = ProjData::read_from_file(argv[2]); + get_fan_info(num_rings, num_detectors_per_ring, max_ring_diff, fan_size, *measured_data->get_proj_data_info_sptr()); + data_fan_sums.grow(IndexRange2D(num_rings, num_detectors_per_ring)); #if 0 FanProjData measured_fan_data; make_fan_data(measured_fan_data, *measured_data); make_fan_sum_data(data_fan_sums, measured_fan_data); #else - make_fan_sum_data(data_fan_sums, *measured_data); + make_fan_sum_data(data_fan_sums, *measured_data); #endif - // write fan sums to file - { - std::string fan_sum_name = "fansums_for_"; - fan_sum_name += argv[2]; - fan_sum_name.erase(fan_sum_name.begin() + fan_sum_name.rfind('.'), - fan_sum_name.end()); - fan_sum_name += ".dat"; - std::ofstream out(fan_sum_name.c_str()); - if (!out) - { - warning("Error opening output file %s\n", fan_sum_name.c_str()); - exit(EXIT_FAILURE); - } - out << data_fan_sums; - if (!out) - { - warning("Error writing data to output file %s\n", fan_sum_name.c_str()); - exit(EXIT_FAILURE); - } + // write fan sums to file + { + std::string fan_sum_name = "fansums_for_"; + fan_sum_name += argv[2]; + fan_sum_name.erase(fan_sum_name.begin() + fan_sum_name.rfind('.'), fan_sum_name.end()); + fan_sum_name += ".dat"; + std::ofstream out(fan_sum_name.c_str()); + if (!out) { + warning("Error opening output file %s\n", fan_sum_name.c_str()); + exit(EXIT_FAILURE); + } + out << data_fan_sums; + if (!out) { + warning("Error writing data to output file %s\n", fan_sum_name.c_str()); + exit(EXIT_FAILURE); } } - else - { - max_ring_diff = atoi(argv[5]); - fan_size = atoi(argv[6]); - std::ifstream in(argv[3]); - if (!in) - { - warning("Error opening input file %s\n", argv[3]); - exit(EXIT_FAILURE); - } - in >> data_fan_sums; - num_rings = data_fan_sums.get_length(); - if (num_rings==0) - { - warning("input file %s should be a 2d list of numbers but I found " - "a list of length 0 (or no list at all).\n", argv[3]); - exit(EXIT_FAILURE); - } - assert(data_fan_sums.get_min_index()==0); - num_detectors_per_ring = data_fan_sums[0].get_length(); - if (!data_fan_sums.is_regular()) - { - warning("input file %s should be a (rectangular) matrix of numbers\n", argv[3]); - exit(EXIT_FAILURE); - } - - if (num_detectors_per_ring==0) - { - warning("input file %s should be a 2d list of numbers but I found something else (zero number of columns?)\n", argv[3]); - exit(EXIT_FAILURE); - } - if (num_rings> data_fan_sums; + num_rings = data_fan_sums.get_length(); + if (num_rings == 0) { + warning("input file %s should be a 2d list of numbers but I found " + "a list of length 0 (or no list at all).\n", + argv[3]); + exit(EXIT_FAILURE); + } + assert(data_fan_sums.get_min_index() == 0); + num_detectors_per_ring = data_fan_sums[0].get_length(); + if (!data_fan_sums.is_regular()) { + warning("input file %s should be a (rectangular) matrix of numbers\n", argv[3]); + exit(EXIT_FAILURE); } - const int half_fan_size = fan_size/2; + if (num_detectors_per_ring == 0) { + warning("input file %s should be a 2d list of numbers but I found something else (zero number of columns?)\n", argv[3]); + exit(EXIT_FAILURE); + } + if (num_rings < max_ring_diff || num_detectors_per_ring < fan_size) { + warning("input file %s is a matrix with sizes %dx%d, but this is " + "too small compared to max_ring_diff (%d) and/or fan_size (%d)\n", + argv[3], num_rings, num_detectors_per_ring, max_ring_diff, fan_size); + exit(EXIT_FAILURE); + } + } + const int half_fan_size = fan_size / 2; CPUTimer timer; timer.start(); - + DetectorEfficiencies efficiencies(IndexRange2D(num_rings, num_detectors_per_ring)); { - float threshold_for_KL = data_fan_sums.find_max()/100000.F; + float threshold_for_KL = data_fan_sums.find_max() / 100000.F; const int iter_num = 1; { - if (iter_num== 1) - { - efficiencies.fill(sqrt(data_fan_sums.sum()/ - compute_num_bins(num_rings, num_detectors_per_ring, max_ring_diff, half_fan_size))); + if (iter_num == 1) { + efficiencies.fill( + sqrt(data_fan_sums.sum() / compute_num_bins(num_rings, num_detectors_per_ring, max_ring_diff, half_fan_size))); } // efficiencies { - for (int eff_iter_num = 1; eff_iter_num<=num_eff_iterations; ++eff_iter_num) - { + for (int eff_iter_num = 1; eff_iter_num <= num_eff_iterations; ++eff_iter_num) { std::cout << "Starting iteration " << eff_iter_num; iterate_efficiencies(efficiencies, data_fan_sums, max_ring_diff, half_fan_size); - if (eff_iter_num==num_eff_iterations || (do_save_interval>0 && eff_iter_num%do_save_interval==0)) - { - char *out_filename = new char[out_filename_prefix.size() + 30]; - sprintf(out_filename, "%s_%s_%d_%d.out", - out_filename_prefix.c_str(), "eff", iter_num, eff_iter_num); + if (eff_iter_num == num_eff_iterations || (do_save_interval > 0 && eff_iter_num % do_save_interval == 0)) { + char* out_filename = new char[out_filename_prefix.size() + 30]; + sprintf(out_filename, "%s_%s_%d_%d.out", out_filename_prefix.c_str(), "eff", iter_num, eff_iter_num); std::ofstream out(out_filename); - if (!out) - { - warning("Error opening output file %s\n", out_filename); - exit(EXIT_FAILURE); - } + if (!out) { + warning("Error opening output file %s\n", out_filename); + exit(EXIT_FAILURE); + } out << efficiencies; - if (!out) - { - warning("Error writing data to output file %s\n", out_filename); - exit(EXIT_FAILURE); - } + if (!out) { + warning("Error writing data to output file %s\n", out_filename); + exit(EXIT_FAILURE); + } delete[] out_filename; } - if (eff_iter_num==num_eff_iterations || (do_KL_interval>0 && eff_iter_num%do_KL_interval==0)) - { - Array<2,float> estimated_fan_sums(data_fan_sums.get_index_range()); - make_fan_sum_data(estimated_fan_sums, efficiencies, max_ring_diff, half_fan_size); - std::cout << "\tKL " << KL(data_fan_sums, estimated_fan_sums, threshold_for_KL); - + if (eff_iter_num == num_eff_iterations || (do_KL_interval > 0 && eff_iter_num % do_KL_interval == 0)) { + Array<2, float> estimated_fan_sums(data_fan_sums.get_index_range()); + make_fan_sum_data(estimated_fan_sums, efficiencies, max_ring_diff, half_fan_size); + std::cout << "\tKL " << KL(data_fan_sums, estimated_fan_sums, threshold_for_KL); } std::cout << std::endl; - if (do_display_interval>0 && eff_iter_num%do_display_interval==0) - { + if (do_display_interval > 0 && eff_iter_num % do_display_interval == 0) { display(efficiencies, "efficiencies"); } - } } // end efficiencies - } - } + } timer.stop(); std::cout << "CPU time " << timer.value() << " secs" << std::endl; return EXIT_SUCCESS; diff --git a/src/utilities/find_fwhm_in_image.cxx b/src/utilities/find_fwhm_in_image.cxx index 3d889071d7..d3fe2e7a0f 100644 --- a/src/utilities/find_fwhm_in_image.cxx +++ b/src/utilities/find_fwhm_in_image.cxx @@ -18,7 +18,7 @@ \file \ingroup utilities \brief List of FWHM and location of maximum in the image - + \author Charalampos Tsoumpas \author Kris Thielemans \author Sanida Mustafovic @@ -28,23 +28,23 @@ find_fwhm_in_image filename [num_maxima] [level] [dimension] [nema] \endcode \param num_maxima defaults to 1 - \param level defaults to 2 (half maximum) + \param level defaults to 2 (half maximum) \param dimension: for point sources (default) set to 0 for line source along z, y, x -axis, set to: 1, 2, 3 respectively - \param NEMA defaults to 1 - - - If you have point sources, it prints the value of the [num_maxima] maximum point source with its location - and the resolution at the three dimensions, sorting from the maximum to the minimum. If you have a line + \param NEMA defaults to 1 + + + If you have point sources, it prints the value of the [num_maxima] maximum point source with its location + and the resolution at the three dimensions, sorting from the maximum to the minimum. If you have a line source, a text file is returned that it contains the maximum value at its one slice, which is sorted from - the mimimum to maximum slice index, at the wanted direction, with its location and the resolution at the - three dimensions. The resolution at the axis of the line is set to be 0. If given as [num_maxima] less - than the total slices it returns the results for some slices by sampling with the same step the total - slices of the wanted dimension. The [nema] parameter enables the oportunity of using the NEMA Standards - Publication NU 2-2001. If it is set to 0 the function estimates the FWHM using 3D interpolation, for - closer approximation. + the mimimum to maximum slice index, at the wanted direction, with its location and the resolution at the + three dimensions. The resolution at the axis of the line is set to be 0. If given as [num_maxima] less + than the total slices it returns the results for some slices by sampling with the same step the total + slices of the wanted dimension. The [nema] parameter enables the oportunity of using the NEMA Standards + Publication NU 2-2001. If it is set to 0 the function estimates the FWHM using 3D interpolation, for + closer approximation. */ #include "stir/shared_ptr.h" #include "stir/DiscretisedDensity.h" @@ -55,93 +55,73 @@ #include #include #include -#include +#include #include #ifndef STIR_NO_NAMESPACES using std::setw; #endif -/***********************************************************/ -int main(int argc, char *argv[]) -{ +/***********************************************************/ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR - if (argc< 2 || argc>6) - { - std::cerr << "Usage:" << argv[0] << " input_image [num_maxima] [level] [dimension] [nema]\n" - << "\tnum_maxima defaults to 1\n" - << "\tlevel of maximum defaults at half maximum: 2\n" - << "\tfor point sources dimension set to 0 (default)\n" - << "\tfor line source along z, y, x -axis dimension set to 1, 2, 3 respectively:\n" - << "\tnema defaults to 1, NEMA Standards NU 2-2001 is enabled\n" - << "returns a file containing the resolutions\n\n"; + if (argc < 2 || argc > 6) { + std::cerr << "Usage:" << argv[0] << " input_image [num_maxima] [level] [dimension] [nema]\n" + << "\tnum_maxima defaults to 1\n" + << "\tlevel of maximum defaults at half maximum: 2\n" + << "\tfor point sources dimension set to 0 (default)\n" + << "\tfor line source along z, y, x -axis dimension set to 1, 2, 3 respectively:\n" + << "\tnema defaults to 1, NEMA Standards NU 2-2001 is enabled\n" + << "returns a file containing the resolutions\n\n"; + + return EXIT_FAILURE; + } + const unsigned short num_maxima = argc >= 3 ? atoi(argv[2]) : 1; + const float level = argc >= 4 ? static_cast(atof(argv[3])) : 2; + const int dimension = argc >= 5 ? atoi(argv[4]) : 0; + const bool nema = argc >= 6 ? (atoi(argv[5]) != 0) : true; + std::cerr << "Finding " << num_maxima << " maxima\n"; + shared_ptr> input_image_sptr(read_from_file>(argv[1])); + DiscretisedDensity<3, float>& input_image = *input_image_sptr; + std::list> list_res_index = find_fwhm_in_image(input_image, num_maxima, level, dimension, nema); + std::list>::iterator current_iter = list_res_index.begin(); + if (dimension != 0) { + std::string output_string; + std::string input_string(argv[1]); + std::string slices_string(argv[2]); + std::string::iterator string_iter; + for (string_iter = input_string.begin(); string_iter != input_string.end() && *string_iter != '.'; ++string_iter) + output_string.push_back(*string_iter); + if (argc >= 4) { + std::string level_string(argv[3]); + output_string += '_' + slices_string + "_slices_FW" + level_string + 'M'; + } else + output_string += '_' + slices_string + "_slices_FWHM"; - return EXIT_FAILURE; - } - const unsigned short num_maxima = argc>=3 ? atoi(argv[2]) : 1 ; - const float level = argc>=4 ? static_cast(atof(argv[3])) : 2 ; - const int dimension = argc>=5 ? atoi(argv[4]) : 0 ; - const bool nema = argc>=6 ? (atoi(argv[5])!=0) : true ; - std::cerr << "Finding " << num_maxima << " maxima\n" ; - shared_ptr< DiscretisedDensity<3,float> > - input_image_sptr(read_from_file >(argv[1])); - DiscretisedDensity<3,float>& input_image = *input_image_sptr; - std::list > list_res_index = - find_fwhm_in_image(input_image,num_maxima,level,dimension,nema); - std::list >:: iterator current_iter=list_res_index.begin(); - if (dimension!=0) - { - std::string output_string; - std::string input_string(argv[1]); - std::string slices_string(argv[2]); - std::string:: iterator string_iter; - for(string_iter=input_string.begin(); - string_iter!=input_string.end() && *string_iter!='.' ; - ++string_iter) - output_string.push_back(*string_iter); - if (argc>=4) - { - std::string level_string(argv[3]); - output_string += '_' + slices_string + "_slices_FW" + level_string + 'M' ; - } - else - output_string += '_' + slices_string + "_slices_FWHM" ; - - std::ofstream out(output_string.c_str()); //output file // - if(!out) - { - std::cerr << "Cannot open text file.\n" ; - return EXIT_FAILURE; - } - out << "Slice\t Z\tY\t X\tResZ(mm) ResY(mm) ResX(mm) Value\n"; - for (short counter=0 ; counter!=num_maxima ; ++counter) - { - out << setw(3) << counter+1 << "\t" - << setw(3) << current_iter->voxel_location[1] << "\t" - << setw(3) << current_iter->voxel_location[2] << "\t" - << setw(3) << current_iter->voxel_location[3] << "\t" - << setw(6) << current_iter->resolution[1]<< "\t" - << setw(6) << current_iter->resolution[2]<< "\t" - << setw(6) << current_iter->resolution[3]<< "\t" - << setw(9) << current_iter->voxel_value << "\n" ; - ++current_iter; - } - out.close(); - } - else - for (short counter=0 ; counter!=num_maxima ; ++counter) - { - std::cout << counter+1 << ". max: " << setw(6) << current_iter->voxel_value - << " at: " << setw(3) << current_iter->voxel_location[1] - << " (Z) ," << setw(3) << current_iter->voxel_location[2] - << " (Y) ," << setw(3) << current_iter->voxel_location[3] << " (X) \n" ; - std::cout << " \n The resolution in z axis is " - << setw(6) << (current_iter->resolution[1]) - << ", \n The resolution in y axis is " - << setw(6) << (current_iter->resolution[2]) - << ", \n The resolution in x axis is " - << setw(6) << (current_iter->resolution[3]) - << ", in mm relative to origin. \n \n"; - ++current_iter; - } + std::ofstream out(output_string.c_str()); // output file // + if (!out) { + std::cerr << "Cannot open text file.\n"; + return EXIT_FAILURE; + } + out << "Slice\t Z\tY\t X\tResZ(mm) ResY(mm) ResX(mm) Value\n"; + for (short counter = 0; counter != num_maxima; ++counter) { + out << setw(3) << counter + 1 << "\t" << setw(3) << current_iter->voxel_location[1] << "\t" << setw(3) + << current_iter->voxel_location[2] << "\t" << setw(3) << current_iter->voxel_location[3] << "\t" << setw(6) + << current_iter->resolution[1] << "\t" << setw(6) << current_iter->resolution[2] << "\t" << setw(6) + << current_iter->resolution[3] << "\t" << setw(9) << current_iter->voxel_value << "\n"; + ++current_iter; + } + out.close(); + } else + for (short counter = 0; counter != num_maxima; ++counter) { + std::cout << counter + 1 << ". max: " << setw(6) << current_iter->voxel_value << " at: " << setw(3) + << current_iter->voxel_location[1] << " (Z) ," << setw(3) << current_iter->voxel_location[2] << " (Y) ," + << setw(3) << current_iter->voxel_location[3] << " (X) \n"; + std::cout << " \n The resolution in z axis is " << setw(6) << (current_iter->resolution[1]) + << ", \n The resolution in y axis is " << setw(6) << (current_iter->resolution[2]) + << ", \n The resolution in x axis is " << setw(6) << (current_iter->resolution[3]) + << ", in mm relative to origin. \n \n"; + ++current_iter; + } return EXIT_SUCCESS; -} +} diff --git a/src/utilities/find_maxima_in_image.cxx b/src/utilities/find_maxima_in_image.cxx index 55cf6083c3..c9b9721c4a 100644 --- a/src/utilities/find_maxima_in_image.cxx +++ b/src/utilities/find_maxima_in_image.cxx @@ -48,7 +48,6 @@ #include #include - #ifndef STIR_NO_NAMESPACES using std::endl; using std::cout; @@ -57,100 +56,80 @@ using std::setw; #endif USING_NAMESPACE_STIR - -int main(int argc, char *argv[]) -{ - - if (argc< 2 || argc>5) - { + +int +main(int argc, char* argv[]) { + + if (argc < 2 || argc > 5) { cerr << "Usage:" << argv[0] << " input_image [num_maxima [ half_mask_size_xy [half_mask_size z]] ]\n" - << "\tnum_maxima defaults to 1\n" - << "\thalf_mask_size_xy defaults to 1\n" - << "\thalf_mask_size_z defaults to half_mask_size_xy" <=3 ? atoi(argv[2]) : 1; - const int mask_size_xy = argc>=4 ? atoi(argv[3]) : 1; - const int mask_size_z = argc>=5 ? atoi(argv[4]) : mask_size_xy; + const unsigned num_maxima = argc >= 3 ? atoi(argv[2]) : 1; + const int mask_size_xy = argc >= 4 ? atoi(argv[3]) : 1; + const int mask_size_z = argc >= 5 ? atoi(argv[4]) : mask_size_xy; - cerr << "Finding " << num_maxima << " maxima, each at least \n\t" - << mask_size_xy << " pixels from each other in x,y direction, and\n\t" - << mask_size_z << " pixels from each other in z direction.\n"; + cerr << "Finding " << num_maxima << " maxima, each at least \n\t" << mask_size_xy + << " pixels from each other in x,y direction, and\n\t" << mask_size_z << " pixels from each other in z direction.\n"; - shared_ptr< DiscretisedDensity<3,float> > - input_image_sptr(read_from_file >(argv[1])); - DiscretisedDensity<3,float>& input_image = *input_image_sptr; + shared_ptr> input_image_sptr(read_from_file>(argv[1])); + DiscretisedDensity<3, float>& input_image = *input_image_sptr; - const float mask_value = std::min(input_image.find_min()-100, -1.E20F); + const float mask_value = std::min(input_image.find_min() - 100, -1.E20F); - for (unsigned int maximum_num=0; maximum_num!=num_maxima; ++ maximum_num) + for (unsigned int maximum_num = 0; maximum_num != num_maxima; ++maximum_num) { + const float current_maximum = input_image.find_max(); + int max_k = 0, max_j = 0, max_i = 0; // initialise to avoid compiler warnings + bool found = false; { - const float current_maximum = input_image.find_max(); - int max_k=0, max_j=0,max_i=0; // initialise to avoid compiler warnings - bool found=false; - { - const int min_k_index = input_image.get_min_index(); - const int max_k_index = input_image.get_max_index(); - for ( int k = min_k_index; k<= max_k_index && !found; ++k) - { - const int min_j_index = input_image[k].get_min_index(); - const int max_j_index = input_image[k].get_max_index(); - for ( int j = min_j_index; j<= max_j_index && !found; ++j) - { - const int min_i_index = input_image[k][j].get_min_index(); - const int max_i_index = input_image[k][j].get_max_index(); - for ( int i = min_i_index; i<= max_i_index && !found; ++i) - { - if ( input_image[k][j][i] == current_maximum) - { - max_k = k; - max_j = j; - max_i = i; - cout << "max: " << setw(6) << current_maximum - << " at: " - << setw(3) << max_k - << ',' << setw(3) << max_j - << ',' << setw(3) << max_i; - { - BasicCoordinate<3,float> phys_coord = - input_image. - get_physical_coordinates_for_indices(make_coordinate(max_k, max_j, max_i)); - cout << " which is " - << setw(6) << phys_coord[1] - << ',' << setw(6) << phys_coord[2] - << ',' << setw(6) < phys_coord = + input_image.get_physical_coordinates_for_indices(make_coordinate(max_k, max_j, max_i)); + cout << " which is " << setw(6) << phys_coord[1] << ',' << setw(6) << phys_coord[2] << ',' << setw(6) + << phys_coord[3] << " in mm in physical coordinates"; + } + cout << '\n'; + found = true; + } + } + } + } + if (!found) { + warning("Something strange going on: can't find maximum %g\n", current_maximum); + return EXIT_FAILURE; + } + if (maximum_num + 1 != num_maxima) { + // now mask it out for next run + for (int k = std::max(max_k - mask_size_z, min_k_index); k <= std::min(max_k + mask_size_z, max_k_index); ++k) { + const int min_j_index = input_image[k].get_min_index(); + const int max_j_index = input_image[k].get_max_index(); + for (int j = std::max(max_j - mask_size_xy, min_j_index); j <= std::min(max_j + mask_size_xy, max_j_index); ++j) { + const int min_i_index = input_image[k][j].get_min_index(); + const int max_i_index = input_image[k][j].get_max_index(); + for (int i = std::max(max_i - mask_size_xy, min_i_index); i <= std::min(max_i + mask_size_xy, max_i_index); ++i) + input_image[k][j][i] = mask_value; + } + } } } + } return EXIT_SUCCESS; } - diff --git a/src/utilities/forward_project.cxx b/src/utilities/forward_project.cxx index 35e26a2545..822bb3a61f 100644 --- a/src/utilities/forward_project.cxx +++ b/src/utilities/forward_project.cxx @@ -55,85 +55,72 @@ #include #include -static void print_usage_and_exit() -{ - std::cerr<<"\nUsage:\nforward_project output-filename image_to_forward_project template_proj_data_file [forwardprojector-parfile ]\n"; - std::cerr<<"The default projector uses the ray-tracing matrix.\n\n"; - std::cerr<<"Example parameter file:\n\n" - <<"Forward Projector parameters:=\n" - <<" type := Matrix\n" - <<" Forward projector Using Matrix Parameters :=\n" - <<" Matrix type := Ray Tracing\n" - <<" Ray tracing matrix parameters :=\n" - <<" End Ray tracing matrix parameters :=\n" - <<" End Forward Projector Using Matrix Parameters :=\n" - <<"End:=\n"; +static void +print_usage_and_exit() { + std::cerr << "\nUsage:\nforward_project output-filename image_to_forward_project template_proj_data_file " + "[forwardprojector-parfile ]\n"; + std::cerr << "The default projector uses the ray-tracing matrix.\n\n"; + std::cerr << "Example parameter file:\n\n" + << "Forward Projector parameters:=\n" + << " type := Matrix\n" + << " Forward projector Using Matrix Parameters :=\n" + << " Matrix type := Ray Tracing\n" + << " Ray tracing matrix parameters :=\n" + << " End Ray tracing matrix parameters :=\n" + << " End Forward Projector Using Matrix Parameters :=\n" + << "End:=\n"; exit(EXIT_FAILURE); } - -int -main (int argc, char * argv[]) -{ +int +main(int argc, char* argv[]) { using namespace stir; - if (argc!=4 && argc!=5 ) + if (argc != 4 && argc != 5) print_usage_and_exit(); - + const std::string output_filename = argv[1]; - shared_ptr > - image_density_sptr(read_from_file >(argv[2])); + shared_ptr> image_density_sptr(read_from_file>(argv[2])); - shared_ptr template_proj_data_sptr = - ProjData::read_from_file(argv[3]); + shared_ptr template_proj_data_sptr = ProjData::read_from_file(argv[3]); // create exam_info. Use most things from the image, as often people will // just have a standard template shared_ptr exam_info_sptr(image_density_sptr->get_exam_info().create_shared_clone()); if (image_density_sptr->get_exam_info().imaging_modality.is_unknown() && - template_proj_data_sptr->get_exam_info().imaging_modality.is_known()) - { - exam_info_sptr->imaging_modality = template_proj_data_sptr->get_exam_info().imaging_modality; - } - else if (image_density_sptr->get_exam_info().imaging_modality != - template_proj_data_sptr->get_exam_info().imaging_modality) + template_proj_data_sptr->get_exam_info().imaging_modality.is_known()) { + exam_info_sptr->imaging_modality = template_proj_data_sptr->get_exam_info().imaging_modality; + } else if (image_density_sptr->get_exam_info().imaging_modality != template_proj_data_sptr->get_exam_info().imaging_modality) error("forward_project: Imaging modality should be the same for the image and the projection data"); - if (template_proj_data_sptr->get_exam_info().has_energy_information()) - { - if (image_density_sptr->get_exam_info().has_energy_information()) - warning("Both image and template have energy information. Using the latter."); + if (template_proj_data_sptr->get_exam_info().has_energy_information()) { + if (image_density_sptr->get_exam_info().has_energy_information()) + warning("Both image and template have energy information. Using the latter."); - exam_info_sptr->set_energy_information_from(template_proj_data_sptr->get_exam_info()); - } + exam_info_sptr->set_energy_information_from(template_proj_data_sptr->get_exam_info()); + } shared_ptr forw_projector_sptr; - if (argc>=5) - { - KeyParser parser; - parser.add_start_key("Forward Projector parameters"); - parser.add_parsing_key("type", &forw_projector_sptr); - parser.add_stop_key("END"); - parser.parse(argv[4]); - } - else - { - shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); - forw_projector_sptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); - } - - forw_projector_sptr->set_up(template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(), - image_density_sptr ); - - ProjDataInterfile output_projdata(exam_info_sptr, - template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(), + if (argc >= 5) { + KeyParser parser; + parser.add_start_key("Forward Projector parameters"); + parser.add_parsing_key("type", &forw_projector_sptr); + parser.add_stop_key("END"); + parser.parse(argv[4]); + } else { + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + forw_projector_sptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); + } + + forw_projector_sptr->set_up(template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(), image_density_sptr); + + ProjDataInterfile output_projdata(exam_info_sptr, template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(), output_filename); - + forw_projector_sptr->forward_project(output_projdata, *image_density_sptr); - + return EXIT_SUCCESS; } - diff --git a/src/utilities/generate_image.cxx b/src/utilities/generate_image.cxx index 4b16eaa444..a6e6272630 100644 --- a/src/utilities/generate_image.cxx +++ b/src/utilities/generate_image.cxx @@ -51,7 +51,7 @@ number format := unsigned integer number_of_bytes_per_pixel:=2 ; fix the scale factor to 1 - ; comment out next line to let STIR use the full dynamic + ; comment out next line to let STIR use the full dynamic ; range of the output type scale_to_write_data:= 1 End Interfile Output File Format Parameters:= @@ -75,7 +75,7 @@ ; Shape3D hierarchy for possible shapes and their parameters shape type:= ellipsoidal cylinder Ellipsoidal Cylinder Parameters:= - radius-x (in mm):= 1 + radius-x (in mm):= 1 radius-y (in mm):= 2 length-z (in mm):= 3 origin (in mm):= {z,y,x} @@ -95,7 +95,7 @@ is at the edge of the image, the current mechanism of generating the image might miss the shape entirely. - \warning Does not currently support interactive parsing, so a par file + \warning Does not currently support interactive parsing, so a par file must be given on the command line. \todo Code duplicates things from stir::InterfileHeader. This is bad as it might @@ -116,17 +116,13 @@ START_NAMESPACE_STIR - -class GenerateImage : public KeyParser -{ +class GenerateImage : public KeyParser { public: - - GenerateImage(const char * const par_filename); - + GenerateImage(const char* const par_filename); Succeeded compute(); -private: +private: virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); @@ -138,13 +134,12 @@ class GenerateImage : public KeyParser int patient_orientation_index; int patient_rotation_index; - std::vector > shape_ptrs; + std::vector> shape_ptrs; shared_ptr current_shape_ptr; std::vector values; float current_value; std::string output_filename; - shared_ptr > > - output_file_format_sptr; + shared_ptr>> output_file_format_sptr; void increment_current_shape_num(); @@ -161,86 +156,73 @@ class GenerateImage : public KeyParser double rel_start_time; }; - -void GenerateImage:: -increment_current_shape_num() -{ - if (!is_null_ptr( current_shape_ptr)) - { - shape_ptrs.push_back(current_shape_ptr); - values.push_back(current_value); - current_shape_ptr.reset(); - } +void +GenerateImage::increment_current_shape_num() { + if (!is_null_ptr(current_shape_ptr)) { + shape_ptrs.push_back(current_shape_ptr); + values.push_back(current_value); + current_shape_ptr.reset(); + } } -void -GenerateImage:: -set_defaults() -{ +void +GenerateImage::set_defaults() { exam_info_sptr.reset(new ExamInfo); // need to default to PET for backwards compatibility exam_info_sptr->imaging_modality = ImagingModality::PT; - patient_orientation_index = 3; //unknown - patient_rotation_index = 5; //unknown - output_image_size_x=128; - output_image_size_y=128; - output_image_size_z=1; - output_voxel_size_x=1; - output_voxel_size_y=1; - output_voxel_size_z=1; - num_samples = CartesianCoordinate3D(5,5,5); + patient_orientation_index = 3; // unknown + patient_rotation_index = 5; // unknown + output_image_size_x = 128; + output_image_size_y = 128; + output_image_size_z = 1; + output_voxel_size_x = 1; + output_voxel_size_y = 1; + output_voxel_size_z = 1; + num_samples = CartesianCoordinate3D(5, 5, 5); shape_ptrs.resize(0); values.resize(0); image_duration = -1.0; rel_start_time = 0; output_filename.resize(0); - output_file_format_sptr = - OutputFileFormat >::default_sptr(); + output_file_format_sptr = OutputFileFormat>::default_sptr(); } -void GenerateImage::set_imaging_modality() -{ +void +GenerateImage::set_imaging_modality() { set_variable(); this->exam_info_sptr->imaging_modality = ImagingModality(imaging_modality_as_string); } -void -GenerateImage:: -initialise_keymap() -{ +void +GenerateImage::initialise_keymap() { add_start_key("generate_image Parameters"); // copy of InterfileHeader (TODO) - add_key("imaging modality", - KeyArgument::ASCII, (KeywordProcessor)&GenerateImage::set_imaging_modality, - &imaging_modality_as_string); + add_key("imaging modality", KeyArgument::ASCII, (KeywordProcessor)&GenerateImage::set_imaging_modality, + &imaging_modality_as_string); add_key("originating system", &exam_info_sptr->originating_system); - add_key("patient orientation", - &patient_orientation_index, - &patient_orientation_values); - add_key("patient rotation", - &patient_rotation_index, - &patient_rotation_values); + add_key("patient orientation", &patient_orientation_index, &patient_orientation_values); + add_key("patient rotation", &patient_rotation_index, &patient_rotation_values); patient_orientation_values.push_back("head_in"); patient_orientation_values.push_back("feet_in"); patient_orientation_values.push_back("other"); - patient_orientation_values.push_back("unknown"); //default + patient_orientation_values.push_back("unknown"); // default patient_rotation_values.push_back("supine"); patient_rotation_values.push_back("prone"); patient_rotation_values.push_back("right"); patient_rotation_values.push_back("left"); patient_rotation_values.push_back("other"); - patient_rotation_values.push_back("unknown"); //default - - add_key("output filename",&output_filename); - add_parsing_key("output file format type",&output_file_format_sptr); - add_key("X output image size (in pixels)",&output_image_size_x); - add_key("Y output image size (in pixels)",&output_image_size_y); - add_key("Z output image size (in pixels)",&output_image_size_z); - add_key("X voxel size (in mm)",&output_voxel_size_x); - add_key("Y voxel size (in mm)",&output_voxel_size_y); - add_key("Z voxel size (in mm)",&output_voxel_size_z); - + patient_rotation_values.push_back("unknown"); // default + + add_key("output filename", &output_filename); + add_parsing_key("output file format type", &output_file_format_sptr); + add_key("X output image size (in pixels)", &output_image_size_x); + add_key("Y output image size (in pixels)", &output_image_size_y); + add_key("Z output image size (in pixels)", &output_image_size_z); + add_key("X voxel size (in mm)", &output_voxel_size_x); + add_key("Y voxel size (in mm)", &output_voxel_size_y); + add_key("Z voxel size (in mm)", &output_voxel_size_z); + add_key("Z number of samples to take per voxel", &num_samples.z()); add_key("Y number of samples to take per voxel", &num_samples.y()); add_key("X number of samples to take per voxel", &num_samples.x()); @@ -250,103 +232,82 @@ initialise_keymap() add_parsing_key("shape type", ¤t_shape_ptr); add_key("value", ¤t_value); - add_key("next shape", KeyArgument::NONE, - (KeywordProcessor)&GenerateImage::increment_current_shape_num); + add_key("next shape", KeyArgument::NONE, (KeywordProcessor)&GenerateImage::increment_current_shape_num); add_stop_key("END"); - } - bool -GenerateImage:: -post_processing() -{ +GenerateImage::post_processing() { assert(values.size() == shape_ptrs.size()); - if (patient_orientation_index<0 || patient_rotation_index<0) + if (patient_orientation_index < 0 || patient_rotation_index < 0) return true; // warning: relies on index taking same values as enums in PatientPosition exam_info_sptr->patient_position.set_rotation(static_cast(patient_rotation_index)); exam_info_sptr->patient_position.set_orientation(static_cast(patient_orientation_index)); - if (!is_null_ptr( current_shape_ptr)) - { - shape_ptrs.push_back(current_shape_ptr); - values.push_back(current_value); - } - if (output_filename.size()==0) - { - warning("You have to specify an output_filename\n"); - return true; - } - if (is_null_ptr(output_file_format_sptr)) - { - warning("You have specified an invalid output file format\n"); - return true; - } - if (output_image_size_x<=0) - { - warning("X output_image_size should be strictly positive\n"); - return true; - } - if (output_image_size_y<=0) - { - warning("Y output_image_size should be strictly positive\n"); - return true; - } - if (output_image_size_z<=0) - { - warning("Z output_image_size should be strictly positive\n"); - return true; - } - if (output_voxel_size_x<=0) - { - warning("X output_voxel_size should be strictly positive\n"); - return true; - } - if (output_voxel_size_y<=0) - { - warning("Y output_voxel_size should be strictly positive\n"); - return true; - } - if (output_voxel_size_z<=0) - { - warning("Z output_voxel_size should be strictly positive\n"); - return true; - } - if (num_samples.z()<=0) - { - warning("number of samples to take in z-direction should be strictly positive\n"); - return true; - } - if (num_samples.y()<=0) - { - warning("number of samples to take in y-direction should be strictly positive\n"); - return true; - } - if (num_samples.x()<=0) - { - warning("number of samples to take in x-direction should be strictly positive\n"); - return true; - } + if (!is_null_ptr(current_shape_ptr)) { + shape_ptrs.push_back(current_shape_ptr); + values.push_back(current_value); + } + if (output_filename.size() == 0) { + warning("You have to specify an output_filename\n"); + return true; + } + if (is_null_ptr(output_file_format_sptr)) { + warning("You have specified an invalid output file format\n"); + return true; + } + if (output_image_size_x <= 0) { + warning("X output_image_size should be strictly positive\n"); + return true; + } + if (output_image_size_y <= 0) { + warning("Y output_image_size should be strictly positive\n"); + return true; + } + if (output_image_size_z <= 0) { + warning("Z output_image_size should be strictly positive\n"); + return true; + } + if (output_voxel_size_x <= 0) { + warning("X output_voxel_size should be strictly positive\n"); + return true; + } + if (output_voxel_size_y <= 0) { + warning("Y output_voxel_size should be strictly positive\n"); + return true; + } + if (output_voxel_size_z <= 0) { + warning("Z output_voxel_size should be strictly positive\n"); + return true; + } + if (num_samples.z() <= 0) { + warning("number of samples to take in z-direction should be strictly positive\n"); + return true; + } + if (num_samples.y() <= 0) { + warning("number of samples to take in y-direction should be strictly positive\n"); + return true; + } + if (num_samples.x() <= 0) { + warning("number of samples to take in x-direction should be strictly positive\n"); + return true; + } return false; } //! \brief parses parameters -/*! \warning Currently does not support interactive input, due to +/*! \warning Currently does not support interactive input, due to the use of the 'next shape' keyword. */ -GenerateImage:: -GenerateImage(const char * const par_filename) -{ +GenerateImage::GenerateImage(const char* const par_filename) { set_defaults(); initialise_keymap(); - if (par_filename!=0) - { - if (parse(par_filename) == false) - exit(EXIT_FAILURE); - } - else + if (par_filename != 0) { + if (parse(par_filename) == false) + exit(EXIT_FAILURE); + } else ask_parameters(); #if 0 @@ -358,14 +319,10 @@ GenerateImage(const char * const par_filename) std::cerr << (**iter).parameter_info() << '\n'; } #endif - } - Succeeded -GenerateImage:: -compute() -{ +GenerateImage::compute() { #if 0 shared_ptr > density_ptr( read_from_file >(template_filename)); @@ -377,44 +334,32 @@ compute() #else - if (image_duration>0.0) - { - std::vector start_times(1, rel_start_time); - std::vector durations(1, image_duration); - TimeFrameDefinitions frame_defs(start_times, durations); - exam_info_sptr->set_time_frame_definitions(frame_defs); - } - else - { - warning("image duration not set, so time frame definitions will not be initialised"); - } - VoxelsOnCartesianGrid - current_image(exam_info_sptr, - IndexRange3D(0,output_image_size_z-1, - -(output_image_size_y/2), - -(output_image_size_y/2)+output_image_size_y-1, - -(output_image_size_x/2), - -(output_image_size_x/2)+output_image_size_x-1), - CartesianCoordinate3D(0,0,0), - CartesianCoordinate3D(output_voxel_size_z, - output_voxel_size_y, - output_voxel_size_x)); - shared_ptr > out_density_ptr(current_image.clone()); + if (image_duration > 0.0) { + std::vector start_times(1, rel_start_time); + std::vector durations(1, image_duration); + TimeFrameDefinitions frame_defs(start_times, durations); + exam_info_sptr->set_time_frame_definitions(frame_defs); + } else { + warning("image duration not set, so time frame definitions will not be initialised"); + } + VoxelsOnCartesianGrid current_image( + exam_info_sptr, + IndexRange3D(0, output_image_size_z - 1, -(output_image_size_y / 2), -(output_image_size_y / 2) + output_image_size_y - 1, + -(output_image_size_x / 2), -(output_image_size_x / 2) + output_image_size_x - 1), + CartesianCoordinate3D(0, 0, 0), + CartesianCoordinate3D(output_voxel_size_z, output_voxel_size_y, output_voxel_size_x)); + shared_ptr> out_density_ptr(current_image.clone()); #endif - std::vector::const_iterator value_iter = values.begin(); - for (std::vector >::const_iterator iter = shape_ptrs.begin(); - iter != shape_ptrs.end(); - ++iter, ++value_iter) - { - std::cerr << "Next shape\n"; //(**iter).parameter_info() << '\n'; - current_image.fill(0); - (**iter).construct_volume(current_image, num_samples); - current_image *= *value_iter; - *out_density_ptr += current_image; - } - return - output_file_format_sptr->write_to_file(output_filename, *out_density_ptr); - + std::vector::const_iterator value_iter = values.begin(); + for (std::vector>::const_iterator iter = shape_ptrs.begin(); iter != shape_ptrs.end(); + ++iter, ++value_iter) { + std::cerr << "Next shape\n"; //(**iter).parameter_info() << '\n'; + current_image.fill(0); + (**iter).construct_volume(current_image, num_samples); + current_image *= *value_iter; + *out_density_ptr += current_image; + } + return output_file_format_sptr->write_to_file(output_filename, *out_density_ptr); } END_NAMESPACE_STIR @@ -422,15 +367,15 @@ END_NAMESPACE_STIR /************************ main ************************/ USING_NAMESPACE_STIR -int main(int argc, char * argv[]) -{ - - if ( argc!=2) { +int +main(int argc, char* argv[]) { + + if (argc != 2) { std::cerr << "Usage: " << argv[0] << " par_file\n"; exit(EXIT_FAILURE); } - GenerateImage application(argc==2 ? argv[1] : 0); + GenerateImage application(argc == 2 ? argv[1] : 0); Succeeded success = application.compute(); - return success==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/utilities/get_time_frame_info.cxx b/src/utilities/get_time_frame_info.cxx index bb6fd46037..f64f6fd830 100644 --- a/src/utilities/get_time_frame_info.cxx +++ b/src/utilities/get_time_frame_info.cxx @@ -37,9 +37,10 @@ using std::cout; USING_NAMESPACE_STIR -void print_usage_and_exit(char const * const prog_name) -{ - cerr << "Usage:\n" << prog_name << " PARAMETERS\n" +void +print_usage_and_exit(char const* const prog_name) { + cerr << "Usage:\n" + << prog_name << " PARAMETERS\n" << "where PARAMETERS has two possibilities:\n\n" << "1) print number of time frames\n" << "\t--num-time-frames Frame_def_filename\n\n" @@ -51,14 +52,13 @@ void print_usage_and_exit(char const * const prog_name) << "and similarly for --start-time, --mid-time and --end-time.\n" << "Without these options, both will be printed to stdout, together with some text.\n\n" << "Times are reported in seconds unless the --msecs option is used.\n\n" - << "end_frame_number defaults to start_frame_number to print just a single frame."<< endl; - exit(EXIT_FAILURE); + << "end_frame_number defaults to start_frame_number to print just a single frame." << endl; + exit(EXIT_FAILURE); } int -main(int argc, char* argv[]) -{ - const char * const prog_name = argv[0]; +main(int argc, char* argv[]) { + const char* const prog_name = argv[0]; bool units_secs = true; bool only_duration = false; @@ -67,108 +67,91 @@ main(int argc, char* argv[]) bool only_mid_time = false; bool only_num_time_frames = false; - while (argc>=2 && argv[1][1]=='-') - { - if (strcmp(argv[1], "--num-time-frames")==0) - { - only_num_time_frames = true; - --argc; ++argv; - } - else - { - if (strcmp(argv[1], "--msecs")==0) - { - units_secs=false; - --argc; ++argv; - } - else if (strcmp(argv[1], "--duration")==0 && !only_start_time && !only_end_time && !only_mid_time) - { - only_duration = true; - --argc; ++argv; - } - else if (strcmp(argv[1], "--start-time")==0 && !only_duration && !only_end_time && !only_mid_time) - { - only_start_time = true; - --argc; ++argv; - } - else if (strcmp(argv[1], "--end-time")==0 && !only_duration && !only_start_time && !only_mid_time) - { - only_end_time = true; - --argc; ++argv; - } - else if (strcmp(argv[1], "--mid-time")==0 && !only_duration && !only_start_time && !only_end_time) - { - only_mid_time = true; - --argc; ++argv; - } - else - print_usage_and_exit(prog_name); - } + while (argc >= 2 && argv[1][1] == '-') { + if (strcmp(argv[1], "--num-time-frames") == 0) { + only_num_time_frames = true; + --argc; + ++argv; + } else { + if (strcmp(argv[1], "--msecs") == 0) { + units_secs = false; + --argc; + ++argv; + } else if (strcmp(argv[1], "--duration") == 0 && !only_start_time && !only_end_time && !only_mid_time) { + only_duration = true; + --argc; + ++argv; + } else if (strcmp(argv[1], "--start-time") == 0 && !only_duration && !only_end_time && !only_mid_time) { + only_start_time = true; + --argc; + ++argv; + } else if (strcmp(argv[1], "--end-time") == 0 && !only_duration && !only_start_time && !only_mid_time) { + only_end_time = true; + --argc; + ++argv; + } else if (strcmp(argv[1], "--mid-time") == 0 && !only_duration && !only_start_time && !only_end_time) { + only_mid_time = true; + --argc; + ++argv; + } else + print_usage_and_exit(prog_name); } + } // we need at least one argument: the filename - if(argc <2) + if (argc < 2) print_usage_and_exit(prog_name); const TimeFrameDefinitions time_def(argv[1]); - if (only_num_time_frames) - { - if(argc !=2) - print_usage_and_exit(prog_name); - cout << time_def.get_num_frames() << std::endl; - exit(EXIT_SUCCESS); - } + if (only_num_time_frames) { + if (argc != 2) + print_usage_and_exit(prog_name); + cout << time_def.get_num_frames() << std::endl; + exit(EXIT_SUCCESS); + } // normal case of info for one or more frames - if(argc !=3 && argc!=4) + if (argc != 3 && argc != 4) print_usage_and_exit(prog_name); const unsigned int start_frame_num = atoi(argv[2]); - const unsigned int end_frame_num = - argc>3 ? atoi(argv[3]) : start_frame_num; - - - for (unsigned frame_num = start_frame_num; frame_num<=end_frame_num; ++frame_num) - { - if (frame_num > time_def.get_num_frames() || frame_num<1) - { - /* Note: we intentionally check this in the loop. - This way, we do get output for valid frames. - */ - warning("frame_num should be between 1 and %d\n", - time_def.get_num_frames()); - exit(EXIT_FAILURE); - } - const double start_frame = time_def.get_start_time(frame_num); - const double end_frame = time_def.get_end_time(frame_num); - const double frame_duration = end_frame-start_frame; - const double mid_frame = (start_frame+end_frame)/2; - - // make sure results never get printed as scientific - // because we pass it on to header_doc/edit_ecat_header - // which expects an int - cout.setf(std::ios::fixed, std::ios::floatfield); - - const int units = units_secs ? 1 : 1000; - const std::string units_string = units_secs ? " secs" : " millisecs"; - if (only_duration) - cout << frame_duration*units << endl; - else if (only_start_time) - cout << start_frame*units << endl; - else if (only_end_time) - cout << end_frame*units << endl; - else if (only_end_time) - cout << end_frame*units << endl; - else if (only_mid_time) - cout << mid_frame*units << endl; - else - cout << "Start of frame " << frame_num << " : " << start_frame*units << units_string - << "\nMiddle of frame " << frame_num << " : " << mid_frame*units << units_string - << "\nEnd of frame " << frame_num << " : " << end_frame*units << units_string - << "\nFrame duration " << frame_num << " : " << frame_duration*units << units_string << endl; - - + const unsigned int end_frame_num = argc > 3 ? atoi(argv[3]) : start_frame_num; + + for (unsigned frame_num = start_frame_num; frame_num <= end_frame_num; ++frame_num) { + if (frame_num > time_def.get_num_frames() || frame_num < 1) { + /* Note: we intentionally check this in the loop. + This way, we do get output for valid frames. + */ + warning("frame_num should be between 1 and %d\n", time_def.get_num_frames()); + exit(EXIT_FAILURE); } + const double start_frame = time_def.get_start_time(frame_num); + const double end_frame = time_def.get_end_time(frame_num); + const double frame_duration = end_frame - start_frame; + const double mid_frame = (start_frame + end_frame) / 2; + + // make sure results never get printed as scientific + // because we pass it on to header_doc/edit_ecat_header + // which expects an int + cout.setf(std::ios::fixed, std::ios::floatfield); + + const int units = units_secs ? 1 : 1000; + const std::string units_string = units_secs ? " secs" : " millisecs"; + if (only_duration) + cout << frame_duration * units << endl; + else if (only_start_time) + cout << start_frame * units << endl; + else if (only_end_time) + cout << end_frame * units << endl; + else if (only_end_time) + cout << end_frame * units << endl; + else if (only_mid_time) + cout << mid_frame * units << endl; + else + cout << "Start of frame " << frame_num << " : " << start_frame * units << units_string << "\nMiddle of frame " + << frame_num << " : " << mid_frame * units << units_string << "\nEnd of frame " << frame_num << " : " + << end_frame * units << units_string << "\nFrame duration " << frame_num << " : " << frame_duration * units + << units_string << endl; + } return EXIT_SUCCESS; } - diff --git a/src/utilities/invert_axis.cxx b/src/utilities/invert_axis.cxx old mode 100755 new mode 100644 index 67f50038f0..cb070da953 --- a/src/utilities/invert_axis.cxx +++ b/src/utilities/invert_axis.cxx @@ -28,34 +28,31 @@ USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if(argc!=4) { - std::cerr << "Usage: " << argv[0] - << " \n" +int +main(int argc, char** argv) { + if (argc != 4) { + std::cerr << "Usage: " << argv[0] << " \n" << " has to be x, y, z\n" << "\nWARNING: this will reorder the voxel values without adjusting the geometric information\n"; exit(EXIT_FAILURE); } InvertAxis invert; - char const * const axis_name = argv[1]; - char const * const output_filename_prefix = argv[2]; - char const * const input_filename= argv[3]; + char const* const axis_name = argv[1]; + char const* const output_filename_prefix = argv[2]; + char const* const input_filename = argv[3]; std::string name(axis_name); - // const int num_planes = atoi(argv[3]); -std::cout<<" the axis to invert is "<< name< > image_aptr(DiscretisedDensity<3,float>::read_from_file(input_filename)); -const std::auto_ptr > out_image_aptr(image_aptr->clone()); + // const int num_planes = atoi(argv[3]); + std::cout << " the axis to invert is " << name << std::endl; + const std::auto_ptr> image_aptr(DiscretisedDensity<3, float>::read_from_file(input_filename)); + const std::auto_ptr> out_image_aptr(image_aptr->clone()); -DiscretisedDensity<3,float>& image = *image_aptr; -DiscretisedDensity<3,float>& out_image = *out_image_aptr; + DiscretisedDensity<3, float>& image = *image_aptr; + DiscretisedDensity<3, float>& out_image = *out_image_aptr; - invert.invert_axis(out_image, - image, - name); + invert.invert_axis(out_image, image, name); - const Succeeded res = OutputFileFormat >::default_sptr()-> - write_to_file(output_filename_prefix, out_image); + const Succeeded res = + OutputFileFormat>::default_sptr()->write_to_file(output_filename_prefix, out_image); - return res==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + return res == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/utilities/list_ROI_values.cxx b/src/utilities/list_ROI_values.cxx index d9c9e62134..b9453e7e96 100644 --- a/src/utilities/list_ROI_values.cxx +++ b/src/utilities/list_ROI_values.cxx @@ -67,66 +67,57 @@ using std::endl; using std::ofstream; #endif - START_NAMESPACE_STIR -//TODO repetition of postfilter.cxx to be able to use its .par file -class ROIValuesParameters : public KeyParser -{ +// TODO repetition of postfilter.cxx to be able to use its .par file +class ROIValuesParameters : public KeyParser { public: ROIValuesParameters(); virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - std::vector > shape_ptrs; + std::vector> shape_ptrs; std::vector shape_names; CartesianCoordinate3D num_samples; - shared_ptr > > filter_ptr; + shared_ptr>> filter_ptr; + private: shared_ptr current_shape_sptr; std::string current_shape_name; void increment_current_shape_num(); }; -ROIValuesParameters::ROIValuesParameters() -{ +ROIValuesParameters::ROIValuesParameters() { set_defaults(); initialise_keymap(); } -void ROIValuesParameters:: -increment_current_shape_num() -{ - if (!is_null_ptr( current_shape_sptr)) - { - shape_ptrs.push_back(current_shape_sptr); - shape_names.push_back(current_shape_name); - current_shape_sptr.reset(); - current_shape_name = ""; - } +void +ROIValuesParameters::increment_current_shape_num() { + if (!is_null_ptr(current_shape_sptr)) { + shape_ptrs.push_back(current_shape_sptr); + shape_names.push_back(current_shape_name); + current_shape_sptr.reset(); + current_shape_name = ""; + } } void -ROIValuesParameters:: -set_defaults() -{ +ROIValuesParameters::set_defaults() { shape_ptrs.resize(0); shape_names.resize(0); filter_ptr.reset(); current_shape_sptr.reset(); current_shape_name = ""; - num_samples = CartesianCoordinate3D(1,1,1); + num_samples = CartesianCoordinate3D(1, 1, 1); } void -ROIValuesParameters:: -initialise_keymap() -{ +ROIValuesParameters::initialise_keymap() { add_start_key("ROIValues Parameters"); add_key("ROI name", ¤t_shape_name); add_parsing_key("ROI Shape type", ¤t_shape_sptr); - add_key("next shape", KeyArgument::NONE, - (KeywordProcessor)&ROIValuesParameters::increment_current_shape_num); + add_key("next shape", KeyArgument::NONE, (KeywordProcessor)&ROIValuesParameters::increment_current_shape_num); add_key("number of samples to take for ROI template-z", &num_samples.z()); add_key("number of samples to take for ROI template-y", &num_samples.y()); add_key("number of samples to take for ROI template-x", &num_samples.x()); @@ -135,30 +126,24 @@ initialise_keymap() } bool -ROIValuesParameters:: -post_processing() -{ +ROIValuesParameters::post_processing() { assert(shape_names.size() == shape_ptrs.size()); - if (!is_null_ptr( current_shape_sptr)) - { - increment_current_shape_num(); - } - if (num_samples.z()<=0) - { - warning("number of samples to take in z-direction should be strictly positive\n"); - return true; - } - if (num_samples.y()<=0) - { - warning("number of samples to take in y-direction should be strictly positive\n"); - return true; - } - if (num_samples.x()<=0) - { - warning("number of samples to take in x-direction should be strictly positive\n"); - return true; - } + if (!is_null_ptr(current_shape_sptr)) { + increment_current_shape_num(); + } + if (num_samples.z() <= 0) { + warning("number of samples to take in z-direction should be strictly positive\n"); + return true; + } + if (num_samples.y() <= 0) { + warning("number of samples to take in y-direction should be strictly positive\n"); + return true; + } + if (num_samples.x() <= 0) { + warning("number of samples to take in x-direction should be strictly positive\n"); + return true; + } return false; } @@ -167,143 +152,123 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR int -main(int argc, char *argv[]) -{ - bool do_CV=false; - bool do_V=false; - bool do_filename=false; - bool do_max=false; - bool do_min=false; - - const char * const progname = argv[0]; - -while (argc>1 && strncmp(argv[1],"--",2)==0) -{ - if(strcmp(argv[1],"--min")==0) - do_min=true; - else if(strcmp(argv[1],"--max")==0) - do_max=true; - else if(strcmp(argv[1],"--list-filename")==0) - do_filename=true; - else if(strcmp(argv[1],"--CV")==0) - do_CV=true; - else if(strcmp(argv[1],"--V")==0) - do_V=true; - else - error(boost::format("Unknown option %s") % argv[1]); - --argc; ++argv; -} - +main(int argc, char* argv[]) { + bool do_CV = false; + bool do_V = false; + bool do_filename = false; + bool do_max = false; + bool do_min = false; + + const char* const progname = argv[0]; + + while (argc > 1 && strncmp(argv[1], "--", 2) == 0) { + if (strcmp(argv[1], "--min") == 0) + do_min = true; + else if (strcmp(argv[1], "--max") == 0) + do_max = true; + else if (strcmp(argv[1], "--list-filename") == 0) + do_filename = true; + else if (strcmp(argv[1], "--CV") == 0) + do_CV = true; + else if (strcmp(argv[1], "--V") == 0) + do_V = true; + else + error(boost::format("Unknown option %s") % argv[1]); + --argc; + ++argv; + } - if(argc!=6 && argc!=5 && argc!=4 && argc!=3) - { - cerr<<"\nUsage: " << progname << " \\\n" - << "\t[--CV] [--V] [--list-filename] [--max] [--min] output_filename data_filename [ ROI_filename.par [min_plane_num max_plane_num]]\n"; + if (argc != 6 && argc != 5 && argc != 4 && argc != 3) { + cerr << "\nUsage: " << progname << " \\\n" + << "\t[--CV] [--V] [--list-filename] [--max] [--min] output_filename data_filename [ ROI_filename.par [min_plane_num " + "max_plane_num]]\n"; cerr << "Normally, only mean and stddev are listed.\n" - << "Use the option --CV to output the Coefficient of Variation as well.\n" - << "Use the option --V to output the Total Volume, as well.\n" - << "Use the option --list-filename to output the filename as well.\n" - << "Use the option --max to output the max value as well.\n" - << "Use the option --min to output the min as well.\n";; + << "Use the option --CV to output the Coefficient of Variation as well.\n" + << "Use the option --V to output the Total Volume, as well.\n" + << "Use the option --list-filename to output the filename as well.\n" + << "Use the option --max to output the max value as well.\n" + << "Use the option --min to output the min as well.\n"; + ; cerr << "If [min_plane_num] is set to 0 and no [max_plane_num given] then sum of the plane values will be listed.\n"; cerr << "When ROI_filename.par is not given, the user will be asked for the parameters.\n" - "Use this to see what a .par file should look like.\n."< > - image_ptr(read_from_file >(input_file)); + shared_ptr> image_ptr(read_from_file>(input_file)); ROIValuesParameters parameters; - if (argc<4) + if (argc < 4) parameters.ask_parameters(); - else - { - if (parameters.parse(argv[3]) == false) - exit(EXIT_FAILURE); - } + else { + if (parameters.parse(argv[3]) == false) + exit(EXIT_FAILURE); + } cerr << "Parameters used (aside from names and ROIs):\n\n" << parameters.parameter_info() << endl; + const int min_plane_number = argc == 6 ? atoi(argv[4]) - 1 : image_ptr->get_min_index(); + const int max_plane_number = argc == 6 ? atoi(argv[5]) - 1 : image_ptr->get_max_index(); - const int min_plane_number = - argc==6 ? atoi(argv[4])-1 : image_ptr->get_min_index(); - const int max_plane_number = - argc==6 ? atoi(argv[5])-1 : image_ptr->get_max_index(); - - const bool by_plane=argc==5 ? (atoi(argv[4])!=0):true ; + const bool by_plane = argc == 5 ? (atoi(argv[4]) != 0) : true; if (!is_null_ptr(parameters.filter_ptr)) parameters.filter_ptr->apply(*image_ptr); -if (do_filename) - out << std::setw(15) << "ImageName"; -else - out << input_file << '\n'; + if (do_filename) + out << std::setw(15) << "ImageName"; + else + out << input_file << '\n'; out << std::setw(15) << "ROI"; - if(by_plane) - out << std::setw(10) << "Plane_num" ; - out << std::setw(15) << "Mean " - << std::setw(15) << "Stddev"; - if(do_max) - out << std::setw(15) << "Max "; - if(do_min) - out << std::setw(15) << "Min "; - if (do_CV) - out << std::setw(15) << "CV"; - if (do_V) - out << std::setw(15) << "Volume"; - out <<'\n'; + if (by_plane) + out << std::setw(10) << "Plane_num"; + out << std::setw(15) << "Mean " << std::setw(15) << "Stddev"; + if (do_max) + out << std::setw(15) << "Max "; + if (do_min) + out << std::setw(15) << "Min "; + if (do_CV) + out << std::setw(15) << "CV"; + if (do_V) + out << std::setw(15) << "Volume"; + out << '\n'; { - std::vector >::const_iterator current_shape_iter = - parameters.shape_ptrs.begin(); - std::vector::const_iterator current_name_iter = - parameters.shape_names.begin(); - for (; - current_shape_iter != parameters.shape_ptrs.end(); - ++current_shape_iter, ++current_name_iter) - { - if(by_plane) - { - VectorWithOffset values; - compute_ROI_values_per_plane(values, *image_ptr, **current_shape_iter, parameters.num_samples); - - for (int i=min_plane_number;i<=max_plane_number;i++) - { - if (do_filename) - out << std::setw(15) <>::const_iterator current_shape_iter = parameters.shape_ptrs.begin(); + std::vector::const_iterator current_name_iter = parameters.shape_names.begin(); + for (; current_shape_iter != parameters.shape_ptrs.end(); ++current_shape_iter, ++current_name_iter) { + if (by_plane) { + VectorWithOffset values; + compute_ROI_values_per_plane(values, *image_ptr, **current_shape_iter, parameters.num_samples); + + for (int i = min_plane_number; i <= max_plane_number; i++) { + if (do_filename) + out << std::setw(15) << input_file; + out << std::setw(15) << *current_name_iter << std::setw(10) << i + 1 << std::setw(15) << values[i].get_mean() + << std::setw(15) << values[i].get_stddev(); + if (do_max) + out << std::setw(15) << values[i].get_max(); + if (do_min) + out << std::setw(15) << values[i].get_min(); + if (do_CV) + out << std::setw(15) << values[i].get_CV(); + if (do_V) + out << std::setw(15) << values[i].get_roi_volume(); + out << '\n'; + } } - } - if(!by_plane) - { + if (!by_plane) { ROIValues values; - values=compute_total_ROI_values(*image_ptr, **current_shape_iter, parameters.num_samples); + values = compute_total_ROI_values(*image_ptr, **current_shape_iter, parameters.num_samples); if (do_filename) - out << std::setw(15) <::const_iterator iter = values.begin(); @@ -322,7 +287,7 @@ else std::cout << iter->report(); } #endif - } + } } return EXIT_SUCCESS; diff --git a/src/utilities/list_detector_and_bin_info.cxx b/src/utilities/list_detector_and_bin_info.cxx index a79ab3e032..c95c0fef6b 100644 --- a/src/utilities/list_detector_and_bin_info.cxx +++ b/src/utilities/list_detector_and_bin_info.cxx @@ -32,7 +32,7 @@ This is really only useful for developers who need to get their head round the STIR conventions. - Currently bin info is listed for non-arccorrected projection data without any + Currently bin info is listed for non-arccorrected projection data without any compression. \author Kris Thielemans @@ -44,38 +44,28 @@ #include "stir/Bin.h" #include "stir/Scanner.h" #include "stir/stream.h" -#include +#include USING_NAMESPACE_STIR -int main(int argc, char *argv[]) -{ - - if(argc!=6) - { - std::cerr<<"Usage: " << argv[0] << " scanner_name crystal1 crystal2 ring1 ring2\n"; - std::cerr<<"\nLists detection and bin info for non-arccorrected projection data without any compression.\n"; - return EXIT_FAILURE; +int +main(int argc, char* argv[]) { + if (argc != 6) { + std::cerr << "Usage: " << argv[0] << " scanner_name crystal1 crystal2 ring1 ring2\n"; + std::cerr << "\nLists detection and bin info for non-arccorrected projection data without any compression.\n"; + return EXIT_FAILURE; } shared_ptr scanner_sptr(Scanner::get_scanner_from_name(argv[1])); - if (scanner_sptr->get_type() == Scanner::Unknown_scanner) - { - std::cerr << "I did not recognise the scanner\n"; - return (EXIT_FAILURE); - } - - shared_ptr proj_data_info_sptr - (dynamic_cast - ( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - 1, scanner_sptr->get_num_rings()-1, - scanner_sptr->get_num_detectors_per_ring()/2, - scanner_sptr->get_default_num_arccorrected_bins(), - false) - )); - + if (scanner_sptr->get_type() == Scanner::Unknown_scanner) { + std::cerr << "I did not recognise the scanner\n"; + return (EXIT_FAILURE); + } + shared_ptr proj_data_info_sptr(dynamic_cast( + ProjDataInfo::ProjDataInfoCTI(scanner_sptr, 1, scanner_sptr->get_num_rings() - 1, + scanner_sptr->get_num_detectors_per_ring() / 2, + scanner_sptr->get_default_num_arccorrected_bins(), false))); { using std::cout; @@ -89,35 +79,26 @@ int main(int argc, char *argv[]) DetectionPositionPair<> det_pos; LORInAxialAndNoArcCorrSinogramCoordinates lor; - proj_data_info_sptr->get_bin_for_det_pair (bin, - det_num_a, ring_a, det_num_b, ring_b); - cout << "bin: (segment " << bin.segment_num() << ", axial pos " << bin.axial_pos_num() - << ", view = " << bin.view_num() + proj_data_info_sptr->get_bin_for_det_pair(bin, det_num_a, ring_a, det_num_b, ring_b); + cout << "bin: (segment " << bin.segment_num() << ", axial pos " << bin.axial_pos_num() << ", view = " << bin.view_num() << ", tangential_pos_num = " << bin.tangential_pos_num() << ")\n"; - cout << "bin coordinates: (tantheta: " << proj_data_info_sptr->get_tantheta(bin) - << ", m: " << proj_data_info_sptr->get_m(bin) - << ", phi: " << proj_data_info_sptr->get_phi(bin) - << ", s: " << proj_data_info_sptr->get_s(bin) - << ")\n"; + cout << "bin coordinates: (tantheta: " << proj_data_info_sptr->get_tantheta(bin) << ", m: " << proj_data_info_sptr->get_m(bin) + << ", phi: " << proj_data_info_sptr->get_phi(bin) << ", s: " << proj_data_info_sptr->get_s(bin) << ")\n"; proj_data_info_sptr->get_LOR(lor, bin); - cout << "LOR cylindrical: (z1: " << lor.z1() << ", z2: " << lor.z2() - << ", phi: " << lor.phi() << ", beta: " << lor.beta() << " (= s: " << lor.s() << ")" - << ")\n"; + cout << "LOR cylindrical: (z1: " << lor.z1() << ", z2: " << lor.z2() << ", phi: " << lor.phi() << ", beta: " << lor.beta() + << " (= s: " << lor.s() << ")" + << ")\n"; LORAs2Points lor_points; lor.get_intersections_with_cylinder(lor_points, scanner_sptr->get_effective_ring_radius()); - cout << "Detection position Cartesian: " << lor_points.p1() << lor_points.p2() <<'\n'; + cout << "Detection position Cartesian: " << lor_points.p1() << lor_points.p2() << '\n'; proj_data_info_sptr->get_det_pos_pair_for_bin(det_pos, bin); cout << "Detection position index " - <<"(c:" << det_pos.pos1().tangential_coord() - << ",r:" << det_pos.pos1().axial_coord() - << ",l:" << det_pos.pos1().radial_coord() - << ")-" - << "(c:" << det_pos.pos2().tangential_coord() - << ",r:" << det_pos.pos2().axial_coord() - << ",l:" << det_pos.pos2().radial_coord() - << ")"; + << "(c:" << det_pos.pos1().tangential_coord() << ",r:" << det_pos.pos1().axial_coord() + << ",l:" << det_pos.pos1().radial_coord() << ")-" + << "(c:" << det_pos.pos2().tangential_coord() << ",r:" << det_pos.pos2().axial_coord() + << ",l:" << det_pos.pos2().radial_coord() << ")"; #if 0 { diff --git a/src/utilities/list_image_info.cxx b/src/utilities/list_image_info.cxx index bf9d3fce25..e9fac87107 100644 --- a/src/utilities/list_image_info.cxx +++ b/src/utilities/list_image_info.cxx @@ -19,9 +19,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities - + \brief This program lists basic image info. It works for dynamic images. Exam info and numerical info can be listed, depending on command line options. Run the utility to get a usage message. @@ -42,18 +42,18 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit(const std::string& program_name) -{ - std::cerr<<"Usage: " << program_name << " [--all | --min | --max | --sum | --exam | --per-volume] image_file\n" - <<"\nAdd one or more options to print the exam/geometric/min/max/sum information.\n" - <<"\nIf no option is specified, geometric/min/max/sum info is printed." - <<"For dynamic images, overall min/max/sum are printed, unless the --per-volume option is specified.\n"; +static void +print_usage_and_exit(const std::string& program_name) { + std::cerr << "Usage: " << program_name << " [--all | --min | --max | --sum | --exam | --per-volume] image_file\n" + << "\nAdd one or more options to print the exam/geometric/min/max/sum information.\n" + << "\nIf no option is specified, geometric/min/max/sum info is printed." + << "For dynamic images, overall min/max/sum are printed, unless the --per-volume option is specified.\n"; exit(EXIT_FAILURE); } -int main(int argc, char *argv[]) -{ - const char * const program_name = argv[0]; +int +main(int argc, char* argv[]) { + const char* const program_name = argv[0]; // skip program name --argc; ++argv; @@ -68,57 +68,47 @@ int main(int argc, char *argv[]) bool no_options = true; // need this for default behaviour // first process command line options - while (argc>0 && argv[0][0]=='-' && argc>=2) - { - no_options=false; - if (strcmp(argv[0], "--all")==0) - { - print_min = print_max = print_sum = print_geom = print_exam = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--per-volume")==0) - { - print_per_volume = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--max")==0) - { - print_max = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--min")==0) - { - print_min = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--sum")==0) - { - print_sum = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--geom")==0) - { - print_geom = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--exam")==0) - { - print_exam = true; - --argc; ++argv; - } - else - print_usage_and_exit(program_name); - } - if (no_options) - { - print_geom = true; - print_min = true; + while (argc > 0 && argv[0][0] == '-' && argc >= 2) { + no_options = false; + if (strcmp(argv[0], "--all") == 0) { + print_min = print_max = print_sum = print_geom = print_exam = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--per-volume") == 0) { + print_per_volume = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--max") == 0) { print_max = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--min") == 0) { + print_min = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--sum") == 0) { print_sum = true; - } + --argc; + ++argv; + } else if (strcmp(argv[0], "--geom") == 0) { + print_geom = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--exam") == 0) { + print_exam = true; + --argc; + ++argv; + } else + print_usage_and_exit(program_name); + } + if (no_options) { + print_geom = true; + print_min = true; + print_max = true; + print_sum = true; + } - if(argc!=1) - { + if (argc != 1) { print_usage_and_exit(program_name); } @@ -129,55 +119,46 @@ int main(int argc, char *argv[]) if (print_exam) std::cout << image_aptr->get_exam_info_sptr()->parameter_info(); - if (print_geom) - { - BasicCoordinate<3,int> min_indices, max_indices; - auto vox = dynamic_cast &>( image_aptr->get_density(1)); - if (!vox.get_regular_range(min_indices, max_indices)) - error("Non-regular range of coordinates. That's strange."); - - BasicCoordinate<3,float> edge_min_indices(min_indices), edge_max_indices(max_indices); - edge_min_indices-= 0.5F; - edge_max_indices+= 0.5F; - - std::cout << "\nOrigin in mm {z,y,x} :" << vox.get_origin() - << "\nVoxel-size in mm {z,y,x}:" << vox.get_voxel_size() - << "\nMin_indices {z,y,x} :" << min_indices - << "\nMax_indices {z,y,x} :" << max_indices - << "\nNumber of voxels {z,y,x}:" << max_indices - min_indices + 1 - << "\nPhysical coordinate of first index in mm {z,y,x} :" - << vox.get_physical_coordinates_for_indices(min_indices) - << "\nPhysical coordinate of last index in mm {z,y,x} :" - << vox.get_physical_coordinates_for_indices(max_indices) - << "\nPhysical coordinate of first edge in mm {z,y,x} :" - << vox.get_physical_coordinates_for_indices(edge_min_indices) - << "\nPhysical coordinate of last edge in mm {z,y,x} :" - << vox.get_physical_coordinates_for_indices(edge_max_indices); - } + if (print_geom) { + BasicCoordinate<3, int> min_indices, max_indices; + auto vox = dynamic_cast&>(image_aptr->get_density(1)); + if (!vox.get_regular_range(min_indices, max_indices)) + error("Non-regular range of coordinates. That's strange."); + + BasicCoordinate<3, float> edge_min_indices(min_indices), edge_max_indices(max_indices); + edge_min_indices -= 0.5F; + edge_max_indices += 0.5F; + + std::cout << "\nOrigin in mm {z,y,x} :" << vox.get_origin() << "\nVoxel-size in mm {z,y,x}:" << vox.get_voxel_size() + << "\nMin_indices {z,y,x} :" << min_indices << "\nMax_indices {z,y,x} :" << max_indices + << "\nNumber of voxels {z,y,x}:" << max_indices - min_indices + 1 + << "\nPhysical coordinate of first index in mm {z,y,x} :" << vox.get_physical_coordinates_for_indices(min_indices) + << "\nPhysical coordinate of last index in mm {z,y,x} :" << vox.get_physical_coordinates_for_indices(max_indices) + << "\nPhysical coordinate of first edge in mm {z,y,x} :" + << vox.get_physical_coordinates_for_indices(edge_min_indices) + << "\nPhysical coordinate of last edge in mm {z,y,x} :" + << vox.get_physical_coordinates_for_indices(edge_max_indices); + } - if (print_per_volume) - { - for (unsigned vol = 1U; vol <= image_aptr->get_num_time_frames(); ++vol) - { - auto& volume = image_aptr->get_density(vol); - if (print_min) - std::cout << "\nImage " << vol << " min: " << *std::min_element(volume.begin_all_const(), volume.end_all_const()); - if (print_max) - std::cout << "\nImage " << vol << " max: " << *std::max_element(volume.begin_all_const(), volume.end_all_const()); - if (print_sum) - std::cout<< "\nImage " << vol << " sum: " << std::accumulate(volume.begin_all_const(), volume.end_all_const(), 0.F); - std::cout << std::endl; - } - } - else - { + if (print_per_volume) { + for (unsigned vol = 1U; vol <= image_aptr->get_num_time_frames(); ++vol) { + auto& volume = image_aptr->get_density(vol); if (print_min) - std::cout << "\nImage min: " << *std::min_element(image_aptr->begin_all_const(), image_aptr->end_all_const()); + std::cout << "\nImage " << vol << " min: " << *std::min_element(volume.begin_all_const(), volume.end_all_const()); if (print_max) - std::cout << "\nImage max: " << *std::max_element(image_aptr->begin_all_const(), image_aptr->end_all_const()); + std::cout << "\nImage " << vol << " max: " << *std::max_element(volume.begin_all_const(), volume.end_all_const()); if (print_sum) - std::cout<< "\nImage sum: " << std::accumulate(image_aptr->begin_all_const(), image_aptr->end_all_const(), 0.F); + std::cout << "\nImage " << vol << " sum: " << std::accumulate(volume.begin_all_const(), volume.end_all_const(), 0.F); std::cout << std::endl; } + } else { + if (print_min) + std::cout << "\nImage min: " << *std::min_element(image_aptr->begin_all_const(), image_aptr->end_all_const()); + if (print_max) + std::cout << "\nImage max: " << *std::max_element(image_aptr->begin_all_const(), image_aptr->end_all_const()); + if (print_sum) + std::cout << "\nImage sum: " << std::accumulate(image_aptr->begin_all_const(), image_aptr->end_all_const(), 0.F); + std::cout << std::endl; + } return EXIT_SUCCESS; } diff --git a/src/utilities/list_image_values.cxx b/src/utilities/list_image_values.cxx index 22f089e6b1..5eb029c5df 100644 --- a/src/utilities/list_image_values.cxx +++ b/src/utilities/list_image_values.cxx @@ -40,100 +40,86 @@ #include #include - - USING_NAMESPACE_STIR -const char * prog_name; +const char* prog_name; -void print_usage_and_exit() -{ - std::cerr << "Usage:\n" << prog_name << " \\\n" +void +print_usage_and_exit() { + std::cerr << "Usage:\n" + << prog_name << " \\\n" << " [ --LPS-output] [--csv] [--no-title-row] \\\n" << " output_profile_name input_image min_plane max_plane min_col max_col min_row max_row\n" << "Indices need to be in the STIR convention (plane starts from 0, col,row are centred around 0)\n" << "Writes 4 columns to file, normally \"plane row column value\", unless --LPS-output is on,\n" << " in which case it writes \"L P S value\"\n" << "Output is separated by spaces, unless --csv is on, in which case commas are used.\n"; - + exit(EXIT_FAILURE); } -int main(int argc, const char *argv[]) -{ +int +main(int argc, const char* argv[]) { bool print_LPS = false; bool print_csv = false; bool print_first_line = true; prog_name = argv[0]; - while (argc>1 && (strncmp(argv[1],"--",2)==0)) - { - if (strcmp(argv[1],"--LPS-output")==0) - print_LPS=true; - else if ((strcmp(argv[1],"--csv")==0) || (strcmp(argv[1],"--CSV")==0)) - print_csv=true; - else if (strcmp(argv[1],"--no-title-row")==0) - print_first_line = false; - else - print_usage_and_exit(); - ++argv; --argc; - } - - if (argc!= 9) + while (argc > 1 && (strncmp(argv[1], "--", 2) == 0)) { + if (strcmp(argv[1], "--LPS-output") == 0) + print_LPS = true; + else if ((strcmp(argv[1], "--csv") == 0) || (strcmp(argv[1], "--CSV") == 0)) + print_csv = true; + else if (strcmp(argv[1], "--no-title-row") == 0) + print_first_line = false; + else + print_usage_and_exit(); + ++argv; + --argc; + } + + if (argc != 9) print_usage_and_exit(); - const char * const output_filename = argv[1]; - const char * const input_filename = argv[2]; + const char* const output_filename = argv[1]; + const char* const input_filename = argv[2]; + + shared_ptr> input_image_sptr(read_from_file>(input_filename)); + const DiscretisedDensity<3, float>& input_image = *input_image_sptr; - - shared_ptr > - input_image_sptr(read_from_file >(input_filename)); - const DiscretisedDensity<3,float>& input_image = - *input_image_sptr; - const int min_plane_num = atoi(argv[3]); - const int max_plane_num = atoi(argv[4]); + const int max_plane_num = atoi(argv[4]); const int min_column_num = atoi(argv[5]); - const int max_column_num = atoi(argv[6]); - const int min_row_num = atoi(argv[7]); - const int max_row_num = atoi(argv[8]); - - std::ofstream profile_file(output_filename); + const int max_column_num = atoi(argv[6]); + const int min_row_num = atoi(argv[7]); + const int max_row_num = atoi(argv[8]); + + std::ofstream profile_file(output_filename); using std::setw; - const char separator = print_csv ? ',' : ' ' ; - - - if (print_first_line) - { - if (print_LPS) - profile_file << setw(8) << "L" << separator << setw(8) << "P" - << separator << setw(8) << "S" << separator << setw(10) << "value" <<'\n'; - else - profile_file << setw(8) << "plane" << separator << setw(8) << "row" - << separator << setw(8) << "column" << separator << setw(10) << "value" <<'\n'; - } - - for (int plane = min_plane_num;plane <=max_plane_num;plane++) - for (int row = min_row_num;row <=max_row_num;row++) - for (int column = min_column_num;column<=max_column_num;column++) - { - const BasicCoordinate<3,int> index = make_coordinate(plane, row, column); - if (print_LPS) - { - const CartesianCoordinate3D LPS = - input_image.get_LPS_coordinates_for_indices(index); - profile_file << setw(8) << LPS[3] << separator << setw(8) << LPS[2] - << separator << setw(8) << LPS[1]; - } - else - { - profile_file << setw(8) << plane << separator << setw(8) << row - << separator << setw(8) << column; - } + const char separator = print_csv ? ',' : ' '; + + if (print_first_line) { + if (print_LPS) + profile_file << setw(8) << "L" << separator << setw(8) << "P" << separator << setw(8) << "S" << separator << setw(10) + << "value" << '\n'; + else + profile_file << setw(8) << "plane" << separator << setw(8) << "row" << separator << setw(8) << "column" << separator + << setw(10) << "value" << '\n'; + } + + for (int plane = min_plane_num; plane <= max_plane_num; plane++) + for (int row = min_row_num; row <= max_row_num; row++) + for (int column = min_column_num; column <= max_column_num; column++) { + const BasicCoordinate<3, int> index = make_coordinate(plane, row, column); + if (print_LPS) { + const CartesianCoordinate3D LPS = input_image.get_LPS_coordinates_for_indices(index); + profile_file << setw(8) << LPS[3] << separator << setw(8) << LPS[2] << separator << setw(8) << LPS[1]; + } else { + profile_file << setw(8) << plane << separator << setw(8) << row << separator << setw(8) << column; + } profile_file << separator << setw(10) << input_image.at(index) << '\n'; } - + return EXIT_SUCCESS; } - diff --git a/src/utilities/list_projdata_info.cxx b/src/utilities/list_projdata_info.cxx index 2b55968974..9dd5b4c199 100644 --- a/src/utilities/list_projdata_info.cxx +++ b/src/utilities/list_projdata_info.cxx @@ -1,7 +1,9 @@ /* Copyright (C) 2002 - 2005-06-09, Hammersmith Imanet Ltd Copyright (C) 2011-07-01 - 2012, Kris Thielemans - Copyright (C) 2013, 2020, University College London + Copyright (C) 2013, 2020 University College London + Copyright (C) 2016, University of Hull + This file is part of STIR. This file is free software; you can redistribute it and/or modify @@ -30,6 +32,7 @@ Add one or more options to print the exam/geometric/min/max/sum information. If no option is specified, geometric info is printed. + \author Nikos Efthimiou \author Kris Thielemans */ @@ -38,23 +41,23 @@ #include "stir/ProjDataInfo.h" #include "stir/SegmentByView.h" #include "stir/is_null_ptr.h" -#include +#include #include #include USING_NAMESPACE_STIR -void print_usage_and_exit(const std::string& program_name) -{ - std::cerr<<"Usage: " << program_name << " [--all | --min | --max | --sum | --geom | --exam] projdata_file\n" - <<"\nAdd one or more options to print the exam/geometric/min/max/sum information.\n" - <<"\nIf no option is specified, geometric info is printed.\n"; +void +print_usage_and_exit(const std::string& program_name) { + std::cerr << "Usage: " << program_name << " [--all | --min | --max | --sum | --geom | --exam] projdata_file\n" + << "\nAdd one or more options to print the exam/geometric/min/max/sum information.\n" + << "\nIf no option is specified, geometric info is printed.\n"; exit(EXIT_FAILURE); } -int main(int argc, char *argv[]) -{ - const char * const program_name = argv[0]; +int +main(int argc, char* argv[]) { + const char* const program_name = argv[0]; // skip program name --argc; ++argv; @@ -68,47 +71,39 @@ int main(int argc, char *argv[]) bool no_options = true; // need this for default behaviour // first process command line options - while (argc>0 && argv[0][0]=='-' && argc>=2) - { - no_options=false; - if (strcmp(argv[0], "--all")==0) - { - print_min = print_max = print_sum = print_geom = print_exam = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--max")==0) - { - print_max = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--min")==0) - { - print_min = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--sum")==0) - { - print_sum = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--geom")==0) - { - print_geom = true; - --argc; ++argv; - } - else if (strcmp(argv[0], "--exam")==0) - { - print_exam = true; - --argc; ++argv; - } - else - print_usage_and_exit(program_name); - } + while (argc > 0 && argv[0][0] == '-' && argc >= 2) { + no_options = false; + if (strcmp(argv[0], "--all") == 0) { + print_min = print_max = print_sum = print_geom = print_exam = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--max") == 0) { + print_max = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--min") == 0) { + print_min = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--sum") == 0) { + print_sum = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--geom") == 0) { + print_geom = true; + --argc; + ++argv; + } else if (strcmp(argv[0], "--exam") == 0) { + print_exam = true; + --argc; + ++argv; + } else + print_usage_and_exit(program_name); + } if (no_options) print_geom = true; - if(argc!=1) - { + if (argc != 1) { print_usage_and_exit(program_name); } @@ -117,50 +112,53 @@ int main(int argc, char *argv[]) shared_ptr proj_data_sptr(ProjData::read_from_file(filename)); - if (is_null_ptr(proj_data_sptr)) - { - warning("Could not read %s", filename.c_str()); - return EXIT_FAILURE; - } + if (is_null_ptr(proj_data_sptr)) { + warning("Could not read %s", filename.c_str()); + return EXIT_FAILURE; + } if (print_exam) std::cout << proj_data_sptr->get_exam_info_sptr()->parameter_info(); if (print_geom) std::cout << proj_data_sptr->get_proj_data_info_sptr()->parameter_info() << std::endl; - if (print_min || print_max || print_sum) - { - const int min_segment_num = proj_data_sptr->get_min_segment_num(); - const int max_segment_num = proj_data_sptr->get_max_segment_num(); + if (print_min || print_max || print_sum) { + const int min_segment_num = proj_data_sptr->get_min_segment_num(); + const int max_segment_num = proj_data_sptr->get_max_segment_num(); + const int min_timing_num = proj_data_sptr->get_min_tof_pos_num(); + const int max_timing_num = proj_data_sptr->get_max_tof_pos_num(); + + for (int timing_num = min_timing_num; timing_num <= max_timing_num; ++timing_num) { + std::cout << "\nTOF bin: " << timing_num; bool accumulators_initialized = false; - float accum_min=std::numeric_limits::max(); // initialize to very large in case projdata is empty (although that's unlikely) - float accum_max=std::numeric_limits::min(); - double sum=0.; - for (int segment_num = min_segment_num; segment_num<= max_segment_num; ++segment_num) - { - const SegmentByView seg(proj_data_sptr->get_segment_by_view(segment_num)); - const float this_max=seg.find_max(); - const float this_min=seg.find_min(); - sum+=static_cast(seg.sum()); - if(!accumulators_initialized) - { - accum_max=this_max; - accum_min=this_min; - accumulators_initialized=true; - } - else - { - if (accum_maxthis_min) accum_min=this_min; - } - } + float accum_min = + std::numeric_limits::max(); // initialize to very large in case projdata is empty (although that's unlikely) + float accum_max = std::numeric_limits::min(); + double sum = 0.; + for (int segment_num = min_segment_num; segment_num <= max_segment_num; ++segment_num) { + const SegmentByView seg(proj_data_sptr->get_segment_by_view(segment_num, timing_num)); + const float this_max = seg.find_max(); + const float this_min = seg.find_min(); + sum += static_cast(seg.sum()); + if (!accumulators_initialized) { + accum_max = this_max; + accum_min = this_min; + accumulators_initialized = true; + } else { + if (accum_max < this_max) + accum_max = this_max; + if (accum_min > this_min) + accum_min = this_min; + } + } if (print_min) - std::cout << "\nData min: " << accum_min; + std::cout << "\nData min: " << accum_min; if (print_max) - std::cout << "\nData max: " << accum_max; + std::cout << "\nData max: " << accum_max; if (print_sum) - std::cout << "\nData sum: " << sum; + std::cout << "\nData sum: " << sum; std::cout << "\n"; } + } return EXIT_SUCCESS; } diff --git a/src/utilities/manip_image.cxx b/src/utilities/manip_image.cxx index 89a7504b47..5ccddb1635 100644 --- a/src/utilities/manip_image.cxx +++ b/src/utilities/manip_image.cxx @@ -18,9 +18,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities - + \brief This program performs operations on image data \author Matthew Jacobson @@ -41,8 +41,7 @@ #include "stir/ArrayFunction.h" #include "stir/zoom.h" - -#include +#include #include #include #include @@ -62,353 +61,339 @@ static void trim_edges(VoxelsOnCartesianGrid& main_buffer); static void get_plane(VoxelsOnCartesianGrid& main_buffer); static void get_plane_row(VoxelsOnCartesianGrid& main_buffer); -static VoxelsOnCartesianGrid ask_interfile_image(const char *const input_query); +static VoxelsOnCartesianGrid ask_interfile_image(const char* const input_query); static void show_menu(); static void show_math_menu(); -static void math_mode(VoxelsOnCartesianGrid &main_buffer, int &quit_from_math); - -static void remove_nan(VoxelsOnCartesianGrid & output_image, - const VoxelsOnCartesianGrid & input_image){ -//change all the pointers - const int min_z = input_image.get_min_index(); - const int max_z = input_image.get_max_index(); +static void math_mode(VoxelsOnCartesianGrid& main_buffer, int& quit_from_math); +static void +remove_nan(VoxelsOnCartesianGrid& output_image, const VoxelsOnCartesianGrid& input_image) { + // change all the pointers + const int min_z = input_image.get_min_index(); + const int max_z = input_image.get_max_index(); - for (int z=min_z; z<=max_z; z++){ + for (int z = min_z; z <= max_z; z++) { - const int min_y = input_image[z].get_min_index(); - const int max_y = input_image[z].get_max_index(); + const int min_y = input_image[z].get_min_index(); + const int max_y = input_image[z].get_max_index(); - for (int y=min_y;y<= max_y;y++){ + for (int y = min_y; y <= max_y; y++) { - const int min_x = input_image[z][y].get_min_index(); - const int max_x = input_image[z][y].get_max_index(); + const int min_x = input_image[z][y].get_min_index(); + const int max_x = input_image[z][y].get_max_index(); - for (int x=min_x;x<= max_x;x++){ - - if(input_image[z][y][x]>=0 && input_image[z][y][x]<=1000000) - output_image[z][y][x]=input_image[z][y][x]; - else - output_image[z][y][x]=0; - } - } - } - } + for (int x = min_x; x <= max_x; x++) { + if (input_image[z][y][x] >= 0 && input_image[z][y][x] <= 1000000) + output_image[z][y][x] = input_image[z][y][x]; + else + output_image[z][y][x] = 0; + } + } + } +} -static VoxelsOnCartesianGrid -transpose_13(const VoxelsOnCartesianGrid & image) -{ +static VoxelsOnCartesianGrid +transpose_13(const VoxelsOnCartesianGrid& image) { CartesianCoordinate3D origin = image.get_origin(); swap(origin.x(), origin.z()); CartesianCoordinate3D voxel_size = image.get_voxel_size(); swap(voxel_size.x(), voxel_size.z()); - VoxelsOnCartesianGrid - out(IndexRange3D(image.get_min_x(),image.get_max_x(), - image.get_min_y(),image.get_max_y(), - image.get_min_z(),image.get_max_z()), - origin, - voxel_size); - for (int x=image.get_min_x(); x<=image.get_max_x(); ++x) - for (int y=image.get_min_y(); y<=image.get_max_y(); ++y) - for (int z=image.get_min_z(); z<=image.get_max_z(); ++z) + VoxelsOnCartesianGrid out(IndexRange3D(image.get_min_x(), image.get_max_x(), image.get_min_y(), image.get_max_y(), + image.get_min_z(), image.get_max_z()), + origin, voxel_size); + for (int x = image.get_min_x(); x <= image.get_max_x(); ++x) + for (int y = image.get_min_y(); y <= image.get_max_y(); ++y) + for (int z = image.get_min_z(); z <= image.get_max_z(); ++z) out[x][y][z] = image[z][y][x]; return out; } -static VoxelsOnCartesianGrid -transpose_12(const VoxelsOnCartesianGrid & image) -{ +static VoxelsOnCartesianGrid +transpose_12(const VoxelsOnCartesianGrid& image) { CartesianCoordinate3D origin = image.get_origin(); swap(origin.y(), origin.z()); CartesianCoordinate3D voxel_size = image.get_voxel_size(); swap(voxel_size.y(), voxel_size.z()); - VoxelsOnCartesianGrid - out(IndexRange3D(image.get_min_y(),image.get_max_y(), - image.get_min_z(),image.get_max_z(), - image.get_min_x(),image.get_max_x()), - origin, - voxel_size); - for (int y=image.get_min_y(); y<=image.get_max_y(); ++y) - for (int z=image.get_min_z(); z<=image.get_max_z(); ++z) - for (int x=image.get_min_x(); x<=image.get_max_x(); ++x) + VoxelsOnCartesianGrid out(IndexRange3D(image.get_min_y(), image.get_max_y(), image.get_min_z(), image.get_max_z(), + image.get_min_x(), image.get_max_x()), + origin, voxel_size); + for (int y = image.get_min_y(); y <= image.get_max_y(); ++y) + for (int z = image.get_min_z(); z <= image.get_max_z(); ++z) + for (int x = image.get_min_x(); x <= image.get_max_x(); ++x) out[y][z][x] = image[z][y][x]; return out; } -int main(int argc, char *argv[]) -{ - // file input - VoxelsOnCartesianGrid main_buffer; - if(argc>1) +int +main(int argc, char* argv[]) { + // file input + VoxelsOnCartesianGrid main_buffer; + if (argc > 1) { + main_buffer = *dynamic_cast*>(DiscretisedDensity<3, float>::read_from_file(argv[1])); + } else { + cerr << endl << "Usage: manip_image

      (*.hv)" << endl << endl; + main_buffer = ask_interfile_image("File to load in main buffer? "); + } + + int zs, ys, xs, ze, ye, xe, choice; + + zs = main_buffer.get_min_z(); + ys = main_buffer.get_min_y(); + xs = main_buffer.get_min_x(); + + ze = main_buffer.get_max_z(); + ye = main_buffer.get_max_y(); + xe = main_buffer.get_max_x(); + + cerr << "resx: " << main_buffer.get_x_size() << endl; + cerr << "resy: " << main_buffer.get_y_size() << endl; + cerr << "resz: " << main_buffer.get_z_size() << endl; + cerr << "Min and Max in image " << main_buffer.find_min() << " " << main_buffer.find_max() << endl; + + int plane = 1, quit_from_math = 0; + + show_menu(); + + do { // start main mode + choice = ask_num("Selection: ", 0, 13, 13); + + switch (choice) { + case 0: // quit + break; + + case 1: // display { - main_buffer= - * dynamic_cast *>( - DiscretisedDensity<3,float>::read_from_file(argv[1])); + const float maxi = ask_num("Maximum in color scale", 0.F, main_buffer.find_max(), main_buffer.find_max()); + + switch (ask_num("transaxial (0), coronal (1), sagital (2)", 0, 2, 0)) { + case 0: + display(main_buffer, maxi); + break; + case 1: + display(transpose_12(main_buffer), maxi); + break; + case 2: + display(transpose_13(main_buffer), maxi); + break; + } + break; } - else { - cerr< (*.hv)"<0 && plane <=ze-zs+1 ) { - plane = ask_num("Input plane # (0 to exit)", 0, ze-zs+1, zs); - - if(plane==0) break; - - for (int y=ys; y <= ye; y++) - for (int x=xs; x<= xe; x++) - cerr<0 && plane <=ze-zs+1 ) { - plane = ask_num("Input plane # (0 to exit)", 0, ze-zs+1, zs); - - if(plane==0) break; - - cerr << "Min and Max in plane " - << main_buffer[zs+plane-1].find_min() - << " " << main_buffer[zs+plane-1].find_max() << endl; - - cerr << "Number of counts = " - << main_buffer[zs+plane-1].sum() - << endl; - } - break; - } - - case 5: // min-max image - { - cerr << "Min and Max in image " << main_buffer.find_min() - << " " << main_buffer.find_max() << endl; - break; - } - - case 6: // trim - { - trim_edges(main_buffer); - break; - } - - case 7: // get plane - { - get_plane(main_buffer); - break; - } - - case 8: // get row - { - get_plane_row(main_buffer); - break; - } - - case 9: // counts - { - cerr<& output_buffer(*main_buffer.get_empty_copy()); - ask_filename_with_extension(outfile, "Output filename (without extension) ", ""); - remove_nan(output_buffer, main_buffer); - write_to_file(outfile, output_buffer); - break; - } - - case 14: show_menu(); - - } // end switch main mode - } while(choice>0 && choice<=13 && (!quit_from_math)); - return EXIT_SUCCESS; -} + case 3: // data plane-wise + { + plane = 1; -void trim_edges(VoxelsOnCartesianGrid& input_image) -{ - const int xe=input_image.get_max_x(); - const int xs=input_image.get_min_x(); - const int xm=(xs+xe)/2; - const int rim_trunc=ask_num("By how many voxels to trim the FOV? ",0,(int)(xe-xm),2); + while (plane > 0 && plane <= ze - zs + 1) { + plane = ask_num("Input plane # (0 to exit)", 0, ze - zs + 1, zs); - truncate_rim(input_image,rim_trunc); + if (plane == 0) + break; - if(ask("Zero end planes?",false)) truncate_end_planes(input_image); -} + for (int y = ys; y <= ye; y++) + for (int x = xs; x <= xe; x++) + cerr << main_buffer[zs + plane - 1][y][x] << " "; // pause + } + break; + } -void get_plane(VoxelsOnCartesianGrid& input_image) -{ - int zs,ys,xs, ze,ye,xe; + case 4: // min-max, counts plane-wise + { + plane = 1; - zs=input_image.get_min_z(); - ys=input_image.get_min_y(); - xs=input_image.get_min_x(); - - ze=input_image.get_max_z(); - ye=input_image.get_max_y(); - xe=input_image.get_max_x(); + while (plane > 0 && plane <= ze - zs + 1) { + plane = ask_num("Input plane # (0 to exit)", 0, ze - zs + 1, zs); - const int zm=(ze+zs)/2; + if (plane == 0) + break; - int plane=ask_num("Which plane?",1,ze-zs+1,(int)zm-zs+1); + cerr << "Min and Max in plane " << main_buffer[zs + plane - 1].find_min() << " " << main_buffer[zs + plane - 1].find_max() + << endl; - ofstream profile; - ask_filename_and_open(profile, "Output filename ", ".prof", ios::out); + cerr << "Number of counts = " << main_buffer[zs + plane - 1].sum() << endl; + } + break; + } - for (int y=ys; y<= ye; y++) - for (int x=xs; x<= xe; x++) - profile<& input_image) -{ - int zs,ys,xs, ze,ye,xe; - - zs=input_image.get_min_z(); - ys=input_image.get_min_y(); - xs=input_image.get_min_x(); - - ze=input_image.get_max_z(); - ye=input_image.get_max_y(); - xe=input_image.get_max_x(); - - float zm=(zs+ze)/2.F; - float ym=(ys+ye)/2.F; - float xm=(xs+xe)/2.F; - - int axdir=ask_num("Which axis direction (z=0,y=1,x=2)?",0,2,2); - - if (axdir==0) { - int xcoord=ask_num("X COORDINATE: ",1,xe-xs+1,(int)xm-xs+1); - int ycoord=ask_num("Y COORDINATE: ",1,ye-ys+1,(int)ym-ys+1); - - ofstream profile; - ask_filename_and_open(profile, "Output filename ", ".prof", ios::out); - - for (int z=zs; z<= ze; z++) - profile<& output_buffer(*main_buffer.get_empty_copy()); + ask_filename_with_extension(outfile, "Output filename (without extension) ", ""); + remove_nan(output_buffer, main_buffer); + write_to_file(outfile, output_buffer); + break; } + + case 14: + show_menu(); + + } // end switch main mode + } while (choice > 0 && choice <= 13 && (!quit_from_math)); + return EXIT_SUCCESS; +} + +void +trim_edges(VoxelsOnCartesianGrid& input_image) { + const int xe = input_image.get_max_x(); + const int xs = input_image.get_min_x(); + const int xm = (xs + xe) / 2; + const int rim_trunc = ask_num("By how many voxels to trim the FOV? ", 0, (int)(xe - xm), 2); + + truncate_rim(input_image, rim_trunc); + + if (ask("Zero end planes?", false)) + truncate_end_planes(input_image); +} + +void +get_plane(VoxelsOnCartesianGrid& input_image) { + int zs, ys, xs, ze, ye, xe; + + zs = input_image.get_min_z(); + ys = input_image.get_min_y(); + xs = input_image.get_min_x(); + + ze = input_image.get_max_z(); + ye = input_image.get_max_y(); + xe = input_image.get_max_x(); + + const int zm = (ze + zs) / 2; + + int plane = ask_num("Which plane?", 1, ze - zs + 1, (int)zm - zs + 1); + + ofstream profile; + ask_filename_and_open(profile, "Output filename ", ".prof", ios::out); + + for (int y = ys; y <= ye; y++) + for (int x = xs; x <= xe; x++) + profile << input_image[zs + plane - 1][y][x] << " "; } -VoxelsOnCartesianGrid ask_interfile_image(const char *const input_query) -{ - char filename[max_filename_length]; +void +get_plane_row(VoxelsOnCartesianGrid& input_image) { + int zs, ys, xs, ze, ye, xe; + + zs = input_image.get_min_z(); + ys = input_image.get_min_y(); + xs = input_image.get_min_x(); + + ze = input_image.get_max_z(); + ye = input_image.get_max_y(); + xe = input_image.get_max_x(); - ask_filename_with_extension(filename, input_query, ".hv"); + float zm = (zs + ze) / 2.F; + float ym = (ys + ye) / 2.F; + float xm = (xs + xe) / 2.F; + + int axdir = ask_num("Which axis direction (z=0,y=1,x=2)?", 0, 2, 2); + + if (axdir == 0) { + int xcoord = ask_num("X COORDINATE: ", 1, xe - xs + 1, (int)xm - xs + 1); + int ycoord = ask_num("Y COORDINATE: ", 1, ye - ys + 1, (int)ym - ys + 1); + + ofstream profile; + ask_filename_and_open(profile, "Output filename ", ".prof", ios::out); - shared_ptr > - image_ptr(read_from_file >(filename)); - return - * dynamic_cast*>(image_ptr.get()); + for (int z = zs; z <= ze; z++) + profile << input_image[z][ycoord + ys - 1][xcoord + xs - 1] << " "; + } + else if (axdir == 1) { + int zcoord = ask_num("Z COORDINATE: ", 1, ze - zs + 1, (int)zm - zs + 1); + int xcoord = ask_num("X COORDINATE: ", 1, xe - xs + 1, (int)xm - xs + 1); + + ofstream profile; + ask_filename_and_open(profile, "Output filename ", ".prof", ios::out); + + for (int y = ys; y <= ye; y++) + profile << input_image[zcoord + zs - 1][y][xcoord + xs - 1] << " "; + } + + else { // axdir=2 + int zcoord = ask_num("Z COORDINATE: ", 1, ze - zs + 1, (int)zm - zs + 1); + int ycoord = ask_num("Y COORDINATE: ", 1, ye - ys + 1, (int)ym - ys + 1); + + ofstream profile; + ask_filename_and_open(profile, "Output filename ", ".prof", ios::out); + + for (int x = xs; x <= xe; x++) + profile << input_image[zcoord + zs - 1][ycoord + ys - 1][x] << " "; + } } +VoxelsOnCartesianGrid +ask_interfile_image(const char* const input_query) { + char filename[max_filename_length]; + + ask_filename_with_extension(filename, input_query, ".hv"); -void show_menu() -{ - cerr<<"\n\ + shared_ptr> image_ptr(read_from_file>(filename)); + return *dynamic_cast*>(image_ptr.get()); +} + +void +show_menu() { + cerr << "\n\ MAIN MODE:\n\ 0. Quit\n\ 1. Display image\n\ @@ -424,11 +409,12 @@ MAIN MODE:\n\ 11. Reload main buffer\n\ 12. Write buffer to file\n\ 13. Remove nan values, substitute nan with 0\n\ -14. Redisplay menu"<& main_buffer, int& quit_from_math) { + VoxelsOnCartesianGrid math_buffer = main_buffer; // initialize math buffer + int operation; + + show_math_menu(); + + do { + operation = ask_num("Choose Operation: ", 0, 16, 15); + + switch (operation) { // math mode + + case 0: // quit + { + quit_from_math = 1; + break; + } + + case 1: // display math buffer + { + display(math_buffer, math_buffer.find_max()); + break; + } + + case 2: // absolute difference + { + + VoxelsOnCartesianGrid aux_image = ask_interfile_image("What image to compare with?"); + + math_buffer -= aux_image; + in_place_abs(math_buffer); + + // MJ 07/10/2000 removed trimming + // trim_edges(math_buffer); + + cerr << endl << "Min and Max absolute difference " << math_buffer.find_min() << " " << math_buffer.find_max() << endl; + cerr << endl << "Difference (L1 norm): " << math_buffer.sum() << endl; -void math_mode(VoxelsOnCartesianGrid &main_buffer, int &quit_from_math) -{ - VoxelsOnCartesianGrid math_buffer=main_buffer; //initialize math buffer - int operation; + break; + } - show_math_menu(); - - do { - operation=ask_num("Choose Operation: ",0,16,15); + case 3: // image addition + { + VoxelsOnCartesianGrid aux_image = ask_interfile_image("What image to add?"); - switch(operation) { // math mode + math_buffer += aux_image; + break; + } + + case 4: // image subtraction + { + VoxelsOnCartesianGrid aux_image = ask_interfile_image("What image to subtract?"); + + math_buffer -= aux_image; + break; + } + + case 5: // image multiplication + { + VoxelsOnCartesianGrid aux_image = ask_interfile_image("What image to multiply?"); + + math_buffer *= aux_image; + break; + } + + case 6: // image division + { + VoxelsOnCartesianGrid aux_image = ask_interfile_image("What image to divide?"); + + divide_array(math_buffer, aux_image); + break; + } + + case 7: // scalar addition + { + float scalar = ask_num("What scalar to add?", -100000.F, +100000.F, 0.F); + + math_buffer += scalar; + break; + } + + case 8: // scalar mulltiplication + { + float scalar = ask_num("What scalar to multiply?", -100000.F, +100000.F, 1.F); + + math_buffer *= scalar; + break; + } + + case 9: // scalar division + { + float scalar = 0.0; + + do { + scalar = ask_num("What scalar to divide?", -100000.F, +100000.F, 1.F); + + if (scalar == 0.0) + cerr << endl << "Illegal -- division by 0" << endl; + + } while (scalar == 0.0); + + math_buffer /= scalar; + break; + } + + case 10: // zoom + { + const float zoom_x = ask_num("Zoom factor x", 0.1F, 5.F, 1.F); + const float zoom_y = ask_num("Zoom factor y", 0.1F, 5.F, zoom_x); + const float zoom_z = ask_num("Zoom factor z", 0.1F, 5.F, 1.F); + const float offset_x = ask_num("Offset x (in mm)", -math_buffer.get_x_size() * math_buffer.get_voxel_size().x(), + math_buffer.get_x_size() * math_buffer.get_voxel_size().x(), 0.F); + const float offset_y = ask_num("Offset y (in mm)", -math_buffer.get_y_size() * math_buffer.get_voxel_size().y(), + math_buffer.get_y_size() * math_buffer.get_voxel_size().y(), 0.F); + const float offset_z = ask_num("Offset z (in mm)", -math_buffer.get_z_size() * math_buffer.get_voxel_size().z(), + math_buffer.get_z_size() * math_buffer.get_voxel_size().z(), 0.F); + const int new_size_x = ask_num("New x size (pixels)", 1, static_cast(math_buffer.get_x_size() * zoom_x * 2), + static_cast(math_buffer.get_x_size() * zoom_x)); + const int new_size_y = + ask_num("New y size (pixels)", 1, static_cast(math_buffer.get_y_size() * zoom_y * 2), new_size_x); + const int new_size_z = ask_num("New z size (pixels)", 1, static_cast(math_buffer.get_z_size() * zoom_z * 2), + static_cast(math_buffer.get_z_size() * zoom_z)); + zoom_image_in_place(math_buffer, CartesianCoordinate3D(zoom_z, zoom_y, zoom_x), + CartesianCoordinate3D(offset_z, offset_y, offset_x), + CartesianCoordinate3D(new_size_z, new_size_y, new_size_x)); + break; + } + + case 11: { + cerr << "Min and Max in image " << math_buffer.find_min() << " " << math_buffer.find_max() << endl; + break; + } + + case 12: // reinitialize math buffer + { + math_buffer = main_buffer; + break; + } + + case 13: // dump math buffer to main buffer + { + main_buffer = math_buffer; + break; + } + + case 14: // reload main buffer in math mode + { + main_buffer = ask_interfile_image("File to load in buffer? "); + break; + } + + case 15: // redisplay menu + { + show_math_menu(); + break; + } + + case 16: // go back to main mode + { + show_menu(); + } - case 0: // quit - { - quit_from_math=1; - break; - } - - case 1: // display math buffer - { - display(math_buffer, math_buffer.find_max()); - break; - } - - case 2: // absolute difference - { - - VoxelsOnCartesianGrid aux_image= - ask_interfile_image("What image to compare with?"); - - math_buffer-=aux_image; - in_place_abs(math_buffer); - - //MJ 07/10/2000 removed trimming - //trim_edges(math_buffer); - - cerr < aux_image= - ask_interfile_image("What image to add?"); - - math_buffer+=aux_image; - break; - } - - - case 4: // image subtraction - { - VoxelsOnCartesianGrid aux_image= - ask_interfile_image("What image to subtract?"); - - math_buffer-=aux_image; - break; - } - - case 5: // image multiplication - { - VoxelsOnCartesianGrid aux_image= - ask_interfile_image("What image to multiply?"); - - math_buffer*=aux_image; - break; - } - - case 6: // image division - { - VoxelsOnCartesianGrid aux_image= - ask_interfile_image("What image to divide?"); - - divide_array(math_buffer, aux_image); - break; - } - - case 7: //scalar addition - { - float scalar=ask_num("What scalar to add?", -100000.F,+100000.F,0.F); - - math_buffer+=scalar; - break; - } - - case 8: //scalar mulltiplication - { - float scalar=ask_num("What scalar to multiply?", -100000.F,+100000.F,1.F); - - math_buffer*=scalar; - break; - } - - case 9: //scalar division - { - float scalar=0.0; - - do { - scalar=ask_num("What scalar to divide?", -100000.F,+100000.F,1.F); - - if(scalar==0.0) cerr<(math_buffer.get_x_size()*zoom_x * 2), - static_cast(math_buffer.get_x_size()*zoom_x)); - const int new_size_y = - ask_num("New y size (pixels)", 1, - static_cast(math_buffer.get_y_size()*zoom_y * 2), - new_size_x); - const int new_size_z = - ask_num("New z size (pixels)", 1, - static_cast(math_buffer.get_z_size()*zoom_z * 2), - static_cast(math_buffer.get_z_size()*zoom_z)); - zoom_image_in_place(math_buffer, - CartesianCoordinate3D(zoom_z, zoom_y, zoom_x), - CartesianCoordinate3D(offset_z, offset_y, offset_x), - CartesianCoordinate3D(new_size_z, new_size_y, new_size_x)); - break; - } - - case 11: - { - cerr << "Min and Max in image " << math_buffer.find_min() - << " " << math_buffer.find_max() << endl; - break; - } - - case 12: //reinitialize math buffer - { - math_buffer=main_buffer; - break; - } - - case 13: //dump math buffer to main buffer - { - main_buffer=math_buffer; - break; - } - - case 14: //reload main buffer in math mode - { - main_buffer = ask_interfile_image("File to load in buffer? "); - break; - } - - case 15: //redisplay menu - { - show_math_menu(); - break; - } - - - case 16: //go back to main mode - { - show_menu(); - } - - } // end switch math mode - } while(operation>0 && operation<16); + } // end switch math mode + } while (operation > 0 && operation < 16); } diff --git a/src/utilities/manip_projdata.cxx b/src/utilities/manip_projdata.cxx index 92b52701b4..239d7e3598 100644 --- a/src/utilities/manip_projdata.cxx +++ b/src/utilities/manip_projdata.cxx @@ -7,12 +7,12 @@ \author Sanida Mustafovic and Kris Thielemans (conversion to new design) \author PARAPET project -This utility programme processes (interfile) sinogram data +This utility programme processes (interfile) sinogram data (maximum number of segments as input). It can
      • display by View - by Segment
      • do operations between two data -
      • do operations with a scalar +
      • do operations with a scalar
      */ /* @@ -37,8 +37,6 @@ This utility programme processes (interfile) sinogram data // TODO get rid of pos, neg segments (can now do each one separately) // MJ doesn't think doing each one separately is a good idea (for display) - - #include "stir/ProjDataFromStream.h" #include "stir/SegmentByView.h" #include "stir/SegmentBySinogram.h" @@ -46,7 +44,7 @@ This utility programme processes (interfile) sinogram data #include "stir/Viewgram.h" //#include "stir/Scanner.h" -#include "stir/ArrayFunction.h" +#include "stir/ArrayFunction.h" #include "stir/recon_array_functions.h" #include "stir/display.h" #include "stir/IO/interfile.h" @@ -55,8 +53,8 @@ This utility programme processes (interfile) sinogram data #include "stir/is_null_ptr.h" #include -#include -#include +#include +#include #ifndef STIR_NO_NAMESPACES using std::cerr; @@ -64,197 +62,200 @@ using std::endl; using std::fstream; #endif - - START_NAMESPACE_STIR // in relation with show_math_menu() // _menu HAS to be the last option -enum options { _quit, _display_view, _display_sino, _absdiff, _add_sino, _subtract_sino, - _mult_sino, _div_sino, _add_scalar, _mult_scalar, _div_scalar, _stats, - _pos_ind, _trunc_neg, _trim, _zero_ends, /*_pad_ends,*/ _restart, _menu}; +enum options { + _quit, + _display_view, + _display_sino, + _absdiff, + _add_sino, + _subtract_sino, + _mult_sino, + _div_sino, + _add_scalar, + _mult_scalar, + _div_scalar, + _stats, + _pos_ind, + _trunc_neg, + _trim, + _zero_ends, + /*_pad_ends,*/ _restart, + _menu +}; //*********************** prototypes // operations between two datas -void do_math(enum options operation, SegmentByView& sino1,SegmentByView &sino2, - float &accum_max, float &accum_min, float &accum_sum, bool accumulators_initialized); +void do_math(enum options operation, SegmentByView& sino1, SegmentByView& sino2, float& accum_max, float& accum_min, + float& accum_sum, bool accumulators_initialized); // display, operations with a scalar, others -void do_math(enum options operation, SegmentByView& sino1, SegmentBySinogram& seg_sinogram, float &accum_max, float &accum_min, float &accum_sum, bool accumulators_initialized,float scalar=0.0); +void do_math(enum options operation, SegmentByView& sino1, SegmentBySinogram& seg_sinogram, float& accum_max, + float& accum_min, float& accum_sum, bool accumulators_initialized, float scalar = 0.0); -void make_buffer_header(const char *data_filename,const char *header_filename, - ProjData& input_sino, int limit_segments, - NumericType::Type output_type=NumericType::FLOAT); +void make_buffer_header(const char* data_filename, const char* header_filename, ProjData& input_sino, int limit_segments, + NumericType::Type output_type = NumericType::FLOAT); void show_math_menu(); float pos_indicate(float x); -shared_ptr ask_proj_data(const char *const input_query); +shared_ptr ask_proj_data(const char* const input_query); //*********************** functions -void do_math(enum options operation, SegmentByView& sino1,SegmentByView &sino2, - float &accum_max, float &accum_min, float &accum_sum, bool accumulators_initialized) -{ - switch(operation) - { - - case _absdiff: { //absolute difference - sino1-=sino2; - in_place_abs(sino1); - - if(!accumulators_initialized) { - accum_max=sino1.find_max(); - accum_min=sino1.find_min(); - accum_sum=sino1.sum(); - accumulators_initialized=true; - } - else { - if (accum_maxsino1.find_min()) accum_min= sino1.find_min(); - accum_sum+=sino1.sum(); - } - break; - } - - case _add_sino: { // sinogram addition - sino1+=sino2; - break; - } - - - case _subtract_sino: { // sinogram subtraction - sino1-=sino2; - break; +void +do_math(enum options operation, SegmentByView& sino1, SegmentByView& sino2, float& accum_max, float& accum_min, + float& accum_sum, bool accumulators_initialized) { + switch (operation) { + + case _absdiff: { // absolute difference + sino1 -= sino2; + in_place_abs(sino1); + + if (!accumulators_initialized) { + accum_max = sino1.find_max(); + accum_min = sino1.find_min(); + accum_sum = sino1.sum(); + accumulators_initialized = true; + } else { + if (accum_max < sino1.find_max()) + accum_max = sino1.find_max(); + if (accum_min > sino1.find_min()) + accum_min = sino1.find_min(); + accum_sum += sino1.sum(); } + break; + } + + case _add_sino: { // sinogram addition + sino1 += sino2; + break; + } + + case _subtract_sino: { // sinogram subtraction + sino1 -= sino2; + break; + } + + case _mult_sino: { // image multiplication + sino1 *= sino2; + break; + } + + case _div_sino: { // sinogram division + divide_array(sino1, sino2); + break; + } + + // MJ 07/14/2000 empty default to suppress warning in gcc 2.95.2 + default: { + // empty statement + } + + } // end switch +} - case _mult_sino: { // image multiplication - sino1*=sino2; - break; +void +do_math(enum options operation, SegmentByView& sino1, SegmentBySinogram& seg_sinogram, float& accum_max, + float& accum_min, float& accum_sum, bool accumulators_initialized, float scalar) { + switch (operation) { + + case _display_view: { // display math buffer by View + char title[100]; + sprintf(title, "Segment %d", sino1.get_segment_num()); + display(sino1, sino1.find_max(), title); + if (ask("Display single viewgram?", false)) { + int vs = sino1.get_min_view_num(); + int ve = sino1.get_max_view_num(); + int view_num = ask_num("Which viewgram?", vs, ve, vs); + + Viewgram viewgram = sino1.get_viewgram(view_num); + display(viewgram); } - - case _div_sino: { // sinogram division - divide_array(sino1,sino2); - break; + break; + } + + case _display_sino: { // display math buffer by sinogram + char title[100]; + sprintf(title, "Segment %d", sino1.get_segment_num()); + display(seg_sinogram, seg_sinogram.find_max()); + break; + } + + case _add_scalar: { // scalar addition + sino1 += scalar; + break; + } + + case _mult_scalar: { // scalar multiplication + sino1 *= scalar; + break; + } + + case _div_scalar: { // scalar division + sino1 /= scalar; + break; + } + + case _stats: { // global min&max + number of counts + if (!accumulators_initialized) { + accum_max = sino1.find_max(); + accum_min = sino1.find_min(); + accum_sum = sino1.sum(); + accumulators_initialized = true; + } else { + if (accum_max < sino1.find_max()) + accum_max = sino1.find_max(); + if (accum_min > sino1.find_min()) + accum_min = sino1.find_min(); + accum_sum += sino1.sum(); } - - - //MJ 07/14/2000 empty default to suppress warning in gcc 2.95.2 - default: - { - //empty statement - } - - - - } // end switch + break; + } + + case _pos_ind: { + in_place_apply_function(sino1, pos_indicate); // positive indicator + break; + } + + case _trim: { + truncate_rim(sino1, (int)scalar); // trim rim + break; + } + + case _trunc_neg: { + in_place_apply_function(sino1, neg_trunc); + break; + } + + // MJ 07/14/2000 empty default to suppress warning in gcc 2.95.2 + default: { + // empty statement + } + + } // end switch } +shared_ptr +ask_proj_data(const char* const input_query) { + char filename[max_filename_length]; -void do_math(enum options operation, SegmentByView& sino1, SegmentBySinogram& seg_sinogram, float &accum_max, float &accum_min, float &accum_sum, bool accumulators_initialized,float scalar) -{ - switch(operation) - { + // system("ls *hs"); + ask_filename_with_extension(filename, input_query, ".hs"); - case _display_view: { //display math buffer by View - char title[100]; - sprintf(title, "Segment %d", sino1.get_segment_num()); - display(sino1,sino1.find_max(), title); - if(ask("Display single viewgram?",false)) { - int vs=sino1.get_min_view_num(); - int ve=sino1.get_max_view_num(); - int view_num=ask_num("Which viewgram?",vs,ve,vs); - - Viewgram viewgram=sino1.get_viewgram(view_num); - display(viewgram); - } - break; - } - - case _display_sino: { //display math buffer by sinogram - char title[100]; - sprintf(title, "Segment %d", sino1.get_segment_num()); - display(seg_sinogram, seg_sinogram.find_max()); - break; - } - - case _add_scalar: { //scalar addition - sino1+=scalar; - break; - } - - case _mult_scalar: { //scalar multiplication - sino1*=scalar; - break; - } - - case _div_scalar: { //scalar division - sino1/=scalar; - break; - } - - case _stats: { //global min&max + number of counts - if(!accumulators_initialized) { - accum_max=sino1.find_max(); - accum_min=sino1.find_min(); - accum_sum=sino1.sum(); - accumulators_initialized=true; - } - else { - if (accum_maxsino1.find_min()) accum_min= sino1.find_min(); - accum_sum+=sino1.sum(); - } - break; - } - - case _pos_ind: - { - in_place_apply_function(sino1,pos_indicate); //positive indicator - break; - } - - case _trim: - { - truncate_rim(sino1, (int) scalar); //trim rim - break; - } - - case _trunc_neg: - { - in_place_apply_function(sino1,neg_trunc); - break; - } - - - //MJ 07/14/2000 empty default to suppress warning in gcc 2.95.2 - default: - { - //empty statement - } - - - } //end switch + return ProjData::read_from_file(filename); } -shared_ptr ask_proj_data(const char *const input_query) -{ - char filename[max_filename_length]; - - //system("ls *hs"); - ask_filename_with_extension(filename, input_query, ".hs"); - - return - ProjData::read_from_file(filename); -} - -void show_math_menu() -{ +void +show_math_menu() { assert(_menu == 17); // KT disabled Pad end planes: 16. Pad end planes of segment 0 \n -cerr<<"\n\ + cerr << "\n\ MENU:\n\ 0. Quit\n\ 1. Display viewgrams\n\ @@ -276,145 +277,132 @@ MENU:\n\ 15. Apply axial truncating window to segment 0 \n\ (scalar operand = No. of planes to truncate)\n\ 16. Restart\n\ -17. Redisplay menu"<0.0)?1.0F:0.0F; +float +pos_indicate(float x) { + return (x > 0.0) ? 1.0F : 0.0F; } END_NAMESPACE_STIR //********************** main - - USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) { + bool quit = false, reload = false; -int main(int argc, char *argv[]) -{ - bool quit=false,reload=false; - - shared_ptr first_operand; - ProjDataFromStream *output_proj_data= NULL; - // Start - do { //(re)start from here - bool buffer_opened=false; - char output_buffer_header[max_filename_length]; - - if (is_null_ptr(first_operand)) - { + shared_ptr first_operand; + ProjDataFromStream* output_proj_data = NULL; + // Start + do { //(re)start from here + bool buffer_opened = false; + char output_buffer_header[max_filename_length]; - if (reload) - // changed the ask... returns ponter - first_operand=ask_proj_data("Input sinogram"); //new - //ProjDataFromStream(ask_proj_data("Input sinogram")); - - else // just starting - { - if(argc<2) - { - cerr< (*.hs)"< (*.hs)" << endl << endl; + first_operand = ask_proj_data("Input sinogram"); + } else + first_operand = ProjData::read_from_file(argv[1]); - int limit_segments=ask_num("Maximum absolute segment number to process: ", 0, first_operand->get_max_segment_num(), first_operand->get_max_segment_num() ); + reload = false; + } + } + int limit_segments = ask_num("Maximum absolute segment number to process: ", 0, first_operand->get_max_segment_num(), + first_operand->get_max_segment_num()); - do { //math operations loop - float accum_max, accum_min, accum_sum; - show_math_menu(); - enum options operation; + do { // math operations loop + float accum_max, accum_min, accum_sum; + show_math_menu(); + enum options operation; - operation= - static_cast( - ask_num("Choose Operation: ", - 0,static_cast(_menu), static_cast(_menu)) - ); - if (operation==_menu) continue; //redisplay menu - if (operation==_restart || operation==_quit) { //restart or quit + operation = static_cast(ask_num("Choose Operation: ", 0, static_cast(_menu), static_cast(_menu))); + if (operation == _menu) + continue; // redisplay menu + if (operation == _restart || operation == _quit) { // restart or quit #if 1 - assert(output_proj_data == NULL); + assert(output_proj_data == NULL); #else - // enable this when using the output buffer for reading/writing at the same time - if (output_proj_data != NULL) - { - delete output_proj_data; - output_proj_data = NULL; - } + // enable this when using the output buffer for reading/writing at the same time + if (output_proj_data != NULL) { + delete output_proj_data; + output_proj_data = NULL; + } #endif - first_operand.reset(); - if(operation==_restart) reload=true; - if(operation==_quit) quit=true; - break; - } - - if (operation!= _display_view && operation!= _display_sino - && operation!= _stats &&!buffer_opened) - { - //operation result is a sinogram - - char output_buffer_root[max_filename_length]; - char output_buffer_filename[max_filename_length]; - - ask_filename_with_extension(output_buffer_root, "Output to which file (without extension)?", ""); - sprintf(output_buffer_filename, "%s.%s",output_buffer_root , "s"); - // TODO relies on write_basic_interfile_PDFS_header using .hs extension - sprintf(output_buffer_header, "%s.%s",output_buffer_root , "hs"); - shared_ptr new_sino_ptr(new fstream); - open_write_binary(*new_sino_ptr, output_buffer_filename); - shared_ptr pdi_ptr = - first_operand->get_proj_data_info_sptr()->create_shared_clone(); - pdi_ptr->reduce_segment_range(-limit_segments, limit_segments); - output_proj_data = new ProjDataFromStream(first_operand->get_exam_info_sptr(), - pdi_ptr, new_sino_ptr); - write_basic_interfile_PDFS_header(output_buffer_filename, *output_proj_data); - buffer_opened=true; - } - - shared_ptr second_operand; - float *scalar=NULL; - - if(operation==_absdiff || operation==_add_sino || operation==_subtract_sino || - operation==_mult_sino || operation==_div_sino) //requiring 2nd sinogram operand - second_operand= ask_proj_data("Second sinogram operand" ); - - if(operation==_add_scalar || operation==_mult_scalar || operation==_div_scalar || - operation==_trim || operation==_zero_ends ) { //requiring scalar operand - bool need_int=false; - float upper_bound=100000.F,lower_bound=-100000.F,deflt=0.F; - - if(operation==_trim) { - need_int=true; - upper_bound=(float) (first_operand->get_proj_data_info_sptr()->get_num_tangential_poss()/2 +1); - lower_bound=deflt=0.0; - } - - if(operation==_zero_ends) { - need_int=true; - upper_bound=(float) (first_operand->get_proj_data_info_sptr()->get_num_axial_poss(0)/2+1); - lower_bound=deflt=1.0; - } - - do scalar= new float (ask_num("Scalar Operand: ",(need_int)?(int)lower_bound:lower_bound , - (need_int)?(int)upper_bound: upper_bound,(need_int)?(int)deflt:deflt)); - while(*scalar==0.0 && operation==_div_scalar ); - - } -// first do segment 0 - { - SegmentByView seg1=first_operand->get_segment_by_view(0); - SegmentBySinogram seg_sinogram=first_operand->get_segment_by_sinogram(0); + first_operand.reset(); + if (operation == _restart) + reload = true; + if (operation == _quit) + quit = true; + break; + } + + if (operation != _display_view && operation != _display_sino && operation != _stats && !buffer_opened) { + // operation result is a sinogram + + char output_buffer_root[max_filename_length]; + char output_buffer_filename[max_filename_length]; + + ask_filename_with_extension(output_buffer_root, "Output to which file (without extension)?", ""); + sprintf(output_buffer_filename, "%s.%s", output_buffer_root, "s"); + // TODO relies on write_basic_interfile_PDFS_header using .hs extension + sprintf(output_buffer_header, "%s.%s", output_buffer_root, "hs"); + shared_ptr new_sino_ptr(new fstream); + open_write_binary(*new_sino_ptr, output_buffer_filename); + shared_ptr pdi_ptr = first_operand->get_proj_data_info_sptr()->create_shared_clone(); + pdi_ptr->reduce_segment_range(-limit_segments, limit_segments); + output_proj_data = new ProjDataFromStream(first_operand->get_exam_info_sptr(), pdi_ptr, new_sino_ptr); + write_basic_interfile_PDFS_header(output_buffer_filename, *output_proj_data); + buffer_opened = true; + } + + shared_ptr second_operand; + float* scalar = NULL; + + if (operation == _absdiff || operation == _add_sino || operation == _subtract_sino || operation == _mult_sino || + operation == _div_sino) // requiring 2nd sinogram operand + second_operand = ask_proj_data("Second sinogram operand"); + + if (operation == _add_scalar || operation == _mult_scalar || operation == _div_scalar || operation == _trim || + operation == _zero_ends) { // requiring scalar operand + bool need_int = false; + float upper_bound = 100000.F, lower_bound = -100000.F, deflt = 0.F; + + if (operation == _trim) { + need_int = true; + upper_bound = (float)(first_operand->get_proj_data_info_sptr()->get_num_tangential_poss() / 2 + 1); + lower_bound = deflt = 0.0; + } + + if (operation == _zero_ends) { + need_int = true; + upper_bound = (float)(first_operand->get_proj_data_info_sptr()->get_num_axial_poss(0) / 2 + 1); + lower_bound = deflt = 1.0; + } + + do + scalar = new float(ask_num("Scalar Operand: ", (need_int) ? (int)lower_bound : lower_bound, + (need_int) ? (int)upper_bound : upper_bound, (need_int) ? (int)deflt : deflt)); + while (*scalar == 0.0 && operation == _div_scalar); + } + // first do segment 0 + { + SegmentByView seg1 = first_operand->get_segment_by_view(0); + SegmentBySinogram seg_sinogram = first_operand->get_segment_by_sinogram(0); #if 0 // TODO grow statement is wrong // also this can't work anymore, as set_segment would complain about incompatible sizes @@ -446,100 +434,94 @@ int main(int argc, char *argv[]) } } #endif - if(!is_null_ptr(second_operand)) { - SegmentByView seg2=second_operand->get_segment_by_view(0); - do_math(operation,seg1,seg2,accum_max,accum_min,accum_sum,false); - } - - else if(scalar != NULL) { - if(operation==_zero_ends ) - for(int i=seg1.get_min_view_num();i<=seg1.get_max_view_num();i++) - for(int j=0;j<*scalar;j++ ) { - seg1[i][seg1.get_min_axial_pos_num()+j].fill(0); - seg1[i][seg1.get_max_axial_pos_num()-j].fill(0); - - - } - else do_math(operation,seg1,seg_sinogram,accum_max,accum_min,accum_sum,false,*scalar); - - - } - - else do_math(operation,seg1,seg_sinogram,accum_max,accum_min,accum_sum,false); - - - - - //Write sinogram result to file - if(operation!= _display_view && operation!= _display_sino && operation!= _stats && buffer_opened) - output_proj_data->set_segment(seg1); - } -//Now do other segments - - - - - if(limit_segments>0) - for (int segment_num = 1; segment_num <= limit_segments ; segment_num++) { - if((operation==_display_view || operation==_display_sino) && ask("Abort display",false)) break; - SegmentByView seg1_pos=first_operand->get_segment_by_view(segment_num); - SegmentByView seg1_neg=first_operand->get_segment_by_view(-segment_num); - SegmentBySinogram seg_sinogram_pos=first_operand->get_segment_by_sinogram(segment_num); - SegmentBySinogram seg_sinogram_neg=first_operand->get_segment_by_sinogram(-segment_num); - - if(!is_null_ptr(second_operand)) { - SegmentByView seg2_pos=second_operand->get_segment_by_view(segment_num); - SegmentByView seg2_neg=second_operand->get_segment_by_view(-segment_num); - do_math(operation,seg1_pos,seg2_pos,accum_max,accum_min,accum_sum,true); - do_math(operation,seg1_neg,seg2_neg,accum_max,accum_min,accum_sum,true); - } - else if(scalar != NULL) { - do_math(operation,seg1_pos,seg_sinogram_pos,accum_max,accum_min,accum_sum,true,*scalar); - do_math(operation,seg1_neg,seg_sinogram_neg,accum_max,accum_min,accum_sum,true,*scalar); - } - else { - do_math(operation,seg1_pos,seg_sinogram_pos,accum_max,accum_min,accum_sum,true); - if((operation==_display_view || operation==_display_sino) - && ask("Abort display",false)) break; - do_math(operation,seg1_neg,seg_sinogram_neg,accum_max,accum_min,accum_sum,true); - if((operation==_display_view || operation==_display_sino) - && segment_numset_segment(seg1_neg); - output_proj_data->set_segment(seg1_pos); - } - } - - -//if buffer changed, reinitialize first operand to output of previous math operation - if(operation!= _display_view && operation!= _display_sino && operation!= _stats && buffer_opened) - { - // at the moment, we close the output buffer, and will reopen it later on - // this is to avoid conflicts with reading and writing from/to the same file - // alternatively, the output_proj_data would use a read/write file, and - // we would do first_operand = output_proj_data - - if (output_proj_data != NULL) - { - delete output_proj_data; - output_proj_data = NULL; - } - buffer_opened = false; - - first_operand=ProjData::read_from_file(output_buffer_header); - } - -//Get accumulator results and de-allocate - if (operation ==_absdiff || operation ==_stats) cerr< seg1_pos = first_operand->get_segment_by_view(segment_num); + SegmentByView seg1_neg = first_operand->get_segment_by_view(-segment_num); + SegmentBySinogram seg_sinogram_pos = first_operand->get_segment_by_sinogram(segment_num); + SegmentBySinogram seg_sinogram_neg = first_operand->get_segment_by_sinogram(-segment_num); + + if (!is_null_ptr(second_operand)) { + SegmentByView seg2_pos = second_operand->get_segment_by_view(segment_num); + SegmentByView seg2_neg = second_operand->get_segment_by_view(-segment_num); + do_math(operation, seg1_pos, seg2_pos, accum_max, accum_min, accum_sum, true); + do_math(operation, seg1_neg, seg2_neg, accum_max, accum_min, accum_sum, true); + } else if (scalar != NULL) { + do_math(operation, seg1_pos, seg_sinogram_pos, accum_max, accum_min, accum_sum, true, *scalar); + do_math(operation, seg1_neg, seg_sinogram_neg, accum_max, accum_min, accum_sum, true, *scalar); + } else { + do_math(operation, seg1_pos, seg_sinogram_pos, accum_max, accum_min, accum_sum, true); + if ((operation == _display_view || operation == _display_sino) && ask("Abort display", false)) + break; + do_math(operation, seg1_neg, seg_sinogram_neg, accum_max, accum_min, accum_sum, true); + if ((operation == _display_view || operation == _display_sino) && segment_num < limit_segments && + ask("Abort display", false)) + break; + } + + // Write sinogram result to file + if (operation != _display_view && operation != _display_sino && operation != _stats && buffer_opened) { + output_proj_data->set_segment(seg1_neg); + output_proj_data->set_segment(seg1_pos); + } + } + + // if buffer changed, reinitialize first operand to output of previous math operation + if (operation != _display_view && operation != _display_sino && operation != _stats && buffer_opened) { + // at the moment, we close the output buffer, and will reopen it later on + // this is to avoid conflicts with reading and writing from/to the same file + // alternatively, the output_proj_data would use a read/write file, and + // we would do first_operand = output_proj_data + + if (output_proj_data != NULL) { + delete output_proj_data; + output_proj_data = NULL; + } + buffer_opened = false; + + first_operand = ProjData::read_from_file(output_buffer_header); + } + + // Get accumulator results and de-allocate + if (operation == _absdiff || operation == _stats) + cerr << endl << "Maximum= " << accum_max << endl; + if (operation == _absdiff || operation == _stats) + cerr << endl << "Minimum= " << accum_min << endl; + if (operation == _absdiff || operation == _stats) + cerr << endl << "Total counts= " << accum_sum << endl; + if (scalar != NULL) + delete scalar; + + } while (!quit); // end math operations do-while loop + } while (!quit); // restart do-while loop + + return EXIT_SUCCESS; +} // end main diff --git a/src/utilities/poisson_noise.cxx b/src/utilities/poisson_noise.cxx index f1195677cb..604791a23d 100644 --- a/src/utilities/poisson_noise.cxx +++ b/src/utilities/poisson_noise.cxx @@ -1,7 +1,7 @@ /*! \file - \ingroup utilities - \brief Generates a noise realisation according to Poisson statistics for + \ingroup utilities + \brief Generates a noise realisation according to Poisson statistics for some projection data \author Kris Thielemans @@ -45,58 +45,50 @@ USING_NAMESPACE_STIR -void usage() -{ - using std::cerr; - cerr <<"Usage: poisson_noise [-p | --preserve-mean] scaling_factor seed-unsigned-int\n" - <<"The seed value for the random number generator has to be strictly positive.\n" - << "Without the -p option, the mean of the output data will" - << " be equal to\nscaling_factor*mean_of_input, otherwise it" - << "will be equal to mean_of_input.\n" - << "The options -p and --preserve-mean are identical.\n"; +void +usage() { + using std::cerr; + cerr << "Usage: poisson_noise [-p | --preserve-mean] scaling_factor " + "seed-unsigned-int\n" + << "The seed value for the random number generator has to be strictly positive.\n" + << "Without the -p option, the mean of the output data will" + << " be equal to\nscaling_factor*mean_of_input, otherwise it" + << "will be equal to mean_of_input.\n" + << "The options -p and --preserve-mean are identical.\n"; } int -main (int argc,char *argv[]) -{ - if(argc<5) - { +main(int argc, char* argv[]) { + if (argc < 5) { usage(); - return(EXIT_FAILURE); - } - + return (EXIT_FAILURE); + } + bool preserve_mean = false; // option processing - if (argv[1][0] == '-') - { - if (strcmp(argv[1],"-p")==0 || - strcmp(argv[1],"--preserve-mean")==0) - preserve_mean = true; - else - { - usage(); - return(EXIT_FAILURE); - } - ++argv; + if (argv[1][0] == '-') { + if (strcmp(argv[1], "-p") == 0 || strcmp(argv[1], "--preserve-mean") == 0) + preserve_mean = true; + else { + usage(); + return (EXIT_FAILURE); } - - const char *const filename = argv[1]; + ++argv; + } + + const char* const filename = argv[1]; const float scaling_factor = static_cast(atof(argv[3])); - shared_ptr in_data = ProjData::read_from_file(argv[2]); + shared_ptr in_data = ProjData::read_from_file(argv[2]); unsigned int seed = atoi(argv[4]); GeneralisedPoissonNoiseGenerator generator(scaling_factor, preserve_mean); generator.seed(seed); - ProjDataInterfile new_data(in_data->get_exam_info_sptr(),in_data->get_proj_data_info_sptr()->create_shared_clone(), filename); + ProjDataInterfile new_data(in_data->get_exam_info_sptr(), in_data->get_proj_data_info_sptr()->create_shared_clone(), filename); + + generator.generate_random(new_data, *in_data); - - generator.generate_random(new_data,*in_data); - return EXIT_SUCCESS; } - - - diff --git a/src/utilities/postfilter.cxx b/src/utilities/postfilter.cxx index 123ab11461..46bd6f40c3 100644 --- a/src/utilities/postfilter.cxx +++ b/src/utilities/postfilter.cxx @@ -20,26 +20,24 @@ */ /*! - \file + \file \ingroup utilities \brief This program performs filtering on image data - + \author Sanida Mustafovic \author Kris Thielemans \author Matthew Jacobson \author PARAPET project \author Richard Brown - - This program enables calling any stir::DataProcessor object on input data, + + This program enables calling any stir::DataProcessor object on input data, and writing it to file. It can take the following command line: \verbatim - postfilter [--verbose] [--dynamic|--parametric] [output_format_par_file] - \endverbatim - This is done to make it easy to process a lot of files with the same - ImageProcessor. However, if the number of command line arguments is not - correct, appropriate questions will be asked interactively. + postfilter [--verbose] [--dynamic|--parametric] + [output_format_par_file] \endverbatim This is done to make it easy to process a lot of files with the same ImageProcessor. + However, if the number of command line arguments is not correct, appropriate questions will be asked interactively. If the --verbose option is used, the filter-parameters that are going to be used will be written to stdout. This is useful for checking/debugging. @@ -48,9 +46,9 @@ (but see stir::MedianImageFilter3D to see if the following example is still correct) \verbatim PostFilteringParameters := - Postfilter type :=Median + Postfilter type :=Median Median Filter Parameters := - mask radius x := 1 + mask radius x := 1 mask radius y := 2 mask radius z := 3 End Median Filter Parameters:= @@ -76,208 +74,177 @@ #include "stir/IO/OutputFileFormat.h" #include "stir/IO/read_from_file.h" #include "stir/Succeeded.h" -#include +#include #ifndef STIR_NO_NAMESPACES using std::cerr; using std::endl; #endif - START_NAMESPACE_STIR -template -STIRImageType * ask_image(const char *const input_query) -{ +template +STIRImageType* +ask_image(const char* const input_query) { char filename[max_filename_length]; - ask_filename_with_extension(filename, - input_query, - ""); - + ask_filename_with_extension(filename, input_query, ""); + return STIRImageType::read_from_file(filename); } - -template -shared_ptr > set_up_output_format(const std::string &filename) -{ - shared_ptr > output = - OutputFileFormat::default_sptr(); - if (filename.size() != 0) { - KeyParser parser; - parser.add_start_key("output file format parameters"); - parser.add_parsing_key("output file format type", &output); - parser.add_stop_key("END"); - if (parser.parse(filename.c_str()) == false || is_null_ptr(output)) { - warning("Error parsing output file format. Using default format."); - output = OutputFileFormat::default_sptr(); - } + +template +shared_ptr> +set_up_output_format(const std::string& filename) { + shared_ptr> output = OutputFileFormat::default_sptr(); + if (filename.size() != 0) { + KeyParser parser; + parser.add_start_key("output file format parameters"); + parser.add_parsing_key("output file format type", &output); + parser.add_stop_key("END"); + if (parser.parse(filename.c_str()) == false || is_null_ptr(output)) { + warning("Error parsing output file format. Using default format."); + output = OutputFileFormat::default_sptr(); } - return output; + } + return output; } -template -static -shared_ptr read_image(const std::string &filename) -{ - shared_ptr output; - if (!filename.empty()) - output = read_from_file(filename); - else - output.reset(ask_image("Image to process?")); - if (is_null_ptr(output)) - error("postfilter: No input image. Not writing any output."); - - return output; +template +static shared_ptr +read_image(const std::string& filename) { + shared_ptr output; + if (!filename.empty()) + output = read_from_file(filename); + else + output.reset(ask_image("Image to process?")); + if (is_null_ptr(output)) + error("postfilter: No input image. Not writing any output."); + + return output; } -template -static -void save_image(shared_ptr image, const std::string &filename, const std::string &par) -{ - shared_ptr > output_file_format = - set_up_output_format(par); +template +static void +save_image(shared_ptr image, const std::string& filename, const std::string& par) { + shared_ptr> output_file_format = set_up_output_format(par); - if (output_file_format->write_to_file(filename,*image) == Succeeded::no) - error("postfilter: Saving image failed."); + if (output_file_format->write_to_file(filename, *image) == Succeeded::no) + error("postfilter: Saving image failed."); } - END_NAMESPACE_STIR USING_NAMESPACE_STIR static void -print_usage() -{ - cerr<<"\nUsage: postfilter [--verbose] [--dynamic|--parametric] [output_format_par_file]\n"< [output_format_par_file]\n" + << endl; } int -main(int argc, char *argv[]) -{ +main(int argc, char* argv[]) { enum ImageType { normal, dynamic, parametric }; ImageType image_type = normal; - shared_ptr > input_image_single_ptr; - shared_ptr input_image_dynamic_ptr; + shared_ptr> input_image_single_ptr; + shared_ptr input_image_dynamic_ptr; shared_ptr input_image_parametric_ptr; - PostFiltering > post_filtering; + PostFiltering> post_filtering; std::string out_filename, output_file_format_par = "", input_filename = ""; bool verbose = false; // option processing - while (argc>1 && argv[1][0]=='-') - { - if (strcmp(argv[1], "--verbose") == 0) - { - verbose = true; - --argc; ++argv; - } - else if (strcmp(argv[1], "--dynamic") == 0) - { - image_type = dynamic; - --argc; ++argv; - } - else if (strcmp(argv[1], "--parametric") == 0) - { - image_type = parametric; - --argc; ++argv; - } - else - { - print_usage(); - return EXIT_FAILURE; - } - } - if (argc<4 || argc>5) - { + while (argc > 1 && argv[1][0] == '-') { + if (strcmp(argv[1], "--verbose") == 0) { + verbose = true; + --argc; + ++argv; + } else if (strcmp(argv[1], "--dynamic") == 0) { + image_type = dynamic; + --argc; + ++argv; + } else if (strcmp(argv[1], "--parametric") == 0) { + image_type = parametric; + --argc; + ++argv; + } else { print_usage(); return EXIT_FAILURE; } - if (argc>1) - { - out_filename = argv[1]; - } - else - { - char outfile[max_filename_length]; - ask_filename_with_extension(outfile, - "Output to which file: ", ""); - out_filename = outfile; - } - if (argc>2) - { - input_filename = argv[2]; - } - - if (argc>3) - { - if (post_filtering.parse(argv[3]) == false) - { - warning("postfilter aborting because error in parsing. Not writing any output"); - return EXIT_FAILURE; - } - } - else - { - cerr << "\nI'm going to ask you for the type of filter (or image processor)\n" - "Possible values:\n"; - DataProcessor >::list_registered_names(cerr); - - post_filtering.ask_parameters(); - } - if (argc>4) - { - output_file_format_par = argv[4]; - } + } + if (argc < 4 || argc > 5) { + print_usage(); + return EXIT_FAILURE; + } + if (argc > 1) { + out_filename = argv[1]; + } else { + char outfile[max_filename_length]; + ask_filename_with_extension(outfile, "Output to which file: ", ""); + out_filename = outfile; + } + if (argc > 2) { + input_filename = argv[2]; + } - if (post_filtering.is_filter_null()) - { - warning("postfilter: No filter set. Not writing any output.\n"); + if (argc > 3) { + if (post_filtering.parse(argv[3]) == false) { + warning("postfilter aborting because error in parsing. Not writing any output"); return EXIT_FAILURE; } + } else { + cerr << "\nI'm going to ask you for the type of filter (or image processor)\n" + "Possible values:\n"; + DataProcessor>::list_registered_names(cerr); + + post_filtering.ask_parameters(); + } + if (argc > 4) { + output_file_format_par = argv[4]; + } + + if (post_filtering.is_filter_null()) { + warning("postfilter: No filter set. Not writing any output.\n"); + return EXIT_FAILURE; + } // Read image if (image_type == normal) - input_image_single_ptr = - read_image >(input_filename); + input_image_single_ptr = read_image>(input_filename); else if (image_type == dynamic) - input_image_dynamic_ptr = - read_image(input_filename); + input_image_dynamic_ptr = read_image(input_filename); else /*if (image_type == parametric)*/ - input_image_parametric_ptr = - read_image(input_filename); + input_image_parametric_ptr = read_image(input_filename); - if (verbose) - { - cerr << "PostFilteringParameters:\n" << post_filtering.parameter_info(); - } + if (verbose) { + cerr << "PostFilteringParameters:\n" << post_filtering.parameter_info(); + } // Post filter! stir::Succeeded success(Succeeded::yes); if (image_type == normal) - success = post_filtering.process_data(*input_image_single_ptr); + success = post_filtering.process_data(*input_image_single_ptr); else if (image_type == dynamic) { - for (unsigned i=1; i<=input_image_dynamic_ptr->get_num_time_frames(); i++) { - if (post_filtering.process_data(input_image_dynamic_ptr->get_density(i)) == Succeeded::no) { - success = Succeeded::no; - break; - } + for (unsigned i = 1; i <= input_image_dynamic_ptr->get_num_time_frames(); i++) { + if (post_filtering.process_data(input_image_dynamic_ptr->get_density(i)) == Succeeded::no) { + success = Succeeded::no; + break; } - } - else /*if (image_type == parametric)*/ { - for (unsigned i=1; i<=input_image_parametric_ptr->get_num_params(); i++) { - VoxelsOnCartesianGrid single_parametric_param = - input_image_parametric_ptr->construct_single_density(int(i)); - if (post_filtering.process_data(single_parametric_param) == Succeeded::no) { - success = Succeeded::no; - break; - } - input_image_parametric_ptr->update_parametric_image(single_parametric_param,i); + } + } else /*if (image_type == parametric)*/ { + for (unsigned i = 1; i <= input_image_parametric_ptr->get_num_params(); i++) { + VoxelsOnCartesianGrid single_parametric_param = input_image_parametric_ptr->construct_single_density(int(i)); + if (post_filtering.process_data(single_parametric_param) == Succeeded::no) { + success = Succeeded::no; + break; } + input_image_parametric_ptr->update_parametric_image(single_parametric_param, i); + } } if (success == Succeeded::no) - error("Postfiltering failed."); + error("Postfiltering failed."); // Save to file if (image_type == normal) @@ -289,5 +256,3 @@ main(int argc, char *argv[]) return EXIT_SUCCESS; } - - diff --git a/src/utilities/rebin_projdata.cxx b/src/utilities/rebin_projdata.cxx index 350b9b340f..291da413e4 100644 --- a/src/utilities/rebin_projdata.cxx +++ b/src/utilities/rebin_projdata.cxx @@ -10,12 +10,12 @@ Here's a sample .par file \verbatim -rebin_projdata Parameters := +rebin_projdata Parameters := rebinning type := FORE FORE Parameters := ... End FORE Parameters:= -END:= +END:= \endverbatim \author Kris Thielemans @@ -38,12 +38,11 @@ END:= See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ProjDataRebinning.h" #include "stir/Succeeded.h" #include "stir/shared_ptr.h" #include "stir/is_null_ptr.h" -#include +#include #ifndef STIR_NO_NAMESPACES using std::cerr; @@ -53,43 +52,32 @@ using std::endl; START_NAMESPACE_STIR // TODO most of this is identical to others, so make a common class -class RebinProjDataParameters : public ParsingObject -{ +class RebinProjDataParameters : public ParsingObject { public: - - RebinProjDataParameters(const char * const par_filename); + RebinProjDataParameters(const char* const par_filename); shared_ptr proj_data_rebinning_sptr; -private: +private: virtual void set_defaults(); virtual void initialise_keymap(); virtual bool post_processing(); - }; -void -RebinProjDataParameters:: -set_defaults() -{ +void +RebinProjDataParameters::set_defaults() { proj_data_rebinning_sptr.reset(); } -void -RebinProjDataParameters:: -initialise_keymap() -{ +void +RebinProjDataParameters::initialise_keymap() { parser.add_start_key("Rebin_projdata Parameters"); parser.add_parsing_key("rebinning type", &proj_data_rebinning_sptr); parser.add_stop_key("END"); } - bool -RebinProjDataParameters:: -post_processing() -{ - if (is_null_ptr(proj_data_rebinning_sptr)) - { +RebinProjDataParameters::post_processing() { + if (is_null_ptr(proj_data_rebinning_sptr)) { warning("Invalid rebinning object\n"); return true; } @@ -97,44 +85,32 @@ post_processing() return false; } -RebinProjDataParameters:: -RebinProjDataParameters(const char * const par_filename) -{ +RebinProjDataParameters::RebinProjDataParameters(const char* const par_filename) { set_defaults(); Succeeded success = Succeeded::yes; - if (par_filename!=0) - success = parse(par_filename)==true? Succeeded::yes : Succeeded::no; + if (par_filename != 0) + success = parse(par_filename) == true ? Succeeded::yes : Succeeded::no; else ask_parameters(); - - if (success== Succeeded::no || - proj_data_rebinning_sptr->set_up()!= Succeeded::yes) - error("Rebin_projdata: set-up failed\n"); - + if (success == Succeeded::no || proj_data_rebinning_sptr->set_up() != Succeeded::yes) + error("Rebin_projdata: set-up failed\n"); } END_NAMESPACE_STIR - -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) { USING_NAMESPACE_STIR - if(argc!=2) - { - cerr<<"Usage: " << argv[0] << " par_file\n" - << endl; + if (argc != 2) { + cerr << "Usage: " << argv[0] << " par_file\n" << endl; } - RebinProjDataParameters parameters( argc==2 ? argv[1] : 0); - - if (argc!=2) - { - cerr << "Corresponding .par file input \n" - << parameters.parameter_info() << endl; - } - - return - parameters.proj_data_rebinning_sptr->rebin() == Succeeded::yes? - EXIT_SUCCESS: EXIT_FAILURE; + RebinProjDataParameters parameters(argc == 2 ? argv[1] : 0); + + if (argc != 2) { + cerr << "Corresponding .par file input \n" << parameters.parameter_info() << endl; + } + + return parameters.proj_data_rebinning_sptr->rebin() == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/utilities/shift_image.cxx b/src/utilities/shift_image.cxx index 5db773bc1b..b0d9867834 100644 --- a/src/utilities/shift_image.cxx +++ b/src/utilities/shift_image.cxx @@ -1,21 +1,21 @@ /* Copyright (C) 2010 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities \brief This program shifts the origin of an image. \author Charalampos Tsoumpas @@ -33,76 +33,74 @@ using std::cerr; USING_NAMESPACE_STIR - -int main(int argc, char **argv) -{ - if(argc<3 || argc>7) { - cerr<<"Usage: " << argv[0] << " [x-shift] [y-shift] [z-shift] [extend_borders]\n" - << "all shifts are in mm and defaults are set to 0mm\n" - << "extend borders is either 1 or 0, defaults to 0\n"; +int +main(int argc, char** argv) { + if (argc < 3 || argc > 7) { + cerr << "Usage: " << argv[0] + << " [x-shift] [y-shift] [z-shift] [extend_borders]\n" + << "all shifts are in mm and defaults are set to 0mm\n" + << "extend borders is either 1 or 0, defaults to 0\n"; exit(EXIT_FAILURE); } - + // get parameters from command line - char const * const output_filename = argv[1]; - char const * const input_filename = argv[2]; - const float x_shift_in_mm = (argc>3) ? static_cast(atof(argv[3])) : 0; - const float y_shift_in_mm = (argc>4) ? static_cast(atof(argv[4])) : 0; - const float z_shift_in_mm = (argc>5) ? static_cast(atof(argv[5])) : 0; - const int extend_borders = (argc>6) ? atoi(argv[6]) : 0; - + char const* const output_filename = argv[1]; + char const* const input_filename = argv[2]; + const float x_shift_in_mm = (argc > 3) ? static_cast(atof(argv[3])) : 0; + const float y_shift_in_mm = (argc > 4) ? static_cast(atof(argv[4])) : 0; + const float z_shift_in_mm = (argc > 5) ? static_cast(atof(argv[5])) : 0; + const int extend_borders = (argc > 6) ? atoi(argv[6]) : 0; + // read image - const shared_ptr > density_sptr( - DiscretisedDensity<3,float>::read_from_file(input_filename)); - const DiscretisedDensityOnCartesianGrid <3,float>* density_cartesian_sptr = - dynamic_cast< DiscretisedDensityOnCartesianGrid<3,float>* > (density_sptr.get()); - const BasicCoordinate<3,float> grid_spacing=density_cartesian_sptr->get_grid_spacing(); - const CartesianCoordinate3D origin=density_cartesian_sptr->get_origin(); + const shared_ptr> density_sptr(DiscretisedDensity<3, float>::read_from_file(input_filename)); + const DiscretisedDensityOnCartesianGrid<3, float>* density_cartesian_sptr = + dynamic_cast*>(density_sptr.get()); + const BasicCoordinate<3, float> grid_spacing = density_cartesian_sptr->get_grid_spacing(); + const CartesianCoordinate3D origin = density_cartesian_sptr->get_origin(); + + const Coordinate3D image_shift(z_shift_in_mm, y_shift_in_mm, x_shift_in_mm); + const int voxel_shift_z = stir::round(image_shift[1] / grid_spacing[1]); + const int voxel_shift_y = stir::round(image_shift[2] / grid_spacing[2]); + const int voxel_shift_x = stir::round(image_shift[3] / grid_spacing[3]); + const Coordinate3D num_voxels_to_shift(voxel_shift_z, voxel_shift_y, voxel_shift_x); + + const float actual_z_shift_in_mm = static_cast(voxel_shift_z) * grid_spacing[1]; + const float actual_y_shift_in_mm = static_cast(voxel_shift_y) * grid_spacing[2]; + const float actual_x_shift_in_mm = static_cast(voxel_shift_x) * grid_spacing[3]; - const Coordinate3D image_shift(z_shift_in_mm,y_shift_in_mm,x_shift_in_mm); - const int voxel_shift_z=stir::round(image_shift[1]/grid_spacing[1]); - const int voxel_shift_y=stir::round(image_shift[2]/grid_spacing[2]); - const int voxel_shift_x=stir::round(image_shift[3]/grid_spacing[3]); - const Coordinate3D num_voxels_to_shift(voxel_shift_z,voxel_shift_y,voxel_shift_x); - - const float actual_z_shift_in_mm = static_cast (voxel_shift_z)*grid_spacing[1]; - const float actual_y_shift_in_mm = static_cast (voxel_shift_y)*grid_spacing[2]; - const float actual_x_shift_in_mm = static_cast (voxel_shift_x)*grid_spacing[3]; - std::cerr << "Actual z shift: " << actual_z_shift_in_mm << "mm\n"; std::cerr << "Actual y shift: " << actual_y_shift_in_mm << "mm\n"; std::cerr << "Actual x shift: " << actual_x_shift_in_mm << "mm\n"; - BasicCoordinate<3,int> min; BasicCoordinate<3,int> max; - const IndexRange<3> range=density_sptr->get_index_range(); - if (!range.get_regular_range(min,max)) + BasicCoordinate<3, int> min; + BasicCoordinate<3, int> max; + const IndexRange<3> range = density_sptr->get_index_range(); + if (!range.get_regular_range(min, max)) error("image is not in regular grid.\n"); - BasicCoordinate<3,int> out_min=min; BasicCoordinate<3,int> out_max=max; - if (extend_borders==1) { - out_min[1]-=abs(voxel_shift_z) ; - out_min[2]-=abs(voxel_shift_y) ; - out_min[3]-=abs(voxel_shift_x) ; - out_max[1]+=abs(voxel_shift_z) ; - out_max[2]+=abs(voxel_shift_y) ; - out_max[3]+=abs(voxel_shift_x) ; + BasicCoordinate<3, int> out_min = min; + BasicCoordinate<3, int> out_max = max; + if (extend_borders == 1) { + out_min[1] -= abs(voxel_shift_z); + out_min[2] -= abs(voxel_shift_y); + out_min[3] -= abs(voxel_shift_x); + out_max[1] += abs(voxel_shift_z); + out_max[2] += abs(voxel_shift_y); + out_max[3] += abs(voxel_shift_x); } - const IndexRange<3> out_range(out_min,out_max); - VoxelsOnCartesianGrid out_density(out_range,origin,grid_spacing); - - BasicCoordinate<3,int> c, d; - for (c[1]=min[1]; c[1]<=max[1]; ++c[1]) - for (c[2]=min[2]; c[2]<=max[2]; ++c[2]) - for (c[3]=min[3]; c[3]<=max[3]; ++c[3]) - { - d=c+num_voxels_to_shift; - if (d[1]>=out_min[1] && d[2]>=out_min[2] && d[3]>=out_min[3] && d[1]<=out_max[1] && d[2]<=out_max[2] && d[3]<=out_max[3]) - out_density[d] = (*density_sptr)[c]; - } - + const IndexRange<3> out_range(out_min, out_max); + VoxelsOnCartesianGrid out_density(out_range, origin, grid_spacing); + + BasicCoordinate<3, int> c, d; + for (c[1] = min[1]; c[1] <= max[1]; ++c[1]) + for (c[2] = min[2]; c[2] <= max[2]; ++c[2]) + for (c[3] = min[3]; c[3] <= max[3]; ++c[3]) { + d = c + num_voxels_to_shift; + if (d[1] >= out_min[1] && d[2] >= out_min[2] && d[3] >= out_min[3] && d[1] <= out_max[1] && d[2] <= out_max[2] && + d[3] <= out_max[3]) + out_density[d] = (*density_sptr)[c]; + } + // write image - Succeeded res = - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, out_density); - return res==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + Succeeded res = OutputFileFormat>::default_sptr()->write_to_file(output_filename, out_density); + return res == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } - diff --git a/src/utilities/shift_image_origin.cxx b/src/utilities/shift_image_origin.cxx index 8387d35f10..e502254aa3 100644 --- a/src/utilities/shift_image_origin.cxx +++ b/src/utilities/shift_image_origin.cxx @@ -1,21 +1,21 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities \brief This program shifts the origin of an image. \author Charalampos Tsoumpas @@ -30,37 +30,30 @@ using std::cerr; USING_NAMESPACE_STIR - -int main(int argc, char **argv) -{ - if(argc<3 || argc>6) { - cerr<<"Usage: " << argv[0] << " [x-shift] [y-shift] [z-shift] ] ] ]\n" - << "all shifts are in mm and defaults are set to 0mm\n"; +int +main(int argc, char** argv) { + if (argc < 3 || argc > 6) { + cerr << "Usage: " << argv[0] << " [x-shift] [y-shift] [z-shift] ] ] ]\n" + << "all shifts are in mm and defaults are set to 0mm\n"; exit(EXIT_FAILURE); } - + // get parameters from command line - char const * const output_filename = argv[1]; - char const * const input_filename = argv[2]; - const float x_shift_in_mm = (argc>3) ? static_cast(atof(argv[3])) : 0; - const float y_shift_in_mm = (argc>4) ? static_cast(atof(argv[4])) : 0; - const float z_shift_in_mm = (argc>5) ? static_cast(atof(argv[5])) : 0; - - // read image - shared_ptr > density_sptr( - DiscretisedDensity<3,float>::read_from_file(input_filename)); - shared_ptr > out_density_sptr(density_sptr->clone()); - const Coordinate3D origin=density_sptr->get_origin(); - const Coordinate3D origin_shift(z_shift_in_mm,y_shift_in_mm,x_shift_in_mm); - out_density_sptr->set_origin(origin+origin_shift); + char const* const output_filename = argv[1]; + char const* const input_filename = argv[2]; + const float x_shift_in_mm = (argc > 3) ? static_cast(atof(argv[3])) : 0; + const float y_shift_in_mm = (argc > 4) ? static_cast(atof(argv[4])) : 0; + const float z_shift_in_mm = (argc > 5) ? static_cast(atof(argv[5])) : 0; + + // read image + shared_ptr> density_sptr(DiscretisedDensity<3, float>::read_from_file(input_filename)); + shared_ptr> out_density_sptr(density_sptr->clone()); + const Coordinate3D origin = density_sptr->get_origin(); + const Coordinate3D origin_shift(z_shift_in_mm, y_shift_in_mm, x_shift_in_mm); + out_density_sptr->set_origin(origin + origin_shift); // write image - Succeeded res = - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, *out_density_sptr); - return res==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + Succeeded res = + OutputFileFormat>::default_sptr()->write_to_file(output_filename, *out_density_sptr); + return res == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } - - - - diff --git a/src/utilities/stir_math.cxx b/src/utilities/stir_math.cxx index 3c2ab3ea7a..442fe81d6f 100644 --- a/src/utilities/stir_math.cxx +++ b/src/utilities/stir_math.cxx @@ -19,23 +19,23 @@ /*! \file \ingroup utilities - \brief add or multiply data, with some other basic math manipulations + \brief add or multiply data, with some other basic math manipulations - This is a command line utility for adding, multiplying, thresholding ... data, - with a somewhat awkward syntax. + This is a command line utility for adding, multiplying, thresholding ... data, + with a somewhat awkward syntax. The command line arguments are as follows (but everything has to fit on 1 line): \code [--output-format parameter-filename ] [--parametric || --dynamic] - [-s [--max_segment_num_to_process number] ] - [--add | --mult] - [--power power_float] - [--times-scalar mult_scalar_float] - [--divide-scalar divide_scalar_float] - [--add-scalar add_scalar_float] + [-s [--max_segment_num_to_process number] ] + [--add | --mult] + [--power power_float] + [--times-scalar mult_scalar_float] + [--divide-scalar divide_scalar_float] + [--add-scalar add_scalar_float] [--min-threshold min_threshold] [--max-threshold max_threshold] - [--including-first] + [--including-first] [--verbose] output_filename_with_extension in_data1 [in_data2 [in_data3...]] \endcode @@ -43,27 +43,27 @@ \code [--output-format parameter-filename ] --accumulate - [-s] + [-s] [--parametric || --dynamic] - [--add | --mult] - [--power power_float] - [--times-scalar mult_scalar_float] - [--divide-scalar divide_scalar_float] - [--add-scalar add_scalar_float] + [--add | --mult] + [--power power_float] + [--times-scalar mult_scalar_float] + [--divide-scalar divide_scalar_float] + [--add-scalar add_scalar_float] [--min-threshold min_threshold] [--max-threshold max_threshold] - [--including-first] + [--including-first] [--verbose] out_and_input_filename in_data2 [in_data3 [in_data4...]] \endcode '--add' is default, and outputs the sum of the result of processed data. '--mult' outputs the multiplication of the result of processed data.
      - The '--include-first' option can be used such that power and scalar - multiplication are done on the first input argument as well. + The '--include-first' option can be used such that power and scalar + multiplication are done on the first input argument as well. Otherwise these manipulations are done only on the 2nd, 3rd,.. argument.
      The '--accumulate' option can be used to say that the first filename given will be - used for input AND output. Note that when using this option together with + used for input AND output. Note that when using this option together with '--including-first', the data in the first filename will first be manipulated according to '--power' and '--times-scalar'.
      The '-s' option is necessary if the arguments are projection data. @@ -78,7 +78,7 @@ The order of the manipulations is as follows:
      (1) thresholding (2) power (3) scalar multiplication (4) scalar addition. - The '--output-format' option can be used to write the output in + The '--output-format' option can be used to write the output in a different file format then the default (although this currently only works for images). The parameter file should have the following format: \verbatim @@ -100,19 +100,19 @@ \code stir_math --accumulate --mult --power -1 in1 in2 \endcode
    - \warning There is no check that the data sizes and other info are compatible - and the output will have the largest data size in the input, - and the characteristics (like voxel-size or so) are taken from the first input data. + \warning There is no check that the data sizes and other info are compatible + and the output will have the largest data size in the input, + and the characteristics (like voxel-size or so) are taken from the first input data. Hence, lots of funny effects can happen if data are not compatible. \warning When '--accumulate' is not used, the output file HAS to be different from all the input files. - \warning The result of using non-integral powers on negative numbers is probably + \warning The result of using non-integral powers on negative numbers is probably system-dependent. \warning For future compatibility, it is recommended to put the command line arguments - in the order that they will be executed (i.e. as listed above). It might be + in the order that they will be executed (i.e. as listed above). It might be that we take the order into account in a future release. - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/ArrayFunction.h" @@ -132,8 +132,8 @@ #include "stir/DynamicDiscretisedDensity.h" #include "stir/stir_math.h" -#include -#include +#include +#include #include #include #include @@ -150,109 +150,77 @@ using std::string; using std::vector; #endif - USING_NAMESPACE_STIR template -void process_data(const string& output_file_name, - const int num_files, char **argv, - const bool no_math_on_data, - const bool except_first, - const bool verbose, - const bool do_add, - const FunctionObjectT& pow_times_add_object, - const OutputFileFormat& output_format) -{ - unique_ptr< DataT > image_ptr = - read_from_file(*argv); - if (!no_math_on_data && !except_first ) +void +process_data(const string& output_file_name, const int num_files, char** argv, const bool no_math_on_data, + const bool except_first, const bool verbose, const bool do_add, const FunctionObjectT& pow_times_add_object, + const OutputFileFormat& output_format) { + unique_ptr image_ptr = read_from_file(*argv); + if (!no_math_on_data && !except_first) in_place_apply_function(*image_ptr, pow_times_add_object); - shared_ptr< DataT > current_image_ptr; - - for (int i=1; ibegin_all(), image_ptr->end_all(), - current_image_ptr->begin_all(), - image_ptr->begin_all(), - std::plus()); - } - else - { - // *image_ptr *= *current_image_ptr; - std::transform(image_ptr->begin_all(), image_ptr->end_all(), - current_image_ptr->begin_all(), - image_ptr->begin_all(), - std::multiplies()); - } + shared_ptr current_image_ptr; + + for (int i = 1; i < num_files; ++i) { + if (verbose) + cout << "Reading image " << argv[i] << endl; + current_image_ptr.reset(DataT::read_from_file(argv[i])); + if (!no_math_on_data) + in_place_apply_function(*current_image_ptr, pow_times_add_object); + if (do_add) { + // TODO the next line doesn't work with some DataT, but its replacement is ugly! + // also, it would be better to be able to call += on each element + //*image_ptr += *current_image_ptr; + std::transform(image_ptr->begin_all(), image_ptr->end_all(), current_image_ptr->begin_all(), image_ptr->begin_all(), + std::plus()); + } else { + // *image_ptr *= *current_image_ptr; + std::transform(image_ptr->begin_all(), image_ptr->end_all(), current_image_ptr->begin_all(), image_ptr->begin_all(), + std::multiplies()); } + } if (verbose) cout << "Writing output image " << output_file_name << endl; output_format.write_to_file(output_file_name, *image_ptr); } -template //class DataT, for DynProjectionData ? -void process_data(const string& output_file_name, - const int num_files, char **argv, - const bool no_math_on_data, - const bool except_first, - const bool verbose, - const bool do_add, - const FunctionObjectT& pow_times_add_object, - const OutputFileFormat& output_format) -{ - unique_ptr - dyn_image_sptr = read_from_file(*argv); - DynamicDiscretisedDensity & dyn_image = *dyn_image_sptr; - for(unsigned int frame_num=1;frame_num<=(dyn_image_sptr->get_time_frame_definitions()).get_num_frames();++frame_num) - { - if (!no_math_on_data && !except_first ) - in_place_apply_function(dyn_image[frame_num], pow_times_add_object); - } +template // class DataT, for DynProjectionData ? +void +process_data(const string& output_file_name, const int num_files, char** argv, const bool no_math_on_data, + const bool except_first, const bool verbose, const bool do_add, const FunctionObjectT& pow_times_add_object, + const OutputFileFormat& output_format) { + unique_ptr dyn_image_sptr = read_from_file(*argv); + DynamicDiscretisedDensity& dyn_image = *dyn_image_sptr; + for (unsigned int frame_num = 1; frame_num <= (dyn_image_sptr->get_time_frame_definitions()).get_num_frames(); ++frame_num) { + if (!no_math_on_data && !except_first) + in_place_apply_function(dyn_image[frame_num], pow_times_add_object); + } shared_ptr dyn_current_image_sptr; - for (int i=1; i(argv[i]); - DynamicDiscretisedDensity & dyn_current_image = *dyn_current_image_sptr; - for(unsigned int frame_num=1;frame_num<=(dyn_image_sptr->get_time_frame_definitions()).get_num_frames();++frame_num) - { - if (!no_math_on_data) - in_place_apply_function(dyn_current_image[frame_num], pow_times_add_object); - if (do_add) - { - // TODO the next line doesn't work with some DataT, but its replacement is ugly! - // also, it would be better to be able to call += on each element - //*image_ptr += *current_image_ptr; - std::transform(dyn_image[frame_num].begin_all(), dyn_image[frame_num].end_all(), - dyn_current_image[frame_num].begin_all(), - dyn_image[frame_num].begin_all(), - std::plus()); - } - else - { - // *image_ptr *= *current_image_ptr; - std::transform(dyn_image[frame_num].begin_all(), dyn_image[frame_num].end_all(), - dyn_current_image[frame_num].begin_all(), - dyn_image[frame_num].begin_all(), - std::multiplies()); - } - } + for (int i = 1; i < num_files; ++i) { + if (verbose) + cout << "Reading image " << argv[i] << endl; + dyn_current_image_sptr = read_from_file(argv[i]); + DynamicDiscretisedDensity& dyn_current_image = *dyn_current_image_sptr; + for (unsigned int frame_num = 1; frame_num <= (dyn_image_sptr->get_time_frame_definitions()).get_num_frames(); ++frame_num) { + if (!no_math_on_data) + in_place_apply_function(dyn_current_image[frame_num], pow_times_add_object); + if (do_add) { + // TODO the next line doesn't work with some DataT, but its replacement is ugly! + // also, it would be better to be able to call += on each element + //*image_ptr += *current_image_ptr; + std::transform(dyn_image[frame_num].begin_all(), dyn_image[frame_num].end_all(), dyn_current_image[frame_num].begin_all(), + dyn_image[frame_num].begin_all(), std::plus()); + } else { + // *image_ptr *= *current_image_ptr; + std::transform(dyn_image[frame_num].begin_all(), dyn_image[frame_num].end_all(), dyn_current_image[frame_num].begin_all(), + dyn_image[frame_num].begin_all(), std::multiplies()); + } } + } if (verbose) cout << "Writing output image " << output_file_name << endl; @@ -260,81 +228,77 @@ void process_data(const string& output_file_name, } template -shared_ptr > -find_output_format(const std::string& filename) -{ +shared_ptr> +find_output_format(const std::string& filename) { if (filename.empty()) return OutputFileFormat::default_sptr(); - shared_ptr > output_format_sptr; + shared_ptr> output_format_sptr; KeyParser parser; parser.add_start_key("output file format parameters"); parser.add_parsing_key("output file format type", &output_format_sptr); parser.add_stop_key("END"); - if (parser.parse(filename.c_str()) == false || is_null_ptr(output_format_sptr)) - { - cerr << "Error parsing output file format from " << filename <().min_value(); @@ -350,258 +314,216 @@ main(int argc, char **argv) // first process command line options - while (argc>0 && argv[0][0]=='-') - { - if (strcmp(argv[0], "--max_segment_num_to_process")==0) - { - if (argc<2) - { cerr << "Option '--max_segment_num_to_process' expects a (int) argument\n"; exit(EXIT_FAILURE); } - max_segment_num_to_process = atoi(argv[1]); - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "--output-format")==0) - { - if (argc<2) - { - cerr << "Option '--output-format' expects a (filename) argument\n"; - exit(EXIT_FAILURE); - } - output_format_filename = argv[1]; - argc-=2; argv+=2; - } - - else if (strcmp(argv[0], "--add-scalar")==0) - { - if (argc<2) - { cerr << "Option '--add-scalar' expects a (float) argument\n"; exit(EXIT_FAILURE); } - add_scalar += static_cast(atof(argv[1])); - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "--times-scalar")==0) - { - if (argc<2) - { cerr << "Option '--times-scalar' expects a (float) argument\n"; exit(EXIT_FAILURE); } - mult_scalar *= static_cast(atof(argv[1])); - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "--divide-scalar")==0) - { - if (argc<2) - { cerr << "Option '--divide-scalar' expects a (float) argument\n"; exit(EXIT_FAILURE); } - mult_scalar /= static_cast(atof(argv[1])); - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "--max-threshold")==0) - { - if (argc<2) - { cerr << "Option '--max-threshold' expects a (float) argument\n"; exit(EXIT_FAILURE); } - max_threshold = static_cast(atof(argv[1])); - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "--min-threshold")==0) - { - if (argc<2) - { cerr << "Option '--min-threshold' expects a (float) argument\n"; exit(EXIT_FAILURE); } - min_threshold = static_cast(atof(argv[1])); - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "--power")==0) - { - if (argc<2) - { cerr << "Option '--power' expects an argument\n"; exit(EXIT_FAILURE); } - power = static_cast(atof(argv[1])); - argc-=2; argv+=2; - } - else if (strcmp(argv[0], "--including-first")==0) - { - except_first = false; - argc-=1; argv+=1; - } - else if (strcmp(argv[0], "--verbose")==0) - { - verbose = true; - argc-=1; argv+=1; - } - else if (strcmp(argv[0], "-s")==0) - { - do_projdata = true; - argc-=1; argv+=1; - } - else if (strcmp(argv[0], "--parametric")==0) - { - parametric = true; - argc-=1; argv+=1; - } - else if (strcmp(argv[0], "--dynamic")==0) - { - dynamic = true; - argc-=1; argv+=1; - } - else if (strcmp(argv[0], "--add")==0) - { - do_add = true; - argc-=1; argv+=1; - } - else if (strcmp(argv[0], "--mult")==0) - { - do_add = false; - argc-=1; argv+=1; - } - else if (strcmp(argv[0], "--accumulate")==0) - { - accumulate = true; - argc-=1; argv+=1; - } - else - { cerr << "Unknown option '" << argv[0] <<"'\n"; exit(EXIT_FAILURE); } + while (argc > 0 && argv[0][0] == '-') { + if (strcmp(argv[0], "--max_segment_num_to_process") == 0) { + if (argc < 2) { + cerr << "Option '--max_segment_num_to_process' expects a (int) argument\n"; + exit(EXIT_FAILURE); + } + max_segment_num_to_process = atoi(argv[1]); + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--output-format") == 0) { + if (argc < 2) { + cerr << "Option '--output-format' expects a (filename) argument\n"; + exit(EXIT_FAILURE); + } + output_format_filename = argv[1]; + argc -= 2; + argv += 2; + } + + else if (strcmp(argv[0], "--add-scalar") == 0) { + if (argc < 2) { + cerr << "Option '--add-scalar' expects a (float) argument\n"; + exit(EXIT_FAILURE); + } + add_scalar += static_cast(atof(argv[1])); + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--times-scalar") == 0) { + if (argc < 2) { + cerr << "Option '--times-scalar' expects a (float) argument\n"; + exit(EXIT_FAILURE); + } + mult_scalar *= static_cast(atof(argv[1])); + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--divide-scalar") == 0) { + if (argc < 2) { + cerr << "Option '--divide-scalar' expects a (float) argument\n"; + exit(EXIT_FAILURE); + } + mult_scalar /= static_cast(atof(argv[1])); + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--max-threshold") == 0) { + if (argc < 2) { + cerr << "Option '--max-threshold' expects a (float) argument\n"; + exit(EXIT_FAILURE); + } + max_threshold = static_cast(atof(argv[1])); + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--min-threshold") == 0) { + if (argc < 2) { + cerr << "Option '--min-threshold' expects a (float) argument\n"; + exit(EXIT_FAILURE); + } + min_threshold = static_cast(atof(argv[1])); + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--power") == 0) { + if (argc < 2) { + cerr << "Option '--power' expects an argument\n"; + exit(EXIT_FAILURE); + } + power = static_cast(atof(argv[1])); + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "--including-first") == 0) { + except_first = false; + argc -= 1; + argv += 1; + } else if (strcmp(argv[0], "--verbose") == 0) { + verbose = true; + argc -= 1; + argv += 1; + } else if (strcmp(argv[0], "-s") == 0) { + do_projdata = true; + argc -= 1; + argv += 1; + } else if (strcmp(argv[0], "--parametric") == 0) { + parametric = true; + argc -= 1; + argv += 1; + } else if (strcmp(argv[0], "--dynamic") == 0) { + dynamic = true; + argc -= 1; + argv += 1; + } else if (strcmp(argv[0], "--add") == 0) { + do_add = true; + argc -= 1; + argv += 1; + } else if (strcmp(argv[0], "--mult") == 0) { + do_add = false; + argc -= 1; + argv += 1; + } else if (strcmp(argv[0], "--accumulate") == 0) { + accumulate = true; + argc -= 1; + argv += 1; + } else { + cerr << "Unknown option '" << argv[0] << "'\n"; + exit(EXIT_FAILURE); } + } - if (argc==0) - { cerr << "No output file (nor input files) on command line\n"; exit(EXIT_FAILURE); } + if (argc == 0) { + cerr << "No output file (nor input files) on command line\n"; + exit(EXIT_FAILURE); + } // find output filename const string output_file_name = *argv; - if (!accumulate) - { - --argc; ++argv; - } + if (!accumulate) { + --argc; + ++argv; + } // some basic error checking and output const int num_files = argc; - if (num_files==0) - { cerr << "No input files on command line\n"; exit(EXIT_FAILURE); } + if (num_files == 0) { + cerr << "No input files on command line\n"; + exit(EXIT_FAILURE); + } - const bool no_math_on_data = power==1 && mult_scalar==1 && add_scalar==0 && - min_threshold == NumericInfo().min_value() && - max_threshold == NumericInfo().max_value(); + const bool no_math_on_data = power == 1 && mult_scalar == 1 && add_scalar == 0 && + min_threshold == NumericInfo().min_value() && + max_threshold == NumericInfo().max_value(); - - if (verbose) - { - cout << program_name << ": " - << (do_add ? "adding " : "multiplying ") - << num_files; - if (!no_math_on_data) - cout <<" files after thresholding to a min value of " - << min_threshold << "\n and a max value of " - << max_threshold << "\n and then taking a power of " - << power << "\n and then multiplying with " - << mult_scalar << "\n and then adding " - << add_scalar - << (except_first?"\n except for" : " including") - <<" the first file"; - cout << endl; - } + if (verbose) { + cout << program_name << ": " << (do_add ? "adding " : "multiplying ") << num_files; + if (!no_math_on_data) + cout << " files after thresholding to a min value of " << min_threshold << "\n and a max value of " << max_threshold + << "\n and then taking a power of " << power << "\n and then multiplying with " << mult_scalar + << "\n and then adding " << add_scalar << (except_first ? "\n except for" : " including") << " the first file"; + cout << endl; + } // construct function object that does the manipulations on each data pow_times_add pow_times_add_object(add_scalar, mult_scalar, power, min_threshold, max_threshold); // start the main processing - if (!do_projdata) - { - - if (!parametric && !dynamic) - { - process_data(output_file_name, - num_files, argv, - no_math_on_data, - except_first, - verbose, - do_add, - pow_times_add_object, - *find_output_format >(output_format_filename)); - } - else if (parametric) - { - process_data(output_file_name, - num_files, argv, - no_math_on_data, - except_first, - verbose, - do_add, - pow_times_add_object, - *find_output_format(output_format_filename)); - } - else if (dynamic) - { - process_data(output_file_name, - num_files, argv, - no_math_on_data, - except_first, - verbose, - do_add, - pow_times_add_object, - *find_output_format(output_format_filename)); - } + if (!do_projdata) { + + if (!parametric && !dynamic) { + process_data(output_file_name, num_files, argv, no_math_on_data, except_first, verbose, do_add, pow_times_add_object, + *find_output_format>(output_format_filename)); + } else if (parametric) { + process_data(output_file_name, num_files, argv, no_math_on_data, except_first, verbose, do_add, pow_times_add_object, + *find_output_format(output_format_filename)); + } else if (dynamic) { + process_data(output_file_name, num_files, argv, no_math_on_data, except_first, verbose, do_add, pow_times_add_object, + *find_output_format(output_format_filename)); + } + } else // do_projdata + { + if (!output_format_filename.empty()) + error("We do not support specifying the output format yet for projection data"); + + vector> all_proj_data(num_files); + shared_ptr out_proj_data_ptr; + if (accumulate) { + all_proj_data[0] = ProjData::read_from_file(argv[0], std::ios::in | std::ios::out); + out_proj_data_ptr = all_proj_data[0]; + + if (max_segment_num_to_process >= 0) + warning("Parameter max_segment_num_to_process will be ignored."); + } else { + all_proj_data[0] = ProjData::read_from_file(argv[0]); + shared_ptr output_proj_data_info_sptr((*all_proj_data[0]).get_proj_data_info_sptr()->clone()); + if (max_segment_num_to_process >= 0) { + output_proj_data_info_sptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); + } + out_proj_data_ptr.reset( + new ProjDataInterfile((*all_proj_data[0]).get_exam_info_sptr(), output_proj_data_info_sptr, output_file_name)); + } + if (num_files > 1) { + // reset time-frames as we don't really know what's happening with all this + ExamInfo new_exam_info(out_proj_data_ptr->get_exam_info()); + new_exam_info.set_time_frame_definitions(TimeFrameDefinitions()); + out_proj_data_ptr->set_exam_info(new_exam_info); + } + // read rest of projection data headers + for (int i = 1; i < num_files; ++i) + all_proj_data[i] = ProjData::read_from_file(argv[i]); + + // do reading/writing in a loop over segments + for (int segment_num = out_proj_data_ptr->get_min_segment_num(); segment_num <= out_proj_data_ptr->get_max_segment_num(); + ++segment_num) { + if (verbose) + cout << "Processing segment num " << segment_num << " for all files" << endl; + + for (int k = out_proj_data_ptr->get_min_tof_pos_num(); k <= out_proj_data_ptr->get_max_tof_pos_num(); ++k) { + SegmentByView segment_by_view = (*all_proj_data[0]).get_segment_by_view(segment_num, k); + if (!no_math_on_data && !except_first) + in_place_apply_function(segment_by_view, pow_times_add_object); + for (int i = 1; i < num_files; ++i) { + SegmentByView current_segment_by_view = (*all_proj_data[i]).get_segment_by_view(segment_num, k); + if (!no_math_on_data) + in_place_apply_function(current_segment_by_view, pow_times_add_object); + if (do_add) + segment_by_view += current_segment_by_view; + else + segment_by_view *= current_segment_by_view; + } + + if (!(out_proj_data_ptr->set_segment(segment_by_view) == Succeeded::yes)) + warning("Error set_segment %d\n", segment_num); + } } - else // do_projdata - { - if (!output_format_filename.empty()) - error("We do not support specifying the output format yet for projection data"); - - vector< shared_ptr > all_proj_data(num_files); - shared_ptr out_proj_data_ptr; - if (accumulate) - { - all_proj_data[0] = ProjData::read_from_file(argv[0], std::ios::in | std::ios::out); - out_proj_data_ptr = all_proj_data[0]; - - if (max_segment_num_to_process>=0) - warning("Parameter max_segment_num_to_process will be ignored."); - } - else - { - all_proj_data[0] = ProjData::read_from_file(argv[0]); - shared_ptr - output_proj_data_info_sptr((*all_proj_data[0]).get_proj_data_info_sptr()->clone()); - if (max_segment_num_to_process>=0) - { - output_proj_data_info_sptr-> - reduce_segment_range(-max_segment_num_to_process, - max_segment_num_to_process); - } - out_proj_data_ptr.reset(new ProjDataInterfile((*all_proj_data[0]).get_exam_info_sptr(), - output_proj_data_info_sptr, - output_file_name)); - } - if (num_files>1) - { - // reset time-frames as we don't really know what's happening with all this - ExamInfo new_exam_info(out_proj_data_ptr->get_exam_info()); - new_exam_info.set_time_frame_definitions(TimeFrameDefinitions()); - out_proj_data_ptr->set_exam_info(new_exam_info); - } - // read rest of projection data headers - for (int i=1; iget_min_segment_num(); - segment_num <= out_proj_data_ptr->get_max_segment_num(); - ++segment_num) - { - if (verbose) - cout << "Processing segment num " << segment_num << " for all files" << endl; - SegmentByView segment_by_view = - (*all_proj_data[0]).get_segment_by_view(segment_num); - if (!no_math_on_data && !except_first ) - in_place_apply_function(segment_by_view, pow_times_add_object); - for (int i=1; i current_segment_by_view = - (*all_proj_data[i]).get_segment_by_view(segment_num); - if (!no_math_on_data) - in_place_apply_function(current_segment_by_view, pow_times_add_object); - if(do_add) - segment_by_view += current_segment_by_view; - else - segment_by_view *= current_segment_by_view; - } - - if (!(out_proj_data_ptr->set_segment(segment_by_view) == Succeeded::yes)) - warning("Error set_segment %d\n", segment_num); - } - } + } return EXIT_SUCCESS; } diff --git a/src/utilities/stir_write_pgm.cxx b/src/utilities/stir_write_pgm.cxx index 2bf3eda394..f07630053b 100644 --- a/src/utilities/stir_write_pgm.cxx +++ b/src/utilities/stir_write_pgm.cxx @@ -18,9 +18,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities - + \brief This program writes a PGM bitmap for an image (preliminary) Run to get a usage message. @@ -47,188 +47,160 @@ START_NAMESPACE_STIR /* helper functions. Currently copied from manip_image. */ -static VoxelsOnCartesianGrid -transpose_13(const VoxelsOnCartesianGrid & image) -{ +static VoxelsOnCartesianGrid +transpose_13(const VoxelsOnCartesianGrid& image) { CartesianCoordinate3D origin = image.get_origin(); std::swap(origin.x(), origin.z()); CartesianCoordinate3D voxel_size = image.get_voxel_size(); std::swap(voxel_size.x(), voxel_size.z()); - VoxelsOnCartesianGrid - out(IndexRange3D(image.get_min_x(),image.get_max_x(), - image.get_min_y(),image.get_max_y(), - image.get_min_z(),image.get_max_z()), - origin, - voxel_size); - for (int x=image.get_min_x(); x<=image.get_max_x(); ++x) - for (int y=image.get_min_y(); y<=image.get_max_y(); ++y) - for (int z=image.get_min_z(); z<=image.get_max_z(); ++z) + VoxelsOnCartesianGrid out(IndexRange3D(image.get_min_x(), image.get_max_x(), image.get_min_y(), image.get_max_y(), + image.get_min_z(), image.get_max_z()), + origin, voxel_size); + for (int x = image.get_min_x(); x <= image.get_max_x(); ++x) + for (int y = image.get_min_y(); y <= image.get_max_y(); ++y) + for (int z = image.get_min_z(); z <= image.get_max_z(); ++z) out[x][y][z] = image[z][y][x]; return out; } -static VoxelsOnCartesianGrid -transpose_12(const VoxelsOnCartesianGrid & image) -{ +static VoxelsOnCartesianGrid +transpose_12(const VoxelsOnCartesianGrid& image) { CartesianCoordinate3D origin = image.get_origin(); std::swap(origin.y(), origin.z()); CartesianCoordinate3D voxel_size = image.get_voxel_size(); std::swap(voxel_size.y(), voxel_size.z()); - VoxelsOnCartesianGrid - out(IndexRange3D(image.get_min_y(),image.get_max_y(), - image.get_min_z(),image.get_max_z(), - image.get_min_x(),image.get_max_x()), - origin, - voxel_size); - for (int y=image.get_min_y(); y<=image.get_max_y(); ++y) - for (int z=image.get_min_z(); z<=image.get_max_z(); ++z) - for (int x=image.get_min_x(); x<=image.get_max_x(); ++x) + VoxelsOnCartesianGrid out(IndexRange3D(image.get_min_y(), image.get_max_y(), image.get_min_z(), image.get_max_z(), + image.get_min_x(), image.get_max_x()), + origin, voxel_size); + for (int y = image.get_min_y(); y <= image.get_max_y(); ++y) + for (int z = image.get_min_z(); z <= image.get_max_z(); ++z) + for (int x = image.get_min_x(); x <= image.get_max_x(); ++x) out[y][z][x] = image[z][y][x]; return out; } template -static -void -write_pgm (const std::string& filename, - const Array<2,elemT>& plane, - const double min_threshold, const double max_threshold) -{ +static void +write_pgm(const std::string& filename, const Array<2, elemT>& plane, const double min_threshold, const double max_threshold) { if (plane.get_length() == 0) return; - + Coordinate2D min_indices; Coordinate2D max_indices; - if (!plane.get_regular_range(min_indices, max_indices)) - { + if (!plane.get_regular_range(min_indices, max_indices)) { warning("write_pgm: can only display 'regular' arrays. Returning.\n"); return; } - FILE *pgm = fopen ( filename.c_str() , "wb"); - if (pgm == NULL) - { - error("Error opening file %s for output to PGM.",filename.c_str()); + FILE* pgm = fopen(filename.c_str(), "wb"); + if (pgm == NULL) { + error("Error opening file %s for output to PGM.", filename.c_str()); } const int pgm_max = 255; { - const int X = max_indices[2] - min_indices[2] + 1; + const int X = max_indices[2] - min_indices[2] + 1; const int Y = (max_indices[1] - min_indices[1] + 1); - fprintf ( pgm, "P5\n#created by STIR\n%d %d\n%d\n", X , Y, pgm_max); + fprintf(pgm, "P5\n#created by STIR\n%d %d\n%d\n", X, Y, pgm_max); } - - for ( int y = min_indices[1]; y <= max_indices[1]; y++) - { - for ( int x = min_indices[2]; x <= max_indices[2]; x++) - { - double val = static_cast(plane[y][x]); - if (val>max_threshold) - val=max_threshold; - else if (val(stir::round(val)) ); - } + + for (int y = min_indices[1]; y <= max_indices[1]; y++) { + for (int x = min_indices[2]; x <= max_indices[2]; x++) { + double val = static_cast(plane[y][x]); + if (val > max_threshold) + val = max_threshold; + else if (val < min_threshold) + val = min_threshold; + // now to pgm range + val = (val - min_threshold) / (max_threshold - min_threshold) * pgm_max; + fprintf(pgm, "%c", static_cast(stir::round(val))); } - fclose ( pgm); + } + fclose(pgm); } END_NAMESPACE_STIR -void print_usage_and_exit(const std::string& program_name) -{ - std::cerr<< "Usage: " << program_name << "\n\t" - << "[--min min_value] [--max max_value] \\\n\t" - << "[--orientation t|c|s] [--slice_index idx] \\\n\t" - << "output_filename.pgm input_filename \n" - << "min_value default to 0, max_value to max in image\n" - <<"oritentation defaults to transverse\n" - << "slice index is zero-based and defaults to the middle of the image (using rounding)\n"; +void +print_usage_and_exit(const std::string& program_name) { + std::cerr << "Usage: " << program_name << "\n\t" + << "[--min min_value] [--max max_value] \\\n\t" + << "[--orientation t|c|s] [--slice_index idx] \\\n\t" + << "output_filename.pgm input_filename \n" + << "min_value default to 0, max_value to max in image\n" + << "oritentation defaults to transverse\n" + << "slice index is zero-based and defaults to the middle of the image (using rounding)\n"; exit(EXIT_FAILURE); } -int -main(int argc, char **argv) -{ - const char * const program_name = argv[0]; +int +main(int argc, char** argv) { + const char* const program_name = argv[0]; // skip program name --argc; ++argv; - double min_threshold=0.; - double max_threshold=-1.; + double min_threshold = 0.; + double max_threshold = -1.; char orientation = 't'; int slice_index = -1; - // first process command line options - while (argc>0 && argv[0][0]=='-' && argc>=2) - { - if (strcmp(argv[0], "--max")==0) - { - max_threshold = atof(argv[1]); - } - else if (strcmp(argv[0], "--min")==0) - { - min_threshold = atof(argv[1]); - } - else if (strcmp(argv[0], "--orientation")==0) - { - orientation = argv[1][0]; - } - else if (strcmp(argv[0], "--slice_index")==0) - { - slice_index = atoi(argv[1]); - } - else - { - std::cerr << "Unknown option: " < 0 && argv[0][0] == '-' && argc >= 2) { + if (strcmp(argv[0], "--max") == 0) { + max_threshold = atof(argv[1]); + } else if (strcmp(argv[0], "--min") == 0) { + min_threshold = atof(argv[1]); + } else if (strcmp(argv[0], "--orientation") == 0) { + orientation = argv[1][0]; + } else if (strcmp(argv[0], "--slice_index") == 0) { + slice_index = atoi(argv[1]); + } else { + std::cerr << "Unknown option: " << argv[0] << '\n'; + print_usage_and_exit(argv[0]); } + argc -= 2; + argv += 2; + } - if(argc!=2) - { - print_usage_and_exit(program_name); - } + if (argc != 2) { + print_usage_and_exit(program_name); + } const std::string filename = argv[0]; const std::string input_filename = argv[1]; - stir::VoxelsOnCartesianGrid image( - dynamic_cast &> - (* stir::read_from_file >(input_filename))); + stir::VoxelsOnCartesianGrid image(dynamic_cast&>( + *stir::read_from_file>(input_filename))); if (max_threshold < min_threshold) max_threshold = image.find_max(); - switch (orientation) - { - case 't': case 'T': - // transverse, nothing to do at the moment - break; - case 's': case 'S': - // sagital - image=stir::transpose_13(image); - break; - case 'c': case 'C': - // coronal - image=stir::transpose_12(image); - break; - default: - stir::error("Unsupported orientation %d, has to be t,s, or c", orientation); - } + switch (orientation) { + case 't': + case 'T': + // transverse, nothing to do at the moment + break; + case 's': + case 'S': + // sagital + image = stir::transpose_13(image); + break; + case 'c': + case 'C': + // coronal + image = stir::transpose_12(image); + break; + default: + stir::error("Unsupported orientation %d, has to be t,s, or c", orientation); + } - if (slice_index<0) - slice_index = stir::round(image.get_length()/2.); - else if (slice_index >= image.get_length()) + if (slice_index < 0) + slice_index = stir::round(image.get_length() / 2.); + else if (slice_index >= image.get_length()) stir::error("Requested slice index too large"); - stir::write_pgm (filename, - image[slice_index + image.get_min_index()], - min_threshold, max_threshold); + stir::write_pgm(filename, image[slice_index + image.get_min_index()], min_threshold, max_threshold); return EXIT_SUCCESS; } diff --git a/src/utilities/warp_and_accumulate_gated_images.cxx b/src/utilities/warp_and_accumulate_gated_images.cxx index 0f98586f8a..ee76b8b174 100644 --- a/src/utilities/warp_and_accumulate_gated_images.cxx +++ b/src/utilities/warp_and_accumulate_gated_images.cxx @@ -2,24 +2,24 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details - */ + */ /*! - \file + \file \ingroup utilities \ingroup spatial_transformation - + \brief This program corrects the motion from an image. \author Charalampos Tsoumpas */ @@ -40,24 +40,23 @@ USING_NAMESPACE_STIR using namespace BSpline; - -int main(int argc, char **argv) -{ - if(argc<3 || argc>4) { - cerr<<"Usage: " << argv[0] << " \n"; +int +main(int argc, char** argv) { + if (argc < 3 || argc > 4) { + cerr << "Usage: " << argv[0] << " \n"; exit(EXIT_FAILURE); } // GatedDiscretisedDensity tmp; const GatedDiscretisedDensity gated_density(argv[2]); GatedSpatialTransformation transformation; - if(argc==3) + if (argc == 3) transformation.read_from_files(argv[2]); - else if(argc==4) + else if (argc == 4) transformation.read_from_files(argv[3]); - shared_ptr > corrected_image_sptr((gated_density[1]).get_empty_copy()); - transformation.warp_image(*corrected_image_sptr,gated_density); - - const Succeeded res = OutputFileFormat >::default_sptr()-> - write_to_file(argv[1], *corrected_image_sptr); - return res==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + shared_ptr> corrected_image_sptr((gated_density[1]).get_empty_copy()); + transformation.warp_image(*corrected_image_sptr, gated_density); + + const Succeeded res = + OutputFileFormat>::default_sptr()->write_to_file(argv[1], *corrected_image_sptr); + return res == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/utilities/warp_image.cxx b/src/utilities/warp_image.cxx index 1affc716d7..4bae0c880a 100644 --- a/src/utilities/warp_image.cxx +++ b/src/utilities/warp_image.cxx @@ -1,24 +1,24 @@ /* Copyright (C) 2010 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities \ingroup spatial_transformation - + \brief This program warps an image. \author Charalampos Tsoumpas */ @@ -29,43 +29,40 @@ USING_NAMESPACE_STIR - -int main(int argc, char **argv) -{ - if(argc<6 || argc>8) { - std::cerr<<"Usage: " << argv[0] << " [x-motion-field] [y-motion-field] [z-motion-field] [spline_type] [extend_borders]\n" - << "all shifts are in mm\n" - << "x, y, z are in STIR conventions\n" - << "extend borders is either 1 or 0, defaults to 0\n"; +int +main(int argc, char** argv) { + if (argc < 6 || argc > 8) { + std::cerr << "Usage: " << argv[0] + << " [x-motion-field] [y-motion-field] [z-motion-field] " + "[spline_type] [extend_borders]\n" + << "all shifts are in mm\n" + << "x, y, z are in STIR conventions\n" + << "extend borders is either 1 or 0, defaults to 0\n"; exit(EXIT_FAILURE); } - + // get parameters from command line - char const * const output_filename = argv[1]; - char const * const input_filename = argv[2]; - char const * const motion_x_filename = argv[3]; - char const * const motion_y_filename = argv[4]; - char const * const motion_z_filename = argv[5]; - const int interpolation_type = (argc==6) ? 3 : atoi(argv[6]); - const bool extend_borders = (argc<=7) ? false : (atoi(argv[7])!=0); + char const* const output_filename = argv[1]; + char const* const input_filename = argv[2]; + char const* const motion_x_filename = argv[3]; + char const* const motion_y_filename = argv[4]; + char const* const motion_z_filename = argv[5]; + const int interpolation_type = (argc == 6) ? 3 : atoi(argv[6]); + const bool extend_borders = (argc <= 7) ? false : (atoi(argv[7]) != 0); - const BSpline::BSplineType spline_type = static_cast (interpolation_type); + const BSpline::BSplineType spline_type = static_cast(interpolation_type); - std::cerr << "Interpolating using with splines level: " << spline_type << "\n"; + std::cerr << "Interpolating using with splines level: " << spline_type << "\n"; // read image - const shared_ptr > density_sptr(read_from_file >(input_filename)); - const shared_ptr > motion_x_sptr( - read_from_file >(motion_x_filename)); - const shared_ptr > motion_y_sptr( - read_from_file >(motion_y_filename)); - const shared_ptr > motion_z_sptr( - read_from_file >(motion_z_filename)); - - const VoxelsOnCartesianGrid out_density=warp_image(density_sptr, motion_x_sptr, motion_y_sptr, motion_z_sptr, spline_type, extend_borders); - + const shared_ptr> density_sptr(read_from_file>(input_filename)); + const shared_ptr> motion_x_sptr(read_from_file>(motion_x_filename)); + const shared_ptr> motion_y_sptr(read_from_file>(motion_y_filename)); + const shared_ptr> motion_z_sptr(read_from_file>(motion_z_filename)); + + const VoxelsOnCartesianGrid out_density = + warp_image(density_sptr, motion_x_sptr, motion_y_sptr, motion_z_sptr, spline_type, extend_borders); + // write image - Succeeded res = - OutputFileFormat >::default_sptr()-> - write_to_file(output_filename, out_density); - return res==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + Succeeded res = OutputFileFormat>::default_sptr()->write_to_file(output_filename, out_density); + return res == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/utilities/write_proj_matrix_by_bin.cxx b/src/utilities/write_proj_matrix_by_bin.cxx index 97cb3ca832..ae4087f9f8 100644 --- a/src/utilities/write_proj_matrix_by_bin.cxx +++ b/src/utilities/write_proj_matrix_by_bin.cxx @@ -8,7 +8,7 @@ \brief Program that writes a projection matrix by bin to file \author Kris Thielemans - + */ /* Copyright (C) 2004- 2011, Hammersmith Imanet Ltd @@ -45,85 +45,63 @@ using std::cerr; using std::endl; #endif - int -main(int argc, char **argv) -{ +main(int argc, char** argv) { USING_NAMESPACE_STIR - if (argc==1 || argc>5) - { - cerr <<"Usage: " << argv[0] << " \\\n" - << "\toutput-filename [proj_data_file [projmatrixbybin-parfile [template-image]]]\n"; + if (argc == 1 || argc > 5) { + cerr << "Usage: " << argv[0] << " \\\n" + << "\toutput-filename [proj_data_file [projmatrixbybin-parfile [template-image]]]\n"; exit(EXIT_FAILURE); } - const std::string output_filename_prefix= - argc>1? argv[1] : ask_string("Output filename prefix"); - - shared_ptr proj_data_info_sptr; - if (argc>2) - { - shared_ptr proj_data_sptr = ProjData::read_from_file(argv[2]); - proj_data_info_sptr=proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); - } - else - { - proj_data_info_sptr.reset(ProjDataInfo::ask_parameters()); - } + const std::string output_filename_prefix = argc > 1 ? argv[1] : ask_string("Output filename prefix"); + + shared_ptr proj_data_info_sptr; + if (argc > 2) { + shared_ptr proj_data_sptr = ProjData::read_from_file(argv[2]); + proj_data_info_sptr = proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); + } else { + proj_data_info_sptr.reset(ProjDataInfo::ask_parameters()); + } shared_ptr proj_matrix_sptr; - if (argc>3) - { - KeyParser parser; - parser.add_start_key("ProjMatrixByBin parameters"); - parser.add_parsing_key("type", &proj_matrix_sptr); - parser.add_stop_key("END"); - parser.parse(argv[3]); - } - - shared_ptr > image_sptr; - - if (argc>4) - { - image_sptr = read_from_file >(argv[4]); - } - else - { - const float zoom = ask_num("Zoom factor (>1 means smaller voxels)",0.F,100.F,1.F); - int xy_size = static_cast(proj_data_info_sptr->get_num_tangential_poss()*zoom); - xy_size = ask_num("Number of x,y pixels",3,xy_size*2,xy_size); - int z_size = 2*proj_data_info_sptr->get_scanner_ptr()->get_num_rings()-1; - z_size = ask_num("Number of z pixels",1,1000,z_size); - VoxelsOnCartesianGrid * vox_image_ptr = - new VoxelsOnCartesianGrid(*proj_data_info_sptr, - zoom, - Coordinate3D(0,0,0), - Coordinate3D(z_size,xy_size,xy_size)); - const float z_origin = - ask_num("Shift z-origin (in pixels)", - -vox_image_ptr->get_length()/2, - vox_image_ptr->get_length()/2, - 0) - *vox_image_ptr->get_voxel_size().z(); - vox_image_ptr->set_origin(Coordinate3D(z_origin,0,0)); - - image_sptr.reset(vox_image_ptr); - } - - while (is_null_ptr(proj_matrix_sptr)) - { - proj_matrix_sptr.reset(ProjMatrixByBin::ask_type_and_parameters()); - } - - proj_matrix_sptr->set_up(proj_data_info_sptr, - image_sptr); - - return - ProjMatrixByBinFromFile:: - write_to_file(output_filename_prefix, - *proj_matrix_sptr, - proj_data_info_sptr, - *image_sptr) == Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; + if (argc > 3) { + KeyParser parser; + parser.add_start_key("ProjMatrixByBin parameters"); + parser.add_parsing_key("type", &proj_matrix_sptr); + parser.add_stop_key("END"); + parser.parse(argv[3]); + } + + shared_ptr> image_sptr; + + if (argc > 4) { + image_sptr = read_from_file>(argv[4]); + } else { + const float zoom = ask_num("Zoom factor (>1 means smaller voxels)", 0.F, 100.F, 1.F); + int xy_size = static_cast(proj_data_info_sptr->get_num_tangential_poss() * zoom); + xy_size = ask_num("Number of x,y pixels", 3, xy_size * 2, xy_size); + int z_size = 2 * proj_data_info_sptr->get_scanner_ptr()->get_num_rings() - 1; + z_size = ask_num("Number of z pixels", 1, 1000, z_size); + VoxelsOnCartesianGrid* vox_image_ptr = new VoxelsOnCartesianGrid( + *proj_data_info_sptr, zoom, Coordinate3D(0, 0, 0), Coordinate3D(z_size, xy_size, xy_size)); + const float z_origin = + ask_num("Shift z-origin (in pixels)", -vox_image_ptr->get_length() / 2, vox_image_ptr->get_length() / 2, 0) * + vox_image_ptr->get_voxel_size().z(); + vox_image_ptr->set_origin(Coordinate3D(z_origin, 0, 0)); + + image_sptr.reset(vox_image_ptr); + } + + while (is_null_ptr(proj_matrix_sptr)) { + proj_matrix_sptr.reset(ProjMatrixByBin::ask_type_and_parameters()); + } + + proj_matrix_sptr->set_up(proj_data_info_sptr, image_sptr); + + return ProjMatrixByBinFromFile::write_to_file(output_filename_prefix, *proj_matrix_sptr, proj_data_info_sptr, *image_sptr) == + Succeeded::yes + ? EXIT_SUCCESS + : EXIT_FAILURE; } -//cache_proj_matrix_elems_for_one_bin +// cache_proj_matrix_elems_for_one_bin diff --git a/src/utilities/zeropad_planes.cxx b/src/utilities/zeropad_planes.cxx index 45ebcec4ef..63035ca92f 100644 --- a/src/utilities/zeropad_planes.cxx +++ b/src/utilities/zeropad_planes.cxx @@ -1,12 +1,12 @@ /* Copyright (C) 2011 - 2013, King's College London This file is part of STIR. - + This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.3 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -15,9 +15,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities - + \brief This program zero pads the start & end planes of an image. \author Charalampos Tsoumpas */ @@ -27,50 +27,45 @@ USING_NAMESPACE_STIR -int main(int argc, char **argv) -{ - if(argc!=4) { - std::cerr << "Usage: " << argv[0] - << " [number of axial planes] \n"; +int +main(int argc, char** argv) { + if (argc != 4) { + std::cerr << "Usage: " << argv[0] << " [number of axial planes] \n"; exit(EXIT_FAILURE); } - char const * const output_filename_prefix = argv[1]; - char const * const input_filename = argv[2]; + char const* const output_filename_prefix = argv[1]; + char const* const input_filename = argv[2]; const int num_planes = atoi(argv[3]); - const shared_ptr > image_sptr(DiscretisedDensity<3,float>::read_from_file(input_filename)); - const shared_ptr > out_image_sptr(image_sptr->clone()); - - BasicCoordinate<3,int> c, min, max; - min[1]=image_sptr->get_min_index(); - max[1]=image_sptr->get_max_index(); - - for (c[1]=min[1]; c[1]<=min[1]+num_planes-1; ++c[1]) - { - min[2]=(*image_sptr)[c[1]].get_min_index(); - max[2]=(*image_sptr)[c[1]].get_max_index(); - for (c[2]=min[2]; c[2]<=max[2]; ++c[2]) - { - min[3]=(*image_sptr)[c[1]][c[2]].get_min_index(); - max[3]=(*image_sptr)[c[1]][c[2]].get_max_index(); - for (c[3]=min[3]; c[3]<=max[3]; ++c[3]) - (*out_image_sptr)[c[1]][c[2]][c[3]]=0.F; - } + const shared_ptr> image_sptr(DiscretisedDensity<3, float>::read_from_file(input_filename)); + const shared_ptr> out_image_sptr(image_sptr->clone()); + + BasicCoordinate<3, int> c, min, max; + min[1] = image_sptr->get_min_index(); + max[1] = image_sptr->get_max_index(); + + for (c[1] = min[1]; c[1] <= min[1] + num_planes - 1; ++c[1]) { + min[2] = (*image_sptr)[c[1]].get_min_index(); + max[2] = (*image_sptr)[c[1]].get_max_index(); + for (c[2] = min[2]; c[2] <= max[2]; ++c[2]) { + min[3] = (*image_sptr)[c[1]][c[2]].get_min_index(); + max[3] = (*image_sptr)[c[1]][c[2]].get_max_index(); + for (c[3] = min[3]; c[3] <= max[3]; ++c[3]) + (*out_image_sptr)[c[1]][c[2]][c[3]] = 0.F; } - for (c[1]=max[1]; c[1]>=max[1]-num_planes+1; --c[1]) - { - min[2]=(*image_sptr)[c[1]].get_min_index(); - max[2]=(*image_sptr)[c[1]].get_max_index(); - for (c[2]=min[2]; c[2]<=max[2]; ++c[2]) - { - min[3]=(*image_sptr)[c[1]][c[2]].get_min_index(); - max[3]=(*image_sptr)[c[1]][c[2]].get_max_index(); - for (c[3]=min[3]; c[3]<=max[3]; ++c[3]) - (*out_image_sptr)[c[1]][c[2]][c[3]]=0.F; - } - } - const Succeeded res = OutputFileFormat >::default_sptr()-> - write_to_file(output_filename_prefix, *out_image_sptr); - - return res==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + } + for (c[1] = max[1]; c[1] >= max[1] - num_planes + 1; --c[1]) { + min[2] = (*image_sptr)[c[1]].get_min_index(); + max[2] = (*image_sptr)[c[1]].get_max_index(); + for (c[2] = min[2]; c[2] <= max[2]; ++c[2]) { + min[3] = (*image_sptr)[c[1]][c[2]].get_min_index(); + max[3] = (*image_sptr)[c[1]][c[2]].get_max_index(); + for (c[3] = min[3]; c[3] <= max[3]; ++c[3]) + (*out_image_sptr)[c[1]][c[2]][c[3]] = 0.F; + } + } + const Succeeded res = + OutputFileFormat>::default_sptr()->write_to_file(output_filename_prefix, *out_image_sptr); + + return res == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/utilities/zoom_image.cxx b/src/utilities/zoom_image.cxx index a77318ef12..0e14781ef9 100644 --- a/src/utilities/zoom_image.cxx +++ b/src/utilities/zoom_image.cxx @@ -18,9 +18,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities - + \brief This program serves as a stand-alone zoom/trim utility for image files Run without arguments to get a usage message. @@ -35,142 +35,125 @@ //#include "stir/utilities.h" #include "stir/Succeeded.h" - #ifndef STIR_NO_NAMESPACES using std::cerr; #endif USING_NAMESPACE_STIR -static void print_usage_and_exit(const std::string& prog_name) -{ - cerr<<"Usage: \n" - << '\t' << prog_name << " [--scaling